dreamcontext 0.10.0 → 0.10.5

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 (145) hide show
  1. package/README.md +39 -5
  2. package/agents/curator-auditor.md +5 -0
  3. package/agents/dreamcontext-explore.md +5 -1
  4. package/agents/initializer-ingestor.md +1 -0
  5. package/agents/initializer-scout.md +5 -0
  6. package/agents/sleep-product.md +2 -0
  7. package/agents/sleep-tasks.md +7 -2
  8. package/dist/agents/curator-auditor.md +5 -0
  9. package/dist/agents/dreamcontext-explore.md +5 -1
  10. package/dist/agents/initializer-ingestor.md +1 -0
  11. package/dist/agents/initializer-scout.md +5 -0
  12. package/dist/agents/sleep-product.md +2 -0
  13. package/dist/agents/sleep-tasks.md +7 -2
  14. package/dist/dashboard/assets/{BrainCanvas3D-DPHKVW49.js → BrainCanvas3D-8hG96aAi.js} +1 -1
  15. package/dist/dashboard/assets/{_baseUniq-CHd2laKt.js → _baseUniq-b4AibH2-.js} +1 -1
  16. package/dist/dashboard/assets/{ar-SA-G6X2FPQ2-CJm41yHw.js → ar-SA-G6X2FPQ2-DpGPIe5Z.js} +1 -1
  17. package/dist/dashboard/assets/{arc-DUqUK5I0.js → arc-BHNPUsz3.js} +1 -1
  18. package/dist/dashboard/assets/{architectureDiagram-Q4EWVU46-CRDXKDvE.js → architectureDiagram-Q4EWVU46-IzEd_B2U.js} +1 -1
  19. package/dist/dashboard/assets/{az-AZ-76LH7QW2-BvugTMBT.js → az-AZ-76LH7QW2-Ccf6e1ON.js} +1 -1
  20. package/dist/dashboard/assets/{bg-BG-XCXSNQG7-CLr0Fn-e.js → bg-BG-XCXSNQG7-XnDUjubv.js} +1 -1
  21. package/dist/dashboard/assets/{blockDiagram-DXYQGD6D-B8exO_lL.js → blockDiagram-DXYQGD6D-CEINLAFi.js} +1 -1
  22. package/dist/dashboard/assets/{bn-BD-2XOGV67Q-D0vwADrS.js → bn-BD-2XOGV67Q-E9FzPBnu.js} +1 -1
  23. package/dist/dashboard/assets/{c4Diagram-AHTNJAMY-Cejeoprm.js → c4Diagram-AHTNJAMY-VrHpmy8U.js} +1 -1
  24. package/dist/dashboard/assets/{ca-ES-6MX7JW3Y-CxqyG_0S.js → ca-ES-6MX7JW3Y-Cnp7YBQb.js} +1 -1
  25. package/dist/dashboard/assets/channel-DwaG7WPN.js +1 -0
  26. package/dist/dashboard/assets/{chunk-4BX2VUAB-BKe2HbO0.js → chunk-4BX2VUAB-CuueCQHq.js} +1 -1
  27. package/dist/dashboard/assets/{chunk-4TB4RGXK-BYd5xUfH.js → chunk-4TB4RGXK-BhlZWQoi.js} +1 -1
  28. package/dist/dashboard/assets/{chunk-55IACEB6-BRmdVuF4.js → chunk-55IACEB6-ClixcVTq.js} +1 -1
  29. package/dist/dashboard/assets/{chunk-EDXVE4YY-B-pwoibO.js → chunk-EDXVE4YY-DUj1uWsJ.js} +1 -1
  30. package/dist/dashboard/assets/{chunk-FMBD7UC4-LC1eQ6Bn.js → chunk-FMBD7UC4-BZClSbG6.js} +1 -1
  31. package/dist/dashboard/assets/{chunk-OYMX7WX6-w2Fbw2qj.js → chunk-OYMX7WX6-CMMXG2K9.js} +1 -1
  32. package/dist/dashboard/assets/{chunk-QZHKN3VN-BCWG4fy9.js → chunk-QZHKN3VN-CI5x9wkp.js} +1 -1
  33. package/dist/dashboard/assets/{chunk-YZCP3GAM-CrKe7Bc4.js → chunk-YZCP3GAM-DnpOMFO-.js} +1 -1
  34. package/dist/dashboard/assets/classDiagram-6PBFFD2Q-COGCH4LQ.js +1 -0
  35. package/dist/dashboard/assets/classDiagram-v2-HSJHXN6E-COGCH4LQ.js +1 -0
  36. package/dist/dashboard/assets/clone-DwBiydth.js +1 -0
  37. package/dist/dashboard/assets/{cose-bilkent-S5V4N54A-Csw9QUYq.js → cose-bilkent-S5V4N54A-C9xnvFgj.js} +1 -1
  38. package/dist/dashboard/assets/{cs-CZ-2BRQDIVT-CogQs_1l.js → cs-CZ-2BRQDIVT-BHebgNbB.js} +1 -1
  39. package/dist/dashboard/assets/{da-DK-5WZEPLOC-CLE1k6n-.js → da-DK-5WZEPLOC-DYuNSWM8.js} +1 -1
  40. package/dist/dashboard/assets/{dagre-KV5264BT-CYO4L2oQ.js → dagre-KV5264BT-Ck8mmM53.js} +1 -1
  41. package/dist/dashboard/assets/{de-DE-XR44H4JA-Cyk4pAkD.js → de-DE-XR44H4JA-CMw5lMuT.js} +1 -1
  42. package/dist/dashboard/assets/{diagram-5BDNPKRD-_l3m-Gzf.js → diagram-5BDNPKRD-L4erno22.js} +1 -1
  43. package/dist/dashboard/assets/{diagram-G4DWMVQ6-ComC4npi.js → diagram-G4DWMVQ6-Dkmwa2-B.js} +1 -1
  44. package/dist/dashboard/assets/{diagram-MMDJMWI5-xZ9cT0uu.js → diagram-MMDJMWI5-v2PnfbZO.js} +1 -1
  45. package/dist/dashboard/assets/{diagram-TYMM5635-Dnq3s1v5.js → diagram-TYMM5635-1ZO4tNjc.js} +1 -1
  46. package/dist/dashboard/assets/{el-GR-BZB4AONW-BFImbdQn.js → el-GR-BZB4AONW-PXD8ArOs.js} +1 -1
  47. package/dist/dashboard/assets/{erDiagram-SMLLAGMA-kcbabKJD.js → erDiagram-SMLLAGMA-B8gV0kGN.js} +1 -1
  48. package/dist/dashboard/assets/{es-ES-U4NZUMDT-jGtxZhYt.js → es-ES-U4NZUMDT-CbfskKe2.js} +1 -1
  49. package/dist/dashboard/assets/{eu-ES-A7QVB2H4-Bzz2d8CD.js → eu-ES-A7QVB2H4-iqrfeyOI.js} +1 -1
  50. package/dist/dashboard/assets/{fa-IR-HGAKTJCU-63k-G3tN.js → fa-IR-HGAKTJCU-PzU2OiC1.js} +1 -1
  51. package/dist/dashboard/assets/{fi-FI-Z5N7JZ37-ezHcIK6s.js → fi-FI-Z5N7JZ37-CbFLdQ9f.js} +1 -1
  52. package/dist/dashboard/assets/{flowDiagram-DWJPFMVM-B1Uy8SMX.js → flowDiagram-DWJPFMVM-CKx3j3bI.js} +1 -1
  53. package/dist/dashboard/assets/{fr-FR-RHASNOE6-C6Pe7vKj.js → fr-FR-RHASNOE6-BuF2MviY.js} +1 -1
  54. package/dist/dashboard/assets/{ganttDiagram-T4ZO3ILL-CABaaerr.js → ganttDiagram-T4ZO3ILL-CAbTd_KO.js} +1 -1
  55. package/dist/dashboard/assets/{gitGraphDiagram-UUTBAWPF-CcyLIbFK.js → gitGraphDiagram-UUTBAWPF-Di7htCsA.js} +1 -1
  56. package/dist/dashboard/assets/{gl-ES-HMX3MZ6V-sdrg75Ty.js → gl-ES-HMX3MZ6V-BqePaODm.js} +1 -1
  57. package/dist/dashboard/assets/{graph-XfL-ygDi.js → graph-CC7SYwBm.js} +1 -1
  58. package/dist/dashboard/assets/{he-IL-6SHJWFNN-C9y7ygPP.js → he-IL-6SHJWFNN-w9d4AvyL.js} +1 -1
  59. package/dist/dashboard/assets/{hi-IN-IWLTKZ5I-Bf7GXs-7.js → hi-IN-IWLTKZ5I-BwHo17vR.js} +1 -1
  60. package/dist/dashboard/assets/{hu-HU-A5ZG7DT2-SU6SehRg.js → hu-HU-A5ZG7DT2-Dm80xRge.js} +1 -1
  61. package/dist/dashboard/assets/{id-ID-SAP4L64H-DVtmANJA.js → id-ID-SAP4L64H-RpPM18i0.js} +1 -1
  62. package/dist/dashboard/assets/index-CkxvR2LH.css +32 -0
  63. package/dist/dashboard/assets/index-DalMBSek.js +511 -0
  64. package/dist/dashboard/assets/{index-C64a-kHY.js → index-sA_NxF_Y.js} +1 -1
  65. package/dist/dashboard/assets/{infoDiagram-42DDH7IO-DfBeu9Gz.js → infoDiagram-42DDH7IO-z-1I4Qyj.js} +1 -1
  66. package/dist/dashboard/assets/{ishikawaDiagram-UXIWVN3A-CbBN1lYP.js → ishikawaDiagram-UXIWVN3A-DWGoVsQO.js} +1 -1
  67. package/dist/dashboard/assets/{it-IT-JPQ66NNP-BbmyFH6C.js → it-IT-JPQ66NNP-DhOvhKWm.js} +1 -1
  68. package/dist/dashboard/assets/{ja-JP-DBVTYXUO-Cbhk39-5.js → ja-JP-DBVTYXUO-CEZ1K0xn.js} +1 -1
  69. package/dist/dashboard/assets/{journeyDiagram-VCZTEJTY-BW4WNn5U.js → journeyDiagram-VCZTEJTY-Dqh8uQwc.js} +1 -1
  70. package/dist/dashboard/assets/{kaa-6HZHGXH3-Cm-Swgc1.js → kaa-6HZHGXH3-DuFoQ8nX.js} +1 -1
  71. package/dist/dashboard/assets/{kab-KAB-ZGHBKWFO-BX9BAQyv.js → kab-KAB-ZGHBKWFO-BkQCP_3o.js} +1 -1
  72. package/dist/dashboard/assets/{kanban-definition-6JOO6SKY-D6dnUpyA.js → kanban-definition-6JOO6SKY-DCs65HUc.js} +1 -1
  73. package/dist/dashboard/assets/{kk-KZ-P5N5QNE5-MHpPSoz0.js → kk-KZ-P5N5QNE5-Dh9BXA8_.js} +1 -1
  74. package/dist/dashboard/assets/{km-KH-HSX4SM5Z-BU3ECFbO.js → km-KH-HSX4SM5Z-D1S2EcQ_.js} +1 -1
  75. package/dist/dashboard/assets/{ko-KR-MTYHY66A-DqT3JGwF.js → ko-KR-MTYHY66A-DsI3vrEx.js} +1 -1
  76. package/dist/dashboard/assets/{ku-TR-6OUDTVRD-DN2-3fDm.js → ku-TR-6OUDTVRD-CyjK_3XH.js} +1 -1
  77. package/dist/dashboard/assets/{layout-BZ4MGsUu.js → layout-B_y9BOh6.js} +1 -1
  78. package/dist/dashboard/assets/{linear-C0etayOa.js → linear-BdGSdQOc.js} +1 -1
  79. package/dist/dashboard/assets/{lt-LT-XHIRWOB4-DQVwHiLl.js → lt-LT-XHIRWOB4-C6tJka1D.js} +1 -1
  80. package/dist/dashboard/assets/{lv-LV-5QDEKY6T-Dad8CoSF.js → lv-LV-5QDEKY6T-C_xyL_ee.js} +1 -1
  81. package/dist/dashboard/assets/{min-Bl_tJyDg.js → min-U_KGhNEt.js} +1 -1
  82. package/dist/dashboard/assets/{mindmap-definition-QFDTVHPH-BNw0aQbU.js → mindmap-definition-QFDTVHPH-sXmpEpKw.js} +1 -1
  83. package/dist/dashboard/assets/{mr-IN-CRQNXWMA-BbxiQT_Z.js → mr-IN-CRQNXWMA-C0TwGtAU.js} +1 -1
  84. package/dist/dashboard/assets/{my-MM-5M5IBNSE-UoAgrIPq.js → my-MM-5M5IBNSE-RlAQCiXW.js} +1 -1
  85. package/dist/dashboard/assets/{nb-NO-T6EIAALU-CImkOb7l.js → nb-NO-T6EIAALU-C1JHqr1t.js} +1 -1
  86. package/dist/dashboard/assets/{nl-NL-IS3SIHDZ-vfeVTewJ.js → nl-NL-IS3SIHDZ-B0BVD_2p.js} +1 -1
  87. package/dist/dashboard/assets/{nn-NO-6E72VCQL-DUCB91yA.js → nn-NO-6E72VCQL-zQTko94P.js} +1 -1
  88. package/dist/dashboard/assets/{oc-FR-POXYY2M6-BkXl0YMF.js → oc-FR-POXYY2M6-CBZRg6ku.js} +1 -1
  89. package/dist/dashboard/assets/{pa-IN-N4M65BXN-CWiVQtSk.js → pa-IN-N4M65BXN-7s6qpn6h.js} +1 -1
  90. package/dist/dashboard/assets/{percentages-BXMCSKIN-BGA-Ex2O.js → percentages-BXMCSKIN-DckRvLSG.js} +7 -7
  91. package/dist/dashboard/assets/{pica-B8XEUChK.js → pica-ByOjSUxE.js} +1 -1
  92. package/dist/dashboard/assets/{pieDiagram-DEJITSTG-Dic1EjdC.js → pieDiagram-DEJITSTG-BJJsFOH9.js} +1 -1
  93. package/dist/dashboard/assets/{pl-PL-T2D74RX3-g55_1Rbd.js → pl-PL-T2D74RX3-QTzNyi10.js} +1 -1
  94. package/dist/dashboard/assets/{pt-BR-5N22H2LF-DQeCXlLm.js → pt-BR-5N22H2LF-tntUlote.js} +1 -1
  95. package/dist/dashboard/assets/{pt-PT-UZXXM6DQ-CHvZqZyF.js → pt-PT-UZXXM6DQ-B9M5aHl1.js} +1 -1
  96. package/dist/dashboard/assets/{quadrantDiagram-34T5L4WZ-CP7lQiIi.js → quadrantDiagram-34T5L4WZ-BearsU1w.js} +1 -1
  97. package/dist/dashboard/assets/{requirementDiagram-MS252O5E-BWtUEAf6.js → requirementDiagram-MS252O5E-BixosHER.js} +1 -1
  98. package/dist/dashboard/assets/{ro-RO-JPDTUUEW-EwDfeMZo.js → ro-RO-JPDTUUEW-qbgXrb57.js} +1 -1
  99. package/dist/dashboard/assets/{ru-RU-B4JR7IUQ-CD2Zj2l8.js → ru-RU-B4JR7IUQ-CgX4A1Ib.js} +1 -1
  100. package/dist/dashboard/assets/{sankeyDiagram-XADWPNL6-DwvQDD5y.js → sankeyDiagram-XADWPNL6-DMSd55sU.js} +1 -1
  101. package/dist/dashboard/assets/{sequenceDiagram-FGHM5R23-BRglyRtb.js → sequenceDiagram-FGHM5R23-D2-Uwrtb.js} +1 -1
  102. package/dist/dashboard/assets/{si-LK-N5RQ5JYF-BY5MM9Vd.js → si-LK-N5RQ5JYF-CWEkBvJB.js} +1 -1
  103. package/dist/dashboard/assets/{sk-SK-C5VTKIMK-5GG4lqoV.js → sk-SK-C5VTKIMK-CG8moyh9.js} +1 -1
  104. package/dist/dashboard/assets/{sl-SI-NN7IZMDC-DX6b0Bj8.js → sl-SI-NN7IZMDC-CsBFEfKt.js} +1 -1
  105. package/dist/dashboard/assets/{stateDiagram-FHFEXIEX-Dl3yCEGL.js → stateDiagram-FHFEXIEX-vG3jGBpo.js} +1 -1
  106. package/dist/dashboard/assets/stateDiagram-v2-QKLJ7IA2-V8xCsZlI.js +1 -0
  107. package/dist/dashboard/assets/{subset-shared.chunk-CmSgs0wP.js → subset-shared.chunk-Bin8VoC6.js} +1 -1
  108. package/dist/dashboard/assets/{subset-worker.chunk-gyKmbtyq.js → subset-worker.chunk-mRsEjVpS.js} +1 -1
  109. package/dist/dashboard/assets/{sv-SE-XGPEYMSR-Cf_qIZ2K.js → sv-SE-XGPEYMSR-BMD7GbQV.js} +1 -1
  110. package/dist/dashboard/assets/{ta-IN-2NMHFXQM-zwatd37w.js → ta-IN-2NMHFXQM-CjZ7GPuA.js} +1 -1
  111. package/dist/dashboard/assets/{th-TH-HPSO5L25-Cw3uejzD.js → th-TH-HPSO5L25-BTE57yWh.js} +1 -1
  112. package/dist/dashboard/assets/{timeline-definition-GMOUNBTQ-C7YbVDU1.js → timeline-definition-GMOUNBTQ-Bz7MuXCz.js} +1 -1
  113. package/dist/dashboard/assets/{tr-TR-DEFEU3FU-C15eSVKk.js → tr-TR-DEFEU3FU-CKY-uY5_.js} +1 -1
  114. package/dist/dashboard/assets/{uk-UA-QMV73CPH-DtjXD0R5.js → uk-UA-QMV73CPH-BuopbANh.js} +1 -1
  115. package/dist/dashboard/assets/{vennDiagram-DHZGUBPP-CM3qRaPy.js → vennDiagram-DHZGUBPP-TsesBmH7.js} +1 -1
  116. package/dist/dashboard/assets/{vi-VN-M7AON7JQ-TYc9r2ul.js → vi-VN-M7AON7JQ-CLrvMDM6.js} +1 -1
  117. package/dist/dashboard/assets/{wardley-RL74JXVD-hKHpsv-V.js → wardley-RL74JXVD-DlttwW9K.js} +1 -1
  118. package/dist/dashboard/assets/{wardleyDiagram-NUSXRM2D-By2VWEm6.js → wardleyDiagram-NUSXRM2D-BfZXChhy.js} +1 -1
  119. package/dist/dashboard/assets/{xychartDiagram-5P7HB3ND-B_jwEdiv.js → xychartDiagram-5P7HB3ND-jjeDn8EJ.js} +1 -1
  120. package/dist/dashboard/assets/{zh-CN-LNUGB5OW-BMLBhdOl.js → zh-CN-LNUGB5OW-C1MYPzyx.js} +1 -1
  121. package/dist/dashboard/assets/{zh-HK-E62DVLB3-B3F6zPCV.js → zh-HK-E62DVLB3-BriaHjNV.js} +1 -1
  122. package/dist/dashboard/assets/{zh-TW-RAJ6MFWO-BtvvFKFv.js → zh-TW-RAJ6MFWO-BUDimtjA.js} +1 -1
  123. package/dist/dashboard/index.html +3 -3
  124. package/dist/index.js +3277 -1196
  125. package/dist/skill-packs/excalidraw/SKILL.md +19 -1
  126. package/dist/skill-packs/excalidraw/scripts/build_excalidraw.js +47 -8
  127. package/dist/skill-packs/excalidraw/scripts/lib/style.js +111 -21
  128. package/dist/skill-packs/goal-skill/SKILL.md +6 -0
  129. package/package.json +1 -1
  130. package/skill/SKILL.md +15 -10
  131. package/skill/references/cli-reference.md +20 -2
  132. package/skill/references/knowledge-and-recall.md +1 -0
  133. package/skill/references/sleep.md +18 -17
  134. package/skill/references/tasks-and-features.md +37 -0
  135. package/skill-packs/excalidraw/SKILL.md +19 -1
  136. package/skill-packs/excalidraw/scripts/build_excalidraw.js +47 -8
  137. package/skill-packs/excalidraw/scripts/lib/style.js +111 -21
  138. package/skill-packs/goal-skill/SKILL.md +6 -0
  139. package/dist/dashboard/assets/channel-44TauaoC.js +0 -1
  140. package/dist/dashboard/assets/classDiagram-6PBFFD2Q-DvAbYAqz.js +0 -1
  141. package/dist/dashboard/assets/classDiagram-v2-HSJHXN6E-DvAbYAqz.js +0 -1
  142. package/dist/dashboard/assets/clone-C56fm_aT.js +0 -1
  143. package/dist/dashboard/assets/index-CC4bLFLV.js +0 -579
  144. package/dist/dashboard/assets/index-DZ3FBso3.css +0 -32
  145. package/dist/dashboard/assets/stateDiagram-v2-QKLJ7IA2-Q3JaGk-b.js +0 -1
@@ -55,30 +55,44 @@ function findVaultRoot(startDir) {
55
55
  }
56
56
 
57
57
  // ---------- text sizing ----------
58
+ // Excalifont glyph advance (multiples of fontSize): latin ~0.58, emoji/arrows/CJK/combining ~1.05.
59
+ // A flat factor under-counted wide glyphs, so emoji labels measured narrow and overflowed their box.
60
+ // This mirrors glyphW() in scripts/lib/style.js so card() pre-wrapping and on-board height agree.
61
+ function isWideGlyph(code) {
62
+ return (
63
+ (code >= 0x1100 && code <= 0x115f) || (code >= 0x2190 && code <= 0x21ff) ||
64
+ (code >= 0x2300 && code <= 0x23ff) || (code >= 0x25a0 && code <= 0x27bf) ||
65
+ (code >= 0x2b00 && code <= 0x2bff) || (code >= 0x2e80 && code <= 0x9fff) ||
66
+ (code >= 0xac00 && code <= 0xd7a3) || (code >= 0xf900 && code <= 0xfaff) ||
67
+ (code >= 0xfe30 && code <= 0xfe4f) || (code >= 0xff00 && code <= 0xff60) ||
68
+ (code >= 0x1f000 && code <= 0x1faff) || (code >= 0x1f1e6 && code <= 0x1f1ff)
69
+ );
70
+ }
71
+ function glyphW(ch, fontSize) { return fontSize * (isWideGlyph(ch.codePointAt(0)) ? 1.05 : 0.58); }
72
+ function measureText(s, fontSize) { let w = 0; for (const ch of String(s)) w += glyphW(ch, fontSize); return w; }
73
+
58
74
  // When a fixedWidth is given the text element is treated as WRAPPING (autoResize off downstream),
59
75
  // so height must reflect word-wrapped line count — otherwise long captions render as one wide line
60
76
  // and overlap their neighbours. Honors explicit \n and greedily wraps each logical line to width.
61
77
  function sizeText(text, fontSize, fixedWidth) {
62
78
  const rawLines = String(text).split('\n');
63
79
  if (fixedWidth != null) {
64
- const charW = fontSize * 0.52; // approx Excalifont glyph advance
65
- const perLine = Math.max(1, Math.floor(fixedWidth / charW));
66
80
  let totalLines = 0;
67
81
  for (const ln of rawLines) {
68
82
  const words = ln.split(/\s+/).filter(Boolean);
69
83
  if (!words.length) { totalLines += 1; continue; }
70
- let cur = 0, lc = 1;
84
+ let cur = '', lc = 1;
71
85
  for (const w of words) {
72
- const add = (cur ? 1 : 0) + w.length;
73
- if (cur + add > perLine && cur > 0) { lc++; cur = w.length; }
74
- else cur += add;
86
+ if (!cur) { cur = w; continue; }
87
+ if (measureText(cur + ' ' + w, fontSize) > fixedWidth) { lc++; cur = w; }
88
+ else cur += ' ' + w;
75
89
  }
76
90
  totalLines += lc;
77
91
  }
78
92
  return { width: fixedWidth, height: Math.max(Math.round(fontSize * 1.25), Math.round(totalLines * fontSize * 1.25)) };
79
93
  }
80
- const maxLen = rawLines.reduce((m, l) => Math.max(m, l.length), 0);
81
- return { width: Math.max(10, Math.round(maxLen * fontSize * 0.6)), height: Math.round(rawLines.length * fontSize * 1.25) };
94
+ const maxW = rawLines.reduce((m, l) => Math.max(m, measureText(l, fontSize)), 0);
95
+ return { width: Math.max(10, Math.round(maxW)), height: Math.round(rawLines.length * fontSize * 1.25) };
82
96
  }
83
97
 
84
98
  // ---------- element factory ----------
@@ -119,6 +133,31 @@ function buildExcalidraw(spec) {
119
133
  const wikilinkMode = spec.wikilinkMode || 'basename';
120
134
  const background = spec.background || '#ffffff';
121
135
 
136
+ // Pre-flight: every referenced image MUST exist on disk before we write the
137
+ // board. A missing asset would otherwise be emitted as a dangling `## Embedded
138
+ // Files` wikilink (`<sha1>: [[missing.png]]`) that can never resolve in any
139
+ // renderer — the board ships with blank images. Collect ALL missing paths and
140
+ // fail once with the full list (and the board path), so the author fixes every
141
+ // gap in a single pass instead of discovering them one throw at a time.
142
+ const missingImages = [];
143
+ for (const e of (spec.elements || [])) {
144
+ if (e && e.type === 'image' && e.path) {
145
+ // A missing file OR a non-file (directory / broken symlink) is unusable —
146
+ // statSync throws for a broken link / absent path, so default to missing.
147
+ let isFile = false;
148
+ try { isFile = fs.statSync(path.resolve(e.path)).isFile(); } catch { isFile = false; }
149
+ if (!isFile) missingImages.push(e.path);
150
+ }
151
+ }
152
+ if (missingImages.length) {
153
+ throw new Error(
154
+ `build_excalidraw: ${missingImages.length} referenced image(s) missing or not a file — ` +
155
+ `refusing to write a board with dangling embeds:\n ` +
156
+ missingImages.join('\n ') +
157
+ `\n(board: ${outPath})`,
158
+ );
159
+ }
160
+
122
161
  const rng = mulberry32(strHash(path.resolve(outPath)));
123
162
  const elements = [];
124
163
  const textEntries = []; // {text, id}
@@ -23,30 +23,112 @@ function pal(c) { return PALETTE[c] || { fill: c, stroke: INK }; }
23
23
  let _gc = 0;
24
24
  const newGroup = (hint) => `g${++_gc}-${hint || ''}`;
25
25
  const lines = (t) => String(t).split('\n').length;
26
- // word-wrapped line count at a given width — keeps card labels vertically centered when they wrap
27
- function wrapLineCount(text, fontSize, width) {
28
- const perLine = Math.max(1, Math.floor(width / (fontSize * 0.52)));
26
+
27
+ // --- text fitting --------------------------------------------------------
28
+ // Excalifont glyph advance, in multiples of fontSize. Latin is ~0.58; emoji, arrows, CJK and
29
+ // combining marks render roughly square (~1.05) — the old flat 0.52 under-counted them, so wide
30
+ // labels measured narrow and spilled out of their card. Mirrored in build_excalidraw.js sizeText().
31
+ function isWideGlyph(code) {
32
+ return (
33
+ (code >= 0x1100 && code <= 0x115f) || // Hangul Jamo
34
+ (code >= 0x2190 && code <= 0x21ff) || // arrows
35
+ (code >= 0x2300 && code <= 0x23ff) || // misc technical (⏰ ⏳ …)
36
+ (code >= 0x25a0 && code <= 0x27bf) || // geometric shapes, misc symbols, dingbats (✅ ★ …)
37
+ (code >= 0x2b00 && code <= 0x2bff) || // extra arrows / symbols
38
+ (code >= 0x2e80 && code <= 0x9fff) || // CJK radicals … unified ideographs
39
+ (code >= 0xac00 && code <= 0xd7a3) || // Hangul syllables
40
+ (code >= 0xf900 && code <= 0xfaff) || // CJK compatibility ideographs
41
+ (code >= 0xfe30 && code <= 0xfe4f) || // CJK compatibility forms
42
+ (code >= 0xff00 && code <= 0xff60) || // fullwidth forms
43
+ (code >= 0x1f000 && code <= 0x1faff) || // emoji & pictographs
44
+ (code >= 0x1f1e6 && code <= 0x1f1ff) // regional indicators (flags)
45
+ );
46
+ }
47
+ function glyphW(ch, fontSize) { return fontSize * (isWideGlyph(ch.codePointAt(0)) ? 1.05 : 0.58); }
48
+ function measureText(s, fontSize) { let w = 0; for (const ch of String(s)) w += glyphW(ch, fontSize); return w; }
49
+
50
+ // Greedy word-wrap to a pixel width, honoring existing \n and HARD-breaking any single word that is
51
+ // itself wider than the box (e.g. a long URL). Returns the text WITH the newlines baked in — the
52
+ // Obsidian plugin keeps them instead of re-flowing the label into one over-wide centered line.
53
+ function wrapToWidth(text, fontSize, width) {
54
+ const out = [];
55
+ for (const logical of String(text).split('\n')) {
56
+ const words = logical.split(/\s+/).filter(Boolean);
57
+ if (!words.length) { out.push(''); continue; }
58
+ let cur = '';
59
+ for (let word of words) {
60
+ while (measureText(word, fontSize) > width) {
61
+ let acc = '';
62
+ for (const ch of word) {
63
+ if (acc && measureText(acc + ch, fontSize) > width) break;
64
+ acc += ch;
65
+ }
66
+ if (cur) { out.push(cur); cur = ''; }
67
+ out.push(acc);
68
+ word = word.slice(acc.length);
69
+ if (!word) break;
70
+ }
71
+ if (!word) continue;
72
+ const candidate = cur ? cur + ' ' + word : word;
73
+ if (cur && measureText(candidate, fontSize) > width) { out.push(cur); cur = word; }
74
+ else cur = candidate;
75
+ }
76
+ if (cur) out.push(cur);
77
+ }
78
+ return out.join('\n');
79
+ }
80
+
81
+ const _warned = new Set();
82
+ function warnFit(msg) { if (!_warned.has(msg)) { _warned.add(msg); try { console.warn('[excalidraw] ' + msg); } catch (e) {} } }
83
+
84
+ // Wrap `text` to the card's inner width, then shrink the font (down to minFont) until the wrapped
85
+ // label also fits the card height. Returns { text (with baked-in newlines), fontSize, lineCount, fits }.
86
+ function fitText(o) {
87
+ const { text = '', w = 260, h = 92, fontSize = 20, minFont = 9, lineHeight = 1.25, padX = 10, padY = 8 } = o;
88
+ const innerW = Math.max(1, w - 2 * padX);
89
+ const innerH = Math.max(1, h - 2 * padY);
90
+ let fs = Math.max(minFont, Math.round(fontSize));
91
+ let wrapped = wrapToWidth(text, fs, innerW);
92
+ let lineCount = wrapped.split('\n').length;
93
+ while (fs > minFont && lineCount * fs * lineHeight > innerH) {
94
+ fs -= 1;
95
+ wrapped = wrapToWidth(text, fs, innerW);
96
+ lineCount = wrapped.split('\n').length;
97
+ }
98
+ return { text: wrapped, fontSize: fs, lineCount, fits: lineCount * fs * lineHeight <= innerH };
99
+ }
100
+
101
+ // arc-length midpoint of a polyline — keeps a connector label on the line even when it elbows
102
+ function polyMid(pts) {
103
+ if (!pts || pts.length < 2) return (pts && pts[0]) || [0, 0];
104
+ const seg = [];
29
105
  let total = 0;
30
- for (const ln of String(text).split('\n')) {
31
- const words = ln.split(/\s+/).filter(Boolean);
32
- if (!words.length) { total += 1; continue; }
33
- let cur = 0, lc = 1;
34
- for (const w of words) { const add = (cur ? 1 : 0) + w.length; if (cur + add > perLine && cur > 0) { lc++; cur = w.length; } else cur += add; }
35
- total += lc;
106
+ for (let i = 1; i < pts.length; i++) { const l = Math.hypot(pts[i][0] - pts[i - 1][0], pts[i][1] - pts[i - 1][1]); seg.push(l); total += l; }
107
+ let half = total / 2;
108
+ for (let i = 1; i < pts.length; i++) {
109
+ if (half <= seg[i - 1] || i === pts.length - 1) {
110
+ const t = seg[i - 1] ? half / seg[i - 1] : 0;
111
+ return [pts[i - 1][0] + (pts[i][0] - pts[i - 1][0]) * t, pts[i - 1][1] + (pts[i][1] - pts[i - 1][1]) * t];
112
+ }
113
+ half -= seg[i - 1];
36
114
  }
37
- return total;
115
+ return pts[0];
38
116
  }
39
117
 
40
- // rounded card: filled rect + centered label, grouped so they move together
118
+ // rounded card: filled rect + centered label, grouped so they move together. The label is
119
+ // hard-wrapped to the card width and the font auto-shrinks (to `minFont`) until it also fits the
120
+ // height, so text can never spill outside the box. Warns if even the floor font won't fit.
41
121
  function card(o) {
42
- const { x, y, w = 260, h = 92, text = '', color = 'blue', fontSize = 20, stroke = INK, strokeWidth = 2, textColor = INK, roundness = true } = o;
122
+ const { x, y, w = 260, h = 92, text = '', color = 'blue', fontSize = 20, stroke = INK, strokeWidth = 2, textColor = INK, roundness = true, minFont = 9, padX = 10, padY = 8 } = o;
43
123
  const group = o.group || newGroup('card');
44
124
  const p = pal(color);
45
- const textH = wrapLineCount(text, fontSize, w) * fontSize * 1.25;
46
- const ty = y + Math.max(6, (h - textH) / 2);
125
+ const fit = fitText({ text, w, h, fontSize, minFont, padX, padY });
126
+ if (!fit.fits) warnFit(`label ${JSON.stringify(String(text).slice(0, 32))} won't fit a ${w}×${h} card even at ${minFont}px — enlarge the card or shorten the text.`);
127
+ const textH = fit.lineCount * fit.fontSize * 1.25;
128
+ const ty = y + Math.max(padY, (h - textH) / 2);
47
129
  return [
48
130
  { type: 'rectangle', x, y, width: w, height: h, strokeColor: stroke, backgroundColor: p.fill, fillStyle: 'solid', strokeWidth, roundness, group },
49
- { type: 'text', x, y: ty, text, fontSize, color: textColor, width: w, align: 'center', fontFamily: 5, group },
131
+ { type: 'text', x, y: ty, text: fit.text, fontSize: fit.fontSize, color: textColor, width: w, align: 'center', fontFamily: 5, group },
50
132
  ];
51
133
  }
52
134
  // small node (flow step) — card with tighter defaults
@@ -58,13 +140,21 @@ function sectionTitle(o) {
58
140
  return [{ type: 'text', x, y, text, fontSize, color, fontFamily: 5, width: Math.max(200, String(text).length * fontSize * 0.6) }];
59
141
  }
60
142
 
61
- // labeled connector arrow between two points (centers of cards, etc.)
143
+ // labeled connector arrow between two points (centers of cards, etc.).
144
+ // Routing: pass `via:[[x,y],…]` for explicit waypoints, or `elbow:'hv'|'vh'` for an auto right-angle
145
+ // bend ('hv' = horizontal then vertical, 'vh' = vertical then horizontal). Use these to route a link
146
+ // AROUND intervening boxes instead of cutting a diagonal straight through them.
62
147
  function connector(o) {
63
- const { from, to, label, double = false, strokeColor = INK, strokeWidth = 2, dashed = false, labelColor = '#495057', fontSize = 16 } = o;
64
- const out = [{ type: 'arrow', points: [from, to], strokeColor, strokeWidth, strokeStyle: dashed ? 'dashed' : 'solid', endArrow: 'arrow', startArrow: double ? 'arrow' : null }];
148
+ const { from, to, label, double = false, strokeColor = INK, strokeWidth = 2, dashed = false, labelColor = '#495057', fontSize = 16, via = null, elbow = null } = o;
149
+ let pts;
150
+ if (via && via.length) pts = [from, ...via, to];
151
+ else if (elbow === 'hv') pts = [from, [to[0], from[1]], to];
152
+ else if (elbow === 'vh') pts = [from, [from[0], to[1]], to];
153
+ else pts = [from, to];
154
+ const out = [{ type: 'arrow', points: pts, strokeColor, strokeWidth, strokeStyle: dashed ? 'dashed' : 'solid', endArrow: 'arrow', startArrow: double ? 'arrow' : null }];
65
155
  if (label) {
66
- const mx = (from[0] + to[0]) / 2, my = (from[1] + to[1]) / 2;
67
- const w = Math.max(40, String(label).length * fontSize * 0.62);
156
+ const [mx, my] = polyMid(pts);
157
+ const w = Math.max(40, measureText(String(label), fontSize) + fontSize);
68
158
  out.push({ type: 'text', x: mx - w / 2, y: my - fontSize - 4, text: label, fontSize, color: labelColor, width: w, align: 'center', fontFamily: 5 });
69
159
  }
70
160
  return out;
@@ -127,4 +217,4 @@ const leftOf = (x, y, w, h) => [x, y + h / 2];
127
217
  const bottomOf = (x, y, w, h) => [x + w / 2, y + h];
128
218
  const topOf = (x, y, w, h) => [x + w / 2, y];
129
219
 
130
- module.exports = { INK, PALETTE, pal, card, node, sectionTitle, connector, annotate, column, hub, bullets, center, rightOf, leftOf, bottomOf, topOf };
220
+ module.exports = { INK, PALETTE, pal, card, node, sectionTitle, connector, annotate, column, hub, bullets, fitText, measureText, center, rightOf, leftOf, bottomOf, topOf };
@@ -122,6 +122,12 @@ dreamcontext tasks status <slug> in_progress "plan validated; implementing"
122
122
 
123
123
  If `<slug>` already exists, de-collide (append a short suffix) rather than clobbering.
124
124
 
125
+ If the project has **roadmap objectives** (`_dream_context/core/objectives/` non-empty — they appear
126
+ in your snapshot), link the task to the objective(s) this goal serves: `tasks create --objectives a,b`
127
+ (or `dreamcontext tasks objectives <slug> a,b` after). One goal often serves several objectives —
128
+ that's expected. If unsure which, ask the user in Phase 0; never leave an obviously-serving task
129
+ unlinked, and never overwrite an existing non-empty `objectives:` list.
130
+
125
131
  If the project declares **custom task fields** (`_dream_context/overrides/task.md`), `tasks create`
126
132
  hard-fails (exit 1) on an unset `required` field — set each with `--field key=value` on create. For
127
133
  any field marked `ask: true`, ask the user for the value back in Phase 0 (it's a human judgment) rather
@@ -1 +0,0 @@
1
- import{aq as o,ar as n}from"./index-CC4bLFLV.js";const t=(r,a)=>o.lang.round(n.parse(r)[a]);export{t as c};
@@ -1 +0,0 @@
1
- import{s as a,c as s,a as e,C as t}from"./chunk-4TB4RGXK-BYd5xUfH.js";import{_ as i}from"./index-CC4bLFLV.js";import"./chunk-FMBD7UC4-LC1eQ6Bn.js";import"./chunk-YZCP3GAM-CrKe7Bc4.js";import"./chunk-55IACEB6-BRmdVuF4.js";import"./chunk-EDXVE4YY-B-pwoibO.js";var u={parser:e,get db(){return new t},renderer:s,styles:a,init:i(r=>{r.class||(r.class={}),r.class.arrowMarkerAbsolute=r.arrowMarkerAbsolute},"init")};export{u as diagram};
@@ -1 +0,0 @@
1
- import{s as a,c as s,a as e,C as t}from"./chunk-4TB4RGXK-BYd5xUfH.js";import{_ as i}from"./index-CC4bLFLV.js";import"./chunk-FMBD7UC4-LC1eQ6Bn.js";import"./chunk-YZCP3GAM-CrKe7Bc4.js";import"./chunk-55IACEB6-BRmdVuF4.js";import"./chunk-EDXVE4YY-B-pwoibO.js";var u={parser:e,get db(){return new t},renderer:s,styles:a,init:i(r=>{r.class||(r.class={}),r.class.arrowMarkerAbsolute=r.arrowMarkerAbsolute},"init")};export{u as diagram};
@@ -1 +0,0 @@
1
- import{b as r}from"./graph-XfL-ygDi.js";var e=4;function a(o){return r(o,e)}export{a as c};