@rubytech/create-maxy-code 0.1.460 → 0.1.462
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/__tests__/cron-heartbeat-registration.test.js +57 -28
- package/dist/__tests__/launchd-plist.test.js +26 -0
- package/dist/cron-registration.js +30 -8
- package/dist/index.js +50 -9
- package/dist/launchd-plist.js +1 -1
- package/dist/uninstall.js +9 -3
- package/package.json +1 -1
- package/payload/platform/lib/graph-mcp/dist/index.d.ts +2 -1
- package/payload/platform/lib/graph-mcp/dist/index.d.ts.map +1 -1
- package/payload/platform/lib/graph-mcp/dist/index.js +14 -22
- package/payload/platform/lib/graph-mcp/dist/index.js.map +1 -1
- package/payload/platform/lib/graph-mcp/src/index.ts +15 -22
- package/payload/platform/lib/mcp-spawn-tee/dist/index.d.ts +8 -7
- package/payload/platform/lib/mcp-spawn-tee/dist/index.d.ts.map +1 -1
- package/payload/platform/lib/mcp-spawn-tee/dist/index.js +19 -19
- package/payload/platform/lib/mcp-spawn-tee/dist/index.js.map +1 -1
- package/payload/platform/lib/mcp-spawn-tee/src/__tests__/spawn-tee.test.ts +34 -5
- package/payload/platform/lib/mcp-spawn-tee/src/index.ts +22 -19
- package/payload/platform/lib/mcp-stderr-tee/dist/index.d.ts +35 -17
- package/payload/platform/lib/mcp-stderr-tee/dist/index.d.ts.map +1 -1
- package/payload/platform/lib/mcp-stderr-tee/dist/index.js +41 -48
- package/payload/platform/lib/mcp-stderr-tee/dist/index.js.map +1 -1
- package/payload/platform/lib/mcp-stderr-tee/src/index.ts +42 -51
- package/payload/platform/lib/storage-broker/dist/__tests__/audit.test.js +27 -0
- package/payload/platform/lib/storage-broker/dist/__tests__/audit.test.js.map +1 -1
- package/payload/platform/lib/storage-broker/dist/__tests__/cf-exec.test.js +49 -0
- package/payload/platform/lib/storage-broker/dist/__tests__/cf-exec.test.js.map +1 -1
- package/payload/platform/lib/storage-broker/dist/audit.d.ts +11 -0
- package/payload/platform/lib/storage-broker/dist/audit.d.ts.map +1 -1
- package/payload/platform/lib/storage-broker/dist/audit.js +16 -0
- package/payload/platform/lib/storage-broker/dist/audit.js.map +1 -1
- package/payload/platform/lib/storage-broker/dist/cf-exec.d.ts +18 -0
- package/payload/platform/lib/storage-broker/dist/cf-exec.d.ts.map +1 -1
- package/payload/platform/lib/storage-broker/dist/cf-exec.js +77 -0
- package/payload/platform/lib/storage-broker/dist/cf-exec.js.map +1 -1
- package/payload/platform/lib/storage-broker/dist/house-scoped-token.js +3 -0
- package/payload/platform/lib/storage-broker/dist/house-scoped-token.js.map +1 -1
- package/payload/platform/lib/storage-broker/dist/registry.d.ts +1 -1
- package/payload/platform/lib/storage-broker/dist/registry.d.ts.map +1 -1
- package/payload/platform/lib/storage-broker/dist/registry.js.map +1 -1
- package/payload/platform/lib/storage-broker/src/__tests__/audit.test.ts +32 -1
- package/payload/platform/lib/storage-broker/src/__tests__/cf-exec.test.ts +61 -0
- package/payload/platform/lib/storage-broker/src/audit.ts +45 -0
- package/payload/platform/lib/storage-broker/src/cf-exec.ts +91 -0
- package/payload/platform/lib/storage-broker/src/house-scoped-token.ts +3 -0
- package/payload/platform/lib/storage-broker/src/registry.ts +5 -1
- package/payload/platform/plugins/admin/lib/mcp-spawn-tee/index.js +19 -19
- package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +22 -11
- package/payload/platform/plugins/aeo/lib/mcp-spawn-tee/index.js +19 -19
- package/payload/platform/plugins/browser/lib/mcp-spawn-tee/index.js +19 -19
- package/payload/platform/plugins/cloudflare/PLUGIN.md +1 -1
- package/payload/platform/plugins/cloudflare/bin/portal-enrol.mjs +96 -0
- package/payload/platform/plugins/cloudflare/mcp/__tests__/auth-route.test.ts +54 -40
- package/payload/platform/plugins/cloudflare/mcp/__tests__/passcode.test.ts +169 -39
- package/payload/platform/plugins/cloudflare/mcp/__tests__/portal-enrol.test.ts +207 -0
- package/payload/platform/plugins/cloudflare/mcp/dist/index.js +5 -5
- package/payload/platform/plugins/cloudflare/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/cloudflare/mcp/package.json +1 -1
- package/payload/platform/plugins/cloudflare/references/hosting-sites.md +2 -0
- package/payload/platform/plugins/cloudflare/skills/calendar-site/SKILL.md +1 -1
- package/payload/platform/plugins/cloudflare/skills/data-portal/SKILL.md +21 -19
- package/payload/platform/plugins/cloudflare/skills/data-portal/template/functions/api/_lib/passcode.mjs +193 -0
- package/payload/platform/plugins/cloudflare/skills/data-portal/template/functions/api/auth.ts +18 -12
- package/payload/platform/plugins/cloudflare/skills/data-portal/template/schema.sql +14 -5
- package/payload/platform/plugins/cloudflare/skills/site-deploy/SKILL.md +2 -0
- package/payload/platform/plugins/connector/lib/mcp-spawn-tee/index.js +19 -19
- package/payload/platform/plugins/contacts/lib/mcp-spawn-tee/index.js +19 -19
- package/payload/platform/plugins/docs/references/admin-session.md +3 -3
- package/payload/platform/plugins/docs/references/cloudflare.md +2 -0
- package/payload/platform/plugins/docs/references/outlook-guide.md +11 -4
- package/payload/platform/plugins/docs/references/plugins-guide.md +8 -6
- package/payload/platform/plugins/email/lib/mcp-spawn-tee/index.js +19 -19
- package/payload/platform/plugins/filesystem/lib/mcp-spawn-tee/index.js +19 -19
- package/payload/platform/plugins/graph-viewer/lib/mcp-spawn-tee/index.js +19 -19
- package/payload/platform/plugins/memory/PLUGIN.md +1 -1
- package/payload/platform/plugins/memory/lib/mcp-spawn-tee/index.js +19 -19
- package/payload/platform/plugins/memory/mcp/dist/lib/log-ingest.js +2 -2
- package/payload/platform/plugins/memory/mcp/dist/lib/log-ingest.js.map +1 -1
- package/payload/platform/plugins/outlook/.claude-plugin/plugin.json +1 -1
- package/payload/platform/plugins/outlook/PLUGIN.md +2 -2
- package/payload/platform/plugins/outlook/lib/mcp-spawn-tee/index.js +19 -19
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/draft-threaded.test.d.ts +2 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/draft-threaded.test.d.ts.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/draft-threaded.test.js +238 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/draft-threaded.test.js.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/index.js +9 -5
- package/payload/platform/plugins/outlook/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/tools/draft.d.ts +58 -9
- package/payload/platform/plugins/outlook/mcp/dist/tools/draft.d.ts.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/tools/draft.js +113 -19
- package/payload/platform/plugins/outlook/mcp/dist/tools/draft.js.map +1 -1
- package/payload/platform/plugins/outlook/skills/outlook/SKILL.md +5 -2
- package/payload/platform/plugins/quickbooks/lib/mcp-spawn-tee/index.js +19 -19
- package/payload/platform/plugins/replicate/lib/mcp-spawn-tee/index.js +19 -19
- package/payload/platform/plugins/scheduling/lib/mcp-spawn-tee/index.js +19 -19
- package/payload/platform/plugins/storage-broker/PLUGIN.md +9 -1
- package/payload/platform/plugins/storage-broker/lib/mcp-spawn-tee/index.js +19 -19
- package/payload/platform/plugins/storage-broker/mcp/dist/confine-path.d.ts.map +1 -1
- package/payload/platform/plugins/storage-broker/mcp/dist/confine-path.js +16 -5
- package/payload/platform/plugins/storage-broker/mcp/dist/confine-path.js.map +1 -1
- package/payload/platform/plugins/storage-broker/mcp/dist/index.js +49 -0
- package/payload/platform/plugins/storage-broker/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/telegram/lib/mcp-spawn-tee/index.js +19 -19
- package/payload/platform/plugins/url-get/lib/mcp-spawn-tee/index.js +19 -19
- package/payload/platform/plugins/voice-mirror/PLUGIN.md +1 -1
- package/payload/platform/plugins/voice-mirror/lib/mcp-spawn-tee/index.js +19 -19
- package/payload/platform/plugins/voice-mirror/mcp/dist/tools/voice-distil-profile.d.ts.map +1 -1
- package/payload/platform/plugins/voice-mirror/mcp/dist/tools/voice-distil-profile.js +98 -9
- package/payload/platform/plugins/voice-mirror/mcp/dist/tools/voice-distil-profile.js.map +1 -1
- package/payload/platform/plugins/voice-mirror/mcp/dist/tools/voice-retrieve-conditioning.d.ts.map +1 -1
- package/payload/platform/plugins/voice-mirror/mcp/dist/tools/voice-retrieve-conditioning.js +54 -21
- package/payload/platform/plugins/voice-mirror/mcp/dist/tools/voice-retrieve-conditioning.js.map +1 -1
- package/payload/platform/plugins/voice-mirror/mcp/scripts/smoke.mjs +110 -0
- package/payload/platform/plugins/voice-mirror/skills/voice-mirror/SKILL.md +6 -3
- package/payload/platform/plugins/web-designer/PLUGIN.md +1 -1
- package/payload/platform/plugins/web-designer/commands/website.md +6 -0
- package/payload/platform/plugins/web-designer/skills/web-design/references/deploy.md +12 -0
- package/payload/platform/plugins/whatsapp/lib/mcp-spawn-tee/index.js +19 -19
- package/payload/platform/plugins/work/lib/mcp-spawn-tee/index.js +19 -19
- package/payload/platform/plugins/workflows/lib/mcp-spawn-tee/index.js +19 -19
- package/payload/platform/scripts/__tests__/logs-rotate.test.sh +260 -0
- package/payload/platform/scripts/__tests__/resume-tunnel.test.sh +79 -0
- package/payload/platform/scripts/logs-read.sh +31 -0
- package/payload/platform/scripts/logs-rotate.sh +207 -0
- package/payload/platform/scripts/resume-tunnel.sh +27 -0
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js +2 -0
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js.map +1 -1
- 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 +41 -5
- package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/index.d.ts +1 -0
- package/payload/platform/services/claude-session-manager/dist/index.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/index.js +22 -0
- package/payload/platform/services/claude-session-manager/dist/index.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/install-start-counter.d.ts +2 -0
- package/payload/platform/services/claude-session-manager/dist/install-start-counter.d.ts.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/install-start-counter.js +12 -0
- package/payload/platform/services/claude-session-manager/dist/install-start-counter.js.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/pty-census.d.ts +122 -9
- package/payload/platform/services/claude-session-manager/dist/pty-census.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/pty-census.js +214 -29
- package/payload/platform/services/claude-session-manager/dist/pty-census.js.map +1 -1
- 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 +39 -1
- 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 +5 -3
- package/payload/platform/services/claude-session-manager/dist/rc-daemon.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/rc-daemon.js +13 -1
- package/payload/platform/services/claude-session-manager/dist/rc-daemon.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/session-memory-cap.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/session-memory-cap.js +4 -2
- package/payload/platform/services/claude-session-manager/dist/session-memory-cap.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/slice-memory-policy.d.ts +150 -0
- package/payload/platform/services/claude-session-manager/dist/slice-memory-policy.d.ts.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/slice-memory-policy.js +333 -0
- package/payload/platform/services/claude-session-manager/dist/slice-memory-policy.js.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/start-counter.d.ts +10 -0
- package/payload/platform/services/claude-session-manager/dist/start-counter.d.ts.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/start-counter.js +55 -0
- package/payload/platform/services/claude-session-manager/dist/start-counter.js.map +1 -0
- package/payload/server/{chunk-JXWFVE5X.js → chunk-BBSPFN45.js} +65 -0
- package/payload/server/public/assets/{AdminLoginScreens-BFbpkEUS.js → AdminLoginScreens-Bed8SDxY.js} +1 -1
- package/payload/server/public/assets/{AdminShell-CdOGObaZ.js → AdminShell-BLh9O6dn.js} +1 -1
- package/payload/server/public/assets/{Checkbox-RFD_F0c0.js → Checkbox-BC_KSbpS.js} +1 -1
- package/payload/server/public/assets/{admin-CYGdL-1O.js → admin-DfWgJVI3.js} +1 -1
- package/payload/server/public/assets/{browser-DVfa_plj.js → browser-C0vkv-hH.js} +1 -1
- package/payload/server/public/assets/{calendar-JC_Dxa4n.js → calendar-_pfHw0Hp.js} +1 -1
- package/payload/server/public/assets/chat-CufidiBQ.js +1 -0
- package/payload/server/public/assets/chevron-left-BnpVBu51.js +1 -0
- package/payload/server/public/assets/data-CR-fbPWr.js +1 -0
- package/payload/server/public/assets/{graph-hBUrRSkr.js → graph-BZiudUGr.js} +1 -1
- package/payload/server/public/assets/{graph-labels-CHh6zs8t.js → graph-labels-BzmmJwCR.js} +1 -1
- package/payload/server/public/assets/{maximize-2-DjxE4rm9.js → maximize-2-Bhdsv0U-.js} +1 -1
- package/payload/server/public/assets/{operator-BqU9SQuu.js → operator-Cj0B_usT.js} +1 -1
- package/payload/server/public/assets/page-84Fdwiu_.js +32 -0
- package/payload/server/public/assets/{page-DiQhU6lD.js → page-8AB3jUa_.js} +1 -1
- package/payload/server/public/assets/{public-Cu_eALgY.js → public-BkNW9e9T.js} +1 -1
- package/payload/server/public/assets/{rotate-ccw-F9DsSTSJ.js → rotate-ccw-D_5cETGt.js} +1 -1
- package/payload/server/public/assets/{tasks-CE-D0f50.js → tasks-EyKLXINi.js} +1 -1
- package/payload/server/public/assets/{time-entry-format-D2rsWhov.js → time-entry-format-DAwmmR3i.js} +1 -1
- package/payload/server/public/assets/{useCopyFeedback-QxOmoobV.js → useCopyFeedback-rOWd_lzl.js} +1 -1
- package/payload/server/public/assets/{useSelectionMode-RIzNqFjV.js → useSelectionMode-DDmLmPph.js} +1 -1
- package/payload/server/public/assets/{useSubAccountSwitcher-BW_fK1Nt.css → useSubAccountSwitcher-pu0jjLCz.css} +1 -1
- package/payload/server/public/assets/{useVoiceRecorder-WrWurSYI.js → useVoiceRecorder-azG8zSUI.js} +1 -1
- package/payload/server/public/browser.html +5 -5
- package/payload/server/public/calendar.html +6 -6
- package/payload/server/public/chat.html +12 -12
- package/payload/server/public/data.html +10 -10
- package/payload/server/public/graph.html +11 -11
- package/payload/server/public/index.html +13 -13
- package/payload/server/public/operator.html +14 -14
- package/payload/server/public/public.html +12 -12
- package/payload/server/public/tasks.html +5 -5
- package/payload/server/server.js +581 -209
- package/payload/server/{src-4F37OHLK.js → src-YLGAZY36.js} +5 -1
- package/payload/platform/plugins/cloudflare/skills/data-portal/template/functions/api/_lib/passcode.ts +0 -73
- package/payload/server/public/assets/chat-Yf8Nkop8.js +0 -1
- package/payload/server/public/assets/chevron-left-CAiAUBxO.js +0 -1
- package/payload/server/public/assets/data-hqdYXaEn.js +0 -1
- package/payload/server/public/assets/page-B4c4_4HP.js +0 -32
- /package/payload/server/public/assets/{useSubAccountSwitcher-wo_qGW-I.js → useSubAccountSwitcher-CU-lOxTd.js} +0 -0
|
@@ -9,7 +9,8 @@
|
|
|
9
9
|
* (falls back to `${PLATFORM_ROOT}/config/.neo4j-password`, matching
|
|
10
10
|
* plugins/memory/mcp/src/lib/neo4j.ts:10-21).
|
|
11
11
|
* 2. Installs the Maxy stderr tee so upstream stderr lands in the
|
|
12
|
-
* per-conversation stream log alongside every other plugin.
|
|
12
|
+
* per-conversation stream log alongside every other plugin. The raw
|
|
13
|
+
* per-server sink is the mcp-spawn-tee shim's, not this module's.
|
|
13
14
|
* 3. Locks the upstream server into read-only mode (`NEO4J_READ_ONLY=true`)
|
|
14
15
|
* and a stable Maxy namespace (`NEO4J_NAMESPACE=maxy-graph`).
|
|
15
16
|
* 4. Parses JSON-RPC lines on the request path to record the cypher and
|
|
@@ -24,7 +25,7 @@
|
|
|
24
25
|
*/
|
|
25
26
|
|
|
26
27
|
import { execFileSync, spawn } from "node:child_process";
|
|
27
|
-
import { accessSync, appendFileSync, constants,
|
|
28
|
+
import { accessSync, appendFileSync, constants, readFileSync, statSync } from "node:fs";
|
|
28
29
|
import { resolve } from "node:path";
|
|
29
30
|
import { StringDecoder } from "node:string_decoder";
|
|
30
31
|
import { initStderrTee } from "../../mcp-stderr-tee/dist/index.js";
|
|
@@ -61,29 +62,21 @@ const UPSTREAM_PACKAGE = "mcp-neo4j-cypher@0.6.0";
|
|
|
61
62
|
|
|
62
63
|
initStderrTee(SERVER_NAME);
|
|
63
64
|
|
|
64
|
-
// Sync-write failure line to the per-
|
|
65
|
-
//
|
|
66
|
-
//
|
|
67
|
-
//
|
|
68
|
-
//
|
|
69
|
-
//
|
|
70
|
-
//
|
|
71
|
-
//
|
|
72
|
-
//
|
|
73
|
-
//
|
|
65
|
+
// Sync-write failure line to the per-conversation stream log. Used only on exit
|
|
66
|
+
// paths (missing password, uvx unresolvable, upstream spawn/exit error) where an
|
|
67
|
+
// async createWriteStream buffer would not flush before process.exit() outraces
|
|
68
|
+
// it. `appendFileSync` returns after the kernel has queued the write, so the line
|
|
69
|
+
// survives an immediate exit. Each destination is wrapped independently — an
|
|
70
|
+
// unwritable destination must not mask the primary failure.
|
|
71
|
+
//
|
|
72
|
+
// Task 1721 removed this function's own raw-file write. The final
|
|
73
|
+
// process.stderr.write goes through the writer the mcp-spawn-tee shim installed
|
|
74
|
+
// (PLUGIN.md spawns this entry under it), and that shim's appendSafe is itself
|
|
75
|
+
// an appendFileSync to the raw sink — so exit-path lines still reach disk
|
|
76
|
+
// synchronously, via one writer instead of two.
|
|
74
77
|
function syncEmit(line: string): void {
|
|
75
78
|
const msg = `[graph-mcp] ${line}`;
|
|
76
79
|
const iso = new Date().toISOString();
|
|
77
|
-
const logDir = process.env.LOG_DIR;
|
|
78
|
-
if (logDir) {
|
|
79
|
-
try {
|
|
80
|
-
mkdirSync(logDir, { recursive: true });
|
|
81
|
-
const date = iso.slice(0, 10);
|
|
82
|
-
appendFileSync(resolve(logDir, `mcp-${SERVER_NAME}-stderr-${date}.log`), `${msg}\n`);
|
|
83
|
-
} catch {
|
|
84
|
-
/* unwritable destination — preserve primary failure */
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
80
|
const streamLogPath = process.env.STREAM_LOG_PATH;
|
|
88
81
|
if (streamLogPath) {
|
|
89
82
|
try {
|
|
@@ -12,14 +12,15 @@
|
|
|
12
12
|
*
|
|
13
13
|
* Claude Code CLI → shim (this file) = node running <real-entry> in-process
|
|
14
14
|
* stdin/stdout : untouched (JSON-RPC channel)
|
|
15
|
-
* stderr : process.stderr.write teed →
|
|
15
|
+
* stderr : process.stderr.write teed → raw sink + passthrough
|
|
16
16
|
*
|
|
17
|
-
* Destinations
|
|
18
|
-
* - `${LOG_DIR}/mcp-<name
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
17
|
+
* Destinations:
|
|
18
|
+
* - `${LOG_DIR}/mcp-<name>-<SESSION_ID>.log` — raw stderr + lifecycle lines.
|
|
19
|
+
* The sole raw sink. Task 1721 retired the per-date twin: its date was
|
|
20
|
+
* pinned at spawn, no reader ever parsed it, and mcp-stderr-tee wrote the
|
|
21
|
+
* same file, so every line landed twice.
|
|
22
|
+
* - `${LOG_DIR}/mcp-<name>-nosession.log` — the same, for a spawn with
|
|
23
|
+
* no SESSION_ID (enumeration). One fixed file per server.
|
|
23
24
|
* - `server.log` via the loopback log-ingest route — best-effort mirror of
|
|
24
25
|
* the [mcp-helper] lifecycle lines.
|
|
25
26
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG"}
|
|
@@ -13,14 +13,15 @@
|
|
|
13
13
|
*
|
|
14
14
|
* Claude Code CLI → shim (this file) = node running <real-entry> in-process
|
|
15
15
|
* stdin/stdout : untouched (JSON-RPC channel)
|
|
16
|
-
* stderr : process.stderr.write teed →
|
|
16
|
+
* stderr : process.stderr.write teed → raw sink + passthrough
|
|
17
17
|
*
|
|
18
|
-
* Destinations
|
|
19
|
-
* - `${LOG_DIR}/mcp-<name
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
18
|
+
* Destinations:
|
|
19
|
+
* - `${LOG_DIR}/mcp-<name>-<SESSION_ID>.log` — raw stderr + lifecycle lines.
|
|
20
|
+
* The sole raw sink. Task 1721 retired the per-date twin: its date was
|
|
21
|
+
* pinned at spawn, no reader ever parsed it, and mcp-stderr-tee wrote the
|
|
22
|
+
* same file, so every line landed twice.
|
|
23
|
+
* - `${LOG_DIR}/mcp-<name>-nosession.log` — the same, for a spawn with
|
|
24
|
+
* no SESSION_ID (enumeration). One fixed file per server.
|
|
24
25
|
* - `server.log` via the loopback log-ingest route — best-effort mirror of
|
|
25
26
|
* the [mcp-helper] lifecycle lines.
|
|
26
27
|
*
|
|
@@ -49,13 +50,13 @@ const PLATFORM_PORT = process.env.PLATFORM_PORT;
|
|
|
49
50
|
const ENTRY = process.argv[2];
|
|
50
51
|
const SESSION_ID8 = SESSION_ID ? SESSION_ID.slice(0, 8) : "—";
|
|
51
52
|
const spawnStamp = Date.now();
|
|
52
|
-
//
|
|
53
|
-
//
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
const
|
|
58
|
-
? (0, node_path_1.resolve)(LOG_DIR, `mcp-${SERVER_NAME}
|
|
53
|
+
// The one raw sink (Task 1721). A sessionless spawn (rc-daemon stamps
|
|
54
|
+
// SESSION_ID='' — rc-daemon.ts:513 — while still stamping LOG_DIR) shares one
|
|
55
|
+
// fixed file per server rather than a date-named one: the date was never read
|
|
56
|
+
// by any reader and named a process lifetime, not a day. Interleaved spawns in
|
|
57
|
+
// the nosession file are separated by the [mcp-helper] op=spawn pid= lines.
|
|
58
|
+
const rawSinkPath = LOG_DIR
|
|
59
|
+
? (0, node_path_1.resolve)(LOG_DIR, SESSION_ID ? `mcp-${SERVER_NAME}-${SESSION_ID}.log` : `mcp-${SERVER_NAME}-nosession.log`)
|
|
59
60
|
: undefined;
|
|
60
61
|
// Rolling tail of entry stderr for op=exit. Capped so a chatty server cannot
|
|
61
62
|
// grow the buffer without bound.
|
|
@@ -66,7 +67,7 @@ let exitEmitted = false;
|
|
|
66
67
|
let exitSignal;
|
|
67
68
|
// The real stderr writer, captured before the tee replaces it. Lifecycle lines
|
|
68
69
|
// and stderr passthrough both go through this so they are never re-teed into
|
|
69
|
-
// the
|
|
70
|
+
// the raw sink nor recursed back into the patched writer.
|
|
70
71
|
const rawStderrWrite = process.stderr.write.bind(process.stderr);
|
|
71
72
|
// LOG_DIR is created once, lazily, on the first successful append — not per
|
|
72
73
|
// chunk. teeWrite runs on the server's own stderr hot path now, so a per-call
|
|
@@ -115,7 +116,7 @@ function postToServerLog(suffix, level) {
|
|
|
115
116
|
// log-ingest route rejects newlines).
|
|
116
117
|
function emitLifecycle(suffix, level) {
|
|
117
118
|
const line = `[mcp-helper] ${suffix}\n`;
|
|
118
|
-
appendSafe(
|
|
119
|
+
appendSafe(rawSinkPath, line);
|
|
119
120
|
try {
|
|
120
121
|
rawStderrWrite(line);
|
|
121
122
|
}
|
|
@@ -127,12 +128,11 @@ if (!ENTRY) {
|
|
|
127
128
|
process.exit(2);
|
|
128
129
|
}
|
|
129
130
|
// Replace process.stderr.write with a tee: mirror every server stderr byte to
|
|
130
|
-
// the
|
|
131
|
+
// the raw sink, keep a rolling tail for op=exit, emit
|
|
131
132
|
// op=boot on the first bytes, then pass the write through to the real stderr.
|
|
132
133
|
const teeWrite = ((...args) => {
|
|
133
134
|
const chunk = args[0];
|
|
134
|
-
appendSafe(
|
|
135
|
-
appendSafe(perSessionPath, chunk); // per-session raw (Task 706)
|
|
135
|
+
appendSafe(rawSinkPath, chunk); // raw sink (Task 1721)
|
|
136
136
|
const text = typeof chunk === "string" ? chunk : Buffer.from(chunk).toString("utf8");
|
|
137
137
|
stderrTail = (stderrTail + text).slice(-TAIL_CAP);
|
|
138
138
|
if (!bootEmitted) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;AACA
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -15,6 +15,9 @@ const tsc = resolve(libRoot, '..', '..', 'node_modules', '.bin', 'tsc')
|
|
|
15
15
|
beforeAll(() => {
|
|
16
16
|
execFileSync(tsc, ['-p', 'tsconfig.json'], { cwd: libRoot, stdio: 'inherit' })
|
|
17
17
|
expect(existsSync(shim)).toBe(true)
|
|
18
|
+
// The duplication guard's stub requires mcp-stderr-tee's built artifact.
|
|
19
|
+
const teeRoot = resolve(libRoot, '..', 'mcp-stderr-tee')
|
|
20
|
+
execFileSync(tsc, ['-p', 'tsconfig.json'], { cwd: teeRoot, stdio: 'inherit' })
|
|
18
21
|
})
|
|
19
22
|
|
|
20
23
|
let tmp = ''
|
|
@@ -130,13 +133,39 @@ describe('mcp-spawn-tee in-process shim', () => {
|
|
|
130
133
|
expect(r.stdout).toBe('JSONRPC-PAYLOAD')
|
|
131
134
|
})
|
|
132
135
|
|
|
133
|
-
it('
|
|
136
|
+
it('writes the nosession sink when SESSION_ID is absent', () => {
|
|
134
137
|
const { stub, logDir } = makeStub('process.stderr.write("enum-boot\\n"); process.exit(0)')
|
|
135
138
|
runSync(stub, { LOG_DIR: logDir, MCP_SPAWN_TEE_NAME: 'stub' }) // SESSION_ID forced empty by runSync
|
|
136
|
-
|
|
137
|
-
expect(
|
|
138
|
-
|
|
139
|
-
|
|
139
|
+
expect(readdirSync(logDir)).toContain('mcp-stub-nosession.log')
|
|
140
|
+
expect(readFileSync(join(logDir, 'mcp-stub-nosession.log'), 'utf8')).toContain('enum-boot')
|
|
141
|
+
})
|
|
142
|
+
|
|
143
|
+
// Task 1721 — the real spawn shape for 21 of 22 plugins: the shim patches
|
|
144
|
+
// stderr, then the entry's initStderrTee patches it again (the INIT_MARKER
|
|
145
|
+
// guard checks a symbol the shim never sets, so the patches stack). Both
|
|
146
|
+
// modules used to write mcp-<name>-stderr-<date>.log, so every line landed
|
|
147
|
+
// there twice. The sink is the only raw file, and it holds one copy.
|
|
148
|
+
it('writes one raw file holding one copy when the entry also installs initStderrTee', () => {
|
|
149
|
+
const teeDist = resolve(libRoot, '..', 'mcp-stderr-tee', 'dist', 'index.js')
|
|
150
|
+
const { stub, logDir } = makeStub(
|
|
151
|
+
`const { initStderrTee } = require(${JSON.stringify(teeDist)});\n` +
|
|
152
|
+
`initStderrTee("stub");\n` +
|
|
153
|
+
`process.stderr.write("ONCE\\n");\n` +
|
|
154
|
+
`setTimeout(() => process.exit(0), 50);\n`,
|
|
155
|
+
)
|
|
156
|
+
runSync(stub, { LOG_DIR: logDir, SESSION_ID: 'dup1', MCP_SPAWN_TEE_NAME: 'stub' })
|
|
157
|
+
// initStderrTee must contribute no second raw file of its own.
|
|
158
|
+
expect(readdirSync(logDir)).toEqual(['mcp-stub-dup1.log'])
|
|
159
|
+
const body = readFileSync(join(logDir, 'mcp-stub-dup1.log'), 'utf8')
|
|
160
|
+
// Exact-line match: op=boot carries head="ONCE" and op=exit carries
|
|
161
|
+
// stderr-tail="ONCE\n", and neither is a duplicate of the raw line.
|
|
162
|
+
expect(body.split('\n').filter((l) => l === 'ONCE')).toHaveLength(1)
|
|
163
|
+
})
|
|
164
|
+
|
|
165
|
+
it('writes no date-named sink for any spawn', () => {
|
|
166
|
+
const { stub, logDir } = makeStub('process.stderr.write("x\\n"); process.exit(0)')
|
|
167
|
+
runSync(stub, { LOG_DIR: logDir, SESSION_ID: 'sess-nodate', MCP_SPAWN_TEE_NAME: 'stub' })
|
|
168
|
+
expect(readdirSync(logDir).some((f) => /stderr-\d{4}-\d{2}-\d{2}\.log$/.test(f))).toBe(false)
|
|
140
169
|
})
|
|
141
170
|
|
|
142
171
|
it('does not crash when PLATFORM_PORT is unreachable', () => {
|
|
@@ -12,14 +12,15 @@
|
|
|
12
12
|
*
|
|
13
13
|
* Claude Code CLI → shim (this file) = node running <real-entry> in-process
|
|
14
14
|
* stdin/stdout : untouched (JSON-RPC channel)
|
|
15
|
-
* stderr : process.stderr.write teed →
|
|
15
|
+
* stderr : process.stderr.write teed → raw sink + passthrough
|
|
16
16
|
*
|
|
17
|
-
* Destinations
|
|
18
|
-
* - `${LOG_DIR}/mcp-<name
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
17
|
+
* Destinations:
|
|
18
|
+
* - `${LOG_DIR}/mcp-<name>-<SESSION_ID>.log` — raw stderr + lifecycle lines.
|
|
19
|
+
* The sole raw sink. Task 1721 retired the per-date twin: its date was
|
|
20
|
+
* pinned at spawn, no reader ever parsed it, and mcp-stderr-tee wrote the
|
|
21
|
+
* same file, so every line landed twice.
|
|
22
|
+
* - `${LOG_DIR}/mcp-<name>-nosession.log` — the same, for a spawn with
|
|
23
|
+
* no SESSION_ID (enumeration). One fixed file per server.
|
|
23
24
|
* - `server.log` via the loopback log-ingest route — best-effort mirror of
|
|
24
25
|
* the [mcp-helper] lifecycle lines.
|
|
25
26
|
*
|
|
@@ -51,13 +52,16 @@ const ENTRY = process.argv[2];
|
|
|
51
52
|
const SESSION_ID8 = SESSION_ID ? SESSION_ID.slice(0, 8) : "—";
|
|
52
53
|
const spawnStamp = Date.now();
|
|
53
54
|
|
|
54
|
-
//
|
|
55
|
-
//
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
const
|
|
60
|
-
? resolve(
|
|
55
|
+
// The one raw sink (Task 1721). A sessionless spawn (rc-daemon stamps
|
|
56
|
+
// SESSION_ID='' — rc-daemon.ts:513 — while still stamping LOG_DIR) shares one
|
|
57
|
+
// fixed file per server rather than a date-named one: the date was never read
|
|
58
|
+
// by any reader and named a process lifetime, not a day. Interleaved spawns in
|
|
59
|
+
// the nosession file are separated by the [mcp-helper] op=spawn pid= lines.
|
|
60
|
+
const rawSinkPath = LOG_DIR
|
|
61
|
+
? resolve(
|
|
62
|
+
LOG_DIR,
|
|
63
|
+
SESSION_ID ? `mcp-${SERVER_NAME}-${SESSION_ID}.log` : `mcp-${SERVER_NAME}-nosession.log`,
|
|
64
|
+
)
|
|
61
65
|
: undefined;
|
|
62
66
|
|
|
63
67
|
// Rolling tail of entry stderr for op=exit. Capped so a chatty server cannot
|
|
@@ -70,7 +74,7 @@ let exitSignal: NodeJS.Signals | undefined;
|
|
|
70
74
|
|
|
71
75
|
// The real stderr writer, captured before the tee replaces it. Lifecycle lines
|
|
72
76
|
// and stderr passthrough both go through this so they are never re-teed into
|
|
73
|
-
// the
|
|
77
|
+
// the raw sink nor recursed back into the patched writer.
|
|
74
78
|
const rawStderrWrite = process.stderr.write.bind(process.stderr);
|
|
75
79
|
|
|
76
80
|
// LOG_DIR is created once, lazily, on the first successful append — not per
|
|
@@ -116,7 +120,7 @@ function postToServerLog(suffix: string, level: "info" | "error"): void {
|
|
|
116
120
|
// log-ingest route rejects newlines).
|
|
117
121
|
function emitLifecycle(suffix: string, level: "info" | "error"): void {
|
|
118
122
|
const line = `[mcp-helper] ${suffix}\n`;
|
|
119
|
-
appendSafe(
|
|
123
|
+
appendSafe(rawSinkPath, line);
|
|
120
124
|
try { rawStderrWrite(line); } catch { /* stderr closed */ }
|
|
121
125
|
postToServerLog(suffix, level);
|
|
122
126
|
}
|
|
@@ -127,12 +131,11 @@ if (!ENTRY) {
|
|
|
127
131
|
}
|
|
128
132
|
|
|
129
133
|
// Replace process.stderr.write with a tee: mirror every server stderr byte to
|
|
130
|
-
// the
|
|
134
|
+
// the raw sink, keep a rolling tail for op=exit, emit
|
|
131
135
|
// op=boot on the first bytes, then pass the write through to the real stderr.
|
|
132
136
|
const teeWrite = ((...args: unknown[]): boolean => {
|
|
133
137
|
const chunk = args[0] as string | Uint8Array;
|
|
134
|
-
appendSafe(
|
|
135
|
-
appendSafe(perSessionPath, chunk); // per-session raw (Task 706)
|
|
138
|
+
appendSafe(rawSinkPath, chunk); // raw sink (Task 1721)
|
|
136
139
|
const text = typeof chunk === "string" ? chunk : Buffer.from(chunk).toString("utf8");
|
|
137
140
|
stderrTail = (stderrTail + text).slice(-TAIL_CAP);
|
|
138
141
|
if (!bootEmitted) {
|
|
@@ -1,10 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* MCP server stderr tee —
|
|
2
|
+
* MCP server stderr tee — per-conversation stream-log capture.
|
|
3
3
|
*
|
|
4
4
|
* Claude Code spawns MCP servers as child processes and consumes their stderr
|
|
5
5
|
* internally. The platform cannot intercept at the spawn level. Each server
|
|
6
6
|
* must tee its own stderr so diagnostic output is retrievable.
|
|
7
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
|
+
*
|
|
8
15
|
* ┌─────────────────────────┐
|
|
9
16
|
* │ MCP server process │
|
|
10
17
|
* │ │
|
|
@@ -15,18 +22,25 @@
|
|
|
15
22
|
* │ │ │
|
|
16
23
|
* │ ├──► original stderr (consumed by Claude Code — opaque)
|
|
17
24
|
* │ │
|
|
18
|
-
* │ ├──► mcp-{name}-stderr-{YYYY-MM-DD}.log (raw chunks, per-plugin)
|
|
19
|
-
* │ │
|
|
20
25
|
* │ └──► $STREAM_LOG_PATH (per-line, prefixed)
|
|
21
26
|
* │ "[<iso>] [mcp:{name}] <line>"
|
|
22
27
|
* └─────────────────────────┘
|
|
23
28
|
*
|
|
24
|
-
* $STREAM_LOG_PATH is set by the spawner
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
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.
|
|
30
44
|
*
|
|
31
45
|
* Every decision is logged via `[mcp-tee-*]` markers on both the target file
|
|
32
46
|
* and the original stderr so an investigator can confirm from the stream log
|
|
@@ -34,16 +48,20 @@
|
|
|
34
48
|
*/
|
|
35
49
|
/**
|
|
36
50
|
* Patch process.stderr.write to tee to:
|
|
37
|
-
* 1.
|
|
38
|
-
* 2. The
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
* standalone invocation). In both absent cases, stderr works unchanged —
|
|
44
|
-
* a `[mcp-tee-skip]` marker is written to original stderr so the skip is
|
|
51
|
+
* 1. The per-conversation stream log at `STREAM_LOG_PATH` — per-line, prefixed.
|
|
52
|
+
* 2. The original stderr (consumed by Claude Code) — always preserved.
|
|
53
|
+
*
|
|
54
|
+
* STREAM_LOG_PATH absent → skip the stream-log destination (older spawner or
|
|
55
|
+
* standalone invocation) and leave stderr entirely unpatched. A
|
|
56
|
+
* `[mcp-tee-skip]` marker is written to original stderr so the skip is
|
|
45
57
|
* visible to journalctl-level readers.
|
|
46
58
|
*
|
|
59
|
+
* This module writes NO raw per-server file and holds NO write stream. Task
|
|
60
|
+
* 1721 moved the raw sink to mcp-spawn-tee, which is every spawned caller's
|
|
61
|
+
* real parent: the two modules were writing the same per-date file, so every
|
|
62
|
+
* line landed twice, and the held stream was the sole reason Task 1706 could
|
|
63
|
+
* not age-purge these logs.
|
|
64
|
+
*
|
|
47
65
|
* Safe to call once at MCP server module load. Refused on second call to
|
|
48
66
|
* prevent stacking patches.
|
|
49
67
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AAeH;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAmHtD"}
|
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/**
|
|
3
|
-
* MCP server stderr tee —
|
|
3
|
+
* MCP server stderr tee — per-conversation stream-log capture.
|
|
4
4
|
*
|
|
5
5
|
* Claude Code spawns MCP servers as child processes and consumes their stderr
|
|
6
6
|
* internally. The platform cannot intercept at the spawn level. Each server
|
|
7
7
|
* must tee its own stderr so diagnostic output is retrievable.
|
|
8
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
|
+
*
|
|
9
16
|
* ┌─────────────────────────┐
|
|
10
17
|
* │ MCP server process │
|
|
11
18
|
* │ │
|
|
@@ -16,18 +23,25 @@
|
|
|
16
23
|
* │ │ │
|
|
17
24
|
* │ ├──► original stderr (consumed by Claude Code — opaque)
|
|
18
25
|
* │ │
|
|
19
|
-
* │ ├──► mcp-{name}-stderr-{YYYY-MM-DD}.log (raw chunks, per-plugin)
|
|
20
|
-
* │ │
|
|
21
26
|
* │ └──► $STREAM_LOG_PATH (per-line, prefixed)
|
|
22
27
|
* │ "[<iso>] [mcp:{name}] <line>"
|
|
23
28
|
* └─────────────────────────┘
|
|
24
29
|
*
|
|
25
|
-
* $STREAM_LOG_PATH is set by the spawner
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
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.
|
|
31
45
|
*
|
|
32
46
|
* Every decision is logged via `[mcp-tee-*]` markers on both the target file
|
|
33
47
|
* and the original stderr so an investigator can confirm from the stream log
|
|
@@ -44,21 +58,24 @@ const node_string_decoder_1 = require("node:string_decoder");
|
|
|
44
58
|
const INIT_MARKER = Symbol.for("maxy.mcpStderrTee.installed");
|
|
45
59
|
/**
|
|
46
60
|
* Patch process.stderr.write to tee to:
|
|
47
|
-
* 1.
|
|
48
|
-
* 2. The
|
|
49
|
-
* 3. The original stderr (consumed by Claude Code) — always preserved.
|
|
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.
|
|
50
63
|
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
* a `[mcp-tee-skip]` marker is written to original stderr so the skip is
|
|
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
|
|
55
67
|
* visible to journalctl-level readers.
|
|
56
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
|
+
*
|
|
57
75
|
* Safe to call once at MCP server module load. Refused on second call to
|
|
58
76
|
* prevent stacking patches.
|
|
59
77
|
*/
|
|
60
78
|
function initStderrTee(serverName) {
|
|
61
|
-
const logDir = process.env.LOG_DIR;
|
|
62
79
|
const streamLogPath = process.env.STREAM_LOG_PATH;
|
|
63
80
|
// Refuse repeat patches — stacking them would double-log every chunk
|
|
64
81
|
// and corrupt the re-entrancy guard (originalWrite would capture the
|
|
@@ -73,27 +90,7 @@ function initStderrTee(serverName) {
|
|
|
73
90
|
const skipTee = (reason, destination) => {
|
|
74
91
|
originalWrite(`${tsPrefix()} [platform] [mcp-tee-skip] server=${serverName} destination=${destination} reason=${JSON.stringify(reason)}\n`);
|
|
75
92
|
};
|
|
76
|
-
// --- Destination
|
|
77
|
-
let perServerStream;
|
|
78
|
-
if (logDir) {
|
|
79
|
-
try {
|
|
80
|
-
(0, node_fs_1.mkdirSync)(logDir, { recursive: true });
|
|
81
|
-
const date = new Date().toISOString().slice(0, 10);
|
|
82
|
-
perServerStream = (0, node_fs_1.createWriteStream)((0, node_path_1.resolve)(logDir, `mcp-${serverName}-stderr-${date}.log`), { flags: "a" });
|
|
83
|
-
perServerStream.on("error", (err) => {
|
|
84
|
-
originalWrite(`${tsPrefix()} [platform] [mcp-tee-error] server=${serverName} destination=per-server reason=${JSON.stringify(err.message)}\n`);
|
|
85
|
-
});
|
|
86
|
-
}
|
|
87
|
-
catch (err) {
|
|
88
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
89
|
-
skipTee(msg, "per-server");
|
|
90
|
-
perServerStream = undefined;
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
else {
|
|
94
|
-
skipTee("LOG_DIR not set", "per-server");
|
|
95
|
-
}
|
|
96
|
-
// --- Destination 2: per-conversation stream log
|
|
93
|
+
// --- Destination: per-conversation stream log
|
|
97
94
|
let streamLogStream;
|
|
98
95
|
if (streamLogPath) {
|
|
99
96
|
try {
|
|
@@ -116,10 +113,10 @@ function initStderrTee(serverName) {
|
|
|
116
113
|
else {
|
|
117
114
|
skipTee("STREAM_LOG_PATH not set", "stream-log");
|
|
118
115
|
}
|
|
119
|
-
//
|
|
120
|
-
//
|
|
121
|
-
//
|
|
122
|
-
if (!
|
|
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) {
|
|
123
120
|
return;
|
|
124
121
|
}
|
|
125
122
|
// Line buffer — accumulates characters written to stderr so complete
|
|
@@ -149,11 +146,7 @@ function initStderrTee(serverName) {
|
|
|
149
146
|
}
|
|
150
147
|
};
|
|
151
148
|
process.stderr.write = (chunk, ...args) => {
|
|
152
|
-
// 1.
|
|
153
|
-
if (perServerStream && !perServerStream.destroyed) {
|
|
154
|
-
perServerStream.write(chunk);
|
|
155
|
-
}
|
|
156
|
-
// 2. Stream log — per-line, prefixed.
|
|
149
|
+
// 1. Stream log — per-line, prefixed.
|
|
157
150
|
if (streamLogStream) {
|
|
158
151
|
try {
|
|
159
152
|
const text = typeof chunk === "string"
|
|
@@ -166,7 +159,7 @@ function initStderrTee(serverName) {
|
|
|
166
159
|
originalWrite(`${tsPrefix()} [platform] [mcp-tee-emit-error] server=${serverName} reason=${JSON.stringify(msg)}\n`);
|
|
167
160
|
}
|
|
168
161
|
}
|
|
169
|
-
//
|
|
162
|
+
// 2. Original stderr — Claude Code still gets what it's always got.
|
|
170
163
|
return originalWrite(chunk, ...args);
|
|
171
164
|
};
|
|
172
165
|
// Mark the patch so a second initStderrTee() call is refused at the top.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|