mulmoterminal 4.5.0 → 4.6.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.
- package/README.md +33 -3
- package/bin/mulmoterminal.js +40 -1
- package/common/agentSessionList.ts +24 -0
- package/common/sessionContext.ts +24 -0
- package/common/sessionRunning.ts +31 -0
- package/dist/assets/{abnfDiagram-VRR7QNED-WSmThe6b-DPaEh_gN.js → abnfDiagram-VRR7QNED-WSmThe6b-944Gbk5i.js} +1 -1
- package/dist/assets/architecture-TIHT7OUA-Cqhmai3f-ByieX7iG.js +1 -0
- package/dist/assets/{architectureDiagram-ZJ3FMSHR-Tj3i7Oow-CUD1E04p.js → architectureDiagram-ZJ3FMSHR-Tj3i7Oow-BIeDl9Cb.js} +1 -1
- package/dist/assets/{blockDiagram-677ZJIJ3-c-hNYBhI-oMocpv9s.js → blockDiagram-677ZJIJ3-c-hNYBhI-CHoEKRcK.js} +1 -1
- package/dist/assets/{c4Diagram-LMCZKHZV-WIGVajf5-DCS5Kt2M.js → c4Diagram-LMCZKHZV-WIGVajf5-C3NSXDDO.js} +1 -1
- package/dist/assets/channel-OqG5cGJi-9tQa1RJG.js +1 -0
- package/dist/assets/{chunk-32BRIVSS-CtSq3QOR-D6jNTV1x.js → chunk-32BRIVSS-CtSq3QOR-P97bmQkL.js} +1 -1
- package/dist/assets/{chunk-52WLFC77-2Up0T-6t-qOt9ZLFS.js → chunk-52WLFC77-2Up0T-6t-DQEaQvVy.js} +1 -1
- package/dist/assets/{chunk-C7G6YPKG-ivengO-7-7utsyMTv.js → chunk-C7G6YPKG-ivengO-7-j3Jy_MLk.js} +1 -1
- package/dist/assets/{chunk-EX3LRPZG-BHoWQ6W8-6OAUxLJG.js → chunk-EX3LRPZG-BHoWQ6W8-DZez9M2G.js} +1 -1
- package/dist/assets/{chunk-FWX5IMBZ-PvRXPghr-CoUoZ066.js → chunk-FWX5IMBZ-PvRXPghr-GfoO6luk.js} +2 -2
- package/dist/assets/{chunk-HOUHSVGY-A3_zwY4q-Z32157__.js → chunk-HOUHSVGY-A3_zwY4q-nq20Wer2.js} +1 -1
- package/dist/assets/{chunk-ICXQ74PX-vzZqgurQ-4S5Kaqhr.js → chunk-ICXQ74PX-vzZqgurQ-D5yDpnEM.js} +1 -1
- package/dist/assets/{chunk-MOJQB5TN-CorQ_Pl1-BFdYgLZH.js → chunk-MOJQB5TN-CorQ_Pl1-Bd3mtm2K.js} +1 -1
- package/dist/assets/{chunk-OGEWGWER-BVhfs7WG-EE3Qh8NO.js → chunk-OGEWGWER-BVhfs7WG-EBKgCF2u.js} +1 -1
- package/dist/assets/{chunk-PUDLZKDR-CJo7KQJ3-D1PA0tz9.js → chunk-PUDLZKDR-CJo7KQJ3-B-xjmG4r.js} +1 -1
- package/dist/assets/{chunk-Q4XR5HBZ-DLkq8ZGO-ySWBhGnM.js → chunk-Q4XR5HBZ-DLkq8ZGO-FAAJasw-.js} +1 -1
- package/dist/assets/{chunk-V7JOEXUC-DqefuUOb-DhSm2NyP.js → chunk-V7JOEXUC-DqefuUOb-BHac54Dp.js} +1 -1
- package/dist/assets/{chunk-VAUOI2AC-BKx35BBi-B60QprFR.js → chunk-VAUOI2AC-BKx35BBi-C-5oHwZ4.js} +1 -1
- package/dist/assets/{chunk-VR4S4FIN-DpJgr4Ur-aiw-751p.js → chunk-VR4S4FIN-DpJgr4Ur-DPh5RPem.js} +1 -1
- package/dist/assets/{chunk-WYO6CB5R-nS6zX9ct-DWK9p9qg.js → chunk-WYO6CB5R-nS6zX9ct-HZI6iW4p.js} +1 -1
- package/dist/assets/{chunk-ZGVPDNZ5-DNtiHxpJ-cQBGQXJU.js → chunk-ZGVPDNZ5-DNtiHxpJ-moQJIMa1.js} +1 -1
- package/dist/assets/classDiagram-OUVF2IWQ-C6h0nbT3-Ct0W6XkH.js +1 -0
- package/dist/assets/classDiagram-v2-EOCWNBFH-CzsXJ_wA-Ct0W6XkH.js +1 -0
- package/dist/assets/cynefin-VYW2F7L2-DvSvuXnG-C2pDg7XE.js +1 -0
- package/dist/assets/{cynefinDiagram-TSTJHNR4-969y1qZK-76_lFdlS.js → cynefinDiagram-TSTJHNR4-969y1qZK-AyVAxduh.js} +1 -1
- package/dist/assets/{dagre-VKFMJZFB-CZfgAZFk-BIp6P02L.js → dagre-VKFMJZFB-CZfgAZFk-3FlboOqe.js} +1 -1
- package/dist/assets/{diagram-FQU43EPY-CSdnleGM-Cfb5V0UI.js → diagram-FQU43EPY-CSdnleGM-XmeOhiBK.js} +1 -1
- package/dist/assets/{diagram-G47NLZAW-DKYe-Mwx-DqsHnBaF.js → diagram-G47NLZAW-DKYe-Mwx-oGKIv19o.js} +1 -1
- package/dist/assets/{diagram-NH7WQ7WH-DMasKpwa-CNiFWceN.js → diagram-NH7WQ7WH-DMasKpwa-hNtNA4bT.js} +1 -1
- package/dist/assets/{diagram-OA4YK3LP-CSyc0BDR-OiAwSIjr.js → diagram-OA4YK3LP-CSyc0BDR-CgkF6797.js} +1 -1
- package/dist/assets/{diagram-WEI45ONY-CcJW2fNK-TQf1z8cW.js → diagram-WEI45ONY-CcJW2fNK-Bs6GsUVb.js} +1 -1
- package/dist/assets/{dist-BezNTABu.js → dist-BLDGY-kQ.js} +1 -1
- package/dist/assets/{dist-RBakV0o4.js → dist-DnpJnWYp.js} +1 -1
- package/dist/assets/{dist-BR8nhjbg.js → dist-DsyF0XCw.js} +1 -1
- package/dist/assets/{dist-9wGqhibT.js → dist-uMLVGS-I.js} +1 -1
- package/dist/assets/{ebnfDiagram-CCIWWBDH-CeBUH2N0-B8mwuH_Q.js → ebnfDiagram-CCIWWBDH-CeBUH2N0-qDGiZqxm.js} +1 -1
- package/dist/assets/{erDiagram-Q63AITRT-1OOp34oV-4zV7QoN3.js → erDiagram-Q63AITRT-1OOp34oV-CGCbIXw6.js} +1 -1
- package/dist/assets/eventmodeling-45OFAUF4-jdctDg0T-DGj5pagQ.js +1 -0
- package/dist/assets/flowDiagram-23GEKE2U-DK0InIny-CYoqs42L.js +1 -0
- package/dist/assets/{ganttDiagram-NO4QXBWP-DQT88dUZ-DmKfWKVt.js → ganttDiagram-NO4QXBWP-DQT88dUZ-BcXauXRP.js} +1 -1
- package/dist/assets/gitGraph-TEB2WS4Q-C4cKwl5j-hM_pJP8C.js +1 -0
- package/dist/assets/{gitGraphDiagram-IHSO6WYX-CeZGS4qi-CPiO74HP.js → gitGraphDiagram-IHSO6WYX-CeZGS4qi-CFqg-BSd.js} +1 -1
- package/dist/assets/index-DWpBB5bS.js +619 -0
- package/dist/assets/index-DnhwCMuN.css +1 -0
- package/dist/assets/info-DKCQHKI2-DPUCBYWS-D2hq_ZvH.js +1 -0
- package/dist/assets/{infoDiagram-FWYZ7A6U-BDt8lBTy-BJdFxf7J.js → infoDiagram-FWYZ7A6U-BDt8lBTy-DuWcN2yb.js} +1 -1
- package/dist/assets/{ishikawaDiagram-FXEZZL3T-DOHYs_AA-DN4-dfNt.js → ishikawaDiagram-FXEZZL3T-DOHYs_AA-B4h8r5-o.js} +1 -1
- package/dist/assets/{journeyDiagram-5HDEW3XC-B33IW9yy-D46iXC-G.js → journeyDiagram-5HDEW3XC-B33IW9yy-BnAHKNKa.js} +1 -1
- package/dist/assets/{kanban-definition-HUTT4EX6-Bkdm46eX-DaJbuRjn.js → kanban-definition-HUTT4EX6-Bkdm46eX-BH5Oa5jm.js} +1 -1
- package/dist/assets/{lib-BD8LgZAH.js → lib-3N8U0X_t.js} +1 -1
- package/dist/assets/{line-Dy_Qlcgo-DWmsY6xO.js → line-Dy_Qlcgo-C2GdKfnD.js} +1 -1
- package/dist/assets/{marp-CwNmXt5E.js → marp-DSdA8U3h.js} +1 -1
- package/dist/assets/{mermaid-parser.core-C1baW7NG-Bt8E3kO2.js → mermaid-parser.core-C1baW7NG-DSG0yv6A.js} +2 -2
- package/dist/assets/{mermaid.core-C09q4TmN-CdpmD79K.js → mermaid.core-C09q4TmN-yteTzMrj.js} +3 -3
- package/dist/assets/{mindmap-definition-LN4V7U3C-bfYIhPQ0-C4RQ97Ls.js → mindmap-definition-LN4V7U3C-bfYIhPQ0-CK8OM9lm.js} +1 -1
- package/dist/assets/packet-7NZHBO7P-CC7His0F-DBkSyrp5.js +1 -0
- package/dist/assets/{pegDiagram-2B236MQR-CZQOKUMC-BGzTvU6v.js → pegDiagram-2B236MQR-CZQOKUMC-BoW13vlD.js} +1 -1
- package/dist/assets/pie-RZYD4A2V-CCrcq2sL-DhH_1kd9.js +1 -0
- package/dist/assets/{pieDiagram-ENE6RG2P-DiVKPdHE-XKldq1E5.js → pieDiagram-ENE6RG2P-DiVKPdHE-ghK3nyU-.js} +1 -1
- package/dist/assets/{quadrantDiagram-ABIIQ3AL-CbPY3kXI-C5r0a9Sf.js → quadrantDiagram-ABIIQ3AL-CbPY3kXI-De-fNZFH.js} +1 -1
- package/dist/assets/radar-I7S5WNFK-C5TUrpHf-B2kw7JUI.js +1 -0
- package/dist/assets/railroad-3IZDKUUU-CGuuFEd8-DrgAOxGb.js +1 -0
- package/dist/assets/railroad-abnf-AHOZXSZD-DuoCSFZY-xKkuEcIV.js +1 -0
- package/dist/assets/railroad-ebnf-EBAXGLYW-ig-DG9e_-ax9Y6qHk.js +1 -0
- package/dist/assets/railroad-peg-LSFZ7HO6-BkBgpyvu-DI85BUnl.js +1 -0
- package/dist/assets/{railroadDiagram-RFXS5EU6-CFRaQzr0-YImSnBwl.js → railroadDiagram-RFXS5EU6-CFRaQzr0-BVCSojzw.js} +1 -1
- package/dist/assets/{requirementDiagram-TGXJPOKE-BiIDduje-CLDWdQ6G.js → requirementDiagram-TGXJPOKE-BiIDduje-B_R-QkST.js} +1 -1
- package/dist/assets/{sankeyDiagram-HTMAVEWB-DcK87A5Y-CzQDWlB1.js → sankeyDiagram-HTMAVEWB-DcK87A5Y-CAwdVvk0.js} +1 -1
- package/dist/assets/{sequenceDiagram-DBY2YBRQ-DgEQYcvc-Cql9GjHP.js → sequenceDiagram-DBY2YBRQ-DgEQYcvc-GvNe1Ov-.js} +1 -1
- package/dist/assets/{stateDiagram-2N3HPSRC-Bg7EXtW2-CN3bsM_d.js → stateDiagram-2N3HPSRC-Bg7EXtW2-DzBMtG4d.js} +1 -1
- package/dist/assets/stateDiagram-v2-6OUMAXLB-BjhArXP_-CS1Pl40x.js +1 -0
- package/dist/assets/{swimlanes-5IMT3BWC-CKORDKr0-cK0-DqfM.js → swimlanes-5IMT3BWC-CKORDKr0-CSoxYOxz.js} +1 -1
- package/dist/assets/swimlanesDiagram-G3AALYLV-CyvIfl1o-C573oTpM.js +8 -0
- package/dist/assets/{timeline-definition-FHXFAJF6-BM3Iky2r-C6aXUCxm.js → timeline-definition-FHXFAJF6-BM3Iky2r-DJknCJjt.js} +1 -1
- package/dist/assets/treeView-QDETBFTQ-CqfT0I1z-DIKDkQMT.js +1 -0
- package/dist/assets/treemap-6X3UGDF4-CiJkiGWo-StkZmf8x.js +1 -0
- package/dist/assets/{vennDiagram-L72KCM5P-VNmAhEFP-T681nWRy.js → vennDiagram-L72KCM5P-VNmAhEFP-DzdfLEFR.js} +1 -1
- package/dist/assets/wardley-OPB4EBWU-D1tuVHAV-D9snqrLP.js +1 -0
- package/dist/assets/{wardleyDiagram-EHGQE667-BkHQpyFm-D-AfB-NA.js → wardleyDiagram-EHGQE667-BkHQpyFm-B4K7c047.js} +1 -1
- package/dist/assets/{xychartDiagram-FW5EYKEG-Yz-8aLqK-CNzoNtQE.js → xychartDiagram-FW5EYKEG-Yz-8aLqK-BS6GgTLs.js} +1 -1
- package/dist/index.html +2 -2
- package/package.json +3 -3
- package/server/agents/antigravity-proto.ts +168 -0
- package/server/agents/antigravity-session.ts +9 -2
- package/server/agents/antigravity-sessions.ts +36 -0
- package/server/agents/antigravity-usage.ts +184 -0
- package/server/agents/codex-events.ts +20 -0
- package/server/agents/codex-usage.spec.ts +77 -0
- package/server/agents/codex-usage.ts +110 -0
- package/server/agents/grok-session.ts +6 -0
- package/server/agents/grok-sessions.ts +200 -0
- package/server/agents/grok-usage.ts +99 -0
- package/server/config/app-config.ts +39 -1
- package/server/config/dir-config.ts +6 -19
- package/server/config/dir-file.ts +33 -0
- package/server/config/dir-icon-detect.ts +7 -2
- package/server/config/dir-icon.ts +9 -20
- package/server/files/open-dir.ts +53 -15
- package/server/files/pick-file.ts +186 -31
- package/server/files/ps-quote.ts +7 -0
- package/server/files/win-folder-dialog.ts +25 -4
- package/server/files/wsl.ts +49 -0
- package/server/index.ts +1 -0
- package/server/routes/session-routes.ts +97 -13
- package/server/routes/ws-routes.ts +136 -133
- package/server/session/agent-badges.ts +200 -0
- package/server/session/agent-conversations.ts +25 -0
- package/server/session/dir-session.ts +20 -0
- package/server/session/last-turn.ts +3 -7
- package/server/session/spawn-antigravity.ts +24 -50
- package/server/session/spawn-deps.ts +4 -0
- package/server/session/spawn-directory-mcp.ts +91 -0
- package/server/session/spawn-grok.ts +12 -48
- package/server/session/transcript.ts +7 -4
- package/server/skills/mulmoterminal-model/SKILL.md +15 -3
- package/dist/assets/architecture-TIHT7OUA-Cqhmai3f-DCOr0rgu.js +0 -1
- package/dist/assets/channel-OqG5cGJi-3dRrNd2x.js +0 -1
- package/dist/assets/classDiagram-OUVF2IWQ-C6h0nbT3-he2Qx8Zy.js +0 -1
- package/dist/assets/classDiagram-v2-EOCWNBFH-CzsXJ_wA-he2Qx8Zy.js +0 -1
- package/dist/assets/cynefin-VYW2F7L2-DvSvuXnG-BM05JO9d.js +0 -1
- package/dist/assets/eventmodeling-45OFAUF4-jdctDg0T-D7yLQEKX.js +0 -1
- package/dist/assets/flowDiagram-23GEKE2U-DK0InIny-XdeCwjZj.js +0 -1
- package/dist/assets/gitGraph-TEB2WS4Q-C4cKwl5j-CNGA-Dxh.js +0 -1
- package/dist/assets/index-B7qYhdzG.js +0 -614
- package/dist/assets/index-DnimPwKc.css +0 -1
- package/dist/assets/info-DKCQHKI2-DPUCBYWS-DggNvHPl.js +0 -1
- package/dist/assets/packet-7NZHBO7P-CC7His0F-DIVJjy2R.js +0 -1
- package/dist/assets/pie-RZYD4A2V-CCrcq2sL-DbntX_Y9.js +0 -1
- package/dist/assets/radar-I7S5WNFK-C5TUrpHf-BjpTp9D5.js +0 -1
- package/dist/assets/railroad-3IZDKUUU-CGuuFEd8-BgrykldZ.js +0 -1
- package/dist/assets/railroad-abnf-AHOZXSZD-DuoCSFZY-4ECSfnJj.js +0 -1
- package/dist/assets/railroad-ebnf-EBAXGLYW-ig-DG9e_-DIGuLSDA.js +0 -1
- package/dist/assets/railroad-peg-LSFZ7HO6-BkBgpyvu-WBfEJm_q.js +0 -1
- package/dist/assets/stateDiagram-v2-6OUMAXLB-BjhArXP_-PWEWNNBX.js +0 -1
- package/dist/assets/swimlanesDiagram-G3AALYLV-CyvIfl1o-DRhfZv9k.js +0 -8
- package/dist/assets/treeView-QDETBFTQ-CqfT0I1z-C1kvz6Pn.js +0 -1
- package/dist/assets/treemap-6X3UGDF4-CiJkiGWo-CWCrFJlO.js +0 -1
- package/dist/assets/wardley-OPB4EBWU-D1tuVHAV-B-2c3CsH.js +0 -1
package/README.md
CHANGED
|
@@ -227,6 +227,7 @@ Needs **Node ≥ 22.9**, plus these CLIs on your `PATH`:
|
|
|
227
227
|
| Optional | `codex` | [Codex sessions](#agents-claude--codex) in a cell, alongside Claude | `npm i -g @openai/codex` |
|
|
228
228
|
| Optional | `ffmpeg` | video rendering from the [mulmo-script panel](#wiki-collections--the-gui-panel) (its plugin ships enabled) | `brew install ffmpeg` · `sudo apt install ffmpeg` · `sudo dnf install ffmpeg` |
|
|
229
229
|
| Optional | `ollama` | [`claude-ollama`](https://receptron.github.io/mulmoterminal/guide/en/claude-ollama.html) — Claude Code against a fully local model | [ollama.com/download](https://ollama.com/download) |
|
|
230
|
+
| Linux only | a file dialog | the **Choose a folder / Insert a file path** buttons, which open an OS dialog on the machine the server runs on. macOS and Windows have one built in; **WSL** uses the Windows one over interop and needs nothing installed. A Linux desktop needs one of these — without any, the buttons say so and you type the path instead (#1447) | `sudo apt install zenity` · `sudo dnf install zenity` · `kdialog`, `qarma` and `yad` also work |
|
|
230
231
|
|
|
231
232
|
The server starts without any of the non-required rows; you just lose that row's feature,
|
|
232
233
|
and the header/panel for it says so. `git` and `gh` are marked required because losing them
|
|
@@ -1142,6 +1143,33 @@ Each grid cell's header shows two badges for its session, refreshed when a turn
|
|
|
1142
1143
|
- **Token badge** — `⇡<in> ⇣<out>`: cumulative input (fresh + cache-read + cache-creation)
|
|
1143
1144
|
and output tokens for the session, k/M-formatted, with a full breakdown in the tooltip.
|
|
1144
1145
|
|
|
1146
|
+
**Both badges are read from the agent's own log**, so what each agent can show differs by
|
|
1147
|
+
what it writes down (`?agent=` on the route picks the reader):
|
|
1148
|
+
|
|
1149
|
+
| Agent | Context badge | Token badge |
|
|
1150
|
+
|---|---|---|
|
|
1151
|
+
| **Claude** | `Opus · ctx 35%` — window from the table above | full |
|
|
1152
|
+
| **Codex** | `gpt-5.5 · ctx 21%` — window from codex's own `model_context_window`, so no table to be out of date | full |
|
|
1153
|
+
| **Grok** | `grok-4.5 · ctx 33%` — window from grok's own `contextWindowTokens`, so no table either | full |
|
|
1154
|
+
| **Antigravity** | `Gemini 3.6 Flash · ctx 78%` — the model from the first step of the conversation's transcript, the reading from agy's own per-generation accounting (a real 256k window, not a table) | full |
|
|
1155
|
+
|
|
1156
|
+
The token badge hides itself when nothing has been counted, and the context badge shows
|
|
1157
|
+
the model alone unless it has **both** a *current-context* token count from the agent and a
|
|
1158
|
+
context window — agent-reported (codex, Grok, Antigravity) or resolved from the built-in table
|
|
1159
|
+
above (Claude, provider models). Either one missing means a name and no percentage. The two
|
|
1160
|
+
badges are independent: an Antigravity session whose accounting cannot be read still shows
|
|
1161
|
+
its model, and one whose cumulative totals are zero still shows a percentage. The context badge is absent
|
|
1162
|
+
entirely until an agent has named a model: codex and Antigravity file their logs under an id
|
|
1163
|
+
the agent mints *after* the session starts, so a brand-new cell shows no model badge until it
|
|
1164
|
+
has been prompted once — a few seconds, not the rest of the session.
|
|
1165
|
+
|
|
1166
|
+
Antigravity's numbers are the one case read from a store with **no published format**: agy keeps
|
|
1167
|
+
its per-generation accounting as protobuf in `~/.gemini/antigravity-cli/conversations/<id>.db`,
|
|
1168
|
+
with no schema on disk, so the fields are identified by measurement (see
|
|
1169
|
+
`server/agents/antigravity-usage.ts`). Every layer of that reader is built to answer *nothing*
|
|
1170
|
+
rather than a number it is unsure of, so if a future agy release moves those fields, an
|
|
1171
|
+
Antigravity cell falls back to showing its model alone — it will not show a wrong percentage.
|
|
1172
|
+
|
|
1145
1173
|
The **Settings** modal (⚙) shows an **estimated $ cost** — Session / Today / Month — from
|
|
1146
1174
|
`GET /api/cost`, using a built-in public per-model price table (cache reads billed at
|
|
1147
1175
|
0.1×, cache writes at 1.25× input). It's an estimate: real billing differs, **flat-plan
|
|
@@ -1369,7 +1397,7 @@ quietly answering about the **default workspace** (#1151):
|
|
|
1369
1397
|
| --- | --- |
|
|
1370
1398
|
| `/ws`, `/ws/codex`, `/ws/antigravity`, `/ws/grok`, `/ws/launch`, `/ws/run` | The socket is closed with `{ type: "error", message }`, which the terminal shows as a red banner and does not retry. |
|
|
1371
1399
|
| A session that is still running (`?session=` names a live PTY or a surviving tmux session) | **Attaches anyway**, with a warning in the server log. Moving or renaming a directory must not shut you out of an agent that is still working in it — and the cwd reported back comes from the running PTY, not from the request. |
|
|
1372
|
-
| `GET /api/scripts`, `/api/skills`, `/api/dir-config`, `/api/dir-sound`, `/api/git-status`, `/api/pr-phase`, `/api/header`, `/api/sessions`, `/api/codex/sessions`, `/api/antigravity/sessions`, `/api/session/:id`, `/api/transcript/*`, `/api/cost` | `404 { error, cwd }` — a directory that is not there. |
|
|
1400
|
+
| `GET /api/scripts`, `/api/skills`, `/api/dir-config`, `/api/dir-sound`, `/api/git-status`, `/api/pr-phase`, `/api/header`, `/api/sessions`, `/api/codex/sessions`, `/api/antigravity/sessions`, `/api/grok/sessions`, `/api/session/:id`, `/api/transcript/*`, `/api/cost` | `404 { error, cwd }` — a directory that is not there. |
|
|
1373
1401
|
| A `?cwd=` that cannot name a directory at all (relative, or repeated as `?cwd=a&cwd=b`) | `400 { error, cwd }`. |
|
|
1374
1402
|
|
|
1375
1403
|
A request that names **no** directory is unaffected: `CLAUDE_CWD` is then the answer it
|
|
@@ -1491,6 +1519,7 @@ same-origin-guarded.
|
|
|
1491
1519
|
| `GET /api/session/:id?cwd=` | One session's summary — cumulative `usage` and `context` (model + last-turn context tokens). Backs the cell token & ctx% badges. |
|
|
1492
1520
|
| `GET /api/codex/sessions?cwd=` | Codex sessions for the project (from `~/.codex` rollouts), newest first. |
|
|
1493
1521
|
| `GET /api/antigravity/sessions?cwd=` | Antigravity conversations for the project, newest first. agy does record a workspace, but never as a complete conversation-to-workspace map (`cache/last_conversations.json` keeps one conversation per directory and is written at exit; `history.jsonl` carries no conversation id), so the project comes from MulmoTerminal's own `~/.mulmoterminal/antigravity-conversations.jsonl`; agy's transcript supplies the title. |
|
|
1522
|
+
| `GET /api/grok/sessions?cwd=` | Grok conversations for the project, newest first. `~/.grok/sessions` is partitioned by working directory (percent-encoded), so this is a directory listing; each conversation's `summary.json` supplies the title and the last-active time, falling back to the directory's `prompt_history.jsonl`. |
|
|
1494
1523
|
| `GET /api/cost?cwd=&session=` | Estimated $ cost — session / today / month. |
|
|
1495
1524
|
| `GET /api/transcript/timeline?session=&cwd=` | Per-session activity timeline (tools run). |
|
|
1496
1525
|
| `GET /api/transcript/last-turn?session=&cwd=&agent=` | A session's last completed exchange (`prompt`, `reply`) plus the `text` to paste into another terminal. `agent=codex` reads the codex rollout instead of the Claude transcript. |
|
|
@@ -1541,7 +1570,7 @@ same-origin-guarded.
|
|
|
1541
1570
|
| `POST /api/transcribe`(`/model`…) | Voice-input transcription (Whisper, macOS). |
|
|
1542
1571
|
| `POST /api/translation` | Runtime UI-string translation. |
|
|
1543
1572
|
| `GET /api/remote-host/status` · `POST /api/remote-host/{connect,disconnect}` | Companion phone-client link. Each response carries the command channel's `health` (`online` / `reconnecting` / `offline`, plus the last listener error), so the toolbar shows a dropped channel instead of the last state it happened to fetch. |
|
|
1544
|
-
| `POST /api/open-dir` · `POST /api/pick-file` | Reveal a dir in Finder/Explorer; OS file-picker → path (`{ directory: true }` opens the folder picker — used by the launcher's Working-directory 📁 button). |
|
|
1573
|
+
| `POST /api/open-dir` · `POST /api/pick-file` | Reveal a dir in Finder/Explorer; OS file-picker → path (`{ directory: true }` opens the folder picker — used by the launcher's Working-directory 📁 button). Both run on the SERVER's machine, and both answer **500 with a reason** when it has nothing to open a dialog with, rather than a silent nothing (#1447). The picker tries every dialog the host might have: macOS `osascript`, Windows PowerShell, **WSL** the Windows dialog over interop (`powershell.exe` + `wslpath`), Linux `zenity` → `kdialog` → `qarma` → `yad`. A user cancel is a 200 with `paths: []`. |
|
|
1545
1574
|
| `POST /api/session/:id/drop` | A dropped file whose path the browser withheld. **Raw bytes**, not JSON, under the file's own content type (base64 in JSON would cap real files near 18 MB, and a dropped `.json` would be parsed as a document); the original name rides percent-encoded in `x-drop-filename` and is used for its **suffix only**. Answers `{ path }` — absolute, inside the private per-session directory the session was granted at launch. 110 MiB cap; 404 for a session this server isn't running. |
|
|
1546
1575
|
|
|
1547
1576
|
The phone itself uses **none** of these routes — it reaches the host over Firestore command
|
|
@@ -1857,7 +1886,8 @@ server/
|
|
|
1857
1886
|
git/ git, GitHub (gh) and GitLab (glab) + worktrees: git-status.ts, gitRemote.ts,
|
|
1858
1887
|
gh.ts, prs.ts, issues.ts, pr-for-branch.ts, worktrees.ts, worktree-*.ts
|
|
1859
1888
|
files/ files-browse.ts (contained tree read/write), pick-file.ts,
|
|
1860
|
-
open-dir.ts,
|
|
1889
|
+
open-dir.ts, wsl.ts (interop detection + wslpath),
|
|
1890
|
+
scripts.ts (Run-menu script.json loader)
|
|
1861
1891
|
infra/ process/transport/misc: tmux.ts, tmux-routes.ts,
|
|
1862
1892
|
pubsub.ts (socket.io /ws/pubsub), spa-fallback.ts, host-tools.ts,
|
|
1863
1893
|
plugins-registry.ts, web-push.ts, install-bundled-skills.ts, accounting-tool.ts
|
package/bin/mulmoterminal.js
CHANGED
|
@@ -9,6 +9,7 @@ import { execSync, spawn } from "node:child_process";
|
|
|
9
9
|
import { existsSync, statSync } from "node:fs";
|
|
10
10
|
import { createRequire } from "node:module";
|
|
11
11
|
import { createServer } from "node:net";
|
|
12
|
+
import { release } from "node:os";
|
|
12
13
|
import { dirname, join, resolve } from "node:path";
|
|
13
14
|
import { createInterface } from "node:readline";
|
|
14
15
|
import { fileURLToPath } from "node:url";
|
|
@@ -106,6 +107,40 @@ const PATH_TOOLS = [
|
|
|
106
107
|
{ cmd: "ollama", versionArg: "--version", required: false, why: "a fully local model via claude-ollama", hint: "https://ollama.com/download" },
|
|
107
108
|
];
|
|
108
109
|
|
|
110
|
+
// The variables WSL exports into a login shell, then the kernel that names itself
|
|
111
|
+
// (`…-microsoft-standard-WSL2`, `…-Microsoft` on WSL1) for the processes those variables never
|
|
112
|
+
// reach. Mirrors `isWsl()` in server/files/wsl.ts, which this file cannot import: bin runs as
|
|
113
|
+
// plain JS, the server runs through tsx. Keep the two in step.
|
|
114
|
+
function isWslHost() {
|
|
115
|
+
if (process.platform !== "linux") return false;
|
|
116
|
+
return Boolean(process.env.WSL_DISTRO_NAME || process.env.WSL_INTEROP) || /microsoft/i.test(release());
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// The file dialog is the one requirement that differs per host, so it is checked per host rather
|
|
120
|
+
// than listed above: macOS and Windows have one built in and can't be missing it. WSL reaches the
|
|
121
|
+
// Windows dialog over interop, and a Linux desktop has whichever toolkit it was installed with —
|
|
122
|
+
// zenity's absence there is what makes the picker look broken (#1447).
|
|
123
|
+
function fileDialogTool() {
|
|
124
|
+
if (process.platform === "darwin" || process.platform === "win32") return null;
|
|
125
|
+
const why = "the file / folder picker";
|
|
126
|
+
if (isWslHost()) {
|
|
127
|
+
return {
|
|
128
|
+
cmd: "powershell.exe",
|
|
129
|
+
versionArg: "-NoProfile -Command exit",
|
|
130
|
+
required: false,
|
|
131
|
+
why: `${why}, using the Windows dialog`,
|
|
132
|
+
hint: "enable WSL interop (wsl.conf), or: sudo apt install zenity",
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
return {
|
|
136
|
+
cmd: "zenity",
|
|
137
|
+
versionArg: "--version",
|
|
138
|
+
required: false,
|
|
139
|
+
why: `${why} (kdialog / qarma / yad also work)`,
|
|
140
|
+
hint: "sudo apt install zenity · sudo dnf install zenity",
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
|
|
109
144
|
function toolCheckLine({ cmd, versionArg, required, why, hint }) {
|
|
110
145
|
if (hasCommand(cmd, versionArg)) return ` ✓ ${cmd} — ${why}`;
|
|
111
146
|
const head = required ? ` ✗ ${cmd} — not found, needed for ${why}` : ` ○ ${cmd} — optional (${why})`;
|
|
@@ -139,7 +174,7 @@ async function runInit(initArgs) {
|
|
|
139
174
|
console.log(" → npm install -g @anthropic-ai/claude-code (then run `claude` and log in)");
|
|
140
175
|
}
|
|
141
176
|
|
|
142
|
-
PATH_TOOLS.forEach((tool) => console.log(toolCheckLine(tool)));
|
|
177
|
+
[...PATH_TOOLS, fileDialogTool()].filter(Boolean).forEach((tool) => console.log(toolCheckLine(tool)));
|
|
143
178
|
|
|
144
179
|
// Config half: derive working-dir presets from Claude history + write config.json.
|
|
145
180
|
console.log("");
|
|
@@ -188,9 +223,13 @@ function runGoogle(googleArgs) {
|
|
|
188
223
|
});
|
|
189
224
|
}
|
|
190
225
|
|
|
226
|
+
// WSL has no Linux browser to open (and often no `xdg-open` either), so the URL goes to the
|
|
227
|
+
// Windows shell — `start` through cmd.exe, which is what opens the user's real browser. It exits
|
|
228
|
+
// 0, unlike `explorer.exe`, so a failure here still means a failure.
|
|
191
229
|
function pickOpenCommand() {
|
|
192
230
|
if (process.platform === "darwin") return "open";
|
|
193
231
|
if (process.platform === "win32") return "start";
|
|
232
|
+
if (isWslHost()) return 'cmd.exe /c start ""';
|
|
194
233
|
return "xdg-open";
|
|
195
234
|
}
|
|
196
235
|
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// Where each agent's own past conversations are listed — one route per agent, keyed by the agent.
|
|
2
|
+
//
|
|
3
|
+
// The launcher's "or resume here" list shows the conversations of whatever the Agent Picker has
|
|
4
|
+
// selected, and each agent keeps its history in its own place: Claude in `~/.claude/projects`,
|
|
5
|
+
// codex in `~/.codex/sessions`, agy in its brain directory (found through our own log), grok in a
|
|
6
|
+
// per-cwd directory under `~/.grok/sessions`. Four stores, four listers, four routes — so the
|
|
7
|
+
// route is chosen, not built.
|
|
8
|
+
//
|
|
9
|
+
// In `common/` because both sides decide from it: the server mounts these paths
|
|
10
|
+
// (server/routes/session-routes.ts) and the UI fetches them (src/composables/useDirLists.ts). A
|
|
11
|
+
// `Record<TerminalAgent, …>` rather than a lookup with a fallback, so a fifth agent is a TYPE
|
|
12
|
+
// ERROR here instead of a picker option that silently lists Claude's history under another name —
|
|
13
|
+
// which is the bug this whole map exists to fix (#1417).
|
|
14
|
+
import type { TerminalAgent } from "./sessionAgent.js";
|
|
15
|
+
|
|
16
|
+
export const AGENT_SESSION_LIST_PATHS: Record<TerminalAgent, string> = {
|
|
17
|
+
claude: "/api/sessions",
|
|
18
|
+
codex: "/api/codex/sessions",
|
|
19
|
+
antigravity: "/api/antigravity/sessions",
|
|
20
|
+
grok: "/api/grok/sessions",
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
/** The listing URL for one agent's conversations in one directory. */
|
|
24
|
+
export const agentSessionListUrl = (agent: TerminalAgent, cwd: string): string => `${AGENT_SESSION_LIST_PATHS[agent]}?cwd=${encodeURIComponent(cwd)}`;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// Which model a session is running and how full its context is: the `context` object
|
|
2
|
+
// GET /api/session/:id answers with, and the thing the header's model badge renders.
|
|
3
|
+
//
|
|
4
|
+
// In `common/` because BOTH sides decide from it. The server fills it from whichever log the
|
|
5
|
+
// session's agent keeps, and the client decides from `contextWindow` whether to trust the agent's
|
|
6
|
+
// own window or fall back to its per-model table (`src/components/modelBadge.ts`). It was mirrored
|
|
7
|
+
// as `LatestTurnContext` on the server and `CellContext` in the UI; both are now this.
|
|
8
|
+
export interface SessionContextInfo {
|
|
9
|
+
/** null until a turn has told us — a session that has not answered yet wears no badge. */
|
|
10
|
+
model: string | null;
|
|
11
|
+
/** Tokens re-sent as context for the NEXT turn, off the most recent completed turn. */
|
|
12
|
+
contextTokens: number;
|
|
13
|
+
/**
|
|
14
|
+
* The model's context window, when the AGENT ITSELF reports one. codex writes
|
|
15
|
+
* `model_context_window` into every `token_count` event, grok `contextWindowTokens` into its
|
|
16
|
+
* `signals.json` and agy the window into its accounting store, which is better than any table we
|
|
17
|
+
* can keep: the substring list in
|
|
18
|
+
* modelBadge.ts has already claimed a model whose window it had wrong (#985), and nothing on
|
|
19
|
+
* this side can notice when a provider changes one.
|
|
20
|
+
*
|
|
21
|
+
* Absent (or null) means nobody told us, NOT "no window" — the client falls back to its table.
|
|
22
|
+
*/
|
|
23
|
+
contextWindow?: number | null;
|
|
24
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// Whether a listed conversation still has a session RUNNING for it, and under which key.
|
|
2
|
+
//
|
|
3
|
+
// Deliberately not part of `SessionOccupancy` next door, which answers a different question for a
|
|
4
|
+
// different caller: "is a terminal holding this right now", the fact a second cell must know before
|
|
5
|
+
// offering to open it. That one is computed from `tmux list-clients` — which reports only sessions
|
|
6
|
+
// that HAVE a client, so it is structurally blind to the case here: a session running with nobody
|
|
7
|
+
// attached. Those are what a server restart leaves behind, and they piled up unseen because nothing
|
|
8
|
+
// in the app could see them either (#1467).
|
|
9
|
+
//
|
|
10
|
+
// In `common/` because both sides decide from it: the server fills it from its pty table plus
|
|
11
|
+
// `tmux list-sessions` (routes/session-routes.ts), and the launcher draws the marker and the stop
|
|
12
|
+
// button from it (components/CellLaunchForm.vue).
|
|
13
|
+
|
|
14
|
+
export interface SessionRunning {
|
|
15
|
+
/**
|
|
16
|
+
* The key of the session running for this row, or null when nothing is.
|
|
17
|
+
*
|
|
18
|
+
* A KEY, not the row's id. A codex/agy conversation started from a grid cell runs under a key
|
|
19
|
+
* MulmoTerminal minted, and only that agent's conversation log connects the two — the same reason
|
|
20
|
+
* `attached` consults it. Terminating the row's id there would kill nothing and report success.
|
|
21
|
+
*/
|
|
22
|
+
runningKey: string | null;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* The same field as the CLIENT may receive it — optional, like `PartialSessionOccupancy`: a page
|
|
27
|
+
* left open across an upgrade parses rows from a server that never said. Absent must read as
|
|
28
|
+
* "nothing running", so an older server's rows keep their old behaviour (no marker, no button)
|
|
29
|
+
* rather than offering to stop something that was never asked about.
|
|
30
|
+
*/
|
|
31
|
+
export type PartialSessionRunning = Partial<SessionRunning>;
|
|
@@ -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-DSG0yv6A.js";import"./chunk-WYO6CB5R-nS6zX9ct-HZI6iW4p.js";import"./chunk-VAUOI2AC-BKx35BBi-C-5oHwZ4.js";import{n as i,r as a,t as o}from"./chunk-MOJQB5TN-CorQ_Pl1-Bd3mtm2K.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-DSG0yv6A.js";export{e as createArchitectureServices};
|