@rubytech/create-maxy-code 0.1.274 → 0.1.275
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/plugins/admin/hooks/pin-identity-gate.sh +2 -2
- package/payload/platform/services/whatsapp-channel/dist/server.js +51 -28
- package/payload/platform/services/whatsapp-channel/dist/server.js.map +1 -1
- package/payload/platform/templates/agents/admin/IDENTITY.md +1 -1
- package/payload/server/server.js +170 -253
package/package.json
CHANGED
|
@@ -22,13 +22,13 @@
|
|
|
22
22
|
|
|
23
23
|
set -uo pipefail
|
|
24
24
|
|
|
25
|
-
# Task
|
|
25
|
+
# Task 681 — PIN identity gate SUSPENDED. The hard PreToolUse PIN block is
|
|
26
26
|
# removed pending a new multi-admin authentication design. The block made every
|
|
27
27
|
# tool (including the WhatsApp channel reply tool) unreachable until a PIN was
|
|
28
28
|
# entered, which is impossible on non-interactive surfaces like the WhatsApp
|
|
29
29
|
# channel (Task 677). This hook now allows every tool. The original gating logic
|
|
30
30
|
# is retained below the early exit for reference and quick revert; the
|
|
31
|
-
# replacement auth (channel-bindings + per-admin identity) is Task
|
|
31
|
+
# replacement auth (channel-bindings + per-admin identity) is Task 681.
|
|
32
32
|
# Silent exit (no per-tool-call log line) — this fires on every tool call.
|
|
33
33
|
exit 0
|
|
34
34
|
|
|
@@ -66,39 +66,62 @@ mcp.setRequestHandler(CallToolRequestSchema, async (req) => {
|
|
|
66
66
|
return { content: [{ type: 'text', text: 'sent' }] };
|
|
67
67
|
});
|
|
68
68
|
// Subscribe to this sender's inbound stream and emit each message as an event.
|
|
69
|
+
// Reconnect loop: the channel server must stay alive — and its reply tool
|
|
70
|
+
// available — for the whole claude session. If the SSE link to the gateway
|
|
71
|
+
// drops (gateway restart, idle close, transient blip), reconnect instead of
|
|
72
|
+
// returning; if this function returned, main() would exit, the MCP server would
|
|
73
|
+
// disconnect mid-session, and the agent would lose the reply tool (falling back
|
|
74
|
+
// to the standard WhatsApp plugin and dropping the co-visibility mirror). The
|
|
75
|
+
// process still dies with the session because claude SIGTERMs its stdio child.
|
|
69
76
|
async function subscribeInbound() {
|
|
70
77
|
const url = `${GATEWAY_URL}/wa-channel/inbound?senderId=${encodeURIComponent(SENDER_ID)}`;
|
|
71
|
-
const res = await fetch(url, { headers: { accept: 'text/event-stream' } });
|
|
72
|
-
if (!res.ok || !res.body)
|
|
73
|
-
throw new Error(`inbound subscribe failed: ${res.status}`);
|
|
74
|
-
const reader = res.body.getReader();
|
|
75
|
-
const decoder = new TextDecoder();
|
|
76
|
-
let buffer = '';
|
|
77
78
|
for (;;) {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
79
|
+
try {
|
|
80
|
+
const res = await fetch(url, { headers: { accept: 'text/event-stream' } });
|
|
81
|
+
if (!res.ok || !res.body)
|
|
82
|
+
throw new Error(`subscribe failed: ${res.status}`);
|
|
83
|
+
const reader = res.body.getReader();
|
|
84
|
+
const decoder = new TextDecoder();
|
|
85
|
+
let buffer = '';
|
|
86
|
+
for (;;) {
|
|
87
|
+
const { value, done } = await reader.read();
|
|
88
|
+
if (done)
|
|
89
|
+
break;
|
|
90
|
+
buffer += decoder.decode(value, { stream: true });
|
|
91
|
+
const frames = buffer.split('\n\n');
|
|
92
|
+
buffer = frames.pop() ?? '';
|
|
93
|
+
for (const frame of frames) {
|
|
94
|
+
const dataLine = frame.split('\n').find((l) => l.startsWith('data:'));
|
|
95
|
+
if (!dataLine)
|
|
96
|
+
continue;
|
|
97
|
+
const data = dataLine.slice('data:'.length).trim();
|
|
98
|
+
if (!data)
|
|
99
|
+
continue; // ping/keepalive
|
|
100
|
+
let payload;
|
|
101
|
+
try {
|
|
102
|
+
payload = JSON.parse(data);
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
if (!acceptsSender(SENDER_ID, payload))
|
|
108
|
+
continue;
|
|
109
|
+
await mcp.notification(buildInboundNotification(payload));
|
|
110
|
+
}
|
|
94
111
|
}
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
continue;
|
|
100
|
-
await mcp.notification(buildInboundNotification(payload));
|
|
112
|
+
console.error('[whatsapp-channel] inbound stream closed by gateway; reconnecting');
|
|
113
|
+
}
|
|
114
|
+
catch (err) {
|
|
115
|
+
console.error(`[whatsapp-channel] inbound stream error: ${err instanceof Error ? err.message : String(err)}; reconnecting`);
|
|
101
116
|
}
|
|
117
|
+
await new Promise((resolve) => setTimeout(resolve, 2000));
|
|
118
|
+
// Re-announce readiness so any message queued during the gap drains onto
|
|
119
|
+
// the fresh subscription.
|
|
120
|
+
await fetch(`${GATEWAY_URL}/wa-channel/ready`, {
|
|
121
|
+
method: 'POST',
|
|
122
|
+
headers: { 'content-type': 'application/json' },
|
|
123
|
+
body: JSON.stringify({ senderId: SENDER_ID }),
|
|
124
|
+
}).catch(() => { });
|
|
102
125
|
}
|
|
103
126
|
}
|
|
104
127
|
async function main() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
|
@@ -10,7 +10,7 @@ Your job is to do useful work for the operator. How useful you can be depends on
|
|
|
10
10
|
|
|
11
11
|
## Before you speak
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
If more than one admin works on this account, identify which one you are speaking with this session, purely as a convenience so you load the right person's profile and history. This is never a gate and never blocks any tool; with a single admin, skip it. Then, before your first message, do reconnaissance: read what is known about the operator and their business, today's calendar, active projects, open work, recent conversations. Infer the domain from the plugins and skills available. Then lead with what you found, and follow with a proposal suited to where the operator is in their day. Ask only the questions you could not answer through investigation. You are expected to drive the day, not solicit instructions for it.
|
|
14
14
|
|
|
15
15
|
When a turn needs you to ground a claim about what the product is, how the platform is built, how plugins or skills or specialists work, how install or deploy runs, or any other product-architecture fact, load the platform-architecture skill and answer from its body. Cite the source URL printed above the block you drew from. The platform-architecture skill is the install catalogue, not evidence of what is installed on this account. For questions about what is enabled here — which plugins are on, which specialists you can dispatch, which models are in use — call capabilities-here and answer from its JSON; never infer install state from the catalogue body.
|
|
16
16
|
|