dreamcontext 0.8.2 → 0.8.3

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 (127) hide show
  1. package/README.md +97 -3
  2. package/agents/sleep-product.md +22 -0
  3. package/agents/sleep-state.md +3 -1
  4. package/agents/sleep-tasks.md +3 -1
  5. package/dist/agents/sleep-product.md +22 -0
  6. package/dist/agents/sleep-state.md +3 -1
  7. package/dist/agents/sleep-tasks.md +3 -1
  8. package/dist/dashboard/assets/{BrainCanvas3D-CNDjMlun.js → BrainCanvas3D-CoTzHqzT.js} +1 -1
  9. package/dist/dashboard/assets/{_baseUniq-DtoPVYjz.js → _baseUniq-BlQ6XWxs.js} +1 -1
  10. package/dist/dashboard/assets/{ar-SA-G6X2FPQ2-D_dXe_8i.js → ar-SA-G6X2FPQ2-C4qyHe9L.js} +1 -1
  11. package/dist/dashboard/assets/{arc-8LFYH4lG.js → arc-uGukQNxI.js} +1 -1
  12. package/dist/dashboard/assets/{architectureDiagram-Q4EWVU46-BIgEpM4v.js → architectureDiagram-Q4EWVU46-BhtWTFvf.js} +1 -1
  13. package/dist/dashboard/assets/{az-AZ-76LH7QW2-C30ZBwgT.js → az-AZ-76LH7QW2-HfK2pIVQ.js} +1 -1
  14. package/dist/dashboard/assets/{bg-BG-XCXSNQG7-D0R9pSdG.js → bg-BG-XCXSNQG7-L7TlhXli.js} +1 -1
  15. package/dist/dashboard/assets/{blockDiagram-DXYQGD6D-DRTa0DpJ.js → blockDiagram-DXYQGD6D-BmPhQEp6.js} +1 -1
  16. package/dist/dashboard/assets/{bn-BD-2XOGV67Q-vkWxteG3.js → bn-BD-2XOGV67Q-DE0uNoU6.js} +1 -1
  17. package/dist/dashboard/assets/{c4Diagram-AHTNJAMY-Do_gB8Cs.js → c4Diagram-AHTNJAMY-DtQKYrmP.js} +1 -1
  18. package/dist/dashboard/assets/{ca-ES-6MX7JW3Y-CTyxGdzW.js → ca-ES-6MX7JW3Y-7JHCTA6b.js} +1 -1
  19. package/dist/dashboard/assets/channel-3OfE-PZ3.js +1 -0
  20. package/dist/dashboard/assets/{chunk-4BX2VUAB-DJlttKoY.js → chunk-4BX2VUAB-BvnLY9qE.js} +1 -1
  21. package/dist/dashboard/assets/{chunk-4TB4RGXK-BdixZX4J.js → chunk-4TB4RGXK--piiFXgS.js} +1 -1
  22. package/dist/dashboard/assets/{chunk-55IACEB6-CPhKaTLr.js → chunk-55IACEB6-C7uvmawY.js} +1 -1
  23. package/dist/dashboard/assets/{chunk-EDXVE4YY-Bv0bQVvi.js → chunk-EDXVE4YY-BuWBKOPY.js} +1 -1
  24. package/dist/dashboard/assets/{chunk-FMBD7UC4-DGjRdLDd.js → chunk-FMBD7UC4-C1Le6hxh.js} +1 -1
  25. package/dist/dashboard/assets/{chunk-OYMX7WX6-B-wzkRri.js → chunk-OYMX7WX6-B8JE8Wz4.js} +1 -1
  26. package/dist/dashboard/assets/{chunk-QZHKN3VN-BwK1NqpV.js → chunk-QZHKN3VN-U9FJi59p.js} +1 -1
  27. package/dist/dashboard/assets/{chunk-YZCP3GAM-DjEwJGlh.js → chunk-YZCP3GAM-BNc94uy1.js} +1 -1
  28. package/dist/dashboard/assets/classDiagram-6PBFFD2Q-Dpt9qwZI.js +1 -0
  29. package/dist/dashboard/assets/classDiagram-v2-HSJHXN6E-Dpt9qwZI.js +1 -0
  30. package/dist/dashboard/assets/clone-CZ-InUnR.js +1 -0
  31. package/dist/dashboard/assets/{cose-bilkent-S5V4N54A-BJXUn11L.js → cose-bilkent-S5V4N54A-D0hUzBCj.js} +1 -1
  32. package/dist/dashboard/assets/{cs-CZ-2BRQDIVT-BjRikaNe.js → cs-CZ-2BRQDIVT-B0rWHDIi.js} +1 -1
  33. package/dist/dashboard/assets/{da-DK-5WZEPLOC-Cn3GTxbV.js → da-DK-5WZEPLOC-D_PQO_T0.js} +1 -1
  34. package/dist/dashboard/assets/{dagre-KV5264BT-BHn2c24z.js → dagre-KV5264BT-B_bjkEDQ.js} +1 -1
  35. package/dist/dashboard/assets/{de-DE-XR44H4JA-IvGsdpTt.js → de-DE-XR44H4JA-D1G4J6Mz.js} +1 -1
  36. package/dist/dashboard/assets/{diagram-5BDNPKRD-YrlF3B5a.js → diagram-5BDNPKRD-B63uEoiS.js} +1 -1
  37. package/dist/dashboard/assets/{diagram-G4DWMVQ6-DHONF1OD.js → diagram-G4DWMVQ6-DShdwm3D.js} +1 -1
  38. package/dist/dashboard/assets/{diagram-MMDJMWI5-B1vJLt5b.js → diagram-MMDJMWI5-DdVsHQ-l.js} +1 -1
  39. package/dist/dashboard/assets/{diagram-TYMM5635-C8P5-4A3.js → diagram-TYMM5635-BdHifyqU.js} +1 -1
  40. package/dist/dashboard/assets/{el-GR-BZB4AONW-B9GA8_lO.js → el-GR-BZB4AONW-a0CO4RfB.js} +1 -1
  41. package/dist/dashboard/assets/{erDiagram-SMLLAGMA-CjWWTCWe.js → erDiagram-SMLLAGMA-CYxdxNcb.js} +1 -1
  42. package/dist/dashboard/assets/{es-ES-U4NZUMDT-Ct1wP_9r.js → es-ES-U4NZUMDT-ejRYVYRf.js} +1 -1
  43. package/dist/dashboard/assets/{eu-ES-A7QVB2H4-C-49gWlR.js → eu-ES-A7QVB2H4-B-4OXJLd.js} +1 -1
  44. package/dist/dashboard/assets/{fa-IR-HGAKTJCU-DUo8t-xv.js → fa-IR-HGAKTJCU-DhOcLy7v.js} +1 -1
  45. package/dist/dashboard/assets/{fi-FI-Z5N7JZ37-DCObnr3i.js → fi-FI-Z5N7JZ37-CKQF9xKf.js} +1 -1
  46. package/dist/dashboard/assets/{flowDiagram-DWJPFMVM-OQ_IRMqG.js → flowDiagram-DWJPFMVM-azQUtREP.js} +1 -1
  47. package/dist/dashboard/assets/{fr-FR-RHASNOE6-0EGg3zhN.js → fr-FR-RHASNOE6-CsGekBXq.js} +1 -1
  48. package/dist/dashboard/assets/{ganttDiagram-T4ZO3ILL-DPTSBcnu.js → ganttDiagram-T4ZO3ILL-DjXmGcb4.js} +2 -2
  49. package/dist/dashboard/assets/{gitGraphDiagram-UUTBAWPF-BxfeiCqm.js → gitGraphDiagram-UUTBAWPF-Dz87wo6e.js} +1 -1
  50. package/dist/dashboard/assets/{gl-ES-HMX3MZ6V-WtVwXY6x.js → gl-ES-HMX3MZ6V-NRfsjlmW.js} +1 -1
  51. package/dist/dashboard/assets/{graph-Du_3_o8q.js → graph-BMW3t-Jz.js} +1 -1
  52. package/dist/dashboard/assets/{he-IL-6SHJWFNN-CfgspIku.js → he-IL-6SHJWFNN-CK4gfEss.js} +1 -1
  53. package/dist/dashboard/assets/{hi-IN-IWLTKZ5I-CS9l2g3B.js → hi-IN-IWLTKZ5I-CqyBl1jA.js} +1 -1
  54. package/dist/dashboard/assets/{hu-HU-A5ZG7DT2-BQ46AerM.js → hu-HU-A5ZG7DT2-BO0SthvO.js} +1 -1
  55. package/dist/dashboard/assets/{id-ID-SAP4L64H-BeShJyKQ.js → id-ID-SAP4L64H-CrHxJe1s.js} +1 -1
  56. package/dist/dashboard/assets/{index-D7dWmypK.js → index-B0pCDfL8.js} +1 -1
  57. package/dist/dashboard/assets/index-rIZLhbl7.js +480 -0
  58. package/dist/dashboard/assets/index-sax--nf3.css +1 -0
  59. package/dist/dashboard/assets/{infoDiagram-42DDH7IO-CcFhyaQp.js → infoDiagram-42DDH7IO-zG-8q9HR.js} +1 -1
  60. package/dist/dashboard/assets/{ishikawaDiagram-UXIWVN3A-9QJeD00p.js → ishikawaDiagram-UXIWVN3A-5OzPmL1c.js} +1 -1
  61. package/dist/dashboard/assets/{it-IT-JPQ66NNP-csyvfk0t.js → it-IT-JPQ66NNP-CW6fpZrT.js} +1 -1
  62. package/dist/dashboard/assets/{ja-JP-DBVTYXUO-DctpJ2yz.js → ja-JP-DBVTYXUO-DMJRiMhd.js} +1 -1
  63. package/dist/dashboard/assets/{journeyDiagram-VCZTEJTY-CU4EYedt.js → journeyDiagram-VCZTEJTY-f8lbDQ22.js} +1 -1
  64. package/dist/dashboard/assets/{kaa-6HZHGXH3-D0tWzHt3.js → kaa-6HZHGXH3-C4yr2X6j.js} +1 -1
  65. package/dist/dashboard/assets/{kab-KAB-ZGHBKWFO-BC-g4xJU.js → kab-KAB-ZGHBKWFO-BtwhZ5Ak.js} +1 -1
  66. package/dist/dashboard/assets/{kanban-definition-6JOO6SKY-BxXqVmz1.js → kanban-definition-6JOO6SKY-BJtF1llZ.js} +1 -1
  67. package/dist/dashboard/assets/{kk-KZ-P5N5QNE5-TLB3Lxri.js → kk-KZ-P5N5QNE5-BiS5ISFw.js} +1 -1
  68. package/dist/dashboard/assets/{km-KH-HSX4SM5Z-DCh7cRAS.js → km-KH-HSX4SM5Z-CJcAjj0D.js} +1 -1
  69. package/dist/dashboard/assets/{ko-KR-MTYHY66A-BPIl5ido.js → ko-KR-MTYHY66A-yw6XRj7m.js} +1 -1
  70. package/dist/dashboard/assets/{ku-TR-6OUDTVRD-TUpeN1Tm.js → ku-TR-6OUDTVRD-nAwdHGyN.js} +1 -1
  71. package/dist/dashboard/assets/{layout-CyrgfqIp.js → layout-guqP2e-e.js} +1 -1
  72. package/dist/dashboard/assets/linear-W2_Ct9N6.js +1 -0
  73. package/dist/dashboard/assets/{lt-LT-XHIRWOB4-BRKyR_Xw.js → lt-LT-XHIRWOB4-D7h1NJrv.js} +1 -1
  74. package/dist/dashboard/assets/{lv-LV-5QDEKY6T-BANbTe4s.js → lv-LV-5QDEKY6T-DJfUJgRc.js} +1 -1
  75. package/dist/dashboard/assets/{min-lcwVZhZ7.js → min-BlLHklQU.js} +1 -1
  76. package/dist/dashboard/assets/{mindmap-definition-QFDTVHPH-fVIbdlXp.js → mindmap-definition-QFDTVHPH-Ch2AO4mc.js} +1 -1
  77. package/dist/dashboard/assets/{mr-IN-CRQNXWMA-DLFutdXk.js → mr-IN-CRQNXWMA-BV3znx0p.js} +1 -1
  78. package/dist/dashboard/assets/{my-MM-5M5IBNSE-CGWrcNBC.js → my-MM-5M5IBNSE-IjUN-e5U.js} +1 -1
  79. package/dist/dashboard/assets/{nb-NO-T6EIAALU-CGRDupuc.js → nb-NO-T6EIAALU-MMsvbc2a.js} +1 -1
  80. package/dist/dashboard/assets/{nl-NL-IS3SIHDZ-BKwBfrzp.js → nl-NL-IS3SIHDZ-ByYTJGOK.js} +1 -1
  81. package/dist/dashboard/assets/{nn-NO-6E72VCQL-DDQkGe44.js → nn-NO-6E72VCQL-Bgbgzvhm.js} +1 -1
  82. package/dist/dashboard/assets/{oc-FR-POXYY2M6-DufeHCWh.js → oc-FR-POXYY2M6-BMBbvfQp.js} +1 -1
  83. package/dist/dashboard/assets/{pa-IN-N4M65BXN-BUzelJDX.js → pa-IN-N4M65BXN-CgcUC9Zd.js} +1 -1
  84. package/dist/dashboard/assets/{percentages-BXMCSKIN-FxAvjywS.js → percentages-BXMCSKIN-AuedyVVS.js} +7 -7
  85. package/dist/dashboard/assets/{pica-Cek5bFnr.js → pica-DxO5y0j_.js} +1 -1
  86. package/dist/dashboard/assets/{pieDiagram-DEJITSTG-PgIrKPnB.js → pieDiagram-DEJITSTG-q-J8tI3B.js} +1 -1
  87. package/dist/dashboard/assets/{pl-PL-T2D74RX3-Bd-rxZs3.js → pl-PL-T2D74RX3-BaZSYTKJ.js} +1 -1
  88. package/dist/dashboard/assets/{pt-BR-5N22H2LF-D0QJGoo5.js → pt-BR-5N22H2LF-DSPF7aLm.js} +1 -1
  89. package/dist/dashboard/assets/{pt-PT-UZXXM6DQ-DjumltMq.js → pt-PT-UZXXM6DQ-aoPTHC3m.js} +1 -1
  90. package/dist/dashboard/assets/{quadrantDiagram-34T5L4WZ-C30tZOBh.js → quadrantDiagram-34T5L4WZ-CGbfFson.js} +1 -1
  91. package/dist/dashboard/assets/{requirementDiagram-MS252O5E-D3vhi-ZB.js → requirementDiagram-MS252O5E-ThxVmoCe.js} +1 -1
  92. package/dist/dashboard/assets/{ro-RO-JPDTUUEW-DmEo8cEd.js → ro-RO-JPDTUUEW-YfCwiIS2.js} +1 -1
  93. package/dist/dashboard/assets/{ru-RU-B4JR7IUQ-ZHCu1nBu.js → ru-RU-B4JR7IUQ-zIVsVhsz.js} +1 -1
  94. package/dist/dashboard/assets/{sankeyDiagram-XADWPNL6-Cmbs-PxO.js → sankeyDiagram-XADWPNL6-BvEv917s.js} +1 -1
  95. package/dist/dashboard/assets/{sequenceDiagram-FGHM5R23-DlBqk4uQ.js → sequenceDiagram-FGHM5R23-JrhjN3MG.js} +1 -1
  96. package/dist/dashboard/assets/{si-LK-N5RQ5JYF-iuqtpRqI.js → si-LK-N5RQ5JYF-CegSAwip.js} +1 -1
  97. package/dist/dashboard/assets/{sk-SK-C5VTKIMK-BWFUWdaQ.js → sk-SK-C5VTKIMK-C_K-Uoai.js} +1 -1
  98. package/dist/dashboard/assets/{sl-SI-NN7IZMDC-irYTfiq_.js → sl-SI-NN7IZMDC-DHGXOoZl.js} +1 -1
  99. package/dist/dashboard/assets/{stateDiagram-FHFEXIEX-B6T9ib8G.js → stateDiagram-FHFEXIEX-BzOtZESp.js} +1 -1
  100. package/dist/dashboard/assets/stateDiagram-v2-QKLJ7IA2-CjcHIbj7.js +1 -0
  101. package/dist/dashboard/assets/{subset-shared.chunk-LTgWgeng.js → subset-shared.chunk-BWfXaC19.js} +1 -1
  102. package/dist/dashboard/assets/{subset-worker.chunk-CT_2iDuG.js → subset-worker.chunk-DHcqLDUZ.js} +1 -1
  103. package/dist/dashboard/assets/{sv-SE-XGPEYMSR-BvDzjArd.js → sv-SE-XGPEYMSR-BoNob2y3.js} +1 -1
  104. package/dist/dashboard/assets/{ta-IN-2NMHFXQM-DdsS_3Yq.js → ta-IN-2NMHFXQM-C8UHJYct.js} +1 -1
  105. package/dist/dashboard/assets/{th-TH-HPSO5L25-Duadkok3.js → th-TH-HPSO5L25-D7wP1iSi.js} +1 -1
  106. package/dist/dashboard/assets/{timeline-definition-GMOUNBTQ-CHTQqVpC.js → timeline-definition-GMOUNBTQ-Gwb0w7bX.js} +1 -1
  107. package/dist/dashboard/assets/{tr-TR-DEFEU3FU-CTnPpl_3.js → tr-TR-DEFEU3FU-He51QB-L.js} +1 -1
  108. package/dist/dashboard/assets/{uk-UA-QMV73CPH-CAqmQ01_.js → uk-UA-QMV73CPH-Blg5n9CR.js} +1 -1
  109. package/dist/dashboard/assets/{vennDiagram-DHZGUBPP-tWl34rwo.js → vennDiagram-DHZGUBPP-y2S0dZjp.js} +1 -1
  110. package/dist/dashboard/assets/{vi-VN-M7AON7JQ-Cz7FDG8R.js → vi-VN-M7AON7JQ-2z-4xcM3.js} +1 -1
  111. package/dist/dashboard/assets/{wardley-RL74JXVD-UjdnBcpJ.js → wardley-RL74JXVD-BNThyuCt.js} +1 -1
  112. package/dist/dashboard/assets/{wardleyDiagram-NUSXRM2D-KhVWSzPf.js → wardleyDiagram-NUSXRM2D-Sljri5hz.js} +1 -1
  113. package/dist/dashboard/assets/{xychartDiagram-5P7HB3ND-SwtVQYTW.js → xychartDiagram-5P7HB3ND-BIFYd4_d.js} +1 -1
  114. package/dist/dashboard/assets/{zh-CN-LNUGB5OW-B7cbFS35.js → zh-CN-LNUGB5OW-DZ8sfmlq.js} +1 -1
  115. package/dist/dashboard/assets/{zh-HK-E62DVLB3-CLi9BFmp.js → zh-HK-E62DVLB3-Zvqwoloz.js} +1 -1
  116. package/dist/dashboard/assets/{zh-TW-RAJ6MFWO-XAcgJHay.js → zh-TW-RAJ6MFWO-Ck_uDtMQ.js} +1 -1
  117. package/dist/dashboard/index.html +2 -2
  118. package/dist/index.js +930 -471
  119. package/package.json +1 -1
  120. package/dist/dashboard/assets/channel-C5p1t-nJ.js +0 -1
  121. package/dist/dashboard/assets/classDiagram-6PBFFD2Q-sTJpbWV4.js +0 -1
  122. package/dist/dashboard/assets/classDiagram-v2-HSJHXN6E-sTJpbWV4.js +0 -1
  123. package/dist/dashboard/assets/clone-DTslXBzp.js +0 -1
  124. package/dist/dashboard/assets/index-C9VT2u9E.js +0 -480
  125. package/dist/dashboard/assets/index-DoFaQKCx.css +0 -1
  126. package/dist/dashboard/assets/linear-B6cMUkoc.js +0 -1
  127. 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
 
@@ -37684,6 +37817,53 @@ var init_snapshot2 = __esm({
37684
37817
  }
37685
37818
  });
37686
37819
 
37820
+ // src/lib/salience.ts
37821
+ function clamp(text) {
37822
+ const oneLine = text.replace(/\s+/g, " ").trim();
37823
+ return oneLine.length <= MAX_MESSAGE_CHARS ? oneLine : oneLine.slice(0, MAX_MESSAGE_CHARS - 1) + "\u2026";
37824
+ }
37825
+ function detectSalience(distilled) {
37826
+ const moments = [];
37827
+ const seen = /* @__PURE__ */ new Set();
37828
+ const push = (message, salience) => {
37829
+ const clamped = clamp(message);
37830
+ if (!clamped) return;
37831
+ const key = `${salience}::${clamped.toLowerCase()}`;
37832
+ if (seen.has(key)) return;
37833
+ seen.add(key);
37834
+ moments.push({ message: clamped, salience });
37835
+ };
37836
+ for (const msg of distilled.userMessages) {
37837
+ if (CORRECTION_RE.test(msg)) {
37838
+ push(`User correction: ${msg}`, 2);
37839
+ }
37840
+ }
37841
+ if (distilled.errors.length > 0 && distilled.codeChanges.length > 0) {
37842
+ const firstError = distilled.errors[0];
37843
+ push(`Error resolved by code change: ${firstError}`, 1);
37844
+ }
37845
+ const decisionSources = [
37846
+ ...distilled.agentDecisions.filter((d) => !d.startsWith("[thinking]")),
37847
+ ...distilled.userMessages
37848
+ ];
37849
+ for (const src of decisionSources) {
37850
+ if (DECISION_RE.test(src)) {
37851
+ push(`Decision: ${src}`, 2);
37852
+ }
37853
+ }
37854
+ return moments.slice(0, MAX_MOMENTS);
37855
+ }
37856
+ var CORRECTION_RE, DECISION_RE, MAX_MOMENTS, MAX_MESSAGE_CHARS;
37857
+ var init_salience = __esm({
37858
+ "src/lib/salience.ts"() {
37859
+ "use strict";
37860
+ CORRECTION_RE = /\b(no|actually|wrong|instead|hayır|yanlış|değil)\b/i;
37861
+ DECISION_RE = /\b(decided|chose|switched to|will use|karar|seçtik)\b/i;
37862
+ MAX_MOMENTS = 5;
37863
+ MAX_MESSAGE_CHARS = 200;
37864
+ }
37865
+ });
37866
+
37687
37867
  // src/cli/commands/transcript.ts
37688
37868
  import { readFileSync as readFileSync35, existsSync as existsSync46, statSync as statSync6 } from "fs";
37689
37869
  function distillTranscript(transcriptPath, sinceTimestamp) {
@@ -38878,53 +39058,6 @@ var init_session_digest = __esm({
38878
39058
  }
38879
39059
  });
38880
39060
 
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
39061
  // src/lib/marketing/path-guards.ts
38929
39062
  import { existsSync as existsSync49, realpathSync } from "fs";
38930
39063
  import { basename as basename14, dirname as dirname24, resolve as resolve8, sep as sep5 } from "path";
@@ -39487,15 +39620,76 @@ function analyzeTranscript(transcriptPath) {
39487
39620
  for (const m of content.matchAll(/"file_path"\s*:\s*"[^"]*_dream_context\/state\/([a-z0-9][a-z0-9-]*)\.md"/g)) {
39488
39621
  slugs.add(m[1]);
39489
39622
  }
39623
+ let userTurns = 0;
39624
+ let assistantChars = 0;
39625
+ let decisionMarkers = 0;
39626
+ for (const line of content.split("\n")) {
39627
+ const trimmed = line.trim();
39628
+ if (!trimmed) continue;
39629
+ if (DECISION_RE.test(trimmed) || CORRECTION_RE.test(trimmed)) {
39630
+ decisionMarkers++;
39631
+ }
39632
+ let rec;
39633
+ try {
39634
+ rec = JSON.parse(trimmed);
39635
+ } catch {
39636
+ continue;
39637
+ }
39638
+ if (!rec || typeof rec !== "object") continue;
39639
+ const role = recordRole(rec);
39640
+ if (role === "user") {
39641
+ userTurns++;
39642
+ } else if (role === "assistant") {
39643
+ assistantChars += sumAssistantTextChars(rec);
39644
+ }
39645
+ }
39490
39646
  return {
39491
39647
  changeCount: changeMatches ? changeMatches.length : 0,
39492
39648
  toolCount: toolMatches ? toolMatches.length : 0,
39493
- taskSlugs: [...slugs]
39649
+ taskSlugs: [...slugs],
39650
+ userTurns,
39651
+ assistantChars,
39652
+ decisionMarkers
39494
39653
  };
39495
39654
  } catch {
39496
39655
  return ZERO_ANALYSIS;
39497
39656
  }
39498
39657
  }
39658
+ function recordRole(rec) {
39659
+ const r = rec;
39660
+ if (typeof r.role === "string") return r.role;
39661
+ if (r.message && typeof r.message === "object" && typeof r.message.role === "string") {
39662
+ return r.message.role;
39663
+ }
39664
+ return null;
39665
+ }
39666
+ function sumAssistantTextChars(rec) {
39667
+ const r = rec;
39668
+ const content = (r.message && typeof r.message === "object" ? r.message.content : void 0) ?? r.content;
39669
+ let total = 0;
39670
+ if (typeof content === "string") {
39671
+ return Math.min(MAX_TEXT_BLOCK_CHARS, content.length);
39672
+ }
39673
+ if (Array.isArray(content)) {
39674
+ for (const block of content) {
39675
+ if (block && typeof block === "object") {
39676
+ const b = block;
39677
+ if (b.type === "text" && typeof b.text === "string") {
39678
+ total += Math.min(MAX_TEXT_BLOCK_CHARS, b.text.length);
39679
+ }
39680
+ }
39681
+ }
39682
+ }
39683
+ return total;
39684
+ }
39685
+ function scoreFromSubstance(signals2) {
39686
+ let pts = 0;
39687
+ if (signals2.userTurns >= 6) pts++;
39688
+ if (signals2.assistantChars >= 6e3) pts++;
39689
+ if (signals2.decisionMarkers >= 1) pts++;
39690
+ if (signals2.taskSlugs.length >= 2) pts++;
39691
+ return Math.min(3, pts);
39692
+ }
39499
39693
  function scoreFromChangeCount(count) {
39500
39694
  if (count <= 0) return 0;
39501
39695
  if (count <= 3) return 1;
@@ -39687,6 +39881,29 @@ function getConsolidationDirective(state) {
39687
39881
  }
39688
39882
  return null;
39689
39883
  }
39884
+ function userPromptReminder(state) {
39885
+ const { debt, bookmarks, sleep_started_at } = state;
39886
+ if (sleep_started_at) {
39887
+ if (debt >= 4) {
39888
+ return `Consolidation already in progress (started: ${sleep_started_at}). Do NOT dispatch another sleep agent.`;
39889
+ }
39890
+ return null;
39891
+ }
39892
+ const criticalBookmarks = bookmarks.filter((b) => b.salience === 3);
39893
+ if (debt >= 10) {
39894
+ return `Sleep debt is ${debt}. CONSOLIDATION REQUIRED. Run sleep flow per SKILL.md (parallel specialist fan-out) NOW.`;
39895
+ }
39896
+ if (criticalBookmarks.length > 0) {
39897
+ return `${criticalBookmarks.length} critical bookmark(s) need consolidation. Run sleep flow per SKILL.md.`;
39898
+ }
39899
+ if (debt >= 7) {
39900
+ return `Sleep debt is ${debt}. Consolidation recommended before starting new work.`;
39901
+ }
39902
+ if (debt >= 4) {
39903
+ return `Sleep debt is ${debt}. After completing the current task, offer to consolidate.`;
39904
+ }
39905
+ return null;
39906
+ }
39690
39907
  function resolveDashboardPort() {
39691
39908
  const raw = process.env.DREAMCONTEXT_DASHBOARD_PORT;
39692
39909
  if (raw) {
@@ -39749,7 +39966,11 @@ function registerHookCommand(program2) {
39749
39966
  const stoppedAt = (/* @__PURE__ */ new Date()).toISOString();
39750
39967
  const analysis = transcriptPath ? analyzeTranscript(transcriptPath) : ZERO_ANALYSIS;
39751
39968
  const { changeCount, toolCount } = analysis;
39752
- const score = Math.max(scoreFromChangeCount(changeCount), scoreFromToolCount(toolCount));
39969
+ const score = Math.max(
39970
+ scoreFromChangeCount(changeCount),
39971
+ scoreFromToolCount(toolCount),
39972
+ scoreFromSubstance(analysis)
39973
+ );
39753
39974
  for (const bookmark of state.bookmarks) {
39754
39975
  if (!bookmark.session_id) {
39755
39976
  bookmark.session_id = sessionId;
@@ -39758,35 +39979,18 @@ function registerHookCommand(program2) {
39758
39979
  const bookmarkTaskSlugs = state.bookmarks.filter((b) => b.session_id === sessionId && b.task_slug).map((b) => b.task_slug);
39759
39980
  const transcriptTaskSlugs = analysis.taskSlugs;
39760
39981
  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);
39982
+ const upsertInput = {
39983
+ session_id: sessionId,
39984
+ transcript_path: transcriptPath,
39985
+ stopped_at: stoppedAt,
39986
+ last_assistant_message: lastAssistantMessage,
39987
+ change_count: changeCount,
39988
+ tool_count: toolCount,
39989
+ score,
39990
+ task_slugs: taskSlugs
39991
+ };
39992
+ const nextState = upsertSessionOnStop(state, upsertInput);
39993
+ writeSleepState(root, nextState);
39790
39994
  });
39791
39995
  hook.command("session-start").description("Analyze previous session + output context snapshot (called by Claude Code SessionStart hook)").action(() => {
39792
39996
  const input2 = readStdin();
@@ -39808,7 +40012,11 @@ function registerHookCommand(program2) {
39808
40012
  continue;
39809
40013
  }
39810
40014
  const analysis = analyzeTranscript(session.transcript_path);
39811
- const score = Math.max(scoreFromChangeCount(analysis.changeCount), scoreFromToolCount(analysis.toolCount));
40015
+ const score = Math.max(
40016
+ scoreFromChangeCount(analysis.changeCount),
40017
+ scoreFromToolCount(analysis.toolCount),
40018
+ scoreFromSubstance(analysis)
40019
+ );
39812
40020
  session.change_count = analysis.changeCount;
39813
40021
  session.tool_count = analysis.toolCount;
39814
40022
  session.score = score;
@@ -39913,23 +40121,12 @@ function registerHookCommand(program2) {
39913
40121
  const root = resolveContextRoot();
39914
40122
  if (!root) process.exit(0);
39915
40123
  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
- }
40124
+ const reminder = userPromptReminder(state);
40125
+ if (state.sleep_started_at) {
40126
+ if (reminder) console.log(reminder);
39921
40127
  return;
39922
40128
  }
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
- }
40129
+ if (reminder) console.log(reminder);
39933
40130
  try {
39934
40131
  const stale = listStaleRecs(24);
39935
40132
  if (stale.length > 0) {
@@ -40079,17 +40276,14 @@ function registerHookCommand(program2) {
40079
40276
  if (!root) process.exit(0);
40080
40277
  const state = readSleepState(root);
40081
40278
  const trigger = input2 && typeof input2.trigger === "string" ? input2.trigger : "unknown";
40082
- state.compaction_log.unshift({
40279
+ const nextState = appendCompactionRecord(state, {
40083
40280
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
40084
40281
  trigger,
40085
40282
  debt_at_compaction: state.debt,
40086
40283
  sessions_count: state.sessions.length,
40087
40284
  bookmarks_count: state.bookmarks.length
40088
40285
  });
40089
- if (state.compaction_log.length > 20) {
40090
- state.compaction_log = state.compaction_log.slice(0, 20);
40091
- }
40092
- writeSleepState(root, state);
40286
+ writeSleepState(root, nextState);
40093
40287
  try {
40094
40288
  const sessionId = input2 && typeof input2.session_id === "string" ? input2.session_id : "";
40095
40289
  const transcriptPath = input2 && typeof input2.transcript_path === "string" ? input2.transcript_path : "";
@@ -40118,12 +40312,14 @@ function registerHookCommand(program2) {
40118
40312
  process.exit(0);
40119
40313
  });
40120
40314
  }
40121
- var MAX_TRANSCRIPT_BYTES2, SKILL_SCORE_THRESHOLD, ZERO_ANALYSIS, JS_TS_EXTENSIONS, MAX_WALK_LEVELS, BIOME_CONFIGS, PRETTIER_CONFIGS, DEFAULT_DASHBOARD_PORT;
40315
+ 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
40316
  var init_hook = __esm({
40123
40317
  "src/cli/commands/hook.ts"() {
40124
40318
  "use strict";
40125
40319
  init_context_path();
40126
40320
  init_sleep();
40321
+ init_sleep_consolidation();
40322
+ init_salience();
40127
40323
  init_transcript();
40128
40324
  init_session_digest();
40129
40325
  init_salience();
@@ -40140,7 +40336,15 @@ var init_hook = __esm({
40140
40336
  init_install_skill();
40141
40337
  MAX_TRANSCRIPT_BYTES2 = 50 * 1024 * 1024;
40142
40338
  SKILL_SCORE_THRESHOLD = 1;
40143
- ZERO_ANALYSIS = { changeCount: 0, toolCount: 0, taskSlugs: [] };
40339
+ ZERO_ANALYSIS = {
40340
+ changeCount: 0,
40341
+ toolCount: 0,
40342
+ taskSlugs: [],
40343
+ userTurns: 0,
40344
+ assistantChars: 0,
40345
+ decisionMarkers: 0
40346
+ };
40347
+ MAX_TEXT_BLOCK_CHARS = 2e4;
40144
40348
  JS_TS_EXTENSIONS = /* @__PURE__ */ new Set([".js", ".jsx", ".ts", ".tsx", ".mjs", ".cjs", ".mts", ".cts"]);
40145
40349
  MAX_WALK_LEVELS = 10;
40146
40350
  BIOME_CONFIGS = ["biome.json", "biome.jsonc"];
@@ -41080,8 +41284,8 @@ async function handleCoreGet(_req, res, params, contextRoot) {
41080
41284
  return;
41081
41285
  }
41082
41286
  if (filename.endsWith(".json")) {
41083
- const { readFileSync: readFileSync66 } = await import("fs");
41084
- const raw2 = readFileSync66(filePath, "utf-8");
41287
+ const { readFileSync: readFileSync67 } = await import("fs");
41288
+ const raw2 = readFileSync67(filePath, "utf-8");
41085
41289
  try {
41086
41290
  const data = JSON.parse(raw2);
41087
41291
  sendJson(res, 200, { filename, type: "json", data });
@@ -41115,8 +41319,8 @@ async function handleCoreGet(_req, res, params, contextRoot) {
41115
41319
  });
41116
41320
  return;
41117
41321
  }
41118
- const { readFileSync: readFileSync65 } = await import("fs");
41119
- const raw = readFileSync65(filePath, "utf-8");
41322
+ const { readFileSync: readFileSync66 } = await import("fs");
41323
+ const raw = readFileSync66(filePath, "utf-8");
41120
41324
  sendJson(res, 200, { filename, type: "text", content: raw });
41121
41325
  }
41122
41326
  async function handleCoreUpdate(req, res, params, contextRoot) {
@@ -41166,8 +41370,8 @@ async function handleCoreUpdate(req, res, params, contextRoot) {
41166
41370
  return;
41167
41371
  }
41168
41372
  changedParts.push("content");
41169
- const { writeFileSync: writeFileSync44 } = await import("fs");
41170
- writeFileSync44(filePath, body.content, "utf-8");
41373
+ const { writeFileSync: writeFileSync45 } = await import("fs");
41374
+ writeFileSync45(filePath, body.content, "utf-8");
41171
41375
  }
41172
41376
  const what = changedParts.length > 0 ? changedParts.join(" and ") : "file";
41173
41377
  recordDashboardChange(contextRoot, {
@@ -42782,8 +42986,9 @@ function buildAskPrompt(question) {
42782
42986
 
42783
42987
  Question: "${question}"`;
42784
42988
  }
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.`;
42989
+ function buildSleepPrompt(depth) {
42990
+ 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.`;
42991
+ 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
42992
  }
42788
42993
  async function handleLauncherCapture(req, res, _params, _contextRoot) {
42789
42994
  const body = await parseJsonBody(req);
@@ -42841,7 +43046,18 @@ async function handleLauncherCapture(req, res, _params, _contextRoot) {
42841
43046
  captureRuns.set(captureId, run2);
42842
43047
  try {
42843
43048
  const shell = process.env.SHELL || "/bin/zsh";
42844
- const prompt = mode === "sleep" ? buildSleepPrompt() : mode === "ask" ? buildAskPrompt(text) : buildCapturePrompt(text);
43049
+ let sleepDepth = "deep";
43050
+ if (mode === "sleep") {
43051
+ try {
43052
+ sleepDepth = consolidationDepth(readSleepState(cwd).debt, {
43053
+ userRequestedDeep: true
43054
+ }).depth;
43055
+ } catch (err) {
43056
+ console.error("[launcher] could not read sleep state for depth:", err);
43057
+ sleepDepth = "deep";
43058
+ }
43059
+ }
43060
+ const prompt = mode === "sleep" ? buildSleepPrompt(sleepDepth) : mode === "ask" ? buildAskPrompt(text) : buildCapturePrompt(text);
42845
43061
  const child = spawn4(shell, ["-ilc", 'exec claude --model sonnet -p "$0"', prompt], {
42846
43062
  cwd,
42847
43063
  stdio: ["ignore", "pipe", "pipe"]
@@ -42888,6 +43104,177 @@ async function handleLauncherDefaults(_req, res, _params, _contextRoot) {
42888
43104
  const home = homedir3();
42889
43105
  sendJson(res, 200, { home, defaultParent: join59(home, "projects") });
42890
43106
  }
43107
+ function computeVaultStatus(v, latest) {
43108
+ const exists = existsSync63(resolve15(v.path));
43109
+ let setupVersion = "0.0.0";
43110
+ let shareable = false;
43111
+ if (exists) {
43112
+ try {
43113
+ const cfg = readSetupConfig(resolve15(v.path));
43114
+ if (cfg) {
43115
+ setupVersion = cfg.setupVersion || "0.0.0";
43116
+ shareable = cfg.shareable === true;
43117
+ }
43118
+ } catch {
43119
+ }
43120
+ }
43121
+ const needsUpdate = exists && compareVersions(setupVersion, latest) < 0;
43122
+ return { name: v.name, path: v.path, exists, setupVersion, latestVersion: latest, needsUpdate, shareable };
43123
+ }
43124
+ async function handleLauncherStatus(_req, res, _params, _contextRoot) {
43125
+ const latest = dreamcontextVersion();
43126
+ const vaults = listVaults().map((v) => computeVaultStatus(v, latest));
43127
+ sendJson(res, 200, { vaults, latestVersion: latest });
43128
+ }
43129
+ async function handleLauncherUnregister(req, res, _params, _contextRoot) {
43130
+ const body = await parseJsonBody(req);
43131
+ if (!body) {
43132
+ sendError(res, 400, "invalid_body", "Request body must be valid JSON.");
43133
+ return;
43134
+ }
43135
+ const name = typeof body.name === "string" ? body.name.trim() : "";
43136
+ if (!name) {
43137
+ sendError(res, 400, "invalid_name", "name must be a non-empty string.");
43138
+ return;
43139
+ }
43140
+ const removed = removeVault(name);
43141
+ sendJson(res, 200, { removed, vaults: listVaults() });
43142
+ }
43143
+ async function handleLauncherUpdate(req, res, _params, _contextRoot) {
43144
+ const body = await parseJsonBody(req);
43145
+ if (!body) {
43146
+ sendError(res, 400, "invalid_body", "Request body must be valid JSON.");
43147
+ return;
43148
+ }
43149
+ const name = typeof body.name === "string" ? body.name.trim() : "";
43150
+ if (!name) {
43151
+ sendError(res, 400, "invalid_name", "name must be a non-empty string.");
43152
+ return;
43153
+ }
43154
+ const vault = listVaults().find((v) => v.name === name);
43155
+ if (!vault) {
43156
+ sendError(res, 400, "unknown_vault", `No registered vault named "${name}".`);
43157
+ return;
43158
+ }
43159
+ const target = resolve15(vault.path);
43160
+ if (!existsSync63(target)) {
43161
+ sendError(res, 400, "missing_vault", `Vault path no longer exists: ${target}`);
43162
+ return;
43163
+ }
43164
+ try {
43165
+ await defaultCliRunner(["update"], target);
43166
+ const latest = dreamcontextVersion();
43167
+ sendJson(res, 200, { ok: true, status: computeVaultStatus(vault, latest) });
43168
+ } catch (err) {
43169
+ console.error("[launcher] update failed:", err);
43170
+ const detail = err instanceof Error ? err.message : "unknown error";
43171
+ sendError(res, 500, "update_failed", `Update failed: ${detail}`);
43172
+ }
43173
+ }
43174
+ async function handleLauncherFederationGraph(_req, res, _params, _contextRoot) {
43175
+ const latest = dreamcontextVersion();
43176
+ const vaults = listVaults();
43177
+ const nodes = vaults.map((v) => computeVaultStatus(v, latest));
43178
+ const shareableByName = new Map(nodes.map((n) => [n.name, n.shareable]));
43179
+ const known = new Set(vaults.map((v) => v.name));
43180
+ const edges = [];
43181
+ const seen = /* @__PURE__ */ new Set();
43182
+ for (const v of vaults) {
43183
+ if (!existsSync63(resolve15(v.path))) continue;
43184
+ const conns = listConnections(join59(resolve15(v.path), "_dream_context"));
43185
+ for (const c of conns) {
43186
+ if (c.direction !== "out" && c.direction !== "both") continue;
43187
+ if (!known.has(c.vault)) continue;
43188
+ if (c.status === "stale") continue;
43189
+ const key = `${v.name}\0${c.vault}`;
43190
+ if (seen.has(key)) continue;
43191
+ seen.add(key);
43192
+ edges.push({ source: v.name, target: c.vault, active: shareableByName.get(c.vault) === true });
43193
+ }
43194
+ }
43195
+ sendJson(res, 200, { nodes, edges, latestVersion: latest });
43196
+ }
43197
+ async function handleLauncherConnectionCreate(req, res, _params, _contextRoot) {
43198
+ const body = await parseJsonBody(req);
43199
+ if (!body) {
43200
+ sendError(res, 400, "invalid_body", "Request body must be valid JSON.");
43201
+ return;
43202
+ }
43203
+ const from = typeof body.from === "string" ? body.from.trim() : "";
43204
+ const to = typeof body.to === "string" ? body.to.trim() : "";
43205
+ if (!from || !to) {
43206
+ sendError(res, 400, "invalid_body", "from and to must be non-empty strings.");
43207
+ return;
43208
+ }
43209
+ const fromVault = listVaults().find((v) => v.name === from);
43210
+ if (!fromVault) {
43211
+ sendError(res, 400, "unknown_vault", `No registered vault named "${from}".`);
43212
+ return;
43213
+ }
43214
+ const fromRoot = join59(resolve15(fromVault.path), "_dream_context");
43215
+ try {
43216
+ addConnection(fromRoot, from, to, "out", null);
43217
+ sendJson(res, 200, { ok: true });
43218
+ } catch (err) {
43219
+ if (err instanceof VaultError) {
43220
+ sendError(res, 400, "invalid_connection", err.message);
43221
+ return;
43222
+ }
43223
+ console.error("[launcher] connection create failed:", err);
43224
+ sendError(res, 500, "connection_failed", "Failed to create connection.");
43225
+ }
43226
+ }
43227
+ async function handleLauncherConnectionRemove(req, res, _params, _contextRoot) {
43228
+ const body = await parseJsonBody(req);
43229
+ if (!body) {
43230
+ sendError(res, 400, "invalid_body", "Request body must be valid JSON.");
43231
+ return;
43232
+ }
43233
+ const from = typeof body.from === "string" ? body.from.trim() : "";
43234
+ const to = typeof body.to === "string" ? body.to.trim() : "";
43235
+ if (!from || !to) {
43236
+ sendError(res, 400, "invalid_body", "from and to must be non-empty strings.");
43237
+ return;
43238
+ }
43239
+ const fromVault = listVaults().find((v) => v.name === from);
43240
+ if (!fromVault) {
43241
+ sendError(res, 400, "unknown_vault", `No registered vault named "${from}".`);
43242
+ return;
43243
+ }
43244
+ const fromRoot = join59(resolve15(fromVault.path), "_dream_context");
43245
+ const removed = removeConnection(fromRoot, to);
43246
+ sendJson(res, 200, { ok: true, removed });
43247
+ }
43248
+ async function handleLauncherShareable(req, res, _params, _contextRoot) {
43249
+ const body = await parseJsonBody(req);
43250
+ if (!body) {
43251
+ sendError(res, 400, "invalid_body", "Request body must be valid JSON.");
43252
+ return;
43253
+ }
43254
+ const name = typeof body.name === "string" ? body.name.trim() : "";
43255
+ const shareable = body.shareable === true;
43256
+ if (!name) {
43257
+ sendError(res, 400, "invalid_name", "name must be a non-empty string.");
43258
+ return;
43259
+ }
43260
+ const vault = listVaults().find((v) => v.name === name);
43261
+ if (!vault) {
43262
+ sendError(res, 400, "unknown_vault", `No registered vault named "${name}".`);
43263
+ return;
43264
+ }
43265
+ const root = resolve15(vault.path);
43266
+ if (!existsSync63(root)) {
43267
+ sendError(res, 400, "missing_vault", `Vault path no longer exists: ${root}`);
43268
+ return;
43269
+ }
43270
+ try {
43271
+ updateSetupConfig(root, { shareable });
43272
+ sendJson(res, 200, { ok: true, name, shareable });
43273
+ } catch (err) {
43274
+ console.error("[launcher] shareable toggle failed:", err);
43275
+ sendError(res, 500, "shareable_failed", "Failed to update sharing.");
43276
+ }
43277
+ }
42891
43278
  var execFileAsync2, captureRuns, CAPTURE_RUN_TTL_MS, CAPTURE_RUNS_MAX, ScaffoldError, defaultCliRunner, SAFE_NAME_RE, SLEEPY_MODES;
42892
43279
  var init_launcher = __esm({
42893
43280
  "src/server/routes/launcher.ts"() {
@@ -42895,12 +43282,18 @@ var init_launcher = __esm({
42895
43282
  init_middleware();
42896
43283
  init_vault_discovery();
42897
43284
  init_vaults();
43285
+ init_connections();
43286
+ init_setup_config();
43287
+ init_manifest();
43288
+ init_version_check();
42898
43289
  init_tech_stack();
42899
43290
  init_ensure_cli();
42900
43291
  init_platforms();
42901
43292
  init_catalog();
42902
43293
  init_json_file();
42903
43294
  init_id();
43295
+ init_sleep();
43296
+ init_sleep_consolidation();
42904
43297
  execFileAsync2 = promisify2(execFile2);
42905
43298
  captureRuns = /* @__PURE__ */ new Map();
42906
43299
  CAPTURE_RUN_TTL_MS = 10 * 60 * 1e3;
@@ -42929,6 +43322,62 @@ var init_launcher = __esm({
42929
43322
  }
42930
43323
  });
42931
43324
 
43325
+ // src/server/routes/ui-settings.ts
43326
+ import { dirname as dirname30, join as join60 } from "path";
43327
+ import { existsSync as existsSync64, mkdirSync as mkdirSync26, readFileSync as readFileSync46, writeFileSync as writeFileSync33 } from "fs";
43328
+ function settingsPath(contextRoot) {
43329
+ return join60(contextRoot, BRAIN_SETTINGS_REL_PATH);
43330
+ }
43331
+ async function handleBrainSettingsGet(_req, res, _params, contextRoot) {
43332
+ const path2 = settingsPath(contextRoot);
43333
+ if (!existsSync64(path2)) {
43334
+ sendJson(res, 200, { settings: {} });
43335
+ return;
43336
+ }
43337
+ try {
43338
+ const raw = JSON.parse(readFileSync46(path2, "utf-8"));
43339
+ const settings = raw && typeof raw === "object" && !Array.isArray(raw) ? raw : {};
43340
+ sendJson(res, 200, { settings });
43341
+ } catch {
43342
+ sendJson(res, 200, { settings: {} });
43343
+ }
43344
+ }
43345
+ async function handleBrainSettingsPut(req, res, _params, contextRoot) {
43346
+ const body = await parseJsonBody(req);
43347
+ if (!body) {
43348
+ sendError(res, 400, "invalid_body", "Request body must be valid JSON.");
43349
+ return;
43350
+ }
43351
+ const settings = body.settings;
43352
+ if (settings === null || typeof settings !== "object" || Array.isArray(settings)) {
43353
+ sendError(res, 400, "invalid_settings", "settings must be a JSON object.");
43354
+ return;
43355
+ }
43356
+ const serialized = JSON.stringify(settings, null, 2);
43357
+ if (Buffer.byteLength(serialized, "utf-8") > MAX_BYTES) {
43358
+ sendError(res, 400, "too_large", "settings payload is too large.");
43359
+ return;
43360
+ }
43361
+ try {
43362
+ const path2 = settingsPath(contextRoot);
43363
+ mkdirSync26(dirname30(path2), { recursive: true });
43364
+ writeFileSync33(path2, serialized + "\n", "utf-8");
43365
+ sendJson(res, 200, { ok: true });
43366
+ } catch (err) {
43367
+ console.error("[ui-settings] brain-settings write failed:", err);
43368
+ sendError(res, 500, "write_failed", "Failed to persist brain settings.");
43369
+ }
43370
+ }
43371
+ var BRAIN_SETTINGS_REL_PATH, MAX_BYTES;
43372
+ var init_ui_settings = __esm({
43373
+ "src/server/routes/ui-settings.ts"() {
43374
+ "use strict";
43375
+ init_middleware();
43376
+ BRAIN_SETTINGS_REL_PATH = "state/.brain-settings.json";
43377
+ MAX_BYTES = 256 * 1024;
43378
+ }
43379
+ });
43380
+
42932
43381
  // src/lib/federation-config.ts
42933
43382
  function isShareable(projectRoot) {
42934
43383
  const cfg = readSetupConfig(projectRoot);
@@ -42942,7 +43391,7 @@ var init_federation_config = __esm({
42942
43391
  });
42943
43392
 
42944
43393
  // src/lib/federation-recall.ts
42945
- import { basename as basename19, dirname as dirname30 } from "path";
43394
+ import { basename as basename19, dirname as dirname31 } from "path";
42946
43395
  function namespacedKey(vault, type, slug) {
42947
43396
  return `${vault}::${type}/${slug}`;
42948
43397
  }
@@ -42967,7 +43416,7 @@ function crossVaultRecall(query, opts) {
42967
43416
  }
42968
43417
  const isCurrent = target.current === true;
42969
43418
  if (!isCurrent) {
42970
- const projectRoot = dirname30(contextRoot);
43419
+ const projectRoot = dirname31(contextRoot);
42971
43420
  if (!isShareable(projectRoot)) continue;
42972
43421
  }
42973
43422
  const corpus = buildCorpus(contextRoot, opts.types ? { types: opts.types } : {}).filter((doc) => !isFederated(doc));
@@ -43040,9 +43489,9 @@ var init_federation_recall = __esm({
43040
43489
  });
43041
43490
 
43042
43491
  // src/server/routes/connections.ts
43043
- import { dirname as dirname31 } from "path";
43492
+ import { dirname as dirname32 } from "path";
43044
43493
  function currentVaultName(contextRoot) {
43045
- return currentVaultTarget(dirname31(contextRoot)).name;
43494
+ return currentVaultTarget(dirname32(contextRoot)).name;
43046
43495
  }
43047
43496
  async function handleConnectionsList(_req, res, _params, contextRoot) {
43048
43497
  sendJson(res, 200, { connections: listConnections(contextRoot) });
@@ -43117,8 +43566,8 @@ var init_connections2 = __esm({
43117
43566
  });
43118
43567
 
43119
43568
  // src/lib/federation-digest.ts
43120
- import { existsSync as existsSync64 } from "fs";
43121
- import { join as join60 } from "path";
43569
+ import { existsSync as existsSync65 } from "fs";
43570
+ import { join as join61 } from "path";
43122
43571
  function buildInterestProfile(peerRoot, topics) {
43123
43572
  if (topics && topics.length > 0) {
43124
43573
  const terms2 = Array.from(new Set(tokenize(topics.join(" "))));
@@ -43137,8 +43586,8 @@ function buildInterestProfile(peerRoot, topics) {
43137
43586
  return { terms, query: terms.join(" ") };
43138
43587
  }
43139
43588
  function activeTaskTerms(peerRoot) {
43140
- const stateDir = join60(peerRoot, "state");
43141
- if (!existsSync64(stateDir)) return [];
43589
+ const stateDir = join61(peerRoot, "state");
43590
+ if (!existsSync65(stateDir)) return [];
43142
43591
  let files;
43143
43592
  try {
43144
43593
  files = import_fast_glob17.default.sync("*.md", { cwd: stateDir, absolute: true });
@@ -43239,7 +43688,7 @@ var init_federation_digest = __esm({
43239
43688
  });
43240
43689
 
43241
43690
  // src/server/routes/federation.ts
43242
- import { dirname as dirname32 } from "path";
43691
+ import { dirname as dirname33 } from "path";
43243
43692
  async function handleFederationInboxGet(_req, res, _params, contextRoot) {
43244
43693
  const { entries, quarantined } = drainInbox(contextRoot);
43245
43694
  const pending = entries.map((e) => e.entry);
@@ -43251,7 +43700,7 @@ async function handleFederationInboxGet(_req, res, _params, contextRoot) {
43251
43700
  });
43252
43701
  }
43253
43702
  async function handleFederationSyncPost(_req, res, _params, contextRoot) {
43254
- const senderName = currentVaultTarget(dirname32(contextRoot)).name;
43703
+ const senderName = currentVaultTarget(dirname33(contextRoot)).name;
43255
43704
  const outbound = listConnections(contextRoot).filter(
43256
43705
  (c) => (c.direction === "out" || c.direction === "both") && c.status !== "stale"
43257
43706
  );
@@ -43299,14 +43748,14 @@ var init_federation = __esm({
43299
43748
  });
43300
43749
 
43301
43750
  // src/server/routes/packs.ts
43302
- import { dirname as dirname33 } from "path";
43751
+ import { dirname as dirname34 } from "path";
43303
43752
  async function handlePacksGet(_req, res, _params, contextRoot) {
43304
43753
  const loaded = loadCatalog();
43305
43754
  if (!loaded) {
43306
43755
  sendJson(res, 200, { packs: [], standalone: [] });
43307
43756
  return;
43308
43757
  }
43309
- const projectRoot = dirname33(contextRoot);
43758
+ const projectRoot = dirname34(contextRoot);
43310
43759
  const packs = loaded.catalog.packs.map((p) => ({ ...p, installed: isSkillInstalled(projectRoot, p.name) }));
43311
43760
  const standalone = loaded.catalog.standalone.map((s) => ({ ...s, installed: isSkillInstalled(projectRoot, s.name) }));
43312
43761
  sendJson(res, 200, { packs, standalone });
@@ -43320,7 +43769,7 @@ var init_packs = __esm({
43320
43769
  });
43321
43770
 
43322
43771
  // src/server/routes/packs-install.ts
43323
- import { dirname as dirname34 } from "path";
43772
+ import { dirname as dirname35 } from "path";
43324
43773
  function validatePackName(name, contextRoot) {
43325
43774
  if (name.includes("/") || name.includes("\0") || safeChildPath2("/x", name) === null) {
43326
43775
  return { ok: false, status: 400, code: "invalid_name", message: "Invalid pack name." };
@@ -43333,7 +43782,7 @@ function validatePackName(name, contextRoot) {
43333
43782
  if (!known) {
43334
43783
  return { ok: false, status: 404, code: "unknown_pack", message: `Pack "${name}" not found.` };
43335
43784
  }
43336
- const projectRoot = dirname34(contextRoot);
43785
+ const projectRoot = dirname35(contextRoot);
43337
43786
  const config = readSetupConfig(projectRoot);
43338
43787
  const platforms = normalizePlatforms(config?.platforms ?? []);
43339
43788
  const resolved = platforms.length > 0 ? platforms : [...DEFAULT_PLATFORMS];
@@ -43406,10 +43855,10 @@ var init_packs_install = __esm({
43406
43855
  });
43407
43856
 
43408
43857
  // src/server/routes/version-check.ts
43409
- import { dirname as dirname35 } from "path";
43858
+ import { dirname as dirname36 } from "path";
43410
43859
  async function handleVersionCheckGet(_req, res, _params, contextRoot) {
43411
43860
  try {
43412
- const projectRoot = dirname35(contextRoot);
43861
+ const projectRoot = dirname36(contextRoot);
43413
43862
  const cache = readVersionCache(projectRoot);
43414
43863
  const fresh = isCacheFresh(cache);
43415
43864
  const installedCli = dreamcontextVersion();
@@ -43464,7 +43913,7 @@ var init_taxonomy2 = __esm({
43464
43913
 
43465
43914
  // src/server/index.ts
43466
43915
  import { createServer } from "http";
43467
- import { join as join61, resolve as resolve16 } from "path";
43916
+ import { join as join62, resolve as resolve16 } from "path";
43468
43917
  import { fileURLToPath as fileURLToPath7 } from "url";
43469
43918
  import { exec } from "child_process";
43470
43919
  function buildRouter() {
@@ -43510,6 +43959,13 @@ function buildRouter() {
43510
43959
  router.get("/api/launcher/capture/status", handleLauncherCaptureStatus);
43511
43960
  router.get("/api/launcher/sleepy-config", handleSleepyConfigGet);
43512
43961
  router.post("/api/launcher/sleepy-config", handleSleepyConfigSet);
43962
+ router.get("/api/launcher/status", handleLauncherStatus);
43963
+ router.post("/api/launcher/unregister", handleLauncherUnregister);
43964
+ router.post("/api/launcher/update", handleLauncherUpdate);
43965
+ router.get("/api/launcher/federation-graph", handleLauncherFederationGraph);
43966
+ router.post("/api/launcher/connection", handleLauncherConnectionCreate);
43967
+ router.post("/api/launcher/connection/remove", handleLauncherConnectionRemove);
43968
+ router.post("/api/launcher/shareable", handleLauncherShareable);
43513
43969
  router.get("/api/sleepy/video", handleSleepyVideo);
43514
43970
  router.get("/api/sleepy/anim", handleSleepyAnim);
43515
43971
  router.get("/api/vaults", handleVaultsGet);
@@ -43521,6 +43977,8 @@ function buildRouter() {
43521
43977
  router.get("/api/packs", handlePacksGet);
43522
43978
  router.post("/api/packs/:name/install", handlePackInstall);
43523
43979
  router.delete("/api/packs/:name", handlePackUninstall);
43980
+ router.get("/api/brain-settings", handleBrainSettingsGet);
43981
+ router.put("/api/brain-settings", handleBrainSettingsPut);
43524
43982
  router.get("/api/version-check", handleVersionCheckGet);
43525
43983
  router.get("/api/taxonomy", handleTaxonomyGet);
43526
43984
  router.get("/api/changelog", handleChangelogGet);
@@ -43542,7 +44000,7 @@ function resolveRequestVault(req) {
43542
44000
  if (/[/\\:.\x00]/.test(h)) return "INVALID";
43543
44001
  const v = listVaults().find((x) => x.name === h);
43544
44002
  if (!v) return "INVALID";
43545
- return join61(v.path, "_dream_context");
44003
+ return join62(v.path, "_dream_context");
43546
44004
  }
43547
44005
  function getDashboardDir() {
43548
44006
  const __dirname8 = fileURLToPath7(new URL(".", import.meta.url));
@@ -43642,6 +44100,7 @@ var init_server = __esm({
43642
44100
  init_config();
43643
44101
  init_vaults2();
43644
44102
  init_launcher();
44103
+ init_ui_settings();
43645
44104
  init_connections2();
43646
44105
  init_federation();
43647
44106
  init_packs();
@@ -43833,8 +44292,8 @@ var init_trigger = __esm({
43833
44292
  });
43834
44293
 
43835
44294
  // 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";
44295
+ import { existsSync as existsSync66, mkdirSync as mkdirSync27, writeFileSync as writeFileSync34 } from "fs";
44296
+ import { join as join63, dirname as dirname37 } from "path";
43838
44297
  function buildExclusionSet(corpus, excludedExtra) {
43839
44298
  const excluded = new Set(excludedExtra);
43840
44299
  for (const doc of corpus) {
@@ -44010,13 +44469,13 @@ function formatReflection(result) {
44010
44469
  return capToBytes(lines, MAX_REFLECTION_BYTES);
44011
44470
  }
44012
44471
  function reflectionPath(root) {
44013
- return join62(root, "state", ".reflection.md");
44472
+ return join63(root, "state", ".reflection.md");
44014
44473
  }
44015
44474
  function writeReflection(root, md) {
44016
44475
  const outPath = reflectionPath(root);
44017
- const dir = dirname36(outPath);
44018
- if (!existsSync65(dir)) {
44019
- mkdirSync26(dir, { recursive: true });
44476
+ const dir = dirname37(outPath);
44477
+ if (!existsSync66(dir)) {
44478
+ mkdirSync27(dir, { recursive: true });
44020
44479
  }
44021
44480
  const tsMatch = md.match(/Generated: ([^\n]+)/);
44022
44481
  const generatedAt = tsMatch ? tsMatch[1].trim() : (/* @__PURE__ */ new Date()).toISOString();
@@ -44027,7 +44486,7 @@ function writeReflection(root, md) {
44027
44486
  "---",
44028
44487
  ""
44029
44488
  ].join("\n");
44030
- writeFileSync33(outPath, frontmatter + md, "utf-8");
44489
+ writeFileSync34(outPath, frontmatter + md, "utf-8");
44031
44490
  return outPath;
44032
44491
  }
44033
44492
  var MAX_REFLECTION_BYTES, DEFAULT_MIN_SESSIONS, DEFAULT_MAX_CANDIDATES, REFLECTION_NOISE;
@@ -44191,14 +44650,14 @@ var init_reflection = __esm({
44191
44650
  });
44192
44651
 
44193
44652
  // src/cli/commands/reflect.ts
44194
- import { existsSync as existsSync66, readFileSync as readFileSync48 } from "fs";
44195
- import { join as join63 } from "path";
44653
+ import { existsSync as existsSync67, readFileSync as readFileSync49 } from "fs";
44654
+ import { join as join64 } from "path";
44196
44655
  function buildBookmarkSessions(root) {
44197
- const sleepPath = join63(root, "state", ".sleep.json");
44656
+ const sleepPath = join64(root, "state", ".sleep.json");
44198
44657
  const result = /* @__PURE__ */ new Map();
44199
- if (!existsSync66(sleepPath)) return result;
44658
+ if (!existsSync67(sleepPath)) return result;
44200
44659
  try {
44201
- const parsed = JSON.parse(readFileSync48(sleepPath, "utf-8"));
44660
+ const parsed = JSON.parse(readFileSync49(sleepPath, "utf-8"));
44202
44661
  const bookmarks = parsed.bookmarks ?? [];
44203
44662
  for (const b of bookmarks) {
44204
44663
  if (b.id && b.session_id) {
@@ -44212,13 +44671,13 @@ function buildBookmarkSessions(root) {
44212
44671
  function buildExcludedExtra(root) {
44213
44672
  const excluded = /* @__PURE__ */ new Set();
44214
44673
  const coreFiles = [
44215
- join63(root, "core", "0.soul.md"),
44216
- join63(root, "core", "1.user.md")
44674
+ join64(root, "core", "0.soul.md"),
44675
+ join64(root, "core", "1.user.md")
44217
44676
  ];
44218
44677
  for (const filePath of coreFiles) {
44219
- if (!existsSync66(filePath)) continue;
44678
+ if (!existsSync67(filePath)) continue;
44220
44679
  try {
44221
- const content = readFileSync48(filePath, "utf-8");
44680
+ const content = readFileSync49(filePath, "utf-8");
44222
44681
  for (const tok of tokenize(content)) {
44223
44682
  excluded.add(tok);
44224
44683
  }
@@ -44269,8 +44728,8 @@ var init_reflect = __esm({
44269
44728
  });
44270
44729
 
44271
44730
  // 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";
44731
+ import { existsSync as existsSync68, mkdirSync as mkdirSync28, readFileSync as readFileSync50, writeFileSync as writeFileSync35 } from "fs";
44732
+ import { join as join65 } from "path";
44274
44733
  function roundRunningStatus(n) {
44275
44734
  return `round_${n}_running`;
44276
44735
  }
@@ -44312,12 +44771,12 @@ function registerCreate(council) {
44312
44771
  }
44313
44772
  const id = generateId("council");
44314
44773
  const dir = getDebateDir(id);
44315
- mkdirSync27(dir, { recursive: true });
44774
+ mkdirSync28(dir, { recursive: true });
44316
44775
  const template = loadTemplate("council-debate.md");
44317
44776
  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"),
44777
+ writeFileSync35(join65(dir, "debate.md"), content, "utf-8");
44778
+ writeFileSync35(
44779
+ join65(dir, "round-log.md"),
44321
44780
  `# Round log \u2014 ${id}
44322
44781
 
44323
44782
  (Main agent appends timeline entries here.)
@@ -44359,8 +44818,8 @@ function registerAgent(council) {
44359
44818
  process.exit(1);
44360
44819
  }
44361
44820
  const personaDir = getPersonaDir(debateId, slug);
44362
- const personaFile = join64(personaDir, "context-and-persona.md");
44363
- if (existsSync67(personaFile) && !opts.force) {
44821
+ const personaFile = join65(personaDir, "context-and-persona.md");
44822
+ if (existsSync68(personaFile) && !opts.force) {
44364
44823
  error(`Persona already exists: ${slug}`, "Use --force to overwrite.");
44365
44824
  process.exit(1);
44366
44825
  }
@@ -44370,14 +44829,14 @@ function registerAgent(council) {
44370
44829
  process.exit(1);
44371
44830
  }
44372
44831
  const aspects = opts.aspects ? opts.aspects.split(",").map((a) => a.trim()).filter(Boolean) : [];
44373
- mkdirSync27(personaDir, { recursive: true });
44832
+ mkdirSync28(personaDir, { recursive: true });
44374
44833
  const template = loadTemplate("council-persona.md");
44375
44834
  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");
44835
+ writeFileSync35(personaFile, personaContent, "utf-8");
44377
44836
  const reportTemplate = loadTemplate("council-report.md");
44378
44837
  const reportContent = reportTemplate.replaceAll("{{SLUG}}", slug);
44379
- writeFileSync34(join64(personaDir, "report.md"), reportContent, "utf-8");
44380
- const debateFile = join64(getDebateDir(debateId), "debate.md");
44838
+ writeFileSync35(join65(personaDir, "report.md"), reportContent, "utf-8");
44839
+ const debateFile = join65(getDebateDir(debateId), "debate.md");
44381
44840
  const { data } = readFrontmatter(debateFile);
44382
44841
  const personas = Array.isArray(data.personas) ? data.personas.slice() : [];
44383
44842
  if (!personas.includes(slug)) personas.push(slug);
@@ -44406,7 +44865,7 @@ function registerRound(council) {
44406
44865
  error(`Round ${n} exceeds planned rounds (${data.rounds_planned}).`);
44407
44866
  process.exit(1);
44408
44867
  }
44409
- const debateFile = join64(getDebateDir(debateId), "debate.md");
44868
+ const debateFile = join65(getDebateDir(debateId), "debate.md");
44410
44869
  const personas = data.personas ?? [];
44411
44870
  if (personas.length === 0) {
44412
44871
  error("No personas registered. Run `council agent create` first.");
@@ -44415,9 +44874,9 @@ function registerRound(council) {
44415
44874
  const crossContextHeader = `## Round ${n} \u2014 Cross-context loaded`;
44416
44875
  if (n >= 2) {
44417
44876
  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");
44877
+ const personaFile = join65(getPersonaDir(debateId, persona), "context-and-persona.md");
44878
+ if (!existsSync68(personaFile)) continue;
44879
+ const existing = readFileSync50(personaFile, "utf-8");
44421
44880
  if (existing.includes(crossContextHeader)) {
44422
44881
  continue;
44423
44882
  }
@@ -44439,7 +44898,7 @@ _(no round ${n - 1} report submitted)_`);
44439
44898
 
44440
44899
  ${peerLines.join("\n\n")}`;
44441
44900
  const updated = existing.trimEnd() + "\n\n" + newSection + "\n";
44442
- writeFileSync34(personaFile, updated, "utf-8");
44901
+ writeFileSync35(personaFile, updated, "utf-8");
44443
44902
  }
44444
44903
  }
44445
44904
  updateFrontmatterFields(debateFile, {
@@ -44447,13 +44906,13 @@ ${peerLines.join("\n\n")}`;
44447
44906
  current_round: n,
44448
44907
  updated_at: today()
44449
44908
  });
44450
- const logFile = join64(getDebateDir(debateId), "round-log.md");
44451
- const logExisting = existsSync67(logFile) ? readFileSync49(logFile, "utf-8") : "";
44909
+ const logFile = join65(getDebateDir(debateId), "round-log.md");
44910
+ const logExisting = existsSync68(logFile) ? readFileSync50(logFile, "utf-8") : "";
44452
44911
  const logEntry = `
44453
44912
  ## Round ${n} started \u2014 ${today()}
44454
44913
  - Personas: ${formatPersonaList(personas)}
44455
44914
  `;
44456
- writeFileSync34(logFile, logExisting.trimEnd() + "\n" + logEntry + "\n", "utf-8");
44915
+ writeFileSync35(logFile, logExisting.trimEnd() + "\n" + logEntry + "\n", "utf-8");
44457
44916
  upsertCouncilIndex({
44458
44917
  id: debateId,
44459
44918
  topic: data.topic,
@@ -44487,18 +44946,18 @@ ${peerLines.join("\n\n")}`;
44487
44946
  error(`Round ${n} incomplete. Missing reports from: ${missing.join(", ")}`);
44488
44947
  process.exit(1);
44489
44948
  }
44490
- const debateFile = join64(getDebateDir(debateId), "debate.md");
44949
+ const debateFile = join65(getDebateDir(debateId), "debate.md");
44491
44950
  updateFrontmatterFields(debateFile, {
44492
44951
  status: roundCompleteStatus(n),
44493
44952
  updated_at: today()
44494
44953
  });
44495
- const logFile = join64(getDebateDir(debateId), "round-log.md");
44496
- const logExisting = existsSync67(logFile) ? readFileSync49(logFile, "utf-8") : "";
44954
+ const logFile = join65(getDebateDir(debateId), "round-log.md");
44955
+ const logExisting = existsSync68(logFile) ? readFileSync50(logFile, "utf-8") : "";
44497
44956
  const logEntry = `
44498
44957
  ## Round ${n} complete \u2014 ${today()}
44499
44958
  - All ${personas.length} personas submitted reports.
44500
44959
  `;
44501
- writeFileSync34(logFile, logExisting.trimEnd() + "\n" + logEntry + "\n", "utf-8");
44960
+ writeFileSync35(logFile, logExisting.trimEnd() + "\n" + logEntry + "\n", "utf-8");
44502
44961
  upsertCouncilIndex({
44503
44962
  id: debateId,
44504
44963
  topic: data.topic,
@@ -44521,8 +44980,8 @@ function registerRoundContext(council) {
44521
44980
  try {
44522
44981
  const data = readDebateFrontmatter(debateId);
44523
44982
  ensurePersonaExists(debateId, personaSlug);
44524
- const personaFile = join64(getPersonaDir(debateId, personaSlug), "context-and-persona.md");
44525
- const personaContent = readFileSync49(personaFile, "utf-8");
44983
+ const personaFile = join65(getPersonaDir(debateId, personaSlug), "context-and-persona.md");
44984
+ const personaContent = readFileSync50(personaFile, "utf-8");
44526
44985
  console.log(`# Council debate: ${data.topic}`);
44527
44986
  console.log(`Debate ID: ${debateId}`);
44528
44987
  console.log(`Current round: ${data.current_round}/${data.rounds_planned}`);
@@ -44531,8 +44990,8 @@ function registerRoundContext(council) {
44531
44990
  console.log("---");
44532
44991
  console.log("");
44533
44992
  console.log(personaContent);
44534
- const debateFile = join64(getDebateDir(debateId), "debate.md");
44535
- const debateRaw = readFileSync49(debateFile, "utf-8");
44993
+ const debateFile = join65(getDebateDir(debateId), "debate.md");
44994
+ const debateRaw = readFileSync50(debateFile, "utf-8");
44536
44995
  const questionMatch = debateRaw.match(/##\s+Question\s*\n([\s\S]*?)(?=\n##\s|\Z)/);
44537
44996
  const constraintsMatch = debateRaw.match(/##\s+Constraints & Known Facts\s*\n([\s\S]*?)(?=\n##\s|\Z)/);
44538
44997
  if (questionMatch) {
@@ -44575,7 +45034,7 @@ function registerReport(council) {
44575
45034
  process.exit(1);
44576
45035
  }
44577
45036
  for (const w of validation.warnings) warn(w);
44578
- const reportFile = join64(getPersonaDir(debateId, personaSlug), "report.md");
45037
+ const reportFile = join65(getPersonaDir(debateId, personaSlug), "report.md");
44579
45038
  const { data: reportData, content } = readFrontmatter(reportFile);
44580
45039
  const existingRounds = parseReportRounds(content);
44581
45040
  if (existingRounds.find((r) => r.round === round)) {
@@ -44597,7 +45056,7 @@ ${otherSerialized}
44597
45056
  persona: personaSlug,
44598
45057
  rounds_completed: Math.max(reportData.rounds_completed ?? 0, round)
44599
45058
  }, "\n" + merged);
44600
- const personaFile = join64(getPersonaDir(debateId, personaSlug), "context-and-persona.md");
45059
+ const personaFile = join65(getPersonaDir(debateId, personaSlug), "context-and-persona.md");
44601
45060
  const { data: pData } = readFrontmatter(personaFile);
44602
45061
  updateFrontmatterFields(personaFile, {
44603
45062
  round_entries: Math.max(pData.round_entries ?? 0, round)
@@ -44640,13 +45099,13 @@ function registerResearch(council) {
44640
45099
  error("Research topic is required.");
44641
45100
  process.exit(1);
44642
45101
  }
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, []);
45102
+ const researchesDir = join65(getPersonaDir(debateId, personaSlug), "researches");
45103
+ mkdirSync28(researchesDir, { recursive: true });
45104
+ const indexPath2 = join65(researchesDir, "index.json");
45105
+ if (!existsSync68(indexPath2)) writeJsonArray(indexPath2, []);
44647
45106
  const slug = slugify(topic);
44648
- const file = join64(researchesDir, `${slug}.md`);
44649
- if (existsSync67(file)) {
45107
+ const file = join65(researchesDir, `${slug}.md`);
45108
+ if (existsSync68(file)) {
44650
45109
  error(`Research note already exists: ${slug}.md`);
44651
45110
  process.exit(1);
44652
45111
  }
@@ -44661,7 +45120,7 @@ _Added ${today()} by ${personaSlug}_
44661
45120
 
44662
45121
  ${body.trim()}
44663
45122
  `;
44664
- writeFileSync34(file, noteContent, "utf-8");
45123
+ writeFileSync35(file, noteContent, "utf-8");
44665
45124
  insertToJsonArray(indexPath2, {
44666
45125
  slug,
44667
45126
  topic,
@@ -44676,9 +45135,9 @@ ${body.trim()}
44676
45135
  research.command("list").argument("<debate_id>").argument("<persona_slug>").description("List this persona's prior research notes.").action((debateId, personaSlug) => {
44677
45136
  try {
44678
45137
  ensurePersonaExists(debateId, personaSlug);
44679
- const researchesDir = join64(getPersonaDir(debateId, personaSlug), "researches");
44680
- const indexPath2 = join64(researchesDir, "index.json");
44681
- if (!existsSync67(indexPath2)) {
45138
+ const researchesDir = join65(getPersonaDir(debateId, personaSlug), "researches");
45139
+ const indexPath2 = join65(researchesDir, "index.json");
45140
+ if (!existsSync68(indexPath2)) {
44682
45141
  console.log(source_default.dim("(no researches)"));
44683
45142
  return;
44684
45143
  }
@@ -44700,7 +45159,7 @@ function registerSynthesize(council) {
44700
45159
  council.command("synthesize").argument("<debate_id>").description("Mark status=synthesizing; print manifest of files synthesizer should read.").action((debateId) => {
44701
45160
  try {
44702
45161
  const data = readDebateFrontmatter(debateId);
44703
- const debateFile = join64(getDebateDir(debateId), "debate.md");
45162
+ const debateFile = join65(getDebateDir(debateId), "debate.md");
44704
45163
  updateFrontmatterFields(debateFile, {
44705
45164
  status: "synthesizing",
44706
45165
  updated_at: today()
@@ -44722,8 +45181,8 @@ function registerSynthesize(council) {
44722
45181
  const personaDir = getPersonaDir(debateId, persona);
44723
45182
  manifest.push(`_dream_context/council/${debateId}/${persona}/context-and-persona.md`);
44724
45183
  manifest.push(`_dream_context/council/${debateId}/${persona}/report.md`);
44725
- const researchesIndex = join64(personaDir, "researches", "index.json");
44726
- if (existsSync67(researchesIndex)) {
45184
+ const researchesIndex = join65(personaDir, "researches", "index.json");
45185
+ if (existsSync68(researchesIndex)) {
44727
45186
  manifest.push(`_dream_context/council/${debateId}/${persona}/researches/`);
44728
45187
  }
44729
45188
  }
@@ -44741,12 +45200,12 @@ function registerComplete(council) {
44741
45200
  council.command("complete").argument("<debate_id>").description("Mark status=complete after final-report.md is written.").action((debateId) => {
44742
45201
  try {
44743
45202
  const data = readDebateFrontmatter(debateId);
44744
- const finalReport = join64(getDebateDir(debateId), "final-report.md");
44745
- if (!existsSync67(finalReport)) {
45203
+ const finalReport = join65(getDebateDir(debateId), "final-report.md");
45204
+ if (!existsSync68(finalReport)) {
44746
45205
  error("final-report.md not found.", "Synthesizer must write it before calling `council complete`.");
44747
45206
  process.exit(1);
44748
45207
  }
44749
- const debateFile = join64(getDebateDir(debateId), "debate.md");
45208
+ const debateFile = join65(getDebateDir(debateId), "debate.md");
44750
45209
  updateFrontmatterFields(debateFile, {
44751
45210
  status: "complete",
44752
45211
  updated_at: today()
@@ -44778,8 +45237,8 @@ function registerPromote(council) {
44778
45237
  error(`Cannot promote: debate status is "${data.status}", expected "complete".`);
44779
45238
  process.exit(1);
44780
45239
  }
44781
- const finalReport = join64(getDebateDir(debateId), "final-report.md");
44782
- if (!existsSync67(finalReport)) {
45240
+ const finalReport = join65(getDebateDir(debateId), "final-report.md");
45241
+ if (!existsSync68(finalReport)) {
44783
45242
  error("final-report.md not found.");
44784
45243
  process.exit(1);
44785
45244
  }
@@ -44792,12 +45251,12 @@ function registerPromote(council) {
44792
45251
 
44793
45252
  ${sec.body.trim()}` : null;
44794
45253
  }).filter(Boolean).join("\n\n");
44795
- const knowledgeDir = join64(root, "knowledge");
44796
- mkdirSync27(knowledgeDir, { recursive: true });
45254
+ const knowledgeDir = join65(root, "knowledge");
45255
+ mkdirSync28(knowledgeDir, { recursive: true });
44797
45256
  const slug = slugify(data.topic).slice(0, 80) || debateId;
44798
45257
  const filename = `decision-${slug}.md`;
44799
- const target = join64(knowledgeDir, filename);
44800
- if (existsSync67(target) && !opts.force) {
45258
+ const target = join65(knowledgeDir, filename);
45259
+ if (existsSync68(target) && !opts.force) {
44801
45260
  error(`Knowledge file exists: ${filename}`, "Use --force to overwrite.");
44802
45261
  process.exit(1);
44803
45262
  }
@@ -44821,7 +45280,7 @@ ${kept}
44821
45280
  _Promoted from council debate \`${debateId}\` on ${today()}. See \`_dream_context/council/${debateId}/final-report.md\` for the full record._
44822
45281
  `;
44823
45282
  writeFrontmatter(target, knowledgeFrontmatter, body);
44824
- updateFrontmatterFields(join64(getDebateDir(debateId), "debate.md"), {
45283
+ updateFrontmatterFields(join65(getDebateDir(debateId), "debate.md"), {
44825
45284
  promoted_to_knowledge: `knowledge/${filename}`,
44826
45285
  updated_at: today()
44827
45286
  });
@@ -44883,10 +45342,10 @@ function registerShow(council) {
44883
45342
  console.log(` promoted: ${data.promoted_to_knowledge ?? source_default.dim("(no)")}`);
44884
45343
  console.log(` created: ${data.created_at}`);
44885
45344
  console.log(` updated: ${data.updated_at}`);
44886
- const logFile = join64(getDebateDir(debateId), "round-log.md");
44887
- if (existsSync67(logFile)) {
45345
+ const logFile = join65(getDebateDir(debateId), "round-log.md");
45346
+ if (existsSync68(logFile)) {
44888
45347
  console.log("\n" + source_default.dim("\u2500\u2500\u2500 Round log \u2500\u2500\u2500"));
44889
- console.log(readFileSync49(logFile, "utf-8"));
45348
+ console.log(readFileSync50(logFile, "utf-8"));
44890
45349
  }
44891
45350
  } catch (err) {
44892
45351
  error(err.message);
@@ -45078,12 +45537,12 @@ var init_env_loader = __esm({
45078
45537
  });
45079
45538
 
45080
45539
  // 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";
45540
+ import { existsSync as existsSync69, readFileSync as readFileSync51, writeFileSync as writeFileSync36, mkdirSync as mkdirSync29 } from "fs";
45541
+ import { dirname as dirname38 } from "path";
45083
45542
  function readEnvFile() {
45084
45543
  const path2 = MARKETING_PATHS.envFile();
45085
- if (!existsSync68(path2)) return {};
45086
- const raw = readFileSync50(path2, "utf8");
45544
+ if (!existsSync69(path2)) return {};
45545
+ const raw = readFileSync51(path2, "utf8");
45087
45546
  const parsed = parseEnv(raw);
45088
45547
  if (parsed.errors.length > 0) {
45089
45548
  for (const e of parsed.errors) {
@@ -45127,9 +45586,9 @@ function requireEnv(keys = REQUIRED_KEYS) {
45127
45586
  }
45128
45587
  function loadConfig() {
45129
45588
  const path2 = MARKETING_PATHS.configFile();
45130
- if (!existsSync68(path2)) return { ...EMPTY_CONFIG, feature_flags: { ...EMPTY_CONFIG.feature_flags } };
45589
+ if (!existsSync69(path2)) return { ...EMPTY_CONFIG, feature_flags: { ...EMPTY_CONFIG.feature_flags } };
45131
45590
  try {
45132
- const raw = readFileSync50(path2, "utf8");
45591
+ const raw = readFileSync51(path2, "utf8");
45133
45592
  const parsed = JSON.parse(raw);
45134
45593
  return {
45135
45594
  default_profile: parsed.default_profile ?? null,
@@ -45144,21 +45603,21 @@ function loadConfig() {
45144
45603
  }
45145
45604
  function writeConfig(cfg) {
45146
45605
  const path2 = MARKETING_PATHS.configFile();
45147
- mkdirSync28(dirname37(path2), { recursive: true });
45148
- writeFileSync35(path2, JSON.stringify(cfg, null, 2) + "\n", "utf8");
45606
+ mkdirSync29(dirname38(path2), { recursive: true });
45607
+ writeFileSync36(path2, JSON.stringify(cfg, null, 2) + "\n", "utf8");
45149
45608
  }
45150
45609
  function ensureConfigFile() {
45151
45610
  const path2 = MARKETING_PATHS.configFile();
45152
- if (existsSync68(path2)) return loadConfig();
45611
+ if (existsSync69(path2)) return loadConfig();
45153
45612
  const cfg = { ...EMPTY_CONFIG, feature_flags: { ...EMPTY_CONFIG.feature_flags } };
45154
45613
  writeConfig(cfg);
45155
45614
  return cfg;
45156
45615
  }
45157
45616
  function ensureEnvFile() {
45158
45617
  const path2 = MARKETING_PATHS.envFile();
45159
- if (existsSync68(path2)) return;
45160
- mkdirSync28(marketingRoot(), { recursive: true });
45161
- writeFileSync35(path2, ENV_TEMPLATE, { encoding: "utf8", mode: 384 });
45618
+ if (existsSync69(path2)) return;
45619
+ mkdirSync29(marketingRoot(), { recursive: true });
45620
+ writeFileSync36(path2, ENV_TEMPLATE, { encoding: "utf8", mode: 384 });
45162
45621
  }
45163
45622
  var DEFAULT_API_VERSION, EMPTY_CONFIG, REQUIRED_KEYS, OPTIONAL_KEYS, ENV_TEMPLATE;
45164
45623
  var init_config2 = __esm({
@@ -45199,9 +45658,9 @@ REINFLUENCE_BIN= # optional override; default uses .venv
45199
45658
 
45200
45659
  // src/lib/marketing/bootstrap.ts
45201
45660
  import { spawn as spawn5, spawnSync as spawnSync2 } from "child_process";
45202
- import { existsSync as existsSync69, mkdirSync as mkdirSync29, cpSync as cpSync3 } from "fs";
45661
+ import { existsSync as existsSync70, mkdirSync as mkdirSync30, cpSync as cpSync3 } from "fs";
45203
45662
  import { fileURLToPath as fileURLToPath8 } from "url";
45204
- import { dirname as dirname38, resolve as resolve17, join as join65 } from "path";
45663
+ import { dirname as dirname39, resolve as resolve17, join as join66 } from "path";
45205
45664
  function findBundledReinfluence() {
45206
45665
  const candidates = [
45207
45666
  // Installed npm package: dist/<chunk>.js -> ../tools/reinfluence
@@ -45211,7 +45670,7 @@ function findBundledReinfluence() {
45211
45670
  resolve17(__dirname7, "..", "..", "..", "tools", "reinfluence")
45212
45671
  ];
45213
45672
  for (const c of candidates) {
45214
- if (existsSync69(join65(c, "__main__.py"))) return c;
45673
+ if (existsSync70(join66(c, "__main__.py"))) return c;
45215
45674
  }
45216
45675
  throw new Error(
45217
45676
  "Bundled reinfluence not found. Reinstall dreamcontext or set REINFLUENCE_BIN."
@@ -45242,18 +45701,18 @@ async function bootstrapMarketing(opts = {}) {
45242
45701
  if (verbose) process.stderr.write(`[mk init] ${msg}
45243
45702
  `);
45244
45703
  };
45245
- mkdirSync29(marketingRoot(), { recursive: true });
45704
+ mkdirSync30(marketingRoot(), { recursive: true });
45246
45705
  const bundled = findBundledReinfluence();
45247
45706
  const target = MARKETING_PATHS.reinfluenceDir();
45248
45707
  log(`copying tools \u2192 ${target}`);
45249
- mkdirSync29(MARKETING_PATHS.toolsDir(), { recursive: true });
45708
+ mkdirSync30(MARKETING_PATHS.toolsDir(), { recursive: true });
45250
45709
  cpSync3(bundled, target, { recursive: true });
45251
45710
  const py = findPython3();
45252
45711
  if (!py) {
45253
45712
  throw new Error("python3 not found on PATH. Install Python 3.10+ and retry.");
45254
45713
  }
45255
45714
  const venv = MARKETING_PATHS.venvDir();
45256
- if (!existsSync69(MARKETING_PATHS.venvPython())) {
45715
+ if (!existsSync70(MARKETING_PATHS.venvPython())) {
45257
45716
  log(`creating venv \u2192 ${venv}`);
45258
45717
  const r2 = runBlocking(py, ["-m", "venv", venv]);
45259
45718
  if (r2.code !== 0) {
@@ -45266,7 +45725,7 @@ async function bootstrapMarketing(opts = {}) {
45266
45725
  log("upgrading pip");
45267
45726
  let r = runBlocking(venvPy, ["-m", "pip", "install", "--upgrade", "pip", "--quiet"]);
45268
45727
  if (r.code !== 0) log(`pip upgrade warning: ${r.stderr.trim().slice(0, 200)}`);
45269
- const reqs = join65(target, "requirements.txt");
45728
+ const reqs = join66(target, "requirements.txt");
45270
45729
  log("installing python deps (whisper / yt-dlp / instaloader) \u2014 first run can take several minutes");
45271
45730
  r = runBlocking(venvPy, ["-m", "pip", "install", "-r", reqs, "--quiet"]);
45272
45731
  if (r.code !== 0) {
@@ -45276,7 +45735,7 @@ ${r.stderr.trim() || r.stdout.trim()}`);
45276
45735
  let whisperPrimed = false;
45277
45736
  if (whisperModel) {
45278
45737
  log(`pre-pulling whisper model "${whisperModel}" into ${MARKETING_PATHS.whisperCacheDir()}`);
45279
- mkdirSync29(MARKETING_PATHS.whisperCacheDir(), { recursive: true });
45738
+ mkdirSync30(MARKETING_PATHS.whisperCacheDir(), { recursive: true });
45280
45739
  whisperPrimed = await primeWhisper(whisperModel);
45281
45740
  if (!whisperPrimed) log("whisper pre-pull failed (will retry on first ingest)");
45282
45741
  }
@@ -45316,15 +45775,15 @@ function subprocessEnv() {
45316
45775
  return {
45317
45776
  ...process.env,
45318
45777
  XDG_CACHE_HOME: cache,
45319
- HF_HOME: join65(cache, "hf"),
45320
- TRANSFORMERS_CACHE: join65(cache, "hf", "transformers"),
45778
+ HF_HOME: join66(cache, "hf"),
45779
+ TRANSFORMERS_CACHE: join66(cache, "hf", "transformers"),
45321
45780
  WHISPER_CACHE_DIR: MARKETING_PATHS.whisperCacheDir(),
45322
45781
  PYTHONUNBUFFERED: "1",
45323
45782
  PYTHONPATH: MARKETING_PATHS.toolsDir()
45324
45783
  };
45325
45784
  }
45326
45785
  function isBootstrapped() {
45327
- return existsSync69(MARKETING_PATHS.venvPython()) && existsSync69(join65(MARKETING_PATHS.reinfluenceDir(), "__main__.py"));
45786
+ return existsSync70(MARKETING_PATHS.venvPython()) && existsSync70(join66(MARKETING_PATHS.reinfluenceDir(), "__main__.py"));
45328
45787
  }
45329
45788
  var __filename, __dirname7;
45330
45789
  var init_bootstrap = __esm({
@@ -45332,12 +45791,12 @@ var init_bootstrap = __esm({
45332
45791
  "use strict";
45333
45792
  init_paths2();
45334
45793
  __filename = fileURLToPath8(import.meta.url);
45335
- __dirname7 = dirname38(__filename);
45794
+ __dirname7 = dirname39(__filename);
45336
45795
  }
45337
45796
  });
45338
45797
 
45339
45798
  // src/cli/commands/marketing/init.ts
45340
- import { mkdirSync as mkdirSync30 } from "fs";
45799
+ import { mkdirSync as mkdirSync31 } from "fs";
45341
45800
  function registerMarketingInit(parent) {
45342
45801
  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
45802
  try {
@@ -45348,7 +45807,7 @@ function registerMarketingInit(parent) {
45348
45807
  }
45349
45808
  console.log(header("Marketing init"));
45350
45809
  const root = marketingRoot();
45351
- mkdirSync30(root, { recursive: true });
45810
+ mkdirSync31(root, { recursive: true });
45352
45811
  for (const dir of [
45353
45812
  MARKETING_PATHS.cohortsDir(),
45354
45813
  MARKETING_PATHS.campaignsDir(),
@@ -45361,7 +45820,7 @@ function registerMarketingInit(parent) {
45361
45820
  MARKETING_PATHS.byIdemDir(),
45362
45821
  MARKETING_PATHS.cacheDir()
45363
45822
  ]) {
45364
- mkdirSync30(dir, { recursive: true });
45823
+ mkdirSync31(dir, { recursive: true });
45365
45824
  }
45366
45825
  info(`folders ready under ${source_default.dim(root)}`);
45367
45826
  ensureEnvFile();
@@ -45401,8 +45860,8 @@ var init_init2 = __esm({
45401
45860
  });
45402
45861
 
45403
45862
  // 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";
45863
+ import { existsSync as existsSync71, readFileSync as readFileSync52, writeFileSync as writeFileSync37 } from "fs";
45864
+ import { dirname as dirname40, join as join67 } from "path";
45406
45865
  function pickVisionProvider(env2 = process.env) {
45407
45866
  const oai = env2.OPENAI_VISION_API_KEY;
45408
45867
  if (oai && oai.trim().length > 0) return { provider: "openai", apiKey: oai.trim() };
@@ -45441,11 +45900,11 @@ function parseLabelsFromText(text, allowlist = LABEL_ALLOWLIST) {
45441
45900
  return out;
45442
45901
  }
45443
45902
  async function readImageAsBase64(framePath) {
45444
- const buf = readFileSync51(framePath);
45903
+ const buf = readFileSync52(framePath);
45445
45904
  return buf.toString("base64");
45446
45905
  }
45447
45906
  async function labelHookFrame(framePath, opts) {
45448
- if (!existsSync70(framePath)) return [];
45907
+ if (!existsSync71(framePath)) return [];
45449
45908
  const fetcher = opts.fetcher ?? defaultFetcher;
45450
45909
  const prompt = opts.promptOverride ?? PROMPT;
45451
45910
  const b64 = await readImageAsBase64(framePath);
@@ -45495,7 +45954,7 @@ async function labelHookFrame(framePath, opts) {
45495
45954
  return parseLabelsFromText(text);
45496
45955
  }
45497
45956
  async function runVisionPassOnPost(postJsonPath, opts = {}) {
45498
- const raw = readFileSync51(postJsonPath, "utf-8");
45957
+ const raw = readFileSync52(postJsonPath, "utf-8");
45499
45958
  const post = JSON.parse(raw);
45500
45959
  const shortcode = post.shortcode ?? "?";
45501
45960
  const provider = opts.provider && opts.apiKey ? { provider: opts.provider, apiKey: opts.apiKey } : pickVisionProvider();
@@ -45534,15 +45993,15 @@ async function runVisionPassOnPost(postJsonPath, opts = {}) {
45534
45993
  post.pattern_tags = [...aggregated].sort();
45535
45994
  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
45995
  const tmp = postJsonPath + ".tmp";
45537
- writeFileSync36(tmp, JSON.stringify(post, null, 2) + "\n", "utf-8");
45996
+ writeFileSync37(tmp, JSON.stringify(post, null, 2) + "\n", "utf-8");
45538
45997
  const fs = await import("fs");
45539
45998
  fs.renameSync(tmp, postJsonPath);
45540
- const mdPath = join66(dirname39(postJsonPath), `${shortcode}.md`);
45541
- if (existsSync70(mdPath)) {
45999
+ const mdPath = join67(dirname40(postJsonPath), `${shortcode}.md`);
46000
+ if (existsSync71(mdPath)) {
45542
46001
  try {
45543
- const md = readFileSync51(mdPath, "utf-8");
46002
+ const md = readFileSync52(mdPath, "utf-8");
45544
46003
  const refreshed = updatePatternTagsInBridge(md, post.pattern_tags);
45545
- writeFileSync36(mdPath, refreshed, "utf-8");
46004
+ writeFileSync37(mdPath, refreshed, "utf-8");
45546
46005
  } catch {
45547
46006
  }
45548
46007
  }
@@ -45617,8 +46076,8 @@ Example output: ["talking-head","prop-driven"]`;
45617
46076
  // src/lib/marketing/competitors.ts
45618
46077
  import { spawn as spawn6 } from "child_process";
45619
46078
  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";
46079
+ import { existsSync as existsSync72, mkdirSync as mkdirSync32, statfsSync } from "fs";
46080
+ import { dirname as dirname41, join as join68, basename as basename20, extname as extname4 } from "path";
45622
46081
  function which(cmd) {
45623
46082
  const r = spawnSync3(process.platform === "win32" ? "where" : "which", [cmd], { encoding: "utf8" });
45624
46083
  if (r.status === 0) return (r.stdout || "").trim().split("\n")[0] || null;
@@ -45695,8 +46154,8 @@ ${h.installHints.join("\n")}`);
45695
46154
  skip_transcripts: !!opts.skipTranscripts,
45696
46155
  skip_frames: !!opts.skipFrames
45697
46156
  });
45698
- const outDir = join67(MARKETING_PATHS.competitorsDir(), "_ingest-tmp", run2.id);
45699
- mkdirSync31(outDir, { recursive: true });
46157
+ const outDir = join68(MARKETING_PATHS.competitorsDir(), "_ingest-tmp", run2.id);
46158
+ mkdirSync32(outDir, { recursive: true });
45700
46159
  const args = [
45701
46160
  "-m",
45702
46161
  "reinfluence",
@@ -45796,15 +46255,15 @@ stderr: ${stderrBuf.slice(0, 1e3)}`));
45796
46255
  return { runId: run2.id, postsIngested, warnings, errors };
45797
46256
  }
45798
46257
  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;
46258
+ const handleDir = join68(MARKETING_PATHS.competitorsDir(), evt.handle);
46259
+ const postsDir = join68(handleDir, "posts");
46260
+ const mediaDir = join68(handleDir, "_media", evt.shortcode);
46261
+ mkdirSync32(postsDir, { recursive: true });
46262
+ mkdirSync32(mediaDir, { recursive: true });
46263
+ const finalVideoPath = evt.video_path ? moveAsset(evt.video_path, join68(mediaDir, basename20(evt.video_path))) : null;
45805
46264
  const finalFramePaths = [];
45806
46265
  for (const fr of evt.frames) {
45807
- const finalP = moveAsset(fr.path, join67(mediaDir, "frames", basename20(fr.path)));
46266
+ const finalP = moveAsset(fr.path, join68(mediaDir, "frames", basename20(fr.path)));
45808
46267
  finalFramePaths.push(finalP);
45809
46268
  }
45810
46269
  const id = `${evt.handle}__${evt.shortcode}`;
@@ -45824,14 +46283,14 @@ function persistPost(evt) {
45824
46283
  ingested_at: (/* @__PURE__ */ new Date()).toISOString(),
45825
46284
  asset_paths: { video: finalVideoPath, frames: finalFramePaths }
45826
46285
  };
45827
- const jsonPath = join67(postsDir, `${evt.shortcode}.json`);
45828
- const bridgePath = join67(postsDir, `${evt.shortcode}.md`);
46286
+ const jsonPath = join68(postsDir, `${evt.shortcode}.json`);
46287
+ const bridgePath = join68(postsDir, `${evt.shortcode}.md`);
45829
46288
  writeJsonWithBridge(jsonPath, bridgePath, json, renderPostBridge(json));
45830
- const metaPath = join67(handleDir, "meta.json");
45831
- if (!existsSync71(metaPath)) {
46289
+ const metaPath = join68(handleDir, "meta.json");
46290
+ if (!existsSync72(metaPath)) {
45832
46291
  writeJsonWithBridge(
45833
46292
  metaPath,
45834
- join67(handleDir, "meta.md"),
46293
+ join68(handleDir, "meta.md"),
45835
46294
  { handle: evt.handle, first_seen_at: (/* @__PURE__ */ new Date()).toISOString() },
45836
46295
  `---
45837
46296
  id: competitor_${evt.handle}
@@ -45848,8 +46307,8 @@ First seen: ${(/* @__PURE__ */ new Date()).toISOString()}
45848
46307
  return jsonPath;
45849
46308
  }
45850
46309
  function moveAsset(src, dest) {
45851
- if (!existsSync71(src)) return dest;
45852
- mkdirSync31(dirname40(dest), { recursive: true });
46310
+ if (!existsSync72(src)) return dest;
46311
+ mkdirSync32(dirname41(dest), { recursive: true });
45853
46312
  const fs = __require("fs");
45854
46313
  try {
45855
46314
  fs.renameSync(src, dest);
@@ -45910,8 +46369,8 @@ var init_competitors = __esm({
45910
46369
  });
45911
46370
 
45912
46371
  // 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";
46372
+ import { existsSync as existsSync73, readdirSync as readdirSync16, statSync as statSync11 } from "fs";
46373
+ import { join as join69 } from "path";
45915
46374
  function registerMarketingCompetitor(parent) {
45916
46375
  const cmd = parent.command("competitor").description("Ingest competitor IG / YouTube content (Reinfluence pipeline).");
45917
46376
  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 +46420,13 @@ function registerMarketingCompetitor(parent) {
45961
46420
  });
45962
46421
  cmd.command("list").description("List ingested competitor handles.").action(() => {
45963
46422
  const dir = MARKETING_PATHS.competitorsDir();
45964
- if (!existsSync72(dir)) {
46423
+ if (!existsSync73(dir)) {
45965
46424
  info("No competitors ingested yet.");
45966
46425
  return;
45967
46426
  }
45968
46427
  const handles = readdirSync16(dir).filter((name) => {
45969
46428
  if (name.startsWith("_") || name.startsWith(".")) return false;
45970
- const full = join68(dir, name);
46429
+ const full = join69(dir, name);
45971
46430
  try {
45972
46431
  return statSync11(full).isDirectory();
45973
46432
  } catch {
@@ -45980,8 +46439,8 @@ function registerMarketingCompetitor(parent) {
45980
46439
  }
45981
46440
  console.log(header("Competitors"));
45982
46441
  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;
46442
+ const postsDir = join69(dir, handle, "posts");
46443
+ const postCount = existsSync73(postsDir) ? readdirSync16(postsDir).filter((f) => f.endsWith(".json")).length : 0;
45985
46444
  console.log(` ${source_default.cyan("@" + handle)} ${source_default.dim(`${postCount} post(s)`)}`);
45986
46445
  }
45987
46446
  });
@@ -45994,11 +46453,11 @@ function registerMarketingCompetitor(parent) {
45994
46453
  }
45995
46454
  info(`Provider: ${provider.provider}`);
45996
46455
  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()) : [];
46456
+ const handles = opts.handle ? [opts.handle] : existsSync73(competitorsDir) ? readdirSync16(competitorsDir).filter((h) => !h.startsWith("_") && statSync11(join69(competitorsDir, h)).isDirectory()) : [];
45998
46457
  const matches = [];
45999
46458
  for (const h of handles) {
46000
- const candidate = join68(competitorsDir, h, "posts", `${shortcode}.json`);
46001
- if (existsSync72(candidate)) matches.push(candidate);
46459
+ const candidate = join69(competitorsDir, h, "posts", `${shortcode}.json`);
46460
+ if (existsSync73(candidate)) matches.push(candidate);
46002
46461
  }
46003
46462
  if (matches.length === 0) {
46004
46463
  error(`No post JSON found for shortcode "${shortcode}".`);
@@ -46033,18 +46492,18 @@ function registerMarketingCompetitor(parent) {
46033
46492
  process.exit(1);
46034
46493
  }
46035
46494
  const competitorsDir = MARKETING_PATHS.competitorsDir();
46036
- if (!existsSync72(competitorsDir)) {
46495
+ if (!existsSync73(competitorsDir)) {
46037
46496
  warn("No competitors directory yet \u2014 nothing to relabel.");
46038
46497
  return;
46039
46498
  }
46040
- const handles = readdirSync16(competitorsDir).filter((h) => !h.startsWith("_") && statSync11(join68(competitorsDir, h)).isDirectory());
46499
+ const handles = readdirSync16(competitorsDir).filter((h) => !h.startsWith("_") && statSync11(join69(competitorsDir, h)).isDirectory());
46041
46500
  let labeled = 0;
46042
46501
  let skipped = 0;
46043
46502
  for (const h of handles) {
46044
- const postsDir = join68(competitorsDir, h, "posts");
46045
- if (!existsSync72(postsDir)) continue;
46503
+ const postsDir = join69(competitorsDir, h, "posts");
46504
+ if (!existsSync73(postsDir)) continue;
46046
46505
  for (const f of readdirSync16(postsDir).filter((n) => n.endsWith(".json"))) {
46047
- const path2 = join68(postsDir, f);
46506
+ const path2 = join69(postsDir, f);
46048
46507
  if (opts.dryRun) {
46049
46508
  info(`would relabel: ${path2}`);
46050
46509
  continue;
@@ -46091,8 +46550,8 @@ var init_competitor = __esm({
46091
46550
  });
46092
46551
 
46093
46552
  // 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";
46553
+ import { existsSync as existsSync74, mkdirSync as mkdirSync33, readFileSync as readFileSync53, writeFileSync as writeFileSync38, statSync as statSync12, openSync as openSync2, readSync, closeSync as closeSync2 } from "fs";
46554
+ import { dirname as dirname42, basename as basename21 } from "path";
46096
46555
  import { randomUUID as randomUUID3 } from "crypto";
46097
46556
  function getQueue(accountId) {
46098
46557
  let q = writeQueues.get(accountId);
@@ -46142,17 +46601,17 @@ function idemCachePath(key) {
46142
46601
  }
46143
46602
  function readIdem(key) {
46144
46603
  const p = idemCachePath(key);
46145
- if (!existsSync73(p)) return null;
46604
+ if (!existsSync74(p)) return null;
46146
46605
  try {
46147
- return JSON.parse(readFileSync52(p, "utf8"));
46606
+ return JSON.parse(readFileSync53(p, "utf8"));
46148
46607
  } catch {
46149
46608
  return null;
46150
46609
  }
46151
46610
  }
46152
46611
  function writeIdem(rec) {
46153
46612
  const p = idemCachePath(rec.key);
46154
- mkdirSync32(dirname41(p), { recursive: true });
46155
- writeFileSync37(p, JSON.stringify(rec, null, 2) + "\n", "utf8");
46613
+ mkdirSync33(dirname42(p), { recursive: true });
46614
+ writeFileSync38(p, JSON.stringify(rec, null, 2) + "\n", "utf8");
46156
46615
  }
46157
46616
  function backoffMs(attempt, hintSec) {
46158
46617
  if (hintSec != null && Number.isFinite(hintSec) && hintSec > 0) {
@@ -46420,7 +46879,7 @@ async function singleShotVideoUpload(ctx, filepath, fields) {
46420
46879
  if (fields.name) form.set("name", fields.name);
46421
46880
  if (fields.title) form.set("title", fields.title);
46422
46881
  if (fields.description) form.set("description", fields.description);
46423
- const buffer = readFileSync52(filepath);
46882
+ const buffer = readFileSync53(filepath);
46424
46883
  const blob = new Blob([new Uint8Array(buffer)], { type: "video/mp4" });
46425
46884
  form.set("source", blob, basename21(filepath));
46426
46885
  const resp = await fetch(url, {
@@ -46469,7 +46928,7 @@ async function uploadImageFile(ctx, filepath) {
46469
46928
  return withWriteSlot(ctx.adAccountId, async () => {
46470
46929
  const url = buildUrl(ctx, { method: "POST", path: `${ctx.adAccountId}/adimages` });
46471
46930
  const form = new FormData();
46472
- const buffer = readFileSync52(filepath);
46931
+ const buffer = readFileSync53(filepath);
46473
46932
  const blob = new Blob([new Uint8Array(buffer)], { type: "image/png" });
46474
46933
  form.set("filename", blob, basename21(filepath));
46475
46934
  const resp = await fetch(url, {
@@ -46888,7 +47347,7 @@ var init_account = __esm({
46888
47347
  });
46889
47348
 
46890
47349
  // src/lib/marketing/hypothesis.ts
46891
- import { existsSync as existsSync74, readFileSync as readFileSync53 } from "fs";
47350
+ import { existsSync as existsSync75, readFileSync as readFileSync54 } from "fs";
46892
47351
  function validateHypothesis(raw, options2 = {}) {
46893
47352
  const errors = [];
46894
47353
  const fieldErrors = {};
@@ -46955,12 +47414,12 @@ function validateHypothesis(raw, options2 = {}) {
46955
47414
  };
46956
47415
  }
46957
47416
  function loadHypothesisFile(path2, options2 = {}) {
46958
- if (!existsSync74(path2)) {
47417
+ if (!existsSync75(path2)) {
46959
47418
  return { ok: false, errors: [`Hypothesis file not found: ${path2}`] };
46960
47419
  }
46961
47420
  let parsed;
46962
47421
  try {
46963
- parsed = JSON.parse(readFileSync53(path2, "utf8"));
47422
+ parsed = JSON.parse(readFileSync54(path2, "utf8"));
46964
47423
  } catch (e) {
46965
47424
  return { ok: false, errors: [`Failed to parse JSON at ${path2}: ${e.message}`] };
46966
47425
  }
@@ -47148,8 +47607,8 @@ var init_cohort2 = __esm({
47148
47607
  });
47149
47608
 
47150
47609
  // 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";
47610
+ import { existsSync as existsSync76, readFileSync as readFileSync55, mkdirSync as mkdirSync34, writeFileSync as writeFileSync39, readdirSync as readdirSync17, statSync as statSync13 } from "fs";
47611
+ import { join as join70 } from "path";
47153
47612
  import { randomBytes as randomBytes3 } from "crypto";
47154
47613
  function snapshotFilename(entityId, pulledAt) {
47155
47614
  const yyyy = pulledAt.getUTCFullYear();
@@ -47160,30 +47619,30 @@ function snapshotFilename(entityId, pulledAt) {
47160
47619
  return `${safe}__${yyyy}-${mm}-${dd}-${hh}.json`;
47161
47620
  }
47162
47621
  function indexPath() {
47163
- return join69(MARKETING_PATHS.insightsDir(), "_index.json");
47622
+ return join70(MARKETING_PATHS.insightsDir(), "_index.json");
47164
47623
  }
47165
47624
  function readIndex() {
47166
47625
  const p = indexPath();
47167
- if (!existsSync75(p)) return { latest: {}, updated_at: "1970-01-01T00:00:00Z" };
47626
+ if (!existsSync76(p)) return { latest: {}, updated_at: "1970-01-01T00:00:00Z" };
47168
47627
  try {
47169
- return JSON.parse(readFileSync54(p, "utf8"));
47628
+ return JSON.parse(readFileSync55(p, "utf8"));
47170
47629
  } catch {
47171
47630
  return { latest: {}, updated_at: "1970-01-01T00:00:00Z" };
47172
47631
  }
47173
47632
  }
47174
47633
  function writeIndex(idx) {
47175
47634
  const p = indexPath();
47176
- mkdirSync33(MARKETING_PATHS.insightsDir(), { recursive: true });
47635
+ mkdirSync34(MARKETING_PATHS.insightsDir(), { recursive: true });
47177
47636
  const tmp = `${p}.tmp.${process.pid}.${randomBytes3(4).toString("hex")}`;
47178
- writeFileSync38(tmp, JSON.stringify(idx, null, 2) + "\n", "utf8");
47637
+ writeFileSync39(tmp, JSON.stringify(idx, null, 2) + "\n", "utf8");
47179
47638
  __require("fs").renameSync(tmp, p);
47180
47639
  }
47181
47640
  function saveInsightsSnapshot(snap) {
47182
- mkdirSync33(MARKETING_PATHS.insightsDir(), { recursive: true });
47641
+ mkdirSync34(MARKETING_PATHS.insightsDir(), { recursive: true });
47183
47642
  const filename = snapshotFilename(snap.entity_id, new Date(snap.pulled_at));
47184
- const fullPath = join69(MARKETING_PATHS.insightsDir(), filename);
47643
+ const fullPath = join70(MARKETING_PATHS.insightsDir(), filename);
47185
47644
  const tmp = `${fullPath}.tmp.${process.pid}.${randomBytes3(4).toString("hex")}`;
47186
- writeFileSync38(tmp, JSON.stringify(snap, null, 2) + "\n", "utf8");
47645
+ writeFileSync39(tmp, JSON.stringify(snap, null, 2) + "\n", "utf8");
47187
47646
  __require("fs").renameSync(tmp, fullPath);
47188
47647
  const idx = readIndex();
47189
47648
  idx.latest[snap.entity_id] = filename;
@@ -47195,10 +47654,10 @@ function getCachedInsights(entityId) {
47195
47654
  const idx = readIndex();
47196
47655
  const filename = idx.latest[entityId];
47197
47656
  if (!filename) return null;
47198
- const fullPath = join69(MARKETING_PATHS.insightsDir(), filename);
47199
- if (!existsSync75(fullPath)) return null;
47657
+ const fullPath = join70(MARKETING_PATHS.insightsDir(), filename);
47658
+ if (!existsSync76(fullPath)) return null;
47200
47659
  try {
47201
- const snap = JSON.parse(readFileSync54(fullPath, "utf8"));
47660
+ const snap = JSON.parse(readFileSync55(fullPath, "utf8"));
47202
47661
  const ageMs = Date.now() - new Date(snap.pulled_at).getTime();
47203
47662
  if (ageMs > INSIGHTS_TTL_MS) return null;
47204
47663
  return snap;
@@ -47210,20 +47669,20 @@ function getLatestSnapshot(entityId) {
47210
47669
  const idx = readIndex();
47211
47670
  const filename = idx.latest[entityId];
47212
47671
  if (!filename) return null;
47213
- const fullPath = join69(MARKETING_PATHS.insightsDir(), filename);
47214
- if (!existsSync75(fullPath)) return null;
47672
+ const fullPath = join70(MARKETING_PATHS.insightsDir(), filename);
47673
+ if (!existsSync76(fullPath)) return null;
47215
47674
  try {
47216
- return JSON.parse(readFileSync54(fullPath, "utf8"));
47675
+ return JSON.parse(readFileSync55(fullPath, "utf8"));
47217
47676
  } catch {
47218
47677
  return null;
47219
47678
  }
47220
47679
  }
47221
47680
  function getPriorSnapshot(entityId, beforeMs) {
47222
47681
  const dir = MARKETING_PATHS.insightsDir();
47223
- if (!existsSync75(dir)) return null;
47682
+ if (!existsSync76(dir)) return null;
47224
47683
  const safe = entityId.replace(/[^A-Za-z0-9_-]/g, "_");
47225
47684
  const candidates = readdirSync17(dir).filter((f) => f.startsWith(`${safe}__`) && f.endsWith(".json")).map((f) => {
47226
- const p = join69(dir, f);
47685
+ const p = join70(dir, f);
47227
47686
  const stat = statSync13(p);
47228
47687
  return { f, p, mtimeMs: stat.mtimeMs };
47229
47688
  }).sort((a, b) => b.mtimeMs - a.mtimeMs);
@@ -47231,7 +47690,7 @@ function getPriorSnapshot(entityId, beforeMs) {
47231
47690
  for (const c of candidates) {
47232
47691
  if (c.mtimeMs <= cutoff) {
47233
47692
  try {
47234
- return JSON.parse(readFileSync54(c.p, "utf8"));
47693
+ return JSON.parse(readFileSync55(c.p, "utf8"));
47235
47694
  } catch {
47236
47695
  continue;
47237
47696
  }
@@ -47867,8 +48326,8 @@ var init_kill = __esm({
47867
48326
  });
47868
48327
 
47869
48328
  // 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";
48329
+ import { readFileSync as readFileSync56, readdirSync as readdirSync18, statSync as statSync14 } from "fs";
48330
+ import { join as join71 } from "path";
47872
48331
  function registerMarketingDoctor(parent) {
47873
48332
  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
48333
  console.log(header("Marketing doctor"));
@@ -47949,7 +48408,7 @@ function scanForSecrets(root) {
47949
48408
  for (const file of walkText(root)) {
47950
48409
  let txt;
47951
48410
  try {
47952
- txt = readFileSync55(file, "utf8");
48411
+ txt = readFileSync56(file, "utf8");
47953
48412
  } catch {
47954
48413
  continue;
47955
48414
  }
@@ -47976,7 +48435,7 @@ function* walkText(dir) {
47976
48435
  }
47977
48436
  for (const e of entries) {
47978
48437
  if (e.startsWith(".") && (e === ".env" || e === ".env.local")) continue;
47979
- const full = join70(dir, e);
48438
+ const full = join71(dir, e);
47980
48439
  let stat;
47981
48440
  try {
47982
48441
  stat = statSync14(full);
@@ -48014,8 +48473,8 @@ var init_doctor2 = __esm({
48014
48473
  });
48015
48474
 
48016
48475
  // 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";
48476
+ import { existsSync as existsSync78, readFileSync as readFileSync57, readdirSync as readdirSync19 } from "fs";
48477
+ import { join as join72 } from "path";
48019
48478
  function dirFor(kind) {
48020
48479
  switch (kind) {
48021
48480
  case "campaign":
@@ -48034,24 +48493,24 @@ function newEntityId(kind) {
48034
48493
  }
48035
48494
  function entityPaths(kind, id) {
48036
48495
  const d = dirFor(kind);
48037
- return { json: join71(d, `${id}.json`), md: join71(d, `${id}.md`) };
48496
+ return { json: join72(d, `${id}.json`), md: join72(d, `${id}.md`) };
48038
48497
  }
48039
48498
  function loadEntity(kind, id) {
48040
48499
  const { json } = entityPaths(kind, id);
48041
- if (!existsSync77(json)) return null;
48500
+ if (!existsSync78(json)) return null;
48042
48501
  try {
48043
- return JSON.parse(readFileSync56(json, "utf8"));
48502
+ return JSON.parse(readFileSync57(json, "utf8"));
48044
48503
  } catch {
48045
48504
  return null;
48046
48505
  }
48047
48506
  }
48048
48507
  function listEntities(kind) {
48049
48508
  const d = dirFor(kind);
48050
- if (!existsSync77(d)) return [];
48509
+ if (!existsSync78(d)) return [];
48051
48510
  const out = [];
48052
48511
  for (const f of readdirSync19(d).filter((x) => x.endsWith(".json"))) {
48053
48512
  try {
48054
- out.push(JSON.parse(readFileSync56(join71(d, f), "utf8")));
48513
+ out.push(JSON.parse(readFileSync57(join72(d, f), "utf8")));
48055
48514
  } catch {
48056
48515
  }
48057
48516
  }
@@ -48245,7 +48704,7 @@ var init_campaign = __esm({
48245
48704
  });
48246
48705
 
48247
48706
  // src/cli/commands/marketing/adset.ts
48248
- import { existsSync as existsSync78, readFileSync as readFileSync57 } from "fs";
48707
+ import { existsSync as existsSync79, readFileSync as readFileSync58 } from "fs";
48249
48708
  function registerMarketingAdSet(parent) {
48250
48709
  const cmd = parent.command("adset").description("Manage adsets.");
48251
48710
  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 +48724,13 @@ function registerMarketingAdSet(parent) {
48265
48724
  }
48266
48725
  throw e;
48267
48726
  }
48268
- if (!existsSync78(opts.targeting)) {
48727
+ if (!existsSync79(opts.targeting)) {
48269
48728
  error(`Targeting file not found: ${opts.targeting}`);
48270
48729
  process.exit(1);
48271
48730
  }
48272
48731
  let targeting;
48273
48732
  try {
48274
- targeting = JSON.parse(readFileSync57(opts.targeting, "utf8"));
48733
+ targeting = JSON.parse(readFileSync58(opts.targeting, "utf8"));
48275
48734
  } catch (e) {
48276
48735
  error(`Failed to parse targeting JSON: ${e.message}`);
48277
48736
  process.exit(1);
@@ -48528,12 +48987,12 @@ var init_creative = __esm({
48528
48987
  });
48529
48988
 
48530
48989
  // src/cli/commands/marketing/asset.ts
48531
- import { existsSync as existsSync79, statSync as statSync15 } from "fs";
48990
+ import { existsSync as existsSync80, statSync as statSync15 } from "fs";
48532
48991
  import { extname as extname5 } from "path";
48533
48992
  function registerMarketingAsset(parent) {
48534
48993
  const cmd = parent.command("asset").description("Upload creative assets to Meta.");
48535
48994
  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)) {
48995
+ if (!existsSync80(path2)) {
48537
48996
  error(`File not found: ${path2}`);
48538
48997
  process.exit(1);
48539
48998
  }
@@ -48701,8 +49160,8 @@ var init_ad = __esm({
48701
49160
  });
48702
49161
 
48703
49162
  // 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";
49163
+ import { existsSync as existsSync81, readFileSync as readFileSync59, writeFileSync as writeFileSync40, mkdirSync as mkdirSync35, renameSync as renameSync8, readdirSync as readdirSync20 } from "fs";
49164
+ import { dirname as dirname43, join as join73, basename as basename22 } from "path";
48706
49165
  import { randomBytes as randomBytes4 } from "crypto";
48707
49166
  function buildLaunchSummary(cohortId) {
48708
49167
  const cohort = loadCohort(cohortId);
@@ -48746,15 +49205,15 @@ function isoTs2() {
48746
49205
  return (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
48747
49206
  }
48748
49207
  function atomicWriteFile3(path2, data) {
48749
- mkdirSync34(dirname42(path2), { recursive: true });
49208
+ mkdirSync35(dirname43(path2), { recursive: true });
48750
49209
  const tmp = `${path2}.tmp.${process.pid}.${randomBytes4(4).toString("hex")}`;
48751
- writeFileSync39(tmp, data, "utf8");
49210
+ writeFileSync40(tmp, data, "utf8");
48752
49211
  renameSync8(tmp, path2);
48753
49212
  }
48754
49213
  function readWal(path2) {
48755
- if (!existsSync80(path2)) return null;
49214
+ if (!existsSync81(path2)) return null;
48756
49215
  try {
48757
- return JSON.parse(readFileSync58(path2, "utf8"));
49216
+ return JSON.parse(readFileSync59(path2, "utf8"));
48758
49217
  } catch {
48759
49218
  return null;
48760
49219
  }
@@ -48764,13 +49223,13 @@ function writeWal(path2, wal) {
48764
49223
  }
48765
49224
  function findWalByRunId(runId) {
48766
49225
  const dir = MARKETING_PATHS.runsDir();
48767
- if (!existsSync80(dir)) return null;
49226
+ if (!existsSync81(dir)) return null;
48768
49227
  for (const f of readdirSync20(dir)) {
48769
49228
  if (!f.endsWith(".json")) continue;
48770
49229
  if (f.startsWith("by-idem")) continue;
48771
49230
  const stem = f.replace(/\.json$/, "");
48772
49231
  if (stem === runId || f === runId || basename22(f, ".json") === runId) {
48773
- return join72(dir, f);
49232
+ return join73(dir, f);
48774
49233
  }
48775
49234
  }
48776
49235
  return null;
@@ -48810,7 +49269,7 @@ function createLaunchWal(args) {
48810
49269
  flipped_count: 0,
48811
49270
  error: null
48812
49271
  };
48813
- const walPath = join72(MARKETING_PATHS.runsDir(), `${id}.json`);
49272
+ const walPath = join73(MARKETING_PATHS.runsDir(), `${id}.json`);
48814
49273
  writeWal(walPath, wal);
48815
49274
  return { walPath, wal };
48816
49275
  }
@@ -49041,7 +49500,7 @@ var init_launch2 = __esm({
49041
49500
  });
49042
49501
 
49043
49502
  // src/cli/commands/marketing/learnings.ts
49044
- import { existsSync as existsSync81, readFileSync as readFileSync59 } from "fs";
49503
+ import { existsSync as existsSync82, readFileSync as readFileSync60 } from "fs";
49045
49504
  function registerMarketingLearnings(parent) {
49046
49505
  const cmd = parent.command("learnings").description("Performance Monitor learnings ledger (per-day .md + index).");
49047
49506
  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 +49643,8 @@ async function resolveBody(body, bodyFile) {
49184
49643
  if (body) return body;
49185
49644
  if (bodyFile === "-") return readStdin3();
49186
49645
  if (bodyFile) {
49187
- if (!existsSync81(bodyFile)) throw new Error(`Body file not found: ${bodyFile}`);
49188
- return readFileSync59(bodyFile, "utf8");
49646
+ if (!existsSync82(bodyFile)) throw new Error(`Body file not found: ${bodyFile}`);
49647
+ return readFileSync60(bodyFile, "utf8");
49189
49648
  }
49190
49649
  return null;
49191
49650
  }
@@ -49215,29 +49674,29 @@ var init_learnings2 = __esm({
49215
49674
 
49216
49675
  // src/lib/marketing/rem-sleep.ts
49217
49676
  import {
49218
- existsSync as existsSync82,
49219
- mkdirSync as mkdirSync35,
49220
- readFileSync as readFileSync60,
49221
- writeFileSync as writeFileSync40,
49677
+ existsSync as existsSync83,
49678
+ mkdirSync as mkdirSync36,
49679
+ readFileSync as readFileSync61,
49680
+ writeFileSync as writeFileSync41,
49222
49681
  readdirSync as readdirSync21,
49223
49682
  statSync as statSync16,
49224
49683
  unlinkSync as unlinkSync3,
49225
49684
  renameSync as renameSync9
49226
49685
  } from "fs";
49227
- import { dirname as dirname43, join as join73 } from "path";
49686
+ import { dirname as dirname44, join as join74 } from "path";
49228
49687
  import { randomBytes as randomBytes5 } from "crypto";
49229
49688
  function atomicWriteFile4(path2, data) {
49230
- mkdirSync35(dirname43(path2), { recursive: true });
49689
+ mkdirSync36(dirname44(path2), { recursive: true });
49231
49690
  const tmp = `${path2}.tmp.${process.pid}.${randomBytes5(4).toString("hex")}`;
49232
- writeFileSync40(tmp, data, "utf8");
49691
+ writeFileSync41(tmp, data, "utf8");
49233
49692
  renameSync9(tmp, path2);
49234
49693
  }
49235
49694
  function pruneRuns(opts = {}) {
49236
49695
  const keepLast = opts.keepLast ?? 100;
49237
49696
  const dir = MARKETING_PATHS.runsDir();
49238
- if (!existsSync82(dir)) return { scanned: 0, kept: 0, deleted: 0, deletedFiles: [] };
49697
+ if (!existsSync83(dir)) return { scanned: 0, kept: 0, deleted: 0, deletedFiles: [] };
49239
49698
  const files = readdirSync21(dir).filter((f) => f.endsWith(".json")).map((f) => {
49240
- const p = join73(dir, f);
49699
+ const p = join74(dir, f);
49241
49700
  try {
49242
49701
  return { f, p, mtimeMs: statSync16(p).mtimeMs };
49243
49702
  } catch {
@@ -49271,13 +49730,13 @@ function compactInsights(opts = {}) {
49271
49730
  const weeklyAfterDays = opts.weeklyAfterDays ?? 14;
49272
49731
  const now = opts.now ?? /* @__PURE__ */ new Date();
49273
49732
  const dir = MARKETING_PATHS.insightsDir();
49274
- if (!existsSync82(dir)) return { scanned: 0, kept: 0, deleted: 0, deletedFiles: [] };
49733
+ if (!existsSync83(dir)) return { scanned: 0, kept: 0, deleted: 0, deletedFiles: [] };
49275
49734
  const files = [];
49276
49735
  for (const f of readdirSync21(dir)) {
49277
49736
  if (!f.endsWith(".json") || f.startsWith("_")) continue;
49278
49737
  const m = f.match(SNAP_RE);
49279
49738
  if (!m) continue;
49280
- const p = join73(dir, f);
49739
+ const p = join74(dir, f);
49281
49740
  try {
49282
49741
  const stat = statSync16(p);
49283
49742
  files.push({ f, p, mtimeMs: stat.mtimeMs, entityId: m[1], bucket: m[2] });
@@ -49343,7 +49802,7 @@ function mergeDailyLearnings(opts = {}) {
49343
49802
  const retainDays = opts.retainDays ?? 7;
49344
49803
  const now = opts.now ?? /* @__PURE__ */ new Date();
49345
49804
  const dir = MARKETING_PATHS.learningsDir();
49346
- if (!existsSync82(dir)) {
49805
+ if (!existsSync83(dir)) {
49347
49806
  return { scanned: 0, merged: 0, archivePath: null, droppedRejected: 0, mergedFiles: [] };
49348
49807
  }
49349
49808
  const dayMs = 24 * 60 * 60 * 1e3;
@@ -49354,7 +49813,7 @@ function mergeDailyLearnings(opts = {}) {
49354
49813
  if (!m) continue;
49355
49814
  const date = m[1];
49356
49815
  const dateMs = (/* @__PURE__ */ new Date(`${date}T00:00:00Z`)).getTime();
49357
- if (dateMs < cutoff) candidates.push({ f, p: join73(dir, f), date });
49816
+ if (dateMs < cutoff) candidates.push({ f, p: join74(dir, f), date });
49358
49817
  }
49359
49818
  if (candidates.length === 0) {
49360
49819
  return { scanned: 0, merged: 0, archivePath: null, droppedRejected: 0, mergedFiles: [] };
@@ -49368,10 +49827,10 @@ function mergeDailyLearnings(opts = {}) {
49368
49827
  const mergedFiles = [];
49369
49828
  let lastArchivePath = null;
49370
49829
  for (const [q, list] of byQuarter) {
49371
- const archivePath = join73(dir, `_archive-${q}.md`);
49830
+ const archivePath = join74(dir, `_archive-${q}.md`);
49372
49831
  list.sort((a, b) => a.date.localeCompare(b.date));
49373
49832
  for (const c of list) {
49374
- const existingArchive = existsSync82(archivePath) ? readFileSync60(archivePath, "utf8") : `# Marketing learnings archive \u2014 ${q}
49833
+ const existingArchive = existsSync83(archivePath) ? readFileSync61(archivePath, "utf8") : `# Marketing learnings archive \u2014 ${q}
49375
49834
  `;
49376
49835
  const dateMarker = `# Marketing learnings \u2014 ${c.date}`;
49377
49836
  const alreadyMerged = existingArchive.includes(dateMarker);
@@ -49380,7 +49839,7 @@ function mergeDailyLearnings(opts = {}) {
49380
49839
  continue;
49381
49840
  }
49382
49841
  if (!alreadyMerged) {
49383
- const body = readFileSync60(c.p, "utf8").trimEnd();
49842
+ const body = readFileSync61(c.p, "utf8").trimEnd();
49384
49843
  const next2 = existingArchive.trimEnd() + "\n\n" + body + "\n";
49385
49844
  atomicWriteFile4(archivePath, next2);
49386
49845
  }
@@ -49423,14 +49882,14 @@ function quarterKey(yyyymmdd) {
49423
49882
  }
49424
49883
  function redactRunsSweep(opts = {}) {
49425
49884
  const dir = MARKETING_PATHS.runsDir();
49426
- if (!existsSync82(dir)) return { scanned: 0, rewritten: 0, rewrittenFiles: [] };
49885
+ if (!existsSync83(dir)) return { scanned: 0, rewritten: 0, rewrittenFiles: [] };
49427
49886
  const files = readdirSync21(dir).filter((f) => f.endsWith(".json"));
49428
49887
  const rewrittenFiles = [];
49429
49888
  for (const f of files) {
49430
- const p = join73(dir, f);
49889
+ const p = join74(dir, f);
49431
49890
  let raw;
49432
49891
  try {
49433
- raw = readFileSync60(p, "utf8");
49892
+ raw = readFileSync61(p, "utf8");
49434
49893
  } catch {
49435
49894
  continue;
49436
49895
  }
@@ -49452,7 +49911,7 @@ function redactRunsSweep(opts = {}) {
49452
49911
  function runRemSleep(opts = {}) {
49453
49912
  const ranAt = (opts.now ?? /* @__PURE__ */ new Date()).toISOString();
49454
49913
  const root = marketingRootIfExists();
49455
- if (!root || !existsSync82(root)) {
49914
+ if (!root || !existsSync83(root)) {
49456
49915
  return {
49457
49916
  ranAt,
49458
49917
  marketingPresent: false,
@@ -49474,7 +49933,7 @@ function runRemSleep(opts = {}) {
49474
49933
  now: opts.now
49475
49934
  });
49476
49935
  const redaction = redactRunsSweep({ dryRun: opts.dryRun });
49477
- void mkdirSync35;
49936
+ void mkdirSync36;
49478
49937
  return { ranAt, marketingPresent: true, runs, insights, learnings, redaction };
49479
49938
  }
49480
49939
  var SNAP_RE;
@@ -49571,9 +50030,9 @@ var init_git_guard = __esm({
49571
50030
  });
49572
50031
 
49573
50032
  // 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";
50033
+ import { existsSync as existsSync84, readFileSync as readFileSync62, writeFileSync as writeFileSync42, chmodSync as chmodSync3, mkdirSync as mkdirSync37, statSync as statSync17 } from "fs";
49575
50034
  import { execFileSync as execFileSync6 } from "child_process";
49576
- import { join as join74 } from "path";
50035
+ import { join as join75 } from "path";
49577
50036
  function findGitDir(cwd = process.cwd()) {
49578
50037
  try {
49579
50038
  const out = execFileSync6("git", ["rev-parse", "--git-dir"], {
@@ -49582,7 +50041,7 @@ function findGitDir(cwd = process.cwd()) {
49582
50041
  stdio: ["ignore", "pipe", "ignore"]
49583
50042
  }).trim();
49584
50043
  if (!out) return null;
49585
- return out.startsWith("/") ? out : join74(cwd, out);
50044
+ return out.startsWith("/") ? out : join75(cwd, out);
49586
50045
  } catch {
49587
50046
  return null;
49588
50047
  }
@@ -49613,11 +50072,11 @@ function registerMarketingHooks(parent) {
49613
50072
  error("Not inside a git repository (or `git` is not on PATH).");
49614
50073
  process.exit(1);
49615
50074
  }
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");
50075
+ const hooksDir = join75(gitDir, "hooks");
50076
+ mkdirSync37(hooksDir, { recursive: true });
50077
+ const target = join75(hooksDir, "pre-commit");
50078
+ if (existsSync84(target)) {
50079
+ const existing = readFileSync62(target, "utf-8");
49621
50080
  if (existing.includes(MANAGED_MARKER)) {
49622
50081
  info("pre-commit hook already managed by dreamcontext \u2014 refreshing.");
49623
50082
  } else if (!opts.force) {
@@ -49629,7 +50088,7 @@ function registerMarketingHooks(parent) {
49629
50088
  warn("Overwriting existing pre-commit hook (--force).");
49630
50089
  }
49631
50090
  }
49632
- writeFileSync41(target, HOOK_LAUNCHER, "utf-8");
50091
+ writeFileSync42(target, HOOK_LAUNCHER, "utf-8");
49633
50092
  try {
49634
50093
  chmodSync3(target, 493);
49635
50094
  } catch {
@@ -49668,26 +50127,26 @@ exec dreamcontext mk hooks check-staged
49668
50127
  });
49669
50128
 
49670
50129
  // src/lib/marketing/council-personas.ts
49671
- import { existsSync as existsSync84, readFileSync as readFileSync62, readdirSync as readdirSync22 } from "fs";
50130
+ import { existsSync as existsSync85, readFileSync as readFileSync63, readdirSync as readdirSync22 } from "fs";
49672
50131
  import { fileURLToPath as fileURLToPath9 } from "url";
49673
- import { join as join75, dirname as dirname44 } from "path";
50132
+ import { join as join76, dirname as dirname45 } from "path";
49674
50133
  function findPersonasDir() {
49675
50134
  const candidates = [
49676
50135
  // dev: src/lib/marketing/council-personas.ts → ../../../skill-packs/...
49677
- join75(__dirname_local, "..", "..", "..", PERSONA_SUBPATH),
50136
+ join76(__dirname_local, "..", "..", "..", PERSONA_SUBPATH),
49678
50137
  // built: dist/index.js → ./skill-packs/...
49679
- join75(__dirname_local, PERSONA_SUBPATH),
50138
+ join76(__dirname_local, PERSONA_SUBPATH),
49680
50139
  // tsup-bundled (deeper nesting if ever): ../skill-packs/...
49681
- join75(__dirname_local, "..", PERSONA_SUBPATH),
49682
- join75(__dirname_local, "..", "..", PERSONA_SUBPATH)
50140
+ join76(__dirname_local, "..", PERSONA_SUBPATH),
50141
+ join76(__dirname_local, "..", "..", PERSONA_SUBPATH)
49683
50142
  ];
49684
50143
  for (const candidate of candidates) {
49685
- if (existsSync84(candidate)) return candidate;
50144
+ if (existsSync85(candidate)) return candidate;
49686
50145
  }
49687
50146
  return null;
49688
50147
  }
49689
50148
  function parsePersonaFile(filePath) {
49690
- const raw = readFileSync62(filePath, "utf-8");
50149
+ const raw = readFileSync63(filePath, "utf-8");
49691
50150
  const parsed = (0, import_gray_matter5.default)(raw);
49692
50151
  const data = parsed.data;
49693
50152
  const slug = typeof data.slug === "string" ? data.slug.trim() : "";
@@ -49707,9 +50166,9 @@ function parsePersonaFile(filePath) {
49707
50166
  }
49708
50167
  function loadAllPersonas(personasDir) {
49709
50168
  const dir = personasDir ?? findPersonasDir();
49710
- if (!dir || !existsSync84(dir)) return [];
50169
+ if (!dir || !existsSync85(dir)) return [];
49711
50170
  const files = readdirSync22(dir).filter((n) => n.endsWith(".md")).sort();
49712
- return files.map((name) => parsePersonaFile(join75(dir, name)));
50171
+ return files.map((name) => parsePersonaFile(join76(dir, name)));
49713
50172
  }
49714
50173
  function selectPersonas(all, requested) {
49715
50174
  if (requested.length === 0) return [...all];
@@ -49728,23 +50187,23 @@ var init_council_personas = __esm({
49728
50187
  import_gray_matter5 = __toESM(require_gray_matter(), 1);
49729
50188
  __dirname_local = (() => {
49730
50189
  try {
49731
- return dirname44(fileURLToPath9(import.meta.url));
50190
+ return dirname45(fileURLToPath9(import.meta.url));
49732
50191
  } catch {
49733
50192
  return process.cwd();
49734
50193
  }
49735
50194
  })();
49736
50195
  VALID_MODELS2 = /* @__PURE__ */ new Set(["opus", "sonnet", "haiku"]);
49737
- PERSONA_SUBPATH = join75("skill-packs", "meta-marketing", "council-personas");
50196
+ PERSONA_SUBPATH = join76("skill-packs", "meta-marketing", "council-personas");
49738
50197
  }
49739
50198
  });
49740
50199
 
49741
50200
  // src/cli/commands/marketing/council.ts
49742
50201
  import { spawnSync as spawnSync4 } from "child_process";
49743
- import { existsSync as existsSync85 } from "fs";
50202
+ import { existsSync as existsSync86 } from "fs";
49744
50203
  function resolveDreamcontextEntry() {
49745
50204
  const node = process.argv[0];
49746
50205
  const script = process.argv[1];
49747
- if (script && existsSync85(script)) {
50206
+ if (script && existsSync86(script)) {
49748
50207
  return { node, script };
49749
50208
  }
49750
50209
  return { node, script: null };
@@ -49916,8 +50375,8 @@ var init_marketing = __esm({
49916
50375
  });
49917
50376
 
49918
50377
  // 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";
50378
+ import { existsSync as existsSync87, unlinkSync as unlinkSync4 } from "fs";
50379
+ import { join as join77, dirname as dirname46 } from "path";
49921
50380
  function collectVault(value, previous) {
49922
50381
  return [...previous, value];
49923
50382
  }
@@ -49929,7 +50388,7 @@ function parseTypes(value) {
49929
50388
  return filtered.length > 0 ? filtered : void 0;
49930
50389
  }
49931
50390
  function recallFederated(contextRoot, query, topK, types, opts) {
49932
- const projectRoot = dirname45(contextRoot);
50391
+ const projectRoot = dirname46(contextRoot);
49933
50392
  const { target: currentTarget } = currentVaultTarget(projectRoot);
49934
50393
  const byName = /* @__PURE__ */ new Map();
49935
50394
  const add = (t) => {
@@ -50082,7 +50541,7 @@ function registerMemoryCommand(program2) {
50082
50541
  const summary = opts.summary ?? (text.length > 200 ? text.slice(0, 197) + "..." : text);
50083
50542
  const references = opts.references ? opts.references.split(",").map((s) => s.trim()).filter(Boolean) : void 0;
50084
50543
  const authors = opts.person ? opts.person.split(",").map((s) => s.trim()).filter(Boolean) : void 0;
50085
- const changelogPath = join76(root, "core", "CHANGELOG.json");
50544
+ const changelogPath = join77(root, "core", "CHANGELOG.json");
50086
50545
  const entry = {
50087
50546
  date: today(),
50088
50547
  type: opts.type ?? "note",
@@ -50100,8 +50559,8 @@ function registerMemoryCommand(program2) {
50100
50559
  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
50560
  async (slug, opts) => {
50102
50561
  const root = ensureContextRoot();
50103
- const filePath = join76(root, "knowledge", `${slug}.md`);
50104
- if (!existsSync86(filePath)) {
50562
+ const filePath = join77(root, "knowledge", `${slug}.md`);
50563
+ if (!existsSync87(filePath)) {
50105
50564
  error(`Knowledge file not found: ${slug}.md`);
50106
50565
  return;
50107
50566
  }
@@ -50148,8 +50607,8 @@ ${opts.append}
50148
50607
  );
50149
50608
  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
50609
  const root = ensureContextRoot();
50151
- const filePath = join76(root, "knowledge", `${slug}.md`);
50152
- if (!existsSync86(filePath)) {
50610
+ const filePath = join77(root, "knowledge", `${slug}.md`);
50611
+ if (!existsSync87(filePath)) {
50153
50612
  error(`Knowledge file not found: ${slug}.md`);
50154
50613
  return;
50155
50614
  }
@@ -50257,13 +50716,13 @@ var init_memory = __esm({
50257
50716
 
50258
50717
  // src/cli/commands/upgrade.ts
50259
50718
  import { execFileSync as execFileSync8 } from "child_process";
50260
- import { dirname as dirname46 } from "path";
50719
+ import { dirname as dirname47 } from "path";
50261
50720
  function defaultInstaller(args) {
50262
50721
  execFileSync8("npm", args, { stdio: "inherit" });
50263
50722
  }
50264
50723
  function projectRootForCache() {
50265
50724
  const contextDir = resolveContextRoot();
50266
- return contextDir ? dirname46(contextDir) : process.cwd();
50725
+ return contextDir ? dirname47(contextDir) : process.cwd();
50267
50726
  }
50268
50727
  function defaultLiveLatest() {
50269
50728
  let latest = null;
@@ -50586,9 +51045,9 @@ var init_vaults3 = __esm({
50586
51045
  });
50587
51046
 
50588
51047
  // src/cli/commands/connections.ts
50589
- import { dirname as dirname47 } from "path";
51048
+ import { dirname as dirname48 } from "path";
50590
51049
  function currentVaultName2(contextRoot) {
50591
- return currentVaultTarget(dirname47(contextRoot)).name;
51050
+ return currentVaultTarget(dirname48(contextRoot)).name;
50592
51051
  }
50593
51052
  function registerConnectionsCommand(program2) {
50594
51053
  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 +51129,17 @@ var init_connections3 = __esm({
50670
51129
  });
50671
51130
 
50672
51131
  // src/lib/federation-ingest.ts
50673
- import { existsSync as existsSync87, mkdirSync as mkdirSync37 } from "fs";
50674
- import { join as join77 } from "path";
51132
+ import { existsSync as existsSync88, mkdirSync as mkdirSync38 } from "fs";
51133
+ import { join as join78 } from "path";
50675
51134
  function ingestEntry(contextRoot, entry) {
50676
- const knowledgeDir = join77(contextRoot, "knowledge");
50677
- mkdirSync37(knowledgeDir, { recursive: true });
51135
+ const knowledgeDir = join78(contextRoot, "knowledge");
51136
+ mkdirSync38(knowledgeDir, { recursive: true });
50678
51137
  const baseSlug = slugFromTitle(entry.title);
50679
- const canonicalPath = join77(knowledgeDir, `${baseSlug}.md`);
50680
- const collided = existsSync87(canonicalPath);
51138
+ const canonicalPath = join78(knowledgeDir, `${baseSlug}.md`);
51139
+ const collided = existsSync88(canonicalPath);
50681
51140
  const slug = collided ? `${baseSlug}--from-${sanitizeVault(entry.origin.vault)}` : baseSlug;
50682
- const targetPath = join77(knowledgeDir, `${slug}.md`);
50683
- if (!existsSync87(targetPath)) {
51141
+ const targetPath = join78(knowledgeDir, `${slug}.md`);
51142
+ if (!existsSync88(targetPath)) {
50684
51143
  writeFrontmatter(
50685
51144
  targetPath,
50686
51145
  {
@@ -50756,9 +51215,9 @@ var init_federation_ingest = __esm({
50756
51215
  });
50757
51216
 
50758
51217
  // src/cli/commands/federation.ts
50759
- import { dirname as dirname48 } from "path";
51218
+ import { dirname as dirname49 } from "path";
50760
51219
  function currentVaultName3(contextRoot) {
50761
- return currentVaultTarget(dirname48(contextRoot)).name;
51220
+ return currentVaultTarget(dirname49(contextRoot)).name;
50762
51221
  }
50763
51222
  function outboundConnections(contextRoot) {
50764
51223
  return listConnections(contextRoot).filter(
@@ -50971,12 +51430,12 @@ var init_people = __esm({
50971
51430
  });
50972
51431
 
50973
51432
  // 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";
51433
+ import { dirname as dirname50 } from "path";
51434
+ import { existsSync as existsSync89, readFileSync as readFileSync65, writeFileSync as writeFileSync44 } from "fs";
51435
+ import { join as join79 } from "path";
50977
51436
  function resolveProjectRoot() {
50978
51437
  const contextRoot = resolveContextRoot();
50979
- return contextRoot ? dirname49(contextRoot) : null;
51438
+ return contextRoot ? dirname50(contextRoot) : null;
50980
51439
  }
50981
51440
  function requireProjectRoot() {
50982
51441
  const projectRoot = resolveProjectRoot();
@@ -51135,7 +51594,7 @@ function registerConfigCommand(program2) {
51135
51594
  const liveToken = resolveClickUpToken(projectRoot);
51136
51595
  let connected = false;
51137
51596
  if (liveToken) {
51138
- const contextRoot = join78(projectRoot, "_dream_context");
51597
+ const contextRoot = join79(projectRoot, "_dream_context");
51139
51598
  const probe = createClickUpBackend(contextRoot, readSetupConfig(projectRoot));
51140
51599
  const test = await probe.testConnection();
51141
51600
  if (test.ok) {
@@ -51178,7 +51637,7 @@ function registerConfigCommand(program2) {
51178
51637
  cfgNow = readSetupConfig(projectRoot);
51179
51638
  }
51180
51639
  if (connected && cfgNow?.clickup?.listId) {
51181
- const contextRoot = join78(projectRoot, "_dream_context");
51640
+ const contextRoot = join79(projectRoot, "_dream_context");
51182
51641
  const backend2 = createClickUpBackend(contextRoot, cfgNow);
51183
51642
  if (await esm_default4({ message: "Create the recommended custom fields on the list (urgency, summary, RICE, \u2026)?", default: true })) {
51184
51643
  const result = await backend2.provisionRemote();
@@ -51233,13 +51692,13 @@ function registerConfigCommand(program2) {
51233
51692
  const contextRoot = resolveContextRoot();
51234
51693
  let userMdSynced = false;
51235
51694
  if (contextRoot) {
51236
- const userMdPath = join78(contextRoot, "core", "1.user.md");
51237
- if (existsSync88(userMdPath)) {
51695
+ const userMdPath = join79(contextRoot, "core", "1.user.md");
51696
+ if (existsSync89(userMdPath)) {
51238
51697
  try {
51239
- const before = readFileSync64(userMdPath, "utf-8");
51698
+ const before = readFileSync65(userMdPath, "utf-8");
51240
51699
  const after = ensurePeopleSection(before, roster);
51241
51700
  if (after !== before) {
51242
- writeFileSync43(userMdPath, after, "utf-8");
51701
+ writeFileSync44(userMdPath, after, "utf-8");
51243
51702
  userMdSynced = true;
51244
51703
  }
51245
51704
  } catch (err) {
@@ -51283,7 +51742,7 @@ function registerConfigCommand(program2) {
51283
51742
  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
51743
  const projectRoot = requireProjectRoot();
51285
51744
  if (!projectRoot) return;
51286
- const contextRoot = join78(projectRoot, "_dream_context");
51745
+ const contextRoot = join79(projectRoot, "_dream_context");
51287
51746
  const existing = readSetupConfig(projectRoot)?.clickup ?? {};
51288
51747
  const ledger = new SyncLedger(contextRoot);
51289
51748
  const changingList = !!existing.listId && existing.listId !== listId && ledger.readMap().length > 0;
@@ -51324,8 +51783,8 @@ function registerConfigCommand(program2) {
51324
51783
  if (!value) {
51325
51784
  if (!process.stdin.isTTY) {
51326
51785
  try {
51327
- const { readFileSync: readFileSync65 } = await import("fs");
51328
- value = readFileSync65(0, "utf-8").trim();
51786
+ const { readFileSync: readFileSync66 } = await import("fs");
51787
+ value = readFileSync66(0, "utf-8").trim();
51329
51788
  } catch {
51330
51789
  value = "";
51331
51790
  }
@@ -51684,12 +52143,12 @@ var init_feedback2 = __esm({
51684
52143
  });
51685
52144
 
51686
52145
  // src/cli/commands/migrations.ts
51687
- import { dirname as dirname50 } from "path";
52146
+ import { dirname as dirname51 } from "path";
51688
52147
  function registerMigrationsCommand(program2) {
51689
52148
  const migrations = program2.command("migrations").description("Inspect and record brain structure migrations");
51690
52149
  migrations.command("pending").description("Print pending agent task instructions for any unfinished migrations").action(() => {
51691
52150
  const root = ensureContextRoot();
51692
- const projectRoot = dirname50(root);
52151
+ const projectRoot = dirname51(root);
51693
52152
  const config = readSetupConfig(projectRoot);
51694
52153
  const fromVersion = config?.setupVersion ?? "0.0.0";
51695
52154
  const toVersion = dreamcontextVersion();