安装
在 DeepSeek Harness 里通过 dsh-market 安装
dsh plugin --profile web add dshmarket
或使用命令行
dsh plugin --profile web add dsh-grafana
装任何插件都等于在你的机器上跑第三方代码,权限和你本人一样大——能读你的文件、用你的凭据、访问网络。请先审阅源码,并尽量锁定 commit(github:owner/repo#sha)。
README
一个面向 Agent 的 Grafana 可观测 DeepSeek Harness 插件——读取大盘、查询实时指标、跟踪趋势与告警、跨源对比调查,并能安全、可审查地写回大盘。插件直接操作 Grafana API 与 Dashboard JSON,不需要截图。
项目状态:1.0 前版本。核心写回路径已经具备安全保护和自动化测试,但尚未完成 Grafana 12+ 兼容性认证。
核心能力
- 通过浏览器 URL 或 UID 获取大盘;超大盘可改用结构化摘要模式,只返回面板/查询/阈值/变量骨架。
- 按标题和标签搜索大盘。
- 粘贴大盘或面板视图 URL,直接查询面板背后的真实数据。
- 把大盘复制为全新大盘,并返回新大盘地址。
- 通过对话调整面板、查询、阈值、变量和布局。
- 写回时自动保持大盘所在文件夹。
- 写入前检测并发修改。
- 每次写入都必须经过 DSH 原生用户审批。
- Service Account 凭证只保存在本机 DSH 凭证库。
- 可配置多个具名 Grafana 源站,每次工具调用按名称指定目标。
环境要求
| 组件 | 已支持基线 |
|---|---|
| Node.js | 20.11 或更高版本 |
| DeepSeek Harness | 0.1.0-rc.6 至 0.2.0-rc.2 的预发布 peer(验证基线:0.1.0-rc.6、0.1.1-rc.2、0.1.2-rc.1、0.1.3-alpha.2、0.1.5-rc.1、0.1.7-rc.2、0.2.0-rc.2;预发布匹配取决于受支持的版本元组) |
| Grafana | Grafana 10/11 文档中的传统 Dashboard HTTP API |
Grafana 12 引入了新 Dashboard API。旧接口可能仍然可用,但 Grafana 12+ 暂未进入本插件的正式兼容矩阵。
本插件无构建步骤:纯 ESM JavaScript,安装即可加载,无需编译或打包。
安装
正式使用应安装不可变的 Release tag:
dsh plugin --profile <profile> add github:guhanfei-ai/dsh-grafana#v<version>
仅在测试时安装会持续变化的默认分支:
dsh plugin --profile <profile> add github:guhanfei-ai/dsh-grafana
本地开发:
npm ci
dsh plugin --profile <profile> add link:/绝对路径/dsh-grafana
安装后重启对应 DSH profile。
Windows 可使用 link:C:/path/to/dsh-grafana 形式的绝对路径。插件运行本身支持跨平台;deploy.sh 需要 Git Bash、WSL、macOS 或 Linux。
升级到 0.12.0
两个工具改名。 grafana_query 改为 grafana_panel_query,grafana_health 改为 grafana_status。参数、输出、超时与审批行为均不变。
| 旧名 | 新名 |
|---|---|
grafana_query |
grafana_panel_query |
grafana_health |
grafana_status |
旧名仍以「只报错」的转发 stub 保留在工具列表中:调用 grafana_query 或 grafana_health 会立即失败并指名新工具,进行中的对话一步即可自愈。自定义 prompt 与保存的工作流仍建议改用新名;按代理配置的工具白名单需要换成新名。
浏览器设置卡片需要 DSH 0.1.2 及以上。 在更旧的宿主(0.1.0–0.1.1)上,卡片会显示明确的「宿主过旧」提示而非源站列表——这是版本门槛,不是配置丢失。宿主侧全部工具在这些版本上照常可用,插件本身也仍可安装在 0.1.0-rc.6 及以上。
配置自动迁移。 升级前 settings.yaml.imported 中的具名源站优先于旧单源凭证;否则旧单源配置会物化为名为 default 的源站(Base URL 与已存令牌不变)。导入文件位于 $DSH_HOME/settings.yaml.imported,未设置 DSH_HOME 时位于 ~/.dsh/settings.yaml.imported。可选依赖 js-yaml 用于完整 YAML 解析,缺失时由内置解析器处理已知的 Grafana 段结构。迁移不会覆盖运行期间并发保存的配置。
配置
在 DSH Web 中打开 设置 → 插件 → Grafana 助手。
提示:设置页按 Host 端的 settings 命名空间(
grafana)派发插件卡片。命名空间列表只在设置文档变更或连接重置时刷新,因此升级插件后如果卡片没有出现,刷新页面(或重连 Web UI)即可。
需要配置:
- Service Account Token:例如
glsa_...。 - Grafana URL:例如
https://grafana.example.com或https://example.com/grafana。
Token 使用 DSH 仅允许 loopback same-origin 访问的特权凭证 RPC:仅写不读,保存后的值不会被读取或回显。URL 存储在 grafana settings namespace 的非 secret 字段中,因此可读回明文并在卡片中显示以便核对。界面支持替换和删除。
HTTP 与 HTTPS 开箱即用,内网未配置证书的环境可直接填写 http:// 地址,无需额外设置。注意:HTTP 会明文传输服务账号令牌,不可信网络环境请务必使用 HTTPS。如需强制仅允许 HTTPS,可在插件配置中关闭:
allowInsecureHttp: false
只读模式面向监控排障等不应修改大盘的角色:
readOnly: true
启用后 grafana_push 与 grafana_clone 完全不注册——模型没有可调用的写入工具。设置卡片顶部提供只读模式开关(开 = 只读,关 = 读写),当前模式一目了然;切换只写插件级 readOnly 配置,不影响已配置的源站与默认源站。
切换到只读立即生效:即使写入工具在启动时已注册,审批门也会在运行时拒绝它们。从只读切回读写可能需要重启 DSH(或重新加载插件),取决于插件加载时的模式:以只读模式启动的插件从未注册写入工具,重启或重载之后才会恢复。
settings 中的 baseUrl 为权威来源;早期版本存在 GRAFANA_BASE_URL 凭证中的 URL 会在启动时自动迁移到 settings,之后凭证值仅作兜底。Token 凭证名默认为 GRAFANA_TOKEN,可通过 tokenRef 修改。
多个 Grafana 源站
设置卡片管理的是一个具名 Grafana 源站列表,而不再是单组 URL/令牌。每个源站包含:
- 源站名称(必填、唯一):中英文皆可。它就是调用工具时传入
source参数用以指定目标源站的值。 - UID(只读):自动生成、全球唯一,以淡色小字显示在名称正下方。它是内部稳定主键——改名不会改变 UID,也不会影响已存令牌,且用户无法编辑。
- Grafana URL 与 Service Account Token:每个源站各自独立。令牌以仅写不读的方式存入 DSH 凭证库。新源站使用
GRAFANA_TOKEN_<uid>引用;轮换已保存的令牌时生成新引用。迁移保留原有引用,包括自定义引用。
点击新增源站创建,移除源站删除,设为默认选择省略 source 时使用哪一台。保存当前源站只保存该卡片,保存全部源站保存所有卡片;写入前校验名称和 URL。移除源站会清除其令牌,但仍被其它源站使用或引用状态无法确认的凭证会保留。清理失败时,卡片会提示并提供重试按钮。
保存前必须成功读取配置。读取失败或返回畸形数据时,卡片保持只读,并提供重新读取按钮。宿主提供配置版本号时,写入会携带该版本,防止陈旧页面覆盖其它页面的新修改。
令牌变更通过一次配置写入切换到新凭证引用。宿主明确拒绝时,旧配置继续生效;应答丢失时,会保留新凭证,等待确认实际保存状态。清理凭证前会检查是否仍有源站引用。成功保存的令牌草稿会清空,其它未保存的编辑予以保留。
每个工具都接受可选的 source 参数(源站名称),省略则用默认源站。调用 grafana_sources 可列出已配置的名称、UID、URL、令牌是否已配以及哪一台是默认源站。写操作的审批文案首行始终标明目标源站名称与 URL,方便确认改的是哪一台;写入与该源站绑定:等待审批期间默认源站若被改掉,写入会被拒绝,而不是发到执行时随手解析到的那一台。读取—审批—写入整条链路还绑定源站的 URL 与凭证引用,改掉源站地址会使其改前取得的快照失效——id/uid/version 相同并不能证明两次响应来自同一实例。早期版本的单源配置会在启动时迁移为一个名为 default 的源站,并保留其原有的自定义 tokenRef。allowInsecureHttp 仍是全局设置,对所有源站生效。
Grafana 权限
优先使用最小权限 RBAC,只授予目标大盘及文件夹所需范围:
dashboards:readdashboards:write- 目标文件夹的
folders:read grafana_panel_query需要datasources:query以及对所查数据源的访问权限
不支持细粒度 RBAC 时才使用 Editor 角色,避免使用 Admin token。
各工具所需的具体权限:
| 工具 | Grafana 权限 |
|---|---|
grafana_get |
dashboards:read |
grafana_push |
dashboards:read + dashboards:write |
grafana_clone |
dashboards:read + dashboards:write |
grafana_panel_query |
dashboards:read + datasources:query |
grafana_datasources |
datasources:read |
grafana_metric |
datasources:read + datasources:query |
grafana_compare |
datasources:read + datasources:query(每台源站各自) |
grafana_trend |
dashboards:read + datasources:query |
grafana_alerts |
alert.instances:read;definitions: true 另需 alert.provisioning:read;ruleStates: true 另需规则读取权限(被拒时就地报出缺失的 scope) |
grafana_search |
dashboards:read |
grafana_status |
dashboards:read(见下注) |
grafana_sources |
无(只读本机插件配置) |
以读为主的配置可用 Viewer 基础角色叠加 Grafana 固定的只读 Alerting 角色;只有跑 grafana_push / grafana_clone 的令牌才需要追加 dashboards:write(或 Editor 基础角色)。关于 grafana_status:/api/health 无需鉴权,故该工具改为调用 GET /api/search 验证凭证,并从 /api/health 的 database 字段读取实例健康状态(该接口没有 status 字段)。
能力覆盖
与单一用途的 Grafana 桥接插件相比,本插件的差异点:
- 多具名源站(至多 50 个):每个工具都接受可选的
source参数,写入审批会标明目标实例,一个插件即可服务一整套 Grafana。 - 凭证不落入配置文档:令牌以只写方式存进 DSH 凭证库,经特权回环 RPC 访问,绝不会被回读、展示或同步。
- 浏览器设置卡片:源站的增删改与校验都在原生设置界面完成,无需手工编辑配置文件。
工具面覆盖从读到写的完整闭环:
| 能力 | 工具 |
|---|---|
| 读大盘(完整 JSON 或结构化摘要) | grafana_get |
| 改大盘 | grafana_push |
| 写 / 新建 | grafana_push、grafana_clone |
| 克隆大盘 | grafana_clone |
| 搜索大盘 | grafana_search |
| 面板实时值 | grafana_panel_query |
| 大盘序列趋势 | grafana_trend |
| 裸查询(PromQL / LogQL) | grafana_metric |
| 跨源站指标横向比较 | grafana_compare |
| 数据源发现 | grafana_datasources |
| 活跃告警与规则定义 | grafana_alerts |
| 源站与凭证健康 | grafana_status、grafana_sources |
| 多源站 | 所有工具经 source 参数 |
工具
每个工具都接受可选的 source 参数(已配置的源站名称)用以指定目标 Grafana 实例;省略则用默认源站。详见多个 Grafana 源站。
| 工具 | 行为 |
|---|---|
grafana_get |
获取完整大盘,并保存一个短期可信的版本和目录快照。传 summary: true 时改为返回结构化摘要(面板、查询、阈值、变量),不记录写快照,适合超大盘。 |
grafana_push |
在审批、身份校验、版本校验和目录保持后写回最近读取的大盘。 |
grafana_clone |
把大盘复制为全新大盘(全新 UID、版本 1),默认留在源文件夹,并返回新大盘完整地址。同样需要审批,继续写入前必须先调用 grafana_get。 |
grafana_panel_query |
执行粘贴的大盘或面板视图 URL(?viewPanel= 限定单面板;沿用 URL 里的 from/to 时间范围)背后的面板数据源查询,返回有界的实时数据摘要。模板变量默认使用大盘保存状态,可通过 variables 参数覆盖——单值({"env":"prod"})、多值({"host":["www","m"]},按查询中使用的格式修饰符展开)或 adhoc 过滤(见模板变量覆盖)。adhoc 过滤按数据源类型翻译:Elasticsearch 拼进各 target 的 Lucene 查询串,Prometheus/Loki 向每个 vector/stream selector 注入 label matcher,SQL 数据源替换 rawSql 中的 ${__adhoc} 占位符;其它数据源类型存在生效的 adhoc 时显式报错并列出支持矩阵。adhoc 覆盖为整体替换保存态,[] 表示清空,并按 target 的数据源 uid 逐个生效——绑定某个数据源的变量不会影响其它数据源。不支持的运算符/数据源组合显式报错,绝不静默忽略。仅支持 query/custom/interval/adhoc/textbox/constant/datasource 类型变量覆盖(datasource 型变量传 uid 字符串),不支持的类型会显式报错。Prometheus/Loki target 中裸多值变量渲染为 `(a |
grafana_datasources |
列出源站上已配置的数据源(uid、插件类型、显示名、是否默认、访问模式、以及配置的 URL——url="(empty)" 的行通常意味着该数据源配置有误、一查即失败,请换用其它 uid)。可按精确插件类型或大小写不敏感的名称子串过滤。结果分页返回(默认每页 40 行;limit 调整页大小,page 翻页),末尾一行披露当前页、总数与如何继续。调用 grafana_metric 前先用它确认要查询的 uid 或名称。只读。 |
grafana_metric |
无需大盘,直接对 Prometheus 或 Loki 数据源执行一条裸文本查询(PromQL 如 up 或 rate(http_requests_total[5m]),或 LogQL 流选择器),数据源按 uid 或精确显示名寻址。mode: "instant"(默认)在区间末端求值一次;mode: "range" 对序列采样并给出每条序列的统计、上升/下降/持平判定与火花线——首行披露实际采样步长(step=),每条序列披露实际返回点数(points=),回答的精度与覆盖范围可见(对 Loki 的 range 查询返回的是日志行而非数值采样点,故这类序列只报行数与末行;Loki 的 instant 模式只接受 metric 查询,日志流选择器需用 range)。其它插件类型与服务端表达式会被拒绝并指向 grafana_panel_query。只读,不记录写快照。 |
grafana_compare |
在多台已配置 Grafana 源站(一次 2-10 台)上并发执行同一 PromQL 查询,按源站独立解析数据源(同名会分别解到各自的 UID),并返回紧凑的横向比较结果;任一源站失败/无数据/多 series 都不会拖累其它成功源站,所有错误均经脱敏截断。全部请求源站都成功且各自返回单个可比较标量时,尾部附数学 summary(最高/最低/均值/比率);range 模式的「可比较标量」指带完整 first/last/min/max/avg 的序列,无时间轴的表格或日志结果只按 per-source 详情呈现并说明不可直接比较。只读,不记写快照也不进审批门。 |
grafana_trend |
一次调用回答大盘的「在涨还是在跌」:把每个可见查询目标以较粗的区间查询重跑,每条序列给出实际返回点数、桶数、首/末/最小/最大/均值、方向判定与火花线;首行披露实际采样步长。表格型结果报告行数与统计并标 trend=n/a,不伪造方向。与 grafana_panel_query 共用同一套面板管线(变量、adhoc 过滤、旧格式数据源引用、逐面板降级)。时间范围最长 90 天。只读,不记录写快照。 |
grafana_alerts |
从内置 Alertmanager 列出源站当前正在告警的条目(默认 state=firing;"suppressed" 表示被静默/抑制,"all" 两者都要)。上游的 active 状态(Alertmanager v2 的活动告警状态)统一报为 state=firing,正常告警不会被当成未知状态漏掉。可按文件夹、跨标签与注解的大小写不敏感子串、或大盘 URL/uid 过滤。活跃告警按 limit 参数封顶(默认 30、上限 100),丢弃的部分在末尾预算行披露。definitions: true 另发一次请求追加 provisioning 的规则定义(独立权限、独立故障隔离)。ruleStates: true 再追加每条规则的评估状态(rule-state 行:inactive、pending、firing、recording、unknown,来自 Prometheus 兼容规则接口)——pending 表示条件已满足但 for 时长未满,这是 Alertmanager 视角回答不了的;该段可用 ruleState 过滤。两个规则段共用 rulesPage 分页(每页 100 条),并披露总数与下一页参数。只读;告警文本是不可信数据。 |
grafana_search |
按标题和精确标签搜索,最多返回 50 条。 |
grafana_status |
检查 Grafana 连通性与 Service Account 凭证。 |
grafana_sources |
列出已配置的 Grafana 源站:每个源站的名称、只读 UID、URL、令牌是否已配,以及哪一台是默认源站。只读,绝不返回令牌值。在向其它工具传 source 之前,可用它发现合法的源站名称。 |
跨源站比较示例(grafana_compare)
grafana_compare 在所列每台源站上对同一 PromQL 查询发请求,汇总成一张紧凑的横向比较视图——把原本三次工具调用 + 手动对比缩成一次调用。常见用法:
Region 对比——同一 P99 延迟在多个区域:
{
"sources": ["tokyo", "singapore", "us"],
"datasource": "Prometheus",
"query": "histogram_quantile(0.99, sum by (le) (rate(http_request_duration_seconds_bucket{service=\"payment\"}[5m])))"
}
环境对比——production 与 staging 之间的错误率:
{
"sources": ["prod", "staging"],
"datasource": "Prometheus",
"query": "sum(rate(http_requests_total{status=~\"5..\"}[5m])) / sum(rate(http_requests_total[5m]))"
}
集群对比——跨 Grafana 集群 A/B/C 的节点 CPU,带更宽的窗口:
{
"sources": ["cluster-a", "cluster-b", "cluster-c"],
"datasource": "Prometheus",
"query": "100 - (avg by (instance) (rate(node_cpu_seconds_total{mode=\"idle\"}[2m])) * 100)",
"mode": "range",
"from": "now-15m",
"to": "now",
"points": 60
}
全部请求源站都成功且各自返回单个可比较标量时,输出末尾会附数学 summary(最高、最低、均值、max/min 比率);mode: "range" 下这要求每台源站的序列都带完整的 first/last/min/max/avg。一旦任一源站多 series、失败、无数据,或返回的形状在当前 mode 下不可比较(range 模式遇到无时间轴的表格/日志帧),summary 就不出,每个源站按各自的 per-series 摘要或清洗后的错误单独呈现,并说明不可直接比较的原因——高基数或部分失败的结果永远不会被当成直接标量比较读出来。
模板变量覆盖(grafana_panel_query)
variables 参数是一个以变量名为键的 JSON 对象。大盘中所有可覆盖变量(query/custom/interval/adhoc/textbox/constant/datasource 类型)均可覆盖;不支持的类型显式报错。
单值——替换该变量出现的所有位置($env、${env}):
{ "env": "prod" }
多值——传数组,展开方式遵循查询里使用的 Grafana 格式修饰符,为多选变量编写的大盘无需改动即可工作:
{ "host": ["www.example.com", "m.example.com"] }
Prometheus / Loki target 里无修饰符的裸多值引用($host)渲染为 (www.example.com|m.example.com)——即 =~ label matcher 里可用的交替形式,与 Grafana 自身渲染一致。值不做正则转义(Grafana 也不转义;双引号 PromQL 字符串里把 . 转义成 \. 是语法错误)。需要精确匹配时使用显式 ${host:regex} 修饰符。
| 查询占位符 | 展开结果 |
|---|---|
$host / ${host} |
www.example.com,m.example.com(CSV,Grafana 默认) |
${host:csv} |
www.example.com,m.example.com |
${host:doublequote} |
"www.example.com","m.example.com" |
${host:singlequote} |
'www.example.com','m.example.com' |
${host:json} |
["www.example.com","m.example.com"] |
${host:raw} |
www.example.com,m.example.com |
${host:pipe} |
www.example.com|m.example.com |
${host:percent} |
逐值 URL 编码后逗号连接(www.example.com,m.example.com;["a b"] → a%20b) |
${host:querystring} |
host=www.example.com&host=m.example.com(以变量名为键) |
${host:regex} |
www\.example\.com|m\.example\.com(逐值正则转义后以 | 连接) |
${host:lucene} |
逐值 Lucene 转义后以空格连接 |
${host:sqlstring} |
'www.example.com','m.example.com'(值内单引号翻倍) |
无修饰符的单值变量展开为裸值(与 String(value) 逐字节一致);修饰符对单值同样生效(${host:json} → "www.example.com",${host:pipe} → www.example.com)。未知格式修饰符显式报错。内建变量($__interval、$__rate_interval、${__from:date} 等)始终原样透传。
adhoc 过滤覆盖——整体替换大盘保存的 adhoc filters([] 表示清空):
{
"adhoc": [
{ "key": "host.keyword", "operator": "=", "value": "www.example.com" },
{ "key": "status", "operator": "!=", "value": "404" }
]
}
未绑定的 adhoc 条目对所有数据源生效;加 "datasourceUid": "<uid>" 可绑定到单个数据源。翻译方式取决于数据源类型:
| 数据源类型 | 翻译方式 | 支持的运算符 |
|---|---|---|
| Elasticsearch | Lucene 条件拼进各 target 的查询串(host.keyword:"www.example.com";面板自带查询串非空时括号包裹后以 AND 连接) |
= != 恒可;> < 仅数字;=~ !~ 映射为 Lucene 正则 field:/pattern/(模式内的 / 会转义;空模式报错) |
| Prometheus | label matcher 注入每个 vector selector(host="www.example.com";裸 metric 名补上 {...}) |
= != =~ !~;> < 报错 |
| Loki | matcher 注入 stream selector({app="api", host="www.example.com"});pipeline 阶段不动 |
= != =~ !~;> < 报错 |
| SQL(MySQL/Postgres/MSSQL/MariaDB/SQLite/ClickHouse) | rawSql 中的 ${__adhoc} / $__adhoc 占位符替换为 WHERE 风格条件(host = 'www.example.com';值做单引号转义) |
= != > <(数字)、=~ !~(映射为 LIKE/NOT LIKE) |
| 其它类型 | 显式报错并列出支持类型 | — |
datasource 型变量——用数据源 uid 字符串覆盖:
{ "datasource": "prom-prod" }
datasource 引用了该变量的面板({"type":"prometheus","uid":"$datasource"})会改查指定的 uid。传入非字符串值(数字、数组)会显式报错。
旧格式 datasource 引用(grafana_panel_query)
旧版大盘的 datasource 引用形状无法直接用于 /api/ds/query,grafana_panel_query 会透明解析:
| 面板 datasource 形状 | 解析方式 |
|---|---|
| 纯字符串 uid(Grafana 8 及更早) | 经 GET /api/datasources 查找,随查询发送解析出的 {type, uid} |
{"uid":"$datasource"} / {"type":"prometheus","uid":"$datasource"}(datasource 型模板变量) |
用该变量保存的 current 值插值进 uid |
保存值为 "default" |
映射到服务端默认数据源("default" 是 /api/ds/query 不接受的保留伪 uid) |
| 索引不可用(403)或 uid 未知 | 裸 {uid} 透传,由 Grafana 自行报错;若此时还有生效的 adhoc 过滤无法对未知类型翻译,则显式报错 |
数据源索引按需懒加载——仅当大盘确实存在需要解析的引用时才请求一次。当所有面板都被跳过时,报错会列出每个面板的 id、标题与跳过原因,而不是一句干巴巴的 "no executable query"。
真机验收矩阵(变量覆盖 × 运算符 × 数据源类型、旧格式大盘形状)记录于 INTEGRATION.md。
安全写回流程
- 让 DSH 获取大盘 URL 或 UID。
- 描述需要修改的内容。
- 检查审批窗口中的大盘身份和变更摘要。
- 批准或拒绝写回。
- 刷新 Grafana;再次写入前重新获取大盘。
grafana_push 默认使用 overwrite: false。写回前会立即重新读取大盘并拒绝过期版本,同时自动保持当前目录。移动目录需要 allowFolderMove: true;强制覆盖需要 forceOverwrite: true,且仍会触发审批。
审批弹窗中展示的大盘身份(UID、标题、版本、所在文件夹)以及「快照于 X 分钟前获取」全部来自 grafana_get 保存的服务端可信快照,而不是模型提交的大盘 JSON,因此模型幻觉或被篡改的标题不会误导审批。没有可信快照时,弹窗会直接说明写回会被拒绝并要求先 grafana_get。审批弹出前插件还会实时核对 Grafana 端当前状态:版本或文件夹与快照不一致时,弹窗会给出醒目警示并列出两侧版本号;无法连接 Grafana 时,弹窗会注明「无法确认当前状态」。实时复核只用于丰富审批文案,写入前的最终校验始终在写回时重新执行。实时复核成功时,弹窗还会附上有界且经过清洗的内容 diff(新增/删除/修改的面板、模板变量与顶层字段),让审批人核对真实改动,而不只是模型自述的变更摘要。
安全与数据边界
- Token 不会进入工具参数、模型消息、日志或 Git。
- 带凭证的请求拒绝 HTTP 重定向,避免凭证被转发到其他来源。
- 非本机明文 HTTP 默认允许(可通过配置关闭)。
- 请求支持取消、超时、响应大小限制和 Dashboard 输入大小限制。
- API 错误只暴露有限的状态和消息。
- Grafana 返回内容始终作为不可信数据处理,而不是模型指令。
Dashboard JSON 仍可能包含 SQL、内部域名、链接、标签和业务信息。获取大盘会把这些 JSON 作为工具上下文发送给当前模型提供商。在处理机密大盘前,请先确认模型提供商的数据政策。
漏洞报告和支持策略参见 SECURITY.md。
开发验证
npm ci
npm run verify
npm pack --dry-run --ignore-scripts
自动化测试使用 Node 内置测试运行器和模拟 Grafana 响应。CI 覆盖 Node 20、22 和 24。
更多信息参见 CONTRIBUTING.md 和 CHANGELOG.md。
发布
普通手工 git push 不会触发版本号、tag 或 Release。发布是一个显式的三步流程,要求 main 工作区干净且变更已提交:
./deploy.sh release # 锁版本:递增版本、提交、打 tag、推送(patch/minor/major 或 x.y.z)
./deploy.sh build # 验证并打包,产物输出到 dist/
./deploy.sh publish # 先将安装包发布到 npm,再创建 GitHub Release 并上传同一产物
直接运行 ./deploy.sh(不带参数)可查看内置帮助。首次发布前需要运行一次 gh auth login 和 npm login。每一步都有自我守卫:all 与 release 在开始前会先预检 GitHub 与 npm 登录状态(避免版本锁定、tag 推送之后才发现凭证失效白跑一遍),release 要求 main 干净且与远端同步,build 要求 tag 已锁定在 HEAD 上,publish 要求打包产物存在且 GitHub 与 npm 凭证就绪;所有会改动远端的操作都会先要求明确确认。
publish 会先把 dist/ 里的安装包发布到 npm,再把同一个文件上传到 GitHub Release,两个渠道分发的产物字节完全一致。npm 版本号不可变:如果 dsh-grafana@<version> 已在 npm 上存在,则跳过 npm 步骤、只创建 GitHub Release;脚本也绝不会覆盖已存在的 GitHub Release。
npm 前置条件
首次 npm 发布前的一次性准备:
- 使用已验证邮箱、并为写操作开启双因素认证的 npmjs.com 账号。
- 执行
npm login,再用npm whoami确认身份。 - 无作用域名称
dsh-grafana已由包所有者账号占用。如需改用@guhanfei-ai/dsh-grafana这类组织作用域名称,请先修改package.json;deploy.sh会从其中读取包名。
开启写操作 2FA 后,npm publish 会交互式提示输入一次性验证码;非交互场景可通过 NPM_OTP 环境变量传入。
如需供应链来源证明,建议改用独立 CI 工作流配置 npm Trusted Publishing 并加 --provenance;本地登录不具备可信来源证明所需的 CI OIDC 身份。
许可证
评论
评论存放在 GitHub Discussions。用 GitHub 账号登录后可发表评论或点表情。