@rubytech/create-maxy-code 0.1.183 → 0.1.185
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/__tests__/platform-port-stamp.test.js +4 -0
- package/dist/index.js +1 -0
- package/dist/port-resolution.js +1 -0
- package/package.json +1 -1
- package/payload/platform/config/brand.json +1 -1
- package/payload/platform/package-lock.json +178 -0
- package/payload/platform/plugins/.claude-plugin/marketplace.json +15 -0
- package/payload/platform/plugins/admin/PLUGIN.md +0 -1
- package/payload/platform/plugins/browser/.claude-plugin/plugin.json +17 -0
- package/payload/platform/plugins/browser/PLUGIN.md +44 -0
- package/payload/platform/plugins/browser/mcp/dist/index.d.ts +2 -0
- package/payload/platform/plugins/browser/mcp/dist/index.d.ts.map +1 -0
- package/payload/platform/plugins/browser/mcp/dist/index.js +61 -0
- package/payload/platform/plugins/browser/mcp/dist/index.js.map +1 -0
- package/payload/platform/plugins/browser/mcp/dist/lib/cdp-render.d.ts +66 -0
- package/payload/platform/plugins/browser/mcp/dist/lib/cdp-render.d.ts.map +1 -0
- package/payload/platform/plugins/browser/mcp/dist/lib/cdp-render.js +248 -0
- package/payload/platform/plugins/browser/mcp/dist/lib/cdp-render.js.map +1 -0
- package/payload/platform/plugins/browser/mcp/package.json +19 -0
- package/payload/platform/plugins/docs/references/internals.md +1 -1
- package/payload/platform/plugins/docs/references/plugins-guide.md +3 -0
- package/payload/platform/plugins/docs/references/troubleshooting.md +4 -4
- package/payload/platform/plugins/memory/PLUGIN.md +1 -0
- package/payload/platform/plugins/memory/mcp/dist/index.js +20 -10
- package/payload/platform/plugins/memory/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/prompt-optimiser/.claude-plugin/plugin.json +8 -0
- package/payload/platform/plugins/prompt-optimiser/PLUGIN.md +14 -0
- package/payload/platform/plugins/prompt-optimiser/skills/prompt-optimiser/SKILL.md +301 -0
- package/payload/platform/plugins/url-get/.claude-plugin/plugin.json +17 -0
- package/payload/platform/plugins/url-get/PLUGIN.md +86 -0
- package/payload/platform/plugins/url-get/mcp/dist/index.d.ts +9 -0
- package/payload/platform/plugins/url-get/mcp/dist/index.d.ts.map +1 -0
- package/payload/platform/plugins/url-get/mcp/dist/index.js +53 -0
- package/payload/platform/plugins/url-get/mcp/dist/index.js.map +1 -0
- package/payload/platform/plugins/url-get/mcp/dist/lib/summarise.d.ts +8 -0
- package/payload/platform/plugins/url-get/mcp/dist/lib/summarise.d.ts.map +1 -0
- package/payload/platform/plugins/url-get/mcp/dist/lib/summarise.js +83 -0
- package/payload/platform/plugins/url-get/mcp/dist/lib/summarise.js.map +1 -0
- package/payload/platform/plugins/url-get/mcp/dist/tools/url-get.d.ts +21 -0
- package/payload/platform/plugins/url-get/mcp/dist/tools/url-get.d.ts.map +1 -0
- package/payload/platform/plugins/url-get/mcp/dist/tools/url-get.js +147 -0
- package/payload/platform/plugins/url-get/mcp/dist/tools/url-get.js.map +1 -0
- package/payload/platform/plugins/url-get/mcp/package.json +22 -0
- package/payload/platform/scripts/setup-account.sh +0 -6
- package/payload/platform/scripts/vnc.sh +1 -1
- package/payload/platform/services/claude-session-manager/dist/http-server.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/http-server.js +46 -0
- 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 +17 -8
- 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 +40 -14
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/specialist-drift.js +2 -2
- package/payload/platform/services/claude-session-manager/dist/specialist-drift.js.map +1 -1
- package/payload/platform/templates/specialists/agents/content-producer.md +3 -3
- package/payload/platform/templates/specialists/agents/librarian.md +1 -1
- package/payload/platform/templates/specialists/agents/personal-assistant.md +3 -3
- package/payload/platform/templates/specialists/agents/research-assistant.md +3 -3
- package/payload/premium-plugins/writer-craft/mcp/dist/index.d.ts.map +1 -1
- package/payload/premium-plugins/writer-craft/mcp/dist/index.js +20 -6
- package/payload/premium-plugins/writer-craft/mcp/dist/index.js.map +1 -1
- package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-retrieve-conditioning.d.ts +14 -0
- package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-retrieve-conditioning.d.ts.map +1 -1
- package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-retrieve-conditioning.js +28 -34
- package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-retrieve-conditioning.js.map +1 -1
- package/payload/premium-plugins/writer-craft/mcp/scripts/smoke.mjs +43 -8
- package/payload/premium-plugins/writer-craft/mcp/src/index.ts +20 -8
- package/payload/premium-plugins/writer-craft/mcp/src/tools/voice-retrieve-conditioning.ts +51 -12
- package/payload/premium-plugins/writer-craft/skills/voice-mirror/SKILL.md +7 -1
- package/payload/server/server.js +222 -126
- package/payload/platform/plugins/admin/hooks/__tests__/playwright-file-guard.test.sh +0 -278
- package/payload/platform/plugins/admin/hooks/playwright-file-guard.sh +0 -214
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Render a JS-heavy page in the device's existing Chromium and return its DOM.
|
|
3
|
+
*
|
|
4
|
+
* The brand's VNC Chromium is launched by platform/scripts/vnc.sh with
|
|
5
|
+
* `--remote-debugging-port=${CDP_PORT}`, so CDP is already listening on
|
|
6
|
+
* 127.0.0.1:<port>. This module attaches to that running browser — it never
|
|
7
|
+
* launches its own — which is why no external browser package ships on device.
|
|
8
|
+
*
|
|
9
|
+
* Lifecycle (HTTP for target create/close, WebSocket for page control):
|
|
10
|
+
*
|
|
11
|
+
* PUT /json/new create a blank target, get its WS URL
|
|
12
|
+
* │
|
|
13
|
+
* ▼
|
|
14
|
+
* ws://…/devtools/page/<id> Page.enable → Page.navigate(url)
|
|
15
|
+
* │ await Page.loadEventFired (load-timeout)
|
|
16
|
+
* ▼
|
|
17
|
+
* Runtime.evaluate outerHTML + body.innerText (returnByValue)
|
|
18
|
+
* │
|
|
19
|
+
* ▼
|
|
20
|
+
* PUT /json/close/<id> always, even on the error paths above
|
|
21
|
+
*
|
|
22
|
+
* `fetch` and `WebSocket` are injected so the unit tests drive every branch
|
|
23
|
+
* without a real browser; production passes the Node 22 globals.
|
|
24
|
+
*/
|
|
25
|
+
const DEFAULT_LOAD_TIMEOUT_MS = 30_000;
|
|
26
|
+
const DEFAULT_COMMAND_TIMEOUT_MS = 15_000;
|
|
27
|
+
/** Create a blank target via the CDP HTTP surface. Maps every transport
|
|
28
|
+
* failure to a structured outcome rather than throwing. */
|
|
29
|
+
async function createTarget(deps, timeoutMs) {
|
|
30
|
+
const endpoint = `http://${deps.cdpHost}:${deps.cdpPort}/json/new`;
|
|
31
|
+
let res;
|
|
32
|
+
try {
|
|
33
|
+
res = await deps.fetchImpl(endpoint, { method: "PUT", signal: AbortSignal.timeout(timeoutMs) });
|
|
34
|
+
}
|
|
35
|
+
catch (err) {
|
|
36
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
37
|
+
if (msg.includes("ECONNREFUSED") || msg.includes("fetch failed") || msg.includes("ENOTFOUND")) {
|
|
38
|
+
return { outcome: "cdp-unreachable", detail: msg };
|
|
39
|
+
}
|
|
40
|
+
return { outcome: "error", detail: msg };
|
|
41
|
+
}
|
|
42
|
+
if (!res.ok) {
|
|
43
|
+
const body = await res.text().catch(() => "<unreadable>");
|
|
44
|
+
return { outcome: "error", detail: `CDP /json/new returned ${res.status}: ${body.slice(0, 200)}` };
|
|
45
|
+
}
|
|
46
|
+
let parsed;
|
|
47
|
+
try {
|
|
48
|
+
parsed = (await res.json());
|
|
49
|
+
}
|
|
50
|
+
catch (err) {
|
|
51
|
+
return { outcome: "error", detail: `CDP /json/new response not JSON: ${err instanceof Error ? err.message : String(err)}` };
|
|
52
|
+
}
|
|
53
|
+
if (!parsed.id || !parsed.webSocketDebuggerUrl) {
|
|
54
|
+
return { outcome: "error", detail: `CDP /json/new missing id/webSocketDebuggerUrl: ${JSON.stringify(parsed).slice(0, 200)}` };
|
|
55
|
+
}
|
|
56
|
+
return { target: { id: parsed.id, webSocketDebuggerUrl: parsed.webSocketDebuggerUrl } };
|
|
57
|
+
}
|
|
58
|
+
/** Best-effort target close. Failure is logged, never surfaced as the render
|
|
59
|
+
* outcome — the DOM was already captured by the time this runs. */
|
|
60
|
+
async function closeTarget(deps, targetId) {
|
|
61
|
+
const endpoint = `http://${deps.cdpHost}:${deps.cdpPort}/json/close/${encodeURIComponent(targetId)}`;
|
|
62
|
+
try {
|
|
63
|
+
await deps.fetchImpl(endpoint, { method: "PUT", signal: AbortSignal.timeout(5_000) });
|
|
64
|
+
}
|
|
65
|
+
catch (err) {
|
|
66
|
+
deps.log(`[browser-render] target-close-failed id=${targetId} err=${JSON.stringify(err instanceof Error ? err.message : String(err))}`);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/** Drives one CDP WebSocket session: correlates command ids to results and
|
|
70
|
+
* resolves a named event. Kept inside renderPage's closure scope so the
|
|
71
|
+
* socket, pending map, and event waiters share one lifetime. */
|
|
72
|
+
class CdpSession {
|
|
73
|
+
ws;
|
|
74
|
+
nextId = 1;
|
|
75
|
+
pending = new Map();
|
|
76
|
+
eventWaiters = new Map();
|
|
77
|
+
closed = false;
|
|
78
|
+
constructor(ws) {
|
|
79
|
+
this.ws = ws;
|
|
80
|
+
ws.addEventListener("message", (ev) => this.onMessage(ev.data));
|
|
81
|
+
ws.addEventListener("close", () => {
|
|
82
|
+
this.closed = true;
|
|
83
|
+
for (const { reject } of this.pending.values())
|
|
84
|
+
reject(new Error("websocket closed"));
|
|
85
|
+
this.pending.clear();
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
onMessage(data) {
|
|
89
|
+
if (typeof data !== "string")
|
|
90
|
+
return;
|
|
91
|
+
let msg;
|
|
92
|
+
try {
|
|
93
|
+
msg = JSON.parse(data);
|
|
94
|
+
}
|
|
95
|
+
catch {
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
if (typeof msg.id === "number") {
|
|
99
|
+
const waiter = this.pending.get(msg.id);
|
|
100
|
+
if (!waiter)
|
|
101
|
+
return;
|
|
102
|
+
this.pending.delete(msg.id);
|
|
103
|
+
if (msg.error)
|
|
104
|
+
waiter.reject(new Error(msg.error.message ?? "CDP command error"));
|
|
105
|
+
else
|
|
106
|
+
waiter.resolve(msg.result);
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
if (msg.method) {
|
|
110
|
+
const waiter = this.eventWaiters.get(msg.method);
|
|
111
|
+
if (waiter) {
|
|
112
|
+
this.eventWaiters.delete(msg.method);
|
|
113
|
+
waiter(msg.params);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
command(method, params, timeoutMs) {
|
|
118
|
+
if (this.closed)
|
|
119
|
+
return Promise.reject(new Error("websocket closed"));
|
|
120
|
+
const id = this.nextId++;
|
|
121
|
+
return new Promise((resolve, reject) => {
|
|
122
|
+
const timer = setTimeout(() => {
|
|
123
|
+
this.pending.delete(id);
|
|
124
|
+
reject(new Error(`CDP ${method} timed out after ${timeoutMs}ms`));
|
|
125
|
+
}, timeoutMs);
|
|
126
|
+
this.pending.set(id, {
|
|
127
|
+
resolve: (v) => { clearTimeout(timer); resolve(v); },
|
|
128
|
+
reject: (e) => { clearTimeout(timer); reject(e); },
|
|
129
|
+
});
|
|
130
|
+
this.ws.send(JSON.stringify({ id, method, params }));
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
waitForEvent(method, timeoutMs) {
|
|
134
|
+
return new Promise((resolve, reject) => {
|
|
135
|
+
const timer = setTimeout(() => {
|
|
136
|
+
this.eventWaiters.delete(method);
|
|
137
|
+
reject(new Error(`event ${method} not received within ${timeoutMs}ms`));
|
|
138
|
+
}, timeoutMs);
|
|
139
|
+
this.eventWaiters.set(method, () => { clearTimeout(timer); resolve(); });
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
function openSocket(WebSocketImpl, url, timeoutMs) {
|
|
144
|
+
return new Promise((resolve) => {
|
|
145
|
+
let settled = false;
|
|
146
|
+
let ws;
|
|
147
|
+
try {
|
|
148
|
+
ws = new WebSocketImpl(url);
|
|
149
|
+
}
|
|
150
|
+
catch (err) {
|
|
151
|
+
resolve({ error: err instanceof Error ? err.message : String(err) });
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
const timer = setTimeout(() => {
|
|
155
|
+
if (settled)
|
|
156
|
+
return;
|
|
157
|
+
settled = true;
|
|
158
|
+
try {
|
|
159
|
+
ws.close();
|
|
160
|
+
}
|
|
161
|
+
catch { /* ignore */ }
|
|
162
|
+
resolve({ error: `websocket open timed out after ${timeoutMs}ms` });
|
|
163
|
+
}, timeoutMs);
|
|
164
|
+
ws.addEventListener("open", () => {
|
|
165
|
+
if (settled)
|
|
166
|
+
return;
|
|
167
|
+
settled = true;
|
|
168
|
+
clearTimeout(timer);
|
|
169
|
+
resolve({ ws });
|
|
170
|
+
});
|
|
171
|
+
ws.addEventListener("error", (ev) => {
|
|
172
|
+
if (settled)
|
|
173
|
+
return;
|
|
174
|
+
settled = true;
|
|
175
|
+
clearTimeout(timer);
|
|
176
|
+
const detail = ev && typeof ev === "object" && "message" in ev ? String(ev.message) : "websocket error";
|
|
177
|
+
resolve({ error: detail });
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
/** Render `url` in the device Chromium and return its rendered DOM text.
|
|
182
|
+
* Always returns a structured RenderResult — never throws, never returns a
|
|
183
|
+
* silent empty page. */
|
|
184
|
+
export async function renderPage(url, opts, deps) {
|
|
185
|
+
const loadTimeoutMs = opts.loadTimeoutMs ?? DEFAULT_LOAD_TIMEOUT_MS;
|
|
186
|
+
const commandTimeoutMs = opts.commandTimeoutMs ?? DEFAULT_COMMAND_TIMEOUT_MS;
|
|
187
|
+
const fail = (outcome, detail) => {
|
|
188
|
+
deps.log(`[browser-render] url=${url} rendered=false outcome=${outcome} detail=${JSON.stringify(detail)}`);
|
|
189
|
+
return { url, rendered: false, outcome, domBytes: 0, text: "", html: "", detail };
|
|
190
|
+
};
|
|
191
|
+
if (!deps.WebSocketImpl) {
|
|
192
|
+
return fail("websocket-unavailable", "global WebSocket is not available on this runtime (Node < 22.4)");
|
|
193
|
+
}
|
|
194
|
+
if (!deps.cdpPort || Number.isNaN(deps.cdpPort)) {
|
|
195
|
+
return fail("cdp-unreachable", `CDP_PORT not set or invalid (got ${JSON.stringify(deps.cdpPort)})`);
|
|
196
|
+
}
|
|
197
|
+
const created = await createTarget(deps, commandTimeoutMs);
|
|
198
|
+
if ("outcome" in created)
|
|
199
|
+
return fail(created.outcome, created.detail);
|
|
200
|
+
const target = created.target;
|
|
201
|
+
const opened = await openSocket(deps.WebSocketImpl, target.webSocketDebuggerUrl, commandTimeoutMs);
|
|
202
|
+
if ("error" in opened) {
|
|
203
|
+
await closeTarget(deps, target.id);
|
|
204
|
+
return fail("cdp-unreachable", `websocket connect failed: ${opened.error}`);
|
|
205
|
+
}
|
|
206
|
+
const session = new CdpSession(opened.ws);
|
|
207
|
+
try {
|
|
208
|
+
await session.command("Page.enable", {}, commandTimeoutMs);
|
|
209
|
+
const loadPromise = session.waitForEvent("Page.loadEventFired", loadTimeoutMs);
|
|
210
|
+
try {
|
|
211
|
+
await session.command("Page.navigate", { url }, commandTimeoutMs);
|
|
212
|
+
}
|
|
213
|
+
catch (err) {
|
|
214
|
+
await closeTarget(deps, target.id);
|
|
215
|
+
return fail("navigate-failed", err instanceof Error ? err.message : String(err));
|
|
216
|
+
}
|
|
217
|
+
try {
|
|
218
|
+
await loadPromise;
|
|
219
|
+
}
|
|
220
|
+
catch (err) {
|
|
221
|
+
await closeTarget(deps, target.id);
|
|
222
|
+
return fail("load-timeout", err instanceof Error ? err.message : String(err));
|
|
223
|
+
}
|
|
224
|
+
let html = "";
|
|
225
|
+
let text = "";
|
|
226
|
+
try {
|
|
227
|
+
const htmlRes = (await session.command("Runtime.evaluate", { expression: "document.documentElement.outerHTML", returnByValue: true }, commandTimeoutMs));
|
|
228
|
+
html = typeof htmlRes?.result?.value === "string" ? htmlRes.result.value : "";
|
|
229
|
+
const textRes = (await session.command("Runtime.evaluate", { expression: "document.body && document.body.innerText || ''", returnByValue: true }, commandTimeoutMs));
|
|
230
|
+
text = typeof textRes?.result?.value === "string" ? textRes.result.value : "";
|
|
231
|
+
}
|
|
232
|
+
catch (err) {
|
|
233
|
+
await closeTarget(deps, target.id);
|
|
234
|
+
return fail("evaluate-failed", err instanceof Error ? err.message : String(err));
|
|
235
|
+
}
|
|
236
|
+
const domBytes = Buffer.byteLength(html, "utf8");
|
|
237
|
+
deps.log(`[browser-render] url=${url} rendered=true domBytes=${domBytes}`);
|
|
238
|
+
await closeTarget(deps, target.id);
|
|
239
|
+
return { url, rendered: true, outcome: "ok", domBytes, text, html };
|
|
240
|
+
}
|
|
241
|
+
finally {
|
|
242
|
+
try {
|
|
243
|
+
opened.ws.close();
|
|
244
|
+
}
|
|
245
|
+
catch { /* ignore */ }
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
//# sourceMappingURL=cdp-render.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cdp-render.js","sourceRoot":"","sources":["../../src/lib/cdp-render.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@maxy/browser",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"build": "tsc",
|
|
9
|
+
"start": "node dist/index.js"
|
|
10
|
+
},
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"@modelcontextprotocol/sdk": "^1.12.1",
|
|
13
|
+
"zod": "^3.24.0"
|
|
14
|
+
},
|
|
15
|
+
"devDependencies": {
|
|
16
|
+
"typescript": "^5.7.0",
|
|
17
|
+
"@types/node": "^22.0.0"
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -451,7 +451,7 @@ For subagents, the same spawn pushes `--add-dir` for every bundled plugin agents
|
|
|
451
451
|
|
|
452
452
|
A boot gate refuses to start the manager when any admin-allowlisted tool `mcp__<plugin>__*` lacks a registered server. The signal is `boot-failed reason=mcp-allowlist-without-server plugin=<p> tool=<t>` followed by `process.exit(1)`. The remediation is a one-line edit to the named `PLUGIN.md`: add the `mcp:` block. The complementary observability emit `mcp-config-allowlist-coverage admin-tools=A admin-registered=R` (where `A === R`) confirms the invariant per boot.
|
|
453
453
|
|
|
454
|
-
A second boot gate walks every specialist `.md` under `platform/templates/specialists/agents/`, every bundled `<plugin>/agents/` directory, and the per-account `<accountDir>/specialists/agents/` directory, parses each file's `tools:` frontmatter line, and classifies every tool name as one of: CC-native (Read, Bash, …), bridge-namespace (`
|
|
454
|
+
A second boot gate walks every specialist `.md` under `platform/templates/specialists/agents/`, every bundled `<plugin>/agents/` directory, and the per-account `<accountDir>/specialists/agents/` directory, parses each file's `tools:` frontmatter line, and classifies every tool name as one of: CC-native (Read, Bash, …), bridge-namespace (`mcp__plugin_*`, `mcp__graph__*`), a tool the loaded `PLUGIN.md` set actually serves, `unknown-tool-in-plugin` (namespace served but tool name absent), `unknown-plugin-namespace` (namespace served by nothing), `brand-excluded-plugin` (namespace served by nothing on this brand, **but** the brand's `brand.json#plugins.excluded` list names it), or `malformed-name` (not CC-native and not `mcp__<plugin>__<tool>`-shaped). The first three pass. The next two refuse boot with one `boot-failed reason=specialist-tool-drift specialist=<name> tool=<t> drift=<class> path=<…>` line per defect, then `process.exit(1)`. `brand-excluded-plugin` is a structural pass: it lands in a per-specialist strip-list, the manager continues to boot, and at spawn time `pty-spawner` removes those tool names from the `--agent <name>` spawn's `--allowed-tools` argv. The complementary observability emit `specialist-tool-strip specialist=<name> plugin=<p> tools=<csv> reason=brand-excluded` fires one line per stripped (specialist, plugin) pair so an operator who reads `server.log` sees the brand filter doing work without cross-referencing `brand.json` against the template. The startup-self-test line `startup-self-test specialist-tool-drift=ok inspected=<N> stripped-specialists=<M>` confirms the gate ran and how many specialists carry strip-lists.
|
|
455
455
|
|
|
456
456
|
This gate was Task 173. The `brand-excluded` branch closes the recurring crash-restart loop on brands that ship without a plugin the shared `personal-assistant.md` template references (e.g. `realagent-code` excludes `telegram` while the template hard-codes `mcp__telegram__*`). The brand-agnostic template stays a single file; the brand-aware filter expresses what the specialist *may* do on this install while the template expresses what it *can* do across brands. Tool typos and renamed plugins still refuse to boot — only namespaces explicitly named in `plugins.excluded` are demoted to strip-and-warn.
|
|
457
457
|
|
|
@@ -16,6 +16,7 @@ These are part of {{productName}}'s foundation and cannot be disabled:
|
|
|
16
16
|
|--------|-------------|
|
|
17
17
|
| `admin` | Platform management — system status, account settings, logs, session control. Also hosts the cross-cutting `plainly` skill: every text-producing agent (admin, public, every specialist) applies a plain-English precision pass to prose returned to humans, as a prime-directive prerogative. Agent-to-machine payloads (image-generate prompts, memory-write arguments, cypher) pass through verbatim. Enforced mechanically by `.claude/hooks/precision-check.sh`. |
|
|
18
18
|
| `memory` | Graph memory — search, write, reindex, and ingest knowledge |
|
|
19
|
+
| `browser` | Headless browser rendering — `browser-render` runs a JavaScript-heavy page in the device's Chromium and returns its rendered DOM. The JS-rendering leg of retrieval: WebFetch (summary) / `url-get` (verbatim, server-rendered) / `browser-render` (JS-rendered). |
|
|
19
20
|
| `maxy-guide` | User guide and platform documentation (this plugin) |
|
|
20
21
|
| `cloudflare` | Cloudflare Tunnel — remote access via your custom domain |
|
|
21
22
|
| `scheduling` | Calendar and scheduling — events, appointments, recurring triggers. Any activity involving time (date, timestamp, day of week, month, duration) routes through `time-resolve` first. Two read-only tools (`current-datetime`, `time-resolve`) are always available to every public agent regardless of enabled plugins. |
|
|
@@ -23,6 +24,8 @@ These are part of {{productName}}'s foundation and cannot be disabled:
|
|
|
23
24
|
| `tasks` | Task lifecycle — create, update, list, relate, complete |
|
|
24
25
|
| `workflows` | Persistent named workflows — reusable instruction sets |
|
|
25
26
|
| `contacts` | CRM contact management — create, lookup, update, list |
|
|
27
|
+
| `prompt-optimiser` | Prompt optimiser — turns a rough draft or task description into a single finished, copy-pasteable prompt tuned for Opus 4.7 adaptive thinking in the chat app (claude.ai, Mac, iOS) |
|
|
28
|
+
| `url-get` | Faithful page retrieval — fetches a server-rendered page, writes a verbatim markdown copy to an account-scoped reference file (no model in the path, so no copyright refusal), and returns a transformative summary plus the file path. Use instead of WebFetch when a faithful copy is needed (e.g. ingesting your own published writing). |
|
|
26
29
|
|
|
27
30
|
### {{productName}} Plugins (user-selectable)
|
|
28
31
|
|
|
@@ -8,13 +8,13 @@
|
|
|
8
8
|
|
|
9
9
|
**Diagnose if it ever recurs:** run `bash platform/scripts/__tests__/first-token-creates-stream-log.test.sh` from the install. Pass = invariant holds; any other exit = the writer-side existence contract is broken and one `[log-tee] missing-on-resolve sessionKey=<8> surface=<…>` line on `server.log` is the operator-visible signal (P0). For the duplicate-file class specifically (the 2026-05-14 recurrence trigger), `bash platform/scripts/log-adherence-check.sh` returns non-zero whenever any sessionKey has more than one `claude-agent-stream-<sk>.log` across account dirs.
|
|
10
10
|
|
|
11
|
-
##
|
|
11
|
+
## A JavaScript-rendered page comes back empty from WebFetch or `url-get`
|
|
12
12
|
|
|
13
|
-
**Symptom:**
|
|
13
|
+
**Symptom:** A page that needs JavaScript to show its content returns empty or a shell document from `WebFetch` (summary) or `url-get` (verbatim, server-rendered).
|
|
14
14
|
|
|
15
|
-
**Resolution
|
|
15
|
+
**Resolution:** Use the `browser` core plugin's `browser-render` tool. It renders the page in the device's per-brand Chromium over the Chrome DevTools Protocol (the same browser the VNC viewer shows) and returns the rendered HTML plus visible text. It attaches to the already-running Chromium on `127.0.0.1:${CDP_PORT}` — nothing is downloaded or installed mid-session.
|
|
16
16
|
|
|
17
|
-
**Diagnose if it ever recurs:** grep the per-conversation stream log for `[
|
|
17
|
+
**Diagnose if it ever recurs:** grep the per-conversation stream log for `[browser-render]`. `rendered=true domBytes=<n>` is the healthy signal. `rendered=false outcome=cdp-unreachable` means no Chromium is listening on the brand's CDP port — confirm with `curl 127.0.0.1:<cdpPort>/json/version`. Other outcomes (`navigate-failed`, `load-timeout`, `evaluate-failed`) name the failed CDP step.
|
|
18
18
|
|
|
19
19
|
## First user-domain write rejected by `[graph-write-gate] reject reason=no-admin-user`
|
|
20
20
|
|
|
@@ -67,11 +67,12 @@ const readOnly = process.env.READ_ONLY === "true";
|
|
|
67
67
|
// Module-init must never throw; plugin-system spawn enumerates tools/list
|
|
68
68
|
// before ACCOUNT_ID is set. Per-call refusal preserves account isolation.
|
|
69
69
|
const accountId = process.env.ACCOUNT_ID ?? null;
|
|
70
|
-
// Task 476 — extended boot signal: sessionId
|
|
71
|
-
// so a stale spawn-env contract is
|
|
72
|
-
//
|
|
73
|
-
//
|
|
74
|
-
|
|
70
|
+
// Task 476/487 — extended boot signal: sessionId, agentSlug (provenance),
|
|
71
|
+
// and agentScope (read-scope) land here so a stale spawn-env contract is
|
|
72
|
+
// visible at the first byte of stderr. Regression shapes: `sessionId ===
|
|
73
|
+
// accountId`; `agentSlug` empty on a specialist spawn (provenance lost);
|
|
74
|
+
// `agentScope` non-empty on the admin operator spawn (search wrongly scoped).
|
|
75
|
+
process.stderr.write(`[memory] boot accountId=${accountId ?? "null"} sessionId=${process.env.SESSION_ID || "-"} agentSlug=${process.env.AGENT_SLUG || "-"} agentScope=${process.env.AGENT_SLUG_SCOPE || "-"}\n`);
|
|
75
76
|
function refuseNoAccount(toolName) {
|
|
76
77
|
process.stderr.write(`[memory] tool=${toolName} refuse reason=no-account-context\n`);
|
|
77
78
|
return {
|
|
@@ -165,10 +166,17 @@ function resolveSessionId(override) {
|
|
|
165
166
|
const fromEnv = process.env.SESSION_ID;
|
|
166
167
|
return fromEnv && fromEnv.trim() ? fromEnv.trim() : undefined;
|
|
167
168
|
}
|
|
168
|
-
//
|
|
169
|
-
// `
|
|
170
|
-
//
|
|
169
|
+
// Provenance stamp: AGENT_SLUG is the agent identity recorded as
|
|
170
|
+
// `createdByAgent` on every write. The admin operator gets the 'admin'
|
|
171
|
+
// sentinel (Task 487); specialists/public get their slug.
|
|
171
172
|
const envAgentSlug = process.env.AGENT_SLUG || undefined;
|
|
173
|
+
// Per-agent knowledge scoping (Task 487 split this off AGENT_SLUG): when set,
|
|
174
|
+
// memory-search only returns nodes whose `agents` array contains this slug.
|
|
175
|
+
// Specialists/public get their slug here (server-level enforcement); the admin
|
|
176
|
+
// operator gets EMPTY so search stays wide-open. For admin, an optional tool
|
|
177
|
+
// param can still scope a single query. Read-scope and provenance are now
|
|
178
|
+
// independent — admin writes stamp 'admin' while admin reads stay unscoped.
|
|
179
|
+
const envAgentScopeSlug = process.env.AGENT_SLUG_SCOPE || undefined;
|
|
172
180
|
// Keyword subscriptions: comma-separated list of keywords for BM25-based reactive
|
|
173
181
|
// knowledge inclusion. When set, memory-search runs a BM25 query per keyword and
|
|
174
182
|
// unions results with directly-tagged nodes. Capped at 5 for Pi performance.
|
|
@@ -239,8 +247,10 @@ eagerTool(server, "memory-search", "Search the knowledge graph using semantic ve
|
|
|
239
247
|
}, async ({ query, labels, limit, expandHops, keywords, keywordMatch, agentSlug: toolAgentSlug, fields, retrievalClass }) => {
|
|
240
248
|
if (!accountId)
|
|
241
249
|
return refuseNoAccount("memory-search");
|
|
242
|
-
//
|
|
243
|
-
|
|
250
|
+
// AGENT_SLUG_SCOPE takes precedence over the tool param (security: public
|
|
251
|
+
// agent server-level enforcement). Empty for the admin operator, so admin
|
|
252
|
+
// falls through to the optional tool param (default: unscoped).
|
|
253
|
+
const effectiveAgentSlug = envAgentScopeSlug ?? toolAgentSlug;
|
|
244
254
|
try {
|
|
245
255
|
const results = await memorySearch({
|
|
246
256
|
query,
|