@rubytech/create-maxy-code 0.1.462 → 0.1.464
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/package.json +1 -1
- package/payload/platform/docs/superpowers/plans/2026-07-17-task-1736-retire-mcp-stderr-tee.md +397 -0
- package/payload/platform/docs/superpowers/specs/2026-07-17-task-1736-retire-mcp-stderr-tee-design.md +128 -0
- package/payload/platform/lib/graph-mcp/dist/index.js +5 -24
- package/payload/platform/lib/graph-mcp/dist/index.js.map +1 -1
- package/payload/platform/lib/graph-mcp/src/index.ts +7 -25
- package/payload/platform/lib/mcp-spawn-tee/dist/index.d.ts +2 -2
- package/payload/platform/lib/mcp-spawn-tee/dist/index.js +2 -2
- package/payload/platform/lib/mcp-spawn-tee/src/__tests__/spawn-tee.test.ts +0 -25
- package/payload/platform/lib/mcp-spawn-tee/src/index.ts +2 -2
- package/payload/platform/package.json +2 -2
- package/payload/platform/plugins/admin/lib/mcp-spawn-tee/index.js +2 -2
- package/payload/platform/plugins/admin/mcp/dist/index.js +0 -2
- package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +12 -30
- package/payload/platform/plugins/aeo/lib/mcp-spawn-tee/index.js +2 -2
- package/payload/platform/plugins/aeo/mcp/dist/index.js +0 -2
- package/payload/platform/plugins/aeo/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/browser/lib/mcp-spawn-tee/index.js +2 -2
- package/payload/platform/plugins/browser/mcp/dist/index.js +0 -2
- package/payload/platform/plugins/browser/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/connector/lib/mcp-spawn-tee/index.js +2 -2
- package/payload/platform/plugins/connector/mcp/dist/index.js +0 -2
- package/payload/platform/plugins/connector/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/contacts/lib/mcp-spawn-tee/index.js +2 -2
- package/payload/platform/plugins/contacts/mcp/dist/index.js +0 -2
- package/payload/platform/plugins/contacts/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/docs/references/internals.md +1 -1
- package/payload/platform/plugins/docs/references/plugins-guide.md +10 -28
- package/payload/platform/plugins/email/lib/mcp-spawn-tee/index.js +2 -2
- package/payload/platform/plugins/email/mcp/dist/index.js +0 -2
- package/payload/platform/plugins/email/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/filesystem/lib/mcp-spawn-tee/index.js +2 -2
- package/payload/platform/plugins/filesystem/mcp/dist/index.js +0 -2
- package/payload/platform/plugins/filesystem/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/graph-viewer/lib/mcp-spawn-tee/index.js +2 -2
- package/payload/platform/plugins/graph-viewer/mcp/dist/index.js +0 -2
- package/payload/platform/plugins/graph-viewer/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/memory/lib/mcp-spawn-tee/index.js +2 -2
- package/payload/platform/plugins/memory/mcp/dist/index.js +0 -2
- package/payload/platform/plugins/memory/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/scripts/boot-smoke.sh +0 -1
- package/payload/platform/plugins/outlook/lib/mcp-spawn-tee/index.js +2 -2
- package/payload/platform/plugins/outlook/mcp/dist/lib/message.d.ts +1 -6
- package/payload/platform/plugins/outlook/mcp/dist/lib/message.d.ts.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/lib/message.js +9 -17
- package/payload/platform/plugins/outlook/mcp/dist/lib/message.js.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/lib/recipients.d.ts +56 -0
- package/payload/platform/plugins/outlook/mcp/dist/lib/recipients.d.ts.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/lib/recipients.js +40 -0
- package/payload/platform/plugins/outlook/mcp/dist/lib/recipients.js.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/tools/draft-edit.d.ts.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/tools/draft-edit.js +1 -3
- package/payload/platform/plugins/outlook/mcp/dist/tools/draft-edit.js.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/tools/draft.d.ts.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/tools/draft.js +3 -18
- package/payload/platform/plugins/outlook/mcp/dist/tools/draft.js.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/tools/mail-fetch-body.d.ts.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/tools/mail-fetch-body.js +1 -3
- package/payload/platform/plugins/outlook/mcp/dist/tools/mail-fetch-body.js.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/tools/mail-reply.d.ts.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/tools/mail-reply.js +3 -18
- package/payload/platform/plugins/outlook/mcp/dist/tools/mail-reply.js.map +1 -1
- package/payload/platform/plugins/quickbooks/lib/mcp-spawn-tee/index.js +2 -2
- package/payload/platform/plugins/quickbooks/mcp/dist/index.js +0 -2
- package/payload/platform/plugins/quickbooks/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/replicate/lib/mcp-spawn-tee/index.js +2 -2
- package/payload/platform/plugins/replicate/mcp/dist/index.js +0 -2
- package/payload/platform/plugins/replicate/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/scheduling/lib/mcp-spawn-tee/index.js +2 -2
- package/payload/platform/plugins/scheduling/mcp/dist/index.js +0 -2
- package/payload/platform/plugins/scheduling/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/agent-turn-dispatch.test.js +6 -32
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/agent-turn-dispatch.test.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/agent-turn-dispatch.d.ts.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/agent-turn-dispatch.js +10 -30
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/agent-turn-dispatch.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/schedule-cancel.test.js +24 -21
- package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/schedule-cancel.test.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-cancel.d.ts +27 -18
- package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-cancel.d.ts.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-cancel.js +31 -27
- package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-cancel.js.map +1 -1
- package/payload/platform/plugins/storage-broker/lib/mcp-spawn-tee/index.js +2 -2
- package/payload/platform/plugins/storage-broker/mcp/dist/index.js +0 -2
- package/payload/platform/plugins/storage-broker/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/telegram/lib/mcp-spawn-tee/index.js +2 -2
- package/payload/platform/plugins/telegram/mcp/dist/index.js +0 -2
- package/payload/platform/plugins/telegram/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/url-get/lib/mcp-spawn-tee/index.js +2 -2
- package/payload/platform/plugins/url-get/mcp/dist/index.js +0 -2
- package/payload/platform/plugins/url-get/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/voice-mirror/lib/mcp-spawn-tee/index.js +2 -2
- package/payload/platform/plugins/voice-mirror/mcp/dist/index.d.ts.map +1 -1
- package/payload/platform/plugins/voice-mirror/mcp/dist/index.js +0 -2
- package/payload/platform/plugins/voice-mirror/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/whatsapp/lib/mcp-spawn-tee/index.js +2 -2
- package/payload/platform/plugins/whatsapp/mcp/dist/index.js +0 -2
- package/payload/platform/plugins/whatsapp/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/work/lib/mcp-spawn-tee/index.js +2 -2
- package/payload/platform/plugins/work/mcp/dist/index.js +0 -2
- package/payload/platform/plugins/work/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/workflows/lib/mcp-spawn-tee/index.js +2 -2
- package/payload/platform/plugins/workflows/mcp/dist/index.js +0 -2
- package/payload/platform/plugins/workflows/mcp/dist/index.js.map +1 -1
- package/payload/platform/scripts/__tests__/logs-rotate.test.sh +2 -2
- package/payload/platform/scripts/check-architecture-skill-no-drift.mjs +21 -14
- package/payload/platform/scripts/logs-rotate.sh +6 -6
- package/payload/platform/services/claude-session-manager/dist/http-server.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/http-server.js +23 -2
- package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/index.js +27 -2
- package/payload/platform/services/claude-session-manager/dist/index.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/jsonl-path.d.ts +8 -0
- package/payload/platform/services/claude-session-manager/dist/jsonl-path.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/jsonl-path.js +11 -0
- package/payload/platform/services/claude-session-manager/dist/jsonl-path.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/passive-print-surface.d.ts +10 -0
- package/payload/platform/services/claude-session-manager/dist/passive-print-surface.d.ts.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/passive-print-surface.js +31 -0
- package/payload/platform/services/claude-session-manager/dist/passive-print-surface.js.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/print-child-launcher.d.ts +8 -0
- package/payload/platform/services/claude-session-manager/dist/print-child-launcher.d.ts.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/print-child-launcher.js +50 -0
- package/payload/platform/services/claude-session-manager/dist/print-child-launcher.js.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts +10 -0
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.js +23 -2
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/rc-daemon.d.ts +2 -2
- package/payload/platform/services/claude-session-manager/dist/rc-daemon.d.ts.map +1 -1
- package/payload/platform/services/telegram-channel/dist/server.d.ts.map +1 -1
- package/payload/platform/services/telegram-channel/dist/server.js +0 -4
- package/payload/platform/services/telegram-channel/dist/server.js.map +1 -1
- package/payload/platform/services/webchat-channel/dist/server.d.ts.map +1 -1
- package/payload/platform/services/webchat-channel/dist/server.js +0 -4
- package/payload/platform/services/webchat-channel/dist/server.js.map +1 -1
- package/payload/platform/services/whatsapp-channel/dist/server.d.ts.map +1 -1
- package/payload/platform/services/whatsapp-channel/dist/server.js +0 -4
- package/payload/platform/services/whatsapp-channel/dist/server.js.map +1 -1
- package/payload/server/public/assets/{chat-CufidiBQ.js → chat-DYT5H81o.js} +1 -1
- package/payload/server/public/assets/{operator-Cj0B_usT.js → operator-gm2eP4r6.js} +1 -1
- package/payload/server/public/assets/page-BoPorLg-.js +32 -0
- package/payload/server/public/assets/{public-BkNW9e9T.js → public-DqJk6qgW.js} +1 -1
- package/payload/server/public/chat.html +2 -2
- package/payload/server/public/operator.html +2 -2
- package/payload/server/public/public.html +2 -2
- package/payload/server/server.js +147 -74
- package/payload/platform/lib/mcp-stderr-tee/dist/index.d.ts +0 -69
- package/payload/platform/lib/mcp-stderr-tee/dist/index.d.ts.map +0 -1
- package/payload/platform/lib/mcp-stderr-tee/dist/index.js +0 -189
- package/payload/platform/lib/mcp-stderr-tee/dist/index.js.map +0 -1
- package/payload/platform/lib/mcp-stderr-tee/package.json +0 -7
- package/payload/platform/lib/mcp-stderr-tee/src/index.ts +0 -197
- package/payload/platform/lib/mcp-stderr-tee/tsconfig.json +0 -8
- package/payload/server/public/assets/page-84Fdwiu_.js +0 -32
|
@@ -1,189 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* MCP server stderr tee — per-conversation stream-log capture.
|
|
4
|
-
*
|
|
5
|
-
* Claude Code spawns MCP servers as child processes and consumes their stderr
|
|
6
|
-
* internally. The platform cannot intercept at the spawn level. Each server
|
|
7
|
-
* must tee its own stderr so diagnostic output is retrievable.
|
|
8
|
-
*
|
|
9
|
-
* This module owns ONE destination: the per-conversation stream log. The raw
|
|
10
|
-
* per-server sink belongs to mcp-spawn-tee (`mcp-<name>-<SESSION_ID>.log`),
|
|
11
|
-
* which is every spawned caller's real parent and writes with appendFileSync.
|
|
12
|
-
* Task 1721 retired this module's own raw file: it was date-named after the
|
|
13
|
-
* process's boot day, no reader parsed that date, and mcp-spawn-tee wrote the
|
|
14
|
-
* same path, so every line landed twice.
|
|
15
|
-
*
|
|
16
|
-
* ┌─────────────────────────┐
|
|
17
|
-
* │ MCP server process │
|
|
18
|
-
* │ │
|
|
19
|
-
* │ console.error("[x] ..") │
|
|
20
|
-
* │ │ │
|
|
21
|
-
* │ ▼ │
|
|
22
|
-
* │ patched stderr.write() │
|
|
23
|
-
* │ │ │
|
|
24
|
-
* │ ├──► original stderr (consumed by Claude Code — opaque)
|
|
25
|
-
* │ │
|
|
26
|
-
* │ └──► $STREAM_LOG_PATH (per-line, prefixed)
|
|
27
|
-
* │ "[<iso>] [mcp:{name}] <line>"
|
|
28
|
-
* └─────────────────────────┘
|
|
29
|
-
*
|
|
30
|
-
* $STREAM_LOG_PATH is meant to be set by the spawner to the per-conversation
|
|
31
|
-
* stream log file. The MCP server code itself knows nothing about
|
|
32
|
-
* conversations — it just trusts the spawner's path. This is the scope
|
|
33
|
-
* boundary intended: the tee is attached per spawn, not per MCP-server process
|
|
34
|
-
* lifetime. Servers spawned for conversation A write to conversation A's file;
|
|
35
|
-
* servers for B write to B's file.
|
|
36
|
-
*
|
|
37
|
-
* NOTE: no spawner actually sets it. `pty-spawner.ts` and `rc-daemon.ts`'s
|
|
38
|
-
* `buildRcChildEnv` stamp LOG_DIR and SESSION_ID but not STREAM_LOG_PATH, and
|
|
39
|
-
* the only assignment in the repo is `plugins/memory/mcp/scripts/boot-smoke.sh`
|
|
40
|
-
* (a smoke harness). So in production this module takes its skip path and
|
|
41
|
-
* patches nothing. The raw bytes are not lost — mcp-spawn-tee writes them to
|
|
42
|
-
* the per-session sink regardless. Whether to wire this up or retire the module
|
|
43
|
-
* is Task 1736. Do not read the paragraph above as a description of live
|
|
44
|
-
* behaviour until that lands.
|
|
45
|
-
*
|
|
46
|
-
* Every decision is logged via `[mcp-tee-*]` markers on both the target file
|
|
47
|
-
* and the original stderr so an investigator can confirm from the stream log
|
|
48
|
-
* which tees were wired up, which were skipped, and why.
|
|
49
|
-
*/
|
|
50
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
51
|
-
exports.initStderrTee = initStderrTee;
|
|
52
|
-
const node_fs_1 = require("node:fs");
|
|
53
|
-
const node_path_1 = require("node:path");
|
|
54
|
-
const node_string_decoder_1 = require("node:string_decoder");
|
|
55
|
-
// Marker on process.stderr.write so repeat calls to initStderrTee() are
|
|
56
|
-
// detected at runtime, not just warned about in the docstring. A second
|
|
57
|
-
// call would stack patches and double-log every chunk.
|
|
58
|
-
const INIT_MARKER = Symbol.for("maxy.mcpStderrTee.installed");
|
|
59
|
-
/**
|
|
60
|
-
* Patch process.stderr.write to tee to:
|
|
61
|
-
* 1. The per-conversation stream log at `STREAM_LOG_PATH` — per-line, prefixed.
|
|
62
|
-
* 2. The original stderr (consumed by Claude Code) — always preserved.
|
|
63
|
-
*
|
|
64
|
-
* STREAM_LOG_PATH absent → skip the stream-log destination (older spawner or
|
|
65
|
-
* standalone invocation) and leave stderr entirely unpatched. A
|
|
66
|
-
* `[mcp-tee-skip]` marker is written to original stderr so the skip is
|
|
67
|
-
* visible to journalctl-level readers.
|
|
68
|
-
*
|
|
69
|
-
* This module writes NO raw per-server file and holds NO write stream. Task
|
|
70
|
-
* 1721 moved the raw sink to mcp-spawn-tee, which is every spawned caller's
|
|
71
|
-
* real parent: the two modules were writing the same per-date file, so every
|
|
72
|
-
* line landed twice, and the held stream was the sole reason Task 1706 could
|
|
73
|
-
* not age-purge these logs.
|
|
74
|
-
*
|
|
75
|
-
* Safe to call once at MCP server module load. Refused on second call to
|
|
76
|
-
* prevent stacking patches.
|
|
77
|
-
*/
|
|
78
|
-
function initStderrTee(serverName) {
|
|
79
|
-
const streamLogPath = process.env.STREAM_LOG_PATH;
|
|
80
|
-
// Refuse repeat patches — stacking them would double-log every chunk
|
|
81
|
-
// and corrupt the re-entrancy guard (originalWrite would capture the
|
|
82
|
-
// already-patched function on the second call).
|
|
83
|
-
if (process.stderr.write[INIT_MARKER])
|
|
84
|
-
return;
|
|
85
|
-
// Keep a direct reference to the unpatched writer. All diagnostic output
|
|
86
|
-
// from inside this module MUST go through originalWrite to avoid
|
|
87
|
-
// re-entering the patched writer (which would recurse on a tee failure).
|
|
88
|
-
const originalWrite = process.stderr.write.bind(process.stderr);
|
|
89
|
-
const tsPrefix = () => `[${new Date().toISOString()}]`;
|
|
90
|
-
const skipTee = (reason, destination) => {
|
|
91
|
-
originalWrite(`${tsPrefix()} [platform] [mcp-tee-skip] server=${serverName} destination=${destination} reason=${JSON.stringify(reason)}\n`);
|
|
92
|
-
};
|
|
93
|
-
// --- Destination: per-conversation stream log
|
|
94
|
-
let streamLogStream;
|
|
95
|
-
if (streamLogPath) {
|
|
96
|
-
try {
|
|
97
|
-
(0, node_fs_1.mkdirSync)((0, node_path_1.dirname)(streamLogPath), { recursive: true });
|
|
98
|
-
const s = (0, node_fs_1.createWriteStream)(streamLogPath, { flags: "a" });
|
|
99
|
-
s.on("error", (err) => {
|
|
100
|
-
originalWrite(`${tsPrefix()} [platform] [mcp-tee-error] server=${serverName} destination=stream-log reason=${JSON.stringify(err.message)}\n`);
|
|
101
|
-
});
|
|
102
|
-
streamLogStream = s;
|
|
103
|
-
// Attach marker lands in the stream log itself so investigators can
|
|
104
|
-
// confirm per-conversation the tee was wired up.
|
|
105
|
-
s.write(`${tsPrefix()} [platform] [mcp-tee-attach] server=${serverName} streamLogPath=${streamLogPath}\n`);
|
|
106
|
-
}
|
|
107
|
-
catch (err) {
|
|
108
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
109
|
-
skipTee(msg, "stream-log");
|
|
110
|
-
streamLogStream = undefined;
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
else {
|
|
114
|
-
skipTee("STREAM_LOG_PATH not set", "stream-log");
|
|
115
|
-
}
|
|
116
|
-
// No stream-log target → leave stderr untouched. Patching the writer to a
|
|
117
|
-
// no-op tee would still consume event-loop cycles on every write for zero
|
|
118
|
-
// observability gain.
|
|
119
|
-
if (!streamLogStream) {
|
|
120
|
-
return;
|
|
121
|
-
}
|
|
122
|
-
// Line buffer — accumulates characters written to stderr so complete
|
|
123
|
-
// newline-terminated lines can be prefixed and emitted to the stream log.
|
|
124
|
-
// Partial chunks are held until a newline arrives (or beforeExit flushes).
|
|
125
|
-
let lineBuffer = "";
|
|
126
|
-
// StringDecoder buffers trailing UTF-8 continuation bytes across chunks.
|
|
127
|
-
// Without it, a multi-byte codepoint that straddles a write boundary would
|
|
128
|
-
// render as two U+FFFD replacement characters in the stream log. Only
|
|
129
|
-
// matters when a caller writes Uint8Array chunks directly — console.error
|
|
130
|
-
// produces strings — but plugins piping child-process stderr can hit this.
|
|
131
|
-
const utf8 = new node_string_decoder_1.StringDecoder("utf8");
|
|
132
|
-
const emitCompleteLinesToStreamLog = (chunk) => {
|
|
133
|
-
if (!streamLogStream)
|
|
134
|
-
return;
|
|
135
|
-
lineBuffer += chunk;
|
|
136
|
-
let newlineIndex;
|
|
137
|
-
// eslint-disable-next-line no-cond-assign
|
|
138
|
-
while ((newlineIndex = lineBuffer.indexOf("\n")) !== -1) {
|
|
139
|
-
const line = lineBuffer.slice(0, newlineIndex);
|
|
140
|
-
lineBuffer = lineBuffer.slice(newlineIndex + 1);
|
|
141
|
-
if (line.length === 0)
|
|
142
|
-
continue; // skip blank lines
|
|
143
|
-
if (streamLogStream.destroyed || streamLogStream.writableEnded)
|
|
144
|
-
continue;
|
|
145
|
-
streamLogStream.write(`${tsPrefix()} [mcp:${serverName}] ${line}\n`);
|
|
146
|
-
}
|
|
147
|
-
};
|
|
148
|
-
process.stderr.write = (chunk, ...args) => {
|
|
149
|
-
// 1. Stream log — per-line, prefixed.
|
|
150
|
-
if (streamLogStream) {
|
|
151
|
-
try {
|
|
152
|
-
const text = typeof chunk === "string"
|
|
153
|
-
? chunk
|
|
154
|
-
: utf8.write(Buffer.from(chunk));
|
|
155
|
-
emitCompleteLinesToStreamLog(text);
|
|
156
|
-
}
|
|
157
|
-
catch (err) {
|
|
158
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
159
|
-
originalWrite(`${tsPrefix()} [platform] [mcp-tee-emit-error] server=${serverName} reason=${JSON.stringify(msg)}\n`);
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
// 2. Original stderr — Claude Code still gets what it's always got.
|
|
163
|
-
return originalWrite(chunk, ...args);
|
|
164
|
-
};
|
|
165
|
-
// Mark the patch so a second initStderrTee() call is refused at the top.
|
|
166
|
-
process.stderr.write[INIT_MARKER] = true;
|
|
167
|
-
// Flush any trailing unterminated segment on graceful event-loop drain.
|
|
168
|
-
// `beforeExit` can fire repeatedly: each async write to `streamLogStream`
|
|
169
|
-
// schedules I/O that keeps the event loop alive, which drains, which fires
|
|
170
|
-
// `beforeExit` again. With N MCP servers attached, the handler can emit
|
|
171
|
-
// thousands of detach lines per second. The `detached` flag gates the
|
|
172
|
-
// drain+detach emission to a single invocation; subsequent firings are
|
|
173
|
-
// no-ops. Buffer flushing also runs only once — partial-line state at true
|
|
174
|
-
// process exit doesn't change across re-fires.
|
|
175
|
-
let detached = false;
|
|
176
|
-
process.on("beforeExit", () => {
|
|
177
|
-
if (detached)
|
|
178
|
-
return;
|
|
179
|
-
detached = true;
|
|
180
|
-
if (streamLogStream && !streamLogStream.destroyed && !streamLogStream.writableEnded) {
|
|
181
|
-
if (lineBuffer.length > 0) {
|
|
182
|
-
streamLogStream.write(`${tsPrefix()} [mcp:${serverName}] ${lineBuffer}\n`);
|
|
183
|
-
}
|
|
184
|
-
streamLogStream.write(`${tsPrefix()} [platform] [mcp-tee-detach] server=${serverName} reason=process-before-exit\n`);
|
|
185
|
-
}
|
|
186
|
-
lineBuffer = "";
|
|
187
|
-
});
|
|
188
|
-
}
|
|
189
|
-
//# sourceMappingURL=index.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,197 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* MCP server stderr tee — per-conversation stream-log capture.
|
|
3
|
-
*
|
|
4
|
-
* Claude Code spawns MCP servers as child processes and consumes their stderr
|
|
5
|
-
* internally. The platform cannot intercept at the spawn level. Each server
|
|
6
|
-
* must tee its own stderr so diagnostic output is retrievable.
|
|
7
|
-
*
|
|
8
|
-
* This module owns ONE destination: the per-conversation stream log. The raw
|
|
9
|
-
* per-server sink belongs to mcp-spawn-tee (`mcp-<name>-<SESSION_ID>.log`),
|
|
10
|
-
* which is every spawned caller's real parent and writes with appendFileSync.
|
|
11
|
-
* Task 1721 retired this module's own raw file: it was date-named after the
|
|
12
|
-
* process's boot day, no reader parsed that date, and mcp-spawn-tee wrote the
|
|
13
|
-
* same path, so every line landed twice.
|
|
14
|
-
*
|
|
15
|
-
* ┌─────────────────────────┐
|
|
16
|
-
* │ MCP server process │
|
|
17
|
-
* │ │
|
|
18
|
-
* │ console.error("[x] ..") │
|
|
19
|
-
* │ │ │
|
|
20
|
-
* │ ▼ │
|
|
21
|
-
* │ patched stderr.write() │
|
|
22
|
-
* │ │ │
|
|
23
|
-
* │ ├──► original stderr (consumed by Claude Code — opaque)
|
|
24
|
-
* │ │
|
|
25
|
-
* │ └──► $STREAM_LOG_PATH (per-line, prefixed)
|
|
26
|
-
* │ "[<iso>] [mcp:{name}] <line>"
|
|
27
|
-
* └─────────────────────────┘
|
|
28
|
-
*
|
|
29
|
-
* $STREAM_LOG_PATH is meant to be set by the spawner to the per-conversation
|
|
30
|
-
* stream log file. The MCP server code itself knows nothing about
|
|
31
|
-
* conversations — it just trusts the spawner's path. This is the scope
|
|
32
|
-
* boundary intended: the tee is attached per spawn, not per MCP-server process
|
|
33
|
-
* lifetime. Servers spawned for conversation A write to conversation A's file;
|
|
34
|
-
* servers for B write to B's file.
|
|
35
|
-
*
|
|
36
|
-
* NOTE: no spawner actually sets it. `pty-spawner.ts` and `rc-daemon.ts`'s
|
|
37
|
-
* `buildRcChildEnv` stamp LOG_DIR and SESSION_ID but not STREAM_LOG_PATH, and
|
|
38
|
-
* the only assignment in the repo is `plugins/memory/mcp/scripts/boot-smoke.sh`
|
|
39
|
-
* (a smoke harness). So in production this module takes its skip path and
|
|
40
|
-
* patches nothing. The raw bytes are not lost — mcp-spawn-tee writes them to
|
|
41
|
-
* the per-session sink regardless. Whether to wire this up or retire the module
|
|
42
|
-
* is Task 1736. Do not read the paragraph above as a description of live
|
|
43
|
-
* behaviour until that lands.
|
|
44
|
-
*
|
|
45
|
-
* Every decision is logged via `[mcp-tee-*]` markers on both the target file
|
|
46
|
-
* and the original stderr so an investigator can confirm from the stream log
|
|
47
|
-
* which tees were wired up, which were skipped, and why.
|
|
48
|
-
*/
|
|
49
|
-
|
|
50
|
-
import {
|
|
51
|
-
mkdirSync,
|
|
52
|
-
createWriteStream,
|
|
53
|
-
type WriteStream,
|
|
54
|
-
} from "node:fs";
|
|
55
|
-
import { dirname } from "node:path";
|
|
56
|
-
import { StringDecoder } from "node:string_decoder";
|
|
57
|
-
|
|
58
|
-
// Marker on process.stderr.write so repeat calls to initStderrTee() are
|
|
59
|
-
// detected at runtime, not just warned about in the docstring. A second
|
|
60
|
-
// call would stack patches and double-log every chunk.
|
|
61
|
-
const INIT_MARKER = Symbol.for("maxy.mcpStderrTee.installed");
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* Patch process.stderr.write to tee to:
|
|
65
|
-
* 1. The per-conversation stream log at `STREAM_LOG_PATH` — per-line, prefixed.
|
|
66
|
-
* 2. The original stderr (consumed by Claude Code) — always preserved.
|
|
67
|
-
*
|
|
68
|
-
* STREAM_LOG_PATH absent → skip the stream-log destination (older spawner or
|
|
69
|
-
* standalone invocation) and leave stderr entirely unpatched. A
|
|
70
|
-
* `[mcp-tee-skip]` marker is written to original stderr so the skip is
|
|
71
|
-
* visible to journalctl-level readers.
|
|
72
|
-
*
|
|
73
|
-
* This module writes NO raw per-server file and holds NO write stream. Task
|
|
74
|
-
* 1721 moved the raw sink to mcp-spawn-tee, which is every spawned caller's
|
|
75
|
-
* real parent: the two modules were writing the same per-date file, so every
|
|
76
|
-
* line landed twice, and the held stream was the sole reason Task 1706 could
|
|
77
|
-
* not age-purge these logs.
|
|
78
|
-
*
|
|
79
|
-
* Safe to call once at MCP server module load. Refused on second call to
|
|
80
|
-
* prevent stacking patches.
|
|
81
|
-
*/
|
|
82
|
-
export function initStderrTee(serverName: string): void {
|
|
83
|
-
const streamLogPath = process.env.STREAM_LOG_PATH;
|
|
84
|
-
|
|
85
|
-
// Refuse repeat patches — stacking them would double-log every chunk
|
|
86
|
-
// and corrupt the re-entrancy guard (originalWrite would capture the
|
|
87
|
-
// already-patched function on the second call).
|
|
88
|
-
if ((process.stderr.write as unknown as { [k: symbol]: boolean })[INIT_MARKER]) return;
|
|
89
|
-
|
|
90
|
-
// Keep a direct reference to the unpatched writer. All diagnostic output
|
|
91
|
-
// from inside this module MUST go through originalWrite to avoid
|
|
92
|
-
// re-entering the patched writer (which would recurse on a tee failure).
|
|
93
|
-
const originalWrite = process.stderr.write.bind(process.stderr);
|
|
94
|
-
|
|
95
|
-
const tsPrefix = () => `[${new Date().toISOString()}]`;
|
|
96
|
-
const skipTee = (reason: string, destination: string) => {
|
|
97
|
-
originalWrite(`${tsPrefix()} [platform] [mcp-tee-skip] server=${serverName} destination=${destination} reason=${JSON.stringify(reason)}\n`);
|
|
98
|
-
};
|
|
99
|
-
|
|
100
|
-
// --- Destination: per-conversation stream log
|
|
101
|
-
let streamLogStream: WriteStream | undefined;
|
|
102
|
-
if (streamLogPath) {
|
|
103
|
-
try {
|
|
104
|
-
mkdirSync(dirname(streamLogPath), { recursive: true });
|
|
105
|
-
const s = createWriteStream(streamLogPath, { flags: "a" });
|
|
106
|
-
s.on("error", (err) => {
|
|
107
|
-
originalWrite(`${tsPrefix()} [platform] [mcp-tee-error] server=${serverName} destination=stream-log reason=${JSON.stringify(err.message)}\n`);
|
|
108
|
-
});
|
|
109
|
-
streamLogStream = s;
|
|
110
|
-
// Attach marker lands in the stream log itself so investigators can
|
|
111
|
-
// confirm per-conversation the tee was wired up.
|
|
112
|
-
s.write(`${tsPrefix()} [platform] [mcp-tee-attach] server=${serverName} streamLogPath=${streamLogPath}\n`);
|
|
113
|
-
} catch (err) {
|
|
114
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
115
|
-
skipTee(msg, "stream-log");
|
|
116
|
-
streamLogStream = undefined;
|
|
117
|
-
}
|
|
118
|
-
} else {
|
|
119
|
-
skipTee("STREAM_LOG_PATH not set", "stream-log");
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
// No stream-log target → leave stderr untouched. Patching the writer to a
|
|
123
|
-
// no-op tee would still consume event-loop cycles on every write for zero
|
|
124
|
-
// observability gain.
|
|
125
|
-
if (!streamLogStream) {
|
|
126
|
-
return;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
// Line buffer — accumulates characters written to stderr so complete
|
|
130
|
-
// newline-terminated lines can be prefixed and emitted to the stream log.
|
|
131
|
-
// Partial chunks are held until a newline arrives (or beforeExit flushes).
|
|
132
|
-
let lineBuffer = "";
|
|
133
|
-
|
|
134
|
-
// StringDecoder buffers trailing UTF-8 continuation bytes across chunks.
|
|
135
|
-
// Without it, a multi-byte codepoint that straddles a write boundary would
|
|
136
|
-
// render as two U+FFFD replacement characters in the stream log. Only
|
|
137
|
-
// matters when a caller writes Uint8Array chunks directly — console.error
|
|
138
|
-
// produces strings — but plugins piping child-process stderr can hit this.
|
|
139
|
-
const utf8 = new StringDecoder("utf8");
|
|
140
|
-
|
|
141
|
-
const emitCompleteLinesToStreamLog = (chunk: string): void => {
|
|
142
|
-
if (!streamLogStream) return;
|
|
143
|
-
lineBuffer += chunk;
|
|
144
|
-
let newlineIndex: number;
|
|
145
|
-
// eslint-disable-next-line no-cond-assign
|
|
146
|
-
while ((newlineIndex = lineBuffer.indexOf("\n")) !== -1) {
|
|
147
|
-
const line = lineBuffer.slice(0, newlineIndex);
|
|
148
|
-
lineBuffer = lineBuffer.slice(newlineIndex + 1);
|
|
149
|
-
if (line.length === 0) continue; // skip blank lines
|
|
150
|
-
if (streamLogStream.destroyed || streamLogStream.writableEnded) continue;
|
|
151
|
-
streamLogStream.write(`${tsPrefix()} [mcp:${serverName}] ${line}\n`);
|
|
152
|
-
}
|
|
153
|
-
};
|
|
154
|
-
|
|
155
|
-
process.stderr.write = (
|
|
156
|
-
chunk: string | Uint8Array,
|
|
157
|
-
...args: unknown[]
|
|
158
|
-
): boolean => {
|
|
159
|
-
// 1. Stream log — per-line, prefixed.
|
|
160
|
-
if (streamLogStream) {
|
|
161
|
-
try {
|
|
162
|
-
const text = typeof chunk === "string"
|
|
163
|
-
? chunk
|
|
164
|
-
: utf8.write(Buffer.from(chunk));
|
|
165
|
-
emitCompleteLinesToStreamLog(text);
|
|
166
|
-
} catch (err) {
|
|
167
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
168
|
-
originalWrite(`${tsPrefix()} [platform] [mcp-tee-emit-error] server=${serverName} reason=${JSON.stringify(msg)}\n`);
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
// 2. Original stderr — Claude Code still gets what it's always got.
|
|
172
|
-
return (originalWrite as (chunk: string | Uint8Array, ...a: unknown[]) => boolean)(chunk, ...args);
|
|
173
|
-
};
|
|
174
|
-
// Mark the patch so a second initStderrTee() call is refused at the top.
|
|
175
|
-
(process.stderr.write as unknown as { [k: symbol]: boolean })[INIT_MARKER] = true;
|
|
176
|
-
|
|
177
|
-
// Flush any trailing unterminated segment on graceful event-loop drain.
|
|
178
|
-
// `beforeExit` can fire repeatedly: each async write to `streamLogStream`
|
|
179
|
-
// schedules I/O that keeps the event loop alive, which drains, which fires
|
|
180
|
-
// `beforeExit` again. With N MCP servers attached, the handler can emit
|
|
181
|
-
// thousands of detach lines per second. The `detached` flag gates the
|
|
182
|
-
// drain+detach emission to a single invocation; subsequent firings are
|
|
183
|
-
// no-ops. Buffer flushing also runs only once — partial-line state at true
|
|
184
|
-
// process exit doesn't change across re-fires.
|
|
185
|
-
let detached = false;
|
|
186
|
-
process.on("beforeExit", () => {
|
|
187
|
-
if (detached) return;
|
|
188
|
-
detached = true;
|
|
189
|
-
if (streamLogStream && !streamLogStream.destroyed && !streamLogStream.writableEnded) {
|
|
190
|
-
if (lineBuffer.length > 0) {
|
|
191
|
-
streamLogStream.write(`${tsPrefix()} [mcp:${serverName}] ${lineBuffer}\n`);
|
|
192
|
-
}
|
|
193
|
-
streamLogStream.write(`${tsPrefix()} [platform] [mcp-tee-detach] server=${serverName} reason=process-before-exit\n`);
|
|
194
|
-
}
|
|
195
|
-
lineBuffer = "";
|
|
196
|
-
});
|
|
197
|
-
}
|