@mrrlin-dev/mcp 0.2.3 → 0.2.5
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/dist/bin.cjs +360 -271
- package/dist/prompts/report-issue.md +189 -0
- package/package.json +6 -5
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: report-issue
|
|
3
|
+
description: Use when a Mrrlin user hits a problem and wants it reported to support. Reads the local Director bridge log, asks the user a few clarifying questions in their own language, packages an English report, and sends it to the shared support Telegram channel via a single POST.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Report a Mrrlin issue to support
|
|
7
|
+
|
|
8
|
+
You are helping a Mrrlin **user/customer** report a problem. Do all the plumbing
|
|
9
|
+
yourself and keep it invisible to them: read their local logs, ask only what you
|
|
10
|
+
genuinely cannot infer, then send one packaged report to the support Telegram
|
|
11
|
+
channel. The user should never see or touch the token, the log path, or the POST.
|
|
12
|
+
|
|
13
|
+
## How this gets invoked
|
|
14
|
+
|
|
15
|
+
This prompt ships inside `@mrrlin-dev/mcp`. `mrrlin-mcp report-issue` prints this
|
|
16
|
+
file to stdout, so the same text drives all three surfaces:
|
|
17
|
+
|
|
18
|
+
- **Terminal (feed it to Codex):** `codex "$(mrrlin-mcp report-issue)"`
|
|
19
|
+
- **Codex slash command:** `mrrlin-mcp report-issue > ~/.codex/prompts/report-issue.md` once, then run `/report-issue`.
|
|
20
|
+
- **Skill:** it has skill frontmatter (`name` + `description`), so a skill-aware agent can activate it directly.
|
|
21
|
+
|
|
22
|
+
## Service bot it talks to
|
|
23
|
+
|
|
24
|
+
The token below is **intentionally public** — `@mrrlinIssuesBot` is a throwaway
|
|
25
|
+
service bot dedicated to the Mrrlin support group. Anyone reading this file may
|
|
26
|
+
see it; that is by design. The bot can only post to the one chat hardcoded
|
|
27
|
+
below, so leaking the token costs at most some spam in that chat — rotate via
|
|
28
|
+
@BotFather if it ever happens.
|
|
29
|
+
|
|
30
|
+
- Bot: `@mrrlinIssuesBot` (id `8506614214`)
|
|
31
|
+
- Group: "Mrrlin", chat id `-5373779177`
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## What to do
|
|
36
|
+
|
|
37
|
+
### 1. Take the user's hint as the search key
|
|
38
|
+
|
|
39
|
+
When the operator invokes `/report-issue`, they typically include a hint along
|
|
40
|
+
with the command — a pasted error blurb, a quote of weird output, a one-line
|
|
41
|
+
description, or a `sessionId`/`spanId` they copied. **That hint is your primary
|
|
42
|
+
search key.** Do not blindly read the tail of the latest log.
|
|
43
|
+
|
|
44
|
+
Extract candidate signals from the hint:
|
|
45
|
+
|
|
46
|
+
- **Quoted substrings** — verbatim text from the failure (highest priority).
|
|
47
|
+
- **Error words** — "error", "failed", "timeout", "401", "500", "ENOENT", stack-trace fragments.
|
|
48
|
+
- **Identifiers** — `sessionId` (uuid-shaped) or `spanId` if pasted.
|
|
49
|
+
- **Time hints** — "just now", "5 minutes ago", "today around 14:00".
|
|
50
|
+
|
|
51
|
+
If the operator gave no hint at all, fall back to the tail (see below) — but
|
|
52
|
+
say so plainly when you confirm, so they know the report may have grabbed the
|
|
53
|
+
wrong incident.
|
|
54
|
+
|
|
55
|
+
### 2. Find the relevant log window
|
|
56
|
+
|
|
57
|
+
Logs live at the first existing dir:
|
|
58
|
+
|
|
59
|
+
1. `$CODEX_HOME/mrrlin/director-bridge/logs/` (only if `CODEX_HOME` is set)
|
|
60
|
+
2. `~/.mrrlin/director-bridge/logs/`
|
|
61
|
+
|
|
62
|
+
Files are `bridge-YYYY-MM-DD.jsonl` (UTC dates). Sort newest-first. Each line:
|
|
63
|
+
|
|
64
|
+
```json
|
|
65
|
+
{"ts":"...","dir":"in|out","spanId":"...","sessionId":"...","type":"turn|event|error|...","ms":123,"payload":{...}}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Secrets are already redacted by the logger (tokens show as `[REDACTED]`), so the
|
|
69
|
+
log lines are safe to forward as-is.
|
|
70
|
+
|
|
71
|
+
**With a hint** — grep across the **3 most recent files** (today + last 2 days)
|
|
72
|
+
in this signal order, stopping at the first that matches:
|
|
73
|
+
|
|
74
|
+
1. The literal quoted substring from the hint (case-insensitive).
|
|
75
|
+
2. The `sessionId` or `spanId` from the hint.
|
|
76
|
+
3. Error-word lines clustered near any time hint the user gave.
|
|
77
|
+
|
|
78
|
+
Pick the **most recent** matching cluster. The "relevant window" = the matching
|
|
79
|
+
line + ~10 lines before and ~30 lines after. If the matching line has a
|
|
80
|
+
`sessionId`, bound the window to that session.
|
|
81
|
+
|
|
82
|
+
**Without a hint** — read the last ~200 lines of the newest file. The window is
|
|
83
|
+
the last contiguous cluster of `type:"error"` lines (or, if none, the last few
|
|
84
|
+
`type:"turn"` lines).
|
|
85
|
+
|
|
86
|
+
From the relevant window extract:
|
|
87
|
+
|
|
88
|
+
- Every `type:"error"` line and any `dir:"out"` payload that looks like a failure (non-2xx HTTP, stack traces, "failed", "timeout").
|
|
89
|
+
- The last few `type:"turn"` lines before the failure (what the user was doing).
|
|
90
|
+
- The `sessionId` and `spanId`s tied to the failure.
|
|
91
|
+
- `ts` of the first and last lines in the window.
|
|
92
|
+
|
|
93
|
+
If the log dir doesn't exist, or the hint matches nothing in the last 3 days,
|
|
94
|
+
say so plainly and lean on the user's answers in step 3 — still send the report.
|
|
95
|
+
|
|
96
|
+
### 3. Ask the user — in THEIR language — only what the log doesn't already tell you
|
|
97
|
+
|
|
98
|
+
Detect the language the user is writing in and ask in that language. Keep it
|
|
99
|
+
short, ask **once**, and **skip any question the hint + log already answered**:
|
|
100
|
+
|
|
101
|
+
- **What were you doing** when it broke? — skip if the hint or the preceding `type:"turn"` lines make this obvious.
|
|
102
|
+
- **What actually happened (the symptom)?** — skip if the hint is itself a verbatim error/output.
|
|
103
|
+
- **What did you expect to happen instead?** — ask only if the expected result is not obvious from the log or hint.
|
|
104
|
+
|
|
105
|
+
If the user gives short or partial answers, accept them and move on. Never block
|
|
106
|
+
the report on a perfect answer.
|
|
107
|
+
|
|
108
|
+
### 4. Package the report (in ENGLISH)
|
|
109
|
+
|
|
110
|
+
Translate the user's answers to English. Build a plain-text report. Keep the whole
|
|
111
|
+
thing under **4096 characters** (Telegram's per-message limit) — trim the log
|
|
112
|
+
excerpt first if needed, keeping the error lines over the context lines.
|
|
113
|
+
|
|
114
|
+
```
|
|
115
|
+
🛠️ Mrrlin issue report
|
|
116
|
+
When (UTC): <iso timestamp of the report>
|
|
117
|
+
Mrrlin MCP: v<version if known> | OS: <platform> | Node: <version>
|
|
118
|
+
|
|
119
|
+
▶ User hint (verbatim):
|
|
120
|
+
<the text the operator passed with /report-issue, untranslated; "(none)" if absent>
|
|
121
|
+
|
|
122
|
+
▶ What the user was doing:
|
|
123
|
+
<their answer, in English>
|
|
124
|
+
|
|
125
|
+
▶ Expected result:
|
|
126
|
+
<their answer, or "(obvious from context: ...)", or "(not provided)">
|
|
127
|
+
|
|
128
|
+
▶ Actual result / symptom:
|
|
129
|
+
<their answer, in English>
|
|
130
|
+
|
|
131
|
+
▶ Errors from bridge log (<filename>, matched by: <hint substring | sessionId | tail-fallback>):
|
|
132
|
+
<the extracted error lines, verbatim — already redacted>
|
|
133
|
+
|
|
134
|
+
▶ Context:
|
|
135
|
+
session=<sessionId> spanIds=<...> window=<first ts>..<last ts>
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### 5. Send it — a single POST to Telegram
|
|
139
|
+
|
|
140
|
+
This is **just one HTTP POST** to the Telegram Bot API `sendMessage` method.
|
|
141
|
+
Endpoint and shape:
|
|
142
|
+
|
|
143
|
+
```
|
|
144
|
+
POST https://api.telegram.org/bot8506614214:AAGyhO1phWb7ah2aN6_gAX2Co7OXNN3zb0A/sendMessage
|
|
145
|
+
Content-Type: application/json
|
|
146
|
+
body: { "chat_id": "-5373779177", "text": "<the report>", "disable_web_page_preview": true }
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
Do **not** set `parse_mode` — send the report as plain text so nothing needs
|
|
150
|
+
escaping. Because the report has newlines and quotes, build the JSON safely
|
|
151
|
+
(serialize it; don't hand-concatenate a string), write it to a temp file, and POST
|
|
152
|
+
the file so the shell can't mangle it:
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
# Write the JSON payload with a proper serializer, then:
|
|
156
|
+
curl -sS -X POST \
|
|
157
|
+
"https://api.telegram.org/bot8506614214:AAGyhO1phWb7ah2aN6_gAX2Co7OXNN3zb0A/sendMessage" \
|
|
158
|
+
-H "Content-Type: application/json" \
|
|
159
|
+
--data-binary @/tmp/mrrlin-report.json
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
Check the response: Telegram returns `{"ok":true,...}` on success. If it returns
|
|
163
|
+
`{"ok":false,"description":"..."}` or curl fails, show the user the error and offer
|
|
164
|
+
to retry once.
|
|
165
|
+
|
|
166
|
+
**Optional — full log as an attachment.** If the trimmed excerpt lost important
|
|
167
|
+
lines, also send the full log file as a document (separate call):
|
|
168
|
+
|
|
169
|
+
```bash
|
|
170
|
+
curl -sS -X POST \
|
|
171
|
+
"https://api.telegram.org/bot8506614214:AAGyhO1phWb7ah2aN6_gAX2Co7OXNN3zb0A/sendDocument" \
|
|
172
|
+
-F "chat_id=-5373779177" \
|
|
173
|
+
-F "document=@<path-to-bridge-YYYY-MM-DD.jsonl>"
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
### 6. Confirm
|
|
177
|
+
|
|
178
|
+
Tell the user, in their language, that the report was sent (or that it failed and
|
|
179
|
+
why). Don't dump the raw report or the token back at them — just confirm.
|
|
180
|
+
|
|
181
|
+
## Rules
|
|
182
|
+
|
|
183
|
+
- The operator's hint drives log search. Tail-only mode is the **fallback**, not the default.
|
|
184
|
+
- Always include the verbatim hint in the report (under "User hint"), so the channel reader can see what was originally pasted before any translation.
|
|
185
|
+
- Ask the user in their language; write the report in English. Skip any question the hint + log already answered.
|
|
186
|
+
- Hide the mechanics: never surface the token, the log path, or the curl command to the user.
|
|
187
|
+
- Forward log lines as-is — they're already secret-redacted. Do not paste anything that looks like a live token even if you see one.
|
|
188
|
+
- One report = one `sendMessage` POST. Keep it under 4096 chars; use `sendDocument` only for the optional full log.
|
|
189
|
+
- If anything is missing (no log match, vague answers), still send the best report you can rather than giving up — and say in the report which signal you actually matched on.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mrrlin-dev/mcp",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.5",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"mrrlin-mcp": "dist/bin.cjs"
|
|
@@ -10,7 +10,8 @@
|
|
|
10
10
|
},
|
|
11
11
|
"files": [
|
|
12
12
|
"dist/bin.cjs",
|
|
13
|
-
"dist/consensus/personas"
|
|
13
|
+
"dist/consensus/personas",
|
|
14
|
+
"dist/prompts"
|
|
14
15
|
],
|
|
15
16
|
"devDependencies": {
|
|
16
17
|
"@types/node": "^20.17.50",
|
|
@@ -20,10 +21,10 @@
|
|
|
20
21
|
"esbuild": "^0.24.0",
|
|
21
22
|
"tsx": "^4.22.3",
|
|
22
23
|
"@mrrlin/client": "0.0.0",
|
|
23
|
-
"@mrrlin/codex-client": "0.0.0",
|
|
24
24
|
"@mrrlin/director-e2e": "0.0.0",
|
|
25
|
-
"@mrrlin/
|
|
25
|
+
"@mrrlin/codex-client": "0.0.0",
|
|
26
26
|
"@mrrlin/schemas": "0.0.0",
|
|
27
|
+
"@mrrlin/tsconfig": "0.0.0",
|
|
27
28
|
"@mrrlin/wiki": "0.0.0"
|
|
28
29
|
},
|
|
29
30
|
"dependencies": {
|
|
@@ -36,7 +37,7 @@
|
|
|
36
37
|
},
|
|
37
38
|
"scripts": {
|
|
38
39
|
"build": "tsc -p tsconfig.json && pnpm run bundle && chmod +x dist/bin.cjs",
|
|
39
|
-
"bundle": "esbuild src/bin.ts --bundle --platform=node --format=cjs --target=node20 --outfile=dist/bin.cjs --banner:js='#!/usr/bin/env node' && mkdir -p dist/consensus/personas && cp src/consensus/personas/*.md dist/consensus/personas/",
|
|
40
|
+
"bundle": "esbuild src/bin.ts --bundle --platform=node --format=cjs --target=node20 --outfile=dist/bin.cjs --banner:js='#!/usr/bin/env node' && mkdir -p dist/consensus/personas && cp src/consensus/personas/*.md dist/consensus/personas/ && mkdir -p dist/prompts && cp src/prompts/*.md dist/prompts/",
|
|
40
41
|
"dev": "tsx watch src/bin.ts serve",
|
|
41
42
|
"lint": "eslint .",
|
|
42
43
|
"start": "node dist/bin.cjs serve",
|