mulmoterminal 8.8.0 → 9.1.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 +1 -0
- package/bin/mulmoterminal.js +3 -0
- package/bin/remotion-check.d.ts +5 -0
- package/bin/remotion-check.js +61 -0
- package/common/dirConfigSource.ts +7 -0
- package/common/mobileFiles.ts +113 -0
- package/dist/assets/{abnfDiagram-O67JEVCF-ByeTkitP.js → abnfDiagram-O67JEVCF-Cql7eDy4.js} +1 -1
- package/dist/assets/architecture-7GRP2DOG-CZIYYJ4J.js +1 -0
- package/dist/assets/{architectureDiagram-NJMV4G6O-BS-bIJ9p.js → architectureDiagram-NJMV4G6O-BPwX4Kdv.js} +1 -1
- package/dist/assets/{blockDiagram-BEXU5L5S-B2ROJmyY.js → blockDiagram-BEXU5L5S-CfKfvGbN.js} +1 -1
- package/dist/assets/{c4Diagram-YGBWAQC7-Ca1VT7np.js → c4Diagram-YGBWAQC7-BxkigRnJ.js} +1 -1
- package/dist/assets/channel-C7PAQOe4.js +1 -0
- package/dist/assets/{chunk-3FUC2YCW-4aA8NTzP.js → chunk-3FUC2YCW-HE1nZO4E.js} +1 -1
- package/dist/assets/{chunk-5DYCD2WN-CsUnssZn.js → chunk-5DYCD2WN-DAiWE_L-.js} +1 -1
- package/dist/assets/{chunk-742MDFTN-7XZaey_z.js → chunk-742MDFTN-0z7Oj4QR.js} +1 -1
- package/dist/assets/{chunk-7INBJB4K-dLz1-dKv.js → chunk-7INBJB4K-Cbz_RcWe.js} +1 -1
- package/dist/assets/{chunk-7M6MHVWA-D1e-V9YF.js → chunk-7M6MHVWA-D0fHotJI.js} +1 -1
- package/dist/assets/{chunk-7PRAP22T-CnkOGYpM.js → chunk-7PRAP22T-C14mAIqt.js} +1 -1
- package/dist/assets/{chunk-GTNCS2PH-SdNqERG5.js → chunk-GTNCS2PH-C-P8WS3W.js} +1 -1
- package/dist/assets/{chunk-GWA4HPMP-Drwy794D.js → chunk-GWA4HPMP-CB4GBCTJ.js} +1 -1
- package/dist/assets/{chunk-MBY4JIJT-DSAANxSJ.js → chunk-MBY4JIJT-IceNmBgh.js} +1 -1
- package/dist/assets/{chunk-NETBCI7D-BXp9T8Ca.js → chunk-NETBCI7D-BSYUBzfP.js} +1 -1
- package/dist/assets/{chunk-O7XYJQB3-GC1aNmH_.js → chunk-O7XYJQB3-BWsd-NGX.js} +1 -1
- package/dist/assets/{chunk-UA2S7LBM-Cw3wF3Tn.js → chunk-UA2S7LBM-CefRaTtZ.js} +1 -1
- package/dist/assets/{chunk-WEXAMYUT-CS8Kpesb.js → chunk-WEXAMYUT-DWwNhWea.js} +1 -1
- package/dist/assets/{chunk-Z7XXMR3K-CykBR0l-.js → chunk-Z7XXMR3K-AxGELBoY.js} +1 -1
- package/dist/assets/{chunk-ZIGJFQKS-BUT-ZZpU.js → chunk-ZIGJFQKS-BjGm6Q_-.js} +1 -1
- package/dist/assets/{classDiagram-v2-NBCMYWYE-C8sptdpH.js → classDiagram-v2-NBCMYWYE-DvblB8tx.js} +1 -1
- package/dist/assets/{cynefin-OW5HDTMX-COfTpi2w.js → cynefin-OW5HDTMX-DtUMK6KD.js} +1 -1
- package/dist/assets/{cynefinDiagram-VND7K2PF-Dg6UIUpz.js → cynefinDiagram-VND7K2PF-CAwbB6dF.js} +1 -1
- package/dist/assets/{dagre-6A5THRUB-Cc_39P-v.js → dagre-6A5THRUB-D5XInuQL.js} +1 -1
- package/dist/assets/{diagram-22UHCM2B-BH-GHrUM.js → diagram-22UHCM2B-CBr8zyf2.js} +1 -1
- package/dist/assets/{diagram-3UASUU5V-M61XyUBN.js → diagram-3UASUU5V-CPh2LwGn.js} +1 -1
- package/dist/assets/{diagram-ATOU4E4O-BNoWQWTb.js → diagram-ATOU4E4O-CZtXRSJ1.js} +1 -1
- package/dist/assets/{diagram-CDSNMT55-CABlLH-2.js → diagram-CDSNMT55-9xay63d0.js} +1 -1
- package/dist/assets/{diagram-MLGK6HIB-B5iLdk3Z.js → diagram-MLGK6HIB-B1gXSuka.js} +1 -1
- package/dist/assets/{diagram-MPIPVDR6-DwltgZb2.js → diagram-MPIPVDR6-D2cdkgqI.js} +1 -1
- package/dist/assets/{dist-BIiP-j2f.js → dist-B6NNAnlb.js} +1 -1
- package/dist/assets/{dist-mhpU1YKL.js → dist-BvxNDT5q.js} +1 -1
- package/dist/assets/{dist-DO_0aHHA.js → dist-COSExo-X.js} +1 -1
- package/dist/assets/{dist-DiTCjsAB.js → dist-CRU2Hx9e.js} +1 -1
- package/dist/assets/{dist-CvKELT7c.js → dist-DiGRwfdQ.js} +1 -1
- package/dist/assets/{ebnfDiagram-ZINNZB2B-CXKDVnbA.js → ebnfDiagram-ZINNZB2B-zw7fYT4W.js} +1 -1
- package/dist/assets/{elk-276RUBZZ-CIZxclQh.js → elk-276RUBZZ-BnbzbO70.js} +1 -1
- package/dist/assets/{erDiagram-OPXOYQCR-C0P_9FC1.js → erDiagram-OPXOYQCR-D3ybTKMV.js} +1 -1
- package/dist/assets/eventmodeling-NTZA5JFV-Du3-gAJl.js +1 -0
- package/dist/assets/flowDiagram-KWPJA3E3-DM38I9KM.js +1 -0
- package/dist/assets/{ganttDiagram-FUAMR5RP-as-EpyjU.js → ganttDiagram-FUAMR5RP-B9IuJaJ7.js} +1 -1
- package/dist/assets/{gitGraph-4MIJSDKK-Czjicpkr.js → gitGraph-4MIJSDKK-CACnw5Rn.js} +1 -1
- package/dist/assets/{gitGraphDiagram-X574FWY7-rc6lYZrW.js → gitGraphDiagram-X574FWY7-mJeRIXgv.js} +1 -1
- package/dist/assets/{index-gp21O7C7.js → index-ywZ0KgS0.js} +332 -303
- package/dist/assets/{info-A6RAGUB7-o0iVLyAo.js → info-A6RAGUB7-B_99gUG6.js} +1 -1
- package/dist/assets/{infoDiagram-VRGFBTTK-CfyUtjjF.js → infoDiagram-VRGFBTTK-CIahd7m7.js} +1 -1
- package/dist/assets/{ishikawaDiagram-OU5B5YK6-DnAtxy_T.js → ishikawaDiagram-OU5B5YK6-_pJwf5z0.js} +1 -1
- package/dist/assets/{journeyDiagram-ZHPQQLJL-D1Phskjm.js → journeyDiagram-ZHPQQLJL-DVu1r_Sp.js} +1 -1
- package/dist/assets/{kanban-definition-PNTS6WVX-BsGYr-P5.js → kanban-definition-PNTS6WVX-Bvf-1KYk.js} +1 -1
- package/dist/assets/{line-CvrAzUfn.js → line-B8A3a3kh.js} +1 -1
- package/dist/assets/{manifold-BiT8ya2j.js → manifold-B4xOJLzD.js} +1 -1
- package/dist/assets/{mermaid-parser.core-CEi2Px_a.js → mermaid-parser.core-DaS4aeEe.js} +3 -3
- package/dist/assets/{mermaid.core-_gwfjuDB.js → mermaid.core-CnYkvp8n.js} +4 -4
- package/dist/assets/{mindmap-definition-NLK3R4M7-khVpAwQW.js → mindmap-definition-NLK3R4M7-CpbXJFTL.js} +1 -1
- package/dist/assets/{packet-AYTQ26CC-Dfg6OZVH.js → packet-AYTQ26CC-jcWTTmks.js} +1 -1
- package/dist/assets/{pegDiagram-GJSIUBJH-DDUqfWnv.js → pegDiagram-GJSIUBJH-Dbc2tsyn.js} +1 -1
- package/dist/assets/{pie-WAS4IAKB-DMsEjDvX.js → pie-WAS4IAKB-CizFfv6i.js} +1 -1
- package/dist/assets/{pieDiagram-5QR66LMP-Cwhk_Wbg.js → pieDiagram-5QR66LMP-DXX3IcV9.js} +1 -1
- package/dist/assets/{quadrantDiagram-O4NWA36T-DpUkdI7g.js → quadrantDiagram-O4NWA36T-D-DOXsw7.js} +1 -1
- package/dist/assets/{radar-RG4KPBEZ-CrDzBZ--.js → radar-RG4KPBEZ-DVaylYAV.js} +1 -1
- package/dist/assets/{railroad-74A4TZTK-Bu3KvE6J.js → railroad-74A4TZTK-DEszSi6n.js} +1 -1
- package/dist/assets/railroad-abnf-HS5TGJTU-BvKljvCm.js +1 -0
- package/dist/assets/railroad-ebnf-LZEXJU2U-C0PANGU1.js +1 -0
- package/dist/assets/railroad-peg-WCYAUIDC-iA0I8YHa.js +1 -0
- package/dist/assets/{railroadDiagram-XR7U4H2S-CPc8T2h7.js → railroadDiagram-XR7U4H2S-D3kqADTa.js} +1 -1
- package/dist/assets/{requirementDiagram-PLB6GJNP-DQ2oYrP1.js → requirementDiagram-PLB6GJNP-YpGYYUq8.js} +1 -1
- package/dist/assets/{sankeyDiagram-IPEJSGJF-2Uz2Meev.js → sankeyDiagram-IPEJSGJF-R4KL4_Zi.js} +1 -1
- package/dist/assets/{sequenceDiagram-PO4LG4MO-BBh835RL.js → sequenceDiagram-PO4LG4MO-tIIojIJD.js} +1 -1
- package/dist/assets/{stateDiagram-v2-GCMORJYK-Bc_98LX6.js → stateDiagram-v2-GCMORJYK-D9jE6vCT.js} +1 -1
- package/dist/assets/{swimlanes-2SLR337P-vUUyNnl4.js → swimlanes-2SLR337P-Bw9cn0PT.js} +1 -1
- package/dist/assets/swimlanesDiagram-TC7HE7FX-BzC92HZb.js +8 -0
- package/dist/assets/{timeline-definition-EJHVYXUP-BkOMOqNA.js → timeline-definition-EJHVYXUP-vzEfdjnB.js} +1 -1
- package/dist/assets/{treeView-Q6P3EWNA-D7IKO2ct.js → treeView-Q6P3EWNA-Lt-Je8zH.js} +1 -1
- package/dist/assets/{treemap-WGGIJYW6-BOilElad.js → treemap-WGGIJYW6-BY_7_NMi.js} +1 -1
- package/dist/assets/{usecaseDiagram-POWQR4AR-CEqD1QMX.js → usecaseDiagram-POWQR4AR-Dgsia1SG.js} +1 -1
- package/dist/assets/{vennDiagram-UO4OBE2U-DB0WIEZ_.js → vennDiagram-UO4OBE2U-C6RtvXya.js} +1 -1
- package/dist/assets/{wardley-WFR3VGLG-C4idmWYw.js → wardley-WFR3VGLG-B2gP_do0.js} +1 -1
- package/dist/assets/{wardleyDiagram-VNRHLVJA-C_OGELwo.js → wardleyDiagram-VNRHLVJA-DeqTsydI.js} +1 -1
- package/dist/assets/{xychartDiagram-PMCCYNJV-CgXABm2q.js → xychartDiagram-PMCCYNJV-D2Sngf-8.js} +1 -1
- package/dist/index.html +1 -1
- package/docs/guide/en/v9.0.0.md +93 -0
- package/docs/guide/en/v9.1.0.md +72 -0
- package/docs/guide/ja/v9.0.0.md +89 -0
- package/docs/guide/ja/v9.1.0.md +63 -0
- package/package.json +8 -8
- package/server/backends/collections.ts +10 -14
- package/server/backends/remoteHost/getFeed.spec.ts +1 -0
- package/server/backends/remoteHost/handlers/deps.ts +4 -0
- package/server/backends/remoteHost/handlers/index.ts +4 -0
- package/server/backends/remoteHost/handlers/listCollectionProjects.ts +2 -2
- package/server/backends/remoteHost/handlers/mobileFiles.ts +154 -0
- package/server/backends/remoteHost/handlers.spec.ts +5 -0
- package/server/backends/remoteHost/hostScreens.ts +13 -1
- package/server/backends/remoteHost/index.ts +15 -4
- package/server/backends/remoteHost/mobileFileInline.ts +109 -0
- package/server/backends/remoteHost/mobileFileProject.ts +20 -0
- package/server/backends/remoteHost/mobileFileStaging.ts +118 -0
- package/server/backends/remoteHost/mobileFileWalk.ts +94 -0
- package/server/backends/remoteHost/terminalScreen.ts +6 -0
- package/server/backends/viewDataParams.ts +27 -0
- package/server/config/config-schema.ts +22 -0
- package/server/config/dir-config.ts +37 -3
- package/server/config/dir-file.ts +11 -2
- package/server/config/worktree-dir-config.ts +2 -0
- package/server/skills/mulmoterminal-config/SKILL.md +22 -2
- package/server/skills/mulmoterminal-dirs/SKILL.md +2 -2
- package/dist/assets/architecture-7GRP2DOG-C2yiAYE0.js +0 -1
- package/dist/assets/channel-BipplUhD.js +0 -1
- package/dist/assets/eventmodeling-NTZA5JFV-B4q1QvMs.js +0 -1
- package/dist/assets/flowDiagram-KWPJA3E3-_kpq6Bfi.js +0 -1
- package/dist/assets/railroad-abnf-HS5TGJTU-CSZDmotE.js +0 -1
- package/dist/assets/railroad-ebnf-LZEXJU2U-DvAT5oFw.js +0 -1
- package/dist/assets/railroad-peg-WCYAUIDC-asx-q7nj.js +0 -1
- package/dist/assets/swimlanesDiagram-TC7HE7FX-9mksZc5U.js +0 -8
package/README.md
CHANGED
|
@@ -289,6 +289,7 @@ Needs **Node ≥ 22.12**, plus these CLIs — on your `PATH`, or named by the ma
|
|
|
289
289
|
| Recommended | `tmux` | [session persistence](#session-persistence-tmux) — terminals survive a server restart | `brew install tmux` · `sudo apt install tmux` · `sudo dnf install tmux` · no native Windows build (falls back to plain PTYs) |
|
|
290
290
|
| Optional | any other agent CLI | a cell can run **Codex**, **Antigravity** (`agy`), **Grok**, **Muse**, **GitHub Copilot CLI** or **Cursor CLI** instead of Claude — install only the ones you use, and a missing one simply fails to start that cell. What each can do is [the capability matrix](docs/agent-capability-matrix.md); how to install and pick one is the [agents guide](https://receptron.github.io/mulmoterminal/guide/en/agents.html) | e.g. `npm i -g @openai/codex` |
|
|
291
291
|
| 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` |
|
|
292
|
+
| Optional | `remotion` packages | MulmoCast's `remotion` beats, where Claude Code writes each scene as a Remotion component (mulmocast 2.13.0). Not a dependency of this app: install them yourself, into your home directory so an `npx` upgrade does not lose them — `init` reports whether mulmocast can see them | [Remotion scenes](https://receptron.github.io/mulmoterminal/guide/en/mulmocast.html#remotion) · [日本語](https://receptron.github.io/mulmoterminal/guide/ja/mulmocast.html#remotion) |
|
|
292
293
|
| 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) |
|
|
293
294
|
| Linux only | a file dialog | the launcher's **Choose a folder** button and the path menu's **Insert a file path**, 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, they say so and you type the path instead (#1447) | `sudo apt install zenity` · `sudo dnf install zenity` · `kdialog`, `qarma` and `yad` also work |
|
|
294
295
|
|
package/bin/mulmoterminal.js
CHANGED
|
@@ -14,6 +14,7 @@ import { dirname, join, resolve } from "node:path";
|
|
|
14
14
|
import { fileURLToPath } from "node:url";
|
|
15
15
|
import { computeUpdateNotice, isUpdateCheckDisabled } from "./update-check.js";
|
|
16
16
|
import { detectNpxCacheDir, npxCacheHintLines } from "./npx-cache-hint.js";
|
|
17
|
+
import { remotionCheck } from "./remotion-check.js";
|
|
17
18
|
import { configuredRemoteServer, sshTunnelHintLines } from "./ssh-hint.js";
|
|
18
19
|
import { planAfterServerExit } from "./server-supervision.js";
|
|
19
20
|
import { waitUntilReady } from "./wait-ready.js";
|
|
@@ -254,6 +255,8 @@ async function runInit(initArgs) {
|
|
|
254
255
|
}
|
|
255
256
|
|
|
256
257
|
[...PATH_TOOLS, fileDialogTool()].filter(Boolean).forEach((tool) => console.log(toolCheckLine(tool)));
|
|
258
|
+
const remotionLine = await remotionCheck(PKG_DIR);
|
|
259
|
+
if (remotionLine) console.log(remotionLine);
|
|
257
260
|
|
|
258
261
|
// Config half: derive working-dir presets from Claude history + write config.json.
|
|
259
262
|
console.log("");
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export declare function resolverFromMulmocast(pkgDir: string): ((name: string) => boolean) | null;
|
|
2
|
+
export declare function remotionPackagesFromMulmocast(pkgDir: string): Promise<readonly string[] | null>;
|
|
3
|
+
export declare function missingRemotionPackages(packages: readonly string[], isResolvable: (name: string) => boolean): string[];
|
|
4
|
+
export declare function remotionCheckLine(missing: readonly string[], total: number): string;
|
|
5
|
+
export declare function remotionCheck(pkgDir: string): Promise<string | null>;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
// Whether mulmocast can render a `remotion` beat on this machine. Its packages are optional peers of
|
|
2
|
+
// mulmocast that a user installs only if they want it — usually into ~/node_modules, since an npx
|
|
3
|
+
// entry is replaced on every release — so the question is asked FROM mulmocast's own location, the
|
|
4
|
+
// way its pre-flight does, rather than from this package.
|
|
5
|
+
|
|
6
|
+
import { createRequire } from "node:module";
|
|
7
|
+
import { join } from "node:path";
|
|
8
|
+
import { pathToFileURL } from "node:url";
|
|
9
|
+
|
|
10
|
+
const GUIDE_URL = "https://receptron.github.io/mulmoterminal/guide/en/mulmocast.html#remotion";
|
|
11
|
+
const WHY = "Remotion scenes in MulmoCast videos";
|
|
12
|
+
|
|
13
|
+
/** A resolver answering from where mulmocast is installed, or null when mulmocast is not found. */
|
|
14
|
+
export function resolverFromMulmocast(pkgDir) {
|
|
15
|
+
try {
|
|
16
|
+
const mulmocastEntry = createRequire(join(pkgDir, "package.json")).resolve("mulmocast");
|
|
17
|
+
const fromMulmocast = createRequire(mulmocastEntry);
|
|
18
|
+
// A package that hides its package.json behind `exports` (three does) is installed; any other
|
|
19
|
+
// failure — a malformed package.json included — is reported, since this check is a diagnosis.
|
|
20
|
+
return (name) => {
|
|
21
|
+
try {
|
|
22
|
+
fromMulmocast.resolve(`${name}/package.json`);
|
|
23
|
+
return true;
|
|
24
|
+
} catch (error) {
|
|
25
|
+
return error instanceof Error && "code" in error && error.code === "ERR_PACKAGE_PATH_NOT_EXPORTED";
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
} catch {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** mulmocast's own list of what a remotion beat needs, or null when mulmocast or that export is missing. */
|
|
34
|
+
export async function remotionPackagesFromMulmocast(pkgDir) {
|
|
35
|
+
try {
|
|
36
|
+
const entry = createRequire(join(pkgDir, "package.json")).resolve("mulmocast/remotion");
|
|
37
|
+
const { REMOTION_PACKAGES } = await import(pathToFileURL(entry).href);
|
|
38
|
+
return Array.isArray(REMOTION_PACKAGES) && REMOTION_PACKAGES.every((name) => typeof name === "string") ? REMOTION_PACKAGES : null;
|
|
39
|
+
} catch {
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function missingRemotionPackages(packages, isResolvable) {
|
|
45
|
+
return packages.filter((name) => !isResolvable(name));
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function remotionCheckLine(missing, total) {
|
|
49
|
+
if (missing.length === 0) return ` ✓ remotion — ${WHY}`;
|
|
50
|
+
const head =
|
|
51
|
+
missing.length === total ? ` ○ remotion — optional (${WHY})` : ` ○ remotion — optional (${WHY}), installed only in part; missing: ${missing.join(", ")}`;
|
|
52
|
+
return `${head}\n → ${GUIDE_URL}`;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** The `init` line for remotion, or null when mulmocast cannot be asked. */
|
|
56
|
+
export async function remotionCheck(pkgDir) {
|
|
57
|
+
const isResolvable = resolverFromMulmocast(pkgDir);
|
|
58
|
+
const packages = await remotionPackagesFromMulmocast(pkgDir);
|
|
59
|
+
if (!isResolvable || !packages) return null;
|
|
60
|
+
return remotionCheckLine(missingRemotionPackages(packages, isResolvable), packages.length);
|
|
61
|
+
}
|
|
@@ -33,6 +33,7 @@ export const DIR_CONFIG_KEYS = [
|
|
|
33
33
|
"commands",
|
|
34
34
|
"skills",
|
|
35
35
|
"decks",
|
|
36
|
+
"mobileFiles",
|
|
36
37
|
"provider",
|
|
37
38
|
"model",
|
|
38
39
|
"addDirs",
|
|
@@ -76,6 +77,10 @@ export interface DirConfigExtras {
|
|
|
76
77
|
model: string | null;
|
|
77
78
|
skills: string[] | null;
|
|
78
79
|
decks: string[] | null;
|
|
80
|
+
// What the phone may see (#2911): the declared directories relative to this one, and the
|
|
81
|
+
// extensions that survived the host's allowlist. Empty when the key is absent or was dropped.
|
|
82
|
+
mobileFileDirs: string[];
|
|
83
|
+
mobileFileExtensions: string[];
|
|
79
84
|
addDirs: string[] | null;
|
|
80
85
|
// Tri-state on purpose: `false` is a setting this file made, and the preview has to show it as
|
|
81
86
|
// one. Carried here because a boolean cannot be read back off the per-cell config the way a
|
|
@@ -99,6 +104,8 @@ export const EMPTY_DIR_CONFIG_EXTRAS: DirConfigExtras = {
|
|
|
99
104
|
model: null,
|
|
100
105
|
skills: null,
|
|
101
106
|
decks: null,
|
|
107
|
+
mobileFileDirs: [],
|
|
108
|
+
mobileFileExtensions: [],
|
|
102
109
|
addDirs: null,
|
|
103
110
|
appendSystemPrompt: null,
|
|
104
111
|
buttonLabels: [],
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
// Which files a project lets the phone see (#2911), and the wire shapes the two commands answer.
|
|
2
|
+
//
|
|
3
|
+
// Declared, never discovered: a project lists the directories and extensions in its
|
|
4
|
+
// `.mulmoterminal.json` under `mobileFiles`, and nothing is visible without that. These rules are
|
|
5
|
+
// pure so the containment-adjacent decisions (which extension, which name) are testable without a
|
|
6
|
+
// filesystem; the filesystem half lives in server/config/dir-file.ts and the remote-host backend.
|
|
7
|
+
|
|
8
|
+
export const MOBILE_FILE_KINDS = ["markdown", "html", "pdf", "image"] as const;
|
|
9
|
+
export type MobileFileKind = (typeof MOBILE_FILE_KINDS)[number];
|
|
10
|
+
|
|
11
|
+
// The host's allowlist. A project can narrow it, never widen it. svg is absent on purpose: it can
|
|
12
|
+
// carry script, and an image on the phone is shown as an image, not run.
|
|
13
|
+
export const MOBILE_FILE_EXTENSIONS = ["md", "markdown", "html", "htm", "pdf", "png", "jpg", "jpeg", "gif", "webp"] as const;
|
|
14
|
+
export type MobileFileExtension = (typeof MOBILE_FILE_EXTENSIONS)[number];
|
|
15
|
+
|
|
16
|
+
const SERVABLE_EXTENSIONS: Readonly<Record<MobileFileExtension, { kind: MobileFileKind; contentType: string }>> = {
|
|
17
|
+
md: { kind: "markdown", contentType: "text/markdown" },
|
|
18
|
+
markdown: { kind: "markdown", contentType: "text/markdown" },
|
|
19
|
+
html: { kind: "html", contentType: "text/html" },
|
|
20
|
+
htm: { kind: "html", contentType: "text/html" },
|
|
21
|
+
pdf: { kind: "pdf", contentType: "application/pdf" },
|
|
22
|
+
png: { kind: "image", contentType: "image/png" },
|
|
23
|
+
jpg: { kind: "image", contentType: "image/jpeg" },
|
|
24
|
+
jpeg: { kind: "image", contentType: "image/jpeg" },
|
|
25
|
+
gif: { kind: "image", contentType: "image/gif" },
|
|
26
|
+
webp: { kind: "image", contentType: "image/webp" },
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const isMobileFileExtension = (value: string): value is MobileFileExtension => MOBILE_FILE_EXTENSIONS.some((extension) => extension === value);
|
|
30
|
+
|
|
31
|
+
export const MAX_MOBILE_FILE_DIRS = 16;
|
|
32
|
+
|
|
33
|
+
/** One `extensions` entry as a person writes it — any case, an optional leading dot. The editor's
|
|
34
|
+
* schema needs a pattern rather than a list, and a spec pins it to MOBILE_FILE_EXTENSIONS. */
|
|
35
|
+
export const MOBILE_FILE_EXTENSION_PATTERN = /^\s*\.?(?:md|markdown|html?|pdf|png|jpe?g|gif|webp)\s*$/i;
|
|
36
|
+
|
|
37
|
+
/** The extension of the last path segment, lowercased, without the dot; "" when there is none. */
|
|
38
|
+
export function extensionOf(relativePath: string): string {
|
|
39
|
+
const name = relativePath.split("/").pop() ?? "";
|
|
40
|
+
const dot = name.lastIndexOf(".");
|
|
41
|
+
return dot <= 0 ? "" : name.slice(dot + 1).toLowerCase();
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function mobileFileKind(relativePath: string): MobileFileKind | null {
|
|
45
|
+
const extension = extensionOf(relativePath);
|
|
46
|
+
return isMobileFileExtension(extension) ? SERVABLE_EXTENSIONS[extension].kind : null;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function mobileFileContentType(relativePath: string): string {
|
|
50
|
+
const extension = extensionOf(relativePath);
|
|
51
|
+
return isMobileFileExtension(extension) ? SERVABLE_EXTENSIONS[extension].contentType : "application/octet-stream";
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** A project's `extensions`, reduced to the allowlist: trimmed, lowercased, leading dot dropped,
|
|
55
|
+
* deduped. Anything the host does not serve is dropped rather than kept. */
|
|
56
|
+
export function normalizeMobileFileExtensions(input: unknown): MobileFileExtension[] {
|
|
57
|
+
if (!Array.isArray(input)) return [];
|
|
58
|
+
const cleaned = input
|
|
59
|
+
.filter((entry): entry is string => typeof entry === "string")
|
|
60
|
+
.map((entry) => entry.trim().replace(/^\./, "").toLowerCase())
|
|
61
|
+
.filter(isMobileFileExtension);
|
|
62
|
+
return [...new Set(cleaned)];
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/** A path segment the phone never sees into: hidden (`.env`, `.git`) or a vendored dependency tree. */
|
|
66
|
+
export const isExcludedSegment = (segment: string): boolean => segment.startsWith(".") || segment === "node_modules";
|
|
67
|
+
|
|
68
|
+
/** Whether a path (POSIX, relative to a declared directory) names a file the phone may see:
|
|
69
|
+
* no excluded segment (`.env`, anything under `.git` or `node_modules`), no empty or `..`
|
|
70
|
+
* segment, and an extension the project declared. */
|
|
71
|
+
export function isServableMobilePath(relativePath: string, extensions: readonly MobileFileExtension[]): boolean {
|
|
72
|
+
const segments = relativePath.split("/");
|
|
73
|
+
if (segments.some((segment) => segment === "" || segment === ".." || isExcludedSegment(segment))) return false;
|
|
74
|
+
const extension = extensionOf(relativePath);
|
|
75
|
+
return isMobileFileExtension(extension) && extensions.includes(extension);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** One row of `listMobileFiles`. `path` is relative to the PROJECT root, POSIX — never absolute,
|
|
79
|
+
* so no home directory travels to the phone. */
|
|
80
|
+
export interface MobileFileEntry {
|
|
81
|
+
path: string;
|
|
82
|
+
kind: MobileFileKind;
|
|
83
|
+
bytes: number;
|
|
84
|
+
modifiedAt: string;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export interface MobileFileListing {
|
|
88
|
+
/** False when the project declares no `mobileFiles`: the phone says how to turn it on. */
|
|
89
|
+
configured: boolean;
|
|
90
|
+
files: MobileFileEntry[];
|
|
91
|
+
total: number;
|
|
92
|
+
offset: number;
|
|
93
|
+
limit: number;
|
|
94
|
+
/** The walk stopped at its budget, so older files may be missing from `total`. */
|
|
95
|
+
truncated: boolean;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/** What `getMobileFile` answers. Text small enough to ride in the command document comes inline
|
|
99
|
+
* (`html` already wrapped in its isolating CSP); anything else is staged in the owner's Storage
|
|
100
|
+
* and read there with the owner's own credentials. */
|
|
101
|
+
export type MobileFileContent =
|
|
102
|
+
| { delivery: "inline"; kind: "markdown" | "html"; path: string; text: string; omittedImages: number }
|
|
103
|
+
| {
|
|
104
|
+
delivery: "storage";
|
|
105
|
+
kind: MobileFileKind;
|
|
106
|
+
path: string;
|
|
107
|
+
/** Read with the owner's own credentials (`getBlob`); deleted at `expiresAt`. */
|
|
108
|
+
storagePath: string;
|
|
109
|
+
contentType: string;
|
|
110
|
+
bytes: number;
|
|
111
|
+
expiresAt: string;
|
|
112
|
+
omittedImages: number;
|
|
113
|
+
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{m as e,t}from"./mermaid-parser.core-
|
|
1
|
+
import{m as e,t}from"./mermaid-parser.core-DaS4aeEe.js";import{n}from"./chunk-Y2CYZVJY-DsF7k-Jl.js";import{m as r}from"./src-CllyRBe0.js";import"./chunk-O7XYJQB3-BWsd-NGX.js";import{n as i,r as a,t as o}from"./chunk-GTNCS2PH-C-P8WS3W.js";import{t as s}from"./chunk-JWPE2WC7-DVXcaiue.js";import"./mermaid.core-CnYkvp8n.js";var c=e().RailroadAbnf.parser.LangiumParser,l=n(e=>{let t=e.alternatives.map(u);return t.length===1?t[0]:{type:`choice`,alternatives:t}},`transformAlternation`),u=n(e=>{let t=e.elements.map(f);return t.length===1?t[0]:{type:`sequence`,elements:t}},`transformConcatenation`),d=n(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=n(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=n(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=n(e=>({name:e.name,definition:l(e.definition)}),`transformRule`),h=n(e=>{s(e,o),e.title&&o.setTitle(e.title),e.rules.map(e=>o.addRule(m(e)))},`populateDb`),g={parser:{parse:n(e=>{o.clear(),r.debug(`[ABNF Parser] Starting Langium parse`);let n=c.parse(e);if(n.lexerErrors.length>0||n.parserErrors.length>0)throw new t(n);let i=n.value;r.debug(`[ABNF Parser] Parsed rules:`,i.rules.length),h(i),r.debug(`[ABNF Parser] Parse complete`)},`parse`),parser:{yy:o}},db:o,renderer:a,styles:i};export{g as diagram};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import"./chunk-FOHPRMQF-DzxwRta7.js";import{M as e}from"./mermaid-parser.core-DaS4aeEe.js";export{e as createArchitectureServices};
|