@wirecat/cli-memo 0.131.69 → 0.131.71

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 (289) hide show
  1. package/README.md +3 -3
  2. package/THIRD_PARTY_NOTICES +2 -0
  3. package/dist/actions/actions.d.ts +2 -1
  4. package/dist/actions/actions.d.ts.map +1 -1
  5. package/dist/actions/actions.js +5 -3
  6. package/dist/actions/actions.js.map +1 -1
  7. package/dist/actions/command.d.ts.map +1 -1
  8. package/dist/actions/command.js +15 -6
  9. package/dist/actions/command.js.map +1 -1
  10. package/dist/answer.d.ts +1 -0
  11. package/dist/answer.d.ts.map +1 -1
  12. package/dist/answer.js +2 -1
  13. package/dist/answer.js.map +1 -1
  14. package/dist/bin/memo.js +2 -2
  15. package/dist/bin/memo.js.map +1 -1
  16. package/dist/bundle/{all-profiles-6JKSPBBO.js → all-profiles-G6S5HOBT.js} +5 -5
  17. package/dist/bundle/{anthropic-YA2N6EJ4.js → anthropic-LA6PXTPQ.js} +2 -2
  18. package/dist/bundle/{app-server-UP3AL2XQ.js → app-server-W622CBPF.js} +35 -35
  19. package/dist/bundle/auto-WUU2MYGS.js +85 -0
  20. package/dist/bundle/{bun-OUFOAYV4.js → bun-PZNVNH4G.js} +2 -2
  21. package/dist/bundle/{bun-sqlite-5RZTFU2Q.js → bun-sqlite-VICDK5FS.js} +2 -2
  22. package/dist/bundle/{chunk-3TFK7RBA.js → chunk-2LTQ6ZBS.js} +23908 -22107
  23. package/dist/bundle/{chunk-IHHXGTMX.js → chunk-3LS76TFB.js} +1 -1
  24. package/dist/bundle/{chunk-IJAILIZR.js → chunk-3PIKTX3U.js} +18 -18
  25. package/dist/bundle/{chunk-N73YBQ42.js → chunk-3ZSPTUG3.js} +9 -7
  26. package/dist/bundle/{chunk-RHW3DDWI.js → chunk-6B3GQMR6.js} +1 -1
  27. package/dist/bundle/{chunk-LYAJUZM4.js → chunk-6EIWRE6E.js} +30 -30
  28. package/dist/bundle/{chunk-EDPA54WQ.js → chunk-6Z62U7NY.js} +3 -3
  29. package/dist/bundle/{chunk-JMGQATR6.js → chunk-ASDOPGKC.js} +2 -2
  30. package/dist/bundle/{chunk-EKSOPEFQ.js → chunk-BE22RDTR.js} +4 -4
  31. package/dist/bundle/{chunk-FZHYGJQ2.js → chunk-CLQXHFKG.js} +5 -5
  32. package/dist/bundle/{chunk-VPKJZKXV.js → chunk-CPUQC7UF.js} +1 -1
  33. package/dist/bundle/{chunk-GGFL64HF.js → chunk-CZUAGRL7.js} +13168 -11987
  34. package/dist/bundle/{chunk-GVP6CAPH.js → chunk-DW6CDBXA.js} +33 -586
  35. package/dist/bundle/{chunk-5MUR6D2G.js → chunk-DXWDHC2K.js} +44 -2
  36. package/dist/bundle/{chunk-5OMM4CDT.js → chunk-ESYCZ575.js} +2 -2
  37. package/dist/bundle/{chunk-OBQ7TSUB.js → chunk-FHIGY5K6.js} +1 -1
  38. package/dist/bundle/{chunk-MK6SQ32Q.js → chunk-FPWF2XLH.js} +12 -12
  39. package/dist/bundle/{chunk-MYLNRBDF.js → chunk-FVJSDDSV.js} +46 -13
  40. package/dist/bundle/{chunk-TV75OHKJ.js → chunk-G3FQTKHT.js} +7 -7
  41. package/dist/bundle/{chunk-WNA2WNDK.js → chunk-G7XOBQB5.js} +3 -3
  42. package/dist/bundle/{chunk-PSYQPO6D.js → chunk-H3LAORYX.js} +2 -2
  43. package/dist/bundle/{chunk-2DQYP2K3.js → chunk-HIHZNBR7.js} +1 -1
  44. package/dist/bundle/{chunk-QAXIZHK7.js → chunk-HNQGX4AG.js} +33 -33
  45. package/dist/bundle/{chunk-22CDLXSR.js → chunk-I4HWKPQR.js} +4 -4
  46. package/dist/bundle/{chunk-2NFI7SDW.js → chunk-INQAQ55X.js} +2304 -1111
  47. package/dist/bundle/{chunk-XTEJXJJ3.js → chunk-IP5CA3CW.js} +10 -10
  48. package/dist/bundle/{chunk-EO4JMJFZ.js → chunk-IXZWUHSG.js} +7 -7
  49. package/dist/bundle/{chunk-MWQI6FSU.js → chunk-K55WZ67L.js} +3 -3
  50. package/dist/bundle/{chunk-YTJWIJIG.js → chunk-KH43CUE2.js} +5 -5
  51. package/dist/bundle/{chunk-2C7Z7CKD.js → chunk-LIF2HXIQ.js} +1 -1
  52. package/dist/bundle/{chunk-GVEY6743.js → chunk-LRS5X7G3.js} +9 -9
  53. package/dist/bundle/{chunk-3LGLKLBA.js → chunk-M2DAITNE.js} +2 -2
  54. package/dist/bundle/{chunk-OAO5UCPJ.js → chunk-MAGAWAPG.js} +1366 -1574
  55. package/dist/bundle/{chunk-7JFLHRQL.js → chunk-MKOQDN3I.js} +1 -1
  56. package/dist/bundle/{chunk-67VEVKMJ.js → chunk-MSTWHRLN.js} +1 -1
  57. package/dist/bundle/{chunk-YXXAPVAZ.js → chunk-NLRPCKUS.js} +8 -8
  58. package/dist/bundle/{chunk-W2FFA7T5.js → chunk-NNUS57F4.js} +5 -5
  59. package/dist/bundle/{chunk-3YVLNOPE.js → chunk-OHBP2KPQ.js} +4 -4
  60. package/dist/bundle/{chunk-BJJULUUC.js → chunk-OWFC6BAF.js} +5 -5
  61. package/dist/bundle/{chunk-267N22E4.js → chunk-PGOMGFXA.js} +1 -1
  62. package/dist/bundle/{chunk-4HSWIXYE.js → chunk-PHL53ERQ.js} +4 -4
  63. package/dist/bundle/{chunk-5EHUHZU5.js → chunk-QNJ4EKKW.js} +80 -68
  64. package/dist/bundle/{chunk-53EAI4VZ.js → chunk-QUPPO7DB.js} +1 -1
  65. package/dist/bundle/{chunk-276KPJI5.js → chunk-RF6KPQWV.js} +2 -2
  66. package/dist/bundle/{chunk-TXOXPQN2.js → chunk-SL2LXOCN.js} +2 -2
  67. package/dist/bundle/{chunk-QZU5IM5E.js → chunk-SR7C53CS.js} +2 -2
  68. package/dist/bundle/{chunk-ECHN36DC.js → chunk-STJWETNW.js} +4 -4
  69. package/dist/bundle/{chunk-BGWPKEKK.js → chunk-SVVSGUMU.js} +4 -4
  70. package/dist/bundle/{chunk-FQ54GW57.js → chunk-TG3XWDFI.js} +8360 -8360
  71. package/dist/bundle/{chunk-V2YS63Z5.js → chunk-U3P5F57B.js} +1 -1
  72. package/dist/bundle/{chunk-PHSYMVYX.js → chunk-UCRR7R6Q.js} +2 -2
  73. package/dist/bundle/{chunk-2F35N6BI.js → chunk-UX52EWLQ.js} +1 -1
  74. package/dist/bundle/{chunk-OHA7HDPX.js → chunk-V6BJM3XW.js} +1024 -676
  75. package/dist/bundle/{chunk-TVZXLAID.js → chunk-X337K4BD.js} +10 -6
  76. package/dist/bundle/{chunk-UEMI6FXR.js → chunk-XNX3U6GD.js} +6 -6
  77. package/dist/bundle/{chunk-7L4PBN5S.js → chunk-ZM6J47GY.js} +2 -2
  78. package/dist/bundle/{command-contract-OGW2DX4C.js → command-contract-7QECBB6M.js} +11 -11
  79. package/dist/bundle/{decode-IJMDTGTW.js → decode-WRWXOJML.js} +2 -2
  80. package/dist/bundle/{echarts-EHYUXOKP.js → echarts-MTCNTCST.js} +2 -2
  81. package/dist/bundle/{embed-RUY3UIVC.js → embed-PPPCHSTE.js} +3 -3
  82. package/dist/bundle/{embedder-P6WBMEGP.js → embedder-UJBIX6A2.js} +6 -6
  83. package/dist/bundle/{entry-7S2ONYSF.js → entry-4P5556KI.js} +4 -4
  84. package/dist/bundle/failure-3F3YHF7G.js +65 -0
  85. package/dist/bundle/{first-run-MLIFZSVH.js → first-run-EKRDZLLY.js} +5 -5
  86. package/dist/bundle/{first-screen-DGTTK6VK.js → first-screen-FRRTKWFB.js} +12 -12
  87. package/dist/bundle/{instructions-ZMG4FLGO.js → instructions-JKIO4JF7.js} +1 -1
  88. package/dist/bundle/{mcp-CFIL7WZU.js → mcp-FQPK2KAF.js} +35 -35
  89. package/dist/bundle/memo.js +14 -11
  90. package/dist/bundle/{node-QYL4B7JS.js → node-3AIXDDDR.js} +2 -2
  91. package/dist/bundle/{node-sqlite-ESTT2OCF.js → node-sqlite-NX722DXD.js} +3 -3
  92. package/dist/bundle/{oauth-CFQFSIRQ.js → oauth-2NPSI7Q3.js} +4 -4
  93. package/dist/bundle/{open-3XO2HMIT.js → open-AFRN6Q36.js} +2 -2
  94. package/dist/bundle/{openai-STUNDBD6.js → openai-U5CQFLRU.js} +7 -7
  95. package/dist/bundle/{process-P4UAJCZX.js → process-J2IBN6X7.js} +1 -1
  96. package/dist/bundle/{program-BXL5ZOVQ.js → program-L5IM35PO.js} +1433 -531
  97. package/dist/bundle/{prompt-ZCYMFMIG.js → prompt-6XNKR4VQ.js} +2 -2
  98. package/dist/bundle/{recognize-V3BY33FK.js → recognize-G3GI32QS.js} +1 -1
  99. package/dist/bundle/{remote-IP4QR7SP.js → remote-DJO255PT.js} +4 -4
  100. package/dist/bundle/{rerank-VKUSF3DM.js → rerank-5SBZRIHF.js} +4 -4
  101. package/dist/bundle/{serve-VBIUARHJ.js → serve-BZVBKGU3.js} +6 -6
  102. package/dist/bundle/server-GCESLOOF.js +48 -0
  103. package/dist/bundle/server-JUSMYLIQ.js +61 -0
  104. package/dist/bundle/{server-JLPZUC42.js → server-LWQAHDBH.js} +55 -52
  105. package/dist/bundle/{state-UBAIZ2WP.js → state-A57F7T5D.js} +3 -3
  106. package/dist/bundle/{store-VQQVUA4W.js → store-WG2GYWTG.js} +9 -9
  107. package/dist/bundle/store-maintenance-command-GTY6VU76.js +47 -0
  108. package/dist/bundle/update-LICMP7UR.js +68 -0
  109. package/dist/context/command.d.ts +2 -1
  110. package/dist/context/command.d.ts.map +1 -1
  111. package/dist/context/command.js +34 -12
  112. package/dist/context/command.js.map +1 -1
  113. package/dist/context/context.d.ts +20 -8
  114. package/dist/context/context.d.ts.map +1 -1
  115. package/dist/context/context.js +65 -40
  116. package/dist/context/context.js.map +1 -1
  117. package/dist/contract-overrides/search.js +1 -1
  118. package/dist/contract-overrides/search.js.map +1 -1
  119. package/dist/contract-overrides/skill.d.ts.map +1 -1
  120. package/dist/contract-overrides/skill.js +5 -10
  121. package/dist/contract-overrides/skill.js.map +1 -1
  122. package/dist/digest/backfill.d.ts.map +1 -1
  123. package/dist/digest/backfill.js +4 -2
  124. package/dist/digest/backfill.js.map +1 -1
  125. package/dist/digest/brief.d.ts +14 -0
  126. package/dist/digest/brief.d.ts.map +1 -0
  127. package/dist/digest/brief.js +143 -0
  128. package/dist/digest/brief.js.map +1 -0
  129. package/dist/digest/digest.d.ts.map +1 -1
  130. package/dist/digest/digest.js +2 -1
  131. package/dist/digest/digest.js.map +1 -1
  132. package/dist/discovery/command.d.ts.map +1 -1
  133. package/dist/discovery/command.js +2 -0
  134. package/dist/discovery/command.js.map +1 -1
  135. package/dist/doctor/command.d.ts +22 -2
  136. package/dist/doctor/command.d.ts.map +1 -1
  137. package/dist/examples.d.ts.map +1 -1
  138. package/dist/examples.js +51 -10
  139. package/dist/examples.js.map +1 -1
  140. package/dist/facts/command.d.ts.map +1 -1
  141. package/dist/facts/command.js +7 -6
  142. package/dist/facts/command.js.map +1 -1
  143. package/dist/finance/deal-text.d.ts +4 -0
  144. package/dist/finance/deal-text.d.ts.map +1 -0
  145. package/dist/finance/deal-text.js +34 -0
  146. package/dist/finance/deal-text.js.map +1 -0
  147. package/dist/finance/deals-command.d.ts +1 -1
  148. package/dist/finance/deals-command.d.ts.map +1 -1
  149. package/dist/finance/deals-command.js +113 -13
  150. package/dist/finance/deals-command.js.map +1 -1
  151. package/dist/knowledge/business-text.d.ts +7 -0
  152. package/dist/knowledge/business-text.d.ts.map +1 -0
  153. package/dist/knowledge/business-text.js +19 -0
  154. package/dist/knowledge/business-text.js.map +1 -0
  155. package/dist/knowledge/command.d.ts +1 -1
  156. package/dist/knowledge/command.d.ts.map +1 -1
  157. package/dist/knowledge/command.js +131 -42
  158. package/dist/knowledge/command.js.map +1 -1
  159. package/dist/knowledge/money-text.d.ts +4 -0
  160. package/dist/knowledge/money-text.d.ts.map +1 -0
  161. package/dist/knowledge/money-text.js +16 -0
  162. package/dist/knowledge/money-text.js.map +1 -0
  163. package/dist/knowledge/organization-text.d.ts +7 -0
  164. package/dist/knowledge/organization-text.d.ts.map +1 -0
  165. package/dist/knowledge/organization-text.js +24 -0
  166. package/dist/knowledge/organization-text.js.map +1 -0
  167. package/dist/knowledge/project-actions-command.js +1 -1
  168. package/dist/knowledge/project-actions-command.js.map +1 -1
  169. package/dist/knowledge/project-actions.d.ts +1 -1
  170. package/dist/knowledge/project-actions.d.ts.map +1 -1
  171. package/dist/knowledge/project-actions.js +2 -2
  172. package/dist/knowledge/project-actions.js.map +1 -1
  173. package/dist/knowledge/project-context.d.ts +27 -1
  174. package/dist/knowledge/project-context.d.ts.map +1 -1
  175. package/dist/knowledge/project-context.js +9 -5
  176. package/dist/knowledge/project-context.js.map +1 -1
  177. package/dist/knowledge/project-status-command.d.ts.map +1 -1
  178. package/dist/knowledge/project-status-command.js +21 -5
  179. package/dist/knowledge/project-status-command.js.map +1 -1
  180. package/dist/knowledge/relationships.d.ts +27 -23
  181. package/dist/knowledge/relationships.d.ts.map +1 -1
  182. package/dist/knowledge/relationships.js +65 -52
  183. package/dist/knowledge/relationships.js.map +1 -1
  184. package/dist/knowledge/roles-command.d.ts +8 -0
  185. package/dist/knowledge/roles-command.d.ts.map +1 -0
  186. package/dist/knowledge/roles-command.js +65 -0
  187. package/dist/knowledge/roles-command.js.map +1 -0
  188. package/dist/mcp/catalogue.d.ts +1 -1
  189. package/dist/mcp/catalogue.d.ts.map +1 -1
  190. package/dist/mcp/catalogue.js +3 -1
  191. package/dist/mcp/catalogue.js.map +1 -1
  192. package/dist/mcp/server.js +1 -1
  193. package/dist/mcp/server.js.map +1 -1
  194. package/dist/memories/command.d.ts.map +1 -1
  195. package/dist/memories/command.js +6 -5
  196. package/dist/memories/command.js.map +1 -1
  197. package/dist/memories/sources.js +2 -2
  198. package/dist/memories/sources.js.map +1 -1
  199. package/dist/models/command.d.ts +1 -1
  200. package/dist/models/command.d.ts.map +1 -1
  201. package/dist/models/command.js +2 -1
  202. package/dist/models/command.js.map +1 -1
  203. package/dist/notes/command.d.ts.map +1 -1
  204. package/dist/notes/command.js +13 -8
  205. package/dist/notes/command.js.map +1 -1
  206. package/dist/notes/embed.d.ts +6 -1
  207. package/dist/notes/embed.d.ts.map +1 -1
  208. package/dist/notes/embed.js +17 -8
  209. package/dist/notes/embed.js.map +1 -1
  210. package/dist/people/command.d.ts.map +1 -1
  211. package/dist/people/command.js +2 -1
  212. package/dist/people/command.js.map +1 -1
  213. package/dist/program.d.ts +13 -1
  214. package/dist/program.d.ts.map +1 -1
  215. package/dist/program.js +173 -11
  216. package/dist/program.js.map +1 -1
  217. package/dist/reasons.d.ts.map +1 -1
  218. package/dist/reasons.js +42 -0
  219. package/dist/reasons.js.map +1 -1
  220. package/dist/review/command.js +2 -2
  221. package/dist/review/command.js.map +1 -1
  222. package/dist/review/review.d.ts +3 -3
  223. package/dist/review/review.d.ts.map +1 -1
  224. package/dist/review/review.js +6 -6
  225. package/dist/review/review.js.map +1 -1
  226. package/dist/review/status.d.ts.map +1 -1
  227. package/dist/review/status.js +5 -4
  228. package/dist/review/status.js.map +1 -1
  229. package/dist/run/import.d.ts +2 -2
  230. package/dist/run/import.d.ts.map +1 -1
  231. package/dist/run/import.js +9 -3
  232. package/dist/run/import.js.map +1 -1
  233. package/dist/search/command.d.ts.map +1 -1
  234. package/dist/search/command.js +21 -3
  235. package/dist/search/command.js.map +1 -1
  236. package/dist/search/denied.d.ts +10 -0
  237. package/dist/search/denied.d.ts.map +1 -0
  238. package/dist/search/denied.js +10 -0
  239. package/dist/search/denied.js.map +1 -0
  240. package/dist/search/people.d.ts.map +1 -1
  241. package/dist/search/people.js +11 -1
  242. package/dist/search/people.js.map +1 -1
  243. package/dist/search/search.d.ts +2 -0
  244. package/dist/search/search.d.ts.map +1 -1
  245. package/dist/search/search.js +37 -12
  246. package/dist/search/search.js.map +1 -1
  247. package/dist/store/group.d.ts +38 -0
  248. package/dist/store/group.d.ts.map +1 -0
  249. package/dist/store/group.js +112 -0
  250. package/dist/store/group.js.map +1 -0
  251. package/dist/store/groups-command.d.ts +10 -0
  252. package/dist/store/groups-command.d.ts.map +1 -0
  253. package/dist/store/groups-command.js +88 -0
  254. package/dist/store/groups-command.js.map +1 -0
  255. package/dist/store/guard.d.ts +29 -0
  256. package/dist/store/guard.d.ts.map +1 -0
  257. package/dist/store/guard.js +94 -0
  258. package/dist/store/guard.js.map +1 -0
  259. package/dist/store/scope.d.ts +3 -3
  260. package/dist/store/scope.d.ts.map +1 -1
  261. package/dist/store/scope.js +7 -6
  262. package/dist/store/scope.js.map +1 -1
  263. package/dist/store/source-list.d.ts +5 -1
  264. package/dist/store/source-list.d.ts.map +1 -1
  265. package/dist/store/source-list.js +30 -15
  266. package/dist/store/source-list.js.map +1 -1
  267. package/dist/tags/command.d.ts.map +1 -1
  268. package/dist/tags/command.js +3 -2
  269. package/dist/tags/command.js.map +1 -1
  270. package/dist/tasks/shared.d.ts.map +1 -1
  271. package/dist/tasks/shared.js +2 -1
  272. package/dist/tasks/shared.js.map +1 -1
  273. package/dist/tasks/tasks.js +3 -3
  274. package/dist/tasks/tasks.js.map +1 -1
  275. package/dist/version.d.ts +1 -1
  276. package/dist/version.js +1 -1
  277. package/package.json +5 -4
  278. package/skills/cli-memo/SKILL.md +7 -7
  279. package/skills/cli-memo/topics/mcp.md +9 -0
  280. package/skills/cli-memo/topics/money.md +14 -1
  281. package/skills/cli-memo/topics/projects.md +2 -1
  282. package/skills/cli-memo/topics/search.md +12 -4
  283. package/dist/bundle/auto-IKZIROGF.js +0 -85
  284. package/dist/bundle/failure-NRZUB77S.js +0 -65
  285. package/dist/bundle/server-AASCSGCI.js +0 -61
  286. package/dist/bundle/server-YQLPZK4Z.js +0 -48
  287. package/dist/bundle/store-maintenance-command-GCBABKEZ.js +0 -47
  288. package/dist/bundle/update-M54Z3SEU.js +0 -68
  289. /package/dist/bundle/{chunk-AWVQHWIS.js → chunk-YSYFOIW7.js} +0 -0
@@ -6,28 +6,30 @@ import {
6
6
  autoState,
7
7
  lastAutoRun,
8
8
  recordAutoRun
9
- } from "./chunk-EKSOPEFQ.js";
9
+ } from "./chunk-BE22RDTR.js";
10
10
  import {
11
11
  installer,
12
12
  latest,
13
13
  upgradeCommand
14
- } from "./chunk-BJJULUUC.js";
14
+ } from "./chunk-OWFC6BAF.js";
15
15
  import {
16
16
  mcpOwnerAllowed,
17
+ memoLevels,
17
18
  readOnlyAvailability,
18
19
  refuseWritesUnderLock
19
- } from "./chunk-W2FFA7T5.js";
20
+ } from "./chunk-NNUS57F4.js";
20
21
  import {
21
22
  answers,
22
23
  atDetail,
23
24
  itemAnswer,
24
25
  listAnswer,
26
+ openMemoStore,
25
27
  plainText,
26
28
  snakeKeys as snakeKeys2,
27
29
  trackAnswers,
28
30
  wholeList,
29
31
  withStore
30
- } from "./chunk-TVZXLAID.js";
32
+ } from "./chunk-X337K4BD.js";
31
33
  import {
32
34
  ATTACHMENT_CHARS,
33
35
  DIALECTS,
@@ -59,15 +61,15 @@ import {
59
61
  showMail,
60
62
  unsetConfigKey,
61
63
  updateConfig
62
- } from "./chunk-FQ54GW57.js";
64
+ } from "./chunk-TG3XWDFI.js";
63
65
  import "./chunk-QP3KNC5D.js";
64
- import "./chunk-TXOXPQN2.js";
65
- import "./chunk-EO4JMJFZ.js";
66
- import "./chunk-MWQI6FSU.js";
66
+ import "./chunk-SL2LXOCN.js";
67
+ import "./chunk-IXZWUHSG.js";
68
+ import "./chunk-K55WZ67L.js";
67
69
  import {
68
70
  errorObject,
69
71
  recognisable
70
- } from "./chunk-3YVLNOPE.js";
72
+ } from "./chunk-OHBP2KPQ.js";
71
73
  import {
72
74
  AGENT_INPUT_MAX_CHARS,
73
75
  DISCOVERY_DESCRIPTIONS,
@@ -77,9 +79,12 @@ import {
77
79
  addMeetingPreparationCommand,
78
80
  advancePastSkipped,
79
81
  backfillScheduleRun,
82
+ baseStagesCommand,
80
83
  checkJson,
81
84
  dateOrNone,
85
+ deniedKindsOf,
82
86
  entityFields,
87
+ groupAware,
83
88
  guideCommand,
84
89
  liftJson,
85
90
  mailWaiting,
@@ -101,6 +106,8 @@ import {
101
106
  readMailFindingsJson,
102
107
  readSchedule,
103
108
  recordRuns,
109
+ refKinds,
110
+ refuseOutsideGroup,
104
111
  runsCommand,
105
112
  scheduleCommandFor,
106
113
  scheduleFile,
@@ -112,54 +119,65 @@ import {
112
119
  tasksStatsCommand,
113
120
  templatesCommand,
114
121
  withSqliteSidecars
115
- } from "./chunk-OHA7HDPX.js";
116
- import "./chunk-7JFLHRQL.js";
117
- import "./chunk-RHW3DDWI.js";
122
+ } from "./chunk-V6BJM3XW.js";
123
+ import "./chunk-MKOQDN3I.js";
124
+ import "./chunk-6B3GQMR6.js";
118
125
  import {
119
126
  allHitItem,
120
127
  coverageGaps,
121
128
  messageHitItem,
122
129
  noteHitItem,
123
130
  shownOf
124
- } from "./chunk-LYAJUZM4.js";
125
- import "./chunk-OBQ7TSUB.js";
131
+ } from "./chunk-6EIWRE6E.js";
132
+ import "./chunk-FHIGY5K6.js";
126
133
  import {
127
134
  REASONS as REASONS2,
128
135
  SKILL_TARGETS,
129
136
  skillCommand,
130
137
  skillPath,
131
138
  skillVersion
132
- } from "./chunk-MYLNRBDF.js";
139
+ } from "./chunk-FVJSDDSV.js";
133
140
  import {
134
141
  recoveryNotes,
135
142
  storeInfo,
136
143
  storeRecoveryCheck,
137
144
  storeRecoveryRun,
138
145
  storeSummary
139
- } from "./chunk-5EHUHZU5.js";
140
- import "./chunk-GVP6CAPH.js";
146
+ } from "./chunk-QNJ4EKKW.js";
147
+ import "./chunk-DW6CDBXA.js";
141
148
  import {
142
149
  LIST_QUERY_GUIDE,
150
+ RESOURCES_SEARCHED,
143
151
  STATUS_SIGNALS,
152
+ addGroupMember,
144
153
  approveAsTask,
145
154
  calendarAccounts,
155
+ canonicalPersonContext,
146
156
  closedStateOf,
147
157
  createMeetingPassageCommand,
148
158
  createMeetingPreparationService,
149
159
  createMeetingSearchCommand,
160
+ dealBrief,
161
+ dealContext,
150
162
  documentPassage,
151
163
  embedMail,
152
164
  embedNotes,
153
165
  excerpt,
154
166
  extractText,
155
167
  gatherStoredProject,
168
+ groupGuardOf,
169
+ groupLockOf,
156
170
  importEngine,
171
+ inGroupOf,
157
172
  ingest,
158
173
  ingestLines,
159
174
  ingestVcard,
160
175
  isVcard,
161
176
  jsonlLines,
177
+ listAccountGroups,
178
+ listContextOf,
162
179
  listQuery,
180
+ lockedRegistry,
163
181
  mailTurn,
164
182
  meaningLane,
165
183
  meetingHitSearchRequest,
@@ -167,9 +185,12 @@ import {
167
185
  meetingSearchArguments,
168
186
  meetingSearchMeta,
169
187
  modelGateway,
188
+ moveGroupMember,
170
189
  nativeField,
171
190
  nativeTerms,
191
+ organizationContext,
172
192
  parseProposalIds,
193
+ personBusiness,
173
194
  personContext,
174
195
  pickPerson,
175
196
  previewProjectAnnotationSnapshot,
@@ -182,7 +203,9 @@ import {
182
203
  questionLookup,
183
204
  readMeetingPassage,
184
205
  readWithRegistry,
206
+ removeGroupMember,
185
207
  scanProjectLinks,
208
+ scopeToGroup,
186
209
  searchAll,
187
210
  searchMeetingHits,
188
211
  searchNotesOf,
@@ -197,18 +220,18 @@ import {
197
220
  timeLimit,
198
221
  typedQuery,
199
222
  withQuery
200
- } from "./chunk-3TFK7RBA.js";
223
+ } from "./chunk-2LTQ6ZBS.js";
201
224
  import {
202
225
  readBoundedUtf8File,
203
226
  writeFileAtomic
204
- } from "./chunk-MK6SQ32Q.js";
227
+ } from "./chunk-FPWF2XLH.js";
205
228
  import {
206
229
  commandsText,
207
230
  inSection,
208
231
  installHelp
209
- } from "./chunk-UEMI6FXR.js";
232
+ } from "./chunk-XNX3U6GD.js";
210
233
  import "./chunk-HTQTIKWP.js";
211
- import "./chunk-JMGQATR6.js";
234
+ import "./chunk-ASDOPGKC.js";
212
235
  import {
213
236
  Command,
214
237
  DEFAULT_TEXT_MODEL,
@@ -224,6 +247,7 @@ import {
224
247
  answerEntity,
225
248
  assertSharedContracts,
226
249
  chosenTextModel,
250
+ commandWords,
227
251
  commandsDocument,
228
252
  customizeSharedCommand,
229
253
  environmentOf,
@@ -231,6 +255,7 @@ import {
231
255
  grantsAuthority,
232
256
  hasSharedContract,
233
257
  itemOf,
258
+ liftProfile,
234
259
  metaOf,
235
260
  outputFor,
236
261
  overrideSharedContract,
@@ -239,29 +264,29 @@ import {
239
264
  progressOf,
240
265
  proposesOnly,
241
266
  provide,
242
- runsDirFor,
267
+ runGroup,
243
268
  settingRows,
244
269
  settingsFor,
245
270
  snakeKeys,
246
271
  textModels,
247
272
  textModelsFile
248
- } from "./chunk-OAO5UCPJ.js";
249
- import "./chunk-N73YBQ42.js";
250
- import "./chunk-XTEJXJJ3.js";
273
+ } from "./chunk-MAGAWAPG.js";
274
+ import "./chunk-3ZSPTUG3.js";
275
+ import "./chunk-IP5CA3CW.js";
251
276
  import {
252
277
  isNewer
253
278
  } from "./chunk-LJCT7YG6.js";
254
279
  import "./chunk-L62FWN3Y.js";
255
- import "./chunk-EDPA54WQ.js";
256
- import "./chunk-GVEY6743.js";
257
- import "./chunk-2DQYP2K3.js";
258
- import "./chunk-22CDLXSR.js";
280
+ import "./chunk-6Z62U7NY.js";
281
+ import "./chunk-LRS5X7G3.js";
282
+ import "./chunk-HIHZNBR7.js";
283
+ import "./chunk-I4HWKPQR.js";
259
284
  import {
260
285
  releaseLock,
261
286
  servingProfiles,
262
287
  takeLock
263
- } from "./chunk-7L4PBN5S.js";
264
- import "./chunk-IHHXGTMX.js";
288
+ } from "./chunk-ZM6J47GY.js";
289
+ import "./chunk-3LS76TFB.js";
265
290
  import {
266
291
  EVIDENCE_FINDINGS_KIND,
267
292
  MAIL_FINDINGS_KIND,
@@ -285,27 +310,20 @@ import {
285
310
  assertMayDecide,
286
311
  contextEvidenceFingerprint,
287
312
  decodeProjectAnnotationSnapshot,
288
- entriesOfList,
289
313
  envelopeOfText,
290
- formatLocator,
291
- formatReference,
292
- isFolderProvider,
293
314
  isGoogleDocumentHost,
294
- isImportedProvider,
295
- kindOf,
296
- looksLikeReference,
297
315
  mailFindingFieldsHelp,
298
316
  mailOwnText,
299
317
  openOf,
300
318
  openStore,
301
- parseLocator,
302
- parseReference,
303
319
  plainQuery,
304
- providerNamed,
305
- refLabel
306
- } from "./chunk-GGFL64HF.js";
320
+ refLabel,
321
+ storedProfilesFor,
322
+ writesWithOf
323
+ } from "./chunk-CZUAGRL7.js";
307
324
  import {
308
325
  CATALOG_KINDS,
326
+ CATEGORIES,
309
327
  CONTRACT_KINDS,
310
328
  CONTRACT_STATUSES,
311
329
  DEAL_KINDS,
@@ -324,8 +342,13 @@ import {
324
342
  MONEY_DIRECTIONS,
325
343
  ORDER_PURPOSES,
326
344
  ORDER_STATUSES,
345
+ ORGANIZATION_ROLES,
327
346
  PRIORITY_LABELS,
347
+ PROJECT_ROLES,
348
+ REF_KINDS,
349
+ RELATION_KINDS,
328
350
  SOURCE_REVIEW_KIND,
351
+ STANDINGS,
329
352
  SUBSCRIPTION_STATUSES,
330
353
  TASK_STATES,
331
354
  TASK_TYPES,
@@ -336,39 +359,54 @@ import {
336
359
  createUpcomingMeetingReader,
337
360
  dateRange,
338
361
  dayBoundary,
362
+ entriesOfList,
339
363
  event,
340
364
  eventItem,
365
+ formatLocator,
341
366
  formatMeetingReference,
367
+ formatReference,
342
368
  isClosedState,
369
+ isFolderProvider,
370
+ isImportedProvider,
371
+ isUsable,
372
+ keyOf,
373
+ kindIn,
374
+ kindOf,
375
+ looksLikeReference,
343
376
  markStoreDamaged,
344
377
  meetingHitsList,
345
378
  minorUnits,
346
379
  moneyOf,
347
380
  normalizeTag,
381
+ parseLocator,
348
382
  parseLucene,
349
383
  parseMeetingReference,
384
+ parseReference,
350
385
  paymentTitle,
351
386
  priorityOf,
387
+ providerNamed,
352
388
  queryError,
353
389
  queryFieldsOf,
390
+ runsDirFor,
391
+ standingOf,
354
392
  timezoneOf,
355
393
  validateQuery,
356
394
  walkQuery
357
- } from "./chunk-2NFI7SDW.js";
358
- import "./chunk-3LGLKLBA.js";
359
- import "./chunk-TV75OHKJ.js";
360
- import "./chunk-BGWPKEKK.js";
361
- import "./chunk-PHSYMVYX.js";
362
- import "./chunk-2C7Z7CKD.js";
363
- import "./chunk-5OMM4CDT.js";
364
- import "./chunk-QZU5IM5E.js";
365
- import "./chunk-FZHYGJQ2.js";
395
+ } from "./chunk-INQAQ55X.js";
396
+ import "./chunk-M2DAITNE.js";
397
+ import "./chunk-G3FQTKHT.js";
398
+ import "./chunk-SVVSGUMU.js";
399
+ import "./chunk-UCRR7R6Q.js";
400
+ import "./chunk-LIF2HXIQ.js";
401
+ import "./chunk-ESYCZ575.js";
402
+ import "./chunk-SR7C53CS.js";
403
+ import "./chunk-CLQXHFKG.js";
366
404
  import {
367
405
  sharedModelsDirectory
368
- } from "./chunk-WNA2WNDK.js";
406
+ } from "./chunk-G7XOBQB5.js";
369
407
  import {
370
408
  storePath
371
- } from "./chunk-V2YS63Z5.js";
409
+ } from "./chunk-U3P5F57B.js";
372
410
  import {
373
411
  provideTerminal,
374
412
  terminalOf
@@ -378,12 +416,12 @@ import {
378
416
  REASONS,
379
417
  STORE_CLIENT,
380
418
  VERSION
381
- } from "./chunk-5MUR6D2G.js";
419
+ } from "./chunk-DXWDHC2K.js";
382
420
  import "./chunk-DSU6UR2X.js";
383
421
  import "./chunk-SYWHHQMC.js";
384
422
  import "./chunk-D72URWJE.js";
385
- import "./chunk-YTJWIJIG.js";
386
- import "./chunk-67VEVKMJ.js";
423
+ import "./chunk-KH43CUE2.js";
424
+ import "./chunk-MSTWHRLN.js";
387
425
  import {
388
426
  configFilePath,
389
427
  createDeadline,
@@ -423,7 +461,7 @@ import {
423
461
  errorCodes,
424
462
  isCliError
425
463
  } from "./chunk-ZTONSM5X.js";
426
- import "./chunk-VPKJZKXV.js";
464
+ import "./chunk-CPUQC7UF.js";
427
465
  import {
428
466
  __name
429
467
  } from "./chunk-ZVVMGPBJ.js";
@@ -512,6 +550,90 @@ var fromAppOption = /* @__PURE__ */ __name((command) => command.option("--from-a
512
550
  var byOption = /* @__PURE__ */ __name((command) => fromAppOption(command.option("--as-owner", "act as you although an agent's terminal runs memo (AI_AGENT or CLAUDECODE set); asks y/N at the terminal")), "byOption");
513
551
  var reasonOption = /* @__PURE__ */ __name((command) => command.option("--reason <text>", "why, in a few words; required when an agent decides for you"), "reasonOption");
514
552
 
553
+ // dist/store/group.js
554
+ var MEMO_ACCOUNT = { provider: "notes", account: "internal" };
555
+ var memoListContext = /* @__PURE__ */ __name(async (store, env) => {
556
+ const held = await store.accounts.storedAccounts();
557
+ const context = await listContextOf(store, MEMO_ACCOUNT, APP, held, env);
558
+ return {
559
+ ...context,
560
+ held: context.held.filter((one2) => one2.id !== 0 || keyOf(one2) !== keyOf(MEMO_ACCOUNT))
561
+ };
562
+ }, "memoListContext");
563
+ var groupOf = /* @__PURE__ */ __name((env, word) => runGroup(APP, env, word), "groupOf");
564
+ var scopeIn = /* @__PURE__ */ __name((run, context) => {
565
+ scopeToGroup(run, {}, context);
566
+ const accounts = entriesOfList(`group:${run.name}`, context).flatMap((entry) => entry.accounts.map(({ provider, account: account2 }) => ({ provider, account: account2 })));
567
+ return { run, accounts, has: inGroupOf(context, run.name) };
568
+ }, "scopeIn");
569
+ var groupScopeOf = /* @__PURE__ */ __name(async (store, env) => {
570
+ const run = groupOf(env);
571
+ return run === void 0 ? void 0 : scopeIn(run, await memoListContext(store, env));
572
+ }, "groupScopeOf");
573
+ var OWN_BUSINESS = { provider: "business", account: "internal" };
574
+ var accountsByKind = /* @__PURE__ */ __name((scope, imports = []) => {
575
+ const kinds2 = {
576
+ messages: [],
577
+ mail: [],
578
+ notes: [MEMO_ACCOUNT],
579
+ events: [],
580
+ crm: [],
581
+ business: [OWN_BUSINESS, ...imports.filter(scope.has)]
582
+ };
583
+ for (const key of scope.accounts) {
584
+ const kind = kindIn(key.provider);
585
+ if (kind === "documents")
586
+ kinds2.notes.push(key);
587
+ else if (kind !== void 0 && kind !== "meetings" && kind in kinds2)
588
+ kinds2[kind].push(key);
589
+ }
590
+ return kinds2;
591
+ }, "accountsByKind");
592
+ var scopedAccounts = /* @__PURE__ */ __name(async (store, env) => {
593
+ const all = await store.accounts.accounts();
594
+ const scope = await groupScopeOf(store, env);
595
+ return scope === void 0 ? all : all.filter(scope.has);
596
+ }, "scopedAccounts");
597
+ var inGroup = /* @__PURE__ */ __name(async (store, env, keys) => {
598
+ const scope = await groupScopeOf(store, env);
599
+ return scope === void 0 ? [...keys] : keys.filter(scope.has);
600
+ }, "inGroup");
601
+ var refInGroup = /* @__PURE__ */ __name(async (store, scope, ref) => {
602
+ const accounts = await store.refs.accounts(ref);
603
+ return !accounts?.length || accounts.some(scope.has);
604
+ }, "refInGroup");
605
+ var keepInGroup = /* @__PURE__ */ __name(async (store, env, items, refOf2) => {
606
+ const scope = await groupScopeOf(store, env);
607
+ if (scope === void 0)
608
+ return [...items];
609
+ const kept = [];
610
+ for (const item of items)
611
+ if (await refInGroup(store, scope, refOf2(item)))
612
+ kept.push(item);
613
+ return kept;
614
+ }, "keepInGroup");
615
+ var optionValue = /* @__PURE__ */ __name((command, name2) => {
616
+ const value = command.getOptionValue(name2);
617
+ return typeof value === "string" ? value : void 0;
618
+ }, "optionValue");
619
+ var declares = /* @__PURE__ */ __name((command, name2) => command.options.some((option) => option.attributeName() === name2), "declares");
620
+ var scopeRunsToGroup = /* @__PURE__ */ __name((program, env, word) => {
621
+ program.hook("preAction", async (_root, command) => {
622
+ const run = groupOf(env, word);
623
+ if (run === void 0)
624
+ return;
625
+ await withStore(env, async (store) => {
626
+ await refuseOutsideGroup(command, { app: APP, env, store });
627
+ const context = await memoListContext(store, env);
628
+ const source = declares(command, "source") ? optionValue(command, "source") : void 0;
629
+ const account2 = declares(command, "account") ? optionValue(command, "account") : void 0;
630
+ const scoped3 = scopeToGroup(run, { ...source === void 0 ? {} : { source }, ...account2 === void 0 ? {} : { account: account2 } }, context);
631
+ if (declares(command, "source") && scoped3.source !== void 0 && command.getOptionValue("all") !== true)
632
+ command.setOptionValue("source", scoped3.source);
633
+ });
634
+ });
635
+ }, "scopeRunsToGroup");
636
+
515
637
  // dist/store/source-list.js
516
638
  var MAIL = /* @__PURE__ */ new Set(["mail", "email"]);
517
639
  var MESSENGERS = /* @__PURE__ */ new Set(["messages", "telegram", "tg", "max", "whatsapp", "wa", "personal", "bots"]);
@@ -532,8 +654,9 @@ var filesAccounts = /* @__PURE__ */ __name(async (store) => {
532
654
  return (one2) => ids.has(String(one2.id));
533
655
  }, "filesAccounts");
534
656
  var messengers = /* @__PURE__ */ __name((entry) => new CliError("validation_error", `${entry}: mentions in chats are the messenger's \u2014 tg <profile> mentions list`), "messengers");
535
- var listedOf = /* @__PURE__ */ __name(async (store, value) => {
536
- const held = await store.accounts.storedAccounts();
657
+ var listedOf = /* @__PURE__ */ __name(async (store, env, value) => {
658
+ const context = await memoListContext(store, env);
659
+ const { held } = context;
537
660
  const holdsFiles = await filesAccounts(store);
538
661
  const named5 = /* @__PURE__ */ __name(async (entry) => {
539
662
  const [provider = "", ...rest] = entry.trim().split(":");
@@ -549,19 +672,22 @@ var listedOf = /* @__PURE__ */ __name(async (store, value) => {
549
672
  return `email:${(await mailboxOf(store, account2)).account}`;
550
673
  }, "named");
551
674
  const each = /* @__PURE__ */ __name((entries) => Promise.all(entries.filter((one2) => one2.trim()).map(named5)), "each");
552
- const groups = Object.fromEntries(await Promise.all(Object.entries(await store.accounts.accountGroups()).map(async ([name2, members]) => [name2, await each(members)])));
675
+ const groups = Object.fromEntries(await Promise.all(Object.entries(context.groups).map(async ([name2, members]) => [name2, await each(members)])));
553
676
  return entriesOfList((await each(value.split(","))).join(","), {
554
- held,
677
+ ...context,
555
678
  groups,
556
- profiles: await store.accounts.profiles(),
557
679
  running: { provider: "email", command: "memo" }
558
680
  });
559
681
  }, "listedOf");
560
- var sourceListOf = /* @__PURE__ */ __name(async (store, env, value) => {
561
- const listed2 = await listedOf(store, value);
682
+ var sourceListOf = /* @__PURE__ */ __name(async (store, env, value, only) => {
683
+ const listed2 = await listedOf(store, env, value);
684
+ const typed = new Set(value.split(",").map((item) => item.trim()));
562
685
  const list = { mail: [], notes: false, documents: false };
563
686
  for (const { entry, accounts } of listed2) {
564
687
  const word = entry.split(":")[0] ?? "";
688
+ const group = word === "group" || !typed.has(entry.trim());
689
+ if (only !== void 0 && group && accounts.every(({ kind }) => kind !== only))
690
+ continue;
565
691
  if (MESSENGERS.has(word))
566
692
  throw messengers(entry);
567
693
  if (word === "notes" || word === "all")
@@ -572,11 +698,13 @@ var sourceListOf = /* @__PURE__ */ __name(async (store, env, value) => {
572
698
  if (kind === "mail") {
573
699
  if (!list.mail.some((one2) => one2.account === account2))
574
700
  list.mail.push({ provider, account: account2 });
575
- } else if (kind === "notes")
701
+ } else if (group && only !== void 0)
702
+ continue;
703
+ else if (kind === "notes")
576
704
  list.notes = true;
577
705
  else if (kind === "documents")
578
706
  list.documents = true;
579
- else if (word !== "all")
707
+ else if (word !== "all" && !group)
580
708
  throw messengers(entry);
581
709
  }
582
710
  }
@@ -585,9 +713,11 @@ var sourceListOf = /* @__PURE__ */ __name(async (store, env, value) => {
585
713
  var SOURCE_HELP = `which texts, separated by commas: ${SHAPES}`;
586
714
  var MAIL_SOURCES = "email:<address>, email or group:<name>";
587
715
  var mailboxesOf = /* @__PURE__ */ __name(async (store, env, value) => {
588
- const list = await sourceListOf(store, env, value);
716
+ const list = await sourceListOf(store, env, value, "mail");
589
717
  if (list.notes || list.documents)
590
718
  throw new CliError("validation_error", `${value}: this reads mail only \u2014 ${MAIL_SOURCES}`);
719
+ if (list.mail.length === 0 && value.split(",").some((entry) => entry.trim().startsWith("group:")))
720
+ throw new CliError("not_found", `${value} holds no mailbox`);
591
721
  return list.mail;
592
722
  }, "mailboxesOf");
593
723
  var ACCOUNTS_HELP = `which accounts, separated by commas: ${SHAPES}`;
@@ -596,14 +726,14 @@ var MEETING_WRITE_HELP = "the meeting account it acts as: provider:account, such
596
726
  var ONE_ACCOUNT_HELP = "the one account: provider:account (telegram:500, email:personal), or a provider or group:<name> that holds only one";
597
727
  var accountsOf = /* @__PURE__ */ __name(async (store, env, value) => {
598
728
  const keys = [];
599
- for (const { accounts } of await listedOf(store, value))
729
+ for (const { accounts } of await listedOf(store, env, value))
600
730
  for (const { provider, account: account2 } of accounts)
601
731
  if (!keys.some((one2) => one2.provider === provider && one2.account === account2))
602
732
  keys.push({ provider, account: account2 });
603
733
  return keys;
604
734
  }, "accountsOf");
605
735
  var named = /* @__PURE__ */ __name((keys) => keys.map((key) => accountName(key)).join(", "), "named");
606
- var unnamed = /* @__PURE__ */ __name(async (store, option = "--source") => new CliError("validation_error", `give ${option} <provider>:<account> \u2014 the store holds ${named(await store.accounts.accounts()) || "no account yet"}`), "unnamed");
736
+ var unnamed = /* @__PURE__ */ __name(async (store, env, option = "--source") => new CliError("validation_error", `give ${option} <provider>:<account> \u2014 the store holds ${named(await scopedAccounts(store, env)) || "no account yet"}`), "unnamed");
607
737
  var storedKeysOf = /* @__PURE__ */ __name(async (store, env, value) => {
608
738
  const held = await store.accounts.storedAccounts();
609
739
  const holdsFiles = await filesAccounts(store);
@@ -621,7 +751,7 @@ var storedKeysOf = /* @__PURE__ */ __name(async (store, env, value) => {
621
751
  var noStoredAccount = /* @__PURE__ */ __name((value) => new CliError("not_found", `${value} names no stored account; notes written with memo notes add belong to none \u2014 name a notes folder (notes:<id>), a mailbox or a messenger account`), "noStoredAccount");
622
752
  var oneAccountOf = /* @__PURE__ */ __name(async (store, env, value, option = "--source") => {
623
753
  if (value === void 0)
624
- throw await unnamed(store, option);
754
+ throw await unnamed(store, env, option);
625
755
  const keys = await storedKeysOf(store, env, value);
626
756
  if (option === "--account" && !value.includes(":") && keys.length === 1)
627
757
  throw new CliError("validation_error", `give --account ${named(keys)}; a provider alone does not name an acting account`);
@@ -636,7 +766,7 @@ var contextSourcesOf = /* @__PURE__ */ __name(async (store, env, value) => {
636
766
  const holdsFiles = await filesAccounts(store);
637
767
  const sources = [];
638
768
  const unread = [];
639
- for (const { entry, accounts } of await listedOf(store, value)) {
769
+ for (const { entry, accounts } of await listedOf(store, env, value)) {
640
770
  let read = 0;
641
771
  for (const { provider, account: account2, kind } of accounts) {
642
772
  const stored = kind === "notes" ? held.find((one2) => holdsFiles(one2) && String(one2.id) === account2) : kind === "messages" || kind === "mail" || kind === "meetings" ? held.find((one2) => one2.provider === provider && one2.account === account2) : void 0;
@@ -665,7 +795,7 @@ var theAccount = /* @__PURE__ */ __name((store, env, options, warn) => oneAccoun
665
795
  var theAccounts = /* @__PURE__ */ __name(async (store, env, options, warn) => {
666
796
  const value = sourceOf(options, warn);
667
797
  if (value === void 0)
668
- return store.accounts.accounts();
798
+ return scopedAccounts(store, env);
669
799
  const keys = await storedKeysOf(store, env, value);
670
800
  if (keys.length === 0)
671
801
  throw noStoredAccount(value);
@@ -673,7 +803,7 @@ var theAccounts = /* @__PURE__ */ __name(async (store, env, options, warn) => {
673
803
  }, "theAccounts");
674
804
  var namedAccounts = /* @__PURE__ */ __name(async (store, env, options, warn) => {
675
805
  if (sourceOf(options, warn) === void 0)
676
- throw await unnamed(store);
806
+ throw await unnamed(store, env);
677
807
  return theAccounts(store, env, options, warn);
678
808
  }, "namedAccounts");
679
809
  var accountName = /* @__PURE__ */ __name(({ provider, account: account2 }) => `${provider}:${account2}`, "accountName");
@@ -710,7 +840,7 @@ var readScope = /* @__PURE__ */ __name((command, help = ONE_ACCOUNT_HELP) => sou
710
840
  var writeScope = /* @__PURE__ */ __name((command, help) => writeOptions(command, help).option("--json", "print JSON; --json=id,title keeps only those fields"), "writeScope");
711
841
  var jsonOption = /* @__PURE__ */ __name((command, fields = "ref,title") => command.option("--json", `print JSON; --json=${fields} keeps only those fields`), "jsonOption");
712
842
 
713
- // node_modules/.pnpm/@wirecat+cli-core@0.618.0_@wirecat+cli-base@0.91.0_commander@15.0.0_esbuild@0.28.2_type_a1c6dd927639f1a41fe5f9c53e24865e/node_modules/@wirecat/cli-core/dist/mail/sender-scores.js
843
+ // node_modules/.pnpm/@wirecat+cli-core@0.619.0_@wirecat+cli-base@0.91.0_commander@15.0.0_esbuild@0.28.2_type_25b690dd810be59ade44e4d26e61c9f5/node_modules/@wirecat/cli-core/dist/mail/sender-scores.js
714
844
  var SCORED = "mail_sender_scores";
715
845
  var DAY = 864e5;
716
846
  var RECENT = 2 * 365 * DAY;
@@ -726,27 +856,10 @@ var demotedSenders = /* @__PURE__ */ __name(async (store) => {
726
856
  return senders;
727
857
  }, "demotedSenders");
728
858
 
729
- // node_modules/.pnpm/@wirecat+cli-core@0.618.0_@wirecat+cli-base@0.91.0_commander@15.0.0_esbuild@0.28.2_type_a1c6dd927639f1a41fe5f9c53e24865e/node_modules/@wirecat/cli-core/dist/mail/sync.js
859
+ // node_modules/.pnpm/@wirecat+cli-core@0.619.0_@wirecat+cli-base@0.91.0_commander@15.0.0_esbuild@0.28.2_type_25b690dd810be59ade44e4d26e61c9f5/node_modules/@wirecat/cli-core/dist/mail/sync.js
730
860
  var DAY2 = 864e5;
731
861
  var EDGE = 2 * DAY2;
732
862
 
733
- // dist/vocabulary/project.js
734
- var canonicalProject = /* @__PURE__ */ __name(async (store, reference2, limits = {}) => {
735
- if (/^project:[1-9]\d*$/.test(reference2)) {
736
- const catalog = await store.knowledge.vocabulary({ kind: "project", ...limits });
737
- if (!catalog.entries.some((entry2) => entry2.id === reference2.slice(8)))
738
- throw new CliError("not_found", "the owner project is unavailable");
739
- return reference2;
740
- }
741
- const found = await store.knowledge.resolveVocabulary(reference2, { kind: "project", ...limits });
742
- if (found.matches.length !== 1)
743
- throw new CliError(found.matches.length ? "validation_error" : "not_found", found.matches.length ? `${reference2} names ${found.matches.length} projects; give one by its key, as memo vocabulary show ${reference2} lists them` : `no project ${reference2}; memo projects list shows yours, memo projects add creates one`, { candidates: found.matches.map((entry2) => ({ id: entry2.id, key: entry2.key, name: entry2.name })) });
744
- const entry = found.matches[0];
745
- if (!entry)
746
- throw new CliError("not_found", "the owner project is unavailable");
747
- return `project:${entry.id}`;
748
- }, "canonicalProject");
749
-
750
863
  // dist/review/kinds.js
751
864
  var REVIEW_KINDS = [
752
865
  "relationship",
@@ -787,6 +900,101 @@ var reviewRegistry = /* @__PURE__ */ __name((store) => {
787
900
  };
788
901
  }, "reviewRegistry");
789
902
 
903
+ // dist/store/guard.js
904
+ var guardOf = /* @__PURE__ */ __name((store, env) => groupGuardOf(store, APP, env), "guardOf");
905
+ var reviewOf = /* @__PURE__ */ __name(async (store, env) => {
906
+ const guard = await guardOf(store, env);
907
+ return guard === void 0 ? reviewRegistry(store) : lockedRegistry(reviewRegistry(store), guard);
908
+ }, "reviewOf");
909
+ var proposalsOf = /* @__PURE__ */ __name(async (store, env) => {
910
+ const guard = await guardOf(store, env);
911
+ return guard === void 0 ? proposalRegistry(store) : lockedRegistry(proposalRegistry(store), guard);
912
+ }, "proposalsOf");
913
+ var stripped = /* @__PURE__ */ __name(async (store, env, value) => {
914
+ const guard = await guardOf(store, env);
915
+ if (guard === void 0)
916
+ return value;
917
+ const { value: kept, out_of_scope } = await guard.strip(value);
918
+ if (out_of_scope === 0 || kept === null || typeof kept !== "object" || Array.isArray(kept))
919
+ return kept;
920
+ if ("items" in kept) {
921
+ const missing = kept.missing ?? [];
922
+ const why = `${out_of_scope} evidence references outside group ${guard.group} left out`;
923
+ return { ...kept, missing: [...missing, { field: "out_of_scope", why }] };
924
+ }
925
+ return { ...kept, out_of_scope };
926
+ }, "stripped");
927
+ var sourcesIn = /* @__PURE__ */ __name(async (store, env, sources) => {
928
+ const guard = await guardOf(store, env);
929
+ if (guard === void 0)
930
+ return { sources: [...sources] };
931
+ const kept = [];
932
+ for (const one2 of sources)
933
+ if (one2.ref === null || await guard.visible(one2.ref))
934
+ kept.push(one2);
935
+ return { sources: kept, ...kept.length < sources.length ? { out_of_scope: sources.length - kept.length } : {} };
936
+ }, "sourcesIn");
937
+ var lockedCoverage = /* @__PURE__ */ __name(async (store, env, value) => {
938
+ const guard = await guardOf(store, env);
939
+ const scope = guard === void 0 ? void 0 : await groupScopeOf(store, env);
940
+ if (guard === void 0 || scope === void 0)
941
+ return value;
942
+ const held = new Set((await store.accounts.storedAccounts()).map(({ provider, account: account2 }) => `${provider}:${account2}`));
943
+ const outside2 = /* @__PURE__ */ __name((source) => held.has(source) && !scope.accounts.some((key) => `${key.provider}:${key.account}` === source), "outside");
944
+ const walk = /* @__PURE__ */ __name((node) => {
945
+ if (Array.isArray(node))
946
+ return node.map(walk);
947
+ if (node === null || typeof node !== "object")
948
+ return node;
949
+ return Object.fromEntries(Object.entries(node).map(([key, inner]) => {
950
+ if (key !== "notRead" || !Array.isArray(inner))
951
+ return [key, walk(inner)];
952
+ const rows = inner;
953
+ const away = rows.filter((one2) => outside2(one2.source)).length;
954
+ const kept = rows.filter((one2) => !outside2(one2.source));
955
+ return [
956
+ key,
957
+ away ? [...kept, { source: "other accounts", reason: `${away} outside group ${guard.group}` }] : kept
958
+ ];
959
+ }));
960
+ }, "walk");
961
+ return walk(value);
962
+ }, "lockedCoverage");
963
+ var refuseOutsideAction = /* @__PURE__ */ __name(async (store, env, id) => {
964
+ const guard = await guardOf(store, env);
965
+ if (guard !== void 0 && !await guard.visible(`action:${id}`))
966
+ throw new CliError("permission_error", `this process is locked to group ${guard.group} \u2014 action ${id} is outside it`, {
967
+ reason: "group.outside"
968
+ });
969
+ }, "refuseOutsideAction");
970
+ var actionsIn = /* @__PURE__ */ __name(async (store, env, actions) => {
971
+ const guard = await guardOf(store, env);
972
+ if (guard === void 0)
973
+ return [...actions];
974
+ const kept = [];
975
+ for (const one2 of actions)
976
+ if (await guard.visible(`action:${one2.id}`))
977
+ kept.push(one2);
978
+ return kept;
979
+ }, "actionsIn");
980
+
981
+ // dist/vocabulary/project.js
982
+ var canonicalProject = /* @__PURE__ */ __name(async (store, reference2, limits = {}) => {
983
+ if (/^project:[1-9]\d*$/.test(reference2)) {
984
+ const catalog = await store.knowledge.vocabulary({ kind: "project", ...limits });
985
+ if (!catalog.entries.some((entry2) => entry2.id === reference2.slice(8)))
986
+ throw new CliError("not_found", "the owner project is unavailable");
987
+ return reference2;
988
+ }
989
+ const found = await store.knowledge.resolveVocabulary(reference2, { kind: "project", ...limits });
990
+ if (found.matches.length !== 1)
991
+ throw new CliError(found.matches.length ? "validation_error" : "not_found", found.matches.length ? `${reference2} names ${found.matches.length} projects; give one by its key, as memo vocabulary show ${reference2} lists them` : `no project ${reference2}; memo projects list shows yours, memo projects add creates one`, { candidates: found.matches.map((entry2) => ({ id: entry2.id, key: entry2.key, name: entry2.name })) });
992
+ const entry = found.matches[0];
993
+ if (!entry)
994
+ throw new CliError("not_found", "the owner project is unavailable");
995
+ return `project:${entry.id}`;
996
+ }, "canonicalProject");
997
+
790
998
  // dist/review/review.js
791
999
  var STATUSES = ["proposed", "confirmed", "rejected", "all"];
792
1000
  var REVIEW_QUERY = {
@@ -890,15 +1098,15 @@ var reviewItem = /* @__PURE__ */ __name((row, label) => ({
890
1098
  var rowRefs = /* @__PURE__ */ __name((row) => [row.subject, row.object, row.project], "rowRefs");
891
1099
  var listReview = /* @__PURE__ */ __name(async (store, env, words, { limit, page }) => {
892
1100
  const filter = await filterOf(store, words);
893
- const found = await reviewRegistry(store).list({ ...filter, limit, offset: (page - 1) * limit });
1101
+ const found = await (await reviewOf(store, env)).list({ ...filter, limit, offset: (page - 1) * limit });
894
1102
  const label = await labelsFor(store, found.items.flatMap(rowRefs));
895
1103
  return { items: found.items.map((row) => reviewItem(row, label)), hasMore: found.hasMore };
896
1104
  }, "listReview");
897
1105
  var REVIEW_SOURCES = "memo review list kind:memory_source_review";
898
- var reviewOf = /* @__PURE__ */ __name(async (store, id) => {
1106
+ var reviewItemOf = /* @__PURE__ */ __name(async (store, id) => {
899
1107
  const row = await reviewRegistry(store).get(id);
900
1108
  return reviewItem(row, await labelsFor(store, rowRefs(row)));
901
- }, "reviewOf");
1109
+ }, "reviewItemOf");
902
1110
  var TEXT_SHOWN = 2e3;
903
1111
  var shown = /* @__PURE__ */ __name((text3) => text3 === null || text3.length <= TEXT_SHOWN ? text3 : `${text3.slice(0, TEXT_SHOWN - 1)}\u2026`, "shown");
904
1112
  var sourceReviewDetail = /* @__PURE__ */ __name(async (store, id, target) => {
@@ -921,7 +1129,7 @@ var sourceReviewDetail = /* @__PURE__ */ __name(async (store, id, target) => {
921
1129
  };
922
1130
  }),
923
1131
  challenges: payload.challenges,
924
- suggestions: (payload.suggestions ?? []).map(({ author, body, evidence, at }) => ({ author, body, evidence, at })),
1132
+ suggestions: (payload.suggestions ?? []).map(({ author, body, evidence, at: at2 }) => ({ author, body, evidence, at: at2 })),
925
1133
  decide: {
926
1134
  stillTrue: `memo review confirm ${id}`,
927
1135
  dismiss: `memo review reject ${id} --reason <why>`,
@@ -932,7 +1140,7 @@ var sourceReviewDetail = /* @__PURE__ */ __name(async (store, id, target) => {
932
1140
  };
933
1141
  }, "sourceReviewDetail");
934
1142
  var showReview = /* @__PURE__ */ __name(async (store, env, id) => {
935
- const row = await reviewRegistry(store).get(id);
1143
+ const row = await (await reviewOf(store, env)).get(id);
936
1144
  const label = await labelsFor(store, [...rowRefs(row), ...row.evidence]);
937
1145
  return {
938
1146
  ...reviewItem(row, label),
@@ -962,12 +1170,12 @@ var senderOf = /* @__PURE__ */ __name(async (store, ref) => {
962
1170
  var idRanges = /* @__PURE__ */ __name((ids) => {
963
1171
  const numbers = ids.filter((id) => /^\d+$/.test(id)).map(Number).sort((a, b) => a - b);
964
1172
  const spans = [];
965
- for (let at = 0; at < numbers.length; ) {
966
- let end = at;
1173
+ for (let at2 = 0; at2 < numbers.length; ) {
1174
+ let end = at2;
967
1175
  while (end + 1 < numbers.length && numbers[end + 1] === numbers[end] + 1)
968
1176
  end++;
969
- spans.push(end === at ? String(numbers[at]) : `${numbers[at]}-${numbers[end]}`);
970
- at = end + 1;
1177
+ spans.push(end === at2 ? String(numbers[at2]) : `${numbers[at2]}-${numbers[end]}`);
1178
+ at2 = end + 1;
971
1179
  }
972
1180
  return [...spans, ...ids.filter((id) => !/^\d+$/.test(id))].join(",");
973
1181
  }, "idRanges");
@@ -986,14 +1194,14 @@ var SHOW_STEP = {
986
1194
  why: "one proposal with its evidence"
987
1195
  };
988
1196
  var reviewSteps = /* @__PURE__ */ __name((items) => {
989
- const pending2 = items.filter((item) => item.status === "proposed");
990
- const first = pending2[0];
1197
+ const pending = items.filter((item) => item.status === "proposed");
1198
+ const first = pending[0];
991
1199
  if (first === void 0)
992
1200
  return [];
993
1201
  return [
994
1202
  stepOf(CONFIRM_STEP, {
995
- args: { ids: idRanges(pending2.map((item) => item.id)) },
996
- values: { count: pending2.length }
1203
+ args: { ids: idRanges(pending.map((item) => item.id)) },
1204
+ values: { count: pending.length }
997
1205
  }),
998
1206
  stepOf(SHOW_STEP, { args: { id: first.id } })
999
1207
  ];
@@ -1012,8 +1220,8 @@ var reviewText = /* @__PURE__ */ __name((items, hasMore) => {
1012
1220
  for (const item of items)
1013
1221
  groups.set(sourceOf2(item), [...groups.get(sourceOf2(item)) ?? [], item]);
1014
1222
  const pad = " ".repeat(width);
1015
- const lines2 = [...groups].flatMap(([source, group], at) => [
1016
- ...at === 0 ? [] : [""],
1223
+ const lines2 = [...groups].flatMap(([source, group], at2) => [
1224
+ ...at2 === 0 ? [] : [""],
1017
1225
  source,
1018
1226
  ...group.flatMap((item) => {
1019
1227
  const head = [
@@ -1041,8 +1249,8 @@ var decisionOf = /* @__PURE__ */ __name((confirm, by, reason) => {
1041
1249
  const why = reason?.trim();
1042
1250
  return { confirm, by, ...by === "owner" && why ? { reason: why } : {} };
1043
1251
  }, "decisionOf");
1044
- var decideOne = /* @__PURE__ */ __name(async (store, id, decision) => {
1045
- const { decided, refused: refused2 } = await proposalRegistry(store).decide([id], decision);
1252
+ var decideOne = /* @__PURE__ */ __name(async (store, env, id, decision) => {
1253
+ const { decided, refused: refused2 } = await (await proposalsOf(store, env)).decide([id], decision);
1046
1254
  const refusal2 = refused2[0];
1047
1255
  if (refusal2)
1048
1256
  throw new CliError(refusal2.code, refusal2.message, { reason: refusal2.reason });
@@ -1062,8 +1270,8 @@ var pageOf = /* @__PURE__ */ __name(async (command, limit, read, { fallback = 10
1062
1270
 
1063
1271
  // dist/store/scope.js
1064
1272
  var choices = /* @__PURE__ */ __name((keys) => keys.length ? `; choose one of ${keys.map(({ provider, account: account2 }) => `${provider}:${account2}`).join(", ")}` : "", "choices");
1065
- var selectAccount = /* @__PURE__ */ __name(async (store, scope) => {
1066
- const held = await store.accounts.accounts();
1273
+ var selectAccount = /* @__PURE__ */ __name(async (store, env, scope) => {
1274
+ const held = await scopedAccounts(store, env);
1067
1275
  if (!scope.provider)
1068
1276
  throw new CliError("validation_error", `give --account <provider>:<account>${choices(held)}`);
1069
1277
  const matches2 = held.filter((key) => key.provider === scope.provider && (scope.account === void 0 || key.account === scope.account));
@@ -1071,16 +1279,16 @@ var selectAccount = /* @__PURE__ */ __name(async (store, scope) => {
1071
1279
  throw new CliError(matches2.length ? "validation_error" : "not_found", matches2.length ? `several accounts match; give one${choices(matches2)}` : `the store holds no ${scope.provider} account matching this selection${choices(held)}`);
1072
1280
  return matches2[0];
1073
1281
  }, "selectAccount");
1074
- var meetingReference = /* @__PURE__ */ __name(async (store, id, scope) => {
1282
+ var meetingReference = /* @__PURE__ */ __name(async (store, env, id, scope) => {
1075
1283
  if (!/^\d+$/.test(id))
1076
1284
  throw new CliError("validation_error", "--meeting takes the meeting's id in the store");
1077
- const account2 = await store.accounts.storedAccount(await selectAccount(store, scope));
1285
+ const account2 = await store.accounts.storedAccount(await selectAccount(store, env, scope));
1078
1286
  const found = await store.meetings.meeting(Number(id));
1079
1287
  if (found === null || found.meeting.accountId !== account2.id)
1080
1288
  throw new CliError("not_found", `the ${account2.provider} account ${account2.account} holds no meeting ${id}`);
1081
1289
  return `meeting:${account2.id}/${found.meeting.id}`;
1082
1290
  }, "meetingReference");
1083
- var selectTarget = /* @__PURE__ */ __name(async (store, input) => {
1291
+ var selectTarget = /* @__PURE__ */ __name(async (store, env, input) => {
1084
1292
  const choices2 = ["message", "chat", "contact", "person", "task", "organization", "project", "meeting"];
1085
1293
  const selected = choices2.filter((name2) => input[name2] !== void 0);
1086
1294
  if (selected.length !== 1)
@@ -1098,7 +1306,7 @@ var selectTarget = /* @__PURE__ */ __name(async (store, input) => {
1098
1306
  throw new CliError("validation_error", "locator and selected account disagree");
1099
1307
  return { key: { provider: parsed.provider, account: parsed.account }, target: { type, locator } };
1100
1308
  }
1101
- return { key: await selectAccount(store, input), target: { type, id: input[type] } };
1309
+ return { key: await selectAccount(store, env, input), target: { type, id: input[type] } };
1102
1310
  }, "selectTarget");
1103
1311
  var scopeOf = /* @__PURE__ */ __name(async (store, env, options, warn) => {
1104
1312
  const value = writeAccountOf(options, warn);
@@ -1147,8 +1355,8 @@ var chatOf = /* @__PURE__ */ __name((reference2) => {
1147
1355
  if (!reference2.startsWith("msg:") && !reference2.startsWith("chat:"))
1148
1356
  return void 0;
1149
1357
  try {
1150
- const at = parseLocator(reference2);
1151
- return { key: { provider: at.provider, account: at.account }, chat: at.chat };
1358
+ const at2 = parseLocator(reference2);
1359
+ return { key: { provider: at2.provider, account: at2.account }, chat: at2.chat };
1152
1360
  } catch {
1153
1361
  return void 0;
1154
1362
  }
@@ -1198,8 +1406,8 @@ var actionItems = /* @__PURE__ */ __name(async (store, actions, { brief = false
1198
1406
  if (batch?.project && !names.has(batch.project))
1199
1407
  for (const project of await store.knowledge.projects())
1200
1408
  names.set(project.ref, project.name);
1201
- return Promise.all(actions.map(async (action, at) => {
1202
- const batch = batches[at];
1409
+ return Promise.all(actions.map(async (action, at2) => {
1410
+ const batch = batches[at2];
1203
1411
  const project = batch?.project ?? (action.target?.startsWith("project:") ? action.target : null);
1204
1412
  const projectName = project === null ? null : names.get(project) ?? null;
1205
1413
  const targetName = action.target === null ? null : names.get(action.target) ?? null;
@@ -1218,7 +1426,8 @@ var actionItems = /* @__PURE__ */ __name(async (store, actions, { brief = false
1218
1426
  }, "actionItems");
1219
1427
  var listActions = /* @__PURE__ */ __name((store, query, limit, options = {}) => {
1220
1428
  const status = queryTerms(query, ACTION_QUERY, "actions list").get("status");
1221
- return pageOf("actions list", limit, async (most) => actionItems(store, await store.proposedActions.list({ limit: most, ...status === void 0 ? {} : { status } }), options));
1429
+ const { keep: keep2 = /* @__PURE__ */ __name(async (rows) => rows, "keep"), ...shown3 } = options;
1430
+ return pageOf("actions list", limit, async (most) => actionItems(store, await keep2(await store.proposedActions.list({ limit: most, ...status === void 0 ? {} : { status } })), shown3));
1222
1431
  }, "listActions");
1223
1432
  var showAction = /* @__PURE__ */ __name(async (store, id) => (await actionItems(store, [await store.proposedActions.get(id)]))[0], "showAction");
1224
1433
  var BATCHES = {
@@ -1262,7 +1471,7 @@ var decideBatch = /* @__PURE__ */ __name(async (store, id, decision) => {
1262
1471
  throw new CliError(refusal2.code, refusal2.message, { reason: refusal2.reason });
1263
1472
  return decided[0];
1264
1473
  }, "decideBatch");
1265
- var propose = /* @__PURE__ */ __name(async (store, proposal, by) => {
1474
+ var propose = /* @__PURE__ */ __name(async (store, env, proposal, by) => {
1266
1475
  let payload;
1267
1476
  if (proposal.payload !== void 0) {
1268
1477
  try {
@@ -1274,7 +1483,7 @@ var propose = /* @__PURE__ */ __name(async (store, proposal, by) => {
1274
1483
  return store.proposedActions.propose({
1275
1484
  kind: proposal.kind,
1276
1485
  by,
1277
- account: await selectAccount(store, proposal),
1486
+ account: await selectAccount(store, env, proposal),
1278
1487
  reason: proposal.reason,
1279
1488
  ...proposal.target === void 0 ? {} : { target: proposal.target },
1280
1489
  ...payload === void 0 ? {} : { payload }
@@ -1288,27 +1497,35 @@ var actionsCommand = /* @__PURE__ */ __name((program, streams, env) => {
1288
1497
  writeOptions(byOption(annotate(actions.command("add"), { effects: LOCAL_WRITE }).description("propose an action, such as a reply or a ban, in the account that would act")).argument("<kind>", "a lower-case word: reply, send, ban, mute, pin, invite, create_task, \u2026").requiredOption("--reason <text>", "why it should be done"), "the account that would act: provider:account, such as telegram:1").option("--target <ref>", "what it acts on: msg:, chat:, contact:, person:, task:, \u2026").option("--payload <json>", "what to do, as JSON, such as the reply's text").option("--json", "print JSON; --json=id,title keeps only those fields").action((kind, { asOwner, account: account2, ...options }, command) => run(options.json, async (store) => {
1289
1498
  const by = await whoRuns(command, env, { asOwner, question: "propose this action as yours?" });
1290
1499
  const key = await writeAccount(store, env, { account: account2 }, (text3) => streams.diagnostic(text3));
1291
- return itemAnswer(await propose(store, { ...options, ...key, kind }, by));
1500
+ return itemAnswer(await propose(store, env, { ...options, ...key, kind }, by));
1501
+ }));
1502
+ withQuery(annotate(actions.command("list"), { effects: LOCAL_READ, output: { entity: "proposed_action" } }).description("proposed actions, newest first"), ACTION_QUERY).option("--limit <n>", "most actions, up to 500", positive, 100).option("--brief", "without each findings batch's cited sources").option("--json", "print JSON; --json=id,title keeps only those fields").action((words, options) => run(options.json, async (store) => stripped(store, env, await listActions(store, words, options.limit, {
1503
+ brief: options.brief === true,
1504
+ keep: /* @__PURE__ */ __name((rows) => actionsIn(store, env, rows), "keep")
1505
+ }))));
1506
+ annotate(actions.command("show"), { effects: LOCAL_READ }).description("one proposed action; a findings batch with its fingerprint and sources").argument("<id>", "the action's id, as actions list gives it").option("--json", "print JSON; --json=id,title keeps only those fields").action((id, options) => run(options.json, async (store) => {
1507
+ await refuseOutsideAction(store, env, id);
1508
+ return itemAnswer(await stripped(store, env, await showAction(store, id)));
1292
1509
  }));
1293
- withQuery(annotate(actions.command("list"), { effects: LOCAL_READ, output: { entity: "proposed_action" } }).description("proposed actions, newest first"), ACTION_QUERY).option("--limit <n>", "most actions, up to 500", positive, 100).option("--brief", "without each findings batch's cited sources").option("--json", "print JSON; --json=id,title keeps only those fields").action((words, options) => run(options.json, (store) => listActions(store, words, options.limit, { brief: options.brief === true })));
1294
- annotate(actions.command("show"), { effects: LOCAL_READ }).description("one proposed action; a findings batch with its fingerprint and sources").argument("<id>", "the action's id, as actions list gives it").option("--json", "print JSON; --json=id,title keeps only those fields").action((id, options) => run(options.json, async (store) => itemAnswer(await showAction(store, id))));
1295
1510
  byOption(annotate(actions.command("confirm"), { effects: LOCAL_WRITE })).summary("confirm it: a task to act on, or a findings batch's facts and tasks").description("confirm it: it becomes a task in the account that would act, nothing is sent; for a findings batch, create the named findings (all when none is named) and reject the rest").argument("<id>", "the action's id, as actions list gives it").argument("[findings...]", "a findings batch: the finding IDs to create").option("--fingerprint <hash>", "a findings batch: the fingerprint actions show gives").option("--reason <text>", "why, in a few words; required when an agent decides for you").option("--json", "print JSON; --json=id,title keeps only those fields").action(async (id, findings, options, command) => {
1296
1511
  const by = await deciderOf(command, env, { ...options, question: `confirm action ${id} as you, the owner?` });
1297
1512
  await run(options.json, async (store) => {
1513
+ await refuseOutsideAction(store, env, id);
1298
1514
  const findingsAnswer = await decideFindings(store, id, { ...options, accept: findings, confirm: true, by });
1299
1515
  if (findingsAnswer)
1300
1516
  return itemAnswer(findingsAnswer);
1301
- assertMayDecide(await proposalRegistry(store).get(id), by, store.decisionPolicy);
1517
+ assertMayDecide(await (await proposalsOf(store, env)).get(id), by, store.decisionPolicy);
1302
1518
  return itemAnswer(await approveAsTask(store, id, by));
1303
1519
  });
1304
1520
  });
1305
1521
  byOption(annotate(actions.command("reject"), { effects: LOCAL_WRITE })).description("reject it; nothing is done. For a findings batch, every new finding").argument("<id>", "the action's id, as actions list gives it").option("--fingerprint <hash>", "a findings batch: the fingerprint actions show gives").option("--reason <text>", "why, in a few words; required when an agent decides for you").option("--json", "print JSON; --json=id,title keeps only those fields").action(async (id, options, command) => {
1306
1522
  const by = await deciderOf(command, env, { ...options, question: `reject action ${id} as you, the owner?` });
1307
1523
  await run(options.json, async (store) => {
1524
+ await refuseOutsideAction(store, env, id);
1308
1525
  const findingsAnswer = await decideFindings(store, id, { ...options, accept: [], confirm: false, by });
1309
1526
  if (findingsAnswer)
1310
1527
  return itemAnswer(findingsAnswer);
1311
- await decideOne(store, id, decisionOf(false, by, options.reason));
1528
+ await decideOne(store, env, id, decisionOf(false, by, options.reason));
1312
1529
  return itemAnswer(await store.proposedActions.get(id));
1313
1530
  });
1314
1531
  });
@@ -1447,12 +1664,12 @@ var markKey = /* @__PURE__ */ __name(async (store, project, ref, reason, author)
1447
1664
  return describe(store, link2);
1448
1665
  }, "markKey");
1449
1666
  var proposeKey = /* @__PURE__ */ __name(async (store, project, ref, reason, author, source) => {
1450
- const pending2 = await store.proposedActions.list({
1667
+ const pending = await store.proposedActions.list({
1451
1668
  kinds: ["key_document"],
1452
1669
  status: "proposed",
1453
1670
  project: project.ref
1454
1671
  });
1455
- const proposal = pending2.find((one2) => one2.payload?.ref === ref) ?? await store.proposedActions.propose({
1672
+ const proposal = pending.find((one2) => one2.payload?.ref === ref) ?? await store.proposedActions.propose({
1456
1673
  kind: "key_document",
1457
1674
  by: author,
1458
1675
  target: ref,
@@ -1614,7 +1831,7 @@ var personTasks = /* @__PURE__ */ __name(async (store, person, accounts, limit)
1614
1831
 
1615
1832
  // dist/search/search.js
1616
1833
  var CHATS_CHECKED = 500;
1617
- var MEMO = { provider: "notes", account: "internal" };
1834
+ var MEMO = MEMO_ACCOUNT;
1618
1835
  var unifiedSearch = /* @__PURE__ */ __name(async (store, query, options) => {
1619
1836
  const limit = options.limit ?? 20, offset = options.offset ?? 0;
1620
1837
  if (!Number.isInteger(limit) || limit < 1 || limit > 100 || !Number.isInteger(offset) || offset < 0 || offset > 1e3)
@@ -1731,7 +1948,7 @@ var searchAccounts = /* @__PURE__ */ __name(async (store, env, options) => {
1731
1948
  if (options.all && options.source !== void 0)
1732
1949
  throw new CliError("validation_error", "use --all alone, or name the accounts with --source");
1733
1950
  if (options.all)
1734
- return { keys: (await store.accounts.accounts()).filter(({ provider }) => provider !== "notes"), notes: true };
1951
+ return { keys: (await scopedAccounts(store, env)).filter(({ provider }) => provider !== "notes"), notes: true };
1735
1952
  if (options.source === void 0)
1736
1953
  throw new CliError("validation_error", "give --all, or name the accounts with --source: telegram:1,email,notes");
1737
1954
  const keys = await accountsOf(store, env, options.source);
@@ -1755,20 +1972,41 @@ var allowedPage = /* @__PURE__ */ __name(async (ask, limit, shows) => {
1755
1972
  const { nextOffset: _, ...rest } = first;
1756
1973
  return { ...rest, items: items.slice(0, limit), hasMore: items.length > limit || page.hasMore };
1757
1974
  }, "allowedPage");
1975
+ var groupScoped = /* @__PURE__ */ __name(async (store, env, only) => {
1976
+ const scope = await groupScopeOf(store, env);
1977
+ if (scope === void 0)
1978
+ return void 0;
1979
+ const kinds2 = accountsByKind(scope, await store.business.accounts());
1980
+ const wanted = only ?? RESOURCES_SEARCHED;
1981
+ const kept = wanted.filter((kind) => kinds2[kind].length > 0);
1982
+ if (kept.length === 0)
1983
+ throw new CliError("validation_error", `group ${scope.run.name} holds no account of ${wanted.join(", ")}`);
1984
+ return {
1985
+ only: kept,
1986
+ scope: Object.fromEntries(kept.map((kind) => [kind, kinds2[kind]])),
1987
+ skipped: wanted.filter((kind) => !kept.includes(kind)).map((resource) => ({
1988
+ resource,
1989
+ code: "not_found",
1990
+ reason: `group ${scope.run.name} holds no account of it`
1991
+ }))
1992
+ };
1993
+ }, "groupScoped");
1758
1994
  var searchEverywhere = /* @__PURE__ */ __name(async (store, env, { text: text3, limit, only, crmKinds, exact, timezone, plainOrder, shows }) => {
1759
- const accounts = await store.accounts.accounts();
1995
+ const accounts = await scopedAccounts(store, env);
1996
+ const group = await groupScoped(store, env, only);
1760
1997
  const messenger2 = { app: { ...APP, command: "tg" }, hintCommand: "memo" };
1761
1998
  const ask = /* @__PURE__ */ __name((offset) => searchAll(store, MEMO, {
1762
1999
  text: text3,
1763
2000
  limit,
1764
2001
  env,
1765
2002
  ...offset === void 0 ? {} : { offset },
1766
- ...only === void 0 ? {} : { only },
2003
+ ...group === void 0 ? only === void 0 ? {} : { only } : { only: group.only, scope: group.scope },
1767
2004
  ...crmKinds === void 0 ? {} : { crmKinds },
1768
2005
  ...exact ? { exact: true } : {},
1769
2006
  ...timezone === void 0 ? {} : { timezone }
1770
2007
  }, messenger2, (query) => searchStore(store, MEMO, query, messenger2), meaningLane({ env, store: /* @__PURE__ */ __name(async () => store, "store"), messenger: { app: { command: "memo" } } })), "ask");
1771
- const found = shows === void 0 ? await ask() : await allowedPage(ask, limit, shows);
2008
+ const searched = shows === void 0 ? await ask() : await allowedPage(ask, limit, shows);
2009
+ const found = group === void 0 ? searched : { ...searched, skipped: [...group.skipped, ...searched.skipped] };
1772
2010
  const tasks = [];
1773
2011
  let tasksIncomplete = false;
1774
2012
  const sources = found.items.map((item) => item.ref);
@@ -1822,7 +2060,7 @@ var searchKind = /* @__PURE__ */ __name(async (store, kind, { text: text3, limit
1822
2060
  return searchStore(store, MEMO, {
1823
2061
  text: text3,
1824
2062
  kind,
1825
- ...hasSource(parseLucene(plain).root) ? {} : { source: "all" },
2063
+ ...hasSource(parseLucene(plain).root) || accounts !== void 0 ? {} : { source: "all" },
1826
2064
  limit,
1827
2065
  ...scope,
1828
2066
  // As search all does: a question finds a short reply by the message it answers, and records holding some words.
@@ -1938,7 +2176,7 @@ var configCommand = /* @__PURE__ */ __name((program, streams, env) => {
1938
2176
  const values = rows.map((row) => `${JSON.stringify(row.value)}${row.from === "default" ? " (default)" : ""}`);
1939
2177
  const wide = /* @__PURE__ */ __name((texts) => texts.reduce((most, text3) => Math.max(most, text3.length), 0), "wide");
1940
2178
  const [settingWidth, valueWidth] = [wide(rows.map((row) => row.setting)), wide(values)];
1941
- const lines2 = rows.map((row, at) => `${row.setting.padEnd(settingWidth)} ${values[at]?.padEnd(valueWidth)} ${row.description}`);
2179
+ const lines2 = rows.map((row, at2) => `${row.setting.padEnd(settingWidth)} ${values[at2]?.padEnd(valueWidth)} ${row.description}`);
1942
2180
  print(options.json, itemAnswer({ path: configPath(env), found: raw !== void 0, settings: rows }), [configPath(env), ...lines2].join("\n"));
1943
2181
  });
1944
2182
  annotate(config.command("migrate"), { effects: LOCAL_WRITE }).description("write each setting the file lacks at its default, keeping yours").option("--json", "print JSON; --json=id,title keeps only those fields").action((options) => {
@@ -1951,6 +2189,18 @@ var configCommand = /* @__PURE__ */ __name((program, streams, env) => {
1951
2189
  });
1952
2190
  }, "configCommand");
1953
2191
 
2192
+ // dist/knowledge/business-text.js
2193
+ var relatedLine = /* @__PURE__ */ __name(({ ref, name: name2, roles }) => ` ${name2 ?? ref} ${ref} ${roles.map((role) => [role.kind, role.role, role.position && `(${role.position})`, role.standing, role.account && `by ${role.account}`].filter(Boolean).join(" ")).join("; ")}`, "relatedLine");
2194
+ var sectionLines = /* @__PURE__ */ __name((title, section2, line3 = relatedLine) => section2.items.length === 0 ? [] : [
2195
+ title,
2196
+ ...section2.items.map(line3),
2197
+ ...section2.hasMore ? [` ${section2.total} in all${section2.next ? ` \u2014 memo ${section2.next}` : ""}`] : []
2198
+ ], "sectionLines");
2199
+ var coverageLines = /* @__PURE__ */ __name((coverage) => [
2200
+ `Read: ${coverage.accounts.join(", ") || "no account"}`,
2201
+ ...coverage.notRead.map(({ source, reason }) => `Not read: ${source} \u2014 ${reason}`)
2202
+ ], "coverageLines");
2203
+
1954
2204
  // dist/notes/bound.js
1955
2205
  import { resolve as resolve2 } from "node:path";
1956
2206
 
@@ -1971,22 +2221,22 @@ var withFolders = /* @__PURE__ */ __name((config, folders) => ({
1971
2221
  }
1972
2222
  }), "withFolders");
1973
2223
  var bindFolder = /* @__PURE__ */ __name((config, folder) => {
1974
- const at = resolve(folder.path);
2224
+ const at2 = resolve(folder.path);
1975
2225
  const folders = noteFolders(config.notes);
1976
- const index = folders.findIndex((other) => other.path === at);
1977
- const bound = { ...folder, path: at };
1978
- const kept = folders.map((other, position) => position === index ? bound : other).filter((other, position) => position === index || other.id !== folder.id && other.path !== at);
2226
+ const index = folders.findIndex((other) => other.path === at2);
2227
+ const bound = { ...folder, path: at2 };
2228
+ const kept = folders.map((other, position) => position === index ? bound : other).filter((other, position) => position === index || other.id !== folder.id && other.path !== at2);
1979
2229
  return withFolders(config, index < 0 ? [...kept, bound] : kept);
1980
2230
  }, "bindFolder");
1981
2231
  var attachFolder = /* @__PURE__ */ __name((config, id, path, format) => {
1982
- const at = resolve(path);
2232
+ const at2 = resolve(path);
1983
2233
  const folders = noteFolders(config.notes);
1984
- const taken = folders.find((folder2) => folder2.path === at && folder2.id !== null && folder2.id !== id);
2234
+ const taken = folders.find((folder2) => folder2.path === at2 && folder2.id !== null && folder2.id !== id);
1985
2235
  if (taken)
1986
- throw new CliError("validation_error", `${at} is already folder ${taken.id} \u2014 attach that id elsewhere first, or remove it from the config`);
2236
+ throw new CliError("validation_error", `${at2} is already folder ${taken.id} \u2014 attach that id elsewhere first, or remove it from the config`);
1987
2237
  const previous = folders.find((folder2) => folder2.id === id);
1988
- const folder = { id, path: at, format: format ?? previous?.format ?? "obsidian" };
1989
- const kept = folders.filter((other) => other.id !== id && other.path !== at);
2238
+ const folder = { id, path: at2, format: format ?? previous?.format ?? "obsidian" };
2239
+ const kept = folders.filter((other) => other.id !== id && other.path !== at2);
1990
2240
  return { config: withFolders(config, [...kept, folder]), folder };
1991
2241
  }, "attachFolder");
1992
2242
  var unbindFolder = /* @__PURE__ */ __name((config, path) => withFolders(config, noteFolders(config.notes).filter((folder) => folder.path !== resolve(path))), "unbindFolder");
@@ -2019,11 +2269,11 @@ var folderIds = /* @__PURE__ */ __name(async (store, env, selected) => {
2019
2269
  return [.../* @__PURE__ */ new Set([...selected.filter((value) => known2.has(value)), ...bound.map(({ id }) => id)])];
2020
2270
  }, "folderIds");
2021
2271
  var folderOfFile = /* @__PURE__ */ __name((folders, file) => {
2022
- const at = resolve2(file);
2023
- const folder = folders.find((candidate) => at.startsWith(`${candidate.path}/`));
2272
+ const at2 = resolve2(file);
2273
+ const folder = folders.find((candidate) => at2.startsWith(`${candidate.path}/`));
2024
2274
  if (!folder)
2025
- throw new CliError("not_found", `${at} is in no configured folder of notes`, { reason: "folder.not-found" });
2026
- return { folder, path: at.slice(folder.path.length + 1) };
2275
+ throw new CliError("not_found", `${at2} is in no configured folder of notes`, { reason: "folder.not-found" });
2276
+ return { folder, path: at2.slice(folder.path.length + 1) };
2027
2277
  }, "folderOfFile");
2028
2278
 
2029
2279
  // dist/people/notes-map.js
@@ -2035,7 +2285,7 @@ import { createHash } from "node:crypto";
2035
2285
  import { existsSync, readFileSync as readFileSync2, statSync } from "node:fs";
2036
2286
  import { basename, extname, relative, sep } from "node:path";
2037
2287
 
2038
- // node_modules/.pnpm/@wirecat+cli-core@0.618.0_@wirecat+cli-base@0.91.0_commander@15.0.0_esbuild@0.28.2_type_a1c6dd927639f1a41fe5f9c53e24865e/node_modules/@wirecat/cli-core/dist/services/documents/extraction.js
2288
+ // node_modules/.pnpm/@wirecat+cli-core@0.619.0_@wirecat+cli-base@0.91.0_commander@15.0.0_esbuild@0.28.2_type_25b690dd810be59ade44e4d26e61c9f5/node_modules/@wirecat/cli-core/dist/services/documents/extraction.js
2039
2289
  var Proposal = object({
2040
2290
  kind: picklist(["summary", "digest", "fact", "preference"]),
2041
2291
  body: pipe(string(), trim(), minLength(1), maxLength(15e3)),
@@ -2043,13 +2293,13 @@ var Proposal = object({
2043
2293
  });
2044
2294
  var Proposals = object({ items: pipe(array(Proposal), maxLength(20)) });
2045
2295
 
2046
- // node_modules/.pnpm/@wirecat+cli-core@0.618.0_@wirecat+cli-base@0.91.0_commander@15.0.0_esbuild@0.28.2_type_a1c6dd927639f1a41fe5f9c53e24865e/node_modules/@wirecat/cli-core/dist/services/documents/mirrors.js
2296
+ // node_modules/.pnpm/@wirecat+cli-core@0.619.0_@wirecat+cli-base@0.91.0_commander@15.0.0_esbuild@0.28.2_type_25b690dd810be59ade44e4d26e61c9f5/node_modules/@wirecat/cli-core/dist/services/documents/mirrors.js
2047
2297
  var ID = pipe(string(), regex(/^[A-Za-z0-9_-]{1,200}$/));
2048
2298
 
2049
- // node_modules/.pnpm/@wirecat+cli-core@0.618.0_@wirecat+cli-base@0.91.0_commander@15.0.0_esbuild@0.28.2_type_a1c6dd927639f1a41fe5f9c53e24865e/node_modules/@wirecat/cli-core/dist/services/documents/sync.js
2299
+ // node_modules/.pnpm/@wirecat+cli-core@0.619.0_@wirecat+cli-base@0.91.0_commander@15.0.0_esbuild@0.28.2_type_25b690dd810be59ade44e4d26e61c9f5/node_modules/@wirecat/cli-core/dist/services/documents/sync.js
2050
2300
  var MAX_PICTURE_BYTES = 25 * 1024 * 1024;
2051
2301
 
2052
- // node_modules/.pnpm/@wirecat+cli-core@0.618.0_@wirecat+cli-base@0.91.0_commander@15.0.0_esbuild@0.28.2_type_a1c6dd927639f1a41fe5f9c53e24865e/node_modules/@wirecat/cli-core/dist/fetch/addresses.js
2302
+ // node_modules/.pnpm/@wirecat+cli-core@0.619.0_@wirecat+cli-base@0.91.0_commander@15.0.0_esbuild@0.28.2_type_25b690dd810be59ade44e4d26e61c9f5/node_modules/@wirecat/cli-core/dist/fetch/addresses.js
2053
2303
  import { isIP } from "node:net";
2054
2304
  var within3 = /* @__PURE__ */ __name((address, [prefix, bits]) => {
2055
2305
  for (let bit = 0; bit < bits; bit++) {
@@ -2100,9 +2350,9 @@ var v6Bytes = /* @__PURE__ */ __name((text3) => {
2100
2350
  const left = groups(head);
2101
2351
  const right = tail === void 0 ? [] : groups(tail);
2102
2352
  const all = [...left, ...new Array(8 - left.length - right.length).fill(0), ...right];
2103
- all.forEach((group, at) => {
2104
- bytes[at * 2] = group >> 8;
2105
- bytes[at * 2 + 1] = group & 255;
2353
+ all.forEach((group, at2) => {
2354
+ bytes[at2 * 2] = group >> 8;
2355
+ bytes[at2 * 2 + 1] = group & 255;
2106
2356
  });
2107
2357
  return bytes;
2108
2358
  }, "v6Bytes");
@@ -2114,13 +2364,13 @@ var isPublicAddress = /* @__PURE__ */ __name((address) => {
2114
2364
  if (family !== 6)
2115
2365
  return false;
2116
2366
  const bytes = v6Bytes(address);
2117
- for (const [prefix, at] of V6_CARRIERS)
2367
+ for (const [prefix, at2] of V6_CARRIERS)
2118
2368
  if (within3(bytes, prefix))
2119
- return publicV4(bytes.subarray(at, at + 4));
2369
+ return publicV4(bytes.subarray(at2, at2 + 4));
2120
2370
  return within3(bytes, [[32], 3]) && !V6_PRIVATE.some((prefix) => within3(bytes, prefix));
2121
2371
  }, "isPublicAddress");
2122
2372
 
2123
- // node_modules/.pnpm/@wirecat+cli-core@0.618.0_@wirecat+cli-base@0.91.0_commander@15.0.0_esbuild@0.28.2_type_a1c6dd927639f1a41fe5f9c53e24865e/node_modules/@wirecat/cli-core/dist/fetch/page.js
2373
+ // node_modules/.pnpm/@wirecat+cli-core@0.619.0_@wirecat+cli-base@0.91.0_commander@15.0.0_esbuild@0.28.2_type_25b690dd810be59ade44e4d26e61c9f5/node_modules/@wirecat/cli-core/dist/fetch/page.js
2124
2374
  import { lookup as dnsLookup } from "node:dns/promises";
2125
2375
  import { request as httpRequest } from "node:http";
2126
2376
  import { request as httpsRequest } from "node:https";
@@ -2209,14 +2459,14 @@ var readBody = /* @__PURE__ */ __name(async (response, limit) => {
2209
2459
  chunks.push(chunk);
2210
2460
  }
2211
2461
  const bytes = new Uint8Array(size);
2212
- let at = 0;
2462
+ let at2 = 0;
2213
2463
  for (const chunk of chunks) {
2214
- bytes.set(chunk, at);
2215
- at += chunk.byteLength;
2464
+ bytes.set(chunk, at2);
2465
+ at2 += chunk.byteLength;
2216
2466
  }
2217
2467
  return bytes;
2218
2468
  }, "readBody");
2219
- var needsSignIn = /* @__PURE__ */ __name((url) => new CliError("authentication_error", `${url.hostname} asks for a sign-in: read a private Google document through Drive`, {
2469
+ var needsSignIn = /* @__PURE__ */ __name((url) => new CliError("authentication_error", `${url.hostname} asks for a sign-in: add a private Google document through Drive, with drive documents add <url> --profiles <names|all>`, {
2220
2470
  reason: "source.needs-sign-in"
2221
2471
  }), "needsSignIn");
2222
2472
  var isSignInPage = /* @__PURE__ */ __name((bytes, contentType) => {
@@ -2395,11 +2645,11 @@ var notesNamed = /* @__PURE__ */ __name((source, target, documents) => {
2395
2645
  return documents.filter((doc) => [stem(posix.basename(doc.path)), ...doc.aliases].some((known2) => fold2(known2) === name2));
2396
2646
  }, "notesNamed");
2397
2647
  var fileLinks = /* @__PURE__ */ __name((source, links, documents) => links.map(({ target, anchor }) => {
2398
- const at = anchor === null ? {} : { anchor };
2648
+ const at2 = anchor === null ? {} : { anchor };
2399
2649
  if (isReference(target))
2400
- return { to: target, kind: "links-to", ...at };
2650
+ return { to: target, kind: "links-to", ...at2 };
2401
2651
  const named5 = notesNamed(source, target, documents);
2402
- return named5.length === 1 ? { to: `document:${named5[0].id}`, kind: "links-to", ...at } : { targetText: posix.basename(target.replace(/\\/g, "/")) || target, kind: "links-to", ...at };
2652
+ return named5.length === 1 ? { to: `document:${named5[0].id}`, kind: "links-to", ...at2 } : { targetText: posix.basename(target.replace(/\\/g, "/")) || target, kind: "links-to", ...at2 };
2403
2653
  }), "fileLinks");
2404
2654
 
2405
2655
  // dist/notes/renames.js
@@ -2654,12 +2904,12 @@ var importNotesMap = /* @__PURE__ */ __name(async (store, env, folders) => {
2654
2904
  done = JSON.parse(readFileSync3(donePath(env), "utf8"));
2655
2905
  } catch {
2656
2906
  }
2657
- const pending2 = Object.entries(map).filter(([uid]) => !done.includes(uid));
2658
- if (pending2.length === 0)
2907
+ const pending = Object.entries(map).filter(([uid]) => !done.includes(uid));
2908
+ if (pending.length === 0)
2659
2909
  return 0;
2660
2910
  const byFolder = /* @__PURE__ */ new Map();
2661
2911
  let linked2 = 0;
2662
- for (const [uid, file] of pending2) {
2912
+ for (const [uid, file] of pending) {
2663
2913
  let place;
2664
2914
  try {
2665
2915
  place = folderOfFile(folders, file);
@@ -2689,7 +2939,7 @@ var importNotesMap = /* @__PURE__ */ __name(async (store, env, folders) => {
2689
2939
  // dist/review/status.js
2690
2940
  var MOST_PAGES = 10;
2691
2941
  var counted2 = /* @__PURE__ */ __name(async (store, env, filter, since) => {
2692
- const registry = reviewRegistry(store);
2942
+ const registry = await reviewOf(store, env);
2693
2943
  const byKind = {};
2694
2944
  let total = 0;
2695
2945
  for (let page = 0; page < MOST_PAGES; page++) {
@@ -2705,7 +2955,7 @@ var counted2 = /* @__PURE__ */ __name(async (store, env, filter, since) => {
2705
2955
  }, "counted");
2706
2956
  var waitingAbout = /* @__PURE__ */ __name(async (store, env, refs) => {
2707
2957
  const wanted = new Set(refs);
2708
- const registry = reviewRegistry(store);
2958
+ const registry = await reviewOf(store, env);
2709
2959
  const kinds2 = {};
2710
2960
  let count = 0;
2711
2961
  for (let page = 0; page < MOST_PAGES; page++) {
@@ -2722,7 +2972,7 @@ var waitingAbout = /* @__PURE__ */ __name(async (store, env, refs) => {
2722
2972
  }, "waitingAbout");
2723
2973
  var reviewStatus = /* @__PURE__ */ __name(async (store, env, since, now = Date.now()) => {
2724
2974
  const mail = [];
2725
- for (const key of (await store.accounts.accounts()).filter((one2) => one2.provider === "email")) {
2975
+ for (const key of (await scopedAccounts(store, env)).filter((one2) => one2.provider === "email")) {
2726
2976
  const stored = await store.accounts.storedAccount(key);
2727
2977
  const turns = (await store.mail.threadActivity(stored.id, now - OWED_DAYS * 864e5)).map((thread) => ({
2728
2978
  at: thread.lastEmailAt,
@@ -2737,14 +2987,14 @@ var reviewStatus = /* @__PURE__ */ __name(async (store, env, since, now = Date.n
2737
2987
  });
2738
2988
  }
2739
2989
  const proposed = await counted2(store, env, { status: "all" }, since);
2740
- const pending2 = await counted2(store, env, { status: "proposed" });
2990
+ const pending = await counted2(store, env, { status: "proposed" });
2741
2991
  return {
2742
2992
  since: new Date(since).toISOString(),
2743
2993
  at: new Date(now).toISOString(),
2744
2994
  mail,
2745
2995
  proposed: { count: proposed.total, kinds: proposed.byKind, complete: proposed.complete },
2746
- waiting: { count: pending2.total, kinds: pending2.byKind, complete: pending2.complete },
2747
- quiet: proposed.total === 0 && pending2.total === 0 && mail.every((one2) => one2.threads === 0 && one2.owed === 0 && one2.waiting === 0)
2996
+ waiting: { count: pending.total, kinds: pending.byKind, complete: pending.complete },
2997
+ quiet: proposed.total === 0 && pending.total === 0 && mail.every((one2) => one2.threads === 0 && one2.owed === 0 && one2.waiting === 0)
2748
2998
  };
2749
2999
  }, "reviewStatus");
2750
3000
  var kindsText = /* @__PURE__ */ __name((kinds2) => Object.entries(kinds2).sort(([, a], [, b]) => b - a).map(([kind, count]) => `${kind} ${count}`).join(", "), "kindsText");
@@ -2762,6 +3012,10 @@ var reviewStatusText = /* @__PURE__ */ __name((status) => {
2762
3012
  ].join("\n");
2763
3013
  }, "reviewStatusText");
2764
3014
 
3015
+ // dist/search/denied.js
3016
+ var deniedCrm = /* @__PURE__ */ __name((command, env) => deniedKindsOf(memoLevels(env, environmentOf(command).agent?.overrides ?? []), DEAL_KINDS, "memo's permissions"), "deniedCrm");
3017
+ var deniedCrmKinds = /* @__PURE__ */ __name((command, env) => deniedCrm(command, env).map(({ kind }) => kind), "deniedCrmKinds");
3018
+
2765
3019
  // dist/people/owner.js
2766
3020
  var withOwner = /* @__PURE__ */ __name(async (store, reference2) => {
2767
3021
  if (reference2.trim() !== "person:me")
@@ -2779,7 +3033,6 @@ var UNTRUSTED_EVENT_FIELDS = [
2779
3033
  "events.recent.title",
2780
3034
  "events.recent.location"
2781
3035
  ];
2782
- var RELATIONS = /* @__PURE__ */ new Set(["member-of", "related-to"]);
2783
3036
  var SOURCE_REPORTS = /* @__PURE__ */ new Set(["google-drive:files.get"]);
2784
3037
  var reportedFiles = /* @__PURE__ */ __name(async (store, links, limit) => {
2785
3038
  const files = [];
@@ -2806,43 +3059,53 @@ var reportedFiles = /* @__PURE__ */ __name(async (store, links, limit) => {
2806
3059
  }
2807
3060
  return files;
2808
3061
  }, "reportedFiles");
2809
- var contextAccountOf = /* @__PURE__ */ __name(async (store, env, person, source) => {
2810
- const key = await oneAccountOf(store, env, source);
2811
- if (!person.startsWith("person:") && key.provider !== person.split(":")[0])
2812
- throw new CliError("validation_error", `${source} is not an account of ${person}'s messenger`);
2813
- return key;
2814
- }, "contextAccountOf");
2815
- var anchorOf = /* @__PURE__ */ __name(async (store, uid, source) => {
2816
- const person = await store.people.personByUid(uid);
2817
- if (person === void 0)
2818
- throw new CliError("not_found", `no person:${uid} in the store`);
2819
- const seen = person.identities.flatMap((identity) => identity.accounts.map((held) => ({
2820
- reference: `${identity.provider}:${identity.id}`,
2821
- provider: identity.provider,
2822
- account: held
2823
- })));
2824
- const matches2 = seen.filter((one2) => source === void 0 || one2.provider === source.provider && one2.account === source.account);
2825
- const accounts = [...new Set(matches2.map((one2) => `${one2.provider}:${one2.account}`))];
2826
- const [first] = matches2;
2827
- if (accounts.length === 1 && first)
2828
- return first;
2829
- throw new CliError(matches2.length === 0 ? "not_found" : "validation_error", matches2.length === 0 ? `no account in the store has seen person:${uid}` : `person:${uid} was seen by ${accounts.length} accounts; give one with --source: ${accounts.join(", ")}`);
2830
- }, "anchorOf");
2831
- var memoContext = /* @__PURE__ */ __name(async (store, reference2, { limit = 20, source } = {}) => {
3062
+ var contextAccountsOf = /* @__PURE__ */ __name(async (store, env, person, source) => {
3063
+ const provider = person.startsWith("person:") ? void 0 : person.split(":")[0];
3064
+ const keys = (await accountsOf(store, env, source)).filter((key) => provider === void 0 || key.provider === provider);
3065
+ if (keys.length === 0)
3066
+ throw new CliError("validation_error", `${source} is not an account of ${person}'s messenger`, { param: "source" });
3067
+ return keys;
3068
+ }, "contextAccountsOf");
3069
+ var accountIn = /* @__PURE__ */ __name((keys) => keys?.length === 1 ? { account: keys[0].account } : {}, "accountIn");
3070
+ var memoContext = /* @__PURE__ */ __name(async (store, env, reference2, { limit = 20, sources, deniedKinds = [] } = {}) => {
2832
3071
  const named5 = (await withOwner(store, reference2)).trim();
3072
+ const scope = await groupScopeOf(store, env);
2833
3073
  if (named5.startsWith("person:")) {
2834
- const anchor = await anchorOf(store, named5.slice("person:".length), source);
2835
- return memoContext(store, anchor.reference, { limit, source: anchor });
3074
+ const accounts2 = sources === void 0 ? scope?.accounts : [...sources];
3075
+ const { events: events2, business: business2, coverage, ...messages2 } = await canonicalPersonContext(store, named5, {
3076
+ messages: limit,
3077
+ limit,
3078
+ deniedKinds,
3079
+ ...accounts2 === void 0 ? {} : { accounts: accounts2 }
3080
+ });
3081
+ const same2 = /* @__PURE__ */ __name((one2) => (key) => key.provider === one2.provider && key.account === one2.account, "same");
3082
+ const read = accounts2 === void 0 ? await scopedAccounts(store, env) : (await store.accounts.accounts()).filter((one2) => accounts2.some(same2(one2)));
3083
+ const calendars2 = (await calendarAccounts(store)).filter((one2) => accounts2 === void 0 || accounts2.some(same2(one2)));
3084
+ return withNotesAndTasks(store, env, { messages: messages2, events: events2, business: business2, coverage }, { accounts: read, calendars: calendars2, deniedKinds, ...accounts2 === void 0 ? {} : { scope: accounts2 } }, limit);
2836
3085
  }
2837
3086
  const [, provider, who] = /^([a-z][a-z0-9-]*):(.+)$/.exec(reference2.trim()) ?? [];
2838
3087
  if (provider === void 0 || who === void 0)
2839
3088
  throw new CliError("validation_error", `"${reference2}" names no messenger \u2014 write it as <messenger>:<name or id>`, {
2840
3089
  reason: "identity.no-messenger"
2841
3090
  });
2842
- const accounts = await store.accounts.accounts();
2843
- const asked = await selectAccount(store, { provider, ...source === void 0 ? {} : { account: source.account } });
2844
- const { events, ...messages } = await personContext(store, asked, who, { messages: limit });
2845
- const calendars = await calendarAccounts(store);
3091
+ const accounts = await scopedAccounts(store, env);
3092
+ const own = sources?.filter((one2) => one2.provider === provider);
3093
+ const asked = own?.length === 1 ? own[0] : await selectAccount(store, env, { provider, ...accountIn(own) });
3094
+ const calendars = await inGroup(store, env, await calendarAccounts(store));
3095
+ const calendarIds = scope === void 0 ? void 0 : await Promise.all(calendars.map(async (key) => (await store.accounts.storedAccount(key)).id));
3096
+ const { events, ...messages } = await personContext(store, asked, who, {
3097
+ messages: limit,
3098
+ ...calendarIds === void 0 ? {} : { calendarIds }
3099
+ });
3100
+ const business = scope === void 0 && deniedKinds.length === 0 ? await personBusiness(store, messages.person.uid, { limit }) : (await canonicalPersonContext(store, `person:${messages.person.uid}`, {
3101
+ ...scope === void 0 ? {} : { accounts: scope.accounts },
3102
+ deniedKinds,
3103
+ limit,
3104
+ messages: 1
3105
+ })).business;
3106
+ return withNotesAndTasks(store, env, { messages, events, business }, { accounts, calendars, deniedKinds, ...scope === void 0 ? {} : { scope: scope.accounts } }, limit);
3107
+ }, "memoContext");
3108
+ var withNotesAndTasks = /* @__PURE__ */ __name(async (store, env, { messages, events, business, coverage }, { accounts, calendars, scope, deniedKinds = [] }, limit) => {
2846
3109
  const person = `person:${messages.person.uid}`;
2847
3110
  const linked2 = await notesAbout(store, { ref: person, person: messages.person }, limit);
2848
3111
  const yourNotes = [];
@@ -2861,25 +3124,32 @@ var memoContext = /* @__PURE__ */ __name(async (store, reference2, { limit = 20,
2861
3124
  source: "mail",
2862
3125
  reason: "no mail address linked to them \u2014 tg <profile> contacts link <person> email:<address>"
2863
3126
  });
2864
- if (calendars.length === 0)
3127
+ if (calendars.length === 0 && coverage === void 0)
2865
3128
  notRead.push({ source: "events", reason: "no calendar in the store \u2014 gcal <profile> sync" });
2866
3129
  const tasks = await personTasks(store, messages.person, accounts, limit);
2867
3130
  const incoming = await store.notes.links({ to: person });
2868
- const relationships = [...await store.notes.links({ from: person }), ...incoming].filter((link2) => RELATIONS.has(link2.kind) && link2.confirmed);
3131
+ const relationships = (await store.knowledge.listRelations({
3132
+ about: person,
3133
+ ...scope === void 0 ? {} : { accounts: scope },
3134
+ ...deniedKinds.length ? { deniedKinds: [...deniedKinds] } : {},
3135
+ limit: 500
3136
+ })).items.filter((one2) => isUsable(one2.standing));
2869
3137
  const files = await reportedFiles(store, incoming, limit);
2870
3138
  const { subject: _, name: __, ...notes2 } = linked2;
2871
3139
  return {
2872
3140
  messages,
2873
- events: { ...events, accounts: calendars.map(({ provider: provider2, account: account2 }) => `${provider2}:${account2}`) },
3141
+ events: { ...events, accounts: calendars.map(({ provider, account: account2 }) => `${provider}:${account2}`) },
2874
3142
  notes: { ...notes2, about: notes2.about.filter((note) => note.source === "file") },
2875
3143
  yourNotes,
2876
3144
  notRead,
2877
3145
  tasks,
2878
3146
  relationships,
3147
+ business,
3148
+ ...coverage === void 0 ? {} : { coverage },
2879
3149
  files,
2880
3150
  untrusted: UNTRUSTED_EVENT_FIELDS
2881
3151
  };
2882
- }, "memoContext");
3152
+ }, "withNotesAndTasks");
2883
3153
  var withOwnMailText = /* @__PURE__ */ __name((context) => {
2884
3154
  const own = /* @__PURE__ */ __name((message) => message?.provider === "email" ? { ...message, text: mailOwnText(message.text) } : message, "own");
2885
3155
  const { last, recent, mentions } = context.messages;
@@ -2900,7 +3170,18 @@ var one = /* @__PURE__ */ __name((message) => message === null ? "\u2014" : `${m
2900
3170
  var eventLine = /* @__PURE__ */ __name((event2) => ` ${(event2.allDay ? event2.startsAt?.slice(0, 10) : event2.startsAt?.slice(0, 16).replace("T", " ")) ?? "\u2014"} ${(event2.title ?? "untitled").replace(/\s+/g, " ").slice(0, MAX_TEXT2)}${event2.location ? ` ${event2.location}` : ""} ${event2.ref}`, "eventLine");
2901
3171
  var noteLine = /* @__PURE__ */ __name((note) => ` ${note.ref}${note.path ?? note.title ? ` ${note.path ?? note.title}` : ""}`, "noteLine");
2902
3172
  var fileLine = /* @__PURE__ */ __name((file) => ` ${file.ref} ${file.role ?? ""} ${file.title ?? ""} ${file.modifiedAt?.slice(0, 16).replace("T", " ") ?? ""} ${file.url ?? ""}`, "fileLine");
2903
- var contextText = /* @__PURE__ */ __name(({ messages, events, notes: notes2, notRead, tasks, yourNotes, files, proposals }) => {
3173
+ var businessLines = /* @__PURE__ */ __name((business) => {
3174
+ const lines2 = [
3175
+ ...sectionLines("Organizations", business.organizations),
3176
+ ...sectionLines("Reports to", business.reportsTo),
3177
+ ...sectionLines("Direct reports", business.directReports),
3178
+ ...sectionLines("Deals and leads", business.deals),
3179
+ ...sectionLines("Projects", business.projects),
3180
+ ...business.categories.length ? [`Categories ${business.categories.join(", ")}`] : []
3181
+ ];
3182
+ return lines2.length ? ["", "Business", ...lines2] : [];
3183
+ }, "businessLines");
3184
+ var contextText = /* @__PURE__ */ __name(({ messages, events, notes: notes2, notRead, tasks, yourNotes, files, proposals, business, coverage }) => {
2904
3185
  const { person, last, recent, shared } = messages;
2905
3186
  return [
2906
3187
  `${person.name ?? person.uid} person:${person.uid}`,
@@ -2916,6 +3197,7 @@ var contextText = /* @__PURE__ */ __name(({ messages, events, notes: notes2, not
2916
3197
  ...recent.groups.length === 0 ? [] : ["", "Recent, in groups", ...recent.groups.map((m) => ` ${one(m)}`)],
2917
3198
  ...events.upcoming.length === 0 ? [] : ["", "Upcoming events", ...events.upcoming.map(eventLine)],
2918
3199
  ...events.recent.length === 0 ? [] : ["", "Recent events", ...events.recent.map(eventLine)],
3200
+ ...businessLines(business),
2919
3201
  "",
2920
3202
  "",
2921
3203
  ...notes2.about.length === 0 ? ["Note about them none \u2014 memo notes links add <identity> <path>"] : ["Notes about them", ...notes2.about.map(noteLine)],
@@ -2925,6 +3207,8 @@ var contextText = /* @__PURE__ */ __name(({ messages, events, notes: notes2, not
2925
3207
  ...files.length === 0 ? [] : ["", "Files, as Google reports", ...files.map(fileLine)],
2926
3208
  ...messages.complete ? [] : ["", `Not read in full: ${messages.notRead.length} chats \u2014 messages sync <chat>`],
2927
3209
  ...notRead.map(({ source, reason }) => `Not read: ${source} \u2014 ${reason}`),
3210
+ ...(coverage?.notRead ?? []).map(({ source, reason }) => `Not read: ${source} \u2014 ${reason}`),
3211
+ ...coverage ? [`Read: ${coverage.accounts.join(", ") || "no account"}`] : [],
2928
3212
  ...tasks.items.length ? [
2929
3213
  "",
2930
3214
  "Open tasks",
@@ -2939,20 +3223,21 @@ var contextText = /* @__PURE__ */ __name(({ messages, events, notes: notes2, not
2939
3223
  }, "contextText");
2940
3224
  var contextCommand = /* @__PURE__ */ __name((program, streams, env) => {
2941
3225
  const { print } = answers(program, streams, env);
2942
- annotate(program.command("context"), { effects: LOCAL_READ }).description("messages, mail, notes and events about a person, each with a link to its source; `proposals` counts what waits for you about them, by kind (`complete: false` means at least), and `next` names the command that lists them").summary("messages, mail, notes and events about a person, each with a link to its source").argument("<person>", "<messenger>:<name or id>, e.g. telegram:Ana or email:ana@example.com, person:<id>, or person:me for you").option("--limit <n>", "most messages, notes and events of each kind", positive, 20).option("--json", "print JSON; --json=id,title keeps only those fields").option("--source <accounts>", "the account to read, as provider:account; required when the store holds several of that messenger").option("--trimmed", "each email's own text, without quoted earlier mail or the signature \u2014 for an agent's reads").action(async (person, options) => {
3226
+ annotate(program.command("context"), { effects: LOCAL_READ, output: { entity: "person_context_memo" } }).description("messages, mail, notes and events about a person, each with a link to its source, and `business`: their organizations, reporting lines, deals and projects, each relationship with its standing (`reported` is a CRM's word only). person:<id> reads every account; `coverage` names what was read and what was not. `proposals` counts what waits for you about them, by kind (`complete: false` means at least), and `next` names the command that lists them").summary("messages, mail, notes and events about a person, each with a link to its source").argument("<person>", "<messenger>:<name or id>, e.g. telegram:Ana or email:ana@example.com, person:<id>, or person:me for you").option("--limit <n>", "most messages, notes and events of each kind", positive, 20).option("--json", "print JSON; --json=id,title keeps only those fields").option("--source <accounts>", "the accounts to read: every one when left out, or the group's in a group run; for <messenger>:<name>, the one account of that messenger").option("--trimmed", "each email's own text, without quoted earlier mail or the signature \u2014 for an agent's reads").action(async (person, options, command) => {
2943
3227
  const answer = await withStore(env, async (store) => {
2944
3228
  await importNotesMap(store, env, await boundFolders(store, env, { strict: false }));
2945
- const source = options.source === void 0 ? void 0 : await contextAccountOf(store, env, person, options.source);
2946
- const found = await memoContext(store, person, {
3229
+ const sources = options.source === void 0 ? void 0 : await contextAccountsOf(store, env, person, options.source);
3230
+ const found = await memoContext(store, env, person, {
2947
3231
  limit: options.limit,
2948
- ...source === void 0 ? {} : { source }
3232
+ deniedKinds: deniedCrmKinds(command, env),
3233
+ ...sources === void 0 ? {} : { sources }
2949
3234
  });
2950
3235
  const { uid, identities } = found.messages.person;
2951
3236
  const refs = [`person:${uid}`, ...identities.map(({ provider, id }) => `${provider}:${id}`)];
2952
- return {
3237
+ return lockedCoverage(store, env, {
2953
3238
  ...options.trimmed ? withOwnMailText(found) : found,
2954
3239
  proposals: { ...await waitingAbout(store, env, refs), next: { command: "review list" } }
2955
- };
3240
+ });
2956
3241
  });
2957
3242
  print(options.json, itemAnswer(answer), contextText(answer));
2958
3243
  });
@@ -3878,7 +4163,7 @@ var search = [
3878
4163
  command: ["search", "all"],
3879
4164
  field: "summary",
3880
4165
  before: "search stored messages, notes, calendar events and selected meeting transcripts",
3881
- after: "messages, mail, notes and calendar events ranked together",
4166
+ after: "messages, mail, notes, events and deals ranked together",
3882
4167
  reason: "Memo searches imported accounts, mail and native notes without a live messenger; its scope, ranking and output controls are explicit provider differences."
3883
4168
  },
3884
4169
  {
@@ -4348,7 +4633,8 @@ var search = [
4348
4633
  ];
4349
4634
 
4350
4635
  // dist/contract-overrides/skill.js
4351
- var REASON2 = "Memo installs its own stored-data instructions through its environment, prints the packaged primary skill without filesystem effects, and takes --json on each skill command because it has no global one.";
4636
+ var REASON2 = "Memo installs its own stored-data instructions through its environment, prints the packaged skills (morning-digest with the owner's brief from the store after it), and takes --json on each skill command because it has no global one.";
4637
+ var SHOW_DESCRIPTION = "print SKILL.md \u2014 `memo skill install` puts it where Claude Code, Codex, Gemini CLI and OpenClaw look for it, and where Hermes does on request; --for prints the copy already there";
4352
4638
  var JSON_OPTION2 = { flags: "--json", description: "print JSON", takes_value: false, mandatory: false };
4353
4639
  var SHOW_FOR = {
4354
4640
  flags: "--for <agents>",
@@ -4368,15 +4654,9 @@ var INSTALL_FOR = {
4368
4654
  var skill = [
4369
4655
  {
4370
4656
  command: ["skill", "show"],
4371
- field: "effects",
4372
- before: {
4373
- remote: "none",
4374
- local: "read"
4375
- },
4376
- after: {
4377
- remote: "none",
4378
- local: "none"
4379
- },
4657
+ field: "description",
4658
+ before: SHOW_DESCRIPTION,
4659
+ after: `${SHOW_DESCRIPTION}; morning-digest ends with your brief from \`memo digest brief\` when you wrote one`,
4380
4660
  reason: REASON2
4381
4661
  },
4382
4662
  {
@@ -4434,12 +4714,122 @@ var skill = [
4434
4714
  var SHELL_OVERRIDES = { search, doctor, skill, mcp, commands, notes, meetings };
4435
4715
 
4436
4716
  // dist/digest/backfill.js
4437
- import { existsSync as existsSync6, readdirSync as readdirSync4 } from "node:fs";
4438
- import { join as join6 } from "node:path";
4717
+ import { existsSync as existsSync7, readdirSync as readdirSync4 } from "node:fs";
4718
+ import { join as join7 } from "node:path";
4719
+
4720
+ // dist/digest/brief.js
4721
+ import { spawnSync } from "node:child_process";
4722
+ import { existsSync as existsSync3, mkdtempSync, readFileSync as readFileSync4, rmSync as rmSync2, writeFileSync as writeFileSync3 } from "node:fs";
4723
+ import { tmpdir } from "node:os";
4724
+ import { join as join3 } from "node:path";
4725
+ var BRIEF = { key: "digest/brief", channel: "text", language: "any" };
4726
+ var BRIEF_LIMIT = 4e3;
4727
+ var readBrief = /* @__PURE__ */ __name(async (env) => {
4728
+ if (!existsSync3(storePath(env)))
4729
+ return void 0;
4730
+ return withStore(env, async (store) => store.templates.get(BRIEF)?.body);
4731
+ }, "readBrief");
4732
+ var withBrief = /* @__PURE__ */ __name((skill2, brief) => brief === void 0 ? skill2 : `${skill2}
4733
+
4734
+ ## The owner's brief
4735
+
4736
+ The owner wrote this himself: it adds to everything above, and where it contradicts a rule of this skill, the brief wins.
4737
+
4738
+ ${brief.trim()}`, "withBrief");
4739
+ var systemEditor = /* @__PURE__ */ __name((path, env) => {
4740
+ const editor = env.VISUAL?.trim() || env.EDITOR?.trim();
4741
+ if (!editor)
4742
+ throw new CliError("validation_error", "set VISUAL or EDITOR, or pass the brief with --file", {
4743
+ reason: "brief.no-editor"
4744
+ });
4745
+ const [program = editor, ...args] = editor.split(/\s+/);
4746
+ const ran = spawnSync(program, [...args, path], { stdio: "inherit", env });
4747
+ if (ran.status !== 0)
4748
+ throw new CliError("validation_error", `the editor exited with ${ran.status ?? ran.signal}; nothing was saved`);
4749
+ }, "systemEditor");
4750
+ var refuseAgent = /* @__PURE__ */ __name((env) => {
4751
+ if (authorOf(env) !== "owner")
4752
+ throw new CliError("permission_error", "only the owner changes the digest brief, not an agent", {
4753
+ reason: "brief.owner-only"
4754
+ });
4755
+ }, "refuseAgent");
4756
+ var historyOf = /* @__PURE__ */ __name((store) => store.templates.history(BRIEF).map((entry) => ({
4757
+ saved_at: new Date(entry.savedAt).toISOString(),
4758
+ saved_by: entry.savedBy,
4759
+ replaced_at: new Date(entry.replacedAt).toISOString(),
4760
+ chars: entry.body.length
4761
+ })), "historyOf");
4762
+ var briefCommand = /* @__PURE__ */ __name((digest, print, env, editor = systemEditor) => {
4763
+ const brief = annotate(new Command("brief"), { effects: LOCAL_READ }).summary("your own instructions on what the morning digest collects").description(`your own instructions on what the morning digest collects: projects, people, topics, what to skip, how many items. The morning-digest skill ends with them, and where they contradict its rules they win; the run stays read only, with memo as its only tool and the schedule's cost cap. At most ${BRIEF_LIMIT} characters`);
4764
+ digest.addCommand(brief);
4765
+ annotate(brief.command("show"), { effects: LOCAL_READ }).summary("the brief the morning digest follows, and the bodies your changes replaced").option("--json", "print JSON").action(async (given2) => {
4766
+ const item = existsSync3(storePath(env)) ? await withStore(env, async (store) => {
4767
+ const row = store.templates.get(BRIEF);
4768
+ return {
4769
+ body: row?.body ?? null,
4770
+ chars: row?.body.length ?? 0,
4771
+ limit: BRIEF_LIMIT,
4772
+ updated_at: row ? new Date(row.updatedAt).toISOString() : null,
4773
+ updated_by: row?.updatedBy ?? null,
4774
+ history: historyOf(store)
4775
+ };
4776
+ }) : { body: null, chars: 0, limit: BRIEF_LIMIT, updated_at: null, updated_by: null, history: [] };
4777
+ print(given2.json, itemAnswer(item), item.body ?? "No brief: the morning digest follows its skill alone. `memo digest brief edit` writes one.");
4778
+ });
4779
+ grantsAuthority(annotate(brief.command("edit"), { effects: LOCAL_WRITE })).summary("write the brief in $EDITOR or from --file; only you, never an agent").description(`write the brief in $EDITOR, or from --file; at most ${BRIEF_LIMIT} characters. The body it replaces is kept, and --undo puts it back. Only you change it, never an agent or a read-only run`).option("--file <file>", "take the brief from this file instead of opening an editor; - reads stdin").addOption(new Option("--undo", "put back the body your last change replaced").conflicts("file")).option("--json", "print JSON").action(async (given2) => {
4780
+ refuseAgent(env);
4781
+ const { current, previous } = await withStore(env, async (store) => ({
4782
+ current: store.templates.get(BRIEF)?.body,
4783
+ previous: store.templates.history(BRIEF, 1)[0]?.body
4784
+ }));
4785
+ let draft;
4786
+ let body;
4787
+ if (given2.undo) {
4788
+ if (previous === void 0)
4789
+ throw new CliError("validation_error", "the brief has no earlier body to put back", {
4790
+ reason: "brief.no-history"
4791
+ });
4792
+ body = previous;
4793
+ } else if (given2.file !== void 0) {
4794
+ body = readFileSync4(given2.file === "-" ? 0 : given2.file, "utf8");
4795
+ } else {
4796
+ draft = join3(mkdtempSync(join3(tmpdir(), "memo-brief-")), "brief.md");
4797
+ writeFileSync3(draft, current ?? "", { mode: 384 });
4798
+ editor(draft, env);
4799
+ body = readFileSync4(draft, "utf8");
4800
+ }
4801
+ const kept = draft ? `. Your text is in ${draft}; fix it and run again with --file ${draft}` : "";
4802
+ body = body.trim();
4803
+ if (!body)
4804
+ throw new CliError("validation_error", `the brief is empty; memo digest brief reset removes it${kept}`, {
4805
+ reason: "brief.empty"
4806
+ });
4807
+ if (body.length > BRIEF_LIMIT)
4808
+ throw new CliError("validation_error", `the brief is ${body.length} characters; the limit is ${BRIEF_LIMIT}, because every morning run reads it and pays for it. Nothing was saved${kept}`, { reason: "brief.too-long", chars: body.length, limit: BRIEF_LIMIT });
4809
+ if (draft)
4810
+ rmSync2(join3(draft, ".."), { recursive: true, force: true });
4811
+ if (body === current) {
4812
+ print(given2.json, itemAnswer({ changed: false, chars: body.length }), "The brief is unchanged; nothing saved.");
4813
+ return;
4814
+ }
4815
+ const saved = await withStore(env, async (store) => store.templates.save(BRIEF, body, "memo"));
4816
+ print(given2.json, itemAnswer({
4817
+ changed: true,
4818
+ chars: body.length,
4819
+ limit: BRIEF_LIMIT,
4820
+ updated_at: new Date(saved.updatedAt).toISOString()
4821
+ }), `Saved the brief (${body.length} of ${BRIEF_LIMIT} characters); the next morning digest follows it.`);
4822
+ });
4823
+ grantsAuthority(annotate(brief.command("reset"), { effects: LOCAL_WRITE })).summary("remove the brief; edit --undo brings it back").description("remove the brief, so the morning digest follows its skill alone; edit --undo brings it back").option("--json", "print JSON").action(async (given2) => {
4824
+ refuseAgent(env);
4825
+ const changed = await withStore(env, async (store) => store.templates.reset(BRIEF));
4826
+ print(given2.json, itemAnswer({ changed }), changed ? "Removed the brief; memo digest brief edit --undo brings it back." : "There was no brief.");
4827
+ });
4828
+ }, "briefCommand");
4439
4829
 
4440
4830
  // dist/digest/tasks.js
4441
- import { existsSync as existsSync5, readdirSync as readdirSync3 } from "node:fs";
4442
- import { join as join5 } from "node:path";
4831
+ import { existsSync as existsSync6, readdirSync as readdirSync3 } from "node:fs";
4832
+ import { join as join6 } from "node:path";
4443
4833
 
4444
4834
  // dist/tasks/list.js
4445
4835
  import { createHash as createHash2 } from "node:crypto";
@@ -4520,17 +4910,17 @@ var accountTasks = /* @__PURE__ */ __name(async (store, keys, options) => {
4520
4910
  });
4521
4911
  }, "accountTasks");
4522
4912
  var accountTerms = /* @__PURE__ */ __name((query) => {
4523
- const leaves2 = query ? walkQuery(query.root) : [];
4524
- const other = leaves2.find(({ field: field2 }) => !ACCOUNT_FIELDS.has(field2));
4913
+ const leaves3 = query ? walkQuery(query.root) : [];
4914
+ const other = leaves3.find(({ field: field2 }) => !ACCOUNT_FIELDS.has(field2));
4525
4915
  if (other)
4526
4916
  throw new CliError("validation_error", `${other.field}: narrows project tasks: add project:<key>, or project:* for every project`);
4527
- const states = new Set(leaves2.filter(({ field: field2 }) => field2 === "state").map(({ value }) => value.toLowerCase()));
4917
+ const states = new Set(leaves3.filter(({ field: field2 }) => field2 === "state").map(({ value }) => value.toLowerCase()));
4528
4918
  if ((states.has("todo") || states.has("in_progress")) && !states.has("open"))
4529
4919
  throw new CliError("validation_error", "todo and in_progress are steps of a project task: add project:");
4530
4920
  const closed = [...states].filter(isClosedState);
4531
4921
  if (closed.length > 1 || closed.length === 1 && states.size > 1)
4532
4922
  throw new CliError("validation_error", "an account's tasks are listed in one state: state:open, done or dismissed");
4533
- const sources = leaves2.filter(({ field: field2 }) => field2 === "source").map(({ value }) => value);
4923
+ const sources = leaves3.filter(({ field: field2 }) => field2 === "source").map(({ value }) => value);
4534
4924
  if (sources.length > 1)
4535
4925
  throw new CliError("validation_error", "source: only once here");
4536
4926
  return { state: closed[0] ?? "open", source: sources[0] };
@@ -4586,9 +4976,9 @@ var listTasks = /* @__PURE__ */ __name(async (store, words, options, accounts) =
4586
4976
  }
4587
4977
  const typed = typedQuery(words);
4588
4978
  const query = listQuery(typed, TASKS_LIST_QUERY, "tasks list", { defaultField: "text" });
4589
- const leaves2 = query ? walkQuery(query.root) : [];
4590
- if (leaves2.some(({ field: field2 }) => field2 === "project")) {
4591
- if (leaves2.some(({ field: field2 }) => field2 === "source"))
4979
+ const leaves3 = query ? walkQuery(query.root) : [];
4980
+ if (leaves3.some(({ field: field2 }) => field2 === "project")) {
4981
+ if (leaves3.some(({ field: field2 }) => field2 === "source"))
4592
4982
  throw new CliError("validation_error", "source: narrows an account's tasks, not a project's");
4593
4983
  return projectTasks(store, typed, await resolveProjects(store, query), options);
4594
4984
  }
@@ -4609,13 +4999,13 @@ var countTasks = /* @__PURE__ */ __name(async (store, words) => {
4609
4999
  }, "countTasks");
4610
5000
 
4611
5001
  // dist/digest/sync-health.js
4612
- import { existsSync as existsSync4, readdirSync as readdirSync2, readFileSync as readFileSync5 } from "node:fs";
4613
- import { join as join4 } from "node:path";
5002
+ import { existsSync as existsSync5, readdirSync as readdirSync2, readFileSync as readFileSync6 } from "node:fs";
5003
+ import { join as join5 } from "node:path";
4614
5004
 
4615
5005
  // dist/knowledge/messenger-sync.js
4616
5006
  import { spawn } from "node:child_process";
4617
- import { existsSync as existsSync3, readdirSync, readFileSync as readFileSync4, realpathSync, statSync as statSync2 } from "node:fs";
4618
- import { delimiter, join as join3 } from "node:path";
5007
+ import { existsSync as existsSync4, readdirSync, readFileSync as readFileSync5, realpathSync, statSync as statSync2 } from "node:fs";
5008
+ import { delimiter, join as join4 } from "node:path";
4619
5009
  var STATE = {
4620
5010
  tg: { appName: "tg-cli", envPrefix: "TG" },
4621
5011
  max: { appName: "max-cli", envPrefix: "MAX" },
@@ -4635,10 +5025,10 @@ var syncProfileOf = /* @__PURE__ */ __name((value, previous = {}) => {
4635
5025
  throw new InvalidArgumentError(`one profile per tool; ${tool} is already ${previous[tool]}`);
4636
5026
  return { ...previous, [tool]: profile };
4637
5027
  }, "syncProfileOf");
4638
- var accountsDir = /* @__PURE__ */ __name((tool, env) => join3(resolvePaths({ appName: tool.appName, prefix: tool.envPrefix, env }).state, "accounts"), "accountsDir");
5028
+ var accountsDir = /* @__PURE__ */ __name((tool, env) => join4(resolvePaths({ appName: tool.appName, prefix: tool.envPrefix, env }).state, "accounts"), "accountsDir");
4639
5029
  var signedInAccount = /* @__PURE__ */ __name((tool, profile, env) => {
4640
5030
  try {
4641
- return JSON.parse(readFileSync4(join3(accountsDir(tool, env), `${profile}.json`), "utf8"))?.account;
5031
+ return JSON.parse(readFileSync5(join4(accountsDir(tool, env), `${profile}.json`), "utf8"))?.account;
4642
5032
  } catch {
4643
5033
  return void 0;
4644
5034
  }
@@ -4648,7 +5038,7 @@ var profileFor = /* @__PURE__ */ __name((provider, account2, env, chosen = {}) =
4648
5038
  if (!tool)
4649
5039
  return void 0;
4650
5040
  const dir = accountsDir(tool, env);
4651
- const profiles = existsSync3(dir) ? readdirSync(dir).filter((name2) => name2.endsWith(".json")).map((name2) => name2.slice(0, -".json".length)).sort() : [];
5041
+ const profiles = existsSync4(dir) ? readdirSync(dir).filter((name2) => name2.endsWith(".json")).map((name2) => name2.slice(0, -".json".length)).sort() : [];
4652
5042
  const accountOf = /* @__PURE__ */ __name((profile) => signedInAccount(tool, profile, env), "accountOf");
4653
5043
  const all = profiles.join(", ") || "none";
4654
5044
  const pick = chosen[tool.tool];
@@ -4668,7 +5058,7 @@ var profileFor = /* @__PURE__ */ __name((provider, account2, env, chosen = {}) =
4668
5058
  };
4669
5059
  return { why: `no ${tool.tool} profile here is signed in to account ${account2}; profiles: ${all}`, profiles: [] };
4670
5060
  }, "profileFor");
4671
- var onPath = /* @__PURE__ */ __name((name2, env) => (env.PATH ?? "").split(delimiter).filter(Boolean).map((dir) => join3(dir, name2)).find((path) => {
5061
+ var onPath = /* @__PURE__ */ __name((name2, env) => (env.PATH ?? "").split(delimiter).filter(Boolean).map((dir) => join4(dir, name2)).find((path) => {
4672
5062
  try {
4673
5063
  return statSync2(path).isFile();
4674
5064
  } catch {
@@ -4678,13 +5068,13 @@ var onPath = /* @__PURE__ */ __name((name2, env) => (env.PATH ?? "").split(delim
4678
5068
  var runChild = /* @__PURE__ */ __name((command, args, { env, signal, onStderr }) => new Promise((resolve6, reject) => {
4679
5069
  const child = spawn(command, args, { env, stdio: ["ignore", "pipe", "pipe"] });
4680
5070
  let stdout = "";
4681
- let pending2 = "";
5071
+ let pending = "";
4682
5072
  child.stdout.setEncoding("utf8").on("data", (chunk) => {
4683
5073
  stdout += chunk;
4684
5074
  });
4685
5075
  child.stderr.setEncoding("utf8").on("data", (chunk) => {
4686
- const lines2 = (pending2 + chunk).split("\n");
4687
- pending2 = lines2.pop() ?? "";
5076
+ const lines2 = (pending + chunk).split("\n");
5077
+ pending = lines2.pop() ?? "";
4688
5078
  for (const line3 of lines2)
4689
5079
  if (line3)
4690
5080
  onStderr?.(line3);
@@ -4699,8 +5089,8 @@ var runChild = /* @__PURE__ */ __name((command, args, { env, signal, onStderr })
4699
5089
  child.on("close", (code) => {
4700
5090
  clearTimeout(hard);
4701
5091
  signal?.removeEventListener("abort", stop);
4702
- if (pending2)
4703
- onStderr?.(pending2);
5092
+ if (pending)
5093
+ onStderr?.(pending);
4704
5094
  resolve6({ code, stdout });
4705
5095
  });
4706
5096
  }), "runChild");
@@ -4724,7 +5114,7 @@ var binaryOf = /* @__PURE__ */ __name(async (provider, env, run) => {
4724
5114
  const real = realpathSync(short);
4725
5115
  if (real.includes(`/${mark}/`))
4726
5116
  return short;
4727
- return statSync2(real).size < 65536 && readFileSync4(real, "utf8").includes(mark) ? short : void 0;
5117
+ return statSync2(real).size < 65536 && readFileSync5(real, "utf8").includes(mark) ? short : void 0;
4728
5118
  }, "binaryOf");
4729
5119
  var answerOf = /* @__PURE__ */ __name((stdout) => {
4730
5120
  try {
@@ -4832,13 +5222,13 @@ var SOURCE_WORDS = {
4832
5222
  var toolOf = /* @__PURE__ */ __name((provider) => provider === "email" ? MAIL2 : messengerToolOf(provider), "toolOf");
4833
5223
  var stateDirs = /* @__PURE__ */ __name((tool, env) => resolvePaths({ appName: tool.appName, prefix: tool.envPrefix, env }), "stateDirs");
4834
5224
  var schedulesOf = /* @__PURE__ */ __name((state) => {
4835
- const dir = join4(state, "schedules");
4836
- if (!existsSync4(dir))
5225
+ const dir = join5(state, "schedules");
5226
+ if (!existsSync5(dir))
4837
5227
  return [];
4838
5228
  const last = new Map(scheduledRuns(state).map((one2) => [one2.job, one2.last]));
4839
5229
  return readdirSync2(dir).flatMap((name2) => {
4840
5230
  try {
4841
- const schedule = JSON.parse(readFileSync5(join4(dir, name2, "schedule.json"), "utf8"));
5231
+ const schedule = JSON.parse(readFileSync6(join5(dir, name2, "schedule.json"), "utf8"));
4842
5232
  return [
4843
5233
  {
4844
5234
  name: String(schedule.name),
@@ -4853,15 +5243,15 @@ var schedulesOf = /* @__PURE__ */ __name((state) => {
4853
5243
  }
4854
5244
  });
4855
5245
  }, "schedulesOf");
4856
- var signedIn = /* @__PURE__ */ __name((dir) => existsSync4(dir) ? readdirSync2(dir).filter((name2) => name2.endsWith(".json")).map((name2) => name2.slice(0, -".json".length)) : [], "signedIn");
5246
+ var signedIn = /* @__PURE__ */ __name((dir) => existsSync5(dir) ? readdirSync2(dir).filter((name2) => name2.endsWith(".json")).map((name2) => name2.slice(0, -".json".length)) : [], "signedIn");
4857
5247
  var profilesOf = /* @__PURE__ */ __name((provider, tool, env) => {
4858
5248
  if (provider !== "email")
4859
- return new Map(signedIn(join4(stateDirs(tool, env).state, "accounts")).map((profile) => [
5249
+ return new Map(signedIn(join5(stateDirs(tool, env).state, "accounts")).map((profile) => [
4860
5250
  profile,
4861
5251
  signedInAccount(tool, profile, env)
4862
5252
  ]));
4863
5253
  try {
4864
- const config = JSON.parse(readFileSync5(configFilePath(stateDirs(MAIL2, env).config), "utf8"));
5254
+ const config = JSON.parse(readFileSync6(configFilePath(stateDirs(MAIL2, env).config), "utf8"));
4865
5255
  return new Map(Object.entries(config?.profiles ?? {}).map(([profile, one2]) => [
4866
5256
  profile,
4867
5257
  one2?.address
@@ -4910,7 +5300,7 @@ var QUIET_AFTER = 3 * DAY3;
4910
5300
  var QUIET_GAPS = 3;
4911
5301
  var hours = /* @__PURE__ */ __name((from, now) => Math.max(0, Math.floor((now - from) / HOUR)), "hours");
4912
5302
  var healthOf = /* @__PURE__ */ __name((sync, activity, now) => {
4913
- const recent = /* @__PURE__ */ __name((at) => at !== null && at >= now - DAY3, "recent");
5303
+ const recent = /* @__PURE__ */ __name((at2) => at2 !== null && at2 >= now - DAY3, "recent");
4914
5304
  if (recent(activity.storedAt) || sync.runs.some((run) => run.exitCode === 0 && recent(Date.parse(run.at))))
4915
5305
  return void 0;
4916
5306
  if (!sync.serving && sync.runs.length > 0 && sync.runs.every((run) => run.exitCode !== 0)) {
@@ -4951,12 +5341,12 @@ var runTime = /* @__PURE__ */ __name((file) => {
4951
5341
  }, "runTime");
4952
5342
  var digestReportTimes = /* @__PURE__ */ __name((env) => {
4953
5343
  const { state, schedule } = digestSchedule(env);
4954
- const runs = schedule ? join5(state, "schedules", schedule.name, "runs") : void 0;
4955
- if (!runs || !existsSync5(runs))
5344
+ const runs = schedule ? join6(state, "schedules", schedule.name, "runs") : void 0;
5345
+ if (!runs || !existsSync6(runs))
4956
5346
  return [];
4957
- return readdirSync3(runs).filter((file) => file.endsWith(".report.json")).map(runTime).filter((at) => !Number.isNaN(at)).sort((a, b) => a - b);
5347
+ return readdirSync3(runs).filter((file) => file.endsWith(".report.json")).map(runTime).filter((at2) => !Number.isNaN(at2)).sort((a, b) => a - b);
4958
5348
  }, "digestReportTimes");
4959
- var digestRunBefore = /* @__PURE__ */ __name((env, until) => new Date(digestReportTimes(env).findLast((at) => at < until) ?? until - DAY4).toISOString(), "digestRunBefore");
5349
+ var digestRunBefore = /* @__PURE__ */ __name((env, until) => new Date(digestReportTimes(env).findLast((at2) => at2 < until) ?? until - DAY4).toISOString(), "digestRunBefore");
4960
5350
  var previousDigestAt = /* @__PURE__ */ __name((env, now) => {
4961
5351
  const last = digestSchedule(env).schedule?.last;
4962
5352
  if (!last)
@@ -5053,8 +5443,8 @@ var gatherTasks = /* @__PURE__ */ __name(async (store, keys, { now, newSince, un
5053
5443
  // dist/digest/backfill.js
5054
5444
  var DAY5 = 864e5;
5055
5445
  var DATE = /^(\d{4})-(\d{2})-(\d{2})$/;
5056
- var localDate = /* @__PURE__ */ __name((at) => {
5057
- const day2 = new Date(at);
5446
+ var localDate = /* @__PURE__ */ __name((at2) => {
5447
+ const day2 = new Date(at2);
5058
5448
  return `${day2.getFullYear()}-${String(day2.getMonth() + 1).padStart(2, "0")}-${String(day2.getDate()).padStart(2, "0")}`;
5059
5449
  }, "localDate");
5060
5450
  var dateOf = /* @__PURE__ */ __name((value, flag) => {
@@ -5074,14 +5464,15 @@ var daysOf = /* @__PURE__ */ __name((from, to, time) => {
5074
5464
  });
5075
5465
  return days2;
5076
5466
  }, "daysOf");
5077
- var inputOf = /* @__PURE__ */ __name((date, at) => `backfill: ${date}
5078
- window: --since-time ${new Date(at - DAY5).toISOString()} --before-time ${new Date(at).toISOString()}
5467
+ var inputOf = /* @__PURE__ */ __name((date, at2) => `backfill: ${date}
5468
+ window: --since-time ${new Date(at2 - DAY5).toISOString()} --before-time ${new Date(at2).toISOString()}
5079
5469
  `, "inputOf");
5080
5470
  var usd = /* @__PURE__ */ __name((value) => `$${value.toFixed(2)}`, "usd");
5081
5471
  var cents = /* @__PURE__ */ __name((value) => Math.round(value * 100) / 100, "cents");
5082
5472
  var digestCommand = /* @__PURE__ */ __name((program, streams, env) => {
5083
5473
  const { print } = answers(program, streams, env);
5084
- const digest = program.command("digest").description("the morning digest's history: build the digests of past days").summary("the morning digest's history");
5474
+ const digest = program.command("digest").description("the morning digest: your brief on what it collects, and the digests of past days").summary("the morning digest: your brief, past days");
5475
+ briefCommand(digest, print, env);
5085
5476
  fromAppOption(annotate(digest.command("backfill"), { effects: LOCAL_WRITE })).summary("build the morning digests of past days, without sending them").description("build the morning digest each past day would have had: the morning-digest schedule's agent runs as its timer does (the same skill, flags and cost caps), reading the agenda as of that day's run time, and the result is kept as that day's run, marked backfill, for WireCat Desktop's digests screen. It is never sent to Telegram or mail. A day that already has a digest is skipped. Without --yes it only prints what it would build and the estimate: the days times the last digest run's cost. Each day is a paid model call: it stops once today's runs cost the schedule's daily cap or a day fails, and only you run it, never an agent. The store keeps what holds now, so a chat answered since reads as answered").requiredOption("--from <date>", "the first day, YYYY-MM-DD").requiredOption("--to <date>", "the last day, YYYY-MM-DD; not a day whose run time is still ahead").option("--yes", "build them; without it, only the estimate is printed").option("--json", "print JSON").action(async (given2, command) => {
5086
5477
  const from = dateOf(given2.from, "--from");
5087
5478
  const to = dateOf(given2.to, "--to");
@@ -5102,8 +5493,8 @@ var digestCommand = /* @__PURE__ */ __name((program, streams, env) => {
5102
5493
  throw new CliError("validation_error", `the ${given2.to} digest's time has not come yet; --to an earlier day`, {
5103
5494
  param: "--to"
5104
5495
  });
5105
- const runs = join6(file, "..", "runs");
5106
- const done = new Set((existsSync6(runs) ? readdirSync4(runs) : []).filter((name2) => name2.endsWith(".report.json")).map((name2) => localDate(runTime(name2))));
5496
+ const runs = join7(file, "..", "runs");
5497
+ const done = new Set((existsSync7(runs) ? readdirSync4(runs) : []).filter((name2) => name2.endsWith(".report.json")).map((name2) => localDate(runTime(name2))));
5107
5498
  const days2 = all.filter((day2) => !done.has(day2.date));
5108
5499
  const skipped = all.filter((day2) => done.has(day2.date)).map((day2) => day2.date);
5109
5500
  const lastCost = schedule.last?.costUsd;
@@ -5208,6 +5599,7 @@ var SECTIONS = [
5208
5599
  ["deals", "organise"],
5209
5600
  ["leads", "organise"],
5210
5601
  ["pipelines", "organise"],
5602
+ ["stages", "organise"],
5211
5603
  ["payments", "organise"],
5212
5604
  ["products", "organise"],
5213
5605
  ["contracts", "organise"],
@@ -5224,6 +5616,7 @@ var SECTIONS = [
5224
5616
  ["jobs", "automate"],
5225
5617
  ["digest", "automate"],
5226
5618
  ["folders", "setup"],
5619
+ ["groups", "setup"],
5227
5620
  ["config", "setup"]
5228
5621
  ];
5229
5622
  var placeInSections = /* @__PURE__ */ __name((program) => {
@@ -5248,9 +5641,9 @@ var commandsCommand = /* @__PURE__ */ __name((program, streams) => {
5248
5641
  }, "commandsCommand");
5249
5642
 
5250
5643
  // dist/doctor/command.js
5251
- import { existsSync as existsSync7, readdirSync as readdirSync5, readFileSync as readFileSync6 } from "node:fs";
5644
+ import { existsSync as existsSync8, readdirSync as readdirSync5, readFileSync as readFileSync7 } from "node:fs";
5252
5645
  import { homedir } from "node:os";
5253
- import { dirname, join as join7 } from "node:path";
5646
+ import { dirname, join as join8 } from "node:path";
5254
5647
  var retiredMailAddresses = /* @__PURE__ */ __name((mail) => {
5255
5648
  const accounts = mail?.accounts;
5256
5649
  if (!Array.isArray(accounts))
@@ -5276,7 +5669,7 @@ var diagnose = /* @__PURE__ */ __name(async (env, program, { deep = false } = {}
5276
5669
  problems.push({ what: "the store is from a newer version than this memo", fix: "memo upgrade" });
5277
5670
  const folders = noteFolders(config.notes).map(({ path, id }) => ({
5278
5671
  path,
5279
- exists: existsSync7(path),
5672
+ exists: existsSync8(path),
5280
5673
  bound: id !== null
5281
5674
  }));
5282
5675
  for (const folder of folders) {
@@ -5307,13 +5700,13 @@ var diagnose = /* @__PURE__ */ __name(async (env, program, { deep = false } = {}
5307
5700
  fix: `fix text_models in ${textModelsFile(env)}, or remove it to go back to ${DEFAULT_TEXT_MODEL}`
5308
5701
  });
5309
5702
  }
5310
- const modelDir = join7(sharedModelsDirectory("text", env), textModel);
5311
- const model = existsSync7(modelDir) && readdirSync5(modelDir).length > 0;
5703
+ const modelDir = join8(sharedModelsDirectory("text", env), textModel);
5704
+ const model = existsSync8(modelDir) && readdirSync5(modelDir).length > 0;
5312
5705
  const state = autoState(config);
5313
- const unitFile = join7(env.XDG_CONFIG_HOME ?? join7(env.HOME ?? homedir(), ".config"), "systemd", "user", "memo-import.service");
5314
- const unit = existsSync7(unitFile) ? readFileSync6(unitFile, "utf8") : void 0;
5706
+ const unitFile = join8(env.XDG_CONFIG_HOME ?? join8(env.HOME ?? homedir(), ".config"), "systemd", "user", "memo-import.service");
5707
+ const unit = existsSync8(unitFile) ? readFileSync7(unitFile, "utf8") : void 0;
5315
5708
  const runs = unit ? unitPaths(unit) : [];
5316
- const missing = runs.filter((path) => !existsSync7(path));
5709
+ const missing = runs.filter((path) => !existsSync8(path));
5317
5710
  const last = lastAutoRun(env);
5318
5711
  const failing = last && last.exitCode !== 0 ? { since: last.failingSince ?? last.at, runs: last.failures ?? 1, reason: last.reason ?? null } : null;
5319
5712
  if (state.enabled && !unit)
@@ -5324,7 +5717,7 @@ var diagnose = /* @__PURE__ */ __name(async (env, program, { deep = false } = {}
5324
5717
  problems.push({ what: `the timer has failed ${failing.runs} runs since ${failing.since}`, fix: "memo jobs status" });
5325
5718
  const skills = SKILL_TARGETS.map((target) => {
5326
5719
  const path = skillPath(target, APP.appName, env);
5327
- const version = existsSync7(path) ? skillVersion(readFileSync6(path, "utf8")) ?? "unknown" : null;
5720
+ const version = existsSync8(path) ? skillVersion(readFileSync7(path, "utf8")) ?? "unknown" : null;
5328
5721
  return { target, path, version };
5329
5722
  });
5330
5723
  if (skills.some(({ version }) => version !== null && version !== VERSION))
@@ -5345,7 +5738,7 @@ var diagnose = /* @__PURE__ */ __name(async (env, program, { deep = false } = {}
5345
5738
  };
5346
5739
  }, "diagnose");
5347
5740
  var yes = /* @__PURE__ */ __name((value) => value ? "yes" : "no", "yes");
5348
- var fileLines = /* @__PURE__ */ __name((d, fixes) => d.files.checked ? d.files.problems.map(({ path, mode, want }, at) => `! ${path} is ${mode}, so others can read it; it should be ${want} \u2014 ${fixes[at]}`) : [], "fileLines");
5741
+ var fileLines = /* @__PURE__ */ __name((d, fixes) => d.files.checked ? d.files.problems.map(({ path, mode, want }, at2) => `! ${path} is ${mode}, so others can read it; it should be ${want} \u2014 ${fixes[at2]}`) : [], "fileLines");
5349
5742
  var onlineLine = /* @__PURE__ */ __name(({ version }) => version.latest === null ? "online npm could not be reached" : version.newer ? `online memo ${version.latest} is published (this is ${version.current}) \u2014 memo upgrade` : `online memo ${version.current} is the newest published`, "onlineLine");
5350
5743
  var doctorText = /* @__PURE__ */ __name((d, fixes = [], online) => [
5351
5744
  `memo ${d.memo.version} on Node ${d.memo.node}, installed by ${d.memo.installed_by}`,
@@ -5403,7 +5796,7 @@ var doctorCommand = /* @__PURE__ */ __name((...args) => {
5403
5796
  }, SHELL_OVERRIDES.doctor);
5404
5797
  }, "doctorCommand");
5405
5798
 
5406
- // node_modules/.pnpm/@wirecat+cli-core@0.618.0_@wirecat+cli-base@0.91.0_commander@15.0.0_esbuild@0.28.2_type_a1c6dd927639f1a41fe5f9c53e24865e/node_modules/@wirecat/cli-core/dist/calendar/sync.js
5799
+ // node_modules/.pnpm/@wirecat+cli-core@0.619.0_@wirecat+cli-base@0.91.0_commander@15.0.0_esbuild@0.28.2_type_25b690dd810be59ade44e4d26e61c9f5/node_modules/@wirecat/cli-core/dist/calendar/sync.js
5407
5800
  var DAY6 = 864e5;
5408
5801
  var SLOTS_EVERY = 7 * DAY6;
5409
5802
  var isWindow = /* @__PURE__ */ __name((value) => typeof value?.from === "number" && typeof value.to === "number", "isWindow");
@@ -5483,10 +5876,10 @@ var calendarStatus = /* @__PURE__ */ __name(async (store, accountId, { profile,
5483
5876
  return { items, page: 1, limit: Math.max(1, items.length), hasMore: false };
5484
5877
  }, "calendarStatus");
5485
5878
 
5486
- // node_modules/.pnpm/@wirecat+cli-core@0.618.0_@wirecat+cli-base@0.91.0_commander@15.0.0_esbuild@0.28.2_type_a1c6dd927639f1a41fe5f9c53e24865e/node_modules/@wirecat/cli-core/dist/calendar/feeds.js
5879
+ // node_modules/.pnpm/@wirecat+cli-core@0.619.0_@wirecat+cli-base@0.91.0_commander@15.0.0_esbuild@0.28.2_type_25b690dd810be59ade44e4d26e61c9f5/node_modules/@wirecat/cli-core/dist/calendar/feeds.js
5487
5880
  var FEED_LIMITS = { maxBytes: 10 * 1024 * 1024, timeoutMs: 3e4, redirects: 5 };
5488
5881
 
5489
- // node_modules/.pnpm/@wirecat+cli-core@0.618.0_@wirecat+cli-base@0.91.0_commander@15.0.0_esbuild@0.28.2_type_a1c6dd927639f1a41fe5f9c53e24865e/node_modules/@wirecat/cli-core/dist/calendar/reads.js
5882
+ // node_modules/.pnpm/@wirecat+cli-core@0.619.0_@wirecat+cli-base@0.91.0_commander@15.0.0_esbuild@0.28.2_type_25b690dd810be59ade44e4d26e61c9f5/node_modules/@wirecat/cli-core/dist/calendar/reads.js
5490
5883
  var LIST = "events list";
5491
5884
  var EVENT_TYPES = [
5492
5885
  "default",
@@ -5563,7 +5956,7 @@ var accountsMeta = /* @__PURE__ */ __name(async (store, accounts, skipped, now)
5563
5956
  };
5564
5957
  }, "accountsMeta");
5565
5958
 
5566
- // node_modules/.pnpm/@wirecat+cli-core@0.618.0_@wirecat+cli-base@0.91.0_commander@15.0.0_esbuild@0.28.2_type_a1c6dd927639f1a41fe5f9c53e24865e/node_modules/@wirecat/cli-core/dist/calendar/writer.js
5959
+ // node_modules/.pnpm/@wirecat+cli-core@0.619.0_@wirecat+cli-base@0.91.0_commander@15.0.0_esbuild@0.28.2_type_25b690dd810be59ade44e4d26e61c9f5/node_modules/@wirecat/cli-core/dist/calendar/writer.js
5567
5960
  var EVENTS_NOTIFY_KEY = "events.notify";
5568
5961
  var EVENTS_DELETE_SERIES_KEY = "events.delete.series";
5569
5962
  var EVENTS_REMIND_HOOK_KEY = "events.remind.hook";
@@ -5644,7 +6037,7 @@ var calendarOf = /* @__PURE__ */ __name((accounts, value) => {
5644
6037
  throw new CliError("not_found", `calendar:${value} names no calendar in the accounts read`);
5645
6038
  throw new CliError("validation_error", `calendar:${value} names ${found.length} calendars; give one by its id: ` + found.map(({ account: account2, calendar }) => `calendar:${calendar.id} (${accountName(account2.key)})`).join(", "));
5646
6039
  }, "calendarOf");
5647
- var localDate2 = /* @__PURE__ */ __name((at, zone) => new Intl.DateTimeFormat("en-CA", { timeZone: zone, year: "numeric", month: "2-digit", day: "2-digit" }).format(at), "localDate");
6040
+ var localDate2 = /* @__PURE__ */ __name((at2, zone) => new Intl.DateTimeFormat("en-CA", { timeZone: zone, year: "numeric", month: "2-digit", day: "2-digit" }).format(at2), "localDate");
5648
6041
  var plusDays = /* @__PURE__ */ __name((date, days2) => {
5649
6042
  const [year, month, day2] = date.split("-").map(Number);
5650
6043
  return new Date(Date.UTC(year, month - 1, day2 + days2)).toISOString().slice(0, 10);
@@ -5778,7 +6171,11 @@ ${plainText(body, command)}`);
5778
6171
 
5779
6172
  // dist/examples.js
5780
6173
  var EXAMPLES = {
5781
- context: ["memo context telegram:'Kai Sample'", "memo context email:kai@example.com --limit 5 --json"],
6174
+ context: [
6175
+ "memo context telegram:'Kai Sample'",
6176
+ "memo context person:7 --json",
6177
+ "memo context email:kai@example.com --limit 5 --json"
6178
+ ],
5782
6179
  show: [
5783
6180
  "memo show chat:max/500/-1001 document:413",
5784
6181
  "memo show note:12 msg:telegram/1/77/42 --json",
@@ -5809,6 +6206,10 @@ var EXAMPLES = {
5809
6206
  "folders update": ["memo folders update 1 ~/notes"],
5810
6207
  "folders remove": ["memo folders remove 1", "memo folders remove 1 --allow-delete --yes"],
5811
6208
  "folders list": ["memo folders list --json"],
6209
+ "groups list": ["memo groups list", "memo groups list --json"],
6210
+ "groups add": ["memo groups add work bitrix24:acme", "memo groups add personal telegram:102"],
6211
+ "groups remove": ["memo groups remove work telegram:102"],
6212
+ "groups move": ["memo groups move telegram:102 personal work"],
5812
6213
  "config show": ["memo config show", "memo config show --json"],
5813
6214
  "config migrate": ["memo config migrate"],
5814
6215
  "config unset": ["memo config unset permissions.notes.edit"],
@@ -5868,7 +6269,7 @@ var EXAMPLES = {
5868
6269
  ],
5869
6270
  "models list": ["memo models list kind:text --json"],
5870
6271
  "commands info": ["memo commands info --json"],
5871
- "models download": ["memo models download e5-small", "memo models download e5-large"],
6272
+ "models download": ["memo models download embeddinggemma", "memo models download e5-small"],
5872
6273
  "models set": ["memo models set e5-large"],
5873
6274
  "models consents show": ["memo models consents show --json"],
5874
6275
  "models consents set": [
@@ -5876,6 +6277,8 @@ var EXAMPLES = {
5876
6277
  "memo models consents set openai --model gpt-4o-mini --yes"
5877
6278
  ],
5878
6279
  "models consents revoke": ["memo models consents revoke"],
6280
+ "models keys set": ["memo models keys set openai", "memo models keys set anthropic"],
6281
+ "models keys remove": ["memo models keys remove openai"],
5879
6282
  "models add": [
5880
6283
  `memo models add e5-base --payload '{"repository":"Xenova/multilingual-e5-base","onnx":"onnx/model_quantized.onnx","dims":768,"pooling":"mean","prefix":{"query":"query: ","passage":"passage: "}}'`
5881
6284
  ],
@@ -5932,8 +6335,12 @@ var EXAMPLES = {
5932
6335
  "memo organizations rename 1 'Harbour Studio Ltd' --json"
5933
6336
  ],
5934
6337
  "organizations show": ["memo organizations show organization:1"],
5935
- "organizations list": ["memo organizations list name:*harbour*", "memo organizations list --json"],
5936
- "organizations context": ["memo organizations context organization:1"],
6338
+ "organizations list": [
6339
+ "memo organizations list name:*harbour*",
6340
+ "memo organizations list category:client",
6341
+ "memo organizations list --json"
6342
+ ],
6343
+ "organizations context": ["memo organizations context organization:1", "memo organizations context 1 --json"],
5937
6344
  "projects meetings list": ["memo projects meetings list HRB --source zoom:me@example.com"],
5938
6345
  "projects meetings link": ["memo projects meetings link HRB 31 --account zoom:me@example.com"],
5939
6346
  "projects add": ["memo projects add 'Harbour' --key HRB --type client --organization 1"],
@@ -5957,12 +6364,20 @@ var EXAMPLES = {
5957
6364
  "memo relationships update 12 --role approver --role-note 'signs the acts'"
5958
6365
  ],
5959
6366
  "relationships add": [
5960
- "memo relationships add person:3 organization:1 --role employee",
5961
- "memo relationships add person:3 project:1 --role client-contact --engagement low",
5962
- "memo relationships add project:2 organization:1 --kind related-to --reason 'same client'"
6367
+ "memo relationships add person:3 organization:1 --role employee --position CTO --start-date 2026-01-01",
6368
+ "memo relationships add person:3 person:5 --kind reports-to",
6369
+ "memo relationships add organization:1 organization:2 --kind customer-of --reason 'signed in October'"
6370
+ ],
6371
+ "relationships list": [
6372
+ 'memo relationships list about:"person:3"',
6373
+ 'memo relationships list kind:reports-to to:"person:5"',
6374
+ "memo relationships list standing:reported include:ended --limit 50"
5963
6375
  ],
5964
- "relationships list": ['memo relationships list about:"person:3"', "memo relationships list confirmed:false"],
5965
6376
  "relationships remove": ["memo relationships remove 4"],
6377
+ "relationships roles list": ["memo relationships roles list", "memo relationships roles list list:deal --json"],
6378
+ "relationships roles add": ["memo relationships roles add organization board-member --label 'Board member'"],
6379
+ "relationships roles remove": ["memo relationships roles remove organization board-member"],
6380
+ "relationships end": ["memo relationships end 4 --end-date 2026-09-30"],
5966
6381
  "relationships confirm": ["memo relationships confirm 4"],
5967
6382
  "relationships scan": [
5968
6383
  "memo relationships scan HRB --source all",
@@ -6012,16 +6427,28 @@ var EXAMPLES = {
6012
6427
  ],
6013
6428
  "deals list": ["memo deals list status:open project:HRB", "memo deals list stage:Quote --json"],
6014
6429
  "deals show": ["memo deals show deal:5"],
6430
+ "deals context": ["memo deals context deal:5", "memo deals context deal:5 --brief --json"],
6431
+ "deals update": ["memo deals update deal:5 --project HRB"],
6015
6432
  "deals add": [
6016
6433
  "memo deals add 'Site for the clinic' Call 500000.00 RUB --organization organization:3 --project HRB",
6017
6434
  "memo deals add 'Support contract' Sales/Quote --person person:7 --role decision-maker --due 2026-12-01"
6018
6435
  ],
6019
- "deals move": ["memo deals move deal:5 Quote"],
6436
+ "deals move": ["memo deals move deal:5 Quote", "memo deals move deal:5 stage:5"],
6020
6437
  "deals close": ["memo deals close deal:5 won", "memo deals close deal:6 lost --reason 'chose a cheaper studio'"],
6021
6438
  "leads list": ["memo leads list status:open"],
6022
6439
  "leads show": ["memo leads show lead:3"],
6440
+ "leads context": ["memo leads context lead:3 --brief"],
6441
+ "leads update": ["memo leads update lead:3 --project HRB"],
6023
6442
  "leads add": ["memo leads add 'Call from the site'", "memo leads add 'Clinic in Kazan' contacted --person person:9"],
6024
- "leads move": ["memo leads move lead:3 qualified"],
6443
+ "leads move": ["memo leads move lead:3 qualified", "memo leads move lead:3 stage:5"],
6444
+ "stages show": ["memo stages show deal", "memo stages show lead --json"],
6445
+ "stages create": ["memo stages create deal Demo", "memo stages create lead Spam lost"],
6446
+ "stages rename": ["memo stages rename deal Proposal 'Quote sent'"],
6447
+ "stages move": ["memo stages move deal Negotiation 2"],
6448
+ "stages remove": ["memo stages remove deal Negotiation"],
6449
+ "stages list": ["memo stages list confirmed:false", "memo stages list kind:deal pipeline:pipeline:3 --json"],
6450
+ "stages set": ["memo stages set stage:41 Proposal"],
6451
+ "stages confirm": ["memo stages confirm --pipeline pipeline:3", "memo stages confirm --all"],
6025
6452
  "leads close": ["memo leads close lead:3 lost --reason 'no budget'"],
6026
6453
  "orders add": [
6027
6454
  "memo orders add 'Shop One' 2499.00 RUB --kind personal --title A-1042",
@@ -6194,6 +6621,13 @@ var EXAMPLES = {
6194
6621
  "memo digest backfill --from 2026-11-01 --to 2026-11-07",
6195
6622
  "memo digest backfill --from 2026-11-01 --to 2026-11-07 --yes --json"
6196
6623
  ],
6624
+ "digest brief show": ["memo digest brief show", "memo digest brief show --json"],
6625
+ "digest brief edit": [
6626
+ "memo digest brief edit",
6627
+ "memo digest brief edit --file brief.md",
6628
+ "memo digest brief edit --undo"
6629
+ ],
6630
+ "digest brief reset": ["memo digest brief reset"],
6197
6631
  "schedule remove": ["memo schedule remove digest"],
6198
6632
  "schedule exec": ["memo schedule exec ~/.local/state/cli-memo/schedules/digest/schedule.json"],
6199
6633
  "templates list": ["memo templates list", "memo templates list channel:telegram source:stored --json"],
@@ -6251,8 +6685,8 @@ var EXAMPLES = {
6251
6685
  help: ["memo help options", "memo help tasks agenda"]
6252
6686
  };
6253
6687
  var leaves = /* @__PURE__ */ __name((command, path = []) => command.commands.flatMap((child) => {
6254
- const at = [...path, child.name()];
6255
- return child.commands.length ? leaves(child, at) : [[at.join(" "), child]];
6688
+ const at2 = [...path, child.name()];
6689
+ return child.commands.length ? leaves(child, at2) : [[at2.join(" "), child]];
6256
6690
  }), "leaves");
6257
6691
  var addExamples = /* @__PURE__ */ __name((program) => {
6258
6692
  for (const [path, command] of leaves(program)) {
@@ -6469,11 +6903,11 @@ var statusLine = /* @__PURE__ */ __name((data) => {
6469
6903
  var personal = /* @__PURE__ */ __name((newest) => !newest.bulk && !newest.list && !newest.envelope && !newest.demoted, "personal");
6470
6904
  var gatherDigest = /* @__PURE__ */ __name(async (store, env, { since, now: clock = Date.now(), until, limit, excerpt: excerpt2, owedWithin, newSince }) => {
6471
6905
  const now = until ?? clock;
6472
- const by = /* @__PURE__ */ __name((at) => until === void 0 || at <= until, "by");
6906
+ const by = /* @__PURE__ */ __name((at2) => until === void 0 || at2 <= until, "by");
6473
6907
  const upTo = /* @__PURE__ */ __name((found) => found.filter((one2) => by(Date.parse(one2.item.at))), "upTo");
6474
6908
  const window = (now - since) / DAY7;
6475
6909
  const days2 = `${Math.max(1, Math.ceil(window))}d`;
6476
- const accounts = await store.accounts.accounts();
6910
+ const accounts = await scopedAccounts(store, env);
6477
6911
  const messengers2 = accounts.filter((key) => MESSENGERS2.has(key.provider));
6478
6912
  const mailboxes = accounts.filter((key) => key.provider === "email");
6479
6913
  const owedSince = Math.min(since, now - owedWithin);
@@ -6610,7 +7044,7 @@ var gatherDigest = /* @__PURE__ */ __name(async (store, env, { since, now: clock
6610
7044
  bulk++;
6611
7045
  continue;
6612
7046
  }
6613
- const pending2 = /* @__PURE__ */ __name((why) => ({
7047
+ const pending = /* @__PURE__ */ __name((why) => ({
6614
7048
  item: {
6615
7049
  ref: ref(thread.threadId),
6616
7050
  who: null,
@@ -6622,15 +7056,15 @@ var gatherDigest = /* @__PURE__ */ __name(async (store, env, { since, now: clock
6622
7056
  }), "pending");
6623
7057
  if (isWatchedChat(key, thread.threadId)) {
6624
7058
  if (inWindow)
6625
- watch.push(pending2("watched thread"));
7059
+ watch.push(pending("watched thread"));
6626
7060
  } else if (mailTurn(last) === "owed") {
6627
7061
  if (inWindow)
6628
- owedMail.push({ pending: pending2("owed reply"), externalId: last.externalId });
7062
+ owedMail.push({ pending: pending("owed reply"), externalId: last.externalId });
6629
7063
  else if (thread.lastEmailAt >= owedSince)
6630
7064
  olderMail++;
6631
7065
  owedHere++;
6632
7066
  } else if (inWindow && !last.outgoing) {
6633
- mail.push(pending2("new mail"));
7067
+ mail.push(pending("new mail"));
6634
7068
  newHere++;
6635
7069
  }
6636
7070
  }
@@ -6879,16 +7313,16 @@ var sinceOf = /* @__PURE__ */ __name((value, now = Date.now()) => {
6879
7313
  return since;
6880
7314
  }, "sinceOf");
6881
7315
  var beforeOf = /* @__PURE__ */ __name((value, now = Date.now()) => {
6882
- const at = /^\d{4}-\d{2}-\d{2}$/.test(value) ? (/* @__PURE__ */ new Date(`${value}T00:00:00`)).getTime() : Date.parse(value);
6883
- if (!/^\d{4}-\d{2}-\d{2}/.test(value) || Number.isNaN(at))
7316
+ const at2 = /^\d{4}-\d{2}-\d{2}$/.test(value) ? (/* @__PURE__ */ new Date(`${value}T00:00:00`)).getTime() : Date.parse(value);
7317
+ if (!/^\d{4}-\d{2}-\d{2}/.test(value) || Number.isNaN(at2))
6884
7318
  throw new CliError("validation_error", `--before-time takes an ISO time or a date, not "${value}"`, {
6885
7319
  param: "before-time"
6886
7320
  });
6887
- if (at > now)
7321
+ if (at2 > now)
6888
7322
  throw new CliError("validation_error", "--before-time is in the future; leave it out for now", {
6889
7323
  param: "before-time"
6890
7324
  });
6891
- return at;
7325
+ return at2;
6892
7326
  }, "beforeOf");
6893
7327
  var reviewAgendaCommand = /* @__PURE__ */ __name((review, print, streams, env) => {
6894
7328
  annotate(review.command("agenda"), { effects: LOCAL_READ }).summary("the morning digest: watch list, owed replies, mail, meetings, tasks, projects").description(`the morning digest, from the store alone with no model call: everything new in what you tagged ${WATCH_TAG} (chats, mail threads, people, projects, a meeting's series), replies you owe to people in messengers and personal mail (not bots or service chats), new personal mail, meetings that ended, tasks, projects that moved, memories and facts whose sources changed (source reviews raised since), proposals waiting. Tasks are the open ones created since the last morning-digest run (a day back when none ran) and those overdue, due today or due tomorrow, each with who asked and who does it. Replies owed reach back 7 days; owed mail lists only senders you know (linked to a person with other identities, or written to before), and mail from new senders is one count with the command that lists it. Each item has its reference, who, when, one line of text and why it is there; a section cut by --limit or --max-output-bytes says how many it left out and the command that reads them. \`scope\` says what was read (the window, sources, counts), \`tasks\` counts each task group and, as \`undated\`, every open task with no due date, and \`health\` names each account whose sync failed, that nothing syncs, or that is quiet for longer than usual, so an unsynced account does not read as a quiet day; an account stored or synced within a day is never named`).option("--since-time <time>", "how far back: hours or days (12h, 7d) or a start date (2026-11-01)", "1d").option("--before-time <time>", "build it as of this past ISO time or date, for a past day's digest: --since-time counts back from it, and what came later is left out; a chat or thread answered since reads as answered").option("--limit <n>", "items per section before the size budget", positive, 25).option("--max-output-bytes <bytes>", "the text answer's size budget in bytes; 40000 with --compact, else 80000", positive).option("--compact", "one line per item, shorter excerpts, the smaller budget: for an agent").option("--json", "print JSON").action(async (given2) => {
@@ -6983,7 +7417,7 @@ var challengeCommand = /* @__PURE__ */ __name((parent, type, streams, env) => {
6983
7417
  by,
6984
7418
  ...options.suggest === void 0 ? {} : { suggestion: options.suggest }
6985
7419
  });
6986
- return itemAnswer(await reviewOf(store, proposal.id));
7420
+ return itemAnswer(await reviewItemOf(store, proposal.id));
6987
7421
  });
6988
7422
  });
6989
7423
  }, "challengeCommand");
@@ -7009,11 +7443,11 @@ var memoriesCommand = /* @__PURE__ */ __name((program, streams, env) => {
7009
7443
  ...options.supersedes === void 0 ? {} : { supersedes: options.supersedes }
7010
7444
  }, await by).catch(explainQuote))));
7011
7445
  });
7012
- withQuery(annotate(memories.command("list"), { effects: LOCAL_READ }).description("memories, newest first"), MEMORY_QUERY).option("--limit <n>", "most memories, up to 500", positive, 100).option("--json", "print JSON; --json=id,title keeps only those fields").action((words, { json: json5, limit }) => run(json5, (store) => listMemories(store, words, limit)));
7013
- annotate(memories.command("show"), { effects: LOCAL_READ, output: { entity: "memory" } }).description("one memory with its evidence").argument("<ref>", "memory:<id>").option("--sources", "read each piece of evidence back: who, when, a short excerpt, and whether it is gone").option("--json", "print JSON; --json=id,title keeps only those fields").action((ref, options) => run(options.json, async (store) => itemAnswer({
7446
+ withQuery(annotate(memories.command("list"), { effects: LOCAL_READ }).description("memories, newest first"), MEMORY_QUERY).option("--limit <n>", "most memories, up to 500", positive, 100).option("--json", "print JSON; --json=id,title keeps only those fields").action((words, { json: json5, limit }) => run(json5, async (store) => stripped(store, env, await listMemories(store, words, limit))));
7447
+ annotate(memories.command("show"), { effects: LOCAL_READ, output: { entity: "memory" } }).description("one memory with its evidence").argument("<ref>", "memory:<id>").option("--sources", "read each piece of evidence back: who, when, a short excerpt, and whether it is gone").option("--json", "print JSON; --json=id,title keeps only those fields").action((ref, options) => run(options.json, async (store) => itemAnswer(await stripped(store, env, {
7014
7448
  ...memoryItem(await store.memories.get(ref)),
7015
- ...options.sources ? { sources: await store.memories.sources(ref) } : {}
7016
- })));
7449
+ ...options.sources ? await sourcesIn(store, env, await store.memories.sources(ref)) : {}
7450
+ }))));
7017
7451
  annotate(memories.command("update"), { effects: LOCAL_WRITE, output: { entity: "memory" } }).description("move a memory to another project, or to none").argument("<ref>", "memory:<id>").requiredOption("--project <project>", "the project's key or project:<id>; none takes it out of its project").option("--json", "print JSON; --json=id,title keeps only those fields").action((ref, options) => run(options.json, async (store) => itemAnswer(memoryItem(await store.memories.update(ref, {
7018
7452
  project: options.project === "none" ? null : await canonicalProject(store, options.project)
7019
7453
  })))));
@@ -7031,7 +7465,7 @@ var memoriesCommand = /* @__PURE__ */ __name((program, streams, env) => {
7031
7465
  const decided = /* @__PURE__ */ __name(async (store, ref, by, confirm) => {
7032
7466
  if ((await store.memories.get(ref)).status !== "proposed")
7033
7467
  return confirm ? store.memories.confirm(ref, by) : store.memories.markStale(ref, by);
7034
- await decideOne(store, ref, { confirm, by });
7468
+ await decideOne(store, env, ref, { confirm, by });
7035
7469
  return store.memories.get(ref);
7036
7470
  }, "decided");
7037
7471
  decide2("confirm", "stand behind a memory: its evidence was checked now", (store, ref, by) => decided(store, ref, by, true));
@@ -7131,11 +7565,11 @@ var factsCommand = /* @__PURE__ */ __name((program, streams, env) => {
7131
7565
  ...options.supersedes === void 0 ? {} : { supersedes: options.supersedes }
7132
7566
  }).catch(explainQuote))));
7133
7567
  });
7134
- withQuery(annotate(facts.command("list"), { effects: LOCAL_READ }).description("facts, latest first"), FACT_QUERY).option("--limit <n>", "most facts, up to 500", positive, 100).option("--json", "print JSON; --json=id,title keeps only those fields").action((words, { json: json5, limit }) => run(json5, (store) => listFacts(store, words, limit)));
7135
- annotate(facts.command("show"), { effects: LOCAL_READ, output: { entity: "fact" } }).description("one fact with its evidence").argument("<ref>", "fact:<id>").option("--sources", "read each piece of evidence back: who, when, a short excerpt, and whether it is gone").option("--json", "print JSON; --json=id,title keeps only those fields").action((ref, options) => run(options.json, async (store) => itemAnswer({
7568
+ withQuery(annotate(facts.command("list"), { effects: LOCAL_READ }).description("facts, latest first"), FACT_QUERY).option("--limit <n>", "most facts, up to 500", positive, 100).option("--json", "print JSON; --json=id,title keeps only those fields").action((words, { json: json5, limit }) => run(json5, async (store) => stripped(store, env, await listFacts(store, words, limit))));
7569
+ annotate(facts.command("show"), { effects: LOCAL_READ, output: { entity: "fact" } }).description("one fact with its evidence").argument("<ref>", "fact:<id>").option("--sources", "read each piece of evidence back: who, when, a short excerpt, and whether it is gone").option("--json", "print JSON; --json=id,title keeps only those fields").action((ref, options) => run(options.json, async (store) => itemAnswer(await stripped(store, env, {
7136
7570
  ...factItem(await store.facts.get(ref)),
7137
- ...options.sources ? { sources: await store.facts.sources(ref) } : {}
7138
- })));
7571
+ ...options.sources ? await sourcesIn(store, env, await store.facts.sources(ref)) : {}
7572
+ }))));
7139
7573
  const decide2 = /* @__PURE__ */ __name((name2, description, act) => reasonOption(byOption(annotate(facts.command(name2), {
7140
7574
  effects: LOCAL_WRITE,
7141
7575
  ...name2 === "remove" ? {} : { output: { entity: "fact" } }
@@ -7148,13 +7582,13 @@ var factsCommand = /* @__PURE__ */ __name((program, streams, env) => {
7148
7582
  });
7149
7583
  }), "decide");
7150
7584
  decide2("confirm", "stand behind a fact an agent proposed; a fact it supersedes stops holding. memo review confirm decides many", async (store, ref, by, why) => {
7151
- await decideOne(store, ref, decisionOf(true, by, why));
7585
+ await decideOne(store, env, ref, decisionOf(true, by, why));
7152
7586
  return store.facts.get(ref);
7153
7587
  }).summary("stand behind a fact an agent proposed");
7154
7588
  decide2("revoke", "take back your approval of an agent's fact; it waits as proposed again. Not for a correction or your own fact", (store, ref, by, why) => store.facts.revoke(ref, by, why)).summary("take back your approval of a fact an agent proposed");
7155
7589
  decide2("reverse", "an accepted decision no longer holds, and nothing replaced it", (store, ref, by) => store.facts.reverse(ref, by));
7156
7590
  decide2("reject", "turn down a fact an agent proposed; it stays, marked rejected", async (store, ref, by, why) => {
7157
- await decideOne(store, ref, decisionOf(false, by, why));
7591
+ await decideOne(store, env, ref, decisionOf(false, by, why));
7158
7592
  return store.facts.get(ref);
7159
7593
  });
7160
7594
  decide2("remove", "forget a fact: erase its text, its links to sources and its tags", (store, ref, by) => store.facts.remove(ref, by)).addHelpText("after", `
@@ -7181,7 +7615,7 @@ var SOURCED = new Set(Object.keys(READS));
7181
7615
  var readSourced = /* @__PURE__ */ __name((store, kind, ref) => READS[kind]?.(store, ref), "readSourced");
7182
7616
  var IMPORT = "import:";
7183
7617
  var imported = /* @__PURE__ */ __name(({ source, account: account2 }) => (account2 ?? null) !== null || !!source?.startsWith(IMPORT), "imported");
7184
- var sourceAccounts = /* @__PURE__ */ __name(async (store, { source, account: account2 }) => {
7618
+ var sourceAccounts2 = /* @__PURE__ */ __name(async (store, { source, account: account2 }) => {
7185
7619
  if (account2)
7186
7620
  return [account2];
7187
7621
  if (!source?.startsWith(IMPORT))
@@ -7196,7 +7630,7 @@ var named2 = /* @__PURE__ */ __name((key) => ({
7196
7630
  var sourcesOf = /* @__PURE__ */ __name(async (store, entity) => {
7197
7631
  const { ref } = entity;
7198
7632
  const records = [];
7199
- for (const { provider, account: account2 } of await sourceAccounts(store, entity)) {
7633
+ for (const { provider, account: account2 } of await sourceAccounts2(store, entity)) {
7200
7634
  if (records.length > MOST)
7201
7635
  break;
7202
7636
  for (const one2 of await store.records.list({ provider, account: account2, entity: ref, limit: MOST + 1 }))
@@ -7541,6 +7975,46 @@ var contractCommands = /* @__PURE__ */ __name((program, streams, env) => {
7541
7975
  });
7542
7976
  }, "contractCommands");
7543
7977
 
7978
+ // dist/knowledge/money-text.js
7979
+ var totalLine = /* @__PURE__ */ __name(({ status, currency, rows, total, open: open2 }) => ` ${status} ${total} ${currency}${open2 === void 0 ? "" : `, ${open2} open`} (${rows})`, "totalLine");
7980
+ var moneyLines = /* @__PURE__ */ __name((money) => [
7981
+ ...sectionLines("Invoices", money.invoices, (one2) => ` ${one2.title} ${one2.ref} ${one2.status} ${one2.total} ${one2.currency}, ${one2.open} open ${one2.review} via ${one2.linkedBy.join(", ")}`),
7982
+ ...sectionLines("Payments", money.payments, (one2) => ` ${one2.title} ${one2.ref} ${one2.amount} ${one2.currency} ${one2.date} ${one2.review}`),
7983
+ ...money.orders ? sectionLines("Orders", money.orders, (one2) => ` ${one2.title} ${one2.ref} ${one2.status} ${[one2.total, one2.currency].filter(Boolean).join(" ")}`) : [],
7984
+ ...money.totals.invoices.length ? ["Invoiced, confirmed", ...money.totals.invoices.map(totalLine)] : [],
7985
+ ...money.totals.payments.length ? ["Paid, confirmed", ...money.totals.payments.map(totalLine)] : [],
7986
+ ...money.unconfirmed ? [` ${money.unconfirmed} not confirmed yet \u2014 not in the totals`] : [],
7987
+ ...money.complete ? [] : [" more rows than one read: the totals may leave some out"]
7988
+ ], "moneyLines");
7989
+
7990
+ // dist/finance/deal-text.js
7991
+ var amountOf = /* @__PURE__ */ __name((amount2, currency) => [amount2, currency].filter(Boolean).join(" "), "amountOf");
7992
+ var dealText = /* @__PURE__ */ __name((context) => {
7993
+ const { deal, organization, owner, project, window, communications } = context;
7994
+ return [
7995
+ `${deal.title} ${deal.ref} ${deal.stage} ${deal.status} ${amountOf(deal.amount, deal.currency)}`,
7996
+ `Client ${organization ? `${organization.name ?? organization.ref} ${organization.ref}` : "none"}`,
7997
+ `Owner ${owner ? relatedLine(owner).trim() : "none"}`,
7998
+ `Project ${project ? `${project.name ?? project.ref} ${project.ref}` : "none"}`,
7999
+ ...sectionLines("Stages", context.stages, (one2) => ` ${one2.at.slice(0, 10)} ${one2.from ?? "\u2014"} \u2192 ${one2.to}`),
8000
+ ...sectionLines("People", context.participants),
8001
+ ...moneyLines(context.money),
8002
+ `Between ${window.since.slice(0, 10)} and ${window.until.slice(0, 10)}, proposed: they share people, nothing links them`,
8003
+ ...sectionLines("Messages, mail and meetings", communications, (one2) => ` ${one2.at?.slice(0, 16).replace("T", " ") ?? "\u2014"} ${one2.kind} ${one2.title ?? ""} ${one2.ref}`),
8004
+ ...sectionLines("Open tasks", context.tasks, (one2) => ` ${one2.key} ${one2.title} ${one2.status}`),
8005
+ ...coverageLines(context.coverage)
8006
+ ].map((line3) => line3.trimEnd()).join("\n");
8007
+ }, "dealText");
8008
+ var dealBriefText = /* @__PURE__ */ __name((brief) => [
8009
+ `${brief.title} ${brief.ref} ${brief.pipeline}/${brief.stage} ${brief.status} ${amountOf(brief.amount, brief.currency)}`,
8010
+ `client ${brief.organization ?? "none"}; owner ${brief.owner ?? "none"}; project ${brief.project ?? "none"}`,
8011
+ ...brief.people.map((one2) => ` ${one2.name ?? one2.ref} ${one2.ref} ${one2.roles.join(", ")} ${one2.standing}`),
8012
+ ...brief.stages.length ? [`stages ${brief.stages.join("; ")}`] : [],
8013
+ `invoiced ${brief.money.invoices.map((one2) => `${one2.status} ${one2.total} ${one2.currency}`).join(", ") || "none"}; paid ${brief.money.payments.map((one2) => `${one2.total} ${one2.currency}`).join(", ") || "none"}`,
8014
+ `${brief.communications.messages} messages, ${brief.communications.mail} emails, ${brief.communications.meetings} meetings (proposed); ${brief.openTasks} open tasks`,
8015
+ ...brief.notRead.map(({ source, reason }) => `not read: ${source} \u2014 ${reason}`)
8016
+ ].map((line3) => line3.trimEnd()).join("\n"), "dealBriefText");
8017
+
7544
8018
  // dist/finance/deals-command.js
7545
8019
  var queryOf = /* @__PURE__ */ __name((entity) => ({
7546
8020
  entity,
@@ -7559,7 +8033,14 @@ var PIPELINE_QUERY = {
7559
8033
  backend: "native",
7560
8034
  fields: [termField("kind", "enum", "kind:lead", { values: DEAL_KINDS }), termField("name", "kw", "name:Sales")]
7561
8035
  };
7562
- var listDeals = /* @__PURE__ */ __name(async (store, kind, words, limit) => {
8036
+ var withWriter = /* @__PURE__ */ __name(async (store) => {
8037
+ const profilesFor2 = storedProfilesFor(await store.accounts.profiles());
8038
+ return (item) => ({
8039
+ ...item,
8040
+ writesWith: writesWithOf(item.account, profilesFor2)
8041
+ });
8042
+ }, "withWriter");
8043
+ var listDeals = /* @__PURE__ */ __name(async (store, env, kind, words, limit) => {
7563
8044
  const command = `${kind}s list`;
7564
8045
  const terms2 = queryTerms(words, QUERIES[kind], command);
7565
8046
  const filter = {
@@ -7570,8 +8051,21 @@ var listDeals = /* @__PURE__ */ __name(async (store, kind, words, limit) => {
7570
8051
  ...terms2.has("pipeline") ? { pipeline: terms2.get("pipeline") } : {},
7571
8052
  ...terms2.has("organization") ? { organization: terms2.get("organization") } : {}
7572
8053
  };
7573
- return pageOf(command, limit, (most) => store.deals.list({ ...filter, limit: most }));
8054
+ const scope = await groupScopeOf(store, env);
8055
+ const writer = await withWriter(store);
8056
+ return pageOf(command, limit, async (most) => (await store.deals.list({ ...filter, ...scope === void 0 ? {} : { accounts: scope.accounts }, limit: most })).map(writer));
7574
8057
  }, "listDeals");
8058
+ var BASE_STAGE = /^stage:\d+$/;
8059
+ var stageToMove = /* @__PURE__ */ __name(async (store, ref, stage) => {
8060
+ if (!BASE_STAGE.test(stage.trim()))
8061
+ return stage;
8062
+ const row = await store.deals.get(ref);
8063
+ if (row.account !== null) {
8064
+ const writesWith = writesWithOf(row.account, storedProfilesFor(await store.accounts.profiles()));
8065
+ throw new CliError("validation_error", `${ref} is a copy from ${row.account.provider}:${row.account.account}; move it there with ${writesWith?.tool ?? "its CRM's CLI"} ${row.kind}s move ${ref} ${stage.trim()}`, { reason: "stage.crm-copy", writes_with: writesWith });
8066
+ }
8067
+ return (await store.baseStages.resolve(ref, stage.trim())).stage.name;
8068
+ }, "stageToMove");
7575
8069
  var roleOf = /* @__PURE__ */ __name((role) => {
7576
8070
  const value = role ?? "contact";
7577
8071
  if (!DEAL_ROLES.includes(value))
@@ -7582,18 +8076,38 @@ var referenceOf = /* @__PURE__ */ __name((kind, value) => /^\d+$/.test(value.tri
7582
8076
  var stageOf = /* @__PURE__ */ __name((stage) => {
7583
8077
  if (stage === void 0)
7584
8078
  return {};
7585
- const at = stage.lastIndexOf("/");
7586
- return at <= 0 ? { stage } : { pipeline: stage.slice(0, at), stage: stage.slice(at + 1) };
8079
+ const at2 = stage.lastIndexOf("/");
8080
+ return at2 <= 0 ? { stage } : { pipeline: stage.slice(0, at2), stage: stage.slice(at2 + 1) };
7587
8081
  }, "stageOf");
7588
8082
  var WHAT = {
7589
8083
  deal: { one: "deal", hope: "what you hope to sell, such as 'Site for the clinic'" },
7590
8084
  lead: { one: "lead", hope: "who or what came in, such as 'Call from the site'" }
7591
8085
  };
7592
- var itemCommands = /* @__PURE__ */ __name((program, kind, run, env) => {
8086
+ var itemCommands = /* @__PURE__ */ __name((program, kind, { run, print }, env) => {
7593
8087
  const { one: one2, hope } = WHAT[kind];
7594
8088
  const group = program.command(`${kind}s`).description(kind === "deal" ? "deals you hope to win: the client, the expected amount, the stage and whether it was won or lost" : "leads: first contacts in a lead pipeline, before they are deals").summary(kind === "deal" ? "deals in your pipelines, open, won or lost" : "leads in your lead pipelines");
7595
- withQuery(json(annotate(group.command("list"), { effects: LOCAL_READ })).description(`${one2}s, newest first; status:open is what is still in play`), QUERIES[kind]).summary(`${one2}s, newest first`).option("--limit <n>", `most ${one2}s, up to 500`, positive, 100).action((words, { json: json5, limit }) => run(json5, (store) => listDeals(store, kind, words, limit)));
8089
+ withQuery(json(annotate(group.command("list"), { effects: LOCAL_READ })).description(`${one2}s, newest first; status:open is what is still in play`), QUERIES[kind]).summary(`${one2}s, newest first`).option("--limit <n>", `most ${one2}s, up to 500`, positive, 100).action((words, { json: json5, limit }) => run(json5, (store) => listDeals(store, env, kind, words, limit)));
7596
8090
  json(annotate(group.command("show"), { effects: LOCAL_READ, output: { entity: kind } })).description(`one ${one2} with its pipeline, stage, status, amount, the people on it and what it was read from`).summary(`one ${one2} with its stage, status, amount and people`).argument("<ref>", `${kind}:<id>`).action((ref, options, command) => run(options.json, async (store) => itemAnswer(await withSources(command, store, await store.deals.get(ref)))));
8091
+ json(annotate(group.command("context"), { effects: LOCAL_READ, output: { entity: "deal_context" } })).description(`one ${one2} whole: its stages, client, people with their roles and standing, owner, project, invoices and payments as stored, its people's messages, mail and meetings in its lifetime (\`proposed\`: they share people, nothing links them), open tasks and \`coverage\`. A stage named Won is not a payment`).summary(`one ${one2}: stages, people, project, money, messages and tasks`).argument("<ref>", `${kind}:<id>`).option("--brief", "the compact form for a model's context: names, roles, totals and counts").option("--limit <n>", "most items in each section", positive, 20).action(async (ref, options, command) => {
8092
+ const answer = await withStore(env, async (store) => {
8093
+ const scope = await groupScopeOf(store, env);
8094
+ return lockedCoverage(store, env, await dealContext(store, ref, {
8095
+ limit: options.limit,
8096
+ ...scope === void 0 ? {} : { accounts: scope.accounts },
8097
+ deniedKinds: deniedCrmKinds(command, env)
8098
+ }));
8099
+ });
8100
+ if (answer.deal.kind !== kind)
8101
+ throw new CliError("validation_error", `${ref} is a ${answer.deal.kind} \u2014 memo ${answer.deal.kind}s context`);
8102
+ print(options.json, itemAnswer(options.brief ? dealBrief(answer) : answer), options.brief ? dealBriefText(dealBrief(answer)) : dealText(answer));
8103
+ });
8104
+ json(annotate(group.command("update"), { effects: LOCAL_WRITE, output: { entity: kind } })).description(`set the project a ${one2} belongs to; a CRM's copy takes it too, and the next sync keeps it. An empty value clears it`).summary(`set the project a ${one2} belongs to`).argument("<ref>", `${kind}:<id>`).requiredOption("--project <project>", "the project: its key or project:<id>").action(async (ref, options) => {
8105
+ const by = authorOf(env);
8106
+ await run(options.json, async (store) => itemAnswer(await store.deals.setProject(ref, {
8107
+ project: options.project === "" ? null : await canonicalProject(store, options.project),
8108
+ by
8109
+ })));
8110
+ });
7597
8111
  json(annotate(group.command("add"), { effects: LOCAL_WRITE, output: { entity: kind }, literal_after_dashes: true }).option("--organization <organization>", "the client: organization:<id>").option("--person <uid>", `a person on the ${one2}: person:<id>; repeat for another, up to 20`, collect).option("--role <role>", `what those people are on it: ${DEAL_ROLES.join(", ")}; contact by default`).option("--due <time>", "the day you expect it to close, such as 2026-12-01").option("--project <project>", "the project it belongs to: its key or project:<id>").option("--reason <text>", "why an agent records it, kept with it").option("--evidence <ref...>", "what shows it, up to 8: msg:, note:, document: or another reference")).description(`record a ${one2} in a stage; it is written at once, whoever runs it`).summary(`record a ${one2} in a stage`).argument("<title>", hope).argument(kind === "deal" ? "<stage>" : "[stage]", kind === "deal" ? "the stage it is in; Sales/Quote or pipeline:3/Quote names the pipeline when two have that stage" : "the stage it is in; the first stage of the only lead pipeline when left out").argument("[amount]", "the expected amount, a decimal such as 500000.00").argument("[currency]", "ISO 4217, such as RUB; given with the amount").action(async (title, stage, amount2, currency, options) => {
7598
8112
  const by = authorOf(env);
7599
8113
  const role = roleOf(options.role);
@@ -7615,9 +8129,9 @@ var itemCommands = /* @__PURE__ */ __name((program, kind, run, env) => {
7615
8129
  }));
7616
8130
  });
7617
8131
  });
7618
- json(annotate(group.command("move"), { effects: LOCAL_WRITE, output: { entity: kind } })).description(`move a ${one2} to another stage of its pipeline; a won or lost stage closes it, an open one reopens it`).summary(`move a ${one2} to another stage`).argument("<ref>", `${kind}:<id>`).argument("<stage>", `a stage of the ${one2}'s pipeline`).action(async (ref, stage, options) => {
8132
+ json(annotate(group.command("move"), { effects: LOCAL_WRITE, output: { entity: kind } })).description(`move a ${one2} to another stage of its pipeline; a won or lost stage closes it, an open one reopens it`).summary(`move a ${one2} to another stage`).argument("<ref>", `${kind}:<id>`).argument("<stage>", `a stage of the ${one2}'s pipeline by its name or stage:<id>; or a base stage's stage:<id>, which moves it to the one stage of its pipeline mapped there, and refuses several (with the candidates) or none`).action(async (ref, stage, options) => {
7619
8133
  const by = authorOf(env);
7620
- await run(options.json, async (store) => itemAnswer(await store.deals.move(ref, { stage, by })));
8134
+ await run(options.json, async (store) => itemAnswer(await store.deals.move(ref, { stage: await stageToMove(store, ref, stage), by })));
7621
8135
  });
7622
8136
  json(annotate(group.command("close"), { effects: LOCAL_WRITE, output: { entity: kind } }).option("--occurred-time <time>", "the day it closed, such as 2026-11-20; today when left out").option("--reason <text>", "why it was won or lost, kept with it")).description(`close a ${one2} as won or lost; it moves to its pipeline's won or lost stage when there is one`).summary(`close a ${one2} as won or lost`).argument("<ref>", `${kind}:<id>`).argument("<outcome>", "won or lost").action(async (ref, outcome, options) => {
7623
8137
  if (outcome !== "won" && outcome !== "lost")
@@ -7638,6 +8152,21 @@ var funnelText = /* @__PURE__ */ __name((report) => [
7638
8152
  ...report.stages.map((stage) => ` ${stage.position}. ${stage.name}${stage.outcome === "open" ? "" : ` [${stage.outcome}]`}: ${stage.open} open, ${stage.reached} reached${percent(stage.conversion)}`),
7639
8153
  ` ${report.totals.items} in all: ${report.totals.open} open, ${report.totals.won} won, ${report.totals.lost} lost` + (report.totals.winRate === null ? "" : `, win rate ${Math.round(report.totals.winRate * 100)}%`)
7640
8154
  ].join("\n"), "funnelText");
8155
+ var inScope = /* @__PURE__ */ __name((scope) => (pipeline) => scope === void 0 || pipeline.account === null || scope.has(pipeline.account), "inScope");
8156
+ var pipelineInGroup = /* @__PURE__ */ __name(async (store, env, reference2) => {
8157
+ const scope = await groupScopeOf(store, env);
8158
+ if (scope === void 0 || /^pipeline:\d+$/.test(reference2.trim()))
8159
+ return reference2;
8160
+ const name2 = reference2.trim().toLocaleLowerCase();
8161
+ const named5 = (await store.deals.pipelines()).filter((one2) => one2.name.toLocaleLowerCase() === name2 && inScope(scope)(one2));
8162
+ if (named5.length === 1)
8163
+ return named5[0].ref;
8164
+ if (named5.length === 0)
8165
+ throw new CliError("not_found", `no pipeline named ${reference2.trim()} in group:${scope.run.name}`, {
8166
+ reason: "pipeline.not-found"
8167
+ });
8168
+ throw new CliError("validation_error", `more than one pipeline in group:${scope.run.name} is named ${reference2.trim()}: ${named5.map((one2) => one2.ref).join(", ")}; name one by its reference`, { reason: "pipeline.ambiguous" });
8169
+ }, "pipelineInGroup");
7641
8170
  var dealCommands = /* @__PURE__ */ __name((program, streams, env) => {
7642
8171
  const { run, print } = answers(program, streams, env);
7643
8172
  const pipelines = program.command("pipelines").description("sales pipelines: the stages a deal or a lead goes through, in order, and how many get through each").summary("sales pipelines, their stages and conversion");
@@ -7645,15 +8174,17 @@ var dealCommands = /* @__PURE__ */ __name((program, streams, env) => {
7645
8174
  const terms2 = queryTerms(words, PIPELINE_QUERY, "pipelines list");
7646
8175
  const name2 = terms2.get("name")?.toLocaleLowerCase();
7647
8176
  const kind = terms2.get("kind");
7648
- const all = await store.deals.pipelines(kind === void 0 ? {} : { kind });
7649
- return wholeList("pipelines list", name2 === void 0 ? all : all.filter((one2) => one2.name.toLocaleLowerCase() === name2));
8177
+ const scope = await groupScopeOf(store, env);
8178
+ const all = (await store.deals.pipelines(kind === void 0 ? {} : { kind })).filter(inScope(scope));
8179
+ const writer = await withWriter(store);
8180
+ return wholeList("pipelines list", (name2 === void 0 ? all : all.filter((one2) => one2.name.toLocaleLowerCase() === name2)).map(writer));
7650
8181
  }));
7651
8182
  json(annotate(pipelines.command("show"), { effects: LOCAL_READ, output: { entity: "pipeline" } }).option("--since-time <time>", "count only deals or leads made since this day, such as 2026-09-01")).description("one pipeline's funnel: per stage the open deals or leads in it, how many reached it, and the share that went on to the next stage; then won, lost and the win rate").summary("one pipeline's stages with counts and conversion").argument("<pipeline>", "pipeline:<id>, or a name only one pipeline has").action(async (pipeline, options, command) => {
7652
8183
  const since = dayOf2(options.sinceTime);
7653
- const report = await withStore(env, async (store) => withSources(command, store, await store.deals.pipeline(pipeline, since === void 0 ? {} : { since })));
8184
+ const report = await withStore(env, async (store) => withSources(command, store, await store.deals.pipeline(await pipelineInGroup(store, env, pipeline), since === void 0 ? {} : { since })));
7654
8185
  print(options.json, itemAnswer(report), funnelText(report));
7655
8186
  });
7656
- json(annotate(pipelines.command("add"), { effects: LOCAL_WRITE, literal_after_dashes: true }).option("--kind <kind>", "what it holds: deal or lead; deal by default")).description("make a pipeline with its stages in order; a stage named won or lost (any letter case) ends a deal or lead as that").summary("make a pipeline with its stages").argument("<name>", "the pipeline's name, such as Sales").argument("<stage...>", "its stages in order, such as Call Quote Contract won lost").action(async (name2, stages, options) => {
8187
+ json(annotate(pipelines.command("add"), { effects: LOCAL_WRITE, literal_after_dashes: true }).option("--kind <kind>", "what it holds: deal or lead; deal by default")).description("make a pipeline with its stages in order; a stage named won or lost (any letter case) ends a deal or lead as that").summary("make a pipeline with its stages").argument("<name>", "the pipeline's name, such as Sales").argument("<stage...>", "its stages in order, such as Call Quote Contract won lost").action(async (name2, stages2, options) => {
7657
8188
  const kind = options.kind ?? "deal";
7658
8189
  if (!DEAL_KINDS.includes(kind))
7659
8190
  throw new CliError("validation_error", "--kind is deal or lead", { param: "--kind" });
@@ -7661,15 +8192,24 @@ var dealCommands = /* @__PURE__ */ __name((program, streams, env) => {
7661
8192
  await run(options.json, async (store) => itemAnswer(await store.deals.addPipeline({
7662
8193
  name: name2,
7663
8194
  kind,
7664
- stages: stages.map((stage) => {
8195
+ stages: stages2.map((stage) => {
7665
8196
  const word = stage.trim().toLocaleLowerCase();
7666
8197
  return word === "won" || word === "lost" ? { name: stage, outcome: word } : stage;
7667
8198
  }),
7668
8199
  by
7669
8200
  })));
7670
8201
  });
7671
- itemCommands(program, "deal", run, env);
7672
- itemCommands(program, "lead", run, env);
8202
+ itemCommands(program, "deal", { run, print }, env);
8203
+ itemCommands(program, "lead", { run, print }, env);
8204
+ const stages = baseStagesCommand(APP, {
8205
+ env: /* @__PURE__ */ __name(() => env, "env"),
8206
+ open: /* @__PURE__ */ __name(() => openMemoStore(env), "open"),
8207
+ output: /* @__PURE__ */ __name((body, command) => print(command.opts().json, body), "output"),
8208
+ accounts: /* @__PURE__ */ __name(async (store) => (await groupScopeOf(store, env))?.accounts, "accounts")
8209
+ });
8210
+ for (const leaf of stages.commands)
8211
+ json(leaf);
8212
+ program.addCommand(stages);
7673
8213
  }, "dealCommands");
7674
8214
  var STATUS_DEALS = 5;
7675
8215
  var openDealsOf = /* @__PURE__ */ __name(async (store, projects) => {
@@ -8017,7 +8557,7 @@ var listWallets = /* @__PURE__ */ __name(async (store, words, limit) => {
8017
8557
  var sourceSays = /* @__PURE__ */ __name(async (store, wallet) => {
8018
8558
  if (wallet.openingBalance !== null)
8019
8559
  return null;
8020
- for (const { provider, account: account2 } of await sourceAccounts(store, wallet)) {
8560
+ for (const { provider, account: account2 } of await sourceAccounts2(store, wallet)) {
8021
8561
  const [record2] = await store.records.list({ provider, account: account2, entity: wallet.ref, limit: 1 });
8022
8562
  const { opening_balance: balance, opening_date: date } = record2?.fields ?? {};
8023
8563
  if (record2 && typeof balance === "string")
@@ -8143,15 +8683,15 @@ var findingsCommand = /* @__PURE__ */ __name((program, streams, env) => {
8143
8683
 
8144
8684
  // dist/json-fields.js
8145
8685
  var commandIn = /* @__PURE__ */ __name((root, words) => {
8146
- let at = root;
8686
+ let at2 = root;
8147
8687
  for (const word of words) {
8148
8688
  if (word.startsWith("-"))
8149
8689
  continue;
8150
- const child = at.commands.find((command) => command.name() === word || command.aliases().includes(word));
8690
+ const child = at2.commands.find((command) => command.name() === word || command.aliases().includes(word));
8151
8691
  if (child)
8152
- at = child;
8692
+ at2 = child;
8153
8693
  }
8154
- return at === root ? void 0 : at;
8694
+ return at2 === root ? void 0 : at2;
8155
8695
  }, "commandIn");
8156
8696
  var keep = /* @__PURE__ */ __name((text3, paths) => {
8157
8697
  let value;
@@ -8246,6 +8786,27 @@ var meetingProjectsCommand = /* @__PURE__ */ __name((projects, streams, env) =>
8246
8786
  })), true));
8247
8787
  }, "meetingProjectsCommand");
8248
8788
 
8789
+ // dist/knowledge/organization-text.js
8790
+ var organizationText = /* @__PURE__ */ __name((answer) => {
8791
+ const { organization, categories, communications } = answer;
8792
+ return [
8793
+ `${organization.name} ${organization.ref}${organization.own ? " (your own)" : ""}`,
8794
+ ...categories.length ? [`Categories ${categories.join(", ")}`] : [],
8795
+ ...answer.tags.length ? [`Tags ${answer.tags.join(", ")}`] : [],
8796
+ ...sectionLines("People", answer.people),
8797
+ ...sectionLines("Customers", answer.customers),
8798
+ ...sectionLines("Suppliers", answer.suppliers),
8799
+ ...sectionLines("Partners", answer.partners),
8800
+ ...sectionLines("Projects", answer.projects, (one2) => ` ${one2.name} ${one2.ref} via ${one2.via.join(", ")}`),
8801
+ ...sectionLines("Open deals and leads", answer.deals, (one2) => ` ${one2.title} ${one2.ref} ${one2.stage} ${[one2.amount, one2.currency].filter(Boolean).join(" ")}`),
8802
+ ...moneyLines(answer.money),
8803
+ `Written by its people ${communications.messages} messages, ${communications.mail} emails, ${communications.meetings} meetings`,
8804
+ ...sectionLines("Open tasks", answer.tasks, (one2) => ` ${one2.key} ${one2.title} ${one2.status}`),
8805
+ ...answer.notes.about.length ? ["Notes about it", ...answer.notes.about.map((note) => ` ${note.ref}`)] : [],
8806
+ ...coverageLines(answer.coverage)
8807
+ ].map((line3) => line3.trimEnd()).join("\n");
8808
+ }, "organizationText");
8809
+
8249
8810
  // dist/knowledge/project-actions.js
8250
8811
  var evidenceContext = /* @__PURE__ */ __name(async (store, ref, fingerprint, words, window) => {
8251
8812
  const record2 = await store.contextRecords?.read(ref);
@@ -8305,14 +8866,14 @@ var projectActions = /* @__PURE__ */ __name(async (store, project, options) => {
8305
8866
  hasMore: found.hasMore
8306
8867
  };
8307
8868
  }, "projectActions");
8308
- var decideAction = /* @__PURE__ */ __name(async (store, project, id, decision) => {
8869
+ var decideAction = /* @__PURE__ */ __name(async (store, env, project, id, decision) => {
8309
8870
  if (!/^(key:)?[1-9]\d*$/.test(id))
8310
8871
  throw new CliError("validation_error", "an action ID is a batch number or key:<id>");
8311
8872
  const row = await proposalRegistry(store).get(id);
8312
8873
  if (row.project !== project.ref || row.kind !== "key_document" && row.kind !== "findings")
8313
8874
  throw new CliError("not_found", `no proposal ${id} in ${project.ref}; memo projects actions list shows them`);
8314
8875
  if (row.kind === "key_document") {
8315
- await decideOne(store, id, decisionOf(decision.confirm, decision.by, decision.reason));
8876
+ await decideOne(store, env, id, decisionOf(decision.confirm, decision.by, decision.reason));
8316
8877
  return { id, kind: "key_document", ref: row.subject, confirmed: decision.confirm, decided_by: decision.by };
8317
8878
  }
8318
8879
  if (decision.fingerprint === void 0)
@@ -8391,7 +8952,7 @@ var projectActionsCommand = /* @__PURE__ */ __name((projects, streams, env) => {
8391
8952
  const by = await deciderOf(command, env, { ...given2, question: `${name2} ${id} as you, the owner?` });
8392
8953
  await run(given2.json, async (store) => {
8393
8954
  const project = await projectOf(store, reference2);
8394
- return itemAnswer(await decideAction(store, project, id, {
8955
+ return itemAnswer(await decideAction(store, env, project, id, {
8395
8956
  confirm: name2 === "confirm",
8396
8957
  ...given2.fingerprint === void 0 ? {} : { fingerprint: given2.fingerprint },
8397
8958
  ...given2.reason === void 0 ? {} : { reason: given2.reason },
@@ -8445,15 +9006,17 @@ var projectFindings = /* @__PURE__ */ __name(async (store, project, links) => {
8445
9006
  // dist/knowledge/project-context.js
8446
9007
  var projectContext = /* @__PURE__ */ __name(async (store, env, reference2) => {
8447
9008
  const project = await projectOf(store, reference2);
8448
- const relationships = byEngagement((await store.notes.links({ to: project.ref })).concat(await store.notes.links({ from: project.ref })).filter((link2) => link2.kind !== "about" && link2.kind !== "links-to" && link2.role !== "key"));
9009
+ const linked2 = byEngagement((await store.notes.links({ to: project.ref })).concat(await store.notes.links({ from: project.ref })).filter((link2) => link2.kind !== "about" && link2.kind !== "links-to" && link2.role !== "key")).map((link2) => ({ ...link2, standing: standingOf(link2, Date.now()) }));
9010
+ const relationships = await keepInGroup(store, env, linked2, (link2) => link2.from === project.ref ? String(link2.to) : link2.from);
8449
9011
  const documents = await keyDocuments(store, project);
8450
- const pending2 = /* @__PURE__ */ __name((kind) => proposalRegistry(store).list({ project: project.ref, kinds: [kind], status: "proposed", limit: 50, offset: 0 }), "pending");
9012
+ const proposals = await proposalsOf(store, env);
9013
+ const pending = /* @__PURE__ */ __name((kind) => proposals.list({ project: project.ref, kinds: [kind], status: "proposed", limit: 50, offset: 0 }), "pending");
8451
9014
  const [facts, tasks, findings, keys, links, waiting2] = await Promise.all([
8452
9015
  store.facts.list({ project: project.ref, status: "proposed", limit: 21 }),
8453
9016
  store.tasks.find({ project: project.ref, status: "open", limit: 21 }),
8454
9017
  projectFindings(store, project.ref, relationships),
8455
- pending2("key_document"),
8456
- pending2("relationship"),
9018
+ pending("key_document"),
9019
+ pending("relationship"),
8457
9020
  waitingAbout(store, env, [project.ref])
8458
9021
  ]);
8459
9022
  const label = await labelsFor(store, [...keys.items, ...links.items].flatMap((row) => [row.subject, row.object]));
@@ -8648,7 +9211,7 @@ var projectGatherCommand = /* @__PURE__ */ __name((projects, print, env, warn) =
8648
9211
  ...found,
8649
9212
  linkedChats: found.linkedChats.map((one2, i) => ({ ...one2, syncCommand: syncs[i]?.command ?? null }))
8650
9213
  }, { ...parts2, ...missing.length ? { missing } : {}, ...next.length ? { next } : {} }), projectEvidenceText(found, {
8651
- sync: /* @__PURE__ */ __name((chat, at) => syncHint(chat, at, env, chosen), "sync"),
9214
+ sync: /* @__PURE__ */ __name((chat, at2) => syncHint(chat, at2, env, chosen), "sync"),
8652
9215
  showDocument: "memo notes show"
8653
9216
  }));
8654
9217
  })
@@ -8688,7 +9251,7 @@ var outside = /* @__PURE__ */ __name((blocked) => (step, found) => {
8688
9251
  };
8689
9252
  }, "outside");
8690
9253
  var asAction = /* @__PURE__ */ __name((step) => step.kind === "command" ? { kind: "user_action", step: step.step, why: `${step.why}: ${step.line}`, safe_to_auto_execute: false } : step, "asAction");
8691
- var projectStatusCommand = /* @__PURE__ */ __name((projects, print, env) => answerEntity(annotate(projects.command("status"), { effects: LOCAL_READ, partial: true }), "project_status", projectStatusSchema, { row: withFinance(projectStatusRow(STATUS_SIGNALS)) }).description("where a project stands, from the stored messages of every chat confirmed as the project's or its child projects', in every account those links name (meta.accounts lists them): the last message, who replies next, open questions both ways, promises, amounts found by words with their direction (only when the project has no confirmed invoice or payment), payments recorded, billed, paid and owed per currency from confirmed invoices and payments (finance), up to five open confirmed deals (deals), how long each --context-query has been quiet on their side, and how much of each chat is held. Amounts, directions and promises found by words are marked pattern: read the cited message before trusting one. Others' questions in a group with no role, and others' word-found promises in a group, are counted on the chat's row as unlisted, not listed. next names at most two chats to read, with the messenger command that reads them. No model call; nothing leaves this machine").summary("where a project stands: whose move, open asks, money, chats to read next").argument("<project>", "an existing project's id, project:<id>, key, exact name or alias").option("--since-time <time>", "how far back: days (60d, at most 730d) or a start date (2026-09-01)", "60d").option("--before-time <time>", "fixed exclusive end: ISO 8601 timestamp with UTC offset; days back count from it").option("--context-query <words>", "words that all appear in one text; reports their last mention per side. Repeat for another", collect, []).option("--sync-profile <tool=profile>", "the messenger profile the next steps name when several are signed in to a chat's account, such as max=default; repeat for another tool", syncProfileOf).option("--purpose <purpose>", "the linked chats' purposes to read, comma-separated: work, sales, support, other, or all; default work", purposeList).addOption(annotateOption(new Option("--compact", "one line per signal, chat and next step, for an agent"), { mcp: false })).option("--json", "print JSON; --json=id,title keeps only those fields").action(async (project, options) => {
9254
+ var projectStatusCommand = /* @__PURE__ */ __name((projects, print, env) => answerEntity(annotate(projects.command("status"), { effects: LOCAL_READ, partial: true }), "project_status", projectStatusSchema, { row: withFinance(projectStatusRow(STATUS_SIGNALS)) }).description("where a project stands, from the stored messages of every chat confirmed as the project's or its child projects', in every account those links name (meta.accounts lists them): the last message, who replies next, open questions both ways, promises, amounts found by words with their direction (only when the project has no confirmed invoice or payment), payments recorded, billed, paid and owed per currency from confirmed invoices and payments (finance), up to five open deals (deals), how long each --context-query has been quiet on their side, and how much of each chat is held. Amounts, directions and promises found by words are marked pattern: read the cited message before trusting one. Others' questions in a group with no role, and others' word-found promises in a group, are counted on the chat's row as unlisted, not listed. next names at most two chats to read, with the messenger command that reads them. No model call; nothing leaves this machine").summary("where a project stands: whose move, open asks, money, chats to read next").argument("<project>", "an existing project's id, project:<id>, key, exact name or alias").option("--since-time <time>", "how far back: days (60d, at most 730d) or a start date (2026-09-01)", "60d").option("--before-time <time>", "fixed exclusive end: ISO 8601 timestamp with UTC offset; days back count from it").option("--context-query <words>", "words that all appear in one text; reports their last mention per side. Repeat for another", collect, []).option("--sync-profile <tool=profile>", "the messenger profile the next steps name when several are signed in to a chat's account, such as max=default; repeat for another tool", syncProfileOf).option("--purpose <purpose>", "the linked chats' purposes to read, comma-separated: work, sales, support, other, or all; default work", purposeList).addOption(annotateOption(new Option("--compact", "one line per signal, chat and next step, for an agent"), { mcp: false })).option("--json", "print JSON; --json=id,title keeps only those fields").action(async (project, options) => {
8692
9255
  if (options.compact && options.json)
8693
9256
  throw new CliError("validation_error", "--compact and --json ask for different output \u2014 pick one", {
8694
9257
  reason: "output.conflict",
@@ -8696,8 +9259,10 @@ var projectStatusCommand = /* @__PURE__ */ __name((projects, print, env) => answ
8696
9259
  });
8697
9260
  const chosen = options.syncProfile ?? {};
8698
9261
  const { found, finance, open: open2 } = await withStore(env, async (store) => {
9262
+ const scope = await groupScopeOf(store, env);
8699
9263
  const status = await projectStatus(store, {
8700
9264
  project,
9265
+ ...scope === void 0 ? {} : { accounts: scope.accounts },
8701
9266
  ...projectWindowOf(options.sinceTime),
8702
9267
  ...options.beforeTime === void 0 ? {} : { asOf: projectCutoffTime(options.beforeTime) },
8703
9268
  contextQueries: options.contextQuery,
@@ -8714,8 +9279,15 @@ var projectStatusCommand = /* @__PURE__ */ __name((projects, print, env) => answ
8714
9279
  read: /* @__PURE__ */ __name((chat, since) => step("messages.list", chatRead(linked(chat), since, env, chosen)), "read"),
8715
9280
  line: /* @__PURE__ */ __name((one2) => one2.kind === "command" ? one2.line ?? one2.command : one2.why, "line")
8716
9281
  };
8717
- const { item, next, missing, meta } = projectStatusAnswer(found, hints);
8718
- const gaps = [...missing, ...blocked.size ? [{ field: "next_command", why: [...blocked].join("; ") }] : []];
9282
+ const lock = groupLockOf(APP, env);
9283
+ const hidden = lock === void 0 ? [] : found.outOfScope.filter(({ reason }) => reason === "other-account");
9284
+ const shown3 = hidden.length ? { ...found, outOfScope: found.outOfScope.filter((one2) => !hidden.includes(one2)) } : found;
9285
+ const { item, next, missing, meta } = projectStatusAnswer(shown3, hints);
9286
+ const gaps = [
9287
+ ...missing,
9288
+ ...hidden.length ? [{ field: "out_of_scope", why: `${hidden.length} of the project's chats are outside group ${lock}` }] : [],
9289
+ ...blocked.size ? [{ field: "next_command", why: [...blocked].join("; ") }] : []
9290
+ ];
8719
9291
  print(options.json, itemOf({
8720
9292
  ...item,
8721
9293
  ...finance.length ? { finance } : {},
@@ -8725,7 +9297,7 @@ var projectStatusCommand = /* @__PURE__ */ __name((projects, print, env) => answ
8725
9297
  ...next.length ? { next: next.map(asAction) } : {},
8726
9298
  ...gaps.length ? { missing: gaps } : {},
8727
9299
  meta
8728
- }), [projectStatusText(found, hints), ...financeText(finance), ...dealsText(open2)].join("\n"), options.compact === true);
9300
+ }), [projectStatusText(shown3, hints), ...financeText(finance), ...dealsText(open2)].join("\n"), options.compact === true);
8729
9301
  }), "projectStatusCommand");
8730
9302
 
8731
9303
  // dist/knowledge/project-transfer.js
@@ -8858,73 +9430,142 @@ var RELATIONSHIP_QUERY = {
8858
9430
  entity: "relationship",
8859
9431
  backend: "native",
8860
9432
  fields: [
8861
- termField("about", "ref", 'about:"project:1"', {
8862
- relation: "the person, organization or project at either end"
9433
+ termField("about", "ref", 'about:"person:5"', {
9434
+ relation: "the person, organization, project, deal or lead at either end; each row says its direction"
8863
9435
  }),
8864
- termField("confirmed", "enum", "confirmed:false", { values: ["true", "false"] })
9436
+ termField("from", "ref", 'from:"person:5"', { relation: "the end that belongs, reports or relates" }),
9437
+ termField("to", "ref", 'to:"person:5"', { relation: "the end it belongs, reports or relates to" }),
9438
+ termField("kind", "enum", "kind:reports-to", { values: RELATION_KINDS }),
9439
+ termField("role", "kw", "role:decision-maker"),
9440
+ termField("standing", "enum", "standing:reported", { values: STANDINGS }),
9441
+ termField("confirmed", "enum", "confirmed:false", { values: ["true", "false"] }),
9442
+ termField("at", "kw", "at:2026-10-01", { relation: "held at the start of that UTC day" }),
9443
+ termField("include", "enum", "include:ended", { values: ["ended"] })
8865
9444
  ]
8866
9445
  };
8867
- var PENDING_LIMIT = 50;
8868
- var pending = /* @__PURE__ */ __name(async (store, about) => {
8869
- const found = await proposalRegistry(store).list({
8870
- kinds: ["relationship"],
8871
- status: "proposed",
8872
- ...about?.startsWith("project:") ? { project: about } : {},
8873
- limit: PENDING_LIMIT,
8874
- offset: 0
8875
- });
8876
- const payloads = new Map((await store.proposedActions.list({ kinds: ["relationship"], status: "proposed", limit: 500 })).map((one2) => [
8877
- one2.id,
8878
- one2.payload ?? {}
8879
- ]));
8880
- const rows = found.items.filter((row) => about === void 0 || row.subject === about || row.object === about);
8881
- return {
8882
- hasMore: found.hasMore,
8883
- items: rows.map((row) => ({
8884
- id: row.id,
8885
- from: row.subject,
8886
- to: row.object,
8887
- kind: payloads.get(row.id)?.kind ?? null,
8888
- role: row.summary,
8889
- purpose: payloads.get(row.id)?.purpose ?? null,
8890
- evidence: row.reason,
8891
- confirmed: false,
8892
- status: "proposed",
8893
- proposer: proposerName(row.proposedBy),
8894
- score: row.score,
8895
- createdAt: row.createdAt
8896
- }))
8897
- };
8898
- }, "pending");
8899
- var listRelationships = /* @__PURE__ */ __name(async (store, words) => {
9446
+ var DAY9 = /^\d{4}-\d{2}-\d{2}$/;
9447
+ var atOf = /* @__PURE__ */ __name((day2) => {
9448
+ const at2 = Date.parse(`${day2}T00:00:00Z`);
9449
+ if (!DAY9.test(day2) || Number.isNaN(at2))
9450
+ throw new CliError("validation_error", `at: takes a day, such as at:2026-10-01 \u2014 not "${day2}"`, {
9451
+ reason: "input.invalid"
9452
+ });
9453
+ return at2;
9454
+ }, "atOf");
9455
+ var listRelationships = /* @__PURE__ */ __name(async (store, env, words, { limit, page, accounts, deniedKinds } = { limit: 100, page: 1 }) => {
8900
9456
  const terms2 = queryTerms(words, RELATIONSHIP_QUERY, "relationships list");
8901
- const about = terms2.get("about");
8902
9457
  const confirmed = terms2.get("confirmed");
8903
- const found = confirmed === "false" ? await pending(store, about) : {
8904
- hasMore: false,
8905
- items: byEngagement(await store.knowledge.relations(null, about)).filter((one2) => confirmed === void 0 || one2.confirmed).map((one2) => ({ ...one2, status: one2.confirmed ? "confirmed" : "proposed" }))
8906
- };
8907
- const label = await labelsFor(store, found.items.flatMap((one2) => [one2.from, one2.to]));
9458
+ const standing = terms2.get("standing") ?? (confirmed === "false" ? "proposed" : confirmed === "true" ? "confirmed" : void 0);
9459
+ const at2 = terms2.get("at");
9460
+ const found = await store.knowledge.listRelations({
9461
+ ...terms2.has("kind") ? { kind: terms2.get("kind") } : {},
9462
+ ...terms2.has("role") ? { role: terms2.get("role") } : {},
9463
+ ...terms2.has("from") ? { from: terms2.get("from") } : {},
9464
+ ...terms2.has("to") ? { to: terms2.get("to") } : {},
9465
+ ...terms2.has("about") ? { about: terms2.get("about") } : {},
9466
+ ...standing === void 0 ? {} : { standing },
9467
+ ...at2 === void 0 ? {} : { at: atOf(at2) },
9468
+ ...terms2.get("include") === "ended" ? { includeEnded: true } : {},
9469
+ ...accounts === void 0 ? {} : { accounts },
9470
+ ...deniedKinds?.length ? { deniedKinds } : {},
9471
+ limit,
9472
+ page
9473
+ });
9474
+ const guard = await guardOf(store, env);
9475
+ const rows = [];
9476
+ for (const one2 of found.items)
9477
+ if (guard === void 0 || await guard.visible(one2.from) && await guard.visible(one2.to))
9478
+ rows.push(one2);
9479
+ const label = await labelsFor(store, rows.flatMap((one2) => [one2.from, one2.to]));
8908
9480
  return {
8909
9481
  hasMore: found.hasMore,
8910
- limit: confirmed === "false" ? PENDING_LIMIT : Math.max(1, found.items.length),
8911
- items: found.items.map((one2) => ({ ...one2, fromTitle: label(one2.from), toTitle: label(one2.to) }))
9482
+ limit,
9483
+ page,
9484
+ items: await Promise.all(byEngagement(rows).map(async (one2) => ({
9485
+ ...one2,
9486
+ status: one2.standing,
9487
+ // Who proposed it is the review's to name; the list says it beside the proposal.
9488
+ ...one2.source === "proposal" ? { proposer: proposerName((await store.proposedActions.get(one2.id)).proposedBy) } : {},
9489
+ fromTitle: label(one2.from),
9490
+ toTitle: label(one2.to)
9491
+ })))
8912
9492
  };
8913
9493
  }, "listRelationships");
8914
9494
  var relationshipsText = /* @__PURE__ */ __name((items) => items.length ? items.map((one2) => [
8915
9495
  one2.id,
8916
9496
  `${one2.fromTitle} \u2192 ${one2.toTitle}`,
8917
9497
  [
8918
- one2.kind,
8919
- one2.role && `as ${one2.role}`,
9498
+ one2.direction === "incoming" ? one2.inverse ?? one2.kind : one2.kind,
9499
+ one2.role && `as ${one2.role}${one2.custom ? " (custom)" : ""}`,
8920
9500
  "roleNote" in one2 && one2.roleNote && `(${one2.roleNote})`,
9501
+ one2.position && `(${one2.position})`,
8921
9502
  one2.purpose && `for ${one2.purpose}`,
8922
9503
  "engagement" in one2 && one2.engagement && `engagement ${one2.engagement}`
8923
9504
  ].filter(Boolean).join(" "),
8924
- "proposer" in one2 ? `proposed by ${one2.proposer}` : one2.confirmed ? "" : "suggested"
9505
+ "proposer" in one2 ? `proposed by ${one2.proposer}` : [one2.standing, one2.account && `by ${one2.account}`].filter(Boolean).join(" ")
8925
9506
  ].filter(Boolean).join(" ")).join("\n") : "no relationships", "relationshipsText");
8926
9507
 
9508
+ // dist/knowledge/roles-command.js
9509
+ var LISTS = ["organization", "project", "deal"];
9510
+ var ROLES_QUERY = {
9511
+ entity: "relationship_role",
9512
+ backend: "native",
9513
+ fields: [termField("list", "enum", "list:organization", { values: LISTS })]
9514
+ };
9515
+ var LIST_HELP = "organization (roles in an organization), project or deal (a deal's or a lead's)";
9516
+ var ownerOnly = /* @__PURE__ */ __name(async (command, env, asOwner, question) => {
9517
+ if (await whoRuns(command, env, { asOwner, question }) !== "owner")
9518
+ throw new CliError("permission_error", "only the owner changes the role lists; an agent uses the roles they hold", {
9519
+ reason: "roles.owner-only"
9520
+ });
9521
+ }, "ownerOnly");
9522
+ var relationshipRolesCommand = /* @__PURE__ */ __name((relations, { print }, env) => {
9523
+ const roles = relations.command("roles").description("the roles a relationship may take: built in and your own");
9524
+ const rows = /* @__PURE__ */ __name(async (lists) => withStore(env, async (store) => (await Promise.all(lists.map(async (list) => (await store.knowledge.roles(list)).map((one2) => ({ list, ...one2 }))))).flat()), "rows");
9525
+ const show = /* @__PURE__ */ __name(async (json5, command, lists) => {
9526
+ const items = await rows(lists);
9527
+ print(json5, listAnswer(command, { items, limit: Math.max(1, items.length), has_more: false }), items.map(({ list, id, label, builtIn }) => `${list} ${id}${label ? ` ${label}` : ""}${builtIn ? "" : " (yours)"}`).join("\n"));
9528
+ }, "show");
9529
+ withQuery(annotate(roles.command("list"), { effects: LOCAL_READ, output: { entity: "relationship_role" } }), ROLES_QUERY).description("the roles of every list, or of one with list:organization, list:project or list:deal; each built in or yours").summary("the roles a relationship may take").option("--json", "print JSON; --json=id,title keeps only those fields").action((words, options) => {
9530
+ const list = queryTerms(words, ROLES_QUERY, "relationships roles list").get("list");
9531
+ return show(options.json, "relationships roles list", list === void 0 ? LISTS : [list]);
9532
+ });
9533
+ byOption(annotate(roles.command("add"), { effects: LOCAL_WRITE, output: { entity: "relationship_role" } }).description("add a role of your own to a list; relationships may then take it. Only you change the lists").summary("add a role of your own").argument("<list>", LIST_HELP, oneOf(LISTS)).argument("<role>", "the role's id: lowercase letters, digits and -, such as board-member").option("--label <label>", "how it reads, such as 'Board member'").option("--json", "print JSON; --json=id,title keeps only those fields")).action(async (list, role, options, command) => {
9534
+ await ownerOnly(command, env, options.asOwner, `add the ${list} role ${role} as you?`);
9535
+ await withStore(env, (store) => store.knowledge.addRole(list, role, options.label));
9536
+ await show(options.json, "relationships roles add", [list]);
9537
+ });
9538
+ byOption(annotate(roles.command("remove"), { effects: LOCAL_WRITE, output: { entity: "relationship_role" } }).description("remove a role of your own; a built-in one stays, and one a relationship still holds is refused").summary("remove a role of your own").argument("<list>", LIST_HELP, oneOf(LISTS)).argument("<role>", "the role's id").option("--json", "print JSON; --json=id,title keeps only those fields")).action(async (list, role, options, command) => {
9539
+ await ownerOnly(command, env, options.asOwner, `remove the ${list} role ${role} as you?`);
9540
+ await withStore(env, (store) => store.knowledge.removeRole(list, role));
9541
+ await show(options.json, "relationships roles remove", [list]);
9542
+ });
9543
+ }, "relationshipRolesCommand");
9544
+
8927
9545
  // dist/knowledge/command.js
9546
+ var ROLE_HELP = `its role: in an organization ${ORGANIZATION_ROLES.join(", ")}; in a project ${PROJECT_ROLES.join(", ")}; on a deal or lead ${DEAL_ROLES.join(", ")}. A job title is not a role`;
9547
+ var ORGANIZATIONS_LIST_QUERY = {
9548
+ ...ORGANIZATIONS_QUERY,
9549
+ fields: [
9550
+ ...ORGANIZATIONS_QUERY.fields,
9551
+ termField("category", "enum", "category:client", {
9552
+ values: CATEGORIES,
9553
+ relation: "what its relationships with your own organizations, or yours with it, make it"
9554
+ })
9555
+ ]
9556
+ };
9557
+ var categoryOf = /* @__PURE__ */ __name((words) => {
9558
+ const named5 = words.map((word) => /^category:(.+)$/.exec(word)?.[1]);
9559
+ const category = named5.find((one2) => one2 !== void 0);
9560
+ return { ...category === void 0 ? {} : { category }, rest: words.filter((_, at2) => named5[at2] === void 0) };
9561
+ }, "categoryOf");
9562
+ var dayOption = /* @__PURE__ */ __name((value) => {
9563
+ const at2 = Date.parse(`${value}T00:00:00Z`);
9564
+ if (!/^\d{4}-\d{2}-\d{2}$/.test(value) || Number.isNaN(at2))
9565
+ throw new InvalidArgumentError("a day, such as 2026-01-01");
9566
+ return at2;
9567
+ }, "dayOption");
9568
+ var lastDayOption = /* @__PURE__ */ __name((value) => dayOption(value) + 864e5, "lastDayOption");
8928
9569
  var pendingLink = /* @__PURE__ */ __name(async (store, id) => {
8929
9570
  try {
8930
9571
  return await proposalRegistry(store).get(`link:${id}`);
@@ -8941,17 +9582,6 @@ var knowledgeCommands = /* @__PURE__ */ __name((program, streams, env) => {
8941
9582
  const act = /* @__PURE__ */ __name((options, work) => run(options.json, async (store) => work(store, await writeAccount(store, env, options, warn))), "act");
8942
9583
  const owned = /* @__PURE__ */ __name((options, work) => run(options.json, async (store) => itemAnswer(await work(store))), "owned");
8943
9584
  const ownedList = /* @__PURE__ */ __name((command, options, work) => run(options.json, async (store) => wholeList(command, await work(store))), "ownedList");
8944
- const contextOf = /* @__PURE__ */ __name(async (store, thing, type, reference2) => {
8945
- if (thing === void 0)
8946
- throw new CliError("not_found", `no ${type} ${reference2}; memo ${type}s list shows them`);
8947
- const { id } = thing;
8948
- return {
8949
- [type]: thing,
8950
- relationships: (await store.notes.links({ to: `${type}:${id}` })).concat(await store.notes.links({ from: `${type}:${id}` })).filter((link2) => link2.kind !== "about" && link2.kind !== "links-to" && link2.role !== "key"),
8951
- notes: await notesAbout(store, { ref: `${type}:${id}` }),
8952
- tags: await store.knowledge.tags(null, { type, id })
8953
- };
8954
- }, "contextOf");
8955
9585
  const organizations = program.command("organizations").description("companies, teams, families and communities of yours");
8956
9586
  annotate(organizations.command("add"), { effects: LOCAL_WRITE, literal_after_dashes: true }).description("add an organization of yours: a company, team, family or community; it is written at once, whoever runs it").summary("add an organization").argument("<name>", "the organization's name").requiredOption("--kind <kind>", ORGANIZATION_KINDS.join(", "), oneOf(ORGANIZATION_KINDS)).option("--scope <scope>", SCOPES.join(", "), oneOf(SCOPES)).option("--json", "print JSON; --json=id,title keeps only those fields").action((name2, options) => owned(options, (store) => store.knowledge.addOrganization({
8957
9587
  kind: options.kind,
@@ -8966,14 +9596,38 @@ var knowledgeCommands = /* @__PURE__ */ __name((program, streams, env) => {
8966
9596
  throw new CliError("not_found", `no organization ${reference2}; memo organizations list shows them`);
8967
9597
  return found;
8968
9598
  }));
8969
- withQuery(annotate(organizations.command("list"), { effects: LOCAL_READ }), ORGANIZATIONS_QUERY).description("your organizations").option("--json", "print JSON; --json=id,title keeps only those fields").action((words, options) => {
8970
- const query = listQuery(typedQuery(words), ORGANIZATIONS_QUERY, "organizations list");
8971
- return ownedList("organizations list", options, (store) => store.knowledge.organizations(query));
9599
+ withQuery(annotate(organizations.command("list"), { effects: LOCAL_READ }), ORGANIZATIONS_LIST_QUERY).description("your organizations; category:client, supplier, partner or employer keeps those its relationships make so").summary("your organizations").option("--json", "print JSON; --json=id,title keeps only those fields").action((words, options) => {
9600
+ const { category, rest } = categoryOf(words);
9601
+ const query = listQuery(typedQuery(rest), ORGANIZATIONS_QUERY, "organizations list");
9602
+ return ownedList("organizations list", options, async (store) => {
9603
+ const scope = await groupScopeOf(store, env);
9604
+ const found = await store.knowledge.organizations(query, {
9605
+ ...category === void 0 ? {} : { category },
9606
+ ...scope === void 0 ? {} : { accounts: scope.accounts }
9607
+ });
9608
+ return keepInGroup(store, env, found, ({ ref }) => ref);
9609
+ });
9610
+ });
9611
+ annotate(organizations.command("context"), {
9612
+ effects: LOCAL_READ,
9613
+ output: { entity: "organization_context_memo" }
9614
+ }).description("one organization by its id or organization:<id>: its people by role, customers, suppliers and partners, projects, open deals and leads, invoices, payments and orders, how much its people wrote, open tasks and categories, each relationship with its standing; then the notes about it and its tags. `coverage` names what was not read").summary("one organization: people, customers, deals, money, tasks, notes").argument("<organization>", "its id or organization:<id>").option("--limit <n>", "most items in each section", positive, 20).option("--json", "print JSON; --json=id,title keeps only those fields").action(async (reference2, options, command) => {
9615
+ const answer = await withStore(env, async (store) => {
9616
+ const scope = await groupScopeOf(store, env);
9617
+ const found = await organizationContext(store, reference2, {
9618
+ limit: options.limit,
9619
+ ...scope === void 0 ? {} : { accounts: scope.accounts },
9620
+ deniedKinds: deniedCrmKinds(command, env)
9621
+ });
9622
+ const ref = found.organization.ref;
9623
+ return lockedCoverage(store, env, {
9624
+ ...found,
9625
+ notes: await notesAbout(store, { ref }),
9626
+ tags: await store.knowledge.tags(null, { type: "organization", id: ref.slice("organization:".length) })
9627
+ });
9628
+ });
9629
+ print(options.json, itemAnswer(answer), organizationText(answer));
8972
9630
  });
8973
- annotate(organizations.command("context"), { effects: LOCAL_READ }).description("one organization by its id or organization:<id>: its relationships, the notes about or linking it, and its tags").summary("one organization: its relationships, notes and tags").argument("<organization>", "its id or organization:<id>").option("--json", "print JSON; --json=id,title keeps only those fields").action((reference2, options) => owned(options, async (store) => {
8974
- const wanted = reference2.replace(/^organization:/, "");
8975
- return contextOf(store, (await store.knowledge.organizations()).find((organization) => organization.id === wanted), "organization", reference2);
8976
- }));
8977
9631
  const projects = program.command("projects").description("projects of yours, each with a short key");
8978
9632
  meetingProjectsCommand(projects, streams, env);
8979
9633
  annotate(projects.command("add"), { effects: LOCAL_WRITE, literal_after_dashes: true }).description("add a project of yours, with a short key its tasks use").argument("<name>", "the project's name").option("--key <key>", "3\u20134 letters and digits; made from the name when left out").option("--type <type>", PROJECT_TYPES.join(", "), oneOf(PROJECT_TYPES)).option("--organization <organization>", "the organization it belongs to: its id or organization:<id>").option("--scope <scope>", SCOPES.join(", "), oneOf(SCOPES)).option("--json", "print JSON; --json=id,title keeps only those fields").action((name2, options) => owned(options, (store) => store.knowledge.addProject({
@@ -8989,7 +9643,7 @@ var knowledgeCommands = /* @__PURE__ */ __name((program, streams, env) => {
8989
9643
  });
8990
9644
  annotate(projects.command("context"), { effects: LOCAL_READ }).description("one project by its id, project:<id>, key, exact name or alias: its key documents first, then its relationships, notes, tags, pending findings and open tasks. Review proposals together; nothing is confirmed. `review.waiting` counts what waits for you, by kind, and `next` names the command that lists them").summary("one project: key documents, pending findings and open tasks; start work here").argument("<project>", "its id, project:<id>, key, exact name or alias").option("--json", "print JSON; --json=id,title keeps only those fields").action(async (reference2, options) => {
8991
9645
  const { context, next } = await withStore(env, async (store) => {
8992
- const context2 = await projectContext(store, env, reference2);
9646
+ const context2 = await stripped(store, env, await projectContext(store, env, reference2));
8993
9647
  return { context: context2, next: await scanStep(store, context2.project, "all") };
8994
9648
  });
8995
9649
  print(options.json, itemAnswer(context, next.length ? { next } : {}), projectContextText(context));
@@ -9012,7 +9666,7 @@ var knowledgeCommands = /* @__PURE__ */ __name((program, streams, env) => {
9012
9666
  return ownedList("projects key-documents list", options, async (store) => keyDocuments(store, await projectOf(store, project), id === void 0 ? {} : { id }));
9013
9667
  });
9014
9668
  const relations = program.command("relationships").description("relations between people, organizations and projects; never between identities");
9015
- byOption(annotate(relations.command("add"), { effects: LOCAL_WRITE }).description("state that a person, organization or project belongs to or relates to another, or that a chat is a project's (member-of only); an agent's waits for you to confirm it").summary("state that a person, organization, project or chat belongs or relates to another")).argument("<from>", "the person:, organization: or project: that belongs or relates, or chat:<provider>/<account>/<chat> of a project").argument("<to>", "the person:, organization: or project: it belongs or relates to").option("--json", "print JSON; --json=id,title keeps only those fields").option("--kind <kind>", "member-of or related-to", "member-of").option("--role <role>", "the role it has there; a person's role in an organization or a project is one from its list, such as employee or contributor").option("--role-note <text>", "what the role means here, in your words, beside a role from its list").option("--engagement <level>", ENGAGEMENT_HELP, oneOf(ENGAGEMENT_LEVELS)).option("--reason <text>", "why you think so, in a sentence").action(async (from, to, options, command) => {
9669
+ byOption(annotate(relations.command("add"), { effects: LOCAL_WRITE }).description("state that a person, organization or project belongs to, reports to, is a customer or partner of, or relates to another, or that a chat is a project's (member-of only); an agent's waits for you to confirm it").summary("state that a person, organization, project or chat belongs or relates to another")).argument("<from>", "the person:, organization: or project: that belongs or relates, or chat:<provider>/<account>/<chat> of a project").argument("<to>", "the person:, organization: or project: it belongs or relates to").option("--json", "print JSON; --json=id,title keeps only those fields").option("--kind <kind>", RELATION_KINDS.join(", "), oneOf(RELATION_KINDS), "member-of").option("--role <role>", ROLE_HELP).option("--role-note <text>", "what the role means here, in your words, beside a role from its list").option("--engagement <level>", ENGAGEMENT_HELP, oneOf(ENGAGEMENT_LEVELS)).option("--position <title>", "the job title, such as 'Procurement manager'; kept apart from the role").option("--start-date <date>", "the first day it held, such as 2026-01-01", dayOption).option("--end-date <date>", "the last day it held, included; it ends at the start of the day after", lastDayOption).option("--reason <text>", "why you think so, in a sentence").action(async (from, to, options, command) => {
9016
9670
  const by = await whoRuns(command, env, { asOwner: options.asOwner, question: "state it as yours?" });
9017
9671
  return owned(options, async (store) => {
9018
9672
  const input = {
@@ -9022,27 +9676,46 @@ var knowledgeCommands = /* @__PURE__ */ __name((program, streams, env) => {
9022
9676
  ...options.role === void 0 ? {} : { role: options.role },
9023
9677
  ...options.roleNote === void 0 ? {} : { roleNote: options.roleNote },
9024
9678
  ...options.engagement === void 0 ? {} : { engagement: options.engagement },
9679
+ ...options.position === void 0 ? {} : { position: options.position },
9680
+ ...options.startDate === void 0 ? {} : { startsAt: options.startDate },
9681
+ ...options.endDate === void 0 ? {} : { endsAt: options.endDate },
9025
9682
  ...options.reason === void 0 ? {} : { evidence: options.reason }
9026
9683
  };
9027
9684
  return by === "owner" ? store.knowledge.relate(null, { ...input, by }) : store.knowledge.relate(null, { ...input, by });
9028
9685
  });
9029
9686
  });
9030
- withQuery(annotate(relations.command("list"), { effects: LOCAL_READ }).description("relationships, all or those of one reference, with titles; confirmed:false lists the proposals waiting for you, as memo review kind:relationship does").summary("relationships with titles; confirmed:false lists those waiting for you"), RELATIONSHIP_QUERY).option("--json", "print JSON; --json=id,title keeps only those fields").action(async (words, options) => {
9031
- const found = await withStore(env, (store) => listRelationships(store, words));
9032
- print(options.json, listAnswer("relationships list", { items: found.items, limit: found.limit, has_more: found.hasMore }), relationshipsText(found.items));
9687
+ withQuery(annotate(relations.command("list"), { effects: LOCAL_READ }).description("relationships, all or those of one reference, with titles; confirmed:false lists the proposals waiting for you, as memo review kind:relationship does").summary("relationships with titles; confirmed:false lists those waiting for you"), RELATIONSHIP_QUERY).option("--limit <n>", "most relationships, up to 500", (value) => Math.min(positive(value), 500), 100).option("--page <n>", "which page, from 1", positive, 1).option("--json", "print JSON; --json=id,title keeps only those fields").action(async (words, options, command) => {
9688
+ const found = await withStore(env, async (store) => {
9689
+ const scope = await groupScopeOf(store, env);
9690
+ return listRelationships(store, env, words, {
9691
+ limit: options.limit,
9692
+ page: options.page,
9693
+ ...scope === void 0 ? {} : { accounts: scope.accounts },
9694
+ deniedKinds: deniedCrmKinds(command, env)
9695
+ });
9696
+ });
9697
+ print(options.json, listAnswer("relationships list", {
9698
+ items: found.items,
9699
+ limit: found.limit,
9700
+ has_more: found.hasMore,
9701
+ page: found.page,
9702
+ args: { query: words.join(" ") }
9703
+ }), relationshipsText(found.items));
9033
9704
  });
9034
- byOption(annotate(relations.command("update"), { effects: LOCAL_WRITE }).description("set what a relationship is: its role and a note beside it, how much you deal with a person on a project, or what a chat is for in a project (work, sales, support, other); an agent's change waits for you in memo review").summary("set a relationship's role, engagement or a chat's purpose in a project").argument("<id>", "the relationship's id, as relationships list gives it").option("--role <role>", "the role it has there, from the same list as relationships add; an empty value clears it").option("--role-note <text>", "what the role means here, in your words; an empty value clears it").option("--engagement <level>", `${ENGAGEMENT_HELP}; an empty value clears it`, (value) => value === "" ? "" : oneOf(ENGAGEMENT_LEVELS)(value)).option("--purpose <purpose>", "what the chat is for in the project: work, sales, support or other").option("--reason <text>", "why, in a sentence").option("--json", "print JSON; --json=id,title keeps only those fields")).action(async (id, options, command) => {
9705
+ byOption(annotate(relations.command("update"), { effects: LOCAL_WRITE }).description("set what a relationship is: its role and a note beside it, how much you deal with a person on a project, or what a chat is for in a project (work, sales, support, other); an agent's change waits for you in memo review").summary("set a relationship's role, engagement or a chat's purpose in a project").argument("<id>", "the relationship's id, as relationships list gives it").option("--role <role>", `${ROLE_HELP}; an empty value clears it`).option("--role-note <text>", "what the role means here, in your words; an empty value clears it").option("--engagement <level>", `${ENGAGEMENT_HELP}; an empty value clears it`, (value) => value === "" ? "" : oneOf(ENGAGEMENT_LEVELS)(value)).option("--position <title>", "the job title; an empty value clears it").option("--start-date <date>", "the first day it held, such as 2026-01-01", dayOption).option("--purpose <purpose>", "what the chat is for in the project: work, sales, support or other").option("--reason <text>", "why, in a sentence").option("--json", "print JSON; --json=id,title keeps only those fields")).action(async (id, options, command) => {
9035
9706
  const cleared = /* @__PURE__ */ __name((value) => value === "" ? null : value, "cleared");
9036
9707
  const change = {
9037
9708
  ...options.role === void 0 ? {} : { role: cleared(options.role) },
9038
9709
  ...options.roleNote === void 0 ? {} : { roleNote: cleared(options.roleNote) },
9039
9710
  ...options.engagement === void 0 ? {} : { engagement: cleared(options.engagement) },
9711
+ ...options.position === void 0 ? {} : { position: cleared(options.position) },
9712
+ ...options.startDate === void 0 ? {} : { startsAt: options.startDate },
9040
9713
  ...options.purpose === void 0 ? {} : { purpose: options.purpose }
9041
9714
  };
9042
9715
  const by = await whoRuns(command, env, { asOwner: options.asOwner, question: `change relationship ${id}?` });
9043
- return owned(options, (store) => {
9044
- if (!Object.keys(change).length)
9045
- throw new CliError("validation_error", "say what to change: --role, --role-note, --engagement or --purpose", {
9716
+ return owned(options, async (store) => {
9717
+ if (Object.keys(change).length === 0)
9718
+ throw new CliError("validation_error", "say what to change: --role, --role-note, --engagement, --position, --start-date or --purpose", {
9046
9719
  reason: "input.invalid",
9047
9720
  param: "--purpose"
9048
9721
  });
@@ -9068,12 +9741,20 @@ var knowledgeCommands = /* @__PURE__ */ __name((program, streams, env) => {
9068
9741
  const suggestion = await pendingLink(store, id);
9069
9742
  if (suggestion === void 0)
9070
9743
  return name2 === "remove" ? store.knowledge.removeRelation(null, id, by) : store.knowledge.confirmRelation(null, id, by);
9071
- await decideOne(store, suggestion.id, decisionOf(name2 === "confirm", by, options.reason));
9744
+ await decideOne(store, env, suggestion.id, decisionOf(name2 === "confirm", by, options.reason));
9072
9745
  if (name2 === "remove")
9073
9746
  return { id, removed: true };
9074
9747
  return (await store.knowledge.relations(null, suggestion.subject)).find((one2) => one2.id === id);
9075
9748
  });
9076
9749
  });
9750
+ byOption(annotate(relations.command("end"), { effects: LOCAL_WRITE }).description("say that a relationship no longer holds, from a day on; it stays, as ended, and relationships list include:ended shows it. An agent's waits for you in memo review").summary("say that a relationship ended").argument("<id>", "the relationship's id, as relationships list gives it").option("--end-date <date>", "the last day it held, included; it ends at the start of the day after. Today when left out", lastDayOption).option("--json", "print JSON; --json=id,title keeps only those fields")).action(async (id, options, command) => {
9751
+ const by = await whoRuns(command, env, { asOwner: options.asOwner, question: `end relationship ${id}?` });
9752
+ const at2 = options.endDate ?? Date.now();
9753
+ return owned(options, async (store) => {
9754
+ return by === "owner" ? store.knowledge.endRelation(null, id, at2, by) : store.knowledge.endRelation(null, id, at2, by);
9755
+ });
9756
+ });
9757
+ relationshipRolesCommand(relations, { print }, env);
9077
9758
  relationshipsScanCommand(relations, print, env, warn);
9078
9759
  const reminders = program.command("reminders").description("durable local reminders; poll hands one out and ack confirms it was shown");
9079
9760
  writeScope(annotate(reminders.command("add"), { effects: LOCAL_WRITE }).description("add a reminder for an open task").argument("<task>", "the task's id")).requiredOption("--at-time <time>", "when to remind: an ISO 8601 time with its UTC offset").option("--timezone <zone>", "IANA timezone; the computer's when not given").action((task, options) => act(options, async (store, key) => {
@@ -9506,9 +10187,9 @@ var messagesCommand = /* @__PURE__ */ __name((program, streams, env) => {
9506
10187
  }, "messagesCommand");
9507
10188
 
9508
10189
  // dist/mcp/command.js
9509
- import { join as join8 } from "node:path";
10190
+ import { join as join9 } from "node:path";
9510
10191
  var DEFAULT_PORT = 8767;
9511
- var httpTokenFile = /* @__PURE__ */ __name((env) => join8(resolvePaths({ appName: APP.appName, prefix: APP.envPrefix, env }).state, "mcp-http", "memo.json"), "httpTokenFile");
10192
+ var httpTokenFile = /* @__PURE__ */ __name((env) => join9(resolvePaths({ appName: APP.appName, prefix: APP.envPrefix, env }).state, "mcp-http", "memo.json"), "httpTokenFile");
9512
10193
  var mcpCommandDefinition = /* @__PURE__ */ __name((program, streams, env, createProgram2) => {
9513
10194
  const out = answers(program, streams, env);
9514
10195
  const mcp2 = annotate(program.command("mcp"), { effects: LOCAL_READ, mcp: false }).summary("serve this profile's commands to an AI agent, and set that up").description("serve memo commands over MCP on stdio or authenticated HTTP, limited by saved permissions \u2014 `claude mcp add memo -- memo mcp serve`");
@@ -9520,10 +10201,10 @@ var mcpCommandDefinition = /* @__PURE__ */ __name((program, streams, env, create
9520
10201
  }).summary("serve this profile's commands to an AI agent").description("serve memo commands over MCP on stdio or authenticated HTTP, limited by saved permissions").option("--permission <key=level>", "tighten one saved permission for this server; repeat for more keys", (value, previous = []) => [...previous, value]).option("--http", "serve on 127.0.0.1 behind an HTTPS tunnel with an owner access-code login").option("--port <port>", `local HTTP port (default ${DEFAULT_PORT}); requires --http`).option("--public-url <url>", "tunnel's HTTPS address without /mcp, or a path of it such as https://<name>.ts.net/memo; requires --http").action(async (options) => {
9521
10202
  if (!options.http && (options.port !== void 0 || options.publicUrl !== void 0))
9522
10203
  throw new CliError("validation_error", "--port and --public-url require --http");
9523
- const { createMemoServer } = await import("./server-JLPZUC42.js");
10204
+ const { createMemoServer } = await import("./server-LWQAHDBH.js");
9524
10205
  const build = /* @__PURE__ */ __name(() => createMemoServer(env, createProgram2, options.permission), "build");
9525
10206
  if (options.http) {
9526
- const { httpLockFile, mcpUrlOf, portOf, publicUrlOf, serveOverHttp } = await import("./mcp-CFIL7WZU.js");
10207
+ const { httpLockFile, mcpUrlOf, portOf, publicUrlOf, serveOverHttp } = await import("./mcp-FQPK2KAF.js");
9527
10208
  const publicUrl = publicUrlOf(options.publicUrl, {
9528
10209
  missing: "--http",
9529
10210
  reaches: "the browser apps reach memo",
@@ -9575,7 +10256,7 @@ var mcpCommandDefinition = /* @__PURE__ */ __name((program, streams, env, create
9575
10256
  });
9576
10257
  });
9577
10258
  annotate(mcp2.command("revoke"), { effects: LOCAL_WRITE, mcp: false, examples: ["memo mcp revoke --json"] }).summary("forget every login given to a browser app").description("forget every login `memo mcp serve --http` gave a browser app; each app must log in again").option("--json", "print JSON").action(async function() {
9578
- const { revokeAll } = await import("./mcp-CFIL7WZU.js");
10259
+ const { revokeAll } = await import("./mcp-FQPK2KAF.js");
9579
10260
  revokeAll(httpTokenFile(env));
9580
10261
  out.print(this.opts().json, itemAnswer({ revoked: true }));
9581
10262
  });
@@ -9850,7 +10531,7 @@ may be ${found.candidates.join(", ")}` : ""));
9850
10531
  }, "mentionsCommand");
9851
10532
 
9852
10533
  // dist/models/command.js
9853
- var modelsCommand = /* @__PURE__ */ __name((program, streams, env, keyring) => {
10534
+ var modelsCommand = /* @__PURE__ */ __name((program, streams, env, keyring, stdin) => {
9854
10535
  const { print } = answers(program, streams, env);
9855
10536
  program.addCommand(modelCatalogueCommand(APP, {
9856
10537
  kinds: ["text"],
@@ -9859,6 +10540,7 @@ var modelsCommand = /* @__PURE__ */ __name((program, streams, env, keyring) => {
9859
10540
  jsonOption: true,
9860
10541
  env: /* @__PURE__ */ __name(() => env, "env"),
9861
10542
  ...keyring ? { keyring } : {},
10543
+ ...stdin ? { stdin: /* @__PURE__ */ __name(() => stdin, "stdin") } : {},
9862
10544
  output: /* @__PURE__ */ __name((body, command) => print(command.optsWithGlobals().json, body), "output"),
9863
10545
  diagnostic: /* @__PURE__ */ __name((line3) => streams.diagnostic(line3), "diagnostic"),
9864
10546
  offline: /* @__PURE__ */ __name(() => program.opts().offline === true, "offline")
@@ -9866,7 +10548,7 @@ var modelsCommand = /* @__PURE__ */ __name((program, streams, env, keyring) => {
9866
10548
  }, "modelsCommand");
9867
10549
 
9868
10550
  // dist/notes/command.js
9869
- import { readFileSync as readFileSync8 } from "node:fs";
10551
+ import { readFileSync as readFileSync9 } from "node:fs";
9870
10552
 
9871
10553
  // dist/people/identity.js
9872
10554
  var identityOf = /* @__PURE__ */ __name(async (store, reference2) => {
@@ -9904,8 +10586,8 @@ import { resolve as resolve3 } from "node:path";
9904
10586
 
9905
10587
  // dist/notes/export.js
9906
10588
  import { createHash as createHash3 } from "node:crypto";
9907
- import { existsSync as existsSync8, mkdirSync as mkdirSync3, readdirSync as readdirSync6, readFileSync as readFileSync7, renameSync as renameSync2, writeFileSync as writeFileSync3 } from "node:fs";
9908
- import { join as join9 } from "node:path";
10589
+ import { existsSync as existsSync9, mkdirSync as mkdirSync3, readdirSync as readdirSync6, readFileSync as readFileSync8, renameSync as renameSync2, writeFileSync as writeFileSync4 } from "node:fs";
10590
+ import { join as join10 } from "node:path";
9909
10591
  var HASH_LINE = /^memo-hash: .*\r?\n/m;
9910
10592
  var PLACEHOLDER = "f".repeat(64);
9911
10593
  var UNSAFE = /[\\/:*?"<>|#^[\]\p{Cc}]/gu;
@@ -9929,7 +10611,7 @@ var exportedIn = /* @__PURE__ */ __name((dir) => {
9929
10611
  for (const entry of readdirSync6(dir, { withFileTypes: true })) {
9930
10612
  if (!entry.isFile() || !/\.(md|markdown)$/i.test(entry.name))
9931
10613
  continue;
9932
- const id = readMemoId(join9(dir, entry.name));
10614
+ const id = readMemoId(join10(dir, entry.name));
9933
10615
  if (id !== null)
9934
10616
  found.set(id, entry.name);
9935
10617
  }
@@ -9946,11 +10628,11 @@ var exportNotes = /* @__PURE__ */ __name(({ dir, dialect, notes: notes2 }) => {
9946
10628
  frontMatter["memo-hash"] = PLACEHOLDER;
9947
10629
  const content = withHash(dialect.render({ ...note, frontMatter }));
9948
10630
  const known2 = existing.get(id);
9949
- const name2 = known2 ?? fileName(note.title, id, (candidate) => claimed.has(candidate) || existsSync8(join9(dir, candidate)));
10631
+ const name2 = known2 ?? fileName(note.title, id, (candidate) => claimed.has(candidate) || existsSync9(join10(dir, candidate)));
9950
10632
  claimed.add(name2);
9951
- const path = join9(dir, name2);
10633
+ const path = join10(dir, name2);
9952
10634
  if (known2 !== void 0) {
9953
- const current = readFileSync7(path, "utf8");
10635
+ const current = readFileSync8(path, "utf8");
9954
10636
  if (editedSinceExport(current)) {
9955
10637
  result.edited.push({ path, id });
9956
10638
  continue;
@@ -9960,8 +10642,8 @@ var exportNotes = /* @__PURE__ */ __name(({ dir, dialect, notes: notes2 }) => {
9960
10642
  continue;
9961
10643
  }
9962
10644
  }
9963
- const partial = join9(dir, `.${name2}.memo-tmp`);
9964
- writeFileSync3(partial, content);
10645
+ const partial = join10(dir, `.${name2}.memo-tmp`);
10646
+ writeFileSync4(partial, content);
9965
10647
  renameSync2(partial, path);
9966
10648
  result.written.push(path);
9967
10649
  }
@@ -10061,7 +10743,7 @@ var textOf = /* @__PURE__ */ __name((options, given2) => {
10061
10743
  if (sources.length !== 1)
10062
10744
  throw new CliError("validation_error", "give the text once: as an argument, --text or --text-file");
10063
10745
  if (options.textFile !== void 0)
10064
- return readFileSync8(options.textFile === "-" ? 0 : options.textFile, "utf8");
10746
+ return readFileSync9(options.textFile === "-" ? 0 : options.textFile, "utf8");
10065
10747
  return sources[0];
10066
10748
  }, "textOf");
10067
10749
  var noteOf = /* @__PURE__ */ __name(async (store, env, reference2) => {
@@ -10129,11 +10811,14 @@ var notesCommandDefinition = /* @__PURE__ */ __name((program, streams, env) => {
10129
10811
  if (about !== void 0 && terms2.size > 1)
10130
10812
  throw new CliError("validation_error", "about: stands alone in notes list: its notes are found through links");
10131
10813
  const options = { ...paging, json: json5 };
10132
- const page = await withNotes(async (store) => listNotes(store, {
10133
- limit: options.limit,
10134
- offset: (options.page - 1) * options.limit,
10135
- ...about === void 0 ? { ...source === void 0 ? {} : { source }, ...search2 === void 0 ? {} : { search: search2 } } : { about: await subjectOf(store, about) }
10136
- }));
10814
+ const page = await withNotes(async (store) => {
10815
+ const found = await listNotes(store, {
10816
+ limit: options.limit,
10817
+ offset: (options.page - 1) * options.limit,
10818
+ ...about === void 0 ? { ...source === void 0 ? {} : { source }, ...search2 === void 0 ? {} : { search: search2 } } : { about: await subjectOf(store, about) }
10819
+ });
10820
+ return { ...found, items: await keepInGroup(store, env, found.items, ({ ref }) => ref) };
10821
+ });
10137
10822
  print(options.json, listAnswer("notes list", {
10138
10823
  items: page.items,
10139
10824
  limit: options.limit,
@@ -10156,7 +10841,7 @@ var notesCommandDefinition = /* @__PURE__ */ __name((program, streams, env) => {
10156
10841
  const answer = await withNotes(async (store) => {
10157
10842
  const about = await Promise.all((options.subject ?? []).map(async (subject) => (await subjectOf(store, subject)).ref));
10158
10843
  if (options.meeting !== void 0)
10159
- about.push(await meetingReference(store, options.meeting, value === void 0 ? {} : await oneAccountOf(store, env, value, "--account")));
10844
+ about.push(await meetingReference(store, env, options.meeting, value === void 0 ? {} : await oneAccountOf(store, env, value, "--account")));
10160
10845
  const note = await store.notes.addNote({
10161
10846
  text: body,
10162
10847
  about,
@@ -10217,9 +10902,9 @@ import { statSync as statSync4 } from "node:fs";
10217
10902
  import { basename as basename2, resolve as resolve4 } from "node:path";
10218
10903
 
10219
10904
  // dist/run/lock.js
10220
- import { join as join10 } from "node:path";
10905
+ import { join as join11 } from "node:path";
10221
10906
  var withImportLock = /* @__PURE__ */ __name(async (env, work) => {
10222
- const lock = join10(resolvePaths({ appName: "cli-memo", prefix: "MEMO", env }).state, "import.lock");
10907
+ const lock = join11(resolvePaths({ appName: "cli-memo", prefix: "MEMO", env }).state, "import.lock");
10223
10908
  const holder = takeLock(lock, { pid: process.pid, startedAt: (/* @__PURE__ */ new Date()).toISOString() });
10224
10909
  if (holder !== void 0)
10225
10910
  throw new CliError("rate_limited", `another memo sync is running (process ${holder.pid}); try again when it ends`, {
@@ -10240,15 +10925,15 @@ var formatOf2 = /* @__PURE__ */ __name((value) => {
10240
10925
  return value;
10241
10926
  }, "formatOf");
10242
10927
  var directory = /* @__PURE__ */ __name((path) => {
10243
- const at = resolve4(path);
10928
+ const at2 = resolve4(path);
10244
10929
  let isDirectory = false;
10245
10930
  try {
10246
- isDirectory = statSync4(at).isDirectory();
10931
+ isDirectory = statSync4(at2).isDirectory();
10247
10932
  } catch {
10248
10933
  }
10249
10934
  if (!isDirectory)
10250
- throw new CliError("not_found", `${at} is not a folder`);
10251
- return at;
10935
+ throw new CliError("not_found", `${at2} is not a folder`);
10936
+ return at2;
10252
10937
  }, "directory");
10253
10938
  var FOLDERS_QUERY = { entity: "notes_folder", backend: "native", fields: [] };
10254
10939
  var keptByDrive = /* @__PURE__ */ __name((name2) => name2.startsWith("google-drive:"), "keptByDrive");
@@ -10261,10 +10946,10 @@ var foldersCommand = /* @__PURE__ */ __name((program, streams, env) => {
10261
10946
  const { print } = answers(program, streams, env);
10262
10947
  const folders = program.command("folders").description("folders of notes: the id links and the store use, and the path on this computer");
10263
10948
  grantsAuthority(annotate(folders.command("add"), { effects: LOCAL_WRITE })).description("give a folder of notes an id, or show the one it has").argument("<path>", "the folder on this computer").option("--format <format>", `how its notes are written: ${DIALECTS.join(", ")} (default: obsidian)`, formatOf2).option("--json", "print JSON; --json=id,title keeps only those fields").action(async (path, options) => {
10264
- const at = directory(path);
10949
+ const at2 = directory(path);
10265
10950
  const answer = await withStore(env, async (store) => {
10266
10951
  const known2 = new Set((await store.notes.folders()).map(({ id }) => id));
10267
- const current = noteFolders(loadConfig(env).notes).find((folder2) => folder2.path === at);
10952
+ const current = noteFolders(loadConfig(env).notes).find((folder2) => folder2.path === at2);
10268
10953
  if (current?.id && known2.has(current.id)) {
10269
10954
  const folder2 = { ...current, id: current.id, format: options.format ?? current.format };
10270
10955
  if (folder2.format !== current.format)
@@ -10272,15 +10957,15 @@ var foldersCommand = /* @__PURE__ */ __name((program, streams, env) => {
10272
10957
  return { ...folder2, created: false };
10273
10958
  }
10274
10959
  const format = options.format ?? current?.format ?? "obsidian";
10275
- const made = await store.notes.addFolder({ name: basename2(at) || at, format });
10276
- const folder = { id: made.id, path: at, format };
10960
+ const made = await store.notes.addFolder({ name: basename2(at2) || at2, format });
10961
+ const folder = { id: made.id, path: at2, format };
10277
10962
  updateConfig((config) => bindFolder(config, folder), env);
10278
10963
  return { ...folder, created: true };
10279
10964
  });
10280
10965
  print(options.json, itemAnswer(answer), answer.id);
10281
10966
  });
10282
10967
  grantsAuthority(annotate(folders.command("update"), { effects: LOCAL_WRITE })).description("bind a folder id from another computer to the folder's path on this one").argument("<id>", "the folder's id, as memo folders add printed it").argument("<path>", "the same folder on this computer").option("--format <format>", `how its notes are written: ${DIALECTS.join(", ")}`, formatOf2).option("--json", "print JSON; --json=id,title keeps only those fields").action(async (id, path, options) => {
10283
- const at = directory(path);
10968
+ const at2 = directory(path);
10284
10969
  const folder = await withStore(env, async (store) => {
10285
10970
  const stored = (await storedFolders(store)).find((candidate) => candidate.id === id);
10286
10971
  if (!stored)
@@ -10291,7 +10976,7 @@ var foldersCommand = /* @__PURE__ */ __name((program, streams, env) => {
10291
10976
  throw new CliError("validation_error", `folder ${id} is Google Drive's (${stored.name}) \u2014 drive keeps it, and memo search already reads it`);
10292
10977
  let bound;
10293
10978
  updateConfig((config) => {
10294
- const result = attachFolder(config, id, at, options.format ?? stored.format);
10979
+ const result = attachFolder(config, id, at2, options.format ?? stored.format);
10295
10980
  bound = result.folder;
10296
10981
  return result.config;
10297
10982
  }, env);
@@ -10350,7 +11035,7 @@ var foldersCommand = /* @__PURE__ */ __name((program, streams, env) => {
10350
11035
  }, "foldersCommand");
10351
11036
 
10352
11037
  // dist/people/command.js
10353
- import { join as join11 } from "node:path";
11038
+ import { join as join12 } from "node:path";
10354
11039
  var noteCommand = /* @__PURE__ */ __name((program, streams, env) => {
10355
11040
  const notes2 = program.commands.find((command) => command.name() === "notes") ?? program.command("notes");
10356
11041
  const links = notes2.command("links").description("imported note files linked to the person behind an identity");
@@ -10403,7 +11088,7 @@ var noteCommand = /* @__PURE__ */ __name((program, streams, env) => {
10403
11088
  }
10404
11089
  const paths = (await files()).map(({ note }) => {
10405
11090
  const folder = folders.find((candidate) => candidate.id === note.folderId);
10406
- return folder ? join11(folder.path, note.path) : note.ref;
11091
+ return folder ? join12(folder.path, note.path) : note.ref;
10407
11092
  });
10408
11093
  return { person: to, name: person.name ?? person.uid, files: paths };
10409
11094
  });
@@ -10424,7 +11109,7 @@ var peopleCommand = /* @__PURE__ */ __name((program, streams, env) => {
10424
11109
  withQuery(annotate(people.command("list"), { effects: LOCAL_READ }).summary("everyone memo knows, the owner first").description("everyone memo knows, by name: the owner first, then by how many tasks name them"), query).option("--limit <n>", "most people, up to 5000", positive, 500).option("--json", "print JSON; --json=id,title keeps only those fields").action(async (words, options) => {
10425
11110
  listQuery(typedQuery(words), query, "people list");
10426
11111
  await withStore(env, async (store) => {
10427
- const found = await store.tasks.taskPeople({ limit: options.limit });
11112
+ const found = await keepInGroup(store, env, await store.tasks.taskPeople({ limit: options.limit }), ({ person }) => person);
10428
11113
  print(options.json, wholeList("people list", found.map(({ person, ...rest }) => ({ ref: person, ...rest }))));
10429
11114
  });
10430
11115
  });
@@ -10467,19 +11152,19 @@ var headerOf2 = /* @__PURE__ */ __name((line3) => {
10467
11152
  return void 0;
10468
11153
  }
10469
11154
  }, "headerOf");
10470
- var accountIn = /* @__PURE__ */ __name((envelope, given2) => {
11155
+ var accountIn2 = /* @__PURE__ */ __name((envelope, given2) => {
10471
11156
  const provider = envelope?.source?.provider;
10472
11157
  return typeof provider === "string" && given2.startsWith(`${provider}:`) ? given2.slice(provider.length + 1) : given2;
10473
11158
  }, "accountIn");
10474
11159
  var deviceOf = /* @__PURE__ */ __name((given2) => {
10475
- const at = given2.indexOf(":");
10476
- if (at < 0)
11160
+ const at2 = given2.indexOf(":");
11161
+ if (at2 < 0)
10477
11162
  return given2;
10478
- if (given2.slice(0, at) !== PHONE)
11163
+ if (given2.slice(0, at2) !== PHONE)
10479
11164
  throw new CliError("validation_error", "a vCard file holds a phone's contacts: --account phone:<device>", {
10480
11165
  param: "--account"
10481
11166
  });
10482
- return given2.slice(at + 1);
11167
+ return given2.slice(at2 + 1);
10483
11168
  }, "deviceOf");
10484
11169
  var importRecords = /* @__PURE__ */ __name(async (store, { file, stdin, account: account2, dryRun, onIssue, region }) => {
10485
11170
  const iterator = (await linesOf(file, stdin))[Symbol.asyncIterator]();
@@ -10536,10 +11221,10 @@ var importRecords = /* @__PURE__ */ __name(async (store, { file, stdin, account:
10536
11221
  }
10537
11222
  }
10538
11223
  __name(all, "all");
10539
- return ingestLines(store, all(), { account: accountIn(header, account2), dryRun, onIssue });
11224
+ return ingestLines(store, all(), { account: accountIn2(header, account2), dryRun, onIssue });
10540
11225
  }
10541
11226
  const envelope = envelopeOfText(await whole2([first]));
10542
- return ingest(store, envelope, { account: accountIn(envelope, account2), dryRun, onIssue });
11227
+ return ingest(store, envelope, { account: accountIn2(envelope, account2), dryRun, onIssue });
10543
11228
  }, "importRecords");
10544
11229
 
10545
11230
  // dist/records/mapping.js
@@ -10567,10 +11252,10 @@ var sourceOf4 = /* @__PURE__ */ __name((account2) => {
10567
11252
  }, "sourceOf");
10568
11253
  var recordOf = /* @__PURE__ */ __name((record2) => {
10569
11254
  const from = record2.startsWith("custom:") ? "custom:".length : 0;
10570
- const at = record2.indexOf(":", from);
10571
- if (at <= from || at === record2.length - 1)
11255
+ const at2 = record2.indexOf(":", from);
11256
+ if (at2 <= from || at2 === record2.length - 1)
10572
11257
  throw new CliError("validation_error", `${record2} is not <type>:<external_id>, such as organization:client or custom:quote:Q-7`, { param: "record" });
10573
- return { type: record2.slice(0, at), externalId: record2.slice(at + 1) };
11258
+ return { type: record2.slice(0, at2), externalId: record2.slice(at2 + 1) };
10574
11259
  }, "recordOf");
10575
11260
  var RECORD_HELP = "<type>:<external_id> as the source names it, such as organization:client or custom:quote:Q-7";
10576
11261
  var ACCOUNT_HELP = "the source, <provider>:<account> as the envelope's source names it, such as sheet:rentals";
@@ -10828,7 +11513,7 @@ ${SOURCE_REVIEW_HELP}`);
10828
11513
  ...given2,
10829
11514
  question: `${name2} ${ids.length} proposal${ids.length === 1 ? "" : "s"} as you, the owner?`
10830
11515
  });
10831
- const result = await withStore(env, (store) => reviewRegistry(store).decide(ids, decisionOf(name2 === "confirm", by, given2.reason)));
11516
+ const result = await withStore(env, async (store) => (await reviewOf(store, env)).decide(ids, decisionOf(name2 === "confirm", by, given2.reason)));
10832
11517
  const issues = result.refused.map((one2) => ({
10833
11518
  code: one2.code,
10834
11519
  source: one2.id,
@@ -10846,26 +11531,26 @@ ${SOURCE_REVIEW_HELP}`);
10846
11531
  }, "reviewCommand");
10847
11532
 
10848
11533
  // dist/notes/embed.js
10849
- import { existsSync as existsSync9, readdirSync as readdirSync7 } from "node:fs";
10850
- import { join as join12 } from "node:path";
11534
+ import { existsSync as existsSync10, readdirSync as readdirSync7 } from "node:fs";
11535
+ import { join as join13 } from "node:path";
10851
11536
  var EMBED_PER_RUN = 600;
11537
+ var MEASURED_WITH = "e5-small";
10852
11538
  var SLOWEST_KNOWN = 2;
10853
11539
  var embedPerRun = /* @__PURE__ */ __name((env = process.env) => {
10854
11540
  const models = textModels(env);
10855
11541
  const speed = /* @__PURE__ */ __name((id) => models.find((model) => model.id === id)?.chunksPerSecond ?? SLOWEST_KNOWN, "speed");
10856
- const ratio = speed(chosenTextModel(env).id) / speed(DEFAULT_TEXT_MODEL);
11542
+ const ratio = speed(chosenTextModel(env).id) / speed(MEASURED_WITH);
10857
11543
  return Math.max(8, Math.min(EMBED_PER_RUN, Math.round(EMBED_PER_RUN * ratio)));
10858
11544
  }, "embedPerRun");
10859
11545
  var missingModel = /* @__PURE__ */ __name((error, env) => {
10860
11546
  const named5 = isCliError(error) ? error.details.model : void 0;
10861
11547
  const id = typeof named5 === "string" ? named5 : chosenTextModel(env).id;
10862
- const terms2 = textModels(env).find((model) => model.id === id)?.terms;
10863
- return `the ${id} model is not downloaded \u2014 memo models download ${id}${terms2 ? " --accept-terms" : ""}`;
11548
+ return `the ${id} model is not downloaded \u2014 memo models download ${id}`;
10864
11549
  }, "missingModel");
10865
11550
  var searchModelPresent = /* @__PURE__ */ __name((env) => {
10866
11551
  try {
10867
- const path = join12(sharedModelsDirectory("text", env), chosenTextModel(env).id);
10868
- return existsSync9(path) && readdirSync7(path).length > 0;
11552
+ const path = join13(sharedModelsDirectory("text", env), chosenTextModel(env).id);
11553
+ return existsSync10(path) && readdirSync7(path).length > 0;
10869
11554
  } catch {
10870
11555
  return false;
10871
11556
  }
@@ -10874,7 +11559,7 @@ var isMissingModel = /* @__PURE__ */ __name((error) => isCliError(error) && erro
10874
11559
  var reportOf = /* @__PURE__ */ __name((run) => {
10875
11560
  if (run === void 0)
10876
11561
  return void 0;
10877
- if (run.status === "failed")
11562
+ if (!("provider" in run))
10878
11563
  return {
10879
11564
  status: "failed",
10880
11565
  sent: 0,
@@ -10884,7 +11569,8 @@ var reportOf = /* @__PURE__ */ __name((run) => {
10884
11569
  inputTokens: 0,
10885
11570
  outputTokens: 0,
10886
11571
  costUsd: 0,
10887
- reason: run.reason
11572
+ reason: run.reason,
11573
+ reasonId: run.reason_id
10888
11574
  };
10889
11575
  return {
10890
11576
  status: run.status,
@@ -10897,7 +11583,8 @@ var reportOf = /* @__PURE__ */ __name((run) => {
10897
11583
  inputTokens: run.usage.input,
10898
11584
  outputTokens: run.usage.output,
10899
11585
  costUsd: run.cost_usd,
10900
- ...run.reason === void 0 ? {} : { reason: run.reason }
11586
+ ...run.reason === void 0 ? {} : { reason: run.reason },
11587
+ ...run.reason_id === void 0 ? {} : { reasonId: run.reason_id }
10901
11588
  };
10902
11589
  }, "reportOf");
10903
11590
  var combinedEnrichment = /* @__PURE__ */ __name((...parts2) => {
@@ -10906,20 +11593,23 @@ var combinedEnrichment = /* @__PURE__ */ __name((...parts2) => {
10906
11593
  return void 0;
10907
11594
  const rank = { done: 0, stopped: 1, failed: 2 };
10908
11595
  const worst = present2.reduce((a, b) => rank[b.status] > rank[a.status] ? b : a);
11596
+ const enriched = present2.reduce((sum, part) => sum + part.enriched, 0);
11597
+ const status = worst.status === "failed" && enriched > 0 ? "stopped" : worst.status;
10909
11598
  const named5 = present2.find((part) => part.provider !== void 0);
10910
11599
  const costs = present2.map((part) => part.costUsd);
10911
11600
  return {
10912
- status: worst.status,
11601
+ status,
10913
11602
  ...named5?.provider === void 0 ? {} : { provider: named5.provider },
10914
11603
  ...named5?.model === void 0 ? {} : { model: named5.model },
10915
11604
  sent: present2.reduce((sum, part) => sum + part.sent, 0),
10916
- enriched: present2.reduce((sum, part) => sum + part.enriched, 0),
11605
+ enriched,
10917
11606
  failed: present2.reduce((sum, part) => sum + part.failed, 0),
10918
11607
  left: present2.reduce((sum, part) => sum + part.left, 0),
10919
11608
  inputTokens: present2.reduce((sum, part) => sum + part.inputTokens, 0),
10920
11609
  outputTokens: present2.reduce((sum, part) => sum + part.outputTokens, 0),
10921
11610
  costUsd: costs.includes(null) ? null : Math.round(costs.reduce((sum, cost) => sum + (cost ?? 0), 0) * 1e6) / 1e6,
10922
- ...worst.reason === void 0 ? {} : { reason: worst.reason }
11611
+ ...worst.reason === void 0 ? {} : { reason: worst.reason },
11612
+ ...worst.reasonId === void 0 ? {} : { reasonId: worst.reasonId }
10923
11613
  };
10924
11614
  }, "combinedEnrichment");
10925
11615
  var embedNoteChunks = /* @__PURE__ */ __name(async (store, { embed = true, env, maxChunks = embedPerRun(env), keyring } = {}) => {
@@ -11080,6 +11770,7 @@ var syncCommand = /* @__PURE__ */ __name((program, streams, env, signal, keyring
11080
11770
  }), "answer");
11081
11771
  const work = withImportLock(env, async () => {
11082
11772
  const store = await openStore({ env, ...STORE_CLIENT, decisions: decisionPolicy(env) });
11773
+ const enriched = [];
11083
11774
  const attempt = /* @__PURE__ */ __name(async (source, work2) => {
11084
11775
  halt();
11085
11776
  try {
@@ -11118,11 +11809,13 @@ var syncCommand = /* @__PURE__ */ __name((program, streams, env, signal, keyring
11118
11809
  });
11119
11810
  if (folders.length > 0)
11120
11811
  await attempt("notes by meaning", async () => {
11121
- run.notesEmbedded = await embedNoteChunks(store, {
11812
+ const { enrichment: enrichment2, ...embedded } = await embedNoteChunks(store, {
11122
11813
  embed: options.embed && config.notes?.embed !== false,
11123
11814
  env,
11124
11815
  ...keyring ? { keyring } : {}
11125
11816
  });
11817
+ run.notesEmbedded = embedded;
11818
+ enriched.push(enrichment2);
11126
11819
  });
11127
11820
  await attempt("people-notes.json", async () => {
11128
11821
  await importNotesMap(store, env, folders);
@@ -11130,13 +11823,15 @@ var syncCommand = /* @__PURE__ */ __name((program, streams, env, signal, keyring
11130
11823
  }
11131
11824
  if (synced.has("mail"))
11132
11825
  await attempt("mail by meaning", async () => {
11133
- run.mailEmbedded = await embedMailChunks(store, {
11826
+ const { enrichment: enrichment2, ...embedded } = await embedMailChunks(store, {
11134
11827
  embed: options.embed,
11135
11828
  env,
11136
11829
  ...keyring ? { keyring } : {}
11137
11830
  });
11831
+ run.mailEmbedded = embedded;
11832
+ enriched.push(enrichment2);
11138
11833
  });
11139
- const enrichment = combinedEnrichment(run.notesEmbedded?.enrichment, run.mailEmbedded?.enrichment);
11834
+ const enrichment = combinedEnrichment(...enriched);
11140
11835
  if (enrichment)
11141
11836
  run.enrichment = enrichment;
11142
11837
  halt();
@@ -11255,10 +11950,10 @@ var mailboxBlock = /* @__PURE__ */ __name((source, review, room = Number.POSITIV
11255
11950
  let fit;
11256
11951
  for (let end = 1; end < cuts.length; end++) {
11257
11952
  const kept = new Set(cuts.slice(0, end).flatMap((cut2) => cut2.items));
11258
- const at = cuts[end - 1];
11953
+ const at2 = cuts[end - 1];
11259
11954
  const block = lines(source, review, {
11260
- key: at?.key,
11261
- cursor: at?.cursor,
11955
+ key: at2?.key,
11956
+ cursor: at2?.cursor,
11262
11957
  items: items.filter((item) => kept.has(item)),
11263
11958
  waiting: items.length - kept.size
11264
11959
  });
@@ -11346,8 +12041,8 @@ var searchText = /* @__PURE__ */ __name((result, offset = 0) => [
11346
12041
  ].join("\n"), "searchText");
11347
12042
 
11348
12043
  // dist/search/hits.js
11349
- var BRIEF = ["ref", "chat_title", "timestamp", "sender_name", "excerpt", "score"];
11350
- var briefHit = /* @__PURE__ */ __name((hit) => Object.fromEntries(BRIEF.flatMap((key) => hit[key] === void 0 || hit[key] === null ? [] : [[key, hit[key]]])), "briefHit");
12044
+ var BRIEF2 = ["ref", "chat_title", "timestamp", "sender_name", "excerpt", "score"];
12045
+ var briefHit = /* @__PURE__ */ __name((hit) => Object.fromEntries(BRIEF2.flatMap((key) => hit[key] === void 0 || hit[key] === null ? [] : [[key, hit[key]]])), "briefHit");
11351
12046
 
11352
12047
  // dist/search/answers.js
11353
12048
  var named4 = /* @__PURE__ */ __name((accounts) => [
@@ -11443,7 +12138,7 @@ var notesAnswer = /* @__PURE__ */ __name((found, limit, page, args = {}) => list
11443
12138
  var holdsNoPeople = /* @__PURE__ */ __name((provider) => provider === "notes" || isFolderProvider(provider), "holdsNoPeople");
11444
12139
  var fold4 = /* @__PURE__ */ __name((text3) => text3.normalize("NFKD").replace(new RegExp("\\p{M}", "gu"), "").toLowerCase(), "fold");
11445
12140
  var scopeOf2 = /* @__PURE__ */ __name(async (store, env, source) => {
11446
- const keys = source === void 0 ? await store.accounts.accounts() : await accountsOf(store, env, source);
12141
+ const keys = source === void 0 ? await scopedAccounts(store, env) : await accountsOf(store, env, source);
11447
12142
  const held = keys.filter((key) => !holdsNoPeople(key.provider));
11448
12143
  if (source !== void 0 && held.length === 0)
11449
12144
  throw new CliError("validation_error", `${source} names no messenger, mail or meeting account that holds people`, {
@@ -11483,6 +12178,13 @@ var searchPeople = /* @__PURE__ */ __name(async (store, env, words, { limit, sou
11483
12178
  hits.set(ref, hit);
11484
12179
  }
11485
12180
  }
12181
+ for (const { person, name: name2 } of source === void 0 ? await store.tasks.taskPeople({ limit: 5e3 }) : []) {
12182
+ if (hits.has(person) || name2 === null || !wanted.every((word) => fold4(name2).includes(word)))
12183
+ continue;
12184
+ const known2 = await store.people.personByUid(person.slice("person:".length));
12185
+ if (known2 && known2.identities.length === 0)
12186
+ hits.set(person, { ref: person, name: name2, identities: [], aliases: [] });
12187
+ }
11486
12188
  const first = wanted.join(" ");
11487
12189
  const rank = /* @__PURE__ */ __name((hit) => fold4(hit.name ?? "").startsWith(first) ? 0 : 1, "rank");
11488
12190
  const sorted = [...hits.values()].sort((a, b) => rank(a) - rank(b) || (a.name ?? "").localeCompare(b.name ?? "") || a.ref.localeCompare(b.ref));
@@ -11500,6 +12202,17 @@ var peopleText = /* @__PURE__ */ __name((found) => found.items.map((hit) => [
11500
12202
  ].join("\n")).join("\n") || "nobody found", "peopleText");
11501
12203
 
11502
12204
  // dist/search/command.js
12205
+ var groupMessengers = /* @__PURE__ */ __name(async (store, env, text3) => {
12206
+ const scope = await groupScopeOf(store, env);
12207
+ if (scope === void 0)
12208
+ return void 0;
12209
+ if (hasSource(parseLucene(text3).root))
12210
+ throw new CliError("validation_error", `in group ${scope.run.name} search messages reads the group's accounts \u2014 leave in: out of the query`);
12211
+ const { messages } = accountsByKind(scope);
12212
+ if (messages.length === 0)
12213
+ throw new CliError("not_found", `group ${scope.run.name} holds no messenger account`);
12214
+ return messages;
12215
+ }, "groupMessengers");
11503
12216
  var ONLY = ["messages", "mail", "notes", "events", "crm", "business"];
11504
12217
  var onlyOf2 = /* @__PURE__ */ __name((value) => {
11505
12218
  const selected = value.split(",").map((part) => part.trim());
@@ -11523,7 +12236,7 @@ var searchCommandDefinition = /* @__PURE__ */ __name((program, streams, env) =>
11523
12236
  throw new InvalidArgumentError("at most 100");
11524
12237
  return limit;
11525
12238
  }, 20).option("--exact", "words as written; skip meaning search").option("--timezone <zone>", "IANA timezone for calendar date boundaries").option("--json", "print JSON; --json=id,title keeps only those fields"), "queryOptions");
11526
- queryOptions(annotate(group.command("all"), { effects: LOCAL_READ, output: { entity: "hit" } }).description("messages, mail, notes, calendar events, deals, leads and business data ranked together; not people, memories, projects or decisions. A kind you know reads better with its own search, with all its fields").summary("messages, mail, notes and calendar events ranked together")).option("--only <resources>", `${ONLY.join(",")}, separated by commas`, onlyOf2).option("--plain-order", "best first by the words alone, without moving mail from suspicious senders down").option("--project <project>", PROJECT_ORDER_HELP).addHelpText("after", `
12239
+ queryOptions(annotate(group.command("all"), { effects: LOCAL_READ, output: { entity: "hit" } }).description("messages, mail, notes, calendar events, deals, leads and business data ranked together; not people, memories, projects or decisions. A kind you know reads better with its own search, with all its fields").summary("messages, mail, notes, events and deals ranked together")).option("--only <resources>", `${ONLY.join(",")}, separated by commas`, onlyOf2).option("--plain-order", "best first by the words alone, without moving mail from suspicious senders down").option("--project <project>", PROJECT_ORDER_HELP).addHelpText("after", `
11527
12240
  content: narrows a search to the text of files, transcript: to voice transcripts, filename: to file names \u2014 memo search all 'content:invoice'.
11528
12241
  Calendar events come from every calendar gcal stored; an event's title, description and place are written by whoever sent the invitation.
11529
12242
  crm finds deals and leads by the words of their title only.
@@ -11591,7 +12304,7 @@ For an agent: read with --compact, one line per hit with its reference. Never wr
11591
12304
  const level = levelOf(options);
11592
12305
  const text3 = words.join(" ");
11593
12306
  const answer = await withStore(env, async (store) => {
11594
- const mailboxes = options.source === void 0 ? void 0 : await mailboxesOf(store, env, options.source);
12307
+ const mailboxes = options.source !== void 0 ? await mailboxesOf(store, env, options.source) : kind === "messages" ? await groupMessengers(store, env, text3) : void 0;
11595
12308
  return searchKind(store, kind, {
11596
12309
  text: text3,
11597
12310
  limit: options.limit,
@@ -11745,7 +12458,7 @@ var showReferences = /* @__PURE__ */ __name(async (store, env, texts, command) =
11745
12458
  }
11746
12459
  return shown3;
11747
12460
  }, "showReferences");
11748
- var minute2 = /* @__PURE__ */ __name((at) => at === null ? null : at.slice(0, 16).replace("T", " "), "minute");
12461
+ var minute2 = /* @__PURE__ */ __name((at2) => at2 === null ? null : at2.slice(0, 16).replace("T", " "), "minute");
11749
12462
  var blockOf = /* @__PURE__ */ __name((one2) => [
11750
12463
  `${one2.ref} ${one2.title ?? ""}`.trimEnd(),
11751
12464
  ` ${[one2.kind, one2.in, one2.state, minute2(one2.at)].filter((part) => part !== null).join(" \xB7 ")}`,
@@ -11768,29 +12481,29 @@ var showCommand = /* @__PURE__ */ __name((program, streams, env) => {
11768
12481
  }, "showCommand");
11769
12482
 
11770
12483
  // dist/sources/command.js
11771
- import { existsSync as existsSync11 } from "node:fs";
12484
+ import { existsSync as existsSync12 } from "node:fs";
11772
12485
 
11773
12486
  // dist/sources/copy.js
11774
12487
  import { randomUUID } from "node:crypto";
11775
- import { existsSync as existsSync10, mkdirSync as mkdirSync4, renameSync as renameSync3, rmSync as rmSync2, writeFileSync as writeFileSync4 } from "node:fs";
11776
- import { isAbsolute, join as join13, relative as relative2, resolve as resolve5, sep as sep2 } from "node:path";
11777
- var copiesDir = /* @__PURE__ */ __name((env) => join13(resolvePaths({ appName: APP.appName, prefix: APP.envPrefix, env }).state, "sources"), "copiesDir");
11778
- var copyPath = /* @__PURE__ */ __name((env, hash) => join13(copiesDir(env), hash), "copyPath");
12488
+ import { existsSync as existsSync11, mkdirSync as mkdirSync4, renameSync as renameSync3, rmSync as rmSync3, writeFileSync as writeFileSync5 } from "node:fs";
12489
+ import { isAbsolute, join as join14, relative as relative2, resolve as resolve5, sep as sep2 } from "node:path";
12490
+ var copiesDir = /* @__PURE__ */ __name((env) => join14(resolvePaths({ appName: APP.appName, prefix: APP.envPrefix, env }).state, "sources"), "copiesDir");
12491
+ var copyPath = /* @__PURE__ */ __name((env, hash) => join14(copiesDir(env), hash), "copyPath");
11779
12492
  var keepCopy = /* @__PURE__ */ __name((env, hash, bytes) => {
11780
12493
  const path = copyPath(env, hash);
11781
- if (existsSync10(path))
12494
+ if (existsSync11(path))
11782
12495
  return { path, wrote: false };
11783
12496
  mkdirSync4(copiesDir(env), { recursive: true, mode: 448 });
11784
12497
  const partial = `${path}.${randomUUID()}.part`;
11785
- writeFileSync4(partial, bytes, { mode: 384 });
12498
+ writeFileSync5(partial, bytes, { mode: 384 });
11786
12499
  renameSync3(partial, path);
11787
12500
  return { path, wrote: true };
11788
12501
  }, "keepCopy");
11789
12502
  var dropCopy = /* @__PURE__ */ __name((env, path) => {
11790
12503
  const inside2 = relative2(resolve5(copiesDir(env)), resolve5(path));
11791
- if (!inside2 || isAbsolute(inside2) || inside2.startsWith("..") || inside2.includes(sep2) || !existsSync10(path))
12504
+ if (!inside2 || isAbsolute(inside2) || inside2.startsWith("..") || inside2.includes(sep2) || !existsSync11(path))
11792
12505
  return false;
11793
- rmSync2(path);
12506
+ rmSync3(path);
11794
12507
  return true;
11795
12508
  }, "dropCopy");
11796
12509
 
@@ -11801,7 +12514,7 @@ var escaped = /* @__PURE__ */ __name((text3) => text3.replace(/[.*+?^${}()|[\]\\
11801
12514
  var folded = /* @__PURE__ */ __name((text3) => text3.normalize("NFC").toLocaleLowerCase(), "folded");
11802
12515
  var mentionsOf = /* @__PURE__ */ __name(async (store, note) => {
11803
12516
  const id = Number(note.id);
11804
- const at = note.modifiedAt ?? note.updatedAt;
12517
+ const at2 = note.modifiedAt ?? note.updatedAt;
11805
12518
  const found = [];
11806
12519
  for (let offset = 0; ; offset += PAGE6) {
11807
12520
  const page = await store.sourceMentions.list("document", void 0, { limit: PAGE6, offset }, []);
@@ -11809,7 +12522,7 @@ var mentionsOf = /* @__PURE__ */ __name(async (store, note) => {
11809
12522
  const when = mention.source.at ?? "";
11810
12523
  if (mention.source.id === id)
11811
12524
  found.push(mention);
11812
- else if (found.length > 0 || when < at || when === at && mention.source.id < id)
12525
+ else if (found.length > 0 || when < at2 || when === at2 && mention.source.id < id)
11813
12526
  return found;
11814
12527
  }
11815
12528
  if (!page.hasMore)
@@ -11852,8 +12565,8 @@ ${note.text}`);
11852
12565
  const name2 = organization.name.trim();
11853
12566
  if (name2.length < 3)
11854
12567
  continue;
11855
- const at = new RegExp(`(?<![\\p{L}\\p{N}])${escaped(folded(name2))}(?![\\p{L}\\p{N}])`, "u");
11856
- if (at.test(text3))
12568
+ const at2 = new RegExp(`(?<![\\p{L}\\p{N}])${escaped(folded(name2))}(?![\\p{L}\\p{N}])`, "u");
12569
+ if (at2.test(text3))
11857
12570
  add(organization.ref, "organization", organization.name, name2);
11858
12571
  }
11859
12572
  return {
@@ -11864,7 +12577,7 @@ ${note.text}`);
11864
12577
  }, "namedIn");
11865
12578
 
11866
12579
  // dist/sources/read.js
11867
- import { readFileSync as readFileSync9, statSync as statSync5 } from "node:fs";
12580
+ import { readFileSync as readFileSync10, statSync as statSync5 } from "node:fs";
11868
12581
  import { basename as basename3, extname as extname2 } from "node:path";
11869
12582
  var SOURCE_TEXT_CHARS = 2e5;
11870
12583
  var URL_LIKE = /^[a-z][a-z0-9+.-]*:\/\//i;
@@ -11982,7 +12695,7 @@ var readFile = /* @__PURE__ */ __name(async (path, { maxChars, load = importEngi
11982
12695
  throw new CliError("validation_error", `${path} is not a file`, { path });
11983
12696
  if (stat.size > MAX_FILE_BYTES)
11984
12697
  throw tooLarge2(name2);
11985
- const bytes = new Uint8Array(readFileSync9(path));
12698
+ const bytes = new Uint8Array(readFileSync10(path));
11986
12699
  const extension = extname2(name2).toLowerCase();
11987
12700
  const mime = MIMES[extension] ?? null;
11988
12701
  const found = await extractText(bytes, { kind: "file", name: name2, mime, path }, load);
@@ -12184,7 +12897,7 @@ var sourcesCommand = /* @__PURE__ */ __name((program, streams, env, { fetch: fet
12184
12897
  mime: source?.mime ?? null,
12185
12898
  bytes: source?.size ?? null,
12186
12899
  // The row says a copy was kept; only the file itself says it still is.
12187
- kept: source === void 0 ? null : source.copy !== null && existsSync11(source.copy) ? "copy" : "text",
12900
+ kept: source === void 0 ? null : source.copy !== null && existsSync12(source.copy) ? "copy" : "text",
12188
12901
  chars: note.text.length,
12189
12902
  text: text3,
12190
12903
  textTruncated: truncated,
@@ -12229,6 +12942,56 @@ var sourcesCommand = /* @__PURE__ */ __name((program, streams, env, { fetch: fet
12229
12942
  });
12230
12943
  }, "sourcesCommand");
12231
12944
 
12945
+ // dist/store/groups-command.js
12946
+ var MEMBER_HELP = "one account, as --source names it: telegram:102, tg:work, email:me@work.example, bitrix24:<portal>";
12947
+ var GROUPS_QUERY = { entity: "account_group", backend: "native", fields: [] };
12948
+ var at = /* @__PURE__ */ __name((store, env) => ({ store, account: MEMO_ACCOUNT, app: APP, env }), "at");
12949
+ var membershipText = /* @__PURE__ */ __name(({ groups, duplicates, suggested, unresolved }) => [
12950
+ ...Object.entries(groups).flatMap(([name2, members]) => [
12951
+ `${name2}${members.length ? "" : " (empty)"}`,
12952
+ ...members.map((member) => [
12953
+ ` ${member.provider}:${member.account}`,
12954
+ member.profiles.length ? member.profiles.join(", ") : "",
12955
+ member.reason === "setting" ? "" : member.reason,
12956
+ member.also_in.length ? `also in ${member.also_in.join(", ")}` : ""
12957
+ ].filter(Boolean).join(" "))
12958
+ ]),
12959
+ ...duplicates.map(({ member, groups: names }) => `duplicate: ${member} is in ${names.join(", ")}`),
12960
+ ...suggested.map(({ group, member, because }) => `suggested: ${member} for ${group} \u2014 ${because}`),
12961
+ ...unresolved.map((entry) => `unresolved: ${entry} names no account`)
12962
+ ].join("\n"), "membershipText");
12963
+ var groupsCommand = /* @__PURE__ */ __name((program, streams, env) => {
12964
+ const { print } = answers(program, streams, env);
12965
+ const groups = program.command("groups").description("account groups: memo <group> \u2026 reads only the group's accounts");
12966
+ const show = /* @__PURE__ */ __name(async (command, json5, work) => {
12967
+ const membership = await withStore(env, work);
12968
+ const { groups: named5, duplicates, suggested, unresolved } = membership;
12969
+ const items = Object.entries(named5).map(([group, members]) => ({
12970
+ group,
12971
+ members,
12972
+ duplicates: duplicates.filter(({ groups: names }) => names.includes(group)),
12973
+ suggested: suggested.filter((one2) => one2.group === group)
12974
+ }));
12975
+ print(json5, listAnswer(command, {
12976
+ items,
12977
+ limit: Math.max(1, items.length),
12978
+ has_more: false,
12979
+ missing: unresolved.map((entry) => ({
12980
+ field: entry,
12981
+ why: "a saved group entry that names no account"
12982
+ }))
12983
+ }), membershipText(membership));
12984
+ }, "show");
12985
+ const reserved = /* @__PURE__ */ __name(() => commandWords(program), "reserved");
12986
+ withQuery(annotate(groups.command("list"), { effects: LOCAL_READ, output: { entity: "account_group" } }), GROUPS_QUERY).description("every saved group, then all, with its accounts, each with its profiles in every app and the other groups that hold it too; duplicates and profile-name suggestions last").summary("the saved groups, then all, with accounts, profiles and duplicates").option("--json", "print JSON; --json=id,title keeps only those fields").action(async (words, options) => {
12987
+ queryTerms(words, GROUPS_QUERY, "groups list");
12988
+ await show("groups list", options.json, (store) => listAccountGroups(at(store, env)));
12989
+ });
12990
+ grantsAuthority(annotate(groups.command("add"), { effects: LOCAL_WRITE, output: { entity: "account_group" } })).description("put an account in a group, which is made when it does not exist; it may stay in others too").summary("put an account in a group").argument("<group>", "the group: letters, digits, - and _, not a memo command word").argument("<source>", MEMBER_HELP).option("--json", "print JSON; --json=id,title keeps only those fields").action((group, member, options) => show("groups add", options.json, (store) => addGroupMember(at(store, env), { group, member, reserved: reserved() })));
12991
+ grantsAuthority(annotate(groups.command("remove"), { effects: LOCAL_WRITE, output: { entity: "account_group" } })).description("take an account out of a group; the account and its data stay, and `all` still reads it").summary("take an account out of a group").argument("<group>", "the group").argument("<source>", MEMBER_HELP).option("--json", "print JSON; --json=id,title keeps only those fields").action((group, member, options) => show("groups remove", options.json, (store) => removeGroupMember(at(store, env), { group, member })));
12992
+ grantsAuthority(annotate(groups.command("move"), { effects: LOCAL_WRITE, output: { entity: "account_group" } })).description("move an account from one group to another in one write; the other group is made when it is new").summary("move an account between groups").argument("<source>", MEMBER_HELP).argument("<from>", "the group it leaves").argument("<to>", "the group it joins").option("--json", "print JSON; --json=id,title keeps only those fields").action((member, from, to, options) => show("groups move", options.json, (store) => moveGroupMember(at(store, env), { member, from, to, reserved: reserved() })));
12993
+ }, "groupsCommand");
12994
+
12232
12995
  // dist/store/info-command.js
12233
12996
  var storeCommand = /* @__PURE__ */ __name((program, streams, env) => {
12234
12997
  const { print } = answers(program, streams, env);
@@ -12330,7 +13093,7 @@ var tagsCommand = /* @__PURE__ */ __name((program, streams, env) => {
12330
13093
  }
12331
13094
  if (options.contact !== void 0 || options.meeting !== void 0) {
12332
13095
  await withStore(env, async (store) => {
12333
- const { key, target: target2 } = await selectTarget(store, { ...options, ...await scoped3(store) });
13096
+ const { key, target: target2 } = await selectTarget(store, env, { ...options, ...await scoped3(store) });
12334
13097
  const changed = await (operation === "add" ? store.knowledge.addTags : store.knowledge.removeTags)(key, target2, given2);
12335
13098
  print(options.json, itemAnswer({ ...key, target: target2, [operation === "add" ? "added" : "removed"]: changed }), `${operation}: ${changed.join(", ") || "no labels changed"}`);
12336
13099
  });
@@ -12367,7 +13130,7 @@ var tagsCommand = /* @__PURE__ */ __name((program, streams, env) => {
12367
13130
  ...terms2.has("type") ? { type: terms2.get("type") } : {}
12368
13131
  };
12369
13132
  await withStore(env, async (store) => {
12370
- const keys = value === void 0 ? await store.accounts.accounts() : await accountsOf(store, env, value);
13133
+ const keys = value === void 0 ? await scopedAccounts(store, env) : await accountsOf(store, env, value);
12371
13134
  const answer = await listTags(store, { ...options, keys });
12372
13135
  const owned = options.type === void 0 || OWNED.includes(options.type) ? await store.knowledge.labelled(null, {
12373
13136
  ...options.tag === void 0 ? {} : { tag: options.tag },
@@ -12439,7 +13202,7 @@ var requireAccount = /* @__PURE__ */ __name((env, warn) => async (_, command) =>
12439
13202
  return;
12440
13203
  if (["show", "update", "claim", "release"].includes(command.name()) && first !== void 0 && await store.tasks.projectTask(first))
12441
13204
  return;
12442
- const listed2 = (await store.accounts.accounts()).map((key) => `${option} ${key.provider}:${key.account}`).join("; ");
13205
+ const listed2 = (await scopedAccounts(store, env)).map((key) => `${option} ${key.provider}:${key.account}`).join("; ");
12443
13206
  throw new CliError("validation_error", `give ${option} \u2014 the stored accounts: ${listed2 || "none yet"}`);
12444
13207
  } finally {
12445
13208
  await store.close();
@@ -12515,7 +13278,7 @@ var addFromSource = /* @__PURE__ */ __name(async (store, env, source, options) =
12515
13278
  const parsed = native ? void 0 : parseLocator(source);
12516
13279
  if (parsed && (options.provider && options.provider !== parsed.provider || options.account && options.account !== parsed.account))
12517
13280
  throw new CliError("validation_error", "locator and selected account disagree");
12518
- const key = parsed ? { provider: parsed.provider, account: parsed.account } : (options.provider === void 0 ? await folderOf(store, source) : void 0) ?? await selectAccount(store, options);
13281
+ const key = parsed ? { provider: parsed.provider, account: parsed.account } : (options.provider === void 0 ? await folderOf(store, source) : void 0) ?? await selectAccount(store, env, options);
12519
13282
  if (parsed && parsed.provider !== "notes" && await heldMessage(store, key, parsed.message, parsed.chat) === void 0)
12520
13283
  throw new CliError("not_found", "the task source is unavailable or deleted");
12521
13284
  const author = authorOf(env);
@@ -12544,7 +13307,7 @@ var closeTask = /* @__PURE__ */ __name(async (store, env, id, options) => {
12544
13307
  }
12545
13308
  if (options.revision !== void 0)
12546
13309
  throw new CliError("validation_error", "--revision checks a project task; a task from a message has none");
12547
- const key = await selectAccount(store, options);
13310
+ const key = await selectAccount(store, env, options);
12548
13311
  return tasksService(storeOnlyDeps(store, key, { app: APP, env })).close(id, {
12549
13312
  as: options.as,
12550
13313
  by: "owner",
@@ -12576,7 +13339,7 @@ var updateTask = /* @__PURE__ */ __name(async (store, env, id, options) => {
12576
13339
  if (options.priority !== void 0 || options.parent !== void 0)
12577
13340
  throw new CliError("validation_error", "--priority and --parent are for a task in a project");
12578
13341
  const assignees = options.assignee?.map((one2) => one2 === "sender" || one2 === "none" ? one2 : personRef(one2));
12579
- const key = await selectAccount(store, options);
13342
+ const key = await selectAccount(store, env, options);
12580
13343
  return tasksService(storeOnlyDeps(store, key, { app: APP, env })).plan(id, {
12581
13344
  ...options.title === void 0 ? {} : { title: options.title },
12582
13345
  ...options.description === void 0 ? {} : { description: options.description },
@@ -12957,6 +13720,38 @@ var OWN_ENTITIES = entityFields({
12957
13720
  agent_action: ["id", "actor", "tool", "tier", "target", "status", "error", "started_at", "finished_at"],
12958
13721
  meeting_project: ["id", "meeting", "project", "confirmed", "provenance", "fingerprint"],
12959
13722
  notes_folder: ["id", "name", "path", "format", "kept_by"],
13723
+ account_group: ["group", "members", "duplicates", "suggested"],
13724
+ relationship_role: ["list", "id", "label", "built_in"],
13725
+ person_context_memo: [
13726
+ "messages",
13727
+ "events",
13728
+ "notes",
13729
+ "your_notes",
13730
+ "not_read",
13731
+ "tasks",
13732
+ "relationships",
13733
+ "business",
13734
+ "coverage",
13735
+ "files",
13736
+ "untrusted",
13737
+ "proposals"
13738
+ ],
13739
+ organization_context_memo: [
13740
+ "organization",
13741
+ "categories",
13742
+ "people",
13743
+ "customers",
13744
+ "suppliers",
13745
+ "partners",
13746
+ "projects",
13747
+ "deals",
13748
+ "money",
13749
+ "communications",
13750
+ "tasks",
13751
+ "coverage",
13752
+ "notes",
13753
+ "tags"
13754
+ ],
12960
13755
  order: [
12961
13756
  "id",
12962
13757
  "ref",
@@ -13233,6 +14028,89 @@ var OWN_ENTITIES = entityFields({
13233
14028
  records_match: ["linked", "created", "unmatched", "proposed", "errors", "truncated"],
13234
14029
  payment_allocation: ["payment", "invoice", "amount", "currency", "created_at"]
13235
14030
  });
14031
+ var GROUP_AWARE = [
14032
+ "context",
14033
+ "show",
14034
+ "messages show",
14035
+ "search all",
14036
+ "search messages",
14037
+ "search mail",
14038
+ "search notes",
14039
+ "search people",
14040
+ "groups",
14041
+ "tags add",
14042
+ "tags remove",
14043
+ "deals",
14044
+ "leads",
14045
+ "pipelines list",
14046
+ "pipelines show",
14047
+ "stages",
14048
+ "organizations",
14049
+ "people list",
14050
+ "people add",
14051
+ "notes list",
14052
+ "notes show",
14053
+ "relationships list",
14054
+ "relationships add",
14055
+ "relationships update",
14056
+ "relationships end",
14057
+ "relationships remove",
14058
+ "relationships confirm",
14059
+ "relationships roles",
14060
+ "mcp serve",
14061
+ "memories",
14062
+ "facts",
14063
+ "actions",
14064
+ "review",
14065
+ "tasks",
14066
+ "projects list",
14067
+ "projects add",
14068
+ "projects context",
14069
+ "projects status",
14070
+ "projects key-documents"
14071
+ ];
14072
+ var isSimpleKind = /* @__PURE__ */ __name((name2) => REF_KINDS.some(({ type }) => type === name2), "isSimpleKind");
14073
+ var REF_KINDS_OF = {
14074
+ deals: { ref: "deal" },
14075
+ leads: { ref: "lead" },
14076
+ memories: { ref: "memory" },
14077
+ facts: { ref: "fact" },
14078
+ tasks: { id: "task", "other-task": "task" },
14079
+ actions: { id: "action" },
14080
+ review: { id: "proposal", ids: "proposal" }
14081
+ };
14082
+ var UNMAPPED_IDS = /* @__PURE__ */ new Set(["id", "ids", "ref", "meeting-id"]);
14083
+ var leaves2 = /* @__PURE__ */ __name((command) => command.commands.length === 0 ? [command] : command.commands.flatMap(leaves2), "leaves");
14084
+ var topOf = /* @__PURE__ */ __name((command) => {
14085
+ let at2 = command;
14086
+ while (at2.parent?.parent)
14087
+ at2 = at2.parent;
14088
+ return at2.name();
14089
+ }, "topOf");
14090
+ var markGroupAware = /* @__PURE__ */ __name((program) => {
14091
+ for (const path of GROUP_AWARE) {
14092
+ let command = program;
14093
+ for (const name2 of path.split(" "))
14094
+ command = command?.commands.find((child) => child.name() === name2);
14095
+ if (!command)
14096
+ throw new Error(`no command to mark group-aware: ${path}`);
14097
+ groupAware(command);
14098
+ for (const leaf of leaves2(command)) {
14099
+ const top = topOf(leaf);
14100
+ const kinds2 = {};
14101
+ let mapped = true;
14102
+ for (const name2 of leaf.registeredArguments.map((argument) => argument.name())) {
14103
+ const kind = REF_KINDS_OF[top]?.[name2] ?? (isSimpleKind(name2) ? name2 : void 0);
14104
+ if (kind !== void 0)
14105
+ kinds2[name2] = kind;
14106
+ else if (UNMAPPED_IDS.has(name2))
14107
+ mapped = false;
14108
+ }
14109
+ if (mapped)
14110
+ refKinds(leaf, kinds2);
14111
+ }
14112
+ }
14113
+ }, "markGroupAware");
13236
14114
  var SKILL_TOPICS = [
13237
14115
  "search",
13238
14116
  "projects",
@@ -13258,11 +14136,13 @@ var FIRST_SCREEN = {
13258
14136
  profile: false,
13259
14137
  start: "memo folders add <path>"
13260
14138
  };
13261
- var createProgram = /* @__PURE__ */ __name(({ streams: raw = processStreams, env = process.env, signal, terminal, keyring, fetchPage: fetchPage2 } = {}) => {
14139
+ var createProgram = /* @__PURE__ */ __name(({ streams: raw = processStreams, env: given2 = process.env, signal, terminal, keyring, fetchPage: fetchPage2, group, stdin } = {}) => {
14140
+ const env = group === void 0 ? given2 : { ...given2, MEMO_GROUP: group };
13262
14141
  const fields = jsonFields(raw, OWN_ENTITIES);
13263
14142
  const { streams } = fields;
13264
14143
  const program = new Command("memo").description("context about people across messengers, notes and mail").version(VERSION).option("--debug", "on failure, show the full error record: cause and stack");
13265
14144
  refuseWritesUnderLock(program, env);
14145
+ scopeRunsToGroup(program, env, group);
13266
14146
  provideTerminal(program, terminal);
13267
14147
  contextCommand(program, streams, env);
13268
14148
  showCommand(program, streams, env);
@@ -13294,7 +14174,7 @@ var createProgram = /* @__PURE__ */ __name(({ streams: raw = processStreams, env
13294
14174
  reviewCommand(program, streams, env);
13295
14175
  agentsCommand(program, streams, env);
13296
14176
  mcpCommand(program, streams, env, createProgram);
13297
- modelsCommand(program, streams, env, keyring);
14177
+ modelsCommand(program, streams, env, keyring, stdin);
13298
14178
  templatesCommand2(program, streams, env);
13299
14179
  searchCommand(program, streams, env);
13300
14180
  meetingReadCommands(program, streams, env);
@@ -13303,6 +14183,7 @@ var createProgram = /* @__PURE__ */ __name(({ streams: raw = processStreams, env
13303
14183
  askCommand(program, streams, env);
13304
14184
  syncCommand(program, streams, env, signal, keyring);
13305
14185
  storeCommand(program, streams, env);
14186
+ groupsCommand(program, streams, env);
13306
14187
  autoCommand(program, streams, env);
13307
14188
  configCommand(program, streams, env);
13308
14189
  doctorCommand(program, streams, env);
@@ -13310,14 +14191,19 @@ var createProgram = /* @__PURE__ */ __name(({ streams: raw = processStreams, env
13310
14191
  program.addCommand(scheduleCommand(env));
13311
14192
  digestCommand(program, streams, env);
13312
14193
  commandsCommand(program, streams);
13313
- const skill2 = customizeSharedCommand(skillCommand2(APP, new URL("../skills/cli-memo/SKILL.md", new URL("../program.js", import.meta.url).href)), "Memo installs its own stored-data instructions through its environment, prints the packaged primary skill without filesystem effects, and takes --json on each skill command because it has no global one.", () => {
14194
+ const skill2 = customizeSharedCommand(skillCommand2(APP, new URL("../skills/cli-memo/SKILL.md", new URL("../program.js", import.meta.url).href)), "Memo installs its own stored-data instructions through its environment, prints the packaged skills (morning-digest with the owner's brief from the store after it), and takes --json on each skill command because it has no global one.", () => {
13314
14195
  const out = answers(program, streams, env);
14196
+ let brief;
13315
14197
  const skill3 = skillCommand(APP, new URL("../skills/cli-memo/SKILL.md", new URL("../program.js", import.meta.url).href), (command) => {
13316
14198
  const json5 = command.opts().json === true;
13317
14199
  const renderer = createRenderer({ format: json5 ? "json" : "pretty", color: false, streams });
14200
+ const result = /* @__PURE__ */ __name((value) => {
14201
+ const shown3 = value;
14202
+ out.print(true, itemAnswer(shown3.content === void 0 ? value : { ...shown3, content: withBrief(shown3.content, brief) }));
14203
+ }, "result");
13318
14204
  return {
13319
- renderer: json5 ? { ...renderer, result: /* @__PURE__ */ __name((value) => out.print(true, itemAnswer(value)), "result") } : renderer,
13320
- streams,
14205
+ renderer: json5 ? { ...renderer, result } : renderer,
14206
+ streams: { ...streams, data: /* @__PURE__ */ __name((text3) => streams.data(withBrief(text3, brief)), "data") },
13321
14207
  env
13322
14208
  };
13323
14209
  }, {
@@ -13328,8 +14214,10 @@ var createProgram = /* @__PURE__ */ __name(({ streams: raw = processStreams, env
13328
14214
  for (const command of skill3.commands)
13329
14215
  command.option("--json", "print JSON");
13330
14216
  const show = skill3.commands.find((command) => command.name() === "show");
13331
- if (show)
13332
- annotate(show, { effects: NO_EFFECTS });
14217
+ show?.description(`${show.description()}; morning-digest ends with your brief from \`memo digest brief\` when you wrote one`);
14218
+ show?.hook("preAction", async (command) => {
14219
+ brief = command.args[0] === "morning-digest" ? await readBrief(env) : void 0;
14220
+ });
13333
14221
  return skill3;
13334
14222
  }, SHELL_OVERRIDES.skill);
13335
14223
  program.addCommand(skill2);
@@ -13361,6 +14249,7 @@ var createProgram = /* @__PURE__ */ __name(({ streams: raw = processStreams, env
13361
14249
  });
13362
14250
  trackAnswers(program);
13363
14251
  placeInSections(program);
14252
+ markGroupAware(program);
13364
14253
  installHelp(program, FIRST_SCREEN);
13365
14254
  provide(program, {
13366
14255
  ...environmentOf(program),
@@ -13379,6 +14268,18 @@ var createProgram = /* @__PURE__ */ __name(({ streams: raw = processStreams, env
13379
14268
  assertSharedContracts(program);
13380
14269
  return program;
13381
14270
  }, "createProgram");
14271
+ var liftGroup = /* @__PURE__ */ __name(async (program, args, env) => {
14272
+ const words = commandWords(program);
14273
+ const { profile: group, rest } = liftProfile([...args], words);
14274
+ if (group === void 0)
14275
+ return { rest };
14276
+ const next = rest.find((arg) => !arg.startsWith("-"));
14277
+ const groups = await withStore(env, async (store) => Object.keys((await memoListContext(store, env)).groups));
14278
+ const known2 = group === "all" || groups.includes(group);
14279
+ if ((known2 || groupLockOf(APP, env) !== void 0) && next !== void 0 && words.has(next))
14280
+ return { group, rest };
14281
+ throw new CliError("validation_error", known2 ? `"${group}" is a group, and a command follows it: memo ${group} search all \u2026` : `"${group}": unknown command or group \u2014 groups here: ${groups.join(", ")}; memo commands lists the commands`, { reason: "input.invalid", groups });
14282
+ }, "liftGroup");
13382
14283
  var refuseJoinedPath = /* @__PURE__ */ __name((program, args) => {
13383
14284
  let command = program;
13384
14285
  const path = [];
@@ -13398,5 +14299,6 @@ var refuseJoinedPath = /* @__PURE__ */ __name((program, args) => {
13398
14299
  export {
13399
14300
  SKILL_TOPICS,
13400
14301
  createProgram,
14302
+ liftGroup,
13401
14303
  refuseJoinedPath
13402
14304
  };