@wirecat/cli-memo 0.131.70 → 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 (279) 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-3OEV7GNU.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-7OXLZZ27.js → chunk-DXWDHC2K.js} +14 -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-EQKS6M52.js → chunk-NNUS57F4.js} +5 -5
  59. package/dist/bundle/{chunk-52F4LHCH.js → chunk-OHBP2KPQ.js} +4 -4
  60. package/dist/bundle/{chunk-YBTUFOQG.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-57SQU2YO.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-RSUVU6HA.js → program-L5IM35PO.js} +1231 -449
  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-BVRPQPGY.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/digest/digest.d.ts.map +1 -1
  120. package/dist/digest/digest.js +2 -1
  121. package/dist/digest/digest.js.map +1 -1
  122. package/dist/discovery/command.d.ts.map +1 -1
  123. package/dist/discovery/command.js +2 -0
  124. package/dist/discovery/command.js.map +1 -1
  125. package/dist/doctor/command.d.ts +22 -2
  126. package/dist/doctor/command.d.ts.map +1 -1
  127. package/dist/examples.d.ts.map +1 -1
  128. package/dist/examples.js +44 -10
  129. package/dist/examples.js.map +1 -1
  130. package/dist/facts/command.d.ts.map +1 -1
  131. package/dist/facts/command.js +7 -6
  132. package/dist/facts/command.js.map +1 -1
  133. package/dist/finance/deal-text.d.ts +4 -0
  134. package/dist/finance/deal-text.d.ts.map +1 -0
  135. package/dist/finance/deal-text.js +34 -0
  136. package/dist/finance/deal-text.js.map +1 -0
  137. package/dist/finance/deals-command.d.ts +1 -1
  138. package/dist/finance/deals-command.d.ts.map +1 -1
  139. package/dist/finance/deals-command.js +113 -13
  140. package/dist/finance/deals-command.js.map +1 -1
  141. package/dist/knowledge/business-text.d.ts +7 -0
  142. package/dist/knowledge/business-text.d.ts.map +1 -0
  143. package/dist/knowledge/business-text.js +19 -0
  144. package/dist/knowledge/business-text.js.map +1 -0
  145. package/dist/knowledge/command.d.ts +1 -1
  146. package/dist/knowledge/command.d.ts.map +1 -1
  147. package/dist/knowledge/command.js +131 -42
  148. package/dist/knowledge/command.js.map +1 -1
  149. package/dist/knowledge/money-text.d.ts +4 -0
  150. package/dist/knowledge/money-text.d.ts.map +1 -0
  151. package/dist/knowledge/money-text.js +16 -0
  152. package/dist/knowledge/money-text.js.map +1 -0
  153. package/dist/knowledge/organization-text.d.ts +7 -0
  154. package/dist/knowledge/organization-text.d.ts.map +1 -0
  155. package/dist/knowledge/organization-text.js +24 -0
  156. package/dist/knowledge/organization-text.js.map +1 -0
  157. package/dist/knowledge/project-actions-command.js +1 -1
  158. package/dist/knowledge/project-actions-command.js.map +1 -1
  159. package/dist/knowledge/project-actions.d.ts +1 -1
  160. package/dist/knowledge/project-actions.d.ts.map +1 -1
  161. package/dist/knowledge/project-actions.js +2 -2
  162. package/dist/knowledge/project-actions.js.map +1 -1
  163. package/dist/knowledge/project-context.d.ts +27 -1
  164. package/dist/knowledge/project-context.d.ts.map +1 -1
  165. package/dist/knowledge/project-context.js +9 -5
  166. package/dist/knowledge/project-context.js.map +1 -1
  167. package/dist/knowledge/project-status-command.d.ts.map +1 -1
  168. package/dist/knowledge/project-status-command.js +21 -5
  169. package/dist/knowledge/project-status-command.js.map +1 -1
  170. package/dist/knowledge/relationships.d.ts +27 -23
  171. package/dist/knowledge/relationships.d.ts.map +1 -1
  172. package/dist/knowledge/relationships.js +65 -52
  173. package/dist/knowledge/relationships.js.map +1 -1
  174. package/dist/knowledge/roles-command.d.ts +8 -0
  175. package/dist/knowledge/roles-command.d.ts.map +1 -0
  176. package/dist/knowledge/roles-command.js +65 -0
  177. package/dist/knowledge/roles-command.js.map +1 -0
  178. package/dist/mcp/catalogue.d.ts +1 -1
  179. package/dist/mcp/catalogue.d.ts.map +1 -1
  180. package/dist/mcp/catalogue.js +3 -1
  181. package/dist/mcp/catalogue.js.map +1 -1
  182. package/dist/mcp/server.js +1 -1
  183. package/dist/mcp/server.js.map +1 -1
  184. package/dist/memories/command.d.ts.map +1 -1
  185. package/dist/memories/command.js +6 -5
  186. package/dist/memories/command.js.map +1 -1
  187. package/dist/memories/sources.js +2 -2
  188. package/dist/memories/sources.js.map +1 -1
  189. package/dist/models/command.d.ts +1 -1
  190. package/dist/models/command.d.ts.map +1 -1
  191. package/dist/models/command.js +2 -1
  192. package/dist/models/command.js.map +1 -1
  193. package/dist/notes/command.d.ts.map +1 -1
  194. package/dist/notes/command.js +13 -8
  195. package/dist/notes/command.js.map +1 -1
  196. package/dist/notes/embed.d.ts +6 -1
  197. package/dist/notes/embed.d.ts.map +1 -1
  198. package/dist/notes/embed.js +17 -8
  199. package/dist/notes/embed.js.map +1 -1
  200. package/dist/people/command.d.ts.map +1 -1
  201. package/dist/people/command.js +2 -1
  202. package/dist/people/command.js.map +1 -1
  203. package/dist/program.d.ts +13 -1
  204. package/dist/program.d.ts.map +1 -1
  205. package/dist/program.js +158 -4
  206. package/dist/program.js.map +1 -1
  207. package/dist/reasons.d.ts.map +1 -1
  208. package/dist/reasons.js +12 -0
  209. package/dist/reasons.js.map +1 -1
  210. package/dist/review/command.js +2 -2
  211. package/dist/review/command.js.map +1 -1
  212. package/dist/review/review.d.ts +3 -3
  213. package/dist/review/review.d.ts.map +1 -1
  214. package/dist/review/review.js +6 -6
  215. package/dist/review/review.js.map +1 -1
  216. package/dist/review/status.d.ts.map +1 -1
  217. package/dist/review/status.js +5 -4
  218. package/dist/review/status.js.map +1 -1
  219. package/dist/run/import.d.ts +2 -2
  220. package/dist/run/import.d.ts.map +1 -1
  221. package/dist/run/import.js +9 -3
  222. package/dist/run/import.js.map +1 -1
  223. package/dist/search/command.d.ts.map +1 -1
  224. package/dist/search/command.js +21 -3
  225. package/dist/search/command.js.map +1 -1
  226. package/dist/search/denied.d.ts +10 -0
  227. package/dist/search/denied.d.ts.map +1 -0
  228. package/dist/search/denied.js +10 -0
  229. package/dist/search/denied.js.map +1 -0
  230. package/dist/search/people.d.ts.map +1 -1
  231. package/dist/search/people.js +11 -1
  232. package/dist/search/people.js.map +1 -1
  233. package/dist/search/search.d.ts +2 -0
  234. package/dist/search/search.d.ts.map +1 -1
  235. package/dist/search/search.js +37 -12
  236. package/dist/search/search.js.map +1 -1
  237. package/dist/store/group.d.ts +38 -0
  238. package/dist/store/group.d.ts.map +1 -0
  239. package/dist/store/group.js +112 -0
  240. package/dist/store/group.js.map +1 -0
  241. package/dist/store/groups-command.d.ts +10 -0
  242. package/dist/store/groups-command.d.ts.map +1 -0
  243. package/dist/store/groups-command.js +88 -0
  244. package/dist/store/groups-command.js.map +1 -0
  245. package/dist/store/guard.d.ts +29 -0
  246. package/dist/store/guard.d.ts.map +1 -0
  247. package/dist/store/guard.js +94 -0
  248. package/dist/store/guard.js.map +1 -0
  249. package/dist/store/scope.d.ts +3 -3
  250. package/dist/store/scope.d.ts.map +1 -1
  251. package/dist/store/scope.js +7 -6
  252. package/dist/store/scope.js.map +1 -1
  253. package/dist/store/source-list.d.ts +5 -1
  254. package/dist/store/source-list.d.ts.map +1 -1
  255. package/dist/store/source-list.js +30 -15
  256. package/dist/store/source-list.js.map +1 -1
  257. package/dist/tags/command.d.ts.map +1 -1
  258. package/dist/tags/command.js +3 -2
  259. package/dist/tags/command.js.map +1 -1
  260. package/dist/tasks/shared.d.ts.map +1 -1
  261. package/dist/tasks/shared.js +2 -1
  262. package/dist/tasks/shared.js.map +1 -1
  263. package/dist/tasks/tasks.js +3 -3
  264. package/dist/tasks/tasks.js.map +1 -1
  265. package/dist/version.d.ts +1 -1
  266. package/dist/version.js +1 -1
  267. package/package.json +4 -3
  268. package/skills/cli-memo/SKILL.md +7 -7
  269. package/skills/cli-memo/topics/mcp.md +9 -0
  270. package/skills/cli-memo/topics/money.md +14 -1
  271. package/skills/cli-memo/topics/projects.md +2 -1
  272. package/skills/cli-memo/topics/search.md +12 -4
  273. package/dist/bundle/auto-CVILDIC6.js +0 -85
  274. package/dist/bundle/failure-HM55W3NH.js +0 -65
  275. package/dist/bundle/server-AASCSGCI.js +0 -61
  276. package/dist/bundle/server-YQLPZK4Z.js +0 -48
  277. package/dist/bundle/store-maintenance-command-GCBABKEZ.js +0 -47
  278. package/dist/bundle/update-ZE53ASCW.js +0 -68
  279. /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-3OEV7GNU.js";
9
+ } from "./chunk-BE22RDTR.js";
10
10
  import {
11
11
  installer,
12
12
  latest,
13
13
  upgradeCommand
14
- } from "./chunk-YBTUFOQG.js";
14
+ } from "./chunk-OWFC6BAF.js";
15
15
  import {
16
16
  mcpOwnerAllowed,
17
+ memoLevels,
17
18
  readOnlyAvailability,
18
19
  refuseWritesUnderLock
19
- } from "./chunk-EQKS6M52.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-57SQU2YO.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-52F4LHCH.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-7OXLZZ27.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
  {
@@ -4625,17 +4910,17 @@ var accountTasks = /* @__PURE__ */ __name(async (store, keys, options) => {
4625
4910
  });
4626
4911
  }, "accountTasks");
4627
4912
  var accountTerms = /* @__PURE__ */ __name((query) => {
4628
- const leaves2 = query ? walkQuery(query.root) : [];
4629
- 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));
4630
4915
  if (other)
4631
4916
  throw new CliError("validation_error", `${other.field}: narrows project tasks: add project:<key>, or project:* for every project`);
4632
- 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()));
4633
4918
  if ((states.has("todo") || states.has("in_progress")) && !states.has("open"))
4634
4919
  throw new CliError("validation_error", "todo and in_progress are steps of a project task: add project:");
4635
4920
  const closed = [...states].filter(isClosedState);
4636
4921
  if (closed.length > 1 || closed.length === 1 && states.size > 1)
4637
4922
  throw new CliError("validation_error", "an account's tasks are listed in one state: state:open, done or dismissed");
4638
- const sources = leaves2.filter(({ field: field2 }) => field2 === "source").map(({ value }) => value);
4923
+ const sources = leaves3.filter(({ field: field2 }) => field2 === "source").map(({ value }) => value);
4639
4924
  if (sources.length > 1)
4640
4925
  throw new CliError("validation_error", "source: only once here");
4641
4926
  return { state: closed[0] ?? "open", source: sources[0] };
@@ -4691,9 +4976,9 @@ var listTasks = /* @__PURE__ */ __name(async (store, words, options, accounts) =
4691
4976
  }
4692
4977
  const typed = typedQuery(words);
4693
4978
  const query = listQuery(typed, TASKS_LIST_QUERY, "tasks list", { defaultField: "text" });
4694
- const leaves2 = query ? walkQuery(query.root) : [];
4695
- if (leaves2.some(({ field: field2 }) => field2 === "project")) {
4696
- 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"))
4697
4982
  throw new CliError("validation_error", "source: narrows an account's tasks, not a project's");
4698
4983
  return projectTasks(store, typed, await resolveProjects(store, query), options);
4699
4984
  }
@@ -4783,13 +5068,13 @@ var onPath = /* @__PURE__ */ __name((name2, env) => (env.PATH ?? "").split(delim
4783
5068
  var runChild = /* @__PURE__ */ __name((command, args, { env, signal, onStderr }) => new Promise((resolve6, reject) => {
4784
5069
  const child = spawn(command, args, { env, stdio: ["ignore", "pipe", "pipe"] });
4785
5070
  let stdout = "";
4786
- let pending2 = "";
5071
+ let pending = "";
4787
5072
  child.stdout.setEncoding("utf8").on("data", (chunk) => {
4788
5073
  stdout += chunk;
4789
5074
  });
4790
5075
  child.stderr.setEncoding("utf8").on("data", (chunk) => {
4791
- const lines2 = (pending2 + chunk).split("\n");
4792
- pending2 = lines2.pop() ?? "";
5076
+ const lines2 = (pending + chunk).split("\n");
5077
+ pending = lines2.pop() ?? "";
4793
5078
  for (const line3 of lines2)
4794
5079
  if (line3)
4795
5080
  onStderr?.(line3);
@@ -4804,8 +5089,8 @@ var runChild = /* @__PURE__ */ __name((command, args, { env, signal, onStderr })
4804
5089
  child.on("close", (code) => {
4805
5090
  clearTimeout(hard);
4806
5091
  signal?.removeEventListener("abort", stop);
4807
- if (pending2)
4808
- onStderr?.(pending2);
5092
+ if (pending)
5093
+ onStderr?.(pending);
4809
5094
  resolve6({ code, stdout });
4810
5095
  });
4811
5096
  }), "runChild");
@@ -5015,7 +5300,7 @@ var QUIET_AFTER = 3 * DAY3;
5015
5300
  var QUIET_GAPS = 3;
5016
5301
  var hours = /* @__PURE__ */ __name((from, now) => Math.max(0, Math.floor((now - from) / HOUR)), "hours");
5017
5302
  var healthOf = /* @__PURE__ */ __name((sync, activity, now) => {
5018
- const recent = /* @__PURE__ */ __name((at) => at !== null && at >= now - DAY3, "recent");
5303
+ const recent = /* @__PURE__ */ __name((at2) => at2 !== null && at2 >= now - DAY3, "recent");
5019
5304
  if (recent(activity.storedAt) || sync.runs.some((run) => run.exitCode === 0 && recent(Date.parse(run.at))))
5020
5305
  return void 0;
5021
5306
  if (!sync.serving && sync.runs.length > 0 && sync.runs.every((run) => run.exitCode !== 0)) {
@@ -5059,9 +5344,9 @@ var digestReportTimes = /* @__PURE__ */ __name((env) => {
5059
5344
  const runs = schedule ? join6(state, "schedules", schedule.name, "runs") : void 0;
5060
5345
  if (!runs || !existsSync6(runs))
5061
5346
  return [];
5062
- 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);
5063
5348
  }, "digestReportTimes");
5064
- 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");
5065
5350
  var previousDigestAt = /* @__PURE__ */ __name((env, now) => {
5066
5351
  const last = digestSchedule(env).schedule?.last;
5067
5352
  if (!last)
@@ -5158,8 +5443,8 @@ var gatherTasks = /* @__PURE__ */ __name(async (store, keys, { now, newSince, un
5158
5443
  // dist/digest/backfill.js
5159
5444
  var DAY5 = 864e5;
5160
5445
  var DATE = /^(\d{4})-(\d{2})-(\d{2})$/;
5161
- var localDate = /* @__PURE__ */ __name((at) => {
5162
- const day2 = new Date(at);
5446
+ var localDate = /* @__PURE__ */ __name((at2) => {
5447
+ const day2 = new Date(at2);
5163
5448
  return `${day2.getFullYear()}-${String(day2.getMonth() + 1).padStart(2, "0")}-${String(day2.getDate()).padStart(2, "0")}`;
5164
5449
  }, "localDate");
5165
5450
  var dateOf = /* @__PURE__ */ __name((value, flag) => {
@@ -5179,8 +5464,8 @@ var daysOf = /* @__PURE__ */ __name((from, to, time) => {
5179
5464
  });
5180
5465
  return days2;
5181
5466
  }, "daysOf");
5182
- var inputOf = /* @__PURE__ */ __name((date, at) => `backfill: ${date}
5183
- 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()}
5184
5469
  `, "inputOf");
5185
5470
  var usd = /* @__PURE__ */ __name((value) => `$${value.toFixed(2)}`, "usd");
5186
5471
  var cents = /* @__PURE__ */ __name((value) => Math.round(value * 100) / 100, "cents");
@@ -5314,6 +5599,7 @@ var SECTIONS = [
5314
5599
  ["deals", "organise"],
5315
5600
  ["leads", "organise"],
5316
5601
  ["pipelines", "organise"],
5602
+ ["stages", "organise"],
5317
5603
  ["payments", "organise"],
5318
5604
  ["products", "organise"],
5319
5605
  ["contracts", "organise"],
@@ -5330,6 +5616,7 @@ var SECTIONS = [
5330
5616
  ["jobs", "automate"],
5331
5617
  ["digest", "automate"],
5332
5618
  ["folders", "setup"],
5619
+ ["groups", "setup"],
5333
5620
  ["config", "setup"]
5334
5621
  ];
5335
5622
  var placeInSections = /* @__PURE__ */ __name((program) => {
@@ -5451,7 +5738,7 @@ var diagnose = /* @__PURE__ */ __name(async (env, program, { deep = false } = {}
5451
5738
  };
5452
5739
  }, "diagnose");
5453
5740
  var yes = /* @__PURE__ */ __name((value) => value ? "yes" : "no", "yes");
5454
- 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");
5455
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");
5456
5743
  var doctorText = /* @__PURE__ */ __name((d, fixes = [], online) => [
5457
5744
  `memo ${d.memo.version} on Node ${d.memo.node}, installed by ${d.memo.installed_by}`,
@@ -5509,7 +5796,7 @@ var doctorCommand = /* @__PURE__ */ __name((...args) => {
5509
5796
  }, SHELL_OVERRIDES.doctor);
5510
5797
  }, "doctorCommand");
5511
5798
 
5512
- // 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
5513
5800
  var DAY6 = 864e5;
5514
5801
  var SLOTS_EVERY = 7 * DAY6;
5515
5802
  var isWindow = /* @__PURE__ */ __name((value) => typeof value?.from === "number" && typeof value.to === "number", "isWindow");
@@ -5589,10 +5876,10 @@ var calendarStatus = /* @__PURE__ */ __name(async (store, accountId, { profile,
5589
5876
  return { items, page: 1, limit: Math.max(1, items.length), hasMore: false };
5590
5877
  }, "calendarStatus");
5591
5878
 
5592
- // 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
5593
5880
  var FEED_LIMITS = { maxBytes: 10 * 1024 * 1024, timeoutMs: 3e4, redirects: 5 };
5594
5881
 
5595
- // 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
5596
5883
  var LIST = "events list";
5597
5884
  var EVENT_TYPES = [
5598
5885
  "default",
@@ -5669,7 +5956,7 @@ var accountsMeta = /* @__PURE__ */ __name(async (store, accounts, skipped, now)
5669
5956
  };
5670
5957
  }, "accountsMeta");
5671
5958
 
5672
- // 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
5673
5960
  var EVENTS_NOTIFY_KEY = "events.notify";
5674
5961
  var EVENTS_DELETE_SERIES_KEY = "events.delete.series";
5675
5962
  var EVENTS_REMIND_HOOK_KEY = "events.remind.hook";
@@ -5750,7 +6037,7 @@ var calendarOf = /* @__PURE__ */ __name((accounts, value) => {
5750
6037
  throw new CliError("not_found", `calendar:${value} names no calendar in the accounts read`);
5751
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(", "));
5752
6039
  }, "calendarOf");
5753
- 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");
5754
6041
  var plusDays = /* @__PURE__ */ __name((date, days2) => {
5755
6042
  const [year, month, day2] = date.split("-").map(Number);
5756
6043
  return new Date(Date.UTC(year, month - 1, day2 + days2)).toISOString().slice(0, 10);
@@ -5884,7 +6171,11 @@ ${plainText(body, command)}`);
5884
6171
 
5885
6172
  // dist/examples.js
5886
6173
  var EXAMPLES = {
5887
- 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
+ ],
5888
6179
  show: [
5889
6180
  "memo show chat:max/500/-1001 document:413",
5890
6181
  "memo show note:12 msg:telegram/1/77/42 --json",
@@ -5915,6 +6206,10 @@ var EXAMPLES = {
5915
6206
  "folders update": ["memo folders update 1 ~/notes"],
5916
6207
  "folders remove": ["memo folders remove 1", "memo folders remove 1 --allow-delete --yes"],
5917
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"],
5918
6213
  "config show": ["memo config show", "memo config show --json"],
5919
6214
  "config migrate": ["memo config migrate"],
5920
6215
  "config unset": ["memo config unset permissions.notes.edit"],
@@ -5974,7 +6269,7 @@ var EXAMPLES = {
5974
6269
  ],
5975
6270
  "models list": ["memo models list kind:text --json"],
5976
6271
  "commands info": ["memo commands info --json"],
5977
- "models download": ["memo models download e5-small", "memo models download e5-large"],
6272
+ "models download": ["memo models download embeddinggemma", "memo models download e5-small"],
5978
6273
  "models set": ["memo models set e5-large"],
5979
6274
  "models consents show": ["memo models consents show --json"],
5980
6275
  "models consents set": [
@@ -5982,6 +6277,8 @@ var EXAMPLES = {
5982
6277
  "memo models consents set openai --model gpt-4o-mini --yes"
5983
6278
  ],
5984
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"],
5985
6282
  "models add": [
5986
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: "}}'`
5987
6284
  ],
@@ -6038,8 +6335,12 @@ var EXAMPLES = {
6038
6335
  "memo organizations rename 1 'Harbour Studio Ltd' --json"
6039
6336
  ],
6040
6337
  "organizations show": ["memo organizations show organization:1"],
6041
- "organizations list": ["memo organizations list name:*harbour*", "memo organizations list --json"],
6042
- "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"],
6043
6344
  "projects meetings list": ["memo projects meetings list HRB --source zoom:me@example.com"],
6044
6345
  "projects meetings link": ["memo projects meetings link HRB 31 --account zoom:me@example.com"],
6045
6346
  "projects add": ["memo projects add 'Harbour' --key HRB --type client --organization 1"],
@@ -6063,12 +6364,20 @@ var EXAMPLES = {
6063
6364
  "memo relationships update 12 --role approver --role-note 'signs the acts'"
6064
6365
  ],
6065
6366
  "relationships add": [
6066
- "memo relationships add person:3 organization:1 --role employee",
6067
- "memo relationships add person:3 project:1 --role client-contact --engagement low",
6068
- "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"
6069
6375
  ],
6070
- "relationships list": ['memo relationships list about:"person:3"', "memo relationships list confirmed:false"],
6071
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"],
6072
6381
  "relationships confirm": ["memo relationships confirm 4"],
6073
6382
  "relationships scan": [
6074
6383
  "memo relationships scan HRB --source all",
@@ -6118,16 +6427,28 @@ var EXAMPLES = {
6118
6427
  ],
6119
6428
  "deals list": ["memo deals list status:open project:HRB", "memo deals list stage:Quote --json"],
6120
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"],
6121
6432
  "deals add": [
6122
6433
  "memo deals add 'Site for the clinic' Call 500000.00 RUB --organization organization:3 --project HRB",
6123
6434
  "memo deals add 'Support contract' Sales/Quote --person person:7 --role decision-maker --due 2026-12-01"
6124
6435
  ],
6125
- "deals move": ["memo deals move deal:5 Quote"],
6436
+ "deals move": ["memo deals move deal:5 Quote", "memo deals move deal:5 stage:5"],
6126
6437
  "deals close": ["memo deals close deal:5 won", "memo deals close deal:6 lost --reason 'chose a cheaper studio'"],
6127
6438
  "leads list": ["memo leads list status:open"],
6128
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"],
6129
6442
  "leads add": ["memo leads add 'Call from the site'", "memo leads add 'Clinic in Kazan' contacted --person person:9"],
6130
- "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"],
6131
6452
  "leads close": ["memo leads close lead:3 lost --reason 'no budget'"],
6132
6453
  "orders add": [
6133
6454
  "memo orders add 'Shop One' 2499.00 RUB --kind personal --title A-1042",
@@ -6364,8 +6685,8 @@ var EXAMPLES = {
6364
6685
  help: ["memo help options", "memo help tasks agenda"]
6365
6686
  };
6366
6687
  var leaves = /* @__PURE__ */ __name((command, path = []) => command.commands.flatMap((child) => {
6367
- const at = [...path, child.name()];
6368
- 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]];
6369
6690
  }), "leaves");
6370
6691
  var addExamples = /* @__PURE__ */ __name((program) => {
6371
6692
  for (const [path, command] of leaves(program)) {
@@ -6582,11 +6903,11 @@ var statusLine = /* @__PURE__ */ __name((data) => {
6582
6903
  var personal = /* @__PURE__ */ __name((newest) => !newest.bulk && !newest.list && !newest.envelope && !newest.demoted, "personal");
6583
6904
  var gatherDigest = /* @__PURE__ */ __name(async (store, env, { since, now: clock = Date.now(), until, limit, excerpt: excerpt2, owedWithin, newSince }) => {
6584
6905
  const now = until ?? clock;
6585
- const by = /* @__PURE__ */ __name((at) => until === void 0 || at <= until, "by");
6906
+ const by = /* @__PURE__ */ __name((at2) => until === void 0 || at2 <= until, "by");
6586
6907
  const upTo = /* @__PURE__ */ __name((found) => found.filter((one2) => by(Date.parse(one2.item.at))), "upTo");
6587
6908
  const window = (now - since) / DAY7;
6588
6909
  const days2 = `${Math.max(1, Math.ceil(window))}d`;
6589
- const accounts = await store.accounts.accounts();
6910
+ const accounts = await scopedAccounts(store, env);
6590
6911
  const messengers2 = accounts.filter((key) => MESSENGERS2.has(key.provider));
6591
6912
  const mailboxes = accounts.filter((key) => key.provider === "email");
6592
6913
  const owedSince = Math.min(since, now - owedWithin);
@@ -6723,7 +7044,7 @@ var gatherDigest = /* @__PURE__ */ __name(async (store, env, { since, now: clock
6723
7044
  bulk++;
6724
7045
  continue;
6725
7046
  }
6726
- const pending2 = /* @__PURE__ */ __name((why) => ({
7047
+ const pending = /* @__PURE__ */ __name((why) => ({
6727
7048
  item: {
6728
7049
  ref: ref(thread.threadId),
6729
7050
  who: null,
@@ -6735,15 +7056,15 @@ var gatherDigest = /* @__PURE__ */ __name(async (store, env, { since, now: clock
6735
7056
  }), "pending");
6736
7057
  if (isWatchedChat(key, thread.threadId)) {
6737
7058
  if (inWindow)
6738
- watch.push(pending2("watched thread"));
7059
+ watch.push(pending("watched thread"));
6739
7060
  } else if (mailTurn(last) === "owed") {
6740
7061
  if (inWindow)
6741
- owedMail.push({ pending: pending2("owed reply"), externalId: last.externalId });
7062
+ owedMail.push({ pending: pending("owed reply"), externalId: last.externalId });
6742
7063
  else if (thread.lastEmailAt >= owedSince)
6743
7064
  olderMail++;
6744
7065
  owedHere++;
6745
7066
  } else if (inWindow && !last.outgoing) {
6746
- mail.push(pending2("new mail"));
7067
+ mail.push(pending("new mail"));
6747
7068
  newHere++;
6748
7069
  }
6749
7070
  }
@@ -6992,16 +7313,16 @@ var sinceOf = /* @__PURE__ */ __name((value, now = Date.now()) => {
6992
7313
  return since;
6993
7314
  }, "sinceOf");
6994
7315
  var beforeOf = /* @__PURE__ */ __name((value, now = Date.now()) => {
6995
- const at = /^\d{4}-\d{2}-\d{2}$/.test(value) ? (/* @__PURE__ */ new Date(`${value}T00:00:00`)).getTime() : Date.parse(value);
6996
- 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))
6997
7318
  throw new CliError("validation_error", `--before-time takes an ISO time or a date, not "${value}"`, {
6998
7319
  param: "before-time"
6999
7320
  });
7000
- if (at > now)
7321
+ if (at2 > now)
7001
7322
  throw new CliError("validation_error", "--before-time is in the future; leave it out for now", {
7002
7323
  param: "before-time"
7003
7324
  });
7004
- return at;
7325
+ return at2;
7005
7326
  }, "beforeOf");
7006
7327
  var reviewAgendaCommand = /* @__PURE__ */ __name((review, print, streams, env) => {
7007
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) => {
@@ -7096,7 +7417,7 @@ var challengeCommand = /* @__PURE__ */ __name((parent, type, streams, env) => {
7096
7417
  by,
7097
7418
  ...options.suggest === void 0 ? {} : { suggestion: options.suggest }
7098
7419
  });
7099
- return itemAnswer(await reviewOf(store, proposal.id));
7420
+ return itemAnswer(await reviewItemOf(store, proposal.id));
7100
7421
  });
7101
7422
  });
7102
7423
  }, "challengeCommand");
@@ -7122,11 +7443,11 @@ var memoriesCommand = /* @__PURE__ */ __name((program, streams, env) => {
7122
7443
  ...options.supersedes === void 0 ? {} : { supersedes: options.supersedes }
7123
7444
  }, await by).catch(explainQuote))));
7124
7445
  });
7125
- 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)));
7126
- 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, {
7127
7448
  ...memoryItem(await store.memories.get(ref)),
7128
- ...options.sources ? { sources: await store.memories.sources(ref) } : {}
7129
- })));
7449
+ ...options.sources ? await sourcesIn(store, env, await store.memories.sources(ref)) : {}
7450
+ }))));
7130
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, {
7131
7452
  project: options.project === "none" ? null : await canonicalProject(store, options.project)
7132
7453
  })))));
@@ -7144,7 +7465,7 @@ var memoriesCommand = /* @__PURE__ */ __name((program, streams, env) => {
7144
7465
  const decided = /* @__PURE__ */ __name(async (store, ref, by, confirm) => {
7145
7466
  if ((await store.memories.get(ref)).status !== "proposed")
7146
7467
  return confirm ? store.memories.confirm(ref, by) : store.memories.markStale(ref, by);
7147
- await decideOne(store, ref, { confirm, by });
7468
+ await decideOne(store, env, ref, { confirm, by });
7148
7469
  return store.memories.get(ref);
7149
7470
  }, "decided");
7150
7471
  decide2("confirm", "stand behind a memory: its evidence was checked now", (store, ref, by) => decided(store, ref, by, true));
@@ -7244,11 +7565,11 @@ var factsCommand = /* @__PURE__ */ __name((program, streams, env) => {
7244
7565
  ...options.supersedes === void 0 ? {} : { supersedes: options.supersedes }
7245
7566
  }).catch(explainQuote))));
7246
7567
  });
7247
- 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)));
7248
- 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, {
7249
7570
  ...factItem(await store.facts.get(ref)),
7250
- ...options.sources ? { sources: await store.facts.sources(ref) } : {}
7251
- })));
7571
+ ...options.sources ? await sourcesIn(store, env, await store.facts.sources(ref)) : {}
7572
+ }))));
7252
7573
  const decide2 = /* @__PURE__ */ __name((name2, description, act) => reasonOption(byOption(annotate(facts.command(name2), {
7253
7574
  effects: LOCAL_WRITE,
7254
7575
  ...name2 === "remove" ? {} : { output: { entity: "fact" } }
@@ -7261,13 +7582,13 @@ var factsCommand = /* @__PURE__ */ __name((program, streams, env) => {
7261
7582
  });
7262
7583
  }), "decide");
7263
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) => {
7264
- await decideOne(store, ref, decisionOf(true, by, why));
7585
+ await decideOne(store, env, ref, decisionOf(true, by, why));
7265
7586
  return store.facts.get(ref);
7266
7587
  }).summary("stand behind a fact an agent proposed");
7267
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");
7268
7589
  decide2("reverse", "an accepted decision no longer holds, and nothing replaced it", (store, ref, by) => store.facts.reverse(ref, by));
7269
7590
  decide2("reject", "turn down a fact an agent proposed; it stays, marked rejected", async (store, ref, by, why) => {
7270
- await decideOne(store, ref, decisionOf(false, by, why));
7591
+ await decideOne(store, env, ref, decisionOf(false, by, why));
7271
7592
  return store.facts.get(ref);
7272
7593
  });
7273
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", `
@@ -7294,7 +7615,7 @@ var SOURCED = new Set(Object.keys(READS));
7294
7615
  var readSourced = /* @__PURE__ */ __name((store, kind, ref) => READS[kind]?.(store, ref), "readSourced");
7295
7616
  var IMPORT = "import:";
7296
7617
  var imported = /* @__PURE__ */ __name(({ source, account: account2 }) => (account2 ?? null) !== null || !!source?.startsWith(IMPORT), "imported");
7297
- var sourceAccounts = /* @__PURE__ */ __name(async (store, { source, account: account2 }) => {
7618
+ var sourceAccounts2 = /* @__PURE__ */ __name(async (store, { source, account: account2 }) => {
7298
7619
  if (account2)
7299
7620
  return [account2];
7300
7621
  if (!source?.startsWith(IMPORT))
@@ -7309,7 +7630,7 @@ var named2 = /* @__PURE__ */ __name((key) => ({
7309
7630
  var sourcesOf = /* @__PURE__ */ __name(async (store, entity) => {
7310
7631
  const { ref } = entity;
7311
7632
  const records = [];
7312
- for (const { provider, account: account2 } of await sourceAccounts(store, entity)) {
7633
+ for (const { provider, account: account2 } of await sourceAccounts2(store, entity)) {
7313
7634
  if (records.length > MOST)
7314
7635
  break;
7315
7636
  for (const one2 of await store.records.list({ provider, account: account2, entity: ref, limit: MOST + 1 }))
@@ -7654,6 +7975,46 @@ var contractCommands = /* @__PURE__ */ __name((program, streams, env) => {
7654
7975
  });
7655
7976
  }, "contractCommands");
7656
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
+
7657
8018
  // dist/finance/deals-command.js
7658
8019
  var queryOf = /* @__PURE__ */ __name((entity) => ({
7659
8020
  entity,
@@ -7672,7 +8033,14 @@ var PIPELINE_QUERY = {
7672
8033
  backend: "native",
7673
8034
  fields: [termField("kind", "enum", "kind:lead", { values: DEAL_KINDS }), termField("name", "kw", "name:Sales")]
7674
8035
  };
7675
- 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) => {
7676
8044
  const command = `${kind}s list`;
7677
8045
  const terms2 = queryTerms(words, QUERIES[kind], command);
7678
8046
  const filter = {
@@ -7683,8 +8051,21 @@ var listDeals = /* @__PURE__ */ __name(async (store, kind, words, limit) => {
7683
8051
  ...terms2.has("pipeline") ? { pipeline: terms2.get("pipeline") } : {},
7684
8052
  ...terms2.has("organization") ? { organization: terms2.get("organization") } : {}
7685
8053
  };
7686
- 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));
7687
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");
7688
8069
  var roleOf = /* @__PURE__ */ __name((role) => {
7689
8070
  const value = role ?? "contact";
7690
8071
  if (!DEAL_ROLES.includes(value))
@@ -7695,18 +8076,38 @@ var referenceOf = /* @__PURE__ */ __name((kind, value) => /^\d+$/.test(value.tri
7695
8076
  var stageOf = /* @__PURE__ */ __name((stage) => {
7696
8077
  if (stage === void 0)
7697
8078
  return {};
7698
- const at = stage.lastIndexOf("/");
7699
- 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) };
7700
8081
  }, "stageOf");
7701
8082
  var WHAT = {
7702
8083
  deal: { one: "deal", hope: "what you hope to sell, such as 'Site for the clinic'" },
7703
8084
  lead: { one: "lead", hope: "who or what came in, such as 'Call from the site'" }
7704
8085
  };
7705
- var itemCommands = /* @__PURE__ */ __name((program, kind, run, env) => {
8086
+ var itemCommands = /* @__PURE__ */ __name((program, kind, { run, print }, env) => {
7706
8087
  const { one: one2, hope } = WHAT[kind];
7707
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");
7708
- 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)));
7709
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
+ });
7710
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) => {
7711
8112
  const by = authorOf(env);
7712
8113
  const role = roleOf(options.role);
@@ -7728,9 +8129,9 @@ var itemCommands = /* @__PURE__ */ __name((program, kind, run, env) => {
7728
8129
  }));
7729
8130
  });
7730
8131
  });
7731
- 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) => {
7732
8133
  const by = authorOf(env);
7733
- 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 })));
7734
8135
  });
7735
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) => {
7736
8137
  if (outcome !== "won" && outcome !== "lost")
@@ -7751,6 +8152,21 @@ var funnelText = /* @__PURE__ */ __name((report) => [
7751
8152
  ...report.stages.map((stage) => ` ${stage.position}. ${stage.name}${stage.outcome === "open" ? "" : ` [${stage.outcome}]`}: ${stage.open} open, ${stage.reached} reached${percent(stage.conversion)}`),
7752
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)}%`)
7753
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");
7754
8170
  var dealCommands = /* @__PURE__ */ __name((program, streams, env) => {
7755
8171
  const { run, print } = answers(program, streams, env);
7756
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");
@@ -7758,15 +8174,17 @@ var dealCommands = /* @__PURE__ */ __name((program, streams, env) => {
7758
8174
  const terms2 = queryTerms(words, PIPELINE_QUERY, "pipelines list");
7759
8175
  const name2 = terms2.get("name")?.toLocaleLowerCase();
7760
8176
  const kind = terms2.get("kind");
7761
- const all = await store.deals.pipelines(kind === void 0 ? {} : { kind });
7762
- 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));
7763
8181
  }));
7764
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) => {
7765
8183
  const since = dayOf2(options.sinceTime);
7766
- 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 })));
7767
8185
  print(options.json, itemAnswer(report), funnelText(report));
7768
8186
  });
7769
- 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) => {
7770
8188
  const kind = options.kind ?? "deal";
7771
8189
  if (!DEAL_KINDS.includes(kind))
7772
8190
  throw new CliError("validation_error", "--kind is deal or lead", { param: "--kind" });
@@ -7774,15 +8192,24 @@ var dealCommands = /* @__PURE__ */ __name((program, streams, env) => {
7774
8192
  await run(options.json, async (store) => itemAnswer(await store.deals.addPipeline({
7775
8193
  name: name2,
7776
8194
  kind,
7777
- stages: stages.map((stage) => {
8195
+ stages: stages2.map((stage) => {
7778
8196
  const word = stage.trim().toLocaleLowerCase();
7779
8197
  return word === "won" || word === "lost" ? { name: stage, outcome: word } : stage;
7780
8198
  }),
7781
8199
  by
7782
8200
  })));
7783
8201
  });
7784
- itemCommands(program, "deal", run, env);
7785
- 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);
7786
8213
  }, "dealCommands");
7787
8214
  var STATUS_DEALS = 5;
7788
8215
  var openDealsOf = /* @__PURE__ */ __name(async (store, projects) => {
@@ -8130,7 +8557,7 @@ var listWallets = /* @__PURE__ */ __name(async (store, words, limit) => {
8130
8557
  var sourceSays = /* @__PURE__ */ __name(async (store, wallet) => {
8131
8558
  if (wallet.openingBalance !== null)
8132
8559
  return null;
8133
- for (const { provider, account: account2 } of await sourceAccounts(store, wallet)) {
8560
+ for (const { provider, account: account2 } of await sourceAccounts2(store, wallet)) {
8134
8561
  const [record2] = await store.records.list({ provider, account: account2, entity: wallet.ref, limit: 1 });
8135
8562
  const { opening_balance: balance, opening_date: date } = record2?.fields ?? {};
8136
8563
  if (record2 && typeof balance === "string")
@@ -8256,15 +8683,15 @@ var findingsCommand = /* @__PURE__ */ __name((program, streams, env) => {
8256
8683
 
8257
8684
  // dist/json-fields.js
8258
8685
  var commandIn = /* @__PURE__ */ __name((root, words) => {
8259
- let at = root;
8686
+ let at2 = root;
8260
8687
  for (const word of words) {
8261
8688
  if (word.startsWith("-"))
8262
8689
  continue;
8263
- 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));
8264
8691
  if (child)
8265
- at = child;
8692
+ at2 = child;
8266
8693
  }
8267
- return at === root ? void 0 : at;
8694
+ return at2 === root ? void 0 : at2;
8268
8695
  }, "commandIn");
8269
8696
  var keep = /* @__PURE__ */ __name((text3, paths) => {
8270
8697
  let value;
@@ -8359,6 +8786,27 @@ var meetingProjectsCommand = /* @__PURE__ */ __name((projects, streams, env) =>
8359
8786
  })), true));
8360
8787
  }, "meetingProjectsCommand");
8361
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
+
8362
8810
  // dist/knowledge/project-actions.js
8363
8811
  var evidenceContext = /* @__PURE__ */ __name(async (store, ref, fingerprint, words, window) => {
8364
8812
  const record2 = await store.contextRecords?.read(ref);
@@ -8418,14 +8866,14 @@ var projectActions = /* @__PURE__ */ __name(async (store, project, options) => {
8418
8866
  hasMore: found.hasMore
8419
8867
  };
8420
8868
  }, "projectActions");
8421
- var decideAction = /* @__PURE__ */ __name(async (store, project, id, decision) => {
8869
+ var decideAction = /* @__PURE__ */ __name(async (store, env, project, id, decision) => {
8422
8870
  if (!/^(key:)?[1-9]\d*$/.test(id))
8423
8871
  throw new CliError("validation_error", "an action ID is a batch number or key:<id>");
8424
8872
  const row = await proposalRegistry(store).get(id);
8425
8873
  if (row.project !== project.ref || row.kind !== "key_document" && row.kind !== "findings")
8426
8874
  throw new CliError("not_found", `no proposal ${id} in ${project.ref}; memo projects actions list shows them`);
8427
8875
  if (row.kind === "key_document") {
8428
- await decideOne(store, id, decisionOf(decision.confirm, decision.by, decision.reason));
8876
+ await decideOne(store, env, id, decisionOf(decision.confirm, decision.by, decision.reason));
8429
8877
  return { id, kind: "key_document", ref: row.subject, confirmed: decision.confirm, decided_by: decision.by };
8430
8878
  }
8431
8879
  if (decision.fingerprint === void 0)
@@ -8504,7 +8952,7 @@ var projectActionsCommand = /* @__PURE__ */ __name((projects, streams, env) => {
8504
8952
  const by = await deciderOf(command, env, { ...given2, question: `${name2} ${id} as you, the owner?` });
8505
8953
  await run(given2.json, async (store) => {
8506
8954
  const project = await projectOf(store, reference2);
8507
- return itemAnswer(await decideAction(store, project, id, {
8955
+ return itemAnswer(await decideAction(store, env, project, id, {
8508
8956
  confirm: name2 === "confirm",
8509
8957
  ...given2.fingerprint === void 0 ? {} : { fingerprint: given2.fingerprint },
8510
8958
  ...given2.reason === void 0 ? {} : { reason: given2.reason },
@@ -8558,15 +9006,17 @@ var projectFindings = /* @__PURE__ */ __name(async (store, project, links) => {
8558
9006
  // dist/knowledge/project-context.js
8559
9007
  var projectContext = /* @__PURE__ */ __name(async (store, env, reference2) => {
8560
9008
  const project = await projectOf(store, reference2);
8561
- 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);
8562
9011
  const documents = await keyDocuments(store, project);
8563
- 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");
8564
9014
  const [facts, tasks, findings, keys, links, waiting2] = await Promise.all([
8565
9015
  store.facts.list({ project: project.ref, status: "proposed", limit: 21 }),
8566
9016
  store.tasks.find({ project: project.ref, status: "open", limit: 21 }),
8567
9017
  projectFindings(store, project.ref, relationships),
8568
- pending2("key_document"),
8569
- pending2("relationship"),
9018
+ pending("key_document"),
9019
+ pending("relationship"),
8570
9020
  waitingAbout(store, env, [project.ref])
8571
9021
  ]);
8572
9022
  const label = await labelsFor(store, [...keys.items, ...links.items].flatMap((row) => [row.subject, row.object]));
@@ -8761,7 +9211,7 @@ var projectGatherCommand = /* @__PURE__ */ __name((projects, print, env, warn) =
8761
9211
  ...found,
8762
9212
  linkedChats: found.linkedChats.map((one2, i) => ({ ...one2, syncCommand: syncs[i]?.command ?? null }))
8763
9213
  }, { ...parts2, ...missing.length ? { missing } : {}, ...next.length ? { next } : {} }), projectEvidenceText(found, {
8764
- sync: /* @__PURE__ */ __name((chat, at) => syncHint(chat, at, env, chosen), "sync"),
9214
+ sync: /* @__PURE__ */ __name((chat, at2) => syncHint(chat, at2, env, chosen), "sync"),
8765
9215
  showDocument: "memo notes show"
8766
9216
  }));
8767
9217
  })
@@ -8801,7 +9251,7 @@ var outside = /* @__PURE__ */ __name((blocked) => (step, found) => {
8801
9251
  };
8802
9252
  }, "outside");
8803
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");
8804
- 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) => {
8805
9255
  if (options.compact && options.json)
8806
9256
  throw new CliError("validation_error", "--compact and --json ask for different output \u2014 pick one", {
8807
9257
  reason: "output.conflict",
@@ -8809,8 +9259,10 @@ var projectStatusCommand = /* @__PURE__ */ __name((projects, print, env) => answ
8809
9259
  });
8810
9260
  const chosen = options.syncProfile ?? {};
8811
9261
  const { found, finance, open: open2 } = await withStore(env, async (store) => {
9262
+ const scope = await groupScopeOf(store, env);
8812
9263
  const status = await projectStatus(store, {
8813
9264
  project,
9265
+ ...scope === void 0 ? {} : { accounts: scope.accounts },
8814
9266
  ...projectWindowOf(options.sinceTime),
8815
9267
  ...options.beforeTime === void 0 ? {} : { asOf: projectCutoffTime(options.beforeTime) },
8816
9268
  contextQueries: options.contextQuery,
@@ -8827,8 +9279,15 @@ var projectStatusCommand = /* @__PURE__ */ __name((projects, print, env) => answ
8827
9279
  read: /* @__PURE__ */ __name((chat, since) => step("messages.list", chatRead(linked(chat), since, env, chosen)), "read"),
8828
9280
  line: /* @__PURE__ */ __name((one2) => one2.kind === "command" ? one2.line ?? one2.command : one2.why, "line")
8829
9281
  };
8830
- const { item, next, missing, meta } = projectStatusAnswer(found, hints);
8831
- 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
+ ];
8832
9291
  print(options.json, itemOf({
8833
9292
  ...item,
8834
9293
  ...finance.length ? { finance } : {},
@@ -8838,7 +9297,7 @@ var projectStatusCommand = /* @__PURE__ */ __name((projects, print, env) => answ
8838
9297
  ...next.length ? { next: next.map(asAction) } : {},
8839
9298
  ...gaps.length ? { missing: gaps } : {},
8840
9299
  meta
8841
- }), [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);
8842
9301
  }), "projectStatusCommand");
8843
9302
 
8844
9303
  // dist/knowledge/project-transfer.js
@@ -8971,73 +9430,142 @@ var RELATIONSHIP_QUERY = {
8971
9430
  entity: "relationship",
8972
9431
  backend: "native",
8973
9432
  fields: [
8974
- termField("about", "ref", 'about:"project:1"', {
8975
- 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"
8976
9435
  }),
8977
- 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"] })
8978
9444
  ]
8979
9445
  };
8980
- var PENDING_LIMIT = 50;
8981
- var pending = /* @__PURE__ */ __name(async (store, about) => {
8982
- const found = await proposalRegistry(store).list({
8983
- kinds: ["relationship"],
8984
- status: "proposed",
8985
- ...about?.startsWith("project:") ? { project: about } : {},
8986
- limit: PENDING_LIMIT,
8987
- offset: 0
8988
- });
8989
- const payloads = new Map((await store.proposedActions.list({ kinds: ["relationship"], status: "proposed", limit: 500 })).map((one2) => [
8990
- one2.id,
8991
- one2.payload ?? {}
8992
- ]));
8993
- const rows = found.items.filter((row) => about === void 0 || row.subject === about || row.object === about);
8994
- return {
8995
- hasMore: found.hasMore,
8996
- items: rows.map((row) => ({
8997
- id: row.id,
8998
- from: row.subject,
8999
- to: row.object,
9000
- kind: payloads.get(row.id)?.kind ?? null,
9001
- role: row.summary,
9002
- purpose: payloads.get(row.id)?.purpose ?? null,
9003
- evidence: row.reason,
9004
- confirmed: false,
9005
- status: "proposed",
9006
- proposer: proposerName(row.proposedBy),
9007
- score: row.score,
9008
- createdAt: row.createdAt
9009
- }))
9010
- };
9011
- }, "pending");
9012
- 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 }) => {
9013
9456
  const terms2 = queryTerms(words, RELATIONSHIP_QUERY, "relationships list");
9014
- const about = terms2.get("about");
9015
9457
  const confirmed = terms2.get("confirmed");
9016
- const found = confirmed === "false" ? await pending(store, about) : {
9017
- hasMore: false,
9018
- items: byEngagement(await store.knowledge.relations(null, about)).filter((one2) => confirmed === void 0 || one2.confirmed).map((one2) => ({ ...one2, status: one2.confirmed ? "confirmed" : "proposed" }))
9019
- };
9020
- 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]));
9021
9480
  return {
9022
9481
  hasMore: found.hasMore,
9023
- limit: confirmed === "false" ? PENDING_LIMIT : Math.max(1, found.items.length),
9024
- 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
+ })))
9025
9492
  };
9026
9493
  }, "listRelationships");
9027
9494
  var relationshipsText = /* @__PURE__ */ __name((items) => items.length ? items.map((one2) => [
9028
9495
  one2.id,
9029
9496
  `${one2.fromTitle} \u2192 ${one2.toTitle}`,
9030
9497
  [
9031
- one2.kind,
9032
- one2.role && `as ${one2.role}`,
9498
+ one2.direction === "incoming" ? one2.inverse ?? one2.kind : one2.kind,
9499
+ one2.role && `as ${one2.role}${one2.custom ? " (custom)" : ""}`,
9033
9500
  "roleNote" in one2 && one2.roleNote && `(${one2.roleNote})`,
9501
+ one2.position && `(${one2.position})`,
9034
9502
  one2.purpose && `for ${one2.purpose}`,
9035
9503
  "engagement" in one2 && one2.engagement && `engagement ${one2.engagement}`
9036
9504
  ].filter(Boolean).join(" "),
9037
- "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(" ")
9038
9506
  ].filter(Boolean).join(" ")).join("\n") : "no relationships", "relationshipsText");
9039
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
+
9040
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");
9041
9569
  var pendingLink = /* @__PURE__ */ __name(async (store, id) => {
9042
9570
  try {
9043
9571
  return await proposalRegistry(store).get(`link:${id}`);
@@ -9054,17 +9582,6 @@ var knowledgeCommands = /* @__PURE__ */ __name((program, streams, env) => {
9054
9582
  const act = /* @__PURE__ */ __name((options, work) => run(options.json, async (store) => work(store, await writeAccount(store, env, options, warn))), "act");
9055
9583
  const owned = /* @__PURE__ */ __name((options, work) => run(options.json, async (store) => itemAnswer(await work(store))), "owned");
9056
9584
  const ownedList = /* @__PURE__ */ __name((command, options, work) => run(options.json, async (store) => wholeList(command, await work(store))), "ownedList");
9057
- const contextOf = /* @__PURE__ */ __name(async (store, thing, type, reference2) => {
9058
- if (thing === void 0)
9059
- throw new CliError("not_found", `no ${type} ${reference2}; memo ${type}s list shows them`);
9060
- const { id } = thing;
9061
- return {
9062
- [type]: thing,
9063
- 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"),
9064
- notes: await notesAbout(store, { ref: `${type}:${id}` }),
9065
- tags: await store.knowledge.tags(null, { type, id })
9066
- };
9067
- }, "contextOf");
9068
9585
  const organizations = program.command("organizations").description("companies, teams, families and communities of yours");
9069
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({
9070
9587
  kind: options.kind,
@@ -9079,14 +9596,38 @@ var knowledgeCommands = /* @__PURE__ */ __name((program, streams, env) => {
9079
9596
  throw new CliError("not_found", `no organization ${reference2}; memo organizations list shows them`);
9080
9597
  return found;
9081
9598
  }));
9082
- 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) => {
9083
- const query = listQuery(typedQuery(words), ORGANIZATIONS_QUERY, "organizations list");
9084
- 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));
9085
9630
  });
9086
- 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) => {
9087
- const wanted = reference2.replace(/^organization:/, "");
9088
- return contextOf(store, (await store.knowledge.organizations()).find((organization) => organization.id === wanted), "organization", reference2);
9089
- }));
9090
9631
  const projects = program.command("projects").description("projects of yours, each with a short key");
9091
9632
  meetingProjectsCommand(projects, streams, env);
9092
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({
@@ -9102,7 +9643,7 @@ var knowledgeCommands = /* @__PURE__ */ __name((program, streams, env) => {
9102
9643
  });
9103
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) => {
9104
9645
  const { context, next } = await withStore(env, async (store) => {
9105
- const context2 = await projectContext(store, env, reference2);
9646
+ const context2 = await stripped(store, env, await projectContext(store, env, reference2));
9106
9647
  return { context: context2, next: await scanStep(store, context2.project, "all") };
9107
9648
  });
9108
9649
  print(options.json, itemAnswer(context, next.length ? { next } : {}), projectContextText(context));
@@ -9125,7 +9666,7 @@ var knowledgeCommands = /* @__PURE__ */ __name((program, streams, env) => {
9125
9666
  return ownedList("projects key-documents list", options, async (store) => keyDocuments(store, await projectOf(store, project), id === void 0 ? {} : { id }));
9126
9667
  });
9127
9668
  const relations = program.command("relationships").description("relations between people, organizations and projects; never between identities");
9128
- 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) => {
9129
9670
  const by = await whoRuns(command, env, { asOwner: options.asOwner, question: "state it as yours?" });
9130
9671
  return owned(options, async (store) => {
9131
9672
  const input = {
@@ -9135,27 +9676,46 @@ var knowledgeCommands = /* @__PURE__ */ __name((program, streams, env) => {
9135
9676
  ...options.role === void 0 ? {} : { role: options.role },
9136
9677
  ...options.roleNote === void 0 ? {} : { roleNote: options.roleNote },
9137
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 },
9138
9682
  ...options.reason === void 0 ? {} : { evidence: options.reason }
9139
9683
  };
9140
9684
  return by === "owner" ? store.knowledge.relate(null, { ...input, by }) : store.knowledge.relate(null, { ...input, by });
9141
9685
  });
9142
9686
  });
9143
- 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) => {
9144
- const found = await withStore(env, (store) => listRelationships(store, words));
9145
- 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));
9146
9704
  });
9147
- 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) => {
9148
9706
  const cleared = /* @__PURE__ */ __name((value) => value === "" ? null : value, "cleared");
9149
9707
  const change = {
9150
9708
  ...options.role === void 0 ? {} : { role: cleared(options.role) },
9151
9709
  ...options.roleNote === void 0 ? {} : { roleNote: cleared(options.roleNote) },
9152
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 },
9153
9713
  ...options.purpose === void 0 ? {} : { purpose: options.purpose }
9154
9714
  };
9155
9715
  const by = await whoRuns(command, env, { asOwner: options.asOwner, question: `change relationship ${id}?` });
9156
- return owned(options, (store) => {
9157
- if (!Object.keys(change).length)
9158
- 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", {
9159
9719
  reason: "input.invalid",
9160
9720
  param: "--purpose"
9161
9721
  });
@@ -9181,12 +9741,20 @@ var knowledgeCommands = /* @__PURE__ */ __name((program, streams, env) => {
9181
9741
  const suggestion = await pendingLink(store, id);
9182
9742
  if (suggestion === void 0)
9183
9743
  return name2 === "remove" ? store.knowledge.removeRelation(null, id, by) : store.knowledge.confirmRelation(null, id, by);
9184
- await decideOne(store, suggestion.id, decisionOf(name2 === "confirm", by, options.reason));
9744
+ await decideOne(store, env, suggestion.id, decisionOf(name2 === "confirm", by, options.reason));
9185
9745
  if (name2 === "remove")
9186
9746
  return { id, removed: true };
9187
9747
  return (await store.knowledge.relations(null, suggestion.subject)).find((one2) => one2.id === id);
9188
9748
  });
9189
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);
9190
9758
  relationshipsScanCommand(relations, print, env, warn);
9191
9759
  const reminders = program.command("reminders").description("durable local reminders; poll hands one out and ack confirms it was shown");
9192
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) => {
@@ -9633,10 +10201,10 @@ var mcpCommandDefinition = /* @__PURE__ */ __name((program, streams, env, create
9633
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) => {
9634
10202
  if (!options.http && (options.port !== void 0 || options.publicUrl !== void 0))
9635
10203
  throw new CliError("validation_error", "--port and --public-url require --http");
9636
- const { createMemoServer } = await import("./server-BVRPQPGY.js");
10204
+ const { createMemoServer } = await import("./server-LWQAHDBH.js");
9637
10205
  const build = /* @__PURE__ */ __name(() => createMemoServer(env, createProgram2, options.permission), "build");
9638
10206
  if (options.http) {
9639
- const { httpLockFile, mcpUrlOf, portOf, publicUrlOf, serveOverHttp } = await import("./mcp-CFIL7WZU.js");
10207
+ const { httpLockFile, mcpUrlOf, portOf, publicUrlOf, serveOverHttp } = await import("./mcp-FQPK2KAF.js");
9640
10208
  const publicUrl = publicUrlOf(options.publicUrl, {
9641
10209
  missing: "--http",
9642
10210
  reaches: "the browser apps reach memo",
@@ -9688,7 +10256,7 @@ var mcpCommandDefinition = /* @__PURE__ */ __name((program, streams, env, create
9688
10256
  });
9689
10257
  });
9690
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() {
9691
- const { revokeAll } = await import("./mcp-CFIL7WZU.js");
10259
+ const { revokeAll } = await import("./mcp-FQPK2KAF.js");
9692
10260
  revokeAll(httpTokenFile(env));
9693
10261
  out.print(this.opts().json, itemAnswer({ revoked: true }));
9694
10262
  });
@@ -9963,7 +10531,7 @@ may be ${found.candidates.join(", ")}` : ""));
9963
10531
  }, "mentionsCommand");
9964
10532
 
9965
10533
  // dist/models/command.js
9966
- var modelsCommand = /* @__PURE__ */ __name((program, streams, env, keyring) => {
10534
+ var modelsCommand = /* @__PURE__ */ __name((program, streams, env, keyring, stdin) => {
9967
10535
  const { print } = answers(program, streams, env);
9968
10536
  program.addCommand(modelCatalogueCommand(APP, {
9969
10537
  kinds: ["text"],
@@ -9972,6 +10540,7 @@ var modelsCommand = /* @__PURE__ */ __name((program, streams, env, keyring) => {
9972
10540
  jsonOption: true,
9973
10541
  env: /* @__PURE__ */ __name(() => env, "env"),
9974
10542
  ...keyring ? { keyring } : {},
10543
+ ...stdin ? { stdin: /* @__PURE__ */ __name(() => stdin, "stdin") } : {},
9975
10544
  output: /* @__PURE__ */ __name((body, command) => print(command.optsWithGlobals().json, body), "output"),
9976
10545
  diagnostic: /* @__PURE__ */ __name((line3) => streams.diagnostic(line3), "diagnostic"),
9977
10546
  offline: /* @__PURE__ */ __name(() => program.opts().offline === true, "offline")
@@ -10242,11 +10811,14 @@ var notesCommandDefinition = /* @__PURE__ */ __name((program, streams, env) => {
10242
10811
  if (about !== void 0 && terms2.size > 1)
10243
10812
  throw new CliError("validation_error", "about: stands alone in notes list: its notes are found through links");
10244
10813
  const options = { ...paging, json: json5 };
10245
- const page = await withNotes(async (store) => listNotes(store, {
10246
- limit: options.limit,
10247
- offset: (options.page - 1) * options.limit,
10248
- ...about === void 0 ? { ...source === void 0 ? {} : { source }, ...search2 === void 0 ? {} : { search: search2 } } : { about: await subjectOf(store, about) }
10249
- }));
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
+ });
10250
10822
  print(options.json, listAnswer("notes list", {
10251
10823
  items: page.items,
10252
10824
  limit: options.limit,
@@ -10269,7 +10841,7 @@ var notesCommandDefinition = /* @__PURE__ */ __name((program, streams, env) => {
10269
10841
  const answer = await withNotes(async (store) => {
10270
10842
  const about = await Promise.all((options.subject ?? []).map(async (subject) => (await subjectOf(store, subject)).ref));
10271
10843
  if (options.meeting !== void 0)
10272
- 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")));
10273
10845
  const note = await store.notes.addNote({
10274
10846
  text: body,
10275
10847
  about,
@@ -10353,15 +10925,15 @@ var formatOf2 = /* @__PURE__ */ __name((value) => {
10353
10925
  return value;
10354
10926
  }, "formatOf");
10355
10927
  var directory = /* @__PURE__ */ __name((path) => {
10356
- const at = resolve4(path);
10928
+ const at2 = resolve4(path);
10357
10929
  let isDirectory = false;
10358
10930
  try {
10359
- isDirectory = statSync4(at).isDirectory();
10931
+ isDirectory = statSync4(at2).isDirectory();
10360
10932
  } catch {
10361
10933
  }
10362
10934
  if (!isDirectory)
10363
- throw new CliError("not_found", `${at} is not a folder`);
10364
- return at;
10935
+ throw new CliError("not_found", `${at2} is not a folder`);
10936
+ return at2;
10365
10937
  }, "directory");
10366
10938
  var FOLDERS_QUERY = { entity: "notes_folder", backend: "native", fields: [] };
10367
10939
  var keptByDrive = /* @__PURE__ */ __name((name2) => name2.startsWith("google-drive:"), "keptByDrive");
@@ -10374,10 +10946,10 @@ var foldersCommand = /* @__PURE__ */ __name((program, streams, env) => {
10374
10946
  const { print } = answers(program, streams, env);
10375
10947
  const folders = program.command("folders").description("folders of notes: the id links and the store use, and the path on this computer");
10376
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) => {
10377
- const at = directory(path);
10949
+ const at2 = directory(path);
10378
10950
  const answer = await withStore(env, async (store) => {
10379
10951
  const known2 = new Set((await store.notes.folders()).map(({ id }) => id));
10380
- const current = noteFolders(loadConfig(env).notes).find((folder2) => folder2.path === at);
10952
+ const current = noteFolders(loadConfig(env).notes).find((folder2) => folder2.path === at2);
10381
10953
  if (current?.id && known2.has(current.id)) {
10382
10954
  const folder2 = { ...current, id: current.id, format: options.format ?? current.format };
10383
10955
  if (folder2.format !== current.format)
@@ -10385,15 +10957,15 @@ var foldersCommand = /* @__PURE__ */ __name((program, streams, env) => {
10385
10957
  return { ...folder2, created: false };
10386
10958
  }
10387
10959
  const format = options.format ?? current?.format ?? "obsidian";
10388
- const made = await store.notes.addFolder({ name: basename2(at) || at, format });
10389
- 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 };
10390
10962
  updateConfig((config) => bindFolder(config, folder), env);
10391
10963
  return { ...folder, created: true };
10392
10964
  });
10393
10965
  print(options.json, itemAnswer(answer), answer.id);
10394
10966
  });
10395
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) => {
10396
- const at = directory(path);
10968
+ const at2 = directory(path);
10397
10969
  const folder = await withStore(env, async (store) => {
10398
10970
  const stored = (await storedFolders(store)).find((candidate) => candidate.id === id);
10399
10971
  if (!stored)
@@ -10404,7 +10976,7 @@ var foldersCommand = /* @__PURE__ */ __name((program, streams, env) => {
10404
10976
  throw new CliError("validation_error", `folder ${id} is Google Drive's (${stored.name}) \u2014 drive keeps it, and memo search already reads it`);
10405
10977
  let bound;
10406
10978
  updateConfig((config) => {
10407
- const result = attachFolder(config, id, at, options.format ?? stored.format);
10979
+ const result = attachFolder(config, id, at2, options.format ?? stored.format);
10408
10980
  bound = result.folder;
10409
10981
  return result.config;
10410
10982
  }, env);
@@ -10537,7 +11109,7 @@ var peopleCommand = /* @__PURE__ */ __name((program, streams, env) => {
10537
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) => {
10538
11110
  listQuery(typedQuery(words), query, "people list");
10539
11111
  await withStore(env, async (store) => {
10540
- 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);
10541
11113
  print(options.json, wholeList("people list", found.map(({ person, ...rest }) => ({ ref: person, ...rest }))));
10542
11114
  });
10543
11115
  });
@@ -10580,19 +11152,19 @@ var headerOf2 = /* @__PURE__ */ __name((line3) => {
10580
11152
  return void 0;
10581
11153
  }
10582
11154
  }, "headerOf");
10583
- var accountIn = /* @__PURE__ */ __name((envelope, given2) => {
11155
+ var accountIn2 = /* @__PURE__ */ __name((envelope, given2) => {
10584
11156
  const provider = envelope?.source?.provider;
10585
11157
  return typeof provider === "string" && given2.startsWith(`${provider}:`) ? given2.slice(provider.length + 1) : given2;
10586
11158
  }, "accountIn");
10587
11159
  var deviceOf = /* @__PURE__ */ __name((given2) => {
10588
- const at = given2.indexOf(":");
10589
- if (at < 0)
11160
+ const at2 = given2.indexOf(":");
11161
+ if (at2 < 0)
10590
11162
  return given2;
10591
- if (given2.slice(0, at) !== PHONE)
11163
+ if (given2.slice(0, at2) !== PHONE)
10592
11164
  throw new CliError("validation_error", "a vCard file holds a phone's contacts: --account phone:<device>", {
10593
11165
  param: "--account"
10594
11166
  });
10595
- return given2.slice(at + 1);
11167
+ return given2.slice(at2 + 1);
10596
11168
  }, "deviceOf");
10597
11169
  var importRecords = /* @__PURE__ */ __name(async (store, { file, stdin, account: account2, dryRun, onIssue, region }) => {
10598
11170
  const iterator = (await linesOf(file, stdin))[Symbol.asyncIterator]();
@@ -10649,10 +11221,10 @@ var importRecords = /* @__PURE__ */ __name(async (store, { file, stdin, account:
10649
11221
  }
10650
11222
  }
10651
11223
  __name(all, "all");
10652
- return ingestLines(store, all(), { account: accountIn(header, account2), dryRun, onIssue });
11224
+ return ingestLines(store, all(), { account: accountIn2(header, account2), dryRun, onIssue });
10653
11225
  }
10654
11226
  const envelope = envelopeOfText(await whole2([first]));
10655
- return ingest(store, envelope, { account: accountIn(envelope, account2), dryRun, onIssue });
11227
+ return ingest(store, envelope, { account: accountIn2(envelope, account2), dryRun, onIssue });
10656
11228
  }, "importRecords");
10657
11229
 
10658
11230
  // dist/records/mapping.js
@@ -10680,10 +11252,10 @@ var sourceOf4 = /* @__PURE__ */ __name((account2) => {
10680
11252
  }, "sourceOf");
10681
11253
  var recordOf = /* @__PURE__ */ __name((record2) => {
10682
11254
  const from = record2.startsWith("custom:") ? "custom:".length : 0;
10683
- const at = record2.indexOf(":", from);
10684
- if (at <= from || at === record2.length - 1)
11255
+ const at2 = record2.indexOf(":", from);
11256
+ if (at2 <= from || at2 === record2.length - 1)
10685
11257
  throw new CliError("validation_error", `${record2} is not <type>:<external_id>, such as organization:client or custom:quote:Q-7`, { param: "record" });
10686
- return { type: record2.slice(0, at), externalId: record2.slice(at + 1) };
11258
+ return { type: record2.slice(0, at2), externalId: record2.slice(at2 + 1) };
10687
11259
  }, "recordOf");
10688
11260
  var RECORD_HELP = "<type>:<external_id> as the source names it, such as organization:client or custom:quote:Q-7";
10689
11261
  var ACCOUNT_HELP = "the source, <provider>:<account> as the envelope's source names it, such as sheet:rentals";
@@ -10941,7 +11513,7 @@ ${SOURCE_REVIEW_HELP}`);
10941
11513
  ...given2,
10942
11514
  question: `${name2} ${ids.length} proposal${ids.length === 1 ? "" : "s"} as you, the owner?`
10943
11515
  });
10944
- 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)));
10945
11517
  const issues = result.refused.map((one2) => ({
10946
11518
  code: one2.code,
10947
11519
  source: one2.id,
@@ -10962,18 +11534,18 @@ ${SOURCE_REVIEW_HELP}`);
10962
11534
  import { existsSync as existsSync10, readdirSync as readdirSync7 } from "node:fs";
10963
11535
  import { join as join13 } from "node:path";
10964
11536
  var EMBED_PER_RUN = 600;
11537
+ var MEASURED_WITH = "e5-small";
10965
11538
  var SLOWEST_KNOWN = 2;
10966
11539
  var embedPerRun = /* @__PURE__ */ __name((env = process.env) => {
10967
11540
  const models = textModels(env);
10968
11541
  const speed = /* @__PURE__ */ __name((id) => models.find((model) => model.id === id)?.chunksPerSecond ?? SLOWEST_KNOWN, "speed");
10969
- const ratio = speed(chosenTextModel(env).id) / speed(DEFAULT_TEXT_MODEL);
11542
+ const ratio = speed(chosenTextModel(env).id) / speed(MEASURED_WITH);
10970
11543
  return Math.max(8, Math.min(EMBED_PER_RUN, Math.round(EMBED_PER_RUN * ratio)));
10971
11544
  }, "embedPerRun");
10972
11545
  var missingModel = /* @__PURE__ */ __name((error, env) => {
10973
11546
  const named5 = isCliError(error) ? error.details.model : void 0;
10974
11547
  const id = typeof named5 === "string" ? named5 : chosenTextModel(env).id;
10975
- const terms2 = textModels(env).find((model) => model.id === id)?.terms;
10976
- 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}`;
10977
11549
  }, "missingModel");
10978
11550
  var searchModelPresent = /* @__PURE__ */ __name((env) => {
10979
11551
  try {
@@ -10987,7 +11559,7 @@ var isMissingModel = /* @__PURE__ */ __name((error) => isCliError(error) && erro
10987
11559
  var reportOf = /* @__PURE__ */ __name((run) => {
10988
11560
  if (run === void 0)
10989
11561
  return void 0;
10990
- if (run.status === "failed")
11562
+ if (!("provider" in run))
10991
11563
  return {
10992
11564
  status: "failed",
10993
11565
  sent: 0,
@@ -10997,7 +11569,8 @@ var reportOf = /* @__PURE__ */ __name((run) => {
10997
11569
  inputTokens: 0,
10998
11570
  outputTokens: 0,
10999
11571
  costUsd: 0,
11000
- reason: run.reason
11572
+ reason: run.reason,
11573
+ reasonId: run.reason_id
11001
11574
  };
11002
11575
  return {
11003
11576
  status: run.status,
@@ -11010,7 +11583,8 @@ var reportOf = /* @__PURE__ */ __name((run) => {
11010
11583
  inputTokens: run.usage.input,
11011
11584
  outputTokens: run.usage.output,
11012
11585
  costUsd: run.cost_usd,
11013
- ...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 }
11014
11588
  };
11015
11589
  }, "reportOf");
11016
11590
  var combinedEnrichment = /* @__PURE__ */ __name((...parts2) => {
@@ -11019,20 +11593,23 @@ var combinedEnrichment = /* @__PURE__ */ __name((...parts2) => {
11019
11593
  return void 0;
11020
11594
  const rank = { done: 0, stopped: 1, failed: 2 };
11021
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;
11022
11598
  const named5 = present2.find((part) => part.provider !== void 0);
11023
11599
  const costs = present2.map((part) => part.costUsd);
11024
11600
  return {
11025
- status: worst.status,
11601
+ status,
11026
11602
  ...named5?.provider === void 0 ? {} : { provider: named5.provider },
11027
11603
  ...named5?.model === void 0 ? {} : { model: named5.model },
11028
11604
  sent: present2.reduce((sum, part) => sum + part.sent, 0),
11029
- enriched: present2.reduce((sum, part) => sum + part.enriched, 0),
11605
+ enriched,
11030
11606
  failed: present2.reduce((sum, part) => sum + part.failed, 0),
11031
11607
  left: present2.reduce((sum, part) => sum + part.left, 0),
11032
11608
  inputTokens: present2.reduce((sum, part) => sum + part.inputTokens, 0),
11033
11609
  outputTokens: present2.reduce((sum, part) => sum + part.outputTokens, 0),
11034
11610
  costUsd: costs.includes(null) ? null : Math.round(costs.reduce((sum, cost) => sum + (cost ?? 0), 0) * 1e6) / 1e6,
11035
- ...worst.reason === void 0 ? {} : { reason: worst.reason }
11611
+ ...worst.reason === void 0 ? {} : { reason: worst.reason },
11612
+ ...worst.reasonId === void 0 ? {} : { reasonId: worst.reasonId }
11036
11613
  };
11037
11614
  }, "combinedEnrichment");
11038
11615
  var embedNoteChunks = /* @__PURE__ */ __name(async (store, { embed = true, env, maxChunks = embedPerRun(env), keyring } = {}) => {
@@ -11193,6 +11770,7 @@ var syncCommand = /* @__PURE__ */ __name((program, streams, env, signal, keyring
11193
11770
  }), "answer");
11194
11771
  const work = withImportLock(env, async () => {
11195
11772
  const store = await openStore({ env, ...STORE_CLIENT, decisions: decisionPolicy(env) });
11773
+ const enriched = [];
11196
11774
  const attempt = /* @__PURE__ */ __name(async (source, work2) => {
11197
11775
  halt();
11198
11776
  try {
@@ -11231,11 +11809,13 @@ var syncCommand = /* @__PURE__ */ __name((program, streams, env, signal, keyring
11231
11809
  });
11232
11810
  if (folders.length > 0)
11233
11811
  await attempt("notes by meaning", async () => {
11234
- run.notesEmbedded = await embedNoteChunks(store, {
11812
+ const { enrichment: enrichment2, ...embedded } = await embedNoteChunks(store, {
11235
11813
  embed: options.embed && config.notes?.embed !== false,
11236
11814
  env,
11237
11815
  ...keyring ? { keyring } : {}
11238
11816
  });
11817
+ run.notesEmbedded = embedded;
11818
+ enriched.push(enrichment2);
11239
11819
  });
11240
11820
  await attempt("people-notes.json", async () => {
11241
11821
  await importNotesMap(store, env, folders);
@@ -11243,13 +11823,15 @@ var syncCommand = /* @__PURE__ */ __name((program, streams, env, signal, keyring
11243
11823
  }
11244
11824
  if (synced.has("mail"))
11245
11825
  await attempt("mail by meaning", async () => {
11246
- run.mailEmbedded = await embedMailChunks(store, {
11826
+ const { enrichment: enrichment2, ...embedded } = await embedMailChunks(store, {
11247
11827
  embed: options.embed,
11248
11828
  env,
11249
11829
  ...keyring ? { keyring } : {}
11250
11830
  });
11831
+ run.mailEmbedded = embedded;
11832
+ enriched.push(enrichment2);
11251
11833
  });
11252
- const enrichment = combinedEnrichment(run.notesEmbedded?.enrichment, run.mailEmbedded?.enrichment);
11834
+ const enrichment = combinedEnrichment(...enriched);
11253
11835
  if (enrichment)
11254
11836
  run.enrichment = enrichment;
11255
11837
  halt();
@@ -11368,10 +11950,10 @@ var mailboxBlock = /* @__PURE__ */ __name((source, review, room = Number.POSITIV
11368
11950
  let fit;
11369
11951
  for (let end = 1; end < cuts.length; end++) {
11370
11952
  const kept = new Set(cuts.slice(0, end).flatMap((cut2) => cut2.items));
11371
- const at = cuts[end - 1];
11953
+ const at2 = cuts[end - 1];
11372
11954
  const block = lines(source, review, {
11373
- key: at?.key,
11374
- cursor: at?.cursor,
11955
+ key: at2?.key,
11956
+ cursor: at2?.cursor,
11375
11957
  items: items.filter((item) => kept.has(item)),
11376
11958
  waiting: items.length - kept.size
11377
11959
  });
@@ -11556,7 +12138,7 @@ var notesAnswer = /* @__PURE__ */ __name((found, limit, page, args = {}) => list
11556
12138
  var holdsNoPeople = /* @__PURE__ */ __name((provider) => provider === "notes" || isFolderProvider(provider), "holdsNoPeople");
11557
12139
  var fold4 = /* @__PURE__ */ __name((text3) => text3.normalize("NFKD").replace(new RegExp("\\p{M}", "gu"), "").toLowerCase(), "fold");
11558
12140
  var scopeOf2 = /* @__PURE__ */ __name(async (store, env, source) => {
11559
- 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);
11560
12142
  const held = keys.filter((key) => !holdsNoPeople(key.provider));
11561
12143
  if (source !== void 0 && held.length === 0)
11562
12144
  throw new CliError("validation_error", `${source} names no messenger, mail or meeting account that holds people`, {
@@ -11596,6 +12178,13 @@ var searchPeople = /* @__PURE__ */ __name(async (store, env, words, { limit, sou
11596
12178
  hits.set(ref, hit);
11597
12179
  }
11598
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
+ }
11599
12188
  const first = wanted.join(" ");
11600
12189
  const rank = /* @__PURE__ */ __name((hit) => fold4(hit.name ?? "").startsWith(first) ? 0 : 1, "rank");
11601
12190
  const sorted = [...hits.values()].sort((a, b) => rank(a) - rank(b) || (a.name ?? "").localeCompare(b.name ?? "") || a.ref.localeCompare(b.ref));
@@ -11613,6 +12202,17 @@ var peopleText = /* @__PURE__ */ __name((found) => found.items.map((hit) => [
11613
12202
  ].join("\n")).join("\n") || "nobody found", "peopleText");
11614
12203
 
11615
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");
11616
12216
  var ONLY = ["messages", "mail", "notes", "events", "crm", "business"];
11617
12217
  var onlyOf2 = /* @__PURE__ */ __name((value) => {
11618
12218
  const selected = value.split(",").map((part) => part.trim());
@@ -11636,7 +12236,7 @@ var searchCommandDefinition = /* @__PURE__ */ __name((program, streams, env) =>
11636
12236
  throw new InvalidArgumentError("at most 100");
11637
12237
  return limit;
11638
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");
11639
- 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", `
11640
12240
  content: narrows a search to the text of files, transcript: to voice transcripts, filename: to file names \u2014 memo search all 'content:invoice'.
11641
12241
  Calendar events come from every calendar gcal stored; an event's title, description and place are written by whoever sent the invitation.
11642
12242
  crm finds deals and leads by the words of their title only.
@@ -11704,7 +12304,7 @@ For an agent: read with --compact, one line per hit with its reference. Never wr
11704
12304
  const level = levelOf(options);
11705
12305
  const text3 = words.join(" ");
11706
12306
  const answer = await withStore(env, async (store) => {
11707
- 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;
11708
12308
  return searchKind(store, kind, {
11709
12309
  text: text3,
11710
12310
  limit: options.limit,
@@ -11858,7 +12458,7 @@ var showReferences = /* @__PURE__ */ __name(async (store, env, texts, command) =
11858
12458
  }
11859
12459
  return shown3;
11860
12460
  }, "showReferences");
11861
- 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");
11862
12462
  var blockOf = /* @__PURE__ */ __name((one2) => [
11863
12463
  `${one2.ref} ${one2.title ?? ""}`.trimEnd(),
11864
12464
  ` ${[one2.kind, one2.in, one2.state, minute2(one2.at)].filter((part) => part !== null).join(" \xB7 ")}`,
@@ -11914,7 +12514,7 @@ var escaped = /* @__PURE__ */ __name((text3) => text3.replace(/[.*+?^${}()|[\]\\
11914
12514
  var folded = /* @__PURE__ */ __name((text3) => text3.normalize("NFC").toLocaleLowerCase(), "folded");
11915
12515
  var mentionsOf = /* @__PURE__ */ __name(async (store, note) => {
11916
12516
  const id = Number(note.id);
11917
- const at = note.modifiedAt ?? note.updatedAt;
12517
+ const at2 = note.modifiedAt ?? note.updatedAt;
11918
12518
  const found = [];
11919
12519
  for (let offset = 0; ; offset += PAGE6) {
11920
12520
  const page = await store.sourceMentions.list("document", void 0, { limit: PAGE6, offset }, []);
@@ -11922,7 +12522,7 @@ var mentionsOf = /* @__PURE__ */ __name(async (store, note) => {
11922
12522
  const when = mention.source.at ?? "";
11923
12523
  if (mention.source.id === id)
11924
12524
  found.push(mention);
11925
- 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)
11926
12526
  return found;
11927
12527
  }
11928
12528
  if (!page.hasMore)
@@ -11965,8 +12565,8 @@ ${note.text}`);
11965
12565
  const name2 = organization.name.trim();
11966
12566
  if (name2.length < 3)
11967
12567
  continue;
11968
- const at = new RegExp(`(?<![\\p{L}\\p{N}])${escaped(folded(name2))}(?![\\p{L}\\p{N}])`, "u");
11969
- 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))
11970
12570
  add(organization.ref, "organization", organization.name, name2);
11971
12571
  }
11972
12572
  return {
@@ -12342,6 +12942,56 @@ var sourcesCommand = /* @__PURE__ */ __name((program, streams, env, { fetch: fet
12342
12942
  });
12343
12943
  }, "sourcesCommand");
12344
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
+
12345
12995
  // dist/store/info-command.js
12346
12996
  var storeCommand = /* @__PURE__ */ __name((program, streams, env) => {
12347
12997
  const { print } = answers(program, streams, env);
@@ -12443,7 +13093,7 @@ var tagsCommand = /* @__PURE__ */ __name((program, streams, env) => {
12443
13093
  }
12444
13094
  if (options.contact !== void 0 || options.meeting !== void 0) {
12445
13095
  await withStore(env, async (store) => {
12446
- const { key, target: target2 } = await selectTarget(store, { ...options, ...await scoped3(store) });
13096
+ const { key, target: target2 } = await selectTarget(store, env, { ...options, ...await scoped3(store) });
12447
13097
  const changed = await (operation === "add" ? store.knowledge.addTags : store.knowledge.removeTags)(key, target2, given2);
12448
13098
  print(options.json, itemAnswer({ ...key, target: target2, [operation === "add" ? "added" : "removed"]: changed }), `${operation}: ${changed.join(", ") || "no labels changed"}`);
12449
13099
  });
@@ -12480,7 +13130,7 @@ var tagsCommand = /* @__PURE__ */ __name((program, streams, env) => {
12480
13130
  ...terms2.has("type") ? { type: terms2.get("type") } : {}
12481
13131
  };
12482
13132
  await withStore(env, async (store) => {
12483
- 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);
12484
13134
  const answer = await listTags(store, { ...options, keys });
12485
13135
  const owned = options.type === void 0 || OWNED.includes(options.type) ? await store.knowledge.labelled(null, {
12486
13136
  ...options.tag === void 0 ? {} : { tag: options.tag },
@@ -12552,7 +13202,7 @@ var requireAccount = /* @__PURE__ */ __name((env, warn) => async (_, command) =>
12552
13202
  return;
12553
13203
  if (["show", "update", "claim", "release"].includes(command.name()) && first !== void 0 && await store.tasks.projectTask(first))
12554
13204
  return;
12555
- 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("; ");
12556
13206
  throw new CliError("validation_error", `give ${option} \u2014 the stored accounts: ${listed2 || "none yet"}`);
12557
13207
  } finally {
12558
13208
  await store.close();
@@ -12628,7 +13278,7 @@ var addFromSource = /* @__PURE__ */ __name(async (store, env, source, options) =
12628
13278
  const parsed = native ? void 0 : parseLocator(source);
12629
13279
  if (parsed && (options.provider && options.provider !== parsed.provider || options.account && options.account !== parsed.account))
12630
13280
  throw new CliError("validation_error", "locator and selected account disagree");
12631
- 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);
12632
13282
  if (parsed && parsed.provider !== "notes" && await heldMessage(store, key, parsed.message, parsed.chat) === void 0)
12633
13283
  throw new CliError("not_found", "the task source is unavailable or deleted");
12634
13284
  const author = authorOf(env);
@@ -12657,7 +13307,7 @@ var closeTask = /* @__PURE__ */ __name(async (store, env, id, options) => {
12657
13307
  }
12658
13308
  if (options.revision !== void 0)
12659
13309
  throw new CliError("validation_error", "--revision checks a project task; a task from a message has none");
12660
- const key = await selectAccount(store, options);
13310
+ const key = await selectAccount(store, env, options);
12661
13311
  return tasksService(storeOnlyDeps(store, key, { app: APP, env })).close(id, {
12662
13312
  as: options.as,
12663
13313
  by: "owner",
@@ -12689,7 +13339,7 @@ var updateTask = /* @__PURE__ */ __name(async (store, env, id, options) => {
12689
13339
  if (options.priority !== void 0 || options.parent !== void 0)
12690
13340
  throw new CliError("validation_error", "--priority and --parent are for a task in a project");
12691
13341
  const assignees = options.assignee?.map((one2) => one2 === "sender" || one2 === "none" ? one2 : personRef(one2));
12692
- const key = await selectAccount(store, options);
13342
+ const key = await selectAccount(store, env, options);
12693
13343
  return tasksService(storeOnlyDeps(store, key, { app: APP, env })).plan(id, {
12694
13344
  ...options.title === void 0 ? {} : { title: options.title },
12695
13345
  ...options.description === void 0 ? {} : { description: options.description },
@@ -13070,6 +13720,38 @@ var OWN_ENTITIES = entityFields({
13070
13720
  agent_action: ["id", "actor", "tool", "tier", "target", "status", "error", "started_at", "finished_at"],
13071
13721
  meeting_project: ["id", "meeting", "project", "confirmed", "provenance", "fingerprint"],
13072
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
+ ],
13073
13755
  order: [
13074
13756
  "id",
13075
13757
  "ref",
@@ -13346,6 +14028,89 @@ var OWN_ENTITIES = entityFields({
13346
14028
  records_match: ["linked", "created", "unmatched", "proposed", "errors", "truncated"],
13347
14029
  payment_allocation: ["payment", "invoice", "amount", "currency", "created_at"]
13348
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");
13349
14114
  var SKILL_TOPICS = [
13350
14115
  "search",
13351
14116
  "projects",
@@ -13371,11 +14136,13 @@ var FIRST_SCREEN = {
13371
14136
  profile: false,
13372
14137
  start: "memo folders add <path>"
13373
14138
  };
13374
- 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 };
13375
14141
  const fields = jsonFields(raw, OWN_ENTITIES);
13376
14142
  const { streams } = fields;
13377
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");
13378
14144
  refuseWritesUnderLock(program, env);
14145
+ scopeRunsToGroup(program, env, group);
13379
14146
  provideTerminal(program, terminal);
13380
14147
  contextCommand(program, streams, env);
13381
14148
  showCommand(program, streams, env);
@@ -13407,7 +14174,7 @@ var createProgram = /* @__PURE__ */ __name(({ streams: raw = processStreams, env
13407
14174
  reviewCommand(program, streams, env);
13408
14175
  agentsCommand(program, streams, env);
13409
14176
  mcpCommand(program, streams, env, createProgram);
13410
- modelsCommand(program, streams, env, keyring);
14177
+ modelsCommand(program, streams, env, keyring, stdin);
13411
14178
  templatesCommand2(program, streams, env);
13412
14179
  searchCommand(program, streams, env);
13413
14180
  meetingReadCommands(program, streams, env);
@@ -13416,6 +14183,7 @@ var createProgram = /* @__PURE__ */ __name(({ streams: raw = processStreams, env
13416
14183
  askCommand(program, streams, env);
13417
14184
  syncCommand(program, streams, env, signal, keyring);
13418
14185
  storeCommand(program, streams, env);
14186
+ groupsCommand(program, streams, env);
13419
14187
  autoCommand(program, streams, env);
13420
14188
  configCommand(program, streams, env);
13421
14189
  doctorCommand(program, streams, env);
@@ -13481,6 +14249,7 @@ var createProgram = /* @__PURE__ */ __name(({ streams: raw = processStreams, env
13481
14249
  });
13482
14250
  trackAnswers(program);
13483
14251
  placeInSections(program);
14252
+ markGroupAware(program);
13484
14253
  installHelp(program, FIRST_SCREEN);
13485
14254
  provide(program, {
13486
14255
  ...environmentOf(program),
@@ -13499,6 +14268,18 @@ var createProgram = /* @__PURE__ */ __name(({ streams: raw = processStreams, env
13499
14268
  assertSharedContracts(program);
13500
14269
  return program;
13501
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");
13502
14283
  var refuseJoinedPath = /* @__PURE__ */ __name((program, args) => {
13503
14284
  let command = program;
13504
14285
  const path = [];
@@ -13518,5 +14299,6 @@ var refuseJoinedPath = /* @__PURE__ */ __name((program, args) => {
13518
14299
  export {
13519
14300
  SKILL_TOPICS,
13520
14301
  createProgram,
14302
+ liftGroup,
13521
14303
  refuseJoinedPath
13522
14304
  };