Skip to content

Commit c1b4004

Browse files
author
SqlRush
committed
Export telemetry events to backends
1 parent 9a813a6 commit c1b4004

12 files changed

Lines changed: 388 additions & 6 deletions

File tree

docs/cc-100-roadmap.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1456,7 +1456,7 @@ M7 补充:terminal input parser 和 configurable keybinding name parser 现在
14561456
- Chrome/computer-use/voice/native integrations。
14571457
- enterprise/gated/platform-specific behavior。
14581458

1459-
当前状态:已新增 `advanced` settings gate 地基,覆盖 bridge/LSP/telemetry/Chrome/voice/computer-use/native integrations 的独立 bool 开关解析、settings merge、headless `/config show advanced` 和 `/config search` 审计;`advanced.telemetry=true` 时会在 session 目录写入安全摘要 JSONL 诊断事件,记录事件类型、session/model、tool/progress keys、token/compact/error 摘要,不写入用户/助手正文或工具结果内容,并已有安全 JSONL 读取、类型/模型过滤、汇总统计、deterministic trace/span id、JSON summary export 和 headless `/status show telemetry` trace/span 审计地基;`advanced.lsp=true` 时才向模型暴露只读 `LSPDiagnostics` 工具,用于读取 session-scoped diagnostics snapshot,并支持 file/severity/limit 过滤,底层已能解析 LSP `textDocument/publishDiagnostics` params/notification payload、按文件替换 snapshot、按 LSP 空 diagnostics 语义清空旧文件诊断;同时会写出 session-scoped LSP manager status,按默认或显式 server definitions 解析 workspace/root marker/file extension 命中情况,将已匹配但未启动的 server 标为 `not_started`,并可通过 headless `/status show lsp` 审计 diagnostics 与 manager runtime state;LSP Content-Length framed JSON-RPC reader/writer 与 diagnostics stream processor 已能持续消费 `textDocument/publishDiagnostics` notification、捕获 initialize response capabilities 并更新 session snapshot;LSP server process lifecycle API 已可启动配置命令、消费 stdout framed diagnostics stream,并把 `running`/`exited`/`failed`、PID 和时间戳写回 manager status;LSP client handshake send path 已可向 server stdin 写入 `initialize`、`initialized` 和 `textDocument/didOpen` framed JSON-RPC,支持 root/client/document metadata 和 file URI/language 默认推断;conversation runner 在 `advanced.lsp=true` 且显式或默认 server definitions 命中 workspace 时,会自动启动可执行命令存在的 LSP server、发送 handshake/startup documents、对缺失命令保持可审计 `not_started` reason,并复用 session diagnostics/manager status 生命周期;`advanced.bridge=true` 时会写出 session-scoped bridge manifest,列出 bridge-safe slash/local command 元数据,提供 command/display/alias 安全解析,并可通过 headless `/status show bridge` 审计;bridge direct HTTP handler 已可复用同一 manifest/registry,提供 `/health`、`/manifest`、`/resolve` 和 `/execute` JSON 端点,执行前强制 bridge-safe 白名单并默认不回传展开后的 prompt 正文;bridge loopback-only direct listener 已有可嵌入启动/关闭 API,默认 `127.0.0.1:0`、拒绝非 loopback 地址,并支持可选 bearer/`X-Bridge-Token` token guard;bridge direct websocket JSON channel 已可通过 `/ws` 执行 `resolve`/`execute` 消息并复用同一白名单、token guard 和 prompt 正文不泄露策略;`advanced.nativeIntegrations=true` 时会写出 session-scoped native capability manifest 和 native file index,只记录路径/大小/mtime 等文件元数据、跳过常见 runtime/vendor 目录,并可通过 headless `/status show native` 审计 index 路径与文件数量;任一 `advanced.chrome`/`advanced.voice`/`advanced.computerUse=true` 时会写出 session-scoped integrations manifest,将 Chrome/voice/computer-use 的 enabled 与 `runtime_state` 分开记录,当前启用项明确标为 `not_wired`,并可通过 headless `/status show integrations` 审计;未启用时仍不注册或泄露 gated 工具 schema。实际 session websocket/direct connect 外部接入、telemetry external exporter/backend、Chrome/voice/computer-use runtime,以及 native clipboard/color diff 等平台 runtime 仍未完成。
1459+
当前状态:已新增 `advanced` settings gate 地基,覆盖 bridge/LSP/telemetry/Chrome/voice/computer-use/native integrations 的独立 bool 开关解析、settings merge、headless `/config show advanced` 和 `/config search` 审计;`advanced.telemetry=true` 时会在 session 目录写入安全摘要 JSONL 诊断事件,记录事件类型、session/model、tool/progress keys、token/compact/error 摘要,不写入用户/助手正文或工具结果内容,并已有安全 JSONL 读取、类型/模型过滤、汇总统计、deterministic trace/span id、JSON summary export、可配置 `telemetryExport` 本地 JSONL exporter / HTTP backend POST、endpoint 脱敏 status,以及 headless `/status show telemetry` trace/span/exporter 审计地基;`advanced.lsp=true` 时才向模型暴露只读 `LSPDiagnostics` 工具,用于读取 session-scoped diagnostics snapshot,并支持 file/severity/limit 过滤,底层已能解析 LSP `textDocument/publishDiagnostics` params/notification payload、按文件替换 snapshot、按 LSP 空 diagnostics 语义清空旧文件诊断;同时会写出 session-scoped LSP manager status,按默认或显式 server definitions 解析 workspace/root marker/file extension 命中情况,将已匹配但未启动的 server 标为 `not_started`,并可通过 headless `/status show lsp` 审计 diagnostics 与 manager runtime state;LSP Content-Length framed JSON-RPC reader/writer 与 diagnostics stream processor 已能持续消费 `textDocument/publishDiagnostics` notification、捕获 initialize response capabilities 并更新 session snapshot;LSP server process lifecycle API 已可启动配置命令、消费 stdout framed diagnostics stream,并把 `running`/`exited`/`failed`、PID 和时间戳写回 manager status;LSP client handshake send path 已可向 server stdin 写入 `initialize`、`initialized` 和 `textDocument/didOpen` framed JSON-RPC,支持 root/client/document metadata 和 file URI/language 默认推断;conversation runner 在 `advanced.lsp=true` 且显式或默认 server definitions 命中 workspace 时,会自动启动可执行命令存在的 LSP server、发送 handshake/startup documents、对缺失命令保持可审计 `not_started` reason,并复用 session diagnostics/manager status 生命周期;`advanced.bridge=true` 时会写出 session-scoped bridge manifest,列出 bridge-safe slash/local command 元数据,提供 command/display/alias 安全解析,并可通过 headless `/status show bridge` 审计;bridge direct HTTP handler 已可复用同一 manifest/registry,提供 `/health`、`/manifest`、`/resolve` 和 `/execute` JSON 端点,执行前强制 bridge-safe 白名单并默认不回传展开后的 prompt 正文;bridge loopback-only direct listener 已有可嵌入启动/关闭 API,默认 `127.0.0.1:0`、拒绝非 loopback 地址,并支持可选 bearer/`X-Bridge-Token` token guard;bridge direct websocket JSON channel 已可通过 `/ws` 执行 `resolve`/`execute` 消息并复用同一白名单、token guard 和 prompt 正文不泄露策略;`advanced.nativeIntegrations=true` 时会写出 session-scoped native capability manifest 和 native file index,只记录路径/大小/mtime 等文件元数据、跳过常见 runtime/vendor 目录,并可通过 headless `/status show native` 审计 index 路径与文件数量;任一 `advanced.chrome`/`advanced.voice`/`advanced.computerUse=true` 时会写出 session-scoped integrations manifest,将 Chrome/voice/computer-use 的 enabled 与 `runtime_state` 分开记录,当前启用项明确标为 `not_wired`,并可通过 headless `/status show integrations` 审计;未启用时仍不注册或泄露 gated 工具 schema。实际 session websocket/direct connect 外部接入、Chrome/voice/computer-use runtime,以及 native clipboard/color diff 等平台 runtime 仍未完成。
14601460

14611461
## Recommended Next Steps
14621462

docs/claude-code-go-rewrite-plan.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -745,7 +745,7 @@ test/parity/ # golden tests against TS/official behavior
745745
- 每个 gated feature 独立开关测试。
746746
- 不启用 feature 时二进制行为和可见 schema 不泄露 gated 工具/命令。
747747

748-
- 本轮补充:新增 `advanced` settings gate 地基,覆盖 bridge/LSP/telemetry/Chrome/voice/computer-use/native integrations 的独立 bool 开关解析、settings merge、headless `/config show advanced` 和 `/config search` 审计;`advanced.telemetry=true` 时会在 session 目录写入安全摘要 JSONL 诊断事件,记录事件类型、session/model、tool/progress keys、token/compact/error 摘要,不写入用户/助手正文或工具结果内容,并已有安全 JSONL 读取、类型/模型过滤、汇总统计、deterministic trace/span id、JSON summary export 和 headless `/status show telemetry` trace/span 审计地基;`advanced.lsp=true` 时才向模型暴露只读 `LSPDiagnostics` 工具,用于读取 session-scoped diagnostics snapshot,并支持 file/severity/limit 过滤,底层已能解析 LSP `textDocument/publishDiagnostics` params/notification payload、按文件替换 snapshot、按 LSP 空 diagnostics 语义清空旧文件诊断;同时会写出 session-scoped LSP manager status,按默认或显式 server definitions 解析 workspace/root marker/file extension 命中情况,将已匹配但未启动的 server 标为 `not_started`,并可通过 headless `/status show lsp` 审计 diagnostics 与 manager runtime state;LSP Content-Length framed JSON-RPC reader/writer 与 diagnostics stream processor 已能持续消费 `textDocument/publishDiagnostics` notification、捕获 initialize response capabilities 并更新 session snapshot;LSP server process lifecycle API 已可启动配置命令、消费 stdout framed diagnostics stream,并把 `running`/`exited`/`failed`、PID 和时间戳写回 manager status;LSP client handshake send path 已可向 server stdin 写入 `initialize`、`initialized` 和 `textDocument/didOpen` framed JSON-RPC,支持 root/client/document metadata 和 file URI/language 默认推断;conversation runner 在 `advanced.lsp=true` 且显式或默认 server definitions 命中 workspace 时,会自动启动可执行命令存在的 LSP server、发送 handshake/startup documents、对缺失命令保持可审计 `not_started` reason,并复用 session diagnostics/manager status 生命周期;`advanced.bridge=true` 时会写出 session-scoped bridge manifest,列出 bridge-safe slash/local command 元数据,提供 command/display/alias 安全解析,并可通过 headless `/status show bridge` 审计;bridge direct HTTP handler 已可复用同一 manifest/registry,提供 `/health`、`/manifest`、`/resolve` 和 `/execute` JSON 端点,执行前强制 bridge-safe 白名单并默认不回传展开后的 prompt 正文;bridge loopback-only direct listener 已有可嵌入启动/关闭 API,默认 `127.0.0.1:0`、拒绝非 loopback 地址,并支持可选 bearer/`X-Bridge-Token` token guard;bridge direct websocket JSON channel 已可通过 `/ws` 执行 `resolve`/`execute` 消息并复用同一白名单、token guard 和 prompt 正文不泄露策略;`advanced.nativeIntegrations=true` 时会写出 session-scoped native capability manifest 和 native file index,只记录路径/大小/mtime 等文件元数据、跳过常见 runtime/vendor 目录,并可通过 headless `/status show native` 审计 index 路径与文件数量;任一 `advanced.chrome`/`advanced.voice`/`advanced.computerUse=true` 时会写出 session-scoped integrations manifest,将 Chrome/voice/computer-use 的 enabled 与 `runtime_state` 分开记录,当前启用项明确标为 `not_wired`,并可通过 headless `/status show integrations` 审计;未启用时仍不注册或泄露 gated 工具 schema。实际 session websocket/direct connect 外部接入、telemetry external exporter/backend、Chrome/voice/computer-use runtime,以及 native clipboard/color diff 等平台 runtime 仍未完成。
748+
- 本轮补充:新增 `advanced` settings gate 地基,覆盖 bridge/LSP/telemetry/Chrome/voice/computer-use/native integrations 的独立 bool 开关解析、settings merge、headless `/config show advanced` 和 `/config search` 审计;`advanced.telemetry=true` 时会在 session 目录写入安全摘要 JSONL 诊断事件,记录事件类型、session/model、tool/progress keys、token/compact/error 摘要,不写入用户/助手正文或工具结果内容,并已有安全 JSONL 读取、类型/模型过滤、汇总统计、deterministic trace/span id、JSON summary export、可配置 `telemetryExport` 本地 JSONL exporter / HTTP backend POST、endpoint 脱敏 status,以及 headless `/status show telemetry` trace/span/exporter 审计地基;`advanced.lsp=true` 时才向模型暴露只读 `LSPDiagnostics` 工具,用于读取 session-scoped diagnostics snapshot,并支持 file/severity/limit 过滤,底层已能解析 LSP `textDocument/publishDiagnostics` params/notification payload、按文件替换 snapshot、按 LSP 空 diagnostics 语义清空旧文件诊断;同时会写出 session-scoped LSP manager status,按默认或显式 server definitions 解析 workspace/root marker/file extension 命中情况,将已匹配但未启动的 server 标为 `not_started`,并可通过 headless `/status show lsp` 审计 diagnostics 与 manager runtime state;LSP Content-Length framed JSON-RPC reader/writer 与 diagnostics stream processor 已能持续消费 `textDocument/publishDiagnostics` notification、捕获 initialize response capabilities 并更新 session snapshot;LSP server process lifecycle API 已可启动配置命令、消费 stdout framed diagnostics stream,并把 `running`/`exited`/`failed`、PID 和时间戳写回 manager status;LSP client handshake send path 已可向 server stdin 写入 `initialize`、`initialized` 和 `textDocument/didOpen` framed JSON-RPC,支持 root/client/document metadata 和 file URI/language 默认推断;conversation runner 在 `advanced.lsp=true` 且显式或默认 server definitions 命中 workspace 时,会自动启动可执行命令存在的 LSP server、发送 handshake/startup documents、对缺失命令保持可审计 `not_started` reason,并复用 session diagnostics/manager status 生命周期;`advanced.bridge=true` 时会写出 session-scoped bridge manifest,列出 bridge-safe slash/local command 元数据,提供 command/display/alias 安全解析,并可通过 headless `/status show bridge` 审计;bridge direct HTTP handler 已可复用同一 manifest/registry,提供 `/health`、`/manifest`、`/resolve` 和 `/execute` JSON 端点,执行前强制 bridge-safe 白名单并默认不回传展开后的 prompt 正文;bridge loopback-only direct listener 已有可嵌入启动/关闭 API,默认 `127.0.0.1:0`、拒绝非 loopback 地址,并支持可选 bearer/`X-Bridge-Token` token guard;bridge direct websocket JSON channel 已可通过 `/ws` 执行 `resolve`/`execute` 消息并复用同一白名单、token guard 和 prompt 正文不泄露策略;`advanced.nativeIntegrations=true` 时会写出 session-scoped native capability manifest 和 native file index,只记录路径/大小/mtime 等文件元数据、跳过常见 runtime/vendor 目录,并可通过 headless `/status show native` 审计 index 路径与文件数量;任一 `advanced.chrome`/`advanced.voice`/`advanced.computerUse=true` 时会写出 session-scoped integrations manifest,将 Chrome/voice/computer-use 的 enabled 与 `runtime_state` 分开记录,当前启用项明确标为 `not_wired`,并可通过 headless `/status show integrations` 审计;未启用时仍不注册或泄露 gated 工具 schema。实际 session websocket/direct connect 外部接入、Chrome/voice/computer-use runtime,以及 native clipboard/color diff 等平台 runtime 仍未完成。
749749

750750
### M12: Parity hardening
751751

internal/config/settings.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,9 @@ func MergeSettings(settings ...contracts.Settings) contracts.Settings {
226226
if s.Advanced != nil {
227227
out.Advanced = mergeAdvancedSetting(out.Advanced, s.Advanced)
228228
}
229+
if s.TelemetryExport != nil {
230+
out.TelemetryExport = cloneTelemetryExportSetting(s.TelemetryExport)
231+
}
229232
if s.AutoUpdatesChannel != "" {
230233
out.AutoUpdatesChannel = s.AutoUpdatesChannel
231234
}
@@ -239,6 +242,20 @@ func MergeSettings(settings ...contracts.Settings) contracts.Settings {
239242
return out
240243
}
241244

245+
func cloneTelemetryExportSetting(setting *contracts.TelemetryExportSetting) *contracts.TelemetryExportSetting {
246+
if setting == nil {
247+
return nil
248+
}
249+
cp := *setting
250+
if setting.Headers != nil {
251+
cp.Headers = map[string]string{}
252+
for key, value := range setting.Headers {
253+
cp.Headers[key] = value
254+
}
255+
}
256+
return &cp
257+
}
258+
242259
func MergeSettingsSources(sources ...SourceSettings) contracts.Settings {
243260
settings := make([]contracts.Settings, 0, len(sources))
244261
for _, source := range sources {

internal/config/settings_test.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,12 @@ func TestMergeSettings(t *testing.T) {
110110
Bridge: &bridgeEnabled,
111111
Telemetry: &telemetryDisabled,
112112
},
113+
TelemetryExport: &contracts.TelemetryExportSetting{
114+
Path: "/tmp/old.jsonl",
115+
Headers: map[string]string{
116+
"X-Old": "old",
117+
},
118+
},
113119
}
114120
b := contracts.Settings{
115121
Env: map[string]string{"A": "2", "B": "3"},
@@ -126,6 +132,13 @@ func TestMergeSettings(t *testing.T) {
126132
Advanced: &contracts.AdvancedSetting{
127133
Telemetry: &telemetryEnabled,
128134
},
135+
TelemetryExport: &contracts.TelemetryExportSetting{
136+
Path: "/tmp/new.jsonl",
137+
URL: "https://example.com/telemetry",
138+
Headers: map[string]string{
139+
"X-New": "new",
140+
},
141+
},
129142
}
130143
merged := MergeSettings(a, b)
131144
if merged.Env["A"] != "2" || merged.Env["B"] != "3" {
@@ -149,6 +162,13 @@ func TestMergeSettings(t *testing.T) {
149162
if merged.Advanced == nil || merged.Advanced.Bridge == nil || !*merged.Advanced.Bridge || merged.Advanced.Telemetry == nil || !*merged.Advanced.Telemetry {
150163
t.Fatalf("advanced = %#v", merged.Advanced)
151164
}
165+
if merged.TelemetryExport == nil ||
166+
merged.TelemetryExport.Path != "/tmp/new.jsonl" ||
167+
merged.TelemetryExport.URL != "https://example.com/telemetry" ||
168+
merged.TelemetryExport.Headers["X-New"] != "new" ||
169+
merged.TelemetryExport.Headers["X-Old"] != "" {
170+
t.Fatalf("telemetry export = %#v", merged.TelemetryExport)
171+
}
152172
}
153173

154174
func TestMergeSettingsPreservesSandboxSettings(t *testing.T) {

internal/contracts/settings.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ type Settings struct {
6363
PluginConfigs map[string]PluginConfig `json:"pluginConfigs,omitempty"`
6464
Remote *RemoteSetting `json:"remote,omitempty"`
6565
Advanced *AdvancedSetting `json:"advanced,omitempty"`
66+
TelemetryExport *TelemetryExportSetting `json:"telemetryExport,omitempty"`
6667
AutoUpdatesChannel string `json:"autoUpdatesChannel,omitempty"`
6768
Plugins map[string]any `json:"plugins,omitempty"`
6869
Extra map[string]any `json:"-"`
@@ -115,6 +116,12 @@ type RemoteSetting struct {
115116
DefaultEnvironmentID string `json:"defaultEnvironmentId,omitempty"`
116117
}
117118

119+
type TelemetryExportSetting struct {
120+
Path string `json:"path,omitempty"`
121+
URL string `json:"url,omitempty"`
122+
Headers map[string]string `json:"headers,omitempty"`
123+
}
124+
118125
type AdvancedSetting struct {
119126
Bridge *bool `json:"bridge,omitempty"`
120127
LSP *bool `json:"lsp,omitempty"`

internal/contracts/settings_json.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ var knownSettingsJSONKeys = []string{
9999
"pluginConfigs",
100100
"remote",
101101
"advanced",
102+
"telemetryExport",
102103
"autoUpdatesChannel",
103104
"plugins",
104105
}

0 commit comments

Comments
 (0)