@ethosagent/tools-india-broker-zerodha 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +3 -0
- package/LICENSE +21 -0
- package/README.md +135 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +735 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +74 -0
- package/dist/index.js +850 -0
- package/dist/index.js.map +1 -0
- package/dist/panel.d.ts +24 -0
- package/dist/panel.js +394 -0
- package/dist/panel.js.map +1 -0
- package/package.json +116 -0
- package/skills/portfolio_review.md +30 -0
- package/skills/position_sizing.md +4 -0
- package/skills/trade_confirmation.md +36 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/auth.ts","../src/store.ts","../src/schema.ts","../src/tools.ts","../src/kite-client.ts"],"sourcesContent":["import { createHash } from 'node:crypto';\n\nconst KITE_SESSION_URL = 'https://api.kite.trade/session/token';\n\nexport interface TokenExchangeResult {\n access_token: string;\n refresh_token: string;\n user_id: string;\n login_time: string;\n}\n\n// Step 1: Generate the login URL for the user to open in browser\nexport function buildLoginUrl(apiKey: string): string {\n return `https://kite.trade/connect/login?v=3&api_key=${apiKey}`;\n}\n\n// Step 2: Compute checksum for request_token exchange\n// checksum = sha256(api_key + request_token + api_secret)\nexport function computeChecksum(apiKey: string, requestToken: string, apiSecret: string): string {\n return createHash('sha256')\n .update(apiKey + requestToken + apiSecret)\n .digest('hex');\n}\n\n// Step 3: Exchange request_token for access_token\nexport async function exchangeToken(\n apiKey: string,\n apiSecret: string,\n requestToken: string\n): Promise<TokenExchangeResult> {\n const checksum = computeChecksum(apiKey, requestToken, apiSecret);\n\n const body = new URLSearchParams();\n body.set('api_key', apiKey);\n body.set('request_token', requestToken);\n body.set('checksum', checksum);\n\n const res = await fetch(KITE_SESSION_URL, {\n method: 'POST',\n headers: { 'Content-Type': 'application/x-www-form-urlencoded' },\n body: body.toString(),\n });\n\n const json = (await res.json()) as {\n status: string;\n data: TokenExchangeResult;\n message?: string;\n };\n\n if (json.status !== 'success') {\n throw new Error(`Token exchange failed: ${json.message ?? 'unknown error'}`);\n }\n\n return json.data;\n}\n\n// Validate that current access token is still alive\nexport async function validateToken(\n apiKey: string,\n accessToken: string\n): Promise<{ valid: boolean; userId?: string; expiresHint?: string }> {\n try {\n const res = await fetch('https://api.kite.trade/user/profile', {\n method: 'GET',\n headers: {\n Authorization: `token ${apiKey}:${accessToken}`,\n 'X-Kite-Version': '3',\n },\n });\n\n if (res.status === 403) {\n return { valid: false, expiresHint: 'Token expired' };\n }\n\n const json = (await res.json()) as {\n status: string;\n data?: { user_id: string };\n error_type?: string;\n };\n\n if (json.error_type === 'TokenException') {\n return { valid: false, expiresHint: 'Token expired' };\n }\n\n if (json.status === 'success' && json.data) {\n return {\n valid: true,\n userId: json.data.user_id,\n expiresHint: 'tonight at midnight IST',\n };\n }\n\n return { valid: false, expiresHint: 'Unknown validation error' };\n } catch {\n return { valid: false, expiresHint: 'Network error during validation' };\n }\n}\n","import Database from 'better-sqlite3';\nimport { migrate } from './schema';\n\nexport interface HoldingRow {\n symbol: string;\n exchange: string;\n isin: string | null;\n quantity: number;\n t1Quantity: number;\n avgPrice: number;\n ltp: number | null;\n pnl: number | null;\n pnlPct: number | null;\n dayChange: number | null;\n product: string;\n refreshedAt: number;\n}\n\nexport interface OrderLogRow {\n id: string;\n createdAt: number;\n symbol: string;\n exchange: string;\n transaction: 'BUY' | 'SELL';\n quantity: number;\n orderType: string;\n price: number | null;\n product: string;\n dryRun: boolean;\n kiteOrderId: string | null;\n status: string;\n rejectionReason: string | null;\n agentSession: string | null;\n}\n\nexport const TTL = {\n HOLDINGS: 60 * 60 * 1000, // 1 hour\n} as const;\n\nexport class ZerodhaStore {\n private db: Database.Database;\n\n constructor(dbPath: string) {\n this.db = new Database(dbPath);\n migrate(this.db);\n }\n\n close(): void {\n this.db.close();\n }\n\n // -- Holdings cache --------------------------------------------------------\n\n replaceHoldings(holdings: HoldingRow[]): void {\n const now = Date.now();\n const tx = this.db.transaction(() => {\n this.db.prepare('DELETE FROM holdings_cache').run();\n const stmt = this.db.prepare(`\n INSERT INTO holdings_cache\n (symbol, exchange, isin, quantity, t1_quantity, avg_price, ltp, pnl, pnl_pct, day_change, product, refreshed_at)\n VALUES\n (@symbol, @exchange, @isin, @quantity, @t1Quantity, @avgPrice, @ltp, @pnl, @pnlPct, @dayChange, @product, @refreshedAt)\n `);\n for (const h of holdings) {\n stmt.run({\n symbol: h.symbol,\n exchange: h.exchange,\n isin: h.isin,\n quantity: h.quantity,\n t1Quantity: h.t1Quantity,\n avgPrice: h.avgPrice,\n ltp: h.ltp,\n pnl: h.pnl,\n pnlPct: h.pnlPct,\n dayChange: h.dayChange,\n product: h.product,\n refreshedAt: h.refreshedAt,\n });\n }\n this.db\n .prepare('INSERT OR REPLACE INTO sync_meta (key, fetched_at, status) VALUES (?, ?, ?)')\n .run('holdings', now, 'ok');\n });\n tx();\n }\n\n getHoldings(): HoldingRow[] {\n const rows = this.db.prepare('SELECT * FROM holdings_cache').all() as Array<{\n symbol: string;\n exchange: string;\n isin: string | null;\n quantity: number;\n t1_quantity: number;\n avg_price: number;\n ltp: number | null;\n pnl: number | null;\n pnl_pct: number | null;\n day_change: number | null;\n product: string;\n refreshed_at: number;\n }>;\n return rows.map((r) => ({\n symbol: r.symbol,\n exchange: r.exchange,\n isin: r.isin,\n quantity: r.quantity,\n t1Quantity: r.t1_quantity,\n avgPrice: r.avg_price,\n ltp: r.ltp,\n pnl: r.pnl,\n pnlPct: r.pnl_pct,\n dayChange: r.day_change,\n product: r.product,\n refreshedAt: r.refreshed_at,\n }));\n }\n\n isStale(key: string, ttlMs: number): boolean {\n const row = this.db.prepare('SELECT fetched_at FROM sync_meta WHERE key = ?').get(key) as\n | { fetched_at: number }\n | undefined;\n if (!row) return true;\n return Date.now() - row.fetched_at > ttlMs;\n }\n\n getLastFetchedAt(key: string): number {\n const row = this.db.prepare('SELECT fetched_at FROM sync_meta WHERE key = ?').get(key) as\n | { fetched_at: number }\n | undefined;\n return row?.fetched_at ?? 0;\n }\n\n setSyncMeta(key: string, status = 'ok'): void {\n this.db\n .prepare('INSERT OR REPLACE INTO sync_meta (key, fetched_at, status) VALUES (?, ?, ?)')\n .run(key, Date.now(), status);\n }\n\n // -- Order audit log -------------------------------------------------------\n\n logOrder(row: OrderLogRow): void {\n this.db\n .prepare(\n `INSERT INTO order_log\n (id, created_at, symbol, exchange, transaction_type, quantity, order_type, price, product, dry_run, kite_order_id, status, rejection_reason, agent_session)\n VALUES\n (@id, @createdAt, @symbol, @exchange, @transactionType, @quantity, @orderType, @price, @product, @dryRun, @kiteOrderId, @status, @rejectionReason, @agentSession)`\n )\n .run({\n id: row.id,\n createdAt: row.createdAt,\n symbol: row.symbol,\n exchange: row.exchange,\n transactionType: row.transaction,\n quantity: row.quantity,\n orderType: row.orderType,\n price: row.price,\n product: row.product,\n dryRun: row.dryRun ? 1 : 0,\n kiteOrderId: row.kiteOrderId,\n status: row.status,\n rejectionReason: row.rejectionReason,\n agentSession: row.agentSession,\n });\n }\n\n getOrderLog(limit = 50): OrderLogRow[] {\n const rows = this.db\n .prepare('SELECT * FROM order_log ORDER BY created_at DESC LIMIT ?')\n .all(limit) as Array<{\n id: string;\n created_at: number;\n symbol: string;\n exchange: string;\n transaction_type: 'BUY' | 'SELL';\n quantity: number;\n order_type: string;\n price: number | null;\n product: string;\n dry_run: number;\n kite_order_id: string | null;\n status: string;\n rejection_reason: string | null;\n agent_session: string | null;\n }>;\n return rows.map((r) => ({\n id: r.id,\n createdAt: r.created_at,\n symbol: r.symbol,\n exchange: r.exchange,\n transaction: r.transaction_type,\n quantity: r.quantity,\n orderType: r.order_type,\n price: r.price,\n product: r.product,\n dryRun: r.dry_run === 1,\n kiteOrderId: r.kite_order_id,\n status: r.status,\n rejectionReason: r.rejection_reason,\n agentSession: r.agent_session,\n }));\n }\n\n clean(): { tablesCleared: string[] } {\n this.db.prepare('DELETE FROM holdings_cache').run();\n this.db.prepare('DELETE FROM order_log').run();\n this.db.prepare('DELETE FROM sync_meta').run();\n return { tablesCleared: ['holdings_cache', 'order_log', 'sync_meta'] };\n }\n}\n","import type Database from 'better-sqlite3';\n\n// -- Holdings snapshot -------------------------------------------------------\n// One row per symbol. Overwritten on each holdings refresh.\n// Purpose: lets agents query holdings without a live API call.\nexport const SQL_CREATE_HOLDINGS_CACHE = `\n CREATE TABLE IF NOT EXISTS holdings_cache (\n symbol TEXT PRIMARY KEY,\n exchange TEXT NOT NULL,\n isin TEXT,\n quantity INTEGER NOT NULL,\n t1_quantity INTEGER NOT NULL DEFAULT 0,\n avg_price REAL NOT NULL,\n ltp REAL,\n pnl REAL,\n pnl_pct REAL,\n day_change REAL,\n product TEXT NOT NULL,\n refreshed_at INTEGER NOT NULL\n ) STRICT;\n`;\n\n// -- Order audit log ---------------------------------------------------------\n// Every order the agent proposes or places, with outcome.\nexport const SQL_CREATE_ORDER_LOG = `\n CREATE TABLE IF NOT EXISTS order_log (\n id TEXT PRIMARY KEY,\n created_at INTEGER NOT NULL,\n symbol TEXT NOT NULL,\n exchange TEXT NOT NULL,\n transaction_type TEXT NOT NULL,\n quantity INTEGER NOT NULL,\n order_type TEXT NOT NULL,\n price REAL,\n product TEXT NOT NULL,\n dry_run INTEGER NOT NULL,\n kite_order_id TEXT,\n status TEXT NOT NULL,\n rejection_reason TEXT,\n agent_session TEXT\n ) STRICT;\n`;\n\n// -- Sync meta ---------------------------------------------------------------\nexport const SQL_CREATE_SYNC_META = `\n CREATE TABLE IF NOT EXISTS sync_meta (\n key TEXT PRIMARY KEY,\n fetched_at INTEGER NOT NULL,\n status TEXT NOT NULL DEFAULT 'ok'\n ) STRICT;\n`;\n\nexport function migrate(db: Database.Database): void {\n db.pragma('journal_mode = WAL');\n db.pragma('foreign_keys = ON');\n db.exec(SQL_CREATE_HOLDINGS_CACHE);\n db.exec(SQL_CREATE_ORDER_LOG);\n db.exec(SQL_CREATE_SYNC_META);\n}\n","import { randomUUID } from 'node:crypto';\nimport { mkdirSync, writeFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport type {\n EthosPlugin,\n EthosPluginApi,\n Tool,\n ToolContext,\n ToolResult,\n} from '@ethosagent/plugin-sdk';\nimport { defineTool, err, ok } from '@ethosagent/plugin-sdk/tool-helpers';\nimport { buildLoginUrl, exchangeToken, validateToken } from './auth';\nimport type { KiteHolding } from './kite-client';\nimport {\n fetchHoldings,\n fetchMargins,\n fetchOrders,\n fetchPositions,\n KiteTokenExpiredError,\n placeOrder,\n} from './kite-client';\nimport type { HoldingRow } from './store';\nimport { TTL, ZerodhaStore } from './store';\n\n// -- Helpers -----------------------------------------------------------------\n\nasync function getCredentials(\n ctx: ToolContext\n): Promise<{ apiKey: string; accessToken: string } | ToolResult> {\n const apiKey = await ctx.secretsResolver?.get('brokers/zerodha/apiKey');\n const accessToken = await ctx.secretsResolver?.get('brokers/zerodha/accessToken');\n\n if (!apiKey || !accessToken) {\n return err(\n 'Zerodha credentials not configured. Store api_key and access_token in ~/.ethos/secrets/brokers/zerodha/',\n 'not_available'\n );\n }\n\n return { apiKey, accessToken };\n}\n\nfunction isToolResult(v: unknown): v is ToolResult {\n return typeof v === 'object' && v !== null && 'ok' in v;\n}\n\nfunction tokenExpiredResult(apiKey?: string): ToolResult {\n const loginUrl = apiKey ? buildLoginUrl(apiKey) : 'https://kite.trade/connect/login?v=3';\n return err(\n `Token expired. Renew daily access token:\\n1. Open ${loginUrl}\\n2. Log in and copy request_token from redirect URL\\n3. Run: zerodha-broker auth --request-token TOKEN`,\n 'not_available'\n );\n}\n\nfunction kiteHoldingToRow(h: KiteHolding, now: number): HoldingRow {\n return {\n symbol: h.tradingsymbol,\n exchange: h.exchange,\n isin: h.isin,\n quantity: h.quantity,\n t1Quantity: h.t1_quantity,\n avgPrice: h.average_price,\n ltp: h.last_price,\n pnl: h.pnl,\n pnlPct:\n h.average_price > 0\n ? Number(((h.pnl / (h.quantity * h.average_price)) * 100).toFixed(2))\n : null,\n dayChange: h.day_change_percentage,\n product: h.product,\n refreshedAt: now,\n };\n}\n\n// -- Default store path ------------------------------------------------------\n\nfunction defaultDbPath(): string {\n const home = process.env.HOME ?? process.env.USERPROFILE ?? '/tmp';\n return process.env.ZERODHA_DB ?? `${home}/.ethos/zerodha/zerodha.db`;\n}\n\n// -- Tool definitions --------------------------------------------------------\n\ninterface AuthStatusArgs {\n [key: string]: unknown;\n}\n\nconst zerodhaAuthStatus: Tool<AuthStatusArgs> = defineTool<AuthStatusArgs>({\n name: 'zerodha_auth_status',\n description: `Check if the Zerodha access token is valid and the account is ready for API calls.\nAlways call this first in a session before reading portfolio data.\nReturns whether token is valid, expiry estimate, and account user_id.\nIf token is expired, returns instructions for renewal.`,\n toolset: 'broker',\n maxResultChars: 1000,\n capabilities: {\n network: { allowedHosts: ['api.kite.trade'] },\n secrets: ['brokers/zerodha/apiKey', 'brokers/zerodha/accessToken'],\n },\n schema: { type: 'object', properties: {} },\n\n async execute(_args: AuthStatusArgs, ctx: ToolContext): Promise<ToolResult> {\n try {\n const creds = await getCredentials(ctx);\n if (isToolResult(creds)) return creds;\n\n const result = await validateToken(creds.apiKey, creds.accessToken);\n\n if (result.valid) {\n return ok(\n JSON.stringify({\n valid: true,\n user_id: result.userId,\n expires_hint: result.expiresHint,\n warning: null,\n })\n );\n }\n\n return tokenExpiredResult(creds.apiKey);\n } catch (e) {\n if (e instanceof KiteTokenExpiredError) {\n return tokenExpiredResult();\n }\n return err(e instanceof Error ? e.message : String(e));\n }\n },\n});\n\ninterface AuthCompleteArgs {\n request_token: string;\n}\n\nconst zerodhaAuthComplete: Tool<AuthCompleteArgs> = defineTool<AuthCompleteArgs>({\n name: 'zerodha_auth_complete',\n description: `Complete daily Zerodha authentication by exchanging a request_token for an access_token.\nCall this after the user has opened the Zerodha login URL and been redirected back with a request_token.\nThe request_token appears in the redirect URL as ?request_token=YYY.\nExchanges it for a fresh access_token and stores it in ~/.ethos/secrets/brokers/zerodha/accessToken.\nThe new token is valid until midnight IST.`,\n toolset: 'broker',\n maxResultChars: 500,\n capabilities: {\n network: { allowedHosts: ['api.kite.trade'] },\n secrets: ['brokers/zerodha/apiKey', 'brokers/zerodha/apiSecret'],\n },\n schema: {\n type: 'object',\n properties: {\n request_token: {\n type: 'string',\n description: 'The request_token from Zerodha redirect URL after login',\n },\n },\n required: ['request_token'],\n },\n\n async execute(args: AuthCompleteArgs, ctx: ToolContext): Promise<ToolResult> {\n try {\n const apiKey = await ctx.secretsResolver?.get('brokers/zerodha/apiKey');\n const apiSecret = await ctx.secretsResolver?.get('brokers/zerodha/apiSecret');\n\n if (!apiKey || !apiSecret) {\n return err(\n 'Zerodha credentials not configured. Store apiKey and apiSecret in ~/.ethos/secrets/brokers/zerodha/',\n 'not_available'\n );\n }\n\n const result = await exchangeToken(apiKey, apiSecret, args.request_token);\n\n const ethosDir =\n process.env.ETHOS_DATA_DIR ??\n join(process.env.HOME ?? process.env.USERPROFILE ?? '/tmp', '.ethos');\n const tokenPath = join(ethosDir, 'secrets', 'brokers', 'zerodha', 'accessToken');\n mkdirSync(dirname(tokenPath), { recursive: true });\n writeFileSync(tokenPath, result.access_token, { mode: 0o600 });\n\n return ok(\n JSON.stringify({\n authenticated: true,\n user_id: result.user_id,\n message: 'Token valid until midnight IST.',\n })\n );\n } catch (e) {\n return err(e instanceof Error ? e.message : String(e));\n }\n },\n});\n\ninterface AccountArgs {\n [key: string]: unknown;\n}\n\nconst zerodhaAccount: Tool<AccountArgs> = defineTool<AccountArgs>({\n name: 'zerodha_account',\n description: `Zerodha account summary — available funds and margin utilisation.\nReturns net available cash, used margin, unrealised M2M, and option premium blocked.\nAll values in INR. Live from Kite API.`,\n toolset: 'broker',\n maxResultChars: 2000,\n capabilities: {\n network: { allowedHosts: ['api.kite.trade'] },\n secrets: ['brokers/zerodha/apiKey', 'brokers/zerodha/accessToken'],\n },\n schema: { type: 'object', properties: {} },\n\n async execute(_args: AccountArgs, ctx: ToolContext): Promise<ToolResult> {\n try {\n const creds = await getCredentials(ctx);\n if (isToolResult(creds)) return creds;\n\n const margins = await fetchMargins(creds);\n const eq = margins.equity;\n\n return ok(\n JSON.stringify({\n net_available_inr: eq.net,\n opening_balance_inr: eq.available.opening_balance,\n m2m_unrealised_inr: eq.utilised.m2m_unrealised,\n exposure_used_inr: eq.utilised.exposure,\n option_premium_blocked_inr: eq.utilised.option_premium,\n equity_enabled: eq.enabled,\n })\n );\n } catch (e) {\n if (e instanceof KiteTokenExpiredError) {\n return tokenExpiredResult();\n }\n return err(e instanceof Error ? e.message : String(e));\n }\n },\n});\n\ninterface HoldingsArgs {\n [key: string]: unknown;\n force_refresh?: boolean;\n}\n\nconst zerodhaHoldings: Tool<HoldingsArgs> = defineTool<HoldingsArgs>({\n name: 'zerodha_holdings',\n description: `Equity holdings (long-term CNC positions) with P&L.\nReturns all stocks held in Zerodha DEMAT — symbol, quantity, average cost, current price,\nunrealised P&L, and day change. Refreshes cache if >1 hour stale. Values in INR.`,\n toolset: 'broker',\n maxResultChars: 8000,\n capabilities: {\n network: { allowedHosts: ['api.kite.trade'] },\n secrets: ['brokers/zerodha/apiKey', 'brokers/zerodha/accessToken'],\n },\n schema: {\n type: 'object',\n properties: {\n force_refresh: {\n type: 'boolean',\n description: 'Force live fetch bypassing 1h cache (default false)',\n },\n },\n },\n\n async execute(args: HoldingsArgs, ctx: ToolContext): Promise<ToolResult> {\n try {\n const creds = await getCredentials(ctx);\n if (isToolResult(creds)) return creds;\n\n const store = new ZerodhaStore(defaultDbPath());\n try {\n const forceRefresh = args.force_refresh ?? false;\n const stale = store.isStale('holdings', TTL.HOLDINGS);\n\n if (forceRefresh || stale) {\n const kiteHoldings = await fetchHoldings(creds);\n const now = Date.now();\n const rows = kiteHoldings.map((h) => kiteHoldingToRow(h, now));\n store.replaceHoldings(rows);\n }\n\n const holdings = store.getHoldings();\n const totalInvested = holdings.reduce((s, h) => s + h.quantity * h.avgPrice, 0);\n const totalCurrent = holdings.reduce((s, h) => s + h.quantity * (h.ltp ?? h.avgPrice), 0);\n const totalPnl = totalCurrent - totalInvested;\n const totalPnlPct = totalInvested > 0 ? (totalPnl / totalInvested) * 100 : 0;\n\n return ok(\n JSON.stringify({\n refreshed_at: new Date(store.getLastFetchedAt('holdings') || Date.now()).toISOString(),\n count: holdings.length,\n total_invested_inr: Number(totalInvested.toFixed(2)),\n total_current_inr: Number(totalCurrent.toFixed(2)),\n total_pnl_inr: Number(totalPnl.toFixed(2)),\n total_pnl_pct: Number(totalPnlPct.toFixed(2)),\n holdings: holdings.map((h) => ({\n symbol: h.symbol,\n exchange: h.exchange,\n quantity: h.quantity,\n avg_price: h.avgPrice,\n ltp: h.ltp,\n pnl_inr: h.pnl,\n pnl_pct: h.pnlPct,\n day_change_pct: h.dayChange,\n })),\n })\n );\n } finally {\n store.close();\n }\n } catch (e) {\n if (e instanceof KiteTokenExpiredError) {\n return tokenExpiredResult();\n }\n return err(e instanceof Error ? e.message : String(e));\n }\n },\n});\n\ninterface PositionsArgs {\n [key: string]: unknown;\n}\n\nconst zerodhaPositions: Tool<PositionsArgs> = defineTool<PositionsArgs>({\n name: 'zerodha_positions',\n description: `Open intraday and overnight positions with real-time P&L.\nReturns both day (MIS — intraday) and net (NRML/CNC — overnight carry) positions.\nIf no open positions, returns an empty list. Values in INR. Always live from Kite API.`,\n toolset: 'broker',\n maxResultChars: 6000,\n capabilities: {\n network: { allowedHosts: ['api.kite.trade'] },\n secrets: ['brokers/zerodha/apiKey', 'brokers/zerodha/accessToken'],\n },\n schema: { type: 'object', properties: {} },\n\n async execute(_args: PositionsArgs, ctx: ToolContext): Promise<ToolResult> {\n try {\n const creds = await getCredentials(ctx);\n if (isToolResult(creds)) return creds;\n\n const positions = await fetchPositions(creds);\n\n const dayPnl = positions.day.reduce((s, p) => s + p.pnl, 0);\n\n return ok(\n JSON.stringify({\n day_positions: positions.day.map((p) => ({\n symbol: p.tradingsymbol,\n exchange: p.exchange,\n product: p.product,\n quantity: p.quantity,\n avg_price: p.average_price,\n ltp: p.last_price,\n pnl_inr: p.pnl,\n unrealised_inr: p.unrealised,\n })),\n net_positions: positions.net.map((p) => ({\n symbol: p.tradingsymbol,\n exchange: p.exchange,\n product: p.product,\n quantity: p.quantity,\n avg_price: p.average_price,\n ltp: p.last_price,\n pnl_inr: p.pnl,\n unrealised_inr: p.unrealised,\n })),\n total_day_pnl_inr: Number(dayPnl.toFixed(2)),\n })\n );\n } catch (e) {\n if (e instanceof KiteTokenExpiredError) {\n return tokenExpiredResult();\n }\n return err(e instanceof Error ? e.message : String(e));\n }\n },\n});\n\ninterface OrdersArgs {\n [key: string]: unknown;\n}\n\nconst zerodhaOrders: Tool<OrdersArgs> = defineTool<OrdersArgs>({\n name: 'zerodha_orders',\n description: `Today's order book — all orders placed, modified, or cancelled today.\nReturns order status, fill price, rejection reason. Always live from Kite API.\nDoes NOT return historical orders from previous days (Zerodha API limitation).`,\n toolset: 'broker',\n maxResultChars: 6000,\n capabilities: {\n network: { allowedHosts: ['api.kite.trade'] },\n secrets: ['brokers/zerodha/apiKey', 'brokers/zerodha/accessToken'],\n },\n schema: { type: 'object', properties: {} },\n\n async execute(_args: OrdersArgs, ctx: ToolContext): Promise<ToolResult> {\n try {\n const creds = await getCredentials(ctx);\n if (isToolResult(creds)) return creds;\n\n const orders = await fetchOrders(creds);\n\n return ok(\n JSON.stringify({\n count: orders.length,\n orders: orders.map((o) => ({\n order_id: o.order_id,\n symbol: o.tradingsymbol,\n side: o.transaction_type,\n quantity: o.quantity,\n order_type: o.order_type,\n price: o.price,\n status: o.status,\n filled_price: o.average_price,\n time: o.order_timestamp,\n })),\n })\n );\n } catch (e) {\n if (e instanceof KiteTokenExpiredError) {\n return tokenExpiredResult();\n }\n return err(e instanceof Error ? e.message : String(e));\n }\n },\n});\n\ninterface PlaceOrderArgs {\n [key: string]: unknown;\n symbol: string;\n exchange?: string;\n side: 'BUY' | 'SELL';\n quantity: number;\n order_type: 'MARKET' | 'LIMIT';\n price?: number;\n dry_run?: boolean;\n variety?: 'regular' | 'amo';\n}\n\nconst zerodhaPlaceOrder: Tool<PlaceOrderArgs> = defineTool<PlaceOrderArgs>({\n name: 'zerodha_place_order',\n description: `Propose or place an equity order via Zerodha Kite.\n\nIMPORTANT SAFETY RULES:\n- dry_run defaults to TRUE. With dry_run: true, the order is SIMULATED — no real trade is placed.\n The agent will describe what would happen and log it to the audit trail.\n- To place a REAL order: the user must explicitly say \"confirm: true\" in their message.\n Do not set confirm: true without explicit user instruction.\n- Only NSE/BSE equity (CNC product) orders are supported. No MIS intraday, no F&O.\n- Market hours only: 09:15–15:30 IST Monday–Friday. AMO (After Market Order) requires variety: 'amo'.\n\nBefore placing any real order, always call zerodha_holdings to verify the position context.`,\n toolset: 'broker',\n maxResultChars: 2000,\n capabilities: {\n network: { allowedHosts: ['api.kite.trade'] },\n secrets: ['brokers/zerodha/apiKey', 'brokers/zerodha/accessToken'],\n },\n schema: {\n type: 'object',\n properties: {\n symbol: {\n type: 'string',\n description: 'NSE/BSE symbol (e.g. RELIANCE, TCS, INFY)',\n },\n exchange: {\n type: 'string',\n enum: ['NSE', 'BSE'],\n description: 'Exchange (default NSE)',\n },\n side: {\n type: 'string',\n enum: ['BUY', 'SELL'],\n description: 'Transaction type',\n },\n quantity: {\n type: 'number',\n description: 'Number of shares (must be positive integer)',\n },\n order_type: {\n type: 'string',\n enum: ['MARKET', 'LIMIT'],\n description: 'MARKET executes immediately at best price; LIMIT requires price parameter',\n },\n price: {\n type: 'number',\n description: 'Limit price in INR (required for LIMIT orders)',\n },\n dry_run: {\n type: 'boolean',\n description:\n 'Simulate only — do NOT place a real order (default: true). Set false only when user explicitly confirms.',\n },\n variety: {\n type: 'string',\n enum: ['regular', 'amo'],\n description:\n \"Order variety: 'regular' (market hours) or 'amo' (after market, 3:45–8:57 AM next day). Default: regular\",\n },\n },\n required: ['symbol', 'side', 'quantity', 'order_type'],\n },\n\n async execute(args: PlaceOrderArgs, ctx: ToolContext): Promise<ToolResult> {\n try {\n const creds = await getCredentials(ctx);\n if (isToolResult(creds)) return creds;\n\n const exchange = (args.exchange ?? 'NSE') as 'NSE' | 'BSE';\n const dryRun = args.dry_run !== false; // default true\n const variety = args.variety ?? 'regular';\n const product = 'CNC' as const;\n\n const orderId = randomUUID();\n const now = Date.now();\n\n if (dryRun) {\n const priceStr =\n args.order_type === 'LIMIT' && args.price != null\n ? `LIMIT ${args.price.toFixed(2)}`\n : 'MARKET';\n const estimatedCost = args.price != null ? args.quantity * args.price : null;\n\n const description = `Would place: ${args.side} ${args.quantity} ${args.symbol} @ ${priceStr} on ${exchange} (${product})`;\n\n // Log dry-run order to audit trail\n const store = new ZerodhaStore(defaultDbPath());\n try {\n store.logOrder({\n id: orderId,\n createdAt: now,\n symbol: args.symbol,\n exchange,\n transaction: args.side,\n quantity: args.quantity,\n orderType: args.order_type,\n price: args.price ?? null,\n product,\n dryRun: true,\n kiteOrderId: null,\n status: 'dry_run',\n rejectionReason: null,\n agentSession: null,\n });\n } finally {\n store.close();\n }\n\n return ok(\n JSON.stringify({\n dry_run: true,\n description,\n estimated_cost_inr: estimatedCost,\n estimated_brokerage_inr: 0.0, // Zerodha zero brokerage on delivery\n logged: true,\n to_place_for_real: 'Add dry_run: false to this request after confirming',\n })\n );\n }\n\n // Real order\n const result = await placeOrder(creds, {\n exchange,\n tradingsymbol: args.symbol,\n transaction_type: args.side,\n quantity: args.quantity,\n order_type: args.order_type,\n product,\n price: args.price,\n variety,\n });\n\n // Log real order to audit trail\n const store = new ZerodhaStore(defaultDbPath());\n try {\n store.logOrder({\n id: orderId,\n createdAt: now,\n symbol: args.symbol,\n exchange,\n transaction: args.side,\n quantity: args.quantity,\n orderType: args.order_type,\n price: args.price ?? null,\n product,\n dryRun: false,\n kiteOrderId: result.order_id,\n status: 'placed',\n rejectionReason: null,\n agentSession: null,\n });\n } finally {\n store.close();\n }\n\n return ok(\n JSON.stringify({\n dry_run: false,\n order_id: result.order_id,\n status: 'placed',\n symbol: args.symbol,\n side: args.side,\n quantity: args.quantity,\n order_type: args.order_type,\n price: args.price ?? null,\n })\n );\n } catch (e) {\n if (e instanceof KiteTokenExpiredError) {\n return tokenExpiredResult();\n }\n return err(e instanceof Error ? e.message : String(e));\n }\n },\n});\n\n// -- Public API --------------------------------------------------------------\n\n/** v2 plugin entry point — registers all tools via EthosPluginApi. */\nexport const plugin: EthosPlugin = {\n activate(api: EthosPluginApi) {\n for (const tool of createZerodhaTools()) {\n api.registerTool(tool);\n }\n },\n};\n\n/** Backward-compatible activate function for v1 hosts. */\nexport function activate(api: { registerTool(tool: Tool): void }): void {\n for (const tool of createZerodhaTools()) {\n api.registerTool(tool);\n }\n}\n\nexport function createZerodhaTools(): Tool<unknown>[] {\n return [\n zerodhaAuthStatus as Tool<unknown>,\n zerodhaAuthComplete as Tool<unknown>,\n zerodhaAccount as Tool<unknown>,\n zerodhaHoldings as Tool<unknown>,\n zerodhaPositions as Tool<unknown>,\n zerodhaOrders as Tool<unknown>,\n zerodhaPlaceOrder as Tool<unknown>,\n ];\n}\n","const KITE_BASE = 'https://api.kite.trade';\n\nexport interface KiteCredentials {\n apiKey: string;\n accessToken: string;\n}\n\nfunction authHeaders(creds: KiteCredentials): Record<string, string> {\n return {\n Authorization: `token ${creds.apiKey}:${creds.accessToken}`,\n 'X-Kite-Version': '3',\n 'Content-Type': 'application/x-www-form-urlencoded',\n };\n}\n\n// -- Error classes -----------------------------------------------------------\n\nexport class KiteTokenExpiredError extends Error {\n readonly code = 'TOKEN_EXPIRED';\n constructor(message = 'Kite access token expired. Renew via zerodha-broker auth.') {\n super(message);\n this.name = 'KiteTokenExpiredError';\n }\n}\n\nexport class KiteApiError extends Error {\n constructor(\n message: string,\n readonly errorType: string,\n readonly statusCode: number\n ) {\n super(message);\n this.name = 'KiteApiError';\n }\n}\n\n// -- Response handling -------------------------------------------------------\n\ninterface KiteResponse<T> {\n status: string;\n data: T;\n message?: string;\n error_type?: string;\n}\n\nasync function kiteGet<T>(creds: KiteCredentials, path: string): Promise<T> {\n const res = await fetch(`${KITE_BASE}${path}`, {\n method: 'GET',\n headers: authHeaders(creds),\n });\n\n const body = (await res.json()) as KiteResponse<T>;\n\n if (res.status === 403 || body.error_type === 'TokenException') {\n throw new KiteTokenExpiredError(body.message);\n }\n\n if (body.status === 'error') {\n throw new KiteApiError(\n body.message ?? 'Unknown error',\n body.error_type ?? 'Unknown',\n res.status\n );\n }\n\n return body.data;\n}\n\n// -- Account -----------------------------------------------------------------\n\nexport interface KiteProfile {\n user_id: string;\n user_name: string;\n email: string;\n user_type: string;\n broker: string;\n}\n\nexport interface KiteMargins {\n equity: {\n enabled: boolean;\n net: number;\n available: { live_balance: number; opening_balance: number };\n utilised: { m2m_unrealised: number; option_premium: number; exposure: number };\n };\n}\n\nexport async function fetchProfile(creds: KiteCredentials): Promise<KiteProfile> {\n return kiteGet<KiteProfile>(creds, '/user/profile');\n}\n\nexport async function fetchMargins(creds: KiteCredentials): Promise<KiteMargins> {\n return kiteGet<KiteMargins>(creds, '/user/margins');\n}\n\n// -- Portfolio ---------------------------------------------------------------\n\nexport interface KiteHolding {\n tradingsymbol: string;\n exchange: string;\n isin: string;\n quantity: number;\n t1_quantity: number;\n average_price: number;\n last_price: number;\n pnl: number;\n day_change: number;\n day_change_percentage: number;\n product: string;\n}\n\nexport interface KitePosition {\n tradingsymbol: string;\n exchange: string;\n product: string;\n quantity: number;\n overnight_quantity: number;\n average_price: number;\n last_price: number;\n pnl: number;\n m2m: number;\n unrealised: number;\n realised: number;\n}\n\nexport async function fetchHoldings(creds: KiteCredentials): Promise<KiteHolding[]> {\n return kiteGet<KiteHolding[]>(creds, '/portfolio/holdings');\n}\n\nexport async function fetchPositions(\n creds: KiteCredentials\n): Promise<{ day: KitePosition[]; net: KitePosition[] }> {\n return kiteGet<{ day: KitePosition[]; net: KitePosition[] }>(creds, '/portfolio/positions');\n}\n\n// -- Orders ------------------------------------------------------------------\n\nexport interface KiteOrder {\n order_id: string;\n exchange: string;\n tradingsymbol: string;\n transaction_type: 'BUY' | 'SELL';\n order_type: string;\n quantity: number;\n price: number;\n trigger_price: number;\n average_price: number;\n filled_quantity: number;\n status: string;\n status_message: string | null;\n order_timestamp: string;\n product: string;\n variety: string;\n}\n\nexport async function fetchOrders(creds: KiteCredentials): Promise<KiteOrder[]> {\n return kiteGet<KiteOrder[]>(creds, '/orders');\n}\n\n// -- Order placement ---------------------------------------------------------\n\nexport interface PlaceOrderParams {\n exchange: 'NSE' | 'BSE';\n tradingsymbol: string;\n transaction_type: 'BUY' | 'SELL';\n quantity: number;\n order_type: 'MARKET' | 'LIMIT' | 'SL' | 'SL-M';\n product: 'CNC' | 'MIS' | 'NRML';\n price?: number;\n trigger_price?: number;\n variety?: 'regular' | 'amo';\n validity?: 'DAY' | 'IOC';\n}\n\nexport interface PlaceOrderResult {\n order_id: string;\n}\n\nexport async function placeOrder(\n creds: KiteCredentials,\n params: PlaceOrderParams\n): Promise<PlaceOrderResult> {\n const variety = params.variety ?? 'regular';\n\n const body = new URLSearchParams();\n body.set('exchange', params.exchange);\n body.set('tradingsymbol', params.tradingsymbol);\n body.set('transaction_type', params.transaction_type);\n body.set('quantity', String(params.quantity));\n body.set('order_type', params.order_type);\n body.set('product', params.product);\n body.set('validity', params.validity ?? 'DAY');\n if (params.price != null) body.set('price', String(params.price));\n if (params.trigger_price != null) body.set('trigger_price', String(params.trigger_price));\n\n const res = await fetch(`${KITE_BASE}/orders/${variety}`, {\n method: 'POST',\n headers: authHeaders(creds),\n body: body.toString(),\n });\n\n const json = (await res.json()) as KiteResponse<PlaceOrderResult>;\n\n if (res.status === 403 || json.error_type === 'TokenException') {\n throw new KiteTokenExpiredError(json.message);\n }\n\n if (json.status === 'error') {\n throw new KiteApiError(\n json.message ?? 'Order placement failed',\n json.error_type ?? 'Unknown',\n res.status\n );\n }\n\n return json.data;\n}\n\nexport async function cancelOrder(\n creds: KiteCredentials,\n orderId: string,\n variety = 'regular'\n): Promise<{ order_id: string }> {\n const res = await fetch(`${KITE_BASE}/orders/${variety}/${orderId}`, {\n method: 'DELETE',\n headers: authHeaders(creds),\n });\n\n const json = (await res.json()) as KiteResponse<{ order_id: string }>;\n\n if (res.status === 403 || json.error_type === 'TokenException') {\n throw new KiteTokenExpiredError(json.message);\n }\n\n if (json.status === 'error') {\n throw new KiteApiError(\n json.message ?? 'Order cancellation failed',\n json.error_type ?? 'Unknown',\n res.status\n );\n }\n\n return json.data;\n}\n"],"mappings":"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","names":["store"]}
|
package/dist/panel.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* PluginPanelProps from @ethosagent/types — declared locally to avoid a hard
|
|
5
|
+
* import-time dependency on a package the host provides at runtime.
|
|
6
|
+
* Matches packages/types/src/plugin-panel.ts in the framework repo.
|
|
7
|
+
*/
|
|
8
|
+
interface PluginPanelProps {
|
|
9
|
+
pluginId: string;
|
|
10
|
+
getCredential(ref: string): Promise<string | null>;
|
|
11
|
+
setCredential(ref: string, value: string): Promise<void>;
|
|
12
|
+
credentialPreview(ref: string): Promise<string | null>;
|
|
13
|
+
requestOAuth(oauthRef: string): void;
|
|
14
|
+
executeTool(toolName: string, args: Record<string, unknown>): Promise<{
|
|
15
|
+
ok: boolean;
|
|
16
|
+
value?: string;
|
|
17
|
+
error?: string;
|
|
18
|
+
code?: string;
|
|
19
|
+
}>;
|
|
20
|
+
theme: 'dark' | 'light';
|
|
21
|
+
}
|
|
22
|
+
declare function ZerodhaHomePanel(props: PluginPanelProps): react_jsx_runtime.JSX.Element;
|
|
23
|
+
|
|
24
|
+
export { ZerodhaHomePanel as default };
|
package/dist/panel.js
ADDED
|
@@ -0,0 +1,394 @@
|
|
|
1
|
+
// src/panel.tsx
|
|
2
|
+
import { useCallback, useEffect, useState } from "react";
|
|
3
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
4
|
+
var v = (name) => `var(--${name})`;
|
|
5
|
+
function StatusBadge({ ok }) {
|
|
6
|
+
return /* @__PURE__ */ jsx(
|
|
7
|
+
"span",
|
|
8
|
+
{
|
|
9
|
+
style: {
|
|
10
|
+
display: "inline-block",
|
|
11
|
+
width: 8,
|
|
12
|
+
height: 8,
|
|
13
|
+
borderRadius: "50%",
|
|
14
|
+
background: ok ? v("success") : v("danger"),
|
|
15
|
+
marginRight: 6
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
function CredentialRow({ label, status }) {
|
|
21
|
+
const isSet = status === "set";
|
|
22
|
+
const checking = status === "checking";
|
|
23
|
+
return /* @__PURE__ */ jsxs("tr", { children: [
|
|
24
|
+
/* @__PURE__ */ jsx("td", { style: { padding: "6px 0", width: 140 }, children: label }),
|
|
25
|
+
/* @__PURE__ */ jsx("td", { style: { color: checking ? v("muted") : isSet ? v("success") : v("danger") }, children: checking ? "Checking..." : isSet ? "Configured" : "Not set" })
|
|
26
|
+
] });
|
|
27
|
+
}
|
|
28
|
+
function TabButton({
|
|
29
|
+
label,
|
|
30
|
+
active,
|
|
31
|
+
onClick
|
|
32
|
+
}) {
|
|
33
|
+
return /* @__PURE__ */ jsx(
|
|
34
|
+
"button",
|
|
35
|
+
{
|
|
36
|
+
type: "button",
|
|
37
|
+
onClick,
|
|
38
|
+
style: {
|
|
39
|
+
padding: "8px 16px",
|
|
40
|
+
border: "none",
|
|
41
|
+
borderBottom: active ? `2px solid ${v("brand")}` : "2px solid transparent",
|
|
42
|
+
background: "transparent",
|
|
43
|
+
color: active ? v("foreground") : v("muted"),
|
|
44
|
+
cursor: "pointer",
|
|
45
|
+
fontWeight: active ? 600 : 400,
|
|
46
|
+
fontSize: 14
|
|
47
|
+
},
|
|
48
|
+
children: label
|
|
49
|
+
}
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
function Spinner() {
|
|
53
|
+
return /* @__PURE__ */ jsx("p", { style: { color: v("muted"), padding: "12px 0" }, children: "Loading..." });
|
|
54
|
+
}
|
|
55
|
+
function ErrorBanner({ message }) {
|
|
56
|
+
return /* @__PURE__ */ jsx(
|
|
57
|
+
"p",
|
|
58
|
+
{
|
|
59
|
+
style: {
|
|
60
|
+
color: v("danger"),
|
|
61
|
+
background: "rgba(255,0,0,0.06)",
|
|
62
|
+
padding: "8px 12px",
|
|
63
|
+
borderRadius: 4,
|
|
64
|
+
fontSize: 13
|
|
65
|
+
},
|
|
66
|
+
children: message
|
|
67
|
+
}
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
function EmptyState({ message }) {
|
|
71
|
+
return /* @__PURE__ */ jsx("p", { style: { color: v("muted"), padding: "12px 0" }, children: message });
|
|
72
|
+
}
|
|
73
|
+
function formatInr(n) {
|
|
74
|
+
if (n == null) return "--";
|
|
75
|
+
return n.toLocaleString("en-IN", {
|
|
76
|
+
style: "currency",
|
|
77
|
+
currency: "INR",
|
|
78
|
+
minimumFractionDigits: 2,
|
|
79
|
+
maximumFractionDigits: 2
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
function pnlColor(n) {
|
|
83
|
+
if (n == null || n === 0) return v("foreground");
|
|
84
|
+
return n > 0 ? v("success") : v("danger");
|
|
85
|
+
}
|
|
86
|
+
function HoldingsTab({ data }) {
|
|
87
|
+
if (!data || data.holdings.length === 0) {
|
|
88
|
+
return /* @__PURE__ */ jsx(EmptyState, { message: "No holdings found." });
|
|
89
|
+
}
|
|
90
|
+
return /* @__PURE__ */ jsxs("div", { children: [
|
|
91
|
+
/* @__PURE__ */ jsxs(
|
|
92
|
+
"div",
|
|
93
|
+
{
|
|
94
|
+
style: {
|
|
95
|
+
display: "flex",
|
|
96
|
+
gap: 24,
|
|
97
|
+
marginBottom: 16,
|
|
98
|
+
fontSize: 13,
|
|
99
|
+
color: v("muted")
|
|
100
|
+
},
|
|
101
|
+
children: [
|
|
102
|
+
/* @__PURE__ */ jsxs("span", { children: [
|
|
103
|
+
"Invested: ",
|
|
104
|
+
formatInr(data.total_invested_inr)
|
|
105
|
+
] }),
|
|
106
|
+
/* @__PURE__ */ jsxs("span", { children: [
|
|
107
|
+
"Current: ",
|
|
108
|
+
formatInr(data.total_current_inr)
|
|
109
|
+
] }),
|
|
110
|
+
/* @__PURE__ */ jsxs("span", { style: { color: pnlColor(data.total_pnl_inr) }, children: [
|
|
111
|
+
"P&L: ",
|
|
112
|
+
formatInr(data.total_pnl_inr),
|
|
113
|
+
" (",
|
|
114
|
+
data.total_pnl_pct.toFixed(2),
|
|
115
|
+
"%)"
|
|
116
|
+
] })
|
|
117
|
+
]
|
|
118
|
+
}
|
|
119
|
+
),
|
|
120
|
+
/* @__PURE__ */ jsxs("table", { style: { borderCollapse: "collapse", width: "100%", fontSize: 13 }, children: [
|
|
121
|
+
/* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { style: { borderBottom: `1px solid ${v("border")}` }, children: [
|
|
122
|
+
/* @__PURE__ */ jsx("th", { style: { textAlign: "left", padding: "6px 8px" }, children: "Symbol" }),
|
|
123
|
+
/* @__PURE__ */ jsx("th", { style: { textAlign: "right", padding: "6px 8px" }, children: "Qty" }),
|
|
124
|
+
/* @__PURE__ */ jsx("th", { style: { textAlign: "right", padding: "6px 8px" }, children: "Avg" }),
|
|
125
|
+
/* @__PURE__ */ jsx("th", { style: { textAlign: "right", padding: "6px 8px" }, children: "LTP" }),
|
|
126
|
+
/* @__PURE__ */ jsx("th", { style: { textAlign: "right", padding: "6px 8px" }, children: "P&L" }),
|
|
127
|
+
/* @__PURE__ */ jsx("th", { style: { textAlign: "right", padding: "6px 8px" }, children: "Day %" })
|
|
128
|
+
] }) }),
|
|
129
|
+
/* @__PURE__ */ jsx("tbody", { children: data.holdings.map((h) => /* @__PURE__ */ jsxs(
|
|
130
|
+
"tr",
|
|
131
|
+
{
|
|
132
|
+
style: { borderBottom: `1px solid ${v("border")}` },
|
|
133
|
+
children: [
|
|
134
|
+
/* @__PURE__ */ jsxs("td", { style: { padding: "6px 8px" }, children: [
|
|
135
|
+
h.symbol,
|
|
136
|
+
/* @__PURE__ */ jsx("span", { style: { color: v("muted"), fontSize: 11, marginLeft: 4 }, children: h.exchange })
|
|
137
|
+
] }),
|
|
138
|
+
/* @__PURE__ */ jsx("td", { style: { textAlign: "right", padding: "6px 8px" }, children: h.quantity }),
|
|
139
|
+
/* @__PURE__ */ jsx("td", { style: { textAlign: "right", padding: "6px 8px" }, children: formatInr(h.avg_price) }),
|
|
140
|
+
/* @__PURE__ */ jsx("td", { style: { textAlign: "right", padding: "6px 8px" }, children: formatInr(h.ltp) }),
|
|
141
|
+
/* @__PURE__ */ jsx("td", { style: { textAlign: "right", padding: "6px 8px", color: pnlColor(h.pnl_inr) }, children: formatInr(h.pnl_inr) }),
|
|
142
|
+
/* @__PURE__ */ jsx(
|
|
143
|
+
"td",
|
|
144
|
+
{
|
|
145
|
+
style: {
|
|
146
|
+
textAlign: "right",
|
|
147
|
+
padding: "6px 8px",
|
|
148
|
+
color: pnlColor(h.day_change_pct)
|
|
149
|
+
},
|
|
150
|
+
children: h.day_change_pct != null ? `${h.day_change_pct.toFixed(2)}%` : "--"
|
|
151
|
+
}
|
|
152
|
+
)
|
|
153
|
+
]
|
|
154
|
+
},
|
|
155
|
+
`${h.exchange}:${h.symbol}`
|
|
156
|
+
)) })
|
|
157
|
+
] })
|
|
158
|
+
] });
|
|
159
|
+
}
|
|
160
|
+
function PositionsTab({ data }) {
|
|
161
|
+
if (!data) return /* @__PURE__ */ jsx(EmptyState, { message: "No position data." });
|
|
162
|
+
const all = [...data.day_positions, ...data.net_positions];
|
|
163
|
+
if (all.length === 0) return /* @__PURE__ */ jsx(EmptyState, { message: "No open positions." });
|
|
164
|
+
return /* @__PURE__ */ jsxs("div", { children: [
|
|
165
|
+
/* @__PURE__ */ jsxs("p", { style: { fontSize: 13, color: v("muted"), marginBottom: 12 }, children: [
|
|
166
|
+
"Day P&L:",
|
|
167
|
+
" ",
|
|
168
|
+
/* @__PURE__ */ jsx("span", { style: { color: pnlColor(data.total_day_pnl_inr) }, children: formatInr(data.total_day_pnl_inr) })
|
|
169
|
+
] }),
|
|
170
|
+
/* @__PURE__ */ jsxs("table", { style: { borderCollapse: "collapse", width: "100%", fontSize: 13 }, children: [
|
|
171
|
+
/* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { style: { borderBottom: `1px solid ${v("border")}` }, children: [
|
|
172
|
+
/* @__PURE__ */ jsx("th", { style: { textAlign: "left", padding: "6px 8px" }, children: "Symbol" }),
|
|
173
|
+
/* @__PURE__ */ jsx("th", { style: { textAlign: "right", padding: "6px 8px" }, children: "Qty" }),
|
|
174
|
+
/* @__PURE__ */ jsx("th", { style: { textAlign: "right", padding: "6px 8px" }, children: "Avg" }),
|
|
175
|
+
/* @__PURE__ */ jsx("th", { style: { textAlign: "right", padding: "6px 8px" }, children: "LTP" }),
|
|
176
|
+
/* @__PURE__ */ jsx("th", { style: { textAlign: "right", padding: "6px 8px" }, children: "P&L" }),
|
|
177
|
+
/* @__PURE__ */ jsx("th", { style: { textAlign: "left", padding: "6px 8px" }, children: "Product" })
|
|
178
|
+
] }) }),
|
|
179
|
+
/* @__PURE__ */ jsx("tbody", { children: all.map((p) => /* @__PURE__ */ jsxs(
|
|
180
|
+
"tr",
|
|
181
|
+
{
|
|
182
|
+
style: { borderBottom: `1px solid ${v("border")}` },
|
|
183
|
+
children: [
|
|
184
|
+
/* @__PURE__ */ jsxs("td", { style: { padding: "6px 8px" }, children: [
|
|
185
|
+
p.symbol,
|
|
186
|
+
/* @__PURE__ */ jsx("span", { style: { color: v("muted"), fontSize: 11, marginLeft: 4 }, children: p.exchange })
|
|
187
|
+
] }),
|
|
188
|
+
/* @__PURE__ */ jsx("td", { style: { textAlign: "right", padding: "6px 8px" }, children: p.quantity }),
|
|
189
|
+
/* @__PURE__ */ jsx("td", { style: { textAlign: "right", padding: "6px 8px" }, children: formatInr(p.avg_price) }),
|
|
190
|
+
/* @__PURE__ */ jsx("td", { style: { textAlign: "right", padding: "6px 8px" }, children: formatInr(p.ltp) }),
|
|
191
|
+
/* @__PURE__ */ jsx("td", { style: { textAlign: "right", padding: "6px 8px", color: pnlColor(p.pnl_inr) }, children: formatInr(p.pnl_inr) }),
|
|
192
|
+
/* @__PURE__ */ jsx("td", { style: { padding: "6px 8px" }, children: p.product })
|
|
193
|
+
]
|
|
194
|
+
},
|
|
195
|
+
`${p.exchange}:${p.symbol}:${p.product}`
|
|
196
|
+
)) })
|
|
197
|
+
] })
|
|
198
|
+
] });
|
|
199
|
+
}
|
|
200
|
+
function OrdersTab({ data }) {
|
|
201
|
+
if (!data || data.orders.length === 0) {
|
|
202
|
+
return /* @__PURE__ */ jsx(EmptyState, { message: "No orders today." });
|
|
203
|
+
}
|
|
204
|
+
return /* @__PURE__ */ jsxs("table", { style: { borderCollapse: "collapse", width: "100%", fontSize: 13 }, children: [
|
|
205
|
+
/* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { style: { borderBottom: `1px solid ${v("border")}` }, children: [
|
|
206
|
+
/* @__PURE__ */ jsx("th", { style: { textAlign: "left", padding: "6px 8px" }, children: "Symbol" }),
|
|
207
|
+
/* @__PURE__ */ jsx("th", { style: { textAlign: "left", padding: "6px 8px" }, children: "Side" }),
|
|
208
|
+
/* @__PURE__ */ jsx("th", { style: { textAlign: "right", padding: "6px 8px" }, children: "Qty" }),
|
|
209
|
+
/* @__PURE__ */ jsx("th", { style: { textAlign: "right", padding: "6px 8px" }, children: "Price" }),
|
|
210
|
+
/* @__PURE__ */ jsx("th", { style: { textAlign: "left", padding: "6px 8px" }, children: "Status" }),
|
|
211
|
+
/* @__PURE__ */ jsx("th", { style: { textAlign: "left", padding: "6px 8px" }, children: "Time" })
|
|
212
|
+
] }) }),
|
|
213
|
+
/* @__PURE__ */ jsx("tbody", { children: data.orders.map((o) => /* @__PURE__ */ jsxs("tr", { style: { borderBottom: `1px solid ${v("border")}` }, children: [
|
|
214
|
+
/* @__PURE__ */ jsx("td", { style: { padding: "6px 8px" }, children: o.symbol }),
|
|
215
|
+
/* @__PURE__ */ jsx(
|
|
216
|
+
"td",
|
|
217
|
+
{
|
|
218
|
+
style: {
|
|
219
|
+
padding: "6px 8px",
|
|
220
|
+
color: o.side === "BUY" ? v("success") : v("danger")
|
|
221
|
+
},
|
|
222
|
+
children: o.side
|
|
223
|
+
}
|
|
224
|
+
),
|
|
225
|
+
/* @__PURE__ */ jsx("td", { style: { textAlign: "right", padding: "6px 8px" }, children: o.quantity }),
|
|
226
|
+
/* @__PURE__ */ jsx("td", { style: { textAlign: "right", padding: "6px 8px" }, children: o.filled_price != null ? formatInr(o.filled_price) : formatInr(o.price) }),
|
|
227
|
+
/* @__PURE__ */ jsx("td", { style: { padding: "6px 8px" }, children: o.status }),
|
|
228
|
+
/* @__PURE__ */ jsx("td", { style: { padding: "6px 8px", color: v("muted"), fontSize: 12 }, children: o.time ?? "--" })
|
|
229
|
+
] }, o.order_id)) })
|
|
230
|
+
] });
|
|
231
|
+
}
|
|
232
|
+
function ZerodhaHomePanel(props) {
|
|
233
|
+
const { credentialPreview, requestOAuth, executeTool } = props;
|
|
234
|
+
const [apiKeyStatus, setApiKeyStatus] = useState("checking");
|
|
235
|
+
const [apiSecretStatus, setApiSecretStatus] = useState("checking");
|
|
236
|
+
const [tokenPreview, setTokenPreview] = useState(null);
|
|
237
|
+
const refreshCreds = useCallback(async () => {
|
|
238
|
+
const [keyPv, secretPv, accessPv] = await Promise.all([
|
|
239
|
+
credentialPreview("brokers/zerodha/apiKey"),
|
|
240
|
+
credentialPreview("brokers/zerodha/apiSecret"),
|
|
241
|
+
credentialPreview("brokers/zerodha/accessToken")
|
|
242
|
+
]);
|
|
243
|
+
setApiKeyStatus(keyPv !== null ? "set" : "unset");
|
|
244
|
+
setApiSecretStatus(secretPv !== null ? "set" : "unset");
|
|
245
|
+
setTokenPreview(accessPv);
|
|
246
|
+
}, [credentialPreview]);
|
|
247
|
+
useEffect(() => {
|
|
248
|
+
void refreshCreds();
|
|
249
|
+
}, [refreshCreds]);
|
|
250
|
+
const [activeTab, setActiveTab] = useState("holdings");
|
|
251
|
+
const [holdingsData, setHoldingsData] = useState(null);
|
|
252
|
+
const [positionsData, setPositionsData] = useState(null);
|
|
253
|
+
const [ordersData, setOrdersData] = useState(null);
|
|
254
|
+
const [loading, setLoading] = useState(false);
|
|
255
|
+
const [error, setError] = useState(null);
|
|
256
|
+
const connected = tokenPreview !== null;
|
|
257
|
+
const fetchTab = useCallback(
|
|
258
|
+
async (tab) => {
|
|
259
|
+
if (!connected) return;
|
|
260
|
+
setLoading(true);
|
|
261
|
+
setError(null);
|
|
262
|
+
const toolMap = {
|
|
263
|
+
holdings: "zerodha_holdings",
|
|
264
|
+
positions: "zerodha_positions",
|
|
265
|
+
orders: "zerodha_orders"
|
|
266
|
+
};
|
|
267
|
+
const result = await executeTool(toolMap[tab], {});
|
|
268
|
+
setLoading(false);
|
|
269
|
+
if (!result.ok) {
|
|
270
|
+
setError(result.error ?? "Tool call failed");
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
try {
|
|
274
|
+
const parsed = JSON.parse(result.value ?? "{}");
|
|
275
|
+
if (tab === "holdings") setHoldingsData(parsed);
|
|
276
|
+
else if (tab === "positions") setPositionsData(parsed);
|
|
277
|
+
else setOrdersData(parsed);
|
|
278
|
+
} catch {
|
|
279
|
+
setError("Unexpected response format");
|
|
280
|
+
}
|
|
281
|
+
},
|
|
282
|
+
[connected, executeTool]
|
|
283
|
+
);
|
|
284
|
+
useEffect(() => {
|
|
285
|
+
void fetchTab(activeTab);
|
|
286
|
+
}, [activeTab, fetchTab]);
|
|
287
|
+
const handleReconnect = () => {
|
|
288
|
+
requestOAuth("zerodha");
|
|
289
|
+
};
|
|
290
|
+
return /* @__PURE__ */ jsxs(
|
|
291
|
+
"div",
|
|
292
|
+
{
|
|
293
|
+
style: {
|
|
294
|
+
padding: 24,
|
|
295
|
+
fontFamily: "inherit",
|
|
296
|
+
color: v("foreground"),
|
|
297
|
+
background: v("background"),
|
|
298
|
+
minHeight: "100%"
|
|
299
|
+
},
|
|
300
|
+
children: [
|
|
301
|
+
/* @__PURE__ */ jsx("h2", { style: { marginTop: 0, marginBottom: 16 }, children: "Zerodha" }),
|
|
302
|
+
/* @__PURE__ */ jsxs("section", { style: { marginBottom: 24 }, children: [
|
|
303
|
+
/* @__PURE__ */ jsx("h3", { style: { fontSize: 14, color: v("muted"), marginBottom: 8 }, children: "Connection" }),
|
|
304
|
+
/* @__PURE__ */ jsx("table", { style: { borderCollapse: "collapse", width: "100%" }, children: /* @__PURE__ */ jsxs("tbody", { children: [
|
|
305
|
+
/* @__PURE__ */ jsx(CredentialRow, { label: "API Key", status: apiKeyStatus }),
|
|
306
|
+
/* @__PURE__ */ jsx(CredentialRow, { label: "API Secret", status: apiSecretStatus }),
|
|
307
|
+
/* @__PURE__ */ jsxs("tr", { children: [
|
|
308
|
+
/* @__PURE__ */ jsx("td", { style: { padding: "6px 0", width: 140 }, children: "Access Token" }),
|
|
309
|
+
/* @__PURE__ */ jsxs(
|
|
310
|
+
"td",
|
|
311
|
+
{
|
|
312
|
+
style: {
|
|
313
|
+
color: connected ? v("success") : v("warning")
|
|
314
|
+
},
|
|
315
|
+
children: [
|
|
316
|
+
/* @__PURE__ */ jsx(StatusBadge, { ok: connected }),
|
|
317
|
+
connected ? `Connected (${tokenPreview})` : "Not connected"
|
|
318
|
+
]
|
|
319
|
+
}
|
|
320
|
+
)
|
|
321
|
+
] })
|
|
322
|
+
] }) }),
|
|
323
|
+
/* @__PURE__ */ jsx(
|
|
324
|
+
"button",
|
|
325
|
+
{
|
|
326
|
+
type: "button",
|
|
327
|
+
onClick: handleReconnect,
|
|
328
|
+
style: {
|
|
329
|
+
marginTop: 12,
|
|
330
|
+
padding: "8px 16px",
|
|
331
|
+
background: v("brand"),
|
|
332
|
+
color: "#fff",
|
|
333
|
+
border: "none",
|
|
334
|
+
borderRadius: 4,
|
|
335
|
+
cursor: "pointer",
|
|
336
|
+
fontSize: 13
|
|
337
|
+
},
|
|
338
|
+
children: connected ? "Reconnect Zerodha" : "Connect Zerodha"
|
|
339
|
+
}
|
|
340
|
+
)
|
|
341
|
+
] }),
|
|
342
|
+
connected && /* @__PURE__ */ jsxs("section", { children: [
|
|
343
|
+
/* @__PURE__ */ jsxs(
|
|
344
|
+
"div",
|
|
345
|
+
{
|
|
346
|
+
style: {
|
|
347
|
+
display: "flex",
|
|
348
|
+
gap: 0,
|
|
349
|
+
borderBottom: `1px solid ${v("border")}`,
|
|
350
|
+
marginBottom: 16
|
|
351
|
+
},
|
|
352
|
+
children: [
|
|
353
|
+
/* @__PURE__ */ jsx(
|
|
354
|
+
TabButton,
|
|
355
|
+
{
|
|
356
|
+
label: "Holdings",
|
|
357
|
+
active: activeTab === "holdings",
|
|
358
|
+
onClick: () => setActiveTab("holdings")
|
|
359
|
+
}
|
|
360
|
+
),
|
|
361
|
+
/* @__PURE__ */ jsx(
|
|
362
|
+
TabButton,
|
|
363
|
+
{
|
|
364
|
+
label: "Positions",
|
|
365
|
+
active: activeTab === "positions",
|
|
366
|
+
onClick: () => setActiveTab("positions")
|
|
367
|
+
}
|
|
368
|
+
),
|
|
369
|
+
/* @__PURE__ */ jsx(
|
|
370
|
+
TabButton,
|
|
371
|
+
{
|
|
372
|
+
label: "Orders",
|
|
373
|
+
active: activeTab === "orders",
|
|
374
|
+
onClick: () => setActiveTab("orders")
|
|
375
|
+
}
|
|
376
|
+
)
|
|
377
|
+
]
|
|
378
|
+
}
|
|
379
|
+
),
|
|
380
|
+
loading && /* @__PURE__ */ jsx(Spinner, {}),
|
|
381
|
+
error && /* @__PURE__ */ jsx(ErrorBanner, { message: error }),
|
|
382
|
+
!loading && !error && activeTab === "holdings" && /* @__PURE__ */ jsx(HoldingsTab, { data: holdingsData }),
|
|
383
|
+
!loading && !error && activeTab === "positions" && /* @__PURE__ */ jsx(PositionsTab, { data: positionsData }),
|
|
384
|
+
!loading && !error && activeTab === "orders" && /* @__PURE__ */ jsx(OrdersTab, { data: ordersData })
|
|
385
|
+
] }),
|
|
386
|
+
!connected && apiKeyStatus !== "checking" && /* @__PURE__ */ jsx("section", { style: { marginTop: 16 }, children: /* @__PURE__ */ jsx("p", { style: { color: v("muted"), fontSize: 13 }, children: "Connect your Zerodha account to view holdings, positions, and orders." }) })
|
|
387
|
+
]
|
|
388
|
+
}
|
|
389
|
+
);
|
|
390
|
+
}
|
|
391
|
+
export {
|
|
392
|
+
ZerodhaHomePanel as default
|
|
393
|
+
};
|
|
394
|
+
//# sourceMappingURL=panel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/panel.tsx"],"sourcesContent":["import { useCallback, useEffect, useState } from 'react';\n\n/**\n * PluginPanelProps from @ethosagent/types — declared locally to avoid a hard\n * import-time dependency on a package the host provides at runtime.\n * Matches packages/types/src/plugin-panel.ts in the framework repo.\n */\ninterface PluginPanelProps {\n pluginId: string;\n getCredential(ref: string): Promise<string | null>;\n setCredential(ref: string, value: string): Promise<void>;\n credentialPreview(ref: string): Promise<string | null>;\n requestOAuth(oauthRef: string): void;\n executeTool(\n toolName: string,\n args: Record<string, unknown>\n ): Promise<{ ok: boolean; value?: string; error?: string; code?: string }>;\n theme: 'dark' | 'light';\n}\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\ntype CredStatus = 'unset' | 'set' | 'checking';\ntype ActiveTab = 'holdings' | 'positions' | 'orders';\n\ninterface Holding {\n symbol: string;\n exchange: string;\n quantity: number;\n avg_price: number;\n ltp: number | null;\n pnl_inr: number | null;\n pnl_pct: number | null;\n day_change_pct: number | null;\n}\n\ninterface HoldingsPayload {\n count: number;\n total_invested_inr: number;\n total_current_inr: number;\n total_pnl_inr: number;\n total_pnl_pct: number;\n holdings: Holding[];\n}\n\ninterface Position {\n symbol: string;\n exchange: string;\n product: string;\n quantity: number;\n avg_price: number;\n ltp: number;\n pnl_inr: number;\n unrealised_inr: number;\n}\n\ninterface PositionsPayload {\n day_positions: Position[];\n net_positions: Position[];\n total_day_pnl_inr: number;\n}\n\ninterface Order {\n order_id: string;\n symbol: string;\n side: string;\n quantity: number;\n order_type: string;\n price: number | null;\n status: string;\n filled_price: number | null;\n time: string | null;\n}\n\ninterface OrdersPayload {\n count: number;\n orders: Order[];\n}\n\n// ---------------------------------------------------------------------------\n// CSS custom-property helpers (theme-aware)\n// ---------------------------------------------------------------------------\n\nconst v = (name: string) => `var(--${name})`;\n\n// ---------------------------------------------------------------------------\n// Sub-components\n// ---------------------------------------------------------------------------\n\nfunction StatusBadge({ ok }: { ok: boolean }) {\n return (\n <span\n style={{\n display: 'inline-block',\n width: 8,\n height: 8,\n borderRadius: '50%',\n background: ok ? v('success') : v('danger'),\n marginRight: 6,\n }}\n />\n );\n}\n\nfunction CredentialRow({ label, status }: { label: string; status: CredStatus }) {\n const isSet = status === 'set';\n const checking = status === 'checking';\n return (\n <tr>\n <td style={{ padding: '6px 0', width: 140 }}>{label}</td>\n <td style={{ color: checking ? v('muted') : isSet ? v('success') : v('danger') }}>\n {checking ? 'Checking...' : isSet ? 'Configured' : 'Not set'}\n </td>\n </tr>\n );\n}\n\nfunction TabButton({\n label,\n active,\n onClick,\n}: {\n label: string;\n active: boolean;\n onClick: () => void;\n}) {\n return (\n <button\n type=\"button\"\n onClick={onClick}\n style={{\n padding: '8px 16px',\n border: 'none',\n borderBottom: active ? `2px solid ${v('brand')}` : '2px solid transparent',\n background: 'transparent',\n color: active ? v('foreground') : v('muted'),\n cursor: 'pointer',\n fontWeight: active ? 600 : 400,\n fontSize: 14,\n }}\n >\n {label}\n </button>\n );\n}\n\nfunction Spinner() {\n return <p style={{ color: v('muted'), padding: '12px 0' }}>Loading...</p>;\n}\n\nfunction ErrorBanner({ message }: { message: string }) {\n return (\n <p\n style={{\n color: v('danger'),\n background: 'rgba(255,0,0,0.06)',\n padding: '8px 12px',\n borderRadius: 4,\n fontSize: 13,\n }}\n >\n {message}\n </p>\n );\n}\n\nfunction EmptyState({ message }: { message: string }) {\n return <p style={{ color: v('muted'), padding: '12px 0' }}>{message}</p>;\n}\n\nfunction formatInr(n: number | null | undefined): string {\n if (n == null) return '--';\n return n.toLocaleString('en-IN', {\n style: 'currency',\n currency: 'INR',\n minimumFractionDigits: 2,\n maximumFractionDigits: 2,\n });\n}\n\nfunction pnlColor(n: number | null | undefined): string {\n if (n == null || n === 0) return v('foreground');\n return n > 0 ? v('success') : v('danger');\n}\n\n// ---------------------------------------------------------------------------\n// Tab panels\n// ---------------------------------------------------------------------------\n\nfunction HoldingsTab({ data }: { data: HoldingsPayload | null }) {\n if (!data || data.holdings.length === 0) {\n return <EmptyState message=\"No holdings found.\" />;\n }\n return (\n <div>\n <div\n style={{\n display: 'flex',\n gap: 24,\n marginBottom: 16,\n fontSize: 13,\n color: v('muted'),\n }}\n >\n <span>Invested: {formatInr(data.total_invested_inr)}</span>\n <span>Current: {formatInr(data.total_current_inr)}</span>\n <span style={{ color: pnlColor(data.total_pnl_inr) }}>\n P&L: {formatInr(data.total_pnl_inr)} ({data.total_pnl_pct.toFixed(2)}%)\n </span>\n </div>\n <table style={{ borderCollapse: 'collapse', width: '100%', fontSize: 13 }}>\n <thead>\n <tr style={{ borderBottom: `1px solid ${v('border')}` }}>\n <th style={{ textAlign: 'left', padding: '6px 8px' }}>Symbol</th>\n <th style={{ textAlign: 'right', padding: '6px 8px' }}>Qty</th>\n <th style={{ textAlign: 'right', padding: '6px 8px' }}>Avg</th>\n <th style={{ textAlign: 'right', padding: '6px 8px' }}>LTP</th>\n <th style={{ textAlign: 'right', padding: '6px 8px' }}>P&L</th>\n <th style={{ textAlign: 'right', padding: '6px 8px' }}>Day %</th>\n </tr>\n </thead>\n <tbody>\n {data.holdings.map((h) => (\n <tr\n key={`${h.exchange}:${h.symbol}`}\n style={{ borderBottom: `1px solid ${v('border')}` }}\n >\n <td style={{ padding: '6px 8px' }}>\n {h.symbol}\n <span style={{ color: v('muted'), fontSize: 11, marginLeft: 4 }}>{h.exchange}</span>\n </td>\n <td style={{ textAlign: 'right', padding: '6px 8px' }}>{h.quantity}</td>\n <td style={{ textAlign: 'right', padding: '6px 8px' }}>{formatInr(h.avg_price)}</td>\n <td style={{ textAlign: 'right', padding: '6px 8px' }}>{formatInr(h.ltp)}</td>\n <td style={{ textAlign: 'right', padding: '6px 8px', color: pnlColor(h.pnl_inr) }}>\n {formatInr(h.pnl_inr)}\n </td>\n <td\n style={{\n textAlign: 'right',\n padding: '6px 8px',\n color: pnlColor(h.day_change_pct),\n }}\n >\n {h.day_change_pct != null ? `${h.day_change_pct.toFixed(2)}%` : '--'}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n );\n}\n\nfunction PositionsTab({ data }: { data: PositionsPayload | null }) {\n if (!data) return <EmptyState message=\"No position data.\" />;\n const all = [...data.day_positions, ...data.net_positions];\n if (all.length === 0) return <EmptyState message=\"No open positions.\" />;\n return (\n <div>\n <p style={{ fontSize: 13, color: v('muted'), marginBottom: 12 }}>\n Day P&L:{' '}\n <span style={{ color: pnlColor(data.total_day_pnl_inr) }}>\n {formatInr(data.total_day_pnl_inr)}\n </span>\n </p>\n <table style={{ borderCollapse: 'collapse', width: '100%', fontSize: 13 }}>\n <thead>\n <tr style={{ borderBottom: `1px solid ${v('border')}` }}>\n <th style={{ textAlign: 'left', padding: '6px 8px' }}>Symbol</th>\n <th style={{ textAlign: 'right', padding: '6px 8px' }}>Qty</th>\n <th style={{ textAlign: 'right', padding: '6px 8px' }}>Avg</th>\n <th style={{ textAlign: 'right', padding: '6px 8px' }}>LTP</th>\n <th style={{ textAlign: 'right', padding: '6px 8px' }}>P&L</th>\n <th style={{ textAlign: 'left', padding: '6px 8px' }}>Product</th>\n </tr>\n </thead>\n <tbody>\n {all.map((p) => (\n <tr\n key={`${p.exchange}:${p.symbol}:${p.product}`}\n style={{ borderBottom: `1px solid ${v('border')}` }}\n >\n <td style={{ padding: '6px 8px' }}>\n {p.symbol}\n <span style={{ color: v('muted'), fontSize: 11, marginLeft: 4 }}>{p.exchange}</span>\n </td>\n <td style={{ textAlign: 'right', padding: '6px 8px' }}>{p.quantity}</td>\n <td style={{ textAlign: 'right', padding: '6px 8px' }}>{formatInr(p.avg_price)}</td>\n <td style={{ textAlign: 'right', padding: '6px 8px' }}>{formatInr(p.ltp)}</td>\n <td style={{ textAlign: 'right', padding: '6px 8px', color: pnlColor(p.pnl_inr) }}>\n {formatInr(p.pnl_inr)}\n </td>\n <td style={{ padding: '6px 8px' }}>{p.product}</td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n );\n}\n\nfunction OrdersTab({ data }: { data: OrdersPayload | null }) {\n if (!data || data.orders.length === 0) {\n return <EmptyState message=\"No orders today.\" />;\n }\n return (\n <table style={{ borderCollapse: 'collapse', width: '100%', fontSize: 13 }}>\n <thead>\n <tr style={{ borderBottom: `1px solid ${v('border')}` }}>\n <th style={{ textAlign: 'left', padding: '6px 8px' }}>Symbol</th>\n <th style={{ textAlign: 'left', padding: '6px 8px' }}>Side</th>\n <th style={{ textAlign: 'right', padding: '6px 8px' }}>Qty</th>\n <th style={{ textAlign: 'right', padding: '6px 8px' }}>Price</th>\n <th style={{ textAlign: 'left', padding: '6px 8px' }}>Status</th>\n <th style={{ textAlign: 'left', padding: '6px 8px' }}>Time</th>\n </tr>\n </thead>\n <tbody>\n {data.orders.map((o) => (\n <tr key={o.order_id} style={{ borderBottom: `1px solid ${v('border')}` }}>\n <td style={{ padding: '6px 8px' }}>{o.symbol}</td>\n <td\n style={{\n padding: '6px 8px',\n color: o.side === 'BUY' ? v('success') : v('danger'),\n }}\n >\n {o.side}\n </td>\n <td style={{ textAlign: 'right', padding: '6px 8px' }}>{o.quantity}</td>\n <td style={{ textAlign: 'right', padding: '6px 8px' }}>\n {o.filled_price != null ? formatInr(o.filled_price) : formatInr(o.price)}\n </td>\n <td style={{ padding: '6px 8px' }}>{o.status}</td>\n <td style={{ padding: '6px 8px', color: v('muted'), fontSize: 12 }}>\n {o.time ?? '--'}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Main panel component\n// ---------------------------------------------------------------------------\n\nexport default function ZerodhaHomePanel(props: PluginPanelProps) {\n const { credentialPreview, requestOAuth, executeTool } = props;\n\n // -- Credential status ----------------------------------------------------\n const [apiKeyStatus, setApiKeyStatus] = useState<CredStatus>('checking');\n const [apiSecretStatus, setApiSecretStatus] = useState<CredStatus>('checking');\n const [tokenPreview, setTokenPreview] = useState<string | null>(null);\n\n const refreshCreds = useCallback(async () => {\n const [keyPv, secretPv, accessPv] = await Promise.all([\n credentialPreview('brokers/zerodha/apiKey'),\n credentialPreview('brokers/zerodha/apiSecret'),\n credentialPreview('brokers/zerodha/accessToken'),\n ]);\n setApiKeyStatus(keyPv !== null ? 'set' : 'unset');\n setApiSecretStatus(secretPv !== null ? 'set' : 'unset');\n setTokenPreview(accessPv);\n }, [credentialPreview]);\n\n useEffect(() => {\n void refreshCreds();\n }, [refreshCreds]);\n\n // -- Tab state ------------------------------------------------------------\n const [activeTab, setActiveTab] = useState<ActiveTab>('holdings');\n\n // -- Data fetching --------------------------------------------------------\n const [holdingsData, setHoldingsData] = useState<HoldingsPayload | null>(null);\n const [positionsData, setPositionsData] = useState<PositionsPayload | null>(null);\n const [ordersData, setOrdersData] = useState<OrdersPayload | null>(null);\n\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const connected = tokenPreview !== null;\n\n const fetchTab = useCallback(\n async (tab: ActiveTab) => {\n if (!connected) return;\n setLoading(true);\n setError(null);\n\n const toolMap: Record<ActiveTab, string> = {\n holdings: 'zerodha_holdings',\n positions: 'zerodha_positions',\n orders: 'zerodha_orders',\n };\n\n const result = await executeTool(toolMap[tab], {});\n setLoading(false);\n\n if (!result.ok) {\n setError(result.error ?? 'Tool call failed');\n return;\n }\n\n try {\n const parsed = JSON.parse(result.value ?? '{}');\n if (tab === 'holdings') setHoldingsData(parsed as HoldingsPayload);\n else if (tab === 'positions') setPositionsData(parsed as PositionsPayload);\n else setOrdersData(parsed as OrdersPayload);\n } catch {\n setError('Unexpected response format');\n }\n },\n [connected, executeTool]\n );\n\n // Fetch data when tab changes or connection state changes\n useEffect(() => {\n void fetchTab(activeTab);\n }, [activeTab, fetchTab]);\n\n // -- Reconnect handler ----------------------------------------------------\n const handleReconnect = () => {\n requestOAuth('zerodha');\n };\n\n // -- Render ---------------------------------------------------------------\n return (\n <div\n style={{\n padding: 24,\n fontFamily: 'inherit',\n color: v('foreground'),\n background: v('background'),\n minHeight: '100%',\n }}\n >\n {/* Header */}\n <h2 style={{ marginTop: 0, marginBottom: 16 }}>Zerodha</h2>\n\n {/* Credential status */}\n <section style={{ marginBottom: 24 }}>\n <h3 style={{ fontSize: 14, color: v('muted'), marginBottom: 8 }}>Connection</h3>\n <table style={{ borderCollapse: 'collapse', width: '100%' }}>\n <tbody>\n <CredentialRow label=\"API Key\" status={apiKeyStatus} />\n <CredentialRow label=\"API Secret\" status={apiSecretStatus} />\n <tr>\n <td style={{ padding: '6px 0', width: 140 }}>Access Token</td>\n <td\n style={{\n color: connected ? v('success') : v('warning'),\n }}\n >\n <StatusBadge ok={connected} />\n {connected ? `Connected (${tokenPreview})` : 'Not connected'}\n </td>\n </tr>\n </tbody>\n </table>\n\n <button\n type=\"button\"\n onClick={handleReconnect}\n style={{\n marginTop: 12,\n padding: '8px 16px',\n background: v('brand'),\n color: '#fff',\n border: 'none',\n borderRadius: 4,\n cursor: 'pointer',\n fontSize: 13,\n }}\n >\n {connected ? 'Reconnect Zerodha' : 'Connect Zerodha'}\n </button>\n </section>\n\n {/* Tabs */}\n {connected && (\n <section>\n <div\n style={{\n display: 'flex',\n gap: 0,\n borderBottom: `1px solid ${v('border')}`,\n marginBottom: 16,\n }}\n >\n <TabButton\n label=\"Holdings\"\n active={activeTab === 'holdings'}\n onClick={() => setActiveTab('holdings')}\n />\n <TabButton\n label=\"Positions\"\n active={activeTab === 'positions'}\n onClick={() => setActiveTab('positions')}\n />\n <TabButton\n label=\"Orders\"\n active={activeTab === 'orders'}\n onClick={() => setActiveTab('orders')}\n />\n </div>\n\n {loading && <Spinner />}\n {error && <ErrorBanner message={error} />}\n\n {!loading && !error && activeTab === 'holdings' && <HoldingsTab data={holdingsData} />}\n {!loading && !error && activeTab === 'positions' && <PositionsTab data={positionsData} />}\n {!loading && !error && activeTab === 'orders' && <OrdersTab data={ordersData} />}\n </section>\n )}\n\n {/* Disconnected state — prompt to connect */}\n {!connected && apiKeyStatus !== 'checking' && (\n <section style={{ marginTop: 16 }}>\n <p style={{ color: v('muted'), fontSize: 13 }}>\n Connect your Zerodha account to view holdings, positions, and orders.\n </p>\n </section>\n )}\n </div>\n );\n}\n"],"mappings":"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","names":[]}
|