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,237 +0,0 @@
1
- import { wrapProvider } from "../providers/wrap-provider.js";
2
- import { getQuote } from "../providers/yahoo-finance.js";
3
- import { isZeroFilledQuote } from "./resolve.js";
4
- import type { MarketStateService, ReportRunRecord, ReportTemplateRecord } from "./service.js";
5
-
6
- export interface DailyWatchlistReportSummary {
7
- watchlistId: number;
8
- symbols: string[];
9
- quoteCount: number;
10
- dataGapCount: number;
11
- }
12
-
13
- export interface DailyWatchlistReport {
14
- generatedAt: string;
15
- text: string;
16
- summary: DailyWatchlistReportSummary;
17
- dataGaps: string[];
18
- }
19
-
20
- // Returns the configured default-watchlist morning template if one exists.
21
- // Manual report runs must never create a schedule template as a side effect;
22
- // only the explicit configure flow stores schedule intent.
23
- export function findDefaultWatchlistReportTemplate(
24
- service: MarketStateService,
25
- ): ReportTemplateRecord | undefined {
26
- return service
27
- .listReportTemplates()
28
- .find(
29
- (template) =>
30
- template.reportType === "watchlist_daily" && targetsDefaultWatchlist(template.configJson),
31
- );
32
- }
33
-
34
- export async function recordDailyWatchlistReportRun(
35
- service: MarketStateService,
36
- params: {
37
- templateId?: number | null;
38
- triggerType: "manual" | "scheduled";
39
- scheduledFor?: string | null;
40
- ownerId?: string | null;
41
- },
42
- ): Promise<{ report: DailyWatchlistReport; run: ReportRunRecord }> {
43
- const report = await generateDailyWatchlistReport(service);
44
- const run = service.recordReportRun({
45
- templateId: params.templateId,
46
- startedAt: report.generatedAt,
47
- completedAt: new Date().toISOString(),
48
- status: "completed",
49
- triggerType: params.triggerType,
50
- scheduledFor: params.scheduledFor,
51
- ownerId: params.ownerId,
52
- summary: { ...report.summary, text: report.text },
53
- errors: report.dataGaps,
54
- });
55
- service.recordNotificationEvent({
56
- sourceType: "report_run",
57
- sourceId: run.id,
58
- severity: report.dataGaps.length > 0 ? "warning" : "info",
59
- title: "Daily watchlist report generated",
60
- body: `Generated ${report.summary.quoteCount} quote(s) with ${report.dataGaps.length} data gap(s).`,
61
- payload: report.summary,
62
- createdAt: run.completedAt ?? report.generatedAt,
63
- });
64
- return { report, run };
65
- }
66
-
67
- export async function generateDailyWatchlistReport(
68
- service: MarketStateService,
69
- ): Promise<DailyWatchlistReport> {
70
- const generatedAt = new Date().toISOString();
71
- const watchlist = service.getDefaultWatchlist();
72
- const items = service.listWatchlistItems(watchlist.id);
73
- const dataGaps: string[] = [];
74
-
75
- const quotes = await Promise.all(
76
- items.map(async (item) => {
77
- const result = await wrapProvider("yahoo", () => getQuote(item.symbol));
78
- if (result.status === "unavailable") {
79
- dataGaps.push(`${item.symbol}: ${result.reason}`);
80
- return null;
81
- }
82
- if (result.stale) {
83
- dataGaps.push(`${item.symbol}: provider returned stale market data`);
84
- return null;
85
- }
86
- if (isZeroFilledQuote(result.data)) {
87
- dataGaps.push(`${item.symbol}: Yahoo returned no valid market data.`);
88
- return null;
89
- }
90
- return { item, quote: result.data };
91
- }),
92
- );
93
-
94
- const validQuotes = quotes.filter((q) => q != null);
95
- const movers = [...validQuotes].sort(
96
- (a, b) => Math.abs(b.quote.changePercent) - Math.abs(a.quote.changePercent),
97
- );
98
- const freshnessLines =
99
- validQuotes.length === 0 ? [` No quote data available.`] : quoteFreshnessLines(validQuotes);
100
- const moverLines =
101
- movers.length === 0
102
- ? [` No movers available.`]
103
- : movers
104
- .slice(0, 5)
105
- .map(
106
- ({ item, quote }) =>
107
- ` ${item.symbol}: ${formatSigned(quote.changePercent)}% to $${quote.price.toFixed(2)}`,
108
- );
109
- const dataGapLines = dataGaps.length === 0 ? [` None.`] : dataGaps.map((gap) => ` ${gap}`);
110
-
111
- const lines = [
112
- `**Daily Watchlist Report**`,
113
- `Generated: ${generatedAt}`,
114
- `Target watchlist: ${watchlist.name}`,
115
- ``,
116
- `Quote freshness`,
117
- ...freshnessLines,
118
- ``,
119
- `Major movers`,
120
- ...moverLines,
121
- ``,
122
- `Recent alerts`,
123
- ` ${service.listAlertEvents().length} recorded alert event(s).`,
124
- ``,
125
- `Data gaps`,
126
- ...dataGapLines,
127
- ];
128
-
129
- return {
130
- generatedAt,
131
- text: lines.join("\n"),
132
- summary: {
133
- watchlistId: watchlist.id,
134
- symbols: items.map((item) => item.symbol),
135
- quoteCount: validQuotes.length,
136
- dataGapCount: dataGaps.length,
137
- },
138
- dataGaps,
139
- };
140
- }
141
-
142
- export function nextDailyReportRunAt(
143
- timezone: string,
144
- localTime: string,
145
- now = new Date(),
146
- ): string {
147
- const [hourPart, minutePart] = localTime.split(":");
148
- const hour = Number(hourPart);
149
- const minute = Number(minutePart);
150
- if (
151
- !Number.isInteger(hour) ||
152
- !Number.isInteger(minute) ||
153
- hour < 0 ||
154
- hour > 23 ||
155
- minute < 0 ||
156
- minute > 59
157
- ) {
158
- throw new Error(`Invalid report local_time: ${localTime}`);
159
- }
160
-
161
- const today = zonedDateParts(now, timezone);
162
- let candidate = zonedTimeToUtc(today, hour, minute, timezone);
163
- if (candidate.getTime() <= now.getTime()) {
164
- const tomorrow = new Date(Date.UTC(today.year, today.month - 1, today.day + 1, 12, 0, 0));
165
- candidate = zonedTimeToUtc(zonedDateParts(tomorrow, timezone), hour, minute, timezone);
166
- }
167
- return candidate.toISOString();
168
- }
169
-
170
- export function targetsDefaultWatchlist(config: unknown): boolean {
171
- if (typeof config !== "object" || config === null) return false;
172
- const targets = (config as { targets?: unknown }).targets;
173
- if (typeof targets !== "object" || targets === null) return false;
174
- return (targets as { default_watchlist?: unknown }).default_watchlist === true;
175
- }
176
-
177
- function quoteFreshnessLines(
178
- quotes: Array<{ item: { symbol: string }; quote: { timestamp: number; price: number } }>,
179
- ): string[] {
180
- return quotes.map(
181
- ({ item, quote }) =>
182
- ` ${item.symbol}: $${quote.price.toFixed(2)} as of ${new Date(quote.timestamp).toISOString()}`,
183
- );
184
- }
185
-
186
- function formatSigned(value: number): string {
187
- return `${value >= 0 ? "+" : ""}${value.toFixed(2)}`;
188
- }
189
-
190
- function zonedDateParts(
191
- date: Date,
192
- timezone: string,
193
- ): { year: number; month: number; day: number } {
194
- const parts = new Intl.DateTimeFormat("en-CA", {
195
- timeZone: timezone,
196
- year: "numeric",
197
- month: "2-digit",
198
- day: "2-digit",
199
- }).formatToParts(date);
200
- return {
201
- year: numberPart(parts, "year"),
202
- month: numberPart(parts, "month"),
203
- day: numberPart(parts, "day"),
204
- };
205
- }
206
-
207
- function zonedTimeToUtc(
208
- date: { year: number; month: number; day: number },
209
- hour: number,
210
- minute: number,
211
- timezone: string,
212
- ): Date {
213
- const naiveUtc = new Date(Date.UTC(date.year, date.month - 1, date.day, hour, minute, 0));
214
- const offsetMs = timeZoneOffsetMs(naiveUtc, timezone);
215
- return new Date(naiveUtc.getTime() - offsetMs);
216
- }
217
-
218
- function timeZoneOffsetMs(date: Date, timezone: string): number {
219
- const parts = new Intl.DateTimeFormat("en-US", {
220
- timeZone: timezone,
221
- timeZoneName: "shortOffset",
222
- hour: "2-digit",
223
- }).formatToParts(date);
224
- const value = parts.find((part) => part.type === "timeZoneName")?.value ?? "GMT";
225
- const match = /^GMT(?<sign>[+-])(?<hours>\d{1,2})(?::(?<minutes>\d{2}))?$/.exec(value);
226
- if (!match?.groups) return 0;
227
- const sign = match.groups.sign === "-" ? -1 : 1;
228
- const hours = Number(match.groups.hours);
229
- const minutes = Number(match.groups.minutes ?? "0");
230
- return sign * ((hours * 60 + minutes) * 60_000);
231
- }
232
-
233
- function numberPart(parts: Intl.DateTimeFormatPart[], type: Intl.DateTimeFormatPartTypes): number {
234
- const value = parts.find((part) => part.type === type)?.value;
235
- if (value == null) throw new Error(`Missing ${type} in formatted date`);
236
- return Number(value);
237
- }
@@ -1,162 +0,0 @@
1
- import type Database from "better-sqlite3";
2
- import {
3
- type AlertRunnerProviders,
4
- type AlertRunnerResult,
5
- defaultAlertRunnerProviders,
6
- runAlertChecks,
7
- } from "./alert-runner.js";
8
- import { nextDailyReportRunAt, recordDailyWatchlistReportRun } from "./daily-report.js";
9
- import { deliverPendingNotifications } from "./notification-delivery.js";
10
- import {
11
- type AutomationRunnerLeaseResult,
12
- MarketStateService,
13
- type ReportRunRecord,
14
- } from "./service.js";
15
-
16
- type DailyReportRunRecorder = typeof recordDailyWatchlistReportRun;
17
- type NotificationDeliverer = typeof deliverPendingNotifications;
18
-
19
- export interface LocalAutomationHeartbeatResult {
20
- lease: AutomationRunnerLeaseResult;
21
- alertCheck: AlertRunnerResult | null;
22
- reportRuns: ReportRunRecord[];
23
- }
24
-
25
- export async function runLocalAutomationHeartbeat(
26
- db: Database.Database,
27
- params: {
28
- ownerId: string;
29
- ownerKind: "writer" | "monitor";
30
- now?: string;
31
- ttlSeconds?: number;
32
- checkAlerts?: boolean;
33
- checkReports?: boolean;
34
- providers?: AlertRunnerProviders;
35
- recordDailyReportRun?: DailyReportRunRecorder;
36
- deliverNotifications?: NotificationDeliverer;
37
- releaseLeaseOnComplete?: boolean;
38
- },
39
- ): Promise<LocalAutomationHeartbeatResult> {
40
- const service = new MarketStateService(db);
41
- const now = params.now ?? new Date().toISOString();
42
- let acquiredLease = false;
43
- try {
44
- service.markStaleAutomationRunsLost({ now, graceSeconds: 300 });
45
- const hadActiveLease = service.getAutomationRunnerLease(now) != null;
46
- const lease = service.acquireAutomationRunnerLease({
47
- ownerId: params.ownerId,
48
- ownerKind: params.ownerKind,
49
- now,
50
- ttlSeconds: params.ttlSeconds ?? 90,
51
- });
52
- acquiredLease = lease.acquired;
53
-
54
- if (!lease.acquired) {
55
- return { lease, alertCheck: null, reportRuns: [] };
56
- }
57
-
58
- const reportRuns =
59
- params.checkReports === false
60
- ? []
61
- : await runDueReports(service, {
62
- ownerId: params.ownerId,
63
- now,
64
- recordDailyReportRun: params.recordDailyReportRun ?? recordDailyWatchlistReportRun,
65
- });
66
- if (params.checkAlerts === false || !hasDueAlertRules(service, now)) {
67
- await (params.deliverNotifications ?? deliverPendingNotifications)(service, { now });
68
- return { lease, alertCheck: null, reportRuns };
69
- }
70
-
71
- const alertCheck = await runAlertChecks(service, {
72
- ownerId: params.ownerId,
73
- triggerType: hadActiveLease ? "heartbeat" : "resume",
74
- now,
75
- providers: params.providers ?? defaultAlertRunnerProviders,
76
- });
77
- await (params.deliverNotifications ?? deliverPendingNotifications)(service, { now });
78
- return {
79
- lease,
80
- alertCheck,
81
- reportRuns,
82
- };
83
- } finally {
84
- if (params.releaseLeaseOnComplete && acquiredLease) {
85
- service.releaseAutomationRunnerLease(params.ownerId);
86
- }
87
- }
88
- }
89
-
90
- function hasDueAlertRules(service: MarketStateService, now: string): boolean {
91
- const nowMs = new Date(now).getTime();
92
- return service.listAlertRules().some((rule) => {
93
- if (!rule.enabled || rule.status !== "active") return false;
94
- if (rule.nextCheckAt == null) return true;
95
- return new Date(rule.nextCheckAt).getTime() <= nowMs;
96
- });
97
- }
98
-
99
- async function runDueReports(
100
- service: MarketStateService,
101
- params: { ownerId: string; now: string; recordDailyReportRun: DailyReportRunRecorder },
102
- ): Promise<ReportRunRecord[]> {
103
- const nowMs = new Date(params.now).getTime();
104
- const dueTemplates = service
105
- .listReportTemplates()
106
- .filter(
107
- (template) =>
108
- template.enabled &&
109
- template.reportType === "watchlist_daily" &&
110
- template.nextRunAt != null &&
111
- new Date(template.nextRunAt).getTime() <= nowMs,
112
- );
113
- const runs: ReportRunRecord[] = [];
114
- for (const template of dueTemplates) {
115
- const scheduledFor = template.nextRunAt;
116
- if (scheduledFor == null) continue;
117
- const nextRunAt = nextDailyReportRunAt(
118
- template.timezone,
119
- template.localTime,
120
- new Date(params.now),
121
- );
122
- const claimed = service.claimDueReportTemplateRun(template.id, {
123
- scheduledFor,
124
- nextRunAt,
125
- claimedAt: params.now,
126
- });
127
- if (claimed == null) continue;
128
- try {
129
- const { run } = await params.recordDailyReportRun(service, {
130
- templateId: template.id,
131
- triggerType: "scheduled",
132
- scheduledFor,
133
- ownerId: params.ownerId,
134
- });
135
- runs.push(run);
136
- } catch (error) {
137
- const message = error instanceof Error ? error.message : String(error);
138
- const failedRun = service.recordReportRun({
139
- templateId: template.id,
140
- startedAt: params.now,
141
- completedAt: new Date().toISOString(),
142
- status: "failed",
143
- triggerType: "scheduled",
144
- scheduledFor,
145
- ownerId: params.ownerId,
146
- errors: [message],
147
- });
148
- service.recordNotificationEvent({
149
- sourceType: "report_run",
150
- sourceId: failedRun.id,
151
- severity: "error",
152
- title: "Daily watchlist report failed",
153
- body: message,
154
- payload: { template_id: template.id, scheduled_for: scheduledFor },
155
- createdAt: failedRun.completedAt ?? params.now,
156
- });
157
- service.updateReportTemplate(template.id, { nextRunAt: scheduledFor });
158
- runs.push(failedRun);
159
- }
160
- }
161
- return runs;
162
- }
@@ -1,158 +0,0 @@
1
- import type { MarketStateService } from "./service.js";
2
-
3
- export interface NotificationDeliveryOptions {
4
- webhookUrl?: string | null;
5
- fetchImpl?: typeof fetch;
6
- now?: string;
7
- timeoutMs?: number;
8
- maxAttempts?: number;
9
- }
10
-
11
- export interface NotificationDeliveryResult {
12
- attempted: number;
13
- succeeded: number;
14
- failed: number;
15
- }
16
-
17
- export async function deliverPendingNotifications(
18
- service: MarketStateService,
19
- options: NotificationDeliveryOptions = {},
20
- ): Promise<NotificationDeliveryResult> {
21
- const webhookUrl = options.webhookUrl ?? process.env.OPENCANDLE_NOTIFICATION_WEBHOOK_URL ?? null;
22
- if (!webhookUrl) return { attempted: 0, succeeded: 0, failed: 0 };
23
-
24
- const now = options.now ?? new Date().toISOString();
25
- const timeoutMs = options.timeoutMs ?? 10_000;
26
- const maxAttempts = options.maxAttempts ?? 5;
27
- const fetchImpl = options.fetchImpl ?? globalThis.fetch;
28
- let attempted = 0;
29
- let succeeded = 0;
30
- let failed = 0;
31
-
32
- const attempts = service.listNotificationDeliveryAttempts();
33
- const deliveredWebhookIds = new Set(
34
- attempts
35
- .filter((attempt) => attempt.channel === "webhook" && attempt.status === "success")
36
- .map((attempt) => attempt.notificationEventId),
37
- );
38
- const lastWebhookAttemptAt = new Map<number, string>();
39
- for (const attempt of attempts) {
40
- if (attempt.channel !== "webhook" || attempt.status === "success") continue;
41
- const current = lastWebhookAttemptAt.get(attempt.notificationEventId);
42
- if (current == null || attempt.attemptedAt > current) {
43
- lastWebhookAttemptAt.set(attempt.notificationEventId, attempt.attemptedAt);
44
- }
45
- }
46
-
47
- const pendingNotifications = service
48
- .listNotificationEvents()
49
- .filter((notification) => !deliveredWebhookIds.has(notification.id))
50
- .sort((left, right) => {
51
- const leftAttempt = lastWebhookAttemptAt.get(left.id);
52
- const rightAttempt = lastWebhookAttemptAt.get(right.id);
53
- if (leftAttempt == null && rightAttempt != null) return -1;
54
- if (leftAttempt != null && rightAttempt == null) return 1;
55
- if (leftAttempt != null && rightAttempt != null && leftAttempt !== rightAttempt) {
56
- return leftAttempt.localeCompare(rightAttempt);
57
- }
58
- if (left.createdAt !== right.createdAt) return left.createdAt.localeCompare(right.createdAt);
59
- return left.id - right.id;
60
- });
61
-
62
- if (!isAllowedWebhookUrl(webhookUrl)) {
63
- const rejectedHost = webhookUrlHost(webhookUrl);
64
- console.warn(`Rejected notification webhook URL host: ${rejectedHost}`);
65
- const rejectedNotifications = pendingNotifications.slice(0, maxAttempts);
66
- const error = `Rejected notification webhook URL host: ${rejectedHost}`;
67
- for (const notification of rejectedNotifications) {
68
- service.recordNotificationDeliveryAttempt({
69
- notificationEventId: notification.id,
70
- channel: "webhook",
71
- status: "failed",
72
- attemptedAt: now,
73
- completedAt: now,
74
- error,
75
- });
76
- }
77
- const rejected = rejectedNotifications.length;
78
- return { attempted: rejected, succeeded: 0, failed: rejected };
79
- }
80
-
81
- for (const notification of pendingNotifications) {
82
- if (attempted >= maxAttempts) break;
83
- attempted++;
84
- const controller = new AbortController();
85
- const timeout = setTimeout(
86
- () => controller.abort(new Error(`Webhook delivery timed out after ${timeoutMs}ms`)),
87
- timeoutMs,
88
- );
89
- try {
90
- const response = await fetchImpl(webhookUrl, {
91
- method: "POST",
92
- headers: { "content-type": "application/json" },
93
- signal: controller.signal,
94
- body: JSON.stringify({
95
- id: notification.id,
96
- source_type: notification.sourceType,
97
- source_id: notification.sourceId,
98
- severity: notification.severity,
99
- title: notification.title,
100
- body: notification.body,
101
- payload: notification.payloadJson,
102
- status: notification.status,
103
- created_at: notification.createdAt,
104
- }),
105
- });
106
- if (!response.ok) throw new Error(`HTTP ${response.status}`);
107
- clearTimeout(timeout);
108
- service.recordNotificationDeliveryAttempt({
109
- notificationEventId: notification.id,
110
- channel: "webhook",
111
- status: "success",
112
- attemptedAt: now,
113
- completedAt: now,
114
- response: { status: response.status },
115
- });
116
- succeeded++;
117
- } catch (error) {
118
- clearTimeout(timeout);
119
- const message = controller.signal.aborted
120
- ? `Webhook delivery timed out after ${timeoutMs}ms`
121
- : error instanceof Error
122
- ? error.message
123
- : String(error);
124
- service.recordNotificationDeliveryAttempt({
125
- notificationEventId: notification.id,
126
- channel: "webhook",
127
- status: "failed",
128
- attemptedAt: now,
129
- completedAt: now,
130
- error: message,
131
- });
132
- failed++;
133
- }
134
- }
135
-
136
- return { attempted, succeeded, failed };
137
- }
138
-
139
- function isAllowedWebhookUrl(raw: string): boolean {
140
- let url: URL;
141
- try {
142
- url = new URL(raw);
143
- } catch {
144
- return false;
145
- }
146
- if (url.protocol !== "https:" && url.protocol !== "http:") return false;
147
- const host = url.hostname;
148
- if (host === "169.254.169.254" || host.startsWith("169.254.")) return false;
149
- return true;
150
- }
151
-
152
- function webhookUrlHost(raw: string): string {
153
- try {
154
- return new URL(raw).hostname || "(empty)";
155
- } catch {
156
- return "(invalid URL)";
157
- }
158
- }
@@ -1,24 +0,0 @@
1
- import { resolveYahooInstrument, searchYahooInstruments } from "./resolve.js";
2
-
3
- export type MutationInstrumentResolution =
4
- | { status: "resolved"; instrument: Awaited<ReturnType<typeof resolveYahooInstrument>> }
5
- | {
6
- status: "needs_selection";
7
- query: string;
8
- candidates: Awaited<ReturnType<typeof searchYahooInstruments>>;
9
- };
10
-
11
- export async function resolveInstrumentForMutation(
12
- symbol: string,
13
- ): Promise<MutationInstrumentResolution> {
14
- try {
15
- return { status: "resolved", instrument: await resolveYahooInstrument(symbol) };
16
- } catch (error) {
17
- const query = symbol.trim();
18
- const candidates = await searchYahooInstruments(query);
19
- if (candidates.length > 0) {
20
- return { status: "needs_selection", query, candidates };
21
- }
22
- throw error;
23
- }
24
- }
@@ -1,112 +0,0 @@
1
- import { cache, TTL } from "../infra/cache.js";
2
- import { httpGet } from "../infra/http-client.js";
3
- import { rateLimiter } from "../infra/rate-limiter.js";
4
- import { wrapProvider } from "../providers/wrap-provider.js";
5
- import { getQuote } from "../providers/yahoo-finance.js";
6
- import type { StockQuote } from "../types/market.js";
7
- import type { InstrumentInput } from "./service.js";
8
-
9
- export interface InstrumentCandidate {
10
- symbol: string;
11
- name: string | null;
12
- quoteType: string;
13
- assetType: string;
14
- exchange: string | null;
15
- provider: "yahoo";
16
- score: number | null;
17
- }
18
-
19
- interface YahooSearchResponse {
20
- quotes?: Array<{
21
- symbol?: string;
22
- shortname?: string;
23
- longname?: string;
24
- quoteType?: string;
25
- exchange?: string;
26
- score?: number;
27
- }>;
28
- }
29
-
30
- export async function searchYahooInstruments(query: string): Promise<InstrumentCandidate[]> {
31
- const trimmed = query.trim();
32
- if (!trimmed) return [];
33
-
34
- const cacheKey = `yahoo:instrument-search:${trimmed.toLowerCase()}`;
35
- const cached = cache.get<InstrumentCandidate[]>(cacheKey);
36
- if (cached) return cached;
37
-
38
- const url = `https://query1.finance.yahoo.com/v1/finance/search?q=${encodeURIComponent(trimmed)}&quotesCount=10&newsCount=0`;
39
- await rateLimiter.acquire("yahoo");
40
- const data = await httpGet<YahooSearchResponse>(url, {
41
- headers: { "User-Agent": "OpenCandle/1.0" },
42
- });
43
-
44
- const candidates = (data.quotes ?? []).flatMap((quote) => {
45
- if (!quote.symbol) return [];
46
- const quoteType = quote.quoteType ?? "UNKNOWN";
47
- return [
48
- {
49
- symbol: quote.symbol.toUpperCase(),
50
- name: quote.longname ?? quote.shortname ?? null,
51
- quoteType,
52
- assetType: assetTypeFromQuoteType(quoteType, quote.symbol),
53
- exchange: quote.exchange ?? null,
54
- provider: "yahoo" as const,
55
- score: quote.score ?? null,
56
- },
57
- ];
58
- });
59
- cache.set(cacheKey, candidates, TTL.WEB_SEARCH);
60
- return candidates;
61
- }
62
-
63
- export async function resolveYahooInstrument(symbol: string): Promise<InstrumentInput> {
64
- const normalized = symbol.trim().toUpperCase();
65
- if (!normalized) {
66
- throw new Error("symbol is required.");
67
- }
68
-
69
- const result = await wrapProvider("yahoo", () => getQuote(normalized));
70
- if (result.status === "unavailable") {
71
- throw new Error(`Could not resolve ${normalized}: ${result.reason}`);
72
- }
73
-
74
- const quote = result.data;
75
- if (isZeroFilledQuote(quote)) {
76
- throw new Error(`Could not resolve ${normalized}: Yahoo returned no valid market data.`);
77
- }
78
-
79
- return {
80
- symbol: quote.symbol?.toUpperCase() ?? normalized,
81
- assetType: inferAssetType(quote.symbol ?? normalized),
82
- currency: quote.currency?.trim().toUpperCase() || null,
83
- provider: "yahoo",
84
- providerMetadata: {
85
- price: quote.price,
86
- volume: quote.volume,
87
- week52High: quote.week52High,
88
- week52Low: quote.week52Low,
89
- timestamp: quote.timestamp,
90
- },
91
- };
92
- }
93
-
94
- export function isZeroFilledQuote(quote: StockQuote): boolean {
95
- return quote.price === 0 && quote.volume === 0 && quote.week52High === 0 && quote.week52Low === 0;
96
- }
97
-
98
- function inferAssetType(symbol: string): string {
99
- if (symbol.endsWith("-USD")) return "crypto";
100
- if (symbol.startsWith("^")) return "index";
101
- return "equity";
102
- }
103
-
104
- function assetTypeFromQuoteType(quoteType: string, symbol: string): string {
105
- const normalized = quoteType.toLowerCase();
106
- if (normalized.includes("etf")) return "etf";
107
- if (normalized.includes("mutualfund")) return "fund";
108
- if (normalized.includes("crypto")) return "crypto";
109
- if (normalized.includes("index")) return "index";
110
- if (normalized.includes("equity")) return "equity";
111
- return inferAssetType(symbol.toUpperCase());
112
- }