Files
cline/apps/cli/bun.mts
T
063ce7c06d feat(telemetry): enable release traces and preserve Langfuse user/session tracking (#13982)
* feat(telemetry): enable OTLP traces exporter in publish builds

Bakes OTEL_TRACES_EXPORTER=otlp into stable/nightly extension and CLI
publish builds. With the client trace pipeline (#13974) this turns on
cline-provider AI SDK trace emission at 100% task sampling, metadata-only
(no prompt/completion content).

Kill switches without a release: remote config openTelemetryTracesExporter
(extension) and the prod otel-collector's probabilistic sampler.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* feat(telemetry): record prompt/completion content on traced requests

Sets CLINE_TRACE_RECORD_CONTENT=true alongside the traces exporter, so
cline-provider traces carry full message content (recordInputs/
recordOutputs) instead of metadata only.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* ci: assert content-capture env is inlined into the packaged extension

Stable gates pre-publish (right after vsce package); nightly packages
inside publish-nightly.mjs so its check is post-publish detection.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(ci): gate nightly publication on content flag inlining

* fix(telemetry): cover combined release packaging and verify trace artifacts

* fix(ci): type trace artifact checker and assert missing bundle fixture

* fix(test): use the .exe outfile Bun compile produces on Windows

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(telemetry): propagate Langfuse identity attributes through OTLP

* refactor(telemetry): move Langfuse integration ownership to llms

* refactor(ci): remove brittle trace artifact checks

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: abeatrix <beatrix@cline.bot>
2026-09-16 17:50:22 -07:00

154 lines
4.3 KiB
TypeScript

import {
copyFileSync,
cpSync,
existsSync,
mkdirSync,
readdirSync,
statSync,
} from "node:fs";
import { dirname, join } from "node:path";
import { fileURLToPath } from "node:url";
import { $ } from "bun";
function defineProcessEnv(name: string): string {
return JSON.stringify(process.env[name] ?? "");
}
const sourcemap = Bun.env.CLINE_SOURCEMAPS === "1" ? "linked" : "none";
const rootDir = dirname(fileURLToPath(import.meta.url));
const repoRoot = join(rootDir, "../../");
const hubWebviewSourcePath = join(repoRoot, "apps/cline-hub/src/webview");
const hubWebviewDistPath = join(repoRoot, "apps/cline-hub/dist/webview");
const hubWebviewIndexPath = join(hubWebviewDistPath, "index.html");
const cliHubWebviewDistPath = join(rootDir, "dist/cline-hub/webview");
function newestFileMtimeMs(dir: string): number {
let newest = 0;
for (const entry of readdirSync(dir, { withFileTypes: true })) {
if (
entry.name === "node_modules" ||
entry.name === "dist" ||
entry.name === ".turbo"
) {
continue;
}
const path = join(dir, entry.name);
if (entry.isDirectory()) {
newest = Math.max(newest, newestFileMtimeMs(path));
} else if (entry.isFile()) {
newest = Math.max(newest, statSync(path).mtimeMs);
}
}
return newest;
}
function shouldBuildHubWebview(): boolean {
if (!existsSync(hubWebviewIndexPath)) {
return true;
}
try {
return (
newestFileMtimeMs(hubWebviewSourcePath) >
statSync(hubWebviewIndexPath).mtimeMs
);
} catch {
return true;
}
}
if (shouldBuildHubWebview()) {
console.log("Building Cline Hub webview...");
await $`bun -F @cline/cline-hub build:webview`.cwd(repoRoot);
}
const result = await Bun.build({
entrypoints: ["./src/index.ts"],
outdir: "./dist",
target: "node",
format: "esm",
sourcemap,
packages: "bundle", // Keep private workspace packages bundled so npm consumers do not need @cline/* at runtime.
external: [
// OpenTUI resolves a platform-specific native package at runtime.
// Bundling through that resolution path rewrites the import in a way that
// breaks Linux e2e runs from dist/. Keep React external too so OpenTUI and
// the CLI share one React runtime instead of ending up with duplicate hook
// dispatchers in the bundle.
"@opentui/core",
"@opentui/react",
"@opentui-ui/dialog",
"opentui-spinner",
"react",
"react/jsx-runtime",
"react/jsx-dev-runtime",
"react-devtools-core",
],
define: {
"process.env.NODE_ENV": '"production"',
...(process.env.TELEMETRY_SERVICE_API_KEY
? {
"process.env.TELEMETRY_SERVICE_API_KEY": defineProcessEnv(
"TELEMETRY_SERVICE_API_KEY",
),
}
: {}),
...(process.env.ERROR_SERVICE_API_KEY
? {
"process.env.ERROR_SERVICE_API_KEY": defineProcessEnv(
"ERROR_SERVICE_API_KEY",
),
}
: {}),
"process.env.OTEL_TELEMETRY_ENABLED": defineProcessEnv(
"OTEL_TELEMETRY_ENABLED",
),
"process.env.OTEL_EXPORTER_OTLP_ENDPOINT": defineProcessEnv(
"OTEL_EXPORTER_OTLP_ENDPOINT",
),
"process.env.OTEL_METRICS_EXPORTER": defineProcessEnv(
"OTEL_METRICS_EXPORTER",
),
"process.env.OTEL_LOGS_EXPORTER": defineProcessEnv("OTEL_LOGS_EXPORTER"),
"process.env.OTEL_TRACES_EXPORTER": defineProcessEnv(
"OTEL_TRACES_EXPORTER",
),
"process.env.CLINE_TRACE_RECORD_CONTENT": defineProcessEnv(
"CLINE_TRACE_RECORD_CONTENT",
),
"process.env.OTEL_EXPORTER_OTLP_PROTOCOL": defineProcessEnv(
"OTEL_EXPORTER_OTLP_PROTOCOL",
),
"process.env.OTEL_METRIC_EXPORT_INTERVAL": defineProcessEnv(
"OTEL_METRIC_EXPORT_INTERVAL",
),
"process.env.OTEL_EXPORTER_OTLP_HEADERS": defineProcessEnv(
"OTEL_EXPORTER_OTLP_HEADERS",
),
},
env: "OTEL_*",
banner:
'import { createRequire as __clineCreateRequire } from "node:module"; const require = __clineCreateRequire(import.meta.url);',
});
if (result.logs.length > 0) {
for (const log of result.logs) {
console.warn(log);
}
}
const coreBootstrapPath = join(
rootDir,
"../../sdk/packages/core/dist/extensions/plugin-sandbox-bootstrap.js",
);
const cliBootstrapPath = join(
rootDir,
"./dist/extensions/plugin-sandbox-bootstrap.js",
);
mkdirSync(dirname(cliBootstrapPath), { recursive: true });
copyFileSync(coreBootstrapPath, cliBootstrapPath);
if (existsSync(hubWebviewDistPath)) {
mkdirSync(dirname(cliHubWebviewDistPath), { recursive: true });
cpSync(hubWebviewDistPath, cliHubWebviewDistPath, { recursive: true });
}