oh-aicoding-tool 0.1.1 → 0.1.4

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.
Files changed (55) hide show
  1. package/README.md +79 -80
  2. package/bin/cli.js +257 -383
  3. package/package.json +28 -56
  4. package/CODEX_LANGFUSE_PLAN.md +0 -62
  5. package/bin/langfuse-cli.js +0 -718
  6. package/codex_langfuse_notify.py +0 -591
  7. package/langfuse_hook.py +0 -603
  8. package/opencode-ohai-report/.claude/commands/report-ai-issue.md +0 -60
  9. package/opencode-ohai-report/.opencode/commands/report-ai-issue.md +0 -30
  10. package/opencode-ohai-report/.opencode/plugins/oh-ai-report.ts +0 -569
  11. package/opencode-ohai-report/README.md +0 -45
  12. package/opencode-ohai-report/bin/cli.js +0 -421
  13. package/opencode-ohai-report/docs/opencode-ai-issue-collection-architecture.md +0 -313
  14. package/opencode-ohai-report/docs/opencode-ai-issue-collection-best-practices.md +0 -476
  15. package/opencode-ohai-report/docs/opencode-ai-issue-collection-phase1-summary.md +0 -405
  16. package/opencode-ohai-report/examples/issue_output.json +0 -4
  17. package/opencode-ohai-report/package.json +0 -40
  18. package/opencode-ohai-report/scripts/claude_report_hook.py +0 -257
  19. package/opencode-ohai-report/scripts/create_issue.py +0 -34
  20. package/opencode-ohai-report/scripts/install-claude-plugin.ps1 +0 -254
  21. package/opencode-ohai-report/scripts/install-opencode-plugin.ps1 +0 -264
  22. package/opencode-ohai-report/scripts/install-opencode-plugin.sh +0 -218
  23. package/opencode-ohai-report/scripts/merge-claude-settings.py +0 -99
  24. package/opencode-ohai-report/tools/ohai-report/README.md +0 -151
  25. package/opencode-ohai-report/tools/ohai-report/examples/issue-input.json +0 -26
  26. package/opencode-ohai-report/tools/ohai-report/ohai_report/__init__.py +0 -5
  27. package/opencode-ohai-report/tools/ohai-report/ohai_report/__main__.py +0 -9
  28. package/opencode-ohai-report/tools/ohai-report/ohai_report/cli.py +0 -319
  29. package/opencode-ohai-report/tools/ohai-report/ohai_report/git_context.py +0 -32
  30. package/opencode-ohai-report/tools/ohai-report/ohai_report/gitcode_defaults.py +0 -14
  31. package/opencode-ohai-report/tools/ohai-report/ohai_report/issue_markdown.py +0 -313
  32. package/opencode-ohai-report/tools/ohai-report/ohai_report/metadata.py +0 -360
  33. package/opencode-ohai-report/tools/ohai-report/ohai_report/observability/__init__.py +0 -1
  34. package/opencode-ohai-report/tools/ohai-report/ohai_report/observability/langfuse.py +0 -38
  35. package/opencode-ohai-report/tools/ohai-report/ohai_report/payload.py +0 -64
  36. package/opencode-ohai-report/tools/ohai-report/ohai_report/schema.py +0 -80
  37. package/opencode-ohai-report/tools/ohai-report/ohai_report/sinks/__init__.py +0 -1
  38. package/opencode-ohai-report/tools/ohai-report/ohai_report/sinks/base.py +0 -15
  39. package/opencode-ohai-report/tools/ohai-report/ohai_report/sinks/gitcode.py +0 -405
  40. package/opencode-ohai-report/tools/ohai-report/ohai_report/sinks/local.py +0 -21
  41. package/opencode-ohai-report/tools/ohai-report/ohai_report/sinks/webhook.py +0 -354
  42. package/opencode-ohai-report/tools/ohai-report/ohai_report/webhook_defaults.py +0 -9
  43. package/opencode-ohai-report/tools/ohai-report/ohai_report/workspace.py +0 -61
  44. package/opencode-ohai-report/tools/ohai-report/ohai_report.py +0 -10
  45. package/opencode-ohai-report/tools/ohai-report/schemas/report_issue.schema.json +0 -166
  46. package/scripts/codex-langfuse-check.mjs +0 -101
  47. package/scripts/codex-langfuse-setup.mjs +0 -181
  48. package/scripts/langfuse-check.mjs +0 -90
  49. package/scripts/langfuse-setup.mjs +0 -278
  50. package/scripts/opencode-langfuse-check.mjs +0 -94
  51. package/scripts/opencode-langfuse-run.mjs +0 -96
  52. package/scripts/opencode-langfuse-setup.mjs +0 -478
  53. package/scripts/resolve-opencode-cli.mjs +0 -58
  54. package/setup-langfuse.bat +0 -163
  55. package/setup-langfuse.sh +0 -130
@@ -1,218 +0,0 @@
1
- #!/usr/bin/env bash
2
- # Install oh-ai-report into OpenCode global config; set OHAI_REPORT_CLI; save company email JSON.
3
- set -euo pipefail
4
-
5
- DRY_RUN=0
6
- PLUGIN_ONLY=0
7
- SKIP_ENV=0
8
- SKIP_EMAIL=0
9
- for arg in "$@"; do
10
- case "$arg" in
11
- --dry-run) DRY_RUN=1 ;;
12
- --plugin-only) PLUGIN_ONLY=1 ;;
13
- --skip-env) SKIP_ENV=1 ;;
14
- --skip-email) SKIP_EMAIL=1 ;;
15
- -h|--help)
16
- echo "Usage: $0 [--dry-run] [--plugin-only] [--skip-env] [--skip-email]"
17
- echo "Non-interactive email: export OHAI_INSTALL_USER_EMAIL=user@company.com"
18
- exit 0
19
- ;;
20
- esac
21
- done
22
-
23
- SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
24
- REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
25
- PLUGIN_SRC="$REPO_ROOT/.opencode/plugins/oh-ai-report.ts"
26
- COMMAND_SRC="$REPO_ROOT/.opencode/commands/report-ai-issue.md"
27
- CLI_PY="$REPO_ROOT/tools/ohai-report/ohai_report.py"
28
-
29
- if [[ ! -f "$PLUGIN_SRC" ]]; then
30
- echo "error: missing $PLUGIN_SRC" >&2
31
- exit 1
32
- fi
33
-
34
- CONFIG_ROOT="${XDG_CONFIG_HOME:-$HOME/.config}/opencode"
35
- PLUGINS_DIR="$CONFIG_ROOT/plugins"
36
- COMMANDS_DIR="$CONFIG_ROOT/commands"
37
- DEST_PLUGIN="$PLUGINS_DIR/oh-ai-report.ts"
38
- DEST_COMMAND="$COMMANDS_DIR/report-ai-issue.md"
39
- EMAIL_JSON="$CONFIG_ROOT/ohai-report/email.json"
40
- LEGACY_USER_JSON="$CONFIG_ROOT/ohai-report-user.json"
41
-
42
- CLI_RESOLVED=""
43
- if [[ -f "$CLI_PY" ]]; then
44
- CLI_RESOLVED="$(cd "$(dirname "$CLI_PY")" && pwd)/$(basename "$CLI_PY")"
45
- fi
46
-
47
- is_email() {
48
- local t="${1//[[:space:]]/}"
49
- [[ -n "$t" ]] || return 1
50
- [[ "$t" =~ ^[^[:space:]@]+@[^[:space:]@]+\.[^[:space:]@]+$ ]] || return 1
51
- return 0
52
- }
53
-
54
- echo ""
55
- echo "=== OpenCode oh-ai-report install ==="
56
- echo "Repo: $REPO_ROOT"
57
- echo "OpenCode global config: $CONFIG_ROOT"
58
- echo ""
59
-
60
- if [[ "$DRY_RUN" -eq 1 ]]; then
61
- echo "[DryRun] mkdir -p $PLUGINS_DIR"
62
- echo "[DryRun] cp $PLUGIN_SRC $DEST_PLUGIN"
63
- if [[ "$PLUGIN_ONLY" -eq 0 ]]; then
64
- echo "[DryRun] mkdir -p $COMMANDS_DIR"
65
- echo "[DryRun] cp $COMMAND_SRC $DEST_COMMAND"
66
- fi
67
- if [[ "$SKIP_EMAIL" -eq 1 ]]; then
68
- echo "[DryRun] skip user email file (--skip-email)"
69
- else
70
- echo "[DryRun] prompt company email + write $EMAIL_JSON"
71
- fi
72
- if [[ "$SKIP_ENV" -eq 1 ]]; then
73
- echo "[DryRun] skip env (--skip-env)"
74
- elif [[ -n "$CLI_RESOLVED" ]]; then
75
- echo "[DryRun] write systemd user env.d + macOS zprofile (if Darwin): OHAI_REPORT_CLI=$CLI_RESOLVED"
76
- else
77
- echo "[DryRun] skip env (ohai_report.py missing)"
78
- fi
79
- exit 0
80
- fi
81
-
82
- USER_EMAIL_SAVE=""
83
- if [[ "$SKIP_EMAIL" -eq 0 ]]; then
84
- if [[ ! -t 0 ]]; then
85
- if [[ -n "${OHAI_INSTALL_USER_EMAIL:-}" ]] && is_email "${OHAI_INSTALL_USER_EMAIL}"; then
86
- USER_EMAIL_SAVE="${OHAI_INSTALL_USER_EMAIL//[[:space:]]/}"
87
- else
88
- echo "error: non-interactive install needs OHAI_INSTALL_USER_EMAIL or --skip-email" >&2
89
- exit 1
90
- fi
91
- else
92
- echo "Please enter your company email (used as user identity in oh-ai-report)."
93
- while true; do
94
- read -r -p "Company email: " line || true
95
- if is_email "$line"; then
96
- USER_EMAIL_SAVE="${line//[[:space:]]/}"
97
- break
98
- fi
99
- echo "Invalid email. Example: name@company.com" >&2
100
- done
101
- fi
102
- fi
103
-
104
- mkdir -p "$PLUGINS_DIR"
105
- cp -f "$PLUGIN_SRC" "$DEST_PLUGIN"
106
- echo "Installed plugin: $DEST_PLUGIN"
107
-
108
- PLUGIN_CONFIG_ENTRY="./plugins/oh-ai-report.ts"
109
- ensure_opencode_plugin_config() {
110
- config_path="$CONFIG_ROOT/opencode.json"
111
- CONFIG_PATH="$config_path" PLUGIN_ENTRY="$PLUGIN_CONFIG_ENTRY" python3 - <<'PY'
112
- import json
113
- import os
114
- from pathlib import Path
115
-
116
- path = Path(os.environ["CONFIG_PATH"])
117
- entry = os.environ["PLUGIN_ENTRY"]
118
- if path.exists():
119
- try:
120
- data = json.loads(path.read_text(encoding="utf-8"))
121
- except Exception as exc:
122
- print(f"Warning: could not parse {path}; leaving it unchanged: {exc}")
123
- raise SystemExit(0)
124
- else:
125
- data = {"$schema": "https://opencode.ai/config.json"}
126
-
127
- plugins = data.get("plugin", [])
128
- if isinstance(plugins, str):
129
- plugins = [plugins]
130
- elif not isinstance(plugins, list):
131
- plugins = []
132
-
133
- plugins = [str(item) for item in plugins if str(item)]
134
- if entry not in plugins:
135
- plugins.append(entry)
136
- data["plugin"] = plugins
137
- path.parent.mkdir(parents=True, exist_ok=True)
138
- path.write_text(json.dumps(data, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
139
- print(f"Updated OpenCode config plugin list: {path}")
140
- else:
141
- print(f"OpenCode config already includes plugin: {entry}")
142
- PY
143
- }
144
-
145
- if [ "$DRY_RUN" = "1" ]; then
146
- echo "[DryRun] ensure opencode.json plugin includes $PLUGIN_CONFIG_ENTRY"
147
- else
148
- ensure_opencode_plugin_config
149
- fi
150
-
151
- if [[ "$PLUGIN_ONLY" -eq 0 ]]; then
152
- if [[ ! -f "$COMMAND_SRC" ]]; then
153
- echo "Skipped command (missing): $COMMAND_SRC" >&2
154
- else
155
- mkdir -p "$COMMANDS_DIR"
156
- cp -f "$COMMAND_SRC" "$DEST_COMMAND"
157
- echo "Installed command: $DEST_COMMAND"
158
- fi
159
- fi
160
-
161
- if [[ "$SKIP_EMAIL" -eq 0 ]] && [[ -n "$USER_EMAIL_SAVE" ]]; then
162
- mkdir -p "$(dirname "$EMAIL_JSON")"
163
- if command -v python3 >/dev/null 2>&1; then
164
- python3 - "$EMAIL_JSON" "$USER_EMAIL_SAVE" <<'PY'
165
- import json, sys
166
- path, email = sys.argv[1], sys.argv[2]
167
- with open(path, "w", encoding="utf-8") as f:
168
- json.dump({"user_email": email}, f, ensure_ascii=False, separators=(",", ":"))
169
- f.write("\n")
170
- PY
171
- else
172
- esc="${USER_EMAIL_SAVE//\\/\\\\}"
173
- esc="${esc//\"/\\\"}"
174
- printf '{"user_email":"%s"}\n' "$esc" >"$EMAIL_JSON"
175
- fi
176
- echo "Saved company email to: $EMAIL_JSON"
177
- echo "Per-repo override (optional): <your-repo>/.ohai-report/user_email.json with {\"user_email\":\"...\"}"
178
- if [[ -f "$LEGACY_USER_JSON" ]]; then
179
- echo "Note: legacy file still read by tools: $LEGACY_USER_JSON" >&2
180
- fi
181
- elif [[ "$SKIP_EMAIL" -eq 1 ]]; then
182
- echo "Skipped user email file (--skip-email)."
183
- fi
184
-
185
- if [[ "$SKIP_ENV" -eq 1 ]]; then
186
- echo "Skipped env (--skip-env)."
187
- elif [[ -z "$CLI_RESOLVED" ]]; then
188
- echo "Skipped env: ohai_report.py not found under this repo." >&2
189
- else
190
- val="$CLI_RESOLVED"
191
- envd="${XDG_CONFIG_HOME:-$HOME/.config}/environment.d"
192
- mkdir -p "$envd"
193
- envfile="$envd/99-ohai-report-opencode.conf"
194
- printf '%s\n' "OHAI_REPORT_CLI=$val" >"$envfile"
195
- echo "Wrote $envfile (systemd --user; re-login for new GUI sessions on many Linux setups)."
196
-
197
- if [[ "$(uname -s)" == "Darwin" ]]; then
198
- zprof="${ZDOTDIR:-$HOME}/.zprofile"
199
- MARK="# oh-ai-report-opencode (install-opencode-plugin.sh)"
200
- if [[ -f "$zprof" ]] && grep -qF "$MARK" "$zprof" 2>/dev/null; then
201
- echo "macOS: $zprof already has oh-ai-report block; not appending again."
202
- else
203
- {
204
- echo ""
205
- echo "$MARK"
206
- printf 'export OHAI_REPORT_CLI=%q\n' "$val"
207
- } >>"$zprof"
208
- echo "Appended OHAI_REPORT_CLI to $zprof (new terminals)."
209
- fi
210
- fi
211
- fi
212
-
213
- echo ""
214
- echo "Next: fully quit and restart OpenCode."
215
- if [[ -n "$CLI_RESOLVED" ]]; then
216
- echo "OHAI_REPORT_CLI (after re-login / new shell as needed): $CLI_RESOLVED"
217
- fi
218
- echo ""
@@ -1,99 +0,0 @@
1
- #!/usr/bin/env python3
2
- """Merge the oh-ai-report Claude hook into settings.json."""
3
-
4
- from __future__ import annotations
5
-
6
- import argparse
7
- import json
8
- import pathlib
9
- from typing import Any
10
-
11
-
12
- def load_settings(path: pathlib.Path) -> dict[str, Any]:
13
- if not path.exists() or not path.read_text(encoding="utf-8-sig").strip():
14
- return {}
15
- try:
16
- data = json.loads(path.read_text(encoding="utf-8-sig"))
17
- except json.JSONDecodeError as exc:
18
- raise SystemExit(f"could not parse existing settings.json: {exc}") from exc
19
- if not isinstance(data, dict):
20
- raise SystemExit("could not merge settings.json: root value must be an object")
21
- return data
22
-
23
-
24
- def ensure_dict(value: dict[str, Any], key: str) -> dict[str, Any]:
25
- current = value.get(key)
26
- if current is None:
27
- current = {}
28
- value[key] = current
29
- if not isinstance(current, dict):
30
- raise SystemExit(f"could not merge settings.json: {key!r} must be an object")
31
- return current
32
-
33
-
34
- def ensure_list(value: dict[str, Any], key: str) -> list[Any]:
35
- current = value.get(key)
36
- if current is None:
37
- current = []
38
- value[key] = current
39
- if not isinstance(current, list):
40
- raise SystemExit(f"could not merge settings.json: {key!r} must be an array")
41
- return current
42
-
43
-
44
- def find_report_hook(entries: list[Any]) -> dict[str, Any] | None:
45
- for item in entries:
46
- if isinstance(item, dict) and item.get("matcher") == "report-ai-issue":
47
- return item
48
- return None
49
-
50
-
51
- def shell_quote(value: str) -> str:
52
- if not value:
53
- return '""'
54
- return '"' + value.replace('"', '\\"') + '"'
55
-
56
-
57
- def main() -> int:
58
- parser = argparse.ArgumentParser()
59
- parser.add_argument("--settings", required=True, type=pathlib.Path)
60
- parser.add_argument("--hook", required=True, type=pathlib.Path)
61
- parser.add_argument("--python-command", default="python")
62
- args = parser.parse_args()
63
-
64
- settings_path = args.settings
65
- hook_path = args.hook
66
- settings = load_settings(settings_path)
67
- hooks = ensure_dict(settings, "hooks")
68
- prompt_expansion = ensure_list(hooks, "UserPromptExpansion")
69
-
70
- desired = {
71
- "matcher": "report-ai-issue",
72
- "hooks": [
73
- {
74
- "type": "command",
75
- "command": f"{shell_quote(args.python_command)} -X utf8 {shell_quote(str(hook_path))}",
76
- "timeout": 120,
77
- }
78
- ],
79
- }
80
- existing = find_report_hook(prompt_expansion)
81
-
82
- if existing == desired:
83
- print("skipped: report-ai-issue hook already registered")
84
- return 0
85
-
86
- if existing is None:
87
- prompt_expansion.append(desired)
88
- else:
89
- existing.clear()
90
- existing.update(desired)
91
-
92
- settings_path.parent.mkdir(parents=True, exist_ok=True)
93
- settings_path.write_text(json.dumps(settings, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
94
- print(f"merged settings.json: {settings_path}")
95
- return 0
96
-
97
-
98
- if __name__ == "__main__":
99
- raise SystemExit(main())
@@ -1,151 +0,0 @@
1
- # ohai-report
2
-
3
- Modular local reporter for the OpenCode issue collection prototype.
4
-
5
- This first version does not upload logs, diffs, transcripts, source snippets, or
6
- tool output. It writes issue payloads under `.ohai-report/issues/` and stores
7
- only template fields plus metadata indexes for Langfuse lookup.
8
-
9
- ## Architecture
10
-
11
- ```text
12
- ohai_report.py
13
- -> ohai_report.cli
14
- -> schema.py
15
- -> metadata.py
16
- -> payload.py
17
- -> sinks/local.py
18
- ```
19
-
20
- Module responsibilities:
21
-
22
- | Module | Responsibility |
23
- | --- | --- |
24
- | `cli.py` | Parse commands and wire modules together |
25
- | `schema.py` | Data contracts, enums, validation |
26
- | `schemas/report_issue.schema.json` | Maintain issue template fields, enums, and max lengths |
27
- | `metadata.py` | Resolve session, trace, user, and context metadata |
28
- | `payload.py` | Build normalized issue payloads |
29
- | `issue_markdown.py` | 「AI 使用问题反馈」正文 Markdown(GitCode/Webhook 共用)|
30
- | `sinks/local.py` | Persist issue payloads as local JSON |
31
- | `sinks/gitcode.py` | GitCode Issues API v5(`POST /api/v5/repos/{owner}/issues`)|
32
- | `gitcode_defaults.py` | 可选写死 `DEFAULT_GITCODE_OWNER` / `DEFAULT_GITCODE_REPO`(Token 仅用环境变量)|
33
- | `sinks/webhook.py` | 通用 JSON Webhook(`POST` `{"title","body"}`,非空时含 **`labels` 逗号分隔字符串**;并合并 `tool:`/`model:`/`level:`/`category:` 维度标签;body 由 `issue_markdown` 生成)|
34
- | `observability/langfuse.py` | 由环境变量推导 Langfuse trace 链接 |
35
-
36
- The compatibility entrypoint remains:
37
-
38
- ```bash
39
- python tools/ohai-report/ohai_report.py ...
40
- ```
41
-
42
- You can also run the package directly when `tools/ohai-report` is on
43
- `PYTHONPATH`:
44
-
45
- ```bash
46
- python -m ohai_report ...
47
- ```
48
-
49
- ## Create
50
-
51
- OpenCode 中推荐通过插件工具 `report_ai_issue` 创建 Issue。该工具能在
52
- `execute(args, context)` 中读取当前 OpenCode session,并把它作为
53
- `OHAI_SESSION_ID` 传给 CLI。下面的 CLI 方式主要用于 fallback、脚本化和本地调试。
54
-
55
- ```bash
56
- python tools/ohai-report/ohai_report.py create --source opencode --title "HDC 远程服务器无法连接本地开发板" --category "环境问题" --summary "远程 OpenCode 无法访问本地 HDC 设备" --expected-behavior "能够定位本地设备访问方案或给出明确配置提示" --actual-behavior "无法发现或连接本地开发板" --severity P2 --user-description "hdc 远程服务器无法连接本地开发板" --metadata auto --quiet --json
57
- ```
58
-
59
- For future schema fields, use repeated `--field key=value` without changing the
60
- CLI parser:
61
-
62
- ```bash
63
- python tools/ohai-report/ohai_report.py create --source opencode --title "测试问题" --category "其他" --summary "验证上报链路" --expected-behavior "生成 payload" --actual-behavior "生成 JSON" --severity P3 --user-description "测试" --field scenario=HDC --metadata auto --quiet --json
64
- ```
65
-
66
- You can also submit all issue fields as JSON:
67
-
68
- ```bash
69
- python tools/ohai-report/ohai_report.py create --source opencode --issue-json "{\"title\":\"测试问题\",\"category\":\"其他\",\"summary\":\"验证上报链路\",\"expected_behavior\":\"生成 payload\",\"actual_behavior\":\"生成 JSON\",\"severity\":\"P3\",\"user_description\":\"测试\"}" --metadata auto --quiet --json
70
- ```
71
-
72
- For scripts and Windows shells, `--issue-file` is usually easier to maintain:
73
-
74
- ```bash
75
- python tools/ohai-report/ohai_report.py create --source opencode --issue-file .ohai-report/issue-input.json --metadata auto --quiet --json
76
- ```
77
-
78
- ## Metadata
79
-
80
- ```bash
81
- python tools/ohai-report/ohai_report.py metadata update --source opencode --session-id "opencode-session-xxx" --message-id "msg-xxx" --opencode-subagent "build" --trace-id "langfuse-trace-xxx" --langfuse-url "https://langfuse.example.com/project/xxx/traces/xxx" --observation-id "obs-xxx" --user-id "alice" --json
82
- ```
83
-
84
- `metadata update` 会把 CLI 参数与**当前进程环境**中的 Langfuse 桥接变量合并写入 `.ohai-report/metadata.json`。`session_id` 取显式 CLI、当前环境,或同工作区且近期更新的磁盘值;trace / observation / user 等其他字段仍按显式 CLI、环境、磁盘旧值的顺序补齐。
85
-
86
- `--metadata auto` reads `.ohai-report/metadata.json`, environment variables, and
87
- git context. **session_id 优先使用进程内环境变量**;`source=opencode` 且没有实时环境时,会接受同工作区且近期更新的磁盘快照,默认窗口为 1800 秒,可用 `OHAI_STORED_SESSION_MAX_AGE_SECONDS` 调整。这样 OpenCode fallback CLI 可复用插件刚写入的会话,同时避免把过期旧会话附到新 Issue。Supported environment variables include:
88
-
89
- - `OHAI_SESSION_ID`
90
- - `OPENCODE_SESSION_ID`
91
- - `LANGFUSE_SESSION_ID`
92
- - `LANGFUSE_TRACE_ID` / `TRACE_ID`
93
- - `LANGFUSE_OBSERVATION_ID` / `OHAI_OBSERVATION_ID` / `OBSERVATION_ID`
94
- - `OPENCODE_MESSAGE_ID` / `OHAI_MESSAGE_ID`(OpenCode 工具 `context.messageID`)
95
- - `OHAI_OPENCODE_SUBAGENT` / `OPENCODE_SUBAGENT`(OpenCode 工具 `context.agent`,子 Agent 名)
96
- - `LANGFUSE_URL` / `LANGFUSE_TRACE_URL`
97
- - `OHAI_USER_ID` / `LANGFUSE_USER_ID` / `USER_ID` / `USERNAME` / `USER`
98
- - `OHAI_USER_NAME`
99
- - `OHAI_TEAM`
100
-
101
- ## Sink:`--sink local`(默认)、`--sink gitcode`、`--sink webhook`
102
-
103
- ```bash
104
- python tools/ohai-report/ohai_report.py create --sink local ...
105
- python tools/ohai-report/ohai_report.py create --sink gitcode ...
106
- python tools/ohai-report/ohai_report.py create --sink webhook ...
107
- ```
108
-
109
- `gitcode` 会在远端创建 Issue 成功后,仍将带 `gitcode`/`status` 的完整 payload 写入 `.ohai-report/issues/`。
110
-
111
- `webhook` 会将 `issue.title` 与 Markdown 正文以 `application/json` POST 到配置的 Webhook。非空时包含 **`labels`** 字段,值为**逗号分隔的单个 JSON 字符串**(例如 `"tool:opencode,model:gpt,level:P2,category:其他,bug,critical"`),与常见机器人服务约定一致。其中 **`tool:` / `model:` / `level:` / `category:`** 四维由本工具根据 payload 自动拼在前面。其后标签:`--webhook-labels` 未传时合并 `issue.labels`(字符串或数组)与 `OHAI_WEBHOOK_LABELS`;传入 `--webhook-labels` 时**仅**从该串解析额外标签(不再读 issue 与环境中的 labels),维度仍前置。合并后若仍无任何标签则不发送 `labels` 字段。成功后同样写入本地 `.ohai-report/issues/`,并在 payload 中附带 `webhook` 与 `status: created-webhook`。
112
-
113
- `scripts/create_issue.py` 与 `webhook` sink 共用 `ohai_report.sinks.webhook`:可从含 `title` + `body`/`content` 的 JSON 推送到 Webhook;根字段 **`labels`** 可为字符串或数组,合并维度后以**逗号分隔字符串** POST(见 `push_legacy_issue_json_file`)。
114
-
115
- **Webhook URL** 解析顺序:`--webhook-url` → 环境变量 `OHAI_WEBHOOK_URL` / `WEBHOOK_URL` → `ohai_report/webhook_defaults.py` 的 `DEFAULT_WEBHOOK_URL`(与 `os.environ.get("WEBHOOK_URL", "<默认>")` 一致)。单次调试可传 CLI `--webhook-url`。
116
-
117
- Webhook 相关环境变量(也可用 `--webhook-secret` / `--webhook-timeout` 覆盖;secret **建议只用环境变量**):
118
-
119
- | 变量 | 含义 |
120
- | --- | --- |
121
- | `OHAI_WEBHOOK_URL` / `WEBHOOK_URL` | Webhook 地址,未设置则用 `DEFAULT_WEBHOOK_URL` |
122
- | `OHAI_WEBHOOK_SECRET` / `WEBHOOK_SECRET` | 可选,对应请求头 `X-Webhook-Secret` |
123
- | `OHAI_WEBHOOK_TIMEOUT` / `WEBHOOK_TIMEOUT` | 超时秒数,默认 `45` |
124
- | `OHAI_WEBHOOK_LABELS` | 可选,逗号分隔;与 `issue.labels` 合并进 POST 的 `labels` 字符串(传入 `--webhook-labels` 时不再合并 issue 与环境,仅 CLI 串 + 维度前缀)|
125
-
126
- 环境变量(也可用 `--gitcode-owner` 等 CLI 覆盖除 token 外的项;token **建议只用环境变量**):
127
-
128
- | 变量 | 含义 |
129
- | --- | --- |
130
- | `OHAI_GITCODE_OWNER` / `GITCODE_OWNER` | 仓库命名空间(owner path)|
131
- | `OHAI_GITCODE_REPO` / `GITCODE_REPO` | 仓库名(与 API 表单 `repo` 一致)|
132
- | `OHAI_GITCODE_TOKEN` / `GITCODE_ACCESS_TOKEN` | 访问令牌(query `access_token`)|
133
- | `OHAI_GITCODE_API_BASE` | API 根,默认 `https://api.gitcode.com` |
134
- | `OHAI_GITCODE_LABELS` | 可选,逗号分隔标签 |
135
-
136
- 当 `metadata auto` 且已有 `trace_id` 但未配置 `langfuse_url` 时,若设置了 `LANGFUSE_BASE_URL`(或 `LANGFUSE_HOST`)与 `LANGFUSE_PROJECT_ID`,CLI 会自动拼接 trace 链接。
137
-
138
- ## 测试
139
-
140
- 在项目 `tools/ohai-report` 目录下:
141
-
142
- ```bash
143
- python -m unittest discover -s tests -p "test_*.py" -v
144
- ```
145
-
146
- ## Upgrade path
147
-
148
- - GitCode sink is implemented; add Jira/DTS by following the same sink pattern.
149
- - Add or change issue template fields in `schemas/report_issue.schema.json`.
150
- - Change payload shape in `payload.py`.
151
- - Change agent-specific behavior only in `.opencode/commands` or plugins.
@@ -1,26 +0,0 @@
1
- {
2
- "title": "kimi 模型上下文消耗过快",
3
- "category": "其他",
4
- "summary": "用户在使用 kimi 模型时发现上下文(context)消耗速度过快,可能导致可用上下文窗口迅速耗尽、会话频繁中断或 token 成本显著上升。",
5
- "expected_behavior": "上下文使用可预期、可监控,长任务可稳定完成。",
6
- "actual_behavior": "上下文消耗明显快于预期,可用窗口迅速减少。",
7
- "severity": "P2",
8
- "user_description": "kimi 模型上下文消耗过快",
9
- "agent": "opencode",
10
- "model": "deepseek",
11
- "level": "P2",
12
- "scenario": "unknown",
13
- "task_type": "unknown",
14
- "workflow_phase": "unknown",
15
- "affected_role": "unknown",
16
- "primary_category": "model-capability",
17
- "sub_category": "none",
18
- "classification_confidence": "low",
19
- "classification_rationale": "上下文消耗过快可能与模型的上下文压缩、摘要策略或 token 使用效率有关,但信息不足,也可能是用户操作或具体使用场景导致。",
20
- "tags": "agent:opencode,category:model-capability,scenario:unknown,issue:poor-context-use",
21
- "impact": "上下文消耗过快会缩短单次会话的有效处理长度,增加会话中断和重启的频率,可能推高 token 使用成本。",
22
- "possible_causes": "模型缺乏有效的上下文压缩或摘要机制,导致历史消息冗余累积。\n用户单次输入或历史上下文中包含大量无关内容。\n当前信息不足,以上均为假设。",
23
- "improvement_direction": "可针对 kimi 模型的上下文管理策略进行优化,例如引入更积极的上下文压缩、智能摘要、或提供上下文使用监控与提示。",
24
- "suggested_follow_up": "具体使用场景、模型版本与平台、与其它模型的对比、会话轮数与费用表现。",
25
- "suggested_dispatch": "模型能力、产品体验、unknown"
26
- }
@@ -1,5 +0,0 @@
1
- """ohai-report package."""
2
-
3
- __all__ = ["__version__"]
4
-
5
- __version__ = "0.2.0"
@@ -1,9 +0,0 @@
1
- """Module entrypoint for `python -m ohai_report`."""
2
-
3
- from __future__ import annotations
4
-
5
- from .cli import main
6
-
7
-
8
- if __name__ == "__main__":
9
- raise SystemExit(main())