@rubytech/create-maxy-code 0.1.307 → 0.1.309
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__/claude-ptys-slice.test.js +1 -1
- package/dist/__tests__/cloudflared-slice.test.js +1 -1
- package/dist/__tests__/macos-darwin-branch.test.js +4 -6
- package/package.json +1 -1
- package/payload/platform/lib/admin-access-password/__tests__/index.test.ts +142 -0
- package/payload/platform/lib/admin-access-password/dist/index.d.ts +49 -0
- package/payload/platform/lib/admin-access-password/dist/index.d.ts.map +1 -0
- package/payload/platform/lib/admin-access-password/dist/index.js +198 -0
- package/payload/platform/lib/admin-access-password/dist/index.js.map +1 -0
- package/payload/platform/lib/admin-access-password/src/index.ts +176 -0
- package/payload/platform/lib/admin-access-password/tsconfig.json +8 -0
- package/payload/platform/lib/models/dist/index.d.ts +13 -0
- package/payload/platform/lib/models/dist/index.d.ts.map +1 -1
- package/payload/platform/lib/models/dist/index.js +20 -1
- package/payload/platform/lib/models/dist/index.js.map +1 -1
- package/payload/platform/lib/models/src/index.ts +19 -0
- package/payload/platform/package.json +2 -2
- package/payload/platform/plugins/admin/PLUGIN.md +1 -0
- package/payload/platform/plugins/admin/mcp/dist/index.js +63 -19
- package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/admin/skills/admin-user-management/SKILL.md +8 -2
- package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +23 -3
- package/payload/platform/plugins/docs/references/admin-ui.md +21 -1
- package/payload/platform/plugins/docs/references/internals.md +1 -1
- package/payload/platform/scripts/check-no-esm-require.mjs +4 -0
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js +1 -0
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/http-server.d.ts +4 -0
- package/payload/platform/services/claude-session-manager/dist/http-server.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/http-server.js +193 -1
- package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts +12 -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 +52 -1
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/session-sidecar.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/session-sidecar.js +9 -3
- package/payload/platform/services/claude-session-manager/dist/session-sidecar.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/webchat-channel-mcp.d.ts +8 -0
- package/payload/platform/services/claude-session-manager/dist/webchat-channel-mcp.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/webchat-channel-mcp.js +7 -0
- package/payload/platform/services/claude-session-manager/dist/webchat-channel-mcp.js.map +1 -1
- package/payload/platform/services/webchat-channel/dist/instructions.d.ts +8 -0
- package/payload/platform/services/webchat-channel/dist/instructions.d.ts.map +1 -0
- package/payload/platform/services/webchat-channel/dist/instructions.js +44 -0
- package/payload/platform/services/webchat-channel/dist/instructions.js.map +1 -0
- package/payload/platform/services/webchat-channel/dist/server.d.ts.map +1 -1
- package/payload/platform/services/webchat-channel/dist/server.js +11 -18
- package/payload/platform/services/webchat-channel/dist/server.js.map +1 -1
- package/payload/server/{chunk-4QFPGAUZ.js → chunk-J6WDAWFJ.js} +190 -82
- package/payload/server/maxy-edge.js +1 -1
- package/payload/server/public/assets/AccessGate-CU4Qw6M6.js +1 -0
- package/payload/server/public/assets/AdminLoginScreens-DUpRIM1h.js +1 -0
- package/payload/server/public/assets/AdminShell-DkoQSsqo.js +1 -0
- package/payload/server/public/assets/{Checkbox-DoPOlZTV.js → Checkbox-DMA1hVhn.js} +1 -1
- package/payload/server/public/assets/OperatorConversations-BIHiyyxU.js +1 -0
- package/payload/server/public/assets/admin-BHvOMcCh.js +1 -0
- package/payload/server/public/assets/{arc-DxSm8tli.js → arc-Dl9QFDgW.js} +1 -1
- package/payload/server/public/assets/architecture-YZFGNWBL-Crq5RSDG.js +1 -0
- package/payload/server/public/assets/{architectureDiagram-Q4EWVU46-7JSAh0vL.js → architectureDiagram-Q4EWVU46-CNLQUVi9.js} +1 -1
- package/payload/server/public/assets/{audio-attachment-mime-BA10IzqQ.js → audio-attachment-mime-DOBET-W1.js} +3 -3
- package/payload/server/public/assets/{blockDiagram-DXYQGD6D-DLoVmHKD.js → blockDiagram-DXYQGD6D-B-QxfVjk.js} +1 -1
- package/payload/server/public/assets/brand-4F9ZXBF8.css +1 -0
- package/payload/server/public/assets/{brand-BaRMO3mZ.js → brand-C7kj0USi.js} +1 -1
- package/payload/server/public/assets/browser-eLSiC7_b.js +1 -0
- package/payload/server/public/assets/{c4Diagram-AHTNJAMY-Nv1G0o9P.js → c4Diagram-AHTNJAMY-NuYFvPDU.js} +1 -1
- package/payload/server/public/assets/channel-KT66MFN2.js +1 -0
- package/payload/server/public/assets/chat-DedpVKUl.js +1 -0
- package/payload/server/public/assets/{chunk-2KRD3SAO-BpqPMhoA.js → chunk-2KRD3SAO-l5VL1KQm.js} +1 -1
- package/payload/server/public/assets/{chunk-336JU56O-DgXHlVU_.js → chunk-336JU56O-C5gVznC2.js} +2 -2
- package/payload/server/public/assets/chunk-426QAEUC-CWMiOm8Y.js +1 -0
- package/payload/server/public/assets/{chunk-4BX2VUAB-nwyZSZH8.js → chunk-4BX2VUAB-BtMVz_Sq.js} +1 -1
- package/payload/server/public/assets/{chunk-4TB4RGXK-Tfxz9LHX.js → chunk-4TB4RGXK-C8-dmCuT.js} +1 -1
- package/payload/server/public/assets/{chunk-55IACEB6-6FMJQGXG.js → chunk-55IACEB6-C5gWvEJW.js} +1 -1
- package/payload/server/public/assets/{chunk-5FUZZQ4R-g2FgZF3D.js → chunk-5FUZZQ4R-BZ7VZoAC.js} +1 -1
- package/payload/server/public/assets/{chunk-5PVQY5BW-DtLwXsPH.js → chunk-5PVQY5BW-C_ajQOGC.js} +1 -1
- package/payload/server/public/assets/{chunk-67CJDMHE-K91CP5ZU.js → chunk-67CJDMHE-BJOR2dwK.js} +1 -1
- package/payload/server/public/assets/{chunk-7N4EOEYR-BGpCQhqK.js → chunk-7N4EOEYR-DvZLpquX.js} +1 -1
- package/payload/server/public/assets/{chunk-AA7GKIK3-jkDbInck.js → chunk-AA7GKIK3-h5tVsPlW.js} +1 -1
- package/payload/server/public/assets/{chunk-BSJP7CBP-mDosdzGs.js → chunk-BSJP7CBP-DLOF2-m3.js} +1 -1
- package/payload/server/public/assets/{chunk-CIAEETIT-DhBxewpQ.js → chunk-CIAEETIT-CQRQMPCf.js} +1 -1
- package/payload/server/public/assets/{chunk-EDXVE4YY-B7c-9Emg.js → chunk-EDXVE4YY-K9-EfuM2.js} +1 -1
- package/payload/server/public/assets/{chunk-ENJZ2VHE-Cqhhncox.js → chunk-ENJZ2VHE-DVoy6NvU.js} +1 -1
- package/payload/server/public/assets/{chunk-FMBD7UC4-BpDq6wj1.js → chunk-FMBD7UC4-CQn_2o2b.js} +1 -1
- package/payload/server/public/assets/{chunk-FOC6F5B3-Ds02-ktu.js → chunk-FOC6F5B3-CuN73goS.js} +1 -1
- package/payload/server/public/assets/{chunk-ICPOFSXX-BTX5POFr.js → chunk-ICPOFSXX-CKhl9J-H.js} +2 -2
- package/payload/server/public/assets/{chunk-K5T4RW27-Du1PXXBU.js → chunk-K5T4RW27-CBskuQmq.js} +1 -1
- package/payload/server/public/assets/{chunk-KGLVRYIC-siasOAf8.js → chunk-KGLVRYIC-Chtjt8xK.js} +1 -1
- package/payload/server/public/assets/{chunk-LIHQZDEY-xf1rbZtf.js → chunk-LIHQZDEY-EOBiBNSH.js} +1 -1
- package/payload/server/public/assets/{chunk-ORNJ4GCN-DeTLQ_LD.js → chunk-ORNJ4GCN-uPPq-5MN.js} +1 -1
- package/payload/server/public/assets/{chunk-OYMX7WX6-DQ7_oVJn.js → chunk-OYMX7WX6-BRzbxJOT.js} +1 -1
- package/payload/server/public/assets/chunk-QZHKN3VN-DCzpF46A.js +1 -0
- package/payload/server/public/assets/{chunk-U2HBQHQK-CXmFUKgn.js → chunk-U2HBQHQK-Bndyn5nF.js} +1 -1
- package/payload/server/public/assets/{chunk-X2U36JSP-Bj8-8Wkz.js → chunk-X2U36JSP-BspGBHXW.js} +1 -1
- package/payload/server/public/assets/{chunk-XPW4576I-Con3TXqt.js → chunk-XPW4576I-HgXQ2k9h.js} +1 -1
- package/payload/server/public/assets/{chunk-YZCP3GAM-Dx8BHGWf.js → chunk-YZCP3GAM-C7oTyCnw.js} +1 -1
- package/payload/server/public/assets/{chunk-ZZ45TVLE-Dp4Q5Y-f.js → chunk-ZZ45TVLE-CufWa7QL.js} +1 -1
- package/payload/server/public/assets/classDiagram-6PBFFD2Q-QOU4HzJJ.js +1 -0
- package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-DcOUai3Z.js +1 -0
- package/payload/server/public/assets/clone-CHh05KN-.js +1 -0
- package/payload/server/public/assets/{cose-bilkent-S5V4N54A-pZiCv69E.js → cose-bilkent-S5V4N54A-BM3yEbF-.js} +1 -1
- package/payload/server/public/assets/{dagre-CLqhEgbL.js → dagre-C7WHNZO8.js} +1 -1
- package/payload/server/public/assets/{dagre-KV5264BT-BCxE8iyk.js → dagre-KV5264BT-bcZx3l06.js} +1 -1
- package/payload/server/public/assets/data-BcoBY39U.js +1 -0
- package/payload/server/public/assets/{diagram-5BDNPKRD-slUEdZzz.js → diagram-5BDNPKRD-B7VotaMF.js} +1 -1
- package/payload/server/public/assets/{diagram-G4DWMVQ6-DPcraMfu.js → diagram-G4DWMVQ6-CWWvEsFx.js} +1 -1
- package/payload/server/public/assets/{diagram-MMDJMWI5-DR6luhGK.js → diagram-MMDJMWI5-DYHVkTYJ.js} +1 -1
- package/payload/server/public/assets/{diagram-TYMM5635-Jap1B4wA.js → diagram-TYMM5635-CHeB6Ama.js} +1 -1
- package/payload/server/public/assets/{dist-Dbh7HrZX.js → dist-CjjtmoWL.js} +1 -1
- package/payload/server/public/assets/{erDiagram-SMLLAGMA-DJKUs2hO.js → erDiagram-SMLLAGMA-C9gog8QP.js} +1 -1
- package/payload/server/public/assets/{flatten-Cl1Bc3dR.js → flatten-QcJDm7yK.js} +1 -1
- package/payload/server/public/assets/{flowDiagram-DWJPFMVM-C8W-ZZ9W.js → flowDiagram-DWJPFMVM-B2O9lKTh.js} +1 -1
- package/payload/server/public/assets/{ganttDiagram-T4ZO3ILL-DYCX4Xu2.js → ganttDiagram-T4ZO3ILL-DEa4AwbR.js} +1 -1
- package/payload/server/public/assets/gitGraph-7Q5UKJZL-BC-u4jgy.js +1 -0
- package/payload/server/public/assets/{gitGraphDiagram-UUTBAWPF-CZu_fpgS.js → gitGraphDiagram-UUTBAWPF-BjXPQpBL.js} +1 -1
- package/payload/server/public/assets/{graph-D29p1FJH.js → graph-C7Hye_vp.js} +2 -2
- package/payload/server/public/assets/{graph-labels-DF3QVHkH.js → graph-labels-YYgGsEVd.js} +1 -1
- package/payload/server/public/assets/{graphlib-Bdp7TA4y.js → graphlib-CBevn2DP.js} +1 -1
- package/payload/server/public/assets/info-OMHHGYJF-DPUetTz-.js +1 -0
- package/payload/server/public/assets/infoDiagram-42DDH7IO-q2dl09-M.js +2 -0
- package/payload/server/public/assets/{isEmpty-D1pGOD1J.js → isEmpty-BO6BAEn7.js} +1 -1
- package/payload/server/public/assets/{ishikawaDiagram-UXIWVN3A-B7KfIX6z.js → ishikawaDiagram-UXIWVN3A-CPLfpvqv.js} +1 -1
- package/payload/server/public/assets/{journeyDiagram-VCZTEJTY-CSDwBfhF.js → journeyDiagram-VCZTEJTY-CTHe8MiD.js} +1 -1
- package/payload/server/public/assets/{kanban-definition-6JOO6SKY-CWzcEKTr.js → kanban-definition-6JOO6SKY-Bm9h1O3Y.js} +1 -1
- package/payload/server/public/assets/{line-BNQSlbYn.js → line-C31b0rtY.js} +1 -1
- package/payload/server/public/assets/{linear-BN6kGN93.js → linear-Cfm_8_pU.js} +1 -1
- package/payload/server/public/assets/{mermaid-parser.core-CcFhkElq.js → mermaid-parser.core-B3tGwOcE.js} +2 -2
- package/payload/server/public/assets/{mermaid.core-BsIeJ7Cc.js → mermaid.core-BM3s85ZW.js} +3 -3
- package/payload/server/public/assets/{mindmap-definition-QFDTVHPH-CQVzj6D_.js → mindmap-definition-QFDTVHPH-CaGv_mIB.js} +1 -1
- package/payload/server/public/assets/operator-WsXhcbBF.js +1 -0
- package/payload/server/public/assets/{ordinal-CBZeH4Yp.js → ordinal-jLCwuvYg.js} +1 -1
- package/payload/server/public/assets/packet-4T2RLAQJ-BcfR-ZwA.js +1 -0
- package/payload/server/public/assets/page-BhHTnqv4.js +1 -0
- package/payload/server/public/assets/pie-ZZUOXDRM-BiKgZdNB.js +1 -0
- package/payload/server/public/assets/{pieDiagram-DEJITSTG-DnrQ9fyn.js → pieDiagram-DEJITSTG-BhAXps4u.js} +1 -1
- package/payload/server/public/assets/public-ViXjC_dA.js +6 -0
- package/payload/server/public/assets/public-next-BKECyMz2.js +1 -0
- package/payload/server/public/assets/{quadrantDiagram-34T5L4WZ-BQWlCyWi.js → quadrantDiagram-34T5L4WZ-BWtTdNs8.js} +1 -1
- package/payload/server/public/assets/radar-PYXPWWZC-nvCjiW_J.js +1 -0
- package/payload/server/public/assets/{reduce-PuPlFPRX.js → reduce-Dmi_NdVH.js} +1 -1
- package/payload/server/public/assets/{requirementDiagram-MS252O5E-Du_vZhU1.js → requirementDiagram-MS252O5E-CWU0qCcP.js} +1 -1
- package/payload/server/public/assets/{sankeyDiagram-XADWPNL6-Cf6Z8GPQ.js → sankeyDiagram-XADWPNL6-DYvutQld.js} +1 -1
- package/payload/server/public/assets/{sequenceDiagram-FGHM5R23-CS8GVol8.js → sequenceDiagram-FGHM5R23-Cir0hBWS.js} +1 -1
- package/payload/server/public/assets/{src-BoaldmnP.js → src-CwB968DO.js} +1 -1
- package/payload/server/public/assets/{stateDiagram-FHFEXIEX-Bv1NW2F1.js → stateDiagram-FHFEXIEX-Be-h8YSS.js} +1 -1
- package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-CAnmjSj7.js +1 -0
- package/payload/server/public/assets/{timeline-definition-GMOUNBTQ-ClGYAsr0.js → timeline-definition-GMOUNBTQ-C3C4Wuyk.js} +1 -1
- package/payload/server/public/assets/treeView-SZITEDCU-BinXCVyM.js +1 -0
- package/payload/server/public/assets/treemap-W4RFUUIX-CSmh20Ze.js +1 -0
- package/payload/server/public/assets/{useSelectionMode-ghXuZicl.js → useSelectionMode-CG_Iel5F.js} +1 -1
- package/payload/server/public/assets/{vennDiagram-DHZGUBPP-C2wTcxQT.js → vennDiagram-DHZGUBPP-mDclw0Sa.js} +1 -1
- package/payload/server/public/assets/wardley-RL74JXVD-BiCmRKWx.js +1 -0
- package/payload/server/public/assets/{wardleyDiagram-NUSXRM2D-D86-ivEx.js → wardleyDiagram-NUSXRM2D-mvk-YA9g.js} +1 -1
- package/payload/server/public/assets/{xychartDiagram-5P7HB3ND-Ba5WAN8P.js → xychartDiagram-5P7HB3ND-9M7k1hmD.js} +1 -1
- package/payload/server/public/browser.html +8 -8
- package/payload/server/public/chat.html +11 -11
- package/payload/server/public/data.html +7 -7
- package/payload/server/public/graph.html +10 -10
- package/payload/server/public/index.html +10 -10
- package/payload/server/public/operator.html +13 -13
- package/payload/server/public/public-next.html +24 -0
- package/payload/server/public/public.html +9 -8
- package/payload/server/server.js +4450 -3781
- package/dist/__tests__/onboarding-state-readback.test.js +0 -61
- package/dist/__tests__/rss-sampler-installer.test.js +0 -27
- package/dist/onboarding-readback.js +0 -27
- package/payload/server/public/assets/AdminLoginScreens-BsC-EwAn.js +0 -1
- package/payload/server/public/assets/AdminShell-CiKKN22G.js +0 -1
- package/payload/server/public/assets/admin-DSwmdCKp.js +0 -1
- package/payload/server/public/assets/architecture-YZFGNWBL-6g9jRVgc.js +0 -1
- package/payload/server/public/assets/brand-C001cin3.css +0 -1
- package/payload/server/public/assets/browser-BKR1eJJb.js +0 -1
- package/payload/server/public/assets/channel-BgQLJanG.js +0 -1
- package/payload/server/public/assets/chat-DZXNRiy-.js +0 -1
- package/payload/server/public/assets/chunk-426QAEUC-Dr_XVuUq.js +0 -1
- package/payload/server/public/assets/chunk-QZHKN3VN-DF4o9HRJ.js +0 -1
- package/payload/server/public/assets/classDiagram-6PBFFD2Q-DAbPKU6u.js +0 -1
- package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-BKuFQLcv.js +0 -1
- package/payload/server/public/assets/clone-DnNHGhNe.js +0 -1
- package/payload/server/public/assets/data-CuVmW1WN.js +0 -1
- package/payload/server/public/assets/file-download-4_hQmMwU.js +0 -1
- package/payload/server/public/assets/gitGraph-7Q5UKJZL-g7mvu6IY.js +0 -1
- package/payload/server/public/assets/info-OMHHGYJF-DZqJuIkB.js +0 -1
- package/payload/server/public/assets/infoDiagram-42DDH7IO-cGfGccHz.js +0 -2
- package/payload/server/public/assets/operator-CQRaBNN7.js +0 -1
- package/payload/server/public/assets/packet-4T2RLAQJ-Hn8rlHpy.js +0 -1
- package/payload/server/public/assets/page-Dz2F3QtB.js +0 -1
- package/payload/server/public/assets/pie-ZZUOXDRM-BPGWVqBm.js +0 -1
- package/payload/server/public/assets/public-B7BQwWpP.js +0 -6
- package/payload/server/public/assets/radar-PYXPWWZC-DMdLrj3E.js +0 -1
- package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-BGUCxPmp.js +0 -1
- package/payload/server/public/assets/treeView-SZITEDCU-CWxofUbI.js +0 -1
- package/payload/server/public/assets/treemap-W4RFUUIX-Cfgb_ZG0.js +0 -1
- package/payload/server/public/assets/wardley-RL74JXVD-B45olYjj.js +0 -1
- /package/payload/server/public/assets/{file-download-qc_xy7Az.css → OperatorConversations-qc_xy7Az.css} +0 -0
- /package/payload/server/public/assets/{_baseFor-brRjpUOX.js → _baseFor-D8P3gUw3.js} +0 -0
- /package/payload/server/public/assets/{array-BGFCBI0e.js → array-CLwNaqU1.js} +0 -0
- /package/payload/server/public/assets/{chunk-Pqm5yXtL.js → chunk-CAM3fms7.js} +0 -0
- /package/payload/server/public/assets/{cytoscape.esm-TvRJ2tGX.js → cytoscape.esm-mZ4wTuB7.js} +0 -0
- /package/payload/server/public/assets/{defaultLocale-CRZydyG6.js → defaultLocale-D_VMtRaY.js} +0 -0
- /package/payload/server/public/assets/{init-B8gtcn7T.js → init-vVpfz1D6.js} +0 -0
- /package/payload/server/public/assets/{katex-RxgSu_dy.js → katex-DaHGEgm7.js} +0 -0
- /package/payload/server/public/assets/{path-DZF-JdEe.js → path-CuyvWNAH.js} +0 -0
- /package/payload/server/public/assets/{preload-helper-CQ36nxok.js → preload-helper-TKOBYGYD.js} +0 -0
- /package/payload/server/public/assets/{rough.esm-6CnTHTkH.js → rough.esm-JX0wREDd.js} +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: platform-architecture
|
|
3
3
|
description: Use when grounding any documented-surface claim about what Maxy ships — plugins, skills, specialists, install/deploy flows, internals. This is the install catalogue, not evidence of what is enabled on the current account. For install state on this account, call `capabilities-here`; for documented surface, cite the `Source:` URL inline.
|
|
4
|
-
content-hash: sha256:
|
|
4
|
+
content-hash: sha256:8fd7006bd54f69d5932bc831cf46f9ced8e01318f5fac0963f4285bc1e4b21a0
|
|
5
5
|
brand: maxy-code
|
|
6
6
|
product-name: Maxy
|
|
7
7
|
---
|
|
@@ -2288,7 +2288,7 @@ either is a regression.
|
|
|
2288
2288
|
|
|
2289
2289
|
**`/chat` Claude-desktop transcript presentation.** The admin webchat keeps the shared `Transcript` shell (stream, follow-tail) but injects a /chat-only item renderer via the component's optional `renderItems` prop: `renderChatTimeline` in `app/chat/transcript-render.tsx`. Presentation: operator turns render as a right-aligned grey bubble with only the message text (no label, no per-turn time); all agent output renders as plain prose (the reply-document filename line stays, as prose); a maximal consecutive run of `tool-call`/`tool-result` turns renders as one collapsed grey one-liner ("Used N tools ›") whose expansion shows every call and result payload — a lone call still gets the one-liner, and prose or a directive row ends a run. The WhatsApp reader (`/whatsapp`) omits the prop and keeps the default `renderTimeline`, so its rendering is unchanged; both presentations are test-pinned (`app/whatsapp/__tests__/Transcript-*.test.tsx` unmodified, `app/chat/__tests__/transcript-render.test.tsx` new).
|
|
2290
2290
|
|
|
2291
|
-
**maxy title for public sessions.** A `role=public` webchat spawn never produces a useful Claude Code `ai-title` (an anonymous one-line visitor turn), so every public row would otherwise read identically. The webchat route (`chat.ts`) composes a deterministic title — `Web · <senderId[:8]>[ · <personId>] · <UTC YYYY-MM-DD HH:mm>` (personId present only for gated visitors) — and threads it through the
|
|
2291
|
+
**maxy title for public sessions.** A `role=public` webchat spawn never produces a useful Claude Code `ai-title` (an anonymous one-line visitor turn), so every public row would otherwise read identically. The webchat route (`chat.ts`) composes a deterministic title — `Web · <senderId[:8]>[ · <personId>] · <UTC YYYY-MM-DD HH:mm>` (personId present only for gated visitors) — and threads it through the native webchat gateway's public spawn (`handleInbound` → `buildPublicWebchatSpawnRequest` → `managerSpawn`) to the manager `POST /public-spawn` body as `name`. `/spawn` validates it with `validateUserTitle` and, for `role=public` only, writes it into `UserTitleStore` so it occupies the operator-rename tier and wins over `ai-title`. Admin (`/rc-spawn`) and WhatsApp titling are unchanged. Observability: every public spawn logs `[spawn] role=public … title="…"` (or `title=missing`); the manager's row builder emits `[public-title] sessionId=… unexpected titleSource=<ai|null>` on the next list read for any public row that did not resolve from the user tier.
|
|
2292
2292
|
|
|
2293
2293
|
### Graph
|
|
2294
2294
|
|
|
@@ -2489,6 +2489,26 @@ authoritative. This section names the surfaces and what backs each.
|
|
|
2489
2489
|
> via the same admin-gated reader routes, never the operator's own session. The
|
|
2490
2490
|
> operator surface is documented in full in the internal doc
|
|
2491
2491
|
> `maxy-code/.docs/operator-dashboard.md`.
|
|
2492
|
+
>
|
|
2493
|
+
> **Width.** The operator header, the operator chat column, and the `/data`
|
|
2494
|
+
> header+toolbar+body all render in one centred column bounded to
|
|
2495
|
+
> `--chat-measure` (48rem). That token is a `:root` design token (beside
|
|
2496
|
+
> `--measure`/`--gutter`); the operator-header clamp
|
|
2497
|
+
> (`.admin-shell-root:has(> .platform-operator) > .admin-header`), the chat-column
|
|
2498
|
+
> clamp (`.platform-operator > .webchat-page`), and the `/data` clamp
|
|
2499
|
+
> (`.data-main`) all read it, so logo and burger align to the panel edges on both
|
|
2500
|
+
> surfaces. The admin shell carries no `--chat-measure` consumer and stays
|
|
2501
|
+
> edge-to-edge; the public webchat (`.public-surface`) inherits the same value.
|
|
2502
|
+
>
|
|
2503
|
+
> **Conversations item.** The dynamic Conversations burger item appears on
|
|
2504
|
+
> **both** the operator chat surface and `/data` whenever ≥1 reviewable
|
|
2505
|
+
> conversation exists (the count/channels are fetched per surface from
|
|
2506
|
+
> `/whatsapp-reader/conversations` with the operator's session key). On `/data`
|
|
2507
|
+
> selecting it renders the same read-only reader in place (the file browser is
|
|
2508
|
+
> swapped for it; Back returns). The flyout-open signal
|
|
2509
|
+
> `[operator-ui] op=conversations-menu present=<bool> channels=[…] count=<n>`
|
|
2510
|
+
> fires on `/data` too — `present=false` there while the chat surface shows the
|
|
2511
|
+
> item is the props-not-wired signature.
|
|
2492
2512
|
|
|
2493
2513
|
| Surface | What it does | Backed by |
|
|
2494
2514
|
|---|---|---|
|
|
@@ -3273,7 +3293,7 @@ The `brand-excluded` branch closes the recurring crash-restart loop on brands th
|
|
|
3273
3293
|
|
|
3274
3294
|
**Per-spawn signals (server.log).** Every spawn emits `pty-spawn-mcp-config servers=<N> tools=<M> bytes=<B> path=<…>` once, plus one `pty-spawn-agents-dir role=<admin|public> path=<…>` per added directory. Specialist spawns additionally emit `pty-spawn-allowlist specialist=<name> count=<N> stripped=<S> sourced-from=agent-frontmatter` where `stripped` is the count of brand-excluded tool names removed before argv emission. The diagnostic one-liner is `grep -E 'pty-spawn-mcp-config|pty-spawn-agents-dir|pty-spawn-allowlist|mcp-config-allowlist-coverage|specialist-tool-strip|boot-failed reason=' ~/.<brand>/logs/server.log | tail -50`.
|
|
3275
3295
|
|
|
3276
|
-
**Channel follower cold-start retry.** Each channel PTY session
|
|
3296
|
+
**Channel follower cold-start retry.** Each `dispatchOnce`-based channel PTY session has one JSONL follower ([`platform/ui/app/lib/channel-pty-bridge/follower.ts`](../../../ui/app/lib/channel-pty-bridge/follower.ts)) reading `GET /<sessionId>/log?follow=1` and fanning each assistant `end_turn` out to the awaiting `dispatchOnce`. (WhatsApp and public webchat have since migrated to the native event channel — an MCP notification in, a `reply`-tool call out — and no longer use this follower; the remaining `dispatchOnce` channels are email and telegram. The webchat detail below is the historical record of the bug the retry fixed.) A freshly-spawned PTY has no JSONL on disk until claude flushes its first line; during that window the manager answers `202 {pending:true}`. The follower retries every `CHANNEL_PTY_FOLLOWER_RETRY_MS` (default 1000) until a 200 stream opens or `CHANNEL_PTY_FOLLOWER_PENDING_MAX_MS` elapses. The follower is shared across channels, so that window defaults to the longest channel turn window (whatsapp's `WHATSAPP_PTY_TURN_TIMEOUT_MS`, 300000 — longer than webchat's 120000) so it never abandons a turn the caller is still awaiting. Because public sessions idle-reap, every webchat greeting is the first turn of a fresh spawn and crosses this window — before the retry, a 202 (which satisfies `res.ok`) was consumed as a single non-event line, the stream ended, and the follower died silently, timing out every public turn. The lifecycle is greppable as `follower-connect status=<code>` → `follower-retry attempt=N reason=pending` → `follower-open` → `outbound bytes=N`; `follower-give-up reason=pending-timeout` marks the JSONL never appearing. A `reject reason=turn-timeout` with no preceding `follower-open` (and no manager `log-follow-open`) for that sessionId is the signature. See `.docs/gated-public-agents.md` "Webchat turn lifecycle" for the full tag list.
|
|
3277
3297
|
|
|
3278
3298
|
**Brand-process start counter.** `platform/ui/server-init.cjs` increments a persistent counter at `/tmp/server-init-<accountId>-restart.count` on every fresh start and emits `[server-init] start count=<N> account=<accountId> counter-path=<…>` to `server.log`. /tmp clears on reboot, so a clean reboot starts the count fresh; any value `>1` between operator-observed reboots means the brand process (driven by its `Requires=<brand>-claude-session-manager.service` clause) is restarting. The diagnostic one-liner is `grep '\[server-init\] start' ~/.<brand>/logs/server.log | tail -5` — the trailing `count=` value is the loop depth without counting SIGTERMs.
|
|
3279
3299
|
|
|
@@ -57,7 +57,7 @@ either is a regression.
|
|
|
57
57
|
|
|
58
58
|
**`/chat` Claude-desktop transcript presentation.** The admin webchat keeps the shared `Transcript` shell (stream, follow-tail) but injects a /chat-only item renderer via the component's optional `renderItems` prop: `renderChatTimeline` in `app/chat/transcript-render.tsx`. Presentation: operator turns render as a right-aligned grey bubble with only the message text (no label, no per-turn time); all agent output renders as plain prose (the reply-document filename line stays, as prose); a maximal consecutive run of `tool-call`/`tool-result` turns renders as one collapsed grey one-liner ("Used N tools ›") whose expansion shows every call and result payload — a lone call still gets the one-liner, and prose or a directive row ends a run. The WhatsApp reader (`/whatsapp`) omits the prop and keeps the default `renderTimeline`, so its rendering is unchanged; both presentations are test-pinned (`app/whatsapp/__tests__/Transcript-*.test.tsx` unmodified, `app/chat/__tests__/transcript-render.test.tsx` new).
|
|
59
59
|
|
|
60
|
-
**maxy title for public sessions.** A `role=public` webchat spawn never produces a useful Claude Code `ai-title` (an anonymous one-line visitor turn), so every public row would otherwise read identically. The webchat route (`chat.ts`) composes a deterministic title — `Web · <senderId[:8]>[ · <personId>] · <UTC YYYY-MM-DD HH:mm>` (personId present only for gated visitors) — and threads it through the
|
|
60
|
+
**maxy title for public sessions.** A `role=public` webchat spawn never produces a useful Claude Code `ai-title` (an anonymous one-line visitor turn), so every public row would otherwise read identically. The webchat route (`chat.ts`) composes a deterministic title — `Web · <senderId[:8]>[ · <personId>] · <UTC YYYY-MM-DD HH:mm>` (personId present only for gated visitors) — and threads it through the native webchat gateway's public spawn (`handleInbound` → `buildPublicWebchatSpawnRequest` → `managerSpawn`) to the manager `POST /public-spawn` body as `name`. `/spawn` validates it with `validateUserTitle` and, for `role=public` only, writes it into `UserTitleStore` so it occupies the operator-rename tier and wins over `ai-title`. Admin (`/rc-spawn`) and WhatsApp titling are unchanged. Observability: every public spawn logs `[spawn] role=public … title="…"` (or `title=missing`); the manager's row builder emits `[public-title] sessionId=… unexpected titleSource=<ai|null>` on the next list read for any public row that did not resolve from the user tier.
|
|
61
61
|
|
|
62
62
|
### Graph
|
|
63
63
|
|
|
@@ -258,6 +258,26 @@ authoritative. This section names the surfaces and what backs each.
|
|
|
258
258
|
> via the same admin-gated reader routes, never the operator's own session. The
|
|
259
259
|
> operator surface is documented in full in the internal doc
|
|
260
260
|
> `maxy-code/.docs/operator-dashboard.md`.
|
|
261
|
+
>
|
|
262
|
+
> **Width.** The operator header, the operator chat column, and the `/data`
|
|
263
|
+
> header+toolbar+body all render in one centred column bounded to
|
|
264
|
+
> `--chat-measure` (48rem). That token is a `:root` design token (beside
|
|
265
|
+
> `--measure`/`--gutter`); the operator-header clamp
|
|
266
|
+
> (`.admin-shell-root:has(> .platform-operator) > .admin-header`), the chat-column
|
|
267
|
+
> clamp (`.platform-operator > .webchat-page`), and the `/data` clamp
|
|
268
|
+
> (`.data-main`) all read it, so logo and burger align to the panel edges on both
|
|
269
|
+
> surfaces. The admin shell carries no `--chat-measure` consumer and stays
|
|
270
|
+
> edge-to-edge; the public webchat (`.public-surface`) inherits the same value.
|
|
271
|
+
>
|
|
272
|
+
> **Conversations item.** The dynamic Conversations burger item appears on
|
|
273
|
+
> **both** the operator chat surface and `/data` whenever ≥1 reviewable
|
|
274
|
+
> conversation exists (the count/channels are fetched per surface from
|
|
275
|
+
> `/whatsapp-reader/conversations` with the operator's session key). On `/data`
|
|
276
|
+
> selecting it renders the same read-only reader in place (the file browser is
|
|
277
|
+
> swapped for it; Back returns). The flyout-open signal
|
|
278
|
+
> `[operator-ui] op=conversations-menu present=<bool> channels=[…] count=<n>`
|
|
279
|
+
> fires on `/data` too — `present=false` there while the chat surface shows the
|
|
280
|
+
> item is the props-not-wired signature.
|
|
261
281
|
|
|
262
282
|
| Surface | What it does | Backed by |
|
|
263
283
|
|---|---|---|
|
|
@@ -477,7 +477,7 @@ The `brand-excluded` branch closes the recurring crash-restart loop on brands th
|
|
|
477
477
|
|
|
478
478
|
**Per-spawn signals (server.log).** Every spawn emits `pty-spawn-mcp-config servers=<N> tools=<M> bytes=<B> path=<…>` once, plus one `pty-spawn-agents-dir role=<admin|public> path=<…>` per added directory. Specialist spawns additionally emit `pty-spawn-allowlist specialist=<name> count=<N> stripped=<S> sourced-from=agent-frontmatter` where `stripped` is the count of brand-excluded tool names removed before argv emission. The diagnostic one-liner is `grep -E 'pty-spawn-mcp-config|pty-spawn-agents-dir|pty-spawn-allowlist|mcp-config-allowlist-coverage|specialist-tool-strip|boot-failed reason=' ~/.<brand>/logs/server.log | tail -50`.
|
|
479
479
|
|
|
480
|
-
**Channel follower cold-start retry.** Each channel PTY session
|
|
480
|
+
**Channel follower cold-start retry.** Each `dispatchOnce`-based channel PTY session has one JSONL follower ([`platform/ui/app/lib/channel-pty-bridge/follower.ts`](../../../ui/app/lib/channel-pty-bridge/follower.ts)) reading `GET /<sessionId>/log?follow=1` and fanning each assistant `end_turn` out to the awaiting `dispatchOnce`. (WhatsApp and public webchat have since migrated to the native event channel — an MCP notification in, a `reply`-tool call out — and no longer use this follower; the remaining `dispatchOnce` channels are email and telegram. The webchat detail below is the historical record of the bug the retry fixed.) A freshly-spawned PTY has no JSONL on disk until claude flushes its first line; during that window the manager answers `202 {pending:true}`. The follower retries every `CHANNEL_PTY_FOLLOWER_RETRY_MS` (default 1000) until a 200 stream opens or `CHANNEL_PTY_FOLLOWER_PENDING_MAX_MS` elapses. The follower is shared across channels, so that window defaults to the longest channel turn window (whatsapp's `WHATSAPP_PTY_TURN_TIMEOUT_MS`, 300000 — longer than webchat's 120000) so it never abandons a turn the caller is still awaiting. Because public sessions idle-reap, every webchat greeting is the first turn of a fresh spawn and crosses this window — before the retry, a 202 (which satisfies `res.ok`) was consumed as a single non-event line, the stream ended, and the follower died silently, timing out every public turn. The lifecycle is greppable as `follower-connect status=<code>` → `follower-retry attempt=N reason=pending` → `follower-open` → `outbound bytes=N`; `follower-give-up reason=pending-timeout` marks the JSONL never appearing. A `reject reason=turn-timeout` with no preceding `follower-open` (and no manager `log-follow-open`) for that sessionId is the signature. See `.docs/gated-public-agents.md` "Webchat turn lifecycle" for the full tag list.
|
|
481
481
|
|
|
482
482
|
**Brand-process start counter.** `platform/ui/server-init.cjs` increments a persistent counter at `/tmp/server-init-<accountId>-restart.count` on every fresh start and emits `[server-init] start count=<N> account=<accountId> counter-path=<…>` to `server.log`. /tmp clears on reboot, so a clean reboot starts the count fresh; any value `>1` between operator-observed reboots means the brand process (driven by its `Requires=<brand>-claude-session-manager.service` clause) is restarting. The diagnostic one-liner is `grep '\[server-init\] start' ~/.<brand>/logs/server.log | tail -5` — the trailing `count=` value is the loop depth without counting SIGTERMs.
|
|
483
483
|
|
|
@@ -55,6 +55,10 @@ const ALLOWLIST = new Set([
|
|
|
55
55
|
// before the module's `../paths` mock fires, to redirect MAXY_DIR off the
|
|
56
56
|
// operator's real home config.
|
|
57
57
|
'platform/ui/app/lib/__tests__/operator-domains.test.ts',
|
|
58
|
+
// Same vi.hoisted pattern: the per-admin remote-auth test builds a tmpdir
|
|
59
|
+
// before the `../paths` mock fires, to point USERS_FILE/REMOTE_PASSWORD_FILE
|
|
60
|
+
// at a temp dir off the operator's real home config.
|
|
61
|
+
'platform/ui/app/lib/__tests__/remote-auth-per-admin.test.ts',
|
|
58
62
|
])
|
|
59
63
|
|
|
60
64
|
const REQUIRE_CALL_RE = /\brequire\s*\(/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"canonical-tool-names.generated.d.ts","sourceRoot":"","sources":["../src/canonical-tool-names.generated.ts"],"names":[],"mappings":"AAQA,+EAA+E;AAC/E,eAAO,MAAM,gBAAgB,EAAE,SAAS,MAAM,EAiB7C,CAAA;AAED,gEAAgE;AAChE,eAAO,MAAM,yBAAyB,EAAE,SAAS,MAAM,
|
|
1
|
+
{"version":3,"file":"canonical-tool-names.generated.d.ts","sourceRoot":"","sources":["../src/canonical-tool-names.generated.ts"],"names":[],"mappings":"AAQA,+EAA+E;AAC/E,eAAO,MAAM,gBAAgB,EAAE,SAAS,MAAM,EAiB7C,CAAA;AAED,gEAAgE;AAChE,eAAO,MAAM,yBAAyB,EAAE,SAAS,MAAM,EAkLtD,CAAA"}
|
package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js
CHANGED
|
@@ -45,6 +45,7 @@ export const CANONICAL_MAXY_TOOL_NAMES = [
|
|
|
45
45
|
"mcp__plugin_admin_admin__public-hostname",
|
|
46
46
|
"mcp__plugin_admin_admin__publish-site",
|
|
47
47
|
"mcp__plugin_admin_admin__qr-generate",
|
|
48
|
+
"mcp__plugin_admin_admin__remote-auth-revoke-password",
|
|
48
49
|
"mcp__plugin_admin_admin__remote-auth-set-password",
|
|
49
50
|
"mcp__plugin_admin_admin__remote-auth-status",
|
|
50
51
|
"mcp__plugin_admin_admin__session-reset",
|
package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"canonical-tool-names.generated.js","sourceRoot":"","sources":["../src/canonical-tool-names.generated.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"canonical-tool-names.generated.js","sourceRoot":"","sources":["../src/canonical-tool-names.generated.ts"],"names":[],"mappings":"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"}
|
|
@@ -35,6 +35,10 @@ export interface HttpDeps extends Omit<SpawnDeps, 'onSessionReady' | 'watcher'>
|
|
|
35
35
|
* short value to exercise the bind-timeout response without a 60s wait. */
|
|
36
36
|
rcSpawnUrlWaitMs?: number;
|
|
37
37
|
}
|
|
38
|
+
export declare function forkArgvSegment(fromSessionId: string, newSessionId: string, model: string): string[];
|
|
39
|
+
export declare function reseatIdentityPrompt(model: string): string;
|
|
40
|
+
export declare function formatReseatLine(fromModel: string | null, toModel: string, oldSessionId: string, newSessionId: string, observed: string | null): string;
|
|
41
|
+
export declare function firstPostArmAssistantModel(lines: string[], armTimeMs: number): string | null;
|
|
38
42
|
/** Task 189 — Hono instance with the test-only fan-out trigger attached.
|
|
39
43
|
* The vitest fixture for the `/events` url-capture re-emit drives this
|
|
40
44
|
* directly (no real PTY spawn in the suite); production callers route
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http-server.d.ts","sourceRoot":"","sources":["../src/http-server.ts"],"names":[],"mappings":"AAsBA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAY3B,OAAO,EAgBL,KAAK,SAAS,EAEf,MAAM,kBAAkB,CAAA;AAqBzB,OAAO,KAAK,EAAE,SAAS,EAAyB,MAAM,iBAAiB,CAAA;AAEvE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAA;AAC1D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAA;AAC3D,OAAO,EAAqB,KAAK,cAAc,EAAE,MAAM,uBAAuB,CAAA;AAC9E,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AACtD,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAA;AAgFhE,eAAO,MAAM,kBAAkB,QAA2B,CAAA;AAS1D,eAAO,MAAM,4BAA4B,QAAS,CAAA;AAIlD,MAAM,WAAW,QAAS,SAAQ,IAAI,CAAC,SAAS,EAAE,gBAAgB,GAAG,SAAS,CAAC;IAC7E;;qEAEiE;IACjE,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,SAAS,CAAA;IAClB,WAAW,EAAE,MAAM,CAAA;IACnB,iBAAiB,EAAE,MAAM,CAAA;IACzB,kBAAkB,EAAE,WAAW,CAAA;IAC/B,eAAe,EAAE,aAAa,CAAA;IAC9B;kFAC8E;IAC9E,cAAc,EAAE,cAAc,CAAA;IAC9B;;gFAE4E;IAC5E,cAAc,EAAE,cAAc,CAAA;IAC9B;;;6BAGyB;IACzB,mBAAmB,CAAC,EAAE,mBAAmB,CAAA;IACzC;;gFAE4E;IAC5E,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAC1B;
|
|
1
|
+
{"version":3,"file":"http-server.d.ts","sourceRoot":"","sources":["../src/http-server.ts"],"names":[],"mappings":"AAsBA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAY3B,OAAO,EAgBL,KAAK,SAAS,EAEf,MAAM,kBAAkB,CAAA;AAqBzB,OAAO,KAAK,EAAE,SAAS,EAAyB,MAAM,iBAAiB,CAAA;AAEvE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAA;AAC1D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAA;AAC3D,OAAO,EAAqB,KAAK,cAAc,EAAE,MAAM,uBAAuB,CAAA;AAC9E,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AACtD,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAA;AAgFhE,eAAO,MAAM,kBAAkB,QAA2B,CAAA;AAS1D,eAAO,MAAM,4BAA4B,QAAS,CAAA;AAIlD,MAAM,WAAW,QAAS,SAAQ,IAAI,CAAC,SAAS,EAAE,gBAAgB,GAAG,SAAS,CAAC;IAC7E;;qEAEiE;IACjE,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,SAAS,CAAA;IAClB,WAAW,EAAE,MAAM,CAAA;IACnB,iBAAiB,EAAE,MAAM,CAAA;IACzB,kBAAkB,EAAE,WAAW,CAAA;IAC/B,eAAe,EAAE,aAAa,CAAA;IAC9B;kFAC8E;IAC9E,cAAc,EAAE,cAAc,CAAA;IAC9B;;gFAE4E;IAC5E,cAAc,EAAE,cAAc,CAAA;IAC9B;;;6BAGyB;IACzB,mBAAmB,CAAC,EAAE,mBAAmB,CAAA;IACzC;;gFAE4E;IAC5E,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAC1B;AAwGD,wBAAgB,eAAe,CAAC,aAAa,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAEpG;AAQD,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE1D;AAMD,wBAAgB,gBAAgB,CAC9B,SAAS,EAAE,MAAM,GAAG,IAAI,EACxB,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,MAAM,EACpB,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,MAAM,GAAG,IAAI,GACtB,MAAM,CAER;AAkCD,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAe5F;AAwJD;;;kEAGkE;AAClE,MAAM,MAAM,OAAO,GAAG,IAAI,GAAG;IAC3B,2BAA2B,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACpD;;;+CAG2C;IAC3C,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;CAChD,CAAA;AAmBD,wBAAgB,YAAY,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAimEpD"}
|
|
@@ -182,6 +182,120 @@ function resolveRow(watcher, id) {
|
|
|
182
182
|
// auto-archive` lines cover the lifecycle.
|
|
183
183
|
const END_TURN_SIGNATURE = '"stop_reason":"end_turn"';
|
|
184
184
|
const AUTO_ARCHIVE_SPECIALIST = 'database-operator';
|
|
185
|
+
// Task 876 — re-seat (operator-initiated model change for an existing admin
|
|
186
|
+
// webchat session). Fork the source onto a fresh session born on the chosen
|
|
187
|
+
// model: `--resume <old>` seeds history, `--fork-session` mints into the
|
|
188
|
+
// pre-supplied `--session-id <new>`, `--model` pins the fork's first turn.
|
|
189
|
+
// Pure so the argv shape is unit-tested without a spawn.
|
|
190
|
+
export function forkArgvSegment(fromSessionId, newSessionId, model) {
|
|
191
|
+
return ['--resume', fromSessionId, '--fork-session', '--session-id', newSessionId, '--model', model];
|
|
192
|
+
}
|
|
193
|
+
// Task 879 — the re-seated fork inherits the source's history, including the
|
|
194
|
+
// source's earlier self-identification on the OLD model. The rc-spawn path does
|
|
195
|
+
// not compose --append-system-prompt (only fresh spawnSession does), so the
|
|
196
|
+
// fork alone gets an authoritative current-model line on its argv: the agent
|
|
197
|
+
// answers the live model on the first ask, without being challenged. General
|
|
198
|
+
// self-ID accuracy (absent a re-seat) is out of scope — only the fork gets it.
|
|
199
|
+
export function reseatIdentityPrompt(model) {
|
|
200
|
+
return `This conversation now runs on the model ${model}. Earlier messages may show you identifying as a different model; that is stale context from before a model change — disregard it and state ${model} as your current model if asked.`;
|
|
201
|
+
}
|
|
202
|
+
// Task 876 — the re-seat post-condition line. Emitted ONLY after a real
|
|
203
|
+
// assistant turn on the fork is read (intention is not logged, per the
|
|
204
|
+
// observability contract): a re-seat that silently lands on the wrong model
|
|
205
|
+
// is visible rather than reported as success. Correlation key: old→new id.
|
|
206
|
+
export function formatReseatLine(fromModel, toModel, oldSessionId, newSessionId, observed) {
|
|
207
|
+
return `[webchat:reseat] op=reseat from-model=${fromModel ?? 'unknown'} to-model=${toModel} old-session=${oldSessionId} new-session=${newSessionId} first-turn-model=${observed ?? 'unknown'}`;
|
|
208
|
+
}
|
|
209
|
+
// Task 876 — read the most-recent real (non-synthetic) assistant model from a
|
|
210
|
+
// session's JSONL. The source's last answered model is the re-seat's
|
|
211
|
+
// from-model; a stranded session whose only tail is a synthetic error yields
|
|
212
|
+
// null ('unknown'). Bottom-up scan: the latest answered turn wins.
|
|
213
|
+
function lastRealAssistantModel(jsonlPath) {
|
|
214
|
+
let lines;
|
|
215
|
+
try {
|
|
216
|
+
lines = readFileSync(jsonlPath, 'utf8').split('\n').filter((l) => l.length > 0);
|
|
217
|
+
}
|
|
218
|
+
catch {
|
|
219
|
+
return null;
|
|
220
|
+
}
|
|
221
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
222
|
+
try {
|
|
223
|
+
const rec = JSON.parse(lines[i]);
|
|
224
|
+
if (rec.type === 'assistant' && typeof rec.message?.model === 'string' && rec.message.model !== '<synthetic>') {
|
|
225
|
+
return rec.message.model;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
catch {
|
|
229
|
+
/* a mid-write line — skip it */
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
return null;
|
|
233
|
+
}
|
|
234
|
+
// Task 876 — the FORK's first post-reseat assistant model. The fork JSONL
|
|
235
|
+
// opens with the copied history, and `--fork-session` PRESERVES each copied
|
|
236
|
+
// turn's original `timestamp` (verified: only `sessionId` is rewritten), so a
|
|
237
|
+
// post-arm timestamp cleanly discriminates the operator's first new turn from
|
|
238
|
+
// the copied history — independent of WHEN the copy flushes to disk (a
|
|
239
|
+
// line-count baseline would race the flush). Returns the first non-synthetic
|
|
240
|
+
// assistant model whose turn timestamp is strictly after `armTimeMs`, or null
|
|
241
|
+
// when no such turn has landed yet.
|
|
242
|
+
export function firstPostArmAssistantModel(lines, armTimeMs) {
|
|
243
|
+
for (const line of lines) {
|
|
244
|
+
if (line.length === 0)
|
|
245
|
+
continue;
|
|
246
|
+
try {
|
|
247
|
+
const rec = JSON.parse(line);
|
|
248
|
+
if (rec.type !== 'assistant')
|
|
249
|
+
continue;
|
|
250
|
+
const model = rec.message?.model;
|
|
251
|
+
if (typeof model !== 'string' || model === '<synthetic>')
|
|
252
|
+
continue;
|
|
253
|
+
const ts = typeof rec.timestamp === 'string' ? Date.parse(rec.timestamp) : NaN;
|
|
254
|
+
if (Number.isFinite(ts) && ts > armTimeMs)
|
|
255
|
+
return model;
|
|
256
|
+
}
|
|
257
|
+
catch {
|
|
258
|
+
/* a mid-write line — skip it */
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
return null;
|
|
262
|
+
}
|
|
263
|
+
// Task 876 — arm a one-shot reader on the FORK's first post-reseat assistant
|
|
264
|
+
// turn. `armTimeMs` is captured here (after bind); only assistant turns
|
|
265
|
+
// timestamped after it are read, so the copied history (old timestamps) is
|
|
266
|
+
// skipped however late it flushes. Emits the correlation line once a real
|
|
267
|
+
// model is read, then detaches; cleaned up on PTY exit.
|
|
268
|
+
function attachReseatObserve(deps, newSessionId, ctx) {
|
|
269
|
+
let done = false;
|
|
270
|
+
const jsonlPath = jsonlPathForSessionId(deps.spawnCwd, newSessionId);
|
|
271
|
+
const armTimeMs = Date.now();
|
|
272
|
+
function tryEmit() {
|
|
273
|
+
if (done)
|
|
274
|
+
return;
|
|
275
|
+
let lines;
|
|
276
|
+
try {
|
|
277
|
+
lines = readFileSync(jsonlPath, 'utf8').split('\n');
|
|
278
|
+
}
|
|
279
|
+
catch {
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
const observed = firstPostArmAssistantModel(lines, armTimeMs);
|
|
283
|
+
if (observed === null)
|
|
284
|
+
return;
|
|
285
|
+
done = true;
|
|
286
|
+
deps.logger(formatReseatLine(ctx.fromModel, ctx.toModel, ctx.oldSessionId, newSessionId, observed));
|
|
287
|
+
}
|
|
288
|
+
const unsubscribe = deps.watcher.subscribe((event) => {
|
|
289
|
+
if (done)
|
|
290
|
+
return;
|
|
291
|
+
if (event.sessionId !== newSessionId)
|
|
292
|
+
return;
|
|
293
|
+
if (event.source !== 'jsonl')
|
|
294
|
+
return;
|
|
295
|
+
tryEmit();
|
|
296
|
+
});
|
|
297
|
+
onPtyExit(newSessionId, () => unsubscribe());
|
|
298
|
+
}
|
|
185
299
|
// One-shot auto-close: once the session's JSONL contains an assistant
|
|
186
300
|
// message with `stop_reason === "end_turn"`, stop the PTY so the session
|
|
187
301
|
// closes after its single turn. Shared by the public-spawn database-operator
|
|
@@ -632,6 +746,17 @@ export function buildHttpApp(deps) {
|
|
|
632
746
|
const personId = typeof body.personId === 'string' && body.personId.length > 0 && body.personId.length <= 128
|
|
633
747
|
? body.personId
|
|
634
748
|
: undefined;
|
|
749
|
+
// Task 756 — the per-conversation webchat native channel for a public
|
|
750
|
+
// spawn. Shape-validated here (all three fields are non-empty strings, the
|
|
751
|
+
// gateway is loopback http) before it reaches the spawn, which composes it
|
|
752
|
+
// under the public ringfence (deny-all + reply-only allow + strict mcp).
|
|
753
|
+
const wc = body.webchatChannel;
|
|
754
|
+
const webchatChannel = wc && typeof wc === 'object'
|
|
755
|
+
&& typeof wc.key === 'string' && wc.key.length > 0
|
|
756
|
+
&& typeof wc.gatewayUrl === 'string' && wc.gatewayUrl.startsWith('http')
|
|
757
|
+
&& typeof wc.serverPath === 'string' && wc.serverPath.startsWith('/')
|
|
758
|
+
? { key: wc.key, gatewayUrl: wc.gatewayUrl, serverPath: wc.serverPath }
|
|
759
|
+
: undefined;
|
|
635
760
|
// Task 624 — maxy-composed public-session title. Validated by the same
|
|
636
761
|
// validateUserTitle the /:sessionId/rename route uses; persisted only for
|
|
637
762
|
// role=public after the sessionId is minted. An invalid/absent name leaves
|
|
@@ -708,6 +833,7 @@ export function buildHttpApp(deps) {
|
|
|
708
833
|
conversationNodeId,
|
|
709
834
|
sliceToken,
|
|
710
835
|
personId,
|
|
836
|
+
webchatChannel,
|
|
711
837
|
});
|
|
712
838
|
if (!result.ok) {
|
|
713
839
|
if ('rejected' in result) {
|
|
@@ -1618,6 +1744,14 @@ export function buildHttpApp(deps) {
|
|
|
1618
1744
|
}
|
|
1619
1745
|
const sessionId = typeof body.sessionId === 'string' && body.sessionId.length > 0 ? body.sessionId : null;
|
|
1620
1746
|
const name = typeof body.name === 'string' && body.name.length > 0 ? body.name : null;
|
|
1747
|
+
// Task 876 — re-seat fork. `forkFromSessionId` is the source whose history
|
|
1748
|
+
// is copied; `sessionId` is the caller-pre-minted fork target; `model` is
|
|
1749
|
+
// the chosen model. The UI allowlist (isSelectableModel) is the
|
|
1750
|
+
// authoritative gate; this shape-guard is defence-in-depth so a malformed
|
|
1751
|
+
// value cannot reach the `--model` argv (the manager has no rootDir-clean
|
|
1752
|
+
// path to import the models lib, so it guards on shape, not the exact list).
|
|
1753
|
+
const forkFromSessionId = typeof body.forkFromSessionId === 'string' && UUID_PATTERN.test(body.forkFromSessionId) ? body.forkFromSessionId : null;
|
|
1754
|
+
const reseatModel = typeof body.model === 'string' && /^claude-[a-z0-9.-]+(\[1m\])?$/i.test(body.model) ? body.model : null;
|
|
1621
1755
|
// Task 626 — per-visitor slice ringfence for the public session-end review
|
|
1622
1756
|
// rc session. Shape-gated identically to /public-spawn so a body-controlled
|
|
1623
1757
|
// value cannot reach the child env. Absent on channel-admin / LinkedIn.
|
|
@@ -1687,6 +1821,27 @@ export function buildHttpApp(deps) {
|
|
|
1687
1821
|
timed(deps.logger, 'POST', '/rc-spawn', 400, Date.now() - start);
|
|
1688
1822
|
return c.json({ error: 'sessionId must be a v4 UUID' }, 400);
|
|
1689
1823
|
}
|
|
1824
|
+
// Task 876 — re-seat fork validation. The fork needs a pre-minted target
|
|
1825
|
+
// id that does NOT yet exist, a shape-valid model, and a source whose
|
|
1826
|
+
// transcript exists (history to copy). Any failure → 400, no spawn.
|
|
1827
|
+
if (forkFromSessionId !== null) {
|
|
1828
|
+
if (sessionId === null) {
|
|
1829
|
+
timed(deps.logger, 'POST', '/rc-spawn', 400, Date.now() - start);
|
|
1830
|
+
return c.json({ error: 're-seat requires a pre-minted sessionId' }, 400);
|
|
1831
|
+
}
|
|
1832
|
+
if (reseatModel === null) {
|
|
1833
|
+
timed(deps.logger, 'POST', '/rc-spawn', 400, Date.now() - start);
|
|
1834
|
+
return c.json({ error: 're-seat requires a valid model' }, 400);
|
|
1835
|
+
}
|
|
1836
|
+
if (!findExistingJsonlForSessionId(deps.claudeConfigDir, forkFromSessionId)) {
|
|
1837
|
+
timed(deps.logger, 'POST', '/rc-spawn', 400, Date.now() - start);
|
|
1838
|
+
return c.json({ error: 're-seat source has no transcript' }, 400);
|
|
1839
|
+
}
|
|
1840
|
+
if (findExistingJsonlForSessionId(deps.claudeConfigDir, sessionId)) {
|
|
1841
|
+
timed(deps.logger, 'POST', '/rc-spawn', 400, Date.now() - start);
|
|
1842
|
+
return c.json({ error: 're-seat target id already exists' }, 400);
|
|
1843
|
+
}
|
|
1844
|
+
}
|
|
1690
1845
|
// Task 702 — never run two processes on one sessionId. If we already own a
|
|
1691
1846
|
// live PTY for this id, the spawn is a no-op (a bridge that lost its
|
|
1692
1847
|
// in-memory index after a restart re-asks; the live PTY takes the next
|
|
@@ -1728,8 +1883,16 @@ export function buildHttpApp(deps) {
|
|
|
1728
1883
|
const argv = ['--remote-control'];
|
|
1729
1884
|
if (name)
|
|
1730
1885
|
argv.push(name);
|
|
1731
|
-
|
|
1886
|
+
// Task 876 — a re-seat forks the source onto the pre-minted target id; the
|
|
1887
|
+
// ordinary fresh/resume single-id push is replaced by the fork segment.
|
|
1888
|
+
if (forkFromSessionId !== null && reseatModel !== null && sessionId) {
|
|
1889
|
+
argv.push(...forkArgvSegment(forkFromSessionId, sessionId, reseatModel));
|
|
1890
|
+
// Task 879 — authoritative current-model signal for the fork only.
|
|
1891
|
+
argv.push('--append-system-prompt', reseatIdentityPrompt(reseatModel));
|
|
1892
|
+
}
|
|
1893
|
+
else if (sessionId) {
|
|
1732
1894
|
argv.push(mode === 'resume' ? '--resume' : '--session-id', sessionId);
|
|
1895
|
+
}
|
|
1733
1896
|
// Task 592 — per-spawn bypass-permissions waiver. The brand settings.json
|
|
1734
1897
|
// carries `defaultMode: bypassPermissions` (Task 583); without this flag
|
|
1735
1898
|
// the first-time "WARNING: … 1. No, exit 2. Yes, I accept" disclaimer
|
|
@@ -2250,6 +2413,35 @@ export function buildHttpApp(deps) {
|
|
|
2250
2413
|
// unit driven by node-pty; the operator-visible spawnMethod marker
|
|
2251
2414
|
// is kept stable so server.log greps survive the Task 573 cleanup.
|
|
2252
2415
|
deps.logger(`[sessions-rc-resume] mode=${mode} sessionId=${sessionId ?? 'none'} jsonlPath=${existingJsonlPath ?? 'none'} name=${name ?? 'none'} spawnedPid=${pty.pid} bridgeId=${bridgeSessionId ?? 'pending'} spawnMethod=systemd-scope env.CLAUDE_CONFIG_DIR=${deps.claudeConfigDir}`);
|
|
2416
|
+
// Task 876 — re-seat post-bind. Once the fork is bound: (1) arm the
|
|
2417
|
+
// one-shot observer so the post-condition line emits on the fork's first
|
|
2418
|
+
// real turn, and (2) best-effort stop the source session's live PTY — the
|
|
2419
|
+
// operator has explicitly moved off it (the removed-model case has no live
|
|
2420
|
+
// PTY, so the stop is a no-op there). Neither must fail the response.
|
|
2421
|
+
if (forkFromSessionId !== null && reseatModel !== null && sessionId && outcome === 'bound') {
|
|
2422
|
+
const sourceJsonl = findExistingJsonlForSessionId(deps.claudeConfigDir, forkFromSessionId);
|
|
2423
|
+
const fromModel = sourceJsonl ? lastRealAssistantModel(sourceJsonl) : null;
|
|
2424
|
+
attachReseatObserve(deps, sessionId, { fromModel, toModel: reseatModel, oldSessionId: forkFromSessionId });
|
|
2425
|
+
try {
|
|
2426
|
+
const source = deps.watcher.getBySessionId(forkFromSessionId);
|
|
2427
|
+
if (source && source.scopeUnitToken) {
|
|
2428
|
+
await stopSession({
|
|
2429
|
+
killGraceMs: deps.killGraceMs,
|
|
2430
|
+
logger: deps.logger,
|
|
2431
|
+
runSystemctl: deps.runSystemctl,
|
|
2432
|
+
rowScopeUnitToken: source.scopeUnitToken,
|
|
2433
|
+
rowPid: source.pid,
|
|
2434
|
+
}, forkFromSessionId);
|
|
2435
|
+
deps.logger(`[webchat:reseat] op=old-session-stop old-session=${forkFromSessionId} result=stopped`);
|
|
2436
|
+
}
|
|
2437
|
+
else {
|
|
2438
|
+
deps.logger(`[webchat:reseat] op=old-session-stop old-session=${forkFromSessionId} result=absent`);
|
|
2439
|
+
}
|
|
2440
|
+
}
|
|
2441
|
+
catch (err) {
|
|
2442
|
+
deps.logger(`[webchat:reseat] op=old-session-stop old-session=${forkFromSessionId} result=error err=${JSON.stringify(err instanceof Error ? err.message : String(err))}`);
|
|
2443
|
+
}
|
|
2444
|
+
}
|
|
2253
2445
|
timed(deps.logger, 'POST', '/rc-spawn', 200, Date.now() - start);
|
|
2254
2446
|
// `slug` is the Task 648 canonical field the client navigates by;
|
|
2255
2447
|
// `bridgeSessionId` is the same value, retained so pre-648 consumers and
|