@rubytech/create-maxy-code 0.1.186 → 0.1.188
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.js +4 -3
- package/payload/platform/lib/graph-mcp/dist/index.js.map +1 -1
- package/payload/platform/lib/graph-mcp/src/index.ts +4 -3
- package/payload/platform/package.json +1 -0
- package/payload/platform/plugins/.claude-plugin/marketplace.json +5 -0
- package/payload/platform/plugins/admin/PLUGIN.md +1 -0
- package/payload/platform/plugins/admin/hooks/lib/maxy-mcp-plugins.txt +16 -0
- package/payload/platform/plugins/admin/hooks/mcp-tool-missing.sh +94 -0
- package/payload/platform/plugins/admin/hooks/turn-completed-graph-write.sh +7 -0
- package/payload/platform/plugins/admin/skills/a4-print-documents/SKILL.md +14 -14
- package/payload/platform/plugins/admin/skills/deck-pages/SKILL.md +9 -23
- package/payload/platform/plugins/admin/skills/professional-document/SKILL.md +1 -1
- package/payload/platform/plugins/admin/skills/publish-site/SKILL.md +3 -3
- package/payload/platform/plugins/admin/skills/skill-builder/SKILL.md +1 -1
- package/payload/platform/plugins/admin/skills/skill-builder/references/pdf-generation.md +4 -4
- package/payload/platform/plugins/admin/skills/stream-log-review/references/analysis-patterns.md +11 -7
- package/payload/platform/plugins/browser/.claude-plugin/plugin.json +1 -1
- package/payload/platform/plugins/browser/PLUGIN.md +78 -8
- package/payload/platform/plugins/browser/mcp/dist/index.js +111 -7
- package/payload/platform/plugins/browser/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/browser/mcp/dist/lib/cdp-actions.d.ts +98 -0
- package/payload/platform/plugins/browser/mcp/dist/lib/cdp-actions.d.ts.map +1 -0
- package/payload/platform/plugins/browser/mcp/dist/lib/cdp-actions.js +455 -0
- package/payload/platform/plugins/browser/mcp/dist/lib/cdp-actions.js.map +1 -0
- package/payload/platform/plugins/browser/mcp/dist/lib/cdp-render.d.ts +9 -31
- package/payload/platform/plugins/browser/mcp/dist/lib/cdp-render.d.ts.map +1 -1
- package/payload/platform/plugins/browser/mcp/dist/lib/cdp-render.js +6 -165
- package/payload/platform/plugins/browser/mcp/dist/lib/cdp-render.js.map +1 -1
- package/payload/platform/plugins/browser/mcp/dist/lib/cdp-session.d.ts +153 -0
- package/payload/platform/plugins/browser/mcp/dist/lib/cdp-session.d.ts.map +1 -0
- package/payload/platform/plugins/browser/mcp/dist/lib/cdp-session.js +401 -0
- package/payload/platform/plugins/browser/mcp/dist/lib/cdp-session.js.map +1 -0
- package/payload/platform/plugins/docs/references/admin-ui.md +3 -4
- package/payload/platform/plugins/docs/references/deployment.md +1 -1
- package/payload/platform/plugins/docs/references/internals.md +6 -4
- package/payload/platform/plugins/docs/references/plugins-guide.md +2 -2
- package/payload/platform/plugins/email/.claude-plugin/plugin.json +1 -1
- package/payload/platform/plugins/email/PLUGIN.md +6 -2
- package/payload/platform/plugins/email/mcp/dist/index.js +38 -0
- package/payload/platform/plugins/email/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/lib/providers.d.ts +28 -0
- package/payload/platform/plugins/email/mcp/dist/lib/providers.d.ts.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/lib/providers.js +106 -0
- package/payload/platform/plugins/email/mcp/dist/lib/providers.js.map +1 -1
- package/payload/platform/plugins/email/references/email-reference.md +19 -15
- package/payload/platform/plugins/graph/.claude-plugin/plugin.json +8 -0
- package/payload/platform/plugins/graph/PLUGIN.md +37 -0
- package/payload/platform/plugins/memory/PLUGIN.md +2 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/conversation-archive-derive-insights.d.ts +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/conversation-archive-derive-insights.js +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-brain-capture-recent.d.ts.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-brain-capture-recent.js +3 -2
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-brain-capture-recent.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-compiled-truth-history.d.ts.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-compiled-truth-history.js +2 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-compiled-truth-history.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-review-queue.d.ts.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-review-queue.js +2 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-review-queue.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/session-retrospective-skip-rate.d.ts +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/session-retrospective-skip-rate.d.ts.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/session-retrospective-skip-rate.js +3 -2
- package/payload/platform/plugins/memory/mcp/dist/tools/session-retrospective-skip-rate.js.map +1 -1
- package/payload/platform/plugins/memory/references/graph-primitives.md +36 -27
- package/payload/platform/plugins/obsidian-import/PLUGIN.md +1 -1
- package/payload/platform/plugins/telegram/mcp/dist/tools/message-history.js +1 -1
- package/payload/platform/plugins/telegram/mcp/dist/tools/message-history.js.map +1 -1
- package/payload/platform/scripts/check-canonical-tool-names.mjs +110 -0
- package/payload/platform/scripts/check-cypher-int-params.mjs +277 -0
- package/payload/platform/scripts/generate-canonical-tool-names.mjs +63 -0
- package/payload/platform/scripts/lib/canonical-tool-names.mjs +88 -0
- package/payload/platform/scripts/setup-account.sh +6 -0
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.d.ts +7 -0
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.d.ts.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.d.ts +5 -0
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.d.ts.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js +204 -0
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.js +23 -0
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.js.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/index.js +30 -6
- package/payload/platform/services/claude-session-manager/dist/index.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/mcp-tools-probe.d.ts +6 -4
- package/payload/platform/services/claude-session-manager/dist/mcp-tools-probe.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/mcp-tools-probe.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts +1 -0
- 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 +50 -26
- 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 +40 -0
- package/payload/platform/services/claude-session-manager/dist/rc-daemon.d.ts.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/rc-daemon.js +200 -0
- package/payload/platform/services/claude-session-manager/dist/rc-daemon.js.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/specialist-drift.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/specialist-drift.js +50 -34
- package/payload/platform/services/claude-session-manager/dist/specialist-drift.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/tool-surface.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/tool-surface.js +23 -13
- package/payload/platform/services/claude-session-manager/dist/tool-surface.js.map +1 -1
- package/payload/platform/templates/specialists/agents/content-producer.md +4 -4
- package/payload/platform/templates/specialists/agents/librarian.md +2 -2
- package/payload/platform/templates/specialists/agents/personal-assistant.md +6 -2
- package/payload/platform/templates/specialists/agents/project-manager.md +1 -1
- package/payload/platform/templates/specialists/agents/research-assistant.md +1 -1
- 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 +33 -1
- package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-retrieve-conditioning.js.map +1 -1
- package/payload/premium-plugins/writer-craft/mcp/src/tools/voice-retrieve-conditioning.ts +5 -2
- package/payload/server/{chunk-L2YK2VK3.js → chunk-WWD4TCJJ.js} +3 -17
- package/payload/server/maxy-edge.js +1 -1
- package/payload/server/public/assets/Checkbox-ChWmQ7if.js +1 -0
- package/payload/server/public/assets/admin-BLi_fAKQ.js +216 -0
- package/payload/server/public/assets/{architectureDiagram-Q4EWVU46-DZoOzmjE.js → architectureDiagram-Q4EWVU46-DSqzB21V.js} +1 -1
- package/payload/server/public/assets/{blockDiagram-DXYQGD6D-DG3yufCR.js → blockDiagram-DXYQGD6D--otTO_UB.js} +1 -1
- package/payload/server/public/assets/brand-Djtb-tLQ.js +9 -0
- package/payload/server/public/assets/{c4Diagram-AHTNJAMY-BBx5wXuZ.js → c4Diagram-AHTNJAMY-CBszqa9W.js} +1 -1
- package/payload/server/public/assets/channel-C-SJYogg.js +1 -0
- package/payload/server/public/assets/{chunk-336JU56O-DwP7g5ns.js → chunk-336JU56O-ClAJP2KY.js} +2 -2
- package/payload/server/public/assets/{chunk-426QAEUC-DXzGdc22.js → chunk-426QAEUC-CgLucS4H.js} +1 -1
- package/payload/server/public/assets/{chunk-4TB4RGXK-1LDRjk0E.js → chunk-4TB4RGXK-BvOX6mSk.js} +1 -1
- package/payload/server/public/assets/{chunk-5FUZZQ4R-BHjWhwhn.js → chunk-5FUZZQ4R-uyN4XtrW.js} +1 -1
- package/payload/server/public/assets/{chunk-5PVQY5BW-CwPHRVN8.js → chunk-5PVQY5BW-B6xHEzh2.js} +1 -1
- package/payload/server/public/assets/{chunk-EDXVE4YY-7443hrYZ.js → chunk-EDXVE4YY-9objw8tW.js} +1 -1
- package/payload/server/public/assets/{chunk-ENJZ2VHE-BTnmmnmX.js → chunk-ENJZ2VHE-pQpbHIJL.js} +1 -1
- package/payload/server/public/assets/{chunk-ICPOFSXX-CPnMJplL.js → chunk-ICPOFSXX-qS23jC3x.js} +1 -1
- package/payload/server/public/assets/{chunk-OYMX7WX6-DCQ5Q4RS.js → chunk-OYMX7WX6-C9YUwGqp.js} +1 -1
- package/payload/server/public/assets/{chunk-U2HBQHQK-BmfZG8e4.js → chunk-U2HBQHQK-D_pYedRJ.js} +1 -1
- package/payload/server/public/assets/{chunk-X2U36JSP-Da2yJL2u.js → chunk-X2U36JSP-nxf6GHD-.js} +1 -1
- package/payload/server/public/assets/{chunk-YZCP3GAM-BdUmMUJ6.js → chunk-YZCP3GAM-DqKT124V.js} +1 -1
- package/payload/server/public/assets/{chunk-ZZ45TVLE-abkGirrZ.js → chunk-ZZ45TVLE-CLwvpbvu.js} +1 -1
- package/payload/server/public/assets/classDiagram-6PBFFD2Q-OBkxl5to.js +1 -0
- package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-CkTyus-1.js +1 -0
- package/payload/server/public/assets/clone-VufdPzJ-.js +1 -0
- package/payload/server/public/assets/{dagre-BVVuAEsU.js → dagre-COCXt23n.js} +1 -1
- package/payload/server/public/assets/{dagre-KV5264BT-VG2kNj19.js → dagre-KV5264BT-DmuVMrt4.js} +1 -1
- package/payload/server/public/assets/data-TlJbMIfa.js +1 -0
- package/payload/server/public/assets/{diagram-5BDNPKRD-DRiVy69K.js → diagram-5BDNPKRD-DOiLSgj_.js} +1 -1
- package/payload/server/public/assets/{diagram-G4DWMVQ6-DtpiRTYX.js → diagram-G4DWMVQ6-quY6PSZQ.js} +1 -1
- package/payload/server/public/assets/{diagram-MMDJMWI5-Da3t99fY.js → diagram-MMDJMWI5-tN2yiz0C.js} +1 -1
- package/payload/server/public/assets/{diagram-TYMM5635-BzQmLTJQ.js → diagram-TYMM5635-CjrRQNQ0.js} +1 -1
- package/payload/server/public/assets/{erDiagram-SMLLAGMA-D3Ll-GDw.js → erDiagram-SMLLAGMA-CrNNMxkA.js} +1 -1
- package/payload/server/public/assets/{flowDiagram-DWJPFMVM-D17bje6d.js → flowDiagram-DWJPFMVM-CCUsJph7.js} +1 -1
- package/payload/server/public/assets/{ganttDiagram-T4ZO3ILL-BjeQ-Bun.js → ganttDiagram-T4ZO3ILL-18276bri.js} +1 -1
- package/payload/server/public/assets/{gitGraphDiagram-UUTBAWPF-LtX4pvZS.js → gitGraphDiagram-UUTBAWPF-CsLsKMjN.js} +1 -1
- package/payload/server/public/assets/graph-D2Yvni5R.js +1 -0
- package/payload/server/public/assets/graph-labels-uksnCgSC.js +1 -0
- package/payload/server/public/assets/{graphlib-CzwsfZOw.js → graphlib-CmtUzIni.js} +1 -1
- package/payload/server/public/assets/{infoDiagram-42DDH7IO-DOgH4i52.js → infoDiagram-42DDH7IO-Dny_ZNz3.js} +1 -1
- package/payload/server/public/assets/{ishikawaDiagram-UXIWVN3A-DYqy5BFj.js → ishikawaDiagram-UXIWVN3A-kUhIUQE-.js} +1 -1
- package/payload/server/public/assets/{journeyDiagram-VCZTEJTY-CsFpIULJ.js → journeyDiagram-VCZTEJTY-DekMvAKB.js} +1 -1
- package/payload/server/public/assets/{kanban-definition-6JOO6SKY-5uZuArw7.js → kanban-definition-6JOO6SKY-st0HNZZo.js} +1 -1
- package/payload/server/public/assets/lib-Ca7uCvl9.js +33 -0
- package/payload/server/public/assets/{line-BY8PmCSW.js → line-BaNk-I7J.js} +1 -1
- package/payload/server/public/assets/{mermaid-parser.core-CJ_9xqwK.js → mermaid-parser.core-CRCHYQ_F.js} +1 -1
- package/payload/server/public/assets/{mermaid.core-CXznBkX7.js → mermaid.core-BaIYEciF.js} +3 -3
- package/payload/server/public/assets/{mindmap-definition-QFDTVHPH-DZbHBud5.js → mindmap-definition-QFDTVHPH-D4u4KU2v.js} +1 -1
- package/payload/server/public/assets/{page-CfN7nw1J.js → page-DayPduMN.js} +2 -2
- package/payload/server/public/assets/page-QQmuB04w.js +1 -0
- package/payload/server/public/assets/{pieDiagram-DEJITSTG-QmOi4DRG.js → pieDiagram-DEJITSTG-BItWEilY.js} +1 -1
- package/payload/server/public/assets/public-Dze4yArS.js +7 -0
- package/payload/server/public/assets/{quadrantDiagram-34T5L4WZ-Cpidq6Xj.js → quadrantDiagram-34T5L4WZ-CeWDBvmH.js} +1 -1
- package/payload/server/public/assets/{requirementDiagram-MS252O5E-CBqtfbzR.js → requirementDiagram-MS252O5E-CcosjedW.js} +1 -1
- package/payload/server/public/assets/{sankeyDiagram-XADWPNL6-4BiY4dV9.js → sankeyDiagram-XADWPNL6-DNGeFpUj.js} +1 -1
- package/payload/server/public/assets/{sequenceDiagram-FGHM5R23-DVlL-l2u.js → sequenceDiagram-FGHM5R23-Cqy_deB6.js} +1 -1
- package/payload/server/public/assets/{stateDiagram-FHFEXIEX-CAm9dW68.js → stateDiagram-FHFEXIEX-2yoAqEsA.js} +1 -1
- package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-Dc5siYvu.js +1 -0
- package/payload/server/public/assets/{timeline-definition-GMOUNBTQ-CD-tZc4y.js → timeline-definition-GMOUNBTQ-Dmeghpw1.js} +1 -1
- package/payload/server/public/assets/{vennDiagram-DHZGUBPP-Davcm0TF.js → vennDiagram-DHZGUBPP-TX5D-Zzp.js} +1 -1
- package/payload/server/public/assets/{wardleyDiagram-NUSXRM2D-40LBYw_Y.js → wardleyDiagram-NUSXRM2D-B7mcpl5E.js} +1 -1
- package/payload/server/public/assets/{xychartDiagram-5P7HB3ND-DEPT-__v.js → xychartDiagram-5P7HB3ND-DH77CxKf.js} +1 -1
- package/payload/server/public/brand/Archive/favicon.ico +0 -0
- package/payload/server/public/brand/Archive/maxy-black.png +0 -0
- package/payload/server/public/brand/Archive/maxy-horizontal.png +0 -0
- package/payload/server/public/brand/Archive/maxy-monochrome.png +0 -0
- package/payload/server/public/brand/Archive/maxy-square.png +0 -0
- package/payload/server/public/brand/Archive/maxy.png +0 -0
- package/payload/server/public/brand/Archive/star.png +0 -0
- package/payload/server/public/brand/Archive.zip +0 -0
- package/payload/server/public/data.html +5 -5
- package/payload/server/public/graph.html +6 -6
- package/payload/server/public/index.html +8 -8
- package/payload/server/public/public.html +5 -5
- package/payload/server/server.js +312 -793
- package/payload/server/public/assets/ChatInput-CvRaT05l.js +0 -13
- package/payload/server/public/assets/Checkbox-BJKNkUYu.js +0 -1
- package/payload/server/public/assets/admin-BNy4N2d6.js +0 -217
- package/payload/server/public/assets/channel-DdtUtt5g.js +0 -1
- package/payload/server/public/assets/classDiagram-6PBFFD2Q-CKk2DFZe.js +0 -1
- package/payload/server/public/assets/classDiagram-v2-HSJHXN6E--YvfDQCh.js +0 -1
- package/payload/server/public/assets/clone-Cw6UfPGM.js +0 -1
- package/payload/server/public/assets/data-uBpwaldK.js +0 -1
- package/payload/server/public/assets/graph-labels-Cn9jAE6I.js +0 -1
- package/payload/server/public/assets/graph-tvTPvBaz.js +0 -1
- package/payload/server/public/assets/lib-p4ylk2XS.js +0 -29
- package/payload/server/public/assets/page-B3VYaBcf.js +0 -1
- package/payload/server/public/assets/public-Bbew78md.js +0 -7
- package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-B2EzXi50.js +0 -1
- /package/payload/server/public/assets/{ChatInput-DzacFNMk.css → brand-DzacFNMk.css} +0 -0
|
@@ -0,0 +1,401 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared Chrome DevTools Protocol primitives for the browser plugin.
|
|
3
|
+
*
|
|
4
|
+
* The brand's VNC Chromium is launched by platform/scripts/vnc.sh with
|
|
5
|
+
* `--remote-debugging-port=${CDP_PORT}`, so CDP listens on 127.0.0.1:<port>.
|
|
6
|
+
* Everything here attaches to that running browser — it never launches its own.
|
|
7
|
+
*
|
|
8
|
+
* Two consumers share these primitives:
|
|
9
|
+
* - cdp-render.ts → stateless one-shot render (create target, read DOM, close).
|
|
10
|
+
* - cdp-actions.ts → interactive automation driven through a persistent
|
|
11
|
+
* BrowserSession that keeps one target + websocket alive
|
|
12
|
+
* across tool calls.
|
|
13
|
+
*
|
|
14
|
+
* `fetch` and `WebSocket` are injected (CdpDeps) so unit tests drive every
|
|
15
|
+
* branch without a real browser; production passes the Node 22 globals.
|
|
16
|
+
*/
|
|
17
|
+
export const DEFAULT_LOAD_TIMEOUT_MS = 30_000;
|
|
18
|
+
export const DEFAULT_COMMAND_TIMEOUT_MS = 15_000;
|
|
19
|
+
/** Create a blank target via the CDP HTTP surface. Maps every transport
|
|
20
|
+
* failure to a structured outcome rather than throwing. */
|
|
21
|
+
export async function createTarget(deps, timeoutMs) {
|
|
22
|
+
const endpoint = `http://${deps.cdpHost}:${deps.cdpPort}/json/new`;
|
|
23
|
+
let res;
|
|
24
|
+
try {
|
|
25
|
+
res = await deps.fetchImpl(endpoint, { method: "PUT", signal: AbortSignal.timeout(timeoutMs) });
|
|
26
|
+
}
|
|
27
|
+
catch (err) {
|
|
28
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
29
|
+
if (msg.includes("ECONNREFUSED") || msg.includes("fetch failed") || msg.includes("ENOTFOUND")) {
|
|
30
|
+
return { outcome: "cdp-unreachable", detail: msg };
|
|
31
|
+
}
|
|
32
|
+
return { outcome: "error", detail: msg };
|
|
33
|
+
}
|
|
34
|
+
if (!res.ok) {
|
|
35
|
+
const body = await res.text().catch(() => "<unreadable>");
|
|
36
|
+
return { outcome: "error", detail: `CDP /json/new returned ${res.status}: ${body.slice(0, 200)}` };
|
|
37
|
+
}
|
|
38
|
+
let parsed;
|
|
39
|
+
try {
|
|
40
|
+
parsed = (await res.json());
|
|
41
|
+
}
|
|
42
|
+
catch (err) {
|
|
43
|
+
return { outcome: "error", detail: `CDP /json/new response not JSON: ${err instanceof Error ? err.message : String(err)}` };
|
|
44
|
+
}
|
|
45
|
+
if (!parsed.id || !parsed.webSocketDebuggerUrl) {
|
|
46
|
+
return { outcome: "error", detail: `CDP /json/new missing id/webSocketDebuggerUrl: ${JSON.stringify(parsed).slice(0, 200)}` };
|
|
47
|
+
}
|
|
48
|
+
return { target: { id: parsed.id, webSocketDebuggerUrl: parsed.webSocketDebuggerUrl } };
|
|
49
|
+
}
|
|
50
|
+
/** Best-effort target close. Failure is logged, never surfaced as an outcome. */
|
|
51
|
+
export async function closeTarget(deps, targetId) {
|
|
52
|
+
const endpoint = `http://${deps.cdpHost}:${deps.cdpPort}/json/close/${encodeURIComponent(targetId)}`;
|
|
53
|
+
try {
|
|
54
|
+
await deps.fetchImpl(endpoint, { method: "PUT", signal: AbortSignal.timeout(5_000) });
|
|
55
|
+
}
|
|
56
|
+
catch (err) {
|
|
57
|
+
deps.log(`[browser] target-close-failed id=${targetId} err=${JSON.stringify(err instanceof Error ? err.message : String(err))}`);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/** List the open page targets via the CDP HTTP surface. */
|
|
61
|
+
export async function listTargets(deps, timeoutMs) {
|
|
62
|
+
const endpoint = `http://${deps.cdpHost}:${deps.cdpPort}/json/list`;
|
|
63
|
+
let res;
|
|
64
|
+
try {
|
|
65
|
+
res = await deps.fetchImpl(endpoint, { method: "GET", signal: AbortSignal.timeout(timeoutMs) });
|
|
66
|
+
}
|
|
67
|
+
catch (err) {
|
|
68
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
69
|
+
if (msg.includes("ECONNREFUSED") || msg.includes("fetch failed") || msg.includes("ENOTFOUND")) {
|
|
70
|
+
return { outcome: "cdp-unreachable", detail: msg };
|
|
71
|
+
}
|
|
72
|
+
return { outcome: "error", detail: msg };
|
|
73
|
+
}
|
|
74
|
+
if (!res.ok) {
|
|
75
|
+
const body = await res.text().catch(() => "<unreadable>");
|
|
76
|
+
return { outcome: "error", detail: `CDP /json/list returned ${res.status}: ${body.slice(0, 200)}` };
|
|
77
|
+
}
|
|
78
|
+
let parsed;
|
|
79
|
+
try {
|
|
80
|
+
parsed = await res.json();
|
|
81
|
+
}
|
|
82
|
+
catch (err) {
|
|
83
|
+
return { outcome: "error", detail: `CDP /json/list response not JSON: ${err instanceof Error ? err.message : String(err)}` };
|
|
84
|
+
}
|
|
85
|
+
if (!Array.isArray(parsed)) {
|
|
86
|
+
return { outcome: "error", detail: `CDP /json/list not an array: ${JSON.stringify(parsed).slice(0, 200)}` };
|
|
87
|
+
}
|
|
88
|
+
const targets = parsed
|
|
89
|
+
.filter((t) => typeof t.id === "string" && typeof t.webSocketDebuggerUrl === "string")
|
|
90
|
+
.map((t) => ({
|
|
91
|
+
id: t.id,
|
|
92
|
+
webSocketDebuggerUrl: t.webSocketDebuggerUrl,
|
|
93
|
+
url: typeof t.url === "string" ? t.url : undefined,
|
|
94
|
+
title: typeof t.title === "string" ? t.title : undefined,
|
|
95
|
+
type: typeof t.type === "string" ? t.type : undefined,
|
|
96
|
+
}));
|
|
97
|
+
return { targets };
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Drives one CDP WebSocket session: correlates command ids to results, resolves
|
|
101
|
+
* one-shot events (waitForEvent), and fans persistent events out to subscribers
|
|
102
|
+
* (subscribe) — the latter is what console buffering and dialog handling need.
|
|
103
|
+
*
|
|
104
|
+
* ws message ──▶ has id? ──yes──▶ resolve/reject pending command
|
|
105
|
+
* │no
|
|
106
|
+
* ▼
|
|
107
|
+
* has method? ──▶ one-shot waiter (consume) + every subscriber
|
|
108
|
+
*/
|
|
109
|
+
export class CdpSession {
|
|
110
|
+
ws;
|
|
111
|
+
nextId = 1;
|
|
112
|
+
pending = new Map();
|
|
113
|
+
eventWaiters = new Map();
|
|
114
|
+
subscribers = new Map();
|
|
115
|
+
closed = false;
|
|
116
|
+
constructor(ws) {
|
|
117
|
+
this.ws = ws;
|
|
118
|
+
ws.addEventListener("message", (ev) => this.onMessage(ev.data));
|
|
119
|
+
ws.addEventListener("close", () => {
|
|
120
|
+
this.closed = true;
|
|
121
|
+
for (const { reject } of this.pending.values())
|
|
122
|
+
reject(new Error("websocket closed"));
|
|
123
|
+
this.pending.clear();
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
isClosed() {
|
|
127
|
+
return this.closed;
|
|
128
|
+
}
|
|
129
|
+
onMessage(data) {
|
|
130
|
+
if (typeof data !== "string")
|
|
131
|
+
return;
|
|
132
|
+
let msg;
|
|
133
|
+
try {
|
|
134
|
+
msg = JSON.parse(data);
|
|
135
|
+
}
|
|
136
|
+
catch {
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
if (typeof msg.id === "number") {
|
|
140
|
+
const waiter = this.pending.get(msg.id);
|
|
141
|
+
if (!waiter)
|
|
142
|
+
return;
|
|
143
|
+
this.pending.delete(msg.id);
|
|
144
|
+
if (msg.error)
|
|
145
|
+
waiter.reject(new Error(msg.error.message ?? "CDP command error"));
|
|
146
|
+
else
|
|
147
|
+
waiter.resolve(msg.result);
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
if (msg.method) {
|
|
151
|
+
const oneShot = this.eventWaiters.get(msg.method);
|
|
152
|
+
if (oneShot) {
|
|
153
|
+
this.eventWaiters.delete(msg.method);
|
|
154
|
+
oneShot(msg.params);
|
|
155
|
+
}
|
|
156
|
+
const subs = this.subscribers.get(msg.method);
|
|
157
|
+
if (subs)
|
|
158
|
+
for (const handler of subs)
|
|
159
|
+
handler(msg.params);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
command(method, params, timeoutMs) {
|
|
163
|
+
if (this.closed)
|
|
164
|
+
return Promise.reject(new Error("websocket closed"));
|
|
165
|
+
const id = this.nextId++;
|
|
166
|
+
return new Promise((resolve, reject) => {
|
|
167
|
+
const timer = setTimeout(() => {
|
|
168
|
+
this.pending.delete(id);
|
|
169
|
+
reject(new Error(`CDP ${method} timed out after ${timeoutMs}ms`));
|
|
170
|
+
}, timeoutMs);
|
|
171
|
+
this.pending.set(id, {
|
|
172
|
+
resolve: (v) => { clearTimeout(timer); resolve(v); },
|
|
173
|
+
reject: (e) => { clearTimeout(timer); reject(e); },
|
|
174
|
+
});
|
|
175
|
+
this.ws.send(JSON.stringify({ id, method, params }));
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
waitForEvent(method, timeoutMs) {
|
|
179
|
+
return new Promise((resolve, reject) => {
|
|
180
|
+
const timer = setTimeout(() => {
|
|
181
|
+
this.eventWaiters.delete(method);
|
|
182
|
+
reject(new Error(`event ${method} not received within ${timeoutMs}ms`));
|
|
183
|
+
}, timeoutMs);
|
|
184
|
+
this.eventWaiters.set(method, () => { clearTimeout(timer); resolve(); });
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
/** Persistent subscription to a CDP event. Returns an unsubscribe function. */
|
|
188
|
+
subscribe(method, handler) {
|
|
189
|
+
let set = this.subscribers.get(method);
|
|
190
|
+
if (!set) {
|
|
191
|
+
set = new Set();
|
|
192
|
+
this.subscribers.set(method, set);
|
|
193
|
+
}
|
|
194
|
+
set.add(handler);
|
|
195
|
+
return () => {
|
|
196
|
+
const s = this.subscribers.get(method);
|
|
197
|
+
if (s)
|
|
198
|
+
s.delete(handler);
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
export function openSocket(WebSocketImpl, url, timeoutMs) {
|
|
203
|
+
return new Promise((resolve) => {
|
|
204
|
+
let settled = false;
|
|
205
|
+
let ws;
|
|
206
|
+
try {
|
|
207
|
+
ws = new WebSocketImpl(url);
|
|
208
|
+
}
|
|
209
|
+
catch (err) {
|
|
210
|
+
resolve({ error: err instanceof Error ? err.message : String(err) });
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
const timer = setTimeout(() => {
|
|
214
|
+
if (settled)
|
|
215
|
+
return;
|
|
216
|
+
settled = true;
|
|
217
|
+
try {
|
|
218
|
+
ws.close();
|
|
219
|
+
}
|
|
220
|
+
catch { /* ignore */ }
|
|
221
|
+
resolve({ error: `websocket open timed out after ${timeoutMs}ms` });
|
|
222
|
+
}, timeoutMs);
|
|
223
|
+
ws.addEventListener("open", () => {
|
|
224
|
+
if (settled)
|
|
225
|
+
return;
|
|
226
|
+
settled = true;
|
|
227
|
+
clearTimeout(timer);
|
|
228
|
+
resolve({ ws });
|
|
229
|
+
});
|
|
230
|
+
ws.addEventListener("error", (ev) => {
|
|
231
|
+
if (settled)
|
|
232
|
+
return;
|
|
233
|
+
settled = true;
|
|
234
|
+
clearTimeout(timer);
|
|
235
|
+
const detail = ev && typeof ev === "object" && "message" in ev ? String(ev.message) : "websocket error";
|
|
236
|
+
resolve({ error: detail });
|
|
237
|
+
});
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
const CONSOLE_RING_CAP = 200;
|
|
241
|
+
/**
|
|
242
|
+
* A single live page driven across many tool calls.
|
|
243
|
+
*
|
|
244
|
+
* Lifecycle:
|
|
245
|
+
* attach() → create target, open ws, Page.enable + Runtime.enable, wire the
|
|
246
|
+
* console ring buffer and the dialog auto-responder.
|
|
247
|
+
* ensure() → return the live session, or null if the page died (ws closed:
|
|
248
|
+
* operator closed the tab, page crashed, browser restarted).
|
|
249
|
+
* close() → close the target and drop all state.
|
|
250
|
+
*
|
|
251
|
+
* The action layer treats a null ensure() as "session-lost" and tells the agent
|
|
252
|
+
* to navigate again — only navigate() re-attaches, so a dead page is never
|
|
253
|
+
* silently replaced by a blank one mid-action.
|
|
254
|
+
*/
|
|
255
|
+
export class BrowserSession {
|
|
256
|
+
deps;
|
|
257
|
+
target = null;
|
|
258
|
+
ws = null;
|
|
259
|
+
session = null;
|
|
260
|
+
consoleRing = [];
|
|
261
|
+
dialogPolicy = null;
|
|
262
|
+
lastDialogUnhandled = false;
|
|
263
|
+
constructor(deps) {
|
|
264
|
+
this.deps = deps;
|
|
265
|
+
}
|
|
266
|
+
/** The live session if the page is still alive, else null. */
|
|
267
|
+
ensure() {
|
|
268
|
+
if (this.session && !this.session.isClosed())
|
|
269
|
+
return this.session;
|
|
270
|
+
// Page died — drop references so the next attach starts clean.
|
|
271
|
+
this.session = null;
|
|
272
|
+
this.ws = null;
|
|
273
|
+
this.target = null;
|
|
274
|
+
return this.session;
|
|
275
|
+
}
|
|
276
|
+
/** Drop our handle on the current page (close the websocket) without closing
|
|
277
|
+
* the target itself — used when switching the active page to another tab so
|
|
278
|
+
* the previous tab stays open. */
|
|
279
|
+
detachWs() {
|
|
280
|
+
const ws = this.ws;
|
|
281
|
+
this.ws = null;
|
|
282
|
+
this.session = null;
|
|
283
|
+
this.target = null;
|
|
284
|
+
if (ws) {
|
|
285
|
+
try {
|
|
286
|
+
ws.close();
|
|
287
|
+
}
|
|
288
|
+
catch { /* ignore */ }
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
currentTargetId() {
|
|
292
|
+
return this.target?.id ?? null;
|
|
293
|
+
}
|
|
294
|
+
setDialogPolicy(policy) {
|
|
295
|
+
this.dialogPolicy = policy;
|
|
296
|
+
}
|
|
297
|
+
/** Drain the console ring buffer (returns and clears). */
|
|
298
|
+
drainConsole() {
|
|
299
|
+
const out = this.consoleRing.slice();
|
|
300
|
+
this.consoleRing.length = 0;
|
|
301
|
+
return out;
|
|
302
|
+
}
|
|
303
|
+
/** True (and resets) if a dialog fired with no policy armed. */
|
|
304
|
+
takeUnhandledDialogFlag() {
|
|
305
|
+
const v = this.lastDialogUnhandled;
|
|
306
|
+
this.lastDialogUnhandled = false;
|
|
307
|
+
return v;
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* Attach a fresh target and wire console + dialog handling.
|
|
311
|
+
* Pass an existing target (from the tabs tool) to adopt it instead of creating one.
|
|
312
|
+
*/
|
|
313
|
+
async attach(commandTimeoutMs, existing) {
|
|
314
|
+
if (!this.deps.WebSocketImpl) {
|
|
315
|
+
return { outcome: "websocket-unavailable", detail: "global WebSocket is not available on this runtime (Node < 22.4)" };
|
|
316
|
+
}
|
|
317
|
+
if (!this.deps.cdpPort || Number.isNaN(this.deps.cdpPort)) {
|
|
318
|
+
return { outcome: "cdp-unreachable", detail: `CDP_PORT not set or invalid (got ${JSON.stringify(this.deps.cdpPort)})` };
|
|
319
|
+
}
|
|
320
|
+
// Release our handle on any current page, but leave its tab open — opening
|
|
321
|
+
// or switching to another tab must not destroy the one we were on.
|
|
322
|
+
this.detachWs();
|
|
323
|
+
let target = existing;
|
|
324
|
+
if (!target) {
|
|
325
|
+
const created = await createTarget(this.deps, commandTimeoutMs);
|
|
326
|
+
if ("outcome" in created)
|
|
327
|
+
return { outcome: created.outcome, detail: created.detail };
|
|
328
|
+
target = created.target;
|
|
329
|
+
}
|
|
330
|
+
const opened = await openSocket(this.deps.WebSocketImpl, target.webSocketDebuggerUrl, commandTimeoutMs);
|
|
331
|
+
if ("error" in opened) {
|
|
332
|
+
if (!existing)
|
|
333
|
+
await closeTarget(this.deps, target.id);
|
|
334
|
+
return { outcome: "cdp-unreachable", detail: `websocket connect failed: ${opened.error}` };
|
|
335
|
+
}
|
|
336
|
+
const session = new CdpSession(opened.ws);
|
|
337
|
+
try {
|
|
338
|
+
await session.command("Page.enable", {}, commandTimeoutMs);
|
|
339
|
+
await session.command("Runtime.enable", {}, commandTimeoutMs);
|
|
340
|
+
}
|
|
341
|
+
catch (err) {
|
|
342
|
+
try {
|
|
343
|
+
opened.ws.close();
|
|
344
|
+
}
|
|
345
|
+
catch { /* ignore */ }
|
|
346
|
+
if (!existing)
|
|
347
|
+
await closeTarget(this.deps, target.id);
|
|
348
|
+
return { outcome: "error", detail: `enable failed: ${err instanceof Error ? err.message : String(err)}` };
|
|
349
|
+
}
|
|
350
|
+
// Console + uncaught-error buffering, from attach onward.
|
|
351
|
+
session.subscribe("Runtime.consoleAPICalled", (params) => this.recordConsole(params));
|
|
352
|
+
session.subscribe("Runtime.exceptionThrown", (params) => this.recordException(params));
|
|
353
|
+
// Dialog auto-responder: apply the armed policy, or dismiss + flag.
|
|
354
|
+
session.subscribe("Page.javascriptDialogOpening", () => {
|
|
355
|
+
const policy = this.dialogPolicy ?? { accept: false };
|
|
356
|
+
if (!this.dialogPolicy)
|
|
357
|
+
this.lastDialogUnhandled = true;
|
|
358
|
+
session.command("Page.handleJavaScriptDialog", policy.promptText !== undefined
|
|
359
|
+
? { accept: policy.accept, promptText: policy.promptText }
|
|
360
|
+
: { accept: policy.accept }, commandTimeoutMs).catch((err) => this.deps.log(`[browser] dialog-handle-failed err=${JSON.stringify(err instanceof Error ? err.message : String(err))}`));
|
|
361
|
+
});
|
|
362
|
+
this.target = target;
|
|
363
|
+
this.ws = opened.ws;
|
|
364
|
+
this.session = session;
|
|
365
|
+
return { session };
|
|
366
|
+
}
|
|
367
|
+
async close(commandTimeoutMs) {
|
|
368
|
+
const ws = this.ws;
|
|
369
|
+
const target = this.target;
|
|
370
|
+
this.ws = null;
|
|
371
|
+
this.session = null;
|
|
372
|
+
this.target = null;
|
|
373
|
+
if (ws) {
|
|
374
|
+
try {
|
|
375
|
+
ws.close();
|
|
376
|
+
}
|
|
377
|
+
catch { /* ignore */ }
|
|
378
|
+
}
|
|
379
|
+
if (target)
|
|
380
|
+
await closeTarget(this.deps, target.id);
|
|
381
|
+
void commandTimeoutMs;
|
|
382
|
+
}
|
|
383
|
+
recordConsole(params) {
|
|
384
|
+
const p = params;
|
|
385
|
+
const text = (p.args ?? [])
|
|
386
|
+
.map((a) => (a.value !== undefined ? String(a.value) : a.description ?? ""))
|
|
387
|
+
.join(" ");
|
|
388
|
+
this.push(`[${p.type ?? "log"}] ${text}`);
|
|
389
|
+
}
|
|
390
|
+
recordException(params) {
|
|
391
|
+
const p = params;
|
|
392
|
+
const text = p.exceptionDetails?.exception?.description ?? p.exceptionDetails?.text ?? "uncaught exception";
|
|
393
|
+
this.push(`[error] ${text}`);
|
|
394
|
+
}
|
|
395
|
+
push(line) {
|
|
396
|
+
this.consoleRing.push(line);
|
|
397
|
+
if (this.consoleRing.length > CONSOLE_RING_CAP)
|
|
398
|
+
this.consoleRing.shift();
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
//# sourceMappingURL=cdp-session.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cdp-session.js","sourceRoot":"","sources":["../../src/lib/cdp-session.ts"],"names":[],"mappings":"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"}
|
|
@@ -44,10 +44,9 @@ either is a regression.
|
|
|
44
44
|
|---|---|---|
|
|
45
45
|
| `/session` | Admin cookie session: PIN-gated mint, validate, rotate. | `GET /`, `POST /` |
|
|
46
46
|
| `/sessions` | Legacy conversation list and lifecycle (kept for the ConversationsModal styling class and the post-action reconcile). | `GET /`, `POST /new`, `POST /switch`, `DELETE /:id`, `POST /:id/resume` |
|
|
47
|
-
| `/claude-sessions` |
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
| `/new-session-submit` | Modal submit handler. | `POST /` |
|
|
47
|
+
| `/claude-sessions` | **Spawn surface only** (Task 500). The single `POST /` is shared by three callers: the public/visitor bridge, `linkedin-ingest`, and the turn-completed-graph-write Stop-hook recorder. The former UI-facing handlers (SSE row feed, list, resume, stop, rename, archive, delete, `/:id/meta`, `/:id/input`, `/:id/log`) were removed — the maxy dashboard no longer manages or displays sessions. | `POST /` |
|
|
48
|
+
|
|
49
|
+
Task 500 — **admin session management moved entirely to claude's own interfaces** (claude.ai/code, claude desktop). A manager-owned per-account `claude rc --spawn same-dir` daemon registers the device as a Remote Control target there; the composer creates / resumes / stops / renames / archives / deletes sessions, with model + permission-mode applied at inception. The model lever is `account.json.adminModel` → `CLAUDE_CONFIG_DIR/settings.json "model"`, written by the daemon supervisor at boot. The maxy admin UI keeps a single "New session" link (`https://claude.ai/code`, opens in a new tab) and no session list, viewer, controls, or model/mode picker. The daemon supervisor lives at [`platform/services/claude-session-manager/src/rc-daemon.ts`](../../../services/claude-session-manager/src/rc-daemon.ts). The `/session-defaults` route and `SpawnPreference` node were deleted with the picker. `/new-session-failure`, `/new-session-submit`, and `/claude-capabilities` are now orphaned (consumed only by the deleted NewSessionModal) — see [`.tasks/501`](../../../.tasks/) for their removal.
|
|
51
50
|
|
|
52
51
|
### Graph
|
|
53
52
|
|
|
@@ -191,7 +191,7 @@ If an action looks stuck, read `~/.maxy/logs/actions/<actionId>.log` directly fo
|
|
|
191
191
|
|
|
192
192
|
On Ubuntu 24.04 (Noble) the system Chromium binary at `/usr/bin/chromium` is a symlink into the snap. Snap's AppArmor profile denies writes to hidden directories under your home folder, so the per-brand Chromium profile at `~/.{brand}/chromium-profile/` is unwritable and the VNC browser never starts. Pi installs (Debian Bookworm) are unaffected because Bookworm ships a real `.deb` chromium.
|
|
193
193
|
|
|
194
|
-
The installer detects this case during system-dependency setup and replaces the snap binary with Google Chrome stable, installed from Google's signed apt repo. The chosen binary's absolute path is recorded in `<INSTALL_DIR>/platform/config/chromium-binary.path` and
|
|
194
|
+
The installer detects this case during system-dependency setup and replaces the snap binary with Google Chrome stable, installed from Google's signed apt repo. The chosen binary's absolute path is recorded in `<INSTALL_DIR>/platform/config/chromium-binary.path` and read by the two call sites that launch Chromium — the VNC service and the in-page Chromium wrapper. (The `browser` plugin never launches its own Chromium; it attaches over CDP to the VNC Chromium that `vnc.sh` starts with `--remote-debugging-port`, so it doesn't consult this path.) If you ever see `chromium-binary.path missing` or `Chromium ... resolves to ... which is snap-confined` in `~/.{brand}/logs/vnc-boot.log`, re-run the installer to re-provision.
|
|
195
195
|
|
|
196
196
|
The post-install acceptance gate at `platform/scripts/test-laptop-vnc-boot.sh` runs four checks: the configured Chromium realpath is non-snap, the path is absolute and executable, the per-brand CDP port returns Chromium version JSON, and the VNC boot log ends with `VNC + browser stack running` with no preceding `Chromium failed to start`. The gate runs automatically at the end of every install on Linux; manual invocation is `MAXY_PLATFORM_ROOT=<install-dir>/platform <install-dir>/platform/scripts/test-laptop-vnc-boot.sh`.
|
|
197
197
|
|
|
@@ -324,7 +324,7 @@ Each row in the Conversations modal exposes a `View logs` row-action that opens
|
|
|
324
324
|
|
|
325
325
|
**Directory canonicalisation.** A request whose disk target is a directory is `301`'d to the trailing-slash form (query string preserved) before any body is served — RFC 3986 §5.3 base resolution requires the trailing slash so relative refs in the served HTML resolve under the directory, not its parent. After the redirect the route serves `<dir>/index.html` if it exists on disk; otherwise `404`. There is **no** implicit-`index.html` invention for missing paths — the publisher owns canonical URLs. A brochure shipped without `index.html` is reached at `/sites/<slug>/<file>.html`, and the admin skill `publish-site` is the sanctioned surface that moves the extracted tree under `<accountDir>/sites/<slug>/` and emits the canonical path slug. Operator-side: drop a brochure at `<accountDir>/sites/properties/<id>/brochure/output/` and it serves at `<public-host>/sites/properties/<id>/brochure/output/brochure.html` (or `<public-host>/sites/properties/<id>/brochure/output/` if that directory contains an `index.html`). See `.docs/web-chat.md` `/sites/*` route entry for the wire contract and `[sites]` log lines (`serve|redirect-trailing-slash|not-found|path-traversal-rejected|symlink-escape-rejected|no-account`).
|
|
326
326
|
|
|
327
|
-
**Deterministic public-hostname surface.** The `<public-host>` half of the URL the operator pastes is resolved by the `
|
|
327
|
+
**Deterministic public-hostname surface.** The `<public-host>` half of the URL the operator pastes is resolved by the `mcp__plugin_admin_admin__public-hostname` MCP tool. It reads `<configDir>/cloudflared/config.yml` (ingress list) then falls back to `<configDir>/alias-domains.json` — the same two files `cloudflared` and `platform/ui/server/index.ts`'s `isPublicHost()` already trust to route. Returns `{hostname, isApex, source}` on hit (`source` is `"cloudflared-config.yml"` or `"alias-domains.json"`), or `{hostname:null, source:null, reason:"no-tunnel"}` on miss. Tiebreak: apex wins over subdomain (single-label, or `www.<apex>` stripped). `publish-site` step 6 calls it after the move and emits the full URL (`https://<hostname><path-slug>`) in the same turn. Graph queries are no longer involved — any earlier graph-backed resolver returned `(none)` on accounts bootstrapped without `cloudflare-task-tracker.ts` writes (laptop Real Agent, manual `cloudflared` setup), the `llm-framing-deterministic` recurrence class. The graph-mcp shim additionally runs a sequential envelope-warning probe on every read response — when Neo4j emits `gql_status` codes matching `^0[12]N5\d$` (e.g. `01N52` "property does not exist"), the shim stitches them into a prefix content block on the response so property-name misses surface to the agent inline instead of returning silent `[]`. Probe failure is best-effort: the upstream response forwards unchanged with `[mcp:graph] probe-error`.
|
|
328
328
|
|
|
329
329
|
### Cross-tab session rotation
|
|
330
330
|
|
|
@@ -439,19 +439,21 @@ The SDK's per-tool override is `_meta["anthropic/alwaysLoad"]: true` on each MCP
|
|
|
439
439
|
1. **In-process plugins.** Every admin-eager tool is registered via `eagerTool(server, name, description, inputSchema, handler)` from `platform/lib/mcp-eager/` instead of `server.tool(...)`. The helper calls `server.registerTool` with the `_meta` flag set.
|
|
440
440
|
2. **Upstream graph proxy.** The upstream Python `mcp-neo4j-cypher` server has no `_meta` channel, so `platform/lib/graph-mcp/src/index.ts` intercepts every `tools/list` response on the wire and injects `_meta["anthropic/alwaysLoad"]: true` into each tool entry. The `[graph-mcp] tools/list eager-flagged count=<N>` stderr line confirms the injection fired.
|
|
441
441
|
|
|
442
|
-
**Curation rule.** Every MCP tool the admin agent calls routinely should be eager
|
|
442
|
+
**Curation rule.** Every MCP tool the admin agent calls routinely should be eager — registered via `eagerTool` (or arriving through the graph-mcp interceptor). Whether a tool is eager is decided at its registration site in the plugin's MCP `index.ts` (`eagerTool` vs `server.tool`); there is no separate allow-list constant. Admin-skill / specialist / public-agent tools that stay on `server.tool()` pay the ToolSearch tax only when their caller invokes them. The admin tool surface (`toolSurface.admin`, the `adminAllowlist: true` set) is the intended eager set; a routinely-called admin tool left on `server.tool()` is a gap to fix at the registration site.
|
|
443
443
|
|
|
444
444
|
**Observability.** Spawn-time emit: `[tool-surface] session=<convId> permission_allowed=N eager_intent=E eager_set_size=T`. Turn-end emit: `[admin-agent] turn-end ... toolsearch=N toolsearch_unique=U`. A non-zero `toolsearch` on a fresh turn for an eager-intended tool means a plugin reverted to `server.tool()` — fix at the plugin's MCP registration site, not the allow-list.
|
|
445
445
|
|
|
446
446
|
## Spawn-time MCP and subagent registration
|
|
447
447
|
|
|
448
|
-
Each `claude` PTY spawn
|
|
448
|
+
Each `claude` PTY spawn registers every callable MCP server and every dispatchable subagent before the operator's first turn. **Platform MCP servers come from one channel — installed plugins — for admin and specialist spawns (Task 502).** Claude Code's plugin system serves every plugin MCP tool under the long prefix `mcp__plugin_<plugin>_<server>__<tool>` (for platform plugins `plugin == server == directory`), which is the canonical name the admin `--allowed-tools` argv and every specialist `tools:` frontmatter bind to. Admin spawns no longer write a per-spawn `.mcp.json` or pass `--mcp-config`; the per-account env (`ACCOUNT_ID`, `USER_ID`, `NEO4J_URI`, `NEO4J_PASSWORD`, `PLATFORM_ROOT`, `CLAUDE_CONFIG_DIR`) rides the PTY env block.
|
|
449
|
+
|
|
450
|
+
**Public agents are the one exception.** A public-facing web agent should boot only the handful of servers it may use, not every installed plugin, so public spawns retain the per-spawn `mcp-config.json` (`--mcp-config <path>`) that restricts the server set to plugins exposing at least one `publicAllowlist: true` tool (minus memory when `liveMemory: false`). Per-spawn descriptors keep the SHORT prefix `mcp__<plugin>__<tool>`, which is why the public allowlist (`toolSurface.public`) stays short while admin/all are long. The descriptor's `command` routes through `lib/mcp-spawn-tee/dist/index.js` so each child server's stderr lands in `${LOG_DIR}/mcp-<name>-stderr-<date>.log` even on synchronous module-load throws (Task 743 wrapper). `--strict-mcp-config` only ever guarded auto-discovery of a project `.mcp.json`; it is retained on the public per-spawn path and dropped from admin spawns that no longer pass `--mcp-config`.
|
|
449
451
|
|
|
450
452
|
For subagents, the same spawn pushes `--add-dir` for every bundled plugin agents directory (`platform/plugins/*/agents/`, `premium-plugins/*/agents/`) — both roles — plus the per-account specialists directory `<accountDir>/specialists/agents/` (admin only). Claude Code's `subagent_type` dispatch reads the agent file off disk via the added directories; without `--add-dir` the dispatcher returns "no matching agent."
|
|
451
453
|
|
|
452
454
|
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
455
|
|
|
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, …),
|
|
456
|
+
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 (canonical long-prefix names since Task 502), and classifies every tool name as one of: CC-native (Read, Bash, …), a tool the loaded `PLUGIN.md` set actually serves (matched as the long canonical name in `toolSurface.all`), a third-party MCP bridge (a `mcp__plugin_*` name whose plugin segment is NOT a maxy platform plugin — Playwright etc., upstream-owned, passes unconditionally), `unknown-tool-in-plugin` (maxy 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__`-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)`. A maxy-plugin `mcp__plugin_*` name is validated against `toolSurface.all`, so a typo or stale long-prefix tool name still refuses boot rather than passing as a bridge; the build-time `check-canonical-tool-names.mjs` gate catches the same drift in instruction files before publish. `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
457
|
|
|
456
458
|
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
459
|
|
|
@@ -46,7 +46,7 @@ These are enabled during onboarding and can be added or removed at any time. Som
|
|
|
46
46
|
| `x-import` | Import an X (Twitter) Basic Data Export — tweet stream renders as one chronological transcript and ingests as a single `:KnowledgeDocument` (`source='x'`); each DM `sessionId` ingests as one `:ConversationArchive` (`source='x-dm'`, keyed on `conversationIdentity`) via `conversation-archive-ingest.sh`. Mentions, replies, and quote-tweet authors resolve to `:Person` on lowercased `xHandle`; every handle and DM senderId confirms against existing nodes (no auto-create). Per-thread KD granularity and `:Post` / `:DirectMessage` labels are explicitly rejected. | Database operator |
|
|
47
47
|
| `substack-import` | Import a Substack "Export your data" archive — per-essay `:KnowledgeDocument {kind:'substack-post'}` via librarian/document-ingest with synthetic stable `attachmentId = "substack-post-${substackPostId}"` (survives Substack edits); one `:KnowledgeDocument {kind:'substack-subscriber-roster'}` per import run with `:MENTIONS {mentionContext:'substack-subscription', tier, totalOpens, totalClicks, lastOpenedAt, lastClickedAt, engagementWindowDays}` to each subscriber `:Person` MERGEd on `(accountId, email)`. Engagement aggregates parsed from `email_activity.csv` (or `subscriber_activity.csv` / `emails.csv`); overwrite-on-reimport. No new label, no new edge type, no new graph writer. Images attach via canonical `:HAS_ENCLOSURE` (or `:MENTIONS` fallback). Bulk-gate at >200 posts or >2000 subscribers. | Database operator |
|
|
48
48
|
| `memory/skills/conversation-archive` | Source-agnostic conversation transcript ingest. One skill for WhatsApp `_chat.txt`, Telegram, Signal, LinkedIn DMs, Zoom transcript, meeting minutes, iMessage, Slack, X DMs — `--source <enum>` selects the per-source normaliser. Single Bash entry — `bash platform/plugins/memory/bin/conversation-archive-ingest.sh <archive> --source <enum> --participant-person-ids <csv> --scope <admin\|public>` — runs normalise → operator-confirms owner + every distinct sender (owner derived from env via Cypher, no flag) → sessionize at the fixed 8h gap → emit one JSON line carrying prepared sessions (turn-attributed text + per-session cursor). The dispatched specialist iterates the sessions in-turn, produces a typed-section JSON chunking for each, and calls the `memory-ingest` MCP tool with `conversationIdentity` set (writes `:ConversationArchive`, source=<enum>) once per session — chunks + cursor advance commit atomically inside one Cypher transaction, so a kill mid-archive resumes from the next session on re-issue without re-classifying anything already written. Re-imports are delta-append. Auto-creating participants is forbidden — any sender outside the operator-confirmed closed set LOUD-FAILs with `parser-miss`. Distinct from the live `whatsapp` plugin (Baileys). | Database operator |
|
|
49
|
-
| `memory/skills/conversation-archive-enrich` | Phase 2 for any named `:ConversationArchive` — source-agnostic per-row insight derivation. Operator-triggered (never auto-fires on Phase 1 completion). Walks the parent's `:Section` chunks in pages via the read-only MCP tool `
|
|
49
|
+
| `memory/skills/conversation-archive-enrich` | Phase 2 for any named `:ConversationArchive` — source-agnostic per-row insight derivation. Operator-triggered (never auto-fires on Phase 1 completion). Walks the parent's `:Section` chunks in pages via the read-only MCP tool `mcp__plugin_memory_memory__conversation-archive-list-chunks`; the dispatched specialist reads each chunk in-turn and emits claims under the four-kind contract (`mention`, `task`, `preference`, `observed-relationship`); the skill hands those claims to `mcp__plugin_memory_memory__conversation-archive-derive-insights` for per-kind cypher emission, then runs the per-row operator gate (`wire / skip / reject`). Idempotent on `(elementId(chunk), kind, contentHash)` — re-runs collapse identical claims. Confidence floor is a hedging-avoidance instruction the skill embeds in the specialist's per-chunk prompt, not a numeric post-filter; per Task 433 the LLM step runs in-turn from the dispatched specialist rather than as a server-side OAuth round-trip. | Database operator |
|
|
50
50
|
|
|
51
51
|
### Claude Official (marketplace)
|
|
52
52
|
|
|
@@ -125,7 +125,7 @@ Ask {{productName}}: "What plugins do I have?" or "List my plugins."
|
|
|
125
125
|
|
|
126
126
|
## Operator-Authored Plugins (skill-builder output)
|
|
127
127
|
|
|
128
|
-
Skills you create at runtime through the admin `skill-builder` skill are saved on disk as their own plugin under `data/accounts/{accountId}/plugins/{pluginName}/`. The admin agent calls `
|
|
128
|
+
Skills you create at runtime through the admin `skill-builder` skill are saved on disk as their own plugin under `data/accounts/{accountId}/plugins/{pluginName}/`. The admin agent calls `mcp__plugin_admin_admin__store-skill`, which composes `PLUGIN.md` (on first call) and `skills/{skillName}/SKILL.md` plus any reference files. The agent supplies `pluginName`, `skillName`, `description`, `publicEmbed`, `body`, and optional references — the path is computed by the tool, never by the agent.
|
|
129
129
|
|
|
130
130
|
These operator-authored plugins survive reinstall because the installer's wipe zone excludes `data/`. At admin session start the platform mirrors `data/accounts/{accountId}/plugins/*` into the runtime plugins directory so the same `parsePluginFrontmatter` / `assemblePublicPluginContent` / `loadEmbeddedPlugins` loaders that read shipped and premium plugins also pick up operator-authored ones — no special-case loader path. The admin agent sees every operator skill by default; per-skill `publicEmbed: true|false` controls which skills surface to the public agent.
|
|
131
131
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "email",
|
|
3
|
-
"description": "Email — dedicated email account. Retrieval: email-graph-query for stored email-thread history as :ConversationArchive {source:'email'} with :Section chunks (recall, search, 'threads about X', 'what did Y send?'); email-read / email-search for live IMAP inbox (with best-effort per-archive section hints from the graph). Ingestion (operator-initiated, human-in-the-loop): email-fetch lists new messages, email-ingest writes the operator-approved subset via the conversation-archive pipeline. Sending: email-send (new), email-reply (threaded — resolves the original via IMAP Message-ID search). Config: email-setup, email-status, email-otp-extract.",
|
|
3
|
+
"description": "Email — dedicated email account. Retrieval: email-graph-query for stored email-thread history as :ConversationArchive {source:'email'} with :Section chunks (recall, search, 'threads about X', 'what did Y send?'); email-read / email-search for live IMAP inbox (with best-effort per-archive section hints from the graph). Ingestion (operator-initiated, human-in-the-loop): email-fetch lists new messages, email-ingest writes the operator-approved subset via the conversation-archive pipeline. Sending: email-send (new), email-reply (threaded — resolves the original via IMAP Message-ID search). Config: email-provider-info (pre-password host + app-password lookup from an address alone), email-setup, email-status, email-otp-extract.",
|
|
4
4
|
"version": "0.1.0",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Rubytech LLC"
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: email
|
|
3
|
-
description: "Email — dedicated email account. Retrieval: email-graph-query for stored email-thread history as :ConversationArchive {source:'email'} with :Section chunks (recall, search, 'threads about X', 'what did Y send?'); email-read / email-search for live IMAP inbox (with best-effort per-archive section hints from the graph). Ingestion (operator-initiated, human-in-the-loop): email-fetch lists new messages, email-ingest writes the operator-approved subset via the conversation-archive pipeline. Sending: email-send (new), email-reply (threaded — resolves the original via IMAP Message-ID search). Config: email-setup, email-status, email-otp-extract."
|
|
3
|
+
description: "Email — dedicated email account. Retrieval: email-graph-query for stored email-thread history as :ConversationArchive {source:'email'} with :Section chunks (recall, search, 'threads about X', 'what did Y send?'); email-read / email-search for live IMAP inbox (with best-effort per-archive section hints from the graph). Ingestion (operator-initiated, human-in-the-loop): email-fetch lists new messages, email-ingest writes the operator-approved subset via the conversation-archive pipeline. Sending: email-send (new), email-reply (threaded — resolves the original via IMAP Message-ID search). Config: email-provider-info (pre-password host + app-password lookup from an address alone), email-setup, email-status, email-otp-extract."
|
|
4
4
|
tools:
|
|
5
|
+
- name: email-provider-info
|
|
6
|
+
publicAllowlist: false
|
|
7
|
+
adminAllowlist: false
|
|
5
8
|
- name: email-setup
|
|
6
9
|
publicAllowlist: false
|
|
7
10
|
adminAllowlist: false
|
|
@@ -57,7 +60,8 @@ Manages the agent's own dedicated email account — IMAP for reading, SMTP for s
|
|
|
57
60
|
|
|
58
61
|
## Capabilities
|
|
59
62
|
|
|
60
|
-
- **
|
|
63
|
+
- **Provider lookup:** `email-provider-info` — given just an email address, returns the inferred IMAP/SMTP hosts and the provider's app-password / trusted-application / IMAP-enable requirement, deterministically from the provider map. Call this BEFORE soliciting a password so the requirement is relayed first; most providers reject the normal login password. Returns "unknown" (operator supplies hosts) or "unsupported" (provider blocks IMAP/SMTP, e.g. Tuta).
|
|
64
|
+
- **Setup:** `email-setup` — collect credentials in plain chat and connect IMAP/SMTP. Hosts are auto-inferred for known providers; supports alias addresses (`agentAddress`).
|
|
61
65
|
- **Read inbox:** `email-read` — metadata only (UID, sender, subject, date), plus a best-effort `Archive`/`Archive-Section` hint when the IMAP message's `receivedAt` falls inside a stored `:ConversationArchive {source:'email'}` section, plus an `Attachments (N): filename (mime, size); …` footer when the message carries enclosures. Supports pagination (`before_uid`), folders (`inbox`/`sent`), filtering by sender/date/subject. Metadata is derived from IMAP `bodyStructure` — no bytes downloaded.
|
|
62
66
|
- **Search inbox:** `email-search` — live IMAP search by sender, subject, body keyword, date range. Same per-archive hint and attachment footer as `email-read`.
|
|
63
67
|
- **Send:** `email-send` — new outbound email.
|