mulmoterminal 4.7.6 → 4.8.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 (139) hide show
  1. package/README.md +10 -2
  2. package/common/collectionNotifyTarget.ts +12 -2
  3. package/common/collectionPortability.ts +84 -0
  4. package/common/toolGroups.ts +14 -0
  5. package/dist/assets/{abnfDiagram-N423BO3Z-D0pzqjdS-mU_JC_gy.js → abnfDiagram-N423BO3Z-D0pzqjdS-C_1F9Lr9.js} +1 -1
  6. package/dist/assets/architecture-TIHT7OUA-Cqhmai3f-EoewX0t1.js +1 -0
  7. package/dist/assets/{architectureDiagram-T3A2C74G-CX-Yoe5G-BYABfiyL.js → architectureDiagram-T3A2C74G-CX-Yoe5G-sXll0esn.js} +1 -1
  8. package/dist/assets/{blockDiagram-VBNYF7ZC-B1eQZQ68-BzYgPGSd.js → blockDiagram-VBNYF7ZC-B1eQZQ68-CPVP1vk2.js} +1 -1
  9. package/dist/assets/{c4Diagram-5PPSVZJV-SBrN9MrU-DeipaoWs.js → c4Diagram-5PPSVZJV-SBrN9MrU-CaDR6PZ5.js} +1 -1
  10. package/dist/assets/channel-DKMa7Sn5-D7uFiXWj.js +1 -0
  11. package/dist/assets/{chunk-2GRJ4B5K-DdkAx9o--B_kTCl3i.js → chunk-2GRJ4B5K-DdkAx9o--BTDRS1ny.js} +1 -1
  12. package/dist/assets/{chunk-3NCLNEKW-CBztX243-DYiY7RPy.js → chunk-3NCLNEKW-CBztX243-CRh6N7eI.js} +1 -1
  13. package/dist/assets/{chunk-4I5QYGJK-CmBJaHzs-apWHpIvV.js → chunk-4I5QYGJK-CmBJaHzs-BQuag-U2.js} +1 -1
  14. package/dist/assets/{chunk-5RXB4S5H-iaipMW_h-CdfjA_Tg.js → chunk-5RXB4S5H-iaipMW_h-Difto-1B.js} +1 -1
  15. package/dist/assets/{chunk-6Q2QTUOP-Cx8nz5_t-CnRVqq3q.js → chunk-6Q2QTUOP-Cx8nz5_t-DoqT-qjo.js} +1 -1
  16. package/dist/assets/{chunk-7Z6QIM7H-CZs6l8Md-p53y8Cce.js → chunk-7Z6QIM7H-CZs6l8Md-DWy67U5n.js} +1 -1
  17. package/dist/assets/{chunk-GF5L2VYU-9OEKHEe4-ClU0Eq5H.js → chunk-GF5L2VYU-9OEKHEe4-CAQrDdMW.js} +1 -1
  18. package/dist/assets/{chunk-I66GZJ75-DSPCVCny-DUUEhGIc.js → chunk-I66GZJ75-DSPCVCny-BJLh4409.js} +1 -1
  19. package/dist/assets/{chunk-J7OUQ5F2-CQoryswr-Bd7yatzt.js → chunk-J7OUQ5F2-CQoryswr-Bgq_Mv29.js} +2 -2
  20. package/dist/assets/{chunk-JQJVKLGR-6F2ui09L-C00hw8rt.js → chunk-JQJVKLGR-6F2ui09L-kUfNk1cv.js} +1 -1
  21. package/dist/assets/{chunk-KBJHAD2P-DXXCSVOS-DikyccfA.js → chunk-KBJHAD2P-DXXCSVOS-DsVXnKcy.js} +1 -1
  22. package/dist/assets/{chunk-NSK5VX7P-DQgMj0Kn-DW0V7wZF.js → chunk-NSK5VX7P-DQgMj0Kn-DuA4A2m-.js} +1 -1
  23. package/dist/assets/{chunk-QR6OTTB3-BQl8P7pD-BsjqkGSs.js → chunk-QR6OTTB3-BQl8P7pD-BZ3iKOMU.js} +1 -1
  24. package/dist/assets/{chunk-UBXNYLIW-BbdYEvTI-BXrjgAx6.js → chunk-UBXNYLIW-BbdYEvTI-BKFsRG54.js} +1 -1
  25. package/dist/assets/{chunk-W5SLKNZC-DSJLk1SI-C2WU94h8.js → chunk-W5SLKNZC-DSJLk1SI-7ayO5NUV.js} +1 -1
  26. package/dist/assets/{chunk-WRU74C26-DOE_TBL8-BM1_oxuE.js → chunk-WRU74C26-DOE_TBL8-CVh6hcjM.js} +1 -1
  27. package/dist/assets/classDiagram-JCYQIIEL-C1ePmEG1-DQsrDAnO.js +1 -0
  28. package/dist/assets/classDiagram-v2-OCEON4UE-C_O3VNBf-DQsrDAnO.js +1 -0
  29. package/dist/assets/cynefin-VYW2F7L2-DvSvuXnG-CbMnaMb8.js +1 -0
  30. package/dist/assets/{cynefinDiagram-MW4NZA55-DuBeESb6-CtkoviKh.js → cynefinDiagram-MW4NZA55-DuBeESb6-DDsWCfbP.js} +1 -1
  31. package/dist/assets/{dagre-VZM6K2ZE-W5cB3U70-RcQsLHRw.js → dagre-VZM6K2ZE-W5cB3U70-D1rl2X4i.js} +1 -1
  32. package/dist/assets/{diagram-7IWD3JNH-Fk1aWqfX-Ck8_3vru.js → diagram-7IWD3JNH-Fk1aWqfX-DzWbtGft.js} +1 -1
  33. package/dist/assets/{diagram-B4RE2ZJO-q-8xygfU-DmLhXIkJ.js → diagram-B4RE2ZJO-q-8xygfU-CxcTRuKd.js} +1 -1
  34. package/dist/assets/{diagram-LBJQPF4R-1SKCcOis-JwGjKf0R.js → diagram-LBJQPF4R-1SKCcOis-V2GRaCiN.js} +1 -1
  35. package/dist/assets/{diagram-Q27KOJAE-CtW4StAQ-CjFTvm0p.js → diagram-Q27KOJAE-CtW4StAQ-BarTqC2z.js} +1 -1
  36. package/dist/assets/{diagram-UB23O5K3-r5fK-tbF-BdXHIyiX.js → diagram-UB23O5K3-r5fK-tbF-pkQL3-5o.js} +1 -1
  37. package/dist/assets/{dist-D7CcWwOu.js → dist-CND5Ye3G.js} +1 -1
  38. package/dist/assets/{dist-DLyXHsFo.js → dist-SVfKHNOC.js} +1 -1
  39. package/dist/assets/{dist-C8a-yjqr.js → dist-WJs7N_4F.js} +1 -1
  40. package/dist/assets/{dist-CDrvAasC.js → dist-s_wb33nB.js} +1 -1
  41. package/dist/assets/{ebnfDiagram-BXEA7PRR-BZoIqTyx-CiH17BLa.js → ebnfDiagram-BXEA7PRR-BZoIqTyx-C-hVWblz.js} +1 -1
  42. package/dist/assets/{erDiagram-JOGREHBK-CM8pI2JI-BzQ3AZBS.js → erDiagram-JOGREHBK-CM8pI2JI-ClKuaaQP.js} +1 -1
  43. package/dist/assets/eventmodeling-45OFAUF4-jdctDg0T-DYxhdsxL.js +1 -0
  44. package/dist/assets/flowDiagram-UKHOOZJN-CR3dcoRl-Bg2gsj-G.js +1 -0
  45. package/dist/assets/{ganttDiagram-PKOTCBZU-DYTkxDIh-9KsdZhhO.js → ganttDiagram-PKOTCBZU-DYTkxDIh-Dbb3I1Ky.js} +1 -1
  46. package/dist/assets/gitGraph-TEB2WS4Q-C4cKwl5j-B3gI81ub.js +1 -0
  47. package/dist/assets/{gitGraphDiagram-DS77QQ5N-DafidN4D-BENdpVYO.js → gitGraphDiagram-DS77QQ5N-DafidN4D-BzvH6u2p.js} +1 -1
  48. package/dist/assets/{index-CG2zWFsc.js → index-0JPMgZUO.js} +189 -189
  49. package/dist/assets/{index-O3HcsBk0.css → index-ClKZRsCv.css} +1 -1
  50. package/dist/assets/info-DKCQHKI2-DPUCBYWS-B4cQvlC-.js +1 -0
  51. package/dist/assets/{infoDiagram-6WML65LV-DxSxsg1o-DohszP_m.js → infoDiagram-6WML65LV-DxSxsg1o-VRdS-8-g.js} +1 -1
  52. package/dist/assets/{ishikawaDiagram-WSZJBQD7-kAIMMFB5-C2ghY9nw.js → ishikawaDiagram-WSZJBQD7-kAIMMFB5-sIxBX_tW.js} +1 -1
  53. package/dist/assets/{journeyDiagram-NVQOT4AX-ClybI8XI-Dd5mVngg.js → journeyDiagram-NVQOT4AX-ClybI8XI-BFleK1p8.js} +1 -1
  54. package/dist/assets/{kanban-definition-27J2QSJJ-DDYHyW1q-p5r5fZtE.js → kanban-definition-27J2QSJJ-DDYHyW1q-BRL0Ieho.js} +1 -1
  55. package/dist/assets/{lib-Jhts0zYK.js → lib-CFJSYJpW.js} +1 -1
  56. package/dist/assets/{line-CtRAsVKI-CxBaSxDR.js → line-CtRAsVKI-Weybbnym.js} +1 -1
  57. package/dist/assets/{marp-CrOOtG2e.js → marp-BEDBCLJs.js} +1 -1
  58. package/dist/assets/{mermaid-parser.core-C1baW7NG-CxIKaNt7.js → mermaid-parser.core-C1baW7NG-B9TNqufx.js} +2 -2
  59. package/dist/assets/{mermaid.core-CGR3z-ay-BeIQeUd9.js → mermaid.core-CGR3z-ay-c1_TNZXz.js} +3 -3
  60. package/dist/assets/{mindmap-definition-FAOFIHXS-DU-wbYKK-DSiJQU50.js → mindmap-definition-FAOFIHXS-DU-wbYKK-CgPoe1x1.js} +1 -1
  61. package/dist/assets/packet-7NZHBO7P-CC7His0F-DGLBqmMP.js +1 -0
  62. package/dist/assets/{pegDiagram-VL7TDLO6-CZuV1UUk-Ciz03uoq.js → pegDiagram-VL7TDLO6-CZuV1UUk-B5vzA-xE.js} +1 -1
  63. package/dist/assets/pie-RZYD4A2V-CCrcq2sL-ggnddn1X.js +1 -0
  64. package/dist/assets/{pieDiagram-7S7Q4E2Y-B6cd1CWd-CPmXRIzT.js → pieDiagram-7S7Q4E2Y-B6cd1CWd-CUDS4Sno.js} +1 -1
  65. package/dist/assets/{quadrantDiagram-CIZ2JOQS-BvGHVjRA-qpv2zwpv.js → quadrantDiagram-CIZ2JOQS-BvGHVjRA-B8lvO4Zk.js} +1 -1
  66. package/dist/assets/radar-I7S5WNFK-C5TUrpHf-Biu2ZB_3.js +1 -0
  67. package/dist/assets/railroad-3IZDKUUU-CGuuFEd8-CWbXRRgb.js +1 -0
  68. package/dist/assets/railroad-abnf-AHOZXSZD-DuoCSFZY-D31d1XeY.js +1 -0
  69. package/dist/assets/railroad-ebnf-EBAXGLYW-ig-DG9e_-yjfgHrSG.js +1 -0
  70. package/dist/assets/railroad-peg-LSFZ7HO6-BkBgpyvu-BJplGLDh.js +1 -0
  71. package/dist/assets/{railroadDiagram-AXF67PYL-DDtBla5s-DswUZ1l7.js → railroadDiagram-AXF67PYL-DDtBla5s-DHWm1Ox2.js} +1 -1
  72. package/dist/assets/{requirementDiagram-LRYGKXZP-DEh2MJlW-DSsLsY6R.js → requirementDiagram-LRYGKXZP-DEh2MJlW-DsCt-Uni.js} +1 -1
  73. package/dist/assets/{sankeyDiagram-W5VNT64P-CHkaBx7U-c9ucgH40.js → sankeyDiagram-W5VNT64P-CHkaBx7U-Bkx-TT6H.js} +1 -1
  74. package/dist/assets/{sequenceDiagram-SI44F4Z6-D8tHDhWP-GbjcMRwM.js → sequenceDiagram-SI44F4Z6-D8tHDhWP-C_n-BVwe.js} +1 -1
  75. package/dist/assets/{stateDiagram-OKZ733FA-KNjKsfsT-oJnFM5PH.js → stateDiagram-OKZ733FA-KNjKsfsT-DTO4blEz.js} +1 -1
  76. package/dist/assets/stateDiagram-v2-UEYNNEHI-B88w7Ous-BMTM7EXJ.js +1 -0
  77. package/dist/assets/{swimlanes-SLNWSIFB-D_yJNxBK-ClZU9R9x.js → swimlanes-SLNWSIFB-D_yJNxBK-DZn7TQsl.js} +1 -1
  78. package/dist/assets/swimlanesDiagram-ULZ7WXOC-DNcZzqTp-DdIK7YaL.js +8 -0
  79. package/dist/assets/{timeline-definition-Z64GVDOM-BcEcbSq1-B4Bzc1Aq.js → timeline-definition-Z64GVDOM-BcEcbSq1-MGNwTSwZ.js} +1 -1
  80. package/dist/assets/treeView-QDETBFTQ-CqfT0I1z-B8T-RCe5.js +1 -0
  81. package/dist/assets/treemap-6X3UGDF4-CiJkiGWo-DT1sAEri.js +1 -0
  82. package/dist/assets/{vennDiagram-T6HMQDX7-CxS3fcVg-D5bZGr-c.js → vennDiagram-T6HMQDX7-CxS3fcVg-Bbm73E7e.js} +1 -1
  83. package/dist/assets/wardley-OPB4EBWU-D1tuVHAV-tVLCXwET.js +1 -0
  84. package/dist/assets/{wardleyDiagram-T6FBY63Y-D_XCiR14-etNVBxbw.js → wardleyDiagram-T6FBY63Y-D_XCiR14-BNNg221Y.js} +1 -1
  85. package/dist/assets/{xychartDiagram-ELKLHX3M-BU4yBDeE-C58nd7P0.js → xychartDiagram-ELKLHX3M-BU4yBDeE-BLHL_8rx.js} +1 -1
  86. package/dist/index.html +2 -2
  87. package/package.json +2 -2
  88. package/server/backends/collectionNotifierAdapter.ts +38 -7
  89. package/server/backends/collectionSelfContainment.ts +278 -0
  90. package/server/backends/collectionWatchers.ts +174 -15
  91. package/server/backends/collections.ts +13 -2
  92. package/server/backends/feeds.ts +21 -12
  93. package/server/backends/files.ts +43 -7
  94. package/server/backends/remoteHost/commandScope.ts +45 -0
  95. package/server/backends/remoteHost/getCollection.spec.ts +14 -1
  96. package/server/backends/remoteHost/handlers/getCollection.ts +11 -6
  97. package/server/backends/remoteHost/handlers/getFeed.ts +9 -4
  98. package/server/backends/remoteHost/handlers/getRemoteView.ts +3 -2
  99. package/server/backends/remoteHost/handlers/getRemoteViewItems.ts +3 -2
  100. package/server/backends/remoteHost/handlers/listCollections.ts +4 -4
  101. package/server/backends/remoteHost/handlers/listFeeds.ts +7 -4
  102. package/server/backends/remoteHost/handlers/listSkills.ts +6 -3
  103. package/server/backends/remoteHost/handlers/mutateRemoteView.ts +3 -2
  104. package/server/backends/remoteView.ts +5 -1
  105. package/server/backends/scheduled-run.ts +86 -0
  106. package/server/backends/scheduler-adapter.ts +39 -0
  107. package/server/backends/scheduler-state-seed.ts +87 -0
  108. package/server/backends/scheduler.ts +98 -26
  109. package/server/backends/system-tasks.ts +10 -4
  110. package/server/backends/worklog.ts +20 -10
  111. package/server/backends/workspaceSetup.ts +8 -1
  112. package/server/index.ts +11 -9
  113. package/server/infra/collection-tool.ts +15 -1
  114. package/server/infra/project-root.ts +51 -7
  115. package/server/routes/app-routes.ts +6 -2
  116. package/server/routes/plugin-routes.ts +72 -22
  117. package/server/session/background-chat.ts +9 -0
  118. package/server/session/scheduled-chat.ts +8 -2
  119. package/dist/assets/architecture-TIHT7OUA-Cqhmai3f-Cv_ndCVi.js +0 -1
  120. package/dist/assets/channel-DKMa7Sn5-BaAfUVFI.js +0 -1
  121. package/dist/assets/classDiagram-JCYQIIEL-C1ePmEG1-C9EzE_DN.js +0 -1
  122. package/dist/assets/classDiagram-v2-OCEON4UE-C_O3VNBf-C9EzE_DN.js +0 -1
  123. package/dist/assets/cynefin-VYW2F7L2-DvSvuXnG-DYdPNWBf.js +0 -1
  124. package/dist/assets/eventmodeling-45OFAUF4-jdctDg0T-CaXk3edG.js +0 -1
  125. package/dist/assets/flowDiagram-UKHOOZJN-CR3dcoRl-BruZOSTL.js +0 -1
  126. package/dist/assets/gitGraph-TEB2WS4Q-C4cKwl5j-2aSGczK5.js +0 -1
  127. package/dist/assets/info-DKCQHKI2-DPUCBYWS-DfgqsrhV.js +0 -1
  128. package/dist/assets/packet-7NZHBO7P-CC7His0F-3jvv5KyU.js +0 -1
  129. package/dist/assets/pie-RZYD4A2V-CCrcq2sL-B1d6EDGA.js +0 -1
  130. package/dist/assets/radar-I7S5WNFK-C5TUrpHf-BNT9q7Hl.js +0 -1
  131. package/dist/assets/railroad-3IZDKUUU-CGuuFEd8-DvKf9W63.js +0 -1
  132. package/dist/assets/railroad-abnf-AHOZXSZD-DuoCSFZY-B6303QUX.js +0 -1
  133. package/dist/assets/railroad-ebnf-EBAXGLYW-ig-DG9e_-eWx1p0cd.js +0 -1
  134. package/dist/assets/railroad-peg-LSFZ7HO6-BkBgpyvu-gjuyjp8y.js +0 -1
  135. package/dist/assets/stateDiagram-v2-UEYNNEHI-B88w7Ous-CJTxIq2F.js +0 -1
  136. package/dist/assets/swimlanesDiagram-ULZ7WXOC-DNcZzqTp-a-R1A8Fy.js +0 -8
  137. package/dist/assets/treeView-QDETBFTQ-CqfT0I1z-CheA8f5U.js +0 -1
  138. package/dist/assets/treemap-6X3UGDF4-CiJkiGWo-93EKyl15.js +0 -1
  139. package/dist/assets/wardley-OPB4EBWU-D1tuVHAV-CHpba1o8.js +0 -1
package/README.md CHANGED
@@ -692,6 +692,14 @@ and not built*. The window is **since the last run** (tracked in
692
692
  work. It reads and reconciles progress against `vision.md` / `milestones.md` (creating
693
693
  empty ones if absent) so a long-running goal isn't forgotten.
694
694
 
695
+ A run due while the server was **off** is not lost: built-in scheduled tasks record their
696
+ runs in `config/scheduler/state.json` and **catch up at startup**, each by its own missed-run
697
+ policy. The worklog's is `run-once` — a single run covering everything since the last, so
698
+ several missed windows don't become several batches summarising the same period. Whether
699
+ they ran, and when they run next, is in `GET /api/scheduler/tasks`; the history is in
700
+ `GET /api/scheduler/logs` (`?taskId=&since=&limit=`, newest first) and on disk under
701
+ `data/scheduler/logs/`.
702
+
695
703
  Output lands in the wiki: one **weekly page** per ISO week
696
704
  (`data/wiki/pages/dev-log-YYYY-www.md` — filenames are lowercase, or the wiki can't open
697
705
  them), each tagged `worklog`. To browse them, open the **作業ログ 一覧** hub page
@@ -1130,9 +1138,9 @@ absent from the answer — which is how a caller learns work cannot start on it.
1130
1138
  Each grid cell's header shows two badges for its session, refreshed when a turn finishes
1131
1139
  (from `GET /api/session/:id`):
1132
1140
 
1133
- ![A live Claude cell — the header shows the model·context and token badges this section describes](https://raw.githubusercontent.com/receptron/mulmoterminal/main/docs/guide/images/grid-cell-live.png)
1141
+ ![A live Claude cell's header, close up — the model·context and token badges this section describes](https://raw.githubusercontent.com/receptron/mulmoterminal/main/docs/guide/images/grid-cell-live.png)
1134
1142
 
1135
- *Both badges, live on a real Claude session: **`Opus · ctx 5%`** (model family + how full its context window is) and **`⇡427k ⇣1.8k`** (cumulative input / output tokens for the session). They sit in the header's first row alongside the **status dot**, directory, and **git chip** (`⎇ main ●2`), with what the agent is doing to the right; the icon buttons and the **timeline** (🕘) of tool calls are on the second row.*
1143
+ *Both badges, live on a real Claude session: **`Sonnet · ctx 9%`** (model family + how full its context window is) and **`⇡1.8M ⇣6.9k`** (cumulative input / output tokens for the session). They sit in the header's first row alongside the **status dot** and the **git chip** (`⎇ main ●2`), with what the agent is doing to the right; the working directory, the icon buttons and the **timeline** (🕘) of tool calls are on the second row.*
1136
1144
 
1137
1145
  - **Context badge** — e.g. `Opus · ctx 35%`: the model family plus how full its context
1138
1146
  window is (the *last* turn's input + cache tokens ÷ the model's window — **1M** for
@@ -19,6 +19,12 @@ export interface CollectionNotifyTarget {
19
19
  slug: string;
20
20
  /** Absent on a collection-level bell — those can't accent a specific record. */
21
21
  itemId?: string | undefined;
22
+ /** The record's project, as the opaque id the API takes. ABSENT MEANS THE WORKSPACE — both
23
+ * because that is what a workspace bell has always written and because it is the only thing
24
+ * MulmoClaude, which has one root, can write. A slug is unique within a root and nowhere
25
+ * else, so a reader that ignores this accents the same-named record of whichever project is
26
+ * on screen. */
27
+ project?: string | undefined;
22
28
  }
23
29
 
24
30
  /** Narrow a notification's opaque `pluginData` to its collection navigate target,
@@ -31,7 +37,11 @@ export function collectionNotifyTargetOf(pluginData: unknown): CollectionNotifyT
31
37
  if (!isRecord(action)) return null;
32
38
  const { target } = action;
33
39
  if (!isRecord(target)) return null;
34
- const { view, slug, itemId } = target;
40
+ const { view, slug, itemId, project } = target;
35
41
  if (view !== COLLECTION_NOTIFY_VIEW || typeof slug !== "string" || slug.length === 0) return null;
36
- return { slug, itemId: typeof itemId === "string" && itemId.length > 0 ? itemId : undefined };
42
+ return {
43
+ slug,
44
+ itemId: typeof itemId === "string" && itemId.length > 0 ? itemId : undefined,
45
+ project: typeof project === "string" && project.length > 0 ? project : undefined,
46
+ };
37
47
  }
@@ -0,0 +1,84 @@
1
+ // "Would this collection survive a clone?" — the wire shape, shared because BOTH sides decide
2
+ // from it: the server produces the report (server/backends/collectionSelfContainment.ts) and the
3
+ // Collections pane renders it, colouring by severity and blocking on `portable`.
4
+ //
5
+ // In `common/` rather than mirrored, for the reason the layout rule gives: a second copy of a
6
+ // union is how a writer and a reader drift while both keep compiling. The RULES stay server-side
7
+ // — they read the filesystem and shell out to git — and only their result crosses.
8
+ import { isRecord } from "./isRecord.js";
9
+ import { isUnknownArray } from "./isUnknownArray.js";
10
+
11
+ /** Why a collection would not survive a clone. Stable strings — a client branches on these, and
12
+ * the prose is free to be rewritten without breaking it. */
13
+ export type SelfContainmentCode =
14
+ /** The skill lives in `~/.claude/skills`, i.e. on this machine and not in the repo. */
15
+ | "user-scope"
16
+ /** Records are one SQLite file: git cannot merge it. */
17
+ | "sqlite-store"
18
+ /** Records are rows of a CSV read through DuckDB — a runtime the clone must also have. */
19
+ | "csv-runtime"
20
+ /** Something the records need is git-ignored: the schema travels, they do not. */
21
+ | "data-ignored"
22
+ /** No `primaryKey`, so ids are 4 random bytes and two machines can mint the same one. */
23
+ | "no-primary-key"
24
+ /** The project is not a git repo, so there is nothing to clone and most checks do not apply. */
25
+ | "not-a-repo";
26
+
27
+ /** `blocker` stops the clone working; `warning` costs something on the other machine; `info` is
28
+ * context. Only a blocker makes `portable` false. */
29
+ export type SelfContainmentSeverity = "blocker" | "warning" | "info";
30
+
31
+ export interface SelfContainmentFinding {
32
+ /** One of `SelfContainmentCode` in practice, typed as a plain string on the WIRE on purpose: a
33
+ * newer server may report a code this build has never heard of, and narrowing here would drop
34
+ * a real finding behind a version skew. Nothing branches on it — the pane renders `message`
35
+ * and colours by `severity` — so widening costs nothing. A spec pins that everything the
36
+ * server produces IS in the union. */
37
+ code: string;
38
+ severity: SelfContainmentSeverity;
39
+ /** What breaks on the other machine, in the terms the person will see it. */
40
+ message: string;
41
+ }
42
+
43
+ export interface SelfContainmentReport {
44
+ slug: string;
45
+ /** True when nothing BLOCKS the clone. Warnings can still be present. */
46
+ portable: boolean;
47
+ findings: SelfContainmentFinding[];
48
+ }
49
+
50
+ /** The severity IS narrowed, unlike the code: it decides how the row is rendered AND whether the
51
+ * finding is a blocker, so an unrecognised one cannot be shown honestly. A predicate rather than
52
+ * a list membership test, so the narrowing is the type system's rather than an assertion's. */
53
+ export function isSelfContainmentSeverity(value: unknown): value is SelfContainmentSeverity {
54
+ return value === "blocker" || value === "warning" || value === "info";
55
+ }
56
+
57
+ function asFinding(value: unknown): SelfContainmentFinding | null {
58
+ if (!isRecord(value)) return null;
59
+ const { code, severity, message } = value;
60
+ if (typeof code !== "string" || typeof message !== "string") return null;
61
+ if (!isSelfContainmentSeverity(severity)) return null;
62
+ return { code, severity, message };
63
+ }
64
+
65
+ /** Narrow a fetched body to the report, or null when it is not one. The body arrives as
66
+ * `unknown` — a truncated response, an error page, an older server — so every level is checked
67
+ * rather than trusted. */
68
+ export function asSelfContainmentReport(body: unknown): SelfContainmentReport | null {
69
+ if (!isRecord(body)) return null;
70
+ const { slug, portable, findings } = body;
71
+ if (typeof slug !== "string" || typeof portable !== "boolean" || !isUnknownArray(findings)) return null;
72
+ const parsed: SelfContainmentFinding[] = [];
73
+ for (const entry of findings) {
74
+ const finding = asFinding(entry);
75
+ // ONE UNREADABLE FINDING REJECTS THE WHOLE REPORT. Skipping it would be the worse failure:
76
+ // if the dropped finding was the only blocker, the caller is handed `findings: []` and tells
77
+ // the user "nothing to fix — it travels" about a collection that does not. A report we cannot
78
+ // fully read is not a clean bill of health, and "could not run the check" is the honest
79
+ // answer — visible and actionable, where a false all-clear is neither.
80
+ if (!finding) return null;
81
+ parsed.push(finding);
82
+ }
83
+ return { slug, portable, findings: parsed };
84
+ }
@@ -31,6 +31,20 @@ export const isToolGroup = (value: unknown): value is ToolGroup => TOOL_GROUPS.s
31
31
  // front of the spend (same reasoning as presentDocument below).
32
32
  export const CANVAS_TOOL_GROUPS: readonly ToolGroup[] = ["render", "media"];
33
33
 
34
+ // The groups the COLLECTIONS pane is made of. `data` is the group manageCollection and
35
+ // presentCollection belong to, and the pane is a window onto exactly that store — a directory
36
+ // that never registered the group has no collection tools, so the pane is a door onto a room the
37
+ // agent beside it cannot enter.
38
+ //
39
+ // Named here rather than written as `"data"` at the call site for the same reason
40
+ // CANVAS_TOOL_GROUPS is: a rename must not leave a literal pointing at a group that is gone.
41
+ export const COLLECTIONS_TOOL_GROUPS: readonly ToolGroup[] = ["data"];
42
+
43
+ /** Does this session/directory have the collection tools? Same shape as `hasCanvasGroup`, and
44
+ * validated the same way — an unknown group name from a newer server must not count. */
45
+ export const hasCollectionsGroup = (groups: unknown): boolean =>
46
+ Array.isArray(groups) && groups.some((group) => isToolGroup(group) && COLLECTIONS_TOOL_GROUPS.includes(group));
47
+
34
48
  // Does a session/directory reach the Canvas at all? Asked of the group list the server reports,
35
49
  // whose members arrive as plain strings — validated rather than cast, since an unknown name from
36
50
  // a newer server must not count as a canvas group.
@@ -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-CxIKaNt7.js";import"./chunk-I66GZJ75-DSPCVCny-DUUEhGIc.js";import"./chunk-3NCLNEKW-CBztX243-DYiY7RPy.js";import{n as i,r as a,t as o}from"./chunk-6Q2QTUOP-Cx8nz5_t-CnRVqq3q.js";import{t as s}from"./chunk-JWPE2WC7-BQ3zXr2k-DSd3Ct95.js";var c=r().RailroadAbnf.parser.LangiumParser,l=e(e=>{let t=e.alternatives.map(u);return t.length===1?t[0]:{type:`choice`,alternatives:t}},`transformAlternation`),u=e(e=>{let t=e.elements.map(f);return t.length===1?t[0]:{type:`sequence`,elements:t}},`transformConcatenation`),d=e(e=>{if(e.includes(`*`)){let[t,n]=e.split(`*`);return{min:t?parseInt(t,10):0,max:n?parseInt(n,10):1/0}}let t=parseInt(e,10);return{min:t,max:t}},`parseRepeat`),f=e(e=>{let t=p(e.primary);if(!e.repeat)return t;let{min:n,max:r}=d(e.repeat);return n===0&&r===1?{type:`optional`,element:t}:{type:`repetition`,element:t,min:n,max:r}},`transformElement`),p=e(e=>{switch(e.$type){case`AbnfStringLiteral`:return{type:`terminal`,value:e.value};case`AbnfNumVal`:return{type:`terminal`,value:e.value};case`AbnfRuleName`:return{type:`nonterminal`,name:e.name};case`AbnfGroup`:return l(e.element);case`AbnfOptionalGroup`:return{type:`optional`,element:l(e.element)};default:throw Error(`Unsupported ABNF primary node: ${e.$type}`)}},`transformPrimary`),m=e(e=>({name:e.name,definition:l(e.definition)}),`transformRule`),h=e(e=>{s(e,a),e.title&&a.setTitle(e.title),e.rules.map(e=>a.addRule(m(e)))},`populateDb`),g={parser:{parse:e(e=>{a.clear(),t.debug(`[ABNF Parser] Starting Langium parse`);let r=c.parse(e);if(r.lexerErrors.length>0||r.parserErrors.length>0)throw new n(r);let i=r.value;t.debug(`[ABNF Parser] Parsed rules:`,i.rules.length),h(i),t.debug(`[ABNF Parser] Parse complete`)},`parse`),parser:{yy:a}},db:a,renderer:o,styles:i};export{g as diagram};
1
+ import{n as e}from"./chunk-Y2CYZVJY-Bdt8pFDJ-DsF7k-Jl.js";import{f as t}from"./src-CvsWqFln-Tc7ZSrRz.js";import{_ as n,g as r}from"./mermaid-parser.core-C1baW7NG-B9TNqufx.js";import"./chunk-I66GZJ75-DSPCVCny-BJLh4409.js";import"./chunk-3NCLNEKW-CBztX243-CRh6N7eI.js";import{n as i,r as a,t as o}from"./chunk-6Q2QTUOP-Cx8nz5_t-DoqT-qjo.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-B9TNqufx.js";export{e as createArchitectureServices};