@goondocks/myco 0.19.6 → 0.20.1

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 (185) hide show
  1. package/dist/{agent-run-WK5NKBYA.js → agent-run-PQXC246Y.js} +8 -8
  2. package/dist/{agent-tasks-2E73GG3A.js → agent-tasks-323BZEBX.js} +8 -8
  3. package/dist/{chunk-VLGBWOBY.js → chunk-22JALAXN.js} +6 -6
  4. package/dist/chunk-22JALAXN.js.map +1 -0
  5. package/dist/{chunk-DURKJTVO.js → chunk-3WOS4TAR.js} +9 -1
  6. package/dist/chunk-3WOS4TAR.js.map +1 -0
  7. package/dist/{chunk-QH5HS54N.js → chunk-3WWJOTYG.js} +3 -3
  8. package/dist/{chunk-Q4QD6LJT.js → chunk-4M7EWPIA.js} +3 -3
  9. package/dist/{chunk-FGKCE5AE.js → chunk-4YFKBL3F.js} +2 -2
  10. package/dist/{chunk-KYH4V4ML.js → chunk-57O67XVF.js} +3 -3
  11. package/dist/{chunk-7ONVLO43.js → chunk-5XIVBO25.js} +2 -2
  12. package/dist/{chunk-W3JUH5S3.js → chunk-63ZGP4Q2.js} +4 -4
  13. package/dist/{chunk-ST2D3SGM.js → chunk-AIYFHQRX.js} +2 -2
  14. package/dist/{chunk-6ZDJXSEO.js → chunk-BPRIYNLE.js} +3 -3
  15. package/dist/chunk-CUDIZJY7.js +36 -0
  16. package/dist/chunk-CUDIZJY7.js.map +1 -0
  17. package/dist/{chunk-WKNAKQKA.js → chunk-DCSGJ7W4.js} +13 -19
  18. package/dist/chunk-DCSGJ7W4.js.map +1 -0
  19. package/dist/{chunk-Q6OEZM3S.js → chunk-EVDQKYCG.js} +237 -10
  20. package/dist/chunk-EVDQKYCG.js.map +1 -0
  21. package/dist/{chunk-P5VNHGVZ.js → chunk-FGY7J6EZ.js} +67 -16
  22. package/dist/chunk-FGY7J6EZ.js.map +1 -0
  23. package/dist/{chunk-I54KLC6H.js → chunk-FLLBJLHM.js} +3 -1
  24. package/dist/{chunk-I54KLC6H.js.map → chunk-FLLBJLHM.js.map} +1 -1
  25. package/dist/{chunk-PMT2LSTQ.js → chunk-FMRZ26U5.js} +2 -2
  26. package/dist/{chunk-3J6TUJSV.js → chunk-KHT24OWC.js} +3 -3
  27. package/dist/{chunk-TMNFCUAD.js → chunk-LZP4IJB3.js} +51 -23
  28. package/dist/chunk-LZP4IJB3.js.map +1 -0
  29. package/dist/{chunk-6DDRJQ4X.js → chunk-MYOZLMB2.js} +2 -2
  30. package/dist/{chunk-UVKQ62II.js → chunk-NGROSFOH.js} +24 -2
  31. package/dist/chunk-NGROSFOH.js.map +1 -0
  32. package/dist/{chunk-FKBPXCH3.js → chunk-QS5TWZBL.js} +4 -4
  33. package/dist/{chunk-NKQZ73LL.js → chunk-SRXTSI25.js} +109 -3
  34. package/dist/chunk-SRXTSI25.js.map +1 -0
  35. package/dist/{chunk-NCBLB2C6.js → chunk-UEWMSIL3.js} +7 -4
  36. package/dist/chunk-UEWMSIL3.js.map +1 -0
  37. package/dist/{chunk-GFR542SM.js → chunk-US4LNCAT.js} +5 -11
  38. package/dist/chunk-US4LNCAT.js.map +1 -0
  39. package/dist/{chunk-44PZCAYS.js → chunk-XL75KZGI.js} +23 -13
  40. package/dist/chunk-XL75KZGI.js.map +1 -0
  41. package/dist/chunk-ZXZPJJN3.js +54 -0
  42. package/dist/chunk-ZXZPJJN3.js.map +1 -0
  43. package/dist/{cli-LCTXK7N6.js → cli-UWBAOHLL.js} +43 -43
  44. package/dist/{client-S47ENM76.js → client-SLDDMSKN.js} +4 -4
  45. package/dist/{config-IO5WALOD.js → config-XPV5GDE4.js} +8 -16
  46. package/dist/config-XPV5GDE4.js.map +1 -0
  47. package/dist/{detect-BEOIHGBC.js → detect-PXNM6TA7.js} +2 -2
  48. package/dist/{detect-providers-2EY55EHK.js → detect-providers-5KOPZ7J2.js} +4 -4
  49. package/dist/{doctor-EE6GAC54.js → doctor-UUUOVDZS.js} +14 -14
  50. package/dist/doctor-UUUOVDZS.js.map +1 -0
  51. package/dist/{executor-NXNSUEMQ.js → executor-J4IBXSBY.js} +21 -22
  52. package/dist/executor-J4IBXSBY.js.map +1 -0
  53. package/dist/{init-IPL3XV6F.js → init-UDH3ZBDD.js} +17 -21
  54. package/dist/init-UDH3ZBDD.js.map +1 -0
  55. package/dist/{installer-WMTB4NCX.js → installer-I6KRGJOO.js} +4 -4
  56. package/dist/{llm-SWDDQQWY.js → llm-TH4NLIRM.js} +4 -4
  57. package/dist/{loader-V774GZU4.js → loader-H7OFASVC.js} +15 -3
  58. package/dist/{loader-AAZ6VUIA.js → loader-TSB5M7FD.js} +3 -3
  59. package/dist/{logs-KNKPQE5A.js → logs-7YVGGBIS.js} +2 -2
  60. package/dist/{main-RPJSS7PT.js → main-E7HU4QYR.js} +842 -249
  61. package/dist/main-E7HU4QYR.js.map +1 -0
  62. package/dist/{open-OYBKVBYX.js → open-4UGDPBKN.js} +8 -8
  63. package/dist/{post-compact-E2OVMNGQ.js → post-compact-BFU3WZSV.js} +9 -8
  64. package/dist/{post-compact-E2OVMNGQ.js.map → post-compact-BFU3WZSV.js.map} +1 -1
  65. package/dist/{post-tool-use-FGQE26GJ.js → post-tool-use-RYHXLCTC.js} +8 -7
  66. package/dist/{post-tool-use-FGQE26GJ.js.map → post-tool-use-RYHXLCTC.js.map} +1 -1
  67. package/dist/{post-tool-use-failure-3CITJYQK.js → post-tool-use-failure-DCVHK2P3.js} +9 -8
  68. package/dist/{post-tool-use-failure-3CITJYQK.js.map → post-tool-use-failure-DCVHK2P3.js.map} +1 -1
  69. package/dist/{pre-compact-GYMHCXII.js → pre-compact-EZZCJ6AG.js} +9 -8
  70. package/dist/{pre-compact-GYMHCXII.js.map → pre-compact-EZZCJ6AG.js.map} +1 -1
  71. package/dist/{provider-check-WCM3SDTM.js → provider-check-43LAMSMH.js} +4 -4
  72. package/dist/{registry-OCM4WAPJ.js → registry-MGJSJBAS.js} +4 -4
  73. package/dist/{remove-72ER3TG5.js → remove-GBBQG3SJ.js} +10 -10
  74. package/dist/{restart-EQHEJCGT.js → restart-RMIGKMA6.js} +9 -9
  75. package/dist/{search-JOBYIW43.js → search-2A5AJVNG.js} +9 -9
  76. package/dist/{server-PZCWYWZL.js → server-TSYZMFFK.js} +40 -27
  77. package/dist/{server-PZCWYWZL.js.map → server-TSYZMFFK.js.map} +1 -1
  78. package/dist/{session-APO4A2C7.js → session-NKREOTEO.js} +9 -10
  79. package/dist/{session-APO4A2C7.js.map → session-NKREOTEO.js.map} +1 -1
  80. package/dist/{session-end-4V4VHAOQ.js → session-end-DQELLTGJ.js} +8 -7
  81. package/dist/{session-end-4V4VHAOQ.js.map → session-end-DQELLTGJ.js.map} +1 -1
  82. package/dist/{session-start-K6ESRZU7.js → session-start-5SUTR5GP.js} +17 -17
  83. package/dist/session-start-5SUTR5GP.js.map +1 -0
  84. package/dist/{setup-llm-QUWOSB7A.js → setup-llm-SLX5764H.js} +10 -9
  85. package/dist/{setup-llm-QUWOSB7A.js.map → setup-llm-SLX5764H.js.map} +1 -1
  86. package/dist/src/cli.js +1 -1
  87. package/dist/src/daemon/main.js +1 -1
  88. package/dist/src/hooks/post-tool-use.js +1 -1
  89. package/dist/src/hooks/session-end.js +1 -1
  90. package/dist/src/hooks/session-start.js +1 -1
  91. package/dist/src/hooks/stop.js +1 -1
  92. package/dist/src/hooks/user-prompt-submit.js +1 -1
  93. package/dist/src/mcp/server.js +1 -1
  94. package/dist/src/symbionts/manifests/codex.yaml +28 -0
  95. package/dist/{stats-TYOZAOP2.js → stats-ARBLNEE3.js} +9 -9
  96. package/dist/{stop-2COOWEYG.js → stop-5AJXBKEE.js} +8 -7
  97. package/dist/{stop-2COOWEYG.js.map → stop-5AJXBKEE.js.map} +1 -1
  98. package/dist/{stop-failure-UQ33GZLE.js → stop-failure-XGKTZPLR.js} +9 -8
  99. package/dist/{stop-failure-UQ33GZLE.js.map → stop-failure-XGKTZPLR.js.map} +1 -1
  100. package/dist/{subagent-start-YENEY6VF.js → subagent-start-2JLIPGJN.js} +9 -8
  101. package/dist/{subagent-start-YENEY6VF.js.map → subagent-start-2JLIPGJN.js.map} +1 -1
  102. package/dist/{subagent-stop-W2757YDB.js → subagent-stop-FV4EOKWZ.js} +9 -8
  103. package/dist/{subagent-stop-W2757YDB.js.map → subagent-stop-FV4EOKWZ.js.map} +1 -1
  104. package/dist/{task-completed-KU6GWMWV.js → task-completed-XJKT366I.js} +9 -8
  105. package/dist/{task-completed-KU6GWMWV.js.map → task-completed-XJKT366I.js.map} +1 -1
  106. package/dist/{team-SNLC6FZM.js → team-3JKF7VAD.js} +5 -5
  107. package/dist/ui/assets/index-C2JuNtRB.css +1 -0
  108. package/dist/ui/assets/index-JLVaQKV2.js +832 -0
  109. package/dist/ui/favicon-dusk.svg +11 -0
  110. package/dist/ui/favicon-moss.svg +11 -0
  111. package/dist/ui/favicon-plum.svg +11 -0
  112. package/dist/ui/favicon-sage.svg +11 -0
  113. package/dist/ui/favicon-slate.svg +11 -0
  114. package/dist/ui/favicon-terracotta.svg +11 -0
  115. package/dist/ui/index.html +3 -3
  116. package/dist/{update-5VYNQZJ4.js → update-XVSAMN4O.js} +10 -10
  117. package/dist/{user-prompt-submit-KATLHAKA.js → user-prompt-submit-TTBTHBBH.js} +9 -8
  118. package/dist/{user-prompt-submit-KATLHAKA.js.map → user-prompt-submit-TTBTHBBH.js.map} +1 -1
  119. package/dist/{verify-BGJVB3K2.js → verify-LMHNEYIP.js} +7 -7
  120. package/dist/verify-LMHNEYIP.js.map +1 -0
  121. package/dist/{version-MKNN5GYM.js → version-HRVSEMUR.js} +2 -2
  122. package/package.json +1 -1
  123. package/skills/myco/SKILL.md +78 -43
  124. package/skills/myco/references/vault-status.md +1 -1
  125. package/dist/chunk-44PZCAYS.js.map +0 -1
  126. package/dist/chunk-5ZT2Q6P5.js +0 -25
  127. package/dist/chunk-5ZT2Q6P5.js.map +0 -1
  128. package/dist/chunk-AULBWINA.js +0 -227
  129. package/dist/chunk-AULBWINA.js.map +0 -1
  130. package/dist/chunk-DURKJTVO.js.map +0 -1
  131. package/dist/chunk-GFR542SM.js.map +0 -1
  132. package/dist/chunk-NCBLB2C6.js.map +0 -1
  133. package/dist/chunk-NKQZ73LL.js.map +0 -1
  134. package/dist/chunk-P5VNHGVZ.js.map +0 -1
  135. package/dist/chunk-Q6OEZM3S.js.map +0 -1
  136. package/dist/chunk-TMNFCUAD.js.map +0 -1
  137. package/dist/chunk-UVKQ62II.js.map +0 -1
  138. package/dist/chunk-VLGBWOBY.js.map +0 -1
  139. package/dist/chunk-VQF5E4ZX.js +0 -91
  140. package/dist/chunk-VQF5E4ZX.js.map +0 -1
  141. package/dist/chunk-WKNAKQKA.js.map +0 -1
  142. package/dist/config-IO5WALOD.js.map +0 -1
  143. package/dist/doctor-EE6GAC54.js.map +0 -1
  144. package/dist/executor-NXNSUEMQ.js.map +0 -1
  145. package/dist/init-IPL3XV6F.js.map +0 -1
  146. package/dist/main-RPJSS7PT.js.map +0 -1
  147. package/dist/resolution-events-PYLSI6QT.js +0 -15
  148. package/dist/session-start-K6ESRZU7.js.map +0 -1
  149. package/dist/ui/assets/index-816yFmz_.js +0 -842
  150. package/dist/ui/assets/index-Dj6vQpFd.css +0 -1
  151. package/dist/verify-BGJVB3K2.js.map +0 -1
  152. package/dist/version-MKNN5GYM.js.map +0 -1
  153. /package/dist/{agent-run-WK5NKBYA.js.map → agent-run-PQXC246Y.js.map} +0 -0
  154. /package/dist/{agent-tasks-2E73GG3A.js.map → agent-tasks-323BZEBX.js.map} +0 -0
  155. /package/dist/{chunk-QH5HS54N.js.map → chunk-3WWJOTYG.js.map} +0 -0
  156. /package/dist/{chunk-Q4QD6LJT.js.map → chunk-4M7EWPIA.js.map} +0 -0
  157. /package/dist/{chunk-FGKCE5AE.js.map → chunk-4YFKBL3F.js.map} +0 -0
  158. /package/dist/{chunk-KYH4V4ML.js.map → chunk-57O67XVF.js.map} +0 -0
  159. /package/dist/{chunk-7ONVLO43.js.map → chunk-5XIVBO25.js.map} +0 -0
  160. /package/dist/{chunk-W3JUH5S3.js.map → chunk-63ZGP4Q2.js.map} +0 -0
  161. /package/dist/{chunk-ST2D3SGM.js.map → chunk-AIYFHQRX.js.map} +0 -0
  162. /package/dist/{chunk-6ZDJXSEO.js.map → chunk-BPRIYNLE.js.map} +0 -0
  163. /package/dist/{chunk-PMT2LSTQ.js.map → chunk-FMRZ26U5.js.map} +0 -0
  164. /package/dist/{chunk-3J6TUJSV.js.map → chunk-KHT24OWC.js.map} +0 -0
  165. /package/dist/{chunk-6DDRJQ4X.js.map → chunk-MYOZLMB2.js.map} +0 -0
  166. /package/dist/{chunk-FKBPXCH3.js.map → chunk-QS5TWZBL.js.map} +0 -0
  167. /package/dist/{cli-LCTXK7N6.js.map → cli-UWBAOHLL.js.map} +0 -0
  168. /package/dist/{client-S47ENM76.js.map → client-SLDDMSKN.js.map} +0 -0
  169. /package/dist/{detect-BEOIHGBC.js.map → detect-PXNM6TA7.js.map} +0 -0
  170. /package/dist/{detect-providers-2EY55EHK.js.map → detect-providers-5KOPZ7J2.js.map} +0 -0
  171. /package/dist/{installer-WMTB4NCX.js.map → installer-I6KRGJOO.js.map} +0 -0
  172. /package/dist/{llm-SWDDQQWY.js.map → llm-TH4NLIRM.js.map} +0 -0
  173. /package/dist/{loader-AAZ6VUIA.js.map → loader-H7OFASVC.js.map} +0 -0
  174. /package/dist/{loader-V774GZU4.js.map → loader-TSB5M7FD.js.map} +0 -0
  175. /package/dist/{logs-KNKPQE5A.js.map → logs-7YVGGBIS.js.map} +0 -0
  176. /package/dist/{open-OYBKVBYX.js.map → open-4UGDPBKN.js.map} +0 -0
  177. /package/dist/{provider-check-WCM3SDTM.js.map → provider-check-43LAMSMH.js.map} +0 -0
  178. /package/dist/{registry-OCM4WAPJ.js.map → registry-MGJSJBAS.js.map} +0 -0
  179. /package/dist/{remove-72ER3TG5.js.map → remove-GBBQG3SJ.js.map} +0 -0
  180. /package/dist/{restart-EQHEJCGT.js.map → restart-RMIGKMA6.js.map} +0 -0
  181. /package/dist/{search-JOBYIW43.js.map → search-2A5AJVNG.js.map} +0 -0
  182. /package/dist/{stats-TYOZAOP2.js.map → stats-ARBLNEE3.js.map} +0 -0
  183. /package/dist/{resolution-events-PYLSI6QT.js.map → team-3JKF7VAD.js.map} +0 -0
  184. /package/dist/{update-5VYNQZJ4.js.map → update-XVSAMN4O.js.map} +0 -0
  185. /package/dist/{team-SNLC6FZM.js.map → version-HRVSEMUR.js.map} +0 -0
@@ -2,10 +2,10 @@ import { createRequire as __cr } from 'node:module'; const require = __cr(import
2
2
  import {
3
3
  DaemonLogger,
4
4
  LEVEL_ORDER
5
- } from "./chunk-DURKJTVO.js";
5
+ } from "./chunk-3WOS4TAR.js";
6
6
  import {
7
7
  withTaskConfig
8
- } from "./chunk-GFR542SM.js";
8
+ } from "./chunk-US4LNCAT.js";
9
9
  import {
10
10
  EMBEDDABLE_TABLES,
11
11
  EMBEDDABLE_TEXT_COLUMNS,
@@ -15,7 +15,7 @@ import {
15
15
  getEmbeddingQueueDepth,
16
16
  getUnembedded,
17
17
  markEmbedded
18
- } from "./chunk-VLGBWOBY.js";
18
+ } from "./chunk-22JALAXN.js";
19
19
  import {
20
20
  getTeamPackageVersion,
21
21
  loadSecrets,
@@ -23,7 +23,7 @@ import {
23
23
  readSecrets,
24
24
  resolveVaultConfigPath,
25
25
  writeSecret
26
- } from "./chunk-FKBPXCH3.js";
26
+ } from "./chunk-QS5TWZBL.js";
27
27
  import {
28
28
  buildTaskInstruction,
29
29
  closeOpenBatches,
@@ -53,6 +53,7 @@ import {
53
53
  incrementActivityCount,
54
54
  incrementSkillUsageCount,
55
55
  insertBatchStateless,
56
+ insertResolutionEvent,
56
57
  isInstructionRequiredTask,
57
58
  listBatchesBySession,
58
59
  listCandidatesWithCount,
@@ -71,24 +72,24 @@ import {
71
72
  setResponseSummary,
72
73
  updateCandidate,
73
74
  updateNotificationStatus
74
- } from "./chunk-P5VNHGVZ.js";
75
+ } from "./chunk-FGY7J6EZ.js";
75
76
  import {
76
77
  fullTextSearch,
77
78
  hydrateSearchResults
78
- } from "./chunk-7ONVLO43.js";
79
+ } from "./chunk-5XIVBO25.js";
79
80
  import {
80
81
  copyTaskToUser,
81
82
  deleteUserTask,
82
83
  loadAllTasks,
83
84
  validateTaskName,
84
85
  writeUserTask
85
- } from "./chunk-KYH4V4ML.js";
86
+ } from "./chunk-57O67XVF.js";
86
87
  import {
87
88
  AgentTaskSchema,
88
89
  registerAgent,
89
90
  resolveDefinitionsDir,
90
91
  taskFromParsed
91
- } from "./chunk-Q4QD6LJT.js";
92
+ } from "./chunk-4M7EWPIA.js";
92
93
  import {
93
94
  listTurnsByRun
94
95
  } from "./chunk-6RFZWV4R.js";
@@ -99,7 +100,7 @@ import {
99
100
  import {
100
101
  Anthropic,
101
102
  createEmbeddingProvider
102
- } from "./chunk-3J6TUJSV.js";
103
+ } from "./chunk-KHT24OWC.js";
103
104
  import {
104
105
  getMachineId
105
106
  } from "./chunk-ENWBFX7F.js";
@@ -109,84 +110,93 @@ import {
109
110
  listBufferSessionIds
110
111
  } from "./chunk-V7XG6V6C.js";
111
112
  import "./chunk-POEPHBQK.js";
112
- import "./chunk-NCBLB2C6.js";
113
+ import "./chunk-UEWMSIL3.js";
113
114
  import "./chunk-SAKJMNSR.js";
114
115
  import {
115
116
  SymbiontInstaller
116
- } from "./chunk-TMNFCUAD.js";
117
+ } from "./chunk-LZP4IJB3.js";
117
118
  import {
118
119
  checkLocalProvider
119
- } from "./chunk-6ZDJXSEO.js";
120
+ } from "./chunk-BPRIYNLE.js";
120
121
  import {
121
122
  LmStudioBackend,
122
123
  OllamaBackend
123
- } from "./chunk-PMT2LSTQ.js";
124
+ } from "./chunk-FMRZ26U5.js";
124
125
  import {
125
126
  countSpores,
126
127
  getSpore,
127
128
  insertSpore,
128
129
  listSpores,
129
130
  updateSporeStatus
130
- } from "./chunk-FGKCE5AE.js";
131
+ } from "./chunk-4YFKBL3F.js";
131
132
  import {
133
+ backfillUnsynced,
132
134
  closeSession,
135
+ countDeadLettered,
136
+ countPending,
133
137
  countSessions,
134
138
  deleteSessionCascade,
139
+ enqueueOutbox,
135
140
  getSession,
136
141
  getSessionImpact,
137
- incrementSessionToolCount,
138
- listSessions,
139
- reactivateSessionIfCompleted,
140
- updateSession,
141
- upsertSession
142
- } from "./chunk-Q6OEZM3S.js";
143
- import {
144
- backfillUnsynced,
145
- countDeadLettered,
146
- countPending,
147
- enqueueOutbox,
148
142
  getTeamMachineId,
149
143
  incrementRetryCount,
144
+ incrementSessionToolCount,
150
145
  initTeamContext,
151
146
  isTeamSyncEnabled,
152
147
  listPending,
148
+ listSessions,
153
149
  markSent,
154
150
  markSourceRowsSynced,
155
151
  pruneOld,
152
+ reactivateSessionIfCompleted,
156
153
  retryDeadLettered,
157
- syncRow
158
- } from "./chunk-AULBWINA.js";
154
+ syncRow,
155
+ updateSession,
156
+ upsertSession
157
+ } from "./chunk-EVDQKYCG.js";
158
+ import {
159
+ evaluateSessionCaptureRules,
160
+ readTranscriptMeta
161
+ } from "./chunk-XL75KZGI.js";
159
162
  import {
160
163
  EMBEDDING_DIMENSIONS,
161
164
  REST_SETTABLE_STATUSES,
162
165
  SCHEMA_VERSION,
163
166
  createSchema
164
- } from "./chunk-6DDRJQ4X.js";
167
+ } from "./chunk-MYOZLMB2.js";
165
168
  import {
166
169
  CONFIG_FILENAME,
167
170
  MycoConfigSchema,
171
+ deepMergeConfig,
168
172
  getEnabledSymbiontNames,
169
173
  loadConfig,
174
+ loadLocalConfig,
175
+ loadMergedConfig,
170
176
  updateBackupConfig,
171
177
  updateConfig,
178
+ updateLocalConfig,
172
179
  updateTeamConfig
173
- } from "./chunk-NKQZ73LL.js";
180
+ } from "./chunk-SRXTSI25.js";
174
181
  import {
175
182
  closeDatabase,
176
183
  getDatabase,
177
184
  initDatabase,
178
185
  vaultDbPath
179
186
  } from "./chunk-MYX5NCRH.js";
187
+ import {
188
+ unsetAtPath
189
+ } from "./chunk-ZXZPJJN3.js";
180
190
  import {
181
191
  resolveCliEntryPath
182
- } from "./chunk-QH5HS54N.js";
192
+ } from "./chunk-3WWJOTYG.js";
183
193
  import {
184
194
  getPluginVersion
185
- } from "./chunk-ST2D3SGM.js";
195
+ } from "./chunk-AIYFHQRX.js";
186
196
  import {
187
197
  loadManifests,
188
198
  resolvePackageRoot
189
- } from "./chunk-UVKQ62II.js";
199
+ } from "./chunk-NGROSFOH.js";
190
200
  import {
191
201
  findPackageRoot
192
202
  } from "./chunk-LPUQPDC2.js";
@@ -203,6 +213,7 @@ import {
203
213
  FEED_DEFAULT_LIMIT,
204
214
  LOG_MESSAGE_PREVIEW_CHARS,
205
215
  LOG_PROMPT_PREVIEW_CHARS,
216
+ MCP_SESSIONS_DEFAULT_LIMIT,
206
217
  MS_PER_DAY,
207
218
  MS_PER_HOUR,
208
219
  MS_PER_SECOND,
@@ -224,6 +235,7 @@ import {
224
235
  RESTART_RESPONSE_FLUSH_MS,
225
236
  SEARCH_RESULTS_DEFAULT_LIMIT,
226
237
  SEARCH_SIMILARITY_THRESHOLD,
238
+ SESSION_SUMMARY_PREVIEW_CHARS,
227
239
  STALE_BUFFER_MAX_AGE_MS,
228
240
  STALE_SESSION_THRESHOLD_MS,
229
241
  SYNC_PROTOCOL_VERSION,
@@ -243,7 +255,7 @@ import {
243
255
  USER_TASK_SOURCE,
244
256
  epochSeconds,
245
257
  estimateTokens
246
- } from "./chunk-I54KLC6H.js";
258
+ } from "./chunk-FLLBJLHM.js";
247
259
  import {
248
260
  LOG_KINDS,
249
261
  kindToComponent
@@ -1377,76 +1389,121 @@ function extractTurnsFromBuffer(events) {
1377
1389
  return turns;
1378
1390
  }
1379
1391
 
1380
- // src/daemon/api/config.ts
1381
- function mergeConfigSections(current, incoming) {
1382
- return {
1383
- ...current,
1384
- daemon: { ...current.daemon, ...incoming.daemon },
1385
- embedding: { ...current.embedding, ...incoming.embedding },
1386
- capture: { ...current.capture, ...incoming.capture },
1387
- agent: { ...current.agent, ...incoming.agent },
1388
- context: { ...current.context, ...incoming.context },
1389
- backup: { ...current.backup, ...incoming.backup },
1390
- team: { ...current.team, ...incoming.team },
1391
- notifications: { ...current.notifications, ...incoming.notifications }
1392
- };
1392
+ // src/daemon/config-reactions/touched-paths.ts
1393
+ function enumerateLeafPaths(obj, prefix = "") {
1394
+ if (obj === null || typeof obj !== "object" || Array.isArray(obj)) {
1395
+ return prefix ? [prefix] : [];
1396
+ }
1397
+ const out = [];
1398
+ for (const [key, value] of Object.entries(obj)) {
1399
+ const next = prefix ? `${prefix}.${key}` : key;
1400
+ out.push(...enumerateLeafPaths(value, next));
1401
+ }
1402
+ return out;
1403
+ }
1404
+ function computeTouchedPaths(patch, clear) {
1405
+ const patchLeaves = patch && typeof patch === "object" ? enumerateLeafPaths(patch) : [];
1406
+ const clearList = Array.isArray(clear) ? clear : [];
1407
+ return [.../* @__PURE__ */ new Set([...patchLeaves, ...clearList])];
1393
1408
  }
1409
+
1410
+ // src/daemon/api/config.ts
1394
1411
  async function handleGetConfig(vaultDir) {
1395
1412
  const config = loadConfig(vaultDir);
1396
1413
  return { body: config };
1397
1414
  }
1398
- async function handlePutConfig(vaultDir, body) {
1399
- const result = MycoConfigSchema.safeParse(body);
1400
- if (!result.success) {
1401
- return {
1402
- status: 400,
1403
- body: { error: "validation_failed", issues: result.error.issues }
1404
- };
1415
+ async function handleGetMergedConfig(vaultDir) {
1416
+ const config = loadMergedConfig(vaultDir);
1417
+ return { body: config };
1418
+ }
1419
+ async function handleGetLocalConfig(vaultDir) {
1420
+ return { body: loadLocalConfig(vaultDir) };
1421
+ }
1422
+ var SCOPED_CONFIG_SCOPES = ["project", "local"];
1423
+ function isScopedConfigScope(value) {
1424
+ return typeof value === "string" && SCOPED_CONFIG_SCOPES.includes(value);
1425
+ }
1426
+ function validateClearList(clear) {
1427
+ if (clear === void 0) return [];
1428
+ if (!Array.isArray(clear)) {
1429
+ return { status: 400, body: { error: "clear must be an array of dot-paths" } };
1430
+ }
1431
+ const invalidEntry = clear.find((entry) => typeof entry !== "string" || entry.trim().length === 0);
1432
+ if (invalidEntry !== void 0) {
1433
+ return { status: 400, body: { error: "clear entries must be non-empty strings" } };
1405
1434
  }
1406
- const updated = updateConfig(vaultDir, (current) => mergeConfigSections(current, result.data));
1407
- return { body: updated };
1435
+ return clear;
1408
1436
  }
1409
- function createPlanDirHandlers(deps) {
1410
- const { vaultDir, symbiontPlanDirsByAgent, symbiontPlanDirs } = deps;
1411
- async function handleGetPlanDirs(_req) {
1412
- const config = loadConfig(vaultDir);
1413
- return {
1414
- body: {
1415
- symbiont: symbiontPlanDirsByAgent,
1416
- custom: deps.planWatchConfig.watchDirs.filter((d) => !symbiontPlanDirs.includes(d)),
1417
- ignore_plan_dirs_in_git: config.capture.ignore_plan_dirs_in_git
1418
- }
1419
- };
1437
+ function pathsOverlap(a, b) {
1438
+ return a === b || a.startsWith(`${b}.`) || b.startsWith(`${a}.`);
1439
+ }
1440
+ async function handlePutScopedConfig(vaultDir, body) {
1441
+ const payload = body ?? {};
1442
+ if (!isScopedConfigScope(payload.scope)) {
1443
+ return { status: 400, body: { error: "scope must be project or local" } };
1420
1444
  }
1421
- async function handleUpdatePlanDirs(req) {
1422
- const body = req.body;
1423
- if (!Array.isArray(body.plan_dirs)) {
1424
- return { status: 400, body: { error: "plan_dirs must be an array" } };
1425
- }
1426
- if (body.ignore_plan_dirs_in_git !== void 0 && typeof body.ignore_plan_dirs_in_git !== "boolean") {
1427
- return { status: 400, body: { error: "ignore_plan_dirs_in_git must be a boolean" } };
1428
- }
1429
- const updated = updateConfig(vaultDir, (cfg) => ({
1430
- ...cfg,
1431
- capture: {
1432
- ...cfg.capture,
1433
- plan_dirs: body.plan_dirs,
1434
- ignore_plan_dirs_in_git: body.ignore_plan_dirs_in_git ?? cfg.capture.ignore_plan_dirs_in_git
1445
+ const scope = payload.scope;
1446
+ const patch = payload.patch ?? {};
1447
+ const clearListOrError = validateClearList(payload.clear);
1448
+ if (Array.isArray(clearListOrError) === false) return clearListOrError;
1449
+ const clearList = clearListOrError;
1450
+ if (typeof patch !== "object" || patch === null || Array.isArray(patch)) {
1451
+ return { status: 400, body: { error: "patch must be an object" } };
1452
+ }
1453
+ const patchLeaves = enumerateLeafPaths(patch);
1454
+ const hasPatch = patchLeaves.length > 0;
1455
+ const hasClear = clearList.length > 0;
1456
+ if (!hasPatch && !hasClear) {
1457
+ return { status: 400, body: { error: "patch or clear required" } };
1458
+ }
1459
+ const overlap = patchLeaves.filter((leaf) => clearList.some((clearPath) => pathsOverlap(leaf, clearPath)));
1460
+ if (overlap.length > 0) {
1461
+ return { status: 400, body: { error: "patch_clear_overlap", keys: overlap } };
1462
+ }
1463
+ if (scope === "local") {
1464
+ try {
1465
+ const project = loadConfig(vaultDir);
1466
+ const updated = updateLocalConfig(vaultDir, (local) => {
1467
+ const working = structuredClone(local);
1468
+ for (const key of clearList) unsetAtPath(working, key);
1469
+ const nextLocal = deepMergeConfig(
1470
+ working,
1471
+ patch
1472
+ );
1473
+ const merged = deepMergeConfig(
1474
+ project,
1475
+ nextLocal
1476
+ );
1477
+ MycoConfigSchema.parse(merged);
1478
+ return nextLocal;
1479
+ });
1480
+ return { body: updated };
1481
+ } catch (err) {
1482
+ if (err instanceof external_exports.ZodError) {
1483
+ return { status: 400, body: { error: "validation_failed", issues: err.issues } };
1435
1484
  }
1436
- }));
1437
- deps.setPlanWatchConfig({
1438
- ...deps.planWatchConfig,
1439
- watchDirs: [.../* @__PURE__ */ new Set([...symbiontPlanDirs, ...body.plan_dirs])]
1485
+ throw err;
1486
+ }
1487
+ }
1488
+ try {
1489
+ const updated = updateConfig(vaultDir, (current) => {
1490
+ const working = structuredClone(current);
1491
+ for (const key of clearList) unsetAtPath(working, key);
1492
+ return deepMergeConfig(working, patch);
1440
1493
  });
1441
- deps.reconcileProjectFiles?.();
1442
- return {
1443
- body: {
1444
- custom: updated.capture.plan_dirs,
1445
- ignore_plan_dirs_in_git: updated.capture.ignore_plan_dirs_in_git
1446
- }
1447
- };
1494
+ return { body: updated };
1495
+ } catch (err) {
1496
+ if (err instanceof external_exports.ZodError) {
1497
+ return { status: 400, body: { error: "validation_failed", issues: err.issues } };
1498
+ }
1499
+ throw err;
1448
1500
  }
1449
- return { handleGetPlanDirs, handleUpdatePlanDirs };
1501
+ }
1502
+ function createPlanDirHandlers(deps) {
1503
+ async function handleGetPlanDirs(_req) {
1504
+ return { body: { symbiont: deps.symbiontPlanDirsByAgent } };
1505
+ }
1506
+ return { handleGetPlanDirs };
1450
1507
  }
1451
1508
 
1452
1509
  // src/utils/parse-csv-list.ts
@@ -2229,8 +2286,8 @@ function getConfiguredManifests(projectRoot, config) {
2229
2286
  }
2230
2287
  return allManifests.filter((manifest) => fs12.existsSync(path12.join(projectRoot, manifest.configDir)));
2231
2288
  }
2232
- function reconcileConfiguredSymbionts(projectRoot, vaultDir = path12.join(projectRoot, ".myco")) {
2233
- const config = loadConfig(vaultDir);
2289
+ function reconcileConfiguredSymbionts(projectRoot, vaultDir = path12.join(projectRoot, ".myco"), preloadedConfig) {
2290
+ const config = preloadedConfig ?? loadMergedConfig(vaultDir);
2234
2291
  const manifests = getConfiguredManifests(projectRoot, config);
2235
2292
  const packageRoot = resolvePackageRoot();
2236
2293
  let updatedCount = 0;
@@ -2400,11 +2457,20 @@ function restoreBackup(db, backupPath) {
2400
2457
  }
2401
2458
 
2402
2459
  // src/daemon/api/backup.ts
2460
+ import os7 from "os";
2403
2461
  import path14 from "path";
2462
+ function resolveBackupDir(config, vaultDir) {
2463
+ const rawDir = config.backup.dir;
2464
+ if (!rawDir) return path14.resolve(vaultDir, "backups");
2465
+ const expanded = rawDir.startsWith("~/") ? path14.join(os7.homedir(), rawDir.slice(2)) : rawDir;
2466
+ return path14.resolve(expanded);
2467
+ }
2404
2468
  function createBackupHandlers(deps) {
2469
+ const currentBackupDir = () => resolveBackupDir(deps.liveConfig.current, deps.vaultDir);
2405
2470
  async function handleCreateBackup(_req) {
2406
- const filePath = createBackup(deps.db, deps.backupDir, deps.machineId);
2407
- const backups = listBackups(deps.backupDir);
2471
+ const backupDir = currentBackupDir();
2472
+ const filePath = createBackup(deps.db, backupDir, deps.machineId);
2473
+ const backups = listBackups(backupDir);
2408
2474
  const created = backups.find((b) => b.machine_id === deps.machineId);
2409
2475
  return {
2410
2476
  body: {
@@ -2415,7 +2481,7 @@ function createBackupHandlers(deps) {
2415
2481
  };
2416
2482
  }
2417
2483
  async function handleListBackups(_req) {
2418
- const backups = listBackups(deps.backupDir);
2484
+ const backups = listBackups(currentBackupDir());
2419
2485
  return { body: { backups } };
2420
2486
  }
2421
2487
  async function handleRestorePreview(req) {
@@ -2423,12 +2489,13 @@ function createBackupHandlers(deps) {
2423
2489
  if (!machine_id) {
2424
2490
  return { status: 400, body: { error: "missing_machine_id" } };
2425
2491
  }
2426
- const backups = listBackups(deps.backupDir);
2492
+ const backupDir = currentBackupDir();
2493
+ const backups = listBackups(backupDir);
2427
2494
  const backup = backups.find((b) => b.machine_id === machine_id);
2428
2495
  if (!backup) {
2429
2496
  return { status: 404, body: { error: "backup_not_found" } };
2430
2497
  }
2431
- const backupPath = `${deps.backupDir}/${backup.file_name}`;
2498
+ const backupPath = `${backupDir}/${backup.file_name}`;
2432
2499
  const tables = restorePreview(deps.db, backupPath);
2433
2500
  const total_new = tables.reduce((sum, t) => sum + t.new, 0);
2434
2501
  const total_existing = tables.reduce((sum, t) => sum + t.existing, 0);
@@ -2439,12 +2506,13 @@ function createBackupHandlers(deps) {
2439
2506
  if (!machine_id) {
2440
2507
  return { status: 400, body: { error: "missing_machine_id" } };
2441
2508
  }
2442
- const backups = listBackups(deps.backupDir);
2509
+ const backupDir = currentBackupDir();
2510
+ const backups = listBackups(backupDir);
2443
2511
  const backup = backups.find((b) => b.machine_id === machine_id);
2444
2512
  if (!backup) {
2445
2513
  return { status: 404, body: { error: "backup_not_found" } };
2446
2514
  }
2447
- const backupPath = `${deps.backupDir}/${backup.file_name}`;
2515
+ const backupPath = `${backupDir}/${backup.file_name}`;
2448
2516
  const result = restoreBackup(deps.db, backupPath);
2449
2517
  return { body: { machine_id, ...result } };
2450
2518
  }
@@ -2458,7 +2526,7 @@ function createBackupHandlers(deps) {
2458
2526
  function createBackupConfigHandlers(deps) {
2459
2527
  const { vaultDir } = deps;
2460
2528
  async function handleGetBackupConfig() {
2461
- const cfg = loadConfig(vaultDir);
2529
+ const cfg = loadMergedConfig(vaultDir);
2462
2530
  return { body: { dir: cfg.backup.dir ?? null, default_dir: path14.resolve(vaultDir, "backups") } };
2463
2531
  }
2464
2532
  async function handlePutBackupConfig(req) {
@@ -2690,17 +2758,15 @@ function createTeamHandlers(deps) {
2690
2758
  worker_url: url
2691
2759
  });
2692
2760
  writeSecret(vaultDir, TEAM_API_KEY_SECRET, api_key);
2693
- deps.setTeamClient(client);
2694
- const config = loadConfig(vaultDir);
2761
+ const config = loadMergedConfig(vaultDir);
2695
2762
  return { body: { connected: true, team: config.team } };
2696
2763
  }
2697
2764
  async function handleDisconnect(_req) {
2698
2765
  updateTeamConfig(vaultDir, { enabled: false });
2699
- deps.setTeamClient(null);
2700
2766
  return { body: { connected: false } };
2701
2767
  }
2702
2768
  async function handleStatus(_req) {
2703
- const config = loadConfig(vaultDir);
2769
+ const config = loadMergedConfig(vaultDir);
2704
2770
  const client = deps.getTeamClient();
2705
2771
  const secrets = readSecrets(vaultDir);
2706
2772
  const hasApiKey = Boolean(secrets[TEAM_API_KEY_SECRET]);
@@ -2772,7 +2838,7 @@ function createTeamHandlers(deps) {
2772
2838
  return { body: { retried: count } };
2773
2839
  }
2774
2840
  async function handleUpgradeWorker(_req) {
2775
- const { upgradeWorker } = await import("./team-SNLC6FZM.js");
2841
+ const { upgradeWorker } = await import("./team-3JKF7VAD.js");
2776
2842
  logger.info("team-sync.upgrade.start", "Starting worker upgrade");
2777
2843
  const result = upgradeWorker(vaultDir);
2778
2844
  if (!result.success) {
@@ -2929,7 +2995,7 @@ function createSessionLifecycleHandlers(deps) {
2929
2995
  powerManager,
2930
2996
  machineId,
2931
2997
  logger,
2932
- config,
2998
+ liveConfig,
2933
2999
  vaultDir
2934
3000
  } = deps;
2935
3001
  async function handleRegister(req) {
@@ -2961,7 +3027,7 @@ function createSessionLifecycleHandlers(deps) {
2961
3027
  message: branch ? `Branch: ${branch}` : void 0,
2962
3028
  link: `/sessions/${session_id}`,
2963
3029
  metadata: { sessionId: session_id, agent: agent ?? "claude-code", branch }
2964
- }, config);
3030
+ }, liveConfig.current);
2965
3031
  return { body: { ok: true, sessions: registry.sessions } };
2966
3032
  }
2967
3033
  async function handleUnregister(req) {
@@ -2981,7 +3047,7 @@ function createSessionLifecycleHandlers(deps) {
2981
3047
  title: "Session ended",
2982
3048
  link: `/sessions/${session_id}`,
2983
3049
  metadata: { sessionId: session_id }
2984
- }, config);
3050
+ }, liveConfig.current);
2985
3051
  return { body: { ok: true, sessions: registry.sessions } };
2986
3052
  }
2987
3053
  return { handleRegister, handleUnregister };
@@ -3164,7 +3230,7 @@ function createSkillRecordDeleteHandler(deps) {
3164
3230
  logger.warn(LOG_KINDS.PROCESSOR_BATCH, "Failed to remove skill directory", { name: record.name, error: String(err) });
3165
3231
  }
3166
3232
  try {
3167
- const { syncSkillSymlinks } = await import("./installer-WMTB4NCX.js");
3233
+ const { syncSkillSymlinks } = await import("./installer-I6KRGJOO.js");
3168
3234
  syncSkillSymlinks(projectRoot, record.name, { remove: true });
3169
3235
  } catch (err) {
3170
3236
  logger.warn(LOG_KINDS.PROCESSOR_BATCH, "Failed to remove skill symlinks", { name: record.name, error: String(err) });
@@ -3177,37 +3243,56 @@ function createSkillRecordDeleteHandler(deps) {
3177
3243
 
3178
3244
  // src/daemon/team-sync-init.ts
3179
3245
  function initTeamSync(deps) {
3180
- const { config, machineId, logger, vaultDir, serverVersion } = deps;
3246
+ const { liveConfig, machineId, logger, vaultDir, serverVersion } = deps;
3181
3247
  let teamClient = null;
3182
- if (config.team.enabled && config.team.worker_url) {
3183
- const secrets = readSecrets(vaultDir);
3184
- const teamApiKey = secrets[TEAM_API_KEY_SECRET];
3185
- if (teamApiKey) {
3186
- teamClient = new TeamSyncClient({
3187
- workerUrl: config.team.worker_url,
3188
- apiKey: teamApiKey,
3189
- machineId,
3190
- syncProtocolVersion: SYNC_PROTOCOL_VERSION
3191
- });
3192
- logger.info(LOG_KINDS.TEAM_SYNC_START, "Team sync client initialized", { worker_url: config.team.worker_url });
3193
- teamClient.connect({
3248
+ let clientSignature = null;
3249
+ async function reconcileClient() {
3250
+ const config = liveConfig.current;
3251
+ const workerUrl = config.team.worker_url?.trim() || null;
3252
+ const apiKey = readSecrets(vaultDir)[TEAM_API_KEY_SECRET]?.trim() || null;
3253
+ const nextSignature = config.team.enabled && workerUrl && apiKey ? `${workerUrl}
3254
+ ${apiKey}` : null;
3255
+ if (!nextSignature) {
3256
+ if (teamClient) {
3257
+ logger.info(LOG_KINDS.TEAM_SYNC_START, "Team sync client cleared", {
3258
+ enabled: config.team.enabled,
3259
+ has_worker_url: Boolean(workerUrl),
3260
+ has_api_key: Boolean(apiKey)
3261
+ });
3262
+ }
3263
+ teamClient = null;
3264
+ clientSignature = null;
3265
+ return;
3266
+ }
3267
+ if (teamClient && clientSignature === nextSignature) return;
3268
+ const activeWorkerUrl = workerUrl;
3269
+ const activeApiKey = apiKey;
3270
+ teamClient = new TeamSyncClient({
3271
+ workerUrl: activeWorkerUrl,
3272
+ apiKey: activeApiKey,
3273
+ machineId,
3274
+ syncProtocolVersion: SYNC_PROTOCOL_VERSION
3275
+ });
3276
+ clientSignature = nextSignature;
3277
+ logger.info(LOG_KINDS.TEAM_SYNC_START, "Team sync client initialized", { worker_url: activeWorkerUrl });
3278
+ try {
3279
+ await teamClient.connect({
3194
3280
  machine_id: machineId,
3195
3281
  version: serverVersion
3196
- }).then(() => {
3197
- logger.info(LOG_KINDS.TEAM_SYNC_START, "Node registered with team worker");
3198
- }).catch((err) => {
3199
- logger.warn(LOG_KINDS.TEAM_SYNC_ERROR, "Node registration failed (will retry on next flush)", { error: err.message });
3200
3282
  });
3201
- setTimeout(() => {
3202
- try {
3203
- const backfilled = backfillUnsynced(machineId);
3204
- if (backfilled > 0) {
3205
- logger.info(LOG_KINDS.TEAM_SYNC_START, `Backfilled ${backfilled} unsynced records into outbox`);
3206
- }
3207
- } catch (err) {
3208
- logger.error(LOG_KINDS.TEAM_SYNC_ERROR, "Backfill failed", { error: err.message });
3209
- }
3210
- }, 0);
3283
+ logger.info(LOG_KINDS.TEAM_SYNC_START, "Node registered with team worker");
3284
+ } catch (err) {
3285
+ logger.warn(LOG_KINDS.TEAM_SYNC_ERROR, "Node registration failed (will retry on next flush)", {
3286
+ error: err.message
3287
+ });
3288
+ }
3289
+ try {
3290
+ const backfilled = backfillUnsynced(machineId);
3291
+ if (backfilled > 0) {
3292
+ logger.info(LOG_KINDS.TEAM_SYNC_START, `Backfilled ${backfilled} unsynced records into outbox`);
3293
+ }
3294
+ } catch (err) {
3295
+ logger.error(LOG_KINDS.TEAM_SYNC_ERROR, "Backfill failed", { error: err.message });
3211
3296
  }
3212
3297
  }
3213
3298
  return {
@@ -3215,8 +3300,8 @@ function initTeamSync(deps) {
3215
3300
  setTeamClient: (client) => {
3216
3301
  teamClient = client;
3217
3302
  },
3303
+ reconcileClient,
3218
3304
  registerFlushJob: (powerManager) => {
3219
- if (!config.team.enabled) return;
3220
3305
  const logDeadLettered = (ids) => {
3221
3306
  if (ids.length > 0) {
3222
3307
  logger.error(LOG_KINDS.TEAM_SYNC_DEAD_LETTER, `Dead-lettered ${ids.length} records after max retries`, { ids });
@@ -3225,8 +3310,9 @@ function initTeamSync(deps) {
3225
3310
  powerManager.register({
3226
3311
  name: "team-sync-flush",
3227
3312
  runIn: ["active", "idle", "sleep"],
3228
- preventsDeepSleep: () => countPending() > 0,
3313
+ preventsDeepSleep: () => liveConfig.current.team.enabled && countPending() > 0,
3229
3314
  fn: async () => {
3315
+ if (!liveConfig.current.team.enabled) return;
3230
3316
  const client = teamClient;
3231
3317
  if (!client) return;
3232
3318
  const pending = listPending();
@@ -3714,6 +3800,14 @@ function upsertPlan(data) {
3714
3800
  syncRow("plans", row);
3715
3801
  return row;
3716
3802
  }
3803
+ function getPlan(id) {
3804
+ const db = getDatabase();
3805
+ const row = db.prepare(
3806
+ `SELECT ${SELECT_COLUMNS4} FROM plans WHERE id = ?`
3807
+ ).get(id);
3808
+ if (!row) return null;
3809
+ return toPlanRow(row);
3810
+ }
3717
3811
  function listPlans(options = {}) {
3718
3812
  const db = getDatabase();
3719
3813
  const conditions = [];
@@ -3784,11 +3878,12 @@ async function cleanupAfterSessionCascade(sessionId, result, embeddingManager, v
3784
3878
 
3785
3879
  // src/daemon/trigger-title-summary.ts
3786
3880
  async function triggerTitleSummary(sessionId, deps) {
3787
- const { vaultDir, embeddingManager, config, logger } = deps;
3881
+ const { vaultDir, embeddingManager, liveConfig, logger } = deps;
3882
+ const config = liveConfig.current;
3788
3883
  if (config.agent.summary_batch_interval <= 0) return;
3789
3884
  if (config.agent.event_tasks_enabled === false) return;
3790
3885
  try {
3791
- const { runAgent } = await import("./executor-NXNSUEMQ.js");
3886
+ const { runAgent } = await import("./executor-J4IBXSBY.js");
3792
3887
  runAgent(vaultDir, {
3793
3888
  task: "title-summary",
3794
3889
  instruction: `Process session ${sessionId} only`,
@@ -3853,7 +3948,7 @@ async function handleGetSessionPlans(req) {
3853
3948
  return { body: plans };
3854
3949
  }
3855
3950
  function createSessionMutationHandlers(deps) {
3856
- const { embeddingManager, vaultDir, logger, config } = deps;
3951
+ const { embeddingManager, vaultDir, logger, liveConfig } = deps;
3857
3952
  async function handleDeleteSession(req) {
3858
3953
  const sessionId = req.params.id;
3859
3954
  const result = deleteSessionCascade(sessionId);
@@ -3877,7 +3972,7 @@ function createSessionMutationHandlers(deps) {
3877
3972
  ended_at: session.ended_at ?? epochSeconds()
3878
3973
  });
3879
3974
  }
3880
- await triggerTitleSummary(sessionId, { vaultDir, embeddingManager, config, logger });
3975
+ await triggerTitleSummary(sessionId, { vaultDir, embeddingManager, liveConfig, logger });
3881
3976
  logger.info(LOG_KINDS.API_SESSION_COMPLETE, "Session manually completed", {
3882
3977
  session_id: sessionId,
3883
3978
  was_active: wasActive
@@ -4313,7 +4408,8 @@ var PromptContextBody = external_exports.object({
4313
4408
  function createSessionContextHandler(deps) {
4314
4409
  return async function handleSessionContext(req) {
4315
4410
  const { session_id, branch } = SessionContextBody.parse(req.body);
4316
- const { logger, config } = deps;
4411
+ const { logger, liveConfig } = deps;
4412
+ const config = liveConfig.current;
4317
4413
  logger.debug(LOG_KINDS.CONTEXT_QUERY, "Session context query", { session_id });
4318
4414
  try {
4319
4415
  const parts = [];
@@ -4425,7 +4521,8 @@ function createResumeContextHandler(deps) {
4425
4521
  function createPromptContextHandler(deps) {
4426
4522
  return async function handlePromptContext(req) {
4427
4523
  const { prompt, session_id } = PromptContextBody.parse(req.body);
4428
- const { logger, config, embeddingManager } = deps;
4524
+ const { logger, liveConfig, embeddingManager } = deps;
4525
+ const config = liveConfig.current;
4429
4526
  if (!config.context.prompt_search) {
4430
4527
  logger.debug(LOG_KINDS.CONTEXT_PROMPT, "Prompt search disabled by config", { session_id });
4431
4528
  return { body: { text: "" } };
@@ -4546,7 +4643,7 @@ async function handleListSymbionts(vaultDir) {
4546
4643
  const manifests = loadManifests();
4547
4644
  let enabledNames = null;
4548
4645
  try {
4549
- enabledNames = getEnabledSymbiontNames(loadConfig(vaultDir));
4646
+ enabledNames = getEnabledSymbiontNames(loadMergedConfig(vaultDir));
4550
4647
  } catch {
4551
4648
  }
4552
4649
  const symbionts = manifests.map((m) => ({
@@ -4563,7 +4660,7 @@ async function handleListSymbionts(vaultDir) {
4563
4660
  var EMBEDDING_STATUS_IDLE = "idle";
4564
4661
  var EMBEDDING_STATUS_PENDING = "pending";
4565
4662
  async function handleGetEmbeddingStatus(vaultDir) {
4566
- const config = loadConfig(vaultDir);
4663
+ const config = loadMergedConfig(vaultDir);
4567
4664
  const { queue_depth, embedded_count } = getEmbeddingQueueDepth();
4568
4665
  return {
4569
4666
  body: {
@@ -5941,6 +6038,13 @@ function registerBuiltinDomains() {
5941
6038
  { id: "daemon.version_sync", label: "Version sync restart", defaultMode: "summary", defaultLevel: "info" }
5942
6039
  ]
5943
6040
  });
6041
+ register({
6042
+ domain: "settings",
6043
+ label: "Settings",
6044
+ types: [
6045
+ { id: "settings.saved", label: "Settings saved", defaultMode: "banner", defaultLevel: "success" }
6046
+ ]
6047
+ });
5944
6048
  }
5945
6049
 
5946
6050
  // src/daemon/api/notifications.ts
@@ -5978,7 +6082,7 @@ async function handleCreateNotification(vaultDir, body) {
5978
6082
  return { status: 400, body: { error: "validation_failed", issues: parsed.error.issues } };
5979
6083
  }
5980
6084
  const { domain, type, title, message, link, metadata } = parsed.data;
5981
- const config = loadConfig(vaultDir);
6085
+ const config = loadMergedConfig(vaultDir);
5982
6086
  if (!config.notifications.enabled) {
5983
6087
  return { body: { ok: true, suppressed: true, reason: "notifications_disabled" } };
5984
6088
  }
@@ -6182,7 +6286,7 @@ async function handleDeleteTask(req, vaultDir) {
6182
6286
  }
6183
6287
  async function handleGetTaskConfig(req, vaultDir) {
6184
6288
  const taskId = req.params.id;
6185
- const config = loadConfig(vaultDir);
6289
+ const config = loadMergedConfig(vaultDir);
6186
6290
  const taskConfig = config.agent.tasks?.[taskId] ?? null;
6187
6291
  return { status: HTTP_OK, body: { taskId, config: taskConfig } };
6188
6292
  }
@@ -6334,18 +6438,19 @@ function buildScheduledJobs(tasks, configOverrides, context, initialLastRuns) {
6334
6438
  }
6335
6439
 
6336
6440
  // src/daemon/task-scheduling.ts
6441
+ var SCHEDULED_JOB_PREFIX = "scheduled:";
6337
6442
  async function registerScheduledTasks(powerManager, deps) {
6338
- const { definitionsDir, vaultDir, embeddingManager, logger, config } = deps;
6443
+ const { definitionsDir, vaultDir, embeddingManager, logger, liveConfig } = deps;
6339
6444
  const runningTasks = /* @__PURE__ */ new Set();
6340
6445
  if (!definitionsDir) {
6341
6446
  logger.warn(LOG_KINDS.AGENT_ERROR, "Skipping dynamic task scheduling \u2014 definitions directory unavailable");
6342
6447
  return;
6343
6448
  }
6344
- if (config.agent.scheduled_tasks_enabled === false) {
6345
- logger.info(LOG_KINDS.AGENT_RUN, "Scheduled agent tasks disabled globally (agent.scheduled_tasks_enabled: false)");
6346
- return;
6449
+ let lastEnabled = liveConfig.current.agent.scheduled_tasks_enabled !== false;
6450
+ if (!lastEnabled) {
6451
+ logger.info(LOG_KINDS.AGENT_RUN, "Scheduled agent tasks disabled (agent.scheduled_tasks_enabled: false) \u2014 jobs registered but will no-op until enabled");
6347
6452
  }
6348
- const { loadAllTasks: loadAllTasks2 } = await import("./registry-OCM4WAPJ.js");
6453
+ const { loadAllTasks: loadAllTasks2 } = await import("./registry-MGJSJBAS.js");
6349
6454
  const allTasks = Array.from(loadAllTasks2(definitionsDir, vaultDir).values());
6350
6455
  const taskAgentMap = /* @__PURE__ */ new Map();
6351
6456
  for (const task of allTasks) {
@@ -6371,7 +6476,17 @@ async function registerScheduledTasks(powerManager, deps) {
6371
6476
  else runningTasks.delete(name);
6372
6477
  },
6373
6478
  runTask: async (taskName) => {
6374
- const { runAgent } = await import("./executor-NXNSUEMQ.js");
6479
+ const config = liveConfig.current;
6480
+ const enabled = config.agent.scheduled_tasks_enabled !== false;
6481
+ if (enabled !== lastEnabled) {
6482
+ logger.info(
6483
+ LOG_KINDS.AGENT_RUN,
6484
+ enabled ? "Scheduled agent tasks re-enabled \u2014 resuming" : "Scheduled agent tasks disabled \u2014 skipping until re-enabled"
6485
+ );
6486
+ lastEnabled = enabled;
6487
+ }
6488
+ if (!enabled) return;
6489
+ const { runAgent } = await import("./executor-J4IBXSBY.js");
6375
6490
  const taskConfig = config.agent.tasks?.[taskName];
6376
6491
  const projectRoot = resolve(vaultDir, "..");
6377
6492
  const built = buildTaskInstruction(taskName, taskConfig?.params, taskAgentMap.get(taskName), projectRoot, embeddingManager);
@@ -6463,14 +6578,12 @@ async function registerScheduledTasks(powerManager, deps) {
6463
6578
  };
6464
6579
  const scheduledJobs = buildScheduledJobs(
6465
6580
  allTasks,
6466
- config.agent.tasks ?? {},
6581
+ liveConfig.current.agent.tasks ?? {},
6467
6582
  scheduledContext,
6468
6583
  initialLastRuns
6469
6584
  );
6470
- for (const job of scheduledJobs) {
6471
- powerManager.register(job);
6472
- }
6473
- logger.info(LOG_KINDS.DAEMON_START, `Registered ${scheduledJobs.length} scheduled task(s)`, {
6585
+ powerManager.replaceGroup(SCHEDULED_JOB_PREFIX, scheduledJobs);
6586
+ logger.info(LOG_KINDS.DAEMON_START, `Synced ${scheduledJobs.length} scheduled task(s)`, {
6474
6587
  tasks: scheduledJobs.map((j) => j.name)
6475
6588
  });
6476
6589
  }
@@ -6487,6 +6600,7 @@ function listTeamMembers() {
6487
6600
  // src/daemon/api/mcp-proxy.ts
6488
6601
  var SPORE_ID_RANDOM_BYTES = 4;
6489
6602
  var RESOLUTION_ID_RANDOM_BYTES = 8;
6603
+ var MIN_CONSOLIDATE_SOURCES = 2;
6490
6604
  var RememberBody = external_exports.object({
6491
6605
  content: external_exports.string(),
6492
6606
  type: external_exports.string().optional(),
@@ -6497,19 +6611,53 @@ var SupersedeBody = external_exports.object({
6497
6611
  new_spore_id: external_exports.string(),
6498
6612
  reason: external_exports.string().optional()
6499
6613
  });
6614
+ function isoToEpochSeconds(iso) {
6615
+ const ms = Date.parse(iso);
6616
+ return Number.isNaN(ms) ? void 0 : Math.floor(ms / 1e3);
6617
+ }
6618
+ function registerMcpUserAgent(createdAt) {
6619
+ registerAgent({
6620
+ id: USER_AGENT_ID,
6621
+ name: USER_AGENT_NAME,
6622
+ created_at: createdAt
6623
+ });
6624
+ }
6625
+ function toPlanProgress(content) {
6626
+ const planContent = content ?? "";
6627
+ const checked = (planContent.match(/- \[x\]/gi) ?? []).length;
6628
+ const unchecked = (planContent.match(/- \[ \]/g) ?? []).length;
6629
+ const total = checked + unchecked;
6630
+ return total === 0 ? "N/A" : `${checked}/${total}`;
6631
+ }
6632
+ function toPlanTags(tags) {
6633
+ return tags ? tags.split(",").map((tag) => tag.trim()) : [];
6634
+ }
6635
+ var ConsolidateBody = external_exports.object({
6636
+ source_spore_ids: external_exports.array(external_exports.string()).min(MIN_CONSOLIDATE_SOURCES),
6637
+ consolidated_content: external_exports.string().min(1),
6638
+ observation_type: external_exports.string(),
6639
+ tags: external_exports.array(external_exports.string()).optional(),
6640
+ reason: external_exports.string().optional()
6641
+ });
6500
6642
  function createMcpProxyHandlers(deps) {
6501
6643
  const { machineId, embeddingManager } = deps;
6644
+ function toPlanSummary(row) {
6645
+ return {
6646
+ id: row.id,
6647
+ title: row.title,
6648
+ status: row.status,
6649
+ progress: toPlanProgress(row.content),
6650
+ tags: toPlanTags(row.tags),
6651
+ created_at: row.created_at
6652
+ };
6653
+ }
6502
6654
  async function handleRemember(req) {
6503
6655
  const { content, type, tags } = RememberBody.parse(req.body);
6504
6656
  const { randomBytes } = await import("crypto");
6505
6657
  const observationType = type ?? "discovery";
6506
6658
  const id = `${observationType}-${randomBytes(SPORE_ID_RANDOM_BYTES).toString("hex")}`;
6507
6659
  const now = epochSeconds();
6508
- registerAgent({
6509
- id: USER_AGENT_ID,
6510
- name: USER_AGENT_NAME,
6511
- created_at: now
6512
- });
6660
+ registerMcpUserAgent(now);
6513
6661
  const spore = insertSpore({
6514
6662
  id,
6515
6663
  agent_id: USER_AGENT_ID,
@@ -6542,12 +6690,7 @@ function createMcpProxyHandlers(deps) {
6542
6690
  embeddingManager.onStatusChanged("spores", old_spore_id, "superseded");
6543
6691
  } catch {
6544
6692
  }
6545
- registerAgent({
6546
- id: USER_AGENT_ID,
6547
- name: USER_AGENT_NAME,
6548
- created_at: now
6549
- });
6550
- const { insertResolutionEvent } = await import("./resolution-events-PYLSI6QT.js");
6693
+ registerMcpUserAgent(now);
6551
6694
  const resolutionId = `res-${randomBytes(RESOLUTION_ID_RANDOM_BYTES).toString("hex")}`;
6552
6695
  insertResolutionEvent({
6553
6696
  id: resolutionId,
@@ -6567,31 +6710,95 @@ function createMcpProxyHandlers(deps) {
6567
6710
  }
6568
6711
  };
6569
6712
  }
6713
+ async function handleConsolidate(req) {
6714
+ const { source_spore_ids, consolidated_content, observation_type, tags, reason } = ConsolidateBody.parse(req.body);
6715
+ const { randomBytes } = await import("crypto");
6716
+ const now = epochSeconds();
6717
+ const newSporeId = `${observation_type}-${randomBytes(SPORE_ID_RANDOM_BYTES).toString("hex")}`;
6718
+ const db = getDatabase();
6719
+ registerMcpUserAgent(now);
6720
+ const { wisdom, sourcesSuperseded } = db.transaction(() => {
6721
+ const insertedWisdom = insertSpore({
6722
+ id: newSporeId,
6723
+ agent_id: USER_AGENT_ID,
6724
+ machine_id: machineId,
6725
+ observation_type,
6726
+ content: consolidated_content,
6727
+ tags: tags ? tags.join(", ") : null,
6728
+ created_at: now
6729
+ });
6730
+ const supersededSourceIds = [];
6731
+ for (const sourceId of source_spore_ids) {
6732
+ updateSporeStatus(sourceId, "superseded", now);
6733
+ insertResolutionEvent({
6734
+ id: `res-${randomBytes(RESOLUTION_ID_RANDOM_BYTES).toString("hex")}`,
6735
+ agent_id: USER_AGENT_ID,
6736
+ machine_id: machineId,
6737
+ spore_id: sourceId,
6738
+ action: "consolidate",
6739
+ new_spore_id: newSporeId,
6740
+ reason: reason ?? null,
6741
+ created_at: now
6742
+ });
6743
+ supersededSourceIds.push(sourceId);
6744
+ }
6745
+ return { wisdom: insertedWisdom, sourcesSuperseded: supersededSourceIds };
6746
+ })();
6747
+ embeddingManager.onContentWritten("spores", wisdom.id, consolidated_content, {
6748
+ status: "active",
6749
+ observation_type
6750
+ }).catch(() => {
6751
+ });
6752
+ for (const sourceId of sourcesSuperseded) {
6753
+ try {
6754
+ embeddingManager.onStatusChanged("spores", sourceId, "superseded");
6755
+ } catch {
6756
+ }
6757
+ }
6758
+ return {
6759
+ body: {
6760
+ new_spore_id: newSporeId,
6761
+ sources_superseded: sourcesSuperseded,
6762
+ status: "consolidated",
6763
+ created_at: now
6764
+ }
6765
+ };
6766
+ }
6570
6767
  async function handlePlans(req) {
6768
+ const id = typeof req.query.id === "string" ? req.query.id : void 0;
6769
+ if (id) {
6770
+ const row = getPlan(id);
6771
+ if (!row) return { body: { plans: [] } };
6772
+ return {
6773
+ body: {
6774
+ plans: [{
6775
+ ...toPlanSummary(row),
6776
+ content: row.content
6777
+ }]
6778
+ }
6779
+ };
6780
+ }
6571
6781
  const statusFilter = req.query.status === "all" ? void 0 : req.query.status;
6572
6782
  const limit = req.query.limit ? Number(req.query.limit) : void 0;
6573
6783
  const rows = listPlans({ status: statusFilter, limit });
6574
- const plans = rows.map((row) => {
6575
- const content = row.content ?? "";
6576
- const checked = (content.match(/- \[x\]/gi) ?? []).length;
6577
- const unchecked = (content.match(/- \[ \]/g) ?? []).length;
6578
- const total = checked + unchecked;
6579
- const progress = total === 0 ? "N/A" : `${checked}/${total}`;
6580
- return {
6581
- id: row.id,
6582
- title: row.title,
6583
- status: row.status,
6584
- progress,
6585
- tags: row.tags ? row.tags.split(",").map((t) => t.trim()) : [],
6586
- created_at: row.created_at
6587
- };
6588
- });
6784
+ const plans = rows.map(toPlanSummary);
6589
6785
  return { body: { plans } };
6590
6786
  }
6591
6787
  async function handleSessions(req) {
6592
- const limit = req.query.limit ? Number(req.query.limit) : 20;
6593
- const status = req.query.status;
6594
- const rows = listSessions({ limit, status });
6788
+ const limit = req.query.limit ? Number(req.query.limit) : MCP_SESSIONS_DEFAULT_LIMIT;
6789
+ const status = typeof req.query.status === "string" ? req.query.status : void 0;
6790
+ const branch = typeof req.query.branch === "string" ? req.query.branch : void 0;
6791
+ const user = typeof req.query.user === "string" ? req.query.user : void 0;
6792
+ const plan = typeof req.query.plan === "string" ? req.query.plan : void 0;
6793
+ const sinceRaw = typeof req.query.since === "string" ? req.query.since : void 0;
6794
+ const since = sinceRaw ? isoToEpochSeconds(sinceRaw) : void 0;
6795
+ let id;
6796
+ if (plan) {
6797
+ const planRow = getPlan(plan);
6798
+ if (!planRow || !planRow.session_id) return { body: { sessions: [] } };
6799
+ id = planRow.session_id;
6800
+ }
6801
+ const rows = listSessions({ limit, status, branch, user, since, id });
6595
6802
  const sessions = rows.map((row) => ({
6596
6803
  id: row.id,
6597
6804
  agent: row.agent,
@@ -6601,7 +6808,7 @@ function createMcpProxyHandlers(deps) {
6601
6808
  ended_at: row.ended_at,
6602
6809
  status: row.status,
6603
6810
  title: row.title,
6604
- summary: (row.summary ?? "").slice(0, 300),
6811
+ summary: (row.summary ?? "").slice(0, SESSION_SUMMARY_PREVIEW_CHARS),
6605
6812
  prompt_count: row.prompt_count,
6606
6813
  tool_count: row.tool_count,
6607
6814
  parent_session_id: row.parent_session_id
@@ -6622,6 +6829,7 @@ function createMcpProxyHandlers(deps) {
6622
6829
  return {
6623
6830
  handleRemember,
6624
6831
  handleSupersede,
6832
+ handleConsolidate,
6625
6833
  handlePlans,
6626
6834
  handleSessions,
6627
6835
  handleTeam
@@ -6640,7 +6848,7 @@ function createAgentRunHandlers(deps) {
6640
6848
  const { vaultDir, embeddingManager, logger } = deps;
6641
6849
  async function handleRun(req) {
6642
6850
  const { task, instruction: rawInstruction, agentId } = AgentRunBody.parse(req.body);
6643
- const mycoConfig = loadConfig(vaultDir);
6851
+ const mycoConfig = loadMergedConfig(vaultDir);
6644
6852
  if (!hasConfiguredProvider(mycoConfig, task)) {
6645
6853
  return {
6646
6854
  status: 400,
@@ -6675,7 +6883,7 @@ function createAgentRunHandlers(deps) {
6675
6883
  };
6676
6884
  }
6677
6885
  }
6678
- const { runAgent } = await import("./executor-NXNSUEMQ.js");
6886
+ const { runAgent } = await import("./executor-J4IBXSBY.js");
6679
6887
  const resultPromise = runAgent(vaultDir, {
6680
6888
  task,
6681
6889
  instruction,
@@ -6833,6 +7041,207 @@ function reconcileLogBuffer(logDir, sinceTimestamp) {
6833
7041
  return replayed;
6834
7042
  }
6835
7043
 
7044
+ // src/config/focus.ts
7045
+ var CONFIG_FOCUS_SECTION_PARAM = "configSection";
7046
+ var CONFIG_FOCUS_FIELD_PARAM = "configField";
7047
+ var CONFIG_SECTION_IDS = {
7048
+ appearance: "config-section-appearance",
7049
+ settingsAgent: "config-section-settings-agent",
7050
+ settingsEmbedding: "config-section-settings-embedding",
7051
+ settingsContextInjection: "config-section-settings-context-injection",
7052
+ settingsNotifications: "config-section-settings-notifications",
7053
+ settingsPlanCapture: "config-section-settings-plan-capture",
7054
+ settingsProject: "config-section-settings-project",
7055
+ agentOperations: "config-section-agent-operations",
7056
+ operationsMaintenance: "config-section-operations-maintenance",
7057
+ operationsBackup: "config-section-operations-backup"
7058
+ };
7059
+ var SECTION_RULES = [
7060
+ {
7061
+ prefix: "appearance",
7062
+ page: "/settings",
7063
+ sectionId: CONFIG_SECTION_IDS.appearance,
7064
+ sectionLabel: "Appearance"
7065
+ },
7066
+ {
7067
+ prefix: "agent.provider",
7068
+ page: "/settings",
7069
+ sectionId: CONFIG_SECTION_IDS.settingsAgent,
7070
+ sectionLabel: "Myco Agent"
7071
+ },
7072
+ {
7073
+ prefix: "embedding",
7074
+ page: "/settings",
7075
+ sectionId: CONFIG_SECTION_IDS.settingsEmbedding,
7076
+ sectionLabel: "Embedding"
7077
+ },
7078
+ {
7079
+ prefix: "context",
7080
+ page: "/settings",
7081
+ sectionId: CONFIG_SECTION_IDS.settingsContextInjection,
7082
+ sectionLabel: "Context Injection"
7083
+ },
7084
+ {
7085
+ prefix: "notifications",
7086
+ page: "/settings",
7087
+ sectionId: CONFIG_SECTION_IDS.settingsNotifications,
7088
+ sectionLabel: "Notifications"
7089
+ },
7090
+ {
7091
+ prefix: "capture",
7092
+ page: "/settings",
7093
+ sectionId: CONFIG_SECTION_IDS.settingsPlanCapture,
7094
+ sectionLabel: "Plan Capture"
7095
+ },
7096
+ {
7097
+ prefix: "daemon",
7098
+ page: "/settings",
7099
+ sectionId: CONFIG_SECTION_IDS.settingsProject,
7100
+ sectionLabel: "Project"
7101
+ },
7102
+ {
7103
+ prefix: "agent.scheduled_tasks_enabled",
7104
+ page: "/agent",
7105
+ sectionId: CONFIG_SECTION_IDS.agentOperations,
7106
+ sectionLabel: "Agent Operations",
7107
+ searchParams: { tab: "config" }
7108
+ },
7109
+ {
7110
+ prefix: "agent.event_tasks_enabled",
7111
+ page: "/agent",
7112
+ sectionId: CONFIG_SECTION_IDS.agentOperations,
7113
+ sectionLabel: "Agent Operations",
7114
+ searchParams: { tab: "config" }
7115
+ },
7116
+ {
7117
+ prefix: "agent.summary_batch_interval",
7118
+ page: "/agent",
7119
+ sectionId: CONFIG_SECTION_IDS.agentOperations,
7120
+ sectionLabel: "Agent Operations",
7121
+ searchParams: { tab: "config" }
7122
+ },
7123
+ {
7124
+ prefix: "maintenance",
7125
+ page: "/operations",
7126
+ sectionId: CONFIG_SECTION_IDS.operationsMaintenance,
7127
+ sectionLabel: "Scheduled Maintenance"
7128
+ },
7129
+ {
7130
+ prefix: "backup",
7131
+ page: "/operations",
7132
+ sectionId: CONFIG_SECTION_IDS.operationsBackup,
7133
+ sectionLabel: "Backup & Restore"
7134
+ }
7135
+ ];
7136
+ var EXACT_FIELD_LABELS = {
7137
+ "appearance.theme": "Color Theme",
7138
+ "appearance.mode": "Mode",
7139
+ "appearance.font": "Font",
7140
+ "appearance.density": "Density",
7141
+ "agent.provider": "Provider",
7142
+ "agent.provider.type": "Provider",
7143
+ "agent.provider.model": "Model",
7144
+ "agent.provider.base_url": "Base URL",
7145
+ "agent.provider.context_length": "Context Length",
7146
+ "embedding.provider": "Provider",
7147
+ "embedding.model": "Model",
7148
+ "embedding.base_url": "Base URL",
7149
+ "context.digest_tier": "Digest Tier",
7150
+ "context.prompt_search": "Prompt Search",
7151
+ "context.prompt_max_spores": "Max Spores per Prompt",
7152
+ "notifications.enabled": "Notifications",
7153
+ "notifications.default_mode": "Default Display",
7154
+ "notifications.system_notifications": "Browser Notifications",
7155
+ "capture.ignore_plan_dirs_in_git": "Ignore Custom Plan Dirs In Git",
7156
+ "capture.plan_dirs": "Custom Directories",
7157
+ "daemon.port": "Daemon Port",
7158
+ "daemon.log_level": "Log Level",
7159
+ "daemon.log_retention_days": "Log Retention (days)",
7160
+ "agent.scheduled_tasks_enabled": "Scheduled Tasks",
7161
+ "agent.event_tasks_enabled": "Event-Driven Tasks",
7162
+ "agent.summary_batch_interval": "Title & Summary Batch Interval",
7163
+ "maintenance.auto_optimize": "Auto-optimize",
7164
+ "maintenance.auto_optimize_interval_hours": "Auto-optimize Interval",
7165
+ "backup.dir": "Backup Directory"
7166
+ };
7167
+ var DYNAMIC_FIELD_LABEL_RULES = [
7168
+ {
7169
+ prefix: "notifications.domains.",
7170
+ format: (path23) => {
7171
+ const match = /^notifications\.domains\.([^.]+)\.(enabled|mode)$/.exec(path23);
7172
+ if (!match) return null;
7173
+ const [, domain, leaf] = match;
7174
+ const domainLabel = humanizeToken(domain);
7175
+ return leaf === "mode" ? `${domainLabel} Display` : `${domainLabel} Notifications`;
7176
+ }
7177
+ }
7178
+ ];
7179
+ var SAVE_MESSAGE_LABEL_LIMIT = 3;
7180
+ function resolveConfigFocusTarget(path23) {
7181
+ const section = findSectionRule(path23);
7182
+ if (!section) return null;
7183
+ return {
7184
+ ...section,
7185
+ fieldPath: path23,
7186
+ fieldLabel: resolveFieldLabel(path23)
7187
+ };
7188
+ }
7189
+ function buildConfigFocusLink(target) {
7190
+ const params = new URLSearchParams(target.searchParams);
7191
+ params.set(CONFIG_FOCUS_SECTION_PARAM, target.sectionId);
7192
+ params.set(CONFIG_FOCUS_FIELD_PARAM, target.fieldPath);
7193
+ return `${target.page}?${params.toString()}`;
7194
+ }
7195
+ function buildScopedConfigSaveNotification(scope, touchedPaths) {
7196
+ const uniquePaths = [...new Set(touchedPaths)];
7197
+ const scopeLabel = scope === "local" ? "Personal" : "Project";
7198
+ const focusTarget = uniquePaths.map(resolveConfigFocusTarget).find((target) => target !== null) ?? null;
7199
+ const fieldLabels = uniquePaths.map(resolveFieldLabel);
7200
+ const primaryLabel = fieldLabels[0] ?? "Setting";
7201
+ const labelList = fieldLabels.slice(0, SAVE_MESSAGE_LABEL_LIMIT).join(", ");
7202
+ const remainingCount = Math.max(0, fieldLabels.length - SAVE_MESSAGE_LABEL_LIMIT);
7203
+ const messageLabel = remainingCount > 0 ? `${labelList}, +${remainingCount} more` : labelList;
7204
+ return {
7205
+ title: uniquePaths.length === 1 ? `${primaryLabel} saved` : `${uniquePaths.length} settings saved`,
7206
+ message: focusTarget ? `${focusTarget.sectionLabel} \xB7 ${messageLabel} \xB7 ${scopeLabel}` : `${messageLabel} \xB7 ${scopeLabel}`,
7207
+ link: focusTarget ? buildConfigFocusLink(focusTarget) : null,
7208
+ metadata: {
7209
+ scope,
7210
+ touched_paths: uniquePaths,
7211
+ field_labels: fieldLabels,
7212
+ focus_target: focusTarget ? {
7213
+ page: focusTarget.page,
7214
+ section_id: focusTarget.sectionId,
7215
+ field_path: focusTarget.fieldPath,
7216
+ field_label: focusTarget.fieldLabel
7217
+ } : null
7218
+ }
7219
+ };
7220
+ }
7221
+ function findSectionRule(path23) {
7222
+ for (const rule of SECTION_RULES) {
7223
+ if (path23 === rule.prefix || path23.startsWith(`${rule.prefix}.`)) {
7224
+ const { page, sectionId, sectionLabel, searchParams } = rule;
7225
+ return { page, sectionId, sectionLabel, searchParams };
7226
+ }
7227
+ }
7228
+ return null;
7229
+ }
7230
+ function resolveFieldLabel(path23) {
7231
+ const exact = EXACT_FIELD_LABELS[path23];
7232
+ if (exact) return exact;
7233
+ for (const rule of DYNAMIC_FIELD_LABEL_RULES) {
7234
+ if (path23 === rule.prefix || path23.startsWith(rule.prefix)) {
7235
+ const label = rule.format(path23);
7236
+ if (label) return label;
7237
+ }
7238
+ }
7239
+ return humanizeToken(path23.split(".").pop() ?? "setting");
7240
+ }
7241
+ function humanizeToken(value) {
7242
+ return value.split(/[-_]/g).filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join(" ");
7243
+ }
7244
+
6836
7245
  // src/daemon/power.ts
6837
7246
  var PowerManager = class {
6838
7247
  state = "active";
@@ -6850,6 +7259,10 @@ var PowerManager = class {
6850
7259
  register(job) {
6851
7260
  this.jobs.push(job);
6852
7261
  }
7262
+ replaceGroup(prefix, jobs) {
7263
+ this.jobs = this.jobs.filter((job) => !job.name.startsWith(prefix));
7264
+ this.jobs.push(...jobs);
7265
+ }
6853
7266
  recordActivity() {
6854
7267
  this.lastActivity = Date.now();
6855
7268
  this.deepSleepHeld = false;
@@ -6999,7 +7412,7 @@ async function runSessionMaintenance(deps) {
6999
7412
  // src/daemon/power-jobs.ts
7000
7413
  var STAGING_MAX_AGE_MS = 24 * 60 * 60 * 1e3;
7001
7414
  function registerPowerJobs(powerManager, deps) {
7002
- const { embeddingManager, registry, logger, config, db, backupDir, machineId, vaultDir, databaseManager } = deps;
7415
+ const { embeddingManager, registry, logger, liveConfig, db, machineId, vaultDir, databaseManager } = deps;
7003
7416
  let reconcileRunning = false;
7004
7417
  powerManager.register({
7005
7418
  name: "embedding-reconcile",
@@ -7022,14 +7435,14 @@ function registerPowerJobs(powerManager, deps) {
7022
7435
  registeredSessionIds: () => registry.sessions,
7023
7436
  embeddingManager,
7024
7437
  vaultDir,
7025
- staleThresholdMs: config.daemon.stale_session_threshold_ms
7438
+ staleThresholdMs: liveConfig.current.daemon.stale_session_threshold_ms
7026
7439
  })
7027
7440
  });
7028
7441
  powerManager.register({
7029
7442
  name: "log-retention",
7030
7443
  runIn: ["idle", "sleep"],
7031
7444
  fn: async () => {
7032
- const retentionDays = config.daemon.log_retention_days;
7445
+ const retentionDays = liveConfig.current.daemon.log_retention_days;
7033
7446
  const cutoff = new Date(Date.now() - retentionDays * MS_PER_DAY).toISOString();
7034
7447
  const deleted = deleteOldLogs(cutoff);
7035
7448
  if (deleted > 0) {
@@ -7042,6 +7455,7 @@ function registerPowerJobs(powerManager, deps) {
7042
7455
  runIn: ["idle", "sleep"],
7043
7456
  fn: async () => {
7044
7457
  try {
7458
+ const backupDir = resolveBackupDir(liveConfig.current, vaultDir);
7045
7459
  logger.info(LOG_KINDS.BACKUP_START, "Auto-backup starting");
7046
7460
  const filePath = createBackup(db, backupDir, machineId);
7047
7461
  logger.info(LOG_KINDS.BACKUP_COMPLETE, "Auto-backup complete", { file_path: filePath });
@@ -7054,6 +7468,7 @@ function registerPowerJobs(powerManager, deps) {
7054
7468
  name: "database-optimize",
7055
7469
  runIn: ["idle", "sleep"],
7056
7470
  fn: async () => {
7471
+ const config = liveConfig.current;
7057
7472
  if (!config.maintenance?.auto_optimize) return;
7058
7473
  const intervalMs = (config.maintenance.auto_optimize_interval_hours ?? 24) * MS_PER_HOUR;
7059
7474
  const lastRun = await databaseManager.getLastOptimizeAt();
@@ -7366,7 +7781,7 @@ function captureBatchImages(input) {
7366
7781
 
7367
7782
  // src/daemon/plan-capture.ts
7368
7783
  import { createHash as createHash4 } from "crypto";
7369
- import os7 from "os";
7784
+ import os8 from "os";
7370
7785
  import path20 from "path";
7371
7786
  function extractTaggedPlans(text, tags) {
7372
7787
  const results = [];
@@ -7395,7 +7810,7 @@ var PLAN_ID_HASH_LENGTH = 16;
7395
7810
  function isInPlanDirectory(filePath, watchDirs, projectRoot) {
7396
7811
  const abs = path20.isAbsolute(filePath) ? filePath : path20.resolve(projectRoot, filePath);
7397
7812
  return watchDirs.some((dir) => {
7398
- const expanded = dir.startsWith("~/") ? path20.join(os7.homedir(), dir.slice(2)) : dir;
7813
+ const expanded = dir.startsWith("~/") ? path20.join(os8.homedir(), dir.slice(2)) : dir;
7399
7814
  const absDir = path20.isAbsolute(expanded) ? expanded : path20.resolve(projectRoot, expanded);
7400
7815
  const prefix = absDir.endsWith(path20.sep) ? absDir : absDir + path20.sep;
7401
7816
  return abs === absDir || abs.startsWith(prefix);
@@ -7499,16 +7914,27 @@ function enrichTurnsWithToolMetadata(turns, events) {
7499
7914
  }
7500
7915
  }
7501
7916
  function createStopProcessor(deps) {
7502
- const { registry, sessionBuffers, transcriptMiner, embeddingManager, logger, config, vaultDir } = deps;
7917
+ const { registry, sessionBuffers, transcriptMiner, embeddingManager, logger, liveConfig, vaultDir } = deps;
7503
7918
  let activeStopProcessing = null;
7504
7919
  const sessionTitleCache = /* @__PURE__ */ new Map();
7505
7920
  const StopBody = external_exports.object({
7506
7921
  session_id: external_exports.string(),
7922
+ agent: external_exports.string().optional(),
7507
7923
  user: external_exports.string().optional(),
7508
7924
  transcript_path: external_exports.string().nullish(),
7509
7925
  last_assistant_message: external_exports.string().nullish()
7510
7926
  });
7511
- const triggerTitleSummary2 = (sessionId) => triggerTitleSummary(sessionId, { vaultDir, embeddingManager, config, logger });
7927
+ const triggerTitleSummary2 = (sessionId) => triggerTitleSummary(sessionId, { vaultDir, embeddingManager, liveConfig, logger });
7928
+ function cleanupInvalidCapturedSession(sessionId) {
7929
+ registry.unregister(sessionId);
7930
+ sessionBuffers.delete(sessionId);
7931
+ sessionTitleCache.delete(sessionId);
7932
+ const result = deleteSessionCascade(sessionId);
7933
+ if (!result.deleted) return false;
7934
+ cleanupAfterSessionCascade(sessionId, result, embeddingManager, vaultDir).catch(() => {
7935
+ });
7936
+ return true;
7937
+ }
7512
7938
  async function processStopEvent(sessionId, user, sessionMeta, hookTranscriptPath, lastAssistantMessage) {
7513
7939
  const transcriptResult = transcriptMiner.getAllTurnsWithSource(sessionId, hookTranscriptPath);
7514
7940
  let allTurns = transcriptResult.turns;
@@ -7681,7 +8107,30 @@ function createStopProcessor(deps) {
7681
8107
  });
7682
8108
  }
7683
8109
  const handleStopRoute = async (req) => {
7684
- const { session_id: sessionId, user, transcript_path: hookTranscriptPath, last_assistant_message: lastAssistantMessage } = StopBody.parse(req.body);
8110
+ const {
8111
+ session_id: sessionId,
8112
+ agent,
8113
+ user,
8114
+ transcript_path: hookTranscriptPath,
8115
+ last_assistant_message: lastAssistantMessage
8116
+ } = StopBody.parse(req.body);
8117
+ if (hookTranscriptPath) {
8118
+ const transcriptMeta = readTranscriptMeta(hookTranscriptPath) ?? void 0;
8119
+ const detectedAgent = agent ?? getSession(sessionId)?.agent ?? "claude-code";
8120
+ const decision = evaluateSessionCaptureRules(loadManifests(), detectedAgent, {
8121
+ transcriptPath: hookTranscriptPath,
8122
+ transcriptMeta
8123
+ });
8124
+ if (decision.action === "drop") {
8125
+ const deleted = cleanupInvalidCapturedSession(sessionId);
8126
+ logger.info(LOG_KINDS.HOOKS_STOP, "Stop ignored \u2014 invalid captured session", {
8127
+ session_id: sessionId,
8128
+ reason: decision.reason ?? "rule",
8129
+ deleted_existing_session: deleted
8130
+ });
8131
+ return { body: { ok: true, ignored: decision.reason ?? "rule" } };
8132
+ }
8133
+ }
7685
8134
  const existingSessionMeta = registry.getSession(sessionId);
7686
8135
  if (!hookTranscriptPath && !existingSessionMeta) {
7687
8136
  logger.info(LOG_KINDS.HOOKS_STOP, "Stop ignored \u2014 ephemeral sub-invocation", {
@@ -7736,7 +8185,7 @@ function createEventDispatcher(deps) {
7736
8185
  powerManager,
7737
8186
  logger,
7738
8187
  machineId,
7739
- config,
8188
+ liveConfig,
7740
8189
  vaultDir,
7741
8190
  reconcileSession,
7742
8191
  planWatchConfig,
@@ -7803,7 +8252,7 @@ function createEventDispatcher(deps) {
7803
8252
  });
7804
8253
  }
7805
8254
  const batchCount = promptNumber;
7806
- const summaryInterval = config.agent.summary_batch_interval;
8255
+ const summaryInterval = liveConfig.current.agent.summary_batch_interval;
7807
8256
  if (summaryInterval > 0 && batchCount > 0 && batchCount % summaryInterval === 0) {
7808
8257
  triggerTitleSummary2(event.session_id);
7809
8258
  }
@@ -7969,9 +8418,64 @@ function createEventDispatcher(deps) {
7969
8418
  };
7970
8419
  }
7971
8420
 
8421
+ // src/daemon/config-reactions/registry.ts
8422
+ function createConfigReactionRegistry(logger) {
8423
+ const entries = [];
8424
+ return {
8425
+ on(paths, fn) {
8426
+ entries.push({ paths, fn });
8427
+ },
8428
+ async fire(touchedPaths, ctx) {
8429
+ for (const entry of entries) {
8430
+ if (!shouldFire(entry.paths, touchedPaths)) continue;
8431
+ try {
8432
+ await entry.fn(ctx);
8433
+ } catch (err) {
8434
+ logger.error("config-reactions", "reaction threw", { error: String(err) });
8435
+ }
8436
+ }
8437
+ }
8438
+ };
8439
+ }
8440
+ function shouldFire(registeredPaths, touched) {
8441
+ if (registeredPaths.length === 0) return true;
8442
+ for (const prefix of registeredPaths) {
8443
+ for (const path23 of touched) {
8444
+ if (path23 === prefix || path23.startsWith(`${prefix}.`)) return true;
8445
+ }
8446
+ }
8447
+ return false;
8448
+ }
8449
+
8450
+ // src/daemon/config-reactions/context.ts
8451
+ function loadReactionContext(vaultDir, logger) {
8452
+ try {
8453
+ return loadMergedConfig(vaultDir);
8454
+ } catch (err) {
8455
+ if (err instanceof external_exports.ZodError) {
8456
+ logger.warn("config-reactions", "skipping reactions because merged config is invalid", {
8457
+ issues: err.issues.map((issue) => ({
8458
+ path: issue.path.join("."),
8459
+ message: issue.message
8460
+ }))
8461
+ });
8462
+ return null;
8463
+ }
8464
+ throw err;
8465
+ }
8466
+ }
8467
+
8468
+ // src/daemon/plan-watch-reaction.ts
8469
+ function createPlanWatchReaction(deps) {
8470
+ return (ctx) => {
8471
+ const customDirs = ctx.capture.plan_dirs ?? [];
8472
+ deps.planWatchConfig.watchDirs = [.../* @__PURE__ */ new Set([...deps.symbiontPlanDirs, ...customDirs])];
8473
+ deps.planWatchConfig.extensions = ctx.capture.artifact_extensions;
8474
+ };
8475
+ }
8476
+
7972
8477
  // src/daemon/main.ts
7973
8478
  import fs23 from "fs";
7974
- import os8 from "os";
7975
8479
  import path22 from "path";
7976
8480
  function killStaleDaemon(vaultDir, logger) {
7977
8481
  const daemonJsonPath = path22.join(vaultDir, "daemon.json");
@@ -7998,12 +8502,13 @@ async function main() {
7998
8502
  }
7999
8503
  const vaultDir = path22.resolve(vaultArg);
8000
8504
  loadSecrets(vaultDir);
8001
- const config = loadConfig(vaultDir);
8505
+ const config = loadMergedConfig(vaultDir);
8506
+ const liveConfig = { current: config };
8002
8507
  const manifests = loadManifests();
8003
8508
  const symbiontPlanDirs = manifests.flatMap((m) => m.capture?.planDirs ?? []);
8004
8509
  const symbiontPlanTags = [...new Set(manifests.flatMap((m) => m.capture?.planTags ?? []))];
8005
8510
  const projectRoot = process.cwd();
8006
- let planWatchConfig = {
8511
+ const planWatchConfig = {
8007
8512
  watchDirs: [.../* @__PURE__ */ new Set([...symbiontPlanDirs, ...config.capture.plan_dirs ?? []])],
8008
8513
  projectRoot,
8009
8514
  extensions: config.capture.artifact_extensions
@@ -8113,7 +8618,7 @@ async function main() {
8113
8618
  const databaseManager = new DatabaseMaintenanceManager(vaultDbPath(vaultDir), vaultDir, logger);
8114
8619
  let definitionsDir;
8115
8620
  try {
8116
- const { registerBuiltInAgentsAndTasks, resolveDefinitionsDir: resolveDefinitionsDir2 } = await import("./loader-AAZ6VUIA.js");
8621
+ const { registerBuiltInAgentsAndTasks, resolveDefinitionsDir: resolveDefinitionsDir2 } = await import("./loader-TSB5M7FD.js");
8117
8622
  definitionsDir = resolveDefinitionsDir2();
8118
8623
  await registerBuiltInAgentsAndTasks(definitionsDir, vaultDir);
8119
8624
  logger.info(LOG_KINDS.AGENT_TASK, "Built-in agents and tasks registered");
@@ -8138,7 +8643,7 @@ async function main() {
8138
8643
  message: "Daemon restarted while run was in progress",
8139
8644
  link: `/agent?run=${row.id}`,
8140
8645
  metadata: { taskName: row.task, runId: row.id, reason: "daemon_restart" }
8141
- }, config);
8646
+ }, liveConfig.current);
8142
8647
  }
8143
8648
  logger.info(LOG_KINDS.AGENT_RUN, "Cleaned stale running agent runs", {
8144
8649
  count: staleRows.length,
@@ -8196,7 +8701,7 @@ async function main() {
8196
8701
  transcriptMiner,
8197
8702
  embeddingManager,
8198
8703
  logger,
8199
- config,
8704
+ liveConfig,
8200
8705
  vaultDir,
8201
8706
  planTags: symbiontPlanTags
8202
8707
  });
@@ -8209,7 +8714,7 @@ async function main() {
8209
8714
  powerManager,
8210
8715
  machineId,
8211
8716
  logger,
8212
- config,
8717
+ liveConfig,
8213
8718
  vaultDir
8214
8719
  });
8215
8720
  server.registerRoute("POST", "/sessions/register", sessionLifecycle.handleRegister);
@@ -8220,7 +8725,7 @@ async function main() {
8220
8725
  powerManager,
8221
8726
  logger,
8222
8727
  machineId,
8223
- config,
8728
+ liveConfig,
8224
8729
  vaultDir,
8225
8730
  reconcileSession: reconciler.reconcileSession,
8226
8731
  planWatchConfig,
@@ -8228,7 +8733,7 @@ async function main() {
8228
8733
  });
8229
8734
  server.registerRoute("POST", "/events", eventDispatcher);
8230
8735
  server.registerRoute("POST", "/events/stop", stopProcessor.handleStopRoute);
8231
- const contextDeps = { embeddingManager, config, logger };
8736
+ const contextDeps = { embeddingManager, liveConfig, logger };
8232
8737
  server.registerRoute("POST", "/context", createSessionContextHandler(contextDeps));
8233
8738
  server.registerRoute("POST", "/context/resume", createResumeContextHandler(contextDeps));
8234
8739
  server.registerRoute("POST", "/context/prompt", createPromptContextHandler(contextDeps));
@@ -8236,39 +8741,76 @@ async function main() {
8236
8741
  let configHash = computeConfigHash(vaultDir);
8237
8742
  server.registerRoute("GET", "/api/config", async () => handleGetConfig(vaultDir));
8238
8743
  server.registerRoute("GET", "/api/symbionts", async () => handleListSymbionts(vaultDir));
8239
- server.registerRoute("PUT", "/api/config", async (req) => {
8240
- const result = await handlePutConfig(vaultDir, req.body);
8241
- if (!result.status || result.status < 400) {
8242
- reconcileConfiguredSymbionts(path22.dirname(vaultDir), vaultDir);
8243
- configHash = computeConfigHash(vaultDir);
8244
- }
8245
- return result;
8246
- });
8744
+ server.registerRoute("GET", "/api/config/merged", async () => handleGetMergedConfig(vaultDir));
8745
+ server.registerRoute("GET", "/api/config/local", async () => handleGetLocalConfig(vaultDir));
8247
8746
  const symbiontPlanDirsByAgent = {};
8248
8747
  for (const m of manifests) {
8249
8748
  const dirs = m.capture?.planDirs ?? [];
8250
8749
  if (dirs.length > 0) symbiontPlanDirsByAgent[m.displayName] = dirs;
8251
8750
  }
8252
- const planDirHandlers = createPlanDirHandlers({
8253
- vaultDir,
8254
- symbiontPlanDirsByAgent,
8751
+ const reactions = createConfigReactionRegistry(logger);
8752
+ reactions.on([], () => {
8753
+ configHash = computeConfigHash(vaultDir);
8754
+ });
8755
+ reactions.on([], (ctx) => {
8756
+ liveConfig.current = ctx;
8757
+ });
8758
+ reactions.on(["capture", "symbionts"], (ctx) => {
8759
+ reconcileConfiguredSymbionts(path22.dirname(vaultDir), vaultDir, ctx);
8760
+ });
8761
+ reactions.on(["capture"], createPlanWatchReaction({
8255
8762
  symbiontPlanDirs,
8256
- planWatchConfig,
8257
- setPlanWatchConfig: (cfg) => {
8258
- planWatchConfig = cfg;
8259
- },
8260
- reconcileProjectFiles: () => {
8261
- reconcileConfiguredSymbionts(path22.dirname(vaultDir), vaultDir);
8763
+ planWatchConfig
8764
+ }));
8765
+ reactions.on(["daemon.log_level"], (ctx) => {
8766
+ logger.setLevel(ctx.daemon.log_level);
8767
+ if (ctx.daemon.log_level === "debug") {
8768
+ process.env.MYCO_AGENT_DEBUG = "1";
8769
+ } else {
8770
+ delete process.env.MYCO_AGENT_DEBUG;
8262
8771
  }
8263
8772
  });
8264
- server.registerRoute("GET", "/api/config/plan-dirs", planDirHandlers.handleGetPlanDirs);
8265
- server.registerRoute("POST", "/api/config/plan-dirs", async (req) => {
8266
- const result = await planDirHandlers.handleUpdatePlanDirs(req);
8267
- if (!result.status || result.status < 400) {
8773
+ async function syncScheduledTasks() {
8774
+ await registerScheduledTasks(powerManager, { definitionsDir, vaultDir, embeddingManager, logger, liveConfig });
8775
+ }
8776
+ reactions.on(["agent.tasks"], async () => {
8777
+ await syncScheduledTasks();
8778
+ });
8779
+ async function applyConfigWriteReactions(touchedPaths) {
8780
+ const reactionContext = loadReactionContext(vaultDir, logger);
8781
+ if (!reactionContext) {
8268
8782
  configHash = computeConfigHash(vaultDir);
8783
+ return null;
8784
+ }
8785
+ await reactions.fire(touchedPaths, reactionContext);
8786
+ return reactionContext;
8787
+ }
8788
+ server.registerRoute("PUT", "/api/config/scoped", async (req) => {
8789
+ const result = await handlePutScopedConfig(vaultDir, req.body);
8790
+ if (!result.status || result.status < 400) {
8791
+ const body = req.body;
8792
+ const touchedPaths = computeTouchedPaths(body.patch, body.clear);
8793
+ const reactionContext = await applyConfigWriteReactions(touchedPaths);
8794
+ if (reactionContext) {
8795
+ const summary = buildScopedConfigSaveNotification(body.scope, touchedPaths);
8796
+ notify(vaultDir, {
8797
+ domain: "settings",
8798
+ type: "settings.saved",
8799
+ title: summary.title,
8800
+ message: summary.message,
8801
+ link: summary.link ?? void 0,
8802
+ metadata: summary.metadata
8803
+ }, reactionContext);
8804
+ } else {
8805
+ configHash = computeConfigHash(vaultDir);
8806
+ }
8269
8807
  }
8270
8808
  return result;
8271
8809
  });
8810
+ const planDirHandlers = createPlanDirHandlers({
8811
+ symbiontPlanDirsByAgent
8812
+ });
8813
+ server.registerRoute("GET", "/api/config/plan-dirs", planDirHandlers.handleGetPlanDirs);
8272
8814
  const configHashRef = { get: () => configHash };
8273
8815
  server.registerRoute("GET", "/api/stats", createLiveStatsHandler({
8274
8816
  vaultDir,
@@ -8302,7 +8844,7 @@ async function main() {
8302
8844
  server.registerRoute("GET", "/api/progress/:token", async (req) => handleGetProgress(progressTracker, req.params.token));
8303
8845
  server.registerRoute("GET", "/api/sessions", handleListSessions);
8304
8846
  server.registerRoute("GET", "/api/sessions/:id", handleGetSession);
8305
- const sessionMutations = createSessionMutationHandlers({ embeddingManager, vaultDir, logger, config });
8847
+ const sessionMutations = createSessionMutationHandlers({ embeddingManager, vaultDir, logger, liveConfig });
8306
8848
  server.registerRoute("GET", "/api/sessions/:id/impact", sessionMutations.handleGetSessionImpact);
8307
8849
  server.registerRoute("POST", "/api/sessions/:id/complete", sessionMutations.handleCompleteSession);
8308
8850
  server.registerRoute("DELETE", "/api/sessions/:id", sessionMutations.handleDeleteSession);
@@ -8335,31 +8877,70 @@ async function main() {
8335
8877
  server.registerRoute("GET", "/api/agent/tasks", async (req) => handleListTasks(req, vaultDir));
8336
8878
  server.registerRoute("GET", "/api/agent/tasks/:id", async (req) => handleGetTask(req, vaultDir));
8337
8879
  server.registerRoute("GET", "/api/agent/tasks/:id/yaml", async (req) => handleGetTaskYaml(req, vaultDir));
8338
- server.registerRoute("PUT", "/api/agent/tasks/:id", async (req) => handleUpdateTask(req, vaultDir));
8339
- server.registerRoute("POST", "/api/agent/tasks", async (req) => handleCreateTask(req, vaultDir));
8340
- server.registerRoute("POST", "/api/agent/tasks/:id/copy", async (req) => handleCopyTask(req, vaultDir));
8341
- server.registerRoute("DELETE", "/api/agent/tasks/:id", async (req) => handleDeleteTask(req, vaultDir));
8880
+ server.registerRoute("PUT", "/api/agent/tasks/:id", async (req) => {
8881
+ const result = await handleUpdateTask(req, vaultDir);
8882
+ if (!result.status || result.status < 400) {
8883
+ await syncScheduledTasks();
8884
+ }
8885
+ return result;
8886
+ });
8887
+ server.registerRoute("POST", "/api/agent/tasks", async (req) => {
8888
+ const result = await handleCreateTask(req, vaultDir);
8889
+ if (!result.status || result.status < 400) {
8890
+ await syncScheduledTasks();
8891
+ }
8892
+ return result;
8893
+ });
8894
+ server.registerRoute("POST", "/api/agent/tasks/:id/copy", async (req) => {
8895
+ const result = await handleCopyTask(req, vaultDir);
8896
+ if (!result.status || result.status < 400) {
8897
+ await syncScheduledTasks();
8898
+ }
8899
+ return result;
8900
+ });
8901
+ server.registerRoute("DELETE", "/api/agent/tasks/:id", async (req) => {
8902
+ const result = await handleDeleteTask(req, vaultDir);
8903
+ if (!result.status || result.status < 400) {
8904
+ await syncScheduledTasks();
8905
+ }
8906
+ return result;
8907
+ });
8342
8908
  server.registerRoute("GET", "/api/agent/tasks/:id/config", async (req) => handleGetTaskConfig(req, vaultDir));
8343
- server.registerRoute("PUT", "/api/agent/tasks/:id/config", async (req) => handleUpdateTaskConfig(req, vaultDir));
8909
+ server.registerRoute("PUT", "/api/agent/tasks/:id/config", async (req) => {
8910
+ const result = await handleUpdateTaskConfig(req, vaultDir);
8911
+ if (!result.status || result.status < 400) {
8912
+ await applyConfigWriteReactions([`agent.tasks.${req.params.id}`]);
8913
+ }
8914
+ return result;
8915
+ });
8344
8916
  server.registerRoute("GET", "/api/providers", async () => handleGetProviders());
8345
8917
  server.registerRoute("POST", "/api/providers/test", async (req) => handleTestProvider(req));
8346
8918
  const mcpProxy = createMcpProxyHandlers({ machineId, embeddingManager });
8347
8919
  server.registerRoute("POST", "/api/mcp/remember", mcpProxy.handleRemember);
8348
8920
  server.registerRoute("POST", "/api/mcp/supersede", mcpProxy.handleSupersede);
8921
+ server.registerRoute("POST", "/api/mcp/consolidate", mcpProxy.handleConsolidate);
8349
8922
  server.registerRoute("GET", "/api/mcp/plans", mcpProxy.handlePlans);
8350
8923
  server.registerRoute("GET", "/api/mcp/sessions", mcpProxy.handleSessions);
8351
8924
  server.registerRoute("GET", "/api/mcp/team", mcpProxy.handleTeam);
8352
- const rawBackupDir = config.backup.dir;
8353
- const backupDir = rawBackupDir ? path22.resolve(rawBackupDir.startsWith("~/") ? path22.join(os8.homedir(), rawBackupDir.slice(2)) : rawBackupDir) : path22.resolve(vaultDir, "backups");
8354
- const backupHandlers = createBackupHandlers({ db, backupDir, machineId });
8925
+ const backupHandlers = createBackupHandlers({ db, machineId, vaultDir, liveConfig });
8355
8926
  server.registerRoute("POST", "/api/backup", backupHandlers.handleCreateBackup);
8356
8927
  server.registerRoute("GET", "/api/backups", backupHandlers.handleListBackups);
8357
8928
  server.registerRoute("POST", "/api/restore/preview", backupHandlers.handleRestorePreview);
8358
8929
  server.registerRoute("POST", "/api/restore", backupHandlers.handleRestore);
8359
8930
  const backupConfigHandlers = createBackupConfigHandlers({ vaultDir });
8360
8931
  server.registerRoute("GET", "/api/backup/config", backupConfigHandlers.handleGetBackupConfig);
8361
- server.registerRoute("PUT", "/api/backup/config", backupConfigHandlers.handlePutBackupConfig);
8362
- const teamSync = initTeamSync({ config, machineId, logger, vaultDir, serverVersion: server.version });
8932
+ server.registerRoute("PUT", "/api/backup/config", async (req) => {
8933
+ const result = await backupConfigHandlers.handlePutBackupConfig(req);
8934
+ if (!result.status || result.status < 400) {
8935
+ await applyConfigWriteReactions(["backup.dir"]);
8936
+ }
8937
+ return result;
8938
+ });
8939
+ const teamSync = initTeamSync({ liveConfig, machineId, logger, vaultDir, serverVersion: server.version });
8940
+ reactions.on(["team"], async () => {
8941
+ await teamSync.reconcileClient();
8942
+ });
8943
+ await teamSync.reconcileClient();
8363
8944
  const teamHandlers = createTeamHandlers({
8364
8945
  vaultDir,
8365
8946
  machineId,
@@ -8367,8 +8948,20 @@ async function main() {
8367
8948
  getTeamClient: teamSync.getTeamClient,
8368
8949
  setTeamClient: teamSync.setTeamClient
8369
8950
  });
8370
- server.registerRoute("POST", "/api/team/connect", teamHandlers.handleConnect);
8371
- server.registerRoute("POST", "/api/team/disconnect", teamHandlers.handleDisconnect);
8951
+ server.registerRoute("POST", "/api/team/connect", async (req) => {
8952
+ const result = await teamHandlers.handleConnect(req);
8953
+ if (!result.status || result.status < 400) {
8954
+ await applyConfigWriteReactions(["team.enabled", "team.worker_url"]);
8955
+ }
8956
+ return result;
8957
+ });
8958
+ server.registerRoute("POST", "/api/team/disconnect", async (req) => {
8959
+ const result = await teamHandlers.handleDisconnect(req);
8960
+ if (!result.status || result.status < 400) {
8961
+ await applyConfigWriteReactions(["team.enabled", "team.worker_url"]);
8962
+ }
8963
+ return result;
8964
+ });
8372
8965
  server.registerRoute("GET", "/api/team/status", teamHandlers.handleStatus);
8373
8966
  server.registerRoute("POST", "/api/team/backfill", teamHandlers.handleBackfill);
8374
8967
  server.registerRoute("POST", "/api/team/retry-failed", teamHandlers.handleRetryFailed);
@@ -8420,9 +9013,9 @@ async function main() {
8420
9013
  logger.warn(LOG_KINDS.DAEMON_CONFIG, "Failed to persist auto-derived port", { error: err.message });
8421
9014
  }
8422
9015
  }
8423
- registerPowerJobs(powerManager, { embeddingManager, registry, logger, config, db, backupDir, machineId, vaultDir, databaseManager });
9016
+ registerPowerJobs(powerManager, { embeddingManager, registry, logger, liveConfig, db, machineId, vaultDir, databaseManager });
8424
9017
  teamSync.registerFlushJob(powerManager);
8425
- await registerScheduledTasks(powerManager, { definitionsDir, vaultDir, embeddingManager, logger, config });
9018
+ await registerScheduledTasks(powerManager, { definitionsDir, vaultDir, embeddingManager, logger, liveConfig });
8426
9019
  powerManager.start();
8427
9020
  const shutdown = async (signal) => {
8428
9021
  logger.info(LOG_KINDS.DAEMON_START, `${signal} received`);
@@ -8454,4 +9047,4 @@ export {
8454
9047
  handleUserPrompt,
8455
9048
  main
8456
9049
  };
8457
- //# sourceMappingURL=main-RPJSS7PT.js.map
9050
+ //# sourceMappingURL=main-E7HU4QYR.js.map