@mrrlin-dev/mcp 0.2.6 → 0.3.1
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 +81 -0
- package/dist/bin.cjs +3748 -389
- package/dist/prompts/report-issue.md +33 -191
- package/package.json +11 -7
- package/scripts/postinstall-restart.cjs +103 -0
|
@@ -1,209 +1,51 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: report-issue
|
|
3
|
-
description:
|
|
3
|
+
description: Deprecated shell helper. Use the in-app Director `/report-issue` flow or the web header's `Report issue` entry; both file GitHub issues in fnnzzz/mrrlin.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# Report
|
|
6
|
+
# Report issue
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
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.
|
|
8
|
+
This slash-command prompt is kept only as a compatibility shim for operators who
|
|
9
|
+
already installed `/report-issue` into Codex.
|
|
12
10
|
|
|
13
|
-
##
|
|
11
|
+
## Preferred flows
|
|
14
12
|
|
|
15
|
-
|
|
16
|
-
file to stdout, so the same text drives all three surfaces:
|
|
13
|
+
Use one of the in-app flows instead of this shell prompt:
|
|
17
14
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
-
|
|
15
|
+
1. In the Director chat, run `/report-issue <what broke>`.
|
|
16
|
+
The app will package:
|
|
17
|
+
- your free-text description
|
|
18
|
+
- screenshots from the current Director turn
|
|
19
|
+
- the recent Director transcript
|
|
20
|
+
- the local Director bridge logs
|
|
21
|
+
- the active project slug and current route
|
|
21
22
|
|
|
22
|
-
|
|
23
|
+
2. In the top-right user menu, choose `Report issue`.
|
|
24
|
+
That modal lets you describe the problem in free text and attach screenshots.
|
|
25
|
+
It also packages recent Director context when available.
|
|
23
26
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
@BotFather if it ever happens.
|
|
27
|
+
Both flows rationalize the evidence locally and create a GitHub issue in
|
|
28
|
+
`fnnzzz/mrrlin` through the operator's local `gh` CLI. The issue is labelled as
|
|
29
|
+
`bug`, includes bridge-log excerpts, transcript context, screenshots, and the
|
|
30
|
+
customer-facing description.
|
|
29
31
|
|
|
30
|
-
|
|
31
|
-
- Group: "Mrrlin", chat id `-5373779177`
|
|
32
|
+
## What this legacy prompt should do
|
|
32
33
|
|
|
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
|
-
```
|
|
34
|
+
If an operator still invokes `/report-issue` from Codex directly:
|
|
67
35
|
|
|
68
|
-
|
|
69
|
-
|
|
36
|
+
- Tell them this flow is deprecated.
|
|
37
|
+
- Point them to the two in-app entry points above.
|
|
38
|
+
- Do not mention Telegram or any legacy support-bot flow.
|
|
39
|
+
- Do not invent a separate reporting pipeline.
|
|
70
40
|
|
|
71
|
-
|
|
72
|
-
in this signal order, stopping at the first that matches:
|
|
41
|
+
Use concise wording. Example:
|
|
73
42
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
3. Error-word lines clustered near any time hint the user gave.
|
|
43
|
+
```text
|
|
44
|
+
Issue reporting moved into the Mrrlin UI.
|
|
77
45
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
`sessionId`, bound the window to that session.
|
|
46
|
+
- Director chat: `/report-issue <what broke>`
|
|
47
|
+
- Header menu: `Report issue`
|
|
81
48
|
|
|
82
|
-
|
|
83
|
-
|
|
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) — every string passes through `mrrlin-mcp redact`
|
|
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
|
-
**Hard rule:** every free-form string going into the report — the user's hint,
|
|
115
|
-
their answers, the log excerpt — passes through the shipped scrubber first.
|
|
116
|
-
There is no "but the log is already redacted by the logger" exception: the hint
|
|
117
|
-
and the user's answers come from outside the logger, so they MUST be scrubbed
|
|
118
|
-
here. Run each through:
|
|
119
|
-
|
|
120
|
-
```bash
|
|
121
|
-
HINT_REDACTED=$(printf %s "$USER_HINT_RAW" | mrrlin-mcp redact)
|
|
122
|
-
EXCERPT_REDACTED=$(mrrlin-mcp redact < /tmp/excerpt-raw.txt)
|
|
123
|
-
# (repeat for each user answer)
|
|
49
|
+
Both flows attach bridge logs, transcript context, screenshots, and file a GitHub
|
|
50
|
+
issue in fnnzzz/mrrlin via your local gh CLI.
|
|
124
51
|
```
|
|
125
|
-
|
|
126
|
-
`mrrlin-mcp redact` reads stdin and writes the redacted bytes to stdout
|
|
127
|
-
(empty input → empty output, exit 0). It uses the same regex set as the
|
|
128
|
-
bridge logger (Bearer/JWT/GitHub-PAT/long-hex/long-base64). It is best-effort,
|
|
129
|
-
not a guarantee — but it is the floor below which raw text is never allowed.
|
|
130
|
-
|
|
131
|
-
Use the redacted versions to fill the template:
|
|
132
|
-
|
|
133
|
-
```
|
|
134
|
-
🛠️ Mrrlin issue report
|
|
135
|
-
When (UTC): <iso timestamp of the report>
|
|
136
|
-
Mrrlin MCP: v<version if known> | OS: <platform> | Node: <version>
|
|
137
|
-
|
|
138
|
-
▶ User hint (verbatim, post-redaction):
|
|
139
|
-
<HINT_REDACTED; "(none)" if absent>
|
|
140
|
-
|
|
141
|
-
▶ What the user was doing:
|
|
142
|
-
<their answer, in English, post-redaction>
|
|
143
|
-
|
|
144
|
-
▶ Expected result:
|
|
145
|
-
<their answer, post-redaction; or "(obvious from context: ...)"; or "(not provided)">
|
|
146
|
-
|
|
147
|
-
▶ Actual result / symptom:
|
|
148
|
-
<their answer, in English, post-redaction>
|
|
149
|
-
|
|
150
|
-
▶ Errors from bridge log (<filename>, search strategy: <hint-driven | tail-fallback>):
|
|
151
|
-
matched on: "<the exact line that triggered the cluster, truncated to 80 chars; or '(no hint provided)' for tail-fallback>"
|
|
152
|
-
<EXCERPT_REDACTED — first the error lines, then the surrounding context>
|
|
153
|
-
|
|
154
|
-
▶ Context:
|
|
155
|
-
session=<sessionId> spanIds=<...> window=<first ts>..<last ts>
|
|
156
|
-
```
|
|
157
|
-
|
|
158
|
-
### 5. Send it — a single POST to Telegram
|
|
159
|
-
|
|
160
|
-
This is **just one HTTP POST** to the Telegram Bot API `sendMessage` method.
|
|
161
|
-
Endpoint and shape:
|
|
162
|
-
|
|
163
|
-
```
|
|
164
|
-
POST https://api.telegram.org/bot8506614214:AAGyhO1phWb7ah2aN6_gAX2Co7OXNN3zb0A/sendMessage
|
|
165
|
-
Content-Type: application/json
|
|
166
|
-
body: { "chat_id": "-5373779177", "text": "<the report>", "disable_web_page_preview": true }
|
|
167
|
-
```
|
|
168
|
-
|
|
169
|
-
Do **not** set `parse_mode` — send the report as plain text so nothing needs
|
|
170
|
-
escaping. Because the report has newlines and quotes, build the JSON safely
|
|
171
|
-
(serialize it; don't hand-concatenate a string), write it to a temp file, and POST
|
|
172
|
-
the file so the shell can't mangle it:
|
|
173
|
-
|
|
174
|
-
```bash
|
|
175
|
-
# Write the JSON payload with a proper serializer, then:
|
|
176
|
-
curl -sS -X POST \
|
|
177
|
-
"https://api.telegram.org/bot8506614214:AAGyhO1phWb7ah2aN6_gAX2Co7OXNN3zb0A/sendMessage" \
|
|
178
|
-
-H "Content-Type: application/json" \
|
|
179
|
-
--data-binary @/tmp/mrrlin-report.json
|
|
180
|
-
```
|
|
181
|
-
|
|
182
|
-
Check the response: Telegram returns `{"ok":true,...}` on success. If it returns
|
|
183
|
-
`{"ok":false,"description":"..."}` or curl fails, show the user the error and offer
|
|
184
|
-
to retry once.
|
|
185
|
-
|
|
186
|
-
**Optional — full log as an attachment.** If the trimmed excerpt lost important
|
|
187
|
-
lines, also send the full log file as a document (separate call):
|
|
188
|
-
|
|
189
|
-
```bash
|
|
190
|
-
curl -sS -X POST \
|
|
191
|
-
"https://api.telegram.org/bot8506614214:AAGyhO1phWb7ah2aN6_gAX2Co7OXNN3zb0A/sendDocument" \
|
|
192
|
-
-F "chat_id=-5373779177" \
|
|
193
|
-
-F "document=@<path-to-bridge-YYYY-MM-DD.jsonl>"
|
|
194
|
-
```
|
|
195
|
-
|
|
196
|
-
### 6. Confirm
|
|
197
|
-
|
|
198
|
-
Tell the user, in their language, that the report was sent (or that it failed and
|
|
199
|
-
why). Don't dump the raw report or the token back at them — just confirm.
|
|
200
|
-
|
|
201
|
-
## Rules
|
|
202
|
-
|
|
203
|
-
- **Every string going into the Telegram body comes out of `mrrlin-mcp redact`** — the user's hint, every translated user answer, the log excerpt. If your pipeline has a path that builds the body from raw text, you are doing it wrong. The bridge logger already redacts what it writes; the hint and the user's answers do NOT come from the logger and must be scrubbed here.
|
|
204
|
-
- The operator's hint drives log search. Tail-fallback is the explicit fallback when no hint is provided.
|
|
205
|
-
- `matched on:` must contain the literal line that triggered the cluster (truncated to 80 chars), so the channel reader can verify the match instead of trusting an LLM assertion.
|
|
206
|
-
- Ask the user in their language; write the report in English. Skip any question the hint + log already answered.
|
|
207
|
-
- Hide the mechanics: never surface the token, the log path, or the curl command to the user.
|
|
208
|
-
- One report = one `sendMessage` POST. Keep it under 4096 chars; use `sendDocument` only for the optional full log.
|
|
209
|
-
- 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 search strategy you used and what `matched on:` you found.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mrrlin-dev/mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"mrrlin-mcp": "dist/bin.cjs"
|
|
@@ -11,20 +11,22 @@
|
|
|
11
11
|
"files": [
|
|
12
12
|
"dist/bin.cjs",
|
|
13
13
|
"dist/consensus/personas",
|
|
14
|
-
"dist/prompts"
|
|
14
|
+
"dist/prompts",
|
|
15
|
+
"scripts/postinstall-restart.cjs"
|
|
15
16
|
],
|
|
16
17
|
"devDependencies": {
|
|
17
18
|
"@types/node": "^20.17.50",
|
|
18
19
|
"@types/proper-lockfile": "^4.1.4",
|
|
19
20
|
"@types/qrcode": "^1.5.6",
|
|
21
|
+
"@types/semver": "^7.7.1",
|
|
20
22
|
"@types/ws": "^8.18.1",
|
|
21
23
|
"esbuild": "^0.24.0",
|
|
22
24
|
"tsx": "^4.22.3",
|
|
23
25
|
"@mrrlin/client": "0.0.0",
|
|
24
26
|
"@mrrlin/director-e2e": "0.0.0",
|
|
25
27
|
"@mrrlin/wiki": "0.0.0",
|
|
26
|
-
"@mrrlin/codex-client": "0.0.0",
|
|
27
28
|
"@mrrlin/schemas": "0.0.0",
|
|
29
|
+
"@mrrlin/codex-client": "0.0.0",
|
|
28
30
|
"@mrrlin/tsconfig": "0.0.0"
|
|
29
31
|
},
|
|
30
32
|
"dependencies": {
|
|
@@ -32,16 +34,18 @@
|
|
|
32
34
|
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
33
35
|
"proper-lockfile": "^4.1.2",
|
|
34
36
|
"qrcode": "^1.5.4",
|
|
37
|
+
"semver": "^7.8.0",
|
|
35
38
|
"ws": "^8.18.0",
|
|
36
39
|
"zod": "^4.0.0"
|
|
37
40
|
},
|
|
38
41
|
"scripts": {
|
|
39
|
-
"build": "tsc -p tsconfig.json && pnpm run bundle && chmod +x dist/bin.cjs",
|
|
40
|
-
"
|
|
42
|
+
"build": "node scripts/write-version.mjs && tsc -p tsconfig.json && pnpm run bundle && chmod +x dist/bin.cjs",
|
|
43
|
+
"postinstall": "node scripts/postinstall-restart.cjs",
|
|
44
|
+
"bundle": "node scripts/write-version.mjs && 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/",
|
|
41
45
|
"dev": "tsx watch src/bin.ts serve",
|
|
42
46
|
"lint": "eslint .",
|
|
43
47
|
"start": "node dist/bin.cjs serve",
|
|
44
|
-
"test": "node --import tsx --test $(find src -name '*.test.ts' | sort | tr '\\n' ' ')",
|
|
45
|
-
"typecheck": "pnpm --filter @mrrlin/schemas build && pnpm --filter @mrrlin/client build && pnpm --filter @mrrlin/wiki build && pnpm --filter @mrrlin/codex-client build && pnpm --filter @mrrlin/director-e2e build && tsc -p tsconfig.json --noEmit"
|
|
48
|
+
"test": "node scripts/write-version.mjs && node --import tsx --test $(find src -name '*.test.ts' | sort | tr '\\n' ' ')",
|
|
49
|
+
"typecheck": "node scripts/write-version.mjs && pnpm --filter @mrrlin/schemas build && pnpm --filter @mrrlin/client build && pnpm --filter @mrrlin/wiki build && pnpm --filter @mrrlin/codex-client build && pnpm --filter @mrrlin/director-e2e build && tsc -p tsconfig.json --noEmit"
|
|
46
50
|
}
|
|
47
51
|
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
|
|
4
|
+
// L2 postinstall nudge for `@mrrlin-dev/mcp`. Sends SIGUSR2 to every running
|
|
5
|
+
// PM2 bridge (matched by canonical name "mrrlin-bridge" OR args "director-bridge")
|
|
6
|
+
// so the bridge can drain its current Codex turn cleanly and let L1 exit on quiet.
|
|
7
|
+
//
|
|
8
|
+
// Guard rails:
|
|
9
|
+
// - Skip on CI or explicit opt-out so test-rigs don't ping running bridges.
|
|
10
|
+
// - Skip when this is NOT a global install (e.g., local `pnpm install` in the
|
|
11
|
+
// monorepo): the postinstall fires in every workspace context otherwise.
|
|
12
|
+
// - Never exit non-zero — a failed nudge must not break the install itself.
|
|
13
|
+
|
|
14
|
+
function runPostinstall() {
|
|
15
|
+
if (process.env.CI === "1" || process.env.MRRLIN_MCP_POSTINSTALL_SKIP === "1") {
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
if (process.env.npm_config_global !== "true") {
|
|
19
|
+
// Local dev install or transitive dep — do not nudge the operator's bridge.
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const { spawnSync } = require("node:child_process");
|
|
24
|
+
|
|
25
|
+
const jlist = spawnSync("pm2", ["jlist"], { encoding: "utf8" });
|
|
26
|
+
if (jlist.status !== 0) {
|
|
27
|
+
if (jlist.error && jlist.error.code === "ENOENT") {
|
|
28
|
+
console.log(
|
|
29
|
+
"[mrrlin-mcp] PM2 not available; bridge will self-update via L1 " +
|
|
30
|
+
"(default 15min interval; tune via MRRLIN_DIRECTOR_BRIDGE_SELF_UPDATE_INTERVAL_MS)",
|
|
31
|
+
);
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
console.log(
|
|
35
|
+
`[mrrlin-mcp] pm2 jlist failed (status=${jlist.status}); skipping nudge`,
|
|
36
|
+
);
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
let entries;
|
|
41
|
+
try {
|
|
42
|
+
entries = JSON.parse(jlist.stdout || "[]");
|
|
43
|
+
if (!Array.isArray(entries)) entries = [];
|
|
44
|
+
} catch (_e) {
|
|
45
|
+
console.log("[mrrlin-mcp] pm2 jlist returned unparseable JSON; skipping nudge");
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function argsIncludesDirectorBridge(args) {
|
|
50
|
+
if (typeof args === "string") return args.includes("director-bridge");
|
|
51
|
+
if (Array.isArray(args)) return args.includes("director-bridge");
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const matches = entries.filter((e) => {
|
|
56
|
+
if (!e || typeof e !== "object") return false;
|
|
57
|
+
const env = e.pm2_env || {};
|
|
58
|
+
if (env.status !== "online") return false;
|
|
59
|
+
if (e.name === "mrrlin-bridge") return true;
|
|
60
|
+
if (argsIncludesDirectorBridge(env.args)) return true;
|
|
61
|
+
return false;
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
if (matches.length === 0) {
|
|
65
|
+
console.log(
|
|
66
|
+
"[mrrlin-mcp] no running bridge to nudge; start with: mrrlin-mcp install-service",
|
|
67
|
+
);
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
for (const entry of matches) {
|
|
72
|
+
const pid = entry.pid;
|
|
73
|
+
if (typeof pid !== "number" || !Number.isInteger(pid)) {
|
|
74
|
+
console.error(`[mrrlin-mcp] skipping entry with non-integer pid: ${pid}`);
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
try {
|
|
78
|
+
process.kill(pid, "SIGUSR2");
|
|
79
|
+
console.log(
|
|
80
|
+
`[mrrlin-mcp] sent SIGUSR2 to bridge pid=${pid} (name=${entry.name}); ` +
|
|
81
|
+
"will restart on next quiet moment via L1",
|
|
82
|
+
);
|
|
83
|
+
} catch (e) {
|
|
84
|
+
console.error(
|
|
85
|
+
`[mrrlin-mcp] failed to signal pid=${pid}: ${e && e.message ? e.message : e}`,
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (require.main === module) {
|
|
92
|
+
try {
|
|
93
|
+
runPostinstall();
|
|
94
|
+
} catch (e) {
|
|
95
|
+
// Best-effort. Never break the install.
|
|
96
|
+
console.error(
|
|
97
|
+
`[mrrlin-mcp] postinstall-restart threw: ${e && e.message ? e.message : e}`,
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
process.exit(0);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
module.exports = { runPostinstall };
|