mulmoterminal 4.6.1 → 4.7.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 +39 -11
- package/bin/update-check.d.ts +10 -0
- package/bin/update-check.js +30 -15
- package/common/agentSessionList.ts +1 -0
- package/common/guiMcpAgents.ts +10 -0
- package/common/launchAgent.ts +1 -1
- package/common/modelPresets.ts +10 -0
- package/common/sessionAgent.ts +3 -2
- package/common/updateStatus.ts +42 -0
- package/dist/assets/{abnfDiagram-VRR7QNED-WSmThe6b-CBO7sBGR.js → abnfDiagram-VRR7QNED-WSmThe6b-dBgFOZJ6.js} +1 -1
- package/dist/assets/architecture-TIHT7OUA-Cqhmai3f-sj7JkliI.js +1 -0
- package/dist/assets/{architectureDiagram-ZJ3FMSHR-Tj3i7Oow-CYG4G6Ik.js → architectureDiagram-ZJ3FMSHR-Tj3i7Oow-DEsMCnCO.js} +1 -1
- package/dist/assets/{blockDiagram-677ZJIJ3-c-hNYBhI-JIMzBO4l.js → blockDiagram-677ZJIJ3-c-hNYBhI-B2nmyPz0.js} +1 -1
- package/dist/assets/{c4Diagram-LMCZKHZV-WIGVajf5-RTNQrsuw.js → c4Diagram-LMCZKHZV-WIGVajf5-CmCUDAtE.js} +1 -1
- package/dist/assets/channel-OqG5cGJi-zdxP6MgL.js +1 -0
- package/dist/assets/{chunk-32BRIVSS-CtSq3QOR-BlWLJRiy.js → chunk-32BRIVSS-CtSq3QOR-DYYdxRvv.js} +1 -1
- package/dist/assets/{chunk-52WLFC77-2Up0T-6t-BdzTLAmw.js → chunk-52WLFC77-2Up0T-6t-DkAuUA9O.js} +1 -1
- package/dist/assets/{chunk-C7G6YPKG-ivengO-7-DPCDeWnS.js → chunk-C7G6YPKG-ivengO-7-DAJ9T7Qf.js} +1 -1
- package/dist/assets/{chunk-EX3LRPZG-BHoWQ6W8-J1DVewfV.js → chunk-EX3LRPZG-BHoWQ6W8-B2e2_95p.js} +1 -1
- package/dist/assets/{chunk-FWX5IMBZ-PvRXPghr-DbyxSH7i.js → chunk-FWX5IMBZ-PvRXPghr-CjeJ_Ar9.js} +2 -2
- package/dist/assets/{chunk-HOUHSVGY-A3_zwY4q-CBRkk157.js → chunk-HOUHSVGY-A3_zwY4q-C95KqDEI.js} +1 -1
- package/dist/assets/{chunk-ICXQ74PX-vzZqgurQ-CkY3Cm-_.js → chunk-ICXQ74PX-vzZqgurQ-FWkJ2cxG.js} +1 -1
- package/dist/assets/{chunk-MOJQB5TN-CorQ_Pl1-C9s38qkp.js → chunk-MOJQB5TN-CorQ_Pl1-mXFOYgnO.js} +1 -1
- package/dist/assets/{chunk-OGEWGWER-BVhfs7WG-DUXfIM9n.js → chunk-OGEWGWER-BVhfs7WG-4RsxS3fR.js} +1 -1
- package/dist/assets/{chunk-PUDLZKDR-CJo7KQJ3-J-MBRM6o.js → chunk-PUDLZKDR-CJo7KQJ3-CqLwqZmB.js} +1 -1
- package/dist/assets/{chunk-Q4XR5HBZ-DLkq8ZGO-sBmUgQuZ.js → chunk-Q4XR5HBZ-DLkq8ZGO-9ClFvrdq.js} +1 -1
- package/dist/assets/{chunk-V7JOEXUC-DqefuUOb-DFq-Kutz.js → chunk-V7JOEXUC-DqefuUOb-H1x3ZOme.js} +1 -1
- package/dist/assets/{chunk-VAUOI2AC-BKx35BBi-Bi2sMyOB.js → chunk-VAUOI2AC-BKx35BBi-E0yAewsj.js} +1 -1
- package/dist/assets/{chunk-VR4S4FIN-DpJgr4Ur-0cTXBZH0.js → chunk-VR4S4FIN-DpJgr4Ur-Cw4po3Ii.js} +1 -1
- package/dist/assets/{chunk-WYO6CB5R-nS6zX9ct-Dttxo6Qs.js → chunk-WYO6CB5R-nS6zX9ct-KrP8SxMs.js} +1 -1
- package/dist/assets/{chunk-ZGVPDNZ5-DNtiHxpJ-B5WBta3u.js → chunk-ZGVPDNZ5-DNtiHxpJ-chUFyGWx.js} +1 -1
- package/dist/assets/classDiagram-OUVF2IWQ-C6h0nbT3-CqjORMBj.js +1 -0
- package/dist/assets/classDiagram-v2-EOCWNBFH-CzsXJ_wA-CqjORMBj.js +1 -0
- package/dist/assets/cynefin-VYW2F7L2-DvSvuXnG-hgNrUHK4.js +1 -0
- package/dist/assets/{cynefinDiagram-TSTJHNR4-969y1qZK-DQgX1EX-.js → cynefinDiagram-TSTJHNR4-969y1qZK-BGIuynhv.js} +1 -1
- package/dist/assets/{dagre-VKFMJZFB-CZfgAZFk-BqyEfjmp.js → dagre-VKFMJZFB-CZfgAZFk-BTpA5SlQ.js} +1 -1
- package/dist/assets/{diagram-FQU43EPY-CSdnleGM-D1XZK34Y.js → diagram-FQU43EPY-CSdnleGM-Bpa9ofDC.js} +1 -1
- package/dist/assets/{diagram-G47NLZAW-DKYe-Mwx-Cbz-8PBv.js → diagram-G47NLZAW-DKYe-Mwx-WAKYgBrz.js} +1 -1
- package/dist/assets/{diagram-NH7WQ7WH-DMasKpwa-DnEIw3Sx.js → diagram-NH7WQ7WH-DMasKpwa-CW4r7qyE.js} +1 -1
- package/dist/assets/{diagram-OA4YK3LP-CSyc0BDR-Btj5hvma.js → diagram-OA4YK3LP-CSyc0BDR-BKacee04.js} +1 -1
- package/dist/assets/{diagram-WEI45ONY-CcJW2fNK-C5jAHtmT.js → diagram-WEI45ONY-CcJW2fNK-BeAKCOeu.js} +1 -1
- package/dist/assets/{dist-Y4oDndO9.js → dist-BxW5R1_A.js} +1 -1
- package/dist/assets/{dist-BpSI4VvT.js → dist-ChlNuoKi.js} +1 -1
- package/dist/assets/{dist-CB8qi_Y9.js → dist-Cpy0pAqt.js} +1 -1
- package/dist/assets/{dist-BmY1PubB.js → dist-V67wX5oT.js} +1 -1
- package/dist/assets/{ebnfDiagram-CCIWWBDH-CeBUH2N0-5KApqrGZ.js → ebnfDiagram-CCIWWBDH-CeBUH2N0-oK8JFLJb.js} +1 -1
- package/dist/assets/{erDiagram-Q63AITRT-1OOp34oV-Bi3p-XfW.js → erDiagram-Q63AITRT-1OOp34oV-BmDLJ3fH.js} +1 -1
- package/dist/assets/eventmodeling-45OFAUF4-jdctDg0T-TG7KUatZ.js +1 -0
- package/dist/assets/flowDiagram-23GEKE2U-DK0InIny-qxrjE7ea.js +1 -0
- package/dist/assets/{ganttDiagram-NO4QXBWP-DQT88dUZ-CuriOslb.js → ganttDiagram-NO4QXBWP-DQT88dUZ-Dgt5eOG6.js} +1 -1
- package/dist/assets/gitGraph-TEB2WS4Q-C4cKwl5j-D7MFV63o.js +1 -0
- package/dist/assets/{gitGraphDiagram-IHSO6WYX-CeZGS4qi-CCZTshH_.js → gitGraphDiagram-IHSO6WYX-CeZGS4qi-CD-l0vgt.js} +1 -1
- package/dist/assets/index-CJj8AYYF.js +621 -0
- package/dist/assets/index-DNLQibYX.css +1 -0
- package/dist/assets/info-DKCQHKI2-DPUCBYWS-BxgyIApr.js +1 -0
- package/dist/assets/{infoDiagram-FWYZ7A6U-BDt8lBTy-dGahtpJc.js → infoDiagram-FWYZ7A6U-BDt8lBTy-BYSwvgW6.js} +1 -1
- package/dist/assets/{ishikawaDiagram-FXEZZL3T-DOHYs_AA-vfSaShVr.js → ishikawaDiagram-FXEZZL3T-DOHYs_AA-DkznAJGt.js} +1 -1
- package/dist/assets/{journeyDiagram-5HDEW3XC-B33IW9yy-BOhaiV65.js → journeyDiagram-5HDEW3XC-B33IW9yy-CknzrT3m.js} +1 -1
- package/dist/assets/{kanban-definition-HUTT4EX6-Bkdm46eX-BaUbZMoA.js → kanban-definition-HUTT4EX6-Bkdm46eX-CY-MchUy.js} +1 -1
- package/dist/assets/{lib-hy6qj_p5.js → lib-B-JYnmBA.js} +1 -1
- package/dist/assets/{line-Dy_Qlcgo-JNJrqeXG.js → line-Dy_Qlcgo-BdzF7qLz.js} +1 -1
- package/dist/assets/{marp-D5gvGPP_.js → marp-BRsT17Gj.js} +1 -1
- package/dist/assets/{mermaid-parser.core-C1baW7NG-B11a01NO.js → mermaid-parser.core-C1baW7NG-DMZf-3IA.js} +2 -2
- package/dist/assets/{mermaid.core-C09q4TmN-Cu9Teakx.js → mermaid.core-C09q4TmN-B_dowtFH.js} +3 -3
- package/dist/assets/{mindmap-definition-LN4V7U3C-bfYIhPQ0-Bf8Ao97t.js → mindmap-definition-LN4V7U3C-bfYIhPQ0-Dx9H0q0M.js} +1 -1
- package/dist/assets/packet-7NZHBO7P-CC7His0F-BDwWs1zX.js +1 -0
- package/dist/assets/{pegDiagram-2B236MQR-CZQOKUMC-_HGU9_9X.js → pegDiagram-2B236MQR-CZQOKUMC-B0QBQEzx.js} +1 -1
- package/dist/assets/pie-RZYD4A2V-CCrcq2sL-BUfGnZ_U.js +1 -0
- package/dist/assets/{pieDiagram-ENE6RG2P-DiVKPdHE-S_FqPflu.js → pieDiagram-ENE6RG2P-DiVKPdHE-6bFmgSSf.js} +1 -1
- package/dist/assets/{quadrantDiagram-ABIIQ3AL-CbPY3kXI-DpxkRpSk.js → quadrantDiagram-ABIIQ3AL-CbPY3kXI-DR6UcImk.js} +1 -1
- package/dist/assets/radar-I7S5WNFK-C5TUrpHf-xJ223euq.js +1 -0
- package/dist/assets/railroad-3IZDKUUU-CGuuFEd8-BjavHk8u.js +1 -0
- package/dist/assets/railroad-abnf-AHOZXSZD-DuoCSFZY-DaxGYsAG.js +1 -0
- package/dist/assets/railroad-ebnf-EBAXGLYW-ig-DG9e_-BiuEkpVy.js +1 -0
- package/dist/assets/railroad-peg-LSFZ7HO6-BkBgpyvu-DjtS9QjD.js +1 -0
- package/dist/assets/{railroadDiagram-RFXS5EU6-CFRaQzr0-BDrUAcXX.js → railroadDiagram-RFXS5EU6-CFRaQzr0-B13UgpCt.js} +1 -1
- package/dist/assets/{requirementDiagram-TGXJPOKE-BiIDduje-DZNC6u3V.js → requirementDiagram-TGXJPOKE-BiIDduje-BnyCbAFy.js} +1 -1
- package/dist/assets/{sankeyDiagram-HTMAVEWB-DcK87A5Y-B3nqjSin.js → sankeyDiagram-HTMAVEWB-DcK87A5Y-DBqEvMS1.js} +1 -1
- package/dist/assets/{sequenceDiagram-DBY2YBRQ-DgEQYcvc-DjRWhNfq.js → sequenceDiagram-DBY2YBRQ-DgEQYcvc-RMWJvTQk.js} +1 -1
- package/dist/assets/{stateDiagram-2N3HPSRC-Bg7EXtW2-TOQBisWT.js → stateDiagram-2N3HPSRC-Bg7EXtW2-DTYEsQki.js} +1 -1
- package/dist/assets/stateDiagram-v2-6OUMAXLB-BjhArXP_-BwX0TEg2.js +1 -0
- package/dist/assets/{swimlanes-5IMT3BWC-CKORDKr0-N0ObHGIY.js → swimlanes-5IMT3BWC-CKORDKr0-D9FhEzB6.js} +1 -1
- package/dist/assets/swimlanesDiagram-G3AALYLV-CyvIfl1o-CdxmBQcP.js +8 -0
- package/dist/assets/{timeline-definition-FHXFAJF6-BM3Iky2r-BUQRFfDw.js → timeline-definition-FHXFAJF6-BM3Iky2r-BYeRiXBY.js} +1 -1
- package/dist/assets/treeView-QDETBFTQ-CqfT0I1z-s6d8KKbp.js +1 -0
- package/dist/assets/treemap-6X3UGDF4-CiJkiGWo-0QbEhU31.js +1 -0
- package/dist/assets/{vennDiagram-L72KCM5P-VNmAhEFP-C7cK3jF6.js → vennDiagram-L72KCM5P-VNmAhEFP-BjzOgidI.js} +1 -1
- package/dist/assets/wardley-OPB4EBWU-D1tuVHAV-8lAEinVX.js +1 -0
- package/dist/assets/{wardleyDiagram-EHGQE667-BkHQpyFm-C0IlB8lV.js → wardleyDiagram-EHGQE667-BkHQpyFm-DzQER1Jf.js} +1 -1
- package/dist/assets/{xychartDiagram-FW5EYKEG-Yz-8aLqK-B5fYxzV_.js → xychartDiagram-FW5EYKEG-Yz-8aLqK-D9KxXZYS.js} +1 -1
- package/dist/index.html +2 -2
- package/package.json +1 -1
- package/server/agents/claude-args.ts +21 -8
- package/server/agents/grok-usage.ts +1 -5
- package/server/agents/muse-args.ts +52 -0
- package/server/agents/muse-mcp.ts +236 -0
- package/server/agents/muse-session.ts +148 -0
- package/server/agents/muse-usage.ts +92 -0
- package/server/agents/muse.ts +7 -0
- package/server/agents/registry.ts +2 -0
- package/server/agents/types.ts +1 -1
- package/server/agents/usage-count.ts +18 -0
- package/server/backends/collectionActionGuards.ts +67 -0
- package/server/backends/collections.ts +20 -45
- package/server/backends/customViewRoutes.ts +9 -28
- package/server/backends/remoteHost/terminalScreen.ts +1 -1
- package/server/config/update-status.ts +21 -19
- package/server/index.ts +9 -0
- package/server/infra/process-tree.ts +37 -0
- package/server/infra/spawnCapture.ts +9 -2
- package/server/infra/tmux.ts +27 -0
- package/server/mcp/bridge.mjs +87 -14
- package/server/routes/app-routes.ts +3 -0
- package/server/routes/mcp-routes.ts +40 -0
- package/server/routes/plugin-routes.ts +11 -4
- package/server/routes/routeParams.ts +2 -1
- package/server/routes/session-routes.ts +44 -1
- package/server/routes/terminal-ws-path.ts +7 -1
- package/server/routes/ws-routes.ts +72 -7
- package/server/session/agent-badges.ts +45 -0
- package/server/session/background-chat.ts +2 -1
- package/server/session/bridge-session.ts +99 -0
- package/server/session/lifecycle.ts +4 -0
- package/server/session/mcp-config.ts +7 -0
- package/server/session/registry.ts +8 -0
- package/server/session/session-reads.ts +6 -5
- package/server/session/session-settings.ts +96 -8
- package/server/session/spawn-antigravity.ts +26 -10
- package/server/session/spawn-claude.ts +11 -6
- package/server/session/spawn-deps.ts +2 -0
- package/server/session/spawn-grok.ts +26 -9
- package/server/session/spawn-muse.ts +131 -0
- package/server/session/spawners.ts +2 -0
- package/server/session/surviving-sessions.ts +4 -3
- package/dist/assets/architecture-TIHT7OUA-Cqhmai3f-BVPuJja5.js +0 -1
- package/dist/assets/channel-OqG5cGJi-C1zDkGpX.js +0 -1
- package/dist/assets/classDiagram-OUVF2IWQ-C6h0nbT3-DY_MwKzV.js +0 -1
- package/dist/assets/classDiagram-v2-EOCWNBFH-CzsXJ_wA-DY_MwKzV.js +0 -1
- package/dist/assets/cynefin-VYW2F7L2-DvSvuXnG-DYKWyT7K.js +0 -1
- package/dist/assets/eventmodeling-45OFAUF4-jdctDg0T-03avWkxI.js +0 -1
- package/dist/assets/flowDiagram-23GEKE2U-DK0InIny-BZsLyoCM.js +0 -1
- package/dist/assets/gitGraph-TEB2WS4Q-C4cKwl5j-DOv-LqUe.js +0 -1
- package/dist/assets/index-C96r_nGv.css +0 -1
- package/dist/assets/index-CHAgxBbv.js +0 -621
- package/dist/assets/info-DKCQHKI2-DPUCBYWS-VT49gBhu.js +0 -1
- package/dist/assets/packet-7NZHBO7P-CC7His0F-C2Dx0oxu.js +0 -1
- package/dist/assets/pie-RZYD4A2V-CCrcq2sL-ve4Gv4SX.js +0 -1
- package/dist/assets/radar-I7S5WNFK-C5TUrpHf-BVg_eCN-.js +0 -1
- package/dist/assets/railroad-3IZDKUUU-CGuuFEd8-DNXTykNc.js +0 -1
- package/dist/assets/railroad-abnf-AHOZXSZD-DuoCSFZY-QHTvGuQ7.js +0 -1
- package/dist/assets/railroad-ebnf-EBAXGLYW-ig-DG9e_-Ch6HzcZ9.js +0 -1
- package/dist/assets/railroad-peg-LSFZ7HO6-BkBgpyvu-hu0tLEcZ.js +0 -1
- package/dist/assets/stateDiagram-v2-6OUMAXLB-BjhArXP_-5o7JJSQT.js +0 -1
- package/dist/assets/swimlanesDiagram-G3AALYLV-CyvIfl1o-DrrXIaEK.js +0 -8
- package/dist/assets/treeView-QDETBFTQ-CqfT0I1z-CF75ZmbN.js +0 -1
- package/dist/assets/treemap-6X3UGDF4-CiJkiGWo-rxMKyn9k.js +0 -1
- package/dist/assets/wardley-OPB4EBWU-D1tuVHAV-CeoD2DSP.js +0 -1
package/README.md
CHANGED
|
@@ -567,12 +567,12 @@ CLAUDE_CWD=/Users/you/my-project
|
|
|
567
567
|
|
|
568
568
|
### UI settings (`~/.mulmoterminal/config.json`)
|
|
569
569
|
|
|
570
|
-
The Settings modal (
|
|
570
|
+
The Settings modal (the gear button) persists per-user UI choices to `~/.mulmoterminal/config.json`
|
|
571
571
|
(read/written via `GET`/`POST /api/config`):
|
|
572
572
|
|
|
573
573
|

|
|
574
574
|
|
|
575
|
-
*Open it from the
|
|
575
|
+
*Open it from the gear button in the toolbar. Under the title, a **Version** row shows what is running: the version from the shipped `package.json`, plus a `commit <sha>` chip on a git checkout — there the version is only whatever was last released, so the commit is what identifies the build. When something newer exists, the row is followed by the header badge's update notice, command included. Pick a **theme**, set the **terminal font size**, **font** and **scroll speed**, set a custom **attention sound**, list the repos the cross-repo **PRs & Issues** view should aggregate, add **launch commands** for grid cells, register your own **MCP servers**, and turn on the switches for what this app writes on your behalf — **issue work comments**, the **PR clone footer**, the **closing summary**, the **decision digest**, the **dev worklog** — no need to hand-edit the config file. Four settings stay with their skill because a form would be the wrong tool for them (`keymap`, `themes`, `providers`, `buttons`/`chips`); Settings shows what each is doing now and launches that skill. Note that **theme, font size and scroll speed are stored per browser** (they're display preferences, so a phone and a desktop keep their own); the rest live in `~/.mulmoterminal/config.json` and are shared by every client.*
|
|
576
576
|
|
|
577
577
|
| Field | Meaning |
|
|
578
578
|
| ------------ | ------- |
|
|
@@ -879,7 +879,7 @@ alongside the Claude sessions. Scripts are **per-directory**: the cell reads the
|
|
|
879
879
|
different projects' scripts.
|
|
880
880
|
|
|
881
881
|
The same launcher also has an **or launch** row for your configured **launch commands**
|
|
882
|
-
— any interactive command — set in Settings (
|
|
882
|
+
— any interactive command — set in Settings (the gear button) → **Launch commands** as
|
|
883
883
|
`{ label, command }` (e.g. `htop` → `htop`, `Codex` → `codex`). A plain shell needs no
|
|
884
884
|
entry here: the Agent Picker's **Shell** option already opens `$SHELL`. Unlike
|
|
885
885
|
a one-shot script, a launcher runs as a **persistent terminal in the cell's directory**:
|
|
@@ -1170,7 +1170,7 @@ with no schema on disk, so the fields are identified by measurement (see
|
|
|
1170
1170
|
rather than a number it is unsure of, so if a future agy release moves those fields, an
|
|
1171
1171
|
Antigravity cell falls back to showing its model alone — it will not show a wrong percentage.
|
|
1172
1172
|
|
|
1173
|
-
The **Settings** modal (
|
|
1173
|
+
The **Settings** modal (the gear button) shows an **estimated $ cost** — Session / Today / Month — from
|
|
1174
1174
|
`GET /api/cost`, using a built-in public per-model price table (cache reads billed at
|
|
1175
1175
|
0.1×, cache writes at 1.25× input). It's an estimate: real billing differs, **flat-plan
|
|
1176
1176
|
(Max) usage isn't reflected**, and turns on unpriced models are flagged and excluded.
|
|
@@ -1205,7 +1205,7 @@ it came from — `mcp__<id>__presentChart` in Claude Code, `mcp-<id>-presentChar
|
|
|
1205
1205
|
also rewrites `-` in the id to `_`). So the id you register under is repeated on every tool, in
|
|
1206
1206
|
every listing, for the life of the session.
|
|
1207
1207
|
|
|
1208
|
-
MulmoTerminal delivers the GUI MCP by **
|
|
1208
|
+
MulmoTerminal delivers the GUI MCP by **three different routes**, and they do not share an id:
|
|
1209
1209
|
|
|
1210
1210
|
| | Workspace cell / single view | Project-directory grid cell |
|
|
1211
1211
|
|---|---|---|
|
|
@@ -1214,14 +1214,39 @@ MulmoTerminal delivers the GUI MCP by **two different routes**, and they do not
|
|
|
1214
1214
|
| Tools carried | all of them, on one URL | only the groups that directory registered |
|
|
1215
1215
|
| Tool name looks like | `mcp__mt__presentChart` | `mcp__mulmoterminal-render__presentChart` |
|
|
1216
1216
|
|
|
1217
|
+
The third is **Muse**, which reads neither a flag nor a file in the directory: its MCP servers are
|
|
1218
|
+
declared by an installed **plugin**, and `muse plugins install` records one per MACHINE. So
|
|
1219
|
+
MulmoTerminal registers a single `mulmoterminal` plugin holding all four group servers, and each
|
|
1220
|
+
session is narrowed back to what its own directory switched on — the bridge asks the server which
|
|
1221
|
+
session it belongs to (by its process tree) and is told which groups that session may reach. The
|
|
1222
|
+
servers are named by group alone, because Muse composes the tool name out of both ids:
|
|
1223
|
+
|
|
1224
|
+
| | Muse cell (anywhere) |
|
|
1225
|
+
|---|---|
|
|
1226
|
+
| How it arrives | a `mulmoterminal` plugin installed for the machine, re-registered whenever the bridge path or port changes |
|
|
1227
|
+
| Server id | **`render`**, `data`, `media`, `external` — inside the `mulmoterminal` plugin |
|
|
1228
|
+
| Tools carried | only the groups that directory registered; the rest serve an empty toolset |
|
|
1229
|
+
| Tool name looks like | `mcp__plugin_mulmoterminal_render__presentChart` |
|
|
1230
|
+
|
|
1231
|
+
Muse's plugin support is behind its own experimental flag (`MUSE_EXPERIMENTAL_PLUGINS`), which
|
|
1232
|
+
MulmoTerminal sets on the sessions it starts. A Muse build without it simply has no GUI tools —
|
|
1233
|
+
the registration fails with one warning and the session starts anyway.
|
|
1234
|
+
|
|
1235
|
+
**A Muse session picks its plugins up when its own process starts, and MulmoTerminal's sessions
|
|
1236
|
+
outlive the server.** So a Muse cell that was already running when you switched a group on — or
|
|
1237
|
+
when you first upgraded to a version that has this — keeps no tools until that CELL is started
|
|
1238
|
+
again. Restarting the server is not enough: the session is still there in tmux and gets reattached,
|
|
1239
|
+
exactly as it was. Close the cell and open a new one (or `Stop` it in Settings → Surviving sessions),
|
|
1240
|
+
and it comes back with the tools its directory registered.
|
|
1241
|
+
|
|
1217
1242
|
Which route a session takes is decided by `carriesFullGuiMcp()` in
|
|
1218
1243
|
`server/session/mcp-config.ts` — the single view, a cell-less chat, or anything whose cwd **is**
|
|
1219
1244
|
the workspace take the first; anything in a project directory takes the second.
|
|
1220
1245
|
|
|
1221
1246
|
**The workspace is agent-agnostic for the agents that can RECEIVE a per-spawn config** — claude and
|
|
1222
1247
|
codex ask the same predicate, so two terminals in the workspace reach the same tools no matter which
|
|
1223
|
-
of the two started them. **Antigravity and
|
|
1224
|
-
first:**
|
|
1248
|
+
of the two started them. **Antigravity, Grok and Muse cannot, and that is the exception you will
|
|
1249
|
+
meet first:**
|
|
1225
1250
|
|
|
1226
1251
|
| Started as | In the workspace | In a project directory |
|
|
1227
1252
|
|---|---|---|
|
|
@@ -1229,11 +1254,13 @@ first:**
|
|
|
1229
1254
|
| codex cell | `mt`, every tool | the directory's registered groups |
|
|
1230
1255
|
| antigravity cell | **the directory's registered groups** — nothing registered means **no GUI tools at all** | the directory's registered groups |
|
|
1231
1256
|
| grok cell | **the directory's registered groups** — nothing registered means **no GUI tools at all** | the directory's registered groups |
|
|
1257
|
+
| muse cell | **the directory's registered groups** — nothing registered means **no GUI tools at all** | the directory's registered groups |
|
|
1232
1258
|
| any launcher chip | untouched | untouched |
|
|
1233
1259
|
|
|
1234
|
-
|
|
1235
|
-
in the working directory, and
|
|
1236
|
-
|
|
1260
|
+
None of the three takes an MCP flag: `agy` reads `.agents/mcp_config.json`, `grok` reads
|
|
1261
|
+
`.grok/config.toml` in the working directory, and `muse` reads a plugin installed for the whole
|
|
1262
|
+
machine — and neither a file shared by every session in a directory nor a machine-wide plugin can be
|
|
1263
|
+
handed to one session and not another — so there is nothing for "this cwd is the workspace" to change. The
|
|
1237
1264
|
membership is `FULL_GUI_MCP_AGENTS` in `common/guiMcpAgents.ts`, in `common/` precisely so the
|
|
1238
1265
|
launcher form and the spawn cannot disagree about it
|
|
1239
1266
|
([#1423](https://github.com/receptron/mulmoterminal/issues/1423)).
|
|
@@ -1584,6 +1611,7 @@ From a shell: `mulmoterminal room read <room>` · `room post <room> <text…> [-
|
|
|
1584
1611
|
| `GET /api/sound?kind=` · `/api/dir-sound?cwd=&kind=` · `/api/sound-preset/:id` · `/api/dir-config?cwd=` | Custom / per-directory / preset attention sound + per-dir config. `kind` selects a config entry, never a path. |
|
|
1585
1612
|
| `GET /api/dir-config-detail?cwd=` | The same per-dir config, **plus** the settings a running terminal doesn't need (`provider`, `model`, `skills`, `addDirs`, header button/chip **labels**), **plus** which keys the file set and how each fared (applied / dropped in validation / not a setting at all). Read-only; backs the Settings modal's **Directory settings** preview. Unlike the other `?cwd=` routes this one does **not** fall back to the default workspace — it reports on the directory it was asked about, so a path that no longer exists comes back as `exists:false`. Sound paths and button commands stay server-side. |
|
|
1586
1613
|
| `GET /api/launch-options` | The Anthropic-compatible backends this server can reach, each with its models and — when it can't — the reason. Reports the **name** of the env var a key is read from, never the key. |
|
|
1614
|
+
| `GET /api/update-status` | What is running and whether anything newer exists: `install` (`npm` / `git`), `version`, `commit` (a checkout's short HEAD sha), `latest` (npm, only when newer) and the one-line `notice`. Backs the header's **Update** badge and the Settings version line. Computed once at startup and served from memory — `ready` is false until that check lands. |
|
|
1587
1615
|
| `GET /api/notifications`(`/history`) · `POST /api/notifications/:id/clear` | Notification feed. |
|
|
1588
1616
|
| `POST /api/transcribe`(`/model`…) | Voice-input transcription (Whisper, macOS). |
|
|
1589
1617
|
| `POST /api/translation` | Runtime UI-string translation. |
|
|
@@ -1931,7 +1959,7 @@ src/
|
|
|
1931
1959
|
PrsOverlay.vue cross-repo PRs & Issues
|
|
1932
1960
|
Wiki*View.vue, Collections*.vue, AccountingOverlay.vue workspace views
|
|
1933
1961
|
TimelineOverlay.vue, ToolsPane.vue, NotificationBell.vue, RemoteHostControl.vue
|
|
1934
|
-
SettingsModal.vue
|
|
1962
|
+
SettingsModal.vue settings — the dialog shell + section order
|
|
1935
1963
|
settings/ one file per settings section (theme, sounds,
|
|
1936
1964
|
web push, google, PR repos, launchers, quick
|
|
1937
1965
|
commands, MCP, cost, shortcuts, …), plus the
|
package/bin/update-check.d.ts
CHANGED
|
@@ -6,6 +6,16 @@ export interface UpdateNoticeDeps {
|
|
|
6
6
|
fetchLatest?: () => Promise<string | null>;
|
|
7
7
|
}
|
|
8
8
|
export declare function computeUpdateNotice(pkgDir: string, currentVersion: string, deps?: UpdateNoticeDeps): Promise<string | null>;
|
|
9
|
+
export declare function readInstallInfo(
|
|
10
|
+
pkgDir: string,
|
|
11
|
+
currentVersion: string,
|
|
12
|
+
deps?: UpdateNoticeDeps,
|
|
13
|
+
): Promise<Pick<import("../common/updateStatus.js").UpdateStatus, "install" | "version" | "commit">>;
|
|
14
|
+
export declare function computeUpdateInfo(
|
|
15
|
+
pkgDir: string,
|
|
16
|
+
currentVersion: string,
|
|
17
|
+
deps?: UpdateNoticeDeps,
|
|
18
|
+
): Promise<Omit<import("../common/updateStatus.js").UpdateStatus, "ready">>;
|
|
9
19
|
export declare function isUpdateCheckDisabled(env: Record<string, string | undefined>): boolean;
|
|
10
20
|
export declare function hasNodeModulesSegment(pkgDir: string): boolean;
|
|
11
21
|
export declare function classifyInstall(pkgDir: string, isGitWorkTree: boolean): "npm" | "git";
|
package/bin/update-check.js
CHANGED
|
@@ -168,15 +168,12 @@ export function gitUpdateNotice({ localSha, localShort, remoteSha, defaultBranch
|
|
|
168
168
|
const LS_REMOTE_TIMEOUT_MS = 6000;
|
|
169
169
|
|
|
170
170
|
// The git branch of the check: local HEAD vs the remote's, read with ls-remote so no fetch is
|
|
171
|
-
// forced. Silent on a dirty tree (can't fast-forward) or any unreadable probe.
|
|
172
|
-
|
|
171
|
+
// forced. Silent on a dirty tree (can't fast-forward) or any unreadable probe. `localShort` is
|
|
172
|
+
// passed in because the caller has already read it for the version display.
|
|
173
|
+
async function gitUpdateNotice_(git, localShort) {
|
|
173
174
|
const status = await git(["status", "--porcelain"]);
|
|
174
175
|
if (status === null || isTreeDirtyForUpdate(status)) return null;
|
|
175
|
-
const [localSha,
|
|
176
|
-
git(["rev-parse", "HEAD"]),
|
|
177
|
-
git(["rev-parse", "--short", "HEAD"]),
|
|
178
|
-
git(["ls-remote", "--symref", "origin", "HEAD"], LS_REMOTE_TIMEOUT_MS),
|
|
179
|
-
]);
|
|
176
|
+
const [localSha, lsRemote] = await Promise.all([git(["rev-parse", "HEAD"]), git(["ls-remote", "--symref", "origin", "HEAD"], LS_REMOTE_TIMEOUT_MS)]);
|
|
180
177
|
return gitUpdateNotice({
|
|
181
178
|
localSha,
|
|
182
179
|
localShort,
|
|
@@ -186,14 +183,32 @@ async function gitUpdateNotice_(git) {
|
|
|
186
183
|
});
|
|
187
184
|
}
|
|
188
185
|
|
|
189
|
-
//
|
|
190
|
-
//
|
|
191
|
-
//
|
|
192
|
-
|
|
193
|
-
export async function computeUpdateNotice(pkgDir, currentVersion, deps = {}) {
|
|
186
|
+
// What is running, without asking the network: the install kind and — for a checkout, where the
|
|
187
|
+
// package.json version is only the last release — the commit that identifies the build. Local
|
|
188
|
+
// probes only, so this is also what the UI gets when the update check is opted out.
|
|
189
|
+
export async function readInstallInfo(pkgDir, currentVersion, deps = {}) {
|
|
194
190
|
const git = deps.runGit ?? ((args, timeout_ms) => runGit(pkgDir, args, timeout_ms));
|
|
195
|
-
const fetchLatest = deps.fetchLatest ?? fetchLatestVersion;
|
|
196
191
|
const inWorkTree = hasNodeModulesSegment(pkgDir) ? false : (await git(["rev-parse", "--is-inside-work-tree"])) === "true";
|
|
197
|
-
|
|
198
|
-
return
|
|
192
|
+
const install = classifyInstall(pkgDir, inWorkTree);
|
|
193
|
+
return { install, version: currentVersion, commit: install === "git" ? await git(["rev-parse", "--short", "HEAD"]) : null };
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// The whole check, front to back: what is running, what is newer, and the one line that says so
|
|
197
|
+
// (null when current). `pkgDir` is where the tool lives — a node_modules dir (→ npm) or a bare
|
|
198
|
+
// checkout (→ git). `deps` lets tests drive it without spawning git or hitting the network;
|
|
199
|
+
// production callers pass nothing and get the real git/registry probes bound to pkgDir.
|
|
200
|
+
export async function computeUpdateInfo(pkgDir, currentVersion, deps = {}) {
|
|
201
|
+
const git = deps.runGit ?? ((args, timeout_ms) => runGit(pkgDir, args, timeout_ms));
|
|
202
|
+
const fetchLatest = deps.fetchLatest ?? fetchLatestVersion;
|
|
203
|
+
const info = await readInstallInfo(pkgDir, currentVersion, { runGit: git });
|
|
204
|
+
if (info.install === "git") return { ...info, latest: null, notice: await gitUpdateNotice_(git, info.commit) };
|
|
205
|
+
const latest = await fetchLatest();
|
|
206
|
+
// `latest` is what the UI OFFERS, so it carries only a version worth moving to — the registry
|
|
207
|
+
// answering with the version already installed is not news.
|
|
208
|
+
return { ...info, latest: latest && isNewerVersion(latest, currentVersion) ? latest : null, notice: npmUpdateNotice(currentVersion, latest) };
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// The notice alone, for the launcher's console line.
|
|
212
|
+
export async function computeUpdateNotice(pkgDir, currentVersion, deps = {}) {
|
|
213
|
+
return (await computeUpdateInfo(pkgDir, currentVersion, deps)).notice;
|
|
199
214
|
}
|
|
@@ -18,6 +18,7 @@ export const AGENT_SESSION_LIST_PATHS: Record<TerminalAgent, string> = {
|
|
|
18
18
|
codex: "/api/codex/sessions",
|
|
19
19
|
antigravity: "/api/antigravity/sessions",
|
|
20
20
|
grok: "/api/grok/sessions",
|
|
21
|
+
muse: "/api/muse/sessions",
|
|
21
22
|
};
|
|
22
23
|
|
|
23
24
|
/** The listing URL for one agent's conversations in one directory. */
|
package/common/guiMcpAgents.ts
CHANGED
|
@@ -19,6 +19,16 @@
|
|
|
19
19
|
// `~/.grok/config.toml` or `./.grok/config.toml` (server/agents/grok-mcp.ts). So a grok session in
|
|
20
20
|
// the workspace gets the groups its DIRECTORY registered, and the launcher form offers it the four
|
|
21
21
|
// per-group toggles — which is the truthful answer, and the one #1423 failed to give.
|
|
22
|
+
//
|
|
23
|
+
// Muse is out for the same reason and reaches its tools a third way. It has no `--mcp-config` and
|
|
24
|
+
// no per-directory config file either: MCP servers are declared by an installed PLUGIN, which
|
|
25
|
+
// `muse plugins install` records per MACHINE (server/agents/muse-mcp.ts). So MulmoTerminal
|
|
26
|
+
// registers one plugin holding all four group servers, and each SESSION is narrowed back to what
|
|
27
|
+
// its directory switched on — by a lookup, not by the environment: a plugin's MCP server is started
|
|
28
|
+
// with a curated environment that carries nothing of ours, so the bridge resolves which session it
|
|
29
|
+
// belongs to (by its process tree) and is told the groups with the answer. Do not add a bridge
|
|
30
|
+
// environment variable; it is dropped on the way and the failure is silent. The launcher form offers muse the same four per-group
|
|
31
|
+
// toggles as grok and agy, which is the truthful answer for the same reason it is theirs.
|
|
22
32
|
import { type SessionAgent } from "./sessionAgent.js";
|
|
23
33
|
import { isLaunchAgent } from "./launchAgent.js";
|
|
24
34
|
import { customAgentFor, type AgentPick, type CustomAgent } from "./customAgents.js";
|
package/common/launchAgent.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
// Deliberately NOT the configured `launchers` list: those are arbitrary user commands, and
|
|
5
5
|
// the phone picks from a fixed set the host can name. "shell" is the OS default shell, the
|
|
6
6
|
// same thing the header's new-terminal button opens.
|
|
7
|
-
export const LAUNCH_AGENTS = ["shell", "claude", "codex", "antigravity", "grok"] as const;
|
|
7
|
+
export const LAUNCH_AGENTS = ["shell", "claude", "codex", "antigravity", "grok", "muse"] as const;
|
|
8
8
|
|
|
9
9
|
export type LaunchAgent = (typeof LAUNCH_AGENTS)[number];
|
|
10
10
|
|
package/common/modelPresets.ts
CHANGED
|
@@ -260,6 +260,16 @@ export const MODEL_PRESETS: readonly ModelPreset[] = [
|
|
|
260
260
|
trials: measured(3, 3, 38),
|
|
261
261
|
},
|
|
262
262
|
|
|
263
|
+
// ── Muse (Meta) ────────────────────────────────────────────────────────────────
|
|
264
|
+
{
|
|
265
|
+
provider: "meta",
|
|
266
|
+
id: "muse-spark-1.2-contributor",
|
|
267
|
+
label: "Muse Spark 1.2",
|
|
268
|
+
contextLength: 1_000_000,
|
|
269
|
+
pricePerMTok: { input: 1, output: 3 },
|
|
270
|
+
trials: { status: "unmeasured" },
|
|
271
|
+
},
|
|
272
|
+
|
|
263
273
|
// ── Reached fine, never drove the tool loop ──────────────────────────────────
|
|
264
274
|
// Kept so the list answers "what about X?" with a measurement instead of silence.
|
|
265
275
|
{
|
package/common/sessionAgent.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// What a remote-host session is running. The server decides it (from the PtyEntry, or from
|
|
2
2
|
// what tmux says is in the pane) and the settings UI offers it as the scope for a quick
|
|
3
3
|
// command, so the list of kinds is a value both sides read.
|
|
4
|
-
export const SESSION_AGENTS = ["claude", "codex", "antigravity", "grok", "shell"] as const;
|
|
4
|
+
export const SESSION_AGENTS = ["claude", "codex", "antigravity", "grok", "muse", "shell"] as const;
|
|
5
5
|
|
|
6
6
|
// Null anywhere this appears means the host cannot tell — a session that outlived a restart
|
|
7
7
|
// exists only in tmux, and nothing recorded what launched it. That is distinct from "shell".
|
|
@@ -9,7 +9,7 @@ export type SessionAgent = (typeof SESSION_AGENTS)[number];
|
|
|
9
9
|
|
|
10
10
|
// The agents a terminal can be LAUNCHED as, which is the session kinds minus "shell" (a shell is
|
|
11
11
|
// a launcher, not an agent). Claude is first because it is the default everywhere below.
|
|
12
|
-
export const TERMINAL_AGENTS = ["claude", "codex", "antigravity", "grok"] as const;
|
|
12
|
+
export const TERMINAL_AGENTS = ["claude", "codex", "antigravity", "grok", "muse"] as const;
|
|
13
13
|
|
|
14
14
|
export type TerminalAgent = (typeof TERMINAL_AGENTS)[number];
|
|
15
15
|
|
|
@@ -47,6 +47,7 @@ const AGENT_BADGES: Partial<Record<TerminalAgent, AgentBadge>> = {
|
|
|
47
47
|
codex: { full: "codex", short: "cx" },
|
|
48
48
|
antigravity: { full: "agy", short: "agy" },
|
|
49
49
|
grok: { full: "grok", short: "gk" },
|
|
50
|
+
muse: { full: "muse", short: "mu" },
|
|
50
51
|
};
|
|
51
52
|
|
|
52
53
|
/** How a session row announces which agent it is running, or null when it wears no badge. The one
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// What GET /api/update-status answers: which install is running, what it is, and what is newer.
|
|
2
|
+
// Shared because both sides decide from it — the server builds it from the startup probe, the
|
|
3
|
+
// header badge and the Settings version line read it.
|
|
4
|
+
|
|
5
|
+
import { isRecord } from "./isRecord.js";
|
|
6
|
+
|
|
7
|
+
/** How the tool was installed, which decides what "the running version" even means. */
|
|
8
|
+
export type InstallKind = "npm" | "git";
|
|
9
|
+
|
|
10
|
+
export interface UpdateStatus {
|
|
11
|
+
/** False until the startup check has landed; `commit` / `latest` / `notice` are not final yet. */
|
|
12
|
+
ready: boolean;
|
|
13
|
+
install: InstallKind;
|
|
14
|
+
/** The shipped package.json version. For a git checkout this is the last release, not the build. */
|
|
15
|
+
version: string;
|
|
16
|
+
/** git installs: short HEAD sha — the only thing that identifies which build is running. */
|
|
17
|
+
commit: string | null;
|
|
18
|
+
/** npm installs: the registry's version, present only when it is newer than `version`. */
|
|
19
|
+
latest: string | null;
|
|
20
|
+
/** The one-line "update available" rendering both the launcher and the header badge show. */
|
|
21
|
+
notice: string | null;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const isInstallKind = (value: unknown): value is InstallKind => value === "npm" || value === "git";
|
|
25
|
+
|
|
26
|
+
const stringOrNull = (value: unknown): string | null => (typeof value === "string" ? value : null);
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* The response as a status, or null when it is not one. Null rather than a filled-in default: a
|
|
30
|
+
* body we could not read must leave the version line hidden, not print a version nobody is on.
|
|
31
|
+
*/
|
|
32
|
+
export function parseUpdateStatus(body: unknown): UpdateStatus | null {
|
|
33
|
+
if (!isRecord(body) || !isInstallKind(body.install) || typeof body.version !== "string") return null;
|
|
34
|
+
return {
|
|
35
|
+
ready: body.ready === true,
|
|
36
|
+
install: body.install,
|
|
37
|
+
version: body.version,
|
|
38
|
+
commit: stringOrNull(body.commit),
|
|
39
|
+
latest: stringOrNull(body.latest),
|
|
40
|
+
notice: stringOrNull(body.notice),
|
|
41
|
+
};
|
|
42
|
+
}
|
|
@@ -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-
|
|
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-DMZf-3IA.js";import"./chunk-WYO6CB5R-nS6zX9ct-KrP8SxMs.js";import"./chunk-VAUOI2AC-BKx35BBi-E0yAewsj.js";import{n as i,r as a,t as o}from"./chunk-MOJQB5TN-CorQ_Pl1-mXFOYgnO.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-DMZf-3IA.js";export{e as createArchitectureServices};
|