mulmoterminal 4.27.0 → 5.0.1
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/README.md +14 -0
- package/common/codeBlocks.ts +33 -4
- package/common/transcriptView.ts +78 -0
- package/dist/assets/{AllPackages-B1YCJRYB-D1H--dDi.js → AllPackages-B1YCJRYB-4WQ_EIrl.js} +1 -1
- package/dist/assets/{BaseConfiguration-B6s_tKOW-NM1em0z-.js → BaseConfiguration-B6s_tKOW-CuXGj6gD.js} +1 -1
- package/dist/assets/{Element-BMI7Nj5w-D60lwUcy.js → Element-BMI7Nj5w-Bik3AfgD.js} +1 -1
- package/dist/assets/{Entities-C8p_0jCn-CRrh9My2.js → Entities-C8p_0jCn-CjiJEF3r.js} +1 -1
- package/dist/assets/{FunctionList-YWk54TCy-DxlXvxS1.js → FunctionList-YWk54TCy-Dq1GQL-M.js} +1 -1
- package/dist/assets/{InputJax-C5dj-ntL-DMM7A5J_.js → InputJax-C5dj-ntL-DEjnMcSa.js} +1 -1
- package/dist/assets/{MathItem-YJvQL-XJ-DjZ8sLcx.js → MathItem-YJvQL-XJ-pMaMH7Pe.js} +1 -1
- package/dist/assets/{MmlFactory-DSoKkE7s-BVH8BvMO.js → MmlFactory-DSoKkE7s-BTFYdeyR.js} +1 -1
- package/dist/assets/{Options-oARQeeuT-CeIzK2vQ.js → Options-oARQeeuT-DN-QpMwi.js} +1 -1
- package/dist/assets/{OutputJax-DfUZNNCu-BipoI_Vx.js → OutputJax-DfUZNNCu-0eNVVspA.js} +1 -1
- package/dist/assets/{PrioritizedList-6lun1Xqd-CkxjdTLH.js → PrioritizedList-6lun1Xqd-B3xDwkAm.js} +1 -1
- package/dist/assets/{Styles-5NmwS-3M-CuS-cAHH.js → Styles-5NmwS-3M-CYH8SIw8.js} +1 -1
- package/dist/assets/{TeXAtom-B5ni9myz-jvVqbY5R.js → TeXAtom-B5ni9myz-B2Lg1OeP.js} +1 -1
- package/dist/assets/{abnfDiagram-VCTEODGH-BGhi-oVb-DdAoBuDS.js → abnfDiagram-VCTEODGH-BGhi-oVb-rfnIw5mF.js} +1 -1
- package/dist/assets/{arc-CK5ru50N-ByhquzQA.js → arc-CK5ru50N-CpwYDtFh.js} +1 -1
- package/dist/assets/architecture-7GRP2DOG-otSkCkT5-BXYe9Y4x.js +1 -0
- package/dist/assets/{architectureDiagram-5GKGNRK7-ELuPYMlf-BMar3__r.js → architectureDiagram-5GKGNRK7-ELuPYMlf-jRFBK2xY.js} +1 -1
- package/dist/assets/{assistive-mml-CdU3rUpx-CvEGUtQr.js → assistive-mml-CdU3rUpx-CfM4F5jW.js} +1 -1
- package/dist/assets/{blockDiagram-I7D4REHJ-BZ7-OGWQ-CzYqZh-X.js → blockDiagram-I7D4REHJ-BZ7-OGWQ-GPkhdnf1.js} +1 -1
- package/dist/assets/{c4Diagram-7LVT6UL2-DCovPZ_4-DVY6zyiz.js → c4Diagram-7LVT6UL2-DCovPZ_4-DlgnltG1.js} +1 -1
- package/dist/assets/channel-Bmu_OOc6-Byl1e1Rn.js +1 -0
- package/dist/assets/{chunk-4HAMMTFA-DqpzLmar-7_4tQ0bg.js → chunk-4HAMMTFA-DqpzLmar-BYwab83k.js} +1 -1
- package/dist/assets/{chunk-75Z2AOVW-CT5TYzp5-CXC4AdVC.js → chunk-75Z2AOVW-CT5TYzp5-BRr2sap2.js} +1 -1
- package/dist/assets/{chunk-DU6HZSFF-BVf-rtdf-B3kg-yCL.js → chunk-DU6HZSFF-BVf-rtdf-BiTD5bH2.js} +1 -1
- package/dist/assets/{chunk-F27PBJKO-rP8pUsk3-BfNwyFPK.js → chunk-F27PBJKO-rP8pUsk3-jZL8tnaO.js} +1 -1
- package/dist/assets/{chunk-IMKFNOWR-D_IT0r3G-C9_8s332.js → chunk-IMKFNOWR-D_IT0r3G-4Na8DCGZ.js} +1 -1
- package/dist/assets/{chunk-POPQ4Y6H-C5YURnHe-eTW1aY6b.js → chunk-POPQ4Y6H-C5YURnHe-BtvIAZQ9.js} +1 -1
- package/dist/assets/{chunk-SHT3W25Y-CfF0J8Qh-v6mzVzMd.js → chunk-SHT3W25Y-CfF0J8Qh-CSKY6pei.js} +1 -1
- package/dist/assets/{chunk-SVP7TREG-CTZbRIbX-RW-t42ub.js → chunk-SVP7TREG-CTZbRIbX-DXmyUlG6.js} +1 -1
- package/dist/assets/{chunk-TICWLB2K-DP1lYmZm-7dMJ2TPj.js → chunk-TICWLB2K-DP1lYmZm-2WQGl4am.js} +1 -1
- package/dist/assets/{chunk-XXDRQBXY-vg0kfC73-DuFfjK1v.js → chunk-XXDRQBXY-vg0kfC73-BNbpCBp8.js} +1 -1
- package/dist/assets/classDiagram-ZZMXUADV-BDQOAOBf-DGA1_qS0.js +1 -0
- package/dist/assets/classDiagram-v2-VYDZK3BY-CwPXtzoF-DGA1_qS0.js +1 -0
- package/dist/assets/{cose-bilkent-JH36ORCC-qIiD3RGD-DrmynCpE.js → cose-bilkent-JH36ORCC-qIiD3RGD-glIzrMsu.js} +1 -1
- package/dist/assets/cynefin-OW5HDTMX-Xr6IPdZG-DCyyQmwN.js +1 -0
- package/dist/assets/{cynefinDiagram-5FMLGOSQ-BZrUCS-v-CKIcLifI.js → cynefinDiagram-5FMLGOSQ-BZrUCS-v-BP9iYDiL.js} +1 -1
- package/dist/assets/{dagre-C2SZ8h4o-DcuFxdj9.js → dagre-C2SZ8h4o-Cvn7MMN8.js} +1 -1
- package/dist/assets/{dagre-GXQ25YYZ-CQcLM4na-DHXn50pv.js → dagre-GXQ25YYZ-CQcLM4na-CUPIues9.js} +1 -1
- package/dist/assets/{diagram-S7CK7UJ4-BdmcmUQh-CPCAAKMD.js → diagram-S7CK7UJ4-BdmcmUQh-BzmDaJl4.js} +1 -1
- package/dist/assets/{diagram-UQ7AKVKN-BtvmEiYl-aA6cOCqA.js → diagram-UQ7AKVKN-BtvmEiYl-C-SDkeQT.js} +1 -1
- package/dist/assets/{diagram-VSXAHHWV-qEG6N0bV-DCHB2hTq.js → diagram-VSXAHHWV-qEG6N0bV-BBEGoVq0.js} +1 -1
- package/dist/assets/{diagram-VX7I27RA-BA8is49N-DOwC18Z0.js → diagram-VX7I27RA-BA8is49N-C_RijuTO.js} +1 -1
- package/dist/assets/{diagram-Z3DM3KII-XPcU7IOQ-C9RPVYC4.js → diagram-Z3DM3KII-XPcU7IOQ-CxOwdwHR.js} +1 -1
- package/dist/assets/{dist-v-Rpnm_y.js → dist-BvG2w_9k.js} +1 -1
- package/dist/assets/{dist-wvHglY68.js → dist-CWF1S7vL.js} +1 -1
- package/dist/assets/{dist-fO6jnnrd.js → dist-DBRVDw9D.js} +1 -1
- package/dist/assets/{dist-DeiyD9Ki-CJ4cIe6S.js → dist-DeiyD9Ki-BDcmanZh.js} +1 -1
- package/dist/assets/{dist-CZghBWKw.js → dist-uQlE_JYp.js} +1 -1
- package/dist/assets/{ebnfDiagram-PWID7BFC-CTHIHdBS-DHkqIR3N.js → ebnfDiagram-PWID7BFC-CTHIHdBS-BGwyAx_X.js} +1 -1
- package/dist/assets/{erDiagram-RLTQ6QDP-DVpWTNZj-C3lwqnXe.js → erDiagram-RLTQ6QDP-DVpWTNZj-CpwnuTPx.js} +1 -1
- package/dist/assets/eventmodeling-NTZA5JFV-B7bRrpt_-DWVjLwmJ.js +1 -0
- package/dist/assets/flowDiagram-HODETNUW-r-3T5g30-CjAJJOoL.js +1 -0
- package/dist/assets/{ganttDiagram-EL5Y4UJY-BfAgk15F-2NYwYOby.js → ganttDiagram-EL5Y4UJY-BfAgk15F-CuhMMDMU.js} +1 -1
- package/dist/assets/gitGraph-4MIJSDKK-BhzSx5wq-CmU_NC2u.js +1 -0
- package/dist/assets/{gitGraphDiagram-WWUBYQGX-DEVVZ6wt-k0BkI3nD.js → gitGraphDiagram-WWUBYQGX-DEVVZ6wt-Bh_VaB4G.js} +1 -1
- package/dist/assets/{graphlib-BYLhHyYO-Bdiyyely.js → graphlib-BYLhHyYO-BCQclP1Y.js} +1 -1
- package/dist/assets/{html-Z7dGbczU-BTiRsVw0.js → html-Z7dGbczU-UIlR1xAp.js} +1 -1
- package/dist/assets/index-DgdW3UkV.css +1 -0
- package/dist/assets/{index-6GNSSCav.js → index-sxsMmFcI.js} +300 -298
- package/dist/assets/info-A6RAGUB7-fR2SUJmJ-Dc6y50d4.js +1 -0
- package/dist/assets/{infoDiagram-27XIBGKW-CvHUhAHd-CrTJpCqo.js → infoDiagram-27XIBGKW-CvHUhAHd-DigY259e.js} +1 -1
- package/dist/assets/{ishikawaDiagram-5VMMS53U-CeqyKdwk-eDLXPEBD.js → ishikawaDiagram-5VMMS53U-CeqyKdwk-ACmU-Jzv.js} +1 -1
- package/dist/assets/{journeyDiagram-3NMN7TZE-Jfi7MPDi-CvhaSk4y.js → journeyDiagram-3NMN7TZE-Jfi7MPDi-YIFwpJyP.js} +1 -1
- package/dist/assets/{kanban-definition-UXKFOSKX-yOrlojns-C2SZht6T.js → kanban-definition-UXKFOSKX-yOrlojns-0RXVl3u9.js} +1 -1
- package/dist/assets/{lengths-CvmPfBid-DqArahpv.js → lengths-CvmPfBid-BAfNjGrF.js} +1 -1
- package/dist/assets/{linear-jdmEy-qs-Cv8NGHBd.js → linear-jdmEy-qs-Djjlqhox.js} +1 -1
- package/dist/assets/{liteAdaptor-pH5MXTG0-B1LIDixs.js → liteAdaptor-pH5MXTG0-pAc8cmKr.js} +1 -1
- package/dist/assets/material-symbols-outlined-Dp0GkOHZ.woff2 +0 -0
- package/dist/assets/{mathjax-DVEo4UYj-CTQSsbqK.js → mathjax-DVEo4UYj-Cnj1zcS1.js} +1 -1
- package/dist/assets/{mermaid-parser.core-CzBW8Fof-BTOBTXVI.js → mermaid-parser.core-CzBW8Fof-s3bWPn0O.js} +2 -2
- package/dist/assets/{mermaid.core-Dv4uylek-CwMi65mG.js → mermaid.core-Dv4uylek-DqGXjOPu.js} +4 -4
- package/dist/assets/{mindmap-definition-YA3MSWOX-DP_2R9Ga-BJ9md154.js → mindmap-definition-YA3MSWOX-DP_2R9Ga-KrOUlEvG.js} +1 -1
- package/dist/assets/{mo-Xv_6CC7A-YT1Ep9ep.js → mo-Xv_6CC7A-5T19MjVl.js} +1 -1
- package/dist/assets/packet-AYTQ26CC-B_oKR9KZ-DzcrK2qY.js +1 -0
- package/dist/assets/{pegDiagram-XKGWAZYB-BsBWryhi-DcmWmYCC.js → pegDiagram-XKGWAZYB-BsBWryhi-DYwgFu60.js} +1 -1
- package/dist/assets/pie-WAS4IAKB-D1ZXrN1W-EXLeDSJc.js +1 -0
- package/dist/assets/{pieDiagram-E7YTZNPT-OugkS2pU-cVOrSsmv.js → pieDiagram-E7YTZNPT-OugkS2pU-CitvFGku.js} +1 -1
- package/dist/assets/{quadrantDiagram-AXDQQJYC-DXEAAaUE-CJ7E8xF3.js → quadrantDiagram-AXDQQJYC-DXEAAaUE-BJz-5fWN.js} +1 -1
- package/dist/assets/radar-RG4KPBEZ-BmUgDkiH-CYsT6Q2i.js +1 -0
- package/dist/assets/railroad-74A4TZTK-6lEXVJo8-CGKkcPl-.js +1 -0
- package/dist/assets/railroad-abnf-HS5TGJTU-BG28Qiz1-CX4pHVjI.js +1 -0
- package/dist/assets/railroad-ebnf-LZEXJU2U-DzpHhtTH-DuFCuwxK.js +1 -0
- package/dist/assets/railroad-peg-WCYAUIDC-B2CHCTyG-BZCRCTz5.js +1 -0
- package/dist/assets/{railroadDiagram-O6MQD6OU-BJys8O96-0MKi1nlY.js → railroadDiagram-O6MQD6OU-BJys8O96-8S8j18MZ.js} +1 -1
- package/dist/assets/{requirementDiagram-BXWQKSXE-BaDgCtM5-Dh9naf1P.js → requirementDiagram-BXWQKSXE-BaDgCtM5-D0sLbDHs.js} +1 -1
- package/dist/assets/{sankeyDiagram-P5KCCOFB-puZsr_vK-DnFp1pF-.js → sankeyDiagram-P5KCCOFB-puZsr_vK-C1OX3N7F.js} +1 -1
- package/dist/assets/{sequenceDiagram-WJ2MYXX4-D1ziEryC-QyuuTtv6.js → sequenceDiagram-WJ2MYXX4-D1ziEryC-CvoJhcsM.js} +1 -1
- package/dist/assets/{src-CLC0ddSd-DaM5Q5tg.js → src-CLC0ddSd-D-EBSy-7.js} +1 -1
- package/dist/assets/{stateDiagram-D77RDMKH-HSEurT6h-CqWtYwN6.js → stateDiagram-D77RDMKH-HSEurT6h-DWNnPlrT.js} +1 -1
- package/dist/assets/stateDiagram-v2-MP3YSRHH-DnOa-Otc-jwvolGHy.js +1 -0
- package/dist/assets/{svg-D_RYJvQC-T-beFXEZ.js → svg-D_RYJvQC-xxS_UOMd.js} +1 -1
- package/dist/assets/{swimlanes-42K2YHIH-umBsuvsI-CBrrgPel.js → swimlanes-42K2YHIH-umBsuvsI-BE4MiInp.js} +1 -1
- package/dist/assets/swimlanesDiagram-VR7AAH4N-ZLUyNmnU-DNoFZykH.js +8 -0
- package/dist/assets/{tex-Dx2UJ3VU-tBwETaM2.js → tex-Dx2UJ3VU-Bvt244KZ.js} +1 -1
- package/dist/assets/{timeline-definition-24CTP7MA-D9plt22Y-XpXWZKjL.js → timeline-definition-24CTP7MA-D9plt22Y-DHwEP0-q.js} +1 -1
- package/dist/assets/treeView-Q6P3EWNA-BdvZ0_C5-Cw7gALPI.js +1 -0
- package/dist/assets/treemap-WGGIJYW6-CIJLPQlC-BuBwqHqi.js +1 -0
- package/dist/assets/{vennDiagram-4TSXK5OY-DZe7wY85-BX7eqUQe.js → vennDiagram-4TSXK5OY-DZe7wY85-BzqCxOQu.js} +1 -1
- package/dist/assets/wardley-WFR3VGLG-CKqtFD8V-Ds6_n_M_.js +1 -0
- package/dist/assets/{wardleyDiagram-VM6X3IG4-DK9yytWx-Dwg2gU8u.js → wardleyDiagram-VM6X3IG4-DK9yytWx-FK9bW_eQ.js} +1 -1
- package/dist/assets/{xychartDiagram-S5SC5T6Z-CLSO4Pc9-D0s7XGBw.js → xychartDiagram-S5SC5T6Z-CLSO4Pc9-BGF6axe4.js} +1 -1
- package/dist/index.html +2 -2
- package/package.json +1 -1
- package/server/agents/copilot-sessions.ts +12 -4
- package/server/agents/sqlite-read.ts +1 -1
- package/server/backends/remoteHost/handlers/deps.ts +1 -1
- package/server/backends/remoteHost/handlers.spec.ts +1 -1
- package/server/infra/jsonl-file.ts +13 -3
- package/server/routes/app-routes.ts +1 -1
- package/server/routes/session-routes.ts +33 -0
- package/server/session/transcript-view-codex.ts +4 -3
- package/server/session/transcript-view-copilot.ts +11 -9
- package/server/session/transcript-view-cursor.ts +3 -2
- package/server/session/transcript-view-read.ts +298 -45
- package/server/session/transcript-view.ts +47 -43
- package/dist/assets/architecture-7GRP2DOG-otSkCkT5-Zckz-s0E.js +0 -1
- package/dist/assets/channel-Bmu_OOc6-Dl37yKXs.js +0 -1
- package/dist/assets/classDiagram-ZZMXUADV-BDQOAOBf-DSv4U5yn.js +0 -1
- package/dist/assets/classDiagram-v2-VYDZK3BY-CwPXtzoF-DSv4U5yn.js +0 -1
- package/dist/assets/cynefin-OW5HDTMX-Xr6IPdZG-BOI4Ydck.js +0 -1
- package/dist/assets/eventmodeling-NTZA5JFV-B7bRrpt_-aX72rk9t.js +0 -1
- package/dist/assets/flowDiagram-HODETNUW-r-3T5g30-BJR3huwZ.js +0 -1
- package/dist/assets/gitGraph-4MIJSDKK-BhzSx5wq-D7vu6KLb.js +0 -1
- package/dist/assets/index-C4KnFBMJ.css +0 -1
- package/dist/assets/info-A6RAGUB7-fR2SUJmJ-CeXI1IP4.js +0 -1
- package/dist/assets/material-symbols-outlined-DhPLOrnb.woff2 +0 -0
- package/dist/assets/packet-AYTQ26CC-B_oKR9KZ-BTHvzsvA.js +0 -1
- package/dist/assets/pie-WAS4IAKB-D1ZXrN1W-D2lL43qt.js +0 -1
- package/dist/assets/radar-RG4KPBEZ-BmUgDkiH-C-pMUxsI.js +0 -1
- package/dist/assets/railroad-74A4TZTK-6lEXVJo8-D0K7WIF_.js +0 -1
- package/dist/assets/railroad-abnf-HS5TGJTU-BG28Qiz1-BwwZFdLC.js +0 -1
- package/dist/assets/railroad-ebnf-LZEXJU2U-DzpHhtTH-DEXLsLfR.js +0 -1
- package/dist/assets/railroad-peg-WCYAUIDC-B2CHCTyG-CIIHCbpi.js +0 -1
- package/dist/assets/stateDiagram-v2-MP3YSRHH-DnOa-Otc-DqMPmDPL.js +0 -1
- package/dist/assets/swimlanesDiagram-VR7AAH4N-ZLUyNmnU-Bew5AEPR.js +0 -8
- package/dist/assets/treeView-Q6P3EWNA-BdvZ0_C5-BheZ-W3N.js +0 -1
- package/dist/assets/treemap-WGGIJYW6-CIJLPQlC-Cjamu2ad.js +0 -1
- package/dist/assets/wardley-WFR3VGLG-CKqtFD8V-BhmuAvdu.js +0 -1
package/README.md
CHANGED
|
@@ -1641,6 +1641,20 @@ narrow and tall for one record you are discussing — and each position keeps it
|
|
|
1641
1641
|
prompt history, codex's rollout), so a prompt sent mid-turn is there and text a skill
|
|
1642
1642
|
injected is not. A `/clear` draws a line: the pane shows what you have asked *since*, the
|
|
1643
1643
|
same way the header, the title and the last reply all stop describing the ended conversation.
|
|
1644
|
+
- **Conversation pane** — the enlarged cell's conversation, read as TURNS rather than as the
|
|
1645
|
+
screen, from `GET /api/transcript/view`. A Claude cell runs on the alternate screen, so the
|
|
1646
|
+
terminal keeps no scrollback worth scrolling; this reads the agent's own transcript instead,
|
|
1647
|
+
and **scrolling up walks the session back to its first turn**, a page at a time.
|
|
1648
|
+
- It **takes the terminal's place when you open it** — the one pane that does, because reading
|
|
1649
|
+
is its whole subject. The expand button puts the terminal back beside it.
|
|
1650
|
+
- **A frame per speaker**: what you asked in one, what the agent answered in another, named
|
|
1651
|
+
("You" / "Claude"). The reply is **rendered markdown** — headings, lists, tables, fenced
|
|
1652
|
+
code — not the characters it is written with.
|
|
1653
|
+
- **Tool traffic is folded away**, one line saying what ran (`Bash · Read`); click to open it.
|
|
1654
|
+
It is most of a turn's bulk and almost none of what you came back to read.
|
|
1655
|
+
- A **snapshot**, not a live tail — the terminal beside it is the live view — and the header's
|
|
1656
|
+
reload fetches the newest turns again. Claude, Codex, Cursor and Copilot; an agent whose
|
|
1657
|
+
conversation no reader here can read yet says so rather than showing an empty pane.
|
|
1644
1658
|
- **Notifications** (🔔) — a toolbar bell with an unread badge and a dropdown of active
|
|
1645
1659
|
notifications; click a row to jump to its session.
|
|
1646
1660
|
- **Star MulmoTerminal** — a star button in the grid toolbar that stars the project on GitHub
|
package/common/codeBlocks.ts
CHANGED
|
@@ -55,9 +55,31 @@ const closes = (line: string, opener: string): boolean => {
|
|
|
55
55
|
return !!fence && fence.run[0] === opener[0] && fence.run.length >= opener.length && fence.info.trim() === "";
|
|
56
56
|
};
|
|
57
57
|
|
|
58
|
-
|
|
58
|
+
/** A run of prose, or one fenced block — the whole text, in order and with nothing dropped.
|
|
59
|
+
*
|
|
60
|
+
* This is the ONE walk over the fences, and `fencedBlocks` below is it with the prose dropped. It
|
|
61
|
+
* is not a second scanner: the two used to be separate loops over the same rules, which is two
|
|
62
|
+
* places for a fence rule to drift.
|
|
63
|
+
*
|
|
64
|
+
* It is deliberately not tied to any one reader. The transcript pane rendered its segments for a
|
|
65
|
+
* while and now renders the reply as markdown instead (#2112); saying otherwise here sends the next
|
|
66
|
+
* reader looking for a consumer that no longer exists (Claude review, round 1). */
|
|
67
|
+
export type MarkdownSegment = { kind: "text"; text: string } | { kind: "code"; lang: string | null; body: string };
|
|
68
|
+
|
|
69
|
+
/** The one walk over the fences. `fencedBlocks` is this with the prose dropped.
|
|
70
|
+
*
|
|
71
|
+
* Prose runs are joined with the newlines they had, so a run's own blank lines survive; a segment
|
|
72
|
+
* is emitted only when it has a line in it, so an input that opens with a fence does not lead with
|
|
73
|
+
* an empty one. */
|
|
74
|
+
export function markdownSegments(markdown: string): MarkdownSegment[] {
|
|
59
75
|
const lines = markdown.split("\n");
|
|
60
|
-
const
|
|
76
|
+
const segments: MarkdownSegment[] = [];
|
|
77
|
+
const prose: string[] = [];
|
|
78
|
+
const flushProse = (): void => {
|
|
79
|
+
if (prose.length === 0) return;
|
|
80
|
+
segments.push({ kind: "text", text: prose.join("\n") });
|
|
81
|
+
prose.length = 0;
|
|
82
|
+
};
|
|
61
83
|
let i = 0;
|
|
62
84
|
// Each line is read into a const before use: with noUncheckedIndexedAccess, `lines[i]` is
|
|
63
85
|
// `string | undefined` even inside `i < lines.length`, and the loop condition is what actually
|
|
@@ -66,9 +88,11 @@ export function fencedBlocks(markdown: string): FencedBlock[] {
|
|
|
66
88
|
const line = lines[i];
|
|
67
89
|
const open = line === undefined ? null : fenceOf(line);
|
|
68
90
|
if (!open) {
|
|
91
|
+
if (line !== undefined) prose.push(line);
|
|
69
92
|
i++;
|
|
70
93
|
continue;
|
|
71
94
|
}
|
|
95
|
+
flushProse();
|
|
72
96
|
const fence = open.run;
|
|
73
97
|
const info = open.info.trim();
|
|
74
98
|
const body: string[] = [];
|
|
@@ -78,9 +102,14 @@ export function fencedBlocks(markdown: string): FencedBlock[] {
|
|
|
78
102
|
i++;
|
|
79
103
|
}
|
|
80
104
|
i++; // step over the closing fence (or past the end, for an unclosed block)
|
|
81
|
-
|
|
105
|
+
segments.push({ kind: "code", lang: info ? (info.split(/\s+/)[0]?.toLowerCase() ?? null) : null, body: body.join("\n") });
|
|
82
106
|
}
|
|
83
|
-
|
|
107
|
+
flushProse();
|
|
108
|
+
return segments;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export function fencedBlocks(markdown: string): FencedBlock[] {
|
|
112
|
+
return markdownSegments(markdown).flatMap((segment) => (segment.kind === "code" ? [{ lang: segment.lang, body: segment.body }] : []));
|
|
84
113
|
}
|
|
85
114
|
|
|
86
115
|
/** The block a reader means by "the code you just gave me": the last one. Null when the reply
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
// What a hosted agent's conversation looks like ON THE WIRE.
|
|
2
|
+
//
|
|
3
|
+
// In `common/` because both ends decide from it: the host folds an agent's JSONL (or copilot's
|
|
4
|
+
// table) into these shapes in `server/session/transcript-view.ts`, and two clients render them —
|
|
5
|
+
// the phone's terminal detail page over the remoteHost socket, and the browser's transcript pane
|
|
6
|
+
// over `/api/transcript/view`. Mirroring the shape into `src/` would let one side gain a status the
|
|
7
|
+
// other silently renders as nothing.
|
|
8
|
+
//
|
|
9
|
+
// The RULES that produce these — the turn boundary, the line budget, the tool-result cap — stay on
|
|
10
|
+
// the server. This file is the vocabulary, not the folding.
|
|
11
|
+
|
|
12
|
+
export type TranscriptRowKind = "user" | "assistant" | "tool" | "unknown";
|
|
13
|
+
|
|
14
|
+
/** One content block, rendered.
|
|
15
|
+
*
|
|
16
|
+
* `text` may itself contain newlines — an assistant answer is passed through whole, because the
|
|
17
|
+
* wrapping belongs to the client's CSS and not to a host that cannot know its width.
|
|
18
|
+
*
|
|
19
|
+
* `clipped` says THIS row's text was cut, which is a different fact from `TranscriptView.truncated`
|
|
20
|
+
* (a whole turn was dropped). Naming them the same word would leave the client unable to decide
|
|
21
|
+
* which mark to draw. */
|
|
22
|
+
export interface TranscriptRow {
|
|
23
|
+
kind: TranscriptRowKind;
|
|
24
|
+
text: string;
|
|
25
|
+
clipped?: boolean;
|
|
26
|
+
/** This tool row is the CALL — the tool's name and the head of its arguments — rather than what
|
|
27
|
+
* the tool answered (#2112).
|
|
28
|
+
*
|
|
29
|
+
* Said by the host because only the host can say it: both halves arrive as `kind: "tool"`, and a
|
|
30
|
+
* client telling them apart by shape ("short and single-line means a name") is guessing about
|
|
31
|
+
* four agents' output at once. A pane that collapses tool traffic needs it to label the fold with
|
|
32
|
+
* what RAN — the part a reader is looking for when they open it again. */
|
|
33
|
+
call?: boolean;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** One exchange: a user prompt and everything that followed it.
|
|
37
|
+
*
|
|
38
|
+
* `at` is the BOUNDARY record's own timestamp — the moment the turn started — or null when it is
|
|
39
|
+
* not a string. Null rather than dropping the turn: a turn is worth more than its clock. */
|
|
40
|
+
export interface TranscriptTurn {
|
|
41
|
+
at: string | null;
|
|
42
|
+
rows: TranscriptRow[];
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** What the host answers. A discriminated union rather than "readable: boolean": "no transcript
|
|
46
|
+
* yet", "the conversation was ended with /clear" and "too big to find a turn in" are three
|
|
47
|
+
* different things to tell a person, and one boolean collapses them into the same blank view. */
|
|
48
|
+
export type TranscriptView =
|
|
49
|
+
| { status: "ok"; turns: TranscriptTurn[]; truncated: boolean }
|
|
50
|
+
| { status: "none" }
|
|
51
|
+
| { status: "cleared" }
|
|
52
|
+
| { status: "too-large" }
|
|
53
|
+
/** This session's agent keeps a conversation somewhere, and no reader here can read it yet
|
|
54
|
+
* (#1822). A DIFFERENT fact from `none`, which means "this session has written nothing we can
|
|
55
|
+
* find" — the phone falls back to the screen for both, but only one of them is worth a sentence
|
|
56
|
+
* to a person, and only one of them is a thing to go and implement.
|
|
57
|
+
*
|
|
58
|
+
* Never answered for a shell or a launcher cell: those have no conversation and never will, so
|
|
59
|
+
* the screen IS their content rather than a fallback from something missing. */
|
|
60
|
+
| { status: "not-supported" };
|
|
61
|
+
|
|
62
|
+
/** One page of a conversation, read backwards from `older` (#2112).
|
|
63
|
+
*
|
|
64
|
+
* The cursor is OPAQUE to the client on purpose: it is a byte offset for the three agents that
|
|
65
|
+
* keep a file and a `turn_index` for the one that keeps a table, and a client that knew which
|
|
66
|
+
* would be deciding something only the host can know. It is handed back verbatim to ask for the
|
|
67
|
+
* page before this one.
|
|
68
|
+
*
|
|
69
|
+
* `older: null` means this page reaches the start of what can be read — either the head of the
|
|
70
|
+
* transcript, or the point past which the host refuses to read (`status: "too-large"`).
|
|
71
|
+
*
|
|
72
|
+
* The view is carried whole rather than flattened in beside the cursor: every non-`ok` status is
|
|
73
|
+
* a sentence the client already knows how to show, and re-deciding them per page is how the two
|
|
74
|
+
* ends drift. */
|
|
75
|
+
export interface TranscriptPage {
|
|
76
|
+
view: TranscriptView;
|
|
77
|
+
older: string | null;
|
|
78
|
+
}
|