@rubytech/create-maxy-code 0.1.544 → 0.1.546
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/mcp-spawn-tee/dist/index.js +11 -0
- 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 +39 -0
- package/payload/platform/lib/mcp-spawn-tee/src/index.ts +12 -0
- package/payload/platform/plugins/admin/lib/mcp-spawn-tee/index.js +11 -0
- package/payload/platform/plugins/admin/skills/channel-instruction/SKILL.md +26 -12
- package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +3 -1
- package/payload/platform/plugins/admin/skills/whats-new/SKILL.md +9 -0
- package/payload/platform/plugins/aeo/lib/mcp-spawn-tee/index.js +11 -0
- package/payload/platform/plugins/browser/lib/mcp-spawn-tee/index.js +11 -0
- package/payload/platform/plugins/connector/lib/mcp-spawn-tee/index.js +11 -0
- package/payload/platform/plugins/contacts/lib/mcp-spawn-tee/index.js +11 -0
- package/payload/platform/plugins/docs/references/channel-wake-and-prompt.md +2 -0
- package/payload/platform/plugins/email/lib/mcp-spawn-tee/index.js +11 -0
- package/payload/platform/plugins/filesystem/lib/mcp-spawn-tee/index.js +11 -0
- package/payload/platform/plugins/google/lib/mcp-spawn-tee/index.js +11 -0
- package/payload/platform/plugins/graph-viewer/lib/mcp-spawn-tee/index.js +11 -0
- package/payload/platform/plugins/ledger/lib/mcp-spawn-tee/index.js +11 -0
- package/payload/platform/plugins/memory/lib/mcp-spawn-tee/index.js +11 -0
- package/payload/platform/plugins/outlook/lib/mcp-spawn-tee/index.js +11 -0
- package/payload/platform/plugins/quickbooks/lib/mcp-spawn-tee/index.js +11 -0
- package/payload/platform/plugins/replicate/lib/mcp-spawn-tee/index.js +11 -0
- package/payload/platform/plugins/scheduling/PLUGIN.md +1 -1
- package/payload/platform/plugins/scheduling/lib/mcp-spawn-tee/index.js +11 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/availability-snapshot.test.d.ts +2 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/availability-snapshot.test.d.ts.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/availability-snapshot.test.js +80 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/availability-snapshot.test.js.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/publish-availability-logging.test.d.ts +2 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/publish-availability-logging.test.d.ts.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/publish-availability-logging.test.js +32 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/publish-availability-logging.test.js.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/availability-snapshot.d.ts +67 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/availability-snapshot.d.ts.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/availability-snapshot.js +88 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/availability-snapshot.js.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/publish-availability.d.ts +2 -1
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/publish-availability.d.ts.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/publish-availability.js +59 -54
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/publish-availability.js.map +1 -1
- package/payload/platform/plugins/storage-broker/lib/mcp-spawn-tee/index.js +11 -0
- package/payload/platform/plugins/telegram/lib/mcp-spawn-tee/index.js +11 -0
- package/payload/platform/plugins/url-get/lib/mcp-spawn-tee/index.js +11 -0
- package/payload/platform/plugins/voice-mirror/lib/mcp-spawn-tee/index.js +11 -0
- package/payload/platform/plugins/whatsapp/lib/mcp-spawn-tee/index.js +11 -0
- package/payload/platform/plugins/work/lib/mcp-spawn-tee/index.js +11 -0
- package/payload/platform/plugins/workflows/lib/mcp-spawn-tee/index.js +11 -0
- package/payload/platform/services/claude-session-manager/dist/channel-mcp.d.ts +5 -0
- package/payload/platform/services/claude-session-manager/dist/channel-mcp.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/channel-mcp.js +16 -2
- package/payload/platform/services/claude-session-manager/dist/channel-mcp.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/channel-spawn-tee.d.ts +34 -0
- package/payload/platform/services/claude-session-manager/dist/channel-spawn-tee.d.ts.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/channel-spawn-tee.js +41 -0
- package/payload/platform/services/claude-session-manager/dist/channel-spawn-tee.js.map +1 -0
- 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 +26 -1
- package/payload/platform/services/claude-session-manager/dist/http-server.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 +11 -0
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/telegram-channel-mcp.d.ts +5 -0
- package/payload/platform/services/claude-session-manager/dist/telegram-channel-mcp.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/telegram-channel-mcp.js +16 -2
- package/payload/platform/services/claude-session-manager/dist/telegram-channel-mcp.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/wa-channel-mcp.d.ts +6 -0
- package/payload/platform/services/claude-session-manager/dist/wa-channel-mcp.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/wa-channel-mcp.js +17 -2
- package/payload/platform/services/claude-session-manager/dist/wa-channel-mcp.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/webchat-channel-mcp.d.ts +5 -0
- package/payload/platform/services/claude-session-manager/dist/webchat-channel-mcp.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/webchat-channel-mcp.js +16 -2
- package/payload/platform/services/claude-session-manager/dist/webchat-channel-mcp.js.map +1 -1
- package/payload/platform/services/telegram-channel/dist/instructions.d.ts +1 -0
- package/payload/platform/services/telegram-channel/dist/instructions.d.ts.map +1 -1
- package/payload/platform/services/telegram-channel/dist/instructions.js +47 -0
- package/payload/platform/services/telegram-channel/dist/instructions.js.map +1 -1
- package/payload/platform/services/telegram-channel/dist/notification.d.ts +8 -14
- package/payload/platform/services/telegram-channel/dist/notification.d.ts.map +1 -1
- package/payload/platform/services/telegram-channel/dist/notification.js +13 -19
- package/payload/platform/services/telegram-channel/dist/notification.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 +3 -10
- package/payload/platform/services/telegram-channel/dist/server.js.map +1 -1
- package/payload/platform/services/webchat-channel/dist/instructions.d.ts +1 -0
- package/payload/platform/services/webchat-channel/dist/instructions.d.ts.map +1 -1
- package/payload/platform/services/webchat-channel/dist/instructions.js +60 -0
- package/payload/platform/services/webchat-channel/dist/instructions.js.map +1 -1
- package/payload/platform/services/webchat-channel/dist/notification.d.ts +9 -14
- package/payload/platform/services/webchat-channel/dist/notification.d.ts.map +1 -1
- package/payload/platform/services/webchat-channel/dist/notification.js +13 -19
- package/payload/platform/services/webchat-channel/dist/notification.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 +5 -10
- package/payload/platform/services/webchat-channel/dist/server.js.map +1 -1
- package/payload/platform/services/whatsapp-channel/dist/notification.d.ts +91 -9
- package/payload/platform/services/whatsapp-channel/dist/notification.d.ts.map +1 -1
- package/payload/platform/services/whatsapp-channel/dist/notification.js +155 -17
- package/payload/platform/services/whatsapp-channel/dist/notification.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 +83 -19
- package/payload/platform/services/whatsapp-channel/dist/server.js.map +1 -1
- package/payload/platform/services/whatsapp-channel/dist/targets.d.ts +23 -3
- package/payload/platform/services/whatsapp-channel/dist/targets.d.ts.map +1 -1
- package/payload/platform/services/whatsapp-channel/dist/targets.js +19 -2
- package/payload/platform/services/whatsapp-channel/dist/targets.js.map +1 -1
- package/payload/server/server.js +42 -43
package/package.json
CHANGED
|
@@ -180,6 +180,17 @@ process.on("exit", (code) => {
|
|
|
180
180
|
`code=${codeField} signal=${exitSignal ?? "—"} lifetimeMs=${lifetimeMs} stderr-tail=${JSON.stringify(tail)}`, level);
|
|
181
181
|
});
|
|
182
182
|
emitLifecycle(`op=spawn session=${SESSION_ID8} server=${SERVER_NAME} pid=${process.pid} entry=${ENTRY}`, "info");
|
|
183
|
+
// Task 2356 — present argv as a direct `node <entry>` invocation before the
|
|
184
|
+
// entry loads. The shim is meant to be transparent: an entry that asks the
|
|
185
|
+
// standard "am I the entry module?" question
|
|
186
|
+
// (`import.meta.url === pathToFileURL(realpathSync(process.argv[1])).href`)
|
|
187
|
+
// must get the same answer it gets when Claude Code runs it without the shim.
|
|
188
|
+
// With the shim's own path left in argv[1] the answer is no, so such an entry
|
|
189
|
+
// loads, starts nothing, and exits 0 — measured on the three channel servers,
|
|
190
|
+
// which all gate main() that way. Plugin MCPs connect at module top level and
|
|
191
|
+
// never read argv, so this is inert for them. ENTRY was captured above, before
|
|
192
|
+
// the rewrite. Extra CLI args keep their positions after the entry slot.
|
|
193
|
+
process.argv = [process.argv[0], ENTRY, ...process.argv.slice(3)];
|
|
183
194
|
// Run the real MCP server in THIS process. Dynamic import() (not top-level
|
|
184
195
|
// await — this file compiles to CommonJS) loads the ESM entry; a load-time
|
|
185
196
|
// failure mirrors the old child spawn-error path (op=error, exit 127). The
|
|
@@ -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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"}
|
|
@@ -143,6 +143,45 @@ describe('mcp-spawn-tee in-process shim', () => {
|
|
|
143
143
|
expect(readdirSync(logDir).some((f) => /stderr-\d{4}-\d{2}-\d{2}\.log$/.test(f))).toBe(false)
|
|
144
144
|
})
|
|
145
145
|
|
|
146
|
+
// Task 2356 — the shim must be transparent to the entry's own "am I the
|
|
147
|
+
// entry module?" check. Every channel server (whatsapp, webchat, telegram)
|
|
148
|
+
// gates main() on `import.meta.url === pathToFileURL(realpath(argv[1]))`. With
|
|
149
|
+
// the shim's own path left in argv[1] that guard is false, so the server
|
|
150
|
+
// loads, connects nothing, and exits 0 — a channel that is silently dead.
|
|
151
|
+
it('presents argv as a direct `node <entry>` invocation', () => {
|
|
152
|
+
const { stub, logDir } = makeStub(
|
|
153
|
+
'process.stdout.write(JSON.stringify(process.argv.slice(1))); process.exit(0)',
|
|
154
|
+
)
|
|
155
|
+
const r = runSync(stub, { LOG_DIR: logDir, SESSION_ID: 'argv1', MCP_SPAWN_TEE_NAME: 'stub' })
|
|
156
|
+
expect(JSON.parse(r.stdout)).toEqual([stub])
|
|
157
|
+
})
|
|
158
|
+
|
|
159
|
+
it('the entry-module guard the channel servers use passes under the shim', () => {
|
|
160
|
+
const { stub, logDir } = makeStub(
|
|
161
|
+
[
|
|
162
|
+
'const { realpathSync } = require("node:fs")',
|
|
163
|
+
'const { pathToFileURL } = require("node:url")',
|
|
164
|
+
'const isEntry = process.argv[1] &&',
|
|
165
|
+
' pathToFileURL(__filename).href === pathToFileURL(realpathSync(process.argv[1])).href',
|
|
166
|
+
'process.stdout.write(isEntry ? "MAIN-RAN" : "MAIN-SKIPPED")',
|
|
167
|
+
'process.exit(0)',
|
|
168
|
+
].join('\n'),
|
|
169
|
+
)
|
|
170
|
+
const r = runSync(stub, { LOG_DIR: logDir, SESSION_ID: 'argv2', MCP_SPAWN_TEE_NAME: 'stub' })
|
|
171
|
+
expect(r.stdout).toBe('MAIN-RAN')
|
|
172
|
+
})
|
|
173
|
+
|
|
174
|
+
it('forwards extra CLI args to the entry, after the entry slot', () => {
|
|
175
|
+
const { stub, logDir } = makeStub(
|
|
176
|
+
'process.stdout.write(JSON.stringify(process.argv.slice(1))); process.exit(0)',
|
|
177
|
+
)
|
|
178
|
+
const r = spawnSync(process.execPath, [shim, stub, '--flag', 'value'], {
|
|
179
|
+
env: { ...process.env, SESSION_ID: 'argv3', PLATFORM_PORT: '', LOG_DIR: logDir, MCP_SPAWN_TEE_NAME: 'stub' },
|
|
180
|
+
encoding: 'utf8',
|
|
181
|
+
})
|
|
182
|
+
expect(JSON.parse(r.stdout)).toEqual([stub, '--flag', 'value'])
|
|
183
|
+
})
|
|
184
|
+
|
|
146
185
|
it('does not crash when PLATFORM_PORT is unreachable', () => {
|
|
147
186
|
const { stub, logDir } = makeStub('process.stderr.write("x\\n"); process.exit(0)')
|
|
148
187
|
const r = runSync(stub, { LOG_DIR: logDir, SESSION_ID: 'p1', MCP_SPAWN_TEE_NAME: 'stub', PLATFORM_PORT: '59999' })
|
|
@@ -189,6 +189,18 @@ process.on("exit", (code) => {
|
|
|
189
189
|
|
|
190
190
|
emitLifecycle(`op=spawn session=${SESSION_ID8} server=${SERVER_NAME} pid=${process.pid} entry=${ENTRY}`, "info");
|
|
191
191
|
|
|
192
|
+
// Task 2356 — present argv as a direct `node <entry>` invocation before the
|
|
193
|
+
// entry loads. The shim is meant to be transparent: an entry that asks the
|
|
194
|
+
// standard "am I the entry module?" question
|
|
195
|
+
// (`import.meta.url === pathToFileURL(realpathSync(process.argv[1])).href`)
|
|
196
|
+
// must get the same answer it gets when Claude Code runs it without the shim.
|
|
197
|
+
// With the shim's own path left in argv[1] the answer is no, so such an entry
|
|
198
|
+
// loads, starts nothing, and exits 0 — measured on the three channel servers,
|
|
199
|
+
// which all gate main() that way. Plugin MCPs connect at module top level and
|
|
200
|
+
// never read argv, so this is inert for them. ENTRY was captured above, before
|
|
201
|
+
// the rewrite. Extra CLI args keep their positions after the entry slot.
|
|
202
|
+
process.argv = [process.argv[0], ENTRY, ...process.argv.slice(3)];
|
|
203
|
+
|
|
192
204
|
// Run the real MCP server in THIS process. Dynamic import() (not top-level
|
|
193
205
|
// await — this file compiles to CommonJS) loads the ESM entry; a load-time
|
|
194
206
|
// failure mirrors the old child spawn-error path (op=error, exit 127). The
|
|
@@ -180,6 +180,17 @@ process.on("exit", (code) => {
|
|
|
180
180
|
`code=${codeField} signal=${exitSignal ?? "—"} lifetimeMs=${lifetimeMs} stderr-tail=${JSON.stringify(tail)}`, level);
|
|
181
181
|
});
|
|
182
182
|
emitLifecycle(`op=spawn session=${SESSION_ID8} server=${SERVER_NAME} pid=${process.pid} entry=${ENTRY}`, "info");
|
|
183
|
+
// Task 2356 — present argv as a direct `node <entry>` invocation before the
|
|
184
|
+
// entry loads. The shim is meant to be transparent: an entry that asks the
|
|
185
|
+
// standard "am I the entry module?" question
|
|
186
|
+
// (`import.meta.url === pathToFileURL(realpathSync(process.argv[1])).href`)
|
|
187
|
+
// must get the same answer it gets when Claude Code runs it without the shim.
|
|
188
|
+
// With the shim's own path left in argv[1] the answer is no, so such an entry
|
|
189
|
+
// loads, starts nothing, and exits 0 — measured on the three channel servers,
|
|
190
|
+
// which all gate main() that way. Plugin MCPs connect at module top level and
|
|
191
|
+
// never read argv, so this is inert for them. ENTRY was captured above, before
|
|
192
|
+
// the rewrite. Extra CLI args keep their positions after the entry slot.
|
|
193
|
+
process.argv = [process.argv[0], ENTRY, ...process.argv.slice(3)];
|
|
183
194
|
// Run the real MCP server in THIS process. Dynamic import() (not top-level
|
|
184
195
|
// await — this file compiles to CommonJS) loads the ESM entry; a load-time
|
|
185
196
|
// failure mirrors the old child spawn-error path (op=error, exit 127). The
|
|
@@ -1,46 +1,60 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: channel-instruction
|
|
3
|
-
description: "Set up or change what this account's agent does
|
|
3
|
+
description: "Set up or change what this account's agent does when a message arrives from someone who is not an account manager. Triggers when the owner says 'set up what my agent does with incoming messages', 'change how you handle WhatsApp messages from customers', 'write my channel instruction', 'my agent replied to a customer and it shouldn't have', or asks why an incoming message got no answer."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Channel instruction
|
|
7
7
|
|
|
8
8
|
Invoked by the admin agent directly.
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
When someone who is not an account manager sends a WhatsApp message to this account's line, the platform wakes each manager's own session with a turn about it. That turn is handed a `## Context` block holding the message and an `## Instruction` block saying what to do with it. This skill is about the file that supplies the second block.
|
|
11
11
|
|
|
12
12
|
## The file
|
|
13
13
|
|
|
14
14
|
`$ACCOUNT_DIR/agents/admin/INSTRUCTION.md`
|
|
15
15
|
|
|
16
|
-
Its whole body becomes the `## Instruction` block, verbatim. The platform wraps it in nothing and adds no wording of its own
|
|
16
|
+
Its whole body becomes the `## Instruction` block on that turn, verbatim. The platform wraps it in nothing and adds no wording of its own.
|
|
17
17
|
|
|
18
18
|
The install creates the file empty. What goes in it is the account owner's, not the platform's.
|
|
19
19
|
|
|
20
|
-
##
|
|
20
|
+
## Which turns it governs, and which it does not
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
It governs one kind of turn: a WhatsApp message from someone who is not an account manager. Nothing else.
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
**A message the owner sends is unaffected by this file.** Whether they type it in the admin webchat, send it from their own WhatsApp handset, or it arrives from the scheduler, the platform supplies its own directive for that turn and never reads this file. An instruction written here for handling a customer will not change how the agent answers the owner.
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
**A public agent does not read this file either.** An account's public agent reads `$ACCOUNT_DIR/agents/<its-slug>/INSTRUCTION.md`, its own. Writing a rule here in the hope of steering the public agent does nothing.
|
|
27
|
+
|
|
28
|
+
If the owner wants to change how the agent behaves toward them personally, this is the wrong file. Identity and manner live in `IDENTITY.md` and `SOUL.md` in the same directory, and they apply to every session.
|
|
29
|
+
|
|
30
|
+
## An empty file drops the message
|
|
31
|
+
|
|
32
|
+
A file that is missing, unreadable, or holds only whitespace resolves to absent, and an absent instruction refuses the turn: no session wakes, and nothing happens about the message. The sender gets silence and the owner is never told.
|
|
33
|
+
|
|
34
|
+
Nothing warns the owner in advance. The only trace is two lines in `server.log`, written at the moment the message was dropped:
|
|
35
|
+
|
|
36
|
+
- `op=instruction-source accountId=<id> turn=relay source=absent bytes=0`
|
|
27
37
|
- `op=inbound … delivery=refused` for the same message
|
|
28
38
|
|
|
29
|
-
So on an account whose
|
|
39
|
+
So on an account whose WhatsApp line is connected and whose file is empty, writing this file is the fix for "a customer wrote in and nothing happened". If the owner reports that, check this file before anything else. Their own chat will be working normally throughout, which is what makes this hard to spot.
|
|
30
40
|
|
|
31
41
|
## Writing it
|
|
32
42
|
|
|
33
43
|
Read the file first and tell the owner what is in it. Then find out what they want and write it.
|
|
34
44
|
|
|
35
|
-
What belongs in it is
|
|
45
|
+
What belongs in it is what should happen when a stranger writes in: who the agent may answer on its own and who it must not, what has to be put to a person, what it must never say, and what it must always do before the turn ends.
|
|
36
46
|
|
|
37
47
|
Two rules on how you write it:
|
|
38
48
|
|
|
39
49
|
- Write only what the owner has told you. A rule they did not ask for is someone else's wording in their file, which is exactly what this file exists to keep out.
|
|
40
50
|
- Never carry rules over from another account or from another owner's file.
|
|
41
51
|
|
|
42
|
-
An edit takes effect on the next incoming message. No restart, no upgrade, no publish. So a change can be checked by
|
|
52
|
+
An edit takes effect on the next incoming message. No restart, no upgrade, no publish. So a change can be checked by having someone message the account's WhatsApp line and reading what the agent does.
|
|
53
|
+
|
|
54
|
+
## Checking which body a turn actually took
|
|
55
|
+
|
|
56
|
+
Every WhatsApp turn writes one line to `server.log` naming the decision:
|
|
43
57
|
|
|
44
|
-
|
|
58
|
+
`op=instruction-source accountId=<id> agentDir=<dir> turn=relay|direct|public source=account|platform|absent bytes=<n>`
|
|
45
59
|
|
|
46
|
-
|
|
60
|
+
`turn=relay` with `source=account` means the turn took this file. `turn=direct` with `source=platform` means the owner sent it themselves and this file was not read. If the owner believes a rule they wrote is being applied to their own messages, that line settles it.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: platform-architecture
|
|
3
3
|
description: Use when grounding any documented-surface claim about what Maxy ships — plugins, skills, specialists, install/deploy flows, internals. This is the install catalogue, not evidence of what is enabled on the current account. For install state on this account, call `capabilities-here`; for documented surface, cite the `Source:` URL inline.
|
|
4
|
-
content-hash: sha256:
|
|
4
|
+
content-hash: sha256:4566431caa948d080401758fc742c6b3f6340a0a1d17129ff51c9887836aaf87
|
|
5
5
|
brand: maxy-code
|
|
6
6
|
product-name: Maxy
|
|
7
7
|
---
|
|
@@ -1710,6 +1710,8 @@ Every turn carries a `source`. Three values exist:
|
|
|
1710
1710
|
| `schedule` | The scheduler wrote this turn. The named destination did not send it. |
|
|
1711
1711
|
| `public-relay` | The platform wrote this turn because a public visitor messaged the account. The named sender is a manager being told, not someone who wrote to you. |
|
|
1712
1712
|
|
|
1713
|
+
**A `public-relay` turn is the one turn whose `## Instruction` block is the account's own.** Its body is `agents/admin/INSTRUCTION.md`, written by the account owner, and it is the only instruction that turn carries: no standing-rules block rides with it. Every other turn on this line, including one the owner sent from their own handset and one the scheduler wrote, takes the platform's own directive and never reads that file. If the file is empty the relay turn is refused outright, so the message is dropped and nobody is told. A public visitor's own turn reads its agent's file at `agents/<slug>/INSTRUCTION.md`, never the admin's.
|
|
1714
|
+
|
|
1713
1715
|
A `public-relay` turn also says so in its own first two lines, and states which handset its reply tool reaches. That handset is the manager's, never the visitor's: the turn runs in the manager's own admin session, so a reply written to the visitor is delivered to the manager. If a turn claims a manager wrote something they plainly would not have written, check the source before answering them.
|
|
1714
1716
|
|
|
1715
1717
|
**On a `public-relay` turn the reply tool is the only way to reach anyone.** On an ordinary turn the platform forwards your closing text to the sender when you called no reply tool. On a relay-woken turn it does not, because the relay carries its own reply path. So whatever you decide the manager should receive has to go through the reply tool; text you merely write at the end of the turn reaches nobody, and a decision not to reply is silence rather than a message.
|
|
@@ -9,6 +9,15 @@ Invoked by the admin agent directly.
|
|
|
9
9
|
|
|
10
10
|
This is the platform's release timeline, newest first. Each entry shows the date it shipped and the version it shipped in, so you can tell the operator how current their install is. To compare, read the installed version from `capabilities-here` and match it against the versions below. Keep answers high level and in plain English; this is a summary, not a full commit log.
|
|
11
11
|
|
|
12
|
+
## 2026-08-02 (0.1.546)
|
|
13
|
+
|
|
14
|
+
- When the assistant notifies you on a channel, the outcome of that notification is now recorded, so a message that never arrived can be traced rather than guessed at.
|
|
15
|
+
|
|
16
|
+
## 2026-08-02 (0.1.545)
|
|
17
|
+
|
|
18
|
+
- The assistant is now instructed differently depending on whether you messaged it directly or the turn was relayed from someone outside your team, so your own standing rules no longer ride along on a relayed turn.
|
|
19
|
+
- Publishing your booking availability now goes through Cloudflare's own interface rather than a command-line tool, and a retry that can no longer finish in time is refused instead of hanging.
|
|
20
|
+
|
|
12
21
|
## 2026-08-02 (0.1.544)
|
|
13
22
|
|
|
14
23
|
- Every channel, including Telegram, now takes its turn instruction from the account's own file rather than text fixed in the code, and a build check stops any of the three services hardcoding it again.
|
|
@@ -180,6 +180,17 @@ process.on("exit", (code) => {
|
|
|
180
180
|
`code=${codeField} signal=${exitSignal ?? "—"} lifetimeMs=${lifetimeMs} stderr-tail=${JSON.stringify(tail)}`, level);
|
|
181
181
|
});
|
|
182
182
|
emitLifecycle(`op=spawn session=${SESSION_ID8} server=${SERVER_NAME} pid=${process.pid} entry=${ENTRY}`, "info");
|
|
183
|
+
// Task 2356 — present argv as a direct `node <entry>` invocation before the
|
|
184
|
+
// entry loads. The shim is meant to be transparent: an entry that asks the
|
|
185
|
+
// standard "am I the entry module?" question
|
|
186
|
+
// (`import.meta.url === pathToFileURL(realpathSync(process.argv[1])).href`)
|
|
187
|
+
// must get the same answer it gets when Claude Code runs it without the shim.
|
|
188
|
+
// With the shim's own path left in argv[1] the answer is no, so such an entry
|
|
189
|
+
// loads, starts nothing, and exits 0 — measured on the three channel servers,
|
|
190
|
+
// which all gate main() that way. Plugin MCPs connect at module top level and
|
|
191
|
+
// never read argv, so this is inert for them. ENTRY was captured above, before
|
|
192
|
+
// the rewrite. Extra CLI args keep their positions after the entry slot.
|
|
193
|
+
process.argv = [process.argv[0], ENTRY, ...process.argv.slice(3)];
|
|
183
194
|
// Run the real MCP server in THIS process. Dynamic import() (not top-level
|
|
184
195
|
// await — this file compiles to CommonJS) loads the ESM entry; a load-time
|
|
185
196
|
// failure mirrors the old child spawn-error path (op=error, exit 127). The
|
|
@@ -180,6 +180,17 @@ process.on("exit", (code) => {
|
|
|
180
180
|
`code=${codeField} signal=${exitSignal ?? "—"} lifetimeMs=${lifetimeMs} stderr-tail=${JSON.stringify(tail)}`, level);
|
|
181
181
|
});
|
|
182
182
|
emitLifecycle(`op=spawn session=${SESSION_ID8} server=${SERVER_NAME} pid=${process.pid} entry=${ENTRY}`, "info");
|
|
183
|
+
// Task 2356 — present argv as a direct `node <entry>` invocation before the
|
|
184
|
+
// entry loads. The shim is meant to be transparent: an entry that asks the
|
|
185
|
+
// standard "am I the entry module?" question
|
|
186
|
+
// (`import.meta.url === pathToFileURL(realpathSync(process.argv[1])).href`)
|
|
187
|
+
// must get the same answer it gets when Claude Code runs it without the shim.
|
|
188
|
+
// With the shim's own path left in argv[1] the answer is no, so such an entry
|
|
189
|
+
// loads, starts nothing, and exits 0 — measured on the three channel servers,
|
|
190
|
+
// which all gate main() that way. Plugin MCPs connect at module top level and
|
|
191
|
+
// never read argv, so this is inert for them. ENTRY was captured above, before
|
|
192
|
+
// the rewrite. Extra CLI args keep their positions after the entry slot.
|
|
193
|
+
process.argv = [process.argv[0], ENTRY, ...process.argv.slice(3)];
|
|
183
194
|
// Run the real MCP server in THIS process. Dynamic import() (not top-level
|
|
184
195
|
// await — this file compiles to CommonJS) loads the ESM entry; a load-time
|
|
185
196
|
// failure mirrors the old child spawn-error path (op=error, exit 127). The
|
|
@@ -180,6 +180,17 @@ process.on("exit", (code) => {
|
|
|
180
180
|
`code=${codeField} signal=${exitSignal ?? "—"} lifetimeMs=${lifetimeMs} stderr-tail=${JSON.stringify(tail)}`, level);
|
|
181
181
|
});
|
|
182
182
|
emitLifecycle(`op=spawn session=${SESSION_ID8} server=${SERVER_NAME} pid=${process.pid} entry=${ENTRY}`, "info");
|
|
183
|
+
// Task 2356 — present argv as a direct `node <entry>` invocation before the
|
|
184
|
+
// entry loads. The shim is meant to be transparent: an entry that asks the
|
|
185
|
+
// standard "am I the entry module?" question
|
|
186
|
+
// (`import.meta.url === pathToFileURL(realpathSync(process.argv[1])).href`)
|
|
187
|
+
// must get the same answer it gets when Claude Code runs it without the shim.
|
|
188
|
+
// With the shim's own path left in argv[1] the answer is no, so such an entry
|
|
189
|
+
// loads, starts nothing, and exits 0 — measured on the three channel servers,
|
|
190
|
+
// which all gate main() that way. Plugin MCPs connect at module top level and
|
|
191
|
+
// never read argv, so this is inert for them. ENTRY was captured above, before
|
|
192
|
+
// the rewrite. Extra CLI args keep their positions after the entry slot.
|
|
193
|
+
process.argv = [process.argv[0], ENTRY, ...process.argv.slice(3)];
|
|
183
194
|
// Run the real MCP server in THIS process. Dynamic import() (not top-level
|
|
184
195
|
// await — this file compiles to CommonJS) loads the ESM entry; a load-time
|
|
185
196
|
// failure mirrors the old child spawn-error path (op=error, exit 127). The
|
|
@@ -180,6 +180,17 @@ process.on("exit", (code) => {
|
|
|
180
180
|
`code=${codeField} signal=${exitSignal ?? "—"} lifetimeMs=${lifetimeMs} stderr-tail=${JSON.stringify(tail)}`, level);
|
|
181
181
|
});
|
|
182
182
|
emitLifecycle(`op=spawn session=${SESSION_ID8} server=${SERVER_NAME} pid=${process.pid} entry=${ENTRY}`, "info");
|
|
183
|
+
// Task 2356 — present argv as a direct `node <entry>` invocation before the
|
|
184
|
+
// entry loads. The shim is meant to be transparent: an entry that asks the
|
|
185
|
+
// standard "am I the entry module?" question
|
|
186
|
+
// (`import.meta.url === pathToFileURL(realpathSync(process.argv[1])).href`)
|
|
187
|
+
// must get the same answer it gets when Claude Code runs it without the shim.
|
|
188
|
+
// With the shim's own path left in argv[1] the answer is no, so such an entry
|
|
189
|
+
// loads, starts nothing, and exits 0 — measured on the three channel servers,
|
|
190
|
+
// which all gate main() that way. Plugin MCPs connect at module top level and
|
|
191
|
+
// never read argv, so this is inert for them. ENTRY was captured above, before
|
|
192
|
+
// the rewrite. Extra CLI args keep their positions after the entry slot.
|
|
193
|
+
process.argv = [process.argv[0], ENTRY, ...process.argv.slice(3)];
|
|
183
194
|
// Run the real MCP server in THIS process. Dynamic import() (not top-level
|
|
184
195
|
// await — this file compiles to CommonJS) loads the ESM entry; a load-time
|
|
185
196
|
// failure mirrors the old child spawn-error path (op=error, exit 127). The
|
|
@@ -28,6 +28,8 @@ Every turn carries a `source`. Three values exist:
|
|
|
28
28
|
| `schedule` | The scheduler wrote this turn. The named destination did not send it. |
|
|
29
29
|
| `public-relay` | The platform wrote this turn because a public visitor messaged the account. The named sender is a manager being told, not someone who wrote to you. |
|
|
30
30
|
|
|
31
|
+
**A `public-relay` turn is the one turn whose `## Instruction` block is the account's own.** Its body is `agents/admin/INSTRUCTION.md`, written by the account owner, and it is the only instruction that turn carries: no standing-rules block rides with it. Every other turn on this line, including one the owner sent from their own handset and one the scheduler wrote, takes the platform's own directive and never reads that file. If the file is empty the relay turn is refused outright, so the message is dropped and nobody is told. A public visitor's own turn reads its agent's file at `agents/<slug>/INSTRUCTION.md`, never the admin's.
|
|
32
|
+
|
|
31
33
|
A `public-relay` turn also says so in its own first two lines, and states which handset its reply tool reaches. That handset is the manager's, never the visitor's: the turn runs in the manager's own admin session, so a reply written to the visitor is delivered to the manager. If a turn claims a manager wrote something they plainly would not have written, check the source before answering them.
|
|
32
34
|
|
|
33
35
|
**On a `public-relay` turn the reply tool is the only way to reach anyone.** On an ordinary turn the platform forwards your closing text to the sender when you called no reply tool. On a relay-woken turn it does not, because the relay carries its own reply path. So whatever you decide the manager should receive has to go through the reply tool; text you merely write at the end of the turn reaches nobody, and a decision not to reply is silence rather than a message.
|
|
@@ -180,6 +180,17 @@ process.on("exit", (code) => {
|
|
|
180
180
|
`code=${codeField} signal=${exitSignal ?? "—"} lifetimeMs=${lifetimeMs} stderr-tail=${JSON.stringify(tail)}`, level);
|
|
181
181
|
});
|
|
182
182
|
emitLifecycle(`op=spawn session=${SESSION_ID8} server=${SERVER_NAME} pid=${process.pid} entry=${ENTRY}`, "info");
|
|
183
|
+
// Task 2356 — present argv as a direct `node <entry>` invocation before the
|
|
184
|
+
// entry loads. The shim is meant to be transparent: an entry that asks the
|
|
185
|
+
// standard "am I the entry module?" question
|
|
186
|
+
// (`import.meta.url === pathToFileURL(realpathSync(process.argv[1])).href`)
|
|
187
|
+
// must get the same answer it gets when Claude Code runs it without the shim.
|
|
188
|
+
// With the shim's own path left in argv[1] the answer is no, so such an entry
|
|
189
|
+
// loads, starts nothing, and exits 0 — measured on the three channel servers,
|
|
190
|
+
// which all gate main() that way. Plugin MCPs connect at module top level and
|
|
191
|
+
// never read argv, so this is inert for them. ENTRY was captured above, before
|
|
192
|
+
// the rewrite. Extra CLI args keep their positions after the entry slot.
|
|
193
|
+
process.argv = [process.argv[0], ENTRY, ...process.argv.slice(3)];
|
|
183
194
|
// Run the real MCP server in THIS process. Dynamic import() (not top-level
|
|
184
195
|
// await — this file compiles to CommonJS) loads the ESM entry; a load-time
|
|
185
196
|
// failure mirrors the old child spawn-error path (op=error, exit 127). The
|
|
@@ -180,6 +180,17 @@ process.on("exit", (code) => {
|
|
|
180
180
|
`code=${codeField} signal=${exitSignal ?? "—"} lifetimeMs=${lifetimeMs} stderr-tail=${JSON.stringify(tail)}`, level);
|
|
181
181
|
});
|
|
182
182
|
emitLifecycle(`op=spawn session=${SESSION_ID8} server=${SERVER_NAME} pid=${process.pid} entry=${ENTRY}`, "info");
|
|
183
|
+
// Task 2356 — present argv as a direct `node <entry>` invocation before the
|
|
184
|
+
// entry loads. The shim is meant to be transparent: an entry that asks the
|
|
185
|
+
// standard "am I the entry module?" question
|
|
186
|
+
// (`import.meta.url === pathToFileURL(realpathSync(process.argv[1])).href`)
|
|
187
|
+
// must get the same answer it gets when Claude Code runs it without the shim.
|
|
188
|
+
// With the shim's own path left in argv[1] the answer is no, so such an entry
|
|
189
|
+
// loads, starts nothing, and exits 0 — measured on the three channel servers,
|
|
190
|
+
// which all gate main() that way. Plugin MCPs connect at module top level and
|
|
191
|
+
// never read argv, so this is inert for them. ENTRY was captured above, before
|
|
192
|
+
// the rewrite. Extra CLI args keep their positions after the entry slot.
|
|
193
|
+
process.argv = [process.argv[0], ENTRY, ...process.argv.slice(3)];
|
|
183
194
|
// Run the real MCP server in THIS process. Dynamic import() (not top-level
|
|
184
195
|
// await — this file compiles to CommonJS) loads the ESM entry; a load-time
|
|
185
196
|
// failure mirrors the old child spawn-error path (op=error, exit 127). The
|
|
@@ -180,6 +180,17 @@ process.on("exit", (code) => {
|
|
|
180
180
|
`code=${codeField} signal=${exitSignal ?? "—"} lifetimeMs=${lifetimeMs} stderr-tail=${JSON.stringify(tail)}`, level);
|
|
181
181
|
});
|
|
182
182
|
emitLifecycle(`op=spawn session=${SESSION_ID8} server=${SERVER_NAME} pid=${process.pid} entry=${ENTRY}`, "info");
|
|
183
|
+
// Task 2356 — present argv as a direct `node <entry>` invocation before the
|
|
184
|
+
// entry loads. The shim is meant to be transparent: an entry that asks the
|
|
185
|
+
// standard "am I the entry module?" question
|
|
186
|
+
// (`import.meta.url === pathToFileURL(realpathSync(process.argv[1])).href`)
|
|
187
|
+
// must get the same answer it gets when Claude Code runs it without the shim.
|
|
188
|
+
// With the shim's own path left in argv[1] the answer is no, so such an entry
|
|
189
|
+
// loads, starts nothing, and exits 0 — measured on the three channel servers,
|
|
190
|
+
// which all gate main() that way. Plugin MCPs connect at module top level and
|
|
191
|
+
// never read argv, so this is inert for them. ENTRY was captured above, before
|
|
192
|
+
// the rewrite. Extra CLI args keep their positions after the entry slot.
|
|
193
|
+
process.argv = [process.argv[0], ENTRY, ...process.argv.slice(3)];
|
|
183
194
|
// Run the real MCP server in THIS process. Dynamic import() (not top-level
|
|
184
195
|
// await — this file compiles to CommonJS) loads the ESM entry; a load-time
|
|
185
196
|
// failure mirrors the old child spawn-error path (op=error, exit 127). The
|
|
@@ -180,6 +180,17 @@ process.on("exit", (code) => {
|
|
|
180
180
|
`code=${codeField} signal=${exitSignal ?? "—"} lifetimeMs=${lifetimeMs} stderr-tail=${JSON.stringify(tail)}`, level);
|
|
181
181
|
});
|
|
182
182
|
emitLifecycle(`op=spawn session=${SESSION_ID8} server=${SERVER_NAME} pid=${process.pid} entry=${ENTRY}`, "info");
|
|
183
|
+
// Task 2356 — present argv as a direct `node <entry>` invocation before the
|
|
184
|
+
// entry loads. The shim is meant to be transparent: an entry that asks the
|
|
185
|
+
// standard "am I the entry module?" question
|
|
186
|
+
// (`import.meta.url === pathToFileURL(realpathSync(process.argv[1])).href`)
|
|
187
|
+
// must get the same answer it gets when Claude Code runs it without the shim.
|
|
188
|
+
// With the shim's own path left in argv[1] the answer is no, so such an entry
|
|
189
|
+
// loads, starts nothing, and exits 0 — measured on the three channel servers,
|
|
190
|
+
// which all gate main() that way. Plugin MCPs connect at module top level and
|
|
191
|
+
// never read argv, so this is inert for them. ENTRY was captured above, before
|
|
192
|
+
// the rewrite. Extra CLI args keep their positions after the entry slot.
|
|
193
|
+
process.argv = [process.argv[0], ENTRY, ...process.argv.slice(3)];
|
|
183
194
|
// Run the real MCP server in THIS process. Dynamic import() (not top-level
|
|
184
195
|
// await — this file compiles to CommonJS) loads the ESM entry; a load-time
|
|
185
196
|
// failure mirrors the old child spawn-error path (op=error, exit 127). The
|
|
@@ -180,6 +180,17 @@ process.on("exit", (code) => {
|
|
|
180
180
|
`code=${codeField} signal=${exitSignal ?? "—"} lifetimeMs=${lifetimeMs} stderr-tail=${JSON.stringify(tail)}`, level);
|
|
181
181
|
});
|
|
182
182
|
emitLifecycle(`op=spawn session=${SESSION_ID8} server=${SERVER_NAME} pid=${process.pid} entry=${ENTRY}`, "info");
|
|
183
|
+
// Task 2356 — present argv as a direct `node <entry>` invocation before the
|
|
184
|
+
// entry loads. The shim is meant to be transparent: an entry that asks the
|
|
185
|
+
// standard "am I the entry module?" question
|
|
186
|
+
// (`import.meta.url === pathToFileURL(realpathSync(process.argv[1])).href`)
|
|
187
|
+
// must get the same answer it gets when Claude Code runs it without the shim.
|
|
188
|
+
// With the shim's own path left in argv[1] the answer is no, so such an entry
|
|
189
|
+
// loads, starts nothing, and exits 0 — measured on the three channel servers,
|
|
190
|
+
// which all gate main() that way. Plugin MCPs connect at module top level and
|
|
191
|
+
// never read argv, so this is inert for them. ENTRY was captured above, before
|
|
192
|
+
// the rewrite. Extra CLI args keep their positions after the entry slot.
|
|
193
|
+
process.argv = [process.argv[0], ENTRY, ...process.argv.slice(3)];
|
|
183
194
|
// Run the real MCP server in THIS process. Dynamic import() (not top-level
|
|
184
195
|
// await — this file compiles to CommonJS) loads the ESM entry; a load-time
|
|
185
196
|
// failure mirrors the old child spawn-error path (op=error, exit 127). The
|
|
@@ -180,6 +180,17 @@ process.on("exit", (code) => {
|
|
|
180
180
|
`code=${codeField} signal=${exitSignal ?? "—"} lifetimeMs=${lifetimeMs} stderr-tail=${JSON.stringify(tail)}`, level);
|
|
181
181
|
});
|
|
182
182
|
emitLifecycle(`op=spawn session=${SESSION_ID8} server=${SERVER_NAME} pid=${process.pid} entry=${ENTRY}`, "info");
|
|
183
|
+
// Task 2356 — present argv as a direct `node <entry>` invocation before the
|
|
184
|
+
// entry loads. The shim is meant to be transparent: an entry that asks the
|
|
185
|
+
// standard "am I the entry module?" question
|
|
186
|
+
// (`import.meta.url === pathToFileURL(realpathSync(process.argv[1])).href`)
|
|
187
|
+
// must get the same answer it gets when Claude Code runs it without the shim.
|
|
188
|
+
// With the shim's own path left in argv[1] the answer is no, so such an entry
|
|
189
|
+
// loads, starts nothing, and exits 0 — measured on the three channel servers,
|
|
190
|
+
// which all gate main() that way. Plugin MCPs connect at module top level and
|
|
191
|
+
// never read argv, so this is inert for them. ENTRY was captured above, before
|
|
192
|
+
// the rewrite. Extra CLI args keep their positions after the entry slot.
|
|
193
|
+
process.argv = [process.argv[0], ENTRY, ...process.argv.slice(3)];
|
|
183
194
|
// Run the real MCP server in THIS process. Dynamic import() (not top-level
|
|
184
195
|
// await — this file compiles to CommonJS) loads the ESM entry; a load-time
|
|
185
196
|
// failure mirrors the old child spawn-error path (op=error, exit 127). The
|
|
@@ -180,6 +180,17 @@ process.on("exit", (code) => {
|
|
|
180
180
|
`code=${codeField} signal=${exitSignal ?? "—"} lifetimeMs=${lifetimeMs} stderr-tail=${JSON.stringify(tail)}`, level);
|
|
181
181
|
});
|
|
182
182
|
emitLifecycle(`op=spawn session=${SESSION_ID8} server=${SERVER_NAME} pid=${process.pid} entry=${ENTRY}`, "info");
|
|
183
|
+
// Task 2356 — present argv as a direct `node <entry>` invocation before the
|
|
184
|
+
// entry loads. The shim is meant to be transparent: an entry that asks the
|
|
185
|
+
// standard "am I the entry module?" question
|
|
186
|
+
// (`import.meta.url === pathToFileURL(realpathSync(process.argv[1])).href`)
|
|
187
|
+
// must get the same answer it gets when Claude Code runs it without the shim.
|
|
188
|
+
// With the shim's own path left in argv[1] the answer is no, so such an entry
|
|
189
|
+
// loads, starts nothing, and exits 0 — measured on the three channel servers,
|
|
190
|
+
// which all gate main() that way. Plugin MCPs connect at module top level and
|
|
191
|
+
// never read argv, so this is inert for them. ENTRY was captured above, before
|
|
192
|
+
// the rewrite. Extra CLI args keep their positions after the entry slot.
|
|
193
|
+
process.argv = [process.argv[0], ENTRY, ...process.argv.slice(3)];
|
|
183
194
|
// Run the real MCP server in THIS process. Dynamic import() (not top-level
|
|
184
195
|
// await — this file compiles to CommonJS) loads the ESM entry; a load-time
|
|
185
196
|
// failure mirrors the old child spawn-error path (op=error, exit 127). The
|
|
@@ -180,6 +180,17 @@ process.on("exit", (code) => {
|
|
|
180
180
|
`code=${codeField} signal=${exitSignal ?? "—"} lifetimeMs=${lifetimeMs} stderr-tail=${JSON.stringify(tail)}`, level);
|
|
181
181
|
});
|
|
182
182
|
emitLifecycle(`op=spawn session=${SESSION_ID8} server=${SERVER_NAME} pid=${process.pid} entry=${ENTRY}`, "info");
|
|
183
|
+
// Task 2356 — present argv as a direct `node <entry>` invocation before the
|
|
184
|
+
// entry loads. The shim is meant to be transparent: an entry that asks the
|
|
185
|
+
// standard "am I the entry module?" question
|
|
186
|
+
// (`import.meta.url === pathToFileURL(realpathSync(process.argv[1])).href`)
|
|
187
|
+
// must get the same answer it gets when Claude Code runs it without the shim.
|
|
188
|
+
// With the shim's own path left in argv[1] the answer is no, so such an entry
|
|
189
|
+
// loads, starts nothing, and exits 0 — measured on the three channel servers,
|
|
190
|
+
// which all gate main() that way. Plugin MCPs connect at module top level and
|
|
191
|
+
// never read argv, so this is inert for them. ENTRY was captured above, before
|
|
192
|
+
// the rewrite. Extra CLI args keep their positions after the entry slot.
|
|
193
|
+
process.argv = [process.argv[0], ENTRY, ...process.argv.slice(3)];
|
|
183
194
|
// Run the real MCP server in THIS process. Dynamic import() (not top-level
|
|
184
195
|
// await — this file compiles to CommonJS) loads the ESM entry; a load-time
|
|
185
196
|
// failure mirrors the old child spawn-error path (op=error, exit 127). The
|
|
@@ -180,6 +180,17 @@ process.on("exit", (code) => {
|
|
|
180
180
|
`code=${codeField} signal=${exitSignal ?? "—"} lifetimeMs=${lifetimeMs} stderr-tail=${JSON.stringify(tail)}`, level);
|
|
181
181
|
});
|
|
182
182
|
emitLifecycle(`op=spawn session=${SESSION_ID8} server=${SERVER_NAME} pid=${process.pid} entry=${ENTRY}`, "info");
|
|
183
|
+
// Task 2356 — present argv as a direct `node <entry>` invocation before the
|
|
184
|
+
// entry loads. The shim is meant to be transparent: an entry that asks the
|
|
185
|
+
// standard "am I the entry module?" question
|
|
186
|
+
// (`import.meta.url === pathToFileURL(realpathSync(process.argv[1])).href`)
|
|
187
|
+
// must get the same answer it gets when Claude Code runs it without the shim.
|
|
188
|
+
// With the shim's own path left in argv[1] the answer is no, so such an entry
|
|
189
|
+
// loads, starts nothing, and exits 0 — measured on the three channel servers,
|
|
190
|
+
// which all gate main() that way. Plugin MCPs connect at module top level and
|
|
191
|
+
// never read argv, so this is inert for them. ENTRY was captured above, before
|
|
192
|
+
// the rewrite. Extra CLI args keep their positions after the entry slot.
|
|
193
|
+
process.argv = [process.argv[0], ENTRY, ...process.argv.slice(3)];
|
|
183
194
|
// Run the real MCP server in THIS process. Dynamic import() (not top-level
|
|
184
195
|
// await — this file compiles to CommonJS) loads the ESM entry; a load-time
|
|
185
196
|
// failure mirrors the old child spawn-error path (op=error, exit 127). The
|
|
@@ -274,7 +274,7 @@ Dispatch results are recorded on the Event node (`lastDispatchResult`, `lastDisp
|
|
|
274
274
|
|
|
275
275
|
It is **armed by the always-running `platform/ui` server on an interval**, because the Pi has no other periodic surface (the same gap `check-due-events` has). A PID lock at `<configDir>/reconcile-bookings.lock` prevents overlapping runs. It registers **no agent tool** — there is nothing for the agent to call — so the tool-surface registries are untouched.
|
|
276
276
|
|
|
277
|
-
Env: `PLATFORM_ROOT`, `NEO4J_URI` (and `NEO4J_PASSWORD` or `config/.neo4j-password`). Per account it reads `data/accounts/<id>/calendar-availability.json` (for `bookingDbName`). The Cloudflare credential is read house-only from `config/cloudflare-house.env`; that credential is a minter, so the calendar mints a `calendar-d1` (D1-only) token from it via `cf-token.sh` and
|
|
277
|
+
Env: `PLATFORM_ROOT`, `NEO4J_URI` (and `NEO4J_PASSWORD` or `config/.neo4j-password`). Per account it reads `data/accounts/<id>/calendar-availability.json` (for `bookingDbName`). The Cloudflare credential is read house-only from `config/cloudflare-house.env`; that credential is a minter, so the calendar mints a `calendar-d1` (D1-only) token from it via `cf-token.sh` and authenticates the D1 reads/writes on that scoped token, never the minter directly. Those reads and writes go over Cloudflare's D1 HTTP query API (`lib/d1-command.ts`), not a `wrangler` shell-out — no scheduling path shells a CLI, on this loop or on the availability publish. The bounds that the retired spawn carried survive as a 60 s per-request timeout and a 16 MB streamed response cap, and the endpoint is addressed per Cloudflare account, so `CLOUDFLARE_ACCOUNT_ID` is required rather than inferred.
|
|
278
278
|
|
|
279
279
|
Observability: one `[calendar-booking]` line per step keyed by `bookingId` (`reconcile-claim`, `meeting-write`, `notify`, `booked`), and one `[calendar-reconcile] account=… eligibleExamined=… pendingUnreconciled=… pendingOldestAgeMin=… orphanMeetings=…` audit line per account per run. `eligibleExamined` separates "nothing to do" from "verified clean". A `pendingUnreconciled` that persists across runs means those rows are failing to become meetings rather than merely lagging — the `attempt=` count on the claim and failure lines says how many times each has been tried. `orphanMeetings` means a booking meeting has no backing eligible D1 row. `pendingOldestAgeMin` ages that backlog: a count cannot separate a short lag from a nine-hour one. The companion `[calendar-reconcile] op=liveness lastRunAgeMin=… lastAuditAgeMin=… lastSkipReason=… stale=<bool>` line is emitted every ten minutes by the platform/ui server rather than by this script, because the failure it detects is this script not reporting at all. `op=liveness-write-failed` is the one case where that record could not be written; it carries the error body and never stops the run, because a run that worked must not be reported as failed for losing its own bookkeeping.
|
|
280
280
|
|
|
@@ -180,6 +180,17 @@ process.on("exit", (code) => {
|
|
|
180
180
|
`code=${codeField} signal=${exitSignal ?? "—"} lifetimeMs=${lifetimeMs} stderr-tail=${JSON.stringify(tail)}`, level);
|
|
181
181
|
});
|
|
182
182
|
emitLifecycle(`op=spawn session=${SESSION_ID8} server=${SERVER_NAME} pid=${process.pid} entry=${ENTRY}`, "info");
|
|
183
|
+
// Task 2356 — present argv as a direct `node <entry>` invocation before the
|
|
184
|
+
// entry loads. The shim is meant to be transparent: an entry that asks the
|
|
185
|
+
// standard "am I the entry module?" question
|
|
186
|
+
// (`import.meta.url === pathToFileURL(realpathSync(process.argv[1])).href`)
|
|
187
|
+
// must get the same answer it gets when Claude Code runs it without the shim.
|
|
188
|
+
// With the shim's own path left in argv[1] the answer is no, so such an entry
|
|
189
|
+
// loads, starts nothing, and exits 0 — measured on the three channel servers,
|
|
190
|
+
// which all gate main() that way. Plugin MCPs connect at module top level and
|
|
191
|
+
// never read argv, so this is inert for them. ENTRY was captured above, before
|
|
192
|
+
// the rewrite. Extra CLI args keep their positions after the entry slot.
|
|
193
|
+
process.argv = [process.argv[0], ENTRY, ...process.argv.slice(3)];
|
|
183
194
|
// Run the real MCP server in THIS process. Dynamic import() (not top-level
|
|
184
195
|
// await — this file compiles to CommonJS) loads the ESM entry; a load-time
|
|
185
196
|
// failure mirrors the old child spawn-error path (op=error, exit 127). The
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"availability-snapshot.test.d.ts","sourceRoot":"","sources":["../../../src/lib/__tests__/availability-snapshot.test.ts"],"names":[],"mappings":""}
|