mulmoterminal 8.7.0 → 9.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (140) hide show
  1. package/README.md +1 -0
  2. package/bin/mulmoterminal.js +3 -0
  3. package/bin/remotion-check.d.ts +5 -0
  4. package/bin/remotion-check.js +61 -0
  5. package/blueprints/adopt/locales/en.json +1 -1
  6. package/blueprints/adopt/presets/help-pages/export.md +1 -1
  7. package/blueprints/adopt/presets/help-pages/login.md +1 -1
  8. package/blueprints/adopt/presets.json +1 -1
  9. package/blueprints/adopt/templates/chaff.yml +1 -1
  10. package/blueprints/docs/checks/chaff.sh +1 -1
  11. package/blueprints/docs/skills/workspace/SKILL.md +1 -1
  12. package/blueprints/polish/locales/en.json +3 -3
  13. package/blueprints/polish/presets/oshirase/oshirase.md +1 -1
  14. package/blueprints/polish/presets/tejun/tejun.md +1 -1
  15. package/blueprints/polish/presets.json +3 -3
  16. package/blueprints/style/skills/report/SKILL.md +1 -1
  17. package/common/dirConfigSource.ts +7 -0
  18. package/common/mobileFiles.ts +113 -0
  19. package/dist/assets/{abnfDiagram-O67JEVCF-B2-5kQv3.js → abnfDiagram-O67JEVCF-B6V1adii.js} +1 -1
  20. package/dist/assets/architecture-7GRP2DOG-DkjGubIF.js +1 -0
  21. package/dist/assets/{architectureDiagram-NJMV4G6O-BWmN0XlI.js → architectureDiagram-NJMV4G6O-tvYBaKg8.js} +1 -1
  22. package/dist/assets/{blockDiagram-BEXU5L5S-C_5XPpUF.js → blockDiagram-BEXU5L5S-ClBST1q8.js} +1 -1
  23. package/dist/assets/{c4Diagram-YGBWAQC7-B9wvcnue.js → c4Diagram-YGBWAQC7-CjUaXS4F.js} +1 -1
  24. package/dist/assets/channel-B_Q3doAb.js +1 -0
  25. package/dist/assets/{chunk-3FUC2YCW-1yMpLc4u.js → chunk-3FUC2YCW-CRT1w_Kc.js} +1 -1
  26. package/dist/assets/{chunk-5DYCD2WN-BwMdArvu.js → chunk-5DYCD2WN-bMSPbdpy.js} +1 -1
  27. package/dist/assets/{chunk-742MDFTN-QbZf4Cjg.js → chunk-742MDFTN-Bez3Tn9M.js} +1 -1
  28. package/dist/assets/{chunk-7INBJB4K-Vs-T9MMd.js → chunk-7INBJB4K-OTp9qRYA.js} +1 -1
  29. package/dist/assets/{chunk-7M6MHVWA-D8TnVHqU.js → chunk-7M6MHVWA-DkCUcQwQ.js} +1 -1
  30. package/dist/assets/{chunk-7PRAP22T-nUiU6pnD.js → chunk-7PRAP22T-BGVTZEEO.js} +1 -1
  31. package/dist/assets/{chunk-GTNCS2PH-DVRz7ZP5.js → chunk-GTNCS2PH-bOY5g867.js} +1 -1
  32. package/dist/assets/{chunk-GWA4HPMP-BegTjzQn.js → chunk-GWA4HPMP-8I7RGjEz.js} +1 -1
  33. package/dist/assets/{chunk-MBY4JIJT-DxWeOcz9.js → chunk-MBY4JIJT-DPo4IY7I.js} +1 -1
  34. package/dist/assets/{chunk-NETBCI7D-BUushUV6.js → chunk-NETBCI7D-c-Trcigi.js} +1 -1
  35. package/dist/assets/{chunk-O7XYJQB3-DEoqIHM1.js → chunk-O7XYJQB3-cZU_kp07.js} +1 -1
  36. package/dist/assets/{chunk-UA2S7LBM-C6TGfJyx.js → chunk-UA2S7LBM-DN8x17Y_.js} +1 -1
  37. package/dist/assets/{chunk-WEXAMYUT-FZ_r2Lcu.js → chunk-WEXAMYUT-GMG85kDe.js} +1 -1
  38. package/dist/assets/{chunk-Z7XXMR3K-n5ujsU8a.js → chunk-Z7XXMR3K-D-5FqhDR.js} +1 -1
  39. package/dist/assets/{chunk-ZIGJFQKS-6d7SXGDn.js → chunk-ZIGJFQKS-JvDNhUM-.js} +1 -1
  40. package/dist/assets/{classDiagram-v2-NBCMYWYE-Df680lYT.js → classDiagram-v2-NBCMYWYE-B00nn8W5.js} +1 -1
  41. package/dist/assets/{cynefin-OW5HDTMX-TdqBlM6E.js → cynefin-OW5HDTMX-CkQBtt5a.js} +1 -1
  42. package/dist/assets/{cynefinDiagram-VND7K2PF-DGOMZS5W.js → cynefinDiagram-VND7K2PF-fkUYZwa5.js} +1 -1
  43. package/dist/assets/{dagre-6A5THRUB-CWwF43DB.js → dagre-6A5THRUB-BS6pMPOZ.js} +1 -1
  44. package/dist/assets/{diagram-22UHCM2B-BoV_v04X.js → diagram-22UHCM2B-DXpbx-lC.js} +1 -1
  45. package/dist/assets/{diagram-3UASUU5V-iMiKC0sq.js → diagram-3UASUU5V-BC-B75aD.js} +1 -1
  46. package/dist/assets/{diagram-ATOU4E4O-CQ41aCKP.js → diagram-ATOU4E4O-C6yFvEkd.js} +1 -1
  47. package/dist/assets/{diagram-CDSNMT55-Dz4tlqxe.js → diagram-CDSNMT55-B7woB__w.js} +1 -1
  48. package/dist/assets/{diagram-MLGK6HIB-u2_J3h9I.js → diagram-MLGK6HIB-ai_wp4u6.js} +1 -1
  49. package/dist/assets/{diagram-MPIPVDR6-k182o0_i.js → diagram-MPIPVDR6-DEr5O9bq.js} +1 -1
  50. package/dist/assets/{dist-CWJPjXUz.js → dist-C9ElF3Om.js} +1 -1
  51. package/dist/assets/{dist-DKIBcK0b.js → dist-CFm6yMLB.js} +1 -1
  52. package/dist/assets/{dist-UMnZIGlW.js → dist-C_f4DhPh.js} +1 -1
  53. package/dist/assets/{dist-DBBlqgRS.js → dist-DWIDz4be.js} +1 -1
  54. package/dist/assets/{dist-CTlGsb4b.js → dist-lwZDIHh-.js} +1 -1
  55. package/dist/assets/{ebnfDiagram-ZINNZB2B-DimQHxn_.js → ebnfDiagram-ZINNZB2B-hj7ZRIO_.js} +1 -1
  56. package/dist/assets/{elk-276RUBZZ-C1ce13Z9.js → elk-276RUBZZ-FHnZS5Rb.js} +1 -1
  57. package/dist/assets/{erDiagram-OPXOYQCR-BDVLXOla.js → erDiagram-OPXOYQCR-L2rhNA9c.js} +1 -1
  58. package/dist/assets/eventmodeling-NTZA5JFV-CWeRTfgf.js +1 -0
  59. package/dist/assets/flowDiagram-KWPJA3E3-C56SysWA.js +1 -0
  60. package/dist/assets/{ganttDiagram-FUAMR5RP-Cuv6mpEd.js → ganttDiagram-FUAMR5RP-D5ZKVKFH.js} +1 -1
  61. package/dist/assets/{gitGraph-4MIJSDKK-BBP0D_nl.js → gitGraph-4MIJSDKK-DUn7Ps8f.js} +1 -1
  62. package/dist/assets/{gitGraphDiagram-X574FWY7-I2cFvTgG.js → gitGraphDiagram-X574FWY7-DcaLifKL.js} +1 -1
  63. package/dist/assets/{index-JI2h4Uzi.css → index-B-X7-YRY.css} +1 -1
  64. package/dist/assets/{index-WzQxkaos.js → index-DWnPZqQq.js} +368 -367
  65. package/dist/assets/{info-A6RAGUB7-ChLt2Y_8.js → info-A6RAGUB7-Btm3TGpy.js} +1 -1
  66. package/dist/assets/{infoDiagram-VRGFBTTK-BKLlG1wy.js → infoDiagram-VRGFBTTK-Dg3Ujxrc.js} +1 -1
  67. package/dist/assets/{ishikawaDiagram-OU5B5YK6-BtiaSc9h.js → ishikawaDiagram-OU5B5YK6-fJBwRz4d.js} +1 -1
  68. package/dist/assets/{journeyDiagram-ZHPQQLJL-DyAa7kYl.js → journeyDiagram-ZHPQQLJL-CtdePFYh.js} +1 -1
  69. package/dist/assets/{kanban-definition-PNTS6WVX-CG7vSRB_.js → kanban-definition-PNTS6WVX-bT8u7muu.js} +1 -1
  70. package/dist/assets/{line-DJc21-yS.js → line-CPsge2Yh.js} +1 -1
  71. package/dist/assets/{manifold-BinHd79x.js → manifold-CuJ-X4HP.js} +1 -1
  72. package/dist/assets/{mermaid-parser.core-NrRwpxGk.js → mermaid-parser.core-BRWPhapQ.js} +3 -3
  73. package/dist/assets/{mermaid.core-C1Q92lDM.js → mermaid.core-DFxM36lr.js} +4 -4
  74. package/dist/assets/{mindmap-definition-NLK3R4M7-E6aB2fhC.js → mindmap-definition-NLK3R4M7-_S6euC1w.js} +1 -1
  75. package/dist/assets/{packet-AYTQ26CC-COIXGLhu.js → packet-AYTQ26CC-C6UcvkYQ.js} +1 -1
  76. package/dist/assets/{pegDiagram-GJSIUBJH-DfWsFyxF.js → pegDiagram-GJSIUBJH-Bd0KlQY8.js} +1 -1
  77. package/dist/assets/{pie-WAS4IAKB-Df4yWTZD.js → pie-WAS4IAKB-BRp3GAqt.js} +1 -1
  78. package/dist/assets/{pieDiagram-5QR66LMP-sYCUFrWD.js → pieDiagram-5QR66LMP-ihKDC_h2.js} +1 -1
  79. package/dist/assets/{quadrantDiagram-O4NWA36T-Bme8aXrP.js → quadrantDiagram-O4NWA36T-BnN-cXYN.js} +1 -1
  80. package/dist/assets/{radar-RG4KPBEZ-ChZNu3RR.js → radar-RG4KPBEZ-B8KPrbnt.js} +1 -1
  81. package/dist/assets/{railroad-74A4TZTK-wuxrUl2y.js → railroad-74A4TZTK-DqDecObi.js} +1 -1
  82. package/dist/assets/railroad-abnf-HS5TGJTU-Cufi7BYM.js +1 -0
  83. package/dist/assets/railroad-ebnf-LZEXJU2U-DwV5T2rR.js +1 -0
  84. package/dist/assets/railroad-peg-WCYAUIDC-BokaacUc.js +1 -0
  85. package/dist/assets/{railroadDiagram-XR7U4H2S-CMbvpXoE.js → railroadDiagram-XR7U4H2S-BAoImlS0.js} +1 -1
  86. package/dist/assets/{requirementDiagram-PLB6GJNP-wD2VwRkI.js → requirementDiagram-PLB6GJNP-CHZdR57i.js} +1 -1
  87. package/dist/assets/{sankeyDiagram-IPEJSGJF-DbZZjCGQ.js → sankeyDiagram-IPEJSGJF-BWkIjIJB.js} +1 -1
  88. package/dist/assets/{sequenceDiagram-PO4LG4MO-BSCmmFnl.js → sequenceDiagram-PO4LG4MO-CqObbOWh.js} +1 -1
  89. package/dist/assets/{stateDiagram-v2-GCMORJYK-DdArzmwd.js → stateDiagram-v2-GCMORJYK-DfHn6IXA.js} +1 -1
  90. package/dist/assets/{swimlanes-2SLR337P-bUgJWexk.js → swimlanes-2SLR337P-D37F980K.js} +1 -1
  91. package/dist/assets/swimlanesDiagram-TC7HE7FX-CIi8juiT.js +8 -0
  92. package/dist/assets/{timeline-definition-EJHVYXUP-DT4VQqev.js → timeline-definition-EJHVYXUP-CO1QhgRv.js} +1 -1
  93. package/dist/assets/{treeView-Q6P3EWNA-fSYKJVAW.js → treeView-Q6P3EWNA-C4HvAeOL.js} +1 -1
  94. package/dist/assets/{treemap-WGGIJYW6-m8rvnRCQ.js → treemap-WGGIJYW6-B46HTs9m.js} +1 -1
  95. package/dist/assets/{usecaseDiagram-POWQR4AR-Be3npLVi.js → usecaseDiagram-POWQR4AR-Ckyf5xpI.js} +1 -1
  96. package/dist/assets/{vennDiagram-UO4OBE2U--r9MxNV0.js → vennDiagram-UO4OBE2U-Ba7Gh7Vi.js} +1 -1
  97. package/dist/assets/{wardley-WFR3VGLG-DG2qmeXK.js → wardley-WFR3VGLG-3dpHiNSr.js} +1 -1
  98. package/dist/assets/{wardleyDiagram-VNRHLVJA-84X2nuVX.js → wardleyDiagram-VNRHLVJA-BavLzskx.js} +1 -1
  99. package/dist/assets/{xychartDiagram-PMCCYNJV-BpBHW9jU.js → xychartDiagram-PMCCYNJV-KWV3k7zo.js} +1 -1
  100. package/dist/index.html +2 -2
  101. package/docs/guide/en/v8.8.0.md +73 -0
  102. package/docs/guide/en/v9.0.0.md +93 -0
  103. package/docs/guide/ja/v8.8.0.md +73 -0
  104. package/docs/guide/ja/v9.0.0.md +89 -0
  105. package/package.json +9 -9
  106. package/server/backends/collections.ts +10 -14
  107. package/server/backends/remoteHost/getFeed.spec.ts +1 -0
  108. package/server/backends/remoteHost/handlers/deps.ts +4 -0
  109. package/server/backends/remoteHost/handlers/index.ts +4 -0
  110. package/server/backends/remoteHost/handlers/listCollectionProjects.ts +2 -2
  111. package/server/backends/remoteHost/handlers/mobileFiles.ts +154 -0
  112. package/server/backends/remoteHost/handlers.spec.ts +5 -0
  113. package/server/backends/remoteHost/index.ts +15 -4
  114. package/server/backends/remoteHost/mobileFileInline.ts +109 -0
  115. package/server/backends/remoteHost/mobileFileStaging.ts +118 -0
  116. package/server/backends/remoteHost/mobileFileWalk.ts +94 -0
  117. package/server/backends/sharedApp/bannerWrites.ts +74 -0
  118. package/server/backends/sharedApp/forkWrites.ts +145 -0
  119. package/server/backends/sharedApp/publicView.ts +20 -6
  120. package/server/backends/sharedApp/publish.ts +37 -7
  121. package/server/backends/sharedApp/unpublish.ts +8 -0
  122. package/server/backends/viewDataParams.ts +27 -0
  123. package/server/config/config-schema.ts +22 -0
  124. package/server/config/dir-config.ts +37 -3
  125. package/server/config/dir-file.ts +11 -2
  126. package/server/config/worktree-dir-config.ts +2 -0
  127. package/server/skills/mulmoterminal-config/SKILL.md +22 -2
  128. package/server/skills/mulmoterminal-dirs/SKILL.md +2 -2
  129. package/server/skills/mulmoterminal-shared-app/SKILL.md +57 -3
  130. package/server/skills/mulmoterminal-shared-app/templates/question-box.md +12 -0
  131. package/server/skills/mulmoterminal-shared-app/templates/survey-results.md +12 -0
  132. package/server/skills/mulmoterminal-shared-app/templates/tally.md +12 -0
  133. package/dist/assets/architecture-7GRP2DOG-Dq2w9np8.js +0 -1
  134. package/dist/assets/channel-Cqhq3KjW.js +0 -1
  135. package/dist/assets/eventmodeling-NTZA5JFV-BZ5TKctG.js +0 -1
  136. package/dist/assets/flowDiagram-KWPJA3E3-DqBWrZAa.js +0 -1
  137. package/dist/assets/railroad-abnf-HS5TGJTU-B256YSjH.js +0 -1
  138. package/dist/assets/railroad-ebnf-LZEXJU2U-Cuv8h7Bb.js +0 -1
  139. package/dist/assets/railroad-peg-WCYAUIDC-ObAP2tRF.js +0 -1
  140. package/dist/assets/swimlanesDiagram-TC7HE7FX-vgwN9gKg.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
 
@@ -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
+ }
@@ -61,7 +61,7 @@
61
61
  "presets": {
62
62
  "help-pages": {
63
63
  "title": "Bring chaff into help pages",
64
- "description": "Measures the sample help pages (login.md and export.md) as \"Procedure, help or manual\", shelves today's findings of sentences that are too long, and from then on only new findings appear. It also makes a workflow that shows findings on GitHub PRs. The originals do not change."
64
+ "description": "Measures the sample help pages (login.md and export.md) as \"Procedure, help or manual\", shelves today's findings (a dropped-ら verb form and a \"here\" link that does not say where it goes), and from then on only new findings appear. It also makes a workflow that shows findings on GitHub PRs. The originals do not change."
65
65
  }
66
66
  }
67
67
  }
@@ -6,4 +6,4 @@
6
6
 
7
7
  ## 書き出せないとき
8
8
 
9
- 一度に書き出せるのは 10,000 行までです。それより多いときは、期間を分けて書き出してください。
9
+ 一度に書き出せるのは 10,000 行までです。それより多いときは、期間を分けて書き出してください。書き出したファイルは、Excel でも見れます。
@@ -6,4 +6,4 @@
6
6
 
7
7
  ## アカウントがロックされたとき
8
8
 
9
- パスワードを5回続けて間違えると、アカウントが30分ロックされます。30分たってから、もう一度ログインしてください。
9
+ パスワードを5回続けて間違えると、アカウントが30分ロックされます。30分たってから、もう一度ログインしてください。急ぎのときは[こちら](https://example.com/support)から問い合わせてください。
@@ -3,7 +3,7 @@
3
3
  {
4
4
  "id": "help-pages",
5
5
  "title": "ヘルプのページに chaff を入れる",
6
- "description": "見本のヘルプ(login.md と export.md)を「手順書・ヘルプ・マニュアル」として測り、今ある長すぎる文の指摘を棚に上げて、以後は新しい指摘だけが出るようにする。GitHub の PR に指摘を出すワークフローも作る。原本は変えない。",
6
+ "description": "見本のヘルプ(login.md と export.md)を「手順書・ヘルプ・マニュアル」として測り、今ある指摘(ら抜き言葉や、行き先の分からない「こちら」のリンク)を棚に上げて、以後は新しい指摘だけが出るようにする。GitHub の PR に指摘を出すワークフローも作る。原本は変えない。",
7
7
  "base": "docs",
8
8
  "answers": {
9
9
  "places": "login.md\nexport.md",
@@ -21,7 +21,7 @@ jobs:
21
21
  - uses: actions/setup-node@v7
22
22
  with:
23
23
  node-version: 24
24
- - run: npx -y chaffjs@0.18 {{PATHS}} --sarif chaff.sarif
24
+ - run: npx -y chaffjs@0.21 {{PATHS}} --sarif chaff.sarif
25
25
  continue-on-error: true
26
26
  - uses: github/codeql-action/upload-sarif@1c5b675653bb5c22dbe9b12b556ec555138e09fd # v4.38.1
27
27
  with:
@@ -4,4 +4,4 @@
4
4
  if [ -n "${CHAFF_BIN:-}" ]; then
5
5
  exec sh -c "$CHAFF_BIN \"\$@\"" chaff "$@"
6
6
  fi
7
- exec npx -y chaffjs@0.18 "$@"
7
+ exec npx -y chaffjs@0.21 "$@"
@@ -12,7 +12,7 @@ repository, `.git/info/exclude`) until the person has approved the models.
12
12
  1. `.blueprint/` already exists (the build created it). Everything this build records goes there.
13
13
  2. Run chaff once through the base pack's wrapper, so its first download happens now and not in the
14
14
  middle of a later step: `sh <base pack>/checks/chaff.sh rules --json > /dev/null`. The wrapper runs the
15
- pinned chaff (`npx -y chaffjs@0.18`) unless `CHAFF_BIN` names another. If it fails, show the person the
15
+ pinned chaff (`npx -y chaffjs@0.21`) unless `CHAFF_BIN` names another. If it fails, show the person the
16
16
  error and stop — do not work around it.
17
17
  3. If the folder is a git repository, add `.blueprint/` to `.git/info/exclude`. That keeps the build's
18
18
  working files out of commits without touching `.gitignore`, which belongs to the person.
@@ -91,7 +91,7 @@
91
91
  "presets": {
92
92
  "oshirase": {
93
93
  "title": "Polish a company notice",
94
- "description": "In the sample notice (oshirase.md), splits the sentences chaff finds too long so they read easily, without changing what they say. The original is kept. Run the \"Make a style\" example in the same folder first and choose its style, and the notice follows that style."
94
+ "description": "In the sample notice (oshirase.md), fixes what chaff finds (such as an intensifier that says nothing) so it reads easily, without changing what it says. The original is kept. Run the \"Make a style\" example in the same folder first and choose its style, and the notice follows that style."
95
95
  },
96
96
  "houkoku": {
97
97
  "title": "Polish a report as a report",
@@ -103,7 +103,7 @@
103
103
  },
104
104
  "tejun": {
105
105
  "title": "Polish a procedure as a procedure",
106
- "description": "Reads the sample procedure (tejun.md) as a manual. Sentences that are too long are split without changing what they say. It looks at what you need before starting, whether one step holds two actions, and how to tell a step worked; where something needs adding, it becomes a question for the author in the report. The original is kept."
106
+ "description": "Reads the sample procedure (tejun.md) as a manual. What chaff finds (such as a \"here\" link that does not say where it goes) is fixed without changing what it says. It looks at what you need before starting, whether one step holds two actions, and how to tell a step worked; where something needs adding, it becomes a question for the author in the report. The original is kept."
107
107
  },
108
108
  "shayo": {
109
109
  "title": "Polish a regulation as a regulation",
@@ -111,7 +111,7 @@
111
111
  },
112
112
  "english-blog": {
113
113
  "title": "Polish an English blog post",
114
- "description": "Reads the sample English technical blog post (post.md) as a technical article. The post stays in English: overlong sentences are split, and an opening that would fit any post or a stock closing line is cut. Where something needs adding, such as a closing that only summarises, it becomes a question for the author in the report. The report comes back in your report language. The original is kept."
114
+ "description": "Reads the sample English technical blog post (post.md) as a technical article. The post stays in English: an opening that would fit any post or a stock closing line is cut. Where something needs adding, such as a closing that only summarises, it becomes a question for the author in the report. The report comes back in your report language. The original is kept."
115
115
  }
116
116
  }
117
117
  }
@@ -1,6 +1,6 @@
1
1
  # 年末年始の休みについてのお知らせ
2
2
 
3
- 年末年始の休みについては、12月29日から1月3日までを会社としての休みとすることになりましたので、その期間中にどうしても対応が必要になるような仕事がある人については、前もって上長の人とよく相談をしておいてもらえるとよいかと思っています。
3
+ 年末年始の休みについては、12月29日から1月3日までを会社としての休みとすることになりましたので、その期間中にどうしても対応が必要になるような仕事がある人については、言うまでもなく前もって上長の人とよく相談をしておいてもらえるとよいかと思っています。
4
4
 
5
5
  休みの期間中の問い合わせについては、急ぎのものについてのみ、当番の人が対応をすることができるような形にしておきたいと考えていますので、当番の人の名前と連絡先については、12月20日までにこのページに書いておくようにします。
6
6
 
@@ -7,7 +7,7 @@
7
7
  1. 経費精算システムを開き、社員番号とパスワードでログインして、左のメニューから「新しい申請」を選びます。
8
8
  2. 申請の種類で「交通費」を選びます。
9
9
  3. 使った日、出発した駅、着いた駅、金額を入れます。往復のときは「往復」に印を付けると、入れた金額が自動で二倍になって表示される仕組みになっているため、往復の合計の金額ではなく片道の金額を入れるように、入れる前にもう一度確かめてから次の手順に進むよう気をつけてください。
10
- 4. 交通系ICカードで払ったときは、利用履歴を印刷したものを写真に撮り、「添付」から付けます。
10
+ 4. 交通系ICカードで払ったときは、利用履歴を印刷したものを写真に撮り、「添付」から付けます。利用履歴の印刷のしかたは[こちら](https://example.com/ic-history)を見てください。
11
11
  5. 「申請する」を押します。
12
12
 
13
13
  ## うまくいかないとき
@@ -3,7 +3,7 @@
3
3
  {
4
4
  "id": "oshirase",
5
5
  "title": "社内のお知らせを整える",
6
- "description": "見本のお知らせ(oshirase.md)のうち、chaff が長すぎると指摘した文を、書いてあることは変えずに分けて読みやすくする。直す前の原本は残す。先に「規約をつくる」の例を同じフォルダで済ませて規約を選ぶと、その規約に合わせて整える。",
6
+ "description": "見本のお知らせ(oshirase.md)のうち、chaff が指摘した所(強めるだけで中身の無い言い方など)を、書いてあることは変えずに直して読みやすくする。直す前の原本は残す。先に「規約をつくる」の例を同じフォルダで済ませて規約を選ぶと、その規約に合わせて整える。",
7
7
  "base": "docs",
8
8
  "answers": {
9
9
  "targets": "oshirase.md",
@@ -42,7 +42,7 @@
42
42
  {
43
43
  "id": "tejun",
44
44
  "title": "手順書を手順書として整える",
45
- "description": "見本の手順書(tejun.md)を「マニュアル・手順書」として読む。長すぎる文は、書いてあることは変えずに分ける。始める前に要るもの、一つの手順に動作が二つ入っていないか、うまくいったことの確かめ方を見て、書き足しが要るところは直さずに、書いた人への質問として報告に並べる。直す前の原本は残す。",
45
+ "description": "見本の手順書(tejun.md)を「マニュアル・手順書」として読む。chaff が指摘した所(行き先の分からない「こちら」のリンクなど)は、書いてあることは変えずに直す。始める前に要るもの、一つの手順に動作が二つ入っていないか、うまくいったことの確かめ方を見て、書き足しが要るところは直さずに、書いた人への質問として報告に並べる。直す前の原本は残す。",
46
46
  "base": "docs",
47
47
  "answers": {
48
48
  "targets": "tejun.md",
@@ -68,7 +68,7 @@
68
68
  {
69
69
  "id": "english-blog",
70
70
  "title": "英語のブログ記事を整える",
71
- "description": "見本の英語の技術ブログ(post.md)を「ブログ(技術記事)」として読む。文書は英語のまま、長すぎる文を分け、どの記事にも当てはまる書き出しや結びの決まり文句は削る。要約だけの結びなど、書き足しが要るところは直さずに、書いた人への質問として報告に並べる。報告は画面の言語で返る。直す前の原本は残す。",
71
+ "description": "見本の英語の技術ブログ(post.md)を「ブログ(技術記事)」として読む。文書は英語のまま、どの記事にも当てはまる書き出しや結びの決まり文句は削る。要約だけの結びなど、書き足しが要るところは直さずに、書いた人への質問として報告に並べる。報告は画面の言語で返る。直す前の原本は残す。",
72
72
  "base": "docs",
73
73
  "answers": {
74
74
  "targets": "post.md",
@@ -8,7 +8,7 @@ description: "Report what became a machine rule, what went to the guide, and wha
8
8
  Write `.blueprint/style-report.md` for the person, in their language and in plain words:
9
9
 
10
10
  - `## 機械の決まり` / `## Machine rules` — `chaff.yaml`: the genre and language, and each rule you set
11
- with its reason, in one line each. How to run it: `npx -y chaffjs@0.18 <file or folder>`.
11
+ with its reason, in one line each. How to run it: `npx -y chaffjs@0.21 <file or folder>`.
12
12
  - `## 手引き` / `## The guide` — what `STYLE.md` asks for that a machine cannot check.
13
13
  - `## 規約にしなかったこと` / `## Left out` — what the models do that you did not make a rule, and why;
14
14
  any genre chaff lacked; any source that was converted from Word or PDF; counter texts chaff could not see.
@@ -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-NrRwpxGk.js";import{n}from"./chunk-Y2CYZVJY-DsF7k-Jl.js";import{m as r}from"./src-CllyRBe0.js";import"./chunk-O7XYJQB3-DEoqIHM1.js";import{n as i,r as a,t as o}from"./chunk-GTNCS2PH-DVRz7ZP5.js";import{t as s}from"./chunk-JWPE2WC7-DVXcaiue.js";import"./mermaid.core-C1Q92lDM.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};
1
+ import{m as e,t}from"./mermaid-parser.core-BRWPhapQ.js";import{n}from"./chunk-Y2CYZVJY-DsF7k-Jl.js";import{m as r}from"./src-CllyRBe0.js";import"./chunk-O7XYJQB3-cZU_kp07.js";import{n as i,r as a,t as o}from"./chunk-GTNCS2PH-bOY5g867.js";import{t as s}from"./chunk-JWPE2WC7-DVXcaiue.js";import"./mermaid.core-DFxM36lr.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-BRWPhapQ.js";export{e as createArchitectureServices};