@vymalo/opencode-otel 0.12.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 vymalo contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,91 @@
1
+ # `@vymalo/opencode-otel`
2
+
3
+ [![npm](https://img.shields.io/npm/v/@vymalo/opencode-otel?label=npm&color=CB3837&logo=npm)](https://www.npmjs.com/package/@vymalo/opencode-otel)
4
+
5
+ **OpenTelemetry export for OpenCode.** Ships what actually happens in a session — cost, tokens, tool
6
+ calls, permission decisions, errors, lines of code — as standard OTLP **traces, metrics and logs**,
7
+ to any OpenTelemetry backend. The OpenCode counterpart to
8
+ [Claude Code's monitoring](https://code.claude.com/docs/en/monitoring-usage) and
9
+ [Codex's `[otel]` block](https://learn.chatgpt.com/docs/config-file/config-advanced).
10
+
11
+ Part of the [OpenCode Toolbelt](https://github.com/ADORSYS-GIS/lightbridge-opencode-toolbeit).
12
+
13
+ ## Install
14
+
15
+ ```sh
16
+ npm install @vymalo/opencode-otel
17
+ ```
18
+
19
+ ```jsonc
20
+ // opencode.json
21
+ {
22
+ "plugin": [
23
+ ["@vymalo/opencode-otel", { "endpoint": "http://localhost:4318" }]
24
+ ]
25
+ }
26
+ ```
27
+
28
+ Or configure it entirely from the environment:
29
+
30
+ ```sh
31
+ export OTEL_EXPORTER_OTLP_ENDPOINT="http://localhost:4318"
32
+ ```
33
+
34
+ With **neither** configured the plugin is completely inert — no providers, no sockets, no hooks.
35
+
36
+ ## Why another one
37
+
38
+ [`opencode-otel-plugin`](https://github.com/felixti/opencode-otel-plugin) already covers traces and
39
+ metrics well, and this package deliberately reuses its GenAI-semconv vocabulary so both land on the
40
+ same dashboards. What it adds:
41
+
42
+ - **The logs signal** — `user_prompt`, `assistant_response`, `tool_result`, `tool_decision`,
43
+ `api_error` and friends. This is the developer-interaction stream; Claude Code ships 17 log event
44
+ types against 8 metrics, and it is where the interesting data lives.
45
+ - **Real USD cost.** OpenCode's host computes `AssistantMessage.cost`; this exports it directly, so
46
+ there is no price table to maintain and nothing to drift when a provider changes rates.
47
+ - **All five token types** — `input`, `output`, `reasoning`, `cache_read`, `cache_write`. On a
48
+ cached agentic session cache-read is routinely the majority of tokens, so summing input+output
49
+ alone measures a different quantity.
50
+ - **Permission decisions**, mapped from OpenCode's `permission.*` events.
51
+ - **`opencode.json` configuration**, not just environment variables — required for
52
+ `.well-known/opencode` distribution.
53
+
54
+ Run one or the other, not both: they would double-count.
55
+
56
+ ## At a glance
57
+
58
+ | Signal | What you get |
59
+ | --- | --- |
60
+ | **Metrics** | `opencode.cost.usage` (USD), `gen_ai.client.token.usage` (5 token types), `gen_ai.client.operation.duration`, session/request/compaction counts, active time, lines of code, tool invocations, permission decisions |
61
+ | **Logs** | `opencode.session_start` / `_idle`, `user_prompt`, `assistant_response`, `tool_result`, `tool_decision`, `api_error`, `file_edited`, `compaction`, `command_executed` |
62
+ | **Traces** | `invoke_agent opencode` → `chat {model}` → `execute_tool {name}`, with W3C `traceparent` propagated into provider requests |
63
+
64
+ ## Privacy
65
+
66
+ **No content is captured** — not prompts, responses, tool arguments or API bodies. Log records carry
67
+ shape only: lengths, counts, durations, sizes, outcomes, error classes.
68
+
69
+ Resource attributes identify the **machine and project, never the developer**. The git author email
70
+ is not collected; add `OTEL_RESOURCE_ATTRIBUTES="enduser.id=…"` if you want per-person attribution.
71
+
72
+ Session id is attached to logs and spans always, but to **metrics only** when `includeSessionId` is
73
+ enabled — it is unbounded cardinality and metric backends bill per series.
74
+
75
+ ## Transport
76
+
77
+ OTLP over **HTTP with a protobuf payload**, only. gRPC is deliberately absent: OpenCode plugins run
78
+ under Bun as well as Node, and `@grpc/grpc-js` is unreliable there. Put a collector in front if your
79
+ backend needs gRPC. See
80
+ [ADR-0009](https://github.com/ADORSYS-GIS/lightbridge-opencode-toolbeit/blob/main/docs/adr/0009-otel-otlp-http-not-grpc.md).
81
+
82
+ ## Full reference
83
+
84
+ - [`docs/otel.md`](https://github.com/ADORSYS-GIS/lightbridge-opencode-toolbeit/blob/main/docs/otel.md)
85
+ — every option, metric, log event and attribute; backend recipes; troubleshooting.
86
+ - [`plans/otel.md`](https://github.com/ADORSYS-GIS/lightbridge-opencode-toolbeit/blob/main/plans/otel.md)
87
+ — design rationale, the prior-art sweep, and the OpenCode-event → OTel-signal mapping table.
88
+
89
+ ## License
90
+
91
+ MIT
@@ -0,0 +1,27 @@
1
+ import type { ResolvedOtelConfig, SignalName } from "./types.js";
2
+ export declare const SIGNALS: readonly SignalName[];
3
+ /** Env source, injectable so tests never touch `process.env`. */
4
+ export type EnvSource = Record<string, string | undefined>;
5
+ /**
6
+ * Parse the OTel `key=value,key2=value2` list format used by both
7
+ * `OTEL_EXPORTER_OTLP_HEADERS` and `OTEL_RESOURCE_ATTRIBUTES`. Values are
8
+ * percent-decoded per spec; an undecodable value is kept verbatim rather than
9
+ * dropping the whole pair.
10
+ */
11
+ export declare function parseKeyValueList(raw: string | undefined): Record<string, string>;
12
+ /**
13
+ * Resolve plugin options against the environment.
14
+ *
15
+ * **Precedence: environment overrides plugin options.** Options are the base
16
+ * layer so a `.well-known/opencode` document can ship a working default for a
17
+ * whole organization; `OTEL_*` variables override per machine so a developer
18
+ * can point at a local collector without editing served config. See
19
+ * `plans/otel.md`.
20
+ */
21
+ export declare function resolveOtelConfig(raw: unknown, env?: EnvSource): ResolvedOtelConfig;
22
+ /**
23
+ * Resolve the OTLP URL for one signal. A per-signal endpoint is used verbatim
24
+ * (spec: it already includes the path); the base endpoint gets the signal path
25
+ * appended.
26
+ */
27
+ export declare function signalUrl(config: ResolvedOtelConfig, signal: SignalName): string | undefined;
package/dist/config.js ADDED
@@ -0,0 +1,224 @@
1
+ export const SIGNALS = ["traces", "metrics", "logs"];
2
+ const DEFAULTS = {
3
+ serviceName: "opencode",
4
+ metricExportIntervalMs: 60_000,
5
+ logExportIntervalMs: 5_000,
6
+ traceExportIntervalMs: 5_000,
7
+ metricTemporality: "delta"
8
+ };
9
+ /**
10
+ * The `OTEL_*` variable names read per signal. The first entry of each tuple is
11
+ * the OTel-spec name; the second (where present) is the Claude-Code-compatible
12
+ * alias, accepted so an operator can move a working env block across tools.
13
+ */
14
+ const SIGNAL_ENV = {
15
+ traces: {
16
+ exporter: "OTEL_TRACES_EXPORTER",
17
+ endpoint: "OTEL_EXPORTER_OTLP_TRACES_ENDPOINT",
18
+ interval: ["OTEL_BSP_SCHEDULE_DELAY", "OTEL_TRACES_EXPORT_INTERVAL"]
19
+ },
20
+ metrics: {
21
+ exporter: "OTEL_METRICS_EXPORTER",
22
+ endpoint: "OTEL_EXPORTER_OTLP_METRICS_ENDPOINT",
23
+ interval: ["OTEL_METRIC_EXPORT_INTERVAL"]
24
+ },
25
+ logs: {
26
+ exporter: "OTEL_LOGS_EXPORTER",
27
+ endpoint: "OTEL_EXPORTER_OTLP_LOGS_ENDPOINT",
28
+ interval: ["OTEL_BLRP_SCHEDULE_DELAY", "OTEL_LOGS_EXPORT_INTERVAL"]
29
+ }
30
+ };
31
+ function parseBool(value) {
32
+ if (value === undefined) {
33
+ return undefined;
34
+ }
35
+ if (/^(1|true|yes|on)$/i.test(value)) {
36
+ return true;
37
+ }
38
+ if (/^(0|false|no|off)$/i.test(value)) {
39
+ return false;
40
+ }
41
+ return undefined;
42
+ }
43
+ function parsePositiveInt(value) {
44
+ if (value === undefined) {
45
+ return undefined;
46
+ }
47
+ const n = Number.parseInt(value.trim(), 10);
48
+ return Number.isFinite(n) && n > 0 ? n : undefined;
49
+ }
50
+ /**
51
+ * Parse the OTel `key=value,key2=value2` list format used by both
52
+ * `OTEL_EXPORTER_OTLP_HEADERS` and `OTEL_RESOURCE_ATTRIBUTES`. Values are
53
+ * percent-decoded per spec; an undecodable value is kept verbatim rather than
54
+ * dropping the whole pair.
55
+ */
56
+ export function parseKeyValueList(raw) {
57
+ if (!raw) {
58
+ return {};
59
+ }
60
+ const out = {};
61
+ for (const pair of raw.split(",")) {
62
+ const eq = pair.indexOf("=");
63
+ if (eq <= 0) {
64
+ continue;
65
+ }
66
+ const key = pair.slice(0, eq).trim();
67
+ const rawValue = pair.slice(eq + 1).trim();
68
+ if (!key) {
69
+ continue;
70
+ }
71
+ try {
72
+ out[key] = decodeURIComponent(rawValue);
73
+ }
74
+ catch {
75
+ out[key] = rawValue;
76
+ }
77
+ }
78
+ return out;
79
+ }
80
+ function parseExporter(value) {
81
+ if (value === undefined) {
82
+ return undefined;
83
+ }
84
+ // The spec allows a comma-separated list; we honour the first recognised
85
+ // entry rather than fanning out to multiple exporters.
86
+ for (const candidate of value.split(",").map((v) => v.trim().toLowerCase())) {
87
+ if (candidate === "otlp" || candidate === "console" || candidate === "none") {
88
+ return candidate;
89
+ }
90
+ }
91
+ return undefined;
92
+ }
93
+ function firstDefined(env, keys) {
94
+ for (const key of keys) {
95
+ const value = env[key];
96
+ if (value !== undefined && value !== "") {
97
+ return value;
98
+ }
99
+ }
100
+ return undefined;
101
+ }
102
+ function stringRecord(raw) {
103
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
104
+ return {};
105
+ }
106
+ const out = {};
107
+ for (const [key, value] of Object.entries(raw)) {
108
+ if (typeof value === "string") {
109
+ out[key] = value;
110
+ }
111
+ else if (typeof value === "number" || typeof value === "boolean") {
112
+ out[key] = String(value);
113
+ }
114
+ }
115
+ return out;
116
+ }
117
+ function stringList(raw) {
118
+ if (Array.isArray(raw)) {
119
+ return raw.filter((v) => typeof v === "string" && v.trim() !== "");
120
+ }
121
+ if (typeof raw === "string") {
122
+ return raw
123
+ .split(",")
124
+ .map((v) => v.trim())
125
+ .filter((v) => v !== "");
126
+ }
127
+ return [];
128
+ }
129
+ /**
130
+ * Resolve plugin options against the environment.
131
+ *
132
+ * **Precedence: environment overrides plugin options.** Options are the base
133
+ * layer so a `.well-known/opencode` document can ship a working default for a
134
+ * whole organization; `OTEL_*` variables override per machine so a developer
135
+ * can point at a local collector without editing served config. See
136
+ * `plans/otel.md`.
137
+ */
138
+ export function resolveOtelConfig(raw, env = process.env) {
139
+ const opts = (raw ?? {});
140
+ const enabled = parseBool(env.OPENCODE_OTEL_ENABLED) ?? opts.enabled !== false;
141
+ const endpoint = env.OTEL_EXPORTER_OTLP_ENDPOINT || opts.endpoint || undefined;
142
+ const endpoints = {};
143
+ for (const signal of SIGNALS) {
144
+ const value = env[SIGNAL_ENV[signal].endpoint] || opts.endpoints?.[signal];
145
+ if (value) {
146
+ endpoints[signal] = value;
147
+ }
148
+ }
149
+ // Env headers merge over option headers key-by-key rather than replacing the
150
+ // map, so a machine can override just its auth token without restating the
151
+ // whole set the served config provided.
152
+ const headers = {
153
+ ...stringRecord(opts.headers),
154
+ ...parseKeyValueList(env.OTEL_EXPORTER_OTLP_HEADERS)
155
+ };
156
+ // An endpoint anywhere is what makes OTLP the implicit default; with none
157
+ // configured the plugin stays completely inert.
158
+ const hasEndpoint = Boolean(endpoint) || SIGNALS.some((s) => Boolean(endpoints[s]));
159
+ const fallback = hasEndpoint ? "otlp" : "none";
160
+ const exporters = {};
161
+ for (const signal of SIGNALS) {
162
+ exporters[signal] =
163
+ parseExporter(env[SIGNAL_ENV[signal].exporter]) ?? opts.exporters?.[signal] ?? fallback;
164
+ }
165
+ const resourceAttributes = {
166
+ ...stringRecord(opts.resourceAttributes),
167
+ ...parseKeyValueList(env.OTEL_RESOURCE_ATTRIBUTES)
168
+ };
169
+ const temporality = env.OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE?.trim().toLowerCase() === "cumulative"
170
+ ? "cumulative"
171
+ : env.OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE?.trim().toLowerCase() === "delta"
172
+ ? "delta"
173
+ : (opts.metricTemporality ?? DEFAULTS.metricTemporality);
174
+ const filteredTools = new Set(env.OTEL_OPENCODE_FILTERED_TOOLS !== undefined
175
+ ? stringList(env.OTEL_OPENCODE_FILTERED_TOOLS)
176
+ : stringList(opts.filteredTools));
177
+ const enabledSignals = SIGNALS.filter((s) => exporters[s] !== "none");
178
+ return {
179
+ enabled,
180
+ active: enabled && enabledSignals.length > 0,
181
+ endpoint,
182
+ endpoints,
183
+ headers,
184
+ exporters,
185
+ serviceName: env.OTEL_SERVICE_NAME || opts.serviceName || DEFAULTS.serviceName,
186
+ environment: env.OPENCODE_OTEL_ENVIRONMENT || opts.environment || undefined,
187
+ resourceAttributes,
188
+ metricExportIntervalMs: parsePositiveInt(firstDefined(env, SIGNAL_ENV.metrics.interval)) ??
189
+ (opts.metricExportIntervalMs && opts.metricExportIntervalMs > 0
190
+ ? opts.metricExportIntervalMs
191
+ : DEFAULTS.metricExportIntervalMs),
192
+ logExportIntervalMs: parsePositiveInt(firstDefined(env, SIGNAL_ENV.logs.interval)) ??
193
+ (opts.logExportIntervalMs && opts.logExportIntervalMs > 0
194
+ ? opts.logExportIntervalMs
195
+ : DEFAULTS.logExportIntervalMs),
196
+ traceExportIntervalMs: parsePositiveInt(firstDefined(env, SIGNAL_ENV.traces.interval)) ??
197
+ (opts.traceExportIntervalMs && opts.traceExportIntervalMs > 0
198
+ ? opts.traceExportIntervalMs
199
+ : DEFAULTS.traceExportIntervalMs),
200
+ metricTemporality: temporality,
201
+ includeSessionId: parseBool(env.OTEL_METRICS_INCLUDE_SESSION_ID) ?? opts.includeSessionId === true,
202
+ filteredTools,
203
+ propagateTraceContext: parseBool(env.OPENCODE_OTEL_PROPAGATE_TRACE_CONTEXT) ??
204
+ (opts.propagateTraceContext !== false && exporters.traces !== "none")
205
+ };
206
+ }
207
+ /**
208
+ * Resolve the OTLP URL for one signal. A per-signal endpoint is used verbatim
209
+ * (spec: it already includes the path); the base endpoint gets the signal path
210
+ * appended.
211
+ */
212
+ export function signalUrl(config, signal) {
213
+ const explicit = config.endpoints[signal];
214
+ if (explicit) {
215
+ return explicit;
216
+ }
217
+ if (!config.endpoint) {
218
+ return undefined;
219
+ }
220
+ const base = config.endpoint.replace(/\/+$/, "");
221
+ const path = signal === "traces" ? "v1/traces" : signal === "metrics" ? "v1/metrics" : "v1/logs";
222
+ return `${base}/${path}`;
223
+ }
224
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAQA,MAAM,CAAC,MAAM,OAAO,GAA0B,CAAC,QAAQ,EAAE,SAAS,EAAE,MAAM,CAAU,CAAC;AAErF,MAAM,QAAQ,GAAG;IACf,WAAW,EAAE,UAAU;IACvB,sBAAsB,EAAE,MAAM;IAC9B,mBAAmB,EAAE,KAAK;IAC1B,qBAAqB,EAAE,KAAK;IAC5B,iBAAiB,EAAE,OAA4B;CACvC,CAAC;AAKX;;;;GAIG;AACH,MAAM,UAAU,GAAG;IACjB,MAAM,EAAE;QACN,QAAQ,EAAE,sBAAsB;QAChC,QAAQ,EAAE,oCAAoC;QAC9C,QAAQ,EAAE,CAAC,yBAAyB,EAAE,6BAA6B,CAAC;KACrE;IACD,OAAO,EAAE;QACP,QAAQ,EAAE,uBAAuB;QACjC,QAAQ,EAAE,qCAAqC;QAC/C,QAAQ,EAAE,CAAC,6BAA6B,CAAC;KAC1C;IACD,IAAI,EAAE;QACJ,QAAQ,EAAE,oBAAoB;QAC9B,QAAQ,EAAE,kCAAkC;QAC5C,QAAQ,EAAE,CAAC,0BAA0B,EAAE,2BAA2B,CAAC;KACpE;CAIF,CAAC;AAEF,SAAS,SAAS,CAAC,KAAyB;IAC1C,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,IAAI,oBAAoB,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QACrC,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,qBAAqB,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QACtC,OAAO,KAAK,CAAC;IACf,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAS,gBAAgB,CAAC,KAAyB;IACjD,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,MAAM,CAAC,GAAG,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;IAC5C,OAAO,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AACrD,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAAC,GAAuB;IACvD,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,MAAM,GAAG,GAA2B,EAAE,CAAC;IACvC,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;QAClC,MAAM,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAC7B,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC;YACZ,SAAS;QACX,CAAC;QACD,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;QACrC,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAC3C,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,SAAS;QACX,CAAC;QACD,IAAI,CAAC;YACH,GAAG,CAAC,GAAG,CAAC,GAAG,kBAAkB,CAAC,QAAQ,CAAC,CAAC;QAC1C,CAAC;QAAC,MAAM,CAAC;YACP,GAAG,CAAC,GAAG,CAAC,GAAG,QAAQ,CAAC;QACtB,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,SAAS,aAAa,CAAC,KAAyB;IAC9C,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,yEAAyE;IACzE,uDAAuD;IACvD,KAAK,MAAM,SAAS,IAAI,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,EAAE,CAAC;QAC5E,IAAI,SAAS,KAAK,MAAM,IAAI,SAAS,KAAK,SAAS,IAAI,SAAS,KAAK,MAAM,EAAE,CAAC;YAC5E,OAAO,SAAS,CAAC;QACnB,CAAC;IACH,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAS,YAAY,CAAC,GAAc,EAAE,IAAuB;IAC3D,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,MAAM,KAAK,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC;QACvB,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,EAAE,EAAE,CAAC;YACxC,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAS,YAAY,CAAC,GAAY;IAChC,IAAI,CAAC,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QAC1D,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,MAAM,GAAG,GAA2B,EAAE,CAAC;IACvC,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAA8B,CAAC,EAAE,CAAC;QAC1E,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;YAC9B,GAAG,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;QACnB,CAAC;aAAM,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,OAAO,KAAK,KAAK,SAAS,EAAE,CAAC;YACnE,GAAG,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;QAC3B,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,SAAS,UAAU,CAAC,GAAY;IAC9B,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QACvB,OAAO,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAClF,CAAC;IACD,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;QAC5B,OAAO,GAAG;aACP,KAAK,CAAC,GAAG,CAAC;aACV,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;aACpB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC;IAC7B,CAAC;IACD,OAAO,EAAE,CAAC;AACZ,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,iBAAiB,CAAC,GAAY,EAAE,MAAiB,OAAO,CAAC,GAAG;IAC1E,MAAM,IAAI,GAAG,CAAC,GAAG,IAAI,EAAE,CAAsB,CAAC;IAE9C,MAAM,OAAO,GAAG,SAAS,CAAC,GAAG,CAAC,qBAAqB,CAAC,IAAI,IAAI,CAAC,OAAO,KAAK,KAAK,CAAC;IAE/E,MAAM,QAAQ,GAAG,GAAG,CAAC,2BAA2B,IAAI,IAAI,CAAC,QAAQ,IAAI,SAAS,CAAC;IAE/E,MAAM,SAAS,GAAwC,EAAE,CAAC;IAC1D,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,MAAM,KAAK,GAAG,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC,MAAM,CAAC,CAAC;QAC3E,IAAI,KAAK,EAAE,CAAC;YACV,SAAS,CAAC,MAAM,CAAC,GAAG,KAAK,CAAC;QAC5B,CAAC;IACH,CAAC;IAED,6EAA6E;IAC7E,2EAA2E;IAC3E,wCAAwC;IACxC,MAAM,OAAO,GAAG;QACd,GAAG,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC;QAC7B,GAAG,iBAAiB,CAAC,GAAG,CAAC,0BAA0B,CAAC;KACrD,CAAC;IAEF,0EAA0E;IAC1E,gDAAgD;IAChD,MAAM,WAAW,GAAG,OAAO,CAAC,QAAQ,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACpF,MAAM,QAAQ,GAAiB,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC;IAE7D,MAAM,SAAS,GAAG,EAAsC,CAAC;IACzD,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,SAAS,CAAC,MAAM,CAAC;YACf,aAAa,CAAC,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC,MAAM,CAAC,IAAI,QAAQ,CAAC;IAC5F,CAAC;IAED,MAAM,kBAAkB,GAAG;QACzB,GAAG,YAAY,CAAC,IAAI,CAAC,kBAAkB,CAAC;QACxC,GAAG,iBAAiB,CAAC,GAAG,CAAC,wBAAwB,CAAC;KACnD,CAAC;IAEF,MAAM,WAAW,GACf,GAAG,CAAC,iDAAiD,EAAE,IAAI,EAAE,CAAC,WAAW,EAAE,KAAK,YAAY;QAC1F,CAAC,CAAC,YAAY;QACd,CAAC,CAAC,GAAG,CAAC,iDAAiD,EAAE,IAAI,EAAE,CAAC,WAAW,EAAE,KAAK,OAAO;YACvF,CAAC,CAAC,OAAO;YACT,CAAC,CAAC,CAAC,IAAI,CAAC,iBAAiB,IAAI,QAAQ,CAAC,iBAAiB,CAAC,CAAC;IAE/D,MAAM,aAAa,GAAG,IAAI,GAAG,CAC3B,GAAG,CAAC,4BAA4B,KAAK,SAAS;QAC5C,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,4BAA4B,CAAC;QAC9C,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,aAAa,CAAC,CACnC,CAAC;IAEF,MAAM,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,CAAC;IAEtE,OAAO;QACL,OAAO;QACP,MAAM,EAAE,OAAO,IAAI,cAAc,CAAC,MAAM,GAAG,CAAC;QAC5C,QAAQ;QACR,SAAS;QACT,OAAO;QACP,SAAS;QACT,WAAW,EAAE,GAAG,CAAC,iBAAiB,IAAI,IAAI,CAAC,WAAW,IAAI,QAAQ,CAAC,WAAW;QAC9E,WAAW,EAAE,GAAG,CAAC,yBAAyB,IAAI,IAAI,CAAC,WAAW,IAAI,SAAS;QAC3E,kBAAkB;QAClB,sBAAsB,EACpB,gBAAgB,CAAC,YAAY,CAAC,GAAG,EAAE,UAAU,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;YAChE,CAAC,IAAI,CAAC,sBAAsB,IAAI,IAAI,CAAC,sBAAsB,GAAG,CAAC;gBAC7D,CAAC,CAAC,IAAI,CAAC,sBAAsB;gBAC7B,CAAC,CAAC,QAAQ,CAAC,sBAAsB,CAAC;QACtC,mBAAmB,EACjB,gBAAgB,CAAC,YAAY,CAAC,GAAG,EAAE,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YAC7D,CAAC,IAAI,CAAC,mBAAmB,IAAI,IAAI,CAAC,mBAAmB,GAAG,CAAC;gBACvD,CAAC,CAAC,IAAI,CAAC,mBAAmB;gBAC1B,CAAC,CAAC,QAAQ,CAAC,mBAAmB,CAAC;QACnC,qBAAqB,EACnB,gBAAgB,CAAC,YAAY,CAAC,GAAG,EAAE,UAAU,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;YAC/D,CAAC,IAAI,CAAC,qBAAqB,IAAI,IAAI,CAAC,qBAAqB,GAAG,CAAC;gBAC3D,CAAC,CAAC,IAAI,CAAC,qBAAqB;gBAC5B,CAAC,CAAC,QAAQ,CAAC,qBAAqB,CAAC;QACrC,iBAAiB,EAAE,WAAW;QAC9B,gBAAgB,EACd,SAAS,CAAC,GAAG,CAAC,+BAA+B,CAAC,IAAI,IAAI,CAAC,gBAAgB,KAAK,IAAI;QAClF,aAAa;QACb,qBAAqB,EACnB,SAAS,CAAC,GAAG,CAAC,qCAAqC,CAAC;YACpD,CAAC,IAAI,CAAC,qBAAqB,KAAK,KAAK,IAAI,SAAS,CAAC,MAAM,KAAK,MAAM,CAAC;KACxE,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,SAAS,CAAC,MAA0B,EAAE,MAAkB;IACtE,MAAM,QAAQ,GAAG,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IAC1C,IAAI,QAAQ,EAAE,CAAC;QACb,OAAO,QAAQ,CAAC;IAClB,CAAC;IACD,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC;QACrB,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,MAAM,IAAI,GAAG,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IACjD,MAAM,IAAI,GAAG,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,SAAS,CAAC;IACjG,OAAO,GAAG,IAAI,IAAI,IAAI,EAAE,CAAC;AAC3B,CAAC"}
@@ -0,0 +1 @@
1
+ export { default } from "./opencode.js";
package/dist/index.js ADDED
@@ -0,0 +1,6 @@
1
+ // Intentionally tiny. OpenCode iterates every named export of the main entry
2
+ // and rejects anything that isn't a `Plugin` function, so the only thing this
3
+ // module exposes is the default plugin. Library/utility exports live in
4
+ // `./lib` (see lib.ts), which OpenCode never inspects.
5
+ export { default } from "./opencode.js";
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,8EAA8E;AAC9E,wEAAwE;AACxE,uDAAuD;AACvD,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC"}
@@ -0,0 +1,29 @@
1
+ import type { Counter, Histogram, Meter } from "@opentelemetry/api";
2
+ /**
3
+ * Every metric this plugin emits, created once per plugin instance.
4
+ *
5
+ * Naming follows the GenAI semantic conventions where one exists
6
+ * (`gen_ai.client.*`) and `opencode.*` otherwise — deliberately matching the
7
+ * vocabulary `opencode-otel-plugin` already established, so both plugins' data
8
+ * lands on the same dashboards. See `plans/otel.md`.
9
+ */
10
+ export interface Instruments {
11
+ /** Real USD, straight from `AssistantMessage.cost` — no price table involved. */
12
+ cost: Counter;
13
+ /** All five token types, discriminated by `gen_ai.token.type`. */
14
+ tokens: Histogram;
15
+ /** Assistant-message wall time, seconds. */
16
+ duration: Histogram;
17
+ sessions: Counter;
18
+ requests: Counter;
19
+ compactions: Counter;
20
+ /** Wall time a session spent `busy`, seconds. */
21
+ activeTime: Counter;
22
+ linesOfCode: Counter;
23
+ toolInvocations: Counter;
24
+ permissionDecisions: Counter;
25
+ commands: Counter;
26
+ }
27
+ export declare function createInstruments(meter: Meter): Instruments;
28
+ /** Best-effort language for a path, by extension. `undefined` when unknown. */
29
+ export declare function detectLanguage(file: string): string | undefined;
@@ -0,0 +1,102 @@
1
+ export function createInstruments(meter) {
2
+ return {
3
+ cost: meter.createCounter("opencode.cost.usage", {
4
+ description: "Cost of model usage, as reported by the OpenCode host",
5
+ unit: "USD"
6
+ }),
7
+ tokens: meter.createHistogram("gen_ai.client.token.usage", {
8
+ description: "Tokens consumed per assistant message, by token type",
9
+ unit: "{token}"
10
+ }),
11
+ duration: meter.createHistogram("gen_ai.client.operation.duration", {
12
+ description: "Duration of a model operation",
13
+ unit: "s"
14
+ }),
15
+ sessions: meter.createCounter("opencode.session.count", {
16
+ description: "Sessions started",
17
+ unit: "{session}"
18
+ }),
19
+ requests: meter.createCounter("opencode.session.request.count", {
20
+ description: "Assistant messages completed",
21
+ unit: "{request}"
22
+ }),
23
+ compactions: meter.createCounter("opencode.session.compaction.count", {
24
+ description: "Context compactions performed",
25
+ unit: "{compaction}"
26
+ }),
27
+ activeTime: meter.createCounter("opencode.active_time.total", {
28
+ description: "Wall time sessions spent busy",
29
+ unit: "s"
30
+ }),
31
+ linesOfCode: meter.createCounter("opencode.lines_of_code.count", {
32
+ description: "Lines added or removed across session diffs",
33
+ unit: "{line}"
34
+ }),
35
+ toolInvocations: meter.createCounter("opencode.tool.invocations", {
36
+ description: "Tool executions",
37
+ unit: "{invocation}"
38
+ }),
39
+ permissionDecisions: meter.createCounter("opencode.permission.decision.count", {
40
+ description: "Permission prompts resolved",
41
+ unit: "{decision}"
42
+ }),
43
+ commands: meter.createCounter("opencode.command.executed.count", {
44
+ description: "Slash commands executed",
45
+ unit: "{command}"
46
+ })
47
+ };
48
+ }
49
+ const EXTENSION_LANGUAGES = {
50
+ ts: "typescript",
51
+ tsx: "typescript",
52
+ mts: "typescript",
53
+ cts: "typescript",
54
+ js: "javascript",
55
+ jsx: "javascript",
56
+ mjs: "javascript",
57
+ cjs: "javascript",
58
+ py: "python",
59
+ rs: "rust",
60
+ go: "go",
61
+ java: "java",
62
+ kt: "kotlin",
63
+ kts: "kotlin",
64
+ swift: "swift",
65
+ dart: "dart",
66
+ rb: "ruby",
67
+ php: "php",
68
+ cs: "csharp",
69
+ c: "c",
70
+ h: "c",
71
+ cc: "cpp",
72
+ cpp: "cpp",
73
+ hpp: "cpp",
74
+ m: "objective-c",
75
+ mm: "objective-c",
76
+ scala: "scala",
77
+ ex: "elixir",
78
+ exs: "elixir",
79
+ sh: "shell",
80
+ bash: "shell",
81
+ zsh: "shell",
82
+ sql: "sql",
83
+ html: "html",
84
+ css: "css",
85
+ scss: "scss",
86
+ json: "json",
87
+ yaml: "yaml",
88
+ yml: "yaml",
89
+ toml: "toml",
90
+ md: "markdown",
91
+ tf: "terraform"
92
+ };
93
+ /** Best-effort language for a path, by extension. `undefined` when unknown. */
94
+ export function detectLanguage(file) {
95
+ const base = file.slice(file.lastIndexOf("/") + 1);
96
+ const dot = base.lastIndexOf(".");
97
+ if (dot <= 0) {
98
+ return undefined;
99
+ }
100
+ return EXTENSION_LANGUAGES[base.slice(dot + 1).toLowerCase()];
101
+ }
102
+ //# sourceMappingURL=instruments.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"instruments.js","sourceRoot":"","sources":["../src/instruments.ts"],"names":[],"mappings":"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"}
package/dist/lib.d.ts ADDED
@@ -0,0 +1,8 @@
1
+ export { createOtelPlugin, OpencodeOtelPlugin, type OtelPluginFactoryOptions } from "./opencode.js";
2
+ export { type EnvSource, parseKeyValueList, resolveOtelConfig, signalUrl, SIGNALS } from "./config.js";
3
+ export { buildResource, createProviders, type ExporterFactories, type TelemetryProviders } from "./providers.js";
4
+ export { createInstruments, detectLanguage, type Instruments } from "./instruments.js";
5
+ export { type RecorderDeps, TelemetryRecorder } from "./recorder.js";
6
+ export { installTracePropagation, type PropagationConfigInput, type ProviderConfigLike } from "./propagation.js";
7
+ export { createJsonConsoleLogger, DEFAULT_LOG_LEVEL, fromOpenCodeLogLevel, type LogFields, type Logger, type LogLevel } from "./logging.js";
8
+ export type { ExporterKind, MetricTemporality, OtelPluginOptions, ResolvedOtelConfig, SignalName } from "./types.js";
package/dist/lib.js ADDED
@@ -0,0 +1,8 @@
1
+ export { createOtelPlugin, OpencodeOtelPlugin } from "./opencode.js";
2
+ export { parseKeyValueList, resolveOtelConfig, signalUrl, SIGNALS } from "./config.js";
3
+ export { buildResource, createProviders } from "./providers.js";
4
+ export { createInstruments, detectLanguage } from "./instruments.js";
5
+ export { TelemetryRecorder } from "./recorder.js";
6
+ export { installTracePropagation } from "./propagation.js";
7
+ export { createJsonConsoleLogger, DEFAULT_LOG_LEVEL, fromOpenCodeLogLevel } from "./logging.js";
8
+ //# sourceMappingURL=lib.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lib.js","sourceRoot":"","sources":["../src/lib.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,EAChB,kBAAkB,EAEnB,MAAM,eAAe,CAAC;AAEvB,OAAO,EAEL,iBAAiB,EACjB,iBAAiB,EACjB,SAAS,EACT,OAAO,EACR,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,aAAa,EACb,eAAe,EAGhB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAoB,MAAM,kBAAkB,CAAC;AAEvF,OAAO,EAAqB,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAErE,OAAO,EACL,uBAAuB,EAGxB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EACL,uBAAuB,EACvB,iBAAiB,EACjB,oBAAoB,EAIrB,MAAM,cAAc,CAAC"}
@@ -0,0 +1,16 @@
1
+ import type { LogLevel } from "./types.js";
2
+ export type { LogLevel } from "./types.js";
3
+ export declare const LOG_LEVEL_PRIORITY: Record<LogLevel, number>;
4
+ export declare const DEFAULT_LOG_LEVEL: LogLevel;
5
+ export interface LogFields {
6
+ [key: string]: unknown;
7
+ }
8
+ export interface Logger {
9
+ trace(event: string, fields?: LogFields): void;
10
+ debug(event: string, fields?: LogFields): void;
11
+ info(event: string, fields?: LogFields): void;
12
+ warn(event: string, fields?: LogFields): void;
13
+ error(event: string, fields?: LogFields): void;
14
+ }
15
+ export declare function createJsonConsoleLogger(minLevel?: LogLevel): Logger;
16
+ export declare function fromOpenCodeLogLevel(value: unknown): LogLevel | undefined;
@@ -0,0 +1,72 @@
1
+ export const LOG_LEVEL_PRIORITY = {
2
+ trace: 5,
3
+ debug: 10,
4
+ info: 20,
5
+ warn: 30,
6
+ error: 40
7
+ };
8
+ export const DEFAULT_LOG_LEVEL = "info";
9
+ function redactFields(fields) {
10
+ if (!fields) {
11
+ return undefined;
12
+ }
13
+ const redacted = {};
14
+ for (const [key, value] of Object.entries(fields)) {
15
+ if (/token|secret|password|authorization/i.test(key)) {
16
+ redacted[key] = "[redacted]";
17
+ continue;
18
+ }
19
+ redacted[key] = value;
20
+ }
21
+ return redacted;
22
+ }
23
+ export function createJsonConsoleLogger(minLevel = DEFAULT_LOG_LEVEL) {
24
+ const minPriority = LOG_LEVEL_PRIORITY[minLevel];
25
+ const write = (level, event, fields) => {
26
+ if (LOG_LEVEL_PRIORITY[level] < minPriority) {
27
+ return;
28
+ }
29
+ const payload = {
30
+ ts: new Date().toISOString(),
31
+ level,
32
+ event,
33
+ ...(redactFields(fields) ?? {})
34
+ };
35
+ const line = JSON.stringify(payload);
36
+ if (level === "error") {
37
+ console.error(line);
38
+ return;
39
+ }
40
+ if (level === "warn") {
41
+ console.warn(line);
42
+ return;
43
+ }
44
+ console.log(line);
45
+ };
46
+ return {
47
+ trace: (event, fields) => write("trace", event, fields),
48
+ debug: (event, fields) => write("debug", event, fields),
49
+ info: (event, fields) => write("info", event, fields),
50
+ warn: (event, fields) => write("warn", event, fields),
51
+ error: (event, fields) => write("error", event, fields)
52
+ };
53
+ }
54
+ export function fromOpenCodeLogLevel(value) {
55
+ if (typeof value !== "string") {
56
+ return undefined;
57
+ }
58
+ switch (value.toUpperCase()) {
59
+ case "DEBUG":
60
+ // Host DEBUG unlocks our most-verbose internal tier (trace).
61
+ return "trace";
62
+ case "INFO":
63
+ return "info";
64
+ case "WARN":
65
+ return "warn";
66
+ case "ERROR":
67
+ return "error";
68
+ default:
69
+ return undefined;
70
+ }
71
+ }
72
+ //# sourceMappingURL=logging.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logging.js","sourceRoot":"","sources":["../src/logging.ts"],"names":[],"mappings":"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"}