neatlogs 1.1.2 → 1.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser.cjs +11 -11
- package/dist/browser.cjs.map +1 -1
- package/dist/browser.d.ts +15 -15
- package/dist/browser.mjs +11 -11
- package/dist/browser.mjs.map +1 -1
- package/dist/index.cjs +83 -81
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.mjs +83 -81
- package/dist/index.mjs.map +1 -1
- package/dist/opencode-plugin.cjs +1 -1
- package/dist/opencode-plugin.cjs.map +1 -1
- package/dist/opencode-plugin.mjs +1 -1
- package/dist/opencode-plugin.mjs.map +1 -1
- package/package.json +1 -1
package/dist/opencode-plugin.cjs
CHANGED
|
@@ -40,7 +40,7 @@ module.exports = __toCommonJS(opencode_plugin_exports);
|
|
|
40
40
|
var import_protobufjs = __toESM(require("protobufjs"));
|
|
41
41
|
|
|
42
42
|
// src/version.ts
|
|
43
|
-
var __version__ = "1.1.
|
|
43
|
+
var __version__ = "1.1.4";
|
|
44
44
|
|
|
45
45
|
// src/opencode-trace-shipper.ts
|
|
46
46
|
var PACKAGE_NAME = "neatlogs.opencode";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/opencode-plugin.ts","../src/opencode-trace-shipper.ts","../src/version.ts"],"sourcesContent":["/**\n * Neatlogs opencode plugin.\n *\n * opencode loads plugins from its config (`opencode.json` → `\"plugin\": [...]`)\n * or from local `.opencode/plugin/*.ts` files. A plugin is an async factory that\n * receives an app context and returns lifecycle hooks. This plugin instruments\n * opencode automatically — no per-call wiring — turning an opencode session into\n * a neatlogs span tree:\n *\n * AGENT opencode.session (one per user turn; parents that turn's spans)\n * ↳ LLM assistant turn (per completed assistant message)\n * ↳ TOOL tool execution (tool.execute.before → tool.execute.after)\n *\n * Every span carries `neatlogs.conversation.id` = the opencode session ID.\n *\n * Export model (mirrors @raindrop-ai/opencode-plugin and neatlogs-claude-code):\n * opencode loads the plugin in-process but `opencode run` is short-lived. Rather\n * than the OpenTelemetry BatchSpanProcessor (whose async, scheduled-delay export\n * + `beforeExit` shutdown races the teardown and drops spans), this plugin builds\n * spans directly and ships them via AWAITED `fetch(POST /v1/traces)` — and it\n * flushes after every completed assistant turn (incremental persistence) plus a\n * final flush on `session.idle`. A `neatlogs.trace.complete` marker is sent so\n * the backend enqueues the trace for finalization (simplification → UI).\n *\n * Setup — either:\n * • npm package, in opencode.json: `{ \"plugin\": [\"neatlogs/opencode\"] }`, OR\n * • local file `.opencode/plugin/neatlogs.ts`:\n * export { NeatlogsOpencodePlugin as default } from 'neatlogs/opencode';\n *\n * Env:\n * NEATLOGS_API_KEY required to export\n * NEATLOGS_ENDPOINT backend base URL (default https://ingest.neatlogs.com)\n * NEATLOGS_WORKFLOW_NAME logical grouping (default: \"opencode\")\n * NEATLOGS_CAPTURE_SYSTEM_PROMPT=true capture system prompt text (default off)\n */\n\nimport {\n TraceShipper,\n type OtlpSpan,\n type OtlpKeyValue,\n SpanStatusCode,\n generateTraceId,\n generateSpanId,\n nowNanoString,\n msToNanoString,\n attrStr,\n attrInt,\n attrDouble,\n} from './opencode-trace-shipper.js';\n\nconst DEFAULT_ENDPOINT = 'https://ingest.neatlogs.com';\n\n/** A span being built incrementally — ended (and shipped) later. */\ninterface OpenSpan {\n spanId: Uint8Array;\n parentSpanId?: Uint8Array;\n name: string;\n startNano: string;\n attributes: OtlpKeyValue[];\n}\n\ninterface SessionState {\n /** Per-session trace id — all spans in a session share it. */\n traceId: Uint8Array;\n /** The current turn's AGENT root span (created on chat.message, ended on idle). */\n rootSpan?: OpenSpan;\n /** Open TOOL spans keyed by callID → start time. */\n toolStarts: Map<string, { spanId: Uint8Array; startNano: string; tool: string; args: any }>;\n /** Accumulated assistant text per messageID (from text parts). */\n outputParts: Map<string, string>;\n /** Tool calls per assistant messageID (so a tool-only turn still has output). */\n toolCalls: Map<string, Array<{ name: string; input: any; callID: string }>>;\n /** assistant messageIDs already emitted (completion can fire repeatedly). */\n processed: Set<string>;\n /** Current user prompt (this turn's input). */\n currentInput: string;\n /** Captured system prompt (if enabled). */\n systemPrompt?: string;\n /** Latest assistant text — the AGENT root's output on close. */\n lastAssistantText: string;\n}\n\nexport const NeatlogsOpencodePlugin = async (_ctx: any): Promise<Record<string, any>> => {\n const apiKey = (process.env.NEATLOGS_API_KEY ?? '').trim();\n const endpoint = (process.env.NEATLOGS_ENDPOINT ?? DEFAULT_ENDPOINT).trim();\n const workflowName = process.env.NEATLOGS_WORKFLOW_NAME || 'opencode';\n const captureSystemPrompt =\n String(process.env.NEATLOGS_CAPTURE_SYSTEM_PROMPT || '').toLowerCase() === 'true';\n const debug = String(process.env.NEATLOGS_DEBUG || '').toLowerCase() === 'true';\n\n const shipper = new TraceShipper({ apiKey, endpoint, workflowName, debug });\n const sessions = new Map<string, SessionState>();\n\n function stateFor(sessionID: string): SessionState {\n let s = sessions.get(sessionID);\n if (!s) {\n s = {\n traceId: generateTraceId(),\n toolStarts: new Map(),\n outputParts: new Map(),\n toolCalls: new Map(),\n processed: new Set(),\n currentInput: '',\n lastAssistantText: '',\n };\n sessions.set(sessionID, s);\n }\n return s;\n }\n\n /** Start the per-turn AGENT root span (idempotent within a turn). */\n function startRoot(st: SessionState, sessionID: string): void {\n if (st.rootSpan) return;\n st.rootSpan = {\n spanId: generateSpanId(),\n name: 'opencode.session',\n startNano: nowNanoString(),\n attributes: [\n { key: 'neatlogs.span.kind', value: { stringValue: 'AGENT' } },\n { key: 'neatlogs.agent.framework', value: { stringValue: 'opencode' } },\n { key: 'neatlogs.conversation.id', value: { stringValue: sessionID } },\n ],\n };\n }\n\n /** End + enqueue the AGENT root, send the completion marker, and flush. */\n async function closeAndFlush(st: SessionState, sessionID: string): Promise<void> {\n if (st.rootSpan) {\n const attrs = st.rootSpan.attributes.slice();\n setIO(attrs, 'AGENT', st.currentInput || undefined, st.lastAssistantText || undefined);\n shipper.enqueue({\n traceId: st.traceId,\n spanId: st.rootSpan.spanId,\n name: st.rootSpan.name,\n kind: 1,\n startTimeUnixNano: st.rootSpan.startNano,\n endTimeUnixNano: nowNanoString(),\n attributes: attrs,\n status: { code: SpanStatusCode.OK },\n });\n // Completion marker — the backend only finalizes (simplifies → UI) a trace\n // once it sees a `neatlogs.trace.complete` span. Parented to the root.\n const m = nowNanoString();\n shipper.enqueue({\n traceId: st.traceId,\n spanId: generateSpanId(),\n parentSpanId: st.rootSpan.spanId,\n name: 'neatlogs.trace.complete',\n kind: 1,\n startTimeUnixNano: m,\n endTimeUnixNano: m,\n attributes: [\n { key: 'neatlogs.trace.complete', value: { boolValue: true } },\n { key: 'neatlogs.internal', value: { boolValue: true } },\n { key: 'neatlogs.span.kind', value: { stringValue: 'Neatlogs.INTERNAL' } },\n ],\n });\n st.rootSpan = undefined;\n }\n await shipper.flush();\n void sessionID;\n }\n\n return {\n /** Fired when the user submits a prompt — open the turn's AGENT root. */\n 'chat.message': async (_input: any, output: any) => {\n try {\n const sessionID = String(_input?.sessionID ?? output?.sessionID ?? '');\n if (!sessionID) return;\n const st = stateFor(sessionID);\n const parts = output?.parts ?? [];\n const text = Array.isArray(parts)\n ? parts\n .filter((p: any) => p?.type === 'text' && typeof p.text === 'string')\n .map((p: any) => p.text)\n .join('\\n')\n : '';\n if (text) st.currentInput = text;\n startRoot(st, sessionID);\n } catch {\n /* ignore */\n }\n },\n\n /** Capture the system prompt (opt-in). */\n 'experimental.chat.system.transform': async (_input: any, output: any) => {\n try {\n if (!captureSystemPrompt) return;\n const sessionID = String(_input?.sessionID ?? '');\n const parts = output?.system ?? output?.parts ?? output;\n const joined = Array.isArray(parts) ? parts.map((p: any) => (typeof p === 'string' ? p : p?.text ?? '')).join('\\n') : String(parts ?? '');\n if (sessionID && joined) stateFor(sessionID).systemPrompt = joined;\n } catch {\n /* ignore */\n }\n },\n\n /** Global event bus — message parts, assistant completions, session idle. */\n event: async ({ event }: { event: any }) => {\n try {\n await handleEvent(shipper, sessions, stateFor, startRoot, closeAndFlush, event);\n } catch {\n // never break opencode over tracing\n }\n },\n\n /** Tool start — record start time + args (span built atomically in `after`). */\n 'tool.execute.before': async (input: any, output: any) => {\n try {\n const sessionID = String(input?.sessionID ?? '');\n if (!sessionID) return;\n const st = stateFor(sessionID);\n startRoot(st, sessionID);\n const callID = String(input?.callID ?? input?.tool ?? '');\n st.toolStarts.set(callID, {\n spanId: generateSpanId(),\n startNano: nowNanoString(),\n tool: String(input?.tool ?? 'tool'),\n args: output?.args,\n });\n } catch {\n /* ignore */\n }\n },\n\n /** Tool end — enqueue the completed TOOL span (parented to the turn root). */\n 'tool.execute.after': async (input: any, result: any) => {\n try {\n const sessionID = String(input?.sessionID ?? '');\n if (!sessionID) return;\n const st = stateFor(sessionID);\n const callID = String(input?.callID ?? input?.tool ?? '');\n const start = st.toolStarts.get(callID);\n if (!start) return;\n st.toolStarts.delete(callID);\n\n const attrs: OtlpKeyValue[] = [\n { key: 'neatlogs.span.kind', value: { stringValue: 'TOOL' } },\n { key: 'neatlogs.tool.name', value: { stringValue: start.tool } },\n { key: 'neatlogs.conversation.id', value: { stringValue: sessionID } },\n ];\n if (start.args !== undefined) {\n // The shipper bypasses the SDK attribute-processor, so emit the\n // already-namespaced keys the backend consumer reads directly\n // (neatlogs.tool.input / .output and the generic neatlogs.input.value),\n // not the raw input.value/output.value the processor would map.\n setIO(attrs, 'TOOL', safeStringify(start.args), undefined);\n push(attrs, attrStr('neatlogs.tool.input', safeStringify(start.args)));\n }\n if (result?.title) push(attrs, attrStr('neatlogs.tool.title', String(result.title)));\n const out = result?.output ?? result?.result;\n if (out !== undefined) {\n const o = typeof out === 'string' ? out : safeStringify(out);\n setIO(attrs, 'TOOL', undefined, o);\n push(attrs, attrStr('neatlogs.tool.output', o));\n }\n if (result?.metadata !== undefined) {\n push(attrs, attrStr('neatlogs.tool.metadata', safeStringify(result.metadata)));\n }\n\n shipper.enqueue({\n traceId: st.traceId,\n spanId: start.spanId,\n parentSpanId: st.rootSpan?.spanId,\n name: `opencode.tool.${start.tool}`,\n kind: 1,\n startTimeUnixNano: start.startNano,\n endTimeUnixNano: nowNanoString(),\n attributes: attrs,\n status: { code: SpanStatusCode.OK },\n });\n } catch {\n /* ignore */\n }\n },\n };\n};\n\n// Convenience aliases so users can import under any common name.\nexport const neatlogsOpencodePlugin = NeatlogsOpencodePlugin;\nexport default NeatlogsOpencodePlugin;\n\n// ---------------------------------------------------------------------------\n// Event handling\n// ---------------------------------------------------------------------------\n\nfunction handleEvent(\n shipper: TraceShipper,\n sessions: Map<string, SessionState>,\n stateFor: (sessionID: string) => SessionState,\n startRoot: (st: SessionState, sessionID: string) => void,\n closeAndFlush: (st: SessionState, sessionID: string) => Promise<void>,\n event: any,\n): Promise<unknown> | undefined {\n const type = event?.type;\n const props = event?.properties ?? {};\n\n // Accumulate text + tool-call parts on an assistant message.\n if (type === 'message.part.updated' || type === 'message.part.completed') {\n const part = props.part ?? props;\n const messageID = part?.messageID ?? part?.message_id;\n const sessionID = part?.sessionID ?? props.sessionID;\n if (!messageID || !sessionID) return undefined;\n const st = stateFor(String(sessionID));\n if (part?.type === 'text' && typeof part?.text === 'string') {\n st.outputParts.set(String(messageID), part.text);\n } else if (part?.type === 'tool' && part?.tool) {\n const list = st.toolCalls.get(String(messageID)) ?? [];\n const callID = String(part.callID ?? part.tool);\n const input = part?.state?.input ?? {};\n const existing = list.find((t) => t.callID === callID);\n if (existing) existing.input = input;\n else list.push({ name: String(part.tool), input, callID });\n st.toolCalls.set(String(messageID), list);\n }\n return undefined;\n }\n\n // Assistant message completed → emit the LLM span, then flush this turn.\n if (type === 'message.updated' || type === 'message.completed') {\n const info = props.info ?? props.message ?? props;\n const sessionID = info?.sessionID ?? info?.session_id;\n if (!sessionID) return undefined;\n if (info?.role !== 'assistant') return undefined;\n const completed = info?.time?.completed ?? info?.completed;\n const id = String(info?.id ?? '');\n if (!completed || !id) return undefined;\n const st = stateFor(String(sessionID));\n if (st.processed.has(id)) return undefined;\n st.processed.add(id);\n startRoot(st, String(sessionID));\n emitLlmSpan(shipper, st, info, String(sessionID));\n // Incremental persistence: ship this turn's spans now (don't wait for idle).\n return shipper.flush().catch(() => undefined);\n }\n\n // Session finished → end root, send completion marker, final flush.\n if (type === 'session.idle' || type === 'session.deleted') {\n const sessionID = props.sessionID ?? props.info?.id;\n if (!sessionID) return undefined;\n const st = sessions.get(String(sessionID));\n if (!st) return undefined;\n st.toolStarts.clear();\n const p = closeAndFlush(st, String(sessionID));\n if (type === 'session.deleted') sessions.delete(String(sessionID));\n return p;\n }\n\n return undefined;\n}\n\nfunction emitLlmSpan(shipper: TraceShipper, st: SessionState, info: any, sessionID: string): void {\n const model = info?.modelID ?? info?.model ?? '';\n const provider = info?.providerID ?? info?.provider ?? '';\n\n const attrs: OtlpKeyValue[] = [\n { key: 'neatlogs.span.kind', value: { stringValue: 'LLM' } },\n { key: 'neatlogs.conversation.id', value: { stringValue: sessionID } },\n ];\n push(attrs, attrStr('neatlogs.llm.model_name', model ? String(model) : undefined));\n push(attrs, attrStr('neatlogs.llm.provider', provider ? String(provider) : undefined));\n\n let inIdx = 0;\n if (st.systemPrompt) {\n push(attrs, attrStr(`neatlogs.llm.input_messages.${inIdx}.role`, 'system'));\n push(attrs, attrStr(`neatlogs.llm.input_messages.${inIdx}.content`, st.systemPrompt));\n inIdx++;\n }\n if (st.currentInput) {\n push(attrs, attrStr(`neatlogs.llm.input_messages.${inIdx}.role`, 'user'));\n push(attrs, attrStr(`neatlogs.llm.input_messages.${inIdx}.content`, st.currentInput));\n setIO(attrs, 'LLM', st.currentInput, undefined);\n }\n\n const outText = st.outputParts.get(String(info?.id)) || messageText(info) || '';\n const toolCalls = st.toolCalls.get(String(info?.id)) ?? [];\n\n if (outText) {\n push(attrs, attrStr('neatlogs.llm.output_messages.0.role', 'assistant'));\n push(attrs, attrStr('neatlogs.llm.output_messages.0.content', outText));\n setIO(attrs, 'LLM', undefined, outText);\n st.lastAssistantText = outText;\n }\n // Tool-deciding turns often carry no text — render the tool call(s) as output.\n if (toolCalls.length) {\n toolCalls.forEach((tc, j) => {\n push(attrs, attrStr(`neatlogs.llm.tool_calls.${j}.name`, tc.name));\n push(attrs, attrStr(`neatlogs.llm.tool_calls.${j}.arguments`, safeStringify(tc.input ?? {})));\n });\n if (!outText) {\n const rendered = toolCalls.map((tc) => `→ ${tc.name}(${safeStringify(tc.input ?? {})})`).join('\\n');\n push(attrs, attrStr('neatlogs.llm.output_messages.0.role', 'assistant'));\n push(attrs, attrStr('neatlogs.llm.output_messages.0.content', rendered));\n setIO(attrs, 'LLM', undefined, rendered);\n }\n }\n\n // Tokens: opencode message tokens { input, output, reasoning, cache:{read,write} }\n const tokens = info?.tokens;\n if (tokens) {\n push(attrs, attrInt('neatlogs.llm.token_count.prompt', tokens.input));\n push(attrs, attrInt('neatlogs.llm.token_count.completion', tokens.output));\n if (tokens.input != null && tokens.output != null) {\n push(attrs, attrInt('neatlogs.llm.token_count.total', tokens.input + tokens.output));\n }\n push(attrs, attrInt('neatlogs.llm.token_count.reasoning', tokens.reasoning));\n push(attrs, attrInt('neatlogs.llm.token_count.cache_read', tokens.cache?.read));\n push(attrs, attrInt('neatlogs.llm.token_count.cache_write', tokens.cache?.write));\n }\n push(attrs, attrDouble('neatlogs.llm.cost_usd', info?.cost));\n\n // Use opencode's real start time when available (else now).\n const createdMs = info?.time?.created;\n const startNano = typeof createdMs === 'number' ? msToNanoString(Math.floor(createdMs)) : nowNanoString();\n\n shipper.enqueue({\n traceId: st.traceId,\n spanId: generateSpanId(),\n parentSpanId: st.rootSpan?.spanId,\n name: `opencode.llm.${model || 'model'}`,\n kind: 1,\n startTimeUnixNano: startNano,\n endTimeUnixNano: nowNanoString(),\n attributes: attrs,\n status: { code: SpanStatusCode.OK },\n });\n\n // Reset accumulated parts for the next turn.\n if (info?.id) {\n st.outputParts.delete(String(info.id));\n st.toolCalls.delete(String(info.id));\n }\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction push(arr: OtlpKeyValue[], kv: OtlpKeyValue | undefined): void {\n if (kv) arr.push(kv);\n}\n\n/**\n * Set generic input/output on a span using the ALREADY-NAMESPACED keys the\n * backend consumer reads. The OTel-SDK wrappers rely on the attribute-processor\n * to map raw `input.value` → `neatlogs.{kind}.input`; this plugin ships spans\n * directly (no processor), so it must emit the namespaced keys itself:\n * neatlogs.input.value / neatlogs.output.value (generic)\n * neatlogs.{kind}.input / neatlogs.{kind}.output (kind-specific)\n * We also keep the raw input.value/output.value for any consumer that maps it.\n */\nfunction setIO(arr: OtlpKeyValue[], kind: string, input?: string, output?: string): void {\n const k = kind.toLowerCase();\n if (input !== undefined) {\n push(arr, attrStr('input.value', input));\n push(arr, attrStr('neatlogs.input.value', input));\n push(arr, attrStr(`neatlogs.${k}.input`, input));\n }\n if (output !== undefined) {\n push(arr, attrStr('output.value', output));\n push(arr, attrStr('neatlogs.output.value', output));\n push(arr, attrStr(`neatlogs.${k}.output`, output));\n }\n}\n\n/** Flatten an opencode message's parts/content to readable text. */\nfunction messageText(info: any): string {\n if (!info) return '';\n if (typeof info.text === 'string') return info.text;\n const parts = info.parts ?? info.content;\n if (typeof parts === 'string') return parts;\n if (!Array.isArray(parts)) return '';\n const out: string[] = [];\n for (const p of parts) {\n if (typeof p === 'string') out.push(p);\n else if (p && typeof p === 'object' && typeof p.text === 'string') out.push(p.text);\n }\n return out.join('');\n}\n\nfunction safeStringify(value: unknown): string {\n if (typeof value === 'string') return value;\n try {\n return JSON.stringify(value) ?? '';\n } catch {\n return String(value);\n }\n}\n","/**\n * Direct OTLP trace shipper for the opencode plugin.\n *\n * opencode loads the plugin in-process but `opencode run` is short-lived — it\n * tears down the moment a session goes idle. The OpenTelemetry BatchSpanProcessor\n * (async, scheduled-delay export + a `beforeExit` shutdown) races that teardown,\n * dropping spans or leaving aborted half-sent requests. This shipper mirrors the\n * proven `neatlogs-claude-code` design instead: spans are queued, then `flush()`\n * does a single AWAITED `fetch(POST /v1/traces)` round-trip that completes before\n * the host process can exit. No batch processor, no exit-time race.\n *\n * Self-contained (inlined OTLP protobuf schema) so it adds no runtime file I/O.\n */\n\nimport protobuf from 'protobufjs';\nimport { __version__ } from './version.js';\n\nconst PACKAGE_NAME = 'neatlogs.opencode';\n\nexport interface OtlpKeyValue {\n key: string;\n value: {\n stringValue?: string;\n intValue?: string;\n doubleValue?: number;\n boolValue?: boolean;\n };\n}\n\nexport interface OtlpSpan {\n traceId: Uint8Array;\n spanId: Uint8Array;\n parentSpanId?: Uint8Array;\n name: string;\n /** OTLP SpanKind enum (0=unspecified, 1=internal, …). Neatlogs kind rides in attributes. */\n kind: number;\n startTimeUnixNano: string;\n endTimeUnixNano: string;\n attributes: OtlpKeyValue[];\n status?: { code: number; message?: string };\n}\n\n// Inlined OTLP proto definition — avoids .proto file I/O at runtime.\nconst OTLP_PROTO_JSON: protobuf.INamespace = {\n nested: {\n opentelemetry: {\n nested: {\n proto: {\n nested: {\n common: {\n nested: {\n v1: {\n nested: {\n AnyValue: {\n oneofs: {\n value: {\n oneof: [\n 'stringValue',\n 'boolValue',\n 'intValue',\n 'doubleValue',\n 'arrayValue',\n 'kvlistValue',\n 'bytesValue',\n ],\n },\n },\n fields: {\n stringValue: { type: 'string', id: 1 },\n boolValue: { type: 'bool', id: 2 },\n intValue: { type: 'int64', id: 3 },\n doubleValue: { type: 'double', id: 4 },\n arrayValue: { type: 'ArrayValue', id: 5 },\n kvlistValue: { type: 'KeyValueList', id: 6 },\n bytesValue: { type: 'bytes', id: 7 },\n },\n },\n ArrayValue: { fields: { values: { rule: 'repeated', type: 'AnyValue', id: 1 } } },\n KeyValueList: { fields: { values: { rule: 'repeated', type: 'KeyValue', id: 1 } } },\n KeyValue: {\n fields: { key: { type: 'string', id: 1 }, value: { type: 'AnyValue', id: 2 } },\n },\n InstrumentationScope: {\n fields: { name: { type: 'string', id: 1 }, version: { type: 'string', id: 2 } },\n },\n },\n },\n },\n },\n resource: {\n nested: {\n v1: {\n nested: {\n Resource: {\n fields: {\n attributes: {\n rule: 'repeated',\n type: 'opentelemetry.proto.common.v1.KeyValue',\n id: 1,\n },\n },\n },\n },\n },\n },\n },\n trace: {\n nested: {\n v1: {\n nested: {\n ResourceSpans: {\n fields: {\n resource: { type: 'opentelemetry.proto.resource.v1.Resource', id: 1 },\n scopeSpans: { rule: 'repeated', type: 'ScopeSpans', id: 2 },\n },\n },\n ScopeSpans: {\n fields: {\n scope: { type: 'opentelemetry.proto.common.v1.InstrumentationScope', id: 1 },\n spans: { rule: 'repeated', type: 'Span', id: 2 },\n },\n },\n Span: {\n fields: {\n traceId: { type: 'bytes', id: 1 },\n spanId: { type: 'bytes', id: 2 },\n traceState: { type: 'string', id: 3 },\n parentSpanId: { type: 'bytes', id: 4 },\n name: { type: 'string', id: 5 },\n kind: { type: 'SpanKind', id: 6 },\n startTimeUnixNano: { type: 'fixed64', id: 7 },\n endTimeUnixNano: { type: 'fixed64', id: 8 },\n attributes: {\n rule: 'repeated',\n type: 'opentelemetry.proto.common.v1.KeyValue',\n id: 9,\n },\n droppedAttributesCount: { type: 'uint32', id: 10 },\n status: { type: 'Status', id: 15 },\n },\n },\n Status: {\n fields: { message: { type: 'string', id: 2 }, code: { type: 'StatusCode', id: 3 } },\n },\n StatusCode: {\n values: { STATUS_CODE_UNSET: 0, STATUS_CODE_OK: 1, STATUS_CODE_ERROR: 2 },\n },\n SpanKind: {\n values: {\n SPAN_KIND_UNSPECIFIED: 0,\n SPAN_KIND_INTERNAL: 1,\n SPAN_KIND_SERVER: 2,\n SPAN_KIND_CLIENT: 3,\n SPAN_KIND_PRODUCER: 4,\n SPAN_KIND_CONSUMER: 5,\n },\n },\n },\n },\n },\n },\n collector: {\n nested: {\n trace: {\n nested: {\n v1: {\n nested: {\n ExportTraceServiceRequest: {\n fields: {\n resourceSpans: {\n rule: 'repeated',\n type: 'opentelemetry.proto.trace.v1.ResourceSpans',\n id: 1,\n },\n },\n },\n },\n },\n },\n },\n },\n },\n },\n },\n },\n },\n },\n};\n\nconst protoRoot = protobuf.Root.fromJSON(OTLP_PROTO_JSON);\nconst ExportTraceServiceRequest = protoRoot.lookupType(\n 'opentelemetry.proto.collector.trace.v1.ExportTraceServiceRequest',\n);\n\nexport const SpanStatusCode = { UNSET: 0, OK: 1, ERROR: 2 } as const;\n\n// ---------------------------------------------------------------------------\n// ID + time + attribute helpers\n// ---------------------------------------------------------------------------\n\nfunction randomBytes(length: number): Uint8Array {\n const out = new Uint8Array(length);\n const crypto = globalThis.crypto;\n if (crypto && typeof crypto.getRandomValues === 'function') {\n crypto.getRandomValues(out);\n return out;\n }\n for (let i = 0; i < out.length; i++) out[i] = Math.floor(Math.random() * 256);\n return out;\n}\n\nexport function generateTraceId(): Uint8Array {\n return randomBytes(16);\n}\n\nexport function generateSpanId(): Uint8Array {\n return randomBytes(8);\n}\n\nexport function bytesToHex(bytes: Uint8Array): string {\n return Array.from(bytes)\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('');\n}\n\nexport function nowNanoString(): string {\n return (BigInt(Date.now()) * 1_000_000n).toString();\n}\n\nexport function msToNanoString(ms: number): string {\n return (BigInt(Math.floor(ms)) * 1_000_000n).toString();\n}\n\nexport function attrStr(key: string, value: string | undefined): OtlpKeyValue | undefined {\n if (value === undefined || value === null) return undefined;\n return { key, value: { stringValue: String(value) } };\n}\n\nexport function attrInt(key: string, value: number | undefined): OtlpKeyValue | undefined {\n if (value === undefined || value === null || !Number.isFinite(value)) return undefined;\n return { key, value: { intValue: String(Math.trunc(value)) } };\n}\n\nexport function attrDouble(key: string, value: number | undefined): OtlpKeyValue | undefined {\n if (value === undefined || value === null || !Number.isFinite(value)) return undefined;\n return { key, value: { doubleValue: value } };\n}\n\nexport interface TraceShipperOptions {\n apiKey: string;\n endpoint: string;\n debug?: boolean;\n maxRetries?: number;\n workflowName?: string;\n}\n\nexport class TraceShipper {\n private apiKey: string;\n private endpoint: string;\n private debug: boolean;\n private maxRetries: number;\n workflowName: string;\n private queue: OtlpSpan[] = [];\n private prefix = '[neatlogs/opencode]';\n\n constructor(opts: TraceShipperOptions) {\n this.apiKey = opts.apiKey;\n this.endpoint = opts.endpoint.endsWith('/') ? opts.endpoint.slice(0, -1) : opts.endpoint;\n this.debug = !!opts.debug;\n this.maxRetries = opts.maxRetries ?? 3;\n this.workflowName = opts.workflowName || '';\n }\n\n enqueue(span: OtlpSpan): void {\n this.queue.push(span);\n }\n\n get pending(): number {\n return this.queue.length;\n }\n\n /**\n * Ship all queued spans in a single awaited POST. Resolves only once the HTTP\n * response is received (or all retries are exhausted) — so a short-lived host\n * can safely exit immediately after awaiting this.\n */\n async flush(): Promise<void> {\n if (this.queue.length === 0) return;\n if (!this.apiKey) {\n this.queue = [];\n return;\n }\n\n const spans = this.queue.splice(0);\n const payload = this.buildProtobuf(spans);\n const url = `${this.endpoint}/v1/traces`;\n\n if (this.debug) console.log(`${this.prefix} Shipping ${spans.length} spans to ${url}`);\n\n for (let attempt = 1; attempt <= this.maxRetries; attempt++) {\n try {\n const resp = await fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-protobuf',\n 'x-api-key': this.apiKey,\n },\n body: payload as any,\n });\n\n if (resp.ok) {\n if (this.debug) console.log(`${this.prefix} Shipped ${spans.length} spans`);\n return;\n }\n if (resp.status === 401) {\n console.warn(`${this.prefix} Invalid API key (401) — dropping ${spans.length} spans`);\n return;\n }\n if (resp.status < 500 && resp.status !== 429) {\n if (this.debug) console.warn(`${this.prefix} HTTP ${resp.status} — dropping spans`);\n return;\n }\n // 429 / 5xx → retry\n } catch (err) {\n if (this.debug) {\n console.warn(\n `${this.prefix} Attempt ${attempt}/${this.maxRetries}: ${(err as Error).message}`,\n );\n }\n }\n if (attempt < this.maxRetries) {\n await new Promise((r) => setTimeout(r, 500 * 2 ** (attempt - 1)));\n }\n }\n console.warn(`${this.prefix} Failed to ship ${spans.length} spans after ${this.maxRetries} attempts`);\n }\n\n private buildProtobuf(spans: OtlpSpan[]): Uint8Array {\n const protoSpans = spans.map((span) => ({\n traceId: span.traceId,\n spanId: span.spanId,\n parentSpanId: span.parentSpanId || undefined,\n name: span.name,\n kind: span.kind,\n startTimeUnixNano: nanoToLong(span.startTimeUnixNano),\n endTimeUnixNano: nanoToLong(span.endTimeUnixNano),\n attributes: span.attributes.map((a) => ({\n key: a.key,\n value:\n a.value.intValue !== undefined\n ? { intValue: nanoToLong(a.value.intValue) }\n : a.value,\n })),\n status: span.status ? { code: span.status.code, message: span.status.message } : undefined,\n }));\n\n const resourceAttributes: Array<{ key: string; value: { stringValue: string } }> = [\n { key: 'service.name', value: { stringValue: 'neatlogs.opencode' } },\n { key: 'service.version', value: { stringValue: __version__ } },\n ];\n if (this.workflowName) {\n resourceAttributes.push({\n key: 'neatlogs.workflow_name',\n value: { stringValue: this.workflowName },\n });\n }\n\n const message = {\n resourceSpans: [\n {\n resource: { attributes: resourceAttributes },\n scopeSpans: [\n {\n scope: { name: PACKAGE_NAME, version: __version__ },\n spans: protoSpans,\n },\n ],\n },\n ],\n };\n\n const errMsg = ExportTraceServiceRequest.verify(message);\n if (errMsg && this.debug) console.warn(`${this.prefix} Proto verify: ${errMsg}`);\n\n return ExportTraceServiceRequest.encode(ExportTraceServiceRequest.fromObject(message)).finish();\n }\n}\n\n/** protobufjs encodes fixed64/int64 from a {low,high,unsigned} Long-like. */\nfunction nanoToLong(nanoStr: string): { low: number; high: number; unsigned: boolean } {\n const big = BigInt(nanoStr);\n const low = Number(big & 0xffffffffn);\n const high = Number((big >> 32n) & 0xffffffffn);\n return { low, high, unsigned: true };\n}\n","/**\n * SDK version. Kept in sync with package.json by the `version:sync` script\n * (runs automatically on `prebuild`). Do not edit by hand — bump package.json.\n */\nexport const __version__ = '1.1.2';\n"],"mappings":"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","names":["protobuf"]}
|
|
1
|
+
{"version":3,"sources":["../src/opencode-plugin.ts","../src/opencode-trace-shipper.ts","../src/version.ts"],"sourcesContent":["/**\n * Neatlogs opencode plugin.\n *\n * opencode loads plugins from its config (`opencode.json` → `\"plugin\": [...]`)\n * or from local `.opencode/plugin/*.ts` files. A plugin is an async factory that\n * receives an app context and returns lifecycle hooks. This plugin instruments\n * opencode automatically — no per-call wiring — turning an opencode session into\n * a neatlogs span tree:\n *\n * AGENT opencode.session (one per user turn; parents that turn's spans)\n * ↳ LLM assistant turn (per completed assistant message)\n * ↳ TOOL tool execution (tool.execute.before → tool.execute.after)\n *\n * Every span carries `neatlogs.conversation.id` = the opencode session ID.\n *\n * Export model (mirrors @raindrop-ai/opencode-plugin and neatlogs-claude-code):\n * opencode loads the plugin in-process but `opencode run` is short-lived. Rather\n * than the OpenTelemetry BatchSpanProcessor (whose async, scheduled-delay export\n * + `beforeExit` shutdown races the teardown and drops spans), this plugin builds\n * spans directly and ships them via AWAITED `fetch(POST /v1/traces)` — and it\n * flushes after every completed assistant turn (incremental persistence) plus a\n * final flush on `session.idle`. A `neatlogs.trace.complete` marker is sent so\n * the backend enqueues the trace for finalization (simplification → UI).\n *\n * Setup — either:\n * • npm package, in opencode.json: `{ \"plugin\": [\"neatlogs/opencode\"] }`, OR\n * • local file `.opencode/plugin/neatlogs.ts`:\n * export { NeatlogsOpencodePlugin as default } from 'neatlogs/opencode';\n *\n * Env:\n * NEATLOGS_API_KEY required to export\n * NEATLOGS_ENDPOINT backend base URL (default https://ingest.neatlogs.com)\n * NEATLOGS_WORKFLOW_NAME logical grouping (default: \"opencode\")\n * NEATLOGS_CAPTURE_SYSTEM_PROMPT=true capture system prompt text (default off)\n */\n\nimport {\n TraceShipper,\n type OtlpSpan,\n type OtlpKeyValue,\n SpanStatusCode,\n generateTraceId,\n generateSpanId,\n nowNanoString,\n msToNanoString,\n attrStr,\n attrInt,\n attrDouble,\n} from './opencode-trace-shipper.js';\n\nconst DEFAULT_ENDPOINT = 'https://ingest.neatlogs.com';\n\n/** A span being built incrementally — ended (and shipped) later. */\ninterface OpenSpan {\n spanId: Uint8Array;\n parentSpanId?: Uint8Array;\n name: string;\n startNano: string;\n attributes: OtlpKeyValue[];\n}\n\ninterface SessionState {\n /** Per-session trace id — all spans in a session share it. */\n traceId: Uint8Array;\n /** The current turn's AGENT root span (created on chat.message, ended on idle). */\n rootSpan?: OpenSpan;\n /** Open TOOL spans keyed by callID → start time. */\n toolStarts: Map<string, { spanId: Uint8Array; startNano: string; tool: string; args: any }>;\n /** Accumulated assistant text per messageID (from text parts). */\n outputParts: Map<string, string>;\n /** Tool calls per assistant messageID (so a tool-only turn still has output). */\n toolCalls: Map<string, Array<{ name: string; input: any; callID: string }>>;\n /** assistant messageIDs already emitted (completion can fire repeatedly). */\n processed: Set<string>;\n /** Current user prompt (this turn's input). */\n currentInput: string;\n /** Captured system prompt (if enabled). */\n systemPrompt?: string;\n /** Latest assistant text — the AGENT root's output on close. */\n lastAssistantText: string;\n}\n\nexport const NeatlogsOpencodePlugin = async (_ctx: any): Promise<Record<string, any>> => {\n const apiKey = (process.env.NEATLOGS_API_KEY ?? '').trim();\n const endpoint = (process.env.NEATLOGS_ENDPOINT ?? DEFAULT_ENDPOINT).trim();\n const workflowName = process.env.NEATLOGS_WORKFLOW_NAME || 'opencode';\n const captureSystemPrompt =\n String(process.env.NEATLOGS_CAPTURE_SYSTEM_PROMPT || '').toLowerCase() === 'true';\n const debug = String(process.env.NEATLOGS_DEBUG || '').toLowerCase() === 'true';\n\n const shipper = new TraceShipper({ apiKey, endpoint, workflowName, debug });\n const sessions = new Map<string, SessionState>();\n\n function stateFor(sessionID: string): SessionState {\n let s = sessions.get(sessionID);\n if (!s) {\n s = {\n traceId: generateTraceId(),\n toolStarts: new Map(),\n outputParts: new Map(),\n toolCalls: new Map(),\n processed: new Set(),\n currentInput: '',\n lastAssistantText: '',\n };\n sessions.set(sessionID, s);\n }\n return s;\n }\n\n /** Start the per-turn AGENT root span (idempotent within a turn). */\n function startRoot(st: SessionState, sessionID: string): void {\n if (st.rootSpan) return;\n st.rootSpan = {\n spanId: generateSpanId(),\n name: 'opencode.session',\n startNano: nowNanoString(),\n attributes: [\n { key: 'neatlogs.span.kind', value: { stringValue: 'AGENT' } },\n { key: 'neatlogs.agent.framework', value: { stringValue: 'opencode' } },\n { key: 'neatlogs.conversation.id', value: { stringValue: sessionID } },\n ],\n };\n }\n\n /** End + enqueue the AGENT root, send the completion marker, and flush. */\n async function closeAndFlush(st: SessionState, sessionID: string): Promise<void> {\n if (st.rootSpan) {\n const attrs = st.rootSpan.attributes.slice();\n setIO(attrs, 'AGENT', st.currentInput || undefined, st.lastAssistantText || undefined);\n shipper.enqueue({\n traceId: st.traceId,\n spanId: st.rootSpan.spanId,\n name: st.rootSpan.name,\n kind: 1,\n startTimeUnixNano: st.rootSpan.startNano,\n endTimeUnixNano: nowNanoString(),\n attributes: attrs,\n status: { code: SpanStatusCode.OK },\n });\n // Completion marker — the backend only finalizes (simplifies → UI) a trace\n // once it sees a `neatlogs.trace.complete` span. Parented to the root.\n const m = nowNanoString();\n shipper.enqueue({\n traceId: st.traceId,\n spanId: generateSpanId(),\n parentSpanId: st.rootSpan.spanId,\n name: 'neatlogs.trace.complete',\n kind: 1,\n startTimeUnixNano: m,\n endTimeUnixNano: m,\n attributes: [\n { key: 'neatlogs.trace.complete', value: { boolValue: true } },\n { key: 'neatlogs.internal', value: { boolValue: true } },\n { key: 'neatlogs.span.kind', value: { stringValue: 'Neatlogs.INTERNAL' } },\n ],\n });\n st.rootSpan = undefined;\n }\n await shipper.flush();\n void sessionID;\n }\n\n return {\n /** Fired when the user submits a prompt — open the turn's AGENT root. */\n 'chat.message': async (_input: any, output: any) => {\n try {\n const sessionID = String(_input?.sessionID ?? output?.sessionID ?? '');\n if (!sessionID) return;\n const st = stateFor(sessionID);\n const parts = output?.parts ?? [];\n const text = Array.isArray(parts)\n ? parts\n .filter((p: any) => p?.type === 'text' && typeof p.text === 'string')\n .map((p: any) => p.text)\n .join('\\n')\n : '';\n if (text) st.currentInput = text;\n startRoot(st, sessionID);\n } catch {\n /* ignore */\n }\n },\n\n /** Capture the system prompt (opt-in). */\n 'experimental.chat.system.transform': async (_input: any, output: any) => {\n try {\n if (!captureSystemPrompt) return;\n const sessionID = String(_input?.sessionID ?? '');\n const parts = output?.system ?? output?.parts ?? output;\n const joined = Array.isArray(parts) ? parts.map((p: any) => (typeof p === 'string' ? p : p?.text ?? '')).join('\\n') : String(parts ?? '');\n if (sessionID && joined) stateFor(sessionID).systemPrompt = joined;\n } catch {\n /* ignore */\n }\n },\n\n /** Global event bus — message parts, assistant completions, session idle. */\n event: async ({ event }: { event: any }) => {\n try {\n await handleEvent(shipper, sessions, stateFor, startRoot, closeAndFlush, event);\n } catch {\n // never break opencode over tracing\n }\n },\n\n /** Tool start — record start time + args (span built atomically in `after`). */\n 'tool.execute.before': async (input: any, output: any) => {\n try {\n const sessionID = String(input?.sessionID ?? '');\n if (!sessionID) return;\n const st = stateFor(sessionID);\n startRoot(st, sessionID);\n const callID = String(input?.callID ?? input?.tool ?? '');\n st.toolStarts.set(callID, {\n spanId: generateSpanId(),\n startNano: nowNanoString(),\n tool: String(input?.tool ?? 'tool'),\n args: output?.args,\n });\n } catch {\n /* ignore */\n }\n },\n\n /** Tool end — enqueue the completed TOOL span (parented to the turn root). */\n 'tool.execute.after': async (input: any, result: any) => {\n try {\n const sessionID = String(input?.sessionID ?? '');\n if (!sessionID) return;\n const st = stateFor(sessionID);\n const callID = String(input?.callID ?? input?.tool ?? '');\n const start = st.toolStarts.get(callID);\n if (!start) return;\n st.toolStarts.delete(callID);\n\n const attrs: OtlpKeyValue[] = [\n { key: 'neatlogs.span.kind', value: { stringValue: 'TOOL' } },\n { key: 'neatlogs.tool.name', value: { stringValue: start.tool } },\n { key: 'neatlogs.conversation.id', value: { stringValue: sessionID } },\n ];\n if (start.args !== undefined) {\n // The shipper bypasses the SDK attribute-processor, so emit the\n // already-namespaced keys the backend consumer reads directly\n // (neatlogs.tool.input / .output and the generic neatlogs.input.value),\n // not the raw input.value/output.value the processor would map.\n setIO(attrs, 'TOOL', safeStringify(start.args), undefined);\n push(attrs, attrStr('neatlogs.tool.input', safeStringify(start.args)));\n }\n if (result?.title) push(attrs, attrStr('neatlogs.tool.title', String(result.title)));\n const out = result?.output ?? result?.result;\n if (out !== undefined) {\n const o = typeof out === 'string' ? out : safeStringify(out);\n setIO(attrs, 'TOOL', undefined, o);\n push(attrs, attrStr('neatlogs.tool.output', o));\n }\n if (result?.metadata !== undefined) {\n push(attrs, attrStr('neatlogs.tool.metadata', safeStringify(result.metadata)));\n }\n\n shipper.enqueue({\n traceId: st.traceId,\n spanId: start.spanId,\n parentSpanId: st.rootSpan?.spanId,\n name: `opencode.tool.${start.tool}`,\n kind: 1,\n startTimeUnixNano: start.startNano,\n endTimeUnixNano: nowNanoString(),\n attributes: attrs,\n status: { code: SpanStatusCode.OK },\n });\n } catch {\n /* ignore */\n }\n },\n };\n};\n\n// Convenience aliases so users can import under any common name.\nexport const neatlogsOpencodePlugin = NeatlogsOpencodePlugin;\nexport default NeatlogsOpencodePlugin;\n\n// ---------------------------------------------------------------------------\n// Event handling\n// ---------------------------------------------------------------------------\n\nfunction handleEvent(\n shipper: TraceShipper,\n sessions: Map<string, SessionState>,\n stateFor: (sessionID: string) => SessionState,\n startRoot: (st: SessionState, sessionID: string) => void,\n closeAndFlush: (st: SessionState, sessionID: string) => Promise<void>,\n event: any,\n): Promise<unknown> | undefined {\n const type = event?.type;\n const props = event?.properties ?? {};\n\n // Accumulate text + tool-call parts on an assistant message.\n if (type === 'message.part.updated' || type === 'message.part.completed') {\n const part = props.part ?? props;\n const messageID = part?.messageID ?? part?.message_id;\n const sessionID = part?.sessionID ?? props.sessionID;\n if (!messageID || !sessionID) return undefined;\n const st = stateFor(String(sessionID));\n if (part?.type === 'text' && typeof part?.text === 'string') {\n st.outputParts.set(String(messageID), part.text);\n } else if (part?.type === 'tool' && part?.tool) {\n const list = st.toolCalls.get(String(messageID)) ?? [];\n const callID = String(part.callID ?? part.tool);\n const input = part?.state?.input ?? {};\n const existing = list.find((t) => t.callID === callID);\n if (existing) existing.input = input;\n else list.push({ name: String(part.tool), input, callID });\n st.toolCalls.set(String(messageID), list);\n }\n return undefined;\n }\n\n // Assistant message completed → emit the LLM span, then flush this turn.\n if (type === 'message.updated' || type === 'message.completed') {\n const info = props.info ?? props.message ?? props;\n const sessionID = info?.sessionID ?? info?.session_id;\n if (!sessionID) return undefined;\n if (info?.role !== 'assistant') return undefined;\n const completed = info?.time?.completed ?? info?.completed;\n const id = String(info?.id ?? '');\n if (!completed || !id) return undefined;\n const st = stateFor(String(sessionID));\n if (st.processed.has(id)) return undefined;\n st.processed.add(id);\n startRoot(st, String(sessionID));\n emitLlmSpan(shipper, st, info, String(sessionID));\n // Incremental persistence: ship this turn's spans now (don't wait for idle).\n return shipper.flush().catch(() => undefined);\n }\n\n // Session finished → end root, send completion marker, final flush.\n if (type === 'session.idle' || type === 'session.deleted') {\n const sessionID = props.sessionID ?? props.info?.id;\n if (!sessionID) return undefined;\n const st = sessions.get(String(sessionID));\n if (!st) return undefined;\n st.toolStarts.clear();\n const p = closeAndFlush(st, String(sessionID));\n if (type === 'session.deleted') sessions.delete(String(sessionID));\n return p;\n }\n\n return undefined;\n}\n\nfunction emitLlmSpan(shipper: TraceShipper, st: SessionState, info: any, sessionID: string): void {\n const model = info?.modelID ?? info?.model ?? '';\n const provider = info?.providerID ?? info?.provider ?? '';\n\n const attrs: OtlpKeyValue[] = [\n { key: 'neatlogs.span.kind', value: { stringValue: 'LLM' } },\n { key: 'neatlogs.conversation.id', value: { stringValue: sessionID } },\n ];\n push(attrs, attrStr('neatlogs.llm.model_name', model ? String(model) : undefined));\n push(attrs, attrStr('neatlogs.llm.provider', provider ? String(provider) : undefined));\n\n let inIdx = 0;\n if (st.systemPrompt) {\n push(attrs, attrStr(`neatlogs.llm.input_messages.${inIdx}.role`, 'system'));\n push(attrs, attrStr(`neatlogs.llm.input_messages.${inIdx}.content`, st.systemPrompt));\n inIdx++;\n }\n if (st.currentInput) {\n push(attrs, attrStr(`neatlogs.llm.input_messages.${inIdx}.role`, 'user'));\n push(attrs, attrStr(`neatlogs.llm.input_messages.${inIdx}.content`, st.currentInput));\n setIO(attrs, 'LLM', st.currentInput, undefined);\n }\n\n const outText = st.outputParts.get(String(info?.id)) || messageText(info) || '';\n const toolCalls = st.toolCalls.get(String(info?.id)) ?? [];\n\n if (outText) {\n push(attrs, attrStr('neatlogs.llm.output_messages.0.role', 'assistant'));\n push(attrs, attrStr('neatlogs.llm.output_messages.0.content', outText));\n setIO(attrs, 'LLM', undefined, outText);\n st.lastAssistantText = outText;\n }\n // Tool-deciding turns often carry no text — render the tool call(s) as output.\n if (toolCalls.length) {\n toolCalls.forEach((tc, j) => {\n push(attrs, attrStr(`neatlogs.llm.tool_calls.${j}.name`, tc.name));\n push(attrs, attrStr(`neatlogs.llm.tool_calls.${j}.arguments`, safeStringify(tc.input ?? {})));\n });\n if (!outText) {\n const rendered = toolCalls.map((tc) => `→ ${tc.name}(${safeStringify(tc.input ?? {})})`).join('\\n');\n push(attrs, attrStr('neatlogs.llm.output_messages.0.role', 'assistant'));\n push(attrs, attrStr('neatlogs.llm.output_messages.0.content', rendered));\n setIO(attrs, 'LLM', undefined, rendered);\n }\n }\n\n // Tokens: opencode message tokens { input, output, reasoning, cache:{read,write} }\n const tokens = info?.tokens;\n if (tokens) {\n push(attrs, attrInt('neatlogs.llm.token_count.prompt', tokens.input));\n push(attrs, attrInt('neatlogs.llm.token_count.completion', tokens.output));\n if (tokens.input != null && tokens.output != null) {\n push(attrs, attrInt('neatlogs.llm.token_count.total', tokens.input + tokens.output));\n }\n push(attrs, attrInt('neatlogs.llm.token_count.reasoning', tokens.reasoning));\n push(attrs, attrInt('neatlogs.llm.token_count.cache_read', tokens.cache?.read));\n push(attrs, attrInt('neatlogs.llm.token_count.cache_write', tokens.cache?.write));\n }\n push(attrs, attrDouble('neatlogs.llm.cost_usd', info?.cost));\n\n // Use opencode's real start time when available (else now).\n const createdMs = info?.time?.created;\n const startNano = typeof createdMs === 'number' ? msToNanoString(Math.floor(createdMs)) : nowNanoString();\n\n shipper.enqueue({\n traceId: st.traceId,\n spanId: generateSpanId(),\n parentSpanId: st.rootSpan?.spanId,\n name: `opencode.llm.${model || 'model'}`,\n kind: 1,\n startTimeUnixNano: startNano,\n endTimeUnixNano: nowNanoString(),\n attributes: attrs,\n status: { code: SpanStatusCode.OK },\n });\n\n // Reset accumulated parts for the next turn.\n if (info?.id) {\n st.outputParts.delete(String(info.id));\n st.toolCalls.delete(String(info.id));\n }\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction push(arr: OtlpKeyValue[], kv: OtlpKeyValue | undefined): void {\n if (kv) arr.push(kv);\n}\n\n/**\n * Set generic input/output on a span using the ALREADY-NAMESPACED keys the\n * backend consumer reads. The OTel-SDK wrappers rely on the attribute-processor\n * to map raw `input.value` → `neatlogs.{kind}.input`; this plugin ships spans\n * directly (no processor), so it must emit the namespaced keys itself:\n * neatlogs.input.value / neatlogs.output.value (generic)\n * neatlogs.{kind}.input / neatlogs.{kind}.output (kind-specific)\n * We also keep the raw input.value/output.value for any consumer that maps it.\n */\nfunction setIO(arr: OtlpKeyValue[], kind: string, input?: string, output?: string): void {\n const k = kind.toLowerCase();\n if (input !== undefined) {\n push(arr, attrStr('input.value', input));\n push(arr, attrStr('neatlogs.input.value', input));\n push(arr, attrStr(`neatlogs.${k}.input`, input));\n }\n if (output !== undefined) {\n push(arr, attrStr('output.value', output));\n push(arr, attrStr('neatlogs.output.value', output));\n push(arr, attrStr(`neatlogs.${k}.output`, output));\n }\n}\n\n/** Flatten an opencode message's parts/content to readable text. */\nfunction messageText(info: any): string {\n if (!info) return '';\n if (typeof info.text === 'string') return info.text;\n const parts = info.parts ?? info.content;\n if (typeof parts === 'string') return parts;\n if (!Array.isArray(parts)) return '';\n const out: string[] = [];\n for (const p of parts) {\n if (typeof p === 'string') out.push(p);\n else if (p && typeof p === 'object' && typeof p.text === 'string') out.push(p.text);\n }\n return out.join('');\n}\n\nfunction safeStringify(value: unknown): string {\n if (typeof value === 'string') return value;\n try {\n return JSON.stringify(value) ?? '';\n } catch {\n return String(value);\n }\n}\n","/**\n * Direct OTLP trace shipper for the opencode plugin.\n *\n * opencode loads the plugin in-process but `opencode run` is short-lived — it\n * tears down the moment a session goes idle. The OpenTelemetry BatchSpanProcessor\n * (async, scheduled-delay export + a `beforeExit` shutdown) races that teardown,\n * dropping spans or leaving aborted half-sent requests. This shipper mirrors the\n * proven `neatlogs-claude-code` design instead: spans are queued, then `flush()`\n * does a single AWAITED `fetch(POST /v1/traces)` round-trip that completes before\n * the host process can exit. No batch processor, no exit-time race.\n *\n * Self-contained (inlined OTLP protobuf schema) so it adds no runtime file I/O.\n */\n\nimport protobuf from 'protobufjs';\nimport { __version__ } from './version.js';\n\nconst PACKAGE_NAME = 'neatlogs.opencode';\n\nexport interface OtlpKeyValue {\n key: string;\n value: {\n stringValue?: string;\n intValue?: string;\n doubleValue?: number;\n boolValue?: boolean;\n };\n}\n\nexport interface OtlpSpan {\n traceId: Uint8Array;\n spanId: Uint8Array;\n parentSpanId?: Uint8Array;\n name: string;\n /** OTLP SpanKind enum (0=unspecified, 1=internal, …). Neatlogs kind rides in attributes. */\n kind: number;\n startTimeUnixNano: string;\n endTimeUnixNano: string;\n attributes: OtlpKeyValue[];\n status?: { code: number; message?: string };\n}\n\n// Inlined OTLP proto definition — avoids .proto file I/O at runtime.\nconst OTLP_PROTO_JSON: protobuf.INamespace = {\n nested: {\n opentelemetry: {\n nested: {\n proto: {\n nested: {\n common: {\n nested: {\n v1: {\n nested: {\n AnyValue: {\n oneofs: {\n value: {\n oneof: [\n 'stringValue',\n 'boolValue',\n 'intValue',\n 'doubleValue',\n 'arrayValue',\n 'kvlistValue',\n 'bytesValue',\n ],\n },\n },\n fields: {\n stringValue: { type: 'string', id: 1 },\n boolValue: { type: 'bool', id: 2 },\n intValue: { type: 'int64', id: 3 },\n doubleValue: { type: 'double', id: 4 },\n arrayValue: { type: 'ArrayValue', id: 5 },\n kvlistValue: { type: 'KeyValueList', id: 6 },\n bytesValue: { type: 'bytes', id: 7 },\n },\n },\n ArrayValue: { fields: { values: { rule: 'repeated', type: 'AnyValue', id: 1 } } },\n KeyValueList: { fields: { values: { rule: 'repeated', type: 'KeyValue', id: 1 } } },\n KeyValue: {\n fields: { key: { type: 'string', id: 1 }, value: { type: 'AnyValue', id: 2 } },\n },\n InstrumentationScope: {\n fields: { name: { type: 'string', id: 1 }, version: { type: 'string', id: 2 } },\n },\n },\n },\n },\n },\n resource: {\n nested: {\n v1: {\n nested: {\n Resource: {\n fields: {\n attributes: {\n rule: 'repeated',\n type: 'opentelemetry.proto.common.v1.KeyValue',\n id: 1,\n },\n },\n },\n },\n },\n },\n },\n trace: {\n nested: {\n v1: {\n nested: {\n ResourceSpans: {\n fields: {\n resource: { type: 'opentelemetry.proto.resource.v1.Resource', id: 1 },\n scopeSpans: { rule: 'repeated', type: 'ScopeSpans', id: 2 },\n },\n },\n ScopeSpans: {\n fields: {\n scope: { type: 'opentelemetry.proto.common.v1.InstrumentationScope', id: 1 },\n spans: { rule: 'repeated', type: 'Span', id: 2 },\n },\n },\n Span: {\n fields: {\n traceId: { type: 'bytes', id: 1 },\n spanId: { type: 'bytes', id: 2 },\n traceState: { type: 'string', id: 3 },\n parentSpanId: { type: 'bytes', id: 4 },\n name: { type: 'string', id: 5 },\n kind: { type: 'SpanKind', id: 6 },\n startTimeUnixNano: { type: 'fixed64', id: 7 },\n endTimeUnixNano: { type: 'fixed64', id: 8 },\n attributes: {\n rule: 'repeated',\n type: 'opentelemetry.proto.common.v1.KeyValue',\n id: 9,\n },\n droppedAttributesCount: { type: 'uint32', id: 10 },\n status: { type: 'Status', id: 15 },\n },\n },\n Status: {\n fields: { message: { type: 'string', id: 2 }, code: { type: 'StatusCode', id: 3 } },\n },\n StatusCode: {\n values: { STATUS_CODE_UNSET: 0, STATUS_CODE_OK: 1, STATUS_CODE_ERROR: 2 },\n },\n SpanKind: {\n values: {\n SPAN_KIND_UNSPECIFIED: 0,\n SPAN_KIND_INTERNAL: 1,\n SPAN_KIND_SERVER: 2,\n SPAN_KIND_CLIENT: 3,\n SPAN_KIND_PRODUCER: 4,\n SPAN_KIND_CONSUMER: 5,\n },\n },\n },\n },\n },\n },\n collector: {\n nested: {\n trace: {\n nested: {\n v1: {\n nested: {\n ExportTraceServiceRequest: {\n fields: {\n resourceSpans: {\n rule: 'repeated',\n type: 'opentelemetry.proto.trace.v1.ResourceSpans',\n id: 1,\n },\n },\n },\n },\n },\n },\n },\n },\n },\n },\n },\n },\n },\n },\n};\n\nconst protoRoot = protobuf.Root.fromJSON(OTLP_PROTO_JSON);\nconst ExportTraceServiceRequest = protoRoot.lookupType(\n 'opentelemetry.proto.collector.trace.v1.ExportTraceServiceRequest',\n);\n\nexport const SpanStatusCode = { UNSET: 0, OK: 1, ERROR: 2 } as const;\n\n// ---------------------------------------------------------------------------\n// ID + time + attribute helpers\n// ---------------------------------------------------------------------------\n\nfunction randomBytes(length: number): Uint8Array {\n const out = new Uint8Array(length);\n const crypto = globalThis.crypto;\n if (crypto && typeof crypto.getRandomValues === 'function') {\n crypto.getRandomValues(out);\n return out;\n }\n for (let i = 0; i < out.length; i++) out[i] = Math.floor(Math.random() * 256);\n return out;\n}\n\nexport function generateTraceId(): Uint8Array {\n return randomBytes(16);\n}\n\nexport function generateSpanId(): Uint8Array {\n return randomBytes(8);\n}\n\nexport function bytesToHex(bytes: Uint8Array): string {\n return Array.from(bytes)\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('');\n}\n\nexport function nowNanoString(): string {\n return (BigInt(Date.now()) * 1_000_000n).toString();\n}\n\nexport function msToNanoString(ms: number): string {\n return (BigInt(Math.floor(ms)) * 1_000_000n).toString();\n}\n\nexport function attrStr(key: string, value: string | undefined): OtlpKeyValue | undefined {\n if (value === undefined || value === null) return undefined;\n return { key, value: { stringValue: String(value) } };\n}\n\nexport function attrInt(key: string, value: number | undefined): OtlpKeyValue | undefined {\n if (value === undefined || value === null || !Number.isFinite(value)) return undefined;\n return { key, value: { intValue: String(Math.trunc(value)) } };\n}\n\nexport function attrDouble(key: string, value: number | undefined): OtlpKeyValue | undefined {\n if (value === undefined || value === null || !Number.isFinite(value)) return undefined;\n return { key, value: { doubleValue: value } };\n}\n\nexport interface TraceShipperOptions {\n apiKey: string;\n endpoint: string;\n debug?: boolean;\n maxRetries?: number;\n workflowName?: string;\n}\n\nexport class TraceShipper {\n private apiKey: string;\n private endpoint: string;\n private debug: boolean;\n private maxRetries: number;\n workflowName: string;\n private queue: OtlpSpan[] = [];\n private prefix = '[neatlogs/opencode]';\n\n constructor(opts: TraceShipperOptions) {\n this.apiKey = opts.apiKey;\n this.endpoint = opts.endpoint.endsWith('/') ? opts.endpoint.slice(0, -1) : opts.endpoint;\n this.debug = !!opts.debug;\n this.maxRetries = opts.maxRetries ?? 3;\n this.workflowName = opts.workflowName || '';\n }\n\n enqueue(span: OtlpSpan): void {\n this.queue.push(span);\n }\n\n get pending(): number {\n return this.queue.length;\n }\n\n /**\n * Ship all queued spans in a single awaited POST. Resolves only once the HTTP\n * response is received (or all retries are exhausted) — so a short-lived host\n * can safely exit immediately after awaiting this.\n */\n async flush(): Promise<void> {\n if (this.queue.length === 0) return;\n if (!this.apiKey) {\n this.queue = [];\n return;\n }\n\n const spans = this.queue.splice(0);\n const payload = this.buildProtobuf(spans);\n const url = `${this.endpoint}/v1/traces`;\n\n if (this.debug) console.log(`${this.prefix} Shipping ${spans.length} spans to ${url}`);\n\n for (let attempt = 1; attempt <= this.maxRetries; attempt++) {\n try {\n const resp = await fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-protobuf',\n 'x-api-key': this.apiKey,\n },\n body: payload as any,\n });\n\n if (resp.ok) {\n if (this.debug) console.log(`${this.prefix} Shipped ${spans.length} spans`);\n return;\n }\n if (resp.status === 401) {\n console.warn(`${this.prefix} Invalid API key (401) — dropping ${spans.length} spans`);\n return;\n }\n if (resp.status < 500 && resp.status !== 429) {\n if (this.debug) console.warn(`${this.prefix} HTTP ${resp.status} — dropping spans`);\n return;\n }\n // 429 / 5xx → retry\n } catch (err) {\n if (this.debug) {\n console.warn(\n `${this.prefix} Attempt ${attempt}/${this.maxRetries}: ${(err as Error).message}`,\n );\n }\n }\n if (attempt < this.maxRetries) {\n await new Promise((r) => setTimeout(r, 500 * 2 ** (attempt - 1)));\n }\n }\n console.warn(`${this.prefix} Failed to ship ${spans.length} spans after ${this.maxRetries} attempts`);\n }\n\n private buildProtobuf(spans: OtlpSpan[]): Uint8Array {\n const protoSpans = spans.map((span) => ({\n traceId: span.traceId,\n spanId: span.spanId,\n parentSpanId: span.parentSpanId || undefined,\n name: span.name,\n kind: span.kind,\n startTimeUnixNano: nanoToLong(span.startTimeUnixNano),\n endTimeUnixNano: nanoToLong(span.endTimeUnixNano),\n attributes: span.attributes.map((a) => ({\n key: a.key,\n value:\n a.value.intValue !== undefined\n ? { intValue: nanoToLong(a.value.intValue) }\n : a.value,\n })),\n status: span.status ? { code: span.status.code, message: span.status.message } : undefined,\n }));\n\n const resourceAttributes: Array<{ key: string; value: { stringValue: string } }> = [\n { key: 'service.name', value: { stringValue: 'neatlogs.opencode' } },\n { key: 'service.version', value: { stringValue: __version__ } },\n ];\n if (this.workflowName) {\n resourceAttributes.push({\n key: 'neatlogs.workflow_name',\n value: { stringValue: this.workflowName },\n });\n }\n\n const message = {\n resourceSpans: [\n {\n resource: { attributes: resourceAttributes },\n scopeSpans: [\n {\n scope: { name: PACKAGE_NAME, version: __version__ },\n spans: protoSpans,\n },\n ],\n },\n ],\n };\n\n const errMsg = ExportTraceServiceRequest.verify(message);\n if (errMsg && this.debug) console.warn(`${this.prefix} Proto verify: ${errMsg}`);\n\n return ExportTraceServiceRequest.encode(ExportTraceServiceRequest.fromObject(message)).finish();\n }\n}\n\n/** protobufjs encodes fixed64/int64 from a {low,high,unsigned} Long-like. */\nfunction nanoToLong(nanoStr: string): { low: number; high: number; unsigned: boolean } {\n const big = BigInt(nanoStr);\n const low = Number(big & 0xffffffffn);\n const high = Number((big >> 32n) & 0xffffffffn);\n return { low, high, unsigned: true };\n}\n","/**\n * SDK version. Kept in sync with package.json by the `version:sync` script\n * (runs automatically on `prebuild`). Do not edit by hand — bump package.json.\n */\nexport const __version__ = '1.1.4';\n"],"mappings":"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","names":["protobuf"]}
|
package/dist/opencode-plugin.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/opencode-trace-shipper.ts","../src/version.ts","../src/opencode-plugin.ts"],"sourcesContent":["/**\n * Direct OTLP trace shipper for the opencode plugin.\n *\n * opencode loads the plugin in-process but `opencode run` is short-lived — it\n * tears down the moment a session goes idle. The OpenTelemetry BatchSpanProcessor\n * (async, scheduled-delay export + a `beforeExit` shutdown) races that teardown,\n * dropping spans or leaving aborted half-sent requests. This shipper mirrors the\n * proven `neatlogs-claude-code` design instead: spans are queued, then `flush()`\n * does a single AWAITED `fetch(POST /v1/traces)` round-trip that completes before\n * the host process can exit. No batch processor, no exit-time race.\n *\n * Self-contained (inlined OTLP protobuf schema) so it adds no runtime file I/O.\n */\n\nimport protobuf from 'protobufjs';\nimport { __version__ } from './version.js';\n\nconst PACKAGE_NAME = 'neatlogs.opencode';\n\nexport interface OtlpKeyValue {\n key: string;\n value: {\n stringValue?: string;\n intValue?: string;\n doubleValue?: number;\n boolValue?: boolean;\n };\n}\n\nexport interface OtlpSpan {\n traceId: Uint8Array;\n spanId: Uint8Array;\n parentSpanId?: Uint8Array;\n name: string;\n /** OTLP SpanKind enum (0=unspecified, 1=internal, …). Neatlogs kind rides in attributes. */\n kind: number;\n startTimeUnixNano: string;\n endTimeUnixNano: string;\n attributes: OtlpKeyValue[];\n status?: { code: number; message?: string };\n}\n\n// Inlined OTLP proto definition — avoids .proto file I/O at runtime.\nconst OTLP_PROTO_JSON: protobuf.INamespace = {\n nested: {\n opentelemetry: {\n nested: {\n proto: {\n nested: {\n common: {\n nested: {\n v1: {\n nested: {\n AnyValue: {\n oneofs: {\n value: {\n oneof: [\n 'stringValue',\n 'boolValue',\n 'intValue',\n 'doubleValue',\n 'arrayValue',\n 'kvlistValue',\n 'bytesValue',\n ],\n },\n },\n fields: {\n stringValue: { type: 'string', id: 1 },\n boolValue: { type: 'bool', id: 2 },\n intValue: { type: 'int64', id: 3 },\n doubleValue: { type: 'double', id: 4 },\n arrayValue: { type: 'ArrayValue', id: 5 },\n kvlistValue: { type: 'KeyValueList', id: 6 },\n bytesValue: { type: 'bytes', id: 7 },\n },\n },\n ArrayValue: { fields: { values: { rule: 'repeated', type: 'AnyValue', id: 1 } } },\n KeyValueList: { fields: { values: { rule: 'repeated', type: 'KeyValue', id: 1 } } },\n KeyValue: {\n fields: { key: { type: 'string', id: 1 }, value: { type: 'AnyValue', id: 2 } },\n },\n InstrumentationScope: {\n fields: { name: { type: 'string', id: 1 }, version: { type: 'string', id: 2 } },\n },\n },\n },\n },\n },\n resource: {\n nested: {\n v1: {\n nested: {\n Resource: {\n fields: {\n attributes: {\n rule: 'repeated',\n type: 'opentelemetry.proto.common.v1.KeyValue',\n id: 1,\n },\n },\n },\n },\n },\n },\n },\n trace: {\n nested: {\n v1: {\n nested: {\n ResourceSpans: {\n fields: {\n resource: { type: 'opentelemetry.proto.resource.v1.Resource', id: 1 },\n scopeSpans: { rule: 'repeated', type: 'ScopeSpans', id: 2 },\n },\n },\n ScopeSpans: {\n fields: {\n scope: { type: 'opentelemetry.proto.common.v1.InstrumentationScope', id: 1 },\n spans: { rule: 'repeated', type: 'Span', id: 2 },\n },\n },\n Span: {\n fields: {\n traceId: { type: 'bytes', id: 1 },\n spanId: { type: 'bytes', id: 2 },\n traceState: { type: 'string', id: 3 },\n parentSpanId: { type: 'bytes', id: 4 },\n name: { type: 'string', id: 5 },\n kind: { type: 'SpanKind', id: 6 },\n startTimeUnixNano: { type: 'fixed64', id: 7 },\n endTimeUnixNano: { type: 'fixed64', id: 8 },\n attributes: {\n rule: 'repeated',\n type: 'opentelemetry.proto.common.v1.KeyValue',\n id: 9,\n },\n droppedAttributesCount: { type: 'uint32', id: 10 },\n status: { type: 'Status', id: 15 },\n },\n },\n Status: {\n fields: { message: { type: 'string', id: 2 }, code: { type: 'StatusCode', id: 3 } },\n },\n StatusCode: {\n values: { STATUS_CODE_UNSET: 0, STATUS_CODE_OK: 1, STATUS_CODE_ERROR: 2 },\n },\n SpanKind: {\n values: {\n SPAN_KIND_UNSPECIFIED: 0,\n SPAN_KIND_INTERNAL: 1,\n SPAN_KIND_SERVER: 2,\n SPAN_KIND_CLIENT: 3,\n SPAN_KIND_PRODUCER: 4,\n SPAN_KIND_CONSUMER: 5,\n },\n },\n },\n },\n },\n },\n collector: {\n nested: {\n trace: {\n nested: {\n v1: {\n nested: {\n ExportTraceServiceRequest: {\n fields: {\n resourceSpans: {\n rule: 'repeated',\n type: 'opentelemetry.proto.trace.v1.ResourceSpans',\n id: 1,\n },\n },\n },\n },\n },\n },\n },\n },\n },\n },\n },\n },\n },\n },\n};\n\nconst protoRoot = protobuf.Root.fromJSON(OTLP_PROTO_JSON);\nconst ExportTraceServiceRequest = protoRoot.lookupType(\n 'opentelemetry.proto.collector.trace.v1.ExportTraceServiceRequest',\n);\n\nexport const SpanStatusCode = { UNSET: 0, OK: 1, ERROR: 2 } as const;\n\n// ---------------------------------------------------------------------------\n// ID + time + attribute helpers\n// ---------------------------------------------------------------------------\n\nfunction randomBytes(length: number): Uint8Array {\n const out = new Uint8Array(length);\n const crypto = globalThis.crypto;\n if (crypto && typeof crypto.getRandomValues === 'function') {\n crypto.getRandomValues(out);\n return out;\n }\n for (let i = 0; i < out.length; i++) out[i] = Math.floor(Math.random() * 256);\n return out;\n}\n\nexport function generateTraceId(): Uint8Array {\n return randomBytes(16);\n}\n\nexport function generateSpanId(): Uint8Array {\n return randomBytes(8);\n}\n\nexport function bytesToHex(bytes: Uint8Array): string {\n return Array.from(bytes)\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('');\n}\n\nexport function nowNanoString(): string {\n return (BigInt(Date.now()) * 1_000_000n).toString();\n}\n\nexport function msToNanoString(ms: number): string {\n return (BigInt(Math.floor(ms)) * 1_000_000n).toString();\n}\n\nexport function attrStr(key: string, value: string | undefined): OtlpKeyValue | undefined {\n if (value === undefined || value === null) return undefined;\n return { key, value: { stringValue: String(value) } };\n}\n\nexport function attrInt(key: string, value: number | undefined): OtlpKeyValue | undefined {\n if (value === undefined || value === null || !Number.isFinite(value)) return undefined;\n return { key, value: { intValue: String(Math.trunc(value)) } };\n}\n\nexport function attrDouble(key: string, value: number | undefined): OtlpKeyValue | undefined {\n if (value === undefined || value === null || !Number.isFinite(value)) return undefined;\n return { key, value: { doubleValue: value } };\n}\n\nexport interface TraceShipperOptions {\n apiKey: string;\n endpoint: string;\n debug?: boolean;\n maxRetries?: number;\n workflowName?: string;\n}\n\nexport class TraceShipper {\n private apiKey: string;\n private endpoint: string;\n private debug: boolean;\n private maxRetries: number;\n workflowName: string;\n private queue: OtlpSpan[] = [];\n private prefix = '[neatlogs/opencode]';\n\n constructor(opts: TraceShipperOptions) {\n this.apiKey = opts.apiKey;\n this.endpoint = opts.endpoint.endsWith('/') ? opts.endpoint.slice(0, -1) : opts.endpoint;\n this.debug = !!opts.debug;\n this.maxRetries = opts.maxRetries ?? 3;\n this.workflowName = opts.workflowName || '';\n }\n\n enqueue(span: OtlpSpan): void {\n this.queue.push(span);\n }\n\n get pending(): number {\n return this.queue.length;\n }\n\n /**\n * Ship all queued spans in a single awaited POST. Resolves only once the HTTP\n * response is received (or all retries are exhausted) — so a short-lived host\n * can safely exit immediately after awaiting this.\n */\n async flush(): Promise<void> {\n if (this.queue.length === 0) return;\n if (!this.apiKey) {\n this.queue = [];\n return;\n }\n\n const spans = this.queue.splice(0);\n const payload = this.buildProtobuf(spans);\n const url = `${this.endpoint}/v1/traces`;\n\n if (this.debug) console.log(`${this.prefix} Shipping ${spans.length} spans to ${url}`);\n\n for (let attempt = 1; attempt <= this.maxRetries; attempt++) {\n try {\n const resp = await fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-protobuf',\n 'x-api-key': this.apiKey,\n },\n body: payload as any,\n });\n\n if (resp.ok) {\n if (this.debug) console.log(`${this.prefix} Shipped ${spans.length} spans`);\n return;\n }\n if (resp.status === 401) {\n console.warn(`${this.prefix} Invalid API key (401) — dropping ${spans.length} spans`);\n return;\n }\n if (resp.status < 500 && resp.status !== 429) {\n if (this.debug) console.warn(`${this.prefix} HTTP ${resp.status} — dropping spans`);\n return;\n }\n // 429 / 5xx → retry\n } catch (err) {\n if (this.debug) {\n console.warn(\n `${this.prefix} Attempt ${attempt}/${this.maxRetries}: ${(err as Error).message}`,\n );\n }\n }\n if (attempt < this.maxRetries) {\n await new Promise((r) => setTimeout(r, 500 * 2 ** (attempt - 1)));\n }\n }\n console.warn(`${this.prefix} Failed to ship ${spans.length} spans after ${this.maxRetries} attempts`);\n }\n\n private buildProtobuf(spans: OtlpSpan[]): Uint8Array {\n const protoSpans = spans.map((span) => ({\n traceId: span.traceId,\n spanId: span.spanId,\n parentSpanId: span.parentSpanId || undefined,\n name: span.name,\n kind: span.kind,\n startTimeUnixNano: nanoToLong(span.startTimeUnixNano),\n endTimeUnixNano: nanoToLong(span.endTimeUnixNano),\n attributes: span.attributes.map((a) => ({\n key: a.key,\n value:\n a.value.intValue !== undefined\n ? { intValue: nanoToLong(a.value.intValue) }\n : a.value,\n })),\n status: span.status ? { code: span.status.code, message: span.status.message } : undefined,\n }));\n\n const resourceAttributes: Array<{ key: string; value: { stringValue: string } }> = [\n { key: 'service.name', value: { stringValue: 'neatlogs.opencode' } },\n { key: 'service.version', value: { stringValue: __version__ } },\n ];\n if (this.workflowName) {\n resourceAttributes.push({\n key: 'neatlogs.workflow_name',\n value: { stringValue: this.workflowName },\n });\n }\n\n const message = {\n resourceSpans: [\n {\n resource: { attributes: resourceAttributes },\n scopeSpans: [\n {\n scope: { name: PACKAGE_NAME, version: __version__ },\n spans: protoSpans,\n },\n ],\n },\n ],\n };\n\n const errMsg = ExportTraceServiceRequest.verify(message);\n if (errMsg && this.debug) console.warn(`${this.prefix} Proto verify: ${errMsg}`);\n\n return ExportTraceServiceRequest.encode(ExportTraceServiceRequest.fromObject(message)).finish();\n }\n}\n\n/** protobufjs encodes fixed64/int64 from a {low,high,unsigned} Long-like. */\nfunction nanoToLong(nanoStr: string): { low: number; high: number; unsigned: boolean } {\n const big = BigInt(nanoStr);\n const low = Number(big & 0xffffffffn);\n const high = Number((big >> 32n) & 0xffffffffn);\n return { low, high, unsigned: true };\n}\n","/**\n * SDK version. Kept in sync with package.json by the `version:sync` script\n * (runs automatically on `prebuild`). Do not edit by hand — bump package.json.\n */\nexport const __version__ = '1.1.2';\n","/**\n * Neatlogs opencode plugin.\n *\n * opencode loads plugins from its config (`opencode.json` → `\"plugin\": [...]`)\n * or from local `.opencode/plugin/*.ts` files. A plugin is an async factory that\n * receives an app context and returns lifecycle hooks. This plugin instruments\n * opencode automatically — no per-call wiring — turning an opencode session into\n * a neatlogs span tree:\n *\n * AGENT opencode.session (one per user turn; parents that turn's spans)\n * ↳ LLM assistant turn (per completed assistant message)\n * ↳ TOOL tool execution (tool.execute.before → tool.execute.after)\n *\n * Every span carries `neatlogs.conversation.id` = the opencode session ID.\n *\n * Export model (mirrors @raindrop-ai/opencode-plugin and neatlogs-claude-code):\n * opencode loads the plugin in-process but `opencode run` is short-lived. Rather\n * than the OpenTelemetry BatchSpanProcessor (whose async, scheduled-delay export\n * + `beforeExit` shutdown races the teardown and drops spans), this plugin builds\n * spans directly and ships them via AWAITED `fetch(POST /v1/traces)` — and it\n * flushes after every completed assistant turn (incremental persistence) plus a\n * final flush on `session.idle`. A `neatlogs.trace.complete` marker is sent so\n * the backend enqueues the trace for finalization (simplification → UI).\n *\n * Setup — either:\n * • npm package, in opencode.json: `{ \"plugin\": [\"neatlogs/opencode\"] }`, OR\n * • local file `.opencode/plugin/neatlogs.ts`:\n * export { NeatlogsOpencodePlugin as default } from 'neatlogs/opencode';\n *\n * Env:\n * NEATLOGS_API_KEY required to export\n * NEATLOGS_ENDPOINT backend base URL (default https://ingest.neatlogs.com)\n * NEATLOGS_WORKFLOW_NAME logical grouping (default: \"opencode\")\n * NEATLOGS_CAPTURE_SYSTEM_PROMPT=true capture system prompt text (default off)\n */\n\nimport {\n TraceShipper,\n type OtlpSpan,\n type OtlpKeyValue,\n SpanStatusCode,\n generateTraceId,\n generateSpanId,\n nowNanoString,\n msToNanoString,\n attrStr,\n attrInt,\n attrDouble,\n} from './opencode-trace-shipper.js';\n\nconst DEFAULT_ENDPOINT = 'https://ingest.neatlogs.com';\n\n/** A span being built incrementally — ended (and shipped) later. */\ninterface OpenSpan {\n spanId: Uint8Array;\n parentSpanId?: Uint8Array;\n name: string;\n startNano: string;\n attributes: OtlpKeyValue[];\n}\n\ninterface SessionState {\n /** Per-session trace id — all spans in a session share it. */\n traceId: Uint8Array;\n /** The current turn's AGENT root span (created on chat.message, ended on idle). */\n rootSpan?: OpenSpan;\n /** Open TOOL spans keyed by callID → start time. */\n toolStarts: Map<string, { spanId: Uint8Array; startNano: string; tool: string; args: any }>;\n /** Accumulated assistant text per messageID (from text parts). */\n outputParts: Map<string, string>;\n /** Tool calls per assistant messageID (so a tool-only turn still has output). */\n toolCalls: Map<string, Array<{ name: string; input: any; callID: string }>>;\n /** assistant messageIDs already emitted (completion can fire repeatedly). */\n processed: Set<string>;\n /** Current user prompt (this turn's input). */\n currentInput: string;\n /** Captured system prompt (if enabled). */\n systemPrompt?: string;\n /** Latest assistant text — the AGENT root's output on close. */\n lastAssistantText: string;\n}\n\nexport const NeatlogsOpencodePlugin = async (_ctx: any): Promise<Record<string, any>> => {\n const apiKey = (process.env.NEATLOGS_API_KEY ?? '').trim();\n const endpoint = (process.env.NEATLOGS_ENDPOINT ?? DEFAULT_ENDPOINT).trim();\n const workflowName = process.env.NEATLOGS_WORKFLOW_NAME || 'opencode';\n const captureSystemPrompt =\n String(process.env.NEATLOGS_CAPTURE_SYSTEM_PROMPT || '').toLowerCase() === 'true';\n const debug = String(process.env.NEATLOGS_DEBUG || '').toLowerCase() === 'true';\n\n const shipper = new TraceShipper({ apiKey, endpoint, workflowName, debug });\n const sessions = new Map<string, SessionState>();\n\n function stateFor(sessionID: string): SessionState {\n let s = sessions.get(sessionID);\n if (!s) {\n s = {\n traceId: generateTraceId(),\n toolStarts: new Map(),\n outputParts: new Map(),\n toolCalls: new Map(),\n processed: new Set(),\n currentInput: '',\n lastAssistantText: '',\n };\n sessions.set(sessionID, s);\n }\n return s;\n }\n\n /** Start the per-turn AGENT root span (idempotent within a turn). */\n function startRoot(st: SessionState, sessionID: string): void {\n if (st.rootSpan) return;\n st.rootSpan = {\n spanId: generateSpanId(),\n name: 'opencode.session',\n startNano: nowNanoString(),\n attributes: [\n { key: 'neatlogs.span.kind', value: { stringValue: 'AGENT' } },\n { key: 'neatlogs.agent.framework', value: { stringValue: 'opencode' } },\n { key: 'neatlogs.conversation.id', value: { stringValue: sessionID } },\n ],\n };\n }\n\n /** End + enqueue the AGENT root, send the completion marker, and flush. */\n async function closeAndFlush(st: SessionState, sessionID: string): Promise<void> {\n if (st.rootSpan) {\n const attrs = st.rootSpan.attributes.slice();\n setIO(attrs, 'AGENT', st.currentInput || undefined, st.lastAssistantText || undefined);\n shipper.enqueue({\n traceId: st.traceId,\n spanId: st.rootSpan.spanId,\n name: st.rootSpan.name,\n kind: 1,\n startTimeUnixNano: st.rootSpan.startNano,\n endTimeUnixNano: nowNanoString(),\n attributes: attrs,\n status: { code: SpanStatusCode.OK },\n });\n // Completion marker — the backend only finalizes (simplifies → UI) a trace\n // once it sees a `neatlogs.trace.complete` span. Parented to the root.\n const m = nowNanoString();\n shipper.enqueue({\n traceId: st.traceId,\n spanId: generateSpanId(),\n parentSpanId: st.rootSpan.spanId,\n name: 'neatlogs.trace.complete',\n kind: 1,\n startTimeUnixNano: m,\n endTimeUnixNano: m,\n attributes: [\n { key: 'neatlogs.trace.complete', value: { boolValue: true } },\n { key: 'neatlogs.internal', value: { boolValue: true } },\n { key: 'neatlogs.span.kind', value: { stringValue: 'Neatlogs.INTERNAL' } },\n ],\n });\n st.rootSpan = undefined;\n }\n await shipper.flush();\n void sessionID;\n }\n\n return {\n /** Fired when the user submits a prompt — open the turn's AGENT root. */\n 'chat.message': async (_input: any, output: any) => {\n try {\n const sessionID = String(_input?.sessionID ?? output?.sessionID ?? '');\n if (!sessionID) return;\n const st = stateFor(sessionID);\n const parts = output?.parts ?? [];\n const text = Array.isArray(parts)\n ? parts\n .filter((p: any) => p?.type === 'text' && typeof p.text === 'string')\n .map((p: any) => p.text)\n .join('\\n')\n : '';\n if (text) st.currentInput = text;\n startRoot(st, sessionID);\n } catch {\n /* ignore */\n }\n },\n\n /** Capture the system prompt (opt-in). */\n 'experimental.chat.system.transform': async (_input: any, output: any) => {\n try {\n if (!captureSystemPrompt) return;\n const sessionID = String(_input?.sessionID ?? '');\n const parts = output?.system ?? output?.parts ?? output;\n const joined = Array.isArray(parts) ? parts.map((p: any) => (typeof p === 'string' ? p : p?.text ?? '')).join('\\n') : String(parts ?? '');\n if (sessionID && joined) stateFor(sessionID).systemPrompt = joined;\n } catch {\n /* ignore */\n }\n },\n\n /** Global event bus — message parts, assistant completions, session idle. */\n event: async ({ event }: { event: any }) => {\n try {\n await handleEvent(shipper, sessions, stateFor, startRoot, closeAndFlush, event);\n } catch {\n // never break opencode over tracing\n }\n },\n\n /** Tool start — record start time + args (span built atomically in `after`). */\n 'tool.execute.before': async (input: any, output: any) => {\n try {\n const sessionID = String(input?.sessionID ?? '');\n if (!sessionID) return;\n const st = stateFor(sessionID);\n startRoot(st, sessionID);\n const callID = String(input?.callID ?? input?.tool ?? '');\n st.toolStarts.set(callID, {\n spanId: generateSpanId(),\n startNano: nowNanoString(),\n tool: String(input?.tool ?? 'tool'),\n args: output?.args,\n });\n } catch {\n /* ignore */\n }\n },\n\n /** Tool end — enqueue the completed TOOL span (parented to the turn root). */\n 'tool.execute.after': async (input: any, result: any) => {\n try {\n const sessionID = String(input?.sessionID ?? '');\n if (!sessionID) return;\n const st = stateFor(sessionID);\n const callID = String(input?.callID ?? input?.tool ?? '');\n const start = st.toolStarts.get(callID);\n if (!start) return;\n st.toolStarts.delete(callID);\n\n const attrs: OtlpKeyValue[] = [\n { key: 'neatlogs.span.kind', value: { stringValue: 'TOOL' } },\n { key: 'neatlogs.tool.name', value: { stringValue: start.tool } },\n { key: 'neatlogs.conversation.id', value: { stringValue: sessionID } },\n ];\n if (start.args !== undefined) {\n // The shipper bypasses the SDK attribute-processor, so emit the\n // already-namespaced keys the backend consumer reads directly\n // (neatlogs.tool.input / .output and the generic neatlogs.input.value),\n // not the raw input.value/output.value the processor would map.\n setIO(attrs, 'TOOL', safeStringify(start.args), undefined);\n push(attrs, attrStr('neatlogs.tool.input', safeStringify(start.args)));\n }\n if (result?.title) push(attrs, attrStr('neatlogs.tool.title', String(result.title)));\n const out = result?.output ?? result?.result;\n if (out !== undefined) {\n const o = typeof out === 'string' ? out : safeStringify(out);\n setIO(attrs, 'TOOL', undefined, o);\n push(attrs, attrStr('neatlogs.tool.output', o));\n }\n if (result?.metadata !== undefined) {\n push(attrs, attrStr('neatlogs.tool.metadata', safeStringify(result.metadata)));\n }\n\n shipper.enqueue({\n traceId: st.traceId,\n spanId: start.spanId,\n parentSpanId: st.rootSpan?.spanId,\n name: `opencode.tool.${start.tool}`,\n kind: 1,\n startTimeUnixNano: start.startNano,\n endTimeUnixNano: nowNanoString(),\n attributes: attrs,\n status: { code: SpanStatusCode.OK },\n });\n } catch {\n /* ignore */\n }\n },\n };\n};\n\n// Convenience aliases so users can import under any common name.\nexport const neatlogsOpencodePlugin = NeatlogsOpencodePlugin;\nexport default NeatlogsOpencodePlugin;\n\n// ---------------------------------------------------------------------------\n// Event handling\n// ---------------------------------------------------------------------------\n\nfunction handleEvent(\n shipper: TraceShipper,\n sessions: Map<string, SessionState>,\n stateFor: (sessionID: string) => SessionState,\n startRoot: (st: SessionState, sessionID: string) => void,\n closeAndFlush: (st: SessionState, sessionID: string) => Promise<void>,\n event: any,\n): Promise<unknown> | undefined {\n const type = event?.type;\n const props = event?.properties ?? {};\n\n // Accumulate text + tool-call parts on an assistant message.\n if (type === 'message.part.updated' || type === 'message.part.completed') {\n const part = props.part ?? props;\n const messageID = part?.messageID ?? part?.message_id;\n const sessionID = part?.sessionID ?? props.sessionID;\n if (!messageID || !sessionID) return undefined;\n const st = stateFor(String(sessionID));\n if (part?.type === 'text' && typeof part?.text === 'string') {\n st.outputParts.set(String(messageID), part.text);\n } else if (part?.type === 'tool' && part?.tool) {\n const list = st.toolCalls.get(String(messageID)) ?? [];\n const callID = String(part.callID ?? part.tool);\n const input = part?.state?.input ?? {};\n const existing = list.find((t) => t.callID === callID);\n if (existing) existing.input = input;\n else list.push({ name: String(part.tool), input, callID });\n st.toolCalls.set(String(messageID), list);\n }\n return undefined;\n }\n\n // Assistant message completed → emit the LLM span, then flush this turn.\n if (type === 'message.updated' || type === 'message.completed') {\n const info = props.info ?? props.message ?? props;\n const sessionID = info?.sessionID ?? info?.session_id;\n if (!sessionID) return undefined;\n if (info?.role !== 'assistant') return undefined;\n const completed = info?.time?.completed ?? info?.completed;\n const id = String(info?.id ?? '');\n if (!completed || !id) return undefined;\n const st = stateFor(String(sessionID));\n if (st.processed.has(id)) return undefined;\n st.processed.add(id);\n startRoot(st, String(sessionID));\n emitLlmSpan(shipper, st, info, String(sessionID));\n // Incremental persistence: ship this turn's spans now (don't wait for idle).\n return shipper.flush().catch(() => undefined);\n }\n\n // Session finished → end root, send completion marker, final flush.\n if (type === 'session.idle' || type === 'session.deleted') {\n const sessionID = props.sessionID ?? props.info?.id;\n if (!sessionID) return undefined;\n const st = sessions.get(String(sessionID));\n if (!st) return undefined;\n st.toolStarts.clear();\n const p = closeAndFlush(st, String(sessionID));\n if (type === 'session.deleted') sessions.delete(String(sessionID));\n return p;\n }\n\n return undefined;\n}\n\nfunction emitLlmSpan(shipper: TraceShipper, st: SessionState, info: any, sessionID: string): void {\n const model = info?.modelID ?? info?.model ?? '';\n const provider = info?.providerID ?? info?.provider ?? '';\n\n const attrs: OtlpKeyValue[] = [\n { key: 'neatlogs.span.kind', value: { stringValue: 'LLM' } },\n { key: 'neatlogs.conversation.id', value: { stringValue: sessionID } },\n ];\n push(attrs, attrStr('neatlogs.llm.model_name', model ? String(model) : undefined));\n push(attrs, attrStr('neatlogs.llm.provider', provider ? String(provider) : undefined));\n\n let inIdx = 0;\n if (st.systemPrompt) {\n push(attrs, attrStr(`neatlogs.llm.input_messages.${inIdx}.role`, 'system'));\n push(attrs, attrStr(`neatlogs.llm.input_messages.${inIdx}.content`, st.systemPrompt));\n inIdx++;\n }\n if (st.currentInput) {\n push(attrs, attrStr(`neatlogs.llm.input_messages.${inIdx}.role`, 'user'));\n push(attrs, attrStr(`neatlogs.llm.input_messages.${inIdx}.content`, st.currentInput));\n setIO(attrs, 'LLM', st.currentInput, undefined);\n }\n\n const outText = st.outputParts.get(String(info?.id)) || messageText(info) || '';\n const toolCalls = st.toolCalls.get(String(info?.id)) ?? [];\n\n if (outText) {\n push(attrs, attrStr('neatlogs.llm.output_messages.0.role', 'assistant'));\n push(attrs, attrStr('neatlogs.llm.output_messages.0.content', outText));\n setIO(attrs, 'LLM', undefined, outText);\n st.lastAssistantText = outText;\n }\n // Tool-deciding turns often carry no text — render the tool call(s) as output.\n if (toolCalls.length) {\n toolCalls.forEach((tc, j) => {\n push(attrs, attrStr(`neatlogs.llm.tool_calls.${j}.name`, tc.name));\n push(attrs, attrStr(`neatlogs.llm.tool_calls.${j}.arguments`, safeStringify(tc.input ?? {})));\n });\n if (!outText) {\n const rendered = toolCalls.map((tc) => `→ ${tc.name}(${safeStringify(tc.input ?? {})})`).join('\\n');\n push(attrs, attrStr('neatlogs.llm.output_messages.0.role', 'assistant'));\n push(attrs, attrStr('neatlogs.llm.output_messages.0.content', rendered));\n setIO(attrs, 'LLM', undefined, rendered);\n }\n }\n\n // Tokens: opencode message tokens { input, output, reasoning, cache:{read,write} }\n const tokens = info?.tokens;\n if (tokens) {\n push(attrs, attrInt('neatlogs.llm.token_count.prompt', tokens.input));\n push(attrs, attrInt('neatlogs.llm.token_count.completion', tokens.output));\n if (tokens.input != null && tokens.output != null) {\n push(attrs, attrInt('neatlogs.llm.token_count.total', tokens.input + tokens.output));\n }\n push(attrs, attrInt('neatlogs.llm.token_count.reasoning', tokens.reasoning));\n push(attrs, attrInt('neatlogs.llm.token_count.cache_read', tokens.cache?.read));\n push(attrs, attrInt('neatlogs.llm.token_count.cache_write', tokens.cache?.write));\n }\n push(attrs, attrDouble('neatlogs.llm.cost_usd', info?.cost));\n\n // Use opencode's real start time when available (else now).\n const createdMs = info?.time?.created;\n const startNano = typeof createdMs === 'number' ? msToNanoString(Math.floor(createdMs)) : nowNanoString();\n\n shipper.enqueue({\n traceId: st.traceId,\n spanId: generateSpanId(),\n parentSpanId: st.rootSpan?.spanId,\n name: `opencode.llm.${model || 'model'}`,\n kind: 1,\n startTimeUnixNano: startNano,\n endTimeUnixNano: nowNanoString(),\n attributes: attrs,\n status: { code: SpanStatusCode.OK },\n });\n\n // Reset accumulated parts for the next turn.\n if (info?.id) {\n st.outputParts.delete(String(info.id));\n st.toolCalls.delete(String(info.id));\n }\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction push(arr: OtlpKeyValue[], kv: OtlpKeyValue | undefined): void {\n if (kv) arr.push(kv);\n}\n\n/**\n * Set generic input/output on a span using the ALREADY-NAMESPACED keys the\n * backend consumer reads. The OTel-SDK wrappers rely on the attribute-processor\n * to map raw `input.value` → `neatlogs.{kind}.input`; this plugin ships spans\n * directly (no processor), so it must emit the namespaced keys itself:\n * neatlogs.input.value / neatlogs.output.value (generic)\n * neatlogs.{kind}.input / neatlogs.{kind}.output (kind-specific)\n * We also keep the raw input.value/output.value for any consumer that maps it.\n */\nfunction setIO(arr: OtlpKeyValue[], kind: string, input?: string, output?: string): void {\n const k = kind.toLowerCase();\n if (input !== undefined) {\n push(arr, attrStr('input.value', input));\n push(arr, attrStr('neatlogs.input.value', input));\n push(arr, attrStr(`neatlogs.${k}.input`, input));\n }\n if (output !== undefined) {\n push(arr, attrStr('output.value', output));\n push(arr, attrStr('neatlogs.output.value', output));\n push(arr, attrStr(`neatlogs.${k}.output`, output));\n }\n}\n\n/** Flatten an opencode message's parts/content to readable text. */\nfunction messageText(info: any): string {\n if (!info) return '';\n if (typeof info.text === 'string') return info.text;\n const parts = info.parts ?? info.content;\n if (typeof parts === 'string') return parts;\n if (!Array.isArray(parts)) return '';\n const out: string[] = [];\n for (const p of parts) {\n if (typeof p === 'string') out.push(p);\n else if (p && typeof p === 'object' && typeof p.text === 'string') out.push(p.text);\n }\n return out.join('');\n}\n\nfunction safeStringify(value: unknown): string {\n if (typeof value === 'string') return value;\n try {\n return JSON.stringify(value) ?? '';\n } catch {\n return String(value);\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/opencode-trace-shipper.ts","../src/version.ts","../src/opencode-plugin.ts"],"sourcesContent":["/**\n * Direct OTLP trace shipper for the opencode plugin.\n *\n * opencode loads the plugin in-process but `opencode run` is short-lived — it\n * tears down the moment a session goes idle. The OpenTelemetry BatchSpanProcessor\n * (async, scheduled-delay export + a `beforeExit` shutdown) races that teardown,\n * dropping spans or leaving aborted half-sent requests. This shipper mirrors the\n * proven `neatlogs-claude-code` design instead: spans are queued, then `flush()`\n * does a single AWAITED `fetch(POST /v1/traces)` round-trip that completes before\n * the host process can exit. No batch processor, no exit-time race.\n *\n * Self-contained (inlined OTLP protobuf schema) so it adds no runtime file I/O.\n */\n\nimport protobuf from 'protobufjs';\nimport { __version__ } from './version.js';\n\nconst PACKAGE_NAME = 'neatlogs.opencode';\n\nexport interface OtlpKeyValue {\n key: string;\n value: {\n stringValue?: string;\n intValue?: string;\n doubleValue?: number;\n boolValue?: boolean;\n };\n}\n\nexport interface OtlpSpan {\n traceId: Uint8Array;\n spanId: Uint8Array;\n parentSpanId?: Uint8Array;\n name: string;\n /** OTLP SpanKind enum (0=unspecified, 1=internal, …). Neatlogs kind rides in attributes. */\n kind: number;\n startTimeUnixNano: string;\n endTimeUnixNano: string;\n attributes: OtlpKeyValue[];\n status?: { code: number; message?: string };\n}\n\n// Inlined OTLP proto definition — avoids .proto file I/O at runtime.\nconst OTLP_PROTO_JSON: protobuf.INamespace = {\n nested: {\n opentelemetry: {\n nested: {\n proto: {\n nested: {\n common: {\n nested: {\n v1: {\n nested: {\n AnyValue: {\n oneofs: {\n value: {\n oneof: [\n 'stringValue',\n 'boolValue',\n 'intValue',\n 'doubleValue',\n 'arrayValue',\n 'kvlistValue',\n 'bytesValue',\n ],\n },\n },\n fields: {\n stringValue: { type: 'string', id: 1 },\n boolValue: { type: 'bool', id: 2 },\n intValue: { type: 'int64', id: 3 },\n doubleValue: { type: 'double', id: 4 },\n arrayValue: { type: 'ArrayValue', id: 5 },\n kvlistValue: { type: 'KeyValueList', id: 6 },\n bytesValue: { type: 'bytes', id: 7 },\n },\n },\n ArrayValue: { fields: { values: { rule: 'repeated', type: 'AnyValue', id: 1 } } },\n KeyValueList: { fields: { values: { rule: 'repeated', type: 'KeyValue', id: 1 } } },\n KeyValue: {\n fields: { key: { type: 'string', id: 1 }, value: { type: 'AnyValue', id: 2 } },\n },\n InstrumentationScope: {\n fields: { name: { type: 'string', id: 1 }, version: { type: 'string', id: 2 } },\n },\n },\n },\n },\n },\n resource: {\n nested: {\n v1: {\n nested: {\n Resource: {\n fields: {\n attributes: {\n rule: 'repeated',\n type: 'opentelemetry.proto.common.v1.KeyValue',\n id: 1,\n },\n },\n },\n },\n },\n },\n },\n trace: {\n nested: {\n v1: {\n nested: {\n ResourceSpans: {\n fields: {\n resource: { type: 'opentelemetry.proto.resource.v1.Resource', id: 1 },\n scopeSpans: { rule: 'repeated', type: 'ScopeSpans', id: 2 },\n },\n },\n ScopeSpans: {\n fields: {\n scope: { type: 'opentelemetry.proto.common.v1.InstrumentationScope', id: 1 },\n spans: { rule: 'repeated', type: 'Span', id: 2 },\n },\n },\n Span: {\n fields: {\n traceId: { type: 'bytes', id: 1 },\n spanId: { type: 'bytes', id: 2 },\n traceState: { type: 'string', id: 3 },\n parentSpanId: { type: 'bytes', id: 4 },\n name: { type: 'string', id: 5 },\n kind: { type: 'SpanKind', id: 6 },\n startTimeUnixNano: { type: 'fixed64', id: 7 },\n endTimeUnixNano: { type: 'fixed64', id: 8 },\n attributes: {\n rule: 'repeated',\n type: 'opentelemetry.proto.common.v1.KeyValue',\n id: 9,\n },\n droppedAttributesCount: { type: 'uint32', id: 10 },\n status: { type: 'Status', id: 15 },\n },\n },\n Status: {\n fields: { message: { type: 'string', id: 2 }, code: { type: 'StatusCode', id: 3 } },\n },\n StatusCode: {\n values: { STATUS_CODE_UNSET: 0, STATUS_CODE_OK: 1, STATUS_CODE_ERROR: 2 },\n },\n SpanKind: {\n values: {\n SPAN_KIND_UNSPECIFIED: 0,\n SPAN_KIND_INTERNAL: 1,\n SPAN_KIND_SERVER: 2,\n SPAN_KIND_CLIENT: 3,\n SPAN_KIND_PRODUCER: 4,\n SPAN_KIND_CONSUMER: 5,\n },\n },\n },\n },\n },\n },\n collector: {\n nested: {\n trace: {\n nested: {\n v1: {\n nested: {\n ExportTraceServiceRequest: {\n fields: {\n resourceSpans: {\n rule: 'repeated',\n type: 'opentelemetry.proto.trace.v1.ResourceSpans',\n id: 1,\n },\n },\n },\n },\n },\n },\n },\n },\n },\n },\n },\n },\n },\n },\n};\n\nconst protoRoot = protobuf.Root.fromJSON(OTLP_PROTO_JSON);\nconst ExportTraceServiceRequest = protoRoot.lookupType(\n 'opentelemetry.proto.collector.trace.v1.ExportTraceServiceRequest',\n);\n\nexport const SpanStatusCode = { UNSET: 0, OK: 1, ERROR: 2 } as const;\n\n// ---------------------------------------------------------------------------\n// ID + time + attribute helpers\n// ---------------------------------------------------------------------------\n\nfunction randomBytes(length: number): Uint8Array {\n const out = new Uint8Array(length);\n const crypto = globalThis.crypto;\n if (crypto && typeof crypto.getRandomValues === 'function') {\n crypto.getRandomValues(out);\n return out;\n }\n for (let i = 0; i < out.length; i++) out[i] = Math.floor(Math.random() * 256);\n return out;\n}\n\nexport function generateTraceId(): Uint8Array {\n return randomBytes(16);\n}\n\nexport function generateSpanId(): Uint8Array {\n return randomBytes(8);\n}\n\nexport function bytesToHex(bytes: Uint8Array): string {\n return Array.from(bytes)\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('');\n}\n\nexport function nowNanoString(): string {\n return (BigInt(Date.now()) * 1_000_000n).toString();\n}\n\nexport function msToNanoString(ms: number): string {\n return (BigInt(Math.floor(ms)) * 1_000_000n).toString();\n}\n\nexport function attrStr(key: string, value: string | undefined): OtlpKeyValue | undefined {\n if (value === undefined || value === null) return undefined;\n return { key, value: { stringValue: String(value) } };\n}\n\nexport function attrInt(key: string, value: number | undefined): OtlpKeyValue | undefined {\n if (value === undefined || value === null || !Number.isFinite(value)) return undefined;\n return { key, value: { intValue: String(Math.trunc(value)) } };\n}\n\nexport function attrDouble(key: string, value: number | undefined): OtlpKeyValue | undefined {\n if (value === undefined || value === null || !Number.isFinite(value)) return undefined;\n return { key, value: { doubleValue: value } };\n}\n\nexport interface TraceShipperOptions {\n apiKey: string;\n endpoint: string;\n debug?: boolean;\n maxRetries?: number;\n workflowName?: string;\n}\n\nexport class TraceShipper {\n private apiKey: string;\n private endpoint: string;\n private debug: boolean;\n private maxRetries: number;\n workflowName: string;\n private queue: OtlpSpan[] = [];\n private prefix = '[neatlogs/opencode]';\n\n constructor(opts: TraceShipperOptions) {\n this.apiKey = opts.apiKey;\n this.endpoint = opts.endpoint.endsWith('/') ? opts.endpoint.slice(0, -1) : opts.endpoint;\n this.debug = !!opts.debug;\n this.maxRetries = opts.maxRetries ?? 3;\n this.workflowName = opts.workflowName || '';\n }\n\n enqueue(span: OtlpSpan): void {\n this.queue.push(span);\n }\n\n get pending(): number {\n return this.queue.length;\n }\n\n /**\n * Ship all queued spans in a single awaited POST. Resolves only once the HTTP\n * response is received (or all retries are exhausted) — so a short-lived host\n * can safely exit immediately after awaiting this.\n */\n async flush(): Promise<void> {\n if (this.queue.length === 0) return;\n if (!this.apiKey) {\n this.queue = [];\n return;\n }\n\n const spans = this.queue.splice(0);\n const payload = this.buildProtobuf(spans);\n const url = `${this.endpoint}/v1/traces`;\n\n if (this.debug) console.log(`${this.prefix} Shipping ${spans.length} spans to ${url}`);\n\n for (let attempt = 1; attempt <= this.maxRetries; attempt++) {\n try {\n const resp = await fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-protobuf',\n 'x-api-key': this.apiKey,\n },\n body: payload as any,\n });\n\n if (resp.ok) {\n if (this.debug) console.log(`${this.prefix} Shipped ${spans.length} spans`);\n return;\n }\n if (resp.status === 401) {\n console.warn(`${this.prefix} Invalid API key (401) — dropping ${spans.length} spans`);\n return;\n }\n if (resp.status < 500 && resp.status !== 429) {\n if (this.debug) console.warn(`${this.prefix} HTTP ${resp.status} — dropping spans`);\n return;\n }\n // 429 / 5xx → retry\n } catch (err) {\n if (this.debug) {\n console.warn(\n `${this.prefix} Attempt ${attempt}/${this.maxRetries}: ${(err as Error).message}`,\n );\n }\n }\n if (attempt < this.maxRetries) {\n await new Promise((r) => setTimeout(r, 500 * 2 ** (attempt - 1)));\n }\n }\n console.warn(`${this.prefix} Failed to ship ${spans.length} spans after ${this.maxRetries} attempts`);\n }\n\n private buildProtobuf(spans: OtlpSpan[]): Uint8Array {\n const protoSpans = spans.map((span) => ({\n traceId: span.traceId,\n spanId: span.spanId,\n parentSpanId: span.parentSpanId || undefined,\n name: span.name,\n kind: span.kind,\n startTimeUnixNano: nanoToLong(span.startTimeUnixNano),\n endTimeUnixNano: nanoToLong(span.endTimeUnixNano),\n attributes: span.attributes.map((a) => ({\n key: a.key,\n value:\n a.value.intValue !== undefined\n ? { intValue: nanoToLong(a.value.intValue) }\n : a.value,\n })),\n status: span.status ? { code: span.status.code, message: span.status.message } : undefined,\n }));\n\n const resourceAttributes: Array<{ key: string; value: { stringValue: string } }> = [\n { key: 'service.name', value: { stringValue: 'neatlogs.opencode' } },\n { key: 'service.version', value: { stringValue: __version__ } },\n ];\n if (this.workflowName) {\n resourceAttributes.push({\n key: 'neatlogs.workflow_name',\n value: { stringValue: this.workflowName },\n });\n }\n\n const message = {\n resourceSpans: [\n {\n resource: { attributes: resourceAttributes },\n scopeSpans: [\n {\n scope: { name: PACKAGE_NAME, version: __version__ },\n spans: protoSpans,\n },\n ],\n },\n ],\n };\n\n const errMsg = ExportTraceServiceRequest.verify(message);\n if (errMsg && this.debug) console.warn(`${this.prefix} Proto verify: ${errMsg}`);\n\n return ExportTraceServiceRequest.encode(ExportTraceServiceRequest.fromObject(message)).finish();\n }\n}\n\n/** protobufjs encodes fixed64/int64 from a {low,high,unsigned} Long-like. */\nfunction nanoToLong(nanoStr: string): { low: number; high: number; unsigned: boolean } {\n const big = BigInt(nanoStr);\n const low = Number(big & 0xffffffffn);\n const high = Number((big >> 32n) & 0xffffffffn);\n return { low, high, unsigned: true };\n}\n","/**\n * SDK version. Kept in sync with package.json by the `version:sync` script\n * (runs automatically on `prebuild`). Do not edit by hand — bump package.json.\n */\nexport const __version__ = '1.1.4';\n","/**\n * Neatlogs opencode plugin.\n *\n * opencode loads plugins from its config (`opencode.json` → `\"plugin\": [...]`)\n * or from local `.opencode/plugin/*.ts` files. A plugin is an async factory that\n * receives an app context and returns lifecycle hooks. This plugin instruments\n * opencode automatically — no per-call wiring — turning an opencode session into\n * a neatlogs span tree:\n *\n * AGENT opencode.session (one per user turn; parents that turn's spans)\n * ↳ LLM assistant turn (per completed assistant message)\n * ↳ TOOL tool execution (tool.execute.before → tool.execute.after)\n *\n * Every span carries `neatlogs.conversation.id` = the opencode session ID.\n *\n * Export model (mirrors @raindrop-ai/opencode-plugin and neatlogs-claude-code):\n * opencode loads the plugin in-process but `opencode run` is short-lived. Rather\n * than the OpenTelemetry BatchSpanProcessor (whose async, scheduled-delay export\n * + `beforeExit` shutdown races the teardown and drops spans), this plugin builds\n * spans directly and ships them via AWAITED `fetch(POST /v1/traces)` — and it\n * flushes after every completed assistant turn (incremental persistence) plus a\n * final flush on `session.idle`. A `neatlogs.trace.complete` marker is sent so\n * the backend enqueues the trace for finalization (simplification → UI).\n *\n * Setup — either:\n * • npm package, in opencode.json: `{ \"plugin\": [\"neatlogs/opencode\"] }`, OR\n * • local file `.opencode/plugin/neatlogs.ts`:\n * export { NeatlogsOpencodePlugin as default } from 'neatlogs/opencode';\n *\n * Env:\n * NEATLOGS_API_KEY required to export\n * NEATLOGS_ENDPOINT backend base URL (default https://ingest.neatlogs.com)\n * NEATLOGS_WORKFLOW_NAME logical grouping (default: \"opencode\")\n * NEATLOGS_CAPTURE_SYSTEM_PROMPT=true capture system prompt text (default off)\n */\n\nimport {\n TraceShipper,\n type OtlpSpan,\n type OtlpKeyValue,\n SpanStatusCode,\n generateTraceId,\n generateSpanId,\n nowNanoString,\n msToNanoString,\n attrStr,\n attrInt,\n attrDouble,\n} from './opencode-trace-shipper.js';\n\nconst DEFAULT_ENDPOINT = 'https://ingest.neatlogs.com';\n\n/** A span being built incrementally — ended (and shipped) later. */\ninterface OpenSpan {\n spanId: Uint8Array;\n parentSpanId?: Uint8Array;\n name: string;\n startNano: string;\n attributes: OtlpKeyValue[];\n}\n\ninterface SessionState {\n /** Per-session trace id — all spans in a session share it. */\n traceId: Uint8Array;\n /** The current turn's AGENT root span (created on chat.message, ended on idle). */\n rootSpan?: OpenSpan;\n /** Open TOOL spans keyed by callID → start time. */\n toolStarts: Map<string, { spanId: Uint8Array; startNano: string; tool: string; args: any }>;\n /** Accumulated assistant text per messageID (from text parts). */\n outputParts: Map<string, string>;\n /** Tool calls per assistant messageID (so a tool-only turn still has output). */\n toolCalls: Map<string, Array<{ name: string; input: any; callID: string }>>;\n /** assistant messageIDs already emitted (completion can fire repeatedly). */\n processed: Set<string>;\n /** Current user prompt (this turn's input). */\n currentInput: string;\n /** Captured system prompt (if enabled). */\n systemPrompt?: string;\n /** Latest assistant text — the AGENT root's output on close. */\n lastAssistantText: string;\n}\n\nexport const NeatlogsOpencodePlugin = async (_ctx: any): Promise<Record<string, any>> => {\n const apiKey = (process.env.NEATLOGS_API_KEY ?? '').trim();\n const endpoint = (process.env.NEATLOGS_ENDPOINT ?? DEFAULT_ENDPOINT).trim();\n const workflowName = process.env.NEATLOGS_WORKFLOW_NAME || 'opencode';\n const captureSystemPrompt =\n String(process.env.NEATLOGS_CAPTURE_SYSTEM_PROMPT || '').toLowerCase() === 'true';\n const debug = String(process.env.NEATLOGS_DEBUG || '').toLowerCase() === 'true';\n\n const shipper = new TraceShipper({ apiKey, endpoint, workflowName, debug });\n const sessions = new Map<string, SessionState>();\n\n function stateFor(sessionID: string): SessionState {\n let s = sessions.get(sessionID);\n if (!s) {\n s = {\n traceId: generateTraceId(),\n toolStarts: new Map(),\n outputParts: new Map(),\n toolCalls: new Map(),\n processed: new Set(),\n currentInput: '',\n lastAssistantText: '',\n };\n sessions.set(sessionID, s);\n }\n return s;\n }\n\n /** Start the per-turn AGENT root span (idempotent within a turn). */\n function startRoot(st: SessionState, sessionID: string): void {\n if (st.rootSpan) return;\n st.rootSpan = {\n spanId: generateSpanId(),\n name: 'opencode.session',\n startNano: nowNanoString(),\n attributes: [\n { key: 'neatlogs.span.kind', value: { stringValue: 'AGENT' } },\n { key: 'neatlogs.agent.framework', value: { stringValue: 'opencode' } },\n { key: 'neatlogs.conversation.id', value: { stringValue: sessionID } },\n ],\n };\n }\n\n /** End + enqueue the AGENT root, send the completion marker, and flush. */\n async function closeAndFlush(st: SessionState, sessionID: string): Promise<void> {\n if (st.rootSpan) {\n const attrs = st.rootSpan.attributes.slice();\n setIO(attrs, 'AGENT', st.currentInput || undefined, st.lastAssistantText || undefined);\n shipper.enqueue({\n traceId: st.traceId,\n spanId: st.rootSpan.spanId,\n name: st.rootSpan.name,\n kind: 1,\n startTimeUnixNano: st.rootSpan.startNano,\n endTimeUnixNano: nowNanoString(),\n attributes: attrs,\n status: { code: SpanStatusCode.OK },\n });\n // Completion marker — the backend only finalizes (simplifies → UI) a trace\n // once it sees a `neatlogs.trace.complete` span. Parented to the root.\n const m = nowNanoString();\n shipper.enqueue({\n traceId: st.traceId,\n spanId: generateSpanId(),\n parentSpanId: st.rootSpan.spanId,\n name: 'neatlogs.trace.complete',\n kind: 1,\n startTimeUnixNano: m,\n endTimeUnixNano: m,\n attributes: [\n { key: 'neatlogs.trace.complete', value: { boolValue: true } },\n { key: 'neatlogs.internal', value: { boolValue: true } },\n { key: 'neatlogs.span.kind', value: { stringValue: 'Neatlogs.INTERNAL' } },\n ],\n });\n st.rootSpan = undefined;\n }\n await shipper.flush();\n void sessionID;\n }\n\n return {\n /** Fired when the user submits a prompt — open the turn's AGENT root. */\n 'chat.message': async (_input: any, output: any) => {\n try {\n const sessionID = String(_input?.sessionID ?? output?.sessionID ?? '');\n if (!sessionID) return;\n const st = stateFor(sessionID);\n const parts = output?.parts ?? [];\n const text = Array.isArray(parts)\n ? parts\n .filter((p: any) => p?.type === 'text' && typeof p.text === 'string')\n .map((p: any) => p.text)\n .join('\\n')\n : '';\n if (text) st.currentInput = text;\n startRoot(st, sessionID);\n } catch {\n /* ignore */\n }\n },\n\n /** Capture the system prompt (opt-in). */\n 'experimental.chat.system.transform': async (_input: any, output: any) => {\n try {\n if (!captureSystemPrompt) return;\n const sessionID = String(_input?.sessionID ?? '');\n const parts = output?.system ?? output?.parts ?? output;\n const joined = Array.isArray(parts) ? parts.map((p: any) => (typeof p === 'string' ? p : p?.text ?? '')).join('\\n') : String(parts ?? '');\n if (sessionID && joined) stateFor(sessionID).systemPrompt = joined;\n } catch {\n /* ignore */\n }\n },\n\n /** Global event bus — message parts, assistant completions, session idle. */\n event: async ({ event }: { event: any }) => {\n try {\n await handleEvent(shipper, sessions, stateFor, startRoot, closeAndFlush, event);\n } catch {\n // never break opencode over tracing\n }\n },\n\n /** Tool start — record start time + args (span built atomically in `after`). */\n 'tool.execute.before': async (input: any, output: any) => {\n try {\n const sessionID = String(input?.sessionID ?? '');\n if (!sessionID) return;\n const st = stateFor(sessionID);\n startRoot(st, sessionID);\n const callID = String(input?.callID ?? input?.tool ?? '');\n st.toolStarts.set(callID, {\n spanId: generateSpanId(),\n startNano: nowNanoString(),\n tool: String(input?.tool ?? 'tool'),\n args: output?.args,\n });\n } catch {\n /* ignore */\n }\n },\n\n /** Tool end — enqueue the completed TOOL span (parented to the turn root). */\n 'tool.execute.after': async (input: any, result: any) => {\n try {\n const sessionID = String(input?.sessionID ?? '');\n if (!sessionID) return;\n const st = stateFor(sessionID);\n const callID = String(input?.callID ?? input?.tool ?? '');\n const start = st.toolStarts.get(callID);\n if (!start) return;\n st.toolStarts.delete(callID);\n\n const attrs: OtlpKeyValue[] = [\n { key: 'neatlogs.span.kind', value: { stringValue: 'TOOL' } },\n { key: 'neatlogs.tool.name', value: { stringValue: start.tool } },\n { key: 'neatlogs.conversation.id', value: { stringValue: sessionID } },\n ];\n if (start.args !== undefined) {\n // The shipper bypasses the SDK attribute-processor, so emit the\n // already-namespaced keys the backend consumer reads directly\n // (neatlogs.tool.input / .output and the generic neatlogs.input.value),\n // not the raw input.value/output.value the processor would map.\n setIO(attrs, 'TOOL', safeStringify(start.args), undefined);\n push(attrs, attrStr('neatlogs.tool.input', safeStringify(start.args)));\n }\n if (result?.title) push(attrs, attrStr('neatlogs.tool.title', String(result.title)));\n const out = result?.output ?? result?.result;\n if (out !== undefined) {\n const o = typeof out === 'string' ? out : safeStringify(out);\n setIO(attrs, 'TOOL', undefined, o);\n push(attrs, attrStr('neatlogs.tool.output', o));\n }\n if (result?.metadata !== undefined) {\n push(attrs, attrStr('neatlogs.tool.metadata', safeStringify(result.metadata)));\n }\n\n shipper.enqueue({\n traceId: st.traceId,\n spanId: start.spanId,\n parentSpanId: st.rootSpan?.spanId,\n name: `opencode.tool.${start.tool}`,\n kind: 1,\n startTimeUnixNano: start.startNano,\n endTimeUnixNano: nowNanoString(),\n attributes: attrs,\n status: { code: SpanStatusCode.OK },\n });\n } catch {\n /* ignore */\n }\n },\n };\n};\n\n// Convenience aliases so users can import under any common name.\nexport const neatlogsOpencodePlugin = NeatlogsOpencodePlugin;\nexport default NeatlogsOpencodePlugin;\n\n// ---------------------------------------------------------------------------\n// Event handling\n// ---------------------------------------------------------------------------\n\nfunction handleEvent(\n shipper: TraceShipper,\n sessions: Map<string, SessionState>,\n stateFor: (sessionID: string) => SessionState,\n startRoot: (st: SessionState, sessionID: string) => void,\n closeAndFlush: (st: SessionState, sessionID: string) => Promise<void>,\n event: any,\n): Promise<unknown> | undefined {\n const type = event?.type;\n const props = event?.properties ?? {};\n\n // Accumulate text + tool-call parts on an assistant message.\n if (type === 'message.part.updated' || type === 'message.part.completed') {\n const part = props.part ?? props;\n const messageID = part?.messageID ?? part?.message_id;\n const sessionID = part?.sessionID ?? props.sessionID;\n if (!messageID || !sessionID) return undefined;\n const st = stateFor(String(sessionID));\n if (part?.type === 'text' && typeof part?.text === 'string') {\n st.outputParts.set(String(messageID), part.text);\n } else if (part?.type === 'tool' && part?.tool) {\n const list = st.toolCalls.get(String(messageID)) ?? [];\n const callID = String(part.callID ?? part.tool);\n const input = part?.state?.input ?? {};\n const existing = list.find((t) => t.callID === callID);\n if (existing) existing.input = input;\n else list.push({ name: String(part.tool), input, callID });\n st.toolCalls.set(String(messageID), list);\n }\n return undefined;\n }\n\n // Assistant message completed → emit the LLM span, then flush this turn.\n if (type === 'message.updated' || type === 'message.completed') {\n const info = props.info ?? props.message ?? props;\n const sessionID = info?.sessionID ?? info?.session_id;\n if (!sessionID) return undefined;\n if (info?.role !== 'assistant') return undefined;\n const completed = info?.time?.completed ?? info?.completed;\n const id = String(info?.id ?? '');\n if (!completed || !id) return undefined;\n const st = stateFor(String(sessionID));\n if (st.processed.has(id)) return undefined;\n st.processed.add(id);\n startRoot(st, String(sessionID));\n emitLlmSpan(shipper, st, info, String(sessionID));\n // Incremental persistence: ship this turn's spans now (don't wait for idle).\n return shipper.flush().catch(() => undefined);\n }\n\n // Session finished → end root, send completion marker, final flush.\n if (type === 'session.idle' || type === 'session.deleted') {\n const sessionID = props.sessionID ?? props.info?.id;\n if (!sessionID) return undefined;\n const st = sessions.get(String(sessionID));\n if (!st) return undefined;\n st.toolStarts.clear();\n const p = closeAndFlush(st, String(sessionID));\n if (type === 'session.deleted') sessions.delete(String(sessionID));\n return p;\n }\n\n return undefined;\n}\n\nfunction emitLlmSpan(shipper: TraceShipper, st: SessionState, info: any, sessionID: string): void {\n const model = info?.modelID ?? info?.model ?? '';\n const provider = info?.providerID ?? info?.provider ?? '';\n\n const attrs: OtlpKeyValue[] = [\n { key: 'neatlogs.span.kind', value: { stringValue: 'LLM' } },\n { key: 'neatlogs.conversation.id', value: { stringValue: sessionID } },\n ];\n push(attrs, attrStr('neatlogs.llm.model_name', model ? String(model) : undefined));\n push(attrs, attrStr('neatlogs.llm.provider', provider ? String(provider) : undefined));\n\n let inIdx = 0;\n if (st.systemPrompt) {\n push(attrs, attrStr(`neatlogs.llm.input_messages.${inIdx}.role`, 'system'));\n push(attrs, attrStr(`neatlogs.llm.input_messages.${inIdx}.content`, st.systemPrompt));\n inIdx++;\n }\n if (st.currentInput) {\n push(attrs, attrStr(`neatlogs.llm.input_messages.${inIdx}.role`, 'user'));\n push(attrs, attrStr(`neatlogs.llm.input_messages.${inIdx}.content`, st.currentInput));\n setIO(attrs, 'LLM', st.currentInput, undefined);\n }\n\n const outText = st.outputParts.get(String(info?.id)) || messageText(info) || '';\n const toolCalls = st.toolCalls.get(String(info?.id)) ?? [];\n\n if (outText) {\n push(attrs, attrStr('neatlogs.llm.output_messages.0.role', 'assistant'));\n push(attrs, attrStr('neatlogs.llm.output_messages.0.content', outText));\n setIO(attrs, 'LLM', undefined, outText);\n st.lastAssistantText = outText;\n }\n // Tool-deciding turns often carry no text — render the tool call(s) as output.\n if (toolCalls.length) {\n toolCalls.forEach((tc, j) => {\n push(attrs, attrStr(`neatlogs.llm.tool_calls.${j}.name`, tc.name));\n push(attrs, attrStr(`neatlogs.llm.tool_calls.${j}.arguments`, safeStringify(tc.input ?? {})));\n });\n if (!outText) {\n const rendered = toolCalls.map((tc) => `→ ${tc.name}(${safeStringify(tc.input ?? {})})`).join('\\n');\n push(attrs, attrStr('neatlogs.llm.output_messages.0.role', 'assistant'));\n push(attrs, attrStr('neatlogs.llm.output_messages.0.content', rendered));\n setIO(attrs, 'LLM', undefined, rendered);\n }\n }\n\n // Tokens: opencode message tokens { input, output, reasoning, cache:{read,write} }\n const tokens = info?.tokens;\n if (tokens) {\n push(attrs, attrInt('neatlogs.llm.token_count.prompt', tokens.input));\n push(attrs, attrInt('neatlogs.llm.token_count.completion', tokens.output));\n if (tokens.input != null && tokens.output != null) {\n push(attrs, attrInt('neatlogs.llm.token_count.total', tokens.input + tokens.output));\n }\n push(attrs, attrInt('neatlogs.llm.token_count.reasoning', tokens.reasoning));\n push(attrs, attrInt('neatlogs.llm.token_count.cache_read', tokens.cache?.read));\n push(attrs, attrInt('neatlogs.llm.token_count.cache_write', tokens.cache?.write));\n }\n push(attrs, attrDouble('neatlogs.llm.cost_usd', info?.cost));\n\n // Use opencode's real start time when available (else now).\n const createdMs = info?.time?.created;\n const startNano = typeof createdMs === 'number' ? msToNanoString(Math.floor(createdMs)) : nowNanoString();\n\n shipper.enqueue({\n traceId: st.traceId,\n spanId: generateSpanId(),\n parentSpanId: st.rootSpan?.spanId,\n name: `opencode.llm.${model || 'model'}`,\n kind: 1,\n startTimeUnixNano: startNano,\n endTimeUnixNano: nowNanoString(),\n attributes: attrs,\n status: { code: SpanStatusCode.OK },\n });\n\n // Reset accumulated parts for the next turn.\n if (info?.id) {\n st.outputParts.delete(String(info.id));\n st.toolCalls.delete(String(info.id));\n }\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction push(arr: OtlpKeyValue[], kv: OtlpKeyValue | undefined): void {\n if (kv) arr.push(kv);\n}\n\n/**\n * Set generic input/output on a span using the ALREADY-NAMESPACED keys the\n * backend consumer reads. The OTel-SDK wrappers rely on the attribute-processor\n * to map raw `input.value` → `neatlogs.{kind}.input`; this plugin ships spans\n * directly (no processor), so it must emit the namespaced keys itself:\n * neatlogs.input.value / neatlogs.output.value (generic)\n * neatlogs.{kind}.input / neatlogs.{kind}.output (kind-specific)\n * We also keep the raw input.value/output.value for any consumer that maps it.\n */\nfunction setIO(arr: OtlpKeyValue[], kind: string, input?: string, output?: string): void {\n const k = kind.toLowerCase();\n if (input !== undefined) {\n push(arr, attrStr('input.value', input));\n push(arr, attrStr('neatlogs.input.value', input));\n push(arr, attrStr(`neatlogs.${k}.input`, input));\n }\n if (output !== undefined) {\n push(arr, attrStr('output.value', output));\n push(arr, attrStr('neatlogs.output.value', output));\n push(arr, attrStr(`neatlogs.${k}.output`, output));\n }\n}\n\n/** Flatten an opencode message's parts/content to readable text. */\nfunction messageText(info: any): string {\n if (!info) return '';\n if (typeof info.text === 'string') return info.text;\n const parts = info.parts ?? info.content;\n if (typeof parts === 'string') return parts;\n if (!Array.isArray(parts)) return '';\n const out: string[] = [];\n for (const p of parts) {\n if (typeof p === 'string') out.push(p);\n else if (p && typeof p === 'object' && typeof p.text === 'string') out.push(p.text);\n }\n return out.join('');\n}\n\nfunction safeStringify(value: unknown): string {\n if (typeof value === 'string') return value;\n try {\n return JSON.stringify(value) ?? '';\n } catch {\n return String(value);\n }\n}\n"],"mappings":";AAcA,OAAO,cAAc;;;ACVd,IAAM,cAAc;;;ADa3B,IAAM,eAAe;AA0BrB,IAAM,kBAAuC;AAAA,EAC3C,QAAQ;AAAA,IACN,eAAe;AAAA,MACb,QAAQ;AAAA,QACN,OAAO;AAAA,UACL,QAAQ;AAAA,YACN,QAAQ;AAAA,cACN,QAAQ;AAAA,gBACN,IAAI;AAAA,kBACF,QAAQ;AAAA,oBACN,UAAU;AAAA,sBACR,QAAQ;AAAA,wBACN,OAAO;AAAA,0BACL,OAAO;AAAA,4BACL;AAAA,4BACA;AAAA,4BACA;AAAA,4BACA;AAAA,4BACA;AAAA,4BACA;AAAA,4BACA;AAAA,0BACF;AAAA,wBACF;AAAA,sBACF;AAAA,sBACA,QAAQ;AAAA,wBACN,aAAa,EAAE,MAAM,UAAU,IAAI,EAAE;AAAA,wBACrC,WAAW,EAAE,MAAM,QAAQ,IAAI,EAAE;AAAA,wBACjC,UAAU,EAAE,MAAM,SAAS,IAAI,EAAE;AAAA,wBACjC,aAAa,EAAE,MAAM,UAAU,IAAI,EAAE;AAAA,wBACrC,YAAY,EAAE,MAAM,cAAc,IAAI,EAAE;AAAA,wBACxC,aAAa,EAAE,MAAM,gBAAgB,IAAI,EAAE;AAAA,wBAC3C,YAAY,EAAE,MAAM,SAAS,IAAI,EAAE;AAAA,sBACrC;AAAA,oBACF;AAAA,oBACA,YAAY,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,YAAY,MAAM,YAAY,IAAI,EAAE,EAAE,EAAE;AAAA,oBAChF,cAAc,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,YAAY,MAAM,YAAY,IAAI,EAAE,EAAE,EAAE;AAAA,oBAClF,UAAU;AAAA,sBACR,QAAQ,EAAE,KAAK,EAAE,MAAM,UAAU,IAAI,EAAE,GAAG,OAAO,EAAE,MAAM,YAAY,IAAI,EAAE,EAAE;AAAA,oBAC/E;AAAA,oBACA,sBAAsB;AAAA,sBACpB,QAAQ,EAAE,MAAM,EAAE,MAAM,UAAU,IAAI,EAAE,GAAG,SAAS,EAAE,MAAM,UAAU,IAAI,EAAE,EAAE;AAAA,oBAChF;AAAA,kBACF;AAAA,gBACF;AAAA,cACF;AAAA,YACF;AAAA,YACA,UAAU;AAAA,cACR,QAAQ;AAAA,gBACN,IAAI;AAAA,kBACF,QAAQ;AAAA,oBACN,UAAU;AAAA,sBACR,QAAQ;AAAA,wBACN,YAAY;AAAA,0BACV,MAAM;AAAA,0BACN,MAAM;AAAA,0BACN,IAAI;AAAA,wBACN;AAAA,sBACF;AAAA,oBACF;AAAA,kBACF;AAAA,gBACF;AAAA,cACF;AAAA,YACF;AAAA,YACA,OAAO;AAAA,cACL,QAAQ;AAAA,gBACN,IAAI;AAAA,kBACF,QAAQ;AAAA,oBACN,eAAe;AAAA,sBACb,QAAQ;AAAA,wBACN,UAAU,EAAE,MAAM,4CAA4C,IAAI,EAAE;AAAA,wBACpE,YAAY,EAAE,MAAM,YAAY,MAAM,cAAc,IAAI,EAAE;AAAA,sBAC5D;AAAA,oBACF;AAAA,oBACA,YAAY;AAAA,sBACV,QAAQ;AAAA,wBACN,OAAO,EAAE,MAAM,sDAAsD,IAAI,EAAE;AAAA,wBAC3E,OAAO,EAAE,MAAM,YAAY,MAAM,QAAQ,IAAI,EAAE;AAAA,sBACjD;AAAA,oBACF;AAAA,oBACA,MAAM;AAAA,sBACJ,QAAQ;AAAA,wBACN,SAAS,EAAE,MAAM,SAAS,IAAI,EAAE;AAAA,wBAChC,QAAQ,EAAE,MAAM,SAAS,IAAI,EAAE;AAAA,wBAC/B,YAAY,EAAE,MAAM,UAAU,IAAI,EAAE;AAAA,wBACpC,cAAc,EAAE,MAAM,SAAS,IAAI,EAAE;AAAA,wBACrC,MAAM,EAAE,MAAM,UAAU,IAAI,EAAE;AAAA,wBAC9B,MAAM,EAAE,MAAM,YAAY,IAAI,EAAE;AAAA,wBAChC,mBAAmB,EAAE,MAAM,WAAW,IAAI,EAAE;AAAA,wBAC5C,iBAAiB,EAAE,MAAM,WAAW,IAAI,EAAE;AAAA,wBAC1C,YAAY;AAAA,0BACV,MAAM;AAAA,0BACN,MAAM;AAAA,0BACN,IAAI;AAAA,wBACN;AAAA,wBACA,wBAAwB,EAAE,MAAM,UAAU,IAAI,GAAG;AAAA,wBACjD,QAAQ,EAAE,MAAM,UAAU,IAAI,GAAG;AAAA,sBACnC;AAAA,oBACF;AAAA,oBACA,QAAQ;AAAA,sBACN,QAAQ,EAAE,SAAS,EAAE,MAAM,UAAU,IAAI,EAAE,GAAG,MAAM,EAAE,MAAM,cAAc,IAAI,EAAE,EAAE;AAAA,oBACpF;AAAA,oBACA,YAAY;AAAA,sBACV,QAAQ,EAAE,mBAAmB,GAAG,gBAAgB,GAAG,mBAAmB,EAAE;AAAA,oBAC1E;AAAA,oBACA,UAAU;AAAA,sBACR,QAAQ;AAAA,wBACN,uBAAuB;AAAA,wBACvB,oBAAoB;AAAA,wBACpB,kBAAkB;AAAA,wBAClB,kBAAkB;AAAA,wBAClB,oBAAoB;AAAA,wBACpB,oBAAoB;AAAA,sBACtB;AAAA,oBACF;AAAA,kBACF;AAAA,gBACF;AAAA,cACF;AAAA,YACF;AAAA,YACA,WAAW;AAAA,cACT,QAAQ;AAAA,gBACN,OAAO;AAAA,kBACL,QAAQ;AAAA,oBACN,IAAI;AAAA,sBACF,QAAQ;AAAA,wBACN,2BAA2B;AAAA,0BACzB,QAAQ;AAAA,4BACN,eAAe;AAAA,8BACb,MAAM;AAAA,8BACN,MAAM;AAAA,8BACN,IAAI;AAAA,4BACN;AAAA,0BACF;AAAA,wBACF;AAAA,sBACF;AAAA,oBACF;AAAA,kBACF;AAAA,gBACF;AAAA,cACF;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AAEA,IAAM,YAAY,SAAS,KAAK,SAAS,eAAe;AACxD,IAAM,4BAA4B,UAAU;AAAA,EAC1C;AACF;AAEO,IAAM,iBAAiB,EAAE,OAAO,GAAG,IAAI,GAAG,OAAO,EAAE;AAM1D,SAAS,YAAY,QAA4B;AAC/C,QAAM,MAAM,IAAI,WAAW,MAAM;AACjC,QAAM,SAAS,WAAW;AAC1B,MAAI,UAAU,OAAO,OAAO,oBAAoB,YAAY;AAC1D,WAAO,gBAAgB,GAAG;AAC1B,WAAO;AAAA,EACT;AACA,WAAS,IAAI,GAAG,IAAI,IAAI,QAAQ,IAAK,KAAI,CAAC,IAAI,KAAK,MAAM,KAAK,OAAO,IAAI,GAAG;AAC5E,SAAO;AACT;AAEO,SAAS,kBAA8B;AAC5C,SAAO,YAAY,EAAE;AACvB;AAEO,SAAS,iBAA6B;AAC3C,SAAO,YAAY,CAAC;AACtB;AAQO,SAAS,gBAAwB;AACtC,UAAQ,OAAO,KAAK,IAAI,CAAC,IAAI,UAAY,SAAS;AACpD;AAEO,SAAS,eAAe,IAAoB;AACjD,UAAQ,OAAO,KAAK,MAAM,EAAE,CAAC,IAAI,UAAY,SAAS;AACxD;AAEO,SAAS,QAAQ,KAAa,OAAqD;AACxF,MAAI,UAAU,UAAa,UAAU,KAAM,QAAO;AAClD,SAAO,EAAE,KAAK,OAAO,EAAE,aAAa,OAAO,KAAK,EAAE,EAAE;AACtD;AAEO,SAAS,QAAQ,KAAa,OAAqD;AACxF,MAAI,UAAU,UAAa,UAAU,QAAQ,CAAC,OAAO,SAAS,KAAK,EAAG,QAAO;AAC7E,SAAO,EAAE,KAAK,OAAO,EAAE,UAAU,OAAO,KAAK,MAAM,KAAK,CAAC,EAAE,EAAE;AAC/D;AAEO,SAAS,WAAW,KAAa,OAAqD;AAC3F,MAAI,UAAU,UAAa,UAAU,QAAQ,CAAC,OAAO,SAAS,KAAK,EAAG,QAAO;AAC7E,SAAO,EAAE,KAAK,OAAO,EAAE,aAAa,MAAM,EAAE;AAC9C;AAUO,IAAM,eAAN,MAAmB;AAAA,EAChB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACR;AAAA,EACQ,QAAoB,CAAC;AAAA,EACrB,SAAS;AAAA,EAEjB,YAAY,MAA2B;AACrC,SAAK,SAAS,KAAK;AACnB,SAAK,WAAW,KAAK,SAAS,SAAS,GAAG,IAAI,KAAK,SAAS,MAAM,GAAG,EAAE,IAAI,KAAK;AAChF,SAAK,QAAQ,CAAC,CAAC,KAAK;AACpB,SAAK,aAAa,KAAK,cAAc;AACrC,SAAK,eAAe,KAAK,gBAAgB;AAAA,EAC3C;AAAA,EAEA,QAAQ,MAAsB;AAC5B,SAAK,MAAM,KAAK,IAAI;AAAA,EACtB;AAAA,EAEA,IAAI,UAAkB;AACpB,WAAO,KAAK,MAAM;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,QAAuB;AAC3B,QAAI,KAAK,MAAM,WAAW,EAAG;AAC7B,QAAI,CAAC,KAAK,QAAQ;AAChB,WAAK,QAAQ,CAAC;AACd;AAAA,IACF;AAEA,UAAM,QAAQ,KAAK,MAAM,OAAO,CAAC;AACjC,UAAM,UAAU,KAAK,cAAc,KAAK;AACxC,UAAM,MAAM,GAAG,KAAK,QAAQ;AAE5B,QAAI,KAAK,MAAO,SAAQ,IAAI,GAAG,KAAK,MAAM,aAAa,MAAM,MAAM,aAAa,GAAG,EAAE;AAErF,aAAS,UAAU,GAAG,WAAW,KAAK,YAAY,WAAW;AAC3D,UAAI;AACF,cAAM,OAAO,MAAM,MAAM,KAAK;AAAA,UAC5B,QAAQ;AAAA,UACR,SAAS;AAAA,YACP,gBAAgB;AAAA,YAChB,aAAa,KAAK;AAAA,UACpB;AAAA,UACA,MAAM;AAAA,QACR,CAAC;AAED,YAAI,KAAK,IAAI;AACX,cAAI,KAAK,MAAO,SAAQ,IAAI,GAAG,KAAK,MAAM,YAAY,MAAM,MAAM,QAAQ;AAC1E;AAAA,QACF;AACA,YAAI,KAAK,WAAW,KAAK;AACvB,kBAAQ,KAAK,GAAG,KAAK,MAAM,0CAAqC,MAAM,MAAM,QAAQ;AACpF;AAAA,QACF;AACA,YAAI,KAAK,SAAS,OAAO,KAAK,WAAW,KAAK;AAC5C,cAAI,KAAK,MAAO,SAAQ,KAAK,GAAG,KAAK,MAAM,SAAS,KAAK,MAAM,wBAAmB;AAClF;AAAA,QACF;AAAA,MAEF,SAAS,KAAK;AACZ,YAAI,KAAK,OAAO;AACd,kBAAQ;AAAA,YACN,GAAG,KAAK,MAAM,YAAY,OAAO,IAAI,KAAK,UAAU,KAAM,IAAc,OAAO;AAAA,UACjF;AAAA,QACF;AAAA,MACF;AACA,UAAI,UAAU,KAAK,YAAY;AAC7B,cAAM,IAAI,QAAQ,CAAC,MAAM,WAAW,GAAG,MAAM,MAAM,UAAU,EAAE,CAAC;AAAA,MAClE;AAAA,IACF;AACA,YAAQ,KAAK,GAAG,KAAK,MAAM,mBAAmB,MAAM,MAAM,gBAAgB,KAAK,UAAU,WAAW;AAAA,EACtG;AAAA,EAEQ,cAAc,OAA+B;AACnD,UAAM,aAAa,MAAM,IAAI,CAAC,UAAU;AAAA,MACtC,SAAS,KAAK;AAAA,MACd,QAAQ,KAAK;AAAA,MACb,cAAc,KAAK,gBAAgB;AAAA,MACnC,MAAM,KAAK;AAAA,MACX,MAAM,KAAK;AAAA,MACX,mBAAmB,WAAW,KAAK,iBAAiB;AAAA,MACpD,iBAAiB,WAAW,KAAK,eAAe;AAAA,MAChD,YAAY,KAAK,WAAW,IAAI,CAAC,OAAO;AAAA,QACtC,KAAK,EAAE;AAAA,QACP,OACE,EAAE,MAAM,aAAa,SACjB,EAAE,UAAU,WAAW,EAAE,MAAM,QAAQ,EAAE,IACzC,EAAE;AAAA,MACV,EAAE;AAAA,MACF,QAAQ,KAAK,SAAS,EAAE,MAAM,KAAK,OAAO,MAAM,SAAS,KAAK,OAAO,QAAQ,IAAI;AAAA,IACnF,EAAE;AAEF,UAAM,qBAA6E;AAAA,MACjF,EAAE,KAAK,gBAAgB,OAAO,EAAE,aAAa,oBAAoB,EAAE;AAAA,MACnE,EAAE,KAAK,mBAAmB,OAAO,EAAE,aAAa,YAAY,EAAE;AAAA,IAChE;AACA,QAAI,KAAK,cAAc;AACrB,yBAAmB,KAAK;AAAA,QACtB,KAAK;AAAA,QACL,OAAO,EAAE,aAAa,KAAK,aAAa;AAAA,MAC1C,CAAC;AAAA,IACH;AAEA,UAAM,UAAU;AAAA,MACd,eAAe;AAAA,QACb;AAAA,UACE,UAAU,EAAE,YAAY,mBAAmB;AAAA,UAC3C,YAAY;AAAA,YACV;AAAA,cACE,OAAO,EAAE,MAAM,cAAc,SAAS,YAAY;AAAA,cAClD,OAAO;AAAA,YACT;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,UAAM,SAAS,0BAA0B,OAAO,OAAO;AACvD,QAAI,UAAU,KAAK,MAAO,SAAQ,KAAK,GAAG,KAAK,MAAM,kBAAkB,MAAM,EAAE;AAE/E,WAAO,0BAA0B,OAAO,0BAA0B,WAAW,OAAO,CAAC,EAAE,OAAO;AAAA,EAChG;AACF;AAGA,SAAS,WAAW,SAAmE;AACrF,QAAM,MAAM,OAAO,OAAO;AAC1B,QAAM,MAAM,OAAO,MAAM,WAAW;AACpC,QAAM,OAAO,OAAQ,OAAO,MAAO,WAAW;AAC9C,SAAO,EAAE,KAAK,MAAM,UAAU,KAAK;AACrC;;;AExVA,IAAM,mBAAmB;AAgClB,IAAM,yBAAyB,OAAO,SAA4C;AACvF,QAAM,UAAU,QAAQ,IAAI,oBAAoB,IAAI,KAAK;AACzD,QAAM,YAAY,QAAQ,IAAI,qBAAqB,kBAAkB,KAAK;AAC1E,QAAM,eAAe,QAAQ,IAAI,0BAA0B;AAC3D,QAAM,sBACJ,OAAO,QAAQ,IAAI,kCAAkC,EAAE,EAAE,YAAY,MAAM;AAC7E,QAAM,QAAQ,OAAO,QAAQ,IAAI,kBAAkB,EAAE,EAAE,YAAY,MAAM;AAEzE,QAAM,UAAU,IAAI,aAAa,EAAE,QAAQ,UAAU,cAAc,MAAM,CAAC;AAC1E,QAAM,WAAW,oBAAI,IAA0B;AAE/C,WAAS,SAAS,WAAiC;AACjD,QAAI,IAAI,SAAS,IAAI,SAAS;AAC9B,QAAI,CAAC,GAAG;AACN,UAAI;AAAA,QACF,SAAS,gBAAgB;AAAA,QACzB,YAAY,oBAAI,IAAI;AAAA,QACpB,aAAa,oBAAI,IAAI;AAAA,QACrB,WAAW,oBAAI,IAAI;AAAA,QACnB,WAAW,oBAAI,IAAI;AAAA,QACnB,cAAc;AAAA,QACd,mBAAmB;AAAA,MACrB;AACA,eAAS,IAAI,WAAW,CAAC;AAAA,IAC3B;AACA,WAAO;AAAA,EACT;AAGA,WAAS,UAAU,IAAkB,WAAyB;AAC5D,QAAI,GAAG,SAAU;AACjB,OAAG,WAAW;AAAA,MACZ,QAAQ,eAAe;AAAA,MACvB,MAAM;AAAA,MACN,WAAW,cAAc;AAAA,MACzB,YAAY;AAAA,QACV,EAAE,KAAK,sBAAsB,OAAO,EAAE,aAAa,QAAQ,EAAE;AAAA,QAC7D,EAAE,KAAK,4BAA4B,OAAO,EAAE,aAAa,WAAW,EAAE;AAAA,QACtE,EAAE,KAAK,4BAA4B,OAAO,EAAE,aAAa,UAAU,EAAE;AAAA,MACvE;AAAA,IACF;AAAA,EACF;AAGA,iBAAe,cAAc,IAAkB,WAAkC;AAC/E,QAAI,GAAG,UAAU;AACf,YAAM,QAAQ,GAAG,SAAS,WAAW,MAAM;AAC3C,YAAM,OAAO,SAAS,GAAG,gBAAgB,QAAW,GAAG,qBAAqB,MAAS;AACrF,cAAQ,QAAQ;AAAA,QACd,SAAS,GAAG;AAAA,QACZ,QAAQ,GAAG,SAAS;AAAA,QACpB,MAAM,GAAG,SAAS;AAAA,QAClB,MAAM;AAAA,QACN,mBAAmB,GAAG,SAAS;AAAA,QAC/B,iBAAiB,cAAc;AAAA,QAC/B,YAAY;AAAA,QACZ,QAAQ,EAAE,MAAM,eAAe,GAAG;AAAA,MACpC,CAAC;AAGD,YAAM,IAAI,cAAc;AACxB,cAAQ,QAAQ;AAAA,QACd,SAAS,GAAG;AAAA,QACZ,QAAQ,eAAe;AAAA,QACvB,cAAc,GAAG,SAAS;AAAA,QAC1B,MAAM;AAAA,QACN,MAAM;AAAA,QACN,mBAAmB;AAAA,QACnB,iBAAiB;AAAA,QACjB,YAAY;AAAA,UACV,EAAE,KAAK,2BAA2B,OAAO,EAAE,WAAW,KAAK,EAAE;AAAA,UAC7D,EAAE,KAAK,qBAAqB,OAAO,EAAE,WAAW,KAAK,EAAE;AAAA,UACvD,EAAE,KAAK,sBAAsB,OAAO,EAAE,aAAa,oBAAoB,EAAE;AAAA,QAC3E;AAAA,MACF,CAAC;AACD,SAAG,WAAW;AAAA,IAChB;AACA,UAAM,QAAQ,MAAM;AACpB,SAAK;AAAA,EACP;AAEA,SAAO;AAAA;AAAA,IAEL,gBAAgB,OAAO,QAAa,WAAgB;AAClD,UAAI;AACF,cAAM,YAAY,OAAO,QAAQ,aAAa,QAAQ,aAAa,EAAE;AACrE,YAAI,CAAC,UAAW;AAChB,cAAM,KAAK,SAAS,SAAS;AAC7B,cAAM,QAAQ,QAAQ,SAAS,CAAC;AAChC,cAAM,OAAO,MAAM,QAAQ,KAAK,IAC5B,MACG,OAAO,CAAC,MAAW,GAAG,SAAS,UAAU,OAAO,EAAE,SAAS,QAAQ,EACnE,IAAI,CAAC,MAAW,EAAE,IAAI,EACtB,KAAK,IAAI,IACZ;AACJ,YAAI,KAAM,IAAG,eAAe;AAC5B,kBAAU,IAAI,SAAS;AAAA,MACzB,QAAQ;AAAA,MAER;AAAA,IACF;AAAA;AAAA,IAGA,sCAAsC,OAAO,QAAa,WAAgB;AACxE,UAAI;AACF,YAAI,CAAC,oBAAqB;AAC1B,cAAM,YAAY,OAAO,QAAQ,aAAa,EAAE;AAChD,cAAM,QAAQ,QAAQ,UAAU,QAAQ,SAAS;AACjD,cAAM,SAAS,MAAM,QAAQ,KAAK,IAAI,MAAM,IAAI,CAAC,MAAY,OAAO,MAAM,WAAW,IAAI,GAAG,QAAQ,EAAG,EAAE,KAAK,IAAI,IAAI,OAAO,SAAS,EAAE;AACxI,YAAI,aAAa,OAAQ,UAAS,SAAS,EAAE,eAAe;AAAA,MAC9D,QAAQ;AAAA,MAER;AAAA,IACF;AAAA;AAAA,IAGA,OAAO,OAAO,EAAE,MAAM,MAAsB;AAC1C,UAAI;AACF,cAAM,YAAY,SAAS,UAAU,UAAU,WAAW,eAAe,KAAK;AAAA,MAChF,QAAQ;AAAA,MAER;AAAA,IACF;AAAA;AAAA,IAGA,uBAAuB,OAAO,OAAY,WAAgB;AACxD,UAAI;AACF,cAAM,YAAY,OAAO,OAAO,aAAa,EAAE;AAC/C,YAAI,CAAC,UAAW;AAChB,cAAM,KAAK,SAAS,SAAS;AAC7B,kBAAU,IAAI,SAAS;AACvB,cAAM,SAAS,OAAO,OAAO,UAAU,OAAO,QAAQ,EAAE;AACxD,WAAG,WAAW,IAAI,QAAQ;AAAA,UACxB,QAAQ,eAAe;AAAA,UACvB,WAAW,cAAc;AAAA,UACzB,MAAM,OAAO,OAAO,QAAQ,MAAM;AAAA,UAClC,MAAM,QAAQ;AAAA,QAChB,CAAC;AAAA,MACH,QAAQ;AAAA,MAER;AAAA,IACF;AAAA;AAAA,IAGA,sBAAsB,OAAO,OAAY,WAAgB;AACvD,UAAI;AACF,cAAM,YAAY,OAAO,OAAO,aAAa,EAAE;AAC/C,YAAI,CAAC,UAAW;AAChB,cAAM,KAAK,SAAS,SAAS;AAC7B,cAAM,SAAS,OAAO,OAAO,UAAU,OAAO,QAAQ,EAAE;AACxD,cAAM,QAAQ,GAAG,WAAW,IAAI,MAAM;AACtC,YAAI,CAAC,MAAO;AACZ,WAAG,WAAW,OAAO,MAAM;AAE3B,cAAM,QAAwB;AAAA,UAC5B,EAAE,KAAK,sBAAsB,OAAO,EAAE,aAAa,OAAO,EAAE;AAAA,UAC5D,EAAE,KAAK,sBAAsB,OAAO,EAAE,aAAa,MAAM,KAAK,EAAE;AAAA,UAChE,EAAE,KAAK,4BAA4B,OAAO,EAAE,aAAa,UAAU,EAAE;AAAA,QACvE;AACA,YAAI,MAAM,SAAS,QAAW;AAK5B,gBAAM,OAAO,QAAQ,cAAc,MAAM,IAAI,GAAG,MAAS;AACzD,eAAK,OAAO,QAAQ,uBAAuB,cAAc,MAAM,IAAI,CAAC,CAAC;AAAA,QACvE;AACA,YAAI,QAAQ,MAAO,MAAK,OAAO,QAAQ,uBAAuB,OAAO,OAAO,KAAK,CAAC,CAAC;AACnF,cAAM,MAAM,QAAQ,UAAU,QAAQ;AACtC,YAAI,QAAQ,QAAW;AACrB,gBAAM,IAAI,OAAO,QAAQ,WAAW,MAAM,cAAc,GAAG;AAC3D,gBAAM,OAAO,QAAQ,QAAW,CAAC;AACjC,eAAK,OAAO,QAAQ,wBAAwB,CAAC,CAAC;AAAA,QAChD;AACA,YAAI,QAAQ,aAAa,QAAW;AAClC,eAAK,OAAO,QAAQ,0BAA0B,cAAc,OAAO,QAAQ,CAAC,CAAC;AAAA,QAC/E;AAEA,gBAAQ,QAAQ;AAAA,UACd,SAAS,GAAG;AAAA,UACZ,QAAQ,MAAM;AAAA,UACd,cAAc,GAAG,UAAU;AAAA,UAC3B,MAAM,iBAAiB,MAAM,IAAI;AAAA,UACjC,MAAM;AAAA,UACN,mBAAmB,MAAM;AAAA,UACzB,iBAAiB,cAAc;AAAA,UAC/B,YAAY;AAAA,UACZ,QAAQ,EAAE,MAAM,eAAe,GAAG;AAAA,QACpC,CAAC;AAAA,MACH,QAAQ;AAAA,MAER;AAAA,IACF;AAAA,EACF;AACF;AAGO,IAAM,yBAAyB;AACtC,IAAO,0BAAQ;AAMf,SAAS,YACP,SACA,UACA,UACA,WACA,eACA,OAC8B;AAC9B,QAAM,OAAO,OAAO;AACpB,QAAM,QAAQ,OAAO,cAAc,CAAC;AAGpC,MAAI,SAAS,0BAA0B,SAAS,0BAA0B;AACxE,UAAM,OAAO,MAAM,QAAQ;AAC3B,UAAM,YAAY,MAAM,aAAa,MAAM;AAC3C,UAAM,YAAY,MAAM,aAAa,MAAM;AAC3C,QAAI,CAAC,aAAa,CAAC,UAAW,QAAO;AACrC,UAAM,KAAK,SAAS,OAAO,SAAS,CAAC;AACrC,QAAI,MAAM,SAAS,UAAU,OAAO,MAAM,SAAS,UAAU;AAC3D,SAAG,YAAY,IAAI,OAAO,SAAS,GAAG,KAAK,IAAI;AAAA,IACjD,WAAW,MAAM,SAAS,UAAU,MAAM,MAAM;AAC9C,YAAM,OAAO,GAAG,UAAU,IAAI,OAAO,SAAS,CAAC,KAAK,CAAC;AACrD,YAAM,SAAS,OAAO,KAAK,UAAU,KAAK,IAAI;AAC9C,YAAM,QAAQ,MAAM,OAAO,SAAS,CAAC;AACrC,YAAM,WAAW,KAAK,KAAK,CAAC,MAAM,EAAE,WAAW,MAAM;AACrD,UAAI,SAAU,UAAS,QAAQ;AAAA,UAC1B,MAAK,KAAK,EAAE,MAAM,OAAO,KAAK,IAAI,GAAG,OAAO,OAAO,CAAC;AACzD,SAAG,UAAU,IAAI,OAAO,SAAS,GAAG,IAAI;AAAA,IAC1C;AACA,WAAO;AAAA,EACT;AAGA,MAAI,SAAS,qBAAqB,SAAS,qBAAqB;AAC9D,UAAM,OAAO,MAAM,QAAQ,MAAM,WAAW;AAC5C,UAAM,YAAY,MAAM,aAAa,MAAM;AAC3C,QAAI,CAAC,UAAW,QAAO;AACvB,QAAI,MAAM,SAAS,YAAa,QAAO;AACvC,UAAM,YAAY,MAAM,MAAM,aAAa,MAAM;AACjD,UAAM,KAAK,OAAO,MAAM,MAAM,EAAE;AAChC,QAAI,CAAC,aAAa,CAAC,GAAI,QAAO;AAC9B,UAAM,KAAK,SAAS,OAAO,SAAS,CAAC;AACrC,QAAI,GAAG,UAAU,IAAI,EAAE,EAAG,QAAO;AACjC,OAAG,UAAU,IAAI,EAAE;AACnB,cAAU,IAAI,OAAO,SAAS,CAAC;AAC/B,gBAAY,SAAS,IAAI,MAAM,OAAO,SAAS,CAAC;AAEhD,WAAO,QAAQ,MAAM,EAAE,MAAM,MAAM,MAAS;AAAA,EAC9C;AAGA,MAAI,SAAS,kBAAkB,SAAS,mBAAmB;AACzD,UAAM,YAAY,MAAM,aAAa,MAAM,MAAM;AACjD,QAAI,CAAC,UAAW,QAAO;AACvB,UAAM,KAAK,SAAS,IAAI,OAAO,SAAS,CAAC;AACzC,QAAI,CAAC,GAAI,QAAO;AAChB,OAAG,WAAW,MAAM;AACpB,UAAM,IAAI,cAAc,IAAI,OAAO,SAAS,CAAC;AAC7C,QAAI,SAAS,kBAAmB,UAAS,OAAO,OAAO,SAAS,CAAC;AACjE,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAEA,SAAS,YAAY,SAAuB,IAAkB,MAAW,WAAyB;AAChG,QAAM,QAAQ,MAAM,WAAW,MAAM,SAAS;AAC9C,QAAM,WAAW,MAAM,cAAc,MAAM,YAAY;AAEvD,QAAM,QAAwB;AAAA,IAC5B,EAAE,KAAK,sBAAsB,OAAO,EAAE,aAAa,MAAM,EAAE;AAAA,IAC3D,EAAE,KAAK,4BAA4B,OAAO,EAAE,aAAa,UAAU,EAAE;AAAA,EACvE;AACA,OAAK,OAAO,QAAQ,2BAA2B,QAAQ,OAAO,KAAK,IAAI,MAAS,CAAC;AACjF,OAAK,OAAO,QAAQ,yBAAyB,WAAW,OAAO,QAAQ,IAAI,MAAS,CAAC;AAErF,MAAI,QAAQ;AACZ,MAAI,GAAG,cAAc;AACnB,SAAK,OAAO,QAAQ,+BAA+B,KAAK,SAAS,QAAQ,CAAC;AAC1E,SAAK,OAAO,QAAQ,+BAA+B,KAAK,YAAY,GAAG,YAAY,CAAC;AACpF;AAAA,EACF;AACA,MAAI,GAAG,cAAc;AACnB,SAAK,OAAO,QAAQ,+BAA+B,KAAK,SAAS,MAAM,CAAC;AACxE,SAAK,OAAO,QAAQ,+BAA+B,KAAK,YAAY,GAAG,YAAY,CAAC;AACpF,UAAM,OAAO,OAAO,GAAG,cAAc,MAAS;AAAA,EAChD;AAEA,QAAM,UAAU,GAAG,YAAY,IAAI,OAAO,MAAM,EAAE,CAAC,KAAK,YAAY,IAAI,KAAK;AAC7E,QAAM,YAAY,GAAG,UAAU,IAAI,OAAO,MAAM,EAAE,CAAC,KAAK,CAAC;AAEzD,MAAI,SAAS;AACX,SAAK,OAAO,QAAQ,uCAAuC,WAAW,CAAC;AACvE,SAAK,OAAO,QAAQ,0CAA0C,OAAO,CAAC;AACtE,UAAM,OAAO,OAAO,QAAW,OAAO;AACtC,OAAG,oBAAoB;AAAA,EACzB;AAEA,MAAI,UAAU,QAAQ;AACpB,cAAU,QAAQ,CAAC,IAAI,MAAM;AAC3B,WAAK,OAAO,QAAQ,2BAA2B,CAAC,SAAS,GAAG,IAAI,CAAC;AACjE,WAAK,OAAO,QAAQ,2BAA2B,CAAC,cAAc,cAAc,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;AAAA,IAC9F,CAAC;AACD,QAAI,CAAC,SAAS;AACZ,YAAM,WAAW,UAAU,IAAI,CAAC,OAAO,UAAK,GAAG,IAAI,IAAI,cAAc,GAAG,SAAS,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,IAAI;AAClG,WAAK,OAAO,QAAQ,uCAAuC,WAAW,CAAC;AACvE,WAAK,OAAO,QAAQ,0CAA0C,QAAQ,CAAC;AACvE,YAAM,OAAO,OAAO,QAAW,QAAQ;AAAA,IACzC;AAAA,EACF;AAGA,QAAM,SAAS,MAAM;AACrB,MAAI,QAAQ;AACV,SAAK,OAAO,QAAQ,mCAAmC,OAAO,KAAK,CAAC;AACpE,SAAK,OAAO,QAAQ,uCAAuC,OAAO,MAAM,CAAC;AACzE,QAAI,OAAO,SAAS,QAAQ,OAAO,UAAU,MAAM;AACjD,WAAK,OAAO,QAAQ,kCAAkC,OAAO,QAAQ,OAAO,MAAM,CAAC;AAAA,IACrF;AACA,SAAK,OAAO,QAAQ,sCAAsC,OAAO,SAAS,CAAC;AAC3E,SAAK,OAAO,QAAQ,uCAAuC,OAAO,OAAO,IAAI,CAAC;AAC9E,SAAK,OAAO,QAAQ,wCAAwC,OAAO,OAAO,KAAK,CAAC;AAAA,EAClF;AACA,OAAK,OAAO,WAAW,yBAAyB,MAAM,IAAI,CAAC;AAG3D,QAAM,YAAY,MAAM,MAAM;AAC9B,QAAM,YAAY,OAAO,cAAc,WAAW,eAAe,KAAK,MAAM,SAAS,CAAC,IAAI,cAAc;AAExG,UAAQ,QAAQ;AAAA,IACd,SAAS,GAAG;AAAA,IACZ,QAAQ,eAAe;AAAA,IACvB,cAAc,GAAG,UAAU;AAAA,IAC3B,MAAM,gBAAgB,SAAS,OAAO;AAAA,IACtC,MAAM;AAAA,IACN,mBAAmB;AAAA,IACnB,iBAAiB,cAAc;AAAA,IAC/B,YAAY;AAAA,IACZ,QAAQ,EAAE,MAAM,eAAe,GAAG;AAAA,EACpC,CAAC;AAGD,MAAI,MAAM,IAAI;AACZ,OAAG,YAAY,OAAO,OAAO,KAAK,EAAE,CAAC;AACrC,OAAG,UAAU,OAAO,OAAO,KAAK,EAAE,CAAC;AAAA,EACrC;AACF;AAMA,SAAS,KAAK,KAAqB,IAAoC;AACrE,MAAI,GAAI,KAAI,KAAK,EAAE;AACrB;AAWA,SAAS,MAAM,KAAqB,MAAc,OAAgB,QAAuB;AACvF,QAAM,IAAI,KAAK,YAAY;AAC3B,MAAI,UAAU,QAAW;AACvB,SAAK,KAAK,QAAQ,eAAe,KAAK,CAAC;AACvC,SAAK,KAAK,QAAQ,wBAAwB,KAAK,CAAC;AAChD,SAAK,KAAK,QAAQ,YAAY,CAAC,UAAU,KAAK,CAAC;AAAA,EACjD;AACA,MAAI,WAAW,QAAW;AACxB,SAAK,KAAK,QAAQ,gBAAgB,MAAM,CAAC;AACzC,SAAK,KAAK,QAAQ,yBAAyB,MAAM,CAAC;AAClD,SAAK,KAAK,QAAQ,YAAY,CAAC,WAAW,MAAM,CAAC;AAAA,EACnD;AACF;AAGA,SAAS,YAAY,MAAmB;AACtC,MAAI,CAAC,KAAM,QAAO;AAClB,MAAI,OAAO,KAAK,SAAS,SAAU,QAAO,KAAK;AAC/C,QAAM,QAAQ,KAAK,SAAS,KAAK;AACjC,MAAI,OAAO,UAAU,SAAU,QAAO;AACtC,MAAI,CAAC,MAAM,QAAQ,KAAK,EAAG,QAAO;AAClC,QAAM,MAAgB,CAAC;AACvB,aAAW,KAAK,OAAO;AACrB,QAAI,OAAO,MAAM,SAAU,KAAI,KAAK,CAAC;AAAA,aAC5B,KAAK,OAAO,MAAM,YAAY,OAAO,EAAE,SAAS,SAAU,KAAI,KAAK,EAAE,IAAI;AAAA,EACpF;AACA,SAAO,IAAI,KAAK,EAAE;AACpB;AAEA,SAAS,cAAc,OAAwB;AAC7C,MAAI,OAAO,UAAU,SAAU,QAAO;AACtC,MAAI;AACF,WAAO,KAAK,UAAU,KAAK,KAAK;AAAA,EAClC,QAAQ;AACN,WAAO,OAAO,KAAK;AAAA,EACrB;AACF;","names":[]}
|
package/package.json
CHANGED