dreamcontext 0.8.2 → 0.8.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 (130) hide show
  1. package/README.md +98 -3
  2. package/agents/sleep-product.md +45 -0
  3. package/agents/sleep-state.md +3 -1
  4. package/agents/sleep-tasks.md +34 -13
  5. package/dist/agents/sleep-product.md +45 -0
  6. package/dist/agents/sleep-state.md +3 -1
  7. package/dist/agents/sleep-tasks.md +34 -13
  8. package/dist/dashboard/assets/{BrainCanvas3D-CNDjMlun.js → BrainCanvas3D-D8PjCqhM.js} +1 -1
  9. package/dist/dashboard/assets/{_baseUniq-DtoPVYjz.js → _baseUniq-Bh1FtvZ1.js} +1 -1
  10. package/dist/dashboard/assets/{ar-SA-G6X2FPQ2-D_dXe_8i.js → ar-SA-G6X2FPQ2-B2U2zDyG.js} +1 -1
  11. package/dist/dashboard/assets/{arc-8LFYH4lG.js → arc-CjP2r6kV.js} +1 -1
  12. package/dist/dashboard/assets/{architectureDiagram-Q4EWVU46-BIgEpM4v.js → architectureDiagram-Q4EWVU46-NKSTolLw.js} +1 -1
  13. package/dist/dashboard/assets/{az-AZ-76LH7QW2-C30ZBwgT.js → az-AZ-76LH7QW2-DVg6avJ2.js} +1 -1
  14. package/dist/dashboard/assets/{bg-BG-XCXSNQG7-D0R9pSdG.js → bg-BG-XCXSNQG7-DGe9j5k-.js} +1 -1
  15. package/dist/dashboard/assets/{blockDiagram-DXYQGD6D-DRTa0DpJ.js → blockDiagram-DXYQGD6D-9TIN16so.js} +1 -1
  16. package/dist/dashboard/assets/{bn-BD-2XOGV67Q-vkWxteG3.js → bn-BD-2XOGV67Q-gu4ZPvYK.js} +1 -1
  17. package/dist/dashboard/assets/{c4Diagram-AHTNJAMY-Do_gB8Cs.js → c4Diagram-AHTNJAMY-CnCRm_Qw.js} +1 -1
  18. package/dist/dashboard/assets/{ca-ES-6MX7JW3Y-CTyxGdzW.js → ca-ES-6MX7JW3Y-DkBWO2rb.js} +1 -1
  19. package/dist/dashboard/assets/channel-CvynutAQ.js +1 -0
  20. package/dist/dashboard/assets/{chunk-4BX2VUAB-DJlttKoY.js → chunk-4BX2VUAB-DWsjDEg5.js} +1 -1
  21. package/dist/dashboard/assets/{chunk-4TB4RGXK-BdixZX4J.js → chunk-4TB4RGXK-BsxBp2-h.js} +1 -1
  22. package/dist/dashboard/assets/{chunk-55IACEB6-CPhKaTLr.js → chunk-55IACEB6-DSTYhHTs.js} +1 -1
  23. package/dist/dashboard/assets/{chunk-EDXVE4YY-Bv0bQVvi.js → chunk-EDXVE4YY-9RDG5so7.js} +1 -1
  24. package/dist/dashboard/assets/{chunk-FMBD7UC4-DGjRdLDd.js → chunk-FMBD7UC4-BQQGv7tV.js} +1 -1
  25. package/dist/dashboard/assets/{chunk-OYMX7WX6-B-wzkRri.js → chunk-OYMX7WX6-B62jTGjc.js} +1 -1
  26. package/dist/dashboard/assets/{chunk-QZHKN3VN-BwK1NqpV.js → chunk-QZHKN3VN-CgTBTZrW.js} +1 -1
  27. package/dist/dashboard/assets/{chunk-YZCP3GAM-DjEwJGlh.js → chunk-YZCP3GAM-3Dg1saYb.js} +1 -1
  28. package/dist/dashboard/assets/classDiagram-6PBFFD2Q-DWhdz8wj.js +1 -0
  29. package/dist/dashboard/assets/classDiagram-v2-HSJHXN6E-DWhdz8wj.js +1 -0
  30. package/dist/dashboard/assets/clone-DJK7V3ll.js +1 -0
  31. package/dist/dashboard/assets/{cose-bilkent-S5V4N54A-BJXUn11L.js → cose-bilkent-S5V4N54A-B3idOsw5.js} +1 -1
  32. package/dist/dashboard/assets/{cs-CZ-2BRQDIVT-BjRikaNe.js → cs-CZ-2BRQDIVT-xyFkB9a5.js} +1 -1
  33. package/dist/dashboard/assets/{da-DK-5WZEPLOC-Cn3GTxbV.js → da-DK-5WZEPLOC-B3hFYjJY.js} +1 -1
  34. package/dist/dashboard/assets/{dagre-KV5264BT-BHn2c24z.js → dagre-KV5264BT-BoSSN-hv.js} +1 -1
  35. package/dist/dashboard/assets/{de-DE-XR44H4JA-IvGsdpTt.js → de-DE-XR44H4JA-Bkx00nEq.js} +1 -1
  36. package/dist/dashboard/assets/{diagram-5BDNPKRD-YrlF3B5a.js → diagram-5BDNPKRD-Buj8iksu.js} +1 -1
  37. package/dist/dashboard/assets/{diagram-G4DWMVQ6-DHONF1OD.js → diagram-G4DWMVQ6-DRBYjDWl.js} +1 -1
  38. package/dist/dashboard/assets/{diagram-MMDJMWI5-B1vJLt5b.js → diagram-MMDJMWI5-DdlofmeO.js} +1 -1
  39. package/dist/dashboard/assets/{diagram-TYMM5635-C8P5-4A3.js → diagram-TYMM5635-C8y8IvnA.js} +1 -1
  40. package/dist/dashboard/assets/{el-GR-BZB4AONW-B9GA8_lO.js → el-GR-BZB4AONW-SsFgxQNu.js} +1 -1
  41. package/dist/dashboard/assets/{erDiagram-SMLLAGMA-CjWWTCWe.js → erDiagram-SMLLAGMA-OZ3J3PG9.js} +1 -1
  42. package/dist/dashboard/assets/{es-ES-U4NZUMDT-Ct1wP_9r.js → es-ES-U4NZUMDT-BInO41Bx.js} +1 -1
  43. package/dist/dashboard/assets/{eu-ES-A7QVB2H4-C-49gWlR.js → eu-ES-A7QVB2H4-DjjnJ8cU.js} +1 -1
  44. package/dist/dashboard/assets/{fa-IR-HGAKTJCU-DUo8t-xv.js → fa-IR-HGAKTJCU-BjCsO05-.js} +1 -1
  45. package/dist/dashboard/assets/{fi-FI-Z5N7JZ37-DCObnr3i.js → fi-FI-Z5N7JZ37-kAJ6_O9R.js} +1 -1
  46. package/dist/dashboard/assets/{flowDiagram-DWJPFMVM-OQ_IRMqG.js → flowDiagram-DWJPFMVM-BvvULyyH.js} +1 -1
  47. package/dist/dashboard/assets/{fr-FR-RHASNOE6-0EGg3zhN.js → fr-FR-RHASNOE6-CrZukXCy.js} +1 -1
  48. package/dist/dashboard/assets/{ganttDiagram-T4ZO3ILL-DPTSBcnu.js → ganttDiagram-T4ZO3ILL-Sv7sneaT.js} +2 -2
  49. package/dist/dashboard/assets/{gitGraphDiagram-UUTBAWPF-BxfeiCqm.js → gitGraphDiagram-UUTBAWPF-BWplv5am.js} +1 -1
  50. package/dist/dashboard/assets/{gl-ES-HMX3MZ6V-WtVwXY6x.js → gl-ES-HMX3MZ6V-CY3NLwyQ.js} +1 -1
  51. package/dist/dashboard/assets/{graph-Du_3_o8q.js → graph-DU5PqGxo.js} +1 -1
  52. package/dist/dashboard/assets/{he-IL-6SHJWFNN-CfgspIku.js → he-IL-6SHJWFNN-DcuQngSU.js} +1 -1
  53. package/dist/dashboard/assets/{hi-IN-IWLTKZ5I-CS9l2g3B.js → hi-IN-IWLTKZ5I-DKr_uuss.js} +1 -1
  54. package/dist/dashboard/assets/{hu-HU-A5ZG7DT2-BQ46AerM.js → hu-HU-A5ZG7DT2-CgZklxQN.js} +1 -1
  55. package/dist/dashboard/assets/{id-ID-SAP4L64H-BeShJyKQ.js → id-ID-SAP4L64H-BFYAclqc.js} +1 -1
  56. package/dist/dashboard/assets/index-CPZ-rEGO.js +480 -0
  57. package/dist/dashboard/assets/{index-D7dWmypK.js → index-DhbH7HLB.js} +1 -1
  58. package/dist/dashboard/assets/index-DrwAz5zg.css +1 -0
  59. package/dist/dashboard/assets/{infoDiagram-42DDH7IO-CcFhyaQp.js → infoDiagram-42DDH7IO-DcL21hYD.js} +1 -1
  60. package/dist/dashboard/assets/{ishikawaDiagram-UXIWVN3A-9QJeD00p.js → ishikawaDiagram-UXIWVN3A-CP4-Ha6a.js} +1 -1
  61. package/dist/dashboard/assets/{it-IT-JPQ66NNP-csyvfk0t.js → it-IT-JPQ66NNP-DgbO8z_0.js} +1 -1
  62. package/dist/dashboard/assets/{ja-JP-DBVTYXUO-DctpJ2yz.js → ja-JP-DBVTYXUO-2nM4bVbo.js} +1 -1
  63. package/dist/dashboard/assets/{journeyDiagram-VCZTEJTY-CU4EYedt.js → journeyDiagram-VCZTEJTY-CZV9JSbl.js} +1 -1
  64. package/dist/dashboard/assets/{kaa-6HZHGXH3-D0tWzHt3.js → kaa-6HZHGXH3-DyVkacqp.js} +1 -1
  65. package/dist/dashboard/assets/{kab-KAB-ZGHBKWFO-BC-g4xJU.js → kab-KAB-ZGHBKWFO-CqnQNV46.js} +1 -1
  66. package/dist/dashboard/assets/{kanban-definition-6JOO6SKY-BxXqVmz1.js → kanban-definition-6JOO6SKY-CMFYpVon.js} +1 -1
  67. package/dist/dashboard/assets/{kk-KZ-P5N5QNE5-TLB3Lxri.js → kk-KZ-P5N5QNE5-CKaF_obh.js} +1 -1
  68. package/dist/dashboard/assets/{km-KH-HSX4SM5Z-DCh7cRAS.js → km-KH-HSX4SM5Z-DX5TUZuC.js} +1 -1
  69. package/dist/dashboard/assets/{ko-KR-MTYHY66A-BPIl5ido.js → ko-KR-MTYHY66A-DX2Igsee.js} +1 -1
  70. package/dist/dashboard/assets/{ku-TR-6OUDTVRD-TUpeN1Tm.js → ku-TR-6OUDTVRD-B0tZGs6G.js} +1 -1
  71. package/dist/dashboard/assets/{layout-CyrgfqIp.js → layout-3g_7BoW1.js} +1 -1
  72. package/dist/dashboard/assets/linear-CXZ_mpWm.js +1 -0
  73. package/dist/dashboard/assets/{lt-LT-XHIRWOB4-BRKyR_Xw.js → lt-LT-XHIRWOB4-BzCZwLwu.js} +1 -1
  74. package/dist/dashboard/assets/{lv-LV-5QDEKY6T-BANbTe4s.js → lv-LV-5QDEKY6T-Dn-Fj6_V.js} +1 -1
  75. package/dist/dashboard/assets/{min-lcwVZhZ7.js → min-bJtV9AiD.js} +1 -1
  76. package/dist/dashboard/assets/{mindmap-definition-QFDTVHPH-fVIbdlXp.js → mindmap-definition-QFDTVHPH-Dz61NELW.js} +1 -1
  77. package/dist/dashboard/assets/{mr-IN-CRQNXWMA-DLFutdXk.js → mr-IN-CRQNXWMA-D8KTtR8X.js} +1 -1
  78. package/dist/dashboard/assets/{my-MM-5M5IBNSE-CGWrcNBC.js → my-MM-5M5IBNSE-BbCYwFaj.js} +1 -1
  79. package/dist/dashboard/assets/{nb-NO-T6EIAALU-CGRDupuc.js → nb-NO-T6EIAALU-DEJxZlzk.js} +1 -1
  80. package/dist/dashboard/assets/{nl-NL-IS3SIHDZ-BKwBfrzp.js → nl-NL-IS3SIHDZ-DTQekKhh.js} +1 -1
  81. package/dist/dashboard/assets/{nn-NO-6E72VCQL-DDQkGe44.js → nn-NO-6E72VCQL-Otz1_Q7Y.js} +1 -1
  82. package/dist/dashboard/assets/{oc-FR-POXYY2M6-DufeHCWh.js → oc-FR-POXYY2M6-BO1pOtcy.js} +1 -1
  83. package/dist/dashboard/assets/{pa-IN-N4M65BXN-BUzelJDX.js → pa-IN-N4M65BXN-o_zcafD8.js} +1 -1
  84. package/dist/dashboard/assets/{percentages-BXMCSKIN-FxAvjywS.js → percentages-BXMCSKIN-C9aZbplb.js} +7 -7
  85. package/dist/dashboard/assets/{pica-Cek5bFnr.js → pica-B0_4dS6Q.js} +1 -1
  86. package/dist/dashboard/assets/{pieDiagram-DEJITSTG-PgIrKPnB.js → pieDiagram-DEJITSTG-CMwhT31D.js} +1 -1
  87. package/dist/dashboard/assets/{pl-PL-T2D74RX3-Bd-rxZs3.js → pl-PL-T2D74RX3-CvJKdZLx.js} +1 -1
  88. package/dist/dashboard/assets/{pt-BR-5N22H2LF-D0QJGoo5.js → pt-BR-5N22H2LF-DH69aomh.js} +1 -1
  89. package/dist/dashboard/assets/{pt-PT-UZXXM6DQ-DjumltMq.js → pt-PT-UZXXM6DQ-Bt_HMT7S.js} +1 -1
  90. package/dist/dashboard/assets/{quadrantDiagram-34T5L4WZ-C30tZOBh.js → quadrantDiagram-34T5L4WZ-BdXgbSGH.js} +1 -1
  91. package/dist/dashboard/assets/{requirementDiagram-MS252O5E-D3vhi-ZB.js → requirementDiagram-MS252O5E-Bq0YQege.js} +1 -1
  92. package/dist/dashboard/assets/{ro-RO-JPDTUUEW-DmEo8cEd.js → ro-RO-JPDTUUEW-DetQ1m4p.js} +1 -1
  93. package/dist/dashboard/assets/{ru-RU-B4JR7IUQ-ZHCu1nBu.js → ru-RU-B4JR7IUQ-B744z7Cd.js} +1 -1
  94. package/dist/dashboard/assets/{sankeyDiagram-XADWPNL6-Cmbs-PxO.js → sankeyDiagram-XADWPNL6-CTYt5Kku.js} +1 -1
  95. package/dist/dashboard/assets/{sequenceDiagram-FGHM5R23-DlBqk4uQ.js → sequenceDiagram-FGHM5R23-BbPhy9K6.js} +1 -1
  96. package/dist/dashboard/assets/{si-LK-N5RQ5JYF-iuqtpRqI.js → si-LK-N5RQ5JYF-DueeMRG5.js} +1 -1
  97. package/dist/dashboard/assets/{sk-SK-C5VTKIMK-BWFUWdaQ.js → sk-SK-C5VTKIMK-BivWC8UI.js} +1 -1
  98. package/dist/dashboard/assets/{sl-SI-NN7IZMDC-irYTfiq_.js → sl-SI-NN7IZMDC-CHxsSSJQ.js} +1 -1
  99. package/dist/dashboard/assets/{stateDiagram-FHFEXIEX-B6T9ib8G.js → stateDiagram-FHFEXIEX-DAPXkQkR.js} +1 -1
  100. package/dist/dashboard/assets/stateDiagram-v2-QKLJ7IA2-ZA5uLv7f.js +1 -0
  101. package/dist/dashboard/assets/{subset-shared.chunk-LTgWgeng.js → subset-shared.chunk-CxWeBga7.js} +1 -1
  102. package/dist/dashboard/assets/{subset-worker.chunk-CT_2iDuG.js → subset-worker.chunk-V3gpxiYs.js} +1 -1
  103. package/dist/dashboard/assets/{sv-SE-XGPEYMSR-BvDzjArd.js → sv-SE-XGPEYMSR-C-EJgqb-.js} +1 -1
  104. package/dist/dashboard/assets/{ta-IN-2NMHFXQM-DdsS_3Yq.js → ta-IN-2NMHFXQM-DAjiKKkH.js} +1 -1
  105. package/dist/dashboard/assets/{th-TH-HPSO5L25-Duadkok3.js → th-TH-HPSO5L25-Bq7BADtY.js} +1 -1
  106. package/dist/dashboard/assets/{timeline-definition-GMOUNBTQ-CHTQqVpC.js → timeline-definition-GMOUNBTQ-BJhY_iVV.js} +1 -1
  107. package/dist/dashboard/assets/{tr-TR-DEFEU3FU-CTnPpl_3.js → tr-TR-DEFEU3FU--adx_Tct.js} +1 -1
  108. package/dist/dashboard/assets/{uk-UA-QMV73CPH-CAqmQ01_.js → uk-UA-QMV73CPH-DfnkGhht.js} +1 -1
  109. package/dist/dashboard/assets/{vennDiagram-DHZGUBPP-tWl34rwo.js → vennDiagram-DHZGUBPP-BpuWdXIB.js} +1 -1
  110. package/dist/dashboard/assets/{vi-VN-M7AON7JQ-Cz7FDG8R.js → vi-VN-M7AON7JQ-RQSwYL0s.js} +1 -1
  111. package/dist/dashboard/assets/{wardley-RL74JXVD-UjdnBcpJ.js → wardley-RL74JXVD-BuB77QmE.js} +1 -1
  112. package/dist/dashboard/assets/{wardleyDiagram-NUSXRM2D-KhVWSzPf.js → wardleyDiagram-NUSXRM2D-BomUXaGE.js} +1 -1
  113. package/dist/dashboard/assets/{xychartDiagram-5P7HB3ND-SwtVQYTW.js → xychartDiagram-5P7HB3ND-BueWOzBo.js} +1 -1
  114. package/dist/dashboard/assets/{zh-CN-LNUGB5OW-B7cbFS35.js → zh-CN-LNUGB5OW-Bq_CyCdn.js} +1 -1
  115. package/dist/dashboard/assets/{zh-HK-E62DVLB3-CLi9BFmp.js → zh-HK-E62DVLB3-dhMk2wl1.js} +1 -1
  116. package/dist/dashboard/assets/{zh-TW-RAJ6MFWO-XAcgJHay.js → zh-TW-RAJ6MFWO-BTBKc5WB.js} +1 -1
  117. package/dist/dashboard/index.html +2 -2
  118. package/dist/index.js +1457 -780
  119. package/dist/skill-packs/goal-skill/SKILL.md +8 -6
  120. package/package.json +1 -1
  121. package/skill/SKILL.md +3 -3
  122. package/skill-packs/goal-skill/SKILL.md +8 -6
  123. package/dist/dashboard/assets/channel-C5p1t-nJ.js +0 -1
  124. package/dist/dashboard/assets/classDiagram-6PBFFD2Q-sTJpbWV4.js +0 -1
  125. package/dist/dashboard/assets/classDiagram-v2-HSJHXN6E-sTJpbWV4.js +0 -1
  126. package/dist/dashboard/assets/clone-DTslXBzp.js +0 -1
  127. package/dist/dashboard/assets/index-C9VT2u9E.js +0 -480
  128. package/dist/dashboard/assets/index-DoFaQKCx.css +0 -1
  129. package/dist/dashboard/assets/linear-B6cMUkoc.js +0 -1
  130. package/dist/dashboard/assets/stateDiagram-v2-QKLJ7IA2-CN0hAOp7.js +0 -1
package/dist/index.js CHANGED
@@ -18458,11 +18458,11 @@ var init_install_claude_md = __esm({
18458
18458
  import { existsSync as existsSync6, mkdirSync as mkdirSync4, readFileSync as readFileSync7, writeFileSync as writeFileSync7 } from "fs";
18459
18459
  import { dirname as dirname4, join as join6 } from "path";
18460
18460
  function applyClaudeAutoMemory(projectRoot, disable) {
18461
- const settingsPath = join6(projectRoot, ".claude", "settings.json");
18461
+ const settingsPath2 = join6(projectRoot, ".claude", "settings.json");
18462
18462
  let settings = {};
18463
- if (existsSync6(settingsPath)) {
18463
+ if (existsSync6(settingsPath2)) {
18464
18464
  try {
18465
- const parsed = JSON.parse(readFileSync7(settingsPath, "utf-8"));
18465
+ const parsed = JSON.parse(readFileSync7(settingsPath2, "utf-8"));
18466
18466
  if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
18467
18467
  settings = parsed;
18468
18468
  }
@@ -18473,8 +18473,8 @@ function applyClaudeAutoMemory(projectRoot, disable) {
18473
18473
  const desired = !disable;
18474
18474
  if (settings.autoMemoryEnabled === desired) return false;
18475
18475
  settings.autoMemoryEnabled = desired;
18476
- mkdirSync4(dirname4(settingsPath), { recursive: true });
18477
- writeFileSync7(settingsPath, JSON.stringify(settings, null, 2) + "\n", "utf-8");
18476
+ mkdirSync4(dirname4(settingsPath2), { recursive: true });
18477
+ writeFileSync7(settingsPath2, JSON.stringify(settings, null, 2) + "\n", "utf-8");
18478
18478
  return true;
18479
18479
  }
18480
18480
  var init_claude_settings = __esm({
@@ -22458,12 +22458,12 @@ async function resolvePlatforms(projectRoot, raw) {
22458
22458
  return platforms;
22459
22459
  }
22460
22460
  function ensureClaudeHooks(projectRoot) {
22461
- const settingsPath = join9(projectRoot, ".claude", "settings.json");
22461
+ const settingsPath2 = join9(projectRoot, ".claude", "settings.json");
22462
22462
  const result = { added: [], migrated: false };
22463
22463
  let settings = {};
22464
- if (existsSync9(settingsPath)) {
22464
+ if (existsSync9(settingsPath2)) {
22465
22465
  try {
22466
- settings = JSON.parse(readFileSync10(settingsPath, "utf-8"));
22466
+ settings = JSON.parse(readFileSync10(settingsPath2, "utf-8"));
22467
22467
  } catch {
22468
22468
  settings = {};
22469
22469
  }
@@ -22497,7 +22497,7 @@ function ensureClaudeHooks(projectRoot) {
22497
22497
  }
22498
22498
  }
22499
22499
  mkdirSync6(join9(projectRoot, ".claude"), { recursive: true });
22500
- writeFileSync9(settingsPath, JSON.stringify(settings, null, 2) + "\n", "utf-8");
22500
+ writeFileSync9(settingsPath2, JSON.stringify(settings, null, 2) + "\n", "utf-8");
22501
22501
  return result;
22502
22502
  }
22503
22503
  function findPackageFile(subdir, filename) {
@@ -34672,6 +34672,170 @@ var init_migration_runner = __esm({
34672
34672
  }
34673
34673
  });
34674
34674
 
34675
+ // src/lib/sleep-consolidation.ts
34676
+ function sleepinessLevel(debt) {
34677
+ if (debt <= 3) return "Alert";
34678
+ if (debt <= 6) return "Drowsy";
34679
+ if (debt <= 9) return "Sleepy";
34680
+ return "Must Sleep";
34681
+ }
34682
+ function sleepinessRange(debt) {
34683
+ if (debt <= 3) return "0-3";
34684
+ if (debt <= 6) return "4-6";
34685
+ if (debt <= 9) return "7-9";
34686
+ return "10+";
34687
+ }
34688
+ function recomputeDebt(sessions) {
34689
+ return sessions.reduce((sum, s) => sum + (s.score ?? 0), 0);
34690
+ }
34691
+ function depthFromDebt(debt) {
34692
+ if (debt <= 3) return "light";
34693
+ if (debt <= 9) return "standard";
34694
+ return "deep";
34695
+ }
34696
+ function consolidationDepth(debt, opts = {}) {
34697
+ const base = depthFromDebt(debt);
34698
+ if (opts.userRequestedDeep) {
34699
+ return { depth: "deep", reason: "user requested deep consolidation", source: "user" };
34700
+ }
34701
+ const bump = Math.max(0, Math.min(2, opts.agentBump ?? 0));
34702
+ if (bump > 0) {
34703
+ const baseIdx = DEPTH_ORDER.indexOf(base);
34704
+ const idx = Math.min(DEPTH_ORDER.length - 1, baseIdx + bump);
34705
+ return {
34706
+ depth: DEPTH_ORDER[idx],
34707
+ reason: `agent bumped depth by ${bump} tier(s) from ${base}`,
34708
+ source: "agent"
34709
+ };
34710
+ }
34711
+ return { depth: base, reason: `debt ${debt} \u2192 ${base}`, source: "debt" };
34712
+ }
34713
+ function isDestructiveAllowed(depth) {
34714
+ return depth === "deep";
34715
+ }
34716
+ function applyConsolidation(state, epoch) {
34717
+ const next = cloneState(state);
34718
+ let sessionsProcessed = 0;
34719
+ let bookmarksProcessed = 0;
34720
+ let processedSessionIds = [];
34721
+ if (epoch) {
34722
+ const processedSessions = next.sessions.filter((s) => !s.stopped_at || s.stopped_at <= epoch);
34723
+ sessionsProcessed = processedSessions.length;
34724
+ processedSessionIds = processedSessions.map((s) => s.session_id);
34725
+ bookmarksProcessed = next.bookmarks.filter((b) => b.created_at <= epoch).length;
34726
+ next.sessions = next.sessions.filter((s) => {
34727
+ if (!s.stopped_at) return false;
34728
+ return s.stopped_at > epoch;
34729
+ });
34730
+ next.bookmarks = next.bookmarks.filter((b) => b.created_at > epoch);
34731
+ next.dashboard_changes = next.dashboard_changes.filter((c) => c.timestamp > epoch);
34732
+ next.debt = recomputeDebt(next.sessions);
34733
+ } else {
34734
+ sessionsProcessed = next.sessions.length;
34735
+ processedSessionIds = next.sessions.map((s) => s.session_id);
34736
+ bookmarksProcessed = next.bookmarks.length;
34737
+ next.sessions = [];
34738
+ next.bookmarks = [];
34739
+ next.dashboard_changes = [];
34740
+ next.debt = 0;
34741
+ }
34742
+ next.triggers = next.triggers.filter((t) => t.fired_count < t.max_fires);
34743
+ return { state: next, sessionsProcessed, bookmarksProcessed, processedSessionIds };
34744
+ }
34745
+ function upsertSessionOnStop(state, input2) {
34746
+ const next = cloneState(state);
34747
+ const existing = next.sessions.findIndex((s) => s.session_id === input2.session_id);
34748
+ if (existing >= 0) {
34749
+ const oldScore = next.sessions[existing].score ?? 0;
34750
+ next.debt = Math.max(0, next.debt - oldScore);
34751
+ const existingSlugs = next.sessions[existing].task_slugs ?? [];
34752
+ next.sessions[existing] = {
34753
+ ...next.sessions[existing],
34754
+ transcript_path: input2.transcript_path,
34755
+ stopped_at: input2.stopped_at,
34756
+ last_assistant_message: input2.last_assistant_message,
34757
+ change_count: input2.change_count,
34758
+ tool_count: input2.tool_count,
34759
+ score: input2.score,
34760
+ task_slugs: [.../* @__PURE__ */ new Set([...existingSlugs, ...input2.task_slugs])]
34761
+ };
34762
+ next.debt += input2.score;
34763
+ } else {
34764
+ next.sessions.unshift({
34765
+ session_id: input2.session_id,
34766
+ transcript_path: input2.transcript_path,
34767
+ stopped_at: input2.stopped_at,
34768
+ last_assistant_message: input2.last_assistant_message,
34769
+ change_count: input2.change_count,
34770
+ tool_count: input2.tool_count,
34771
+ score: input2.score,
34772
+ task_slugs: input2.task_slugs
34773
+ });
34774
+ next.debt += input2.score;
34775
+ next.sessions_since_last_sleep = (next.sessions_since_last_sleep || 0) + 1;
34776
+ }
34777
+ return next;
34778
+ }
34779
+ function appendCompactionRecord(state, record) {
34780
+ const next = cloneState(state);
34781
+ next.compaction_log.unshift(record);
34782
+ if (next.compaction_log.length > COMPACTION_LOG_CAP) {
34783
+ next.compaction_log = next.compaction_log.slice(0, COMPACTION_LOG_CAP);
34784
+ }
34785
+ return next;
34786
+ }
34787
+ function validateSleepAdd(scoreStr, desc) {
34788
+ const score = parseInt(scoreStr, 10);
34789
+ if (isNaN(score) || score < 1 || score > 3) {
34790
+ return { ok: false, error: "Score must be 1, 2, or 3." };
34791
+ }
34792
+ if (!desc.trim()) {
34793
+ return { ok: false, error: "Description is required." };
34794
+ }
34795
+ return { ok: true };
34796
+ }
34797
+ function buildHistoryEntry(prevDebt, result, summary, today2) {
34798
+ return {
34799
+ date: today2,
34800
+ consolidated_at: (/* @__PURE__ */ new Date()).toISOString(),
34801
+ summary: summary.trim(),
34802
+ debt_before: prevDebt,
34803
+ debt_after: result.state.debt,
34804
+ sessions_processed: result.sessionsProcessed,
34805
+ bookmarks_processed: result.bookmarksProcessed,
34806
+ session_ids: result.processedSessionIds
34807
+ };
34808
+ }
34809
+ function finalizeSleepState(state, summary, today2) {
34810
+ const next = cloneState(state);
34811
+ next.last_sleep = today2;
34812
+ next.last_sleep_summary = summary.trim();
34813
+ next.sleep_started_at = null;
34814
+ next.sessions_since_last_sleep = 0;
34815
+ next.consolidation_depth = null;
34816
+ return next;
34817
+ }
34818
+ function cloneState(state) {
34819
+ return {
34820
+ ...state,
34821
+ sessions: state.sessions.map((s) => ({ ...s, task_slugs: [...s.task_slugs ?? []] })),
34822
+ bookmarks: state.bookmarks.map((b) => ({ ...b })),
34823
+ triggers: state.triggers.map((t) => ({ ...t })),
34824
+ knowledge_access: { ...state.knowledge_access },
34825
+ dashboard_changes: state.dashboard_changes.map((c) => ({ ...c })),
34826
+ compaction_log: state.compaction_log.map((c) => ({ ...c })),
34827
+ pendingMigrationNotices: [...state.pendingMigrationNotices]
34828
+ };
34829
+ }
34830
+ var DEPTH_ORDER, COMPACTION_LOG_CAP;
34831
+ var init_sleep_consolidation = __esm({
34832
+ "src/lib/sleep-consolidation.ts"() {
34833
+ "use strict";
34834
+ DEPTH_ORDER = ["light", "standard", "deep"];
34835
+ COMPACTION_LOG_CAP = 20;
34836
+ }
34837
+ });
34838
+
34675
34839
  // src/cli/commands/sleep.ts
34676
34840
  import { existsSync as existsSync37 } from "fs";
34677
34841
  import { join as join37, dirname as dirname18 } from "path";
@@ -34763,8 +34927,8 @@ function registerSleepCommand(program2) {
34763
34927
  sleep2.command("status").description("Show current sleep debt level and history").action(() => {
34764
34928
  const root = ensureContextRoot();
34765
34929
  const state = readSleepState(root);
34766
- const level = getSleepinessLevel(state.debt);
34767
- const range = getSleepinessRange(state.debt);
34930
+ const level = sleepinessLevel(state.debt);
34931
+ const range = sleepinessRange(state.debt);
34768
34932
  console.log(header("Sleep State"));
34769
34933
  console.log(` Debt: ${source_default.bold(String(state.debt))} ${source_default.dim(`(${range})`)} ${source_default.magentaBright(level)}`);
34770
34934
  console.log(` Last sleep: ${state.last_sleep ? source_default.white(state.last_sleep) : source_default.dim("never")}`);
@@ -34792,16 +34956,13 @@ function registerSleepCommand(program2) {
34792
34956
  }
34793
34957
  });
34794
34958
  sleep2.command("add").argument("<score>", "Debt score to add (1-3)").argument("<description...>", "Description of what happened").description("Record a debt-accumulating action").action((scoreStr, descParts) => {
34795
- const score = parseInt(scoreStr, 10);
34796
- if (isNaN(score) || score < 1 || score > 3) {
34797
- error("Score must be 1, 2, or 3.");
34798
- return;
34799
- }
34800
34959
  const description = descParts.join(" ");
34801
- if (!description.trim()) {
34802
- error("Description is required.");
34960
+ const valid = validateSleepAdd(scoreStr, description);
34961
+ if (!valid.ok) {
34962
+ error(valid.error);
34803
34963
  return;
34804
34964
  }
34965
+ const score = parseInt(scoreStr, 10);
34805
34966
  const root = ensureContextRoot();
34806
34967
  const state = readSleepState(root);
34807
34968
  state.sessions.unshift({
@@ -34816,7 +34977,7 @@ function registerSleepCommand(program2) {
34816
34977
  });
34817
34978
  state.debt += score;
34818
34979
  writeSleepState(root, state);
34819
- const level = getSleepinessLevel(state.debt);
34980
+ const level = sleepinessLevel(state.debt);
34820
34981
  success(`Sleep debt: ${state.debt} (${level})`);
34821
34982
  if (state.debt >= 10) {
34822
34983
  warn("Must sleep! Debt is 10+. Consolidation needed.");
@@ -34824,12 +34985,14 @@ function registerSleepCommand(program2) {
34824
34985
  info("Getting sleepy. Consider consolidating soon.");
34825
34986
  }
34826
34987
  });
34827
- sleep2.command("start").description("Mark beginning of consolidation (sets epoch for safe clearing)").action(() => {
34988
+ sleep2.command("start").description("Mark beginning of consolidation (sets epoch for safe clearing)").option("--deep", "Force a deep consolidation (authorizes destructive knowledge ops)").action((opts) => {
34828
34989
  const root = ensureContextRoot();
34829
34990
  const state = readSleepState(root);
34830
34991
  if (state.sleep_started_at) {
34831
34992
  warn(`Consolidation already in progress (started ${state.sleep_started_at}). Overwriting epoch.`);
34832
34993
  }
34994
+ const decision = consolidationDepth(state.debt, { userRequestedDeep: !!opts.deep });
34995
+ state.consolidation_depth = decision.depth;
34833
34996
  state.pendingMigrationNotices = [];
34834
34997
  const projectRoot = dirname18(root);
34835
34998
  const config = readSetupConfig(projectRoot);
@@ -34853,6 +35016,10 @@ function registerSleepCommand(program2) {
34853
35016
  state.sleep_started_at = (/* @__PURE__ */ new Date()).toISOString();
34854
35017
  writeSleepState(root, state);
34855
35018
  success(`Consolidation epoch set: ${state.sleep_started_at}`);
35019
+ info(`Consolidation depth: ${decision.depth} (source: ${decision.source}) \u2014 ${decision.reason}`);
35020
+ if (decision.depth !== "deep") {
35021
+ info("Light/standard consolidation: do NOT merge/summarize-replace/delete knowledge \u2014 flag candidates in the report instead.");
35022
+ }
34856
35023
  });
34857
35024
  sleep2.command("done").argument("<summary...>", "Summary of what was consolidated").description("Mark consolidation complete, reset debt").action(async (summaryParts) => {
34858
35025
  const summary = summaryParts.join(" ");
@@ -34864,52 +35031,17 @@ function registerSleepCommand(program2) {
34864
35031
  const state = readSleepState(root);
34865
35032
  const previousDebt = state.debt;
34866
35033
  const epoch = state.sleep_started_at;
34867
- let sessionsProcessed = 0;
34868
- let bookmarksProcessed = 0;
34869
- let processedSessionIds = [];
34870
- if (epoch) {
34871
- const processedSessions = state.sessions.filter((s) => !s.stopped_at || s.stopped_at <= epoch);
34872
- sessionsProcessed = processedSessions.length;
34873
- processedSessionIds = processedSessions.map((s) => s.session_id);
34874
- bookmarksProcessed = state.bookmarks.filter((b) => b.created_at <= epoch).length;
34875
- state.sessions = state.sessions.filter((s) => {
34876
- if (!s.stopped_at) return false;
34877
- return s.stopped_at > epoch;
34878
- });
34879
- state.bookmarks = state.bookmarks.filter((b) => b.created_at > epoch);
34880
- state.dashboard_changes = state.dashboard_changes.filter((c) => c.timestamp > epoch);
34881
- state.debt = state.sessions.reduce((sum, s) => sum + (s.score ?? 0), 0);
34882
- } else {
34883
- sessionsProcessed = state.sessions.length;
34884
- processedSessionIds = state.sessions.map((s) => s.session_id);
34885
- bookmarksProcessed = state.bookmarks.length;
34886
- state.sessions = [];
34887
- state.bookmarks = [];
34888
- state.dashboard_changes = [];
34889
- state.debt = 0;
34890
- }
34891
- state.triggers = state.triggers.filter((t) => t.fired_count < t.max_fires);
35034
+ const result = applyConsolidation(state, epoch);
35035
+ const today_ = today();
34892
35036
  const history = readSleepHistory(root);
34893
- history.unshift({
34894
- date: today(),
34895
- consolidated_at: (/* @__PURE__ */ new Date()).toISOString(),
34896
- summary: summary.trim(),
34897
- debt_before: previousDebt,
34898
- debt_after: state.debt,
34899
- sessions_processed: sessionsProcessed,
34900
- bookmarks_processed: bookmarksProcessed,
34901
- session_ids: processedSessionIds
34902
- });
35037
+ history.unshift(buildHistoryEntry(previousDebt, result, summary, today_));
34903
35038
  writeSleepHistory(root, history);
34904
- state.last_sleep = today();
34905
- state.last_sleep_summary = summary.trim();
34906
- state.sleep_started_at = null;
34907
- state.sessions_since_last_sleep = 0;
34908
- writeSleepState(root, state);
34909
- if (epoch && state.sessions.length > 0) {
34910
- success(`Consolidation complete. Debt reduced from ${previousDebt} to ${state.debt}. ${state.sessions.length} post-epoch session(s) preserved.`);
35039
+ const finalState = finalizeSleepState(result.state, summary, today_);
35040
+ writeSleepState(root, finalState);
35041
+ if (epoch && finalState.sessions.length > 0) {
35042
+ success(`Consolidation complete. Debt reduced from ${previousDebt} to ${finalState.debt}. ${finalState.sessions.length} post-epoch session(s) preserved.`);
34911
35043
  } else {
34912
- success(`Consolidation complete. Debt reset from ${previousDebt} to ${state.debt}.`);
35044
+ success(`Consolidation complete. Debt reset from ${previousDebt} to ${finalState.debt}.`);
34913
35045
  }
34914
35046
  try {
34915
35047
  const backend = getTaskBackend(root);
@@ -35001,6 +35133,7 @@ var init_sleep = __esm({
35001
35133
  init_migration_runner();
35002
35134
  init_setup_config();
35003
35135
  init_manifest();
35136
+ init_sleep_consolidation();
35004
35137
  }
35005
35138
  });
35006
35139
 
@@ -36736,6 +36869,44 @@ var init_setup_drift = __esm({
36736
36869
  }
36737
36870
  });
36738
36871
 
36872
+ // src/lib/asset-drift-cache.ts
36873
+ import { existsSync as existsSync45, readFileSync as readFileSync34, writeFileSync as writeFileSync29, mkdirSync as mkdirSync22 } from "fs";
36874
+ import { join as join45, dirname as dirname22 } from "path";
36875
+ function assetDriftCachePath(contextRoot) {
36876
+ return join45(contextRoot, "state", ".asset-drift.json");
36877
+ }
36878
+ function readAssetDriftCache(contextRoot) {
36879
+ try {
36880
+ const p = assetDriftCachePath(contextRoot);
36881
+ if (!existsSync45(p)) return null;
36882
+ const parsed = JSON.parse(readFileSync34(p, "utf-8"));
36883
+ if (!parsed || typeof parsed.cliVersion !== "string" || typeof parsed.setupVersion !== "string" || typeof parsed.usedAssetsChanged !== "boolean") {
36884
+ return null;
36885
+ }
36886
+ return {
36887
+ cliVersion: parsed.cliVersion,
36888
+ setupVersion: parsed.setupVersion,
36889
+ usedAssetsChanged: parsed.usedAssetsChanged,
36890
+ checkedAt: typeof parsed.checkedAt === "number" ? parsed.checkedAt : 0
36891
+ };
36892
+ } catch {
36893
+ return null;
36894
+ }
36895
+ }
36896
+ function writeAssetDriftCache(contextRoot, cache) {
36897
+ const p = assetDriftCachePath(contextRoot);
36898
+ mkdirSync22(dirname22(p), { recursive: true });
36899
+ writeFileSync29(p, JSON.stringify(cache, null, 2) + "\n", "utf-8");
36900
+ }
36901
+ function cacheConfidentlyClean(cache, cliVersion, setupVersion) {
36902
+ return cache !== null && cache.cliVersion === cliVersion && cache.setupVersion === setupVersion && cache.usedAssetsChanged === false;
36903
+ }
36904
+ var init_asset_drift_cache = __esm({
36905
+ "src/lib/asset-drift-cache.ts"() {
36906
+ "use strict";
36907
+ }
36908
+ });
36909
+
36739
36910
  // src/lib/snapshot-budget.ts
36740
36911
  function estimateTokens(s) {
36741
36912
  return Math.ceil(s.length / 4);
@@ -36841,8 +37012,8 @@ var init_snapshot_budget = __esm({
36841
37012
  });
36842
37013
 
36843
37014
  // src/cli/commands/snapshot.ts
36844
- import { readFileSync as readFileSync34, existsSync as existsSync45, statSync as statSync5 } from "fs";
36845
- import { join as join45, basename as basename12, dirname as dirname22 } from "path";
37015
+ import { readFileSync as readFileSync35, existsSync as existsSync46, statSync as statSync5 } from "fs";
37016
+ import { join as join46, basename as basename12, dirname as dirname23 } from "path";
36846
37017
  function extractFirstParagraph(content) {
36847
37018
  const lines = content.split("\n");
36848
37019
  const paragraphLines = [];
@@ -36876,8 +37047,8 @@ function sortTaskEntriesByActivity(entries) {
36876
37047
  return [...entries].sort((a, b) => statusRank(a.status) - statusRank(b.status) || prioRank(a.priority) - prioRank(b.priority) || b.updated.localeCompare(a.updated));
36877
37048
  }
36878
37049
  function getActiveTaskEntries(root) {
36879
- const stateDir = join45(root, "state");
36880
- if (!existsSync45(stateDir)) return [];
37050
+ const stateDir = join46(root, "state");
37051
+ if (!existsSync46(stateDir)) return [];
36881
37052
  const taskFiles = import_fast_glob11.default.sync("*.md", { cwd: stateDir, absolute: true });
36882
37053
  const entries = [];
36883
37054
  for (const file of taskFiles) {
@@ -36909,15 +37080,15 @@ function getActiveTaskEntries(root) {
36909
37080
  return entries;
36910
37081
  }
36911
37082
  function resolveActiveTaskPath(root) {
36912
- const stateDir = join45(root, "state");
36913
- if (!existsSync45(stateDir)) return null;
36914
- const overridePath = join45(stateDir, ".active-task");
36915
- if (existsSync45(overridePath)) {
37083
+ const stateDir = join46(root, "state");
37084
+ if (!existsSync46(stateDir)) return null;
37085
+ const overridePath = join46(stateDir, ".active-task");
37086
+ if (existsSync46(overridePath)) {
36916
37087
  try {
36917
- const slug = readFileSync34(overridePath, "utf-8").trim();
37088
+ const slug = readFileSync35(overridePath, "utf-8").trim();
36918
37089
  if (slug) {
36919
- const taskPath = join45(stateDir, `${slug}.md`);
36920
- if (existsSync45(taskPath)) return taskPath;
37090
+ const taskPath = join46(stateDir, `${slug}.md`);
37091
+ if (existsSync46(taskPath)) return taskPath;
36921
37092
  }
36922
37093
  } catch {
36923
37094
  }
@@ -36943,7 +37114,7 @@ function resolveActiveTaskPath(root) {
36943
37114
  return candidates[0].path;
36944
37115
  }
36945
37116
  function getActiveProductKnowledge(root) {
36946
- const config = readSetupConfig(dirname22(root));
37117
+ const config = readSetupConfig(dirname23(root));
36947
37118
  if (!config || !Array.isArray(config.multiProduct) || config.multiProduct.length === 0) {
36948
37119
  return [];
36949
37120
  }
@@ -36960,11 +37131,11 @@ function getActiveProductKnowledge(root) {
36960
37131
  }
36961
37132
  if (!product) return [];
36962
37133
  if (!config.multiProduct.includes(product)) return [];
36963
- const productKnowledgePath = join45(root, "knowledge", "products", `${product}.md`);
36964
- if (!existsSync45(productKnowledgePath)) return [];
37134
+ const productKnowledgePath = join46(root, "knowledge", "products", `${product}.md`);
37135
+ if (!existsSync46(productKnowledgePath)) return [];
36965
37136
  let raw;
36966
37137
  try {
36967
- raw = readFileSync34(productKnowledgePath, "utf-8");
37138
+ raw = readFileSync35(productKnowledgePath, "utf-8");
36968
37139
  } catch {
36969
37140
  return [];
36970
37141
  }
@@ -36999,7 +37170,7 @@ function getActiveProductKnowledge(root) {
36999
37170
  }
37000
37171
  function getVersionNudge(root) {
37001
37172
  try {
37002
- const projectRoot = dirname22(root);
37173
+ const projectRoot = dirname23(root);
37003
37174
  const cache = readVersionCache(projectRoot);
37004
37175
  if (!cache || !isCacheFresh(cache)) return "";
37005
37176
  const installedCli = dreamcontextVersion();
@@ -37015,9 +37186,9 @@ function getVersionNudge(root) {
37015
37186
  }
37016
37187
  function getMigrationNote(root) {
37017
37188
  try {
37018
- const sleepPath = join45(root, "state", ".sleep.json");
37019
- if (!existsSync45(sleepPath)) return "";
37020
- const raw = readFileSync34(sleepPath, "utf-8");
37189
+ const sleepPath = join46(root, "state", ".sleep.json");
37190
+ if (!existsSync46(sleepPath)) return "";
37191
+ const raw = readFileSync35(sleepPath, "utf-8");
37021
37192
  const parsed = JSON.parse(raw);
37022
37193
  if (!parsed || !Array.isArray(parsed.pendingMigrationNotices) || parsed.pendingMigrationNotices.length === 0) {
37023
37194
  return "";
@@ -37035,14 +37206,21 @@ Migrations applied since last session: ${notices.join("; ")}`;
37035
37206
  }
37036
37207
  function getDriftDirective(root) {
37037
37208
  try {
37038
- const projectRoot = dirname22(root);
37209
+ const projectRoot = dirname23(root);
37039
37210
  const config = readSetupConfig(projectRoot);
37040
37211
  if (!config) return "";
37041
- return buildDriftDirective({
37042
- cliVersion: dreamcontextVersion(),
37212
+ const cliVersion = dreamcontextVersion();
37213
+ const driftInput = {
37214
+ cliVersion,
37043
37215
  setupVersion: config.setupVersion,
37044
37216
  driftCheckEnv: process.env.DREAMCONTEXT_DRIFT_CHECK
37045
- }) ?? "";
37217
+ };
37218
+ const state = resolveDriftState(driftInput);
37219
+ if (state === "stale" || state === "bootstrap") {
37220
+ const cache = readAssetDriftCache(root);
37221
+ if (cacheConfidentlyClean(cache, cliVersion, config.setupVersion)) return "";
37222
+ }
37223
+ return buildDriftDirective(driftInput) ?? "";
37046
37224
  } catch {
37047
37225
  return "";
37048
37226
  }
@@ -37058,24 +37236,24 @@ function generateSnapshot(rootOverride) {
37058
37236
  parts = [];
37059
37237
  }
37060
37238
  };
37061
- const soulPath = join45(root, "core", "0.soul.md");
37062
- if (existsSync45(soulPath)) {
37063
- const content = readFileSync34(soulPath, "utf-8").trim();
37239
+ const soulPath = join46(root, "core", "0.soul.md");
37240
+ if (existsSync46(soulPath)) {
37241
+ const content = readFileSync35(soulPath, "utf-8").trim();
37064
37242
  parts.push("## Soul (Agent Identity, Principles, Rules)\n");
37065
37243
  parts.push(content);
37066
37244
  parts.push("");
37067
37245
  }
37068
- const userPath = join45(root, "core", "1.user.md");
37069
- if (existsSync45(userPath)) {
37070
- const content = readFileSync34(userPath, "utf-8").trim();
37246
+ const userPath = join46(root, "core", "1.user.md");
37247
+ if (existsSync46(userPath)) {
37248
+ const content = readFileSync35(userPath, "utf-8").trim();
37071
37249
  parts.push("## User (Preferences, Project Details, Rules)\n");
37072
37250
  parts.push(content);
37073
37251
  parts.push("");
37074
37252
  }
37075
37253
  flush("identity", { neverEvict: true });
37076
- const memoryPath = join45(root, "core", "2.memory.md");
37077
- if (existsSync45(memoryPath)) {
37078
- const content = readFileSync34(memoryPath, "utf-8").trim();
37254
+ const memoryPath = join46(root, "core", "2.memory.md");
37255
+ if (existsSync46(memoryPath)) {
37256
+ const content = readFileSync35(memoryPath, "utf-8").trim();
37079
37257
  if (content) {
37080
37258
  parts.push("## Memory (Technical Decisions, Known Issues, Session Log)\n");
37081
37259
  parts.push(content);
@@ -37140,8 +37318,8 @@ function generateSnapshot(rootOverride) {
37140
37318
  if (sleepState.triggers.length > 0) {
37141
37319
  const taskNames = [];
37142
37320
  const taskTags = [];
37143
- const stateDir = join45(root, "state");
37144
- if (existsSync45(stateDir)) {
37321
+ const stateDir = join46(root, "state");
37322
+ if (existsSync46(stateDir)) {
37145
37323
  const taskFiles = import_fast_glob11.default.sync("*.md", { cwd: stateDir, absolute: true });
37146
37324
  for (const file of taskFiles) {
37147
37325
  try {
@@ -37177,14 +37355,14 @@ function generateSnapshot(rootOverride) {
37177
37355
  const CHANGELOG_TIER2 = 10;
37178
37356
  const TIER1_BODY_CHARS = 300;
37179
37357
  const TIER2_LINE_CHARS = 140;
37180
- const multiPerson = isMultiPerson(readSetupConfig(dirname22(root)));
37358
+ const multiPerson = isMultiPerson(readSetupConfig(dirname23(root)));
37181
37359
  const authorSuffix = (e) => {
37182
37360
  if (!multiPerson) return "";
37183
37361
  const authors = Array.isArray(e.authors) ? e.authors.filter((a) => typeof a === "string") : [];
37184
37362
  return authors.length > 0 ? ` \u2014 by ${authors.join(", ")}` : "";
37185
37363
  };
37186
- const changelogPath = join45(root, "core", "CHANGELOG.json");
37187
- if (existsSync45(changelogPath)) {
37364
+ const changelogPath = join46(root, "core", "CHANGELOG.json");
37365
+ if (existsSync46(changelogPath)) {
37188
37366
  try {
37189
37367
  const entries = readJsonArray(changelogPath);
37190
37368
  const tier1 = entries.slice(0, CHANGELOG_TIER1);
@@ -37240,8 +37418,8 @@ function generateSnapshot(rootOverride) {
37240
37418
  } catch {
37241
37419
  }
37242
37420
  }
37243
- const releasesPath = join45(root, "core", "RELEASES.json");
37244
- if (existsSync45(releasesPath)) {
37421
+ const releasesPath = join46(root, "core", "RELEASES.json");
37422
+ if (existsSync46(releasesPath)) {
37245
37423
  try {
37246
37424
  const releases = readJsonArray(releasesPath);
37247
37425
  if (releases.length > 0) {
@@ -37277,8 +37455,8 @@ function generateSnapshot(rootOverride) {
37277
37455
  }
37278
37456
  }
37279
37457
  flush("releases", { neverEvict: true });
37280
- const featuresDir = join45(root, "core", "features");
37281
- if (existsSync45(featuresDir)) {
37458
+ const featuresDir = join46(root, "core", "features");
37459
+ if (existsSync46(featuresDir)) {
37282
37460
  const featureFiles = import_fast_glob11.default.sync("*.md", { cwd: featuresDir, absolute: true });
37283
37461
  const features = [];
37284
37462
  const featureMeta = [];
@@ -37366,8 +37544,8 @@ function generateSnapshot(rootOverride) {
37366
37544
  const pinnedEntries = [];
37367
37545
  const warmEntries = [];
37368
37546
  const activeTaskTags = [];
37369
- const stDir = join45(root, "state");
37370
- if (existsSync45(stDir)) {
37547
+ const stDir = join46(root, "state");
37548
+ if (existsSync46(stDir)) {
37371
37549
  const tFiles = import_fast_glob11.default.sync("*.md", { cwd: stDir, absolute: true });
37372
37550
  for (const file of tFiles) {
37373
37551
  try {
@@ -37501,8 +37679,8 @@ function generateSubagentBriefing() {
37501
37679
  parts.push('`dreamcontext memory recall "<keywords>"` (BM25 over knowledge/features/tasks/');
37502
37680
  parts.push("memory/changelog, <100ms, zero token overhead) BEFORE Glob/Grep \u2014 it frequently");
37503
37681
  parts.push("beats blind exploration outright.\n");
37504
- const soulPath = join45(root, "core", "0.soul.md");
37505
- if (existsSync45(soulPath)) {
37682
+ const soulPath = join46(root, "core", "0.soul.md");
37683
+ if (existsSync46(soulPath)) {
37506
37684
  const { data, content } = readFrontmatter(soulPath);
37507
37685
  const projectName = typeof data.name === "string" ? data.name : "";
37508
37686
  const lines = content.split("\n");
@@ -37521,8 +37699,8 @@ function generateSubagentBriefing() {
37521
37699
  `);
37522
37700
  }
37523
37701
  }
37524
- const featuresDir = join45(root, "core", "features");
37525
- if (existsSync45(featuresDir)) {
37702
+ const featuresDir = join46(root, "core", "features");
37703
+ if (existsSync46(featuresDir)) {
37526
37704
  const featureFiles = import_fast_glob11.default.sync("*.md", { cwd: featuresDir, absolute: true });
37527
37705
  const features = [];
37528
37706
  for (const file of featureFiles) {
@@ -37589,8 +37767,8 @@ function generateSubagentBriefing() {
37589
37767
  }
37590
37768
  parts.push("");
37591
37769
  }
37592
- const coreDir = join45(root, "core");
37593
- if (existsSync45(coreDir)) {
37770
+ const coreDir = join46(root, "core");
37771
+ if (existsSync46(coreDir)) {
37594
37772
  const allCoreFiles = import_fast_glob11.default.sync(["[0-9]*"], { cwd: coreDir, absolute: true });
37595
37773
  allCoreFiles.sort((a, b) => basename12(a).localeCompare(basename12(b), void 0, { numeric: true }));
37596
37774
  if (allCoreFiles.length > 0) {
@@ -37678,14 +37856,62 @@ var init_snapshot2 = __esm({
37678
37856
  init_version_check();
37679
37857
  init_manifest();
37680
37858
  init_setup_drift();
37859
+ init_asset_drift_cache();
37681
37860
  init_feature_freshness();
37682
37861
  init_federation_inbox();
37683
37862
  init_snapshot_budget();
37684
37863
  }
37685
37864
  });
37686
37865
 
37866
+ // src/lib/salience.ts
37867
+ function clamp(text) {
37868
+ const oneLine = text.replace(/\s+/g, " ").trim();
37869
+ return oneLine.length <= MAX_MESSAGE_CHARS ? oneLine : oneLine.slice(0, MAX_MESSAGE_CHARS - 1) + "\u2026";
37870
+ }
37871
+ function detectSalience(distilled) {
37872
+ const moments = [];
37873
+ const seen = /* @__PURE__ */ new Set();
37874
+ const push = (message, salience) => {
37875
+ const clamped = clamp(message);
37876
+ if (!clamped) return;
37877
+ const key = `${salience}::${clamped.toLowerCase()}`;
37878
+ if (seen.has(key)) return;
37879
+ seen.add(key);
37880
+ moments.push({ message: clamped, salience });
37881
+ };
37882
+ for (const msg of distilled.userMessages) {
37883
+ if (CORRECTION_RE.test(msg)) {
37884
+ push(`User correction: ${msg}`, 2);
37885
+ }
37886
+ }
37887
+ if (distilled.errors.length > 0 && distilled.codeChanges.length > 0) {
37888
+ const firstError = distilled.errors[0];
37889
+ push(`Error resolved by code change: ${firstError}`, 1);
37890
+ }
37891
+ const decisionSources = [
37892
+ ...distilled.agentDecisions.filter((d) => !d.startsWith("[thinking]")),
37893
+ ...distilled.userMessages
37894
+ ];
37895
+ for (const src of decisionSources) {
37896
+ if (DECISION_RE.test(src)) {
37897
+ push(`Decision: ${src}`, 2);
37898
+ }
37899
+ }
37900
+ return moments.slice(0, MAX_MOMENTS);
37901
+ }
37902
+ var CORRECTION_RE, DECISION_RE, MAX_MOMENTS, MAX_MESSAGE_CHARS;
37903
+ var init_salience = __esm({
37904
+ "src/lib/salience.ts"() {
37905
+ "use strict";
37906
+ CORRECTION_RE = /\b(no|actually|wrong|instead|hayır|yanlış|değil)\b/i;
37907
+ DECISION_RE = /\b(decided|chose|switched to|will use|karar|seçtik)\b/i;
37908
+ MAX_MOMENTS = 5;
37909
+ MAX_MESSAGE_CHARS = 200;
37910
+ }
37911
+ });
37912
+
37687
37913
  // src/cli/commands/transcript.ts
37688
- import { readFileSync as readFileSync35, existsSync as existsSync46, statSync as statSync6 } from "fs";
37914
+ import { readFileSync as readFileSync36, existsSync as existsSync47, statSync as statSync6 } from "fs";
37689
37915
  function distillTranscript(transcriptPath, sinceTimestamp) {
37690
37916
  const result = {
37691
37917
  userMessages: [],
@@ -37694,11 +37920,11 @@ function distillTranscript(transcriptPath, sinceTimestamp) {
37694
37920
  errors: [],
37695
37921
  bookmarks: []
37696
37922
  };
37697
- if (!existsSync46(transcriptPath)) return result;
37923
+ if (!existsSync47(transcriptPath)) return result;
37698
37924
  try {
37699
37925
  const stat = statSync6(transcriptPath);
37700
37926
  if (stat.size === 0 || stat.size > MAX_TRANSCRIPT_BYTES) return result;
37701
- const content = readFileSync35(transcriptPath, "utf-8");
37927
+ const content = readFileSync36(transcriptPath, "utf-8");
37702
37928
  const lines = content.split("\n").filter((l) => l.trim());
37703
37929
  for (const line of lines) {
37704
37930
  let entry;
@@ -37882,7 +38108,7 @@ function registerTranscriptCommand(program2) {
37882
38108
  error(`No transcript path for session: ${sessionId}`);
37883
38109
  return;
37884
38110
  }
37885
- if (!existsSync46(session.transcript_path)) {
38111
+ if (!existsSync47(session.transcript_path)) {
37886
38112
  error(`Transcript file not found: ${session.transcript_path}`);
37887
38113
  return;
37888
38114
  }
@@ -38059,8 +38285,8 @@ var init_recall_synonyms = __esm({
38059
38285
  });
38060
38286
 
38061
38287
  // src/lib/recall.ts
38062
- import { existsSync as existsSync47, readFileSync as readFileSync36 } from "fs";
38063
- import { join as join46, basename as basename13, dirname as dirname23, relative as relative3 } from "path";
38288
+ import { existsSync as existsSync48, readFileSync as readFileSync37 } from "fs";
38289
+ import { join as join47, basename as basename13, dirname as dirname24, relative as relative3 } from "path";
38064
38290
  function isFederated(doc) {
38065
38291
  return doc.federated === true;
38066
38292
  }
@@ -38149,7 +38375,7 @@ function productFromRelPath(relPath) {
38149
38375
  return m ? m[1] : void 0;
38150
38376
  }
38151
38377
  function loadMarkdownDocs(dir, type, contextRoot) {
38152
- if (!existsSync47(dir)) return [];
38378
+ if (!existsSync48(dir)) return [];
38153
38379
  const files = import_fast_glob12.default.sync("**/*.md", { cwd: dir, absolute: true });
38154
38380
  const boardDirs = diagramFolderDirs(files);
38155
38381
  const out = [];
@@ -38192,11 +38418,11 @@ function loadMarkdownDocs(dir, type, contextRoot) {
38192
38418
  return out;
38193
38419
  }
38194
38420
  function loadChangelogEntries(contextRoot) {
38195
- const path2 = join46(contextRoot, "core", "CHANGELOG.json");
38196
- if (!existsSync47(path2)) return [];
38421
+ const path2 = join47(contextRoot, "core", "CHANGELOG.json");
38422
+ if (!existsSync48(path2)) return [];
38197
38423
  let entries = [];
38198
38424
  try {
38199
- const raw = readFileSync36(path2, "utf-8");
38425
+ const raw = readFileSync37(path2, "utf-8");
38200
38426
  const parsed = JSON.parse(raw);
38201
38427
  if (Array.isArray(parsed)) entries = parsed;
38202
38428
  } catch {
@@ -38244,9 +38470,9 @@ function loadChangelogEntries(contextRoot) {
38244
38470
  return out;
38245
38471
  }
38246
38472
  function loadMemoryFile(contextRoot) {
38247
- const path2 = join46(contextRoot, "core", "2.memory.md");
38248
- if (!existsSync47(path2)) return [];
38249
- const raw = readFileSync36(path2, "utf-8");
38473
+ const path2 = join47(contextRoot, "core", "2.memory.md");
38474
+ if (!existsSync48(path2)) return [];
38475
+ const raw = readFileSync37(path2, "utf-8");
38250
38476
  const sections = raw.split(/^##\s+/m).slice(1);
38251
38477
  const out = [];
38252
38478
  for (let i = 0; i < sections.length; i++) {
@@ -38278,11 +38504,11 @@ function loadMemoryFile(contextRoot) {
38278
38504
  return out;
38279
38505
  }
38280
38506
  function loadBookmarkDocs(contextRoot) {
38281
- const path2 = join46(contextRoot, "state", ".sleep.json");
38282
- if (!existsSync47(path2)) return [];
38507
+ const path2 = join47(contextRoot, "state", ".sleep.json");
38508
+ if (!existsSync48(path2)) return [];
38283
38509
  let bookmarks = [];
38284
38510
  try {
38285
- const parsed = JSON.parse(readFileSync36(path2, "utf-8"));
38511
+ const parsed = JSON.parse(readFileSync37(path2, "utf-8"));
38286
38512
  if (parsed && typeof parsed === "object" && Array.isArray(parsed.bookmarks)) {
38287
38513
  bookmarks = parsed.bookmarks;
38288
38514
  }
@@ -38324,14 +38550,14 @@ function loadBookmarkDocs(contextRoot) {
38324
38550
  return out;
38325
38551
  }
38326
38552
  function loadSkillDocs(skillsRoot) {
38327
- if (!existsSync47(skillsRoot)) return [];
38553
+ if (!existsSync48(skillsRoot)) return [];
38328
38554
  const files = import_fast_glob12.default.sync("*/SKILL.md", { cwd: skillsRoot, absolute: true });
38329
38555
  const out = [];
38330
38556
  for (const file of files) {
38331
38557
  try {
38332
38558
  const { data, content } = readFrontmatter(file);
38333
38559
  if (data.alwaysApply === true) continue;
38334
- const slug = typeof data.name === "string" && data.name ? data.name : basename13(dirname23(file));
38560
+ const slug = typeof data.name === "string" && data.name ? data.name : basename13(dirname24(file));
38335
38561
  const title = slug;
38336
38562
  const description = typeof data.description === "string" ? data.description : "";
38337
38563
  const tags = Array.isArray(data.tags) ? data.tags.map(String) : [];
@@ -38363,13 +38589,13 @@ function buildCorpus(contextRoot, opts = {}) {
38363
38589
  const types = new Set(opts.types ?? ["knowledge", "feature", "task", "memory", "changelog"]);
38364
38590
  const docs = [];
38365
38591
  if (types.has("knowledge")) {
38366
- docs.push(...loadMarkdownDocs(join46(contextRoot, "knowledge"), "knowledge", contextRoot));
38592
+ docs.push(...loadMarkdownDocs(join47(contextRoot, "knowledge"), "knowledge", contextRoot));
38367
38593
  }
38368
38594
  if (types.has("feature")) {
38369
- docs.push(...loadMarkdownDocs(join46(contextRoot, "core", "features"), "feature", contextRoot));
38595
+ docs.push(...loadMarkdownDocs(join47(contextRoot, "core", "features"), "feature", contextRoot));
38370
38596
  }
38371
38597
  if (types.has("task")) {
38372
- docs.push(...loadMarkdownDocs(join46(contextRoot, "state"), "task", contextRoot));
38598
+ docs.push(...loadMarkdownDocs(join47(contextRoot, "state"), "task", contextRoot));
38373
38599
  docs.push(...loadDigestDocs(contextRoot));
38374
38600
  }
38375
38601
  if (types.has("memory")) {
@@ -38719,8 +38945,8 @@ var init_recall = __esm({
38719
38945
  });
38720
38946
 
38721
38947
  // src/lib/session-digest.ts
38722
- import { existsSync as existsSync48, mkdirSync as mkdirSync22, writeFileSync as writeFileSync29 } from "fs";
38723
- import { join as join47 } from "path";
38948
+ import { existsSync as existsSync49, mkdirSync as mkdirSync23, writeFileSync as writeFileSync30 } from "fs";
38949
+ import { join as join48 } from "path";
38724
38950
  function coerceCreatedAt(value) {
38725
38951
  if (typeof value === "string" && value.trim()) return value.trim();
38726
38952
  if (value instanceof Date && !Number.isNaN(value.getTime())) return value.toISOString();
@@ -38778,18 +39004,18 @@ function enforceByteCap(lines, maxBytes) {
38778
39004
  return out.trimEnd() + "\n";
38779
39005
  }
38780
39006
  function digestsDir(root) {
38781
- return join47(root, "state", DIGESTS_DIRNAME);
39007
+ return join48(root, "state", DIGESTS_DIRNAME);
38782
39008
  }
38783
39009
  function digestPath(root, sessionId) {
38784
39010
  const safe = sessionId.replace(/[^a-zA-Z0-9_-]/g, "_");
38785
- return join47(digestsDir(root), `${safe}.md`);
39011
+ return join48(digestsDir(root), `${safe}.md`);
38786
39012
  }
38787
39013
  function digestExists(root, sessionId) {
38788
- return existsSync48(digestPath(root, sessionId));
39014
+ return existsSync49(digestPath(root, sessionId));
38789
39015
  }
38790
39016
  function digestIsPartial(root, sessionId) {
38791
39017
  const file = digestPath(root, sessionId);
38792
- if (!existsSync48(file)) return false;
39018
+ if (!existsSync49(file)) return false;
38793
39019
  try {
38794
39020
  const { data } = readFrontmatter(file);
38795
39021
  return data.partial === true;
@@ -38799,7 +39025,7 @@ function digestIsPartial(root, sessionId) {
38799
39025
  }
38800
39026
  function writeDigest(root, sessionId, md, opts = {}) {
38801
39027
  const dir = digestsDir(root);
38802
- mkdirSync22(dir, { recursive: true });
39028
+ mkdirSync23(dir, { recursive: true });
38803
39029
  const file = digestPath(root, sessionId);
38804
39030
  const safeId = sessionId.replace(/[^a-zA-Z0-9_-]/g, "_");
38805
39031
  const frontmatter = [
@@ -38811,12 +39037,12 @@ function writeDigest(root, sessionId, md, opts = {}) {
38811
39037
  "---",
38812
39038
  ""
38813
39039
  ].join("\n");
38814
- writeFileSync29(file, frontmatter + md, "utf-8");
39040
+ writeFileSync30(file, frontmatter + md, "utf-8");
38815
39041
  return file;
38816
39042
  }
38817
39043
  function loadDigestDocs(root) {
38818
39044
  const dir = digestsDir(root);
38819
- if (!existsSync48(dir)) return [];
39045
+ if (!existsSync49(dir)) return [];
38820
39046
  const files = import_fast_glob13.default.sync("*.md", { cwd: dir, absolute: true });
38821
39047
  const parsed = [];
38822
39048
  for (const file of files) {
@@ -38827,7 +39053,7 @@ function loadDigestDocs(root) {
38827
39053
  const title = `Session digest ${sessionId}`;
38828
39054
  const body = content.trim();
38829
39055
  if (!body) continue;
38830
- const relPath = join47("state", DIGESTS_DIRNAME, `${sessionId}.md`);
39056
+ const relPath = join48("state", DIGESTS_DIRNAME, `${sessionId}.md`);
38831
39057
  const createdAt = coerceCreatedAt(data.created_at);
38832
39058
  const fields = buildFields({ slug, title, description: "", tags: [], body });
38833
39059
  const ms = createdAt ? Date.parse(createdAt) : NaN;
@@ -38878,56 +39104,9 @@ var init_session_digest = __esm({
38878
39104
  }
38879
39105
  });
38880
39106
 
38881
- // src/lib/salience.ts
38882
- function clamp(text) {
38883
- const oneLine = text.replace(/\s+/g, " ").trim();
38884
- return oneLine.length <= MAX_MESSAGE_CHARS ? oneLine : oneLine.slice(0, MAX_MESSAGE_CHARS - 1) + "\u2026";
38885
- }
38886
- function detectSalience(distilled) {
38887
- const moments = [];
38888
- const seen = /* @__PURE__ */ new Set();
38889
- const push = (message, salience) => {
38890
- const clamped = clamp(message);
38891
- if (!clamped) return;
38892
- const key = `${salience}::${clamped.toLowerCase()}`;
38893
- if (seen.has(key)) return;
38894
- seen.add(key);
38895
- moments.push({ message: clamped, salience });
38896
- };
38897
- for (const msg of distilled.userMessages) {
38898
- if (CORRECTION_RE.test(msg)) {
38899
- push(`User correction: ${msg}`, 2);
38900
- }
38901
- }
38902
- if (distilled.errors.length > 0 && distilled.codeChanges.length > 0) {
38903
- const firstError = distilled.errors[0];
38904
- push(`Error resolved by code change: ${firstError}`, 1);
38905
- }
38906
- const decisionSources = [
38907
- ...distilled.agentDecisions.filter((d) => !d.startsWith("[thinking]")),
38908
- ...distilled.userMessages
38909
- ];
38910
- for (const src of decisionSources) {
38911
- if (DECISION_RE.test(src)) {
38912
- push(`Decision: ${src}`, 2);
38913
- }
38914
- }
38915
- return moments.slice(0, MAX_MOMENTS);
38916
- }
38917
- var CORRECTION_RE, DECISION_RE, MAX_MOMENTS, MAX_MESSAGE_CHARS;
38918
- var init_salience = __esm({
38919
- "src/lib/salience.ts"() {
38920
- "use strict";
38921
- CORRECTION_RE = /\b(no|actually|wrong|instead|hayır|yanlış|değil)\b/i;
38922
- DECISION_RE = /\b(decided|chose|switched to|will use|karar|seçtik)\b/i;
38923
- MAX_MOMENTS = 5;
38924
- MAX_MESSAGE_CHARS = 200;
38925
- }
38926
- });
38927
-
38928
39107
  // src/lib/marketing/path-guards.ts
38929
- import { existsSync as existsSync49, realpathSync } from "fs";
38930
- import { basename as basename14, dirname as dirname24, resolve as resolve8, sep as sep5 } from "path";
39108
+ import { existsSync as existsSync50, realpathSync } from "fs";
39109
+ import { basename as basename14, dirname as dirname25, resolve as resolve8, sep as sep5 } from "path";
38931
39110
  function isMarketingEnvPath(filePath, from) {
38932
39111
  if (!filePath) return false;
38933
39112
  const root = resolveContextRoot(from);
@@ -38941,7 +39120,7 @@ function isMarketingEnvPath(filePath, from) {
38941
39120
  }
38942
39121
  function realpathOrSelf(p) {
38943
39122
  try {
38944
- return existsSync49(p) ? realpathSync(p) : p;
39123
+ return existsSync50(p) ? realpathSync(p) : p;
38945
39124
  } catch {
38946
39125
  return p;
38947
39126
  }
@@ -38949,9 +39128,9 @@ function realpathOrSelf(p) {
38949
39128
  function realpathOfNearestAncestor(p) {
38950
39129
  let current = p;
38951
39130
  const tail = [];
38952
- while (current && current !== sep5 && !existsSync49(current)) {
39131
+ while (current && current !== sep5 && !existsSync50(current)) {
38953
39132
  tail.unshift(basename14(current));
38954
- current = dirname24(current);
39133
+ current = dirname25(current);
38955
39134
  }
38956
39135
  if (!current || current === sep5) return p;
38957
39136
  try {
@@ -39093,17 +39272,17 @@ If pure greeting: {"skip":true}`;
39093
39272
  // src/cli/commands/app.ts
39094
39273
  import { execFileSync as execFileSync3, spawn as spawnProcess } from "child_process";
39095
39274
  import {
39096
- existsSync as existsSync50,
39097
- mkdirSync as mkdirSync23,
39275
+ existsSync as existsSync51,
39276
+ mkdirSync as mkdirSync24,
39098
39277
  mkdtempSync,
39099
- readFileSync as readFileSync38,
39100
- writeFileSync as writeFileSync30,
39278
+ readFileSync as readFileSync39,
39279
+ writeFileSync as writeFileSync31,
39101
39280
  rmSync as rmSync6,
39102
39281
  renameSync as renameSync7,
39103
39282
  readdirSync as readdirSync12
39104
39283
  } from "fs";
39105
39284
  import { homedir as homedir2, tmpdir } from "os";
39106
- import { join as join48, resolve as resolve9, dirname as dirname25 } from "path";
39285
+ import { join as join49, resolve as resolve9, dirname as dirname26 } from "path";
39107
39286
  import { createHash as createHash2 } from "crypto";
39108
39287
  function detectPlatform(platform2 = process.platform, arch2 = process.arch) {
39109
39288
  const os3 = platform2 === "darwin" ? "darwin" : platform2 === "win32" ? "win32" : platform2 === "linux" ? "linux" : "other";
@@ -39116,16 +39295,16 @@ function pickAssetForArch(assetNames, arch2) {
39116
39295
  return exact ?? null;
39117
39296
  }
39118
39297
  function defaultInstallDir(home = homedir2()) {
39119
- return join48(home, "Applications");
39298
+ return join49(home, "Applications");
39120
39299
  }
39121
39300
  function appManifestPath(home = homedir2()) {
39122
- return join48(home, ".dreamcontext", "app.json");
39301
+ return join49(home, ".dreamcontext", "app.json");
39123
39302
  }
39124
39303
  function readAppManifest(home = homedir2()) {
39125
39304
  const p = appManifestPath(home);
39126
- if (!existsSync50(p)) return null;
39305
+ if (!existsSync51(p)) return null;
39127
39306
  try {
39128
- const parsed = JSON.parse(readFileSync38(p, "utf-8"));
39307
+ const parsed = JSON.parse(readFileSync39(p, "utf-8"));
39129
39308
  if (!parsed || typeof parsed.version !== "string" || typeof parsed.path !== "string") return null;
39130
39309
  return {
39131
39310
  version: parsed.version,
@@ -39139,8 +39318,8 @@ function readAppManifest(home = homedir2()) {
39139
39318
  }
39140
39319
  function writeAppManifest(manifest, home = homedir2()) {
39141
39320
  const p = appManifestPath(home);
39142
- mkdirSync23(dirname25(p), { recursive: true });
39143
- writeFileSync30(p, JSON.stringify(manifest, null, 2) + "\n", "utf-8");
39321
+ mkdirSync24(dirname26(p), { recursive: true });
39322
+ writeFileSync31(p, JSON.stringify(manifest, null, 2) + "\n", "utf-8");
39144
39323
  }
39145
39324
  function run(cmd, args) {
39146
39325
  execFileSync3(cmd, args, { stdio: ["ignore", "ignore", "pipe"] });
@@ -39149,17 +39328,17 @@ function runCapture(cmd, args) {
39149
39328
  return execFileSync3(cmd, args, { encoding: "utf-8" }).toString().trim();
39150
39329
  }
39151
39330
  function validateAppBundle(appDir) {
39152
- if (!appDir.endsWith(".app") || !existsSync50(appDir)) {
39331
+ if (!appDir.endsWith(".app") || !existsSync51(appDir)) {
39153
39332
  throw new Error(`Not a .app bundle: ${appDir}`);
39154
39333
  }
39155
- const macos = join48(appDir, "Contents", "MacOS");
39156
- const plist = join48(appDir, "Contents", "Info.plist");
39157
- if (!existsSync50(macos) || !existsSync50(plist)) {
39334
+ const macos = join49(appDir, "Contents", "MacOS");
39335
+ const plist = join49(appDir, "Contents", "Info.plist");
39336
+ if (!existsSync51(macos) || !existsSync51(plist)) {
39158
39337
  throw new Error(`Malformed .app (missing Contents/MacOS or Info.plist): ${appDir}`);
39159
39338
  }
39160
39339
  }
39161
39340
  function readBundleVersion(appDir) {
39162
- const plist = join48(appDir, "Contents", "Info.plist");
39341
+ const plist = join49(appDir, "Contents", "Info.plist");
39163
39342
  try {
39164
39343
  return runCapture("plutil", ["-extract", "CFBundleShortVersionString", "raw", "-o", "-", plist]) || null;
39165
39344
  } catch {
@@ -39168,11 +39347,11 @@ function readBundleVersion(appDir) {
39168
39347
  }
39169
39348
  function findAppInDir(dir) {
39170
39349
  const entries = readdirSync12(dir).filter((e) => e.endsWith(".app"));
39171
- return entries.length > 0 ? join48(dir, entries[0]) : null;
39350
+ return entries.length > 0 ? join49(dir, entries[0]) : null;
39172
39351
  }
39173
39352
  function materializeAppBundle(source, workDir) {
39174
39353
  const src = resolve9(source);
39175
- if (!existsSync50(src)) throw new Error(`Source not found: ${src}`);
39354
+ if (!existsSync51(src)) throw new Error(`Source not found: ${src}`);
39176
39355
  if (src.endsWith(".app")) {
39177
39356
  return src;
39178
39357
  }
@@ -39209,14 +39388,14 @@ function installAppBundle(source, opts = {}) {
39209
39388
  }
39210
39389
  const home = opts.home ?? homedir2();
39211
39390
  const installDir = opts.installDir ?? defaultInstallDir(home);
39212
- mkdirSync23(installDir, { recursive: true });
39213
- const workDir = mkdtempSync(join48(tmpdir(), "dc-app-"));
39391
+ mkdirSync24(installDir, { recursive: true });
39392
+ const workDir = mkdtempSync(join49(tmpdir(), "dc-app-"));
39214
39393
  try {
39215
39394
  const appDir = materializeAppBundle(source, workDir);
39216
39395
  validateAppBundle(appDir);
39217
- const target = join48(installDir, APP_BUNDLE_NAME);
39218
- const staging = join48(installDir, `.${APP_BUNDLE_NAME}.new-${process.pid}`);
39219
- const backup = join48(installDir, `.${APP_BUNDLE_NAME}.old-${process.pid}`);
39396
+ const target = join49(installDir, APP_BUNDLE_NAME);
39397
+ const staging = join49(installDir, `.${APP_BUNDLE_NAME}.new-${process.pid}`);
39398
+ const backup = join49(installDir, `.${APP_BUNDLE_NAME}.old-${process.pid}`);
39220
39399
  rmSync6(staging, { recursive: true, force: true });
39221
39400
  rmSync6(backup, { recursive: true, force: true });
39222
39401
  let wasRunning;
@@ -39228,11 +39407,11 @@ function installAppBundle(source, opts = {}) {
39228
39407
  } catch {
39229
39408
  }
39230
39409
  wasRunning = isAppRunning();
39231
- replaced = existsSync50(target);
39410
+ replaced = existsSync51(target);
39232
39411
  if (replaced) renameSync7(target, backup);
39233
39412
  renameSync7(staging, target);
39234
39413
  } catch (e) {
39235
- if (existsSync50(target) === false && existsSync50(backup)) {
39414
+ if (existsSync51(target) === false && existsSync51(backup)) {
39236
39415
  try {
39237
39416
  renameSync7(backup, target);
39238
39417
  } catch {
@@ -39278,10 +39457,10 @@ async function downloadTo(url, destFile, fetchImpl = fetch) {
39278
39457
  const res = await fetchImpl(url, { headers: { "User-Agent": "dreamcontext-cli" } });
39279
39458
  if (!res.ok) throw new Error(`Download failed (${res.status}): ${url}`);
39280
39459
  const buf = Buffer.from(await res.arrayBuffer());
39281
- writeFileSync30(destFile, buf);
39460
+ writeFileSync31(destFile, buf);
39282
39461
  }
39283
39462
  function sha256File(file) {
39284
- return createHash2("sha256").update(readFileSync38(file)).digest("hex");
39463
+ return createHash2("sha256").update(readFileSync39(file)).digest("hex");
39285
39464
  }
39286
39465
  async function downloadLatestArtifact(repo = APP_RELEASE_REPO, fetchImpl = fetch) {
39287
39466
  const plat = detectPlatform();
@@ -39297,13 +39476,13 @@ async function downloadLatestArtifact(repo = APP_RELEASE_REPO, fetchImpl = fetch
39297
39476
  `Release ${release2.tag_name} is missing ${assetName}.sha256 \u2014 refusing to install an unverified binary.`
39298
39477
  );
39299
39478
  }
39300
- const workDir = mkdtempSync(join48(tmpdir(), "dc-app-dl-"));
39479
+ const workDir = mkdtempSync(join49(tmpdir(), "dc-app-dl-"));
39301
39480
  try {
39302
- const archivePath = join48(workDir, assetName);
39481
+ const archivePath = join49(workDir, assetName);
39303
39482
  await downloadTo(asset.browser_download_url, archivePath, fetchImpl);
39304
- const sumFile = join48(workDir, `${assetName}.sha256`);
39483
+ const sumFile = join49(workDir, `${assetName}.sha256`);
39305
39484
  await downloadTo(sumAsset.browser_download_url, sumFile, fetchImpl);
39306
- const expected = readFileSync38(sumFile, "utf-8").trim().split(/\s+/)[0].toLowerCase();
39485
+ const expected = readFileSync39(sumFile, "utf-8").trim().split(/\s+/)[0].toLowerCase();
39307
39486
  const actual = sha256File(archivePath).toLowerCase();
39308
39487
  if (!expected || expected !== actual) {
39309
39488
  throw new Error(`Checksum mismatch for ${assetName}: expected ${expected || "(empty)"}, got ${actual}`);
@@ -39365,7 +39544,7 @@ async function doInstall(from, dir) {
39365
39544
  }
39366
39545
  source = dl.archivePath;
39367
39546
  sourceLabel = "github";
39368
- tempToClean = dirname25(dl.archivePath);
39547
+ tempToClean = dirname26(dl.archivePath);
39369
39548
  }
39370
39549
  try {
39371
39550
  const res = installAppBundle(source, { installDir: dir, sourceLabel });
@@ -39417,7 +39596,7 @@ async function doUpdate(from, dir) {
39417
39596
  console.log(source_default.green(`\u2713 Updated dreamcontext-beta ${installed.version} \u2192 ${res.version ?? dl.version}`));
39418
39597
  if (res.wasRunning) console.log(source_default.yellow("Restart the app to apply the update."));
39419
39598
  } finally {
39420
- rmSync6(dirname25(dl.archivePath), { recursive: true, force: true });
39599
+ rmSync6(dirname26(dl.archivePath), { recursive: true, force: true });
39421
39600
  }
39422
39601
  }
39423
39602
  function doStatus() {
@@ -39426,7 +39605,7 @@ function doStatus() {
39426
39605
  console.log("Desktop app: not installed (run `dreamcontext app install`).");
39427
39606
  return;
39428
39607
  }
39429
- const onDisk = existsSync50(installed.path);
39608
+ const onDisk = existsSync51(installed.path);
39430
39609
  console.log(`Desktop app: ${installed.version}`);
39431
39610
  console.log(` path: ${installed.path}${onDisk ? "" : source_default.red(" (missing!)")}`);
39432
39611
  console.log(` source: ${installed.source}`);
@@ -39455,15 +39634,82 @@ var init_app = __esm({
39455
39634
  }
39456
39635
  });
39457
39636
 
39637
+ // src/cli/commands/asset-drift.ts
39638
+ import { mkdtempSync as mkdtempSync2, rmSync as rmSync7, existsSync as existsSync52, readFileSync as readFileSync40, readdirSync as readdirSync13 } from "fs";
39639
+ import { tmpdir as tmpdir2 } from "os";
39640
+ import { join as join50, dirname as dirname27 } from "path";
39641
+ function walkFiles(dir, base, out) {
39642
+ for (const entry of readdirSync13(dir, { withFileTypes: true })) {
39643
+ const abs = join50(dir, entry.name);
39644
+ if (entry.isDirectory()) walkFiles(abs, base, out);
39645
+ else if (entry.isFile()) out.push(abs.slice(base.length + 1));
39646
+ }
39647
+ }
39648
+ async function computeUsedAssetsChanged(projectRoot, config) {
39649
+ const tmp = mkdtempSync2(join50(tmpdir2(), "dc-assetdrift-"));
39650
+ try {
39651
+ for (const platform2 of config.platforms) {
39652
+ await installCoreForPlatform(platform2, tmp);
39653
+ }
39654
+ if (config.packs.length > 0) {
39655
+ directPackInstall(config.packs, tmp, config.platforms, emptyManifest());
39656
+ }
39657
+ const produced = [];
39658
+ walkFiles(tmp, tmp, produced);
39659
+ for (const rel of produced) {
39660
+ if (rel.endsWith("settings.json")) continue;
39661
+ if (rel.startsWith("_dream_context/")) continue;
39662
+ const onDisk = join50(projectRoot, rel);
39663
+ if (!existsSync52(onDisk)) return true;
39664
+ if (!readFileSync40(join50(tmp, rel)).equals(readFileSync40(onDisk))) return true;
39665
+ }
39666
+ return false;
39667
+ } finally {
39668
+ try {
39669
+ rmSync7(tmp, { recursive: true, force: true });
39670
+ } catch {
39671
+ }
39672
+ }
39673
+ }
39674
+ async function runAssetDriftRefresh(contextRoot) {
39675
+ const projectRoot = dirname27(contextRoot);
39676
+ const config = readSetupConfig(projectRoot);
39677
+ if (!config) return;
39678
+ const cliVersion = dreamcontextVersion();
39679
+ const state = resolveDriftState({
39680
+ cliVersion,
39681
+ setupVersion: config.setupVersion,
39682
+ driftCheckEnv: process.env.DREAMCONTEXT_DRIFT_CHECK
39683
+ });
39684
+ if (state !== "stale" && state !== "bootstrap") return;
39685
+ const usedAssetsChanged = await computeUsedAssetsChanged(projectRoot, config);
39686
+ writeAssetDriftCache(contextRoot, {
39687
+ cliVersion,
39688
+ setupVersion: config.setupVersion,
39689
+ usedAssetsChanged,
39690
+ checkedAt: Date.now()
39691
+ });
39692
+ }
39693
+ var init_asset_drift = __esm({
39694
+ "src/cli/commands/asset-drift.ts"() {
39695
+ "use strict";
39696
+ init_setup_config();
39697
+ init_manifest();
39698
+ init_setup_drift();
39699
+ init_asset_drift_cache();
39700
+ init_install_skill();
39701
+ }
39702
+ });
39703
+
39458
39704
  // src/cli/commands/hook.ts
39459
- import { readFileSync as readFileSync39, existsSync as existsSync51, statSync as statSync7 } from "fs";
39705
+ import { readFileSync as readFileSync41, existsSync as existsSync53, statSync as statSync7 } from "fs";
39460
39706
  import { execFileSync as execFileSync4, spawn as spawn3 } from "child_process";
39461
39707
  import { get as httpGet } from "http";
39462
- import { dirname as dirname26, resolve as resolve10, join as join49, extname as extname2, basename as basename15, relative as relative4 } from "path";
39708
+ import { dirname as dirname28, resolve as resolve10, join as join51, extname as extname2, basename as basename15, relative as relative4 } from "path";
39463
39709
  function readStdin() {
39464
39710
  if (process.stdin.isTTY) return null;
39465
39711
  try {
39466
- const raw = readFileSync39(0, "utf-8");
39712
+ const raw = readFileSync41(0, "utf-8");
39467
39713
  if (!raw.trim()) return null;
39468
39714
  const parsed = JSON.parse(raw);
39469
39715
  if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) return null;
@@ -39473,11 +39719,11 @@ function readStdin() {
39473
39719
  }
39474
39720
  }
39475
39721
  function analyzeTranscript(transcriptPath) {
39476
- if (!existsSync51(transcriptPath)) return ZERO_ANALYSIS;
39722
+ if (!existsSync53(transcriptPath)) return ZERO_ANALYSIS;
39477
39723
  try {
39478
39724
  const stat = statSync7(transcriptPath);
39479
39725
  if (stat.size === 0 || stat.size > MAX_TRANSCRIPT_BYTES2) return ZERO_ANALYSIS;
39480
- const content = readFileSync39(transcriptPath, "utf-8");
39726
+ const content = readFileSync41(transcriptPath, "utf-8");
39481
39727
  const changeMatches = content.match(/"name"\s*:\s*"(?:Write|Edit)"/g);
39482
39728
  const toolMatches = content.match(/"name"\s*:\s*"[A-Za-z_]+"/g);
39483
39729
  const slugs = /* @__PURE__ */ new Set();
@@ -39487,15 +39733,76 @@ function analyzeTranscript(transcriptPath) {
39487
39733
  for (const m of content.matchAll(/"file_path"\s*:\s*"[^"]*_dream_context\/state\/([a-z0-9][a-z0-9-]*)\.md"/g)) {
39488
39734
  slugs.add(m[1]);
39489
39735
  }
39736
+ let userTurns = 0;
39737
+ let assistantChars = 0;
39738
+ let decisionMarkers = 0;
39739
+ for (const line of content.split("\n")) {
39740
+ const trimmed = line.trim();
39741
+ if (!trimmed) continue;
39742
+ if (DECISION_RE.test(trimmed) || CORRECTION_RE.test(trimmed)) {
39743
+ decisionMarkers++;
39744
+ }
39745
+ let rec;
39746
+ try {
39747
+ rec = JSON.parse(trimmed);
39748
+ } catch {
39749
+ continue;
39750
+ }
39751
+ if (!rec || typeof rec !== "object") continue;
39752
+ const role = recordRole(rec);
39753
+ if (role === "user") {
39754
+ userTurns++;
39755
+ } else if (role === "assistant") {
39756
+ assistantChars += sumAssistantTextChars(rec);
39757
+ }
39758
+ }
39490
39759
  return {
39491
39760
  changeCount: changeMatches ? changeMatches.length : 0,
39492
39761
  toolCount: toolMatches ? toolMatches.length : 0,
39493
- taskSlugs: [...slugs]
39762
+ taskSlugs: [...slugs],
39763
+ userTurns,
39764
+ assistantChars,
39765
+ decisionMarkers
39494
39766
  };
39495
39767
  } catch {
39496
39768
  return ZERO_ANALYSIS;
39497
39769
  }
39498
39770
  }
39771
+ function recordRole(rec) {
39772
+ const r = rec;
39773
+ if (typeof r.role === "string") return r.role;
39774
+ if (r.message && typeof r.message === "object" && typeof r.message.role === "string") {
39775
+ return r.message.role;
39776
+ }
39777
+ return null;
39778
+ }
39779
+ function sumAssistantTextChars(rec) {
39780
+ const r = rec;
39781
+ const content = (r.message && typeof r.message === "object" ? r.message.content : void 0) ?? r.content;
39782
+ let total = 0;
39783
+ if (typeof content === "string") {
39784
+ return Math.min(MAX_TEXT_BLOCK_CHARS, content.length);
39785
+ }
39786
+ if (Array.isArray(content)) {
39787
+ for (const block of content) {
39788
+ if (block && typeof block === "object") {
39789
+ const b = block;
39790
+ if (b.type === "text" && typeof b.text === "string") {
39791
+ total += Math.min(MAX_TEXT_BLOCK_CHARS, b.text.length);
39792
+ }
39793
+ }
39794
+ }
39795
+ }
39796
+ return total;
39797
+ }
39798
+ function scoreFromSubstance(signals2) {
39799
+ let pts = 0;
39800
+ if (signals2.userTurns >= 6) pts++;
39801
+ if (signals2.assistantChars >= 6e3) pts++;
39802
+ if (signals2.decisionMarkers >= 1) pts++;
39803
+ if (signals2.taskSlugs.length >= 2) pts++;
39804
+ return Math.min(3, pts);
39805
+ }
39499
39806
  function scoreFromChangeCount(count) {
39500
39807
  if (count <= 0) return 0;
39501
39808
  if (count <= 3) return 1;
@@ -39512,39 +39819,39 @@ function isJsTsFile(filePath) {
39512
39819
  return JS_TS_EXTENSIONS.has(extname2(filePath).toLowerCase());
39513
39820
  }
39514
39821
  function findProjectConfig(filePath) {
39515
- let dir = dirname26(resolve10(filePath));
39822
+ let dir = dirname28(resolve10(filePath));
39516
39823
  let formatter = null;
39517
39824
  let tsconfig = null;
39518
39825
  for (let i = 0; i <= MAX_WALK_LEVELS; i++) {
39519
39826
  if (!formatter) {
39520
39827
  for (const name of BIOME_CONFIGS) {
39521
- if (existsSync51(join49(dir, name))) {
39522
- formatter = { type: "biome", configPath: join49(dir, name), projectRoot: dir };
39828
+ if (existsSync53(join51(dir, name))) {
39829
+ formatter = { type: "biome", configPath: join51(dir, name), projectRoot: dir };
39523
39830
  break;
39524
39831
  }
39525
39832
  }
39526
39833
  if (!formatter) {
39527
39834
  for (const name of PRETTIER_CONFIGS) {
39528
- if (existsSync51(join49(dir, name))) {
39529
- formatter = { type: "prettier", configPath: join49(dir, name), projectRoot: dir };
39835
+ if (existsSync53(join51(dir, name))) {
39836
+ formatter = { type: "prettier", configPath: join51(dir, name), projectRoot: dir };
39530
39837
  break;
39531
39838
  }
39532
39839
  }
39533
39840
  }
39534
39841
  }
39535
- if (!tsconfig && existsSync51(join49(dir, "tsconfig.json"))) {
39536
- tsconfig = join49(dir, "tsconfig.json");
39842
+ if (!tsconfig && existsSync53(join51(dir, "tsconfig.json"))) {
39843
+ tsconfig = join51(dir, "tsconfig.json");
39537
39844
  }
39538
39845
  if (formatter && tsconfig) break;
39539
- const parent = dirname26(dir);
39846
+ const parent = dirname28(dir);
39540
39847
  if (parent === dir) break;
39541
39848
  dir = parent;
39542
39849
  }
39543
39850
  return { formatter, tsconfig };
39544
39851
  }
39545
39852
  function resolveLocalBin(binName, projectRoot) {
39546
- const localBin = join49(projectRoot, "node_modules", ".bin", binName);
39547
- return existsSync51(localBin) ? localBin : null;
39853
+ const localBin = join51(projectRoot, "node_modules", ".bin", binName);
39854
+ return existsSync53(localBin) ? localBin : null;
39548
39855
  }
39549
39856
  function runFormatter(detection, filePath) {
39550
39857
  try {
@@ -39586,7 +39893,7 @@ function runFormatter(detection, filePath) {
39586
39893
  }
39587
39894
  }
39588
39895
  function runTscCheckWithConfig(filePath, tsconfigPath) {
39589
- const projectRoot = dirname26(tsconfigPath);
39896
+ const projectRoot = dirname28(tsconfigPath);
39590
39897
  let tscOutput;
39591
39898
  try {
39592
39899
  const localBin = resolveLocalBin("tsc", projectRoot);
@@ -39687,6 +39994,29 @@ function getConsolidationDirective(state) {
39687
39994
  }
39688
39995
  return null;
39689
39996
  }
39997
+ function userPromptReminder(state) {
39998
+ const { debt, bookmarks, sleep_started_at } = state;
39999
+ if (sleep_started_at) {
40000
+ if (debt >= 4) {
40001
+ return `Consolidation already in progress (started: ${sleep_started_at}). Do NOT dispatch another sleep agent.`;
40002
+ }
40003
+ return null;
40004
+ }
40005
+ const criticalBookmarks = bookmarks.filter((b) => b.salience === 3);
40006
+ if (debt >= 10) {
40007
+ return `Sleep debt is ${debt}. CONSOLIDATION REQUIRED. Run sleep flow per SKILL.md (parallel specialist fan-out) NOW.`;
40008
+ }
40009
+ if (criticalBookmarks.length > 0) {
40010
+ return `${criticalBookmarks.length} critical bookmark(s) need consolidation. Run sleep flow per SKILL.md.`;
40011
+ }
40012
+ if (debt >= 7) {
40013
+ return `Sleep debt is ${debt}. Consolidation recommended before starting new work.`;
40014
+ }
40015
+ if (debt >= 4) {
40016
+ return `Sleep debt is ${debt}. After completing the current task, offer to consolidate.`;
40017
+ }
40018
+ return null;
40019
+ }
39690
40020
  function resolveDashboardPort() {
39691
40021
  const raw = process.env.DREAMCONTEXT_DASHBOARD_PORT;
39692
40022
  if (raw) {
@@ -39728,6 +40058,16 @@ function spawnDashboard(port) {
39728
40058
  });
39729
40059
  child.unref();
39730
40060
  }
40061
+ function spawnAssetDriftRefresh() {
40062
+ const cliEntry = process.argv[1];
40063
+ if (!cliEntry) return;
40064
+ const child = spawn3(process.execPath, [cliEntry, "hook", "refresh-asset-drift"], {
40065
+ detached: true,
40066
+ stdio: "ignore",
40067
+ cwd: process.cwd()
40068
+ });
40069
+ child.unref();
40070
+ }
39731
40071
  function registerHookCommand(program2) {
39732
40072
  const hook = program2.command("hook").description("Hook handlers for Claude Code (stop, session-start, subagent-start, pre-tool-use, user-prompt-submit, post-tool-use, pre-compact)");
39733
40073
  hook.command("stop").description("Record session metadata (called by Claude Code Stop hook)").action(() => {
@@ -39749,7 +40089,11 @@ function registerHookCommand(program2) {
39749
40089
  const stoppedAt = (/* @__PURE__ */ new Date()).toISOString();
39750
40090
  const analysis = transcriptPath ? analyzeTranscript(transcriptPath) : ZERO_ANALYSIS;
39751
40091
  const { changeCount, toolCount } = analysis;
39752
- const score = Math.max(scoreFromChangeCount(changeCount), scoreFromToolCount(toolCount));
40092
+ const score = Math.max(
40093
+ scoreFromChangeCount(changeCount),
40094
+ scoreFromToolCount(toolCount),
40095
+ scoreFromSubstance(analysis)
40096
+ );
39753
40097
  for (const bookmark of state.bookmarks) {
39754
40098
  if (!bookmark.session_id) {
39755
40099
  bookmark.session_id = sessionId;
@@ -39758,35 +40102,18 @@ function registerHookCommand(program2) {
39758
40102
  const bookmarkTaskSlugs = state.bookmarks.filter((b) => b.session_id === sessionId && b.task_slug).map((b) => b.task_slug);
39759
40103
  const transcriptTaskSlugs = analysis.taskSlugs;
39760
40104
  const taskSlugs = [.../* @__PURE__ */ new Set([...transcriptTaskSlugs, ...bookmarkTaskSlugs])];
39761
- const existing = state.sessions.findIndex((s) => s.session_id === sessionId);
39762
- if (existing >= 0) {
39763
- const oldScore = state.sessions[existing].score ?? 0;
39764
- state.debt = Math.max(0, state.debt - oldScore);
39765
- state.sessions[existing].transcript_path = transcriptPath;
39766
- state.sessions[existing].stopped_at = stoppedAt;
39767
- state.sessions[existing].last_assistant_message = lastAssistantMessage;
39768
- state.sessions[existing].change_count = changeCount;
39769
- state.sessions[existing].tool_count = toolCount;
39770
- state.sessions[existing].score = score;
39771
- const existingSlugs = state.sessions[existing].task_slugs ?? [];
39772
- state.sessions[existing].task_slugs = [.../* @__PURE__ */ new Set([...existingSlugs, ...taskSlugs])];
39773
- } else {
39774
- state.sessions.unshift({
39775
- session_id: sessionId,
39776
- transcript_path: transcriptPath,
39777
- stopped_at: stoppedAt,
39778
- last_assistant_message: lastAssistantMessage,
39779
- change_count: changeCount,
39780
- tool_count: toolCount,
39781
- score,
39782
- task_slugs: taskSlugs
39783
- });
39784
- }
39785
- state.debt += score;
39786
- if (existing < 0) {
39787
- state.sessions_since_last_sleep = (state.sessions_since_last_sleep || 0) + 1;
39788
- }
39789
- writeSleepState(root, state);
40105
+ const upsertInput = {
40106
+ session_id: sessionId,
40107
+ transcript_path: transcriptPath,
40108
+ stopped_at: stoppedAt,
40109
+ last_assistant_message: lastAssistantMessage,
40110
+ change_count: changeCount,
40111
+ tool_count: toolCount,
40112
+ score,
40113
+ task_slugs: taskSlugs
40114
+ };
40115
+ const nextState = upsertSessionOnStop(state, upsertInput);
40116
+ writeSleepState(root, nextState);
39790
40117
  });
39791
40118
  hook.command("session-start").description("Analyze previous session + output context snapshot (called by Claude Code SessionStart hook)").action(() => {
39792
40119
  const input2 = readStdin();
@@ -39808,7 +40135,11 @@ function registerHookCommand(program2) {
39808
40135
  continue;
39809
40136
  }
39810
40137
  const analysis = analyzeTranscript(session.transcript_path);
39811
- const score = Math.max(scoreFromChangeCount(analysis.changeCount), scoreFromToolCount(analysis.toolCount));
40138
+ const score = Math.max(
40139
+ scoreFromChangeCount(analysis.changeCount),
40140
+ scoreFromToolCount(analysis.toolCount),
40141
+ scoreFromSubstance(analysis)
40142
+ );
39812
40143
  session.change_count = analysis.changeCount;
39813
40144
  session.tool_count = analysis.toolCount;
39814
40145
  session.score = score;
@@ -39913,23 +40244,12 @@ function registerHookCommand(program2) {
39913
40244
  const root = resolveContextRoot();
39914
40245
  if (!root) process.exit(0);
39915
40246
  const state = readSleepState(root);
39916
- const { debt, bookmarks, sleep_started_at } = state;
39917
- if (sleep_started_at) {
39918
- if (debt >= 4) {
39919
- console.log(`Consolidation already in progress (started: ${sleep_started_at}). Do NOT dispatch another sleep agent.`);
39920
- }
40247
+ const reminder = userPromptReminder(state);
40248
+ if (state.sleep_started_at) {
40249
+ if (reminder) console.log(reminder);
39921
40250
  return;
39922
40251
  }
39923
- const criticalBookmarks = bookmarks.filter((b) => b.salience === 3);
39924
- if (debt >= 10) {
39925
- console.log(`Sleep debt is ${debt}. CONSOLIDATION REQUIRED. Run sleep flow per SKILL.md (parallel specialist fan-out) NOW.`);
39926
- } else if (criticalBookmarks.length > 0) {
39927
- console.log(`${criticalBookmarks.length} critical bookmark(s) need consolidation. Run sleep flow per SKILL.md.`);
39928
- } else if (debt >= 7) {
39929
- console.log(`Sleep debt is ${debt}. Consolidation recommended before starting new work.`);
39930
- } else if (debt >= 4) {
39931
- console.log(`Sleep debt is ${debt}. After completing the current task, offer to consolidate.`);
39932
- }
40252
+ if (reminder) console.log(reminder);
39933
40253
  try {
39934
40254
  const stale = listStaleRecs(24);
39935
40255
  if (stale.length > 0) {
@@ -39943,7 +40263,7 @@ function registerHookCommand(program2) {
39943
40263
  }
39944
40264
  if (process.env.DREAMCONTEXT_VERSION_CHECK !== "0") {
39945
40265
  try {
39946
- const projectRoot = dirname26(root);
40266
+ const projectRoot = dirname28(root);
39947
40267
  let vcache = readVersionCache(projectRoot);
39948
40268
  if (!isCacheFresh(vcache)) {
39949
40269
  const loaded = loadCatalog();
@@ -39954,6 +40274,7 @@ function registerHookCommand(program2) {
39954
40274
  refreshVersionCache(projectRoot, { catalogPackNames: packNames });
39955
40275
  vcache = readVersionCache(projectRoot);
39956
40276
  maybeTriggerAppUpdate();
40277
+ spawnAssetDriftRefresh();
39957
40278
  }
39958
40279
  const notice = maybeAutoUpgrade(projectRoot, dreamcontextVersion(), vcache);
39959
40280
  if (notice) console.log(notice);
@@ -40018,7 +40339,7 @@ function registerHookCommand(program2) {
40018
40339
  try {
40019
40340
  const prompt = String(input2.prompt ?? "");
40020
40341
  if (prompt.trim().length >= 8) {
40021
- const skillsRoot = join49(process.cwd(), ".claude", "skills");
40342
+ const skillsRoot = join51(process.cwd(), ".claude", "skills");
40022
40343
  const docs = loadSkillDocs(skillsRoot);
40023
40344
  if (docs.length > 0 && bm25Search(prompt, docs, 5).some((h) => h.score >= SKILL_SCORE_THRESHOLD)) {
40024
40345
  gatedSkills = true;
@@ -40079,30 +40400,37 @@ function registerHookCommand(program2) {
40079
40400
  if (!root) process.exit(0);
40080
40401
  const state = readSleepState(root);
40081
40402
  const trigger = input2 && typeof input2.trigger === "string" ? input2.trigger : "unknown";
40082
- state.compaction_log.unshift({
40403
+ const nextState = appendCompactionRecord(state, {
40083
40404
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
40084
40405
  trigger,
40085
40406
  debt_at_compaction: state.debt,
40086
40407
  sessions_count: state.sessions.length,
40087
40408
  bookmarks_count: state.bookmarks.length
40088
40409
  });
40089
- if (state.compaction_log.length > 20) {
40090
- state.compaction_log = state.compaction_log.slice(0, 20);
40091
- }
40092
- writeSleepState(root, state);
40410
+ writeSleepState(root, nextState);
40093
40411
  try {
40094
40412
  const sessionId = input2 && typeof input2.session_id === "string" ? input2.session_id : "";
40095
40413
  const transcriptPath = input2 && typeof input2.transcript_path === "string" ? input2.transcript_path : "";
40096
- if (sessionId && transcriptPath && existsSync51(transcriptPath)) {
40414
+ if (sessionId && transcriptPath && existsSync53(transcriptPath)) {
40097
40415
  const distilled = distillTranscript(transcriptPath);
40098
40416
  writeDigest(root, sessionId, buildDigest(distilled), { partial: true });
40099
40417
  }
40100
40418
  } catch {
40101
40419
  }
40102
40420
  });
40421
+ hook.command("refresh-asset-drift").description("Recompute whether `dreamcontext update` would change any asset this project uses (detached cache refresh)").action(async () => {
40422
+ readStdin();
40423
+ try {
40424
+ const root = resolveContextRoot();
40425
+ if (root) await runAssetDriftRefresh(root);
40426
+ } catch {
40427
+ }
40428
+ process.exit(0);
40429
+ });
40103
40430
  hook.command("ensure-dashboard").description("Open the web dashboard if it is not already running (called by Claude Code SessionStart hook)").action(async () => {
40104
40431
  readStdin();
40105
40432
  if (process.env.DREAMCONTEXT_AUTO_DASHBOARD === "0") process.exit(0);
40433
+ if (readAppManifest() !== null) process.exit(0);
40106
40434
  const root = resolveContextRoot();
40107
40435
  if (!root) process.exit(0);
40108
40436
  const port = resolveDashboardPort();
@@ -40118,12 +40446,14 @@ function registerHookCommand(program2) {
40118
40446
  process.exit(0);
40119
40447
  });
40120
40448
  }
40121
- var MAX_TRANSCRIPT_BYTES2, SKILL_SCORE_THRESHOLD, ZERO_ANALYSIS, JS_TS_EXTENSIONS, MAX_WALK_LEVELS, BIOME_CONFIGS, PRETTIER_CONFIGS, DEFAULT_DASHBOARD_PORT;
40449
+ var MAX_TRANSCRIPT_BYTES2, SKILL_SCORE_THRESHOLD, ZERO_ANALYSIS, MAX_TEXT_BLOCK_CHARS, JS_TS_EXTENSIONS, MAX_WALK_LEVELS, BIOME_CONFIGS, PRETTIER_CONFIGS, DEFAULT_DASHBOARD_PORT;
40122
40450
  var init_hook = __esm({
40123
40451
  "src/cli/commands/hook.ts"() {
40124
40452
  "use strict";
40125
40453
  init_context_path();
40126
40454
  init_sleep();
40455
+ init_sleep_consolidation();
40456
+ init_salience();
40127
40457
  init_transcript();
40128
40458
  init_session_digest();
40129
40459
  init_salience();
@@ -40137,10 +40467,19 @@ var init_hook = __esm({
40137
40467
  init_version_check();
40138
40468
  init_manifest();
40139
40469
  init_app();
40470
+ init_asset_drift();
40140
40471
  init_install_skill();
40141
40472
  MAX_TRANSCRIPT_BYTES2 = 50 * 1024 * 1024;
40142
40473
  SKILL_SCORE_THRESHOLD = 1;
40143
- ZERO_ANALYSIS = { changeCount: 0, toolCount: 0, taskSlugs: [] };
40474
+ ZERO_ANALYSIS = {
40475
+ changeCount: 0,
40476
+ toolCount: 0,
40477
+ taskSlugs: [],
40478
+ userTurns: 0,
40479
+ assistantChars: 0,
40480
+ decisionMarkers: 0
40481
+ };
40482
+ MAX_TEXT_BLOCK_CHARS = 2e4;
40144
40483
  JS_TS_EXTENSIONS = /* @__PURE__ */ new Set([".js", ".jsx", ".ts", ".tsx", ".mjs", ".cjs", ".mts", ".cts"]);
40145
40484
  MAX_WALK_LEVELS = 10;
40146
40485
  BIOME_CONFIGS = ["biome.json", "biome.jsonc"];
@@ -40159,11 +40498,11 @@ var init_hook = __esm({
40159
40498
  });
40160
40499
 
40161
40500
  // src/cli/commands/doctor.ts
40162
- import { existsSync as existsSync52, readFileSync as readFileSync40, readdirSync as readdirSync13, statSync as statSync8 } from "fs";
40163
- import { join as join50 } from "path";
40501
+ import { existsSync as existsSync54, readFileSync as readFileSync42, readdirSync as readdirSync14, statSync as statSync8 } from "fs";
40502
+ import { join as join52 } from "path";
40164
40503
  function checkFile(root, relPath, label, required) {
40165
- const fullPath = join50(root, relPath);
40166
- if (!existsSync52(fullPath)) {
40504
+ const fullPath = join52(root, relPath);
40505
+ if (!existsSync54(fullPath)) {
40167
40506
  return {
40168
40507
  name: label,
40169
40508
  status: required ? "error" : "warn",
@@ -40179,7 +40518,7 @@ function checkFile(root, relPath, label, required) {
40179
40518
  };
40180
40519
  }
40181
40520
  if (relPath.endsWith(".md")) {
40182
- const content = readFileSync40(fullPath, "utf-8");
40521
+ const content = readFileSync42(fullPath, "utf-8");
40183
40522
  if (content.includes("(Add your") || content.includes("{{") || content.includes("(To be defined)")) {
40184
40523
  return {
40185
40524
  name: label,
@@ -40191,12 +40530,12 @@ function checkFile(root, relPath, label, required) {
40191
40530
  return { name: label, status: "ok", message: relPath };
40192
40531
  }
40193
40532
  function checkJson(root, relPath, label) {
40194
- const fullPath = join50(root, relPath);
40195
- if (!existsSync52(fullPath)) {
40533
+ const fullPath = join52(root, relPath);
40534
+ if (!existsSync54(fullPath)) {
40196
40535
  return { name: label, status: "error", message: `Missing: ${relPath}` };
40197
40536
  }
40198
40537
  try {
40199
- const content = readFileSync40(fullPath, "utf-8");
40538
+ const content = readFileSync42(fullPath, "utf-8");
40200
40539
  JSON.parse(content);
40201
40540
  return { name: label, status: "ok", message: relPath };
40202
40541
  } catch {
@@ -40204,8 +40543,8 @@ function checkJson(root, relPath, label) {
40204
40543
  }
40205
40544
  }
40206
40545
  function checkDirectory(root, relPath, label) {
40207
- const fullPath = join50(root, relPath);
40208
- if (!existsSync52(fullPath)) {
40546
+ const fullPath = join52(root, relPath);
40547
+ if (!existsSync54(fullPath)) {
40209
40548
  return { name: label, status: "error", message: `Missing directory: ${relPath}` };
40210
40549
  }
40211
40550
  return { name: label, status: "ok", message: relPath };
@@ -40213,13 +40552,13 @@ function checkDirectory(root, relPath, label) {
40213
40552
  function checkDataStructures(root) {
40214
40553
  const results = [];
40215
40554
  const dirRel = "knowledge/data-structures";
40216
- const dirAbs = join50(root, dirRel);
40555
+ const dirAbs = join52(root, dirRel);
40217
40556
  const oldRel = "core/data-structures";
40218
- const oldAbs = join50(root, oldRel);
40219
- const oldExists = existsSync52(oldAbs);
40557
+ const oldAbs = join52(root, oldRel);
40558
+ const oldExists = existsSync54(oldAbs);
40220
40559
  const legacyRel = "core/5.data_structures.sql";
40221
- const legacyExists = existsSync52(join50(root, legacyRel));
40222
- if (!existsSync52(dirAbs)) {
40560
+ const legacyExists = existsSync54(join52(root, legacyRel));
40561
+ if (!existsSync54(dirAbs)) {
40223
40562
  if (oldExists) {
40224
40563
  results.push({
40225
40564
  name: "Data structures",
@@ -40243,7 +40582,7 @@ function checkDataStructures(root) {
40243
40582
  }
40244
40583
  let mdCount = 0;
40245
40584
  try {
40246
- mdCount = readdirSync13(dirAbs).filter((f) => f.endsWith(".md")).length;
40585
+ mdCount = readdirSync14(dirAbs).filter((f) => f.endsWith(".md")).length;
40247
40586
  } catch {
40248
40587
  results.push({
40249
40588
  name: "Data structures",
@@ -40315,19 +40654,19 @@ function registerDoctorCommand(program2) {
40315
40654
  checkFile(root, "core/4.tech_stack.md", "Tech stack", false),
40316
40655
  ...checkDataStructures(root),
40317
40656
  // Taxonomy vocabulary (non-fatal: absent means DEFAULT_VOCABULARY used)
40318
- ...!existsSync52(join50(root, "core", "taxonomy.json")) ? [{
40657
+ ...!existsSync54(join52(root, "core", "taxonomy.json")) ? [{
40319
40658
  name: "Taxonomy vocabulary",
40320
40659
  status: "warn",
40321
40660
  message: "core/taxonomy.json not found \u2014 run `dreamcontext taxonomy init` to scaffold it"
40322
40661
  }] : [checkJson(root, "core/taxonomy.json", "Taxonomy vocabulary")],
40323
40662
  // Sleep state (optional — created on first Stop hook)
40324
- ...existsSync52(join50(root, "state", ".sleep.json")) ? [checkJson(root, "state/.sleep.json", "Sleep state")] : [],
40325
- ...existsSync52(join50(root, "state", ".platforms.json")) ? [checkJson(root, "state/.platforms.json", "Platform defaults")] : []
40663
+ ...existsSync54(join52(root, "state", ".sleep.json")) ? [checkJson(root, "state/.sleep.json", "Sleep state")] : [],
40664
+ ...existsSync54(join52(root, "state", ".platforms.json")) ? [checkJson(root, "state/.platforms.json", "Platform defaults")] : []
40326
40665
  ];
40327
- const sleepPath = join50(root, "state", ".sleep.json");
40328
- if (existsSync52(sleepPath)) {
40666
+ const sleepPath = join52(root, "state", ".sleep.json");
40667
+ if (existsSync54(sleepPath)) {
40329
40668
  try {
40330
- const parsed = JSON.parse(readFileSync40(sleepPath, "utf-8"));
40669
+ const parsed = JSON.parse(readFileSync42(sleepPath, "utf-8"));
40331
40670
  if (typeof parsed.debt !== "number" || parsed.debt < 0) {
40332
40671
  results.push({ name: "Sleep debt", status: "warn", message: "Invalid debt value in .sleep.json" });
40333
40672
  }
@@ -40490,23 +40829,23 @@ var init_middleware = __esm({
40490
40829
  });
40491
40830
 
40492
40831
  // src/server/static.ts
40493
- import { existsSync as existsSync53, readFileSync as readFileSync41, statSync as statSync9 } from "fs";
40494
- import { join as join51, extname as extname3 } from "path";
40832
+ import { existsSync as existsSync55, readFileSync as readFileSync43, statSync as statSync9 } from "fs";
40833
+ import { join as join53, extname as extname3 } from "path";
40495
40834
  function serveStatic(req, res, staticDir) {
40496
40835
  const url = new URL(req.url || "/", `http://${req.headers.host}`);
40497
- let filePath = join51(staticDir, url.pathname);
40836
+ let filePath = join53(staticDir, url.pathname);
40498
40837
  if (!filePath.startsWith(staticDir)) {
40499
40838
  res.writeHead(403, { "Content-Type": "text/plain" });
40500
40839
  res.end("Forbidden");
40501
40840
  return;
40502
40841
  }
40503
- if (existsSync53(filePath) && statSync9(filePath).isDirectory()) {
40504
- filePath = join51(filePath, "index.html");
40842
+ if (existsSync55(filePath) && statSync9(filePath).isDirectory()) {
40843
+ filePath = join53(filePath, "index.html");
40505
40844
  }
40506
- if (existsSync53(filePath) && statSync9(filePath).isFile()) {
40845
+ if (existsSync55(filePath) && statSync9(filePath).isFile()) {
40507
40846
  const ext = extname3(filePath);
40508
40847
  const contentType = MIME_TYPES[ext] || "application/octet-stream";
40509
- const content = readFileSync41(filePath);
40848
+ const content = readFileSync43(filePath);
40510
40849
  res.writeHead(200, {
40511
40850
  "Content-Type": contentType,
40512
40851
  "Content-Length": content.length,
@@ -40515,9 +40854,9 @@ function serveStatic(req, res, staticDir) {
40515
40854
  res.end(content);
40516
40855
  return;
40517
40856
  }
40518
- const indexPath2 = join51(staticDir, "index.html");
40519
- if (existsSync53(indexPath2)) {
40520
- const content = readFileSync41(indexPath2);
40857
+ const indexPath2 = join53(staticDir, "index.html");
40858
+ if (existsSync55(indexPath2)) {
40859
+ const content = readFileSync43(indexPath2);
40521
40860
  res.writeHead(200, {
40522
40861
  "Content-Type": "text/html; charset=utf-8",
40523
40862
  "Content-Length": content.length,
@@ -41038,20 +41377,20 @@ var init_sleep2 = __esm({
41038
41377
  });
41039
41378
 
41040
41379
  // src/server/routes/core.ts
41041
- import { existsSync as existsSync54, readdirSync as readdirSync14 } from "fs";
41042
- import { join as join52 } from "path";
41380
+ import { existsSync as existsSync56, readdirSync as readdirSync15 } from "fs";
41381
+ import { join as join54 } from "path";
41043
41382
  function getCoreDir(contextRoot) {
41044
- return join52(contextRoot, "core");
41383
+ return join54(contextRoot, "core");
41045
41384
  }
41046
41385
  async function handleCoreList(_req, res, _params, contextRoot) {
41047
41386
  const coreDir = getCoreDir(contextRoot);
41048
- if (!existsSync54(coreDir)) {
41387
+ if (!existsSync56(coreDir)) {
41049
41388
  sendJson(res, 200, { files: [] });
41050
41389
  return;
41051
41390
  }
41052
- const entries = readdirSync14(coreDir, { withFileTypes: true });
41391
+ const entries = readdirSync15(coreDir, { withFileTypes: true });
41053
41392
  const files = entries.filter((e) => e.isFile() && (e.name.endsWith(".md") || e.name.endsWith(".sql") || e.name.endsWith(".json"))).map((e) => {
41054
- const filePath = join52(coreDir, e.name);
41393
+ const filePath = join54(coreDir, e.name);
41055
41394
  let frontmatter = {};
41056
41395
  if (e.name.endsWith(".md")) {
41057
41396
  try {
@@ -41075,13 +41414,13 @@ async function handleCoreGet(_req, res, params, contextRoot) {
41075
41414
  sendError(res, 400, "invalid_path", "Invalid filename.");
41076
41415
  return;
41077
41416
  }
41078
- if (!existsSync54(filePath)) {
41417
+ if (!existsSync56(filePath)) {
41079
41418
  sendError(res, 404, "not_found", `Core file not found: ${filename}`);
41080
41419
  return;
41081
41420
  }
41082
41421
  if (filename.endsWith(".json")) {
41083
- const { readFileSync: readFileSync66 } = await import("fs");
41084
- const raw2 = readFileSync66(filePath, "utf-8");
41422
+ const { readFileSync: readFileSync69 } = await import("fs");
41423
+ const raw2 = readFileSync69(filePath, "utf-8");
41085
41424
  try {
41086
41425
  const data = JSON.parse(raw2);
41087
41426
  sendJson(res, 200, { filename, type: "json", data });
@@ -41115,8 +41454,8 @@ async function handleCoreGet(_req, res, params, contextRoot) {
41115
41454
  });
41116
41455
  return;
41117
41456
  }
41118
- const { readFileSync: readFileSync65 } = await import("fs");
41119
- const raw = readFileSync65(filePath, "utf-8");
41457
+ const { readFileSync: readFileSync68 } = await import("fs");
41458
+ const raw = readFileSync68(filePath, "utf-8");
41120
41459
  sendJson(res, 200, { filename, type: "text", content: raw });
41121
41460
  }
41122
41461
  async function handleCoreUpdate(req, res, params, contextRoot) {
@@ -41126,7 +41465,7 @@ async function handleCoreUpdate(req, res, params, contextRoot) {
41126
41465
  sendError(res, 400, "invalid_path", "Invalid filename.");
41127
41466
  return;
41128
41467
  }
41129
- if (!existsSync54(filePath)) {
41468
+ if (!existsSync56(filePath)) {
41130
41469
  sendError(res, 404, "not_found", `Core file not found: ${filename}`);
41131
41470
  return;
41132
41471
  }
@@ -41166,8 +41505,8 @@ async function handleCoreUpdate(req, res, params, contextRoot) {
41166
41505
  return;
41167
41506
  }
41168
41507
  changedParts.push("content");
41169
- const { writeFileSync: writeFileSync44 } = await import("fs");
41170
- writeFileSync44(filePath, body.content, "utf-8");
41508
+ const { writeFileSync: writeFileSync46 } = await import("fs");
41509
+ writeFileSync46(filePath, body.content, "utf-8");
41171
41510
  }
41172
41511
  const what = changedParts.length > 0 ? changedParts.join(" and ") : "file";
41173
41512
  recordDashboardChange(contextRoot, {
@@ -41190,10 +41529,10 @@ var init_core2 = __esm({
41190
41529
  });
41191
41530
 
41192
41531
  // src/server/routes/knowledge.ts
41193
- import { existsSync as existsSync55 } from "fs";
41194
- import { join as join53 } from "path";
41532
+ import { existsSync as existsSync57 } from "fs";
41533
+ import { join as join55 } from "path";
41195
41534
  function getKnowledgeDir2(contextRoot) {
41196
- return join53(contextRoot, "knowledge");
41535
+ return join55(contextRoot, "knowledge");
41197
41536
  }
41198
41537
  async function handleKnowledgeList(_req, res, _params, contextRoot) {
41199
41538
  const entries = buildKnowledgeIndex(contextRoot);
@@ -41206,7 +41545,7 @@ async function handleKnowledgeGet(_req, res, params, contextRoot) {
41206
41545
  sendError(res, 400, "invalid_path", `Invalid knowledge slug: ${slug}`);
41207
41546
  return;
41208
41547
  }
41209
- if (!existsSync55(filePath)) {
41548
+ if (!existsSync57(filePath)) {
41210
41549
  sendError(res, 404, "not_found", `Knowledge file not found: ${slug}`);
41211
41550
  return;
41212
41551
  }
@@ -41230,7 +41569,7 @@ async function handleKnowledgeUpdate(req, res, params, contextRoot) {
41230
41569
  sendError(res, 400, "invalid_path", `Invalid knowledge slug: ${slug}`);
41231
41570
  return;
41232
41571
  }
41233
- if (!existsSync55(filePath)) {
41572
+ if (!existsSync57(filePath)) {
41234
41573
  sendError(res, 404, "not_found", `Knowledge file not found: ${slug}`);
41235
41574
  return;
41236
41575
  }
@@ -41287,14 +41626,14 @@ var init_knowledge2 = __esm({
41287
41626
  });
41288
41627
 
41289
41628
  // src/server/routes/features.ts
41290
- import { existsSync as existsSync56 } from "fs";
41291
- import { join as join54, basename as basename16 } from "path";
41629
+ import { existsSync as existsSync58 } from "fs";
41630
+ import { join as join56, basename as basename16 } from "path";
41292
41631
  function getFeaturesDir2(contextRoot) {
41293
- return join54(contextRoot, "core", "features");
41632
+ return join56(contextRoot, "core", "features");
41294
41633
  }
41295
41634
  async function handleFeaturesList(_req, res, _params, contextRoot) {
41296
41635
  const featuresDir = getFeaturesDir2(contextRoot);
41297
- if (!existsSync56(featuresDir)) {
41636
+ if (!existsSync58(featuresDir)) {
41298
41637
  sendJson(res, 200, { features: [] });
41299
41638
  return;
41300
41639
  }
@@ -41325,7 +41664,7 @@ async function handleFeaturesGet(_req, res, params, contextRoot) {
41325
41664
  sendError(res, 400, "invalid_path", `Invalid feature slug: ${slug}`);
41326
41665
  return;
41327
41666
  }
41328
- if (!existsSync56(filePath)) {
41667
+ if (!existsSync58(filePath)) {
41329
41668
  sendError(res, 404, "not_found", `Feature not found: ${slug}`);
41330
41669
  return;
41331
41670
  }
@@ -41367,11 +41706,11 @@ var init_features2 = __esm({
41367
41706
  });
41368
41707
 
41369
41708
  // src/server/routes/changelog.ts
41370
- import { existsSync as existsSync57 } from "fs";
41371
- import { join as join55 } from "path";
41709
+ import { existsSync as existsSync59 } from "fs";
41710
+ import { join as join57 } from "path";
41372
41711
  async function handleChangelogGet(_req, res, _params, contextRoot) {
41373
- const filePath = join55(contextRoot, "core", "CHANGELOG.json");
41374
- if (!existsSync57(filePath)) {
41712
+ const filePath = join57(contextRoot, "core", "CHANGELOG.json");
41713
+ if (!existsSync59(filePath)) {
41375
41714
  sendJson(res, 200, { entries: [] });
41376
41715
  return;
41377
41716
  }
@@ -41383,8 +41722,8 @@ async function handleChangelogGet(_req, res, _params, contextRoot) {
41383
41722
  }
41384
41723
  }
41385
41724
  async function handleReleasesGet(_req, res, _params, contextRoot) {
41386
- const filePath = join55(contextRoot, "core", "RELEASES.json");
41387
- if (!existsSync57(filePath)) {
41725
+ const filePath = join57(contextRoot, "core", "RELEASES.json");
41726
+ if (!existsSync59(filePath)) {
41388
41727
  sendJson(res, 200, { entries: [] });
41389
41728
  return;
41390
41729
  }
@@ -41438,7 +41777,7 @@ async function handleReleasesCreate(req, res, _params, contextRoot) {
41438
41777
  tasks: Array.isArray(body.tasks) ? body.tasks : [],
41439
41778
  changelog: Array.isArray(body.changelog) ? body.changelog : []
41440
41779
  };
41441
- const filePath = join55(contextRoot, "core", "RELEASES.json");
41780
+ const filePath = join57(contextRoot, "core", "RELEASES.json");
41442
41781
  insertToJsonArray(filePath, release2);
41443
41782
  if (release2.features.length > 0) {
41444
41783
  backPopulateFeatures(contextRoot, release2.features, release2.version);
@@ -41457,8 +41796,8 @@ async function handleReleasesUpdate(req, res, params, contextRoot) {
41457
41796
  sendError(res, 400, "invalid_body", "Request body must be JSON.");
41458
41797
  return;
41459
41798
  }
41460
- const filePath = join55(contextRoot, "core", "RELEASES.json");
41461
- if (!existsSync57(filePath)) {
41799
+ const filePath = join57(contextRoot, "core", "RELEASES.json");
41800
+ if (!existsSync59(filePath)) {
41462
41801
  sendError(res, 404, "not_found", `Release not found: ${params.version}`);
41463
41802
  return;
41464
41803
  }
@@ -41512,8 +41851,8 @@ var init_changelog = __esm({
41512
41851
  });
41513
41852
 
41514
41853
  // src/lib/graph.ts
41515
- import { existsSync as existsSync58, readFileSync as readFileSync42 } from "fs";
41516
- import { join as join56, basename as basename17 } from "path";
41854
+ import { existsSync as existsSync60, readFileSync as readFileSync44 } from "fs";
41855
+ import { join as join58, basename as basename17 } from "path";
41517
41856
  function buildGraph(contextRoot) {
41518
41857
  const nodes = [];
41519
41858
  const links = [];
@@ -41527,14 +41866,14 @@ function buildGraph(contextRoot) {
41527
41866
  byId.set(node.id, node);
41528
41867
  if (slug) bySlug.set(slug, node);
41529
41868
  };
41530
- const coreDir = join56(contextRoot, "core");
41869
+ const coreDir = join58(contextRoot, "core");
41531
41870
  const foundational = [
41532
41871
  { prefix: "0", group: "soul" },
41533
41872
  { prefix: "1", group: "user" },
41534
41873
  { prefix: "2", group: "memory" }
41535
41874
  ];
41536
41875
  for (const { prefix, group } of foundational) {
41537
- if (!existsSync58(coreDir)) continue;
41876
+ if (!existsSync60(coreDir)) continue;
41538
41877
  const matches = import_fast_glob15.default.sync(`${prefix}.*.md`, { cwd: coreDir, absolute: true });
41539
41878
  for (const file of matches) {
41540
41879
  try {
@@ -41554,7 +41893,7 @@ function buildGraph(contextRoot) {
41554
41893
  }
41555
41894
  }
41556
41895
  }
41557
- if (existsSync58(coreDir)) {
41896
+ if (existsSync60(coreDir)) {
41558
41897
  const others = import_fast_glob15.default.sync("[3-9]*.md", { cwd: coreDir, absolute: true });
41559
41898
  for (const file of others) {
41560
41899
  const filename = basename17(file);
@@ -41574,8 +41913,8 @@ function buildGraph(contextRoot) {
41574
41913
  }
41575
41914
  }
41576
41915
  }
41577
- const featuresDir = join56(coreDir, "features");
41578
- if (existsSync58(featuresDir)) {
41916
+ const featuresDir = join58(coreDir, "features");
41917
+ if (existsSync60(featuresDir)) {
41579
41918
  const files = import_fast_glob15.default.sync("*.md", { cwd: featuresDir, absolute: true });
41580
41919
  for (const file of files) {
41581
41920
  const fileSlug = basename17(file, ".md");
@@ -41605,8 +41944,8 @@ function buildGraph(contextRoot) {
41605
41944
  }
41606
41945
  }
41607
41946
  }
41608
- const stateDir = join56(contextRoot, "state");
41609
- if (existsSync58(stateDir)) {
41947
+ const stateDir = join58(contextRoot, "state");
41948
+ if (existsSync60(stateDir)) {
41610
41949
  const files = import_fast_glob15.default.sync("*.md", { cwd: stateDir, absolute: true });
41611
41950
  for (const file of files) {
41612
41951
  const fileSlug = basename17(file, ".md");
@@ -41657,8 +41996,8 @@ function buildGraph(contextRoot) {
41657
41996
  entry.slug
41658
41997
  );
41659
41998
  }
41660
- const inboxDir2 = join56(contextRoot, "inbox");
41661
- if (existsSync58(inboxDir2)) {
41999
+ const inboxDir2 = join58(contextRoot, "inbox");
42000
+ if (existsSync60(inboxDir2)) {
41662
42001
  const files = import_fast_glob15.default.sync("*.md", { cwd: inboxDir2, absolute: true });
41663
42002
  for (const file of files) {
41664
42003
  const slug = basename17(file, ".md");
@@ -41679,11 +42018,11 @@ function buildGraph(contextRoot) {
41679
42018
  });
41680
42019
  }
41681
42020
  }
41682
- const releasesPath = join56(coreDir, "RELEASES.json");
42021
+ const releasesPath = join58(coreDir, "RELEASES.json");
41683
42022
  let releases = [];
41684
- if (existsSync58(releasesPath)) {
42023
+ if (existsSync60(releasesPath)) {
41685
42024
  try {
41686
- const parsed = JSON.parse(readFileSync42(releasesPath, "utf-8"));
42025
+ const parsed = JSON.parse(readFileSync44(releasesPath, "utf-8"));
41687
42026
  if (Array.isArray(parsed)) releases = parsed;
41688
42027
  } catch {
41689
42028
  }
@@ -41779,7 +42118,7 @@ var init_graph = __esm({
41779
42118
  });
41780
42119
 
41781
42120
  // src/server/routes/graph.ts
41782
- import { existsSync as existsSync59, readFileSync as readFileSync43 } from "fs";
42121
+ import { existsSync as existsSync61, readFileSync as readFileSync45 } from "fs";
41783
42122
  import { normalize, resolve as resolve11, sep as sep6 } from "path";
41784
42123
  async function handleGraphGet(_req, res, _params, contextRoot) {
41785
42124
  try {
@@ -41803,7 +42142,7 @@ async function handleGraphContentGet(req, res, _params, contextRoot) {
41803
42142
  sendError(res, 400, "invalid_path", "Path escapes context root.");
41804
42143
  return;
41805
42144
  }
41806
- if (!existsSync59(absTarget)) {
42145
+ if (!existsSync61(absTarget)) {
41807
42146
  sendError(res, 404, "not_found", `Path not found: ${rawPath}`);
41808
42147
  return;
41809
42148
  }
@@ -41824,7 +42163,7 @@ async function handleGraphContentGet(req, res, _params, contextRoot) {
41824
42163
  }
41825
42164
  if (absTarget.endsWith(".json")) {
41826
42165
  try {
41827
- const raw = readFileSync43(absTarget, "utf-8");
42166
+ const raw = readFileSync45(absTarget, "utf-8");
41828
42167
  try {
41829
42168
  sendJson(res, 200, { path: rawPath, type: "json", data: JSON.parse(raw) });
41830
42169
  } catch {
@@ -41837,7 +42176,7 @@ async function handleGraphContentGet(req, res, _params, contextRoot) {
41837
42176
  return;
41838
42177
  }
41839
42178
  try {
41840
- const content = readFileSync43(absTarget, "utf-8");
42179
+ const content = readFileSync45(absTarget, "utf-8");
41841
42180
  sendJson(res, 200, { path: rawPath, type: "text", content });
41842
42181
  } catch (err) {
41843
42182
  const message = err instanceof Error ? err.message : "Failed to read file";
@@ -41854,12 +42193,12 @@ var init_graph2 = __esm({
41854
42193
  });
41855
42194
 
41856
42195
  // src/lib/council.ts
41857
- import { existsSync as existsSync60, mkdirSync as mkdirSync24, readFileSync as readFileSync44 } from "fs";
41858
- import { join as join57, resolve as resolve12, sep as sep7 } from "path";
42196
+ import { existsSync as existsSync62, mkdirSync as mkdirSync25, readFileSync as readFileSync46 } from "fs";
42197
+ import { join as join59, resolve as resolve12, sep as sep7 } from "path";
41859
42198
  import { fileURLToPath as fileURLToPath6 } from "url";
41860
42199
  function getCouncilDir() {
41861
42200
  const root = ensureContextRoot();
41862
- return join57(root, "council");
42201
+ return join59(root, "council");
41863
42202
  }
41864
42203
  function assertSafeSegment(kind, id) {
41865
42204
  if (!id || typeof id !== "string") {
@@ -41882,29 +42221,29 @@ function assertWithinCouncil(target) {
41882
42221
  }
41883
42222
  function getDebateDir(debateId) {
41884
42223
  assertSafeSegment("debate_id", debateId);
41885
- const target = join57(getCouncilDir(), debateId);
42224
+ const target = join59(getCouncilDir(), debateId);
41886
42225
  return assertWithinCouncil(target);
41887
42226
  }
41888
42227
  function getPersonaDir(debateId, personaSlug) {
41889
42228
  assertSafeSegment("persona_slug", personaSlug);
41890
- const target = join57(getDebateDir(debateId), personaSlug);
42229
+ const target = join59(getDebateDir(debateId), personaSlug);
41891
42230
  return assertWithinCouncil(target);
41892
42231
  }
41893
42232
  function getCouncilIndexPath() {
41894
- return join57(getCouncilDir(), "index.json");
42233
+ return join59(getCouncilDir(), "index.json");
41895
42234
  }
41896
42235
  function ensureCouncilDir() {
41897
42236
  const dir = getCouncilDir();
41898
- mkdirSync24(dir, { recursive: true });
42237
+ mkdirSync25(dir, { recursive: true });
41899
42238
  const indexPath2 = getCouncilIndexPath();
41900
- if (!existsSync60(indexPath2)) {
42239
+ if (!existsSync62(indexPath2)) {
41901
42240
  writeJsonArray(indexPath2, []);
41902
42241
  }
41903
42242
  return dir;
41904
42243
  }
41905
42244
  function ensureDebateExists(debateId) {
41906
42245
  const dir = getDebateDir(debateId);
41907
- if (!existsSync60(dir)) {
42246
+ if (!existsSync62(dir)) {
41908
42247
  throw new Error(`Debate not found: ${debateId}`);
41909
42248
  }
41910
42249
  return dir;
@@ -41912,19 +42251,19 @@ function ensureDebateExists(debateId) {
41912
42251
  function ensurePersonaExists(debateId, personaSlug) {
41913
42252
  ensureDebateExists(debateId);
41914
42253
  const dir = getPersonaDir(debateId, personaSlug);
41915
- if (!existsSync60(dir)) {
42254
+ if (!existsSync62(dir)) {
41916
42255
  throw new Error(`Persona not found in ${debateId}: ${personaSlug}`);
41917
42256
  }
41918
42257
  return dir;
41919
42258
  }
41920
42259
  function readDebateFrontmatter(debateId) {
41921
42260
  ensureDebateExists(debateId);
41922
- const { data } = readFrontmatter(join57(getDebateDir(debateId), "debate.md"));
42261
+ const { data } = readFrontmatter(join59(getDebateDir(debateId), "debate.md"));
41923
42262
  return data;
41924
42263
  }
41925
42264
  function loadCouncilIndex() {
41926
42265
  const indexPath2 = getCouncilIndexPath();
41927
- if (!existsSync60(indexPath2)) return [];
42266
+ if (!existsSync62(indexPath2)) return [];
41928
42267
  return readJsonArray(indexPath2);
41929
42268
  }
41930
42269
  function saveCouncilIndex(entries) {
@@ -41942,17 +42281,17 @@ function upsertCouncilIndex(entry) {
41942
42281
  }
41943
42282
  function loadTemplate(filename) {
41944
42283
  const candidates = [
41945
- join57(__dirname6, "templates", filename),
42284
+ join59(__dirname6, "templates", filename),
41946
42285
  // bundled: dist/templates/
41947
- join57(__dirname6, "..", "templates", filename),
42286
+ join59(__dirname6, "..", "templates", filename),
41948
42287
  // alt layout
41949
- join57(__dirname6, "..", "src", "templates", filename),
42288
+ join59(__dirname6, "..", "src", "templates", filename),
41950
42289
  // dev fallback
41951
- join57(__dirname6, "..", "..", "src", "templates", filename)
42290
+ join59(__dirname6, "..", "..", "src", "templates", filename)
41952
42291
  ];
41953
42292
  for (const path2 of candidates) {
41954
- if (existsSync60(path2)) {
41955
- return readFileSync44(path2, "utf-8");
42293
+ if (existsSync62(path2)) {
42294
+ return readFileSync46(path2, "utf-8");
41956
42295
  }
41957
42296
  }
41958
42297
  throw new Error(`Template not found: ${filename}`);
@@ -42026,8 +42365,8 @@ function parseReportRounds(reportContent) {
42026
42365
  return entries;
42027
42366
  }
42028
42367
  function getPersonaRoundSummary(debateId, personaSlug, round) {
42029
- const reportPath = join57(getPersonaDir(debateId, personaSlug), "report.md");
42030
- if (!existsSync60(reportPath)) return null;
42368
+ const reportPath = join59(getPersonaDir(debateId, personaSlug), "report.md");
42369
+ if (!existsSync62(reportPath)) return null;
42031
42370
  const { content } = readFrontmatter(reportPath);
42032
42371
  const entries = parseReportRounds(content);
42033
42372
  const entry = entries.find((e) => e.round === round);
@@ -42061,10 +42400,10 @@ var init_council = __esm({
42061
42400
  });
42062
42401
 
42063
42402
  // src/server/routes/council.ts
42064
- import { existsSync as existsSync61 } from "fs";
42065
- import { join as join58, resolve as resolve13, sep as sep8 } from "path";
42403
+ import { existsSync as existsSync63 } from "fs";
42404
+ import { join as join60, resolve as resolve13, sep as sep8 } from "path";
42066
42405
  function getCouncilDir2(contextRoot) {
42067
- return join58(contextRoot, "council");
42406
+ return join60(contextRoot, "council");
42068
42407
  }
42069
42408
  function assertSafeSegment2(id) {
42070
42409
  if (!id || typeof id !== "string") return false;
@@ -42117,14 +42456,14 @@ function toParsedRound(entry) {
42117
42456
  };
42118
42457
  }
42119
42458
  function loadPersonaDetail(debateDir, slug) {
42120
- const personaDir = join58(debateDir, slug);
42121
- if (!existsSync61(personaDir)) return null;
42122
- const personaFile = join58(personaDir, "context-and-persona.md");
42123
- const reportFile = join58(personaDir, "report.md");
42459
+ const personaDir = join60(debateDir, slug);
42460
+ if (!existsSync63(personaDir)) return null;
42461
+ const personaFile = join60(personaDir, "context-and-persona.md");
42462
+ const reportFile = join60(personaDir, "report.md");
42124
42463
  let fm = { name: slug, model: "unknown", aspects: [], round_entries: 0 };
42125
42464
  let persona = "";
42126
42465
  let crossContext = {};
42127
- if (existsSync61(personaFile)) {
42466
+ if (existsSync63(personaFile)) {
42128
42467
  const parsed = readFrontmatter(personaFile);
42129
42468
  fm = {
42130
42469
  name: parsed.data.name ?? slug,
@@ -42137,13 +42476,13 @@ function loadPersonaDetail(debateDir, slug) {
42137
42476
  crossContext = split.crossContext;
42138
42477
  }
42139
42478
  let rounds = [];
42140
- if (existsSync61(reportFile)) {
42479
+ if (existsSync63(reportFile)) {
42141
42480
  const { content } = readFrontmatter(reportFile);
42142
42481
  rounds = parseReportRounds(content).map(toParsedRound);
42143
42482
  }
42144
- const researchIndex = join58(personaDir, "researches", "index.json");
42483
+ const researchIndex = join60(personaDir, "researches", "index.json");
42145
42484
  let researches = [];
42146
- if (existsSync61(researchIndex)) {
42485
+ if (existsSync63(researchIndex)) {
42147
42486
  try {
42148
42487
  researches = readJsonArray(researchIndex);
42149
42488
  } catch {
@@ -42153,17 +42492,17 @@ function loadPersonaDetail(debateDir, slug) {
42153
42492
  return { slug, frontmatter: fm, persona, crossContext, rounds, researches };
42154
42493
  }
42155
42494
  async function handleCouncilList(_req, res, _params, contextRoot) {
42156
- const indexPath2 = join58(getCouncilDir2(contextRoot), "index.json");
42157
- if (!existsSync61(indexPath2)) {
42495
+ const indexPath2 = join60(getCouncilDir2(contextRoot), "index.json");
42496
+ if (!existsSync63(indexPath2)) {
42158
42497
  sendJson(res, 200, { debates: [] });
42159
42498
  return;
42160
42499
  }
42161
42500
  try {
42162
42501
  const debates = readJsonArray(indexPath2);
42163
42502
  const enriched = debates.map((d) => {
42164
- const debateFile = join58(getCouncilDir2(contextRoot), d.id, "debate.md");
42503
+ const debateFile = join60(getCouncilDir2(contextRoot), d.id, "debate.md");
42165
42504
  let personaSlugs = [];
42166
- if (existsSync61(debateFile)) {
42505
+ if (existsSync63(debateFile)) {
42167
42506
  try {
42168
42507
  const fm = readFrontmatter(debateFile).data;
42169
42508
  if (Array.isArray(fm.personas)) personaSlugs = fm.personas;
@@ -42186,14 +42525,14 @@ async function handleCouncilGet(_req, res, params, contextRoot) {
42186
42525
  return;
42187
42526
  }
42188
42527
  const councilDir = getCouncilDir2(contextRoot);
42189
- const debateDirUnchecked = join58(councilDir, debateId);
42528
+ const debateDirUnchecked = join60(councilDir, debateId);
42190
42529
  const debateDir = assertWithin(councilDir, debateDirUnchecked);
42191
- if (!debateDir || !existsSync61(debateDir)) {
42530
+ if (!debateDir || !existsSync63(debateDir)) {
42192
42531
  sendError(res, 404, "not_found", `Debate not found: ${debateId}`);
42193
42532
  return;
42194
42533
  }
42195
- const debateFile = join58(debateDir, "debate.md");
42196
- if (!existsSync61(debateFile)) {
42534
+ const debateFile = join60(debateDir, "debate.md");
42535
+ if (!existsSync63(debateFile)) {
42197
42536
  sendError(res, 404, "not_found", `Debate metadata missing: ${debateId}`);
42198
42537
  return;
42199
42538
  }
@@ -42210,11 +42549,11 @@ async function handleCouncilGet(_req, res, params, contextRoot) {
42210
42549
  created_at: String(fmRaw.created_at ?? ""),
42211
42550
  updated_at: String(fmRaw.updated_at ?? "")
42212
42551
  };
42213
- const roundLogFile = join58(debateDir, "round-log.md");
42214
- const roundLog = existsSync61(roundLogFile) ? readFrontmatter(roundLogFile).content : null;
42215
- const finalReportFile = join58(debateDir, "final-report.md");
42552
+ const roundLogFile = join60(debateDir, "round-log.md");
42553
+ const roundLog = existsSync63(roundLogFile) ? readFrontmatter(roundLogFile).content : null;
42554
+ const finalReportFile = join60(debateDir, "final-report.md");
42216
42555
  let finalReport = null;
42217
- if (existsSync61(finalReportFile)) {
42556
+ if (existsSync63(finalReportFile)) {
42218
42557
  const parsed = readFrontmatter(finalReportFile);
42219
42558
  finalReport = { frontmatter: parsed.data, content: parsed.content };
42220
42559
  }
@@ -42242,9 +42581,9 @@ async function handleCouncilResearchGet(_req, res, params, contextRoot) {
42242
42581
  const councilDir = getCouncilDir2(contextRoot);
42243
42582
  const researchFile = assertWithin(
42244
42583
  councilDir,
42245
- join58(councilDir, debateId, personaSlug, "researches", `${researchSlug}.md`)
42584
+ join60(councilDir, debateId, personaSlug, "researches", `${researchSlug}.md`)
42246
42585
  );
42247
- if (!researchFile || !existsSync61(researchFile)) {
42586
+ if (!researchFile || !existsSync63(researchFile)) {
42248
42587
  sendError(res, 404, "not_found", `Research not found: ${researchSlug}`);
42249
42588
  return;
42250
42589
  }
@@ -42262,9 +42601,9 @@ var init_council2 = __esm({
42262
42601
  });
42263
42602
 
42264
42603
  // src/server/routes/config.ts
42265
- import { dirname as dirname27 } from "path";
42604
+ import { dirname as dirname29 } from "path";
42266
42605
  async function handleConfigGet(_req, res, _params, contextRoot) {
42267
- const config = readSetupConfig(dirname27(contextRoot));
42606
+ const config = readSetupConfig(dirname29(contextRoot));
42268
42607
  sendJson(res, 200, { config });
42269
42608
  }
42270
42609
  async function handleConfigUpdate(req, res, _params, contextRoot) {
@@ -42348,14 +42687,14 @@ async function handleConfigUpdate(req, res, _params, contextRoot) {
42348
42687
  }
42349
42688
  picked.changelogTarget = "comments";
42350
42689
  }
42351
- const existing = readSetupConfig(dirname27(contextRoot))?.clickup ?? {};
42690
+ const existing = readSetupConfig(dirname29(contextRoot))?.clickup ?? {};
42352
42691
  patch.clickup = { ...existing, ...picked };
42353
42692
  }
42354
42693
  if (patch.platforms === void 0 && patch.packs === void 0 && patch.disableNativeMemory === void 0 && patch.taskBackend === void 0 && patch.cloudTaskManagement === void 0 && patch.clickup === void 0 && patch.shareable === void 0) {
42355
42694
  sendError(res, 400, "no_changes", "Provide at least one of: platforms, packs, disableNativeMemory, taskBackend, cloudTaskManagement, clickup, shareable.");
42356
42695
  return;
42357
42696
  }
42358
- const projectRoot = dirname27(contextRoot);
42697
+ const projectRoot = dirname29(contextRoot);
42359
42698
  if (patch.taskBackend === "clickup") {
42360
42699
  try {
42361
42700
  ensureRemoteBackendGitignore(projectRoot);
@@ -42382,11 +42721,11 @@ var init_config = __esm({
42382
42721
  });
42383
42722
 
42384
42723
  // src/server/routes/vaults.ts
42385
- import { dirname as dirname28, resolve as resolve14 } from "path";
42386
- import { existsSync as existsSync62 } from "fs";
42724
+ import { dirname as dirname30, resolve as resolve14 } from "path";
42725
+ import { existsSync as existsSync64 } from "fs";
42387
42726
  async function handleVaultsGet(_req, res, _params, contextRoot) {
42388
- const vaults = listVaults().map((v) => ({ ...v, exists: existsSync62(resolve14(v.path)) }));
42389
- const current = contextRoot ? vaults.find((v) => resolve14(v.path) === resolve14(dirname28(contextRoot)))?.name ?? null : null;
42727
+ const vaults = listVaults().map((v) => ({ ...v, exists: existsSync64(resolve14(v.path)) }));
42728
+ const current = contextRoot ? vaults.find((v) => resolve14(v.path) === resolve14(dirname30(contextRoot)))?.name ?? null : null;
42390
42729
  sendJson(res, 200, { vaults, current });
42391
42730
  }
42392
42731
  var init_vaults2 = __esm({
@@ -42398,7 +42737,7 @@ var init_vaults2 = __esm({
42398
42737
  });
42399
42738
 
42400
42739
  // src/lib/vault-discovery.ts
42401
- import { dirname as dirname29 } from "path";
42740
+ import { dirname as dirname31 } from "path";
42402
42741
  function discoverVaults(root) {
42403
42742
  const matches = import_fast_glob16.default.sync("**/_dream_context", {
42404
42743
  cwd: root,
@@ -42409,7 +42748,7 @@ function discoverVaults(root) {
42409
42748
  suppressErrors: true
42410
42749
  });
42411
42750
  const projects = /* @__PURE__ */ new Set();
42412
- for (const ctx of matches) projects.add(dirname29(ctx));
42751
+ for (const ctx of matches) projects.add(dirname31(ctx));
42413
42752
  return Array.from(projects).sort();
42414
42753
  }
42415
42754
  async function discoverVaultsAsync(root) {
@@ -42422,7 +42761,7 @@ async function discoverVaultsAsync(root) {
42422
42761
  suppressErrors: true
42423
42762
  });
42424
42763
  const projects = /* @__PURE__ */ new Set();
42425
- for (const ctx of matches) projects.add(dirname29(ctx));
42764
+ for (const ctx of matches) projects.add(dirname31(ctx));
42426
42765
  return Array.from(projects).sort();
42427
42766
  }
42428
42767
  var import_fast_glob16;
@@ -42480,8 +42819,8 @@ var init_ensure_cli = __esm({
42480
42819
  });
42481
42820
 
42482
42821
  // src/server/routes/launcher.ts
42483
- import { basename as basename18, isAbsolute, join as join59, resolve as resolve15, sep as sep9 } from "path";
42484
- import { existsSync as existsSync63, mkdirSync as mkdirSync25, readdirSync as readdirSync15, statSync as statSync10, createReadStream, readFileSync as readFileSync45, writeFileSync as writeFileSync32 } from "fs";
42822
+ import { basename as basename18, isAbsolute, join as join61, resolve as resolve15, sep as sep9 } from "path";
42823
+ import { existsSync as existsSync65, mkdirSync as mkdirSync26, readdirSync as readdirSync16, statSync as statSync10, createReadStream, readFileSync as readFileSync47, writeFileSync as writeFileSync33 } from "fs";
42485
42824
  import { homedir as homedir3 } from "os";
42486
42825
  import { execFile as execFile2, spawn as spawn4 } from "child_process";
42487
42826
  import { promisify as promisify2 } from "util";
@@ -42505,7 +42844,7 @@ async function handleLauncherDiscover(req, res, _params, _contextRoot) {
42505
42844
  return;
42506
42845
  }
42507
42846
  const resolvedRoot = resolve15(root);
42508
- if (!existsSync63(resolvedRoot)) {
42847
+ if (!existsSync65(resolvedRoot)) {
42509
42848
  sendError(res, 400, "invalid_root", `Path does not exist: ${resolvedRoot}`);
42510
42849
  return;
42511
42850
  }
@@ -42548,7 +42887,7 @@ async function handleLauncherRegister(req, res, _params, _contextRoot) {
42548
42887
  }
42549
42888
  function isNonEmptyDir(dir) {
42550
42889
  try {
42551
- return statSync10(dir).isDirectory() && readdirSync15(dir).length > 0;
42890
+ return statSync10(dir).isDirectory() && readdirSync16(dir).length > 0;
42552
42891
  } catch {
42553
42892
  return false;
42554
42893
  }
@@ -42573,30 +42912,30 @@ async function scaffoldProject(a, runner = defaultCliRunner, home) {
42573
42912
  throw new ScaffoldError("parentDir must be an absolute path.");
42574
42913
  }
42575
42914
  const resolvedParent = resolve15(parentDir);
42576
- if (!existsSync63(resolvedParent) || !statSync10(resolvedParent).isDirectory()) {
42915
+ if (!existsSync65(resolvedParent) || !statSync10(resolvedParent).isDirectory()) {
42577
42916
  throw new ScaffoldError(`Parent directory does not exist: ${resolvedParent}`);
42578
42917
  }
42579
42918
  target = resolve15(resolvedParent, name);
42580
- if (target !== join59(resolvedParent, name) || !target.startsWith(resolvedParent + sep9)) {
42919
+ if (target !== join61(resolvedParent, name) || !target.startsWith(resolvedParent + sep9)) {
42581
42920
  throw new ScaffoldError("Resolved project path escapes the parent directory.");
42582
42921
  }
42583
- if (isNonEmptyDir(target) && !existsSync63(join59(target, "_dream_context"))) {
42922
+ if (isNonEmptyDir(target) && !existsSync65(join61(target, "_dream_context"))) {
42584
42923
  throw new ScaffoldError(`A non-empty folder already exists at ${target}.`);
42585
42924
  }
42586
- mkdirSync25(target, { recursive: true });
42925
+ mkdirSync26(target, { recursive: true });
42587
42926
  } else if (a.mode === "existing") {
42588
42927
  const projectPath = (a.projectPath ?? "").trim();
42589
42928
  if (!projectPath || !isAbsolute(projectPath)) {
42590
42929
  throw new ScaffoldError("projectPath must be an absolute path.");
42591
42930
  }
42592
42931
  target = resolve15(projectPath);
42593
- if (!existsSync63(target) || !statSync10(target).isDirectory()) {
42932
+ if (!existsSync65(target) || !statSync10(target).isDirectory()) {
42594
42933
  throw new ScaffoldError(`Folder does not exist: ${target}`);
42595
42934
  }
42596
42935
  } else {
42597
42936
  throw new ScaffoldError("mode must be 'new' or 'existing'.");
42598
42937
  }
42599
- const alreadyProject = existsSync63(join59(target, "_dream_context"));
42938
+ const alreadyProject = existsSync65(join61(target, "_dream_context"));
42600
42939
  if (!alreadyProject) {
42601
42940
  const initArgs = ["init", "--yes", "--platforms", platformArg, "--name", name];
42602
42941
  if (a.description?.trim()) initArgs.push("--description", a.description.trim());
@@ -42651,13 +42990,13 @@ async function handleLauncherDetect(req, res, _params, _contextRoot) {
42651
42990
  return;
42652
42991
  }
42653
42992
  const resolved = resolve15(path2);
42654
- if (!existsSync63(resolved)) {
42993
+ if (!existsSync65(resolved)) {
42655
42994
  sendError(res, 400, "invalid_path", `Path does not exist: ${resolved}`);
42656
42995
  return;
42657
42996
  }
42658
42997
  sendJson(res, 200, {
42659
42998
  stack: detectTechStack(resolved) ?? "",
42660
- hasContext: existsSync63(join59(resolved, "_dream_context")),
42999
+ hasContext: existsSync65(join61(resolved, "_dream_context")),
42661
43000
  name: basename18(resolved)
42662
43001
  });
42663
43002
  }
@@ -42677,15 +43016,15 @@ async function handleLauncherCatalog(_req, res, _params, _contextRoot) {
42677
43016
  sendJson(res, 200, { platforms, packs });
42678
43017
  }
42679
43018
  function sleepyConfigPath() {
42680
- return join59(homedir3(), ".dreamcontext", "sleepy.json");
43019
+ return join61(homedir3(), ".dreamcontext", "sleepy.json");
42681
43020
  }
42682
43021
  async function handleSleepyConfigGet(_req, res, _params, _contextRoot) {
42683
43022
  let enabled = false;
42684
43023
  let hotkey = "Alt+Cmd+S";
42685
43024
  try {
42686
43025
  const p = sleepyConfigPath();
42687
- if (existsSync63(p)) {
42688
- const raw = JSON.parse(readFileSync45(p, "utf-8"));
43026
+ if (existsSync65(p)) {
43027
+ const raw = JSON.parse(readFileSync47(p, "utf-8"));
42689
43028
  enabled = raw.enabled === true;
42690
43029
  if (typeof raw.hotkey === "string" && raw.hotkey.trim()) hotkey = raw.hotkey;
42691
43030
  }
@@ -42703,8 +43042,8 @@ async function handleSleepyConfigSet(req, res, _params, _contextRoot) {
42703
43042
  const hotkey = typeof body.hotkey === "string" && body.hotkey.trim() ? body.hotkey.trim() : "Alt+Cmd+S";
42704
43043
  try {
42705
43044
  const p = sleepyConfigPath();
42706
- mkdirSync25(join59(homedir3(), ".dreamcontext"), { recursive: true });
42707
- writeFileSync32(p, JSON.stringify({ enabled, hotkey }, null, 2) + "\n", "utf-8");
43045
+ mkdirSync26(join61(homedir3(), ".dreamcontext"), { recursive: true });
43046
+ writeFileSync33(p, JSON.stringify({ enabled, hotkey }, null, 2) + "\n", "utf-8");
42708
43047
  sendJson(res, 200, { enabled, hotkey });
42709
43048
  } catch (err) {
42710
43049
  console.error("[launcher] sleepy-config write failed:", err);
@@ -42724,8 +43063,8 @@ async function handleSleepyVideo(req, res, _params, _contextRoot) {
42724
43063
  res.end();
42725
43064
  return;
42726
43065
  }
42727
- const file = join59(dir, `${mode}.mp4`);
42728
- if (!existsSync63(file)) {
43066
+ const file = join61(dir, `${mode}.mp4`);
43067
+ if (!existsSync65(file)) {
42729
43068
  res.writeHead(404);
42730
43069
  res.end();
42731
43070
  return;
@@ -42756,8 +43095,8 @@ async function handleSleepyAnim(req, res, _params, _contextRoot) {
42756
43095
  return;
42757
43096
  }
42758
43097
  const dir = process.env.DREAMCONTEXT_SLEEPY_DIR;
42759
- const file = dir ? join59(dir, `${mode}.webp`) : "";
42760
- if (!file || !existsSync63(file)) {
43098
+ const file = dir ? join61(dir, `${mode}.webp`) : "";
43099
+ if (!file || !existsSync65(file)) {
42761
43100
  res.writeHead(404);
42762
43101
  res.end();
42763
43102
  return;
@@ -42782,8 +43121,9 @@ function buildAskPrompt(question) {
42782
43121
 
42783
43122
  Question: "${question}"`;
42784
43123
  }
42785
- function buildSleepPrompt() {
42786
- return `Think hard. Run a dreamcontext memory consolidation ("sleep") for THIS project now, fully autonomously \u2014 do NOT ask any questions. Follow the project's dreamcontext sleep/consolidation flow: pin the epoch with \`dreamcontext sleep start\`, reconcile the task/changelog/knowledge/feature files to current truth as warranted (prefer updating existing entities over creating new ones), then close the cycle with \`dreamcontext sleep done "<one-paragraph summary>"\` to reset the debt. When finished, reply with a SHORT GitHub-flavored Markdown summary (a few bullets) of what was consolidated. Keep it concise.`;
43124
+ function buildSleepPrompt(depth) {
43125
+ const depthLine = isDestructiveAllowed(depth) ? `This is a DEEP consolidation: you ARE authorized to perform destructive/expensive knowledge ops (merge-with-delete, summarize-and-replace still-valid detail, archive/delete stale files) \u2014 but first copy any file you will merge/replace/delete to \`_dream_context/knowledge/.archive/<slug>-<YYYYMMDD>.md\` (create the dir if absent).` : `This is a ${depth.toUpperCase()} consolidation: do NOT merge, summarize-and-replace, or delete any knowledge. Only create/extend/retag/tick. If you spot merge or deletion candidates, FLAG them in your report instead of acting on them.`;
43126
+ return `Think hard. Run a dreamcontext memory consolidation ("sleep") for THIS project now, fully autonomously \u2014 do NOT ask any questions. Follow the project's dreamcontext sleep/consolidation flow: pin the epoch with \`dreamcontext sleep start\`, reconcile the task/changelog/knowledge/feature files to current truth as warranted (prefer updating existing entities over creating new ones), then close the cycle with \`dreamcontext sleep done "<one-paragraph summary>"\` to reset the debt. ${depthLine} When finished, reply with a SHORT GitHub-flavored Markdown summary (a few bullets) of what was consolidated. Keep it concise.`;
42787
43127
  }
42788
43128
  async function handleLauncherCapture(req, res, _params, _contextRoot) {
42789
43129
  const body = await parseJsonBody(req);
@@ -42808,14 +43148,14 @@ async function handleLauncherCapture(req, res, _params, _contextRoot) {
42808
43148
  return;
42809
43149
  }
42810
43150
  const cwd = resolve15(vault.path);
42811
- if (!existsSync63(cwd)) {
43151
+ if (!existsSync65(cwd)) {
42812
43152
  sendError(res, 400, "missing_vault", `Vault path no longer exists: ${cwd}`);
42813
43153
  return;
42814
43154
  }
42815
43155
  if (mode === "learn") {
42816
43156
  try {
42817
- const changelogPath = join59(cwd, "_dream_context", "core", "CHANGELOG.json");
42818
- if (!existsSync63(changelogPath)) {
43157
+ const changelogPath = join61(cwd, "_dream_context", "core", "CHANGELOG.json");
43158
+ if (!existsSync65(changelogPath)) {
42819
43159
  sendError(res, 400, "not_initialized", `"${vaultName}" has no _dream_context \u2014 run init first.`);
42820
43160
  return;
42821
43161
  }
@@ -42841,7 +43181,18 @@ async function handleLauncherCapture(req, res, _params, _contextRoot) {
42841
43181
  captureRuns.set(captureId, run2);
42842
43182
  try {
42843
43183
  const shell = process.env.SHELL || "/bin/zsh";
42844
- const prompt = mode === "sleep" ? buildSleepPrompt() : mode === "ask" ? buildAskPrompt(text) : buildCapturePrompt(text);
43184
+ let sleepDepth = "deep";
43185
+ if (mode === "sleep") {
43186
+ try {
43187
+ sleepDepth = consolidationDepth(readSleepState(cwd).debt, {
43188
+ userRequestedDeep: true
43189
+ }).depth;
43190
+ } catch (err) {
43191
+ console.error("[launcher] could not read sleep state for depth:", err);
43192
+ sleepDepth = "deep";
43193
+ }
43194
+ }
43195
+ const prompt = mode === "sleep" ? buildSleepPrompt(sleepDepth) : mode === "ask" ? buildAskPrompt(text) : buildCapturePrompt(text);
42845
43196
  const child = spawn4(shell, ["-ilc", 'exec claude --model sonnet -p "$0"', prompt], {
42846
43197
  cwd,
42847
43198
  stdio: ["ignore", "pipe", "pipe"]
@@ -42886,21 +43237,275 @@ async function handleLauncherCaptureStatus(req, res, _params, _contextRoot) {
42886
43237
  }
42887
43238
  async function handleLauncherDefaults(_req, res, _params, _contextRoot) {
42888
43239
  const home = homedir3();
42889
- sendJson(res, 200, { home, defaultParent: join59(home, "projects") });
43240
+ sendJson(res, 200, { home, defaultParent: join61(home, "projects") });
43241
+ }
43242
+ function computeVaultStatus(v, latest) {
43243
+ const exists = existsSync65(resolve15(v.path));
43244
+ let setupVersion = "0.0.0";
43245
+ let shareable = false;
43246
+ if (exists) {
43247
+ try {
43248
+ const cfg = readSetupConfig(resolve15(v.path));
43249
+ if (cfg) {
43250
+ setupVersion = cfg.setupVersion || "0.0.0";
43251
+ shareable = cfg.shareable === true;
43252
+ }
43253
+ } catch {
43254
+ }
43255
+ }
43256
+ const needsUpdate = exists && compareVersions(setupVersion, latest) < 0;
43257
+ return { name: v.name, path: v.path, exists, setupVersion, latestVersion: latest, needsUpdate, shareable };
43258
+ }
43259
+ async function handleLauncherStatus(_req, res, _params, _contextRoot) {
43260
+ const latest = dreamcontextVersion();
43261
+ const vaults = listVaults().map((v) => computeVaultStatus(v, latest));
43262
+ sendJson(res, 200, { vaults, latestVersion: latest });
43263
+ }
43264
+ async function handleLauncherUnregister(req, res, _params, _contextRoot) {
43265
+ const body = await parseJsonBody(req);
43266
+ if (!body) {
43267
+ sendError(res, 400, "invalid_body", "Request body must be valid JSON.");
43268
+ return;
43269
+ }
43270
+ const name = typeof body.name === "string" ? body.name.trim() : "";
43271
+ if (!name) {
43272
+ sendError(res, 400, "invalid_name", "name must be a non-empty string.");
43273
+ return;
43274
+ }
43275
+ const removed = removeVault(name);
43276
+ sendJson(res, 200, { removed, vaults: listVaults() });
43277
+ }
43278
+ async function handleLauncherUpdate(req, res, _params, _contextRoot) {
43279
+ const body = await parseJsonBody(req);
43280
+ if (!body) {
43281
+ sendError(res, 400, "invalid_body", "Request body must be valid JSON.");
43282
+ return;
43283
+ }
43284
+ const name = typeof body.name === "string" ? body.name.trim() : "";
43285
+ if (!name) {
43286
+ sendError(res, 400, "invalid_name", "name must be a non-empty string.");
43287
+ return;
43288
+ }
43289
+ const vault = listVaults().find((v) => v.name === name);
43290
+ if (!vault) {
43291
+ sendError(res, 400, "unknown_vault", `No registered vault named "${name}".`);
43292
+ return;
43293
+ }
43294
+ const target = resolve15(vault.path);
43295
+ if (!existsSync65(target)) {
43296
+ sendError(res, 400, "missing_vault", `Vault path no longer exists: ${target}`);
43297
+ return;
43298
+ }
43299
+ try {
43300
+ await defaultCliRunner(["update"], target);
43301
+ const latest = dreamcontextVersion();
43302
+ sendJson(res, 200, { ok: true, status: computeVaultStatus(vault, latest) });
43303
+ } catch (err) {
43304
+ console.error("[launcher] update failed:", err);
43305
+ const detail = err instanceof Error ? err.message : "unknown error";
43306
+ sendError(res, 500, "update_failed", `Update failed: ${detail}`);
43307
+ }
43308
+ }
43309
+ async function handleLauncherFederationGraph(_req, res, _params, _contextRoot) {
43310
+ const latest = dreamcontextVersion();
43311
+ const vaults = listVaults();
43312
+ const nodes = vaults.map((v) => computeVaultStatus(v, latest));
43313
+ const shareableByName = new Map(nodes.map((n) => [n.name, n.shareable]));
43314
+ const known = new Set(vaults.map((v) => v.name));
43315
+ const edges = [];
43316
+ const connections = [];
43317
+ const seen = /* @__PURE__ */ new Set();
43318
+ for (const v of vaults) {
43319
+ if (!existsSync65(resolve15(v.path))) continue;
43320
+ const conns = listConnections(join61(resolve15(v.path), "_dream_context"));
43321
+ for (const c of conns) {
43322
+ if (!known.has(c.vault)) continue;
43323
+ if (c.status === "stale") continue;
43324
+ connections.push({ from: v.name, to: c.vault, direction: c.direction });
43325
+ if (c.direction !== "out" && c.direction !== "both") continue;
43326
+ const key = `${v.name} ${c.vault}`;
43327
+ if (seen.has(key)) continue;
43328
+ seen.add(key);
43329
+ edges.push({ source: v.name, target: c.vault, active: shareableByName.get(c.vault) === true });
43330
+ }
43331
+ }
43332
+ sendJson(res, 200, { nodes, edges, connections, latestVersion: latest });
43333
+ }
43334
+ async function handleLauncherConnectionCreate(req, res, _params, _contextRoot) {
43335
+ const body = await parseJsonBody(req);
43336
+ if (!body) {
43337
+ sendError(res, 400, "invalid_body", "Request body must be valid JSON.");
43338
+ return;
43339
+ }
43340
+ const from = typeof body.from === "string" ? body.from.trim() : "";
43341
+ const to = typeof body.to === "string" ? body.to.trim() : "";
43342
+ if (!from || !to) {
43343
+ sendError(res, 400, "invalid_body", "from and to must be non-empty strings.");
43344
+ return;
43345
+ }
43346
+ const fromVault = listVaults().find((v) => v.name === from);
43347
+ if (!fromVault) {
43348
+ sendError(res, 400, "unknown_vault", `No registered vault named "${from}".`);
43349
+ return;
43350
+ }
43351
+ const fromRoot = join61(resolve15(fromVault.path), "_dream_context");
43352
+ try {
43353
+ const cur = dirToward(fromRoot, to);
43354
+ addConnection(fromRoot, from, to, addOut(cur?.dir ?? null), cur?.topics ?? null);
43355
+ sendJson(res, 200, { ok: true });
43356
+ } catch (err) {
43357
+ if (err instanceof VaultError) {
43358
+ sendError(res, 400, "invalid_connection", err.message);
43359
+ return;
43360
+ }
43361
+ console.error("[launcher] connection create failed:", err);
43362
+ sendError(res, 500, "connection_failed", "Failed to create connection.");
43363
+ }
42890
43364
  }
42891
- var execFileAsync2, captureRuns, CAPTURE_RUN_TTL_MS, CAPTURE_RUNS_MAX, ScaffoldError, defaultCliRunner, SAFE_NAME_RE, SLEEPY_MODES;
43365
+ async function handleLauncherConnectionRemove(req, res, _params, _contextRoot) {
43366
+ const body = await parseJsonBody(req);
43367
+ if (!body) {
43368
+ sendError(res, 400, "invalid_body", "Request body must be valid JSON.");
43369
+ return;
43370
+ }
43371
+ const from = typeof body.from === "string" ? body.from.trim() : "";
43372
+ const to = typeof body.to === "string" ? body.to.trim() : "";
43373
+ if (!from || !to) {
43374
+ sendError(res, 400, "invalid_body", "from and to must be non-empty strings.");
43375
+ return;
43376
+ }
43377
+ const fromVault = listVaults().find((v) => v.name === from);
43378
+ if (!fromVault) {
43379
+ sendError(res, 400, "unknown_vault", `No registered vault named "${from}".`);
43380
+ return;
43381
+ }
43382
+ const fromRoot = join61(resolve15(fromVault.path), "_dream_context");
43383
+ const a = dirToward(fromRoot, to);
43384
+ if (a) applyDir(fromRoot, from, to, dropOut(a.dir), a.topics);
43385
+ const toRoot = vaultRoot(to);
43386
+ if (toRoot) {
43387
+ const b = dirToward(toRoot, from);
43388
+ if (b) applyDir(toRoot, to, from, dropIn(b.dir), b.topics);
43389
+ }
43390
+ sendJson(res, 200, { ok: true, removed: true });
43391
+ }
43392
+ function dirToward(root, peer) {
43393
+ const c = listConnections(root).find((x) => x.vault === peer);
43394
+ return c ? { dir: c.direction, topics: c.topics } : null;
43395
+ }
43396
+ function vaultRoot(name) {
43397
+ const v = listVaults().find((x) => x.name === name);
43398
+ return v ? join61(resolve15(v.path), "_dream_context") : null;
43399
+ }
43400
+ function applyDir(fromRoot, fromName, peer, next, topics) {
43401
+ if (next === null) removeConnection(fromRoot, peer);
43402
+ else addConnection(fromRoot, fromName, peer, next, topics);
43403
+ }
43404
+ async function handleLauncherSyncCreate(req, res, _params, _contextRoot) {
43405
+ const body = await parseJsonBody(req);
43406
+ if (!body) {
43407
+ sendError(res, 400, "invalid_body", "Request body must be valid JSON.");
43408
+ return;
43409
+ }
43410
+ const from = typeof body.from === "string" ? body.from.trim() : "";
43411
+ const to = typeof body.to === "string" ? body.to.trim() : "";
43412
+ if (!from || !to) {
43413
+ sendError(res, 400, "invalid_body", "from and to must be non-empty strings.");
43414
+ return;
43415
+ }
43416
+ const fromRoot = vaultRoot(from);
43417
+ const toRoot = vaultRoot(to);
43418
+ if (!fromRoot) {
43419
+ sendError(res, 400, "unknown_vault", `No registered vault named "${from}".`);
43420
+ return;
43421
+ }
43422
+ if (!toRoot) {
43423
+ sendError(res, 400, "unknown_vault", `No registered vault named "${to}".`);
43424
+ return;
43425
+ }
43426
+ try {
43427
+ const a = dirToward(fromRoot, to);
43428
+ addConnection(fromRoot, from, to, addOut(a?.dir ?? null), a?.topics ?? null);
43429
+ const b = dirToward(toRoot, from);
43430
+ addConnection(toRoot, to, from, addIn(b?.dir ?? null), b?.topics ?? null);
43431
+ sendJson(res, 200, { ok: true });
43432
+ } catch (err) {
43433
+ if (err instanceof VaultError) {
43434
+ sendError(res, 400, "invalid_connection", err.message);
43435
+ return;
43436
+ }
43437
+ console.error("[launcher] sync create failed:", err);
43438
+ sendError(res, 500, "sync_failed", "Failed to enable sync.");
43439
+ }
43440
+ }
43441
+ async function handleLauncherSyncRemove(req, res, _params, _contextRoot) {
43442
+ const body = await parseJsonBody(req);
43443
+ if (!body) {
43444
+ sendError(res, 400, "invalid_body", "Request body must be valid JSON.");
43445
+ return;
43446
+ }
43447
+ const from = typeof body.from === "string" ? body.from.trim() : "";
43448
+ const to = typeof body.to === "string" ? body.to.trim() : "";
43449
+ if (!from || !to) {
43450
+ sendError(res, 400, "invalid_body", "from and to must be non-empty strings.");
43451
+ return;
43452
+ }
43453
+ const toRoot = vaultRoot(to);
43454
+ if (toRoot) {
43455
+ const b = dirToward(toRoot, from);
43456
+ if (b) applyDir(toRoot, to, from, dropIn(b.dir), b.topics);
43457
+ }
43458
+ sendJson(res, 200, { ok: true });
43459
+ }
43460
+ async function handleLauncherShareable(req, res, _params, _contextRoot) {
43461
+ const body = await parseJsonBody(req);
43462
+ if (!body) {
43463
+ sendError(res, 400, "invalid_body", "Request body must be valid JSON.");
43464
+ return;
43465
+ }
43466
+ const name = typeof body.name === "string" ? body.name.trim() : "";
43467
+ const shareable = body.shareable === true;
43468
+ if (!name) {
43469
+ sendError(res, 400, "invalid_name", "name must be a non-empty string.");
43470
+ return;
43471
+ }
43472
+ const vault = listVaults().find((v) => v.name === name);
43473
+ if (!vault) {
43474
+ sendError(res, 400, "unknown_vault", `No registered vault named "${name}".`);
43475
+ return;
43476
+ }
43477
+ const root = resolve15(vault.path);
43478
+ if (!existsSync65(root)) {
43479
+ sendError(res, 400, "missing_vault", `Vault path no longer exists: ${root}`);
43480
+ return;
43481
+ }
43482
+ try {
43483
+ updateSetupConfig(root, { shareable });
43484
+ sendJson(res, 200, { ok: true, name, shareable });
43485
+ } catch (err) {
43486
+ console.error("[launcher] shareable toggle failed:", err);
43487
+ sendError(res, 500, "shareable_failed", "Failed to update sharing.");
43488
+ }
43489
+ }
43490
+ var execFileAsync2, captureRuns, CAPTURE_RUN_TTL_MS, CAPTURE_RUNS_MAX, ScaffoldError, defaultCliRunner, SAFE_NAME_RE, SLEEPY_MODES, addOut, addIn, dropOut, dropIn;
42892
43491
  var init_launcher = __esm({
42893
43492
  "src/server/routes/launcher.ts"() {
42894
43493
  "use strict";
42895
43494
  init_middleware();
42896
43495
  init_vault_discovery();
42897
43496
  init_vaults();
43497
+ init_connections();
43498
+ init_setup_config();
43499
+ init_manifest();
43500
+ init_version_check();
42898
43501
  init_tech_stack();
42899
43502
  init_ensure_cli();
42900
43503
  init_platforms();
42901
43504
  init_catalog();
42902
43505
  init_json_file();
42903
43506
  init_id();
43507
+ init_sleep();
43508
+ init_sleep_consolidation();
42904
43509
  execFileAsync2 = promisify2(execFile2);
42905
43510
  captureRuns = /* @__PURE__ */ new Map();
42906
43511
  CAPTURE_RUN_TTL_MS = 10 * 60 * 1e3;
@@ -42926,6 +43531,66 @@ var init_launcher = __esm({
42926
43531
  };
42927
43532
  SAFE_NAME_RE = /^[^/\\]+$/;
42928
43533
  SLEEPY_MODES = /* @__PURE__ */ new Set(["idle", "sleepy", "sleeps"]);
43534
+ addOut = (d) => d === "in" || d === "both" ? "both" : "out";
43535
+ addIn = (d) => d === "out" || d === "both" ? "both" : "in";
43536
+ dropOut = (d) => d === "both" ? "in" : d === "in" ? "in" : null;
43537
+ dropIn = (d) => d === "both" ? "out" : d === "out" ? "out" : null;
43538
+ }
43539
+ });
43540
+
43541
+ // src/server/routes/ui-settings.ts
43542
+ import { dirname as dirname32, join as join62 } from "path";
43543
+ import { existsSync as existsSync66, mkdirSync as mkdirSync27, readFileSync as readFileSync48, writeFileSync as writeFileSync34 } from "fs";
43544
+ function settingsPath(contextRoot) {
43545
+ return join62(contextRoot, BRAIN_SETTINGS_REL_PATH);
43546
+ }
43547
+ async function handleBrainSettingsGet(_req, res, _params, contextRoot) {
43548
+ const path2 = settingsPath(contextRoot);
43549
+ if (!existsSync66(path2)) {
43550
+ sendJson(res, 200, { settings: {} });
43551
+ return;
43552
+ }
43553
+ try {
43554
+ const raw = JSON.parse(readFileSync48(path2, "utf-8"));
43555
+ const settings = raw && typeof raw === "object" && !Array.isArray(raw) ? raw : {};
43556
+ sendJson(res, 200, { settings });
43557
+ } catch {
43558
+ sendJson(res, 200, { settings: {} });
43559
+ }
43560
+ }
43561
+ async function handleBrainSettingsPut(req, res, _params, contextRoot) {
43562
+ const body = await parseJsonBody(req);
43563
+ if (!body) {
43564
+ sendError(res, 400, "invalid_body", "Request body must be valid JSON.");
43565
+ return;
43566
+ }
43567
+ const settings = body.settings;
43568
+ if (settings === null || typeof settings !== "object" || Array.isArray(settings)) {
43569
+ sendError(res, 400, "invalid_settings", "settings must be a JSON object.");
43570
+ return;
43571
+ }
43572
+ const serialized = JSON.stringify(settings, null, 2);
43573
+ if (Buffer.byteLength(serialized, "utf-8") > MAX_BYTES) {
43574
+ sendError(res, 400, "too_large", "settings payload is too large.");
43575
+ return;
43576
+ }
43577
+ try {
43578
+ const path2 = settingsPath(contextRoot);
43579
+ mkdirSync27(dirname32(path2), { recursive: true });
43580
+ writeFileSync34(path2, serialized + "\n", "utf-8");
43581
+ sendJson(res, 200, { ok: true });
43582
+ } catch (err) {
43583
+ console.error("[ui-settings] brain-settings write failed:", err);
43584
+ sendError(res, 500, "write_failed", "Failed to persist brain settings.");
43585
+ }
43586
+ }
43587
+ var BRAIN_SETTINGS_REL_PATH, MAX_BYTES;
43588
+ var init_ui_settings = __esm({
43589
+ "src/server/routes/ui-settings.ts"() {
43590
+ "use strict";
43591
+ init_middleware();
43592
+ BRAIN_SETTINGS_REL_PATH = "state/.brain-settings.json";
43593
+ MAX_BYTES = 256 * 1024;
42929
43594
  }
42930
43595
  });
42931
43596
 
@@ -42942,7 +43607,7 @@ var init_federation_config = __esm({
42942
43607
  });
42943
43608
 
42944
43609
  // src/lib/federation-recall.ts
42945
- import { basename as basename19, dirname as dirname30 } from "path";
43610
+ import { basename as basename19, dirname as dirname33 } from "path";
42946
43611
  function namespacedKey(vault, type, slug) {
42947
43612
  return `${vault}::${type}/${slug}`;
42948
43613
  }
@@ -42967,7 +43632,7 @@ function crossVaultRecall(query, opts) {
42967
43632
  }
42968
43633
  const isCurrent = target.current === true;
42969
43634
  if (!isCurrent) {
42970
- const projectRoot = dirname30(contextRoot);
43635
+ const projectRoot = dirname33(contextRoot);
42971
43636
  if (!isShareable(projectRoot)) continue;
42972
43637
  }
42973
43638
  const corpus = buildCorpus(contextRoot, opts.types ? { types: opts.types } : {}).filter((doc) => !isFederated(doc));
@@ -43040,9 +43705,9 @@ var init_federation_recall = __esm({
43040
43705
  });
43041
43706
 
43042
43707
  // src/server/routes/connections.ts
43043
- import { dirname as dirname31 } from "path";
43708
+ import { dirname as dirname34 } from "path";
43044
43709
  function currentVaultName(contextRoot) {
43045
- return currentVaultTarget(dirname31(contextRoot)).name;
43710
+ return currentVaultTarget(dirname34(contextRoot)).name;
43046
43711
  }
43047
43712
  async function handleConnectionsList(_req, res, _params, contextRoot) {
43048
43713
  sendJson(res, 200, { connections: listConnections(contextRoot) });
@@ -43117,8 +43782,8 @@ var init_connections2 = __esm({
43117
43782
  });
43118
43783
 
43119
43784
  // src/lib/federation-digest.ts
43120
- import { existsSync as existsSync64 } from "fs";
43121
- import { join as join60 } from "path";
43785
+ import { existsSync as existsSync67 } from "fs";
43786
+ import { join as join63 } from "path";
43122
43787
  function buildInterestProfile(peerRoot, topics) {
43123
43788
  if (topics && topics.length > 0) {
43124
43789
  const terms2 = Array.from(new Set(tokenize(topics.join(" "))));
@@ -43137,8 +43802,8 @@ function buildInterestProfile(peerRoot, topics) {
43137
43802
  return { terms, query: terms.join(" ") };
43138
43803
  }
43139
43804
  function activeTaskTerms(peerRoot) {
43140
- const stateDir = join60(peerRoot, "state");
43141
- if (!existsSync64(stateDir)) return [];
43805
+ const stateDir = join63(peerRoot, "state");
43806
+ if (!existsSync67(stateDir)) return [];
43142
43807
  let files;
43143
43808
  try {
43144
43809
  files = import_fast_glob17.default.sync("*.md", { cwd: stateDir, absolute: true });
@@ -43239,7 +43904,7 @@ var init_federation_digest = __esm({
43239
43904
  });
43240
43905
 
43241
43906
  // src/server/routes/federation.ts
43242
- import { dirname as dirname32 } from "path";
43907
+ import { dirname as dirname35 } from "path";
43243
43908
  async function handleFederationInboxGet(_req, res, _params, contextRoot) {
43244
43909
  const { entries, quarantined } = drainInbox(contextRoot);
43245
43910
  const pending = entries.map((e) => e.entry);
@@ -43251,7 +43916,7 @@ async function handleFederationInboxGet(_req, res, _params, contextRoot) {
43251
43916
  });
43252
43917
  }
43253
43918
  async function handleFederationSyncPost(_req, res, _params, contextRoot) {
43254
- const senderName = currentVaultTarget(dirname32(contextRoot)).name;
43919
+ const senderName = currentVaultTarget(dirname35(contextRoot)).name;
43255
43920
  const outbound = listConnections(contextRoot).filter(
43256
43921
  (c) => (c.direction === "out" || c.direction === "both") && c.status !== "stale"
43257
43922
  );
@@ -43299,14 +43964,14 @@ var init_federation = __esm({
43299
43964
  });
43300
43965
 
43301
43966
  // src/server/routes/packs.ts
43302
- import { dirname as dirname33 } from "path";
43967
+ import { dirname as dirname36 } from "path";
43303
43968
  async function handlePacksGet(_req, res, _params, contextRoot) {
43304
43969
  const loaded = loadCatalog();
43305
43970
  if (!loaded) {
43306
43971
  sendJson(res, 200, { packs: [], standalone: [] });
43307
43972
  return;
43308
43973
  }
43309
- const projectRoot = dirname33(contextRoot);
43974
+ const projectRoot = dirname36(contextRoot);
43310
43975
  const packs = loaded.catalog.packs.map((p) => ({ ...p, installed: isSkillInstalled(projectRoot, p.name) }));
43311
43976
  const standalone = loaded.catalog.standalone.map((s) => ({ ...s, installed: isSkillInstalled(projectRoot, s.name) }));
43312
43977
  sendJson(res, 200, { packs, standalone });
@@ -43320,7 +43985,7 @@ var init_packs = __esm({
43320
43985
  });
43321
43986
 
43322
43987
  // src/server/routes/packs-install.ts
43323
- import { dirname as dirname34 } from "path";
43988
+ import { dirname as dirname37 } from "path";
43324
43989
  function validatePackName(name, contextRoot) {
43325
43990
  if (name.includes("/") || name.includes("\0") || safeChildPath2("/x", name) === null) {
43326
43991
  return { ok: false, status: 400, code: "invalid_name", message: "Invalid pack name." };
@@ -43333,7 +43998,7 @@ function validatePackName(name, contextRoot) {
43333
43998
  if (!known) {
43334
43999
  return { ok: false, status: 404, code: "unknown_pack", message: `Pack "${name}" not found.` };
43335
44000
  }
43336
- const projectRoot = dirname34(contextRoot);
44001
+ const projectRoot = dirname37(contextRoot);
43337
44002
  const config = readSetupConfig(projectRoot);
43338
44003
  const platforms = normalizePlatforms(config?.platforms ?? []);
43339
44004
  const resolved = platforms.length > 0 ? platforms : [...DEFAULT_PLATFORMS];
@@ -43406,10 +44071,10 @@ var init_packs_install = __esm({
43406
44071
  });
43407
44072
 
43408
44073
  // src/server/routes/version-check.ts
43409
- import { dirname as dirname35 } from "path";
44074
+ import { dirname as dirname38 } from "path";
43410
44075
  async function handleVersionCheckGet(_req, res, _params, contextRoot) {
43411
44076
  try {
43412
- const projectRoot = dirname35(contextRoot);
44077
+ const projectRoot = dirname38(contextRoot);
43413
44078
  const cache = readVersionCache(projectRoot);
43414
44079
  const fresh = isCacheFresh(cache);
43415
44080
  const installedCli = dreamcontextVersion();
@@ -43464,7 +44129,7 @@ var init_taxonomy2 = __esm({
43464
44129
 
43465
44130
  // src/server/index.ts
43466
44131
  import { createServer } from "http";
43467
- import { join as join61, resolve as resolve16 } from "path";
44132
+ import { join as join64, resolve as resolve16 } from "path";
43468
44133
  import { fileURLToPath as fileURLToPath7 } from "url";
43469
44134
  import { exec } from "child_process";
43470
44135
  function buildRouter() {
@@ -43510,6 +44175,15 @@ function buildRouter() {
43510
44175
  router.get("/api/launcher/capture/status", handleLauncherCaptureStatus);
43511
44176
  router.get("/api/launcher/sleepy-config", handleSleepyConfigGet);
43512
44177
  router.post("/api/launcher/sleepy-config", handleSleepyConfigSet);
44178
+ router.get("/api/launcher/status", handleLauncherStatus);
44179
+ router.post("/api/launcher/unregister", handleLauncherUnregister);
44180
+ router.post("/api/launcher/update", handleLauncherUpdate);
44181
+ router.get("/api/launcher/federation-graph", handleLauncherFederationGraph);
44182
+ router.post("/api/launcher/connection", handleLauncherConnectionCreate);
44183
+ router.post("/api/launcher/connection/remove", handleLauncherConnectionRemove);
44184
+ router.post("/api/launcher/sync", handleLauncherSyncCreate);
44185
+ router.post("/api/launcher/sync/remove", handleLauncherSyncRemove);
44186
+ router.post("/api/launcher/shareable", handleLauncherShareable);
43513
44187
  router.get("/api/sleepy/video", handleSleepyVideo);
43514
44188
  router.get("/api/sleepy/anim", handleSleepyAnim);
43515
44189
  router.get("/api/vaults", handleVaultsGet);
@@ -43521,6 +44195,8 @@ function buildRouter() {
43521
44195
  router.get("/api/packs", handlePacksGet);
43522
44196
  router.post("/api/packs/:name/install", handlePackInstall);
43523
44197
  router.delete("/api/packs/:name", handlePackUninstall);
44198
+ router.get("/api/brain-settings", handleBrainSettingsGet);
44199
+ router.put("/api/brain-settings", handleBrainSettingsPut);
43524
44200
  router.get("/api/version-check", handleVersionCheckGet);
43525
44201
  router.get("/api/taxonomy", handleTaxonomyGet);
43526
44202
  router.get("/api/changelog", handleChangelogGet);
@@ -43542,7 +44218,7 @@ function resolveRequestVault(req) {
43542
44218
  if (/[/\\:.\x00]/.test(h)) return "INVALID";
43543
44219
  const v = listVaults().find((x) => x.name === h);
43544
44220
  if (!v) return "INVALID";
43545
- return join61(v.path, "_dream_context");
44221
+ return join64(v.path, "_dream_context");
43546
44222
  }
43547
44223
  function getDashboardDir() {
43548
44224
  const __dirname8 = fileURLToPath7(new URL(".", import.meta.url));
@@ -43642,6 +44318,7 @@ var init_server = __esm({
43642
44318
  init_config();
43643
44319
  init_vaults2();
43644
44320
  init_launcher();
44321
+ init_ui_settings();
43645
44322
  init_connections2();
43646
44323
  init_federation();
43647
44324
  init_packs();
@@ -43833,8 +44510,8 @@ var init_trigger = __esm({
43833
44510
  });
43834
44511
 
43835
44512
  // src/lib/reflection.ts
43836
- import { existsSync as existsSync65, mkdirSync as mkdirSync26, writeFileSync as writeFileSync33 } from "fs";
43837
- import { join as join62, dirname as dirname36 } from "path";
44513
+ import { existsSync as existsSync68, mkdirSync as mkdirSync28, writeFileSync as writeFileSync35 } from "fs";
44514
+ import { join as join65, dirname as dirname39 } from "path";
43838
44515
  function buildExclusionSet(corpus, excludedExtra) {
43839
44516
  const excluded = new Set(excludedExtra);
43840
44517
  for (const doc of corpus) {
@@ -44010,13 +44687,13 @@ function formatReflection(result) {
44010
44687
  return capToBytes(lines, MAX_REFLECTION_BYTES);
44011
44688
  }
44012
44689
  function reflectionPath(root) {
44013
- return join62(root, "state", ".reflection.md");
44690
+ return join65(root, "state", ".reflection.md");
44014
44691
  }
44015
44692
  function writeReflection(root, md) {
44016
44693
  const outPath = reflectionPath(root);
44017
- const dir = dirname36(outPath);
44018
- if (!existsSync65(dir)) {
44019
- mkdirSync26(dir, { recursive: true });
44694
+ const dir = dirname39(outPath);
44695
+ if (!existsSync68(dir)) {
44696
+ mkdirSync28(dir, { recursive: true });
44020
44697
  }
44021
44698
  const tsMatch = md.match(/Generated: ([^\n]+)/);
44022
44699
  const generatedAt = tsMatch ? tsMatch[1].trim() : (/* @__PURE__ */ new Date()).toISOString();
@@ -44027,7 +44704,7 @@ function writeReflection(root, md) {
44027
44704
  "---",
44028
44705
  ""
44029
44706
  ].join("\n");
44030
- writeFileSync33(outPath, frontmatter + md, "utf-8");
44707
+ writeFileSync35(outPath, frontmatter + md, "utf-8");
44031
44708
  return outPath;
44032
44709
  }
44033
44710
  var MAX_REFLECTION_BYTES, DEFAULT_MIN_SESSIONS, DEFAULT_MAX_CANDIDATES, REFLECTION_NOISE;
@@ -44191,14 +44868,14 @@ var init_reflection = __esm({
44191
44868
  });
44192
44869
 
44193
44870
  // src/cli/commands/reflect.ts
44194
- import { existsSync as existsSync66, readFileSync as readFileSync48 } from "fs";
44195
- import { join as join63 } from "path";
44871
+ import { existsSync as existsSync69, readFileSync as readFileSync51 } from "fs";
44872
+ import { join as join66 } from "path";
44196
44873
  function buildBookmarkSessions(root) {
44197
- const sleepPath = join63(root, "state", ".sleep.json");
44874
+ const sleepPath = join66(root, "state", ".sleep.json");
44198
44875
  const result = /* @__PURE__ */ new Map();
44199
- if (!existsSync66(sleepPath)) return result;
44876
+ if (!existsSync69(sleepPath)) return result;
44200
44877
  try {
44201
- const parsed = JSON.parse(readFileSync48(sleepPath, "utf-8"));
44878
+ const parsed = JSON.parse(readFileSync51(sleepPath, "utf-8"));
44202
44879
  const bookmarks = parsed.bookmarks ?? [];
44203
44880
  for (const b of bookmarks) {
44204
44881
  if (b.id && b.session_id) {
@@ -44212,13 +44889,13 @@ function buildBookmarkSessions(root) {
44212
44889
  function buildExcludedExtra(root) {
44213
44890
  const excluded = /* @__PURE__ */ new Set();
44214
44891
  const coreFiles = [
44215
- join63(root, "core", "0.soul.md"),
44216
- join63(root, "core", "1.user.md")
44892
+ join66(root, "core", "0.soul.md"),
44893
+ join66(root, "core", "1.user.md")
44217
44894
  ];
44218
44895
  for (const filePath of coreFiles) {
44219
- if (!existsSync66(filePath)) continue;
44896
+ if (!existsSync69(filePath)) continue;
44220
44897
  try {
44221
- const content = readFileSync48(filePath, "utf-8");
44898
+ const content = readFileSync51(filePath, "utf-8");
44222
44899
  for (const tok of tokenize(content)) {
44223
44900
  excluded.add(tok);
44224
44901
  }
@@ -44269,8 +44946,8 @@ var init_reflect = __esm({
44269
44946
  });
44270
44947
 
44271
44948
  // src/cli/commands/council.ts
44272
- import { existsSync as existsSync67, mkdirSync as mkdirSync27, readFileSync as readFileSync49, writeFileSync as writeFileSync34 } from "fs";
44273
- import { join as join64 } from "path";
44949
+ import { existsSync as existsSync70, mkdirSync as mkdirSync29, readFileSync as readFileSync52, writeFileSync as writeFileSync36 } from "fs";
44950
+ import { join as join67 } from "path";
44274
44951
  function roundRunningStatus(n) {
44275
44952
  return `round_${n}_running`;
44276
44953
  }
@@ -44312,12 +44989,12 @@ function registerCreate(council) {
44312
44989
  }
44313
44990
  const id = generateId("council");
44314
44991
  const dir = getDebateDir(id);
44315
- mkdirSync27(dir, { recursive: true });
44992
+ mkdirSync29(dir, { recursive: true });
44316
44993
  const template = loadTemplate("council-debate.md");
44317
44994
  const content = template.replaceAll("{{ID}}", id).replaceAll("{{TOPIC}}", topic.replace(/"/g, '\\"')).replaceAll("{{ROUNDS}}", String(rounds)).replaceAll("{{INTERRUPT}}", opts.interrupt ? "true" : "false").replaceAll("{{DATE}}", today());
44318
- writeFileSync34(join64(dir, "debate.md"), content, "utf-8");
44319
- writeFileSync34(
44320
- join64(dir, "round-log.md"),
44995
+ writeFileSync36(join67(dir, "debate.md"), content, "utf-8");
44996
+ writeFileSync36(
44997
+ join67(dir, "round-log.md"),
44321
44998
  `# Round log \u2014 ${id}
44322
44999
 
44323
45000
  (Main agent appends timeline entries here.)
@@ -44359,8 +45036,8 @@ function registerAgent(council) {
44359
45036
  process.exit(1);
44360
45037
  }
44361
45038
  const personaDir = getPersonaDir(debateId, slug);
44362
- const personaFile = join64(personaDir, "context-and-persona.md");
44363
- if (existsSync67(personaFile) && !opts.force) {
45039
+ const personaFile = join67(personaDir, "context-and-persona.md");
45040
+ if (existsSync70(personaFile) && !opts.force) {
44364
45041
  error(`Persona already exists: ${slug}`, "Use --force to overwrite.");
44365
45042
  process.exit(1);
44366
45043
  }
@@ -44370,14 +45047,14 @@ function registerAgent(council) {
44370
45047
  process.exit(1);
44371
45048
  }
44372
45049
  const aspects = opts.aspects ? opts.aspects.split(",").map((a) => a.trim()).filter(Boolean) : [];
44373
- mkdirSync27(personaDir, { recursive: true });
45050
+ mkdirSync29(personaDir, { recursive: true });
44374
45051
  const template = loadTemplate("council-persona.md");
44375
45052
  const personaContent = template.replaceAll("{{SLUG}}", slug).replaceAll("{{MODEL}}", opts.model).replaceAll("{{ASPECTS}}", JSON.stringify(aspects)).replaceAll("{{PERSONA_BODY}}", body.trim());
44376
- writeFileSync34(personaFile, personaContent, "utf-8");
45053
+ writeFileSync36(personaFile, personaContent, "utf-8");
44377
45054
  const reportTemplate = loadTemplate("council-report.md");
44378
45055
  const reportContent = reportTemplate.replaceAll("{{SLUG}}", slug);
44379
- writeFileSync34(join64(personaDir, "report.md"), reportContent, "utf-8");
44380
- const debateFile = join64(getDebateDir(debateId), "debate.md");
45056
+ writeFileSync36(join67(personaDir, "report.md"), reportContent, "utf-8");
45057
+ const debateFile = join67(getDebateDir(debateId), "debate.md");
44381
45058
  const { data } = readFrontmatter(debateFile);
44382
45059
  const personas = Array.isArray(data.personas) ? data.personas.slice() : [];
44383
45060
  if (!personas.includes(slug)) personas.push(slug);
@@ -44406,7 +45083,7 @@ function registerRound(council) {
44406
45083
  error(`Round ${n} exceeds planned rounds (${data.rounds_planned}).`);
44407
45084
  process.exit(1);
44408
45085
  }
44409
- const debateFile = join64(getDebateDir(debateId), "debate.md");
45086
+ const debateFile = join67(getDebateDir(debateId), "debate.md");
44410
45087
  const personas = data.personas ?? [];
44411
45088
  if (personas.length === 0) {
44412
45089
  error("No personas registered. Run `council agent create` first.");
@@ -44415,9 +45092,9 @@ function registerRound(council) {
44415
45092
  const crossContextHeader = `## Round ${n} \u2014 Cross-context loaded`;
44416
45093
  if (n >= 2) {
44417
45094
  for (const persona of personas) {
44418
- const personaFile = join64(getPersonaDir(debateId, persona), "context-and-persona.md");
44419
- if (!existsSync67(personaFile)) continue;
44420
- const existing = readFileSync49(personaFile, "utf-8");
45095
+ const personaFile = join67(getPersonaDir(debateId, persona), "context-and-persona.md");
45096
+ if (!existsSync70(personaFile)) continue;
45097
+ const existing = readFileSync52(personaFile, "utf-8");
44421
45098
  if (existing.includes(crossContextHeader)) {
44422
45099
  continue;
44423
45100
  }
@@ -44439,7 +45116,7 @@ _(no round ${n - 1} report submitted)_`);
44439
45116
 
44440
45117
  ${peerLines.join("\n\n")}`;
44441
45118
  const updated = existing.trimEnd() + "\n\n" + newSection + "\n";
44442
- writeFileSync34(personaFile, updated, "utf-8");
45119
+ writeFileSync36(personaFile, updated, "utf-8");
44443
45120
  }
44444
45121
  }
44445
45122
  updateFrontmatterFields(debateFile, {
@@ -44447,13 +45124,13 @@ ${peerLines.join("\n\n")}`;
44447
45124
  current_round: n,
44448
45125
  updated_at: today()
44449
45126
  });
44450
- const logFile = join64(getDebateDir(debateId), "round-log.md");
44451
- const logExisting = existsSync67(logFile) ? readFileSync49(logFile, "utf-8") : "";
45127
+ const logFile = join67(getDebateDir(debateId), "round-log.md");
45128
+ const logExisting = existsSync70(logFile) ? readFileSync52(logFile, "utf-8") : "";
44452
45129
  const logEntry = `
44453
45130
  ## Round ${n} started \u2014 ${today()}
44454
45131
  - Personas: ${formatPersonaList(personas)}
44455
45132
  `;
44456
- writeFileSync34(logFile, logExisting.trimEnd() + "\n" + logEntry + "\n", "utf-8");
45133
+ writeFileSync36(logFile, logExisting.trimEnd() + "\n" + logEntry + "\n", "utf-8");
44457
45134
  upsertCouncilIndex({
44458
45135
  id: debateId,
44459
45136
  topic: data.topic,
@@ -44487,18 +45164,18 @@ ${peerLines.join("\n\n")}`;
44487
45164
  error(`Round ${n} incomplete. Missing reports from: ${missing.join(", ")}`);
44488
45165
  process.exit(1);
44489
45166
  }
44490
- const debateFile = join64(getDebateDir(debateId), "debate.md");
45167
+ const debateFile = join67(getDebateDir(debateId), "debate.md");
44491
45168
  updateFrontmatterFields(debateFile, {
44492
45169
  status: roundCompleteStatus(n),
44493
45170
  updated_at: today()
44494
45171
  });
44495
- const logFile = join64(getDebateDir(debateId), "round-log.md");
44496
- const logExisting = existsSync67(logFile) ? readFileSync49(logFile, "utf-8") : "";
45172
+ const logFile = join67(getDebateDir(debateId), "round-log.md");
45173
+ const logExisting = existsSync70(logFile) ? readFileSync52(logFile, "utf-8") : "";
44497
45174
  const logEntry = `
44498
45175
  ## Round ${n} complete \u2014 ${today()}
44499
45176
  - All ${personas.length} personas submitted reports.
44500
45177
  `;
44501
- writeFileSync34(logFile, logExisting.trimEnd() + "\n" + logEntry + "\n", "utf-8");
45178
+ writeFileSync36(logFile, logExisting.trimEnd() + "\n" + logEntry + "\n", "utf-8");
44502
45179
  upsertCouncilIndex({
44503
45180
  id: debateId,
44504
45181
  topic: data.topic,
@@ -44521,8 +45198,8 @@ function registerRoundContext(council) {
44521
45198
  try {
44522
45199
  const data = readDebateFrontmatter(debateId);
44523
45200
  ensurePersonaExists(debateId, personaSlug);
44524
- const personaFile = join64(getPersonaDir(debateId, personaSlug), "context-and-persona.md");
44525
- const personaContent = readFileSync49(personaFile, "utf-8");
45201
+ const personaFile = join67(getPersonaDir(debateId, personaSlug), "context-and-persona.md");
45202
+ const personaContent = readFileSync52(personaFile, "utf-8");
44526
45203
  console.log(`# Council debate: ${data.topic}`);
44527
45204
  console.log(`Debate ID: ${debateId}`);
44528
45205
  console.log(`Current round: ${data.current_round}/${data.rounds_planned}`);
@@ -44531,8 +45208,8 @@ function registerRoundContext(council) {
44531
45208
  console.log("---");
44532
45209
  console.log("");
44533
45210
  console.log(personaContent);
44534
- const debateFile = join64(getDebateDir(debateId), "debate.md");
44535
- const debateRaw = readFileSync49(debateFile, "utf-8");
45211
+ const debateFile = join67(getDebateDir(debateId), "debate.md");
45212
+ const debateRaw = readFileSync52(debateFile, "utf-8");
44536
45213
  const questionMatch = debateRaw.match(/##\s+Question\s*\n([\s\S]*?)(?=\n##\s|\Z)/);
44537
45214
  const constraintsMatch = debateRaw.match(/##\s+Constraints & Known Facts\s*\n([\s\S]*?)(?=\n##\s|\Z)/);
44538
45215
  if (questionMatch) {
@@ -44575,7 +45252,7 @@ function registerReport(council) {
44575
45252
  process.exit(1);
44576
45253
  }
44577
45254
  for (const w of validation.warnings) warn(w);
44578
- const reportFile = join64(getPersonaDir(debateId, personaSlug), "report.md");
45255
+ const reportFile = join67(getPersonaDir(debateId, personaSlug), "report.md");
44579
45256
  const { data: reportData, content } = readFrontmatter(reportFile);
44580
45257
  const existingRounds = parseReportRounds(content);
44581
45258
  if (existingRounds.find((r) => r.round === round)) {
@@ -44597,7 +45274,7 @@ ${otherSerialized}
44597
45274
  persona: personaSlug,
44598
45275
  rounds_completed: Math.max(reportData.rounds_completed ?? 0, round)
44599
45276
  }, "\n" + merged);
44600
- const personaFile = join64(getPersonaDir(debateId, personaSlug), "context-and-persona.md");
45277
+ const personaFile = join67(getPersonaDir(debateId, personaSlug), "context-and-persona.md");
44601
45278
  const { data: pData } = readFrontmatter(personaFile);
44602
45279
  updateFrontmatterFields(personaFile, {
44603
45280
  round_entries: Math.max(pData.round_entries ?? 0, round)
@@ -44640,13 +45317,13 @@ function registerResearch(council) {
44640
45317
  error("Research topic is required.");
44641
45318
  process.exit(1);
44642
45319
  }
44643
- const researchesDir = join64(getPersonaDir(debateId, personaSlug), "researches");
44644
- mkdirSync27(researchesDir, { recursive: true });
44645
- const indexPath2 = join64(researchesDir, "index.json");
44646
- if (!existsSync67(indexPath2)) writeJsonArray(indexPath2, []);
45320
+ const researchesDir = join67(getPersonaDir(debateId, personaSlug), "researches");
45321
+ mkdirSync29(researchesDir, { recursive: true });
45322
+ const indexPath2 = join67(researchesDir, "index.json");
45323
+ if (!existsSync70(indexPath2)) writeJsonArray(indexPath2, []);
44647
45324
  const slug = slugify(topic);
44648
- const file = join64(researchesDir, `${slug}.md`);
44649
- if (existsSync67(file)) {
45325
+ const file = join67(researchesDir, `${slug}.md`);
45326
+ if (existsSync70(file)) {
44650
45327
  error(`Research note already exists: ${slug}.md`);
44651
45328
  process.exit(1);
44652
45329
  }
@@ -44661,7 +45338,7 @@ _Added ${today()} by ${personaSlug}_
44661
45338
 
44662
45339
  ${body.trim()}
44663
45340
  `;
44664
- writeFileSync34(file, noteContent, "utf-8");
45341
+ writeFileSync36(file, noteContent, "utf-8");
44665
45342
  insertToJsonArray(indexPath2, {
44666
45343
  slug,
44667
45344
  topic,
@@ -44676,9 +45353,9 @@ ${body.trim()}
44676
45353
  research.command("list").argument("<debate_id>").argument("<persona_slug>").description("List this persona's prior research notes.").action((debateId, personaSlug) => {
44677
45354
  try {
44678
45355
  ensurePersonaExists(debateId, personaSlug);
44679
- const researchesDir = join64(getPersonaDir(debateId, personaSlug), "researches");
44680
- const indexPath2 = join64(researchesDir, "index.json");
44681
- if (!existsSync67(indexPath2)) {
45356
+ const researchesDir = join67(getPersonaDir(debateId, personaSlug), "researches");
45357
+ const indexPath2 = join67(researchesDir, "index.json");
45358
+ if (!existsSync70(indexPath2)) {
44682
45359
  console.log(source_default.dim("(no researches)"));
44683
45360
  return;
44684
45361
  }
@@ -44700,7 +45377,7 @@ function registerSynthesize(council) {
44700
45377
  council.command("synthesize").argument("<debate_id>").description("Mark status=synthesizing; print manifest of files synthesizer should read.").action((debateId) => {
44701
45378
  try {
44702
45379
  const data = readDebateFrontmatter(debateId);
44703
- const debateFile = join64(getDebateDir(debateId), "debate.md");
45380
+ const debateFile = join67(getDebateDir(debateId), "debate.md");
44704
45381
  updateFrontmatterFields(debateFile, {
44705
45382
  status: "synthesizing",
44706
45383
  updated_at: today()
@@ -44722,8 +45399,8 @@ function registerSynthesize(council) {
44722
45399
  const personaDir = getPersonaDir(debateId, persona);
44723
45400
  manifest.push(`_dream_context/council/${debateId}/${persona}/context-and-persona.md`);
44724
45401
  manifest.push(`_dream_context/council/${debateId}/${persona}/report.md`);
44725
- const researchesIndex = join64(personaDir, "researches", "index.json");
44726
- if (existsSync67(researchesIndex)) {
45402
+ const researchesIndex = join67(personaDir, "researches", "index.json");
45403
+ if (existsSync70(researchesIndex)) {
44727
45404
  manifest.push(`_dream_context/council/${debateId}/${persona}/researches/`);
44728
45405
  }
44729
45406
  }
@@ -44741,12 +45418,12 @@ function registerComplete(council) {
44741
45418
  council.command("complete").argument("<debate_id>").description("Mark status=complete after final-report.md is written.").action((debateId) => {
44742
45419
  try {
44743
45420
  const data = readDebateFrontmatter(debateId);
44744
- const finalReport = join64(getDebateDir(debateId), "final-report.md");
44745
- if (!existsSync67(finalReport)) {
45421
+ const finalReport = join67(getDebateDir(debateId), "final-report.md");
45422
+ if (!existsSync70(finalReport)) {
44746
45423
  error("final-report.md not found.", "Synthesizer must write it before calling `council complete`.");
44747
45424
  process.exit(1);
44748
45425
  }
44749
- const debateFile = join64(getDebateDir(debateId), "debate.md");
45426
+ const debateFile = join67(getDebateDir(debateId), "debate.md");
44750
45427
  updateFrontmatterFields(debateFile, {
44751
45428
  status: "complete",
44752
45429
  updated_at: today()
@@ -44778,8 +45455,8 @@ function registerPromote(council) {
44778
45455
  error(`Cannot promote: debate status is "${data.status}", expected "complete".`);
44779
45456
  process.exit(1);
44780
45457
  }
44781
- const finalReport = join64(getDebateDir(debateId), "final-report.md");
44782
- if (!existsSync67(finalReport)) {
45458
+ const finalReport = join67(getDebateDir(debateId), "final-report.md");
45459
+ if (!existsSync70(finalReport)) {
44783
45460
  error("final-report.md not found.");
44784
45461
  process.exit(1);
44785
45462
  }
@@ -44792,12 +45469,12 @@ function registerPromote(council) {
44792
45469
 
44793
45470
  ${sec.body.trim()}` : null;
44794
45471
  }).filter(Boolean).join("\n\n");
44795
- const knowledgeDir = join64(root, "knowledge");
44796
- mkdirSync27(knowledgeDir, { recursive: true });
45472
+ const knowledgeDir = join67(root, "knowledge");
45473
+ mkdirSync29(knowledgeDir, { recursive: true });
44797
45474
  const slug = slugify(data.topic).slice(0, 80) || debateId;
44798
45475
  const filename = `decision-${slug}.md`;
44799
- const target = join64(knowledgeDir, filename);
44800
- if (existsSync67(target) && !opts.force) {
45476
+ const target = join67(knowledgeDir, filename);
45477
+ if (existsSync70(target) && !opts.force) {
44801
45478
  error(`Knowledge file exists: ${filename}`, "Use --force to overwrite.");
44802
45479
  process.exit(1);
44803
45480
  }
@@ -44821,7 +45498,7 @@ ${kept}
44821
45498
  _Promoted from council debate \`${debateId}\` on ${today()}. See \`_dream_context/council/${debateId}/final-report.md\` for the full record._
44822
45499
  `;
44823
45500
  writeFrontmatter(target, knowledgeFrontmatter, body);
44824
- updateFrontmatterFields(join64(getDebateDir(debateId), "debate.md"), {
45501
+ updateFrontmatterFields(join67(getDebateDir(debateId), "debate.md"), {
44825
45502
  promoted_to_knowledge: `knowledge/${filename}`,
44826
45503
  updated_at: today()
44827
45504
  });
@@ -44883,10 +45560,10 @@ function registerShow(council) {
44883
45560
  console.log(` promoted: ${data.promoted_to_knowledge ?? source_default.dim("(no)")}`);
44884
45561
  console.log(` created: ${data.created_at}`);
44885
45562
  console.log(` updated: ${data.updated_at}`);
44886
- const logFile = join64(getDebateDir(debateId), "round-log.md");
44887
- if (existsSync67(logFile)) {
45563
+ const logFile = join67(getDebateDir(debateId), "round-log.md");
45564
+ if (existsSync70(logFile)) {
44888
45565
  console.log("\n" + source_default.dim("\u2500\u2500\u2500 Round log \u2500\u2500\u2500"));
44889
- console.log(readFileSync49(logFile, "utf-8"));
45566
+ console.log(readFileSync52(logFile, "utf-8"));
44890
45567
  }
44891
45568
  } catch (err) {
44892
45569
  error(err.message);
@@ -45078,12 +45755,12 @@ var init_env_loader = __esm({
45078
45755
  });
45079
45756
 
45080
45757
  // src/lib/marketing/config.ts
45081
- import { existsSync as existsSync68, readFileSync as readFileSync50, writeFileSync as writeFileSync35, mkdirSync as mkdirSync28 } from "fs";
45082
- import { dirname as dirname37 } from "path";
45758
+ import { existsSync as existsSync71, readFileSync as readFileSync53, writeFileSync as writeFileSync37, mkdirSync as mkdirSync30 } from "fs";
45759
+ import { dirname as dirname40 } from "path";
45083
45760
  function readEnvFile() {
45084
45761
  const path2 = MARKETING_PATHS.envFile();
45085
- if (!existsSync68(path2)) return {};
45086
- const raw = readFileSync50(path2, "utf8");
45762
+ if (!existsSync71(path2)) return {};
45763
+ const raw = readFileSync53(path2, "utf8");
45087
45764
  const parsed = parseEnv(raw);
45088
45765
  if (parsed.errors.length > 0) {
45089
45766
  for (const e of parsed.errors) {
@@ -45127,9 +45804,9 @@ function requireEnv(keys = REQUIRED_KEYS) {
45127
45804
  }
45128
45805
  function loadConfig() {
45129
45806
  const path2 = MARKETING_PATHS.configFile();
45130
- if (!existsSync68(path2)) return { ...EMPTY_CONFIG, feature_flags: { ...EMPTY_CONFIG.feature_flags } };
45807
+ if (!existsSync71(path2)) return { ...EMPTY_CONFIG, feature_flags: { ...EMPTY_CONFIG.feature_flags } };
45131
45808
  try {
45132
- const raw = readFileSync50(path2, "utf8");
45809
+ const raw = readFileSync53(path2, "utf8");
45133
45810
  const parsed = JSON.parse(raw);
45134
45811
  return {
45135
45812
  default_profile: parsed.default_profile ?? null,
@@ -45144,21 +45821,21 @@ function loadConfig() {
45144
45821
  }
45145
45822
  function writeConfig(cfg) {
45146
45823
  const path2 = MARKETING_PATHS.configFile();
45147
- mkdirSync28(dirname37(path2), { recursive: true });
45148
- writeFileSync35(path2, JSON.stringify(cfg, null, 2) + "\n", "utf8");
45824
+ mkdirSync30(dirname40(path2), { recursive: true });
45825
+ writeFileSync37(path2, JSON.stringify(cfg, null, 2) + "\n", "utf8");
45149
45826
  }
45150
45827
  function ensureConfigFile() {
45151
45828
  const path2 = MARKETING_PATHS.configFile();
45152
- if (existsSync68(path2)) return loadConfig();
45829
+ if (existsSync71(path2)) return loadConfig();
45153
45830
  const cfg = { ...EMPTY_CONFIG, feature_flags: { ...EMPTY_CONFIG.feature_flags } };
45154
45831
  writeConfig(cfg);
45155
45832
  return cfg;
45156
45833
  }
45157
45834
  function ensureEnvFile() {
45158
45835
  const path2 = MARKETING_PATHS.envFile();
45159
- if (existsSync68(path2)) return;
45160
- mkdirSync28(marketingRoot(), { recursive: true });
45161
- writeFileSync35(path2, ENV_TEMPLATE, { encoding: "utf8", mode: 384 });
45836
+ if (existsSync71(path2)) return;
45837
+ mkdirSync30(marketingRoot(), { recursive: true });
45838
+ writeFileSync37(path2, ENV_TEMPLATE, { encoding: "utf8", mode: 384 });
45162
45839
  }
45163
45840
  var DEFAULT_API_VERSION, EMPTY_CONFIG, REQUIRED_KEYS, OPTIONAL_KEYS, ENV_TEMPLATE;
45164
45841
  var init_config2 = __esm({
@@ -45199,9 +45876,9 @@ REINFLUENCE_BIN= # optional override; default uses .venv
45199
45876
 
45200
45877
  // src/lib/marketing/bootstrap.ts
45201
45878
  import { spawn as spawn5, spawnSync as spawnSync2 } from "child_process";
45202
- import { existsSync as existsSync69, mkdirSync as mkdirSync29, cpSync as cpSync3 } from "fs";
45879
+ import { existsSync as existsSync72, mkdirSync as mkdirSync31, cpSync as cpSync3 } from "fs";
45203
45880
  import { fileURLToPath as fileURLToPath8 } from "url";
45204
- import { dirname as dirname38, resolve as resolve17, join as join65 } from "path";
45881
+ import { dirname as dirname41, resolve as resolve17, join as join68 } from "path";
45205
45882
  function findBundledReinfluence() {
45206
45883
  const candidates = [
45207
45884
  // Installed npm package: dist/<chunk>.js -> ../tools/reinfluence
@@ -45211,7 +45888,7 @@ function findBundledReinfluence() {
45211
45888
  resolve17(__dirname7, "..", "..", "..", "tools", "reinfluence")
45212
45889
  ];
45213
45890
  for (const c of candidates) {
45214
- if (existsSync69(join65(c, "__main__.py"))) return c;
45891
+ if (existsSync72(join68(c, "__main__.py"))) return c;
45215
45892
  }
45216
45893
  throw new Error(
45217
45894
  "Bundled reinfluence not found. Reinstall dreamcontext or set REINFLUENCE_BIN."
@@ -45242,18 +45919,18 @@ async function bootstrapMarketing(opts = {}) {
45242
45919
  if (verbose) process.stderr.write(`[mk init] ${msg}
45243
45920
  `);
45244
45921
  };
45245
- mkdirSync29(marketingRoot(), { recursive: true });
45922
+ mkdirSync31(marketingRoot(), { recursive: true });
45246
45923
  const bundled = findBundledReinfluence();
45247
45924
  const target = MARKETING_PATHS.reinfluenceDir();
45248
45925
  log(`copying tools \u2192 ${target}`);
45249
- mkdirSync29(MARKETING_PATHS.toolsDir(), { recursive: true });
45926
+ mkdirSync31(MARKETING_PATHS.toolsDir(), { recursive: true });
45250
45927
  cpSync3(bundled, target, { recursive: true });
45251
45928
  const py = findPython3();
45252
45929
  if (!py) {
45253
45930
  throw new Error("python3 not found on PATH. Install Python 3.10+ and retry.");
45254
45931
  }
45255
45932
  const venv = MARKETING_PATHS.venvDir();
45256
- if (!existsSync69(MARKETING_PATHS.venvPython())) {
45933
+ if (!existsSync72(MARKETING_PATHS.venvPython())) {
45257
45934
  log(`creating venv \u2192 ${venv}`);
45258
45935
  const r2 = runBlocking(py, ["-m", "venv", venv]);
45259
45936
  if (r2.code !== 0) {
@@ -45266,7 +45943,7 @@ async function bootstrapMarketing(opts = {}) {
45266
45943
  log("upgrading pip");
45267
45944
  let r = runBlocking(venvPy, ["-m", "pip", "install", "--upgrade", "pip", "--quiet"]);
45268
45945
  if (r.code !== 0) log(`pip upgrade warning: ${r.stderr.trim().slice(0, 200)}`);
45269
- const reqs = join65(target, "requirements.txt");
45946
+ const reqs = join68(target, "requirements.txt");
45270
45947
  log("installing python deps (whisper / yt-dlp / instaloader) \u2014 first run can take several minutes");
45271
45948
  r = runBlocking(venvPy, ["-m", "pip", "install", "-r", reqs, "--quiet"]);
45272
45949
  if (r.code !== 0) {
@@ -45276,7 +45953,7 @@ ${r.stderr.trim() || r.stdout.trim()}`);
45276
45953
  let whisperPrimed = false;
45277
45954
  if (whisperModel) {
45278
45955
  log(`pre-pulling whisper model "${whisperModel}" into ${MARKETING_PATHS.whisperCacheDir()}`);
45279
- mkdirSync29(MARKETING_PATHS.whisperCacheDir(), { recursive: true });
45956
+ mkdirSync31(MARKETING_PATHS.whisperCacheDir(), { recursive: true });
45280
45957
  whisperPrimed = await primeWhisper(whisperModel);
45281
45958
  if (!whisperPrimed) log("whisper pre-pull failed (will retry on first ingest)");
45282
45959
  }
@@ -45316,15 +45993,15 @@ function subprocessEnv() {
45316
45993
  return {
45317
45994
  ...process.env,
45318
45995
  XDG_CACHE_HOME: cache,
45319
- HF_HOME: join65(cache, "hf"),
45320
- TRANSFORMERS_CACHE: join65(cache, "hf", "transformers"),
45996
+ HF_HOME: join68(cache, "hf"),
45997
+ TRANSFORMERS_CACHE: join68(cache, "hf", "transformers"),
45321
45998
  WHISPER_CACHE_DIR: MARKETING_PATHS.whisperCacheDir(),
45322
45999
  PYTHONUNBUFFERED: "1",
45323
46000
  PYTHONPATH: MARKETING_PATHS.toolsDir()
45324
46001
  };
45325
46002
  }
45326
46003
  function isBootstrapped() {
45327
- return existsSync69(MARKETING_PATHS.venvPython()) && existsSync69(join65(MARKETING_PATHS.reinfluenceDir(), "__main__.py"));
46004
+ return existsSync72(MARKETING_PATHS.venvPython()) && existsSync72(join68(MARKETING_PATHS.reinfluenceDir(), "__main__.py"));
45328
46005
  }
45329
46006
  var __filename, __dirname7;
45330
46007
  var init_bootstrap = __esm({
@@ -45332,12 +46009,12 @@ var init_bootstrap = __esm({
45332
46009
  "use strict";
45333
46010
  init_paths2();
45334
46011
  __filename = fileURLToPath8(import.meta.url);
45335
- __dirname7 = dirname38(__filename);
46012
+ __dirname7 = dirname41(__filename);
45336
46013
  }
45337
46014
  });
45338
46015
 
45339
46016
  // src/cli/commands/marketing/init.ts
45340
- import { mkdirSync as mkdirSync30 } from "fs";
46017
+ import { mkdirSync as mkdirSync32 } from "fs";
45341
46018
  function registerMarketingInit(parent) {
45342
46019
  parent.command("init").description("Bootstrap _dream_context/marketing/ (folders, .env, venv, reinfluence tools, whisper cache)").option("--skip-bootstrap", "Only create folders + .env template; skip venv + pip install", false).option("--whisper-model <model>", "Whisper model to pre-pull (default: medium)", "medium").option("--no-whisper", "Skip Whisper model pre-pull").action(async (opts) => {
45343
46020
  try {
@@ -45348,7 +46025,7 @@ function registerMarketingInit(parent) {
45348
46025
  }
45349
46026
  console.log(header("Marketing init"));
45350
46027
  const root = marketingRoot();
45351
- mkdirSync30(root, { recursive: true });
46028
+ mkdirSync32(root, { recursive: true });
45352
46029
  for (const dir of [
45353
46030
  MARKETING_PATHS.cohortsDir(),
45354
46031
  MARKETING_PATHS.campaignsDir(),
@@ -45361,7 +46038,7 @@ function registerMarketingInit(parent) {
45361
46038
  MARKETING_PATHS.byIdemDir(),
45362
46039
  MARKETING_PATHS.cacheDir()
45363
46040
  ]) {
45364
- mkdirSync30(dir, { recursive: true });
46041
+ mkdirSync32(dir, { recursive: true });
45365
46042
  }
45366
46043
  info(`folders ready under ${source_default.dim(root)}`);
45367
46044
  ensureEnvFile();
@@ -45401,8 +46078,8 @@ var init_init2 = __esm({
45401
46078
  });
45402
46079
 
45403
46080
  // src/lib/marketing/vision.ts
45404
- import { existsSync as existsSync70, readFileSync as readFileSync51, writeFileSync as writeFileSync36 } from "fs";
45405
- import { dirname as dirname39, join as join66 } from "path";
46081
+ import { existsSync as existsSync73, readFileSync as readFileSync54, writeFileSync as writeFileSync38 } from "fs";
46082
+ import { dirname as dirname42, join as join69 } from "path";
45406
46083
  function pickVisionProvider(env2 = process.env) {
45407
46084
  const oai = env2.OPENAI_VISION_API_KEY;
45408
46085
  if (oai && oai.trim().length > 0) return { provider: "openai", apiKey: oai.trim() };
@@ -45441,11 +46118,11 @@ function parseLabelsFromText(text, allowlist = LABEL_ALLOWLIST) {
45441
46118
  return out;
45442
46119
  }
45443
46120
  async function readImageAsBase64(framePath) {
45444
- const buf = readFileSync51(framePath);
46121
+ const buf = readFileSync54(framePath);
45445
46122
  return buf.toString("base64");
45446
46123
  }
45447
46124
  async function labelHookFrame(framePath, opts) {
45448
- if (!existsSync70(framePath)) return [];
46125
+ if (!existsSync73(framePath)) return [];
45449
46126
  const fetcher = opts.fetcher ?? defaultFetcher;
45450
46127
  const prompt = opts.promptOverride ?? PROMPT;
45451
46128
  const b64 = await readImageAsBase64(framePath);
@@ -45495,7 +46172,7 @@ async function labelHookFrame(framePath, opts) {
45495
46172
  return parseLabelsFromText(text);
45496
46173
  }
45497
46174
  async function runVisionPassOnPost(postJsonPath, opts = {}) {
45498
- const raw = readFileSync51(postJsonPath, "utf-8");
46175
+ const raw = readFileSync54(postJsonPath, "utf-8");
45499
46176
  const post = JSON.parse(raw);
45500
46177
  const shortcode = post.shortcode ?? "?";
45501
46178
  const provider = opts.provider && opts.apiKey ? { provider: opts.provider, apiKey: opts.apiKey } : pickVisionProvider();
@@ -45534,15 +46211,15 @@ async function runVisionPassOnPost(postJsonPath, opts = {}) {
45534
46211
  post.pattern_tags = [...aggregated].sort();
45535
46212
  post.vision_summary = post.pattern_tags.length > 0 ? `Vision-tagged ${framesLabeled}/${hookFrames.length} hook frames; patterns: ${post.pattern_tags.join(", ")}.` : `Vision pass found no allowlisted patterns across ${hookFrames.length} hook frames.`;
45536
46213
  const tmp = postJsonPath + ".tmp";
45537
- writeFileSync36(tmp, JSON.stringify(post, null, 2) + "\n", "utf-8");
46214
+ writeFileSync38(tmp, JSON.stringify(post, null, 2) + "\n", "utf-8");
45538
46215
  const fs = await import("fs");
45539
46216
  fs.renameSync(tmp, postJsonPath);
45540
- const mdPath = join66(dirname39(postJsonPath), `${shortcode}.md`);
45541
- if (existsSync70(mdPath)) {
46217
+ const mdPath = join69(dirname42(postJsonPath), `${shortcode}.md`);
46218
+ if (existsSync73(mdPath)) {
45542
46219
  try {
45543
- const md = readFileSync51(mdPath, "utf-8");
46220
+ const md = readFileSync54(mdPath, "utf-8");
45544
46221
  const refreshed = updatePatternTagsInBridge(md, post.pattern_tags);
45545
- writeFileSync36(mdPath, refreshed, "utf-8");
46222
+ writeFileSync38(mdPath, refreshed, "utf-8");
45546
46223
  } catch {
45547
46224
  }
45548
46225
  }
@@ -45617,8 +46294,8 @@ Example output: ["talking-head","prop-driven"]`;
45617
46294
  // src/lib/marketing/competitors.ts
45618
46295
  import { spawn as spawn6 } from "child_process";
45619
46296
  import { spawnSync as spawnSync3 } from "child_process";
45620
- import { existsSync as existsSync71, mkdirSync as mkdirSync31, statfsSync } from "fs";
45621
- import { dirname as dirname40, join as join67, basename as basename20, extname as extname4 } from "path";
46297
+ import { existsSync as existsSync74, mkdirSync as mkdirSync33, statfsSync } from "fs";
46298
+ import { dirname as dirname43, join as join70, basename as basename20, extname as extname4 } from "path";
45622
46299
  function which(cmd) {
45623
46300
  const r = spawnSync3(process.platform === "win32" ? "where" : "which", [cmd], { encoding: "utf8" });
45624
46301
  if (r.status === 0) return (r.stdout || "").trim().split("\n")[0] || null;
@@ -45695,8 +46372,8 @@ ${h.installHints.join("\n")}`);
45695
46372
  skip_transcripts: !!opts.skipTranscripts,
45696
46373
  skip_frames: !!opts.skipFrames
45697
46374
  });
45698
- const outDir = join67(MARKETING_PATHS.competitorsDir(), "_ingest-tmp", run2.id);
45699
- mkdirSync31(outDir, { recursive: true });
46375
+ const outDir = join70(MARKETING_PATHS.competitorsDir(), "_ingest-tmp", run2.id);
46376
+ mkdirSync33(outDir, { recursive: true });
45700
46377
  const args = [
45701
46378
  "-m",
45702
46379
  "reinfluence",
@@ -45796,15 +46473,15 @@ stderr: ${stderrBuf.slice(0, 1e3)}`));
45796
46473
  return { runId: run2.id, postsIngested, warnings, errors };
45797
46474
  }
45798
46475
  function persistPost(evt) {
45799
- const handleDir = join67(MARKETING_PATHS.competitorsDir(), evt.handle);
45800
- const postsDir = join67(handleDir, "posts");
45801
- const mediaDir = join67(handleDir, "_media", evt.shortcode);
45802
- mkdirSync31(postsDir, { recursive: true });
45803
- mkdirSync31(mediaDir, { recursive: true });
45804
- const finalVideoPath = evt.video_path ? moveAsset(evt.video_path, join67(mediaDir, basename20(evt.video_path))) : null;
46476
+ const handleDir = join70(MARKETING_PATHS.competitorsDir(), evt.handle);
46477
+ const postsDir = join70(handleDir, "posts");
46478
+ const mediaDir = join70(handleDir, "_media", evt.shortcode);
46479
+ mkdirSync33(postsDir, { recursive: true });
46480
+ mkdirSync33(mediaDir, { recursive: true });
46481
+ const finalVideoPath = evt.video_path ? moveAsset(evt.video_path, join70(mediaDir, basename20(evt.video_path))) : null;
45805
46482
  const finalFramePaths = [];
45806
46483
  for (const fr of evt.frames) {
45807
- const finalP = moveAsset(fr.path, join67(mediaDir, "frames", basename20(fr.path)));
46484
+ const finalP = moveAsset(fr.path, join70(mediaDir, "frames", basename20(fr.path)));
45808
46485
  finalFramePaths.push(finalP);
45809
46486
  }
45810
46487
  const id = `${evt.handle}__${evt.shortcode}`;
@@ -45824,14 +46501,14 @@ function persistPost(evt) {
45824
46501
  ingested_at: (/* @__PURE__ */ new Date()).toISOString(),
45825
46502
  asset_paths: { video: finalVideoPath, frames: finalFramePaths }
45826
46503
  };
45827
- const jsonPath = join67(postsDir, `${evt.shortcode}.json`);
45828
- const bridgePath = join67(postsDir, `${evt.shortcode}.md`);
46504
+ const jsonPath = join70(postsDir, `${evt.shortcode}.json`);
46505
+ const bridgePath = join70(postsDir, `${evt.shortcode}.md`);
45829
46506
  writeJsonWithBridge(jsonPath, bridgePath, json, renderPostBridge(json));
45830
- const metaPath = join67(handleDir, "meta.json");
45831
- if (!existsSync71(metaPath)) {
46507
+ const metaPath = join70(handleDir, "meta.json");
46508
+ if (!existsSync74(metaPath)) {
45832
46509
  writeJsonWithBridge(
45833
46510
  metaPath,
45834
- join67(handleDir, "meta.md"),
46511
+ join70(handleDir, "meta.md"),
45835
46512
  { handle: evt.handle, first_seen_at: (/* @__PURE__ */ new Date()).toISOString() },
45836
46513
  `---
45837
46514
  id: competitor_${evt.handle}
@@ -45848,8 +46525,8 @@ First seen: ${(/* @__PURE__ */ new Date()).toISOString()}
45848
46525
  return jsonPath;
45849
46526
  }
45850
46527
  function moveAsset(src, dest) {
45851
- if (!existsSync71(src)) return dest;
45852
- mkdirSync31(dirname40(dest), { recursive: true });
46528
+ if (!existsSync74(src)) return dest;
46529
+ mkdirSync33(dirname43(dest), { recursive: true });
45853
46530
  const fs = __require("fs");
45854
46531
  try {
45855
46532
  fs.renameSync(src, dest);
@@ -45910,8 +46587,8 @@ var init_competitors = __esm({
45910
46587
  });
45911
46588
 
45912
46589
  // src/cli/commands/marketing/competitor.ts
45913
- import { existsSync as existsSync72, readdirSync as readdirSync16, statSync as statSync11 } from "fs";
45914
- import { join as join68 } from "path";
46590
+ import { existsSync as existsSync75, readdirSync as readdirSync17, statSync as statSync11 } from "fs";
46591
+ import { join as join71 } from "path";
45915
46592
  function registerMarketingCompetitor(parent) {
45916
46593
  const cmd = parent.command("competitor").description("Ingest competitor IG / YouTube content (Reinfluence pipeline).");
45917
46594
  cmd.command("ingest <target>").description("Ingest a single URL or an IG handle. Outputs land under _dream_context/marketing/competitors/<handle>/.").option("--model <name>", "Whisper model size (tiny|base|small|medium|large)", "medium").option("--max <n>", "Max reels for IG handle ingest (0 = all)", "0").option("--skip-transcripts", "Skip Whisper transcription", false).option("--skip-frames", "Skip frame extraction", false).option("--timeout <seconds>", "Wall-clock kill", "600").action(async (target, opts) => {
@@ -45961,13 +46638,13 @@ function registerMarketingCompetitor(parent) {
45961
46638
  });
45962
46639
  cmd.command("list").description("List ingested competitor handles.").action(() => {
45963
46640
  const dir = MARKETING_PATHS.competitorsDir();
45964
- if (!existsSync72(dir)) {
46641
+ if (!existsSync75(dir)) {
45965
46642
  info("No competitors ingested yet.");
45966
46643
  return;
45967
46644
  }
45968
- const handles = readdirSync16(dir).filter((name) => {
46645
+ const handles = readdirSync17(dir).filter((name) => {
45969
46646
  if (name.startsWith("_") || name.startsWith(".")) return false;
45970
- const full = join68(dir, name);
46647
+ const full = join71(dir, name);
45971
46648
  try {
45972
46649
  return statSync11(full).isDirectory();
45973
46650
  } catch {
@@ -45980,8 +46657,8 @@ function registerMarketingCompetitor(parent) {
45980
46657
  }
45981
46658
  console.log(header("Competitors"));
45982
46659
  for (const handle of handles) {
45983
- const postsDir = join68(dir, handle, "posts");
45984
- const postCount = existsSync72(postsDir) ? readdirSync16(postsDir).filter((f) => f.endsWith(".json")).length : 0;
46660
+ const postsDir = join71(dir, handle, "posts");
46661
+ const postCount = existsSync75(postsDir) ? readdirSync17(postsDir).filter((f) => f.endsWith(".json")).length : 0;
45985
46662
  console.log(` ${source_default.cyan("@" + handle)} ${source_default.dim(`${postCount} post(s)`)}`);
45986
46663
  }
45987
46664
  });
@@ -45994,11 +46671,11 @@ function registerMarketingCompetitor(parent) {
45994
46671
  }
45995
46672
  info(`Provider: ${provider.provider}`);
45996
46673
  const competitorsDir = MARKETING_PATHS.competitorsDir();
45997
- const handles = opts.handle ? [opts.handle] : existsSync72(competitorsDir) ? readdirSync16(competitorsDir).filter((h) => !h.startsWith("_") && statSync11(join68(competitorsDir, h)).isDirectory()) : [];
46674
+ const handles = opts.handle ? [opts.handle] : existsSync75(competitorsDir) ? readdirSync17(competitorsDir).filter((h) => !h.startsWith("_") && statSync11(join71(competitorsDir, h)).isDirectory()) : [];
45998
46675
  const matches = [];
45999
46676
  for (const h of handles) {
46000
- const candidate = join68(competitorsDir, h, "posts", `${shortcode}.json`);
46001
- if (existsSync72(candidate)) matches.push(candidate);
46677
+ const candidate = join71(competitorsDir, h, "posts", `${shortcode}.json`);
46678
+ if (existsSync75(candidate)) matches.push(candidate);
46002
46679
  }
46003
46680
  if (matches.length === 0) {
46004
46681
  error(`No post JSON found for shortcode "${shortcode}".`);
@@ -46033,18 +46710,18 @@ function registerMarketingCompetitor(parent) {
46033
46710
  process.exit(1);
46034
46711
  }
46035
46712
  const competitorsDir = MARKETING_PATHS.competitorsDir();
46036
- if (!existsSync72(competitorsDir)) {
46713
+ if (!existsSync75(competitorsDir)) {
46037
46714
  warn("No competitors directory yet \u2014 nothing to relabel.");
46038
46715
  return;
46039
46716
  }
46040
- const handles = readdirSync16(competitorsDir).filter((h) => !h.startsWith("_") && statSync11(join68(competitorsDir, h)).isDirectory());
46717
+ const handles = readdirSync17(competitorsDir).filter((h) => !h.startsWith("_") && statSync11(join71(competitorsDir, h)).isDirectory());
46041
46718
  let labeled = 0;
46042
46719
  let skipped = 0;
46043
46720
  for (const h of handles) {
46044
- const postsDir = join68(competitorsDir, h, "posts");
46045
- if (!existsSync72(postsDir)) continue;
46046
- for (const f of readdirSync16(postsDir).filter((n) => n.endsWith(".json"))) {
46047
- const path2 = join68(postsDir, f);
46721
+ const postsDir = join71(competitorsDir, h, "posts");
46722
+ if (!existsSync75(postsDir)) continue;
46723
+ for (const f of readdirSync17(postsDir).filter((n) => n.endsWith(".json"))) {
46724
+ const path2 = join71(postsDir, f);
46048
46725
  if (opts.dryRun) {
46049
46726
  info(`would relabel: ${path2}`);
46050
46727
  continue;
@@ -46091,8 +46768,8 @@ var init_competitor = __esm({
46091
46768
  });
46092
46769
 
46093
46770
  // src/lib/marketing/meta-fetch.ts
46094
- import { existsSync as existsSync73, mkdirSync as mkdirSync32, readFileSync as readFileSync52, writeFileSync as writeFileSync37, statSync as statSync12, openSync as openSync2, readSync, closeSync as closeSync2 } from "fs";
46095
- import { dirname as dirname41, basename as basename21 } from "path";
46771
+ import { existsSync as existsSync76, mkdirSync as mkdirSync34, readFileSync as readFileSync55, writeFileSync as writeFileSync39, statSync as statSync12, openSync as openSync2, readSync, closeSync as closeSync2 } from "fs";
46772
+ import { dirname as dirname44, basename as basename21 } from "path";
46096
46773
  import { randomUUID as randomUUID3 } from "crypto";
46097
46774
  function getQueue(accountId) {
46098
46775
  let q = writeQueues.get(accountId);
@@ -46142,17 +46819,17 @@ function idemCachePath(key) {
46142
46819
  }
46143
46820
  function readIdem(key) {
46144
46821
  const p = idemCachePath(key);
46145
- if (!existsSync73(p)) return null;
46822
+ if (!existsSync76(p)) return null;
46146
46823
  try {
46147
- return JSON.parse(readFileSync52(p, "utf8"));
46824
+ return JSON.parse(readFileSync55(p, "utf8"));
46148
46825
  } catch {
46149
46826
  return null;
46150
46827
  }
46151
46828
  }
46152
46829
  function writeIdem(rec) {
46153
46830
  const p = idemCachePath(rec.key);
46154
- mkdirSync32(dirname41(p), { recursive: true });
46155
- writeFileSync37(p, JSON.stringify(rec, null, 2) + "\n", "utf8");
46831
+ mkdirSync34(dirname44(p), { recursive: true });
46832
+ writeFileSync39(p, JSON.stringify(rec, null, 2) + "\n", "utf8");
46156
46833
  }
46157
46834
  function backoffMs(attempt, hintSec) {
46158
46835
  if (hintSec != null && Number.isFinite(hintSec) && hintSec > 0) {
@@ -46420,7 +47097,7 @@ async function singleShotVideoUpload(ctx, filepath, fields) {
46420
47097
  if (fields.name) form.set("name", fields.name);
46421
47098
  if (fields.title) form.set("title", fields.title);
46422
47099
  if (fields.description) form.set("description", fields.description);
46423
- const buffer = readFileSync52(filepath);
47100
+ const buffer = readFileSync55(filepath);
46424
47101
  const blob = new Blob([new Uint8Array(buffer)], { type: "video/mp4" });
46425
47102
  form.set("source", blob, basename21(filepath));
46426
47103
  const resp = await fetch(url, {
@@ -46469,7 +47146,7 @@ async function uploadImageFile(ctx, filepath) {
46469
47146
  return withWriteSlot(ctx.adAccountId, async () => {
46470
47147
  const url = buildUrl(ctx, { method: "POST", path: `${ctx.adAccountId}/adimages` });
46471
47148
  const form = new FormData();
46472
- const buffer = readFileSync52(filepath);
47149
+ const buffer = readFileSync55(filepath);
46473
47150
  const blob = new Blob([new Uint8Array(buffer)], { type: "image/png" });
46474
47151
  form.set("filename", blob, basename21(filepath));
46475
47152
  const resp = await fetch(url, {
@@ -46888,7 +47565,7 @@ var init_account = __esm({
46888
47565
  });
46889
47566
 
46890
47567
  // src/lib/marketing/hypothesis.ts
46891
- import { existsSync as existsSync74, readFileSync as readFileSync53 } from "fs";
47568
+ import { existsSync as existsSync77, readFileSync as readFileSync56 } from "fs";
46892
47569
  function validateHypothesis(raw, options2 = {}) {
46893
47570
  const errors = [];
46894
47571
  const fieldErrors = {};
@@ -46955,12 +47632,12 @@ function validateHypothesis(raw, options2 = {}) {
46955
47632
  };
46956
47633
  }
46957
47634
  function loadHypothesisFile(path2, options2 = {}) {
46958
- if (!existsSync74(path2)) {
47635
+ if (!existsSync77(path2)) {
46959
47636
  return { ok: false, errors: [`Hypothesis file not found: ${path2}`] };
46960
47637
  }
46961
47638
  let parsed;
46962
47639
  try {
46963
- parsed = JSON.parse(readFileSync53(path2, "utf8"));
47640
+ parsed = JSON.parse(readFileSync56(path2, "utf8"));
46964
47641
  } catch (e) {
46965
47642
  return { ok: false, errors: [`Failed to parse JSON at ${path2}: ${e.message}`] };
46966
47643
  }
@@ -47148,8 +47825,8 @@ var init_cohort2 = __esm({
47148
47825
  });
47149
47826
 
47150
47827
  // src/lib/marketing/insights-cache.ts
47151
- import { existsSync as existsSync75, readFileSync as readFileSync54, mkdirSync as mkdirSync33, writeFileSync as writeFileSync38, readdirSync as readdirSync17, statSync as statSync13 } from "fs";
47152
- import { join as join69 } from "path";
47828
+ import { existsSync as existsSync78, readFileSync as readFileSync57, mkdirSync as mkdirSync35, writeFileSync as writeFileSync40, readdirSync as readdirSync18, statSync as statSync13 } from "fs";
47829
+ import { join as join72 } from "path";
47153
47830
  import { randomBytes as randomBytes3 } from "crypto";
47154
47831
  function snapshotFilename(entityId, pulledAt) {
47155
47832
  const yyyy = pulledAt.getUTCFullYear();
@@ -47160,30 +47837,30 @@ function snapshotFilename(entityId, pulledAt) {
47160
47837
  return `${safe}__${yyyy}-${mm}-${dd}-${hh}.json`;
47161
47838
  }
47162
47839
  function indexPath() {
47163
- return join69(MARKETING_PATHS.insightsDir(), "_index.json");
47840
+ return join72(MARKETING_PATHS.insightsDir(), "_index.json");
47164
47841
  }
47165
47842
  function readIndex() {
47166
47843
  const p = indexPath();
47167
- if (!existsSync75(p)) return { latest: {}, updated_at: "1970-01-01T00:00:00Z" };
47844
+ if (!existsSync78(p)) return { latest: {}, updated_at: "1970-01-01T00:00:00Z" };
47168
47845
  try {
47169
- return JSON.parse(readFileSync54(p, "utf8"));
47846
+ return JSON.parse(readFileSync57(p, "utf8"));
47170
47847
  } catch {
47171
47848
  return { latest: {}, updated_at: "1970-01-01T00:00:00Z" };
47172
47849
  }
47173
47850
  }
47174
47851
  function writeIndex(idx) {
47175
47852
  const p = indexPath();
47176
- mkdirSync33(MARKETING_PATHS.insightsDir(), { recursive: true });
47853
+ mkdirSync35(MARKETING_PATHS.insightsDir(), { recursive: true });
47177
47854
  const tmp = `${p}.tmp.${process.pid}.${randomBytes3(4).toString("hex")}`;
47178
- writeFileSync38(tmp, JSON.stringify(idx, null, 2) + "\n", "utf8");
47855
+ writeFileSync40(tmp, JSON.stringify(idx, null, 2) + "\n", "utf8");
47179
47856
  __require("fs").renameSync(tmp, p);
47180
47857
  }
47181
47858
  function saveInsightsSnapshot(snap) {
47182
- mkdirSync33(MARKETING_PATHS.insightsDir(), { recursive: true });
47859
+ mkdirSync35(MARKETING_PATHS.insightsDir(), { recursive: true });
47183
47860
  const filename = snapshotFilename(snap.entity_id, new Date(snap.pulled_at));
47184
- const fullPath = join69(MARKETING_PATHS.insightsDir(), filename);
47861
+ const fullPath = join72(MARKETING_PATHS.insightsDir(), filename);
47185
47862
  const tmp = `${fullPath}.tmp.${process.pid}.${randomBytes3(4).toString("hex")}`;
47186
- writeFileSync38(tmp, JSON.stringify(snap, null, 2) + "\n", "utf8");
47863
+ writeFileSync40(tmp, JSON.stringify(snap, null, 2) + "\n", "utf8");
47187
47864
  __require("fs").renameSync(tmp, fullPath);
47188
47865
  const idx = readIndex();
47189
47866
  idx.latest[snap.entity_id] = filename;
@@ -47195,10 +47872,10 @@ function getCachedInsights(entityId) {
47195
47872
  const idx = readIndex();
47196
47873
  const filename = idx.latest[entityId];
47197
47874
  if (!filename) return null;
47198
- const fullPath = join69(MARKETING_PATHS.insightsDir(), filename);
47199
- if (!existsSync75(fullPath)) return null;
47875
+ const fullPath = join72(MARKETING_PATHS.insightsDir(), filename);
47876
+ if (!existsSync78(fullPath)) return null;
47200
47877
  try {
47201
- const snap = JSON.parse(readFileSync54(fullPath, "utf8"));
47878
+ const snap = JSON.parse(readFileSync57(fullPath, "utf8"));
47202
47879
  const ageMs = Date.now() - new Date(snap.pulled_at).getTime();
47203
47880
  if (ageMs > INSIGHTS_TTL_MS) return null;
47204
47881
  return snap;
@@ -47210,20 +47887,20 @@ function getLatestSnapshot(entityId) {
47210
47887
  const idx = readIndex();
47211
47888
  const filename = idx.latest[entityId];
47212
47889
  if (!filename) return null;
47213
- const fullPath = join69(MARKETING_PATHS.insightsDir(), filename);
47214
- if (!existsSync75(fullPath)) return null;
47890
+ const fullPath = join72(MARKETING_PATHS.insightsDir(), filename);
47891
+ if (!existsSync78(fullPath)) return null;
47215
47892
  try {
47216
- return JSON.parse(readFileSync54(fullPath, "utf8"));
47893
+ return JSON.parse(readFileSync57(fullPath, "utf8"));
47217
47894
  } catch {
47218
47895
  return null;
47219
47896
  }
47220
47897
  }
47221
47898
  function getPriorSnapshot(entityId, beforeMs) {
47222
47899
  const dir = MARKETING_PATHS.insightsDir();
47223
- if (!existsSync75(dir)) return null;
47900
+ if (!existsSync78(dir)) return null;
47224
47901
  const safe = entityId.replace(/[^A-Za-z0-9_-]/g, "_");
47225
- const candidates = readdirSync17(dir).filter((f) => f.startsWith(`${safe}__`) && f.endsWith(".json")).map((f) => {
47226
- const p = join69(dir, f);
47902
+ const candidates = readdirSync18(dir).filter((f) => f.startsWith(`${safe}__`) && f.endsWith(".json")).map((f) => {
47903
+ const p = join72(dir, f);
47227
47904
  const stat = statSync13(p);
47228
47905
  return { f, p, mtimeMs: stat.mtimeMs };
47229
47906
  }).sort((a, b) => b.mtimeMs - a.mtimeMs);
@@ -47231,7 +47908,7 @@ function getPriorSnapshot(entityId, beforeMs) {
47231
47908
  for (const c of candidates) {
47232
47909
  if (c.mtimeMs <= cutoff) {
47233
47910
  try {
47234
- return JSON.parse(readFileSync54(c.p, "utf8"));
47911
+ return JSON.parse(readFileSync57(c.p, "utf8"));
47235
47912
  } catch {
47236
47913
  continue;
47237
47914
  }
@@ -47867,8 +48544,8 @@ var init_kill = __esm({
47867
48544
  });
47868
48545
 
47869
48546
  // src/cli/commands/marketing/doctor.ts
47870
- import { readFileSync as readFileSync55, readdirSync as readdirSync18, statSync as statSync14 } from "fs";
47871
- import { join as join70 } from "path";
48547
+ import { readFileSync as readFileSync58, readdirSync as readdirSync19, statSync as statSync14 } from "fs";
48548
+ import { join as join73 } from "path";
47872
48549
  function registerMarketingDoctor(parent) {
47873
48550
  parent.command("doctor").description("Run diagnostics: env, FK integrity, retroactive secret scan, Reinfluence health.").option("--scan", "Run retroactive secret scan over the entire _dream_context/ tree", false).action(async (opts) => {
47874
48551
  console.log(header("Marketing doctor"));
@@ -47949,7 +48626,7 @@ function scanForSecrets(root) {
47949
48626
  for (const file of walkText(root)) {
47950
48627
  let txt;
47951
48628
  try {
47952
- txt = readFileSync55(file, "utf8");
48629
+ txt = readFileSync58(file, "utf8");
47953
48630
  } catch {
47954
48631
  continue;
47955
48632
  }
@@ -47970,13 +48647,13 @@ function scanForSecrets(root) {
47970
48647
  function* walkText(dir) {
47971
48648
  let entries;
47972
48649
  try {
47973
- entries = readdirSync18(dir);
48650
+ entries = readdirSync19(dir);
47974
48651
  } catch {
47975
48652
  return;
47976
48653
  }
47977
48654
  for (const e of entries) {
47978
48655
  if (e.startsWith(".") && (e === ".env" || e === ".env.local")) continue;
47979
- const full = join70(dir, e);
48656
+ const full = join73(dir, e);
47980
48657
  let stat;
47981
48658
  try {
47982
48659
  stat = statSync14(full);
@@ -48014,8 +48691,8 @@ var init_doctor2 = __esm({
48014
48691
  });
48015
48692
 
48016
48693
  // src/lib/marketing/entity-store.ts
48017
- import { existsSync as existsSync77, readFileSync as readFileSync56, readdirSync as readdirSync19 } from "fs";
48018
- import { join as join71 } from "path";
48694
+ import { existsSync as existsSync80, readFileSync as readFileSync59, readdirSync as readdirSync20 } from "fs";
48695
+ import { join as join74 } from "path";
48019
48696
  function dirFor(kind) {
48020
48697
  switch (kind) {
48021
48698
  case "campaign":
@@ -48034,24 +48711,24 @@ function newEntityId(kind) {
48034
48711
  }
48035
48712
  function entityPaths(kind, id) {
48036
48713
  const d = dirFor(kind);
48037
- return { json: join71(d, `${id}.json`), md: join71(d, `${id}.md`) };
48714
+ return { json: join74(d, `${id}.json`), md: join74(d, `${id}.md`) };
48038
48715
  }
48039
48716
  function loadEntity(kind, id) {
48040
48717
  const { json } = entityPaths(kind, id);
48041
- if (!existsSync77(json)) return null;
48718
+ if (!existsSync80(json)) return null;
48042
48719
  try {
48043
- return JSON.parse(readFileSync56(json, "utf8"));
48720
+ return JSON.parse(readFileSync59(json, "utf8"));
48044
48721
  } catch {
48045
48722
  return null;
48046
48723
  }
48047
48724
  }
48048
48725
  function listEntities(kind) {
48049
48726
  const d = dirFor(kind);
48050
- if (!existsSync77(d)) return [];
48727
+ if (!existsSync80(d)) return [];
48051
48728
  const out = [];
48052
- for (const f of readdirSync19(d).filter((x) => x.endsWith(".json"))) {
48729
+ for (const f of readdirSync20(d).filter((x) => x.endsWith(".json"))) {
48053
48730
  try {
48054
- out.push(JSON.parse(readFileSync56(join71(d, f), "utf8")));
48731
+ out.push(JSON.parse(readFileSync59(join74(d, f), "utf8")));
48055
48732
  } catch {
48056
48733
  }
48057
48734
  }
@@ -48245,7 +48922,7 @@ var init_campaign = __esm({
48245
48922
  });
48246
48923
 
48247
48924
  // src/cli/commands/marketing/adset.ts
48248
- import { existsSync as existsSync78, readFileSync as readFileSync57 } from "fs";
48925
+ import { existsSync as existsSync81, readFileSync as readFileSync60 } from "fs";
48249
48926
  function registerMarketingAdSet(parent) {
48250
48927
  const cmd = parent.command("adset").description("Manage adsets.");
48251
48928
  cmd.command("create").description("Create an adset (PAUSED). --daily-budget required (no fallback).").requiredOption("--campaign <id>", "parent campaign local id").requiredOption("--name <name>", "adset name").requiredOption("--daily-budget <amount>", "daily budget (major-currency units)").requiredOption("--targeting <file>", "JSON file with Meta targeting spec").option("--currency <code>", "currency code", "TRY").option("--optimization-goal <goal>", "OFFSITE_CONVERSIONS|LINK_CLICKS|...", "OFFSITE_CONVERSIONS").option("--billing-event <event>", "IMPRESSIONS|LINK_CLICKS|THRUPLAY", "IMPRESSIONS").option("--custom-event-type <evt>", "e.g. PURCHASE, COMPLETE_REGISTRATION (for OFFSITE_CONVERSIONS)").option("--no-dry-run", "Actually create on Meta").action(async (opts) => {
@@ -48265,13 +48942,13 @@ function registerMarketingAdSet(parent) {
48265
48942
  }
48266
48943
  throw e;
48267
48944
  }
48268
- if (!existsSync78(opts.targeting)) {
48945
+ if (!existsSync81(opts.targeting)) {
48269
48946
  error(`Targeting file not found: ${opts.targeting}`);
48270
48947
  process.exit(1);
48271
48948
  }
48272
48949
  let targeting;
48273
48950
  try {
48274
- targeting = JSON.parse(readFileSync57(opts.targeting, "utf8"));
48951
+ targeting = JSON.parse(readFileSync60(opts.targeting, "utf8"));
48275
48952
  } catch (e) {
48276
48953
  error(`Failed to parse targeting JSON: ${e.message}`);
48277
48954
  process.exit(1);
@@ -48528,12 +49205,12 @@ var init_creative = __esm({
48528
49205
  });
48529
49206
 
48530
49207
  // src/cli/commands/marketing/asset.ts
48531
- import { existsSync as existsSync79, statSync as statSync15 } from "fs";
49208
+ import { existsSync as existsSync82, statSync as statSync15 } from "fs";
48532
49209
  import { extname as extname5 } from "path";
48533
49210
  function registerMarketingAsset(parent) {
48534
49211
  const cmd = parent.command("asset").description("Upload creative assets to Meta.");
48535
49212
  cmd.command("upload <path>").description("Upload a video (>50MB \u2192 chunked) or image to Meta. Returns id/hash.").option("--type <type>", "override auto-detection (video|image)").option("--name <name>", "asset name (videos)").option("--no-dry-run", "Actually upload to Meta").action(async (path2, opts) => {
48536
- if (!existsSync79(path2)) {
49213
+ if (!existsSync82(path2)) {
48537
49214
  error(`File not found: ${path2}`);
48538
49215
  process.exit(1);
48539
49216
  }
@@ -48701,8 +49378,8 @@ var init_ad = __esm({
48701
49378
  });
48702
49379
 
48703
49380
  // src/lib/marketing/launch.ts
48704
- import { existsSync as existsSync80, readFileSync as readFileSync58, writeFileSync as writeFileSync39, mkdirSync as mkdirSync34, renameSync as renameSync8, readdirSync as readdirSync20 } from "fs";
48705
- import { dirname as dirname42, join as join72, basename as basename22 } from "path";
49381
+ import { existsSync as existsSync83, readFileSync as readFileSync61, writeFileSync as writeFileSync41, mkdirSync as mkdirSync36, renameSync as renameSync8, readdirSync as readdirSync21 } from "fs";
49382
+ import { dirname as dirname45, join as join75, basename as basename22 } from "path";
48706
49383
  import { randomBytes as randomBytes4 } from "crypto";
48707
49384
  function buildLaunchSummary(cohortId) {
48708
49385
  const cohort = loadCohort(cohortId);
@@ -48746,15 +49423,15 @@ function isoTs2() {
48746
49423
  return (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
48747
49424
  }
48748
49425
  function atomicWriteFile3(path2, data) {
48749
- mkdirSync34(dirname42(path2), { recursive: true });
49426
+ mkdirSync36(dirname45(path2), { recursive: true });
48750
49427
  const tmp = `${path2}.tmp.${process.pid}.${randomBytes4(4).toString("hex")}`;
48751
- writeFileSync39(tmp, data, "utf8");
49428
+ writeFileSync41(tmp, data, "utf8");
48752
49429
  renameSync8(tmp, path2);
48753
49430
  }
48754
49431
  function readWal(path2) {
48755
- if (!existsSync80(path2)) return null;
49432
+ if (!existsSync83(path2)) return null;
48756
49433
  try {
48757
- return JSON.parse(readFileSync58(path2, "utf8"));
49434
+ return JSON.parse(readFileSync61(path2, "utf8"));
48758
49435
  } catch {
48759
49436
  return null;
48760
49437
  }
@@ -48764,13 +49441,13 @@ function writeWal(path2, wal) {
48764
49441
  }
48765
49442
  function findWalByRunId(runId) {
48766
49443
  const dir = MARKETING_PATHS.runsDir();
48767
- if (!existsSync80(dir)) return null;
48768
- for (const f of readdirSync20(dir)) {
49444
+ if (!existsSync83(dir)) return null;
49445
+ for (const f of readdirSync21(dir)) {
48769
49446
  if (!f.endsWith(".json")) continue;
48770
49447
  if (f.startsWith("by-idem")) continue;
48771
49448
  const stem = f.replace(/\.json$/, "");
48772
49449
  if (stem === runId || f === runId || basename22(f, ".json") === runId) {
48773
- return join72(dir, f);
49450
+ return join75(dir, f);
48774
49451
  }
48775
49452
  }
48776
49453
  return null;
@@ -48810,7 +49487,7 @@ function createLaunchWal(args) {
48810
49487
  flipped_count: 0,
48811
49488
  error: null
48812
49489
  };
48813
- const walPath = join72(MARKETING_PATHS.runsDir(), `${id}.json`);
49490
+ const walPath = join75(MARKETING_PATHS.runsDir(), `${id}.json`);
48814
49491
  writeWal(walPath, wal);
48815
49492
  return { walPath, wal };
48816
49493
  }
@@ -49041,7 +49718,7 @@ var init_launch2 = __esm({
49041
49718
  });
49042
49719
 
49043
49720
  // src/cli/commands/marketing/learnings.ts
49044
- import { existsSync as existsSync81, readFileSync as readFileSync59 } from "fs";
49721
+ import { existsSync as existsSync84, readFileSync as readFileSync62 } from "fs";
49045
49722
  function registerMarketingLearnings(parent) {
49046
49723
  const cmd = parent.command("learnings").description("Performance Monitor learnings ledger (per-day .md + index).");
49047
49724
  cmd.command("show").description("Show today's (or specified day's) learnings file.").option("--date <YYYY-MM-DD>", "Day to show (default: today UTC)").option("--id <id>", "Show a single entry by id").action((opts) => {
@@ -49184,8 +49861,8 @@ async function resolveBody(body, bodyFile) {
49184
49861
  if (body) return body;
49185
49862
  if (bodyFile === "-") return readStdin3();
49186
49863
  if (bodyFile) {
49187
- if (!existsSync81(bodyFile)) throw new Error(`Body file not found: ${bodyFile}`);
49188
- return readFileSync59(bodyFile, "utf8");
49864
+ if (!existsSync84(bodyFile)) throw new Error(`Body file not found: ${bodyFile}`);
49865
+ return readFileSync62(bodyFile, "utf8");
49189
49866
  }
49190
49867
  return null;
49191
49868
  }
@@ -49215,29 +49892,29 @@ var init_learnings2 = __esm({
49215
49892
 
49216
49893
  // src/lib/marketing/rem-sleep.ts
49217
49894
  import {
49218
- existsSync as existsSync82,
49219
- mkdirSync as mkdirSync35,
49220
- readFileSync as readFileSync60,
49221
- writeFileSync as writeFileSync40,
49222
- readdirSync as readdirSync21,
49895
+ existsSync as existsSync85,
49896
+ mkdirSync as mkdirSync37,
49897
+ readFileSync as readFileSync63,
49898
+ writeFileSync as writeFileSync42,
49899
+ readdirSync as readdirSync22,
49223
49900
  statSync as statSync16,
49224
49901
  unlinkSync as unlinkSync3,
49225
49902
  renameSync as renameSync9
49226
49903
  } from "fs";
49227
- import { dirname as dirname43, join as join73 } from "path";
49904
+ import { dirname as dirname46, join as join76 } from "path";
49228
49905
  import { randomBytes as randomBytes5 } from "crypto";
49229
49906
  function atomicWriteFile4(path2, data) {
49230
- mkdirSync35(dirname43(path2), { recursive: true });
49907
+ mkdirSync37(dirname46(path2), { recursive: true });
49231
49908
  const tmp = `${path2}.tmp.${process.pid}.${randomBytes5(4).toString("hex")}`;
49232
- writeFileSync40(tmp, data, "utf8");
49909
+ writeFileSync42(tmp, data, "utf8");
49233
49910
  renameSync9(tmp, path2);
49234
49911
  }
49235
49912
  function pruneRuns(opts = {}) {
49236
49913
  const keepLast = opts.keepLast ?? 100;
49237
49914
  const dir = MARKETING_PATHS.runsDir();
49238
- if (!existsSync82(dir)) return { scanned: 0, kept: 0, deleted: 0, deletedFiles: [] };
49239
- const files = readdirSync21(dir).filter((f) => f.endsWith(".json")).map((f) => {
49240
- const p = join73(dir, f);
49915
+ if (!existsSync85(dir)) return { scanned: 0, kept: 0, deleted: 0, deletedFiles: [] };
49916
+ const files = readdirSync22(dir).filter((f) => f.endsWith(".json")).map((f) => {
49917
+ const p = join76(dir, f);
49241
49918
  try {
49242
49919
  return { f, p, mtimeMs: statSync16(p).mtimeMs };
49243
49920
  } catch {
@@ -49271,13 +49948,13 @@ function compactInsights(opts = {}) {
49271
49948
  const weeklyAfterDays = opts.weeklyAfterDays ?? 14;
49272
49949
  const now = opts.now ?? /* @__PURE__ */ new Date();
49273
49950
  const dir = MARKETING_PATHS.insightsDir();
49274
- if (!existsSync82(dir)) return { scanned: 0, kept: 0, deleted: 0, deletedFiles: [] };
49951
+ if (!existsSync85(dir)) return { scanned: 0, kept: 0, deleted: 0, deletedFiles: [] };
49275
49952
  const files = [];
49276
- for (const f of readdirSync21(dir)) {
49953
+ for (const f of readdirSync22(dir)) {
49277
49954
  if (!f.endsWith(".json") || f.startsWith("_")) continue;
49278
49955
  const m = f.match(SNAP_RE);
49279
49956
  if (!m) continue;
49280
- const p = join73(dir, f);
49957
+ const p = join76(dir, f);
49281
49958
  try {
49282
49959
  const stat = statSync16(p);
49283
49960
  files.push({ f, p, mtimeMs: stat.mtimeMs, entityId: m[1], bucket: m[2] });
@@ -49343,18 +50020,18 @@ function mergeDailyLearnings(opts = {}) {
49343
50020
  const retainDays = opts.retainDays ?? 7;
49344
50021
  const now = opts.now ?? /* @__PURE__ */ new Date();
49345
50022
  const dir = MARKETING_PATHS.learningsDir();
49346
- if (!existsSync82(dir)) {
50023
+ if (!existsSync85(dir)) {
49347
50024
  return { scanned: 0, merged: 0, archivePath: null, droppedRejected: 0, mergedFiles: [] };
49348
50025
  }
49349
50026
  const dayMs = 24 * 60 * 60 * 1e3;
49350
50027
  const cutoff = now.getTime() - retainDays * dayMs;
49351
50028
  const candidates = [];
49352
- for (const f of readdirSync21(dir)) {
50029
+ for (const f of readdirSync22(dir)) {
49353
50030
  const m = f.match(/^(\d{4}-\d{2}-\d{2})\.md$/);
49354
50031
  if (!m) continue;
49355
50032
  const date = m[1];
49356
50033
  const dateMs = (/* @__PURE__ */ new Date(`${date}T00:00:00Z`)).getTime();
49357
- if (dateMs < cutoff) candidates.push({ f, p: join73(dir, f), date });
50034
+ if (dateMs < cutoff) candidates.push({ f, p: join76(dir, f), date });
49358
50035
  }
49359
50036
  if (candidates.length === 0) {
49360
50037
  return { scanned: 0, merged: 0, archivePath: null, droppedRejected: 0, mergedFiles: [] };
@@ -49368,10 +50045,10 @@ function mergeDailyLearnings(opts = {}) {
49368
50045
  const mergedFiles = [];
49369
50046
  let lastArchivePath = null;
49370
50047
  for (const [q, list] of byQuarter) {
49371
- const archivePath = join73(dir, `_archive-${q}.md`);
50048
+ const archivePath = join76(dir, `_archive-${q}.md`);
49372
50049
  list.sort((a, b) => a.date.localeCompare(b.date));
49373
50050
  for (const c of list) {
49374
- const existingArchive = existsSync82(archivePath) ? readFileSync60(archivePath, "utf8") : `# Marketing learnings archive \u2014 ${q}
50051
+ const existingArchive = existsSync85(archivePath) ? readFileSync63(archivePath, "utf8") : `# Marketing learnings archive \u2014 ${q}
49375
50052
  `;
49376
50053
  const dateMarker = `# Marketing learnings \u2014 ${c.date}`;
49377
50054
  const alreadyMerged = existingArchive.includes(dateMarker);
@@ -49380,7 +50057,7 @@ function mergeDailyLearnings(opts = {}) {
49380
50057
  continue;
49381
50058
  }
49382
50059
  if (!alreadyMerged) {
49383
- const body = readFileSync60(c.p, "utf8").trimEnd();
50060
+ const body = readFileSync63(c.p, "utf8").trimEnd();
49384
50061
  const next2 = existingArchive.trimEnd() + "\n\n" + body + "\n";
49385
50062
  atomicWriteFile4(archivePath, next2);
49386
50063
  }
@@ -49423,14 +50100,14 @@ function quarterKey(yyyymmdd) {
49423
50100
  }
49424
50101
  function redactRunsSweep(opts = {}) {
49425
50102
  const dir = MARKETING_PATHS.runsDir();
49426
- if (!existsSync82(dir)) return { scanned: 0, rewritten: 0, rewrittenFiles: [] };
49427
- const files = readdirSync21(dir).filter((f) => f.endsWith(".json"));
50103
+ if (!existsSync85(dir)) return { scanned: 0, rewritten: 0, rewrittenFiles: [] };
50104
+ const files = readdirSync22(dir).filter((f) => f.endsWith(".json"));
49428
50105
  const rewrittenFiles = [];
49429
50106
  for (const f of files) {
49430
- const p = join73(dir, f);
50107
+ const p = join76(dir, f);
49431
50108
  let raw;
49432
50109
  try {
49433
- raw = readFileSync60(p, "utf8");
50110
+ raw = readFileSync63(p, "utf8");
49434
50111
  } catch {
49435
50112
  continue;
49436
50113
  }
@@ -49452,7 +50129,7 @@ function redactRunsSweep(opts = {}) {
49452
50129
  function runRemSleep(opts = {}) {
49453
50130
  const ranAt = (opts.now ?? /* @__PURE__ */ new Date()).toISOString();
49454
50131
  const root = marketingRootIfExists();
49455
- if (!root || !existsSync82(root)) {
50132
+ if (!root || !existsSync85(root)) {
49456
50133
  return {
49457
50134
  ranAt,
49458
50135
  marketingPresent: false,
@@ -49474,7 +50151,7 @@ function runRemSleep(opts = {}) {
49474
50151
  now: opts.now
49475
50152
  });
49476
50153
  const redaction = redactRunsSweep({ dryRun: opts.dryRun });
49477
- void mkdirSync35;
50154
+ void mkdirSync37;
49478
50155
  return { ranAt, marketingPresent: true, runs, insights, learnings, redaction };
49479
50156
  }
49480
50157
  var SNAP_RE;
@@ -49571,9 +50248,9 @@ var init_git_guard = __esm({
49571
50248
  });
49572
50249
 
49573
50250
  // src/cli/commands/marketing/hooks.ts
49574
- import { existsSync as existsSync83, readFileSync as readFileSync61, writeFileSync as writeFileSync41, chmodSync as chmodSync3, mkdirSync as mkdirSync36, statSync as statSync17 } from "fs";
50251
+ import { existsSync as existsSync86, readFileSync as readFileSync64, writeFileSync as writeFileSync43, chmodSync as chmodSync3, mkdirSync as mkdirSync38, statSync as statSync17 } from "fs";
49575
50252
  import { execFileSync as execFileSync6 } from "child_process";
49576
- import { join as join74 } from "path";
50253
+ import { join as join77 } from "path";
49577
50254
  function findGitDir(cwd = process.cwd()) {
49578
50255
  try {
49579
50256
  const out = execFileSync6("git", ["rev-parse", "--git-dir"], {
@@ -49582,7 +50259,7 @@ function findGitDir(cwd = process.cwd()) {
49582
50259
  stdio: ["ignore", "pipe", "ignore"]
49583
50260
  }).trim();
49584
50261
  if (!out) return null;
49585
- return out.startsWith("/") ? out : join74(cwd, out);
50262
+ return out.startsWith("/") ? out : join77(cwd, out);
49586
50263
  } catch {
49587
50264
  return null;
49588
50265
  }
@@ -49613,11 +50290,11 @@ function registerMarketingHooks(parent) {
49613
50290
  error("Not inside a git repository (or `git` is not on PATH).");
49614
50291
  process.exit(1);
49615
50292
  }
49616
- const hooksDir = join74(gitDir, "hooks");
49617
- mkdirSync36(hooksDir, { recursive: true });
49618
- const target = join74(hooksDir, "pre-commit");
49619
- if (existsSync83(target)) {
49620
- const existing = readFileSync61(target, "utf-8");
50293
+ const hooksDir = join77(gitDir, "hooks");
50294
+ mkdirSync38(hooksDir, { recursive: true });
50295
+ const target = join77(hooksDir, "pre-commit");
50296
+ if (existsSync86(target)) {
50297
+ const existing = readFileSync64(target, "utf-8");
49621
50298
  if (existing.includes(MANAGED_MARKER)) {
49622
50299
  info("pre-commit hook already managed by dreamcontext \u2014 refreshing.");
49623
50300
  } else if (!opts.force) {
@@ -49629,7 +50306,7 @@ function registerMarketingHooks(parent) {
49629
50306
  warn("Overwriting existing pre-commit hook (--force).");
49630
50307
  }
49631
50308
  }
49632
- writeFileSync41(target, HOOK_LAUNCHER, "utf-8");
50309
+ writeFileSync43(target, HOOK_LAUNCHER, "utf-8");
49633
50310
  try {
49634
50311
  chmodSync3(target, 493);
49635
50312
  } catch {
@@ -49668,26 +50345,26 @@ exec dreamcontext mk hooks check-staged
49668
50345
  });
49669
50346
 
49670
50347
  // src/lib/marketing/council-personas.ts
49671
- import { existsSync as existsSync84, readFileSync as readFileSync62, readdirSync as readdirSync22 } from "fs";
50348
+ import { existsSync as existsSync87, readFileSync as readFileSync65, readdirSync as readdirSync23 } from "fs";
49672
50349
  import { fileURLToPath as fileURLToPath9 } from "url";
49673
- import { join as join75, dirname as dirname44 } from "path";
50350
+ import { join as join78, dirname as dirname47 } from "path";
49674
50351
  function findPersonasDir() {
49675
50352
  const candidates = [
49676
50353
  // dev: src/lib/marketing/council-personas.ts → ../../../skill-packs/...
49677
- join75(__dirname_local, "..", "..", "..", PERSONA_SUBPATH),
50354
+ join78(__dirname_local, "..", "..", "..", PERSONA_SUBPATH),
49678
50355
  // built: dist/index.js → ./skill-packs/...
49679
- join75(__dirname_local, PERSONA_SUBPATH),
50356
+ join78(__dirname_local, PERSONA_SUBPATH),
49680
50357
  // tsup-bundled (deeper nesting if ever): ../skill-packs/...
49681
- join75(__dirname_local, "..", PERSONA_SUBPATH),
49682
- join75(__dirname_local, "..", "..", PERSONA_SUBPATH)
50358
+ join78(__dirname_local, "..", PERSONA_SUBPATH),
50359
+ join78(__dirname_local, "..", "..", PERSONA_SUBPATH)
49683
50360
  ];
49684
50361
  for (const candidate of candidates) {
49685
- if (existsSync84(candidate)) return candidate;
50362
+ if (existsSync87(candidate)) return candidate;
49686
50363
  }
49687
50364
  return null;
49688
50365
  }
49689
50366
  function parsePersonaFile(filePath) {
49690
- const raw = readFileSync62(filePath, "utf-8");
50367
+ const raw = readFileSync65(filePath, "utf-8");
49691
50368
  const parsed = (0, import_gray_matter5.default)(raw);
49692
50369
  const data = parsed.data;
49693
50370
  const slug = typeof data.slug === "string" ? data.slug.trim() : "";
@@ -49707,9 +50384,9 @@ function parsePersonaFile(filePath) {
49707
50384
  }
49708
50385
  function loadAllPersonas(personasDir) {
49709
50386
  const dir = personasDir ?? findPersonasDir();
49710
- if (!dir || !existsSync84(dir)) return [];
49711
- const files = readdirSync22(dir).filter((n) => n.endsWith(".md")).sort();
49712
- return files.map((name) => parsePersonaFile(join75(dir, name)));
50387
+ if (!dir || !existsSync87(dir)) return [];
50388
+ const files = readdirSync23(dir).filter((n) => n.endsWith(".md")).sort();
50389
+ return files.map((name) => parsePersonaFile(join78(dir, name)));
49713
50390
  }
49714
50391
  function selectPersonas(all, requested) {
49715
50392
  if (requested.length === 0) return [...all];
@@ -49728,23 +50405,23 @@ var init_council_personas = __esm({
49728
50405
  import_gray_matter5 = __toESM(require_gray_matter(), 1);
49729
50406
  __dirname_local = (() => {
49730
50407
  try {
49731
- return dirname44(fileURLToPath9(import.meta.url));
50408
+ return dirname47(fileURLToPath9(import.meta.url));
49732
50409
  } catch {
49733
50410
  return process.cwd();
49734
50411
  }
49735
50412
  })();
49736
50413
  VALID_MODELS2 = /* @__PURE__ */ new Set(["opus", "sonnet", "haiku"]);
49737
- PERSONA_SUBPATH = join75("skill-packs", "meta-marketing", "council-personas");
50414
+ PERSONA_SUBPATH = join78("skill-packs", "meta-marketing", "council-personas");
49738
50415
  }
49739
50416
  });
49740
50417
 
49741
50418
  // src/cli/commands/marketing/council.ts
49742
50419
  import { spawnSync as spawnSync4 } from "child_process";
49743
- import { existsSync as existsSync85 } from "fs";
50420
+ import { existsSync as existsSync88 } from "fs";
49744
50421
  function resolveDreamcontextEntry() {
49745
50422
  const node = process.argv[0];
49746
50423
  const script = process.argv[1];
49747
- if (script && existsSync85(script)) {
50424
+ if (script && existsSync88(script)) {
49748
50425
  return { node, script };
49749
50426
  }
49750
50427
  return { node, script: null };
@@ -49916,8 +50593,8 @@ var init_marketing = __esm({
49916
50593
  });
49917
50594
 
49918
50595
  // src/cli/commands/memory.ts
49919
- import { existsSync as existsSync86, unlinkSync as unlinkSync4 } from "fs";
49920
- import { join as join76, dirname as dirname45 } from "path";
50596
+ import { existsSync as existsSync89, unlinkSync as unlinkSync4 } from "fs";
50597
+ import { join as join79, dirname as dirname48 } from "path";
49921
50598
  function collectVault(value, previous) {
49922
50599
  return [...previous, value];
49923
50600
  }
@@ -49929,7 +50606,7 @@ function parseTypes(value) {
49929
50606
  return filtered.length > 0 ? filtered : void 0;
49930
50607
  }
49931
50608
  function recallFederated(contextRoot, query, topK, types, opts) {
49932
- const projectRoot = dirname45(contextRoot);
50609
+ const projectRoot = dirname48(contextRoot);
49933
50610
  const { target: currentTarget } = currentVaultTarget(projectRoot);
49934
50611
  const byName = /* @__PURE__ */ new Map();
49935
50612
  const add = (t) => {
@@ -50082,7 +50759,7 @@ function registerMemoryCommand(program2) {
50082
50759
  const summary = opts.summary ?? (text.length > 200 ? text.slice(0, 197) + "..." : text);
50083
50760
  const references = opts.references ? opts.references.split(",").map((s) => s.trim()).filter(Boolean) : void 0;
50084
50761
  const authors = opts.person ? opts.person.split(",").map((s) => s.trim()).filter(Boolean) : void 0;
50085
- const changelogPath = join76(root, "core", "CHANGELOG.json");
50762
+ const changelogPath = join79(root, "core", "CHANGELOG.json");
50086
50763
  const entry = {
50087
50764
  date: today(),
50088
50765
  type: opts.type ?? "note",
@@ -50100,8 +50777,8 @@ function registerMemoryCommand(program2) {
50100
50777
  memory.command("update").argument("<slug>", "Knowledge file slug (without .md)").option("-d, --description <desc>", "New description (replaces existing)").option("-t, --tags <tags>", "New tags (comma-separated, replaces existing)").option("-c, --content <content>", "New body content (replaces existing)").option("--append <text>", "Append text to body (preserves existing content)").option("--pin", "Set pinned: true").option("--unpin", "Set pinned: false").description("Update a knowledge file (frontmatter and/or body)").action(
50101
50778
  async (slug, opts) => {
50102
50779
  const root = ensureContextRoot();
50103
- const filePath = join76(root, "knowledge", `${slug}.md`);
50104
- if (!existsSync86(filePath)) {
50780
+ const filePath = join79(root, "knowledge", `${slug}.md`);
50781
+ if (!existsSync89(filePath)) {
50105
50782
  error(`Knowledge file not found: ${slug}.md`);
50106
50783
  return;
50107
50784
  }
@@ -50148,8 +50825,8 @@ ${opts.append}
50148
50825
  );
50149
50826
  memory.command("delete").argument("<slug>", "Knowledge file slug to delete (without .md)").option("-f, --force", "Skip confirmation prompt").description("Delete a knowledge file (irreversible; use git to recover)").action(async (slug, opts) => {
50150
50827
  const root = ensureContextRoot();
50151
- const filePath = join76(root, "knowledge", `${slug}.md`);
50152
- if (!existsSync86(filePath)) {
50828
+ const filePath = join79(root, "knowledge", `${slug}.md`);
50829
+ if (!existsSync89(filePath)) {
50153
50830
  error(`Knowledge file not found: ${slug}.md`);
50154
50831
  return;
50155
50832
  }
@@ -50257,13 +50934,13 @@ var init_memory = __esm({
50257
50934
 
50258
50935
  // src/cli/commands/upgrade.ts
50259
50936
  import { execFileSync as execFileSync8 } from "child_process";
50260
- import { dirname as dirname46 } from "path";
50937
+ import { dirname as dirname49 } from "path";
50261
50938
  function defaultInstaller(args) {
50262
50939
  execFileSync8("npm", args, { stdio: "inherit" });
50263
50940
  }
50264
50941
  function projectRootForCache() {
50265
50942
  const contextDir = resolveContextRoot();
50266
- return contextDir ? dirname46(contextDir) : process.cwd();
50943
+ return contextDir ? dirname49(contextDir) : process.cwd();
50267
50944
  }
50268
50945
  function defaultLiveLatest() {
50269
50946
  let latest = null;
@@ -50586,9 +51263,9 @@ var init_vaults3 = __esm({
50586
51263
  });
50587
51264
 
50588
51265
  // src/cli/commands/connections.ts
50589
- import { dirname as dirname47 } from "path";
51266
+ import { dirname as dirname50 } from "path";
50590
51267
  function currentVaultName2(contextRoot) {
50591
- return currentVaultTarget(dirname47(contextRoot)).name;
51268
+ return currentVaultTarget(dirname50(contextRoot)).name;
50592
51269
  }
50593
51270
  function registerConnectionsCommand(program2) {
50594
51271
  program2.command("connect <vault>").description("Connect this vault to a peer for federation (out|in|both)").option("-d, --direction <direction>", "Connection direction: out | in | both", "both").option("--topics <list>", "Comma-separated topic filter (default: all topics)").action((vault, opts) => {
@@ -50670,17 +51347,17 @@ var init_connections3 = __esm({
50670
51347
  });
50671
51348
 
50672
51349
  // src/lib/federation-ingest.ts
50673
- import { existsSync as existsSync87, mkdirSync as mkdirSync37 } from "fs";
50674
- import { join as join77 } from "path";
51350
+ import { existsSync as existsSync90, mkdirSync as mkdirSync39 } from "fs";
51351
+ import { join as join80 } from "path";
50675
51352
  function ingestEntry(contextRoot, entry) {
50676
- const knowledgeDir = join77(contextRoot, "knowledge");
50677
- mkdirSync37(knowledgeDir, { recursive: true });
51353
+ const knowledgeDir = join80(contextRoot, "knowledge");
51354
+ mkdirSync39(knowledgeDir, { recursive: true });
50678
51355
  const baseSlug = slugFromTitle(entry.title);
50679
- const canonicalPath = join77(knowledgeDir, `${baseSlug}.md`);
50680
- const collided = existsSync87(canonicalPath);
51356
+ const canonicalPath = join80(knowledgeDir, `${baseSlug}.md`);
51357
+ const collided = existsSync90(canonicalPath);
50681
51358
  const slug = collided ? `${baseSlug}--from-${sanitizeVault(entry.origin.vault)}` : baseSlug;
50682
- const targetPath = join77(knowledgeDir, `${slug}.md`);
50683
- if (!existsSync87(targetPath)) {
51359
+ const targetPath = join80(knowledgeDir, `${slug}.md`);
51360
+ if (!existsSync90(targetPath)) {
50684
51361
  writeFrontmatter(
50685
51362
  targetPath,
50686
51363
  {
@@ -50756,9 +51433,9 @@ var init_federation_ingest = __esm({
50756
51433
  });
50757
51434
 
50758
51435
  // src/cli/commands/federation.ts
50759
- import { dirname as dirname48 } from "path";
51436
+ import { dirname as dirname51 } from "path";
50760
51437
  function currentVaultName3(contextRoot) {
50761
- return currentVaultTarget(dirname48(contextRoot)).name;
51438
+ return currentVaultTarget(dirname51(contextRoot)).name;
50762
51439
  }
50763
51440
  function outboundConnections(contextRoot) {
50764
51441
  return listConnections(contextRoot).filter(
@@ -50971,12 +51648,12 @@ var init_people = __esm({
50971
51648
  });
50972
51649
 
50973
51650
  // src/cli/commands/config.ts
50974
- import { dirname as dirname49 } from "path";
50975
- import { existsSync as existsSync88, readFileSync as readFileSync64, writeFileSync as writeFileSync43 } from "fs";
50976
- import { join as join78 } from "path";
51651
+ import { dirname as dirname52 } from "path";
51652
+ import { existsSync as existsSync91, readFileSync as readFileSync67, writeFileSync as writeFileSync45 } from "fs";
51653
+ import { join as join81 } from "path";
50977
51654
  function resolveProjectRoot() {
50978
51655
  const contextRoot = resolveContextRoot();
50979
- return contextRoot ? dirname49(contextRoot) : null;
51656
+ return contextRoot ? dirname52(contextRoot) : null;
50980
51657
  }
50981
51658
  function requireProjectRoot() {
50982
51659
  const projectRoot = resolveProjectRoot();
@@ -51135,7 +51812,7 @@ function registerConfigCommand(program2) {
51135
51812
  const liveToken = resolveClickUpToken(projectRoot);
51136
51813
  let connected = false;
51137
51814
  if (liveToken) {
51138
- const contextRoot = join78(projectRoot, "_dream_context");
51815
+ const contextRoot = join81(projectRoot, "_dream_context");
51139
51816
  const probe = createClickUpBackend(contextRoot, readSetupConfig(projectRoot));
51140
51817
  const test = await probe.testConnection();
51141
51818
  if (test.ok) {
@@ -51178,7 +51855,7 @@ function registerConfigCommand(program2) {
51178
51855
  cfgNow = readSetupConfig(projectRoot);
51179
51856
  }
51180
51857
  if (connected && cfgNow?.clickup?.listId) {
51181
- const contextRoot = join78(projectRoot, "_dream_context");
51858
+ const contextRoot = join81(projectRoot, "_dream_context");
51182
51859
  const backend2 = createClickUpBackend(contextRoot, cfgNow);
51183
51860
  if (await esm_default4({ message: "Create the recommended custom fields on the list (urgency, summary, RICE, \u2026)?", default: true })) {
51184
51861
  const result = await backend2.provisionRemote();
@@ -51233,13 +51910,13 @@ function registerConfigCommand(program2) {
51233
51910
  const contextRoot = resolveContextRoot();
51234
51911
  let userMdSynced = false;
51235
51912
  if (contextRoot) {
51236
- const userMdPath = join78(contextRoot, "core", "1.user.md");
51237
- if (existsSync88(userMdPath)) {
51913
+ const userMdPath = join81(contextRoot, "core", "1.user.md");
51914
+ if (existsSync91(userMdPath)) {
51238
51915
  try {
51239
- const before = readFileSync64(userMdPath, "utf-8");
51916
+ const before = readFileSync67(userMdPath, "utf-8");
51240
51917
  const after = ensurePeopleSection(before, roster);
51241
51918
  if (after !== before) {
51242
- writeFileSync43(userMdPath, after, "utf-8");
51919
+ writeFileSync45(userMdPath, after, "utf-8");
51243
51920
  userMdSynced = true;
51244
51921
  }
51245
51922
  } catch (err) {
@@ -51283,7 +51960,7 @@ function registerConfigCommand(program2) {
51283
51960
  config.command("clickup-list <teamId> <spaceId> <listId>").description("Set the ClickUp team/space/list the tasks sync against").option("--migrate", "When changing lists: reset the sync ledger so the next sync recreates every local task in the NEW list").option("--keep", "When changing lists: keep existing task mappings (tasks were moved in ClickUp itself)").action(async (teamId, spaceId, listId, opts) => {
51284
51961
  const projectRoot = requireProjectRoot();
51285
51962
  if (!projectRoot) return;
51286
- const contextRoot = join78(projectRoot, "_dream_context");
51963
+ const contextRoot = join81(projectRoot, "_dream_context");
51287
51964
  const existing = readSetupConfig(projectRoot)?.clickup ?? {};
51288
51965
  const ledger = new SyncLedger(contextRoot);
51289
51966
  const changingList = !!existing.listId && existing.listId !== listId && ledger.readMap().length > 0;
@@ -51324,8 +52001,8 @@ function registerConfigCommand(program2) {
51324
52001
  if (!value) {
51325
52002
  if (!process.stdin.isTTY) {
51326
52003
  try {
51327
- const { readFileSync: readFileSync65 } = await import("fs");
51328
- value = readFileSync65(0, "utf-8").trim();
52004
+ const { readFileSync: readFileSync68 } = await import("fs");
52005
+ value = readFileSync68(0, "utf-8").trim();
51329
52006
  } catch {
51330
52007
  value = "";
51331
52008
  }
@@ -51684,12 +52361,12 @@ var init_feedback2 = __esm({
51684
52361
  });
51685
52362
 
51686
52363
  // src/cli/commands/migrations.ts
51687
- import { dirname as dirname50 } from "path";
52364
+ import { dirname as dirname53 } from "path";
51688
52365
  function registerMigrationsCommand(program2) {
51689
52366
  const migrations = program2.command("migrations").description("Inspect and record brain structure migrations");
51690
52367
  migrations.command("pending").description("Print pending agent task instructions for any unfinished migrations").action(() => {
51691
52368
  const root = ensureContextRoot();
51692
- const projectRoot = dirname50(root);
52369
+ const projectRoot = dirname53(root);
51693
52370
  const config = readSetupConfig(projectRoot);
51694
52371
  const fromVersion = config?.setupVersion ?? "0.0.0";
51695
52372
  const toVersion = dreamcontextVersion();