opencandle 0.11.1 → 0.13.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.
Files changed (678) hide show
  1. package/README.md +50 -186
  2. package/dist/analysts/contracts.js +0 -1
  3. package/dist/analysts/orchestrator.js +0 -1
  4. package/dist/cli-main.js +22 -15
  5. package/dist/cli-options.d.ts +4 -0
  6. package/dist/cli-options.js +33 -0
  7. package/dist/cli.js +8 -3
  8. package/dist/config.d.ts +4 -0
  9. package/dist/config.js +1 -1
  10. package/dist/doctor/cli-command.js +9 -5
  11. package/dist/doctor/render.js +0 -1
  12. package/dist/doctor/report.js +53 -11
  13. package/dist/gui/server/ask-user-bridge.d.ts +19 -0
  14. package/dist/gui/server/ask-user-bridge.js +55 -0
  15. package/dist/gui/server/automation-heartbeat.d.ts +25 -0
  16. package/dist/gui/server/automation-heartbeat.js +61 -0
  17. package/dist/gui/server/background-quotes.d.ts +39 -0
  18. package/dist/gui/server/background-quotes.js +71 -0
  19. package/dist/gui/server/chat-event-adapter.d.ts +16 -0
  20. package/dist/gui/server/chat-event-adapter.js +388 -0
  21. package/dist/gui/server/gui-session-manager.d.ts +2 -0
  22. package/dist/gui/server/gui-session-manager.js +4 -0
  23. package/dist/gui/server/history-snapshot-store.d.ts +8 -0
  24. package/dist/gui/server/history-snapshot-store.js +43 -0
  25. package/dist/gui/server/http-routes.d.ts +71 -0
  26. package/dist/gui/server/http-routes.js +1033 -0
  27. package/dist/gui/server/invoke-tool.d.ts +47 -0
  28. package/dist/gui/server/invoke-tool.js +373 -0
  29. package/dist/gui/server/live-chat-event-adapter.d.ts +21 -0
  30. package/dist/gui/server/live-chat-event-adapter.js +224 -0
  31. package/dist/gui/server/local-session-coordinator.d.ts +26 -0
  32. package/dist/gui/server/local-session-coordinator.js +53 -0
  33. package/dist/gui/server/market-indices-api.d.ts +21 -0
  34. package/dist/gui/server/market-indices-api.js +26 -0
  35. package/dist/gui/server/market-indices-snapshot-store.d.ts +12 -0
  36. package/dist/gui/server/market-indices-snapshot-store.js +56 -0
  37. package/dist/gui/server/market-state-api.d.ts +250 -0
  38. package/dist/gui/server/market-state-api.js +597 -0
  39. package/dist/gui/server/model-setup.d.ts +55 -0
  40. package/dist/gui/server/model-setup.js +154 -0
  41. package/dist/gui/server/private-api-access.d.ts +6 -0
  42. package/dist/gui/server/private-api-access.js +53 -0
  43. package/dist/gui/server/projector.d.ts +49 -0
  44. package/dist/gui/server/projector.js +296 -0
  45. package/dist/gui/server/prompt-observation.d.ts +8 -0
  46. package/dist/gui/server/prompt-observation.js +43 -0
  47. package/dist/gui/server/quote-snapshot-store.d.ts +14 -0
  48. package/dist/gui/server/quote-snapshot-store.js +49 -0
  49. package/dist/gui/server/server.d.ts +1 -0
  50. package/dist/gui/server/server.js +262 -0
  51. package/dist/gui/server/session-actions.d.ts +60 -0
  52. package/dist/gui/server/session-actions.js +218 -0
  53. package/dist/gui/server/session-entry-wait.d.ts +27 -0
  54. package/dist/gui/server/session-entry-wait.js +129 -0
  55. package/dist/gui/server/session-list.d.ts +2 -0
  56. package/dist/gui/server/session-list.js +11 -0
  57. package/dist/gui/server/shutdown.d.ts +10 -0
  58. package/dist/gui/server/shutdown.js +29 -0
  59. package/dist/gui/server/tool-invoke-ack.d.ts +17 -0
  60. package/dist/gui/server/tool-invoke-ack.js +26 -0
  61. package/dist/gui/server/tool-metadata.d.ts +93 -0
  62. package/dist/gui/server/tool-metadata.js +148 -0
  63. package/dist/gui/server/websocket.d.ts +9 -0
  64. package/dist/gui/server/websocket.js +124 -0
  65. package/dist/gui/server/writer-lock.d.ts +1 -0
  66. package/dist/gui/server/writer-lock.js +1 -0
  67. package/dist/gui/server/ws-hub.d.ts +50 -0
  68. package/dist/gui/server/ws-hub.js +284 -0
  69. package/dist/gui/shared/chat-events.d.ts +174 -0
  70. package/dist/gui/shared/chat-events.js +13 -0
  71. package/dist/gui/shared/event-reducer.d.ts +3 -0
  72. package/dist/gui/shared/event-reducer.js +187 -0
  73. package/dist/index.js +0 -1
  74. package/dist/infra/cache.d.ts +4 -0
  75. package/dist/infra/cache.js +4 -1
  76. package/dist/infra/freshness.js +0 -1
  77. package/dist/infra/http-client.js +1 -2
  78. package/dist/infra/index.js +0 -1
  79. package/dist/infra/lse-byte-budget.d.ts +10 -0
  80. package/dist/infra/lse-byte-budget.js +47 -0
  81. package/dist/infra/market-calendar.js +0 -1
  82. package/dist/infra/native-dependencies.js +0 -1
  83. package/dist/infra/node-version.js +0 -1
  84. package/dist/infra/open-url.js +0 -1
  85. package/dist/infra/opencandle-paths.js +0 -1
  86. package/dist/infra/rate-limiter.js +1 -1
  87. package/dist/market-state/alert-conditions.js +0 -1
  88. package/dist/market-state/alert-runner.d.ts +1 -0
  89. package/dist/market-state/alert-runner.js +5 -4
  90. package/dist/market-state/daily-report.js +0 -1
  91. package/dist/market-state/local-automation-service.js +0 -1
  92. package/dist/market-state/notification-delivery.js +0 -1
  93. package/dist/market-state/resolve-for-mutation.js +0 -1
  94. package/dist/market-state/resolve.js +0 -1
  95. package/dist/market-state/service.d.ts +26 -21
  96. package/dist/market-state/service.js +175 -36
  97. package/dist/market-state/summaries.js +1 -13
  98. package/dist/memory/index.js +0 -1
  99. package/dist/memory/manager.js +0 -1
  100. package/dist/memory/preference-extractor.js +0 -1
  101. package/dist/memory/retrieval.js +0 -1
  102. package/dist/memory/sqlite.js +60 -11
  103. package/dist/memory/storage.js +0 -1
  104. package/dist/memory/tool-defaults.js +0 -1
  105. package/dist/memory/types.js +0 -1
  106. package/dist/monitor.js +0 -1
  107. package/dist/onboarding/connect.js +0 -1
  108. package/dist/onboarding/credential-interceptor.js +0 -1
  109. package/dist/onboarding/degradation-accumulator.js +0 -1
  110. package/dist/onboarding/prompt-user.d.ts +1 -1
  111. package/dist/onboarding/prompt-user.js +0 -1
  112. package/dist/onboarding/provider-status.js +0 -1
  113. package/dist/onboarding/providers.d.ts +16 -1
  114. package/dist/onboarding/providers.js +20 -1
  115. package/dist/onboarding/state.js +0 -1
  116. package/dist/onboarding/tool-helpers.js +0 -1
  117. package/dist/onboarding/tool-tags.js +0 -1
  118. package/dist/onboarding/validate-model-key.d.ts +17 -0
  119. package/dist/onboarding/validate-model-key.js +86 -0
  120. package/dist/onboarding/validation.js +8 -1
  121. package/dist/pi/opencandle-extension.d.ts +2 -1
  122. package/dist/pi/opencandle-extension.js +4 -4
  123. package/dist/pi/session-action-dedupe.js +0 -1
  124. package/dist/pi/session-storage.js +0 -1
  125. package/dist/pi/session-writer-lock.js +0 -1
  126. package/dist/pi/session.d.ts +2 -3
  127. package/dist/pi/session.js +7 -6
  128. package/dist/pi/setup.d.ts +4 -2
  129. package/dist/pi/setup.js +60 -61
  130. package/dist/pi/tool-adapter.js +0 -1
  131. package/dist/pi/tui-session-coordinator.js +0 -1
  132. package/dist/prompts/context-builder.js +1 -2
  133. package/dist/prompts/disclaimer.js +0 -1
  134. package/dist/prompts/policy-cards.js +0 -1
  135. package/dist/prompts/sections.js +0 -1
  136. package/dist/prompts/symbol-preflight.js +0 -1
  137. package/dist/prompts/workflow-prompts.js +16 -15
  138. package/dist/providers/alpha-vantage.js +2 -3
  139. package/dist/providers/coingecko.js +0 -1
  140. package/dist/providers/errors.js +0 -1
  141. package/dist/providers/exa-search.js +11 -10
  142. package/dist/providers/external-tool-command.js +0 -1
  143. package/dist/providers/external-tool-error.js +0 -1
  144. package/dist/providers/fear-greed.js +0 -1
  145. package/dist/providers/finnhub.js +0 -1
  146. package/dist/providers/fred.js +0 -1
  147. package/dist/providers/index.d.ts +1 -0
  148. package/dist/providers/index.js +1 -1
  149. package/dist/providers/lse.d.ts +35 -0
  150. package/dist/providers/lse.js +284 -0
  151. package/dist/providers/polymarket.js +22 -6
  152. package/dist/providers/provider-credential-error.js +0 -1
  153. package/dist/providers/reddit-cli.js +0 -1
  154. package/dist/providers/reddit.js +0 -1
  155. package/dist/providers/sec-edgar.js +0 -1
  156. package/dist/providers/tradingview.js +1 -2
  157. package/dist/providers/twitter-cli.js +0 -1
  158. package/dist/providers/twitter.js +0 -1
  159. package/dist/providers/web-search.js +15 -12
  160. package/dist/providers/with-fallback.js +0 -1
  161. package/dist/providers/wrap-provider.js +1 -1
  162. package/dist/providers/yahoo-finance.js +68 -4
  163. package/dist/routing/classify-intent.js +0 -1
  164. package/dist/routing/defaults.js +0 -1
  165. package/dist/routing/entity-extractor.js +2 -3
  166. package/dist/routing/fund-symbols.js +0 -1
  167. package/dist/routing/horizon.js +0 -1
  168. package/dist/routing/index.js +0 -1
  169. package/dist/routing/legacy-rule-router.js +0 -1
  170. package/dist/routing/planning.js +0 -1
  171. package/dist/routing/route-manifest.js +1 -1
  172. package/dist/routing/router-llm-client.d.ts +2 -2
  173. package/dist/routing/router-llm-client.js +0 -1
  174. package/dist/routing/router-prompt.js +0 -1
  175. package/dist/routing/router-types.js +0 -1
  176. package/dist/routing/router.js +9 -3
  177. package/dist/routing/slot-resolver.js +0 -1
  178. package/dist/routing/symbol-disambiguator.js +0 -1
  179. package/dist/routing/turn-context.js +0 -1
  180. package/dist/routing/types.js +0 -1
  181. package/dist/runtime/answer-contracts.js +0 -1
  182. package/dist/runtime/artifact-contracts.js +0 -1
  183. package/dist/runtime/evidence.d.ts +1 -0
  184. package/dist/runtime/evidence.js +1 -2
  185. package/dist/runtime/numeric-claims.js +0 -1
  186. package/dist/runtime/planning-evidence.js +0 -1
  187. package/dist/runtime/prompt-step.js +0 -1
  188. package/dist/runtime/provider-tracker.js +0 -1
  189. package/dist/runtime/run-context.js +0 -1
  190. package/dist/runtime/session-coordinator.d.ts +2 -2
  191. package/dist/runtime/session-coordinator.js +2 -3
  192. package/dist/runtime/session-title.js +0 -1
  193. package/dist/runtime/tool-defaults-wrapper.js +0 -1
  194. package/dist/runtime/validation.js +0 -1
  195. package/dist/runtime/workflow-events.js +0 -1
  196. package/dist/runtime/workflow-runner.d.ts +1 -0
  197. package/dist/runtime/workflow-runner.js +8 -3
  198. package/dist/runtime/workflow-types.js +0 -1
  199. package/dist/sentiment/adapters/finnhub.js +0 -1
  200. package/dist/sentiment/adapters/reddit.js +0 -1
  201. package/dist/sentiment/adapters/twitter.js +0 -1
  202. package/dist/sentiment/adapters/web.js +0 -1
  203. package/dist/sentiment/index.js +4 -2
  204. package/dist/sentiment/insights.js +0 -1
  205. package/dist/sentiment/keywords.js +0 -1
  206. package/dist/sentiment/pipeline.js +0 -1
  207. package/dist/sentiment/scorer.js +0 -1
  208. package/dist/sentiment/store.js +0 -1
  209. package/dist/sentiment/trends.js +0 -1
  210. package/dist/sentiment/types.js +0 -1
  211. package/dist/system-prompt.js +0 -1
  212. package/dist/tool-kit.js +0 -1
  213. package/dist/tools/fundamentals/company-overview.d.ts +1 -1
  214. package/dist/tools/fundamentals/company-overview.js +2 -1
  215. package/dist/tools/fundamentals/comps.js +6 -4
  216. package/dist/tools/fundamentals/dcf.js +37 -9
  217. package/dist/tools/fundamentals/earnings.d.ts +1 -1
  218. package/dist/tools/fundamentals/earnings.js +2 -1
  219. package/dist/tools/fundamentals/financials.js +88 -9
  220. package/dist/tools/fundamentals/sec-filings.js +0 -1
  221. package/dist/tools/index.d.ts +121 -2
  222. package/dist/tools/index.js +3 -1
  223. package/dist/tools/interaction/ask-user.js +11 -1
  224. package/dist/tools/macro/event-probabilities.js +0 -1
  225. package/dist/tools/macro/fear-greed.d.ts +1 -1
  226. package/dist/tools/macro/fear-greed.js +0 -1
  227. package/dist/tools/macro/fred-data.d.ts +1 -1
  228. package/dist/tools/macro/fred-data.js +2 -1
  229. package/dist/tools/market/crypto-history.js +0 -1
  230. package/dist/tools/market/crypto-price.d.ts +2 -2
  231. package/dist/tools/market/crypto-price.js +0 -1
  232. package/dist/tools/market/price-comparison.d.ts +30 -0
  233. package/dist/tools/market/price-comparison.js +202 -0
  234. package/dist/tools/market/screen-stocks.js +0 -1
  235. package/dist/tools/market/search-ticker.js +1 -2
  236. package/dist/tools/market/stock-history.d.ts +18 -3
  237. package/dist/tools/market/stock-history.js +132 -18
  238. package/dist/tools/market/stock-quote.d.ts +2 -2
  239. package/dist/tools/market/stock-quote.js +0 -1
  240. package/dist/tools/options/greeks.js +0 -1
  241. package/dist/tools/options/option-chain.d.ts +2 -2
  242. package/dist/tools/options/option-chain.js +0 -1
  243. package/dist/tools/portfolio/alerts.d.ts +2 -1
  244. package/dist/tools/portfolio/alerts.js +228 -2
  245. package/dist/tools/portfolio/correlation.d.ts +1 -1
  246. package/dist/tools/portfolio/correlation.js +23 -5
  247. package/dist/tools/portfolio/daily-report.js +0 -1
  248. package/dist/tools/portfolio/holdings-overlap.js +0 -1
  249. package/dist/tools/portfolio/notifications.js +0 -1
  250. package/dist/tools/portfolio/risk-analysis.d.ts +2 -2
  251. package/dist/tools/portfolio/risk-analysis.js +0 -1
  252. package/dist/tools/portfolio/tracker.d.ts +3 -1
  253. package/dist/tools/portfolio/tracker.js +57 -10
  254. package/dist/tools/portfolio/watchlist.d.ts +3 -6
  255. package/dist/tools/portfolio/watchlist.js +101 -110
  256. package/dist/tools/sentiment/insight-format.js +0 -1
  257. package/dist/tools/sentiment/query-match.js +0 -1
  258. package/dist/tools/sentiment/reddit-sentiment.js +0 -1
  259. package/dist/tools/sentiment/sentiment-summary.js +8 -4
  260. package/dist/tools/sentiment/sentiment-trend.d.ts +5 -1
  261. package/dist/tools/sentiment/sentiment-trend.js +6 -2
  262. package/dist/tools/sentiment/twitter-sentiment.js +0 -1
  263. package/dist/tools/sentiment/untrusted-text.js +0 -1
  264. package/dist/tools/sentiment/web-search.d.ts +1 -1
  265. package/dist/tools/sentiment/web-search.js +0 -1
  266. package/dist/tools/sentiment/web-sentiment.js +0 -1
  267. package/dist/tools/technical/backtest.js +0 -1
  268. package/dist/tools/technical/indicators.js +0 -1
  269. package/dist/types/fundamentals.js +0 -1
  270. package/dist/types/index.js +0 -1
  271. package/dist/types/macro.js +0 -1
  272. package/dist/types/market.d.ts +8 -0
  273. package/dist/types/market.js +0 -1
  274. package/dist/types/options.js +0 -1
  275. package/dist/types/portfolio.js +0 -1
  276. package/dist/types/prediction-markets.js +0 -1
  277. package/dist/types/sentiment.js +0 -1
  278. package/dist/workflows/compare-assets.js +0 -1
  279. package/dist/workflows/index.js +0 -1
  280. package/dist/workflows/options-screener.js +0 -1
  281. package/dist/workflows/portfolio-builder.js +0 -1
  282. package/gui/web/dist/assets/CatalogOverlay-Cy8Fq0fn.js +1 -0
  283. package/gui/web/dist/assets/allocation-donut-DgBRIKCk.js +52 -0
  284. package/gui/web/dist/assets/index-DIlFyIOO.js +66 -0
  285. package/gui/web/dist/assets/index-DS4jESOB.css +2 -0
  286. package/gui/web/dist/assets/market-chart-DammaCjH.js +1 -0
  287. package/gui/web/dist/assets/utils-CnADgYgh.js +1 -0
  288. package/gui/web/dist/index.html +3 -2
  289. package/package.json +23 -26
  290. package/dist/analysts/contracts.js.map +0 -1
  291. package/dist/analysts/orchestrator.js.map +0 -1
  292. package/dist/cli-main.js.map +0 -1
  293. package/dist/cli.js.map +0 -1
  294. package/dist/config.js.map +0 -1
  295. package/dist/doctor/cli-command.js.map +0 -1
  296. package/dist/doctor/render.js.map +0 -1
  297. package/dist/doctor/report.js.map +0 -1
  298. package/dist/index.js.map +0 -1
  299. package/dist/infra/cache.js.map +0 -1
  300. package/dist/infra/freshness.js.map +0 -1
  301. package/dist/infra/http-client.js.map +0 -1
  302. package/dist/infra/index.js.map +0 -1
  303. package/dist/infra/market-calendar.js.map +0 -1
  304. package/dist/infra/native-dependencies.js.map +0 -1
  305. package/dist/infra/node-version.js.map +0 -1
  306. package/dist/infra/open-url.js.map +0 -1
  307. package/dist/infra/opencandle-paths.js.map +0 -1
  308. package/dist/infra/rate-limiter.js.map +0 -1
  309. package/dist/market-state/alert-conditions.js.map +0 -1
  310. package/dist/market-state/alert-runner.js.map +0 -1
  311. package/dist/market-state/daily-report.js.map +0 -1
  312. package/dist/market-state/local-automation-service.js.map +0 -1
  313. package/dist/market-state/notification-delivery.js.map +0 -1
  314. package/dist/market-state/resolve-for-mutation.js.map +0 -1
  315. package/dist/market-state/resolve.js.map +0 -1
  316. package/dist/market-state/service.js.map +0 -1
  317. package/dist/market-state/summaries.js.map +0 -1
  318. package/dist/memory/index.js.map +0 -1
  319. package/dist/memory/manager.js.map +0 -1
  320. package/dist/memory/preference-extractor.js.map +0 -1
  321. package/dist/memory/retrieval.js.map +0 -1
  322. package/dist/memory/sqlite.js.map +0 -1
  323. package/dist/memory/storage.js.map +0 -1
  324. package/dist/memory/tool-defaults.js.map +0 -1
  325. package/dist/memory/types.js.map +0 -1
  326. package/dist/monitor.js.map +0 -1
  327. package/dist/onboarding/connect.js.map +0 -1
  328. package/dist/onboarding/credential-interceptor.js.map +0 -1
  329. package/dist/onboarding/degradation-accumulator.js.map +0 -1
  330. package/dist/onboarding/prompt-user.js.map +0 -1
  331. package/dist/onboarding/provider-status.js.map +0 -1
  332. package/dist/onboarding/providers.js.map +0 -1
  333. package/dist/onboarding/state.js.map +0 -1
  334. package/dist/onboarding/tool-helpers.js.map +0 -1
  335. package/dist/onboarding/tool-tags.js.map +0 -1
  336. package/dist/onboarding/validation.js.map +0 -1
  337. package/dist/pi/opencandle-extension.js.map +0 -1
  338. package/dist/pi/session-action-dedupe.js.map +0 -1
  339. package/dist/pi/session-storage.js.map +0 -1
  340. package/dist/pi/session-writer-lock.js.map +0 -1
  341. package/dist/pi/session.js.map +0 -1
  342. package/dist/pi/setup.js.map +0 -1
  343. package/dist/pi/tool-adapter.js.map +0 -1
  344. package/dist/pi/tui-session-coordinator.js.map +0 -1
  345. package/dist/prompts/context-builder.js.map +0 -1
  346. package/dist/prompts/disclaimer.js.map +0 -1
  347. package/dist/prompts/policy-cards.js.map +0 -1
  348. package/dist/prompts/sections.js.map +0 -1
  349. package/dist/prompts/symbol-preflight.js.map +0 -1
  350. package/dist/prompts/workflow-prompts.js.map +0 -1
  351. package/dist/providers/alpha-vantage.js.map +0 -1
  352. package/dist/providers/coingecko.js.map +0 -1
  353. package/dist/providers/errors.js.map +0 -1
  354. package/dist/providers/exa-search.js.map +0 -1
  355. package/dist/providers/external-tool-command.js.map +0 -1
  356. package/dist/providers/external-tool-error.js.map +0 -1
  357. package/dist/providers/fear-greed.js.map +0 -1
  358. package/dist/providers/finnhub.js.map +0 -1
  359. package/dist/providers/fred.js.map +0 -1
  360. package/dist/providers/index.js.map +0 -1
  361. package/dist/providers/polymarket.js.map +0 -1
  362. package/dist/providers/provider-credential-error.js.map +0 -1
  363. package/dist/providers/reddit-cli.js.map +0 -1
  364. package/dist/providers/reddit.js.map +0 -1
  365. package/dist/providers/sec-edgar.js.map +0 -1
  366. package/dist/providers/tradingview.js.map +0 -1
  367. package/dist/providers/twitter-cli.js.map +0 -1
  368. package/dist/providers/twitter.js.map +0 -1
  369. package/dist/providers/web-search.js.map +0 -1
  370. package/dist/providers/with-fallback.js.map +0 -1
  371. package/dist/providers/wrap-provider.js.map +0 -1
  372. package/dist/providers/yahoo-finance.js.map +0 -1
  373. package/dist/routing/classify-intent.js.map +0 -1
  374. package/dist/routing/defaults.js.map +0 -1
  375. package/dist/routing/entity-extractor.js.map +0 -1
  376. package/dist/routing/fund-symbols.js.map +0 -1
  377. package/dist/routing/horizon.js.map +0 -1
  378. package/dist/routing/index.js.map +0 -1
  379. package/dist/routing/legacy-rule-router.js.map +0 -1
  380. package/dist/routing/planning.js.map +0 -1
  381. package/dist/routing/route-manifest.js.map +0 -1
  382. package/dist/routing/router-llm-client.js.map +0 -1
  383. package/dist/routing/router-prompt.js.map +0 -1
  384. package/dist/routing/router-types.js.map +0 -1
  385. package/dist/routing/router.js.map +0 -1
  386. package/dist/routing/slot-resolver.js.map +0 -1
  387. package/dist/routing/symbol-disambiguator.js.map +0 -1
  388. package/dist/routing/turn-context.js.map +0 -1
  389. package/dist/routing/types.js.map +0 -1
  390. package/dist/runtime/answer-contracts.js.map +0 -1
  391. package/dist/runtime/artifact-contracts.js.map +0 -1
  392. package/dist/runtime/evidence.js.map +0 -1
  393. package/dist/runtime/numeric-claims.js.map +0 -1
  394. package/dist/runtime/planning-evidence.js.map +0 -1
  395. package/dist/runtime/prompt-step.js.map +0 -1
  396. package/dist/runtime/provider-tracker.js.map +0 -1
  397. package/dist/runtime/run-context.js.map +0 -1
  398. package/dist/runtime/session-coordinator.js.map +0 -1
  399. package/dist/runtime/session-title.js.map +0 -1
  400. package/dist/runtime/tool-defaults-wrapper.js.map +0 -1
  401. package/dist/runtime/validation.js.map +0 -1
  402. package/dist/runtime/workflow-events.js.map +0 -1
  403. package/dist/runtime/workflow-runner.js.map +0 -1
  404. package/dist/runtime/workflow-types.js.map +0 -1
  405. package/dist/sentiment/adapters/finnhub.js.map +0 -1
  406. package/dist/sentiment/adapters/reddit.js.map +0 -1
  407. package/dist/sentiment/adapters/twitter.js.map +0 -1
  408. package/dist/sentiment/adapters/web.js.map +0 -1
  409. package/dist/sentiment/index.js.map +0 -1
  410. package/dist/sentiment/insights.js.map +0 -1
  411. package/dist/sentiment/keywords.js.map +0 -1
  412. package/dist/sentiment/pipeline.js.map +0 -1
  413. package/dist/sentiment/scorer.js.map +0 -1
  414. package/dist/sentiment/store.js.map +0 -1
  415. package/dist/sentiment/trends.js.map +0 -1
  416. package/dist/sentiment/types.js.map +0 -1
  417. package/dist/system-prompt.js.map +0 -1
  418. package/dist/tool-kit.js.map +0 -1
  419. package/dist/tools/fundamentals/company-overview.js.map +0 -1
  420. package/dist/tools/fundamentals/comps.js.map +0 -1
  421. package/dist/tools/fundamentals/dcf.js.map +0 -1
  422. package/dist/tools/fundamentals/earnings.js.map +0 -1
  423. package/dist/tools/fundamentals/financials.js.map +0 -1
  424. package/dist/tools/fundamentals/sec-filings.js.map +0 -1
  425. package/dist/tools/index.js.map +0 -1
  426. package/dist/tools/interaction/ask-user.js.map +0 -1
  427. package/dist/tools/macro/event-probabilities.js.map +0 -1
  428. package/dist/tools/macro/fear-greed.js.map +0 -1
  429. package/dist/tools/macro/fred-data.js.map +0 -1
  430. package/dist/tools/market/crypto-history.js.map +0 -1
  431. package/dist/tools/market/crypto-price.js.map +0 -1
  432. package/dist/tools/market/screen-stocks.js.map +0 -1
  433. package/dist/tools/market/search-ticker.js.map +0 -1
  434. package/dist/tools/market/stock-history.js.map +0 -1
  435. package/dist/tools/market/stock-quote.js.map +0 -1
  436. package/dist/tools/options/greeks.js.map +0 -1
  437. package/dist/tools/options/option-chain.js.map +0 -1
  438. package/dist/tools/portfolio/alerts.js.map +0 -1
  439. package/dist/tools/portfolio/correlation.js.map +0 -1
  440. package/dist/tools/portfolio/daily-report.js.map +0 -1
  441. package/dist/tools/portfolio/holdings-overlap.js.map +0 -1
  442. package/dist/tools/portfolio/notifications.js.map +0 -1
  443. package/dist/tools/portfolio/risk-analysis.js.map +0 -1
  444. package/dist/tools/portfolio/tracker.js.map +0 -1
  445. package/dist/tools/portfolio/watchlist.js.map +0 -1
  446. package/dist/tools/sentiment/insight-format.js.map +0 -1
  447. package/dist/tools/sentiment/query-match.js.map +0 -1
  448. package/dist/tools/sentiment/reddit-sentiment.js.map +0 -1
  449. package/dist/tools/sentiment/sentiment-summary.js.map +0 -1
  450. package/dist/tools/sentiment/sentiment-trend.js.map +0 -1
  451. package/dist/tools/sentiment/twitter-sentiment.js.map +0 -1
  452. package/dist/tools/sentiment/untrusted-text.js.map +0 -1
  453. package/dist/tools/sentiment/web-search.js.map +0 -1
  454. package/dist/tools/sentiment/web-sentiment.js.map +0 -1
  455. package/dist/tools/technical/backtest.js.map +0 -1
  456. package/dist/tools/technical/indicators.js.map +0 -1
  457. package/dist/types/fundamentals.js.map +0 -1
  458. package/dist/types/index.js.map +0 -1
  459. package/dist/types/macro.js.map +0 -1
  460. package/dist/types/market.js.map +0 -1
  461. package/dist/types/options.js.map +0 -1
  462. package/dist/types/portfolio.js.map +0 -1
  463. package/dist/types/prediction-markets.js.map +0 -1
  464. package/dist/types/sentiment.js.map +0 -1
  465. package/dist/workflows/compare-assets.js.map +0 -1
  466. package/dist/workflows/index.js.map +0 -1
  467. package/dist/workflows/options-screener.js.map +0 -1
  468. package/dist/workflows/portfolio-builder.js.map +0 -1
  469. package/gui/server/ask-user-bridge.ts +0 -89
  470. package/gui/server/automation-heartbeat.ts +0 -97
  471. package/gui/server/background-quotes.ts +0 -127
  472. package/gui/server/chat-event-adapter.ts +0 -294
  473. package/gui/server/gui-session-manager.ts +0 -5
  474. package/gui/server/http-routes.ts +0 -1201
  475. package/gui/server/invoke-tool.ts +0 -490
  476. package/gui/server/live-chat-event-adapter.ts +0 -243
  477. package/gui/server/local-session-coordinator.ts +0 -97
  478. package/gui/server/market-state-api.ts +0 -331
  479. package/gui/server/model-setup.ts +0 -254
  480. package/gui/server/package.json +0 -5
  481. package/gui/server/private-api-access.ts +0 -62
  482. package/gui/server/projector.ts +0 -392
  483. package/gui/server/prompt-observation.ts +0 -58
  484. package/gui/server/quote-snapshot-store.ts +0 -50
  485. package/gui/server/server.ts +0 -289
  486. package/gui/server/session-actions.ts +0 -323
  487. package/gui/server/session-entry-wait.ts +0 -179
  488. package/gui/server/shutdown.ts +0 -47
  489. package/gui/server/tool-invoke-ack.ts +0 -49
  490. package/gui/server/tool-metadata.ts +0 -167
  491. package/gui/server/websocket.ts +0 -138
  492. package/gui/server/writer-lock.ts +0 -1
  493. package/gui/server/ws-hub.ts +0 -403
  494. package/gui/shared/chat-events.ts +0 -165
  495. package/gui/shared/event-reducer.ts +0 -220
  496. package/gui/web/dist/assets/CatalogOverlay-DZ1niyQm.js +0 -1
  497. package/gui/web/dist/assets/index-D4F9AJnn.css +0 -2
  498. package/gui/web/dist/assets/index-DtqMMBTr.js +0 -65
  499. package/src/analysts/contracts.ts +0 -176
  500. package/src/analysts/orchestrator.ts +0 -244
  501. package/src/cli-main.ts +0 -510
  502. package/src/cli.ts +0 -17
  503. package/src/config.ts +0 -272
  504. package/src/doctor/cli-command.ts +0 -83
  505. package/src/doctor/render.ts +0 -37
  506. package/src/doctor/report.ts +0 -638
  507. package/src/index.ts +0 -5
  508. package/src/infra/cache.ts +0 -127
  509. package/src/infra/freshness.ts +0 -165
  510. package/src/infra/http-client.ts +0 -134
  511. package/src/infra/index.ts +0 -14
  512. package/src/infra/market-calendar.ts +0 -193
  513. package/src/infra/native-dependencies.ts +0 -84
  514. package/src/infra/node-version.ts +0 -23
  515. package/src/infra/open-url.ts +0 -28
  516. package/src/infra/opencandle-paths.ts +0 -53
  517. package/src/infra/rate-limiter.ts +0 -77
  518. package/src/market-state/alert-conditions.ts +0 -82
  519. package/src/market-state/alert-runner.ts +0 -863
  520. package/src/market-state/daily-report.ts +0 -237
  521. package/src/market-state/local-automation-service.ts +0 -162
  522. package/src/market-state/notification-delivery.ts +0 -158
  523. package/src/market-state/resolve-for-mutation.ts +0 -24
  524. package/src/market-state/resolve.ts +0 -112
  525. package/src/market-state/service.ts +0 -2208
  526. package/src/market-state/summaries.ts +0 -75
  527. package/src/memory/index.ts +0 -10
  528. package/src/memory/manager.ts +0 -190
  529. package/src/memory/preference-extractor.ts +0 -106
  530. package/src/memory/retrieval.ts +0 -71
  531. package/src/memory/sqlite.ts +0 -577
  532. package/src/memory/storage.ts +0 -195
  533. package/src/memory/tool-defaults.ts +0 -108
  534. package/src/memory/types.ts +0 -71
  535. package/src/monitor.ts +0 -123
  536. package/src/onboarding/connect.ts +0 -177
  537. package/src/onboarding/credential-interceptor.ts +0 -122
  538. package/src/onboarding/degradation-accumulator.ts +0 -77
  539. package/src/onboarding/prompt-user.ts +0 -85
  540. package/src/onboarding/provider-status.ts +0 -382
  541. package/src/onboarding/providers.ts +0 -442
  542. package/src/onboarding/state.ts +0 -216
  543. package/src/onboarding/tool-helpers.ts +0 -104
  544. package/src/onboarding/tool-tags.ts +0 -244
  545. package/src/onboarding/validation.ts +0 -152
  546. package/src/pi/opencandle-extension.ts +0 -1294
  547. package/src/pi/session-action-dedupe.ts +0 -155
  548. package/src/pi/session-storage.ts +0 -5
  549. package/src/pi/session-writer-lock.ts +0 -426
  550. package/src/pi/session.ts +0 -84
  551. package/src/pi/setup.ts +0 -399
  552. package/src/pi/tool-adapter.ts +0 -49
  553. package/src/pi/tui-session-coordinator.ts +0 -351
  554. package/src/prompts/context-builder.ts +0 -326
  555. package/src/prompts/disclaimer.ts +0 -9
  556. package/src/prompts/policy-cards.ts +0 -228
  557. package/src/prompts/sections.ts +0 -46
  558. package/src/prompts/symbol-preflight.ts +0 -80
  559. package/src/prompts/workflow-prompts.ts +0 -504
  560. package/src/providers/alpha-vantage.ts +0 -340
  561. package/src/providers/coingecko.ts +0 -95
  562. package/src/providers/errors.ts +0 -9
  563. package/src/providers/exa-search.ts +0 -375
  564. package/src/providers/external-tool-command.ts +0 -164
  565. package/src/providers/external-tool-error.ts +0 -20
  566. package/src/providers/fear-greed.ts +0 -45
  567. package/src/providers/finnhub.ts +0 -125
  568. package/src/providers/fred.ts +0 -83
  569. package/src/providers/index.ts +0 -17
  570. package/src/providers/polymarket.ts +0 -214
  571. package/src/providers/provider-credential-error.ts +0 -23
  572. package/src/providers/reddit-cli.ts +0 -286
  573. package/src/providers/reddit.ts +0 -106
  574. package/src/providers/sec-edgar.ts +0 -326
  575. package/src/providers/tradingview.ts +0 -399
  576. package/src/providers/twitter-cli.ts +0 -202
  577. package/src/providers/twitter.ts +0 -102
  578. package/src/providers/web-search.ts +0 -303
  579. package/src/providers/with-fallback.ts +0 -42
  580. package/src/providers/wrap-provider.ts +0 -105
  581. package/src/providers/yahoo-finance.ts +0 -984
  582. package/src/routing/classify-intent.ts +0 -380
  583. package/src/routing/defaults.ts +0 -29
  584. package/src/routing/entity-extractor.ts +0 -557
  585. package/src/routing/fund-symbols.ts +0 -58
  586. package/src/routing/horizon.ts +0 -7
  587. package/src/routing/index.ts +0 -70
  588. package/src/routing/legacy-rule-router.ts +0 -13
  589. package/src/routing/planning.ts +0 -829
  590. package/src/routing/route-manifest.ts +0 -308
  591. package/src/routing/router-llm-client.ts +0 -64
  592. package/src/routing/router-prompt.ts +0 -159
  593. package/src/routing/router-types.ts +0 -84
  594. package/src/routing/router.ts +0 -1332
  595. package/src/routing/slot-resolver.ts +0 -213
  596. package/src/routing/symbol-disambiguator.ts +0 -72
  597. package/src/routing/turn-context.ts +0 -108
  598. package/src/routing/types.ts +0 -77
  599. package/src/runtime/answer-contracts.ts +0 -693
  600. package/src/runtime/artifact-contracts.ts +0 -77
  601. package/src/runtime/evidence.ts +0 -78
  602. package/src/runtime/numeric-claims.ts +0 -108
  603. package/src/runtime/planning-evidence.ts +0 -597
  604. package/src/runtime/prompt-step.ts +0 -185
  605. package/src/runtime/provider-tracker.ts +0 -40
  606. package/src/runtime/run-context.ts +0 -32
  607. package/src/runtime/session-coordinator.ts +0 -1037
  608. package/src/runtime/session-title.ts +0 -60
  609. package/src/runtime/tool-defaults-wrapper.ts +0 -43
  610. package/src/runtime/validation.ts +0 -211
  611. package/src/runtime/workflow-events.ts +0 -77
  612. package/src/runtime/workflow-runner.ts +0 -182
  613. package/src/runtime/workflow-types.ts +0 -105
  614. package/src/sentiment/adapters/finnhub.ts +0 -49
  615. package/src/sentiment/adapters/reddit.ts +0 -65
  616. package/src/sentiment/adapters/twitter.ts +0 -36
  617. package/src/sentiment/adapters/web.ts +0 -44
  618. package/src/sentiment/index.ts +0 -49
  619. package/src/sentiment/insights.ts +0 -269
  620. package/src/sentiment/keywords.ts +0 -31
  621. package/src/sentiment/pipeline.ts +0 -91
  622. package/src/sentiment/scorer.ts +0 -89
  623. package/src/sentiment/store.ts +0 -260
  624. package/src/sentiment/trends.ts +0 -96
  625. package/src/sentiment/types.ts +0 -112
  626. package/src/system-prompt.ts +0 -115
  627. package/src/tool-kit.ts +0 -69
  628. package/src/tools/AGENTS.md +0 -36
  629. package/src/tools/fundamentals/company-overview.ts +0 -64
  630. package/src/tools/fundamentals/comps.ts +0 -180
  631. package/src/tools/fundamentals/dcf.ts +0 -447
  632. package/src/tools/fundamentals/earnings.ts +0 -57
  633. package/src/tools/fundamentals/financials.ts +0 -63
  634. package/src/tools/fundamentals/sec-filings.ts +0 -105
  635. package/src/tools/index.ts +0 -104
  636. package/src/tools/interaction/ask-user.ts +0 -93
  637. package/src/tools/macro/event-probabilities.ts +0 -141
  638. package/src/tools/macro/fear-greed.ts +0 -41
  639. package/src/tools/macro/fred-data.ts +0 -92
  640. package/src/tools/market/crypto-history.ts +0 -72
  641. package/src/tools/market/crypto-price.ts +0 -65
  642. package/src/tools/market/screen-stocks.ts +0 -290
  643. package/src/tools/market/search-ticker.ts +0 -254
  644. package/src/tools/market/stock-history.ts +0 -104
  645. package/src/tools/market/stock-quote.ts +0 -73
  646. package/src/tools/options/greeks.ts +0 -81
  647. package/src/tools/options/option-chain.ts +0 -134
  648. package/src/tools/portfolio/alerts.ts +0 -457
  649. package/src/tools/portfolio/correlation.ts +0 -189
  650. package/src/tools/portfolio/daily-report.ts +0 -107
  651. package/src/tools/portfolio/holdings-overlap.ts +0 -139
  652. package/src/tools/portfolio/notifications.ts +0 -45
  653. package/src/tools/portfolio/risk-analysis.ts +0 -173
  654. package/src/tools/portfolio/tracker.ts +0 -308
  655. package/src/tools/portfolio/watchlist.ts +0 -288
  656. package/src/tools/sentiment/insight-format.ts +0 -50
  657. package/src/tools/sentiment/query-match.ts +0 -117
  658. package/src/tools/sentiment/reddit-sentiment.ts +0 -403
  659. package/src/tools/sentiment/sentiment-summary.ts +0 -383
  660. package/src/tools/sentiment/sentiment-trend.ts +0 -75
  661. package/src/tools/sentiment/twitter-sentiment.ts +0 -287
  662. package/src/tools/sentiment/untrusted-text.ts +0 -21
  663. package/src/tools/sentiment/web-search.ts +0 -186
  664. package/src/tools/sentiment/web-sentiment.ts +0 -96
  665. package/src/tools/technical/backtest.ts +0 -336
  666. package/src/tools/technical/indicators.ts +0 -281
  667. package/src/types/fundamentals.ts +0 -47
  668. package/src/types/index.ts +0 -26
  669. package/src/types/macro.ts +0 -27
  670. package/src/types/market.ts +0 -46
  671. package/src/types/options.ts +0 -53
  672. package/src/types/portfolio.ts +0 -83
  673. package/src/types/prediction-markets.ts +0 -13
  674. package/src/types/sentiment.ts +0 -129
  675. package/src/workflows/compare-assets.ts +0 -89
  676. package/src/workflows/index.ts +0 -3
  677. package/src/workflows/options-screener.ts +0 -125
  678. package/src/workflows/portfolio-builder.ts +0 -63
@@ -1,399 +0,0 @@
1
- import { cache, STALE_LIMIT, TTL } from "../infra/cache.js";
2
- import { httpPost } from "../infra/http-client.js";
3
- import { rateLimiter } from "../infra/rate-limiter.js";
4
-
5
- const BASE_URL = "https://scanner.tradingview.com";
6
- const DATA_CAVEAT =
7
- "TradingView scanner data may be delayed about 15 minutes and comes from an unofficial endpoint.";
8
- const BROWSER_UA =
9
- "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36";
10
-
11
- const QUOTE_COLUMNS = [
12
- "name",
13
- "close",
14
- "change",
15
- "change_abs",
16
- "volume",
17
- "exchange",
18
- "market",
19
- "description",
20
- "type",
21
- "typespecs",
22
- ] as const;
23
-
24
- export const DEFAULT_COLUMNS = [
25
- "name",
26
- "close",
27
- "change",
28
- "volume",
29
- "market_cap_basic",
30
- "price_earnings_ttm",
31
- ] as const;
32
-
33
- export type ScreenFilterOp =
34
- | "greater"
35
- | "egreater"
36
- | "less"
37
- | "eless"
38
- | "equal"
39
- | "nequal"
40
- | "in_range"
41
- | "not_in_range"
42
- | "crosses"
43
- | "crosses_above"
44
- | "crosses_below"
45
- | "above%"
46
- | "below%"
47
- | "match"
48
- | "nmatch"
49
- | "has"
50
- | "has_none_of"
51
- | "empty"
52
- | "nempty";
53
-
54
- export interface ScreenFilterClause {
55
- field: string;
56
- op: ScreenFilterOp;
57
- value?: unknown;
58
- }
59
-
60
- export interface ScreenSort {
61
- field: string;
62
- direction?: "asc" | "desc";
63
- }
64
-
65
- export interface ScreenStocksOpts {
66
- market?: string;
67
- columns?: string[];
68
- filter?: ScreenFilterClause[];
69
- sort?: ScreenSort;
70
- limit?: number;
71
- }
72
-
73
- export interface ScreenerRow {
74
- tvSymbol: string;
75
- symbol: string;
76
- values: Record<string, unknown | null>;
77
- sourceProvider: "tradingview";
78
- dataCaveat: string;
79
- }
80
-
81
- export interface TradingViewQuote {
82
- requestedSymbol: string;
83
- tvSymbol: string;
84
- symbol: string;
85
- price: number;
86
- change: number;
87
- changePercent: number;
88
- volume: number;
89
- exchange?: string;
90
- market?: string;
91
- name?: string;
92
- type?: string;
93
- typespecs?: unknown;
94
- sourceProvider: "tradingview";
95
- dataCaveat: string;
96
- }
97
-
98
- interface TradingViewResponse {
99
- fields?: string[];
100
- symbols?: Array<{
101
- s: string;
102
- f: unknown[];
103
- }>;
104
- }
105
-
106
- interface ScannerBody {
107
- markets?: string[];
108
- symbols?: { tickers?: string[]; query?: { types: string[] } };
109
- columns: readonly string[];
110
- filter?: Array<{ left: string; operation: string; right?: unknown }>;
111
- sort?: { sortBy: string; sortOrder: "asc" | "desc" };
112
- range: [number, number];
113
- options: { lang: "en" };
114
- }
115
-
116
- interface DecodedRow {
117
- tvSymbol: string;
118
- symbol: string;
119
- values: Record<string, unknown | null>;
120
- }
121
-
122
- export function buildTvSymbol(exchange: string, ticker: string): string {
123
- const trimmedTicker = ticker.trim().toUpperCase();
124
- if (trimmedTicker.includes(":")) return trimmedTicker;
125
- const trimmedExchange = exchange.trim().toUpperCase();
126
- return trimmedExchange ? `${trimmedExchange}:${trimmedTicker}` : trimmedTicker;
127
- }
128
-
129
- export async function screenStocks(opts: ScreenStocksOpts = {}): Promise<ScreenerRow[]> {
130
- const market = opts.market?.trim().toLowerCase() || "america";
131
- const columns = opts.columns?.length ? opts.columns : [...DEFAULT_COLUMNS];
132
- const body = buildScannerBody({
133
- market,
134
- columns,
135
- filter: opts.filter,
136
- sort: opts.sort,
137
- limit: opts.limit,
138
- });
139
- const rows = decodeScannerRows(await scannerFetch(market, body), columns);
140
- return rows.map((row) => ({
141
- ...row,
142
- sourceProvider: "tradingview" as const,
143
- dataCaveat: DATA_CAVEAT,
144
- }));
145
- }
146
-
147
- export async function getQuotes(symbols: string[]): Promise<TradingViewQuote[]> {
148
- const requested = symbols.map(normalizeRequestedSymbol).filter(Boolean);
149
- const qualified = requested.filter(isTradingViewQualified);
150
- const bare = requested.filter(
151
- (symbol) => !isTradingViewQualified(symbol) && !shouldSkipTradingView(symbol),
152
- );
153
-
154
- const resolved = new Map<string, TradingViewQuote>();
155
-
156
- if (qualified.length > 0) {
157
- const body = buildQualifiedQuoteBody(qualified);
158
- const rows = decodeScannerRows(await scannerFetch("global", body), [...QUOTE_COLUMNS]);
159
- const byTvSymbol = new Map(rows.map((row) => [row.tvSymbol.toUpperCase(), row]));
160
- for (const symbol of qualified) {
161
- const row = byTvSymbol.get(symbol);
162
- const quote = row ? rowToQuote(symbol, row) : undefined;
163
- if (quote) resolved.set(symbol, quote);
164
- }
165
- }
166
-
167
- if (bare.length > 0) {
168
- const body = buildBareQuoteBody(bare);
169
- const rows = decodeScannerRows(await scannerFetch("america", body), [...QUOTE_COLUMNS]);
170
- const byName = groupRowsByName(rows);
171
- for (const symbol of bare) {
172
- const row = pickPrimaryListing(byName.get(symbol) ?? []);
173
- const quote = row ? rowToQuote(symbol, row) : undefined;
174
- if (quote) resolved.set(symbol, quote);
175
- }
176
- }
177
-
178
- return requested.flatMap((symbol) => {
179
- const quote = resolved.get(symbol);
180
- return quote ? [quote] : [];
181
- });
182
- }
183
-
184
- function buildScannerBody(
185
- opts: Required<Pick<ScreenStocksOpts, "market" | "columns">> &
186
- Pick<ScreenStocksOpts, "filter" | "sort" | "limit">,
187
- ): ScannerBody {
188
- const limit = clampLimit(opts.limit);
189
- return {
190
- markets: [opts.market],
191
- columns: opts.columns,
192
- ...(opts.filter?.length && { filter: opts.filter.map(mapFilterClause) }),
193
- ...(opts.sort && {
194
- sort: {
195
- sortBy: opts.sort.field,
196
- sortOrder: opts.sort.direction ?? "desc",
197
- },
198
- }),
199
- range: [0, limit],
200
- options: { lang: "en" },
201
- };
202
- }
203
-
204
- function buildQualifiedQuoteBody(tickers: string[]): ScannerBody {
205
- return {
206
- symbols: { tickers },
207
- columns: QUOTE_COLUMNS,
208
- range: [0, clampLimit(tickers.length)],
209
- options: { lang: "en" },
210
- };
211
- }
212
-
213
- function buildBareQuoteBody(symbols: string[]): ScannerBody {
214
- return {
215
- markets: ["america"],
216
- symbols: { query: { types: [] } },
217
- columns: QUOTE_COLUMNS,
218
- filter: [
219
- { left: "name", operation: "in_range", right: symbols },
220
- { left: "is_primary", operation: "equal", right: true },
221
- { left: "type", operation: "in_range", right: ["stock", "fund", "dr"] },
222
- ],
223
- range: [0, 500],
224
- options: { lang: "en" },
225
- };
226
- }
227
-
228
- function mapFilterClause(clause: ScreenFilterClause): {
229
- left: string;
230
- operation: string;
231
- right?: unknown;
232
- } {
233
- return {
234
- left: clause.field,
235
- operation: clause.op,
236
- ...(clause.value !== undefined && { right: clause.value }),
237
- };
238
- }
239
-
240
- async function scannerFetch(market: string, body: ScannerBody): Promise<TradingViewResponse> {
241
- const endpoint = `${BASE_URL}/${market}/scan2?label-product=screener-stock`;
242
- const cacheKey = `tradingview:scan2:${market}:${stableStringify(body)}`;
243
- const cached = cache.get<TradingViewResponse>(cacheKey);
244
- if (cached) return cached;
245
-
246
- try {
247
- await rateLimiter.acquire("tradingview");
248
- const response = await httpPost<TradingViewResponse>(endpoint, body, {
249
- headers: {
250
- Origin: "https://www.tradingview.com",
251
- Referer: "https://www.tradingview.com/",
252
- "User-Agent": BROWSER_UA,
253
- },
254
- });
255
- cache.set(cacheKey, response, TTL.SCREENER);
256
- return response;
257
- } catch (error) {
258
- const stale = cache.getStale<TradingViewResponse>(cacheKey, STALE_LIMIT.SCREENER);
259
- if (stale) return stale.value;
260
- throw error;
261
- }
262
- }
263
-
264
- function decodeScannerRows(
265
- response: TradingViewResponse,
266
- requestedColumns: readonly string[],
267
- ): DecodedRow[] {
268
- const fields = response.fields ?? [];
269
- return (response.symbols ?? []).map((row) => {
270
- const values: Record<string, unknown | null> = {};
271
- for (const column of requestedColumns) {
272
- const index = fields.indexOf(column);
273
- values[column] = index >= 0 ? (row.f[index] ?? null) : null;
274
- }
275
- return {
276
- tvSymbol: row.s,
277
- symbol: stringValue(values.name) ?? symbolFromTvSymbol(row.s),
278
- values,
279
- };
280
- });
281
- }
282
-
283
- function rowToQuote(requestedSymbol: string, row: DecodedRow): TradingViewQuote | undefined {
284
- const price = numberValue(row.values.close);
285
- if (price === undefined) return undefined;
286
- const changePercent = numberValue(row.values.change) ?? 0;
287
- const changeAbs = numberValue(row.values.change_abs) ?? 0;
288
- return {
289
- requestedSymbol,
290
- tvSymbol: row.tvSymbol,
291
- symbol: row.symbol,
292
- price,
293
- change: changeAbs,
294
- changePercent,
295
- volume: numberValue(row.values.volume) ?? 0,
296
- exchange: stringValue(row.values.exchange),
297
- market: stringValue(row.values.market),
298
- name: stringValue(row.values.description),
299
- type: stringValue(row.values.type),
300
- typespecs: row.values.typespecs ?? undefined,
301
- sourceProvider: "tradingview",
302
- dataCaveat: DATA_CAVEAT,
303
- };
304
- }
305
-
306
- function groupRowsByName(rows: DecodedRow[]): Map<string, DecodedRow[]> {
307
- const grouped = new Map<string, DecodedRow[]>();
308
- for (const row of rows) {
309
- const name = row.symbol.toUpperCase();
310
- grouped.set(name, [...(grouped.get(name) ?? []), row]);
311
- }
312
- return grouped;
313
- }
314
-
315
- function pickPrimaryListing(rows: DecodedRow[]): DecodedRow | undefined {
316
- if (rows.length === 0) return undefined;
317
- return [...rows].sort(compareListings)[0];
318
- }
319
-
320
- function compareListings(a: DecodedRow, b: DecodedRow): number {
321
- return (
322
- scoreMarket(a) - scoreMarket(b) ||
323
- scoreType(a) - scoreType(b) ||
324
- scoreExchange(a) - scoreExchange(b) ||
325
- a.tvSymbol.localeCompare(b.tvSymbol)
326
- );
327
- }
328
-
329
- function scoreMarket(row: DecodedRow): number {
330
- return stringValue(row.values.market)?.toLowerCase() === "america" ? 0 : 1;
331
- }
332
-
333
- function scoreType(row: DecodedRow): number {
334
- const type = stringValue(row.values.type)?.toLowerCase();
335
- if (type === "stock") return 0;
336
- if (type === "fund") return 1;
337
- if (type === "dr") return 2;
338
- return 3;
339
- }
340
-
341
- function scoreExchange(row: DecodedRow): number {
342
- const exchange = stringValue(row.values.exchange)?.toUpperCase();
343
- if (exchange === "NASDAQ") return 0;
344
- if (exchange === "NYSE") return 1;
345
- if (exchange === "AMEX") return 2;
346
- return 3;
347
- }
348
-
349
- function clampLimit(limit: number | undefined): number {
350
- if (limit == null) return 50;
351
- if (limit < 1) return 50;
352
- return Math.min(Math.floor(limit), 500);
353
- }
354
-
355
- function normalizeRequestedSymbol(symbol: string): string {
356
- return symbol.trim().toUpperCase();
357
- }
358
-
359
- export function isTradingViewQualified(symbol: string): boolean {
360
- return /^[A-Z0-9_]+:[A-Z0-9._-]+$/.test(symbol);
361
- }
362
-
363
- export function shouldSkipTradingView(symbol: string): boolean {
364
- return /(?:-USD|\.(?:TO|DE|T|L|HK))$/i.test(symbol);
365
- }
366
-
367
- export function canUseTradingViewQuote(symbol: string): boolean {
368
- const normalized = normalizeRequestedSymbol(symbol);
369
- return (
370
- normalized.length > 0 &&
371
- (isTradingViewQualified(normalized) || !shouldSkipTradingView(normalized))
372
- );
373
- }
374
-
375
- function symbolFromTvSymbol(tvSymbol: string): string {
376
- return tvSymbol.includes(":") ? tvSymbol.split(":").at(-1)! : tvSymbol;
377
- }
378
-
379
- function stringValue(value: unknown): string | undefined {
380
- return typeof value === "string" ? value : undefined;
381
- }
382
-
383
- function numberValue(value: unknown): number | undefined {
384
- return typeof value === "number" && Number.isFinite(value) ? value : undefined;
385
- }
386
-
387
- function stableStringify(value: unknown): string {
388
- return JSON.stringify(sortObjectKeys(value));
389
- }
390
-
391
- function sortObjectKeys(value: unknown): unknown {
392
- if (Array.isArray(value)) return value.map(sortObjectKeys);
393
- if (!value || typeof value !== "object") return value;
394
- return Object.fromEntries(
395
- Object.entries(value)
396
- .sort(([a], [b]) => a.localeCompare(b))
397
- .map(([key, nested]) => [key, sortObjectKeys(nested)]),
398
- );
399
- }
@@ -1,202 +0,0 @@
1
- import type { TwitterTweet } from "../types/sentiment.js";
2
- import { type ExternalToolCommandResult, runExternalToolCommand } from "./external-tool-command.js";
3
- import { ExternalToolError, ExternalToolNotInstalled } from "./external-tool-error.js";
4
-
5
- const TWITTER_CLI_BINARY = "twitter";
6
- const TWITTER_CLI_TOOL_NAME = "twitter-cli";
7
- const TWITTER_CLI_INSTALL_CMD = "uv tool install twitter-cli";
8
- const COMMAND_TIMEOUT_MS = 20_000;
9
- const MAX_OUTPUT_CHARS = 2_000_000;
10
-
11
- export interface RawTweet {
12
- readonly id?: string;
13
- readonly text?: string;
14
- readonly author?: {
15
- readonly username?: string;
16
- readonly screenName?: string;
17
- readonly name?: string;
18
- };
19
- readonly username?: string;
20
- readonly url?: string;
21
- readonly permanentUrl?: string;
22
- readonly createdAt?: string | number;
23
- readonly created_at?: string | number;
24
- readonly likeCount?: number;
25
- readonly likes?: number;
26
- readonly retweetCount?: number;
27
- readonly retweets?: number;
28
- readonly replyCount?: number;
29
- readonly replies?: number;
30
- readonly viewCount?: number | null;
31
- readonly views?: number | null;
32
- readonly metrics?: {
33
- readonly likes?: number;
34
- readonly retweets?: number;
35
- readonly replies?: number;
36
- readonly views?: number | null;
37
- };
38
- }
39
-
40
- interface TwitterCliEnvelope<T> {
41
- readonly ok: boolean;
42
- readonly schema_version: string;
43
- readonly data: T;
44
- readonly error?: {
45
- readonly code?: string;
46
- readonly message?: string;
47
- };
48
- }
49
-
50
- type TwitterCliCommandRunner = (
51
- command: string,
52
- args: readonly string[],
53
- ) => Promise<ExternalToolCommandResult>;
54
-
55
- let commandRunner: TwitterCliCommandRunner = runCommand;
56
-
57
- export function setTwitterCliCommandRunnerForTests(runner: TwitterCliCommandRunner): void {
58
- commandRunner = runner;
59
- }
60
-
61
- export function resetTwitterCliCommandRunnerForTests(): void {
62
- commandRunner = runCommand;
63
- }
64
-
65
- export async function searchTweets(query: string, max = 20): Promise<TwitterTweet[]> {
66
- const envelope = await runTwitterCli<TwitterCliEnvelope<RawTweet[]>>([
67
- "search",
68
- query,
69
- "--max",
70
- String(max),
71
- "-t",
72
- "Latest",
73
- "--json",
74
- ]);
75
-
76
- if (!envelope.ok) {
77
- throw new ExternalToolError(
78
- TWITTER_CLI_TOOL_NAME,
79
- redactSensitiveOutput(envelope.error?.message ?? "twitter-cli returned an error"),
80
- envelope.error?.code,
81
- );
82
- }
83
- if (!Array.isArray(envelope.data)) {
84
- throw new ExternalToolError(TWITTER_CLI_TOOL_NAME, "twitter-cli returned invalid tweet data");
85
- }
86
- return envelope.data.map(adaptRawTweet);
87
- }
88
-
89
- async function runTwitterCli<T>(args: readonly string[]): Promise<T> {
90
- let result: ExternalToolCommandResult;
91
- try {
92
- result = await commandRunner(TWITTER_CLI_BINARY, args);
93
- } catch (err) {
94
- const nodeError = err as NodeJS.ErrnoException;
95
- if (nodeError.code === "ENOENT") {
96
- throw new ExternalToolNotInstalled(TWITTER_CLI_TOOL_NAME, TWITTER_CLI_INSTALL_CMD);
97
- }
98
- throw new ExternalToolError(
99
- TWITTER_CLI_TOOL_NAME,
100
- redactSensitiveOutput(err instanceof Error ? err.message : String(err)),
101
- );
102
- }
103
-
104
- if (result.code !== 0) {
105
- const envelopeError = parseCliErrorEnvelope(result.stdout);
106
- if (envelopeError) {
107
- throw new ExternalToolError(
108
- TWITTER_CLI_TOOL_NAME,
109
- redactSensitiveOutput(envelopeError.message),
110
- envelopeError.code,
111
- );
112
- }
113
- throw new ExternalToolError(
114
- TWITTER_CLI_TOOL_NAME,
115
- redactSensitiveOutput(result.stderr.trim() || `twitter-cli exited with code ${result.code}`),
116
- );
117
- }
118
-
119
- try {
120
- return JSON.parse(result.stdout) as T;
121
- } catch {
122
- throw new ExternalToolError(
123
- TWITTER_CLI_TOOL_NAME,
124
- `twitter-cli returned non-JSON output: ${redactSensitiveOutput(result.stdout.slice(0, 200))}`,
125
- );
126
- }
127
- }
128
-
129
- function parseCliErrorEnvelope(stdout: string): { code?: string; message: string } | null {
130
- try {
131
- const parsed = JSON.parse(stdout) as {
132
- ok?: unknown;
133
- error?: { code?: unknown; message?: unknown };
134
- };
135
- if (parsed.ok !== false || typeof parsed.error?.message !== "string") return null;
136
- return {
137
- code: typeof parsed.error.code === "string" ? parsed.error.code : undefined,
138
- message: parsed.error.message,
139
- };
140
- } catch {
141
- return null;
142
- }
143
- }
144
-
145
- function adaptRawTweet(raw: RawTweet): TwitterTweet {
146
- return {
147
- id: stringValue(raw.id),
148
- text: stringValue(raw.text).slice(0, 280),
149
- author:
150
- stringValue(raw.author?.username) ||
151
- stringValue(raw.author?.screenName) ||
152
- stringValue(raw.username) ||
153
- "unknown",
154
- likes: numberValue(raw.metrics?.likes ?? raw.likeCount ?? raw.likes),
155
- retweets: numberValue(raw.metrics?.retweets ?? raw.retweetCount ?? raw.retweets),
156
- replies: numberValue(raw.metrics?.replies ?? raw.replyCount ?? raw.replies),
157
- views: nullableNumberValue(raw.metrics?.views ?? raw.viewCount ?? raw.views),
158
- url: stringValue(raw.url ?? raw.permanentUrl),
159
- created: normalizeCreatedAt(raw.createdAt ?? raw.created_at),
160
- };
161
- }
162
-
163
- function normalizeCreatedAt(value: string | number | undefined): string {
164
- if (typeof value === "number") {
165
- const millis = value > 1_000_000_000_000 ? value : value * 1000;
166
- return new Date(millis).toISOString();
167
- }
168
- if (typeof value === "string" && value.length > 0) {
169
- const millis = Date.parse(value);
170
- if (!Number.isNaN(millis)) return new Date(millis).toISOString();
171
- }
172
- return new Date(0).toISOString();
173
- }
174
-
175
- function stringValue(value: unknown): string {
176
- return typeof value === "string" ? value : "";
177
- }
178
-
179
- function numberValue(value: unknown): number {
180
- return typeof value === "number" && Number.isFinite(value) ? value : 0;
181
- }
182
-
183
- function nullableNumberValue(value: unknown): number | null {
184
- return typeof value === "number" && Number.isFinite(value) ? value : null;
185
- }
186
-
187
- export function redactSensitiveOutput(input: string): string {
188
- const xCookieNames =
189
- "auth_token|ct0|twid|kdt|guest_id|guest_id_ads|guest_id_marketing|personalization_id";
190
- return input
191
- .slice(0, MAX_OUTPUT_CHARS)
192
- .replace(/\b(cookie|set-cookie)\s*:\s*[^\r\n]+/gi, "$1: [redacted]")
193
- .replace(new RegExp(`\\b(${xCookieNames})\\b\\s*[:=]\\s*[^;\\s,)]+`, "gi"), "$1=[redacted]")
194
- .replace(new RegExp(`\\b(${xCookieNames})=([^;\\s,)]+)`, "gi"), "$1=[redacted]");
195
- }
196
-
197
- function runCommand(command: string, args: readonly string[]): Promise<ExternalToolCommandResult> {
198
- return runExternalToolCommand(command, args, {
199
- timeoutMs: COMMAND_TIMEOUT_MS,
200
- maxOutputChars: MAX_OUTPUT_CHARS,
201
- });
202
- }
@@ -1,102 +0,0 @@
1
- import { cache, STALE_LIMIT, TTL } from "../infra/cache.js";
2
- import { rateLimiter } from "../infra/rate-limiter.js";
3
- import type { TwitterSentimentResult, TwitterTweet } from "../types/sentiment.js";
4
- import { searchTweets } from "./twitter-cli.js";
5
-
6
- // ── Sentiment scoring ────────────────────────────────────
7
-
8
- import { BEARISH_TERMS, BULLISH_TERMS } from "../sentiment/keywords.js";
9
-
10
- export function scoreTwitterSentiment(
11
- tweets: Array<{ text: string; likes: number; retweets: number }>,
12
- ): { score: number; bullish: number; bearish: number } {
13
- let bullishWeight = 0;
14
- let bearishWeight = 0;
15
- let bullishCount = 0;
16
- let bearishCount = 0;
17
-
18
- for (const tweet of tweets) {
19
- const lower = tweet.text.toLowerCase();
20
- const engagement = 1 + (tweet.likes ?? 0) + (tweet.retweets ?? 0);
21
- const tweetBullish = BULLISH_TERMS.filter((t) => lower.includes(t)).length;
22
- const tweetBearish = BEARISH_TERMS.filter((t) => lower.includes(t)).length;
23
-
24
- bullishCount += tweetBullish;
25
- bearishCount += tweetBearish;
26
- bullishWeight += tweetBullish * engagement;
27
- bearishWeight += tweetBearish * engagement;
28
- }
29
-
30
- const totalWeight = bullishWeight + bearishWeight;
31
- return {
32
- score: totalWeight === 0 ? 0 : (bullishWeight - bearishWeight) / totalWeight,
33
- bullish: bullishCount,
34
- bearish: bearishCount,
35
- };
36
- }
37
-
38
- // ── Query normalization ──────────────────────────────────
39
-
40
- export function normalizeQuery(query: string): string {
41
- if (/^[A-Z]{1,5}$/.test(query)) return `$${query}`;
42
- return query;
43
- }
44
-
45
- // ── Main provider function ───────────────────────────────
46
-
47
- export async function getTwitterSentiment(
48
- query: string,
49
- limit: number = 50,
50
- hours: number = 24,
51
- ): Promise<TwitterSentimentResult> {
52
- const normalizedQuery = normalizeQuery(query);
53
- const cacheKey = `twitter:${normalizedQuery}:${limit}:${hours}`;
54
- const cached = cache.get<TwitterSentimentResult>(cacheKey);
55
- if (cached) return cached;
56
-
57
- await rateLimiter.acquire("twitter");
58
-
59
- try {
60
- const cutoff = new Date(Date.now() - hours * 3_600_000);
61
- const tweets: TwitterTweet[] = (await searchTweets(normalizedQuery, limit))
62
- .filter((tweet) => new Date(tweet.created) >= cutoff)
63
- .slice(0, limit);
64
-
65
- // Extract co-mentioned cashtags
66
- const tickerRegex = /\$([A-Z]{1,5})\b/g;
67
- const mentionCounts = new Map<string, number>();
68
- // Exclude the searched ticker itself from co-mentions
69
- const searchedTicker = normalizedQuery.startsWith("$") ? normalizedQuery.slice(1) : null;
70
- for (const t of tweets) {
71
- for (const match of t.text.matchAll(tickerRegex)) {
72
- const ticker = match[1];
73
- if (ticker === searchedTicker) continue;
74
- mentionCounts.set(ticker, (mentionCounts.get(ticker) ?? 0) + 1);
75
- }
76
- }
77
- const topMentions = [...mentionCounts.entries()]
78
- .sort((a, b) => b[1] - a[1])
79
- .slice(0, 10)
80
- .map(([ticker]) => ticker);
81
-
82
- const sentiment = scoreTwitterSentiment(tweets);
83
-
84
- const result: TwitterSentimentResult = {
85
- query: normalizedQuery,
86
- tweetCount: tweets.length,
87
- tweets,
88
- sentimentScore: sentiment.score,
89
- bullishCount: sentiment.bullish,
90
- bearishCount: sentiment.bearish,
91
- topMentions,
92
- fetchedAt: new Date().toISOString(),
93
- };
94
-
95
- cache.set(cacheKey, result, TTL.SENTIMENT);
96
- return result;
97
- } catch (error) {
98
- const stale = cache.getStale<TwitterSentimentResult>(cacheKey, STALE_LIMIT.SENTIMENT);
99
- if (stale) return stale.value;
100
- throw error;
101
- }
102
- }