@rubytech/create-maxy-code 0.1.461 → 0.1.463
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/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 +23 -12
- 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/mcp/dist/index.js +5 -5
- package/payload/platform/plugins/cloudflare/mcp/dist/index.js.map +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/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/internals.md +1 -1
- 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/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 +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 +97 -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/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/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/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/lib/mcp-spawn-tee/index.js +19 -19
- 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 +24 -20
- package/payload/platform/scripts/logs-read.sh +31 -0
- package/payload/platform/scripts/logs-rotate.sh +21 -18
- 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/pty-spawner.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.js +37 -0
- 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.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/{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-DYT5H81o.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-gm2eP4r6.js} +1 -1
- package/payload/server/public/assets/{page-DiQhU6lD.js → page-8AB3jUa_.js} +1 -1
- package/payload/server/public/assets/page-BoPorLg-.js +32 -0
- package/payload/server/public/assets/{public-Cu_eALgY.js → public-DqJk6qgW.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 +596 -235
- package/payload/server/{src-4F37OHLK.js → src-YLGAZY36.js} +5 -1
- 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
|
@@ -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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"}
|
|
@@ -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
|
|
@@ -38,7 +52,7 @@ import {
|
|
|
38
52
|
createWriteStream,
|
|
39
53
|
type WriteStream,
|
|
40
54
|
} from "node:fs";
|
|
41
|
-
import {
|
|
55
|
+
import { dirname } from "node:path";
|
|
42
56
|
import { StringDecoder } from "node:string_decoder";
|
|
43
57
|
|
|
44
58
|
// Marker on process.stderr.write so repeat calls to initStderrTee() are
|
|
@@ -48,21 +62,24 @@ const INIT_MARKER = Symbol.for("maxy.mcpStderrTee.installed");
|
|
|
48
62
|
|
|
49
63
|
/**
|
|
50
64
|
* Patch process.stderr.write to tee to:
|
|
51
|
-
* 1.
|
|
52
|
-
* 2. The
|
|
53
|
-
* 3. The original stderr (consumed by Claude Code) — always preserved.
|
|
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.
|
|
54
67
|
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
* a `[mcp-tee-skip]` marker is written to original stderr so the skip is
|
|
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
|
|
59
71
|
* visible to journalctl-level readers.
|
|
60
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
|
+
*
|
|
61
79
|
* Safe to call once at MCP server module load. Refused on second call to
|
|
62
80
|
* prevent stacking patches.
|
|
63
81
|
*/
|
|
64
82
|
export function initStderrTee(serverName: string): void {
|
|
65
|
-
const logDir = process.env.LOG_DIR;
|
|
66
83
|
const streamLogPath = process.env.STREAM_LOG_PATH;
|
|
67
84
|
|
|
68
85
|
// Refuse repeat patches — stacking them would double-log every chunk
|
|
@@ -80,29 +97,7 @@ export function initStderrTee(serverName: string): void {
|
|
|
80
97
|
originalWrite(`${tsPrefix()} [platform] [mcp-tee-skip] server=${serverName} destination=${destination} reason=${JSON.stringify(reason)}\n`);
|
|
81
98
|
};
|
|
82
99
|
|
|
83
|
-
// --- Destination
|
|
84
|
-
let perServerStream: WriteStream | undefined;
|
|
85
|
-
if (logDir) {
|
|
86
|
-
try {
|
|
87
|
-
mkdirSync(logDir, { recursive: true });
|
|
88
|
-
const date = new Date().toISOString().slice(0, 10);
|
|
89
|
-
perServerStream = createWriteStream(
|
|
90
|
-
resolve(logDir, `mcp-${serverName}-stderr-${date}.log`),
|
|
91
|
-
{ flags: "a" },
|
|
92
|
-
);
|
|
93
|
-
perServerStream.on("error", (err) => {
|
|
94
|
-
originalWrite(`${tsPrefix()} [platform] [mcp-tee-error] server=${serverName} destination=per-server reason=${JSON.stringify(err.message)}\n`);
|
|
95
|
-
});
|
|
96
|
-
} catch (err) {
|
|
97
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
98
|
-
skipTee(msg, "per-server");
|
|
99
|
-
perServerStream = undefined;
|
|
100
|
-
}
|
|
101
|
-
} else {
|
|
102
|
-
skipTee("LOG_DIR not set", "per-server");
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
// --- Destination 2: per-conversation stream log
|
|
100
|
+
// --- Destination: per-conversation stream log
|
|
106
101
|
let streamLogStream: WriteStream | undefined;
|
|
107
102
|
if (streamLogPath) {
|
|
108
103
|
try {
|
|
@@ -124,10 +119,10 @@ export function initStderrTee(serverName: string): void {
|
|
|
124
119
|
skipTee("STREAM_LOG_PATH not set", "stream-log");
|
|
125
120
|
}
|
|
126
121
|
|
|
127
|
-
//
|
|
128
|
-
//
|
|
129
|
-
//
|
|
130
|
-
if (!
|
|
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) {
|
|
131
126
|
return;
|
|
132
127
|
}
|
|
133
128
|
|
|
@@ -161,11 +156,7 @@ export function initStderrTee(serverName: string): void {
|
|
|
161
156
|
chunk: string | Uint8Array,
|
|
162
157
|
...args: unknown[]
|
|
163
158
|
): boolean => {
|
|
164
|
-
// 1.
|
|
165
|
-
if (perServerStream && !perServerStream.destroyed) {
|
|
166
|
-
perServerStream.write(chunk);
|
|
167
|
-
}
|
|
168
|
-
// 2. Stream log — per-line, prefixed.
|
|
159
|
+
// 1. Stream log — per-line, prefixed.
|
|
169
160
|
if (streamLogStream) {
|
|
170
161
|
try {
|
|
171
162
|
const text = typeof chunk === "string"
|
|
@@ -177,7 +168,7 @@ export function initStderrTee(serverName: string): void {
|
|
|
177
168
|
originalWrite(`${tsPrefix()} [platform] [mcp-tee-emit-error] server=${serverName} reason=${JSON.stringify(msg)}\n`);
|
|
178
169
|
}
|
|
179
170
|
}
|
|
180
|
-
//
|
|
171
|
+
// 2. Original stderr — Claude Code still gets what it's always got.
|
|
181
172
|
return (originalWrite as (chunk: string | Uint8Array, ...a: unknown[]) => boolean)(chunk, ...args);
|
|
182
173
|
};
|
|
183
174
|
// Mark the patch so a second initStderrTee() call is refused at the top.
|
|
@@ -43,4 +43,31 @@ const clean = {
|
|
|
43
43
|
});
|
|
44
44
|
strict_1.default.ok(strays.some((s) => s.kind === "account-wide-token" && s.detail === "acc-b:CLOUDFLARE_API_TOKEN"));
|
|
45
45
|
});
|
|
46
|
+
// --- Task 1728: Pages ownership reconcile --------------------------------
|
|
47
|
+
(0, node_test_1.default)("reconcilePages reports a live project with no owner as an orphan", async () => {
|
|
48
|
+
const r = await (0, audit_js_1.reconcilePages)({
|
|
49
|
+
cfProjects: async () => ["glsmithandsons", "ac-electrical"],
|
|
50
|
+
registeredProjects: async () => ["ac-electrical"],
|
|
51
|
+
});
|
|
52
|
+
strict_1.default.deepEqual(r.orphans, ["glsmithandsons"]);
|
|
53
|
+
strict_1.default.deepEqual(r.phantoms, []);
|
|
54
|
+
strict_1.default.equal(r.projects, 2);
|
|
55
|
+
strict_1.default.equal(r.registered, 1);
|
|
56
|
+
});
|
|
57
|
+
(0, node_test_1.default)("reconcilePages reports a registered project Cloudflare does not have as a phantom", async () => {
|
|
58
|
+
const r = await (0, audit_js_1.reconcilePages)({
|
|
59
|
+
cfProjects: async () => ["ac-electrical"],
|
|
60
|
+
registeredProjects: async () => ["ac-electrical", "deleted-site"],
|
|
61
|
+
});
|
|
62
|
+
strict_1.default.deepEqual(r.orphans, []);
|
|
63
|
+
strict_1.default.deepEqual(r.phantoms, ["deleted-site"]);
|
|
64
|
+
});
|
|
65
|
+
(0, node_test_1.default)("reconcilePages is clean when every live project has exactly one owner", async () => {
|
|
66
|
+
const r = await (0, audit_js_1.reconcilePages)({
|
|
67
|
+
cfProjects: async () => ["a", "b"],
|
|
68
|
+
registeredProjects: async () => ["b", "a"],
|
|
69
|
+
});
|
|
70
|
+
strict_1.default.deepEqual(r.orphans, []);
|
|
71
|
+
strict_1.default.deepEqual(r.phantoms, []);
|
|
72
|
+
});
|
|
46
73
|
//# sourceMappingURL=audit.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"audit.test.js","sourceRoot":"","sources":["../../src/__tests__/audit.test.ts"],"names":[],"mappings":";;;;;AAAA,0DAA6B;AAC7B,gEAAwC;AACxC,0CAA+
|
|
1
|
+
{"version":3,"file":"audit.test.js","sourceRoot":"","sources":["../../src/__tests__/audit.test.ts"],"names":[],"mappings":";;;;;AAAA,0DAA6B;AAC7B,gEAAwC;AACxC,0CAA+E;AAE/E,MAAM,KAAK,GAAc;IACvB,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,WAAW,CAAC;IAC/B,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC,EAAE;IACpB,eAAe,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAC/D,mBAAmB,EAAE,KAAK,IAAI,EAAE,CAAC;QAC/B,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,2CAA2C,EAAE;KAC1F;CACF,CAAC;AAEF,IAAA,mBAAI,EAAC,mCAAmC,EAAE,KAAK,IAAI,EAAE;IACnD,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,IAAA,2BAAgB,EAAC,KAAK,CAAC,CAAC;IACjD,gBAAM,CAAC,SAAS,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;AAC/B,CAAC,CAAC,CAAC;AAEH,IAAA,mBAAI,EAAC,mCAAmC,EAAE,KAAK,IAAI,EAAE;IACnD,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,IAAA,2BAAgB,EAAC;QACxC,GAAG,KAAK;QACR,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,kBAAkB,CAAC;KACpD,CAAC,CAAC;IACH,gBAAM,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,iBAAiB,IAAI,CAAC,CAAC,MAAM,KAAK,kBAAkB,CAAC,CAAC,CAAC;AACjG,CAAC,CAAC,CAAC;AAEH,IAAA,mBAAI,EAAC,sCAAsC,EAAE,KAAK,IAAI,EAAE;IACtD,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,IAAA,2BAAgB,EAAC;QACxC,GAAG,KAAK;QACR,mBAAmB,EAAE,KAAK,IAAI,EAAE,CAAC;YAC/B,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,+BAA+B,EAAE;SAC9E;KACF,CAAC,CAAC;IACH,gBAAM,CAAC,EAAE,CACP,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,oBAAoB,IAAI,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAClF,CAAC;AACJ,CAAC,CAAC,CAAC;AAEH,IAAA,mBAAI,EAAC,gCAAgC,EAAE,KAAK,IAAI,EAAE;IAChD,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,IAAA,2BAAgB,EAAC;QACxC,GAAG,KAAK;QACR,mBAAmB,EAAE,KAAK,IAAI,EAAE,CAAC;YAC/B,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,oCAAoC,EAAE;SACnF;KACF,CAAC,CAAC;IACH,gBAAM,CAAC,EAAE,CACP,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,oBAAoB,IAAI,CAAC,CAAC,MAAM,KAAK,4BAA4B,CAAC,CACjG,CAAC;AACJ,CAAC,CAAC,CAAC;AAEH,4EAA4E;AAE5E,IAAA,mBAAI,EAAC,kEAAkE,EAAE,KAAK,IAAI,EAAE;IAClF,MAAM,CAAC,GAAG,MAAM,IAAA,yBAAc,EAAC;QAC7B,UAAU,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,gBAAgB,EAAE,eAAe,CAAC;QAC3D,kBAAkB,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,eAAe,CAAC;KAClD,CAAC,CAAC;IACH,gBAAM,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,gBAAgB,CAAC,CAAC,CAAC;IAChD,gBAAM,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;IACjC,gBAAM,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC;IAC5B,gBAAM,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC;AAChC,CAAC,CAAC,CAAC;AAEH,IAAA,mBAAI,EAAC,mFAAmF,EAAE,KAAK,IAAI,EAAE;IACnG,MAAM,CAAC,GAAG,MAAM,IAAA,yBAAc,EAAC;QAC7B,UAAU,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,eAAe,CAAC;QACzC,kBAAkB,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,eAAe,EAAE,cAAc,CAAC;KAClE,CAAC,CAAC;IACH,gBAAM,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;IAChC,gBAAM,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,cAAc,CAAC,CAAC,CAAC;AACjD,CAAC,CAAC,CAAC;AAEH,IAAA,mBAAI,EAAC,uEAAuE,EAAE,KAAK,IAAI,EAAE;IACvF,MAAM,CAAC,GAAG,MAAM,IAAA,yBAAc,EAAC;QAC7B,UAAU,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC;QAClC,kBAAkB,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC;KAC3C,CAAC,CAAC;IACH,gBAAM,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;IAChC,gBAAM,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;AACnC,CAAC,CAAC,CAAC"}
|
|
@@ -599,4 +599,53 @@ function objectPage(keys, opts = {}) {
|
|
|
599
599
|
const found = await cf.r2ObjectFind("b", "k");
|
|
600
600
|
strict_1.default.equal(found?.size, 4);
|
|
601
601
|
});
|
|
602
|
+
// --- Task 1728: house-run Pages publishing -------------------------------
|
|
603
|
+
function projectPage(names, cursor) {
|
|
604
|
+
return JSON.stringify({
|
|
605
|
+
success: true,
|
|
606
|
+
errors: [],
|
|
607
|
+
messages: [],
|
|
608
|
+
result: names.map((name) => ({ name, subdomain: `${name}.pages.dev` })),
|
|
609
|
+
result_info: cursor === undefined ? {} : { cursor, per_page: 20 },
|
|
610
|
+
});
|
|
611
|
+
}
|
|
612
|
+
(0, node_test_1.default)("pagesDeploy shells npx wrangler (never bare) and returns the deployment url", async () => {
|
|
613
|
+
const { run, calls } = recordingRun("Uploading... (2/2)\n✨ Deployment complete! Take a peek over at https://abc123.glsmithandsons.pages.dev\n");
|
|
614
|
+
const cf = (0, cf_exec_js_1.makeCfExec)(cred, run);
|
|
615
|
+
const { url } = await cf.pagesDeploy("/acct/sites/gls", "glsmithandsons", "main");
|
|
616
|
+
strict_1.default.equal(url, "https://abc123.glsmithandsons.pages.dev");
|
|
617
|
+
strict_1.default.equal(calls[0].cmd, "npx");
|
|
618
|
+
strict_1.default.deepEqual(calls[0].args, [
|
|
619
|
+
"wrangler", "pages", "deploy", "/acct/sites/gls",
|
|
620
|
+
"--project-name", "glsmithandsons", "--branch", "main",
|
|
621
|
+
]);
|
|
622
|
+
strict_1.default.equal(calls[0].env.CLOUDFLARE_API_TOKEN, "cfat_x");
|
|
623
|
+
});
|
|
624
|
+
(0, node_test_1.default)("pagesDeploy omits --branch when no branch is given", async () => {
|
|
625
|
+
const { run, calls } = recordingRun("✨ Deployment complete! Take a peek over at https://x.y.pages.dev\n");
|
|
626
|
+
const cf = (0, cf_exec_js_1.makeCfExec)(cred, run);
|
|
627
|
+
await cf.pagesDeploy("/acct/sites/gls", "glsmithandsons");
|
|
628
|
+
strict_1.default.deepEqual(calls[0].args, [
|
|
629
|
+
"wrangler", "pages", "deploy", "/acct/sites/gls", "--project-name", "glsmithandsons",
|
|
630
|
+
]);
|
|
631
|
+
});
|
|
632
|
+
(0, node_test_1.default)("pagesDeploy throws with the body when wrangler prints no deployment url", async () => {
|
|
633
|
+
const { run } = recordingRun("Uploading... (0/0)\nsomething went sideways\n");
|
|
634
|
+
const cf = (0, cf_exec_js_1.makeCfExec)(cred, run);
|
|
635
|
+
await strict_1.default.rejects(() => cf.pagesDeploy("/acct/sites/gls", "glsmithandsons"), /something went sideways/, "a url-less wrangler run must surface its output, never report a silent success");
|
|
636
|
+
});
|
|
637
|
+
(0, node_test_1.default)("pagesProjectList follows the pagination cursor to exhaustion via the API, never wrangler", async () => {
|
|
638
|
+
const { fetchFn, calls } = sequenceFetch([
|
|
639
|
+
{ ok: true, status: 200, body: projectPage(["glsmithandsons"], "c1") },
|
|
640
|
+
{ ok: true, status: 200, body: projectPage(["ac-electrical"]) },
|
|
641
|
+
]);
|
|
642
|
+
const cf = (0, cf_exec_js_1.makeCfExec)(cred, throwingRun, fetchFn);
|
|
643
|
+
strict_1.default.deepEqual(await cf.pagesProjectList(), [
|
|
644
|
+
{ name: "glsmithandsons" },
|
|
645
|
+
{ name: "ac-electrical" },
|
|
646
|
+
]);
|
|
647
|
+
strict_1.default.equal(calls.length, 2);
|
|
648
|
+
strict_1.default.ok(!calls[0].url.includes("per_page"), "per_page is never sent (its max is unconfirmed)");
|
|
649
|
+
strict_1.default.ok(calls[1].url.includes("cursor=c1"), "the second request carries the cursor");
|
|
650
|
+
});
|
|
602
651
|
//# sourceMappingURL=cf-exec.test.js.map
|