opencandle 0.11.1 → 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.
Files changed (653) hide show
  1. package/README.md +20 -24
  2. package/dist/analysts/contracts.js +0 -1
  3. package/dist/analysts/orchestrator.js +0 -1
  4. package/dist/cli-main.js +13 -7
  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.js +0 -1
  9. package/dist/doctor/cli-command.js +2 -1
  10. package/dist/doctor/render.js +0 -1
  11. package/dist/doctor/report.js +40 -11
  12. package/dist/gui/server/ask-user-bridge.d.ts +19 -0
  13. package/dist/gui/server/ask-user-bridge.js +55 -0
  14. package/dist/gui/server/automation-heartbeat.d.ts +25 -0
  15. package/dist/gui/server/automation-heartbeat.js +61 -0
  16. package/dist/gui/server/background-quotes.d.ts +39 -0
  17. package/dist/gui/server/background-quotes.js +71 -0
  18. package/dist/gui/server/chat-event-adapter.d.ts +16 -0
  19. package/dist/gui/server/chat-event-adapter.js +263 -0
  20. package/dist/gui/server/gui-session-manager.d.ts +2 -0
  21. package/dist/gui/server/gui-session-manager.js +4 -0
  22. package/dist/gui/server/http-routes.d.ts +69 -0
  23. package/dist/gui/server/http-routes.js +1008 -0
  24. package/dist/gui/server/invoke-tool.d.ts +47 -0
  25. package/dist/gui/server/invoke-tool.js +373 -0
  26. package/dist/gui/server/live-chat-event-adapter.d.ts +19 -0
  27. package/dist/gui/server/live-chat-event-adapter.js +206 -0
  28. package/dist/gui/server/local-session-coordinator.d.ts +26 -0
  29. package/dist/gui/server/local-session-coordinator.js +53 -0
  30. package/dist/gui/server/market-state-api.d.ts +138 -0
  31. package/dist/gui/server/market-state-api.js +355 -0
  32. package/dist/gui/server/model-setup.d.ts +64 -0
  33. package/dist/gui/server/model-setup.js +150 -0
  34. package/dist/gui/server/private-api-access.d.ts +6 -0
  35. package/dist/gui/server/private-api-access.js +53 -0
  36. package/dist/gui/server/projector.d.ts +49 -0
  37. package/dist/gui/server/projector.js +296 -0
  38. package/dist/gui/server/prompt-observation.d.ts +8 -0
  39. package/dist/gui/server/prompt-observation.js +43 -0
  40. package/dist/gui/server/quote-snapshot-store.d.ts +14 -0
  41. package/dist/gui/server/quote-snapshot-store.js +49 -0
  42. package/dist/gui/server/server.d.ts +1 -0
  43. package/dist/gui/server/server.js +259 -0
  44. package/dist/gui/server/session-actions.d.ts +60 -0
  45. package/dist/gui/server/session-actions.js +218 -0
  46. package/dist/gui/server/session-entry-wait.d.ts +27 -0
  47. package/dist/gui/server/session-entry-wait.js +129 -0
  48. package/dist/gui/server/session-list.d.ts +2 -0
  49. package/dist/gui/server/session-list.js +11 -0
  50. package/dist/gui/server/shutdown.d.ts +10 -0
  51. package/dist/gui/server/shutdown.js +29 -0
  52. package/dist/gui/server/tool-invoke-ack.d.ts +17 -0
  53. package/dist/gui/server/tool-invoke-ack.js +26 -0
  54. package/dist/gui/server/tool-metadata.d.ts +93 -0
  55. package/dist/gui/server/tool-metadata.js +148 -0
  56. package/dist/gui/server/websocket.d.ts +9 -0
  57. package/dist/gui/server/websocket.js +124 -0
  58. package/dist/gui/server/writer-lock.d.ts +1 -0
  59. package/dist/gui/server/writer-lock.js +1 -0
  60. package/dist/gui/server/ws-hub.d.ts +50 -0
  61. package/dist/gui/server/ws-hub.js +284 -0
  62. package/dist/gui/shared/chat-events.d.ts +174 -0
  63. package/dist/gui/shared/chat-events.js +13 -0
  64. package/dist/gui/shared/event-reducer.d.ts +3 -0
  65. package/dist/gui/shared/event-reducer.js +187 -0
  66. package/dist/index.js +0 -1
  67. package/dist/infra/cache.js +0 -1
  68. package/dist/infra/freshness.js +0 -1
  69. package/dist/infra/http-client.js +1 -2
  70. package/dist/infra/index.js +0 -1
  71. package/dist/infra/market-calendar.js +0 -1
  72. package/dist/infra/native-dependencies.js +0 -1
  73. package/dist/infra/node-version.js +0 -1
  74. package/dist/infra/open-url.js +0 -1
  75. package/dist/infra/opencandle-paths.js +0 -1
  76. package/dist/infra/rate-limiter.js +0 -1
  77. package/dist/market-state/alert-conditions.js +0 -1
  78. package/dist/market-state/alert-runner.d.ts +1 -0
  79. package/dist/market-state/alert-runner.js +5 -4
  80. package/dist/market-state/daily-report.js +0 -1
  81. package/dist/market-state/local-automation-service.js +0 -1
  82. package/dist/market-state/notification-delivery.js +0 -1
  83. package/dist/market-state/resolve-for-mutation.js +0 -1
  84. package/dist/market-state/resolve.js +0 -1
  85. package/dist/market-state/service.d.ts +26 -21
  86. package/dist/market-state/service.js +175 -36
  87. package/dist/market-state/summaries.js +1 -13
  88. package/dist/memory/index.js +0 -1
  89. package/dist/memory/manager.js +0 -1
  90. package/dist/memory/preference-extractor.js +0 -1
  91. package/dist/memory/retrieval.js +0 -1
  92. package/dist/memory/sqlite.js +60 -11
  93. package/dist/memory/storage.js +0 -1
  94. package/dist/memory/tool-defaults.js +0 -1
  95. package/dist/memory/types.js +0 -1
  96. package/dist/monitor.js +0 -1
  97. package/dist/onboarding/connect.js +0 -1
  98. package/dist/onboarding/credential-interceptor.js +0 -1
  99. package/dist/onboarding/degradation-accumulator.js +0 -1
  100. package/dist/onboarding/prompt-user.d.ts +1 -1
  101. package/dist/onboarding/prompt-user.js +0 -1
  102. package/dist/onboarding/provider-status.js +0 -1
  103. package/dist/onboarding/providers.js +0 -1
  104. package/dist/onboarding/state.js +0 -1
  105. package/dist/onboarding/tool-helpers.js +0 -1
  106. package/dist/onboarding/tool-tags.js +0 -1
  107. package/dist/onboarding/validate-model-key.d.ts +17 -0
  108. package/dist/onboarding/validate-model-key.js +54 -0
  109. package/dist/onboarding/validation.js +0 -1
  110. package/dist/pi/opencandle-extension.js +2 -2
  111. package/dist/pi/session-action-dedupe.js +0 -1
  112. package/dist/pi/session-storage.js +0 -1
  113. package/dist/pi/session-writer-lock.js +0 -1
  114. package/dist/pi/session.js +0 -1
  115. package/dist/pi/setup.d.ts +2 -0
  116. package/dist/pi/setup.js +10 -3
  117. package/dist/pi/tool-adapter.js +0 -1
  118. package/dist/pi/tui-session-coordinator.js +0 -1
  119. package/dist/prompts/context-builder.js +1 -2
  120. package/dist/prompts/disclaimer.js +0 -1
  121. package/dist/prompts/policy-cards.js +0 -1
  122. package/dist/prompts/sections.js +0 -1
  123. package/dist/prompts/symbol-preflight.js +0 -1
  124. package/dist/prompts/workflow-prompts.js +0 -1
  125. package/dist/providers/alpha-vantage.js +2 -3
  126. package/dist/providers/coingecko.js +0 -1
  127. package/dist/providers/errors.js +0 -1
  128. package/dist/providers/exa-search.js +11 -10
  129. package/dist/providers/external-tool-command.js +0 -1
  130. package/dist/providers/external-tool-error.js +0 -1
  131. package/dist/providers/fear-greed.js +0 -1
  132. package/dist/providers/finnhub.js +0 -1
  133. package/dist/providers/fred.js +0 -1
  134. package/dist/providers/index.js +0 -1
  135. package/dist/providers/polymarket.js +0 -1
  136. package/dist/providers/provider-credential-error.js +0 -1
  137. package/dist/providers/reddit-cli.js +0 -1
  138. package/dist/providers/reddit.js +0 -1
  139. package/dist/providers/sec-edgar.js +0 -1
  140. package/dist/providers/tradingview.js +1 -2
  141. package/dist/providers/twitter-cli.js +0 -1
  142. package/dist/providers/twitter.js +0 -1
  143. package/dist/providers/web-search.js +15 -12
  144. package/dist/providers/with-fallback.js +0 -1
  145. package/dist/providers/wrap-provider.js +0 -1
  146. package/dist/providers/yahoo-finance.js +67 -4
  147. package/dist/routing/classify-intent.js +0 -1
  148. package/dist/routing/defaults.js +0 -1
  149. package/dist/routing/entity-extractor.js +2 -3
  150. package/dist/routing/fund-symbols.js +0 -1
  151. package/dist/routing/horizon.js +0 -1
  152. package/dist/routing/index.js +0 -1
  153. package/dist/routing/legacy-rule-router.js +0 -1
  154. package/dist/routing/planning.js +0 -1
  155. package/dist/routing/route-manifest.js +0 -1
  156. package/dist/routing/router-llm-client.d.ts +2 -2
  157. package/dist/routing/router-llm-client.js +0 -1
  158. package/dist/routing/router-prompt.js +0 -1
  159. package/dist/routing/router-types.js +0 -1
  160. package/dist/routing/router.js +1 -2
  161. package/dist/routing/slot-resolver.js +0 -1
  162. package/dist/routing/symbol-disambiguator.js +0 -1
  163. package/dist/routing/turn-context.js +0 -1
  164. package/dist/routing/types.js +0 -1
  165. package/dist/runtime/answer-contracts.js +0 -1
  166. package/dist/runtime/artifact-contracts.js +0 -1
  167. package/dist/runtime/evidence.js +0 -1
  168. package/dist/runtime/numeric-claims.js +0 -1
  169. package/dist/runtime/planning-evidence.js +0 -1
  170. package/dist/runtime/prompt-step.js +0 -1
  171. package/dist/runtime/provider-tracker.js +0 -1
  172. package/dist/runtime/run-context.js +0 -1
  173. package/dist/runtime/session-coordinator.js +0 -1
  174. package/dist/runtime/session-title.js +0 -1
  175. package/dist/runtime/tool-defaults-wrapper.js +0 -1
  176. package/dist/runtime/validation.js +0 -1
  177. package/dist/runtime/workflow-events.js +0 -1
  178. package/dist/runtime/workflow-runner.d.ts +1 -0
  179. package/dist/runtime/workflow-runner.js +8 -3
  180. package/dist/runtime/workflow-types.js +0 -1
  181. package/dist/sentiment/adapters/finnhub.js +0 -1
  182. package/dist/sentiment/adapters/reddit.js +0 -1
  183. package/dist/sentiment/adapters/twitter.js +0 -1
  184. package/dist/sentiment/adapters/web.js +0 -1
  185. package/dist/sentiment/index.js +4 -2
  186. package/dist/sentiment/insights.js +0 -1
  187. package/dist/sentiment/keywords.js +0 -1
  188. package/dist/sentiment/pipeline.js +0 -1
  189. package/dist/sentiment/scorer.js +0 -1
  190. package/dist/sentiment/store.js +0 -1
  191. package/dist/sentiment/trends.js +0 -1
  192. package/dist/sentiment/types.js +0 -1
  193. package/dist/system-prompt.js +0 -1
  194. package/dist/tool-kit.js +0 -1
  195. package/dist/tools/fundamentals/company-overview.d.ts +1 -1
  196. package/dist/tools/fundamentals/company-overview.js +2 -1
  197. package/dist/tools/fundamentals/comps.js +6 -4
  198. package/dist/tools/fundamentals/dcf.js +0 -1
  199. package/dist/tools/fundamentals/earnings.d.ts +1 -1
  200. package/dist/tools/fundamentals/earnings.js +2 -1
  201. package/dist/tools/fundamentals/financials.js +2 -1
  202. package/dist/tools/fundamentals/sec-filings.js +0 -1
  203. package/dist/tools/index.d.ts +116 -2
  204. package/dist/tools/index.js +0 -1
  205. package/dist/tools/interaction/ask-user.js +11 -1
  206. package/dist/tools/macro/event-probabilities.js +0 -1
  207. package/dist/tools/macro/fear-greed.d.ts +1 -1
  208. package/dist/tools/macro/fear-greed.js +0 -1
  209. package/dist/tools/macro/fred-data.d.ts +1 -1
  210. package/dist/tools/macro/fred-data.js +2 -1
  211. package/dist/tools/market/crypto-history.js +0 -1
  212. package/dist/tools/market/crypto-price.d.ts +2 -2
  213. package/dist/tools/market/crypto-price.js +0 -1
  214. package/dist/tools/market/screen-stocks.js +0 -1
  215. package/dist/tools/market/search-ticker.js +1 -2
  216. package/dist/tools/market/stock-history.js +0 -1
  217. package/dist/tools/market/stock-quote.d.ts +2 -2
  218. package/dist/tools/market/stock-quote.js +0 -1
  219. package/dist/tools/options/greeks.js +0 -1
  220. package/dist/tools/options/option-chain.d.ts +2 -2
  221. package/dist/tools/options/option-chain.js +0 -1
  222. package/dist/tools/portfolio/alerts.d.ts +2 -1
  223. package/dist/tools/portfolio/alerts.js +228 -2
  224. package/dist/tools/portfolio/correlation.js +23 -5
  225. package/dist/tools/portfolio/daily-report.js +0 -1
  226. package/dist/tools/portfolio/holdings-overlap.js +0 -1
  227. package/dist/tools/portfolio/notifications.js +0 -1
  228. package/dist/tools/portfolio/risk-analysis.d.ts +1 -1
  229. package/dist/tools/portfolio/risk-analysis.js +0 -1
  230. package/dist/tools/portfolio/tracker.d.ts +3 -1
  231. package/dist/tools/portfolio/tracker.js +57 -10
  232. package/dist/tools/portfolio/watchlist.d.ts +3 -6
  233. package/dist/tools/portfolio/watchlist.js +101 -110
  234. package/dist/tools/sentiment/insight-format.js +0 -1
  235. package/dist/tools/sentiment/query-match.js +0 -1
  236. package/dist/tools/sentiment/reddit-sentiment.js +0 -1
  237. package/dist/tools/sentiment/sentiment-summary.js +8 -4
  238. package/dist/tools/sentiment/sentiment-trend.d.ts +5 -1
  239. package/dist/tools/sentiment/sentiment-trend.js +6 -2
  240. package/dist/tools/sentiment/twitter-sentiment.js +0 -1
  241. package/dist/tools/sentiment/untrusted-text.js +0 -1
  242. package/dist/tools/sentiment/web-search.d.ts +1 -1
  243. package/dist/tools/sentiment/web-search.js +0 -1
  244. package/dist/tools/sentiment/web-sentiment.js +0 -1
  245. package/dist/tools/technical/backtest.js +0 -1
  246. package/dist/tools/technical/indicators.js +0 -1
  247. package/dist/types/fundamentals.js +0 -1
  248. package/dist/types/index.js +0 -1
  249. package/dist/types/macro.js +0 -1
  250. package/dist/types/market.d.ts +6 -0
  251. package/dist/types/market.js +0 -1
  252. package/dist/types/options.js +0 -1
  253. package/dist/types/portfolio.js +0 -1
  254. package/dist/types/prediction-markets.js +0 -1
  255. package/dist/types/sentiment.js +0 -1
  256. package/dist/workflows/compare-assets.js +0 -1
  257. package/dist/workflows/index.js +0 -1
  258. package/dist/workflows/options-screener.js +0 -1
  259. package/dist/workflows/portfolio-builder.js +0 -1
  260. package/gui/web/dist/assets/CatalogOverlay-CAc7e3Pf.js +1 -0
  261. package/gui/web/dist/assets/index-BOEKd9wT.css +2 -0
  262. package/gui/web/dist/assets/index-C-H05cQ2.js +65 -0
  263. package/gui/web/dist/index.html +2 -2
  264. package/package.json +11 -12
  265. package/dist/analysts/contracts.js.map +0 -1
  266. package/dist/analysts/orchestrator.js.map +0 -1
  267. package/dist/cli-main.js.map +0 -1
  268. package/dist/cli.js.map +0 -1
  269. package/dist/config.js.map +0 -1
  270. package/dist/doctor/cli-command.js.map +0 -1
  271. package/dist/doctor/render.js.map +0 -1
  272. package/dist/doctor/report.js.map +0 -1
  273. package/dist/index.js.map +0 -1
  274. package/dist/infra/cache.js.map +0 -1
  275. package/dist/infra/freshness.js.map +0 -1
  276. package/dist/infra/http-client.js.map +0 -1
  277. package/dist/infra/index.js.map +0 -1
  278. package/dist/infra/market-calendar.js.map +0 -1
  279. package/dist/infra/native-dependencies.js.map +0 -1
  280. package/dist/infra/node-version.js.map +0 -1
  281. package/dist/infra/open-url.js.map +0 -1
  282. package/dist/infra/opencandle-paths.js.map +0 -1
  283. package/dist/infra/rate-limiter.js.map +0 -1
  284. package/dist/market-state/alert-conditions.js.map +0 -1
  285. package/dist/market-state/alert-runner.js.map +0 -1
  286. package/dist/market-state/daily-report.js.map +0 -1
  287. package/dist/market-state/local-automation-service.js.map +0 -1
  288. package/dist/market-state/notification-delivery.js.map +0 -1
  289. package/dist/market-state/resolve-for-mutation.js.map +0 -1
  290. package/dist/market-state/resolve.js.map +0 -1
  291. package/dist/market-state/service.js.map +0 -1
  292. package/dist/market-state/summaries.js.map +0 -1
  293. package/dist/memory/index.js.map +0 -1
  294. package/dist/memory/manager.js.map +0 -1
  295. package/dist/memory/preference-extractor.js.map +0 -1
  296. package/dist/memory/retrieval.js.map +0 -1
  297. package/dist/memory/sqlite.js.map +0 -1
  298. package/dist/memory/storage.js.map +0 -1
  299. package/dist/memory/tool-defaults.js.map +0 -1
  300. package/dist/memory/types.js.map +0 -1
  301. package/dist/monitor.js.map +0 -1
  302. package/dist/onboarding/connect.js.map +0 -1
  303. package/dist/onboarding/credential-interceptor.js.map +0 -1
  304. package/dist/onboarding/degradation-accumulator.js.map +0 -1
  305. package/dist/onboarding/prompt-user.js.map +0 -1
  306. package/dist/onboarding/provider-status.js.map +0 -1
  307. package/dist/onboarding/providers.js.map +0 -1
  308. package/dist/onboarding/state.js.map +0 -1
  309. package/dist/onboarding/tool-helpers.js.map +0 -1
  310. package/dist/onboarding/tool-tags.js.map +0 -1
  311. package/dist/onboarding/validation.js.map +0 -1
  312. package/dist/pi/opencandle-extension.js.map +0 -1
  313. package/dist/pi/session-action-dedupe.js.map +0 -1
  314. package/dist/pi/session-storage.js.map +0 -1
  315. package/dist/pi/session-writer-lock.js.map +0 -1
  316. package/dist/pi/session.js.map +0 -1
  317. package/dist/pi/setup.js.map +0 -1
  318. package/dist/pi/tool-adapter.js.map +0 -1
  319. package/dist/pi/tui-session-coordinator.js.map +0 -1
  320. package/dist/prompts/context-builder.js.map +0 -1
  321. package/dist/prompts/disclaimer.js.map +0 -1
  322. package/dist/prompts/policy-cards.js.map +0 -1
  323. package/dist/prompts/sections.js.map +0 -1
  324. package/dist/prompts/symbol-preflight.js.map +0 -1
  325. package/dist/prompts/workflow-prompts.js.map +0 -1
  326. package/dist/providers/alpha-vantage.js.map +0 -1
  327. package/dist/providers/coingecko.js.map +0 -1
  328. package/dist/providers/errors.js.map +0 -1
  329. package/dist/providers/exa-search.js.map +0 -1
  330. package/dist/providers/external-tool-command.js.map +0 -1
  331. package/dist/providers/external-tool-error.js.map +0 -1
  332. package/dist/providers/fear-greed.js.map +0 -1
  333. package/dist/providers/finnhub.js.map +0 -1
  334. package/dist/providers/fred.js.map +0 -1
  335. package/dist/providers/index.js.map +0 -1
  336. package/dist/providers/polymarket.js.map +0 -1
  337. package/dist/providers/provider-credential-error.js.map +0 -1
  338. package/dist/providers/reddit-cli.js.map +0 -1
  339. package/dist/providers/reddit.js.map +0 -1
  340. package/dist/providers/sec-edgar.js.map +0 -1
  341. package/dist/providers/tradingview.js.map +0 -1
  342. package/dist/providers/twitter-cli.js.map +0 -1
  343. package/dist/providers/twitter.js.map +0 -1
  344. package/dist/providers/web-search.js.map +0 -1
  345. package/dist/providers/with-fallback.js.map +0 -1
  346. package/dist/providers/wrap-provider.js.map +0 -1
  347. package/dist/providers/yahoo-finance.js.map +0 -1
  348. package/dist/routing/classify-intent.js.map +0 -1
  349. package/dist/routing/defaults.js.map +0 -1
  350. package/dist/routing/entity-extractor.js.map +0 -1
  351. package/dist/routing/fund-symbols.js.map +0 -1
  352. package/dist/routing/horizon.js.map +0 -1
  353. package/dist/routing/index.js.map +0 -1
  354. package/dist/routing/legacy-rule-router.js.map +0 -1
  355. package/dist/routing/planning.js.map +0 -1
  356. package/dist/routing/route-manifest.js.map +0 -1
  357. package/dist/routing/router-llm-client.js.map +0 -1
  358. package/dist/routing/router-prompt.js.map +0 -1
  359. package/dist/routing/router-types.js.map +0 -1
  360. package/dist/routing/router.js.map +0 -1
  361. package/dist/routing/slot-resolver.js.map +0 -1
  362. package/dist/routing/symbol-disambiguator.js.map +0 -1
  363. package/dist/routing/turn-context.js.map +0 -1
  364. package/dist/routing/types.js.map +0 -1
  365. package/dist/runtime/answer-contracts.js.map +0 -1
  366. package/dist/runtime/artifact-contracts.js.map +0 -1
  367. package/dist/runtime/evidence.js.map +0 -1
  368. package/dist/runtime/numeric-claims.js.map +0 -1
  369. package/dist/runtime/planning-evidence.js.map +0 -1
  370. package/dist/runtime/prompt-step.js.map +0 -1
  371. package/dist/runtime/provider-tracker.js.map +0 -1
  372. package/dist/runtime/run-context.js.map +0 -1
  373. package/dist/runtime/session-coordinator.js.map +0 -1
  374. package/dist/runtime/session-title.js.map +0 -1
  375. package/dist/runtime/tool-defaults-wrapper.js.map +0 -1
  376. package/dist/runtime/validation.js.map +0 -1
  377. package/dist/runtime/workflow-events.js.map +0 -1
  378. package/dist/runtime/workflow-runner.js.map +0 -1
  379. package/dist/runtime/workflow-types.js.map +0 -1
  380. package/dist/sentiment/adapters/finnhub.js.map +0 -1
  381. package/dist/sentiment/adapters/reddit.js.map +0 -1
  382. package/dist/sentiment/adapters/twitter.js.map +0 -1
  383. package/dist/sentiment/adapters/web.js.map +0 -1
  384. package/dist/sentiment/index.js.map +0 -1
  385. package/dist/sentiment/insights.js.map +0 -1
  386. package/dist/sentiment/keywords.js.map +0 -1
  387. package/dist/sentiment/pipeline.js.map +0 -1
  388. package/dist/sentiment/scorer.js.map +0 -1
  389. package/dist/sentiment/store.js.map +0 -1
  390. package/dist/sentiment/trends.js.map +0 -1
  391. package/dist/sentiment/types.js.map +0 -1
  392. package/dist/system-prompt.js.map +0 -1
  393. package/dist/tool-kit.js.map +0 -1
  394. package/dist/tools/fundamentals/company-overview.js.map +0 -1
  395. package/dist/tools/fundamentals/comps.js.map +0 -1
  396. package/dist/tools/fundamentals/dcf.js.map +0 -1
  397. package/dist/tools/fundamentals/earnings.js.map +0 -1
  398. package/dist/tools/fundamentals/financials.js.map +0 -1
  399. package/dist/tools/fundamentals/sec-filings.js.map +0 -1
  400. package/dist/tools/index.js.map +0 -1
  401. package/dist/tools/interaction/ask-user.js.map +0 -1
  402. package/dist/tools/macro/event-probabilities.js.map +0 -1
  403. package/dist/tools/macro/fear-greed.js.map +0 -1
  404. package/dist/tools/macro/fred-data.js.map +0 -1
  405. package/dist/tools/market/crypto-history.js.map +0 -1
  406. package/dist/tools/market/crypto-price.js.map +0 -1
  407. package/dist/tools/market/screen-stocks.js.map +0 -1
  408. package/dist/tools/market/search-ticker.js.map +0 -1
  409. package/dist/tools/market/stock-history.js.map +0 -1
  410. package/dist/tools/market/stock-quote.js.map +0 -1
  411. package/dist/tools/options/greeks.js.map +0 -1
  412. package/dist/tools/options/option-chain.js.map +0 -1
  413. package/dist/tools/portfolio/alerts.js.map +0 -1
  414. package/dist/tools/portfolio/correlation.js.map +0 -1
  415. package/dist/tools/portfolio/daily-report.js.map +0 -1
  416. package/dist/tools/portfolio/holdings-overlap.js.map +0 -1
  417. package/dist/tools/portfolio/notifications.js.map +0 -1
  418. package/dist/tools/portfolio/risk-analysis.js.map +0 -1
  419. package/dist/tools/portfolio/tracker.js.map +0 -1
  420. package/dist/tools/portfolio/watchlist.js.map +0 -1
  421. package/dist/tools/sentiment/insight-format.js.map +0 -1
  422. package/dist/tools/sentiment/query-match.js.map +0 -1
  423. package/dist/tools/sentiment/reddit-sentiment.js.map +0 -1
  424. package/dist/tools/sentiment/sentiment-summary.js.map +0 -1
  425. package/dist/tools/sentiment/sentiment-trend.js.map +0 -1
  426. package/dist/tools/sentiment/twitter-sentiment.js.map +0 -1
  427. package/dist/tools/sentiment/untrusted-text.js.map +0 -1
  428. package/dist/tools/sentiment/web-search.js.map +0 -1
  429. package/dist/tools/sentiment/web-sentiment.js.map +0 -1
  430. package/dist/tools/technical/backtest.js.map +0 -1
  431. package/dist/tools/technical/indicators.js.map +0 -1
  432. package/dist/types/fundamentals.js.map +0 -1
  433. package/dist/types/index.js.map +0 -1
  434. package/dist/types/macro.js.map +0 -1
  435. package/dist/types/market.js.map +0 -1
  436. package/dist/types/options.js.map +0 -1
  437. package/dist/types/portfolio.js.map +0 -1
  438. package/dist/types/prediction-markets.js.map +0 -1
  439. package/dist/types/sentiment.js.map +0 -1
  440. package/dist/workflows/compare-assets.js.map +0 -1
  441. package/dist/workflows/index.js.map +0 -1
  442. package/dist/workflows/options-screener.js.map +0 -1
  443. package/dist/workflows/portfolio-builder.js.map +0 -1
  444. package/gui/server/ask-user-bridge.ts +0 -89
  445. package/gui/server/automation-heartbeat.ts +0 -97
  446. package/gui/server/background-quotes.ts +0 -127
  447. package/gui/server/chat-event-adapter.ts +0 -294
  448. package/gui/server/gui-session-manager.ts +0 -5
  449. package/gui/server/http-routes.ts +0 -1201
  450. package/gui/server/invoke-tool.ts +0 -490
  451. package/gui/server/live-chat-event-adapter.ts +0 -243
  452. package/gui/server/local-session-coordinator.ts +0 -97
  453. package/gui/server/market-state-api.ts +0 -331
  454. package/gui/server/model-setup.ts +0 -254
  455. package/gui/server/package.json +0 -5
  456. package/gui/server/private-api-access.ts +0 -62
  457. package/gui/server/projector.ts +0 -392
  458. package/gui/server/prompt-observation.ts +0 -58
  459. package/gui/server/quote-snapshot-store.ts +0 -50
  460. package/gui/server/server.ts +0 -289
  461. package/gui/server/session-actions.ts +0 -323
  462. package/gui/server/session-entry-wait.ts +0 -179
  463. package/gui/server/shutdown.ts +0 -47
  464. package/gui/server/tool-invoke-ack.ts +0 -49
  465. package/gui/server/tool-metadata.ts +0 -167
  466. package/gui/server/websocket.ts +0 -138
  467. package/gui/server/writer-lock.ts +0 -1
  468. package/gui/server/ws-hub.ts +0 -403
  469. package/gui/shared/chat-events.ts +0 -165
  470. package/gui/shared/event-reducer.ts +0 -220
  471. package/gui/web/dist/assets/CatalogOverlay-DZ1niyQm.js +0 -1
  472. package/gui/web/dist/assets/index-D4F9AJnn.css +0 -2
  473. package/gui/web/dist/assets/index-DtqMMBTr.js +0 -65
  474. package/src/analysts/contracts.ts +0 -176
  475. package/src/analysts/orchestrator.ts +0 -244
  476. package/src/cli-main.ts +0 -510
  477. package/src/cli.ts +0 -17
  478. package/src/config.ts +0 -272
  479. package/src/doctor/cli-command.ts +0 -83
  480. package/src/doctor/render.ts +0 -37
  481. package/src/doctor/report.ts +0 -638
  482. package/src/index.ts +0 -5
  483. package/src/infra/cache.ts +0 -127
  484. package/src/infra/freshness.ts +0 -165
  485. package/src/infra/http-client.ts +0 -134
  486. package/src/infra/index.ts +0 -14
  487. package/src/infra/market-calendar.ts +0 -193
  488. package/src/infra/native-dependencies.ts +0 -84
  489. package/src/infra/node-version.ts +0 -23
  490. package/src/infra/open-url.ts +0 -28
  491. package/src/infra/opencandle-paths.ts +0 -53
  492. package/src/infra/rate-limiter.ts +0 -77
  493. package/src/market-state/alert-conditions.ts +0 -82
  494. package/src/market-state/alert-runner.ts +0 -863
  495. package/src/market-state/daily-report.ts +0 -237
  496. package/src/market-state/local-automation-service.ts +0 -162
  497. package/src/market-state/notification-delivery.ts +0 -158
  498. package/src/market-state/resolve-for-mutation.ts +0 -24
  499. package/src/market-state/resolve.ts +0 -112
  500. package/src/market-state/service.ts +0 -2208
  501. package/src/market-state/summaries.ts +0 -75
  502. package/src/memory/index.ts +0 -10
  503. package/src/memory/manager.ts +0 -190
  504. package/src/memory/preference-extractor.ts +0 -106
  505. package/src/memory/retrieval.ts +0 -71
  506. package/src/memory/sqlite.ts +0 -577
  507. package/src/memory/storage.ts +0 -195
  508. package/src/memory/tool-defaults.ts +0 -108
  509. package/src/memory/types.ts +0 -71
  510. package/src/monitor.ts +0 -123
  511. package/src/onboarding/connect.ts +0 -177
  512. package/src/onboarding/credential-interceptor.ts +0 -122
  513. package/src/onboarding/degradation-accumulator.ts +0 -77
  514. package/src/onboarding/prompt-user.ts +0 -85
  515. package/src/onboarding/provider-status.ts +0 -382
  516. package/src/onboarding/providers.ts +0 -442
  517. package/src/onboarding/state.ts +0 -216
  518. package/src/onboarding/tool-helpers.ts +0 -104
  519. package/src/onboarding/tool-tags.ts +0 -244
  520. package/src/onboarding/validation.ts +0 -152
  521. package/src/pi/opencandle-extension.ts +0 -1294
  522. package/src/pi/session-action-dedupe.ts +0 -155
  523. package/src/pi/session-storage.ts +0 -5
  524. package/src/pi/session-writer-lock.ts +0 -426
  525. package/src/pi/session.ts +0 -84
  526. package/src/pi/setup.ts +0 -399
  527. package/src/pi/tool-adapter.ts +0 -49
  528. package/src/pi/tui-session-coordinator.ts +0 -351
  529. package/src/prompts/context-builder.ts +0 -326
  530. package/src/prompts/disclaimer.ts +0 -9
  531. package/src/prompts/policy-cards.ts +0 -228
  532. package/src/prompts/sections.ts +0 -46
  533. package/src/prompts/symbol-preflight.ts +0 -80
  534. package/src/prompts/workflow-prompts.ts +0 -504
  535. package/src/providers/alpha-vantage.ts +0 -340
  536. package/src/providers/coingecko.ts +0 -95
  537. package/src/providers/errors.ts +0 -9
  538. package/src/providers/exa-search.ts +0 -375
  539. package/src/providers/external-tool-command.ts +0 -164
  540. package/src/providers/external-tool-error.ts +0 -20
  541. package/src/providers/fear-greed.ts +0 -45
  542. package/src/providers/finnhub.ts +0 -125
  543. package/src/providers/fred.ts +0 -83
  544. package/src/providers/index.ts +0 -17
  545. package/src/providers/polymarket.ts +0 -214
  546. package/src/providers/provider-credential-error.ts +0 -23
  547. package/src/providers/reddit-cli.ts +0 -286
  548. package/src/providers/reddit.ts +0 -106
  549. package/src/providers/sec-edgar.ts +0 -326
  550. package/src/providers/tradingview.ts +0 -399
  551. package/src/providers/twitter-cli.ts +0 -202
  552. package/src/providers/twitter.ts +0 -102
  553. package/src/providers/web-search.ts +0 -303
  554. package/src/providers/with-fallback.ts +0 -42
  555. package/src/providers/wrap-provider.ts +0 -105
  556. package/src/providers/yahoo-finance.ts +0 -984
  557. package/src/routing/classify-intent.ts +0 -380
  558. package/src/routing/defaults.ts +0 -29
  559. package/src/routing/entity-extractor.ts +0 -557
  560. package/src/routing/fund-symbols.ts +0 -58
  561. package/src/routing/horizon.ts +0 -7
  562. package/src/routing/index.ts +0 -70
  563. package/src/routing/legacy-rule-router.ts +0 -13
  564. package/src/routing/planning.ts +0 -829
  565. package/src/routing/route-manifest.ts +0 -308
  566. package/src/routing/router-llm-client.ts +0 -64
  567. package/src/routing/router-prompt.ts +0 -159
  568. package/src/routing/router-types.ts +0 -84
  569. package/src/routing/router.ts +0 -1332
  570. package/src/routing/slot-resolver.ts +0 -213
  571. package/src/routing/symbol-disambiguator.ts +0 -72
  572. package/src/routing/turn-context.ts +0 -108
  573. package/src/routing/types.ts +0 -77
  574. package/src/runtime/answer-contracts.ts +0 -693
  575. package/src/runtime/artifact-contracts.ts +0 -77
  576. package/src/runtime/evidence.ts +0 -78
  577. package/src/runtime/numeric-claims.ts +0 -108
  578. package/src/runtime/planning-evidence.ts +0 -597
  579. package/src/runtime/prompt-step.ts +0 -185
  580. package/src/runtime/provider-tracker.ts +0 -40
  581. package/src/runtime/run-context.ts +0 -32
  582. package/src/runtime/session-coordinator.ts +0 -1037
  583. package/src/runtime/session-title.ts +0 -60
  584. package/src/runtime/tool-defaults-wrapper.ts +0 -43
  585. package/src/runtime/validation.ts +0 -211
  586. package/src/runtime/workflow-events.ts +0 -77
  587. package/src/runtime/workflow-runner.ts +0 -182
  588. package/src/runtime/workflow-types.ts +0 -105
  589. package/src/sentiment/adapters/finnhub.ts +0 -49
  590. package/src/sentiment/adapters/reddit.ts +0 -65
  591. package/src/sentiment/adapters/twitter.ts +0 -36
  592. package/src/sentiment/adapters/web.ts +0 -44
  593. package/src/sentiment/index.ts +0 -49
  594. package/src/sentiment/insights.ts +0 -269
  595. package/src/sentiment/keywords.ts +0 -31
  596. package/src/sentiment/pipeline.ts +0 -91
  597. package/src/sentiment/scorer.ts +0 -89
  598. package/src/sentiment/store.ts +0 -260
  599. package/src/sentiment/trends.ts +0 -96
  600. package/src/sentiment/types.ts +0 -112
  601. package/src/system-prompt.ts +0 -115
  602. package/src/tool-kit.ts +0 -69
  603. package/src/tools/AGENTS.md +0 -36
  604. package/src/tools/fundamentals/company-overview.ts +0 -64
  605. package/src/tools/fundamentals/comps.ts +0 -180
  606. package/src/tools/fundamentals/dcf.ts +0 -447
  607. package/src/tools/fundamentals/earnings.ts +0 -57
  608. package/src/tools/fundamentals/financials.ts +0 -63
  609. package/src/tools/fundamentals/sec-filings.ts +0 -105
  610. package/src/tools/index.ts +0 -104
  611. package/src/tools/interaction/ask-user.ts +0 -93
  612. package/src/tools/macro/event-probabilities.ts +0 -141
  613. package/src/tools/macro/fear-greed.ts +0 -41
  614. package/src/tools/macro/fred-data.ts +0 -92
  615. package/src/tools/market/crypto-history.ts +0 -72
  616. package/src/tools/market/crypto-price.ts +0 -65
  617. package/src/tools/market/screen-stocks.ts +0 -290
  618. package/src/tools/market/search-ticker.ts +0 -254
  619. package/src/tools/market/stock-history.ts +0 -104
  620. package/src/tools/market/stock-quote.ts +0 -73
  621. package/src/tools/options/greeks.ts +0 -81
  622. package/src/tools/options/option-chain.ts +0 -134
  623. package/src/tools/portfolio/alerts.ts +0 -457
  624. package/src/tools/portfolio/correlation.ts +0 -189
  625. package/src/tools/portfolio/daily-report.ts +0 -107
  626. package/src/tools/portfolio/holdings-overlap.ts +0 -139
  627. package/src/tools/portfolio/notifications.ts +0 -45
  628. package/src/tools/portfolio/risk-analysis.ts +0 -173
  629. package/src/tools/portfolio/tracker.ts +0 -308
  630. package/src/tools/portfolio/watchlist.ts +0 -288
  631. package/src/tools/sentiment/insight-format.ts +0 -50
  632. package/src/tools/sentiment/query-match.ts +0 -117
  633. package/src/tools/sentiment/reddit-sentiment.ts +0 -403
  634. package/src/tools/sentiment/sentiment-summary.ts +0 -383
  635. package/src/tools/sentiment/sentiment-trend.ts +0 -75
  636. package/src/tools/sentiment/twitter-sentiment.ts +0 -287
  637. package/src/tools/sentiment/untrusted-text.ts +0 -21
  638. package/src/tools/sentiment/web-search.ts +0 -186
  639. package/src/tools/sentiment/web-sentiment.ts +0 -96
  640. package/src/tools/technical/backtest.ts +0 -336
  641. package/src/tools/technical/indicators.ts +0 -281
  642. package/src/types/fundamentals.ts +0 -47
  643. package/src/types/index.ts +0 -26
  644. package/src/types/macro.ts +0 -27
  645. package/src/types/market.ts +0 -46
  646. package/src/types/options.ts +0 -53
  647. package/src/types/portfolio.ts +0 -83
  648. package/src/types/prediction-markets.ts +0 -13
  649. package/src/types/sentiment.ts +0 -129
  650. package/src/workflows/compare-assets.ts +0 -89
  651. package/src/workflows/index.ts +0 -3
  652. package/src/workflows/options-screener.ts +0 -125
  653. package/src/workflows/portfolio-builder.ts +0 -63
@@ -1,117 +0,0 @@
1
- import { extractEntities } from "../../routing/entity-extractor.js";
2
- import type { SentinelRecord } from "../../sentiment/types.js";
3
-
4
- const STOP_TERMS = new Set([
5
- "about",
6
- "around",
7
- "are",
8
- "from",
9
- "how",
10
- "is",
11
- "latest",
12
- "mood",
13
- "now",
14
- "on",
15
- "or",
16
- "people",
17
- "reddit",
18
- "retail",
19
- "right",
20
- "say",
21
- "saying",
22
- "says",
23
- "sentiment",
24
- "social",
25
- "stock",
26
- "stocks",
27
- "talking",
28
- "the",
29
- "think",
30
- "thinking",
31
- "to",
32
- "tweet",
33
- "tweets",
34
- "twitter",
35
- "what",
36
- "with",
37
- ]);
38
-
39
- export function sentimentQueryTerms(query: string): string[] {
40
- const hasSp500 = /\bs\s*&\s*p\s*500\b/i.test(query) || /\bspx\b/i.test(query);
41
-
42
- const symbols = hasSp500
43
- ? ["sp500"]
44
- : extractEntities(query).symbols.map((symbol) => symbol.toLowerCase());
45
- const punctuationTerms = [...query.toLowerCase().matchAll(/\b([a-z])\s*[&/]\s*([a-z])\b/g)].map(
46
- (match) => `${match[1]}${match[2]}`,
47
- );
48
- const terms = query.toLowerCase().match(/[a-z0-9]{2,}/g);
49
- if (!terms) {
50
- if (punctuationTerms.length > 0) return [...new Set(punctuationTerms)];
51
- const compact = query.toLowerCase().replace(/[^a-z0-9]/g, "");
52
- if (compact.length >= 2) return [compact];
53
- return query.trim().length > 0 ? [query.trim().toLowerCase()] : [];
54
- }
55
-
56
- const stopTerms = hasSp500 ? new Set([...STOP_TERMS, "sp", "spx", "500"]) : STOP_TERMS;
57
- const filtered = [
58
- ...new Set([...punctuationTerms, ...terms.filter((term) => !stopTerms.has(term))]),
59
- ].slice(0, 6);
60
- if (symbols.length > 0) {
61
- return [
62
- ...new Set([
63
- ...symbols,
64
- ...filtered.filter((term) => !symbols.some((symbol) => symbol.startsWith(term))),
65
- ]),
66
- ].slice(0, 6);
67
- }
68
- if (filtered.length > 0) return filtered;
69
- return query.trim().length > 0 ? [query.trim().toLowerCase()] : [];
70
- }
71
-
72
- export function recordMatchesSentimentQuery(
73
- record: SentinelRecord,
74
- terms: readonly string[],
75
- ): boolean {
76
- if (terms.length === 0) return true;
77
- const text = `${record.title ?? ""}\n${record.text}`.toLowerCase();
78
- const textTokens = new Set(text.match(/[a-z0-9]+/g) ?? []);
79
- const metadataTokens = new Set<string>();
80
- const subreddit = record.metadata.subreddit;
81
- if (typeof subreddit === "string") {
82
- metadataTokens.add(subreddit.toLowerCase());
83
- metadataTokens.add(subreddit.toLowerCase().replace(/^r\//, ""));
84
- }
85
- if (/\bs\s*&\s*p\s*500\b/i.test(text) || /\bspx\b/i.test(text)) textTokens.add("sp500");
86
- for (const match of text.matchAll(/\b([a-z])\s*[&/]\s*([a-z])\b/g)) {
87
- textTokens.add(`${match[1]}${match[2]}`);
88
- }
89
- for (const match of text.matchAll(/\b([a-z]{1,5})[.-]([a-z])\b/g)) {
90
- textTokens.add(`${match[1]}${match[2]}`);
91
- }
92
- const tickerTokens = new Set<string>();
93
- for (const ticker of record.sentiment.tickers) {
94
- const normalized = ticker.toLowerCase();
95
- tickerTokens.add(normalized);
96
- tickerTokens.add(normalized.replace(/[^a-z0-9]/g, ""));
97
- }
98
- const matchedTerms = terms.filter(
99
- (term) => tickerTokens.has(term) || textTokens.has(term) || metadataTokens.has(term),
100
- );
101
- for (const term of terms) {
102
- if (matchedTerms.includes(term) || !term.includes(" ")) continue;
103
- if (text.includes(term)) matchedTerms.push(term);
104
- }
105
- for (const term of terms) {
106
- if (matchedTerms.includes(term) || term.length < 4) continue;
107
- if (textTokens.has(`${term}s`)) {
108
- matchedTerms.push(term);
109
- continue;
110
- }
111
- if (term.endsWith("s") && textTokens.has(term.slice(0, -1))) {
112
- matchedTerms.push(term);
113
- }
114
- }
115
- const requiredMatches = terms.length > 1 ? 2 : 1;
116
- return matchedTerms.length >= requiredMatches;
117
- }
@@ -1,403 +0,0 @@
1
- import type { AgentTool } from "@earendil-works/pi-agent-core";
2
- import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
3
- import { Type } from "@sinclair/typebox";
4
- import { getConfig } from "../../config.js";
5
- import { promptUser } from "../../onboarding/prompt-user.js";
6
- import { getProvider } from "../../onboarding/providers.js";
7
- import {
8
- loadOnboardingState,
9
- markProviderNeverAsk,
10
- saveOnboardingState,
11
- } from "../../onboarding/state.js";
12
- import { buildExternalToolRequiredTag, buildSkippedTag } from "../../onboarding/tool-tags.js";
13
- import { getPostComments, getSubredditPosts } from "../../providers/reddit.js";
14
- import { wrapProvider } from "../../providers/wrap-provider.js";
15
- import { RedditAdapter } from "../../sentiment/adapters/reddit.js";
16
- import { getSentimentPipeline } from "../../sentiment/index.js";
17
- import type { AskUserHandler } from "../../types/index.js";
18
- import type { RedditSentimentResult } from "../../types/sentiment.js";
19
- import { formatInsightSection } from "./insight-format.js";
20
- import { recordMatchesSentimentQuery, sentimentQueryTerms } from "./query-match.js";
21
- import { renderUntrustedText, untrustedContentHeader } from "./untrusted-text.js";
22
-
23
- const params = Type.Object({
24
- subreddit: Type.Optional(
25
- Type.String({
26
- description:
27
- "Subreddit name (e.g. wallstreetbets, stocks). If omitted, searches across default subreddits.",
28
- }),
29
- ),
30
- query: Type.Optional(
31
- Type.String({
32
- description:
33
- "Topic or ticker to filter posts by (e.g. AAPL, bitcoin). Searches titles and post bodies.",
34
- }),
35
- ),
36
- subreddits: Type.Optional(
37
- Type.Array(Type.String(), {
38
- description: "Multiple subreddits to search. Overrides single subreddit param.",
39
- }),
40
- ),
41
- limit: Type.Optional(
42
- Type.Number({ description: "Number of posts per subreddit. Default: 25, max: 100" }),
43
- ),
44
- });
45
-
46
- const INSTALL_CONTINUE_LABEL = "Continue after installing Reddit";
47
- const SESSION_CONTINUE_LABEL = "Continue after logging in to Reddit";
48
- const SKIP_ONCE_LABEL = "Skip Reddit once";
49
- const ALWAYS_SKIP_LABEL = "Always skip Reddit";
50
-
51
- interface ExtensionContextWithAskUserHandler extends Partial<ExtensionContext> {
52
- askUserHandler?: AskUserHandler;
53
- }
54
-
55
- interface RedditSentimentToolOptions {
56
- askUserHandler?: AskUserHandler;
57
- }
58
-
59
- type RedditToolDetails = RedditSentimentResult | null;
60
-
61
- export function createRedditSentimentTool(
62
- options: RedditSentimentToolOptions = {},
63
- ): AgentTool<typeof params, RedditToolDetails> {
64
- return {
65
- name: "get_reddit_sentiment",
66
- label: "Reddit Sentiment",
67
- description:
68
- "Analyze sentiment from financial Reddit communities. Supports single subreddit, multi-subreddit, and topic filtering. Returns scored posts with comment analysis and trend context.",
69
- parameters: params,
70
- async execute(_toolCallId, args, _signal, _onUpdate, ctx?: ExtensionContext) {
71
- const limit = Math.min(args.limit ?? 25, 100);
72
- const config = getConfig();
73
- const state = loadOnboardingState();
74
- const descriptor = getProvider("reddit");
75
- if (state.providers.reddit?.status === "never_ask") {
76
- return skippedRedditResult(
77
- "You previously asked not to be reminded about Reddit.",
78
- "run opencandle doctor --enable reddit to re-enable Reddit sentiment (silenced)",
79
- true,
80
- );
81
- }
82
-
83
- // Determine subreddits to search
84
- let subreddits: string[];
85
- if (args.subreddits && args.subreddits.length > 0) {
86
- subreddits = args.subreddits;
87
- } else if (args.subreddit) {
88
- subreddits = [args.subreddit];
89
- } else {
90
- subreddits = config.sentiment?.defaultSubreddits ?? [
91
- "wallstreetbets",
92
- "stocks",
93
- "investing",
94
- "options",
95
- ];
96
- }
97
-
98
- let { allResults, warnings } = await fetchRedditSubreddits(subreddits, limit, args.query);
99
- let retriedAfterContinue = false;
100
- let promptedSetupIssue: ReturnType<typeof classifyRedditSetupIssue> = null;
101
-
102
- if (allResults.length === 0) {
103
- const setupIssue = classifyRedditSetupIssue(warnings);
104
- if (setupIssue) {
105
- promptedSetupIssue = setupIssue;
106
- const askUserHandler =
107
- options.askUserHandler ??
108
- (ctx as ExtensionContextWithAskUserHandler | undefined)?.askUserHandler;
109
- const canAsk = askUserHandler != null || ctx?.hasUI === true;
110
- if (canAsk) {
111
- const promptResult = await promptUser(
112
- (ctx ?? { hasUI: false }) as ExtensionContext,
113
- {
114
- question:
115
- setupIssue === "not_installed"
116
- ? "Reddit sentiment needs the local rdt-cli command before it can fetch discussions. Install command: uv tool install rdt-cli. How would you like to proceed?"
117
- : "Reddit sentiment needs an active Reddit browser session for rdt-cli. Login command: rdt login. How would you like to proceed?",
118
- questionType: "select",
119
- options: [
120
- setupIssue === "not_installed" ? INSTALL_CONTINUE_LABEL : SESSION_CONTINUE_LABEL,
121
- SKIP_ONCE_LABEL,
122
- ALWAYS_SKIP_LABEL,
123
- ],
124
- reason: "Reddit sentiment needs rdt-cli and a Reddit browser session.",
125
- },
126
- askUserHandler,
127
- );
128
-
129
- if (!promptResult.cancelled && promptResult.answer?.startsWith("Continue")) {
130
- retriedAfterContinue = true;
131
- ({ allResults, warnings } = await fetchRedditSubreddits(
132
- subreddits,
133
- limit,
134
- args.query,
135
- ));
136
- } else if (!promptResult.cancelled && promptResult.answer === ALWAYS_SKIP_LABEL) {
137
- saveOnboardingState(markProviderNeverAsk(state, "reddit"));
138
- return skippedRedditResult(
139
- `User chose to always skip ${descriptor.displayName} data. Do not ask about Reddit setup again unless the user explicitly re-enables it.`,
140
- "run opencandle doctor --enable reddit to re-enable Reddit sentiment (silenced)",
141
- true,
142
- );
143
- } else {
144
- return skippedRedditResult(
145
- `User chose to skip ${descriptor.displayName} data for this request. Do not ask about Reddit setup again in this turn.`,
146
- "user chose to skip Reddit for this request",
147
- false,
148
- );
149
- }
150
- }
151
- }
152
- }
153
-
154
- if (allResults.length === 0) {
155
- const setupIssue = classifyRedditSetupIssue(warnings);
156
- if (retriedAfterContinue && (!setupIssue || setupIssue === promptedSetupIssue)) {
157
- return unavailableRedditResult(warnings);
158
- }
159
- if (setupIssue) {
160
- const tag = buildExternalToolRequiredTag({
161
- provider: "reddit",
162
- reason: setupIssue,
163
- installCmd: "uv tool install rdt-cli",
164
- loginCmd: "rdt login",
165
- fallback: "twitter-web-news",
166
- });
167
- const guidance =
168
- setupIssue === "not_installed"
169
- ? "Reddit sentiment requires the local rdt-cli tool. Install it with `uv tool install rdt-cli`, then run `rdt login` if needed."
170
- : "Reddit sentiment requires an active Reddit browser session for rdt-cli. Run `rdt login` or refresh your Reddit browser login.";
171
- return {
172
- content: [{ type: "text", text: `${tag}\n\n${guidance}` }],
173
- details: null,
174
- };
175
- }
176
- return unavailableRedditResult(warnings);
177
- }
178
-
179
- // Merge records returned by the provider. rdt-cli handles query-bearing
180
- // requests server-side; the local filter remains a defensive post-filter.
181
- const adapter = new RedditAdapter();
182
- let allRecords = allResults.flatMap((r) =>
183
- adapter.mapPostsToRecords(r, args.query ?? subreddits.join("+")),
184
- );
185
- const queryTerms = args.query ? sentimentQueryTerms(args.query) : null;
186
-
187
- // Topic filtering
188
- if (queryTerms) {
189
- allRecords = allRecords.filter((record) => recordMatchesSentimentQuery(record, queryTerms));
190
- }
191
-
192
- // Deduplicate by sourceId (crossposts)
193
- const seen = new Set<string>();
194
- allRecords = allRecords.filter((r) => {
195
- if (seen.has(r.sourceId)) return false;
196
- seen.add(r.sourceId);
197
- return true;
198
- });
199
-
200
- // Fetch comments for top 10 posts by engagement
201
- const commentsPerPost = config.sentiment?.commentsPerPost ?? 5;
202
- const topPosts = [...allRecords]
203
- .sort((a, b) => b.engagement.score - a.engagement.score)
204
- .slice(0, 10);
205
-
206
- for (const post of topPosts) {
207
- const sub = (post.metadata.subreddit as string) ?? subreddits[0];
208
- if ((post.engagement.replies ?? 0) === 0) continue;
209
- try {
210
- const comments = await getPostComments(sub, post.sourceId, commentsPerPost);
211
- const commentRecords = adapter.mapCommentsToRecords(
212
- comments,
213
- post.sourceId,
214
- sub,
215
- args.query ?? subreddits.join("+"),
216
- );
217
- allRecords.push(
218
- ...(queryTerms
219
- ? commentRecords.filter((record) => recordMatchesSentimentQuery(record, queryTerms))
220
- : commentRecords),
221
- );
222
- } catch {
223
- // Comment fetch failures are non-fatal
224
- }
225
- }
226
-
227
- // Process through pipeline
228
- const pipeline = getSentimentPipeline();
229
- const pipelineResult = await pipeline.processRecords(
230
- allRecords,
231
- args.query ?? subreddits.join("+"),
232
- );
233
-
234
- // Build output using first result as base for backward compatibility
235
- const firstResult = allResults[0];
236
- const postRecords = pipelineResult.fresh.filter((r) => !r.metadata.isComment);
237
- const commentRecords = pipelineResult.fresh.filter((r) => r.metadata.isComment);
238
- const sentimentRecords = pipelineResult.fresh;
239
- const rawPostsById = new Map(
240
- allResults.flatMap((result) => result.posts.map((post) => [post.id, post] as const)),
241
- );
242
- const aggregatePosts: RedditSentimentResult["posts"] = postRecords.map((record) => {
243
- const rawPost = rawPostsById.get(record.sourceId);
244
- return {
245
- id: record.sourceId,
246
- title: rawPost?.title ?? record.title ?? "",
247
- selftext: rawPost?.selftext ?? "",
248
- author: rawPost?.author ?? record.author ?? "unknown",
249
- score: rawPost?.score ?? record.engagement.score,
250
- comments: rawPost?.comments ?? record.engagement.replies ?? 0,
251
- url: rawPost?.url ?? record.url,
252
- created: rawPost?.created ?? record.publishedAt ?? record.fetchedAt,
253
- };
254
- });
255
- const aggregateTopMentions = [
256
- ...new Set(postRecords.flatMap((record) => record.sentiment.tickers)),
257
- ];
258
- const avgScore =
259
- sentimentRecords.length > 0
260
- ? sentimentRecords.reduce((s, r) => s + r.sentiment.score, 0) / sentimentRecords.length
261
- : 0;
262
-
263
- const sentimentLabel =
264
- avgScore > 0.3
265
- ? "Bullish"
266
- : avgScore < -0.3
267
- ? "Bearish"
268
- : avgScore > 0
269
- ? "Leaning Bullish"
270
- : avgScore < 0
271
- ? "Leaning Bearish"
272
- : "Neutral";
273
-
274
- const subLabel =
275
- subreddits.length === 1 ? `r/${subreddits[0]}` : `${subreddits.length} subreddits`;
276
- const lines = [
277
- `**Reddit: ${args.query ?? subLabel}** — ${postRecords.length} posts, ${commentRecords.length} comments`,
278
- `Sentiment: ${avgScore.toFixed(2)} (${sentimentLabel})`,
279
- ];
280
-
281
- const details: RedditSentimentResult = {
282
- ...firstResult,
283
- subreddit: subreddits.length === 1 ? firstResult.subreddit : subreddits.join(","),
284
- postCount: postRecords.length,
285
- posts: aggregatePosts,
286
- topMentions: aggregateTopMentions,
287
- sentimentScore: avgScore,
288
- bullishCount: sentimentRecords.filter((record) => record.sentiment.score > 0).length,
289
- bearishCount: sentimentRecords.filter((record) => record.sentiment.score < 0).length,
290
- insight: pipelineResult.insight,
291
- records: pipelineResult.fresh,
292
- };
293
-
294
- if (pipelineResult.insight) {
295
- lines.push(...formatInsightSection(pipelineResult.insight));
296
- }
297
-
298
- if (aggregateTopMentions.length > 0) {
299
- lines.push(`Tickers: ${aggregateTopMentions.map((t) => `$${t}`).join(", ")}`);
300
- }
301
-
302
- lines.push("");
303
- lines.push(untrustedContentHeader("Reddit posts"));
304
- for (const post of postRecords.slice(0, 10)) {
305
- const scoreIndicator =
306
- post.sentiment.score > 0 ? "🟢" : post.sentiment.score < 0 ? "🔴" : "⚪";
307
- lines.push(
308
- ` ${scoreIndicator} ⬆${post.engagement.score} 💬${post.engagement.replies ?? 0} — ${renderUntrustedText(post.title ?? post.text, 100)}`,
309
- );
310
- }
311
-
312
- if (pipelineResult.trend && pipelineResult.trend.length > 0) {
313
- const t = pipelineResult.trend[0];
314
- lines.push("");
315
- lines.push(
316
- `Trend: ${t.sparkline} ${t.direction} (${t.delta >= 0 ? "+" : ""}${t.delta.toFixed(2)}, ${t.count} records)`,
317
- );
318
- }
319
-
320
- if (warnings.length > 0) {
321
- lines.push("");
322
- lines.push(`⚠ ${warnings.join("; ")}`);
323
- }
324
-
325
- return { content: [{ type: "text", text: lines.join("\n") }], details };
326
- },
327
- };
328
- }
329
-
330
- export const redditSentimentTool = createRedditSentimentTool();
331
-
332
- function unavailableRedditResult(warnings: readonly string[]): {
333
- content: [{ type: "text"; text: string }];
334
- details: null;
335
- } {
336
- return {
337
- content: [{ type: "text", text: `⚠ Reddit sentiment unavailable (${warnings.join("; ")}).` }],
338
- details: null,
339
- };
340
- }
341
-
342
- async function fetchRedditSubreddits(
343
- subreddits: readonly string[],
344
- limit: number,
345
- query: string | undefined,
346
- ): Promise<{ allResults: RedditSentimentResult[]; warnings: string[] }> {
347
- const allResults: RedditSentimentResult[] = [];
348
- const warnings: string[] = [];
349
- for (const sub of subreddits) {
350
- const providerResult = await wrapProvider("reddit", () => getSubredditPosts(sub, limit, query));
351
- if (providerResult.status === "unavailable") {
352
- warnings.push(`r/${sub}: ${providerResult.reason}`);
353
- continue;
354
- }
355
- allResults.push(providerResult.data);
356
- }
357
- return { allResults, warnings };
358
- }
359
-
360
- function skippedRedditResult(
361
- message: string,
362
- remediation: string,
363
- silenced: boolean,
364
- ): { content: [{ type: "text"; text: string }]; details: null } {
365
- return {
366
- content: [
367
- {
368
- type: "text",
369
- text: `${buildSkippedTag({
370
- provider: "reddit",
371
- reason: "credential_not_provided",
372
- remediation,
373
- silenced,
374
- })}\n\n${message}`,
375
- },
376
- ],
377
- details: null,
378
- };
379
- }
380
-
381
- function classifyRedditSetupIssue(
382
- warnings: readonly string[],
383
- ): "not_installed" | "session_missing" | "session_stale" | null {
384
- const combined = warnings.join("\n").toLowerCase();
385
- if (combined.includes("not installed") || combined.includes("enoent")) {
386
- return "not_installed";
387
- }
388
- if (
389
- combined.includes("no reddit cookies") ||
390
- combined.includes("not authenticated") ||
391
- combined.includes("rdt login")
392
- ) {
393
- return "session_missing";
394
- }
395
- if (
396
- combined.includes("401") ||
397
- combined.includes("unauthorized") ||
398
- combined.includes("expired")
399
- ) {
400
- return "session_stale";
401
- }
402
- return null;
403
- }