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.
@@ -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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oh-langfuse",
3
- "version": "0.1.73",
3
+ "version": "0.1.75",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "Use npm scripts to configure Claude Code / OpenCode / Codex with Langfuse tracing.",
@@ -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('if exist "%OH_LANGFUSE_REAL_OPENCODE%" (');
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(' call "%%O" %*');
1049
- cmd.push(" exit /b %ERRORLEVEL%");
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 (fs.existsSync(p)) return path.resolve(p);
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 (c && fs.existsSync(c)) return c;
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 (line && fs.existsSync(line)) return line;
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) {