oh-langfuse 0.1.16 → 0.1.17
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/README.md +6 -7
- package/bin/cli.js +93 -70
- package/package.json +1 -1
- package/scripts/opencode-langfuse-check.mjs +1 -5
- package/scripts/opencode-langfuse-setup.mjs +18 -22
- package/scripts/wsl-utils.mjs +0 -39
package/README.md
CHANGED
|
@@ -109,19 +109,18 @@ Langfuse 配置启动 OpenCode。安装器可以读取带注释或尾随逗号
|
|
|
109
109
|
此时配置会写入 WSL 用户自己的 `$HOME/.config/opencode`:
|
|
110
110
|
|
|
111
111
|
```bash
|
|
112
|
-
npx oh-langfuse@latest setup opencode --userId=h00613222
|
|
112
|
+
npx oh-langfuse@latest setup opencode --userId=h00613222 --yes
|
|
113
113
|
npx oh-langfuse@latest check opencode
|
|
114
114
|
```
|
|
115
115
|
|
|
116
|
+
安装完成后会自动执行一次 `check opencode`。如果检查提示当前终端缺少
|
|
117
|
+
`LANGFUSE_*`,请新开一个 WSL 终端,或执行安装器提示的 `source ~/.bashrc`
|
|
118
|
+
/ `source ~/.zshrc`,也可以直接使用生成的
|
|
119
|
+
`~/.config/opencode/launch-opencode-langfuse.sh` 启动 OpenCode。
|
|
120
|
+
|
|
116
121
|
如果 `opencode.json` 原本是 JSONC 风格(例如带注释或尾随逗号),安装器会先兼容读取,
|
|
117
122
|
再写回标准 JSON。
|
|
118
123
|
|
|
119
|
-
如果你确实是在 Windows PowerShell 里远程配置 WSL,才需要使用 `--wsl`:
|
|
120
|
-
|
|
121
|
-
```bash
|
|
122
|
-
npx oh-langfuse@latest setup opencode --wsl=Ubuntu --userId=h00613222
|
|
123
|
-
```
|
|
124
|
-
|
|
125
124
|
### Codex
|
|
126
125
|
|
|
127
126
|
安装 `codex_langfuse_notify.py`,创建 `~/.codex/langfuse-venv`,安装 Python
|
package/bin/cli.js
CHANGED
|
@@ -451,22 +451,27 @@ async function askMultiChoice(rl, label, choices, options = {}) {
|
|
|
451
451
|
.map((idx) => choices[idx].value);
|
|
452
452
|
}
|
|
453
453
|
|
|
454
|
-
function langfuseConfig() {
|
|
455
|
-
|
|
456
|
-
baseUrl: envDefault("LANGFUSE_BASEURL", envDefault("LANGFUSE_HOST", DEFAULT_LANGFUSE_BASE_URL)),
|
|
457
|
-
publicKey: envDefault("LANGFUSE_PUBLIC_KEY", DEFAULT_LANGFUSE_PUBLIC_KEY),
|
|
458
|
-
secretKey: envDefault("LANGFUSE_SECRET_KEY", DEFAULT_LANGFUSE_SECRET_KEY),
|
|
459
|
-
userId: envDefault("LANGFUSE_USER_ID", envDefault("CC_USER_ID", ""))
|
|
460
|
-
};
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
454
|
+
function langfuseConfig(overrides = {}) {
|
|
455
|
+
const config = {
|
|
456
|
+
baseUrl: envDefault("LANGFUSE_BASEURL", envDefault("LANGFUSE_HOST", DEFAULT_LANGFUSE_BASE_URL)),
|
|
457
|
+
publicKey: envDefault("LANGFUSE_PUBLIC_KEY", DEFAULT_LANGFUSE_PUBLIC_KEY),
|
|
458
|
+
secretKey: envDefault("LANGFUSE_SECRET_KEY", DEFAULT_LANGFUSE_SECRET_KEY),
|
|
459
|
+
userId: envDefault("LANGFUSE_USER_ID", envDefault("CC_USER_ID", ""))
|
|
460
|
+
};
|
|
461
|
+
for (const [key, value] of Object.entries(overrides)) {
|
|
462
|
+
if (hasValue(value)) config[key] = value;
|
|
463
|
+
}
|
|
464
|
+
return config;
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
async function collectLangfuseConfig(rl, { requireUserId = false, overrides = {} } = {}) {
|
|
468
|
+
const config = langfuseConfig(overrides);
|
|
469
|
+
renderSection("Langfuse Target", [
|
|
470
|
+
labelValue("Base URL", config.baseUrl, t.teal),
|
|
471
|
+
labelValue("Public Key", config.publicKey, t.blue),
|
|
472
|
+
labelValue("Secret Key", "configured", t.teal)
|
|
473
|
+
]);
|
|
474
|
+
if (requireUserId && hasValue(config.userId)) return config;
|
|
470
475
|
config.userId = await askText(rl, "User ID / employee number, for example h00613222", {
|
|
471
476
|
defaultValue: requireUserId ? "" : config.userId,
|
|
472
477
|
required: requireUserId
|
|
@@ -474,11 +479,11 @@ async function collectLangfuseConfig(rl, { requireUserId = false } = {}) {
|
|
|
474
479
|
return config;
|
|
475
480
|
}
|
|
476
481
|
|
|
477
|
-
async function collectSharedConfig(rl, options) {
|
|
478
|
-
clearScreen();
|
|
479
|
-
renderBrand(options);
|
|
480
|
-
return await collectLangfuseConfig(rl, { requireUserId: true });
|
|
481
|
-
}
|
|
482
|
+
async function collectSharedConfig(rl, options) {
|
|
483
|
+
clearScreen();
|
|
484
|
+
renderBrand(options);
|
|
485
|
+
return await collectLangfuseConfig(rl, { requireUserId: true, overrides: options.configOverrides });
|
|
486
|
+
}
|
|
482
487
|
|
|
483
488
|
function commonLangfuseArgs(config) {
|
|
484
489
|
return [
|
|
@@ -493,27 +498,22 @@ function optionalInstallerArgs(options) {
|
|
|
493
498
|
return [...(hasValue(options.pipIndexUrl) ? [`--pipIndexUrl=${options.pipIndexUrl}`] : [])];
|
|
494
499
|
}
|
|
495
500
|
|
|
496
|
-
function
|
|
497
|
-
return [
|
|
498
|
-
...(options.wsl ? [typeof options.wsl === "string" ? `--wsl=${options.wsl}` : "--wsl"] : []),
|
|
499
|
-
...(hasValue(options.wslDistro) ? [`--wslDistro=${options.wslDistro}`] : [])
|
|
500
|
-
];
|
|
501
|
-
}
|
|
502
|
-
|
|
503
|
-
async function confirmAction(rl, title, rows, options) {
|
|
501
|
+
async function confirmAction(rl, title, rows, options) {
|
|
504
502
|
clearScreen();
|
|
505
503
|
renderBrand(options);
|
|
506
504
|
renderSection(title, rows);
|
|
507
|
-
if (options.dryRun) return true;
|
|
505
|
+
if (options.dryRun || options.yes) return true;
|
|
508
506
|
console.log("");
|
|
509
507
|
return await askYesNo(rl, "Continue with these changes", { defaultValue: true });
|
|
510
508
|
}
|
|
511
509
|
|
|
512
|
-
async function setupClaude(rl, options) {
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
510
|
+
async function setupClaude(rl, options) {
|
|
511
|
+
if (!options.dryRun) {
|
|
512
|
+
while (!(await ensureEnvironment(rl, "claude", options))) {}
|
|
513
|
+
}
|
|
514
|
+
clearScreen();
|
|
515
|
+
renderBrand(options);
|
|
516
|
+
const config = options.config || (await collectLangfuseConfig(rl, { requireUserId: true, overrides: options.configOverrides }));
|
|
517
517
|
const defaultHook = path.join(rootDir, "langfuse_hook.py");
|
|
518
518
|
const pyPath = fs.existsSync(defaultHook) ? defaultHook : path.join(rootDir, "langfuse_hook.py");
|
|
519
519
|
|
|
@@ -528,26 +528,29 @@ async function setupClaude(rl, options) {
|
|
|
528
528
|
labelValue("Python package", "langfuse", t.gold)
|
|
529
529
|
],
|
|
530
530
|
options
|
|
531
|
-
);
|
|
532
|
-
if (!ok) return 0;
|
|
533
|
-
|
|
534
|
-
}
|
|
535
|
-
|
|
531
|
+
);
|
|
532
|
+
if (!ok) return 0;
|
|
533
|
+
const code = runNodeScript("langfuse-setup.mjs", args, options);
|
|
534
|
+
if (code === 0 && !options.dryRun && !options.skipCheck) return checkClaude(options, { clear: false });
|
|
535
|
+
return code;
|
|
536
|
+
}
|
|
537
|
+
|
|
536
538
|
async function setupOpenCode(rl, options) {
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
const
|
|
543
|
-
const
|
|
539
|
+
if (!options.dryRun) {
|
|
540
|
+
while (!(await ensureEnvironment(rl, "opencode", options))) {}
|
|
541
|
+
}
|
|
542
|
+
clearScreen();
|
|
543
|
+
renderBrand(options);
|
|
544
|
+
const config = options.config || (await collectLangfuseConfig(rl, { requireUserId: true, overrides: options.configOverrides }));
|
|
545
|
+
const setEnv = !options.noSetEnv;
|
|
546
|
+
const installPlugin = !options.skipPluginInstall;
|
|
547
|
+
const cliPath = options.cmd || "";
|
|
544
548
|
|
|
545
549
|
const args = [
|
|
546
550
|
...commonLangfuseArgs(config),
|
|
547
551
|
...(hasValue(options.npmRegistry) ? [`--npmRegistry=${options.npmRegistry}`] : []),
|
|
548
|
-
...opencodePlatformArgs(options),
|
|
549
552
|
...(!setEnv ? ["--no-set-env"] : []),
|
|
550
|
-
...(!installPlugin ? ["--skip-plugin-install"] : []),
|
|
553
|
+
...(!installPlugin ? ["--skip-plugin-install"] : []),
|
|
551
554
|
...(hasValue(cliPath) ? [`--cmd=${cliPath}`] : [])
|
|
552
555
|
];
|
|
553
556
|
const ok = await confirmAction(
|
|
@@ -555,23 +558,27 @@ async function setupOpenCode(rl, options) {
|
|
|
555
558
|
"OpenCode Langfuse Setup",
|
|
556
559
|
[
|
|
557
560
|
labelValue("User ID", config.userId || "<none>", config.userId ? t.teal : t.muted),
|
|
558
|
-
labelValue("User env vars", setEnv ? "write" : "skip", setEnv ? t.teal : t.gold),
|
|
561
|
+
labelValue("User env vars", setEnv ? "write" : "skip", setEnv ? t.teal : t.gold),
|
|
559
562
|
labelValue("Plugin install", installPlugin ? "install/update" : "skip", installPlugin ? t.teal : t.gold),
|
|
560
563
|
labelValue("CLI path", cliPath || "auto-detect", t.blue),
|
|
561
|
-
labelValue("Target runtime",
|
|
564
|
+
labelValue("Target runtime", "current shell", t.violet),
|
|
562
565
|
labelValue("Config file", "~/.config/opencode/opencode.json", t.violet)
|
|
563
566
|
],
|
|
564
567
|
options
|
|
565
|
-
);
|
|
566
|
-
if (!ok) return 0;
|
|
567
|
-
|
|
568
|
-
}
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
568
|
+
);
|
|
569
|
+
if (!ok) return 0;
|
|
570
|
+
const code = runNodeScript("opencode-langfuse-setup.mjs", args, options);
|
|
571
|
+
if (code === 0 && !options.dryRun && !options.skipCheck) return checkOpenCode(options, { clear: false });
|
|
572
|
+
return code;
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
async function setupCodex(rl, options) {
|
|
576
|
+
if (!options.dryRun) {
|
|
577
|
+
while (!(await ensureEnvironment(rl, "codex", options))) {}
|
|
578
|
+
}
|
|
579
|
+
clearScreen();
|
|
580
|
+
renderBrand(options);
|
|
581
|
+
const config = options.config || (await collectLangfuseConfig(rl, { requireUserId: true, overrides: options.configOverrides }));
|
|
575
582
|
const defaultHook = path.join(rootDir, "codex_langfuse_notify.py");
|
|
576
583
|
const pyPath = fs.existsSync(defaultHook) ? defaultHook : path.join(rootDir, "codex_langfuse_notify.py");
|
|
577
584
|
|
|
@@ -586,10 +593,12 @@ async function setupCodex(rl, options) {
|
|
|
586
593
|
labelValue("Python package", "langfuse", t.gold)
|
|
587
594
|
],
|
|
588
595
|
options
|
|
589
|
-
);
|
|
590
|
-
if (!ok) return 0;
|
|
591
|
-
|
|
592
|
-
}
|
|
596
|
+
);
|
|
597
|
+
if (!ok) return 0;
|
|
598
|
+
const code = runNodeScript("codex-langfuse-setup.mjs", args, options);
|
|
599
|
+
if (code === 0 && !options.dryRun && !options.skipCheck) return checkCodex(options, { clear: false });
|
|
600
|
+
return code;
|
|
601
|
+
}
|
|
593
602
|
|
|
594
603
|
function checkClaude(options, { clear = true } = {}) {
|
|
595
604
|
if (clear) clearScreen();
|
|
@@ -600,7 +609,7 @@ function checkClaude(options, { clear = true } = {}) {
|
|
|
600
609
|
function checkOpenCode(options, { clear = true } = {}) {
|
|
601
610
|
if (clear) clearScreen();
|
|
602
611
|
renderBrand(options);
|
|
603
|
-
return runNodeScript("opencode-langfuse-check.mjs",
|
|
612
|
+
return runNodeScript("opencode-langfuse-check.mjs", [], options);
|
|
604
613
|
}
|
|
605
614
|
|
|
606
615
|
function checkCodex(options, { clear = true } = {}) {
|
|
@@ -713,9 +722,14 @@ function printHelp() {
|
|
|
713
722
|
]);
|
|
714
723
|
renderSection("Options", [
|
|
715
724
|
`${paint("--dry-run", t.gold)} Preview actions without writing files or installing packages.`,
|
|
716
|
-
`${paint("--
|
|
725
|
+
`${paint("--userId=ID", t.gold)} Provide the Langfuse user id without prompting.`,
|
|
726
|
+
`${paint("--langfuseBaseUrl=URL", t.gold)} Override the Langfuse base URL.`,
|
|
727
|
+
`${paint("--publicKey=KEY", t.gold)} Override the Langfuse public key.`,
|
|
728
|
+
`${paint("--secretKey=KEY", t.gold)} Override the Langfuse secret key.`,
|
|
729
|
+
`${paint("--yes", t.gold)} Accept setup changes without the confirmation prompt.`,
|
|
717
730
|
`${paint("--npmRegistry=URL", t.gold)} Use a specific npm registry when installing the OpenCode plugin.`,
|
|
718
731
|
`${paint("--pipIndexUrl=URL", t.gold)} Use a specific pip index for Python Langfuse installs.`,
|
|
732
|
+
`${paint("--skip-check", t.gold)} Do not run the target check after a successful setup.`,
|
|
719
733
|
`${paint("--help", t.gold)} Show this help.`
|
|
720
734
|
]);
|
|
721
735
|
}
|
|
@@ -724,10 +738,19 @@ async function main() {
|
|
|
724
738
|
const args = parseArgs(process.argv.slice(2));
|
|
725
739
|
const options = {
|
|
726
740
|
dryRun: !!args["dry-run"],
|
|
727
|
-
wsl: args.wsl || !!(args.wslDistro || args["wsl-distro"]),
|
|
728
|
-
wslDistro: args.wslDistro || args["wsl-distro"] || "",
|
|
729
741
|
npmRegistry: args.npmRegistry || "",
|
|
730
|
-
pipIndexUrl: args.pipIndexUrl || ""
|
|
742
|
+
pipIndexUrl: args.pipIndexUrl || "",
|
|
743
|
+
yes: !!(args.yes || args.y),
|
|
744
|
+
noSetEnv: !!args["no-set-env"],
|
|
745
|
+
skipPluginInstall: !!(args["skip-plugin-install"] || args.skipNpmInstall),
|
|
746
|
+
skipCheck: !!args["skip-check"],
|
|
747
|
+
cmd: args.cmd || "",
|
|
748
|
+
configOverrides: {
|
|
749
|
+
baseUrl: args.langfuseBaseUrl || args.langfuseHost || args.host || "",
|
|
750
|
+
publicKey: args.publicKey || "",
|
|
751
|
+
secretKey: args.secretKey || "",
|
|
752
|
+
userId: args.userId || args.userid || ""
|
|
753
|
+
}
|
|
731
754
|
};
|
|
732
755
|
const [cmd, target] = args._;
|
|
733
756
|
|
package/package.json
CHANGED
|
@@ -2,7 +2,6 @@ import fs from "node:fs";
|
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import os from "node:os";
|
|
4
4
|
import { parseJsonRelaxed, stripBom } from "./json-utils.mjs";
|
|
5
|
-
import { runOhLangfuseInWsl, shouldRunInWsl } from "./wsl-utils.mjs";
|
|
6
5
|
|
|
7
6
|
function parseArgs(argv) {
|
|
8
7
|
const args = {};
|
|
@@ -198,10 +197,7 @@ function main() {
|
|
|
198
197
|
}
|
|
199
198
|
|
|
200
199
|
try {
|
|
201
|
-
|
|
202
|
-
if (shouldRunInWsl(args)) {
|
|
203
|
-
process.exit(runOhLangfuseInWsl(args, ["npx", "-y", "oh-langfuse@latest", "check", "opencode"]));
|
|
204
|
-
}
|
|
200
|
+
parseArgs(process.argv.slice(2));
|
|
205
201
|
main();
|
|
206
202
|
} catch (e) {
|
|
207
203
|
console.error(e?.message || String(e));
|
|
@@ -3,7 +3,6 @@ import path from "node:path";
|
|
|
3
3
|
import os from "node:os";
|
|
4
4
|
import { spawn, spawnSync } from "node:child_process";
|
|
5
5
|
import { parseJsonRelaxed, stripBom } from "./json-utils.mjs";
|
|
6
|
-
import { runOhLangfuseInWsl, shouldRunInWsl } from "./wsl-utils.mjs";
|
|
7
6
|
|
|
8
7
|
function parseArgs(argv) {
|
|
9
8
|
const args = {};
|
|
@@ -438,23 +437,6 @@ function updateShellConfig({ publicKey, secretKey, baseUrl, userId }) {
|
|
|
438
437
|
|
|
439
438
|
async function main() {
|
|
440
439
|
const args = parseArgs(process.argv.slice(2));
|
|
441
|
-
if (shouldRunInWsl(args)) {
|
|
442
|
-
const forwarded = [
|
|
443
|
-
"npx",
|
|
444
|
-
"-y",
|
|
445
|
-
"oh-langfuse@latest",
|
|
446
|
-
"setup",
|
|
447
|
-
"opencode",
|
|
448
|
-
...(args.langfuseBaseUrl ? [`--langfuseBaseUrl=${args.langfuseBaseUrl}`] : []),
|
|
449
|
-
...(args.publicKey ? [`--publicKey=${args.publicKey}`] : []),
|
|
450
|
-
...(args.secretKey ? [`--secretKey=${args.secretKey}`] : []),
|
|
451
|
-
...(args.userId || args.userid ? [`--userId=${args.userId || args.userid}`] : []),
|
|
452
|
-
...(args.npmRegistry ? [`--npmRegistry=${args.npmRegistry}`] : []),
|
|
453
|
-
...(args["no-set-env"] ? ["--no-set-env"] : []),
|
|
454
|
-
...(args["skip-plugin-install"] ? ["--skip-plugin-install"] : [])
|
|
455
|
-
];
|
|
456
|
-
process.exit(runOhLangfuseInWsl(args, forwarded));
|
|
457
|
-
}
|
|
458
440
|
|
|
459
441
|
const setEnv = !args["no-set-env"];
|
|
460
442
|
const skipPluginInstall =
|
|
@@ -546,7 +528,8 @@ async function main() {
|
|
|
546
528
|
printCommandHint("如果新终端仍读不到环境变量,可运行:", unixLauncher);
|
|
547
529
|
}
|
|
548
530
|
|
|
549
|
-
|
|
531
|
+
let shellConfigPathWritten = "";
|
|
532
|
+
if (setEnv) {
|
|
550
533
|
if (process.platform === "win32") {
|
|
551
534
|
console.log("写入用户级环境变量:LANGFUSE_PUBLIC_KEY / LANGFUSE_SECRET_KEY / LANGFUSE_BASEURL …");
|
|
552
535
|
setWindowsUserEnv({ publicKey, secretKey, baseUrl: baseUrl });
|
|
@@ -560,7 +543,8 @@ async function main() {
|
|
|
560
543
|
console.log("提示:新开一个终端后环境变量才会对应用生效。");
|
|
561
544
|
} else {
|
|
562
545
|
console.log("正在写入环境变量到 shell 配置文件 …");
|
|
563
|
-
const configPath = updateShellConfig({ publicKey, secretKey, baseUrl, userId });
|
|
546
|
+
const configPath = updateShellConfig({ publicKey, secretKey, baseUrl, userId });
|
|
547
|
+
shellConfigPathWritten = configPath;
|
|
564
548
|
console.log(`已更新:${configPath}`);
|
|
565
549
|
|
|
566
550
|
// 自动 source 配置文件
|
|
@@ -580,9 +564,21 @@ async function main() {
|
|
|
580
564
|
|
|
581
565
|
console.log(paint("完成。", colors.green, colors.bold));
|
|
582
566
|
printCommandHint("可运行以下命令校验:", "npx oh-langfuse@latest check opencode");
|
|
567
|
+
if (process.platform !== "win32") {
|
|
568
|
+
console.log("");
|
|
569
|
+
console.log("Important for WSL/Linux:");
|
|
570
|
+
console.log("This installer wrote LANGFUSE_* to your shell rc file, but it cannot update an already-open parent shell.");
|
|
571
|
+
if (shellConfigPathWritten) {
|
|
572
|
+
printCommandHint("Before starting OpenCode from this same terminal, run:", `source ${shellConfigPathWritten}`);
|
|
573
|
+
}
|
|
574
|
+
if (unixLauncher) {
|
|
575
|
+
printCommandHint("Or start OpenCode with the generated launcher:", unixLauncher);
|
|
576
|
+
}
|
|
577
|
+
console.log("Opening a new WSL terminal also loads the variables for normal shell setups.");
|
|
578
|
+
}
|
|
583
579
|
}
|
|
584
|
-
|
|
585
|
-
try {
|
|
580
|
+
|
|
581
|
+
try {
|
|
586
582
|
await main();
|
|
587
583
|
} catch (e) {
|
|
588
584
|
console.error(e?.message || String(e));
|
package/scripts/wsl-utils.mjs
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import { spawnSync } from "node:child_process";
|
|
2
|
-
|
|
3
|
-
export function shouldRunInWsl(args) {
|
|
4
|
-
return process.platform === "win32" && !!(args.wsl || args.wslDistro || args["wsl-distro"]);
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
function wslDistro(args) {
|
|
8
|
-
if (typeof args.wsl === "string" && args.wsl.trim() && args.wsl.trim().toLowerCase() !== "true") {
|
|
9
|
-
return args.wsl.trim();
|
|
10
|
-
}
|
|
11
|
-
if (typeof args.wslDistro === "string" && args.wslDistro.trim()) return args.wslDistro.trim();
|
|
12
|
-
if (typeof args["wsl-distro"] === "string" && args["wsl-distro"].trim()) return args["wsl-distro"].trim();
|
|
13
|
-
return "";
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
function shQuote(value) {
|
|
17
|
-
return `'${String(value).replace(/'/g, "'\"'\"'")}'`;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export function runOhLangfuseInWsl(args, ohLangfuseArgs) {
|
|
21
|
-
const distro = wslDistro(args);
|
|
22
|
-
const wslArgs = [];
|
|
23
|
-
if (distro) wslArgs.push("-d", distro);
|
|
24
|
-
wslArgs.push("--", "sh", "-lc", ohLangfuseArgs.map(shQuote).join(" "));
|
|
25
|
-
|
|
26
|
-
console.log(
|
|
27
|
-
distro
|
|
28
|
-
? `Forwarding OpenCode Langfuse command to WSL distro: ${distro}`
|
|
29
|
-
: "Forwarding OpenCode Langfuse command to the default WSL distro"
|
|
30
|
-
);
|
|
31
|
-
|
|
32
|
-
const r = spawnSync("wsl.exe", wslArgs, { stdio: "inherit", windowsHide: true });
|
|
33
|
-
if (r.error) {
|
|
34
|
-
console.error(r.error.message);
|
|
35
|
-
console.error("WSL is not available from this Windows session. Run the same oh-langfuse command inside WSL instead.");
|
|
36
|
-
return 1;
|
|
37
|
-
}
|
|
38
|
-
return r.status ?? 1;
|
|
39
|
-
}
|