oh-langfuse 0.1.53 → 0.1.55

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oh-langfuse",
3
- "version": "0.1.53",
3
+ "version": "0.1.55",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "Use npm scripts to configure Claude Code / OpenCode / Codex with Langfuse tracing.",
@@ -1,190 +1,190 @@
1
- import fs from "node:fs";
2
- import path from "node:path";
3
- import readline from "node:readline";
4
- import { spawnSync } from "node:child_process";
5
- import { fileURLToPath } from "node:url";
6
- import { extractVersionFromNpmMetadata, isNewerVersion } from "./update-utils.mjs";
7
- import { getRuntimeInstallRecord } from "./runtime-state-utils.mjs";
8
-
9
- const rootDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
10
- const packageJson = JSON.parse(fs.readFileSync(path.join(rootDir, "package.json"), "utf8"));
11
- const ALLOWED_TARGETS = new Set(["claude", "opencode", "codex"]);
12
-
13
- const colorEnabled = process.stdout.isTTY && process.env.NO_COLOR !== "1";
14
- const ansi = (code) => (colorEnabled ? `\x1b[${code}m` : "");
15
- const t = {
16
- reset: ansi(0),
17
- bold: ansi(1),
18
- cyan: ansi("96"),
19
- green: ansi("92"),
20
- gold: ansi("93"),
21
- };
22
-
23
- function paint(text, ...styles) {
24
- if (!colorEnabled) return text;
25
- return `${styles.join("")}${text}${t.reset}`;
26
- }
27
-
28
- function parseArgs(argv) {
29
- const args = { _: [] };
30
- for (const raw of argv) {
31
- if (!raw.startsWith("--")) {
32
- args._.push(raw);
33
- continue;
34
- }
35
- const eq = raw.indexOf("=");
36
- if (eq === -1) args[raw.slice(2)] = true;
37
- else args[raw.slice(2, eq)] = raw.slice(eq + 1);
38
- }
39
- return args;
40
- }
41
-
42
- async function latestVersion(registry = "https://registry.npmjs.org") {
43
- const base = registry.replace(/\/+$/, "");
44
- const response = await fetch(`${base}/oh-langfuse`, { headers: { accept: "application/json" } });
45
- if (!response.ok) throw new Error(`npm registry ${response.status} ${response.statusText}`);
46
- return extractVersionFromNpmMetadata(await response.json());
47
- }
48
-
49
- function question(text) {
50
- const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
51
- return new Promise((resolve) => {
52
- rl.question(text, (answer) => {
53
- rl.close();
54
- resolve(String(answer || "").trim());
55
- });
56
- });
57
- }
58
-
59
- function npxCommand() {
60
- return process.platform === "win32" ? "npx.cmd" : "npx";
61
- }
62
-
63
- function runNpx(args, options = {}) {
64
- if (process.platform === "win32") {
65
- return spawnSync("cmd.exe", ["/d", "/s", "/c", npxCommand(), ...args], {
66
- ...options,
67
- windowsHide: true,
68
- });
69
- }
70
- return spawnSync(npxCommand(), args, {
71
- ...options,
72
- windowsHide: true,
73
- });
74
- }
75
-
76
- function targetLabel(target) {
77
- if (target === "claude") return "Claude";
78
- if (target === "codex") return "Codex";
79
- if (target === "opencode") return "OpenCode";
80
- return target;
81
- }
82
-
83
- function printUpdateAvailable(target, message, updateCommand) {
84
- const label = targetLabel(target);
85
- console.log(paint(`[UPDATE] \u68c0\u6d4b\u5230 ${label} Langfuse \u53ef\u66f4\u65b0`, t.bold, t.gold));
86
- console.log(`[INFO] ${message}`);
87
- console.log(`${paint("[CMD]", t.bold, t.cyan)} ${updateCommand}`);
88
- }
89
-
90
- function printUpdateCommand(target, updateCommand) {
91
- const label = targetLabel(target);
92
- console.log(paint(`[UPDATE] \u6b63\u5728\u6267\u884c\u66f4\u65b0\u547d\u4ee4\uff1a${label} Langfuse`, t.bold, t.cyan));
93
- console.log(`${paint("[CMD]", t.bold, t.cyan)} ${updateCommand}`);
94
- }
95
-
96
- function shouldPrintStartupStatus(args, env = process.env) {
97
- const raw = String(env.OH_LANGFUSE_AUTO_UPDATE_STATUS || "").trim().toLowerCase();
98
- return !!(args["startup-status"] || args.startupStatus || /^(1|true|yes|on)$/i.test(raw));
99
- }
100
-
101
- function printAlreadyCurrent(target, version) {
102
- const label = targetLabel(target);
103
- console.log(paint(`[OK] ${label} Langfuse \u5df2\u662f\u6700\u65b0\uff1a${packageJson.name}@${version}`, t.bold, t.green));
104
- }
105
-
106
- function runUpdate(target, args) {
107
- const updateArgs = ["-y", "oh-langfuse@latest", "update", target];
108
- if (args["skip-check"]) updateArgs.push("--skip-check");
109
- if (args.npmRegistry) updateArgs.push(`--npmRegistry=${args.npmRegistry}`);
110
- if (args.pipIndexUrl) updateArgs.push(`--pipIndexUrl=${args.pipIndexUrl}`);
111
- const result = runNpx(updateArgs, {
112
- stdio: "inherit",
113
- timeout: 900000,
114
- });
115
- return result.status ?? (result.error ? 1 : 0);
116
- }
117
-
118
- function autoUpdateMode(args, env = process.env) {
119
- const raw = String(env.OH_LANGFUSE_AUTO_UPDATE || "").trim().toLowerCase();
120
- if (/^(0|false|no|off)$/i.test(raw)) return "off";
121
- if (args.yes || args.y || raw === "auto" || raw === "yes" || raw === "1" || raw === "true") return "auto";
122
- if (args["notify-only"] || args.notifyOnly || raw === "notify" || raw === "prompt") return "notify";
123
- return "ask";
124
- }
125
-
126
- async function main() {
127
- const args = parseArgs(process.argv.slice(2));
128
- const mode = autoUpdateMode(args);
129
- if (mode === "off") return 0;
130
-
131
- const target = String(args._[0] || "").trim().toLowerCase();
132
- if (!ALLOWED_TARGETS.has(target)) {
133
- throw new Error("Usage: oh-langfuse auto-update <claude|opencode|codex>");
134
- }
135
-
136
- let latest;
137
- try {
138
- latest = await latestVersion(args.npmRegistry);
139
- } catch (error) {
140
- if (args.verbose) console.log(`[INFO] oh-langfuse update check skipped: ${error.message}`);
141
- return 0;
142
- }
143
-
144
- const record = getRuntimeInstallRecord(target);
145
- const installedVersion = record?.packageVersion || record?.version || "";
146
- const needsUpdate = installedVersion ? isNewerVersion(latest, installedVersion) : isNewerVersion(latest, packageJson.version);
147
- if (!needsUpdate) {
148
- if (shouldPrintStartupStatus(args)) printAlreadyCurrent(target, installedVersion || packageJson.version);
149
- return 0;
150
- }
151
-
152
- const message = installedVersion
153
- ? `oh-langfuse ${target} runtime update available: ${installedVersion} -> ${latest}.`
154
- : `oh-langfuse ${target} runtime may need update. Latest package: ${latest}.`;
155
- const updateCommand = `npx oh-langfuse@latest update ${target}`;
156
-
157
- if (mode === "notify") {
158
- printUpdateAvailable(target, message, updateCommand);
159
- console.log(`[INFO] To update safely, close the agent and run: ${updateCommand}`);
160
- return 0;
161
- }
162
-
163
- if (mode === "auto") {
164
- printUpdateAvailable(target, message, updateCommand);
165
- printUpdateCommand(target, updateCommand);
166
- const code = runUpdate(target, args);
167
- return args.strict ? code : 0;
168
- }
169
-
170
- if (!process.stdin.isTTY || !process.stdout.isTTY) {
171
- printUpdateAvailable(target, message, updateCommand);
172
- return 0;
173
- }
174
-
175
- printUpdateAvailable(target, message, updateCommand);
176
- const answer = await question(`${paint("[CONFIRM]", t.bold, t.gold)} Update now? (y/N) `);
177
- if (!/^(y|yes)$/i.test(answer)) return 0;
178
- printUpdateCommand(target, updateCommand);
179
- const code = runUpdate(target, args);
180
- return args.strict ? code : 0;
181
- }
182
-
183
- main()
184
- .then((code) => {
185
- process.exitCode = code;
186
- })
187
- .catch((error) => {
188
- console.error(`[WARN] oh-langfuse auto-update skipped: ${error?.message || String(error)}`);
189
- process.exitCode = 0;
190
- });
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import readline from "node:readline";
4
+ import { spawnSync } from "node:child_process";
5
+ import { fileURLToPath } from "node:url";
6
+ import { extractVersionFromNpmMetadata, isNewerVersion } from "./update-utils.mjs";
7
+ import { getRuntimeInstallRecord } from "./runtime-state-utils.mjs";
8
+
9
+ const rootDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
10
+ const packageJson = JSON.parse(fs.readFileSync(path.join(rootDir, "package.json"), "utf8"));
11
+ const ALLOWED_TARGETS = new Set(["claude", "opencode", "codex"]);
12
+
13
+ const colorEnabled = process.stdout.isTTY && process.env.NO_COLOR !== "1";
14
+ const ansi = (code) => (colorEnabled ? `\x1b[${code}m` : "");
15
+ const t = {
16
+ reset: ansi(0),
17
+ bold: ansi(1),
18
+ cyan: ansi("96"),
19
+ green: ansi("92"),
20
+ gold: ansi("93"),
21
+ };
22
+
23
+ function paint(text, ...styles) {
24
+ if (!colorEnabled) return text;
25
+ return `${styles.join("")}${text}${t.reset}`;
26
+ }
27
+
28
+ function parseArgs(argv) {
29
+ const args = { _: [] };
30
+ for (const raw of argv) {
31
+ if (!raw.startsWith("--")) {
32
+ args._.push(raw);
33
+ continue;
34
+ }
35
+ const eq = raw.indexOf("=");
36
+ if (eq === -1) args[raw.slice(2)] = true;
37
+ else args[raw.slice(2, eq)] = raw.slice(eq + 1);
38
+ }
39
+ return args;
40
+ }
41
+
42
+ async function latestVersion(registry = "https://registry.npmjs.org") {
43
+ const base = registry.replace(/\/+$/, "");
44
+ const response = await fetch(`${base}/oh-langfuse`, { headers: { accept: "application/json" } });
45
+ if (!response.ok) throw new Error(`npm registry ${response.status} ${response.statusText}`);
46
+ return extractVersionFromNpmMetadata(await response.json());
47
+ }
48
+
49
+ function question(text) {
50
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
51
+ return new Promise((resolve) => {
52
+ rl.question(text, (answer) => {
53
+ rl.close();
54
+ resolve(String(answer || "").trim());
55
+ });
56
+ });
57
+ }
58
+
59
+ function npxCommand() {
60
+ return process.platform === "win32" ? "npx.cmd" : "npx";
61
+ }
62
+
63
+ function runNpx(args, options = {}) {
64
+ if (process.platform === "win32") {
65
+ return spawnSync("cmd.exe", ["/d", "/s", "/c", npxCommand(), ...args], {
66
+ ...options,
67
+ windowsHide: true,
68
+ });
69
+ }
70
+ return spawnSync(npxCommand(), args, {
71
+ ...options,
72
+ windowsHide: true,
73
+ });
74
+ }
75
+
76
+ function targetLabel(target) {
77
+ if (target === "claude") return "Claude";
78
+ if (target === "codex") return "Codex";
79
+ if (target === "opencode") return "OpenCode";
80
+ return target;
81
+ }
82
+
83
+ function printUpdateAvailable(target, message, updateCommand) {
84
+ const label = targetLabel(target);
85
+ console.log(paint(`[UPDATE] \u68c0\u6d4b\u5230 ${label} Langfuse \u53ef\u66f4\u65b0`, t.bold, t.gold));
86
+ console.log(`[INFO] ${message}`);
87
+ console.log(`${paint("[CMD]", t.bold, t.cyan)} ${updateCommand}`);
88
+ }
89
+
90
+ function printUpdateCommand(target, updateCommand) {
91
+ const label = targetLabel(target);
92
+ console.log(paint(`[UPDATE] \u6b63\u5728\u6267\u884c\u66f4\u65b0\u547d\u4ee4\uff1a${label} Langfuse`, t.bold, t.cyan));
93
+ console.log(`${paint("[CMD]", t.bold, t.cyan)} ${updateCommand}`);
94
+ }
95
+
96
+ function shouldPrintStartupStatus(args, env = process.env) {
97
+ const raw = String(env.OH_LANGFUSE_AUTO_UPDATE_STATUS || "").trim().toLowerCase();
98
+ return !!(args["startup-status"] || args.startupStatus || /^(1|true|yes|on)$/i.test(raw));
99
+ }
100
+
101
+ function printAlreadyCurrent(target, version) {
102
+ const label = targetLabel(target);
103
+ console.log(paint(`[OK] ${label} Langfuse \u5df2\u662f\u6700\u65b0\uff1a${packageJson.name}@${version}`, t.bold, t.green));
104
+ }
105
+
106
+ function runUpdate(target, args) {
107
+ const updateArgs = ["-y", "oh-langfuse@latest", "update", target];
108
+ if (args["skip-check"]) updateArgs.push("--skip-check");
109
+ if (args.npmRegistry) updateArgs.push(`--npmRegistry=${args.npmRegistry}`);
110
+ if (args.pipIndexUrl) updateArgs.push(`--pipIndexUrl=${args.pipIndexUrl}`);
111
+ const result = runNpx(updateArgs, {
112
+ stdio: "inherit",
113
+ timeout: 900000,
114
+ });
115
+ return result.status ?? (result.error ? 1 : 0);
116
+ }
117
+
118
+ function autoUpdateMode(args, env = process.env) {
119
+ const raw = String(env.OH_LANGFUSE_AUTO_UPDATE || "").trim().toLowerCase();
120
+ if (/^(0|false|no|off)$/i.test(raw)) return "off";
121
+ if (args.yes || args.y || raw === "auto" || raw === "yes" || raw === "1" || raw === "true") return "auto";
122
+ if (args["notify-only"] || args.notifyOnly || raw === "notify" || raw === "prompt") return "notify";
123
+ return "ask";
124
+ }
125
+
126
+ async function main() {
127
+ const args = parseArgs(process.argv.slice(2));
128
+ const mode = autoUpdateMode(args);
129
+ if (mode === "off") return 0;
130
+
131
+ const target = String(args._[0] || "").trim().toLowerCase();
132
+ if (!ALLOWED_TARGETS.has(target)) {
133
+ throw new Error("Usage: oh-langfuse auto-update <claude|opencode|codex>");
134
+ }
135
+
136
+ let latest;
137
+ try {
138
+ latest = await latestVersion(args.npmRegistry);
139
+ } catch (error) {
140
+ if (args.verbose) console.log(`[INFO] oh-langfuse update check skipped: ${error.message}`);
141
+ return 0;
142
+ }
143
+
144
+ const record = getRuntimeInstallRecord(target);
145
+ const installedVersion = record?.packageVersion || record?.version || "";
146
+ const needsUpdate = installedVersion ? isNewerVersion(latest, installedVersion) : isNewerVersion(latest, packageJson.version);
147
+ if (!needsUpdate) {
148
+ if (shouldPrintStartupStatus(args)) printAlreadyCurrent(target, installedVersion || packageJson.version);
149
+ return 0;
150
+ }
151
+
152
+ const message = installedVersion
153
+ ? `oh-langfuse ${target} runtime update available: ${installedVersion} -> ${latest}.`
154
+ : `oh-langfuse ${target} runtime may need update. Latest package: ${latest}.`;
155
+ const updateCommand = `npx oh-langfuse@latest update ${target}`;
156
+
157
+ if (mode === "notify") {
158
+ printUpdateAvailable(target, message, updateCommand);
159
+ console.log(`[INFO] To update safely, close the agent and run: ${updateCommand}`);
160
+ return 0;
161
+ }
162
+
163
+ if (mode === "auto") {
164
+ printUpdateAvailable(target, message, updateCommand);
165
+ printUpdateCommand(target, updateCommand);
166
+ const code = runUpdate(target, args);
167
+ return args.strict ? code : 0;
168
+ }
169
+
170
+ if (!process.stdin.isTTY || !process.stdout.isTTY) {
171
+ printUpdateAvailable(target, message, updateCommand);
172
+ return 0;
173
+ }
174
+
175
+ printUpdateAvailable(target, message, updateCommand);
176
+ const answer = await question(`${paint("[CONFIRM]", t.bold, t.gold)} Update now? (y/N) `);
177
+ if (!/^(y|yes)$/i.test(answer)) return 0;
178
+ printUpdateCommand(target, updateCommand);
179
+ const code = runUpdate(target, args);
180
+ return args.strict ? code : 0;
181
+ }
182
+
183
+ main()
184
+ .then((code) => {
185
+ process.exitCode = code;
186
+ })
187
+ .catch((error) => {
188
+ console.error(`[WARN] oh-langfuse auto-update skipped: ${error?.message || String(error)}`);
189
+ process.exitCode = 0;
190
+ });
@@ -49,15 +49,15 @@ function venvPython(codexHome) {
49
49
  : path.join(codexHome, "langfuse-venv", "bin", "python");
50
50
  }
51
51
 
52
- function configHasNotify(configText) {
53
- const firstSection = configText.search(/^\s*\[/m);
54
- const topLevel = firstSection === -1 ? configText : configText.slice(0, firstSection);
55
- return /^\s*notify\s*=.*codex_langfuse_notify\.py/m.test(topLevel);
56
- }
57
-
58
- function addResult(results, item, ok, detail, fix = "", options = {}) {
59
- results.push({ item, ok, detail, fix, required: options.required !== false });
60
- }
52
+ function configHasNotify(configText) {
53
+ const firstSection = configText.search(/^\s*\[/m);
54
+ const topLevel = firstSection === -1 ? configText : configText.slice(0, firstSection);
55
+ return /^\s*notify\s*=.*codex_langfuse_notify\.py/m.test(topLevel);
56
+ }
57
+
58
+ function addResult(results, item, ok, detail, fix = "", options = {}) {
59
+ results.push({ item, ok, detail, fix, required: options.required !== false });
60
+ }
61
61
 
62
62
  function main() {
63
63
  const codexHome = process.env.CODEX_HOME || path.join(os.homedir(), ".codex");
@@ -72,80 +72,80 @@ function main() {
72
72
  const python = commandOk(process.platform === "win32" ? "python" : "python3", ["--version"]);
73
73
  const langfuseImport = commandOk(hookPython, ["-c", "import langfuse; print('langfuse ok')"]);
74
74
 
75
- const logPath = path.join(codexHome, "langfuse", "codex_langfuse_notify.log");
76
- const logText = fs.existsSync(logPath) ? stripBom(fs.readFileSync(logPath, "utf8")) : "";
77
- const recentLogHasError = /Traceback|ERROR|Exception|Failed/i.test(logText.slice(-4000));
78
-
79
- const results = [];
80
- addResult(results, "Codex home", fs.existsSync(codexHome), codexHome, "Run: npx oh-langfuse@latest setup codex");
81
- addResult(results, "config.toml", fs.existsSync(configPath), configPath, "Run setup again to update Codex config.");
82
- addResult(
83
- results,
84
- "notify hook configured",
85
- configHasNotify(configText),
86
- configHasNotify(configText) ? "OK" : "missing notify entry for codex_langfuse_notify.py",
87
- "Run setup again, then restart Codex."
88
- );
89
- addResult(results, "hook script", fs.existsSync(hookPath), hookPath, "Run setup again to install the notify hook.");
90
- addResult(results, "Langfuse config", !!langfuseConfig, langfuseConfigPath, "Run setup again to write Langfuse credentials.");
91
- addResult(
92
- results,
93
- "Langfuse keys",
94
- !!(langfuseConfig?.publicKey && langfuseConfig?.secretKey),
95
- langfuseConfig?.publicKey ? "configured" : "missing",
96
- "Provide publicKey/secretKey or use the defaults from the installer."
97
- );
98
- addResult(
99
- results,
100
- "sessions directory",
101
- fs.existsSync(sessionsDir),
102
- fs.existsSync(sessionsDir) ? sessionsDir : `${sessionsDir} (not created yet)`,
103
- "Start Codex once so session JSONL files are created.",
104
- { required: false }
105
- );
106
- addResult(
107
- results,
108
- "latest session JSONL",
109
- !!latestSession,
110
- latestSession || "not found yet",
111
- "Start a Codex conversation, then check again.",
112
- { required: false }
113
- );
114
- addResult(results, "Python", python.ok, python.detail || "not found", "Install Python and pip, then rerun setup.");
115
- addResult(results, "Langfuse venv Python", fs.existsSync(hookPython), hookPython, "Run setup again; on Linux install python3-venv if venv creation fails.");
116
- addResult(
117
- results,
118
- "Python langfuse package",
119
- langfuseImport.ok,
120
- langfuseImport.detail || "not importable from venv",
121
- "Run setup again, or pass --pipIndexUrl=https://pypi.tuna.tsinghua.edu.cn/simple."
122
- );
123
- addResult(
124
- results,
125
- "notify log recent errors",
126
- !recentLogHasError,
127
- fs.existsSync(logPath) ? logPath : "log not created yet",
128
- "Open the log path above and inspect the newest error after running Codex."
129
- );
75
+ const logPath = path.join(codexHome, "langfuse", "codex_langfuse_notify.log");
76
+ const logText = fs.existsSync(logPath) ? stripBom(fs.readFileSync(logPath, "utf8")) : "";
77
+ const recentLogHasError = /Traceback|ERROR|Exception|Failed/i.test(logText.slice(-4000));
78
+
79
+ const results = [];
80
+ addResult(results, "Codex home", fs.existsSync(codexHome), codexHome, "Run: npx oh-langfuse@latest setup codex");
81
+ addResult(results, "config.toml", fs.existsSync(configPath), configPath, "Run setup again to update Codex config.");
82
+ addResult(
83
+ results,
84
+ "notify hook configured",
85
+ configHasNotify(configText),
86
+ configHasNotify(configText) ? "OK" : "missing notify entry for codex_langfuse_notify.py",
87
+ "Run setup again, then restart Codex."
88
+ );
89
+ addResult(results, "hook script", fs.existsSync(hookPath), hookPath, "Run setup again to install the notify hook.");
90
+ addResult(results, "Langfuse config", !!langfuseConfig, langfuseConfigPath, "Run setup again to write Langfuse credentials.");
91
+ addResult(
92
+ results,
93
+ "Langfuse keys",
94
+ !!(langfuseConfig?.publicKey && langfuseConfig?.secretKey),
95
+ langfuseConfig?.publicKey ? "configured" : "missing",
96
+ "Provide publicKey/secretKey or use the defaults from the installer."
97
+ );
98
+ addResult(
99
+ results,
100
+ "sessions directory",
101
+ fs.existsSync(sessionsDir),
102
+ fs.existsSync(sessionsDir) ? sessionsDir : `${sessionsDir} (not created yet)`,
103
+ "Start Codex once so session JSONL files are created.",
104
+ { required: false }
105
+ );
106
+ addResult(
107
+ results,
108
+ "latest session JSONL",
109
+ !!latestSession,
110
+ latestSession || "not found yet",
111
+ "Start a Codex conversation, then check again.",
112
+ { required: false }
113
+ );
114
+ addResult(results, "Python", python.ok, python.detail || "not found", "Install Python and pip, then rerun setup.");
115
+ addResult(results, "Langfuse venv Python", fs.existsSync(hookPython), hookPython, "Run setup again; on Linux install python3-venv if venv creation fails.");
116
+ addResult(
117
+ results,
118
+ "Python langfuse package",
119
+ langfuseImport.ok,
120
+ langfuseImport.detail || "not importable from venv",
121
+ "Run setup again, or pass --pipIndexUrl=https://pypi.tuna.tsinghua.edu.cn/simple."
122
+ );
123
+ addResult(
124
+ results,
125
+ "notify log recent errors",
126
+ !recentLogHasError,
127
+ fs.existsSync(logPath) ? logPath : "log not created yet",
128
+ "Open the log path above and inspect the newest error after running Codex."
129
+ );
130
130
 
131
131
  const w = Math.max(...results.map((r) => r.item.length)) + 2;
132
132
  const pad = (s, n) => (s.length >= n ? s : s + " ".repeat(n - s.length));
133
- const failed = [];
134
- for (const r of results) {
135
- const status = r.ok ? "OK " : r.required ? "BAD" : "INFO";
136
- console.log(`${status} ${pad(r.item, w)} ${r.detail}`);
137
- if (!r.ok && r.required) failed.push(r);
138
- }
139
-
140
- if (failed.length) {
141
- console.log("");
142
- console.log("Fix suggestions:");
143
- for (const r of failed) {
144
- if (r.fix) console.log(`- ${r.item}: ${r.fix}`);
145
- }
146
- }
147
-
148
- process.exit(failed.length ? 2 : 0);
149
- }
133
+ const failed = [];
134
+ for (const r of results) {
135
+ const status = r.ok ? "OK " : r.required ? "BAD" : "INFO";
136
+ console.log(`${status} ${pad(r.item, w)} ${r.detail}`);
137
+ if (!r.ok && r.required) failed.push(r);
138
+ }
139
+
140
+ if (failed.length) {
141
+ console.log("");
142
+ console.log("Fix suggestions:");
143
+ for (const r of failed) {
144
+ if (r.fix) console.log(`- ${r.item}: ${r.fix}`);
145
+ }
146
+ }
147
+
148
+ process.exit(failed.length ? 2 : 0);
149
+ }
150
150
 
151
151
  main();