@rubytech/create-realagent 1.0.614 → 1.0.616

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/dist/index.js +42 -8
  2. package/package.json +1 -1
  3. package/payload/platform/config/brand.json +4 -0
  4. package/payload/platform/lib/mcp-stderr-tee/dist/index.d.ts +23 -13
  5. package/payload/platform/lib/mcp-stderr-tee/dist/index.d.ts.map +1 -1
  6. package/payload/platform/lib/mcp-stderr-tee/dist/index.js +86 -89
  7. package/payload/platform/lib/mcp-stderr-tee/dist/index.js.map +1 -1
  8. package/payload/platform/lib/mcp-stderr-tee/src/index.ts +86 -101
  9. package/payload/platform/plugins/admin/mcp/dist/index.js +33 -2
  10. package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -1
  11. package/payload/platform/plugins/admin/mcp/dist/lib/review-tools.d.ts.map +1 -1
  12. package/payload/platform/plugins/admin/mcp/dist/lib/review-tools.js +2 -0
  13. package/payload/platform/plugins/admin/mcp/dist/lib/review-tools.js.map +1 -1
  14. package/payload/platform/plugins/admin/skills/stream-log-review/SKILL.md +22 -8
  15. package/payload/platform/plugins/cloudflare/PLUGIN.md +5 -4
  16. package/payload/platform/plugins/cloudflare/mcp/__tests__/auth-binding.test.ts +196 -0
  17. package/payload/platform/plugins/cloudflare/mcp/__tests__/brand-load.test.ts +81 -0
  18. package/payload/platform/plugins/cloudflare/mcp/__tests__/manifest-scope.test.ts +65 -0
  19. package/payload/platform/plugins/cloudflare/mcp/__tests__/verify-scenario-0.test.ts +70 -0
  20. package/payload/platform/plugins/cloudflare/mcp/__tests__/verify-scenario-B.test.ts +124 -0
  21. package/payload/platform/plugins/cloudflare/mcp/dist/index.js +232 -183
  22. package/payload/platform/plugins/cloudflare/mcp/dist/index.js.map +1 -1
  23. package/payload/platform/plugins/cloudflare/mcp/dist/lib/cloudflared.d.ts +181 -30
  24. package/payload/platform/plugins/cloudflare/mcp/dist/lib/cloudflared.d.ts.map +1 -1
  25. package/payload/platform/plugins/cloudflare/mcp/dist/lib/cloudflared.js +938 -154
  26. package/payload/platform/plugins/cloudflare/mcp/dist/lib/cloudflared.js.map +1 -1
  27. package/payload/platform/plugins/cloudflare/mcp/package.json +5 -2
  28. package/payload/platform/plugins/cloudflare/mcp/vitest.config.ts +10 -0
  29. package/payload/platform/plugins/cloudflare/references/setup-guide.md +32 -27
  30. package/payload/platform/plugins/cloudflare/skills/setup-tunnel/SKILL.md +25 -3
  31. package/payload/platform/plugins/docs/PLUGIN.md +2 -0
  32. package/payload/platform/plugins/docs/references/cloudflare.md +68 -0
  33. package/payload/platform/plugins/docs/references/plugins-guide.md +8 -6
  34. package/payload/platform/plugins/docs/references/troubleshooting.md +2 -0
  35. package/payload/platform/plugins/email/mcp/dist/lib/providers.d.ts +9 -2
  36. package/payload/platform/plugins/email/mcp/dist/lib/providers.d.ts.map +1 -1
  37. package/payload/platform/plugins/email/mcp/dist/lib/providers.js +545 -92
  38. package/payload/platform/plugins/email/mcp/dist/lib/providers.js.map +1 -1
  39. package/payload/platform/scripts/logs-read.sh +114 -54
  40. package/payload/platform/templates/agents/admin/IDENTITY.md +6 -0
  41. package/payload/platform/templates/agents/public/IDENTITY.md +1 -0
  42. package/payload/platform/templates/specialists/agents/content-producer.md +4 -0
  43. package/payload/platform/templates/specialists/agents/personal-assistant.md +16 -8
  44. package/payload/platform/templates/specialists/agents/project-manager.md +4 -0
  45. package/payload/platform/templates/specialists/agents/research-assistant.md +4 -0
  46. package/payload/server/server.js +714 -125
package/dist/index.js CHANGED
@@ -906,22 +906,56 @@ function deployPayload() {
906
906
  }
907
907
  }
908
908
  }
909
- // Migrate cloudflared tunnel state from ~/.cloudflared/ to ~/{configDir}/cloudflared/.
909
+ // Migrate cloudflared state from ~/.cloudflared/ to ~/{configDir}/cloudflared/.
910
910
  // Pre-Task-441 code hardcoded ~/.cloudflared/ for all brands. On upgrade, existing
911
- // tunnel.state and cert.pem may exist at the legacy path. Copy (not move) so
912
- // cloudflared's internal use of ~/.cloudflared/ is undisturbed.
913
- // This runs for ALL brands (including default .maxy) since the legacy path was
914
- // ~/.cloudflared/ regardless of brand.
911
+ // tunnel.state and cert.pem may exist at the legacy path. Runs for ALL brands
912
+ // (including default .maxy) since the legacy path was ~/.cloudflared/ regardless of brand.
913
+ //
914
+ // tunnel.state: COPY (not move). cloudflared's `tunnel run` reads state from
915
+ // ~/.cloudflared/ when no --config is passed — emptying that path risks tunnel-startup regression.
916
+ //
917
+ // cert.pem: MOVE (copy + remove). Maxy's code always passes --origincert pointing
918
+ // at the brand path, so the legacy copy is unreferenced post-migration. Leaving it
919
+ // in place lets `tunnel-login force=true` look like a reset but silently re-import
920
+ // the stale cert on the next read (Task 531). Removing the legacy file makes the
921
+ // recovery path Task 529's pre-flight error recommends actually work.
915
922
  const legacyCloudflaredDir = resolve(process.env.HOME ?? "/root", ".cloudflared");
916
923
  const brandCloudflaredDir = join(persistentDir, "cloudflared");
917
- const MIGRATABLE_CLOUDFLARED = ["tunnel.state", "cert.pem"];
918
- for (const file of MIGRATABLE_CLOUDFLARED) {
924
+ const CLOUDFLARED_MIGRATIONS = [
925
+ { file: "tunnel.state", removeLegacy: false },
926
+ { file: "cert.pem", removeLegacy: true },
927
+ ];
928
+ for (const { file, removeLegacy } of CLOUDFLARED_MIGRATIONS) {
919
929
  const legacyFile = join(legacyCloudflaredDir, file);
920
930
  const brandFile = join(brandCloudflaredDir, file);
921
931
  if (existsSync(legacyFile) && !existsSync(brandFile)) {
922
932
  mkdirSync(brandCloudflaredDir, { recursive: true });
923
933
  cpSync(legacyFile, brandFile);
924
- console.log(` Migrated ${file} from ~/.cloudflared/ to ~/${BRAND.configDir}/cloudflared/`);
934
+ if (removeLegacy) {
935
+ // Explicit try/catch instead of rmSync({force:true}): force swallows
936
+ // EACCES/EBUSY as well as ENOENT, which would silently leave a
937
+ // root-owned legacy cert.pem in place while logging success — the
938
+ // exact silent-failure class Task 531 exists to close. Surface the
939
+ // error so the operator knows the migration is incomplete.
940
+ try {
941
+ rmSync(legacyFile);
942
+ console.log(` Migrated ${file} from ~/.cloudflared/ to ~/${BRAND.configDir}/cloudflared/ (and removed legacy copy)`);
943
+ }
944
+ catch (err) {
945
+ const code = err.code;
946
+ if (code === "ENOENT") {
947
+ // Legacy file vanished between existsSync and rmSync — benign
948
+ console.log(` Migrated ${file} from ~/.cloudflared/ to ~/${BRAND.configDir}/cloudflared/ (legacy copy already gone)`);
949
+ }
950
+ else {
951
+ console.log(` Migrated ${file} from ~/.cloudflared/ to ~/${BRAND.configDir}/cloudflared/ — WARNING: could not remove legacy ${legacyFile}: ${err}`);
952
+ console.log(` Remove manually with: sudo rm ${legacyFile}`);
953
+ }
954
+ }
955
+ }
956
+ else {
957
+ console.log(` Migrated ${file} from ~/.cloudflared/ to ~/${BRAND.configDir}/cloudflared/`);
958
+ }
925
959
  }
926
960
  }
927
961
  // Migrate Cloudflare API token from ~/.cloudflare/ to ~/{configDir}/cloudflare/.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rubytech/create-realagent",
3
- "version": "1.0.614",
3
+ "version": "1.0.616",
4
4
  "description": "Install Real Agent — Built for agents. By agents.",
5
5
  "bin": {
6
6
  "create-realagent": "./dist/index.js"
@@ -43,5 +43,9 @@
43
43
  "defaultEnabled": ["sales"],
44
44
  "available": ["deep-research", "waitlist", "projects", "whatsapp", "replicate"],
45
45
  "excluded": ["telegram"]
46
+ },
47
+
48
+ "cloudflare": {
49
+ "zones": ["realagent.network"]
46
50
  }
47
51
  }
@@ -15,27 +15,37 @@
15
15
  * │ │ │
16
16
  * │ ├──► original stderr (consumed by Claude Code — opaque)
17
17
  * │ │
18
- * │ ├──► mcp-{name}-stderr-{YYYY-MM-DD}.log (raw chunks; Task 362)
18
+ * │ ├──► mcp-{name}-stderr-{YYYY-MM-DD}.log (raw chunks, per-plugin)
19
19
  * │ │
20
- * │ └──► claude-agent-stream-{YYYY-MM-DD}.log (per-line, prefixed; Task 524)
20
+ * │ └──► $STREAM_LOG_PATH (per-line, prefixed)
21
21
  * │ "[<iso>] [mcp:{name}] <line>"
22
- * │ rotates on date boundary
23
22
  * └─────────────────────────┘
24
23
  *
25
- * The stream-log destination puts MCP diagnostic lines in the same file the
26
- * platform already writes agent events to, so a single logs-read returns a
27
- * complete session timeline. The per-server file is retained unchanged
28
- * it remains the grep-one-plugin surface.
24
+ * $STREAM_LOG_PATH is set by the spawner (`getMcpServers` in `claude-agent.ts`)
25
+ * to the per-conversation stream log file. The MCP server code itself knows
26
+ * nothing about conversations it just trusts the spawner's path. This is
27
+ * the scope boundary introduced by Task 532: the tee is attached per spawn,
28
+ * not per MCP-server process lifetime. Servers spawned for conversation A
29
+ * write to conversation A's file; servers for B write to B's file.
30
+ *
31
+ * Every decision is logged via `[mcp-tee-*]` markers on both the target file
32
+ * and the original stderr so an investigator can confirm from the stream log
33
+ * which tees were wired up, which were skipped, and why.
29
34
  */
30
35
  /**
31
- * Patch process.stderr.write to tee to both a per-server raw log and the
32
- * unified claude-agent-stream log (with a [mcp:<serverName>] prefix).
36
+ * Patch process.stderr.write to tee to:
37
+ * 1. Per-server raw log (`mcp-<serverName>-stderr-<date>.log` under LOG_DIR).
38
+ * 2. The per-conversation stream log at `STREAM_LOG_PATH` — per-line, prefixed.
39
+ * 3. The original stderr (consumed by Claude Code) — always preserved.
33
40
  *
34
- * Reads LOG_DIR from environment. When absent (dev mode, tool discovery),
35
- * does nothing stderr works as before with no markers emitted.
41
+ * LOG_DIR absent skip per-server raw file (dev mode / tool discovery).
42
+ * STREAM_LOG_PATH absent skip stream-log destination (older spawner or
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
45
+ * visible to journalctl-level readers.
36
46
  *
37
- * Safe to call once at MCP server module load. Not safe to call twice —
38
- * repeated calls would stack patches and double-log every chunk.
47
+ * Safe to call once at MCP server module load. Refused on second call to
48
+ * prevent stacking patches.
39
49
  */
40
50
  export declare function initStderrTee(serverName: string): void;
41
51
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAeH;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAkKtD"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAeH;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAyItD"}
@@ -16,17 +16,22 @@
16
16
  * │ │ │
17
17
  * │ ├──► original stderr (consumed by Claude Code — opaque)
18
18
  * │ │
19
- * │ ├──► mcp-{name}-stderr-{YYYY-MM-DD}.log (raw chunks; Task 362)
19
+ * │ ├──► mcp-{name}-stderr-{YYYY-MM-DD}.log (raw chunks, per-plugin)
20
20
  * │ │
21
- * │ └──► claude-agent-stream-{YYYY-MM-DD}.log (per-line, prefixed; Task 524)
21
+ * │ └──► $STREAM_LOG_PATH (per-line, prefixed)
22
22
  * │ "[<iso>] [mcp:{name}] <line>"
23
- * │ rotates on date boundary
24
23
  * └─────────────────────────┘
25
24
  *
26
- * The stream-log destination puts MCP diagnostic lines in the same file the
27
- * platform already writes agent events to, so a single logs-read returns a
28
- * complete session timeline. The per-server file is retained unchanged
29
- * it remains the grep-one-plugin surface.
25
+ * $STREAM_LOG_PATH is set by the spawner (`getMcpServers` in `claude-agent.ts`)
26
+ * to the per-conversation stream log file. The MCP server code itself knows
27
+ * nothing about conversations it just trusts the spawner's path. This is
28
+ * the scope boundary introduced by Task 532: the tee is attached per spawn,
29
+ * not per MCP-server process lifetime. Servers spawned for conversation A
30
+ * write to conversation A's file; servers for B write to B's file.
31
+ *
32
+ * Every decision is logged via `[mcp-tee-*]` markers on both the target file
33
+ * and the original stderr so an investigator can confirm from the stream log
34
+ * which tees were wired up, which were skipped, and why.
30
35
  */
31
36
  Object.defineProperty(exports, "__esModule", { value: true });
32
37
  exports.initStderrTee = initStderrTee;
@@ -38,19 +43,23 @@ const node_string_decoder_1 = require("node:string_decoder");
38
43
  // call would stack patches and double-log every chunk.
39
44
  const INIT_MARKER = Symbol.for("maxy.mcpStderrTee.installed");
40
45
  /**
41
- * Patch process.stderr.write to tee to both a per-server raw log and the
42
- * unified claude-agent-stream log (with a [mcp:<serverName>] prefix).
46
+ * Patch process.stderr.write to tee to:
47
+ * 1. Per-server raw log (`mcp-<serverName>-stderr-<date>.log` under LOG_DIR).
48
+ * 2. The per-conversation stream log at `STREAM_LOG_PATH` — per-line, prefixed.
49
+ * 3. The original stderr (consumed by Claude Code) — always preserved.
43
50
  *
44
- * Reads LOG_DIR from environment. When absent (dev mode, tool discovery),
45
- * does nothing stderr works as before with no markers emitted.
51
+ * LOG_DIR absent skip per-server raw file (dev mode / tool discovery).
52
+ * STREAM_LOG_PATH absent skip stream-log destination (older spawner or
53
+ * standalone invocation). In both absent cases, stderr works unchanged —
54
+ * a `[mcp-tee-skip]` marker is written to original stderr so the skip is
55
+ * visible to journalctl-level readers.
46
56
  *
47
- * Safe to call once at MCP server module load. Not safe to call twice —
48
- * repeated calls would stack patches and double-log every chunk.
57
+ * Safe to call once at MCP server module load. Refused on second call to
58
+ * prevent stacking patches.
49
59
  */
50
60
  function initStderrTee(serverName) {
51
61
  const logDir = process.env.LOG_DIR;
52
- if (!logDir)
53
- return; // Dev mode or tool discovery — stderr only
62
+ const streamLogPath = process.env.STREAM_LOG_PATH;
54
63
  // Refuse repeat patches — stacking them would double-log every chunk
55
64
  // and corrupt the re-entrancy guard (originalWrite would capture the
56
65
  // already-patched function on the second call).
@@ -60,74 +69,59 @@ function initStderrTee(serverName) {
60
69
  // from inside this module MUST go through originalWrite to avoid
61
70
  // re-entering the patched writer (which would recurse on a tee failure).
62
71
  const originalWrite = process.stderr.write.bind(process.stderr);
63
- // Per-server raw-chunk file (Task 362). Opened once, never rotated —
64
- // preserves existing behaviour.
72
+ const tsPrefix = () => `[${new Date().toISOString()}]`;
73
+ const skipTee = (reason, destination) => {
74
+ originalWrite(`${tsPrefix()} [platform] [mcp-tee-skip] server=${serverName} destination=${destination} reason=${JSON.stringify(reason)}\n`);
75
+ };
76
+ // --- Destination 1: per-server raw file (optional, existing Task 362 behaviour)
65
77
  let perServerStream;
66
- try {
67
- (0, node_fs_1.mkdirSync)(logDir, { recursive: true });
68
- const date = new Date().toISOString().slice(0, 10);
69
- perServerStream = (0, node_fs_1.createWriteStream)((0, node_path_1.resolve)(logDir, `mcp-${serverName}-stderr-${date}.log`), { flags: "a" });
70
- perServerStream.on("error", (err) => {
71
- originalWrite(`[${new Date().toISOString()}] [platform] mcp stream tee per-server write error server=${serverName} reason=${err.message}\n`);
72
- });
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
+ }
73
92
  }
74
- catch (err) {
75
- const msg = err instanceof Error ? err.message : String(err);
76
- originalWrite(`[${new Date().toISOString()}] [platform] mcp stream tee disabled reason=${msg} server=${serverName} destination=per-server\n`);
77
- // If the per-server file can't be opened, the LOG_DIR itself is likely
78
- // unusable — give up on the whole tee rather than half-install it.
79
- return;
93
+ else {
94
+ skipTee("LOG_DIR not set", "per-server");
80
95
  }
81
- // Stream-log destination (Task 524). Lazily re-opened on date boundary so
82
- // a long-lived MCP server started yesterday routes today's output into
83
- // today's stream-log file, matching the platform's rotation semantics.
96
+ // --- Destination 2: per-conversation stream log (Task 532)
84
97
  let streamLogStream;
85
- let streamLogDate = ""; // YYYY-MM-DD the current stream was opened for
86
- let streamLogDisabledReason;
87
- const openStreamLog = () => {
88
- const today = new Date().toISOString().slice(0, 10);
89
- if (streamLogStream && streamLogDate === today)
90
- return streamLogStream;
91
- // Date boundary crossed (or first open). Close the old stream before
92
- // opening the new one so the file descriptor is released. Also clear
93
- // any prior disabled reason — the previous failure may have been
94
- // transient (EMFILE, ENOSPC), and the new day's path is fresh.
95
- if (streamLogStream && streamLogDate !== today) {
96
- try {
97
- streamLogStream.end();
98
- }
99
- catch { /* ignore */ }
100
- streamLogStream = undefined;
101
- streamLogDisabledReason = undefined;
102
- }
103
- if (streamLogDisabledReason)
104
- return undefined;
105
- const path = (0, node_path_1.resolve)(logDir, `claude-agent-stream-${today}.log`);
98
+ if (streamLogPath) {
106
99
  try {
107
- const s = (0, node_fs_1.createWriteStream)(path, { flags: "a" });
100
+ (0, node_fs_1.mkdirSync)((0, node_path_1.dirname)(streamLogPath), { recursive: true });
101
+ const s = (0, node_fs_1.createWriteStream)(streamLogPath, { flags: "a" });
108
102
  s.on("error", (err) => {
109
- originalWrite(`[${new Date().toISOString()}] [platform] mcp stream tee stream-log write error server=${serverName} reason=${err.message}\n`);
103
+ originalWrite(`${tsPrefix()} [platform] [mcp-tee-error] server=${serverName} destination=stream-log reason=${JSON.stringify(err.message)}\n`);
110
104
  });
111
105
  streamLogStream = s;
112
- streamLogDate = today;
113
- // Startup marker lands in the stream log itself so investigators reading
114
- // a session's stream-log file can confirm the tee was wired up.
115
- s.write(`[${new Date().toISOString()}] [platform] attaching mcp stream tee for server=${serverName} logPath=${path}\n`);
116
- return s;
106
+ // Attach marker lands in the stream log itself so investigators can
107
+ // confirm per-conversation the tee was wired up.
108
+ s.write(`${tsPrefix()} [platform] [mcp-tee-attach] server=${serverName} streamLogPath=${streamLogPath}\n`);
117
109
  }
118
110
  catch (err) {
119
111
  const msg = err instanceof Error ? err.message : String(err);
120
- streamLogDisabledReason = msg;
121
- const line = `[${new Date().toISOString()}] [platform] mcp stream tee disabled reason=${msg} server=${serverName} destination=stream-log\n`;
122
- originalWrite(line);
123
- if (perServerStream && !perServerStream.destroyed)
124
- perServerStream.write(line);
125
- return undefined;
112
+ skipTee(msg, "stream-log");
113
+ streamLogStream = undefined;
126
114
  }
127
- };
128
- // Prime the stream log once so the startup marker appears immediately
129
- // rather than waiting for the first stderr chunk.
130
- openStreamLog();
115
+ }
116
+ else {
117
+ skipTee("STREAM_LOG_PATH not set", "stream-log");
118
+ }
119
+ // If neither tee target is available, leave stderr untouched — patching
120
+ // the writer to a no-op tee would still consume event-loop cycles on
121
+ // every write for zero observability gain.
122
+ if (!perServerStream && !streamLogStream) {
123
+ return;
124
+ }
131
125
  // Line buffer — accumulates characters written to stderr so complete
132
126
  // newline-terminated lines can be prefixed and emitted to the stream log.
133
127
  // Partial chunks are held until a newline arrives (or beforeExit flushes).
@@ -139,6 +133,8 @@ function initStderrTee(serverName) {
139
133
  // produces strings — but plugins piping child-process stderr can hit this.
140
134
  const utf8 = new node_string_decoder_1.StringDecoder("utf8");
141
135
  const emitCompleteLinesToStreamLog = (chunk) => {
136
+ if (!streamLogStream)
137
+ return;
142
138
  lineBuffer += chunk;
143
139
  let newlineIndex;
144
140
  // eslint-disable-next-line no-cond-assign
@@ -147,10 +143,9 @@ function initStderrTee(serverName) {
147
143
  lineBuffer = lineBuffer.slice(newlineIndex + 1);
148
144
  if (line.length === 0)
149
145
  continue; // skip blank lines
150
- const stream = openStreamLog();
151
- if (!stream || stream.destroyed || stream.writableEnded)
146
+ if (streamLogStream.destroyed || streamLogStream.writableEnded)
152
147
  continue;
153
- stream.write(`[${new Date().toISOString()}] [mcp:${serverName}] ${line}\n`);
148
+ streamLogStream.write(`${tsPrefix()} [mcp:${serverName}] ${line}\n`);
154
149
  }
155
150
  };
156
151
  process.stderr.write = (chunk, ...args) => {
@@ -158,16 +153,18 @@ function initStderrTee(serverName) {
158
153
  if (perServerStream && !perServerStream.destroyed) {
159
154
  perServerStream.write(chunk);
160
155
  }
161
- // 2. Stream log — per-line, prefixed, date-rotating.
162
- try {
163
- const text = typeof chunk === "string"
164
- ? chunk
165
- : utf8.write(Buffer.from(chunk));
166
- emitCompleteLinesToStreamLog(text);
167
- }
168
- catch (err) {
169
- const msg = err instanceof Error ? err.message : String(err);
170
- originalWrite(`[${new Date().toISOString()}] [platform] mcp stream tee emit error server=${serverName} reason=${msg}\n`);
156
+ // 2. Stream log — per-line, prefixed.
157
+ if (streamLogStream) {
158
+ try {
159
+ const text = typeof chunk === "string"
160
+ ? chunk
161
+ : utf8.write(Buffer.from(chunk));
162
+ emitCompleteLinesToStreamLog(text);
163
+ }
164
+ catch (err) {
165
+ const msg = err instanceof Error ? err.message : String(err);
166
+ originalWrite(`${tsPrefix()} [platform] [mcp-tee-emit-error] server=${serverName} reason=${JSON.stringify(msg)}\n`);
167
+ }
171
168
  }
172
169
  // 3. Original stderr — Claude Code still gets what it's always got.
173
170
  return originalWrite(chunk, ...args);
@@ -181,11 +178,11 @@ function initStderrTee(serverName) {
181
178
  // shutdown anyway. This hook exists for the rare caller that uses
182
179
  // process.stderr.write without a trailing newline.
183
180
  process.on("beforeExit", () => {
184
- if (lineBuffer.length === 0)
185
- return;
186
- const stream = openStreamLog();
187
- if (stream && !stream.destroyed && !stream.writableEnded) {
188
- stream.write(`[${new Date().toISOString()}] [mcp:${serverName}] ${lineBuffer}\n`);
181
+ if (streamLogStream && !streamLogStream.destroyed && !streamLogStream.writableEnded) {
182
+ if (lineBuffer.length > 0) {
183
+ streamLogStream.write(`${tsPrefix()} [mcp:${serverName}] ${lineBuffer}\n`);
184
+ }
185
+ streamLogStream.write(`${tsPrefix()} [platform] [mcp-tee-detach] server=${serverName} reason=process-before-exit\n`);
189
186
  }
190
187
  lineBuffer = "";
191
188
  });
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}