import { definePlugin, defineView } from '@jaspers-ai/sdk' import { z } from 'zod' import { barSources } from './stocks-bars' import { snapSources } from './stocks-snap' import { tickSources } from './ticks' import { referenceSources } from './reference' import { news } from './news' import { financials } from './financials' import { optionSources } from './options' import { globalSources } from './global' import { indicator } from './indicators' import { selfCheck } from './selfcheck' import { NewsView } from './NewsView' import { PriceView } from './PriceView' import { WatchlistView } from './WatchlistView' import { ChainView } from './ChainView' const sources = { ...barSources, ...snapSources, ...tickSources, ...referenceSources, news, financials, ...optionSources, ...globalSources, indicator, 'self-check': selfCheck, } export default definePlugin({ id: 'massive', secrets: { apikey: { label: 'Massive (Polygon.io) API key' } }, sources, views: { watchlist: defineView(WatchlistView, { title: 'Massive watchlist', state: z.object({ tickers: z.array(z.string()).max(100).default(['AAPL', 'MSFT', 'NVDA']).describe('Stock tickers to show.'), }), output: z.object({ tickers: z.array(z.string()), count: z.number(), error: z.string().nullable() }), instructions: 'A snapshot table of stocks: last, change, change %, volume. Set state.tickers to the tickers; the user refreshes it with its button.', renders: [snapSources.snapshot], summarize: (state, output) => `Watchlist: ${output.count} of ${state.tickers?.length ?? 0} tickers`, }), chart: defineView(PriceView, { title: 'Massive price chart', state: z.object({ ticker: z.string().default('AAPL').describe('Any ticker: AAPL, O:..., I:SPX, C:EURUSD, X:BTCUSD.'), multiplier: z.number().int().min(1).default(1).describe('Timespans per bar.'), timespan: z.enum(['minute', 'hour', 'day', 'week', 'month', 'quarter', 'year']).default('day').describe('Bar size.'), from: z.string().optional().describe('Start date YYYY-MM-DD. Defaults to six months ago.'), to: z.string().optional().describe('End date YYYY-MM-DD. Defaults to today.'), style: z.enum(['candles', 'line']).default('candles').describe('Candlesticks or a close line.'), }), output: z.object({ ticker: z.string(), bars: z.number(), first: z.string().nullable(), last: z.string().nullable(), close: z.number().nullable(), error: z.string().nullable() }), instructions: 'A candlestick or line chart with volume bars from Massive aggregates. Set state.ticker, and optionally multiplier, timespan, from, to, style.', renders: [barSources.aggregates], summarize: (state, output) => `${state.ticker ?? 'AAPL'} chart: ${output.bars} bars, last close ${output.close ?? '–'}`, }), chain: defineView(ChainView, { title: 'Massive option chain', state: z.object({ underlying: z.string().default('SPY').describe('The underlying ticker.'), expiration: z.string().optional().describe('Expiration YYYY-MM-DD. Defaults to the nearest one.'), strike_min: z.number().optional().describe('Lowest strike shown.'), strike_max: z.number().optional().describe('Highest strike shown.'), }), output: z.object({ underlying: z.string(), expiration: z.string().nullable(), strikes: z.number(), underlyingPrice: z.number().nullable(), error: z.string().nullable() }), instructions: 'Calls and puts side by side by strike for one underlying and expiration. Set state.underlying, state.expiration, and a strike range.', renders: [optionSources['option-chain']], summarize: (state, output) => `${state.underlying ?? 'SPY'} chain ${output.expiration ?? ''}: ${output.strikes} strikes`, }), news: defineView(NewsView, { title: 'Massive news', state: z.object({ tickers: z.array(z.string()).max(20).default(['AAPL']).describe('Tickers whose news to list.'), limit: z.number().int().min(1).max(200).default(50).describe('How many articles.'), }), output: z.object({ tickers: z.array(z.string()), count: z.number(), latest: z.string().nullable(), error: z.string().nullable() }), instructions: 'Ticker news from Massive, newest first, with publisher, time, link, summary, and sentiment. Set state.tickers and state.limit.', renders: [news], summarize: (state, output) => `News for ${(state.tickers ?? []).join(', ')}: ${output.count} articles`, }), }, })