oh-langfuse 0.1.73 → 0.1.75
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/codex_langfuse_notify.py
CHANGED
|
@@ -748,6 +748,10 @@ def _skill_agent_path(agent: str, detected_by: str) -> str:
|
|
|
748
748
|
return "codex_skill_script_exec"
|
|
749
749
|
if detected_by == "codex_implicit_doc_read":
|
|
750
750
|
return "codex_skill_doc_read"
|
|
751
|
+
if detected_by == "codex_skill_tool":
|
|
752
|
+
return "codex_skill_tool_invoke"
|
|
753
|
+
if detected_by == "codex_skill_doc_read":
|
|
754
|
+
return "codex_skill_doc_read_tool"
|
|
751
755
|
if detected_by == "tool_call":
|
|
752
756
|
return "codex_unsupported_skill_tool"
|
|
753
757
|
if detected_by == "skill_file_path":
|
|
@@ -758,7 +762,7 @@ def _skill_agent_path(agent: str, detected_by: str) -> str:
|
|
|
758
762
|
def _skill_invocation_mode(agent: str, detected_by: str) -> str:
|
|
759
763
|
if agent == "codex" and detected_by == "codex_explicit_injection":
|
|
760
764
|
return "explicit"
|
|
761
|
-
if agent == "codex" and detected_by in ("codex_implicit_script", "codex_implicit_doc_read"):
|
|
765
|
+
if agent == "codex" and detected_by in ("codex_implicit_script", "codex_implicit_doc_read", "codex_skill_tool", "codex_skill_doc_read"):
|
|
762
766
|
return "implicit"
|
|
763
767
|
return "detected"
|
|
764
768
|
|
|
@@ -766,7 +770,7 @@ def _skill_invocation_mode(agent: str, detected_by: str) -> str:
|
|
|
766
770
|
def _skill_event_type(detected_by: str, agent: str = "unknown") -> str:
|
|
767
771
|
if agent == "codex" and detected_by == "tool_call":
|
|
768
772
|
return "detected"
|
|
769
|
-
return "invoked" if detected_by in ("codex_explicit_injection", "codex_implicit_script", "codex_implicit_doc_read") else "detected"
|
|
773
|
+
return "invoked" if detected_by in ("codex_explicit_injection", "codex_implicit_script", "codex_implicit_doc_read", "codex_skill_tool", "codex_skill_doc_read") else "detected"
|
|
770
774
|
|
|
771
775
|
|
|
772
776
|
def _skill_id_segment(name: str) -> str:
|
|
@@ -837,7 +841,31 @@ def _detect_codex_skill_command(command: str, known_skills: set) -> List[Dict[st
|
|
|
837
841
|
def detect_skill_usages(tool_calls: List[Dict[str, Any]], known_skills: set) -> List[Dict[str, str]]:
|
|
838
842
|
found: List[Dict[str, str]] = []
|
|
839
843
|
for call in tool_calls or []:
|
|
844
|
+
call_name = str(call.get("name") or "").strip().lower()
|
|
840
845
|
input_obj = call.get("input") if isinstance(call.get("input"), (dict, list, str)) else {}
|
|
846
|
+
|
|
847
|
+
if call_name == "skill":
|
|
848
|
+
skill_input_name = None
|
|
849
|
+
if isinstance(input_obj, dict):
|
|
850
|
+
skill_input_name = str(input_obj.get("name") or "").strip()
|
|
851
|
+
if skill_input_name:
|
|
852
|
+
name = _accept_known_skill(skill_input_name, known_skills)
|
|
853
|
+
if name:
|
|
854
|
+
found.append(_skill_usage(name, "codex_skill_tool"))
|
|
855
|
+
continue
|
|
856
|
+
|
|
857
|
+
if call_name == "read":
|
|
858
|
+
if isinstance(input_obj, dict):
|
|
859
|
+
file_path = str(input_obj.get("filePath") or "").strip()
|
|
860
|
+
if file_path:
|
|
861
|
+
doc_pattern = r"[\\/](?:skills|skill)[\\/]([^\\/\"'\s]+)[\\/]SKILL\.md$"
|
|
862
|
+
match = re.search(doc_pattern, file_path, re.IGNORECASE)
|
|
863
|
+
if match:
|
|
864
|
+
name = _accept_known_skill(match.group(1), known_skills)
|
|
865
|
+
if name:
|
|
866
|
+
found.append(_skill_usage(name, "codex_skill_doc_read"))
|
|
867
|
+
continue
|
|
868
|
+
|
|
841
869
|
found.extend(_detect_codex_skill_command(_command_from_tool_input(input_obj), known_skills))
|
|
842
870
|
return found
|
|
843
871
|
|
package/package.json
CHANGED
|
@@ -1007,7 +1007,8 @@ function writeOpencodeCommandShim(opencodeDir, { publicKey, secretKey, baseUrl,
|
|
|
1007
1007
|
cmd.push(...windowsGitPathBootstrap());
|
|
1008
1008
|
cmd.push(windowsAutoUpdateCommand("opencode"));
|
|
1009
1009
|
cmd.push(`set "OH_LANGFUSE_REAL_OPENCODE=${cmdSetValue(realOpencodeCli)}"`);
|
|
1010
|
-
cmd.push('
|
|
1010
|
+
cmd.push('echo "%OH_LANGFUSE_REAL_OPENCODE%" | findstr /I "\\node_modules\\opencode-ai\\bin\\opencode.exe" >nul');
|
|
1011
|
+
cmd.push('if errorlevel 1 if exist "%OH_LANGFUSE_REAL_OPENCODE%" (');
|
|
1011
1012
|
cmd.push(' call "%OH_LANGFUSE_REAL_OPENCODE%" %*');
|
|
1012
1013
|
cmd.push(" exit /b %ERRORLEVEL%");
|
|
1013
1014
|
cmd.push(")");
|
|
@@ -1023,10 +1024,6 @@ function writeOpencodeCommandShim(opencodeDir, { publicKey, secretKey, baseUrl,
|
|
|
1023
1024
|
cmd.push(' call "%APPDATA%\\npm\\opencode.cmd" %*');
|
|
1024
1025
|
cmd.push(" exit /b %ERRORLEVEL%");
|
|
1025
1026
|
cmd.push(")");
|
|
1026
|
-
cmd.push('if exist "%APPDATA%\\npm\\node_modules\\opencode-ai\\bin\\opencode.exe" (');
|
|
1027
|
-
cmd.push(' call "%APPDATA%\\npm\\node_modules\\opencode-ai\\bin\\opencode.exe" %*');
|
|
1028
|
-
cmd.push(" exit /b %ERRORLEVEL%");
|
|
1029
|
-
cmd.push(")");
|
|
1030
1027
|
cmd.push('if exist "%APPDATA%\\npm\\node_modules\\opencode-ai\\node_modules\\opencode-windows-x64\\bin\\opencode.exe" (');
|
|
1031
1028
|
cmd.push(' call "%APPDATA%\\npm\\node_modules\\opencode-ai\\node_modules\\opencode-windows-x64\\bin\\opencode.exe" %*');
|
|
1032
1029
|
cmd.push(" exit /b %ERRORLEVEL%");
|
|
@@ -1045,8 +1042,11 @@ function writeOpencodeCommandShim(opencodeDir, { publicKey, secretKey, baseUrl,
|
|
|
1045
1042
|
cmd.push(")");
|
|
1046
1043
|
cmd.push('for /f "delims=" %%O in (\'where.exe opencode 2^>nul\') do (');
|
|
1047
1044
|
cmd.push(' if /I not "%%~fO"=="%~f0" (');
|
|
1048
|
-
cmd.push('
|
|
1049
|
-
cmd.push("
|
|
1045
|
+
cmd.push(' echo %%~fO | findstr /I "\\node_modules\\opencode-ai\\bin\\opencode.exe" >nul');
|
|
1046
|
+
cmd.push(" if errorlevel 1 (");
|
|
1047
|
+
cmd.push(' call "%%O" %*');
|
|
1048
|
+
cmd.push(" exit /b %ERRORLEVEL%");
|
|
1049
|
+
cmd.push(" )");
|
|
1050
1050
|
cmd.push(" )");
|
|
1051
1051
|
cmd.push(")");
|
|
1052
1052
|
cmd.push("echo [ERROR] OpenCode CLI not found. Install OpenCode CLI first. 1>&2");
|
|
@@ -3,18 +3,28 @@ import path from "node:path";
|
|
|
3
3
|
import os from "node:os";
|
|
4
4
|
import { spawnSync } from "node:child_process";
|
|
5
5
|
import { listSystemCliCandidates } from "./cli-detection-utils.mjs";
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
|
|
7
|
+
function isKnownBrokenWindowsOpencodeCandidate(candidate) {
|
|
8
|
+
if (process.platform !== "win32") return false;
|
|
9
|
+
const normalized = String(candidate || "").replace(/\//g, "\\").toLowerCase();
|
|
10
|
+
return normalized.endsWith("\\node_modules\\opencode-ai\\bin\\opencode.exe");
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function usableCandidate(candidate) {
|
|
14
|
+
return candidate && !isKnownBrokenWindowsOpencodeCandidate(candidate) && fs.existsSync(candidate);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
8
18
|
* OpenCode CLI 的官方安装脚本默认会把二进制放到 ~/.opencode/bin;
|
|
9
19
|
* npm 全局安装则可能出现在 %AppData%\npm\opencode.cmd;PATH 也可能只认识 `opencode`。
|
|
10
20
|
* @param {string|undefined} preferred --cmd=xxx 或可执行文件路径
|
|
11
21
|
* @returns {string|null} 可执行的绝对路径,或仅在 PATH 中解析到则用 `opencode`
|
|
12
22
|
*/
|
|
13
23
|
export function resolveOpencodeCli(preferred) {
|
|
14
|
-
if (typeof preferred === "string" && preferred.trim()) {
|
|
15
|
-
const p = preferred.trim();
|
|
16
|
-
if (
|
|
17
|
-
}
|
|
24
|
+
if (typeof preferred === "string" && preferred.trim()) {
|
|
25
|
+
const p = preferred.trim();
|
|
26
|
+
if (usableCandidate(p)) return path.resolve(p);
|
|
27
|
+
}
|
|
18
28
|
|
|
19
29
|
const home = os.homedir();
|
|
20
30
|
|
|
@@ -30,7 +40,6 @@ export function resolveOpencodeCli(preferred) {
|
|
|
30
40
|
if (process.env.APPDATA) {
|
|
31
41
|
candidates.push(path.join(process.env.APPDATA, "npm", "opencode.cmd"));
|
|
32
42
|
candidates.push(path.join(process.env.APPDATA, "npm", "opencode"));
|
|
33
|
-
candidates.push(path.join(process.env.APPDATA, "npm", "node_modules", "opencode-ai", "bin", "opencode.exe"));
|
|
34
43
|
candidates.push(path.join(process.env.APPDATA, "npm", "node_modules", "opencode-ai", "node_modules", "opencode-windows-x64", "bin", "opencode.exe"));
|
|
35
44
|
candidates.push(path.join(process.env.APPDATA, "npm", "node_modules", "opencode-ai", "node_modules", "opencode-windows-x64-baseline", "bin", "opencode.exe"));
|
|
36
45
|
candidates.push(path.join(process.env.APPDATA, "npm", "node_modules", "opencode-windows-x64", "bin", "opencode.exe"));
|
|
@@ -42,17 +51,17 @@ export function resolveOpencodeCli(preferred) {
|
|
|
42
51
|
candidates.push(path.join(home, ".local", "bin", "opencode"));
|
|
43
52
|
candidates.push(...listSystemCliCandidates("opencode"));
|
|
44
53
|
}
|
|
45
|
-
|
|
46
|
-
for (const c of candidates) {
|
|
47
|
-
if (
|
|
48
|
-
}
|
|
54
|
+
|
|
55
|
+
for (const c of candidates) {
|
|
56
|
+
if (usableCandidate(c)) return c;
|
|
57
|
+
}
|
|
49
58
|
|
|
50
59
|
if (process.platform === "win32") {
|
|
51
60
|
const r = spawnSync("where.exe", ["opencode"], { encoding: "utf8", windowsHide: true });
|
|
52
61
|
if (r.status === 0 && r.stdout) {
|
|
53
|
-
const line = r.stdout.trim().split(/\r?\n/)[0]?.trim();
|
|
54
|
-
if (
|
|
55
|
-
}
|
|
62
|
+
const line = r.stdout.trim().split(/\r?\n/)[0]?.trim();
|
|
63
|
+
if (usableCandidate(line)) return line;
|
|
64
|
+
}
|
|
56
65
|
} else {
|
|
57
66
|
const r = spawnSync("which", ["opencode"], { encoding: "utf8" });
|
|
58
67
|
if (r.status === 0 && r.stdout) {
|