@363045841yyt/klinechart-core 0.8.2 → 0.8.3
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/dist/controllers/createChartController.d.ts.map +1 -1
- package/dist/controllers/createChartController.js +31 -0
- package/dist/controllers/createChartController.js.map +1 -1
- package/dist/controllers/types.d.ts +16 -0
- package/dist/controllers/types.d.ts.map +1 -1
- package/dist/data-fetchers/baostock.d.ts +9 -2
- package/dist/data-fetchers/baostock.d.ts.map +1 -1
- package/dist/data-fetchers/baostock.js +78 -9
- package/dist/data-fetchers/baostock.js.map +1 -1
- package/dist/data-fetchers/fetcherDefinitionRegistry.d.ts +13 -0
- package/dist/data-fetchers/fetcherDefinitionRegistry.d.ts.map +1 -0
- package/dist/data-fetchers/fetcherDefinitionRegistry.js +36 -0
- package/dist/data-fetchers/fetcherDefinitionRegistry.js.map +1 -0
- package/dist/data-fetchers/gotdx.d.ts +9 -2
- package/dist/data-fetchers/gotdx.d.ts.map +1 -1
- package/dist/data-fetchers/gotdx.js +72 -5
- package/dist/data-fetchers/gotdx.js.map +1 -1
- package/dist/data-fetchers/hundred-mock.d.ts +9 -2
- package/dist/data-fetchers/hundred-mock.d.ts.map +1 -1
- package/dist/data-fetchers/hundred-mock.js +66 -4
- package/dist/data-fetchers/hundred-mock.js.map +1 -1
- package/dist/data-fetchers/index.d.ts +7 -5
- package/dist/data-fetchers/index.d.ts.map +1 -1
- package/dist/data-fetchers/index.js +6 -5
- package/dist/data-fetchers/index.js.map +1 -1
- package/dist/data-fetchers/router.d.ts.map +1 -1
- package/dist/data-fetchers/router.js +14 -18
- package/dist/data-fetchers/router.js.map +1 -1
- package/dist/data-fetchers/thousand-mock.d.ts +9 -2
- package/dist/data-fetchers/thousand-mock.d.ts.map +1 -1
- package/dist/data-fetchers/thousand-mock.js +66 -4
- package/dist/data-fetchers/thousand-mock.js.map +1 -1
- package/dist/data-fetchers/tradingview.d.ts +9 -2
- package/dist/data-fetchers/tradingview.d.ts.map +1 -1
- package/dist/data-fetchers/tradingview.js +73 -9
- package/dist/data-fetchers/tradingview.js.map +1 -1
- package/dist/data-fetchers/types.d.ts +21 -0
- package/dist/data-fetchers/types.d.ts.map +1 -0
- package/dist/data-fetchers/types.js +2 -0
- package/dist/data-fetchers/types.js.map +1 -0
- package/dist/engine/renderers/Indicator/ichimoku.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/ichimoku.js +8 -5
- package/dist/engine/renderers/Indicator/ichimoku.js.map +1 -1
- package/dist/engine/renderers/Indicator/sar.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/sar.js +3 -3
- package/dist/engine/renderers/Indicator/sar.js.map +1 -1
- package/dist/engine/renderers/Indicator/supertrend.d.ts.map +1 -1
- package/dist/engine/renderers/Indicator/supertrend.js +3 -3
- package/dist/engine/renderers/Indicator/supertrend.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/mcp/chartBridge.d.ts +47 -0
- package/dist/mcp/chartBridge.d.ts.map +1 -0
- package/dist/mcp/chartBridge.js +167 -0
- package/dist/mcp/chartBridge.js.map +1 -0
- package/dist/mcp/index.d.ts +3 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +2 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/mcp/types.d.ts +17 -0
- package/dist/mcp/types.d.ts.map +1 -0
- package/dist/mcp/types.js +2 -0
- package/dist/mcp/types.js.map +1 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
- package/src/controllers/createChartController.ts +34 -0
- package/src/controllers/types.ts +9 -0
- package/src/data-fetchers/__tests__/fetcherRegistry.test.ts +192 -0
- package/src/data-fetchers/baostock.ts +54 -22
- package/src/data-fetchers/fetcherDefinitionRegistry.ts +50 -0
- package/src/data-fetchers/gotdx.ts +28 -6
- package/src/data-fetchers/hundred-mock.ts +21 -4
- package/src/data-fetchers/index.ts +19 -5
- package/src/data-fetchers/router.ts +27 -18
- package/src/data-fetchers/thousand-mock.ts +21 -4
- package/src/data-fetchers/tradingview.ts +30 -11
- package/src/data-fetchers/types.ts +27 -0
- package/src/engine/renderers/Indicator/ichimoku.ts +10 -4
- package/src/engine/renderers/Indicator/sar.ts +3 -3
- package/src/engine/renderers/Indicator/supertrend.ts +3 -4
- package/src/index.ts +1 -0
- package/src/mcp/chartBridge.ts +220 -0
- package/src/mcp/index.ts +2 -0
- package/src/mcp/types.ts +19 -0
- package/src/version.ts +1 -1
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { RendererPluginWithHost, RenderContext, PluginHost } from '../../../plugin'
|
|
2
2
|
import { RENDERER_PRIORITY } from '../../../plugin'
|
|
3
|
+
import { resolveThemeColors } from '../../../tokens'
|
|
3
4
|
import type { KLineData } from '../../../types/price'
|
|
4
5
|
import type { IchimokuRenderState } from '../../indicators/ichimokuState'
|
|
5
6
|
import { createIchimokuStateKey, EMPTY_ICHIMOKU_STATE } from '../../indicators/ichimokuState'
|
|
@@ -14,8 +15,6 @@ const KIJUN_COLOR = '#2563eb'
|
|
|
14
15
|
const SPAN_A_COLOR = '#16a34a'
|
|
15
16
|
const SPAN_B_COLOR = '#dc2626'
|
|
16
17
|
const CHIKOU_COLOR = '#7c3aed'
|
|
17
|
-
const CLOUD_BULL = 'rgba(34, 197, 94, 0.15)'
|
|
18
|
-
const CLOUD_BEAR = 'rgba(239, 68, 68, 0.15)'
|
|
19
18
|
|
|
20
19
|
type Point = { x: number; y: number }
|
|
21
20
|
|
|
@@ -58,6 +57,7 @@ export function createIchimokuRendererPlugin(options: IchimokuRendererOptions =
|
|
|
58
57
|
|
|
59
58
|
draw(context: RenderContext) {
|
|
60
59
|
const { ctx, pane, range, scrollLeft, kLineCenters, lineWebGLSurface } = context
|
|
60
|
+
const colors = resolveThemeColors(context.theme, context.isAsiaMarket, context.colorPresetSettings)
|
|
61
61
|
const stateKey = resolveKey()
|
|
62
62
|
if (!stateKey) return
|
|
63
63
|
const state = pluginHost?.getSharedState<IchimokuRenderState>(stateKey)
|
|
@@ -94,7 +94,7 @@ export function createIchimokuRendererPlugin(options: IchimokuRendererOptions =
|
|
|
94
94
|
if (params.showCloud && cloudSegs.length >= 2) {
|
|
95
95
|
ctx.save()
|
|
96
96
|
ctx.translate(-scrollLeft, 0)
|
|
97
|
-
fillCloud(ctx, cloudSegs)
|
|
97
|
+
fillCloud(ctx, cloudSegs, colors.candleUpBody, colors.candleDownBody)
|
|
98
98
|
ctx.restore()
|
|
99
99
|
}
|
|
100
100
|
|
|
@@ -153,11 +153,16 @@ function drawLine(ctx: CanvasRenderingContext2D, pts: Point[], color: string): v
|
|
|
153
153
|
function fillCloud(
|
|
154
154
|
ctx: CanvasRenderingContext2D,
|
|
155
155
|
segs: { x: number; ya: number; yb: number; bull: boolean }[],
|
|
156
|
+
bullColor: string,
|
|
157
|
+
bearColor: string,
|
|
158
|
+
alpha = 0.15,
|
|
156
159
|
): void {
|
|
160
|
+
ctx.save()
|
|
161
|
+
ctx.globalAlpha = alpha
|
|
157
162
|
for (let i = 0; i < segs.length - 1; i++) {
|
|
158
163
|
const a = segs[i]!
|
|
159
164
|
const b = segs[i + 1]!
|
|
160
|
-
ctx.fillStyle = a.bull ?
|
|
165
|
+
ctx.fillStyle = a.bull ? bullColor : bearColor
|
|
161
166
|
ctx.beginPath()
|
|
162
167
|
ctx.moveTo(a.x, a.ya)
|
|
163
168
|
ctx.lineTo(b.x, b.ya)
|
|
@@ -166,6 +171,7 @@ function fillCloud(
|
|
|
166
171
|
ctx.closePath()
|
|
167
172
|
ctx.fill()
|
|
168
173
|
}
|
|
174
|
+
ctx.restore()
|
|
169
175
|
}
|
|
170
176
|
|
|
171
177
|
export function getIchimokuTitleInfo(
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { RendererPluginWithHost, RenderContext, PluginHost } from '../../../plugin'
|
|
2
2
|
import { RENDERER_PRIORITY } from '../../../plugin'
|
|
3
|
+
import { resolveThemeColors } from '../../../tokens'
|
|
3
4
|
import type { KLineData } from '../../../types/price'
|
|
4
5
|
import type { SARRenderState } from '../../indicators/sarState'
|
|
5
6
|
import { createSARStateKey, EMPTY_SAR_STATE } from '../../indicators/sarState'
|
|
@@ -9,8 +10,6 @@ import type { IndicatorScheduler, SARSchedulerConfig } from '../../indicators/sc
|
|
|
9
10
|
import { calcSARData } from '../../indicators/calculators'
|
|
10
11
|
import { createValuePointVisibleStateComposer } from '../../indicators/visibleStateComposers'
|
|
11
12
|
|
|
12
|
-
const SAR_UP_COLOR = '#22c55e'
|
|
13
|
-
const SAR_DOWN_COLOR = '#ef4444'
|
|
14
13
|
const DOT_RADIUS = 1.5
|
|
15
14
|
const TAU = Math.PI * 2
|
|
16
15
|
|
|
@@ -59,6 +58,7 @@ export function createSARRendererPlugin(options: SARRendererOptions = {}): Rende
|
|
|
59
58
|
|
|
60
59
|
draw(context: RenderContext) {
|
|
61
60
|
const { ctx, pane, range, scrollLeft, kLineCenters } = context
|
|
61
|
+
const colors = resolveThemeColors(context.theme, context.isAsiaMarket, context.colorPresetSettings)
|
|
62
62
|
|
|
63
63
|
const stateKey = resolveKey()
|
|
64
64
|
if (!stateKey) return
|
|
@@ -77,7 +77,7 @@ export function createSARRendererPlugin(options: SARRendererOptions = {}): Rende
|
|
|
77
77
|
const centerX = kLineCenters[i - range.start]
|
|
78
78
|
if (centerX === undefined) continue
|
|
79
79
|
const y = pane.yAxis.priceToY(point.value)
|
|
80
|
-
ctx.fillStyle = point.trend === 'up' ?
|
|
80
|
+
ctx.fillStyle = point.trend === 'up' ? colors.candleUpBody : colors.candleDownBody
|
|
81
81
|
ctx.beginPath()
|
|
82
82
|
ctx.arc(centerX, y, DOT_RADIUS, 0, TAU)
|
|
83
83
|
ctx.fill()
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { RendererPluginWithHost, RenderContext, PluginHost } from '../../../plugin'
|
|
2
2
|
import { RENDERER_PRIORITY } from '../../../plugin'
|
|
3
|
+
import { resolveThemeColors } from '../../../tokens'
|
|
3
4
|
import type { KLineData } from '../../../types/price'
|
|
4
5
|
import type { SuperTrendRenderState } from '../../indicators/supertrendState'
|
|
5
6
|
import { createSuperTrendStateKey, EMPTY_SUPERTREND_STATE } from '../../indicators/supertrendState'
|
|
@@ -9,9 +10,6 @@ import type { IndicatorScheduler, SuperTrendSchedulerConfig } from '../../indica
|
|
|
9
10
|
import { calcSuperTrendData } from '../../indicators/calculators'
|
|
10
11
|
import { createValuePointVisibleStateComposer } from '../../indicators/visibleStateComposers'
|
|
11
12
|
|
|
12
|
-
const ST_UP_COLOR = '#22c55e'
|
|
13
|
-
const ST_DOWN_COLOR = '#ef4444'
|
|
14
|
-
|
|
15
13
|
export interface SuperTrendRendererOptions {
|
|
16
14
|
paneId?: string
|
|
17
15
|
}
|
|
@@ -51,6 +49,7 @@ export function createSuperTrendRendererPlugin(options: SuperTrendRendererOption
|
|
|
51
49
|
|
|
52
50
|
draw(context: RenderContext) {
|
|
53
51
|
const { ctx, pane, range, scrollLeft, kLineCenters } = context
|
|
52
|
+
const colors = resolveThemeColors(context.theme, context.isAsiaMarket, context.colorPresetSettings)
|
|
54
53
|
const stateKey = resolveKey()
|
|
55
54
|
if (!stateKey) return
|
|
56
55
|
const state = pluginHost?.getSharedState<SuperTrendRenderState>(stateKey)
|
|
@@ -77,7 +76,7 @@ export function createSuperTrendRendererPlugin(options: SuperTrendRendererOption
|
|
|
77
76
|
const y = pane.yAxis.priceToY(point.value)
|
|
78
77
|
|
|
79
78
|
if (prevX !== null && prevTrend === point.trend) {
|
|
80
|
-
ctx.strokeStyle = point.trend === 'up' ?
|
|
79
|
+
ctx.strokeStyle = point.trend === 'up' ? colors.candleUpBody : colors.candleDownBody
|
|
81
80
|
ctx.beginPath()
|
|
82
81
|
ctx.moveTo(prevX, prevY!)
|
|
83
82
|
ctx.lineTo(centerX, y)
|
package/src/index.ts
CHANGED
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
import type { ToolCall, ToolResult, ControllerDescription, ToolCallHandler } from './types'
|
|
2
|
+
|
|
3
|
+
export interface ChartBridgeOptions {
|
|
4
|
+
wsUrl: string
|
|
5
|
+
onToolCall: ToolCallHandler
|
|
6
|
+
sessionId?: string
|
|
7
|
+
autoReconnect?: boolean
|
|
8
|
+
reconnectDelay?: number
|
|
9
|
+
heartbeatInterval?: number
|
|
10
|
+
wsImpl?: new (url: string) => WebSocket
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export type ChartBridgeEvent =
|
|
14
|
+
| 'connected'
|
|
15
|
+
| 'disconnected'
|
|
16
|
+
| 'error'
|
|
17
|
+
| 'stateChanged'
|
|
18
|
+
|
|
19
|
+
type MessageHandler = (...args: unknown[]) => void
|
|
20
|
+
|
|
21
|
+
export class ChartBridge {
|
|
22
|
+
readonly sessionId: string
|
|
23
|
+
private readonly autoReconnect: boolean
|
|
24
|
+
private readonly reconnectDelay: number
|
|
25
|
+
private readonly heartbeatInterval: number
|
|
26
|
+
private readonly onToolCall: ToolCallHandler
|
|
27
|
+
|
|
28
|
+
private readonly wsImpl: new (url: string) => WebSocket
|
|
29
|
+
private ws: WebSocket | null = null
|
|
30
|
+
private reconnectTimer: ReturnType<typeof setTimeout> | null = null
|
|
31
|
+
private heartbeatTimer: ReturnType<typeof setInterval> | null = null
|
|
32
|
+
private destroyed = false
|
|
33
|
+
|
|
34
|
+
private listeners = new Map<ChartBridgeEvent, Set<MessageHandler>>()
|
|
35
|
+
|
|
36
|
+
onConnected?: () => void
|
|
37
|
+
onDisconnected?: () => void
|
|
38
|
+
onError?: (err: Error) => void
|
|
39
|
+
onStateChange?: () => void
|
|
40
|
+
|
|
41
|
+
constructor(options: ChartBridgeOptions) {
|
|
42
|
+
this.sessionId = options.sessionId ?? crypto.randomUUID()
|
|
43
|
+
this.autoReconnect = options.autoReconnect ?? true
|
|
44
|
+
this.reconnectDelay = options.reconnectDelay ?? 3000
|
|
45
|
+
this.heartbeatInterval = options.heartbeatInterval ?? 30_000
|
|
46
|
+
this.onToolCall = options.onToolCall
|
|
47
|
+
this.wsImpl = options.wsImpl ?? WebSocket
|
|
48
|
+
this.wsUrl = options.wsUrl
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
private wsUrl: string
|
|
52
|
+
|
|
53
|
+
async connect(): Promise<void> {
|
|
54
|
+
if (this.destroyed) return
|
|
55
|
+
this.disconnect()
|
|
56
|
+
|
|
57
|
+
return new Promise((resolve, reject) => {
|
|
58
|
+
try {
|
|
59
|
+
const ws = new this.wsImpl(this.wsUrl)
|
|
60
|
+
|
|
61
|
+
ws.onopen = () => {
|
|
62
|
+
this.ws = ws
|
|
63
|
+
console.info(
|
|
64
|
+
`[ChartBridge] WS opened → sending register (sessionId=${this.sessionId})`,
|
|
65
|
+
)
|
|
66
|
+
ws.send(JSON.stringify({ type: 'register', sessionId: this.sessionId }))
|
|
67
|
+
this.startHeartbeat()
|
|
68
|
+
this.onConnected?.()
|
|
69
|
+
this.emit('connected')
|
|
70
|
+
resolve()
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
ws.onmessage = (event: MessageEvent) => {
|
|
74
|
+
let msg: Record<string, unknown>
|
|
75
|
+
try {
|
|
76
|
+
msg = JSON.parse(event.data as string)
|
|
77
|
+
} catch {
|
|
78
|
+
return
|
|
79
|
+
}
|
|
80
|
+
this.handleMessage(msg)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
ws.onclose = () => {
|
|
84
|
+
console.warn(
|
|
85
|
+
`[ChartBridge] WS closed, autoReconnect=${this.autoReconnect}`,
|
|
86
|
+
)
|
|
87
|
+
this.ws = null
|
|
88
|
+
this.stopHeartbeat()
|
|
89
|
+
this.onDisconnected?.()
|
|
90
|
+
this.emit('disconnected')
|
|
91
|
+
if (this.autoReconnect && !this.destroyed) {
|
|
92
|
+
this.scheduleReconnect()
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
ws.onerror = () => {
|
|
97
|
+
console.error(`[ChartBridge] WS error — connection failed`)
|
|
98
|
+
const err = new Error('WebSocket connection failed')
|
|
99
|
+
this.onError?.(err)
|
|
100
|
+
this.emit('error', err)
|
|
101
|
+
reject(err)
|
|
102
|
+
}
|
|
103
|
+
} catch (err) {
|
|
104
|
+
reject(err)
|
|
105
|
+
}
|
|
106
|
+
})
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
disconnect(): void {
|
|
110
|
+
this.ws?.close()
|
|
111
|
+
this.ws = null
|
|
112
|
+
this.cancelReconnect()
|
|
113
|
+
this.stopHeartbeat()
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
destroy(): void {
|
|
117
|
+
this.destroyed = true
|
|
118
|
+
this.disconnect()
|
|
119
|
+
this.listeners.clear()
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
private handleMessage(msg: Record<string, unknown>): void {
|
|
123
|
+
switch (msg.type) {
|
|
124
|
+
case 'registered':
|
|
125
|
+
break
|
|
126
|
+
|
|
127
|
+
case 'tool:call': {
|
|
128
|
+
const call = msg.call as ToolCall
|
|
129
|
+
const requestId = msg.requestId as string
|
|
130
|
+
this.dispatchToolCall(requestId, call)
|
|
131
|
+
break
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
case 'ping': {
|
|
135
|
+
this.ws?.send(JSON.stringify({ type: 'pong' }))
|
|
136
|
+
break
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
private async dispatchToolCall(requestId: string, call: ToolCall): Promise<void> {
|
|
142
|
+
const result = await this.onToolCall(call)
|
|
143
|
+
this.sendResult(requestId, result)
|
|
144
|
+
|
|
145
|
+
if (this.onStateChange) {
|
|
146
|
+
this.onStateChange()
|
|
147
|
+
}
|
|
148
|
+
this.emit('stateChanged')
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
private sendResult(requestId: string, result: ToolResult): void {
|
|
152
|
+
this.ws?.send(
|
|
153
|
+
JSON.stringify({
|
|
154
|
+
type: 'tool:result',
|
|
155
|
+
requestId,
|
|
156
|
+
result,
|
|
157
|
+
}),
|
|
158
|
+
)
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
sendStateUpdate(
|
|
162
|
+
descriptions: Record<string, ControllerDescription>,
|
|
163
|
+
): void {
|
|
164
|
+
this.ws?.send(
|
|
165
|
+
JSON.stringify({
|
|
166
|
+
type: 'state:update',
|
|
167
|
+
sessionId: this.sessionId,
|
|
168
|
+
descriptions,
|
|
169
|
+
}),
|
|
170
|
+
)
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
private startHeartbeat(): void {
|
|
174
|
+
this.stopHeartbeat()
|
|
175
|
+
this.heartbeatTimer = setInterval(() => {
|
|
176
|
+
if (this.ws?.readyState === 1) {
|
|
177
|
+
this.ws.send(JSON.stringify({ type: 'ping' }))
|
|
178
|
+
}
|
|
179
|
+
}, this.heartbeatInterval)
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
private stopHeartbeat(): void {
|
|
183
|
+
if (this.heartbeatTimer !== null) {
|
|
184
|
+
clearInterval(this.heartbeatTimer)
|
|
185
|
+
this.heartbeatTimer = null
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
private scheduleReconnect(): void {
|
|
190
|
+
this.cancelReconnect()
|
|
191
|
+
this.reconnectTimer = setTimeout(() => {
|
|
192
|
+
if (!this.destroyed) {
|
|
193
|
+
this.connect()
|
|
194
|
+
}
|
|
195
|
+
}, this.reconnectDelay)
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
private cancelReconnect(): void {
|
|
199
|
+
if (this.reconnectTimer !== null) {
|
|
200
|
+
clearTimeout(this.reconnectTimer)
|
|
201
|
+
this.reconnectTimer = null
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
private emit(event: ChartBridgeEvent, ...args: unknown[]): void {
|
|
206
|
+
this.listeners.get(event)?.forEach((fn) => fn(...args))
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
on(event: ChartBridgeEvent, handler: MessageHandler): () => void {
|
|
210
|
+
if (!this.listeners.has(event)) {
|
|
211
|
+
this.listeners.set(event, new Set())
|
|
212
|
+
}
|
|
213
|
+
this.listeners.get(event)!.add(handler)
|
|
214
|
+
return () => this.listeners.get(event)?.delete(handler)
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
off(event: ChartBridgeEvent, handler: MessageHandler): void {
|
|
218
|
+
this.listeners.get(event)?.delete(handler)
|
|
219
|
+
}
|
|
220
|
+
}
|
package/src/mcp/index.ts
ADDED
package/src/mcp/types.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export interface ToolCall {
|
|
2
|
+
name: string
|
|
3
|
+
input: Record<string, unknown>
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export interface ToolResult {
|
|
7
|
+
success: boolean
|
|
8
|
+
error?: string
|
|
9
|
+
data?: unknown
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export type ToolCallHandler = (call: ToolCall) => ToolResult | Promise<ToolResult>
|
|
13
|
+
|
|
14
|
+
export interface ControllerDescription {
|
|
15
|
+
controllerId: string
|
|
16
|
+
summary: string
|
|
17
|
+
facts: Readonly<Record<string, string | number | boolean | null>>
|
|
18
|
+
warnings?: ReadonlyArray<string>
|
|
19
|
+
}
|
package/src/version.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const VERSION = "0.8.
|
|
1
|
+
export const VERSION = "0.8.3"
|