ai-otel-setup 1.0.4 → 1.0.5
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/cli.js +26 -5
- package/package.json +1 -1
package/cli.js
CHANGED
|
@@ -280,10 +280,32 @@ function stripLegacyCodexHook(text) {
|
|
|
280
280
|
|
|
281
281
|
function stripLegacyCodexHooksFlag(text) {
|
|
282
282
|
// Codex 把 [features].codex_hooks 重命名为 [features].hooks,旧 key 启动时触发 deprecation 警告
|
|
283
|
-
// 删 = true 这行,由
|
|
283
|
+
// 删 = true 这行,由 ensureFeaturesHooksTrue 统一写 hooks = true;= false 是显式 opt-out,保留
|
|
284
284
|
return text.replace(/^[ \t]*codex_hooks[ \t]*=[ \t]*true[ \t]*\r?\n/gm, "");
|
|
285
285
|
}
|
|
286
286
|
|
|
287
|
+
function ensureFeaturesHooksTrue(text) {
|
|
288
|
+
// 在用户已有的 [features] 块原地插入 hooks = true(如缺失);没有 [features] 就新建。
|
|
289
|
+
// 不能写在 managed 块里——TOML 1.0 禁止同名 table 重复声明,会被严格解析器拒绝。
|
|
290
|
+
const lines = text.split(/\r?\n/);
|
|
291
|
+
let featuresIdx = -1;
|
|
292
|
+
let hooksKeyExists = false;
|
|
293
|
+
for (let i = 0; i < lines.length; i++) {
|
|
294
|
+
if (featuresIdx === -1) {
|
|
295
|
+
if (/^\s*\[features\]\s*$/.test(lines[i])) featuresIdx = i;
|
|
296
|
+
continue;
|
|
297
|
+
}
|
|
298
|
+
if (/^\s*\[/.test(lines[i])) break; // 下一个 section,结束 [features] 主块扫描
|
|
299
|
+
if (/^[ \t]*hooks[ \t]*=/.test(lines[i])) hooksKeyExists = true;
|
|
300
|
+
}
|
|
301
|
+
if (featuresIdx >= 0) {
|
|
302
|
+
if (hooksKeyExists) return text; // 任何 hooks = ... 都尊重,不覆盖用户显式选择
|
|
303
|
+
lines.splice(featuresIdx + 1, 0, "hooks = true");
|
|
304
|
+
return lines.join("\n");
|
|
305
|
+
}
|
|
306
|
+
return text.trimEnd() + "\n\n[features]\nhooks = true\n";
|
|
307
|
+
}
|
|
308
|
+
|
|
287
309
|
function buildCodexManagedBlock(endpoint, hookDest, launcherDest) {
|
|
288
310
|
// exporter / trace_exporter / metrics_exporter 是 externally-tagged enum:
|
|
289
311
|
// - 写 scalar `exporter = "otlp-grpc"`:codex 解析为 unit variant,因为
|
|
@@ -293,11 +315,9 @@ function buildCodexManagedBlock(endpoint, hookDest, launcherDest) {
|
|
|
293
315
|
// - 只写 table `[otel.exporter."otlp-grpc"]`:✓ codex 把它解析为
|
|
294
316
|
// OtlpGrpc { endpoint },tag 来自 key 名。
|
|
295
317
|
// 官方 sample 之所以能 `exporter = "none"`,是因为 None 本身就是 unit variant。
|
|
318
|
+
// [features].hooks = true 由 ensureFeaturesHooksTrue 写到用户块里,避免重复声明 [features]
|
|
296
319
|
return [
|
|
297
320
|
CODEX_MANAGED_BEGIN,
|
|
298
|
-
"[features]",
|
|
299
|
-
"hooks = true",
|
|
300
|
-
"",
|
|
301
321
|
"[otel]",
|
|
302
322
|
'environment = "prod"',
|
|
303
323
|
"log_user_prompt = false",
|
|
@@ -336,11 +356,12 @@ function installCodex(home, endpoint) {
|
|
|
336
356
|
const bak = backup(configPath);
|
|
337
357
|
let existing = fs.existsSync(configPath) ? fs.readFileSync(configPath, "utf8") : "";
|
|
338
358
|
|
|
339
|
-
//
|
|
359
|
+
// 先剥离上一次的 managed 块和旧 schema 残留,再保证用户块里有 hooks = true
|
|
340
360
|
existing = stripCodexManagedBlock(existing);
|
|
341
361
|
existing = stripLegacyCodexOtel(existing);
|
|
342
362
|
existing = stripLegacyCodexHook(existing);
|
|
343
363
|
existing = stripLegacyCodexHooksFlag(existing);
|
|
364
|
+
existing = ensureFeaturesHooksTrue(existing);
|
|
344
365
|
|
|
345
366
|
// hook 同目录的 endpoint.json:hook 脚本运行时读它拿 logs endpoint,避免依赖
|
|
346
367
|
// shell 前缀注入 env(cmd.exe 不认那种语法,跨平台必须改成走文件)。
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ai-otel-setup",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.5",
|
|
4
4
|
"description": "One-shot installer for AI CLI OpenTelemetry forwarding. Writes Claude Code, Codex CLI, and Gemini CLI telemetry config in a single npx command.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"ai-otel-setup": "cli.js",
|