@v587d/capital-generation 0.0.0-stage → 2.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (117) hide show
  1. package/CHANGELOG.md +794 -0
  2. package/LICENSE +21 -0
  3. package/README.md +116 -2
  4. package/assets/cg-icon.png +0 -0
  5. package/capital-config/client.js +28 -0
  6. package/capital-config/client.src.cjs +388 -0
  7. package/capital-config/index.js +113 -0
  8. package/capital-config/package.json +36 -0
  9. package/capital-watchlist/client.js +182 -0
  10. package/capital-watchlist/client.src.cjs +1229 -0
  11. package/capital-watchlist/index.js +772 -0
  12. package/capital-watchlist/package.json +37 -0
  13. package/chart-ui/README.md +112 -0
  14. package/chart-ui/client.js +16 -0
  15. package/chart-ui/client.src.cjs +126 -0
  16. package/chart-ui/index.js +205 -0
  17. package/chart-ui/package.json +30 -0
  18. package/cordis.patch.yml +72 -0
  19. package/lib/agents/bash-guard.d.ts +55 -0
  20. package/lib/agents/bash-guard.js +162 -0
  21. package/lib/agents/root-tool-policy.d.ts +164 -0
  22. package/lib/agents/root-tool-policy.js +309 -0
  23. package/lib/chart/artifact-ref.d.ts +65 -0
  24. package/lib/chart/artifact-ref.js +107 -0
  25. package/lib/chart/downsample.d.ts +8 -0
  26. package/lib/chart/downsample.js +53 -0
  27. package/lib/chart/errors.d.ts +16 -0
  28. package/lib/chart/errors.js +15 -0
  29. package/lib/chart/events.d.ts +120 -0
  30. package/lib/chart/events.js +471 -0
  31. package/lib/chart/html.d.ts +21 -0
  32. package/lib/chart/html.js +154 -0
  33. package/lib/chart/runtime.d.ts +20 -0
  34. package/lib/chart/runtime.js +270 -0
  35. package/lib/chart/series.d.ts +102 -0
  36. package/lib/chart/series.js +424 -0
  37. package/lib/chart/source-token.d.ts +64 -0
  38. package/lib/chart/source-token.js +217 -0
  39. package/lib/chart/spec.d.ts +58 -0
  40. package/lib/chart/spec.js +265 -0
  41. package/lib/chart/tool.d.ts +86 -0
  42. package/lib/chart/tool.js +288 -0
  43. package/lib/chart/vendor/LICENSE +201 -0
  44. package/lib/chart/vendor/VERSION.json +8 -0
  45. package/lib/chart/vendor/lightweight-charts.standalone.production.js +7 -0
  46. package/lib/data-collector/args.d.ts +38 -0
  47. package/lib/data-collector/args.js +114 -0
  48. package/lib/data-collector/dataset-tools.d.ts +3 -0
  49. package/lib/data-collector/dataset-tools.js +421 -0
  50. package/lib/data-collector/describe.d.ts +99 -0
  51. package/lib/data-collector/describe.js +256 -0
  52. package/lib/data-collector/hub.d.ts +187 -0
  53. package/lib/data-collector/hub.js +469 -0
  54. package/lib/data-collector/query-time.d.ts +58 -0
  55. package/lib/data-collector/query-time.js +101 -0
  56. package/lib/data-collector/query.d.ts +57 -0
  57. package/lib/data-collector/query.js +473 -0
  58. package/lib/data-collector/store.d.ts +499 -0
  59. package/lib/data-collector/store.js +1486 -0
  60. package/lib/data-collector/time-axis.d.ts +169 -0
  61. package/lib/data-collector/time-axis.js +419 -0
  62. package/lib/data-collector/tools.d.ts +32 -0
  63. package/lib/data-collector/tools.js +216 -0
  64. package/lib/index.d.ts +275 -0
  65. package/lib/index.js +458 -0
  66. package/lib/net/eastmoney-client.d.ts +104 -0
  67. package/lib/net/eastmoney-client.js +118 -0
  68. package/lib/net/throttle.d.ts +16 -0
  69. package/lib/net/throttle.js +34 -0
  70. package/lib/ocr/client.d.ts +82 -0
  71. package/lib/ocr/client.js +281 -0
  72. package/lib/ocr/markdown.d.ts +75 -0
  73. package/lib/ocr/markdown.js +209 -0
  74. package/lib/ocr/store.d.ts +119 -0
  75. package/lib/ocr/store.js +226 -0
  76. package/lib/sources/eastmoney-http.d.ts +2 -0
  77. package/lib/sources/eastmoney-http.js +1253 -0
  78. package/lib/sources/fuyao-core.d.ts +52 -0
  79. package/lib/sources/fuyao-core.js +96 -0
  80. package/lib/sources/fuyao-rest.d.ts +14 -0
  81. package/lib/sources/fuyao-rest.js +2057 -0
  82. package/lib/sources/security-code.d.ts +27 -0
  83. package/lib/sources/security-code.js +104 -0
  84. package/lib/sources/security-identity.d.ts +24 -0
  85. package/lib/sources/security-identity.js +89 -0
  86. package/lib/sources/tencent-http.d.ts +2 -0
  87. package/lib/sources/tencent-http.js +1053 -0
  88. package/lib/sources/wind-mcp.d.ts +8 -0
  89. package/lib/sources/wind-mcp.js +593 -0
  90. package/lib/time/tools.d.ts +74 -0
  91. package/lib/time/tools.js +464 -0
  92. package/lib/tool-exec.d.ts +29 -0
  93. package/lib/tool-exec.js +17 -0
  94. package/lib/web-retriever/engines.d.ts +61 -0
  95. package/lib/web-retriever/engines.js +202 -0
  96. package/lib/web-retriever/html-markdown.d.ts +50 -0
  97. package/lib/web-retriever/html-markdown.js +321 -0
  98. package/lib/web-retriever/local-fetch.d.ts +121 -0
  99. package/lib/web-retriever/local-fetch.js +562 -0
  100. package/lib/web-retriever/retriever.d.ts +58 -0
  101. package/lib/web-retriever/retriever.js +94 -0
  102. package/lib/web-retriever/sources.d.ts +235 -0
  103. package/lib/web-retriever/sources.js +961 -0
  104. package/lib/web-retriever/tools.d.ts +50 -0
  105. package/lib/web-retriever/tools.js +1029 -0
  106. package/lib/web-retriever/wind-client.d.ts +69 -0
  107. package/lib/web-retriever/wind-client.js +311 -0
  108. package/locale/en.json +6 -0
  109. package/locale/zh.json +6 -0
  110. package/package.json +76 -4
  111. package/preset/capital-generation/README.md +161 -0
  112. package/preset/capital-generation/agent.patch.yml +509 -0
  113. package/preset/capital-generation/skills/capital-chart-protocol/SKILL.md +137 -0
  114. package/preset/capital-generation/skills/capital-data-protocol/SKILL.md +416 -0
  115. package/preset/capital-generation/skills/capital-orchestration/SKILL.md +174 -0
  116. package/preset/capital-generation/skills/capital-visualization-protocol/SKILL.md +296 -0
  117. package/preset/capital-generation/skills/capital-web-protocol/SKILL.md +240 -0
@@ -0,0 +1,20 @@
1
+ /**
2
+ * 浏览器侧渲染运行时 —— 以**源码字符串**形式存在,而不是一个模块。
3
+ *
4
+ * 为什么是字符串:同一段渲染代码有两个宿主,二者都不能 pre-built 共用同一份模块——
5
+ * 1. **自包含 HTML 产物**(本步就有):内联进 `<script>`,离线双击可开;
6
+ * 2. **对话流内嵌视图**(Step 3):DSH 客户端 bundle 里再包一次。
7
+ * 写成字符串可以保证两边**逐字节同源**,不会出现"文件里对、页面上错"。
8
+ * 代价是这里没有类型检查,所以 test/chart-runtime.test.mjs 会用 `new Function`
9
+ * 做一次语法与 API 形状校验,把笔误挡在测试里而不是浏览器里。
10
+ *
11
+ * 约束:这段源码里**不能**出现反引号或 `${`(它本身在 TS 模板字符串里)。
12
+ * 依赖:DOM,以及**由调用方传入**的图表库对象(自包含 HTML 传 UMD 全局,Step 3 客户端传
13
+ * ESM import)。刻意不读、也不回退到 `globalThis.LightweightCharts`:那条全局正是与其它
14
+ * 插件带的同库不同版本互相覆盖的来源(见内部设计文档 docs/design/chart-visualization.md §9 风险表)。
15
+ * 形态:IIFE **返回** `{ render, version }`,由各宿主自行捕获(HTML 用 `var __capitalChart =`,
16
+ * 客户端 bundle 存为模块局部),**不往任何全局挂载**。
17
+ * 主题:只读 CSS 变量 `--dsw-*`(见 docs/reference/dsh-surface-ledger.md L7),
18
+ * 不调 DSH 的 theme 服务;自包含 HTML 自己定义同一批变量,因此两边渲染完全一致。
19
+ */
20
+ export declare const CHART_RUNTIME_SOURCE = "\n(function () {\n 'use strict'\n\n var FALLBACK = {\n '--dsw-alias-bg-base': '#ffffff',\n '--dsw-alias-border-l1': 'rgba(0, 0, 0, 0.10)',\n '--dsw-alias-label-primary': '#1f2328',\n '--dsw-alias-label-secondary': '#6b7280',\n '--dsw-alias-brand-primary': '#2563eb',\n '--dsw-alias-state-error-primary': '#d94a3d',\n '--dsw-alias-state-success-primary': '#2f9e44'\n }\n\n // \u4E3B\u9898 token \u4E0D\u4E00\u5B9A\u662F\u5341\u516D\u8FDB\u5236\uFF08\u4E5F\u53EF\u80FD\u662F rgb/rgba \u6216\u81EA\u5B9A\u4E49 CSS \u8272\u503C\uFF09\u3002\u53EA\u6709\u786E\u8BA4\u662F\n // \u5341\u516D\u8FDB\u5236\u65F6\u624D\u8FFD\u52A0 alpha\uFF1B\u5176\u4F59\u683C\u5F0F\u8F6C\u6362\u6210 rgba\uFF0C\u8F6C\u6362\u4E0D\u4E86\u5C31\u9000\u56DE\u539F\u8272\uFF0C\u7EDD\u4E0D\u62FC\u51FA\u975E\u6CD5 CSS\u3002\n function withAlpha(color, alpha) {\n var text = String(color || '').trim()\n var hex = /^#([0-9a-f]{3}|[0-9a-f]{6})$/i.exec(text)\n if (hex) {\n var expanded = hex[1].length === 3\n ? '#' + hex[1].split('').map(function (part) { return part + part }).join('')\n : text\n return expanded + Math.round(alpha * 255).toString(16).padStart(2, '0')\n }\n var rgb = /^rgba?\\(\\s*([^)]*)\\)$/i.exec(text)\n if (rgb) {\n var parts = rgb[1].split(/[,\\s/]+/).filter(Boolean)\n if (parts.length >= 3 && parts.slice(0, 3).every(function (part) { return /^[-+]?\\d*\\.?\\d+%?$/.test(part) })) {\n return 'rgba(' + parts.slice(0, 3).join(', ') + ', ' + alpha + ')'\n }\n }\n return text\n }\n\n // \u591A\u5E8F\u5217\u914D\u8272\uFF1A\u7B2C\u4E00\u6761\u7528\u4E3B\u9898\u54C1\u724C\u8272\uFF0C\u5176\u4F59\u7528\u56FA\u5B9A\u8272\u677F\uFF08\u4FDD\u8BC1\u540C\u4E00\u6761\u5E8F\u5217\u5728\u4E0D\u540C\u56FE\u91CC\u989C\u8272\u4E00\u81F4\uFF09\u3002\n var PALETTE = ['#f59e0b', '#10b981', '#8b5cf6', '#0ea5e9', '#ec4899']\n\n function readToken(name) {\n try {\n var value = getComputedStyle(document.documentElement).getPropertyValue(name)\n if (value && value.trim().length > 0) return value.trim()\n } catch (error) {\n /* \u975E\u6D4F\u89C8\u5668\u73AF\u5883\u6216\u53D6\u4E0D\u5230\u6837\u5F0F\u65F6\u9000\u56DE\u9ED8\u8BA4\u8272 */\n }\n return FALLBACK[name]\n }\n\n function resolveColors() {\n return {\n bg: readToken('--dsw-alias-bg-base'),\n grid: readToken('--dsw-alias-border-l1'),\n text: readToken('--dsw-alias-label-secondary'),\n strong: readToken('--dsw-alias-label-primary'),\n brand: readToken('--dsw-alias-brand-primary'),\n up: readToken('--dsw-alias-state-error-primary'),\n down: readToken('--dsw-alias-state-success-primary')\n }\n }\n\n function showError(container, message) {\n container.textContent = ''\n var box = document.createElement('div')\n box.setAttribute('data-chart-error', '1')\n box.style.cssText = 'padding:12px;border:0.5px solid ' + readToken('--dsw-alias-border-l1') + ';border-radius:8px;color:' + readToken('--dsw-alias-label-secondary') + ';font-size:13px;line-height:1.6'\n box.textContent = message\n container.appendChild(box)\n }\n\n function applyIndexLabels(chart, labels) {\n function format(time) {\n var key = String(time)\n return Object.prototype.hasOwnProperty.call(labels, key) ? labels[key] : key\n }\n // \u8F74\u7684\u523B\u5EA6\u6587\u6848\u5F52 timeScale.tickMarkFormatter \u7BA1\uFF0C\u5341\u5B57\u7EBF/\u63D0\u793A\u5F52 localization.timeFormatter\uFF1B\n // \u5206\u7C7B\u8F74\u4E24\u8FB9\u90FD\u8981\u6362\u6389\uFF0C\u5426\u5219\u6807\u5C3A\u4E0A\u8FD8\u662F 2000 \u5E74\u90A3\u79CD\u5408\u6210\u65E5\u671F\u3002\n chart.applyOptions({\n localization: { timeFormatter: format },\n timeScale: { tickMarkFormatter: function (time) { return format(time) } }\n })\n }\n\n /**\n * \u6302\u6807\u8BB0\u70B9\u3002v5 \u628A markers \u4ECE series API \u79FB\u5230\u4E86 createSeriesMarkers(series, markers)\n * \u8FD4\u56DE\u7684\u63D2\u4EF6\u5BF9\u8C61\u4E0A\uFF1B\u8FD9\u91CC\u540C\u65F6\u517C\u5BB9\u4E24\u79CD\u5F62\u72B6\uFF0C\u4E0A\u6E38\u518D\u52A8\u4E00\u6B21\u4E5F\u4E0D\u4F1A\u9759\u9ED8\u4E22\u6389\u6807\u8BB0\u3002\n */\n function attachMarkers(anchor, markers, LWC) {\n if (typeof LWC.createSeriesMarkers === 'function') {\n LWC.createSeriesMarkers(anchor, markers)\n return true\n }\n if (anchor && typeof anchor.setMarkers === 'function') {\n anchor.setMarkers(markers)\n return true\n }\n return false\n }\n\n function volumePointColor(point, colors) {\n if (point.direction === 'up') return colors.up\n if (point.direction === 'down') return colors.down\n return colors.brand\n }\n\n function seriesColor(index, colors) {\n return index === 0 ? colors.brand : PALETTE[(index - 1) % PALETTE.length]\n }\n\n function appendLegend(container, payload, colors) {\n var items = []\n if (payload.ohlc && payload.ohlc.label) items.push({ label: payload.ohlc.label, color: colors.up })\n if (Array.isArray(payload.series)) {\n payload.series.forEach(function (item, index) {\n if (item && item.label) items.push({ label: item.label, color: seriesColor(index, colors) })\n })\n }\n if (payload.volume && payload.volume.label) items.push({ label: payload.volume.label, color: colors.brand })\n if (items.length === 0) return\n\n var legend = document.createElement('div')\n legend.setAttribute('data-chart-legend', '1')\n legend.style.cssText = 'position:absolute;z-index:2;top:8px;left:8px;right:8px;display:flex;flex-wrap:wrap;gap:4px 10px;align-items:center;pointer-events:none;color:' + colors.text + ';font-size:11px;line-height:16px'\n items.forEach(function (item) {\n var entry = document.createElement('span')\n entry.style.cssText = 'display:inline-flex;align-items:center;gap:4px;padding:1px 5px;border-radius:4px;background:' + withAlpha(colors.bg, 0.8)\n var swatch = document.createElement('span')\n swatch.style.cssText = 'width:7px;height:7px;border-radius:50%;background:' + item.color + ';flex:none'\n var label = document.createElement('span')\n label.textContent = item.label\n entry.appendChild(swatch)\n entry.appendChild(label)\n legend.appendChild(entry)\n })\n container.appendChild(legend)\n }\n\n function renderCapitalChart(container, payload, library) {\n if (!container) throw new Error('renderCapitalChart: container is required')\n if (!payload || typeof payload !== 'object') throw new Error('renderCapitalChart: payload is required')\n // \u56FE\u8868\u5E93\u7531\u8C03\u7528\u65B9\u6CE8\u5165\uFF0C\u7EDD\u4E0D\u56DE\u9000\u5230\u9875\u9762\u5168\u5C40\uFF1A\u56DE\u9000\u4F1A\u8BA9\"\u53E6\u4E00\u4E2A\u63D2\u4EF6\u7684\u540C\u5E93\u7248\u672C\"\u6084\u6084\u751F\u6548\u3002\n var LWC = library\n if (!LWC || typeof LWC.createChart !== 'function') {\n showError(container, '\u56FE\u8868\u5E93\u672A\u52A0\u8F7D\uFF08\u8C03\u7528\u65B9\u672A\u63D0\u4F9B LightweightCharts\uFF09\u3002')\n return null\n }\n\n var colors = resolveColors()\n container.textContent = ''\n if (container.style) container.style.position = 'relative'\n container.setAttribute('data-chart-id', String(payload.chart_id || ''))\n container.setAttribute('data-chart-kind', String(payload.kind || ''))\n\n var chart = LWC.createChart(container, {\n autoSize: true,\n // attributionLogo \u4FDD\u6301\u5F00\u542F\uFF1A\u8FD9\u6EE1\u8DB3 Apache-2.0 \u5F52\u5C5E\u8981\u6C42\uFF08\u89C1 vendor/lightweight-charts/VERSION.json\uFF09\u3002\n layout: { background: { color: 'transparent' }, textColor: colors.text, fontFamily: 'inherit', attributionLogo: true },\n grid: { vertLines: { color: colors.grid }, horzLines: { color: colors.grid } },\n rightPriceScale: { borderColor: colors.grid, entireTextOnly: true },\n timeScale: { borderColor: colors.grid, rightOffset: 2, barSpacing: 6, minBarSpacing: 0.5 },\n crosshair: { mode: LWC.CrosshairMode ? LWC.CrosshairMode.Normal : 0 },\n localization: { locale: 'zh-CN' }\n })\n\n if (payload.axis === 'index' && payload.labels) applyIndexLabels(chart, payload.labels)\n\n var anchor = null\n\n if (payload.ohlc && Array.isArray(payload.ohlc.data) && payload.ohlc.data.length > 0) {\n // kind=bar \u7528 BarSeries\uFF08OHLC \u67F1\uFF09\uFF0C\u5176\u4F59 OHLC \u56FE\u5F62\u7528 CandlestickSeries\u3002\n // \u4E24\u8005\u7684\u6570\u636E\u5951\u7EA6\u76F8\u540C\uFF08\u90FD\u7EE7\u627F OhlcData\uFF09\uFF0C\u533A\u522B\u53EA\u5728\u6E32\u67D3\u6837\u5F0F\u3002\n var isOhlcBar = payload.kind === 'bar'\n var candles = chart.addSeries(isOhlcBar ? LWC.BarSeries : LWC.CandlestickSeries, {\n upColor: colors.up,\n downColor: colors.down,\n borderUpColor: colors.up,\n borderDownColor: colors.down,\n wickUpColor: colors.up,\n wickDownColor: colors.down\n })\n candles.setData(payload.ohlc.data)\n anchor = candles\n }\n\n if (Array.isArray(payload.series)) {\n for (var index = 0; index < payload.series.length; index += 1) {\n var item = payload.series[index]\n if (!item || !Array.isArray(item.data) || item.data.length === 0) continue\n var color = seriesColor(index, colors)\n var options = { title: item.label || '', priceLineVisible: false, lastValueVisible: true }\n var series = null\n if (item.type === 'area') {\n options.lineColor = color\n options.topColor = withAlpha(color, 0.2)\n options.bottomColor = withAlpha(color, 0.02)\n options.lineWidth = 2\n series = chart.addSeries(LWC.AreaSeries, options)\n } else if (item.type === 'column') {\n // \u5355\u503C\u67F1\uFF1AHistogramSeries \u5403 SingleValueData\uFF08{time, value}\uFF09\u3002\n // \u6CE8\u610F\u4E0D\u80FD\u7528 BarSeries \u2014\u2014 \u5B83\u8981 OhlcData\uFF0C\u585E\u5355\u503C\u53EA\u4F1A\u753B\u51FA\u7A7A\u56FE\u3002\n options.color = color\n options.base = 0\n series = chart.addSeries(LWC.HistogramSeries, options)\n } else {\n options.color = color\n options.lineWidth = 2\n series = chart.addSeries(LWC.LineSeries, options)\n }\n series.setData(item.data)\n if (anchor === null) anchor = series\n }\n }\n\n if (payload.volume && Array.isArray(payload.volume.data) && payload.volume.data.length > 0) {\n var volume = chart.addSeries(LWC.HistogramSeries, {\n title: payload.volume.label || '',\n priceFormat: { type: 'volume' },\n priceLineVisible: false,\n lastValueVisible: false\n }, 1)\n volume.setData(payload.volume.data.map(function (point) {\n return { time: point.time, value: point.value, color: volumePointColor(point, colors) }\n }))\n }\n\n if (anchor === null) {\n showError(container, '\u8FD9\u5F20\u56FE\u6CA1\u6709\u53EF\u6E32\u67D3\u7684\u5E8F\u5217\uFF08payload \u91CC\u65E2\u6CA1\u6709 ohlc \u4E5F\u6CA1\u6709 series\uFF09\u3002')\n return chart\n }\n\n if (Array.isArray(payload.markers) && payload.markers.length > 0) {\n attachMarkers(anchor, payload.markers.map(function (marker) {\n return { time: marker.time, position: marker.position, text: marker.text, color: colors.strong, shape: 'circle' }\n }), LWC)\n }\n\n appendLegend(container, payload, colors)\n\n // \u4E3B\u56FE\u4E0E\u6210\u4EA4\u91CF\u526F\u56FE\u7684\u9AD8\u5EA6\u6BD4 3:1\uFF1B\u53EA\u6709\u4E00\u4E2A pane \u65F6 panes()[1] \u4E0D\u5B58\u5728\u3002\n var panes = typeof chart.panes === 'function' ? chart.panes() : []\n if (panes.length > 1) {\n if (typeof panes[0].setStretchFactor === 'function') panes[0].setStretchFactor(3)\n if (typeof panes[1].setStretchFactor === 'function') panes[1].setStretchFactor(1)\n }\n\n chart.timeScale().fitContent()\n return chart\n }\n\n return { render: renderCapitalChart, version: 1 }\n})()\n";
@@ -0,0 +1,270 @@
1
+ /**
2
+ * 浏览器侧渲染运行时 —— 以**源码字符串**形式存在,而不是一个模块。
3
+ *
4
+ * 为什么是字符串:同一段渲染代码有两个宿主,二者都不能 pre-built 共用同一份模块——
5
+ * 1. **自包含 HTML 产物**(本步就有):内联进 `<script>`,离线双击可开;
6
+ * 2. **对话流内嵌视图**(Step 3):DSH 客户端 bundle 里再包一次。
7
+ * 写成字符串可以保证两边**逐字节同源**,不会出现"文件里对、页面上错"。
8
+ * 代价是这里没有类型检查,所以 test/chart-runtime.test.mjs 会用 `new Function`
9
+ * 做一次语法与 API 形状校验,把笔误挡在测试里而不是浏览器里。
10
+ *
11
+ * 约束:这段源码里**不能**出现反引号或 `${`(它本身在 TS 模板字符串里)。
12
+ * 依赖:DOM,以及**由调用方传入**的图表库对象(自包含 HTML 传 UMD 全局,Step 3 客户端传
13
+ * ESM import)。刻意不读、也不回退到 `globalThis.LightweightCharts`:那条全局正是与其它
14
+ * 插件带的同库不同版本互相覆盖的来源(见内部设计文档 docs/design/chart-visualization.md §9 风险表)。
15
+ * 形态:IIFE **返回** `{ render, version }`,由各宿主自行捕获(HTML 用 `var __capitalChart =`,
16
+ * 客户端 bundle 存为模块局部),**不往任何全局挂载**。
17
+ * 主题:只读 CSS 变量 `--dsw-*`(见 docs/reference/dsh-surface-ledger.md L7),
18
+ * 不调 DSH 的 theme 服务;自包含 HTML 自己定义同一批变量,因此两边渲染完全一致。
19
+ */
20
+ export const CHART_RUNTIME_SOURCE = `
21
+ (function () {
22
+ 'use strict'
23
+
24
+ var FALLBACK = {
25
+ '--dsw-alias-bg-base': '#ffffff',
26
+ '--dsw-alias-border-l1': 'rgba(0, 0, 0, 0.10)',
27
+ '--dsw-alias-label-primary': '#1f2328',
28
+ '--dsw-alias-label-secondary': '#6b7280',
29
+ '--dsw-alias-brand-primary': '#2563eb',
30
+ '--dsw-alias-state-error-primary': '#d94a3d',
31
+ '--dsw-alias-state-success-primary': '#2f9e44'
32
+ }
33
+
34
+ // 主题 token 不一定是十六进制(也可能是 rgb/rgba 或自定义 CSS 色值)。只有确认是
35
+ // 十六进制时才追加 alpha;其余格式转换成 rgba,转换不了就退回原色,绝不拼出非法 CSS。
36
+ function withAlpha(color, alpha) {
37
+ var text = String(color || '').trim()
38
+ var hex = /^#([0-9a-f]{3}|[0-9a-f]{6})$/i.exec(text)
39
+ if (hex) {
40
+ var expanded = hex[1].length === 3
41
+ ? '#' + hex[1].split('').map(function (part) { return part + part }).join('')
42
+ : text
43
+ return expanded + Math.round(alpha * 255).toString(16).padStart(2, '0')
44
+ }
45
+ var rgb = /^rgba?\\(\\s*([^)]*)\\)$/i.exec(text)
46
+ if (rgb) {
47
+ var parts = rgb[1].split(/[,\\s/]+/).filter(Boolean)
48
+ if (parts.length >= 3 && parts.slice(0, 3).every(function (part) { return /^[-+]?\\d*\\.?\\d+%?$/.test(part) })) {
49
+ return 'rgba(' + parts.slice(0, 3).join(', ') + ', ' + alpha + ')'
50
+ }
51
+ }
52
+ return text
53
+ }
54
+
55
+ // 多序列配色:第一条用主题品牌色,其余用固定色板(保证同一条序列在不同图里颜色一致)。
56
+ var PALETTE = ['#f59e0b', '#10b981', '#8b5cf6', '#0ea5e9', '#ec4899']
57
+
58
+ function readToken(name) {
59
+ try {
60
+ var value = getComputedStyle(document.documentElement).getPropertyValue(name)
61
+ if (value && value.trim().length > 0) return value.trim()
62
+ } catch (error) {
63
+ /* 非浏览器环境或取不到样式时退回默认色 */
64
+ }
65
+ return FALLBACK[name]
66
+ }
67
+
68
+ function resolveColors() {
69
+ return {
70
+ bg: readToken('--dsw-alias-bg-base'),
71
+ grid: readToken('--dsw-alias-border-l1'),
72
+ text: readToken('--dsw-alias-label-secondary'),
73
+ strong: readToken('--dsw-alias-label-primary'),
74
+ brand: readToken('--dsw-alias-brand-primary'),
75
+ up: readToken('--dsw-alias-state-error-primary'),
76
+ down: readToken('--dsw-alias-state-success-primary')
77
+ }
78
+ }
79
+
80
+ function showError(container, message) {
81
+ container.textContent = ''
82
+ var box = document.createElement('div')
83
+ box.setAttribute('data-chart-error', '1')
84
+ box.style.cssText = 'padding:12px;border:0.5px solid ' + readToken('--dsw-alias-border-l1') + ';border-radius:8px;color:' + readToken('--dsw-alias-label-secondary') + ';font-size:13px;line-height:1.6'
85
+ box.textContent = message
86
+ container.appendChild(box)
87
+ }
88
+
89
+ function applyIndexLabels(chart, labels) {
90
+ function format(time) {
91
+ var key = String(time)
92
+ return Object.prototype.hasOwnProperty.call(labels, key) ? labels[key] : key
93
+ }
94
+ // 轴的刻度文案归 timeScale.tickMarkFormatter 管,十字线/提示归 localization.timeFormatter;
95
+ // 分类轴两边都要换掉,否则标尺上还是 2000 年那种合成日期。
96
+ chart.applyOptions({
97
+ localization: { timeFormatter: format },
98
+ timeScale: { tickMarkFormatter: function (time) { return format(time) } }
99
+ })
100
+ }
101
+
102
+ /**
103
+ * 挂标记点。v5 把 markers 从 series API 移到了 createSeriesMarkers(series, markers)
104
+ * 返回的插件对象上;这里同时兼容两种形状,上游再动一次也不会静默丢掉标记。
105
+ */
106
+ function attachMarkers(anchor, markers, LWC) {
107
+ if (typeof LWC.createSeriesMarkers === 'function') {
108
+ LWC.createSeriesMarkers(anchor, markers)
109
+ return true
110
+ }
111
+ if (anchor && typeof anchor.setMarkers === 'function') {
112
+ anchor.setMarkers(markers)
113
+ return true
114
+ }
115
+ return false
116
+ }
117
+
118
+ function volumePointColor(point, colors) {
119
+ if (point.direction === 'up') return colors.up
120
+ if (point.direction === 'down') return colors.down
121
+ return colors.brand
122
+ }
123
+
124
+ function seriesColor(index, colors) {
125
+ return index === 0 ? colors.brand : PALETTE[(index - 1) % PALETTE.length]
126
+ }
127
+
128
+ function appendLegend(container, payload, colors) {
129
+ var items = []
130
+ if (payload.ohlc && payload.ohlc.label) items.push({ label: payload.ohlc.label, color: colors.up })
131
+ if (Array.isArray(payload.series)) {
132
+ payload.series.forEach(function (item, index) {
133
+ if (item && item.label) items.push({ label: item.label, color: seriesColor(index, colors) })
134
+ })
135
+ }
136
+ if (payload.volume && payload.volume.label) items.push({ label: payload.volume.label, color: colors.brand })
137
+ if (items.length === 0) return
138
+
139
+ var legend = document.createElement('div')
140
+ legend.setAttribute('data-chart-legend', '1')
141
+ legend.style.cssText = 'position:absolute;z-index:2;top:8px;left:8px;right:8px;display:flex;flex-wrap:wrap;gap:4px 10px;align-items:center;pointer-events:none;color:' + colors.text + ';font-size:11px;line-height:16px'
142
+ items.forEach(function (item) {
143
+ var entry = document.createElement('span')
144
+ entry.style.cssText = 'display:inline-flex;align-items:center;gap:4px;padding:1px 5px;border-radius:4px;background:' + withAlpha(colors.bg, 0.8)
145
+ var swatch = document.createElement('span')
146
+ swatch.style.cssText = 'width:7px;height:7px;border-radius:50%;background:' + item.color + ';flex:none'
147
+ var label = document.createElement('span')
148
+ label.textContent = item.label
149
+ entry.appendChild(swatch)
150
+ entry.appendChild(label)
151
+ legend.appendChild(entry)
152
+ })
153
+ container.appendChild(legend)
154
+ }
155
+
156
+ function renderCapitalChart(container, payload, library) {
157
+ if (!container) throw new Error('renderCapitalChart: container is required')
158
+ if (!payload || typeof payload !== 'object') throw new Error('renderCapitalChart: payload is required')
159
+ // 图表库由调用方注入,绝不回退到页面全局:回退会让"另一个插件的同库版本"悄悄生效。
160
+ var LWC = library
161
+ if (!LWC || typeof LWC.createChart !== 'function') {
162
+ showError(container, '图表库未加载(调用方未提供 LightweightCharts)。')
163
+ return null
164
+ }
165
+
166
+ var colors = resolveColors()
167
+ container.textContent = ''
168
+ if (container.style) container.style.position = 'relative'
169
+ container.setAttribute('data-chart-id', String(payload.chart_id || ''))
170
+ container.setAttribute('data-chart-kind', String(payload.kind || ''))
171
+
172
+ var chart = LWC.createChart(container, {
173
+ autoSize: true,
174
+ // attributionLogo 保持开启:这满足 Apache-2.0 归属要求(见 vendor/lightweight-charts/VERSION.json)。
175
+ layout: { background: { color: 'transparent' }, textColor: colors.text, fontFamily: 'inherit', attributionLogo: true },
176
+ grid: { vertLines: { color: colors.grid }, horzLines: { color: colors.grid } },
177
+ rightPriceScale: { borderColor: colors.grid, entireTextOnly: true },
178
+ timeScale: { borderColor: colors.grid, rightOffset: 2, barSpacing: 6, minBarSpacing: 0.5 },
179
+ crosshair: { mode: LWC.CrosshairMode ? LWC.CrosshairMode.Normal : 0 },
180
+ localization: { locale: 'zh-CN' }
181
+ })
182
+
183
+ if (payload.axis === 'index' && payload.labels) applyIndexLabels(chart, payload.labels)
184
+
185
+ var anchor = null
186
+
187
+ if (payload.ohlc && Array.isArray(payload.ohlc.data) && payload.ohlc.data.length > 0) {
188
+ // kind=bar 用 BarSeries(OHLC 柱),其余 OHLC 图形用 CandlestickSeries。
189
+ // 两者的数据契约相同(都继承 OhlcData),区别只在渲染样式。
190
+ var isOhlcBar = payload.kind === 'bar'
191
+ var candles = chart.addSeries(isOhlcBar ? LWC.BarSeries : LWC.CandlestickSeries, {
192
+ upColor: colors.up,
193
+ downColor: colors.down,
194
+ borderUpColor: colors.up,
195
+ borderDownColor: colors.down,
196
+ wickUpColor: colors.up,
197
+ wickDownColor: colors.down
198
+ })
199
+ candles.setData(payload.ohlc.data)
200
+ anchor = candles
201
+ }
202
+
203
+ if (Array.isArray(payload.series)) {
204
+ for (var index = 0; index < payload.series.length; index += 1) {
205
+ var item = payload.series[index]
206
+ if (!item || !Array.isArray(item.data) || item.data.length === 0) continue
207
+ var color = seriesColor(index, colors)
208
+ var options = { title: item.label || '', priceLineVisible: false, lastValueVisible: true }
209
+ var series = null
210
+ if (item.type === 'area') {
211
+ options.lineColor = color
212
+ options.topColor = withAlpha(color, 0.2)
213
+ options.bottomColor = withAlpha(color, 0.02)
214
+ options.lineWidth = 2
215
+ series = chart.addSeries(LWC.AreaSeries, options)
216
+ } else if (item.type === 'column') {
217
+ // 单值柱:HistogramSeries 吃 SingleValueData({time, value})。
218
+ // 注意不能用 BarSeries —— 它要 OhlcData,塞单值只会画出空图。
219
+ options.color = color
220
+ options.base = 0
221
+ series = chart.addSeries(LWC.HistogramSeries, options)
222
+ } else {
223
+ options.color = color
224
+ options.lineWidth = 2
225
+ series = chart.addSeries(LWC.LineSeries, options)
226
+ }
227
+ series.setData(item.data)
228
+ if (anchor === null) anchor = series
229
+ }
230
+ }
231
+
232
+ if (payload.volume && Array.isArray(payload.volume.data) && payload.volume.data.length > 0) {
233
+ var volume = chart.addSeries(LWC.HistogramSeries, {
234
+ title: payload.volume.label || '',
235
+ priceFormat: { type: 'volume' },
236
+ priceLineVisible: false,
237
+ lastValueVisible: false
238
+ }, 1)
239
+ volume.setData(payload.volume.data.map(function (point) {
240
+ return { time: point.time, value: point.value, color: volumePointColor(point, colors) }
241
+ }))
242
+ }
243
+
244
+ if (anchor === null) {
245
+ showError(container, '这张图没有可渲染的序列(payload 里既没有 ohlc 也没有 series)。')
246
+ return chart
247
+ }
248
+
249
+ if (Array.isArray(payload.markers) && payload.markers.length > 0) {
250
+ attachMarkers(anchor, payload.markers.map(function (marker) {
251
+ return { time: marker.time, position: marker.position, text: marker.text, color: colors.strong, shape: 'circle' }
252
+ }), LWC)
253
+ }
254
+
255
+ appendLegend(container, payload, colors)
256
+
257
+ // 主图与成交量副图的高度比 3:1;只有一个 pane 时 panes()[1] 不存在。
258
+ var panes = typeof chart.panes === 'function' ? chart.panes() : []
259
+ if (panes.length > 1) {
260
+ if (typeof panes[0].setStretchFactor === 'function') panes[0].setStretchFactor(3)
261
+ if (typeof panes[1].setStretchFactor === 'function') panes[1].setStretchFactor(1)
262
+ }
263
+
264
+ chart.timeScale().fitContent()
265
+ return chart
266
+ }
267
+
268
+ return { render: renderCapitalChart, version: 1 }
269
+ })()
270
+ `;
@@ -0,0 +1,102 @@
1
+ import type { ChartKind, ChartSeriesType, MarkerPosition, NormalizedChartSpec } from './spec.js';
2
+ /** 单张图保留的最大点数(下采样后)。轻量图表在这个量级仍然流畅,且载荷只有几十 KB。 */
3
+ export declare const MAX_CHART_POINTS = 2000;
4
+ /** 字段候选清单最多回报多少个(错误路径本身也不能变成上下文炸弹)。 */
5
+ export declare const MAX_FIELD_HINTS = 15;
6
+ export interface ChartSeriesPayload {
7
+ id: string;
8
+ label: string;
9
+ type: ChartSeriesType;
10
+ data: Array<{
11
+ time: number | string;
12
+ value: number;
13
+ }>;
14
+ }
15
+ export interface ChartOhlcPayload {
16
+ label: string;
17
+ data: Array<{
18
+ time: number | string;
19
+ open: number;
20
+ high: number;
21
+ low: number;
22
+ close: number;
23
+ }>;
24
+ }
25
+ export interface ChartVolumePayload {
26
+ label: string;
27
+ data: Array<{
28
+ time: number | string;
29
+ value: number;
30
+ direction?: 'up' | 'down';
31
+ }>;
32
+ }
33
+ export interface ChartPayload {
34
+ chart_id: string;
35
+ title: string;
36
+ kind: ChartKind;
37
+ axis: 'time' | 'index';
38
+ series: ChartSeriesPayload[];
39
+ ohlc?: ChartOhlcPayload;
40
+ volume?: ChartVolumePayload;
41
+ markers: Array<{
42
+ time: number | string;
43
+ text: string;
44
+ position: MarkerPosition;
45
+ }>;
46
+ /** 分类轴专用:合成时间 → 原始标签,运行时用它做刻度与十字线文案。 */
47
+ labels?: Record<string, string>;
48
+ meta: {
49
+ points: number;
50
+ original_points: number;
51
+ downsampled: boolean;
52
+ time_field?: string;
53
+ axis: 'time' | 'index';
54
+ source_kind: 'dataset' | 'path';
55
+ dataset_id?: string;
56
+ source_label?: string;
57
+ captured_at?: number;
58
+ skipped_rows: number;
59
+ warnings: string[];
60
+ };
61
+ }
62
+ /**
63
+ * 从解析好的 JSON 里取出行数组。
64
+ *
65
+ * 真实数据源的同花顺返回常常是 envelope(行数组在 `item` / `data` / `stock_items` …),
66
+ * 所以这里不能只认顶层数组;但也不能乱猜——猜错会让用户看到一张空图或错图。
67
+ * 策略:顶层数组直接用;否则在候选键里找;候选都没有时列出**全部**数组型顶层键让模型
68
+ * 自己指定路径,而不是静默取第一个。
69
+ */
70
+ export declare function extractRows(value: unknown): {
71
+ rows: unknown[];
72
+ shape: string;
73
+ };
74
+ interface ParsedTime {
75
+ /** 交给图表库的值:'YYYY-MM-DD' 字符串(业务日)或 UTC 秒数。 */
76
+ display: string | number;
77
+ /** 用于排序/过滤/对齐的比较键(UTC 秒)。 */
78
+ seconds: number;
79
+ /** 该值是否来自"纯日期"字符串(决定整张图是否用业务日显示)。 */
80
+ dateOnly: boolean;
81
+ }
82
+ /**
83
+ * 时间值解析。规则必须**确定**(同一份数据在任何机器上得到同一张图):
84
+ * - 纯日期 `YYYY-MM-DD` → 业务日字符串,交给图表库按业务日显示(不做时区换算,避免差一天);
85
+ * - `YYYY-MM-DD HH:mm[:ss]` 无时区 → 按 UTC 解释(显式规则,不依赖宿主本地时区);
86
+ * - 数字/纯数字字符串 → epoch;`>= 1e11` 视为毫秒,否则视为秒;
87
+ * - 其余字符串 → `Date.parse`;失败即视为该行没有时间。
88
+ */
89
+ export declare function parseTimeValue(value: unknown): ParsedTime | undefined;
90
+ export interface BuildChartPayloadInput {
91
+ chart_id: string;
92
+ spec: NormalizedChartSpec;
93
+ rows: readonly unknown[];
94
+ meta: {
95
+ source_kind: 'dataset' | 'path';
96
+ dataset_id?: string;
97
+ source_label?: string;
98
+ captured_at?: number;
99
+ };
100
+ }
101
+ export declare function buildChartPayload(input: BuildChartPayloadInput): ChartPayload;
102
+ export {};