mulmoterminal 4.9.0 → 4.10.0

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.
Files changed (148) hide show
  1. package/README.md +39 -15
  2. package/common/machineLoad.ts +64 -0
  3. package/common/showLoadAverage.ts +17 -0
  4. package/dist/assets/{abnfDiagram-N423BO3Z-D0pzqjdS-tsokipTX.js → abnfDiagram-N423BO3Z-D0pzqjdS-BvsHO44n.js} +1 -1
  5. package/dist/assets/architecture-TIHT7OUA-Cqhmai3f-CLCb_c-T.js +1 -0
  6. package/dist/assets/{architectureDiagram-T3A2C74G-CX-Yoe5G-DgpViJOA.js → architectureDiagram-T3A2C74G-CX-Yoe5G-BwAFwV8W.js} +1 -1
  7. package/dist/assets/{blockDiagram-VBNYF7ZC-B1eQZQ68-l6UrEUWt.js → blockDiagram-VBNYF7ZC-B1eQZQ68-BsLub1_h.js} +1 -1
  8. package/dist/assets/{c4Diagram-5PPSVZJV-SBrN9MrU-Bak3wKoW.js → c4Diagram-5PPSVZJV-SBrN9MrU-CZb8utHI.js} +1 -1
  9. package/dist/assets/channel-DKMa7Sn5-Ou3t759d.js +1 -0
  10. package/dist/assets/{chunk-2GRJ4B5K-DdkAx9o--Btdgu33f.js → chunk-2GRJ4B5K-DdkAx9o--BCARbOFt.js} +1 -1
  11. package/dist/assets/{chunk-3NCLNEKW-CBztX243-DSaECkf1.js → chunk-3NCLNEKW-CBztX243-CwupLy1v.js} +1 -1
  12. package/dist/assets/{chunk-4I5QYGJK-CmBJaHzs-B0Cdj__3.js → chunk-4I5QYGJK-CmBJaHzs-Bs_NsidJ.js} +1 -1
  13. package/dist/assets/{chunk-5RXB4S5H-iaipMW_h-DTYhZhRx.js → chunk-5RXB4S5H-iaipMW_h-DXdJa9DX.js} +1 -1
  14. package/dist/assets/{chunk-6Q2QTUOP-Cx8nz5_t-CzxkXkeW.js → chunk-6Q2QTUOP-Cx8nz5_t-KpLSy3XB.js} +1 -1
  15. package/dist/assets/{chunk-7Z6QIM7H-CZs6l8Md-vvG9hcRg.js → chunk-7Z6QIM7H-CZs6l8Md-BaANsP0E.js} +1 -1
  16. package/dist/assets/{chunk-GF5L2VYU-9OEKHEe4-0OT7at6j.js → chunk-GF5L2VYU-9OEKHEe4-TrjUerld.js} +1 -1
  17. package/dist/assets/{chunk-I66GZJ75-DSPCVCny-CcYhEHb5.js → chunk-I66GZJ75-DSPCVCny-DOUjXnuq.js} +1 -1
  18. package/dist/assets/{chunk-J7OUQ5F2-CQoryswr-BPyac73K.js → chunk-J7OUQ5F2-CQoryswr-D9XFzqLS.js} +2 -2
  19. package/dist/assets/{chunk-JQJVKLGR-6F2ui09L-B9WKQa27.js → chunk-JQJVKLGR-6F2ui09L-mfVBAqeN.js} +1 -1
  20. package/dist/assets/{chunk-KBJHAD2P-DXXCSVOS-DTQzS_lP.js → chunk-KBJHAD2P-DXXCSVOS-DwHLxn0S.js} +1 -1
  21. package/dist/assets/{chunk-NSK5VX7P-DQgMj0Kn-DHwNEvsc.js → chunk-NSK5VX7P-DQgMj0Kn-BoNgwYTd.js} +1 -1
  22. package/dist/assets/{chunk-QR6OTTB3-BQl8P7pD-NaScgAMT.js → chunk-QR6OTTB3-BQl8P7pD-DrRFZ-Y0.js} +1 -1
  23. package/dist/assets/{chunk-UBXNYLIW-BbdYEvTI-Cw1DJYdl.js → chunk-UBXNYLIW-BbdYEvTI-BmD3ozr0.js} +1 -1
  24. package/dist/assets/{chunk-W5SLKNZC-DSJLk1SI-2433ih9f.js → chunk-W5SLKNZC-DSJLk1SI-Nylm2ts1.js} +1 -1
  25. package/dist/assets/{chunk-WRU74C26-DOE_TBL8-TwO1OeO3.js → chunk-WRU74C26-DOE_TBL8-C9bmvsn0.js} +1 -1
  26. package/dist/assets/classDiagram-JCYQIIEL-C1ePmEG1-D8OKeA_z.js +1 -0
  27. package/dist/assets/classDiagram-v2-OCEON4UE-C_O3VNBf-D8OKeA_z.js +1 -0
  28. package/dist/assets/cynefin-VYW2F7L2-DvSvuXnG-DMUsZMnb.js +1 -0
  29. package/dist/assets/{cynefinDiagram-MW4NZA55-DuBeESb6-DESaAtqc.js → cynefinDiagram-MW4NZA55-DuBeESb6-DQy8fpqk.js} +1 -1
  30. package/dist/assets/{dagre-VZM6K2ZE-W5cB3U70-CMnlYH3n.js → dagre-VZM6K2ZE-W5cB3U70-RwN_3tbh.js} +1 -1
  31. package/dist/assets/{diagram-7IWD3JNH-Fk1aWqfX-DRcZC0ZJ.js → diagram-7IWD3JNH-Fk1aWqfX-Cwe62lRg.js} +1 -1
  32. package/dist/assets/{diagram-B4RE2ZJO-q-8xygfU-tDoHZfs1.js → diagram-B4RE2ZJO-q-8xygfU-lcnUHOaS.js} +1 -1
  33. package/dist/assets/{diagram-LBJQPF4R-1SKCcOis-D0wi_ISa.js → diagram-LBJQPF4R-1SKCcOis-COQZ8iPL.js} +1 -1
  34. package/dist/assets/{diagram-Q27KOJAE-CtW4StAQ-Dog4fjWc.js → diagram-Q27KOJAE-CtW4StAQ-e68yDEZJ.js} +1 -1
  35. package/dist/assets/{diagram-UB23O5K3-r5fK-tbF-BcyhXO2Z.js → diagram-UB23O5K3-r5fK-tbF-B7rkjSDi.js} +1 -1
  36. package/dist/assets/{dist-DejxKqvO.js → dist-Bg-nVQQu.js} +1 -1
  37. package/dist/assets/{dist-CztsQcLD.js → dist-CaihYBew.js} +1 -1
  38. package/dist/assets/{dist-DZ_5WoC2.js → dist-De-v7q9K.js} +1 -1
  39. package/dist/assets/{dist-DXiBDDNa.js → dist-ZVGiaLdr.js} +1 -1
  40. package/dist/assets/{ebnfDiagram-BXEA7PRR-BZoIqTyx-O2S-Ztbj.js → ebnfDiagram-BXEA7PRR-BZoIqTyx-8fKBdNJd.js} +1 -1
  41. package/dist/assets/{erDiagram-JOGREHBK-CM8pI2JI-ClxE9ArW.js → erDiagram-JOGREHBK-CM8pI2JI-l7PlF8g5.js} +1 -1
  42. package/dist/assets/eventmodeling-45OFAUF4-jdctDg0T-BqpGpJr1.js +1 -0
  43. package/dist/assets/flowDiagram-UKHOOZJN-CR3dcoRl-C_VJVnQC.js +1 -0
  44. package/dist/assets/{ganttDiagram-PKOTCBZU-DYTkxDIh-BWid4w0-.js → ganttDiagram-PKOTCBZU-DYTkxDIh-DW_JRrXN.js} +1 -1
  45. package/dist/assets/gitGraph-TEB2WS4Q-C4cKwl5j-BUtQCHgQ.js +1 -0
  46. package/dist/assets/{gitGraphDiagram-DS77QQ5N-DafidN4D-B2rG9g1c.js → gitGraphDiagram-DS77QQ5N-DafidN4D-CWgu8mad.js} +1 -1
  47. package/dist/assets/{index-CXypRX5w.js → index-CBvtM9Ua.js} +223 -203
  48. package/dist/assets/index-Cmd7HCPm.css +1 -0
  49. package/dist/assets/info-DKCQHKI2-DPUCBYWS-BfrCpjtZ.js +1 -0
  50. package/dist/assets/{infoDiagram-6WML65LV-DxSxsg1o-CBIrfawM.js → infoDiagram-6WML65LV-DxSxsg1o-CUqPCVTg.js} +1 -1
  51. package/dist/assets/{ishikawaDiagram-WSZJBQD7-kAIMMFB5-BUr-KlRN.js → ishikawaDiagram-WSZJBQD7-kAIMMFB5-Dn6LnnS9.js} +1 -1
  52. package/dist/assets/{journeyDiagram-NVQOT4AX-ClybI8XI-CLfVRFK4.js → journeyDiagram-NVQOT4AX-ClybI8XI-BJf0S4qE.js} +1 -1
  53. package/dist/assets/{kanban-definition-27J2QSJJ-DDYHyW1q-BAhFiewn.js → kanban-definition-27J2QSJJ-DDYHyW1q-D0SzsN09.js} +1 -1
  54. package/dist/assets/{lib-F7cE_AFU.js → lib-BKiHN82U.js} +1 -1
  55. package/dist/assets/{line-CtRAsVKI-9L65MT5n.js → line-CtRAsVKI-Dp0NclGV.js} +1 -1
  56. package/dist/assets/{marp-CIsjVw1j.js → marp-1Q8kNVhm.js} +1 -1
  57. package/dist/assets/{mermaid-parser.core-C1baW7NG-BzDlu5Ub.js → mermaid-parser.core-C1baW7NG-C1lkUbAr.js} +2 -2
  58. package/dist/assets/{mermaid.core-CGR3z-ay-CjhO0dwd.js → mermaid.core-CGR3z-ay-C82H1PH-.js} +3 -3
  59. package/dist/assets/{mindmap-definition-FAOFIHXS-DU-wbYKK-BsksvxN4.js → mindmap-definition-FAOFIHXS-DU-wbYKK-5rzb7n6I.js} +1 -1
  60. package/dist/assets/packet-7NZHBO7P-CC7His0F-BzOuQKXH.js +1 -0
  61. package/dist/assets/{pegDiagram-VL7TDLO6-CZuV1UUk-DqhlfAbV.js → pegDiagram-VL7TDLO6-CZuV1UUk-BC4N2Xma.js} +1 -1
  62. package/dist/assets/pie-RZYD4A2V-CCrcq2sL-D9aIUAJO.js +1 -0
  63. package/dist/assets/{pieDiagram-7S7Q4E2Y-B6cd1CWd-BCJp-Agh.js → pieDiagram-7S7Q4E2Y-B6cd1CWd-Bqpk1v8T.js} +1 -1
  64. package/dist/assets/{quadrantDiagram-CIZ2JOQS-BvGHVjRA-D49aYGir.js → quadrantDiagram-CIZ2JOQS-BvGHVjRA-Pag-TAt4.js} +1 -1
  65. package/dist/assets/radar-I7S5WNFK-C5TUrpHf-BMtoxTgP.js +1 -0
  66. package/dist/assets/railroad-3IZDKUUU-CGuuFEd8-b6J7gf_7.js +1 -0
  67. package/dist/assets/railroad-abnf-AHOZXSZD-DuoCSFZY-IJGsdvHy.js +1 -0
  68. package/dist/assets/railroad-ebnf-EBAXGLYW-ig-DG9e_-BjA_DQ8C.js +1 -0
  69. package/dist/assets/railroad-peg-LSFZ7HO6-BkBgpyvu-DDTEG0fo.js +1 -0
  70. package/dist/assets/{railroadDiagram-AXF67PYL-DDtBla5s-K2XHXDJr.js → railroadDiagram-AXF67PYL-DDtBla5s-DPql6jcO.js} +1 -1
  71. package/dist/assets/{requirementDiagram-LRYGKXZP-DEh2MJlW-BSbaLCze.js → requirementDiagram-LRYGKXZP-DEh2MJlW-jVVSfC2R.js} +1 -1
  72. package/dist/assets/{sankeyDiagram-W5VNT64P-CHkaBx7U-BmapScg3.js → sankeyDiagram-W5VNT64P-CHkaBx7U-DVIEYAwp.js} +1 -1
  73. package/dist/assets/{sequenceDiagram-SI44F4Z6-D8tHDhWP-CUdmKVJE.js → sequenceDiagram-SI44F4Z6-D8tHDhWP-Bj1KJGOw.js} +1 -1
  74. package/dist/assets/{stateDiagram-OKZ733FA-KNjKsfsT-C4vYhP8-.js → stateDiagram-OKZ733FA-KNjKsfsT-vLgbrwuG.js} +1 -1
  75. package/dist/assets/stateDiagram-v2-UEYNNEHI-B88w7Ous-BOFDuPd3.js +1 -0
  76. package/dist/assets/{swimlanes-SLNWSIFB-D_yJNxBK-DKm4q9Sk.js → swimlanes-SLNWSIFB-D_yJNxBK-SUjcLMes.js} +1 -1
  77. package/dist/assets/swimlanesDiagram-ULZ7WXOC-DNcZzqTp-Dfg75y0Z.js +8 -0
  78. package/dist/assets/{timeline-definition-Z64GVDOM-BcEcbSq1-CgoBgtz4.js → timeline-definition-Z64GVDOM-BcEcbSq1-BJqnlWN6.js} +1 -1
  79. package/dist/assets/treeView-QDETBFTQ-CqfT0I1z-iQRJmXRe.js +1 -0
  80. package/dist/assets/treemap-6X3UGDF4-CiJkiGWo-C7FurOE9.js +1 -0
  81. package/dist/assets/{vennDiagram-T6HMQDX7-CxS3fcVg-DsaLFuAp.js → vennDiagram-T6HMQDX7-CxS3fcVg-C34mxRKL.js} +1 -1
  82. package/dist/assets/wardley-OPB4EBWU-D1tuVHAV-C_FNXnWT.js +1 -0
  83. package/dist/assets/{wardleyDiagram-T6FBY63Y-D_XCiR14-DrUj15Q7.js → wardleyDiagram-T6FBY63Y-D_XCiR14-D-z1s9B7.js} +1 -1
  84. package/dist/assets/{xychartDiagram-ELKLHX3M-BU4yBDeE-NFXplYhk.js → xychartDiagram-ELKLHX3M-BU4yBDeE-7PHz5Wuv.js} +1 -1
  85. package/dist/index.html +2 -2
  86. package/package.json +3 -3
  87. package/server/agents/codex-sessions.ts +143 -20
  88. package/server/agents/transcript-head.ts +54 -5
  89. package/server/backends/remoteHost/getFeed.spec.ts +1 -0
  90. package/server/backends/remoteHost/handlers/deps.ts +5 -0
  91. package/server/backends/remoteHost/handlers/terminalSession.ts +18 -0
  92. package/server/backends/remoteHost/handlers.spec.ts +53 -0
  93. package/server/backends/remoteHost/index.ts +1 -0
  94. package/server/backends/sharedApp/declare.ts +47 -3
  95. package/server/backends/sharedApp/ensureAid.ts +33 -0
  96. package/server/backends/sharedApp/establish.ts +24 -1
  97. package/server/backends/sharedApp/headlessHarness.ts +142 -16
  98. package/server/backends/sharedApp/headlessPreview.ts +450 -20
  99. package/server/backends/sharedApp/headlessReport.ts +221 -25
  100. package/server/backends/sharedApp/preview.ts +3 -1
  101. package/server/backends/sharedApp/previewWrite.ts +21 -9
  102. package/server/backends/sharedApp/publish.ts +89 -37
  103. package/server/backends/sharedApp/recovery.ts +68 -0
  104. package/server/backends/sharedApp/slug.ts +17 -2
  105. package/server/config/app-config.ts +10 -0
  106. package/server/config/header-title.ts +68 -5
  107. package/server/index.ts +13 -6
  108. package/server/infra/machine-load.ts +12 -0
  109. package/server/infra/mapConcurrent.ts +23 -0
  110. package/server/infra/shared-app-tool.ts +95 -11
  111. package/server/routes/app-routes.ts +4 -0
  112. package/server/routes/load-routes.ts +17 -0
  113. package/server/routes/session-routes.ts +14 -4
  114. package/server/session/command-summary.ts +58 -4
  115. package/server/session/session-detail-view.ts +4 -1
  116. package/server/session/session-title.ts +121 -39
  117. package/server/session/transcript-view-read.ts +173 -0
  118. package/server/session/transcript-view.ts +367 -0
  119. package/server/session/transcript.ts +5 -2
  120. package/server/skills/mulmoterminal-config/SKILL.md +17 -2
  121. package/server/skills/mulmoterminal-shared-app/SKILL.md +288 -36
  122. package/server/skills/mulmoterminal-shared-app/templates/gym.md +110 -3
  123. package/server/skills/mulmoterminal-shared-app/templates/live-poll.md +537 -0
  124. package/server/skills/mulmoterminal-shared-app/templates/meeting-room.md +37 -5
  125. package/server/skills/mulmoterminal-shared-app/templates/salon.md +7 -1
  126. package/server/skills/mulmoterminal-shared-app/templates/survey.md +451 -0
  127. package/dist/assets/architecture-TIHT7OUA-Cqhmai3f-B3dDUaH7.js +0 -1
  128. package/dist/assets/channel-DKMa7Sn5-Br0ptK8f.js +0 -1
  129. package/dist/assets/classDiagram-JCYQIIEL-C1ePmEG1-B62snhgn.js +0 -1
  130. package/dist/assets/classDiagram-v2-OCEON4UE-C_O3VNBf-B62snhgn.js +0 -1
  131. package/dist/assets/cynefin-VYW2F7L2-DvSvuXnG-DwKiuHWt.js +0 -1
  132. package/dist/assets/eventmodeling-45OFAUF4-jdctDg0T-DoXp2eXw.js +0 -1
  133. package/dist/assets/flowDiagram-UKHOOZJN-CR3dcoRl-DgzdW-cs.js +0 -1
  134. package/dist/assets/gitGraph-TEB2WS4Q-C4cKwl5j-BlK_wv9x.js +0 -1
  135. package/dist/assets/index-VWLTHNzn.css +0 -1
  136. package/dist/assets/info-DKCQHKI2-DPUCBYWS-BzVbMGm2.js +0 -1
  137. package/dist/assets/packet-7NZHBO7P-CC7His0F-zsacmAHQ.js +0 -1
  138. package/dist/assets/pie-RZYD4A2V-CCrcq2sL-DMKX4oTe.js +0 -1
  139. package/dist/assets/radar-I7S5WNFK-C5TUrpHf-C9eW7eNu.js +0 -1
  140. package/dist/assets/railroad-3IZDKUUU-CGuuFEd8-DaWTqvuI.js +0 -1
  141. package/dist/assets/railroad-abnf-AHOZXSZD-DuoCSFZY-C4fjzt9_.js +0 -1
  142. package/dist/assets/railroad-ebnf-EBAXGLYW-ig-DG9e_-BMyXLUtT.js +0 -1
  143. package/dist/assets/railroad-peg-LSFZ7HO6-BkBgpyvu-Bvq8TVK0.js +0 -1
  144. package/dist/assets/stateDiagram-v2-UEYNNEHI-B88w7Ous-BdVKMAxq.js +0 -1
  145. package/dist/assets/swimlanesDiagram-ULZ7WXOC-DNcZzqTp-7j8MQOf5.js +0 -8
  146. package/dist/assets/treeView-QDETBFTQ-CqfT0I1z-DFVDoISi.js +0 -1
  147. package/dist/assets/treemap-6X3UGDF4-CiJkiGWo-CHV83aQM.js +0 -1
  148. package/dist/assets/wardley-OPB4EBWU-D1tuVHAV-DAoS-Peb.js +0 -1
package/README.md CHANGED
@@ -364,9 +364,10 @@ The launcher detects it and prints the exact, OS-appropriate removal command; ru
364
364
  see [Agents: Claude & Codex](#agents-claude--codex) and [Scripts (Run menu)](#scripts-run-menu).
365
365
  - In dev (`yarn dev`) the Vite dev server runs on its own port (`CLIENT_PORT`,
366
366
  default `6856`) and proxies `/ws` (a prefix covering `/ws/codex`, `/ws/launch`, and
367
- `/ws/run`), `/ws/pubsub`, `/api`, and `/artifacts` to the backend (`PORT`, default
368
- `34567`) — so you open the Vite port (e.g. `http://localhost:6856`). In production the
369
- backend serves the built client from `dist/` on `PORT`, and you open that.
367
+ `/ws/run`), `/ws/pubsub`, `/api`, `/artifacts`, and `/htmlfile` to the backend
368
+ (`PORT`, default `34567`) — so you open the Vite port (e.g. `http://localhost:6856`).
369
+ In production the backend serves the built client from `dist/` on `PORT`, and you open
370
+ that.
370
371
 
371
372
  ---
372
373
 
@@ -539,7 +540,8 @@ the `claude` / `codex` sessions themselves.
539
540
  | `CLAUDE_BIN` | `claude` | The Claude Code binary to spawn. On Windows a bare name is resolved on `PATH` before it reaches the PTY layer (which matches file names exactly): to the `.exe` when there is one, otherwise to the `.cmd` shim an npm-global install leaves, run through `cmd.exe`. |
540
541
  | `CLAUDE_CWD` | current dir | Working directory each `claude` PTY runs in; determines which project's sessions are listed. Via `npx mulmoterminal@latest` it defaults to the directory you ran the command from (override with `--cwd <dir>`, relative allowed); when the server is run directly it falls back to `~/mulmoclaude`. A value read from `.env` must be an absolute path (`~` is not expanded). |
541
542
  | `CLAUDE_PERMISSION_MODE` | `auto` | Permission mode passed to each `claude` spawn. |
542
- | `MT_TITLE_MODEL` | `haiku` | Model used for the cell header's AI title (a cheap/fast model summarizing the recent turns). Accepts a `--model` alias or a full model id. |
543
+ | `MT_TITLE_SOURCE` | `transcript` | Where the cell header's AI title comes from. `transcript` reads the title Claude Code writes into its own transcript — no extra process. `headless` restores the old behaviour of summarizing the recent turns with `claude -p`, which costs a model call but follows a session whose topic drifts (Claude's own title is written once and never revised). |
544
+ | `MT_TITLE_MODEL` | `haiku` | Model used for the cell header's AI title. Only read when `MT_TITLE_SOURCE=headless`. Accepts a `--model` alias or a full model id. |
543
545
  | `CODEX_BIN` | `codex` | The Codex CLI binary to spawn. |
544
546
  | `CODEX_MODEL`| codex default | Model passed to Codex as `--model` (unset = Codex's own default). |
545
547
  | `CODEX_HOME` | `~/.codex` | Codex home — where its session rollouts and MulmoTerminal-mirrored skills live. |
@@ -602,6 +604,7 @@ The Settings modal (the gear button) persists per-user UI choices to `~/.mulmote
602
604
  | `appendSystemPrompt` | Whether a spawned Claude session is asked to end a reply with a **closing summary** — what was asked, what was achieved, what was not (see [Closing summary](#closing-summary)). **On by default**; set `false` to opt out, and a directory's `.mulmoterminal.json` outranks this. Settings → **Sessions and background tasks** has the switch. Read per spawn, so no restart is needed, though a session already running keeps what it was launched with. `true` / `false` only. |
603
605
  | `autoDirIcon` | Whether a project that sets no `icon` shows the favicon its repository already ships (`public/favicon.svg`, `apple-touch-icon.png`, a web manifest — first hit wins, ordered by how the image survives at 14px). **On by default**; Settings → **Directory appearance** has the switch. A single project opts out with `"icon": false` in its own `.mulmoterminal.json`, which this does not override. A key that was written and got it wrong shows nothing rather than falling back — a broken setting has to look broken. `true` / `false` only. |
604
606
  | `cockpitLines` | `{ summary, prompt, response }` — how many lines each **cockpit-roster** row shows before it clamps (default `2` / `2` / `3`, each clamped to `1`–`20`). Raising them trades how many sessions fit on screen for reading a long one in place. Three steppers in Settings → **Waiting rows**. |
607
+ | `showLoadAverage` | Whether the grid header draws this machine's **load average** beside the 5h / 7d usage windows, as a percentage of its cores (`load 334%` = a 20-core machine with 66.8 runnable processes). **On by default**; amber at 100%, red at 200%, hover for the raw 1 / 5 / 15-minute figures. Settings → **Grid header read-outs** has the switch. A host that keeps no load average (Windows) shows nothing rather than `0%`, whatever this says. `true` / `false` only. |
605
608
  | `fontFamily` | The **terminal font** every session renders in — a CSS font-family stack, e.g. `"'Cica', 'MS Gothic', monospace"`. Set it in Settings → **Terminal font**, applied at once; editing the file instead needs a **restart** (this config is read once at startup). Unset uses the built-in stack (JetBrains Mono / Fira Code / Menlo / Consolas, then CJK faces for Japanese, Korean and Chinese). Unlike the per-browser font **size**, this is one value for the whole host — it names fonts, and which fonts exist is a property of the machine. A directory can override it. See the [Configuration guide](https://receptron.github.io/mulmoterminal/guide/en/config.html#font-family). |
606
609
 
607
610
  Every MulmoTerminal on the machine shares this one file, so an older build could save over a key a
@@ -855,7 +858,10 @@ them. They exist as separate projects because each has its own compiler options
855
858
  `noUncheckedIndexedAccess` off).
856
859
 
857
860
  In dev, open the Vite URL; its proxy forwards `/ws`, `/ws/pubsub`, and `/api` to
858
- `:34567`. In production, run `yarn build` then `yarn server` and open
861
+ `:34567`, plus the two mounts that serve a presentHtml page to the Canvas iframe,
862
+ `/artifacts` and `/htmlfile` — a page path missing from that list is answered by
863
+ Vite's SPA catch-all with `index.html`, which renders as a blank iframe rather
864
+ than an error. In production, run `yarn build` then `yarn server` and open
859
865
  `http://localhost:34567`.
860
866
 
861
867
  ---
@@ -1515,6 +1521,14 @@ The browser sends the cell's xterm buffer as `log`; the server truncates it to t
1515
1521
  last **32 KB** (the tail, where errors + the exit line live), runs the CLI with the
1516
1522
  log piped on stdin (argv — no shell), and returns its answer. Same-origin guarded.
1517
1523
 
1524
+ The summarizer gets **no tools** (#1769): the spawn carries a `--settings` deny of `*`,
1525
+ a `--disallowedTools` list, no MCP servers, and a working directory outside any
1526
+ repository. A deny rule outranks the ambient allow rules — including the user-level
1527
+ `~/.claude/settings.json`, which a neutral working directory does not escape — and it
1528
+ covers tools that do not exist yet, which a list of names cannot. The log being
1529
+ summarized is not content we control, so this is the guarantee rather than the prompt's
1530
+ wording (the prompt says it too).
1531
+
1518
1532
  **Request `application/json`**:
1519
1533
 
1520
1534
  ```jsonc
@@ -1912,15 +1926,24 @@ appears, at which point the on-disk title takes over.
1912
1926
  The raw last prompt is a poor cell-header label once a session becomes a
1913
1927
  back-and-forth: a follow-up is either a trivial ack (`ok`, `はい` — skipped, so the
1914
1928
  header keeps showing the now-stale opening task) or context-dependent (`2番目にして`
1915
- — meaningless on its own). So the server summarizes the **recent turns** with a cheap
1916
- model (`MT_TITLE_MODEL`, default `haiku`) into a short title and shows it in the cell
1917
- header (falling back to the last prompt when there's no title yet).
1918
-
1919
- Generation is kept low-cost — it runs at a turn's `Stop` (when the reply is on disk)
1920
- only when a title is **due**: none yet, the newest prompt was a trivial/context-dependent
1921
- ack (so the raw last prompt would be stale), or every few turns to keep a long session's
1922
- title current. The title lives in memory (never written into Claude's own transcript); a
1923
- resumed session falls back to any on-disk `ai-title`.
1929
+ — meaningless on its own). So the header shows a short **AI title** instead, falling back
1930
+ to the last prompt when there is none yet.
1931
+
1932
+ By default that title is **read, not generated**: Claude Code writes an `ai-title` record
1933
+ into its own transcript, and the server picks it up from the pass it already makes over
1934
+ that file. Nothing is spawned, so nothing has to be given tools — the previous behaviour
1935
+ launched a full `claude -p` session per title, and one of those ran `git push origin main`
1936
+ in a working repository (#1769). The cost is freshness: Claude's own title is written once
1937
+ per session and never revised, so it describes what the session STARTED as. Set
1938
+ `MT_TITLE_SOURCE=headless` to go back to summarizing the recent turns with a cheap model
1939
+ (`MT_TITLE_MODEL`, default `haiku`), which does follow a drifting topic.
1940
+
1941
+ Either way the title is refreshed on the same schedule — at a turn's `Stop` (when the reply
1942
+ is on disk) and only when one is **due**: none yet, the newest prompt was a
1943
+ trivial/context-dependent ack (so the raw last prompt would be stale), or every few turns.
1944
+ The cadence matters much less now that the default source costs nothing to read. The title
1945
+ this server is showing lives in memory (this repo never writes `ai-title` lines into Claude's
1946
+ own transcript); a resumed session falls back to the on-disk `ai-title` directly.
1924
1947
 
1925
1948
  ### Session note
1926
1949
 
@@ -1998,7 +2021,8 @@ common/ Shared by server/ and src/ — both tsconfigs include it, so a
1998
2021
  wire type either side decides from belongs HERE, never mirrored in both:
1999
2022
  dirChrome.ts, ghItems.ts, gitStatus.ts, launchOptions.ts, shortcuts.ts,
2000
2023
  sourceExtensions.ts, modelPresets.ts, modelIds.ts, theme*.ts, …
2001
- vite.config.ts Dev proxy for /ws (+ /ws/codex, /ws/launch, /ws/run), /ws/pubsub, /api, /artifacts
2024
+ vite.config.ts Dev proxy for /ws (+ /ws/codex, /ws/launch, /ws/run), /ws/pubsub, /api,
2025
+ /artifacts, /htmlfile
2002
2026
  vitest.config.ts jsdom test environment
2003
2027
  ```
2004
2028
 
@@ -0,0 +1,64 @@
1
+ // The machine's own run-queue load, shown beside the 5h / 7d usage gauges (#1786): "may I start
2
+ // another agent right now?" is a question about this host, and it was the one number the grid
3
+ // header did not carry.
4
+ //
5
+ // Shared because both sides decide from it: the server reads the kernel's figures, the header
6
+ // turns them into a percentage of the cores it has.
7
+
8
+ import { isRecord } from "./isRecord.js";
9
+
10
+ export interface MachineLoad {
11
+ /** The 1 / 5 / 15 minute averages, as the kernel reports them. */
12
+ avg1: number;
13
+ avg5: number;
14
+ avg15: number;
15
+ /** What makes the averages readable — 66.8 is quiet on 128 cores and hopeless on 4. */
16
+ cores: number;
17
+ }
18
+
19
+ /** Windows keeps no load average, and Node says so by returning `[0, 0, 0]` rather than failing.
20
+ * Decided on the PLATFORM and never on the values: an idle mac reports 0.00 too, and reading
21
+ * that as "unknown" would drop the one reading we can vouch for. */
22
+ export const keepsLoadAverage = (platform: string): boolean => platform !== "win32";
23
+
24
+ // A negative average, a NaN, or a machine claiming zero cores describes no machine. Rejected
25
+ // whole rather than per field: the percentage divides one by the other, so a reading missing
26
+ // either half cannot be drawn at all.
27
+ const usableLoad = (avg1: number, avg5: number, avg15: number, cores: number): MachineLoad | null => {
28
+ const sane = (n: number): boolean => Number.isFinite(n) && n >= 0;
29
+ if (!sane(avg1) || !sane(avg5) || !sane(avg15)) return null;
30
+ if (!Number.isInteger(cores) || cores <= 0) return null;
31
+ return { avg1, avg5, avg15, cores };
32
+ };
33
+
34
+ /** The reading, or null where there is nothing to report. Pure — `node:os` is touched by the one
35
+ * caller in `server/infra/machine-load.ts`, so every rule here stays testable without waiting for
36
+ * a machine that happens to be busy. */
37
+ export function machineLoadFrom(averages: readonly number[], cores: number, platform: string): MachineLoad | null {
38
+ if (!keepsLoadAverage(platform)) return null;
39
+ const [avg1, avg5, avg15] = averages;
40
+ if (avg1 === undefined || avg5 === undefined || avg15 === undefined) return null;
41
+ return usableLoad(avg1, avg5, avg15, cores);
42
+ }
43
+
44
+ /** What the browser accepts back. A field of the wrong type is not "absent" — it is a shape this
45
+ * client has not been taught, and rendering half of it would put a number on screen that no
46
+ * machine reported. */
47
+ export function parseMachineLoad(value: unknown): MachineLoad | null {
48
+ if (!isRecord(value)) return null;
49
+ const { avg1, avg5, avg15, cores } = value;
50
+ if (typeof avg1 !== "number" || typeof avg5 !== "number" || typeof avg15 !== "number" || typeof cores !== "number") return null;
51
+ return usableLoad(avg1, avg5, avg15, cores);
52
+ }
53
+
54
+ /** What a `GET /api/load` body means, in the one place both the meaning and the shape are known.
55
+ *
56
+ * `null` is "nothing usable arrived" — a body this client cannot read says nothing about the
57
+ * machine, so whatever is on screen stays until it goes stale. `{ load: null }` is the opposite:
58
+ * the host answering that it keeps no load average, which the header must act on at once. */
59
+ export function readLoadBody(body: unknown): { load: MachineLoad | null } | null {
60
+ if (!isRecord(body)) return null;
61
+ if (body.load === null) return { load: null };
62
+ const load = parseMachineLoad(body.load);
63
+ return load ? { load } : null;
64
+ }
@@ -0,0 +1,17 @@
1
+ // The one place the `showLoadAverage` setting is defined (#1786). Both sides decide from it — the
2
+ // server sanitizes what the config file says, the browser hydrates a flag from the same field —
3
+ // and a default that disagrees across the two shows up only as a checkbox that does not match
4
+ // what the server does.
5
+
6
+ /** ON unless the config says otherwise: the read-out is the feature, and a header that has to be
7
+ * switched on is one nobody finds. */
8
+ export const SHOW_LOAD_AVERAGE_DEFAULT = true;
9
+
10
+ // The KEY deliberately stays a literal on both sides. `settings-coverage.spec.ts` proves a
11
+ // setting is reachable by finding `createGlobalFlag("<key>"` in the Settings sources, so a shared
12
+ // constant there buys nothing and silently removes that guarantee — the name is already pinned,
13
+ // it is the DEFAULT that could drift unseen.
14
+
15
+ /** Anything that is not a boolean is "unconfigured", which is what every config file written
16
+ * before this feature existed contains. */
17
+ export const sanitizeShowLoadAverage = (input: unknown): boolean => (typeof input === "boolean" ? input : SHOW_LOAD_AVERAGE_DEFAULT);
@@ -1 +1 @@
1
- import{n as e}from"./chunk-Y2CYZVJY-Bdt8pFDJ-DsF7k-Jl.js";import{f as t}from"./src-CvsWqFln-Tc7ZSrRz.js";import{_ as n,g as r}from"./mermaid-parser.core-C1baW7NG-BzDlu5Ub.js";import"./chunk-I66GZJ75-DSPCVCny-CcYhEHb5.js";import"./chunk-3NCLNEKW-CBztX243-DSaECkf1.js";import{n as i,r as a,t as o}from"./chunk-6Q2QTUOP-Cx8nz5_t-CzxkXkeW.js";import{t as s}from"./chunk-JWPE2WC7-BQ3zXr2k-DSd3Ct95.js";var c=r().RailroadAbnf.parser.LangiumParser,l=e(e=>{let t=e.alternatives.map(u);return t.length===1?t[0]:{type:`choice`,alternatives:t}},`transformAlternation`),u=e(e=>{let t=e.elements.map(f);return t.length===1?t[0]:{type:`sequence`,elements:t}},`transformConcatenation`),d=e(e=>{if(e.includes(`*`)){let[t,n]=e.split(`*`);return{min:t?parseInt(t,10):0,max:n?parseInt(n,10):1/0}}let t=parseInt(e,10);return{min:t,max:t}},`parseRepeat`),f=e(e=>{let t=p(e.primary);if(!e.repeat)return t;let{min:n,max:r}=d(e.repeat);return n===0&&r===1?{type:`optional`,element:t}:{type:`repetition`,element:t,min:n,max:r}},`transformElement`),p=e(e=>{switch(e.$type){case`AbnfStringLiteral`:return{type:`terminal`,value:e.value};case`AbnfNumVal`:return{type:`terminal`,value:e.value};case`AbnfRuleName`:return{type:`nonterminal`,name:e.name};case`AbnfGroup`:return l(e.element);case`AbnfOptionalGroup`:return{type:`optional`,element:l(e.element)};default:throw Error(`Unsupported ABNF primary node: ${e.$type}`)}},`transformPrimary`),m=e(e=>({name:e.name,definition:l(e.definition)}),`transformRule`),h=e(e=>{s(e,a),e.title&&a.setTitle(e.title),e.rules.map(e=>a.addRule(m(e)))},`populateDb`),g={parser:{parse:e(e=>{a.clear(),t.debug(`[ABNF Parser] Starting Langium parse`);let r=c.parse(e);if(r.lexerErrors.length>0||r.parserErrors.length>0)throw new n(r);let i=r.value;t.debug(`[ABNF Parser] Parsed rules:`,i.rules.length),h(i),t.debug(`[ABNF Parser] Parse complete`)},`parse`),parser:{yy:a}},db:a,renderer:o,styles:i};export{g as diagram};
1
+ import{n as e}from"./chunk-Y2CYZVJY-Bdt8pFDJ-DsF7k-Jl.js";import{f as t}from"./src-CvsWqFln-Tc7ZSrRz.js";import{_ as n,g as r}from"./mermaid-parser.core-C1baW7NG-C1lkUbAr.js";import"./chunk-I66GZJ75-DSPCVCny-DOUjXnuq.js";import"./chunk-3NCLNEKW-CBztX243-CwupLy1v.js";import{n as i,r as a,t as o}from"./chunk-6Q2QTUOP-Cx8nz5_t-KpLSy3XB.js";import{t as s}from"./chunk-JWPE2WC7-BQ3zXr2k-DSd3Ct95.js";var c=r().RailroadAbnf.parser.LangiumParser,l=e(e=>{let t=e.alternatives.map(u);return t.length===1?t[0]:{type:`choice`,alternatives:t}},`transformAlternation`),u=e(e=>{let t=e.elements.map(f);return t.length===1?t[0]:{type:`sequence`,elements:t}},`transformConcatenation`),d=e(e=>{if(e.includes(`*`)){let[t,n]=e.split(`*`);return{min:t?parseInt(t,10):0,max:n?parseInt(n,10):1/0}}let t=parseInt(e,10);return{min:t,max:t}},`parseRepeat`),f=e(e=>{let t=p(e.primary);if(!e.repeat)return t;let{min:n,max:r}=d(e.repeat);return n===0&&r===1?{type:`optional`,element:t}:{type:`repetition`,element:t,min:n,max:r}},`transformElement`),p=e(e=>{switch(e.$type){case`AbnfStringLiteral`:return{type:`terminal`,value:e.value};case`AbnfNumVal`:return{type:`terminal`,value:e.value};case`AbnfRuleName`:return{type:`nonterminal`,name:e.name};case`AbnfGroup`:return l(e.element);case`AbnfOptionalGroup`:return{type:`optional`,element:l(e.element)};default:throw Error(`Unsupported ABNF primary node: ${e.$type}`)}},`transformPrimary`),m=e(e=>({name:e.name,definition:l(e.definition)}),`transformRule`),h=e(e=>{s(e,a),e.title&&a.setTitle(e.title),e.rules.map(e=>a.addRule(m(e)))},`populateDb`),g={parser:{parse:e(e=>{a.clear(),t.debug(`[ABNF Parser] Starting Langium parse`);let r=c.parse(e);if(r.lexerErrors.length>0||r.parserErrors.length>0)throw new n(r);let i=r.value;t.debug(`[ABNF Parser] Parsed rules:`,i.rules.length),h(i),t.debug(`[ABNF Parser] Parse complete`)},`parse`),parser:{yy:a}},db:a,renderer:o,styles:i};export{g as diagram};
@@ -0,0 +1 @@
1
+ import{f as e}from"./mermaid-parser.core-C1baW7NG-C1lkUbAr.js";export{e as createArchitectureServices};