@wirecat/cli-memo 0.131.62 → 0.131.64

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 (163) hide show
  1. package/dist/bin/memo.js +2 -2
  2. package/dist/bundle/{app-server-QBJG7OGQ.js → app-server-7KM4MSDA.js} +9 -9
  3. package/dist/bundle/{auto-Z4MEU5OY.js → auto-V3FUD6RW.js} +16 -16
  4. package/dist/bundle/{chunk-LK6D26RK.js → chunk-3SCHFNUH.js} +5 -5
  5. package/dist/bundle/{chunk-HGNWJJDT.js → chunk-3YNJBKGV.js} +13 -1
  6. package/dist/bundle/{chunk-Q3VEUHC7.js → chunk-6OS7PTOC.js} +3 -3
  7. package/dist/bundle/{chunk-2UCLF4AO.js → chunk-DXTNBVLV.js} +394 -115
  8. package/dist/bundle/{chunk-2VDRVJCR.js → chunk-EDBZEHAU.js} +5 -4
  9. package/dist/bundle/{chunk-H3COKFXP.js → chunk-FHZKHKBJ.js} +1651 -11
  10. package/dist/bundle/{chunk-TBSWOVM3.js → chunk-FKUA3BTM.js} +14 -14
  11. package/dist/bundle/{chunk-TSKGEK2S.js → chunk-LVLFLWGY.js} +3 -3
  12. package/dist/bundle/{chunk-O2NQCWRM.js → chunk-ML46T7UC.js} +8 -8
  13. package/dist/bundle/{chunk-XX37LSNV.js → chunk-MYXB2T77.js} +25 -1
  14. package/dist/bundle/{chunk-WDZOEBTE.js → chunk-NH3A5QTW.js} +2 -2
  15. package/dist/bundle/{chunk-6OZ2WI7Y.js → chunk-NIJZXGJN.js} +1 -1
  16. package/dist/bundle/{chunk-EGI6JHIA.js → chunk-NRHF7TQ4.js} +2 -2
  17. package/dist/bundle/{chunk-WDWKG7FJ.js → chunk-PVGK67AJ.js} +17 -0
  18. package/dist/bundle/{chunk-E5JQFEIQ.js → chunk-QHNAPLVB.js} +4 -4
  19. package/dist/bundle/{chunk-SJ55SMBE.js → chunk-QTF4ZXOL.js} +2 -1
  20. package/dist/bundle/chunk-T3LVSUNZ.js +301 -0
  21. package/dist/bundle/{chunk-OXBETHGN.js → chunk-UXAP7MNL.js} +4 -4
  22. package/dist/bundle/{chunk-3ZXWLFUG.js → chunk-VLUDHCCX.js} +3 -3
  23. package/dist/bundle/{chunk-KREN56SX.js → chunk-WINH45XG.js} +4 -4
  24. package/dist/bundle/{chunk-FD3OQYFL.js → chunk-XPT5PX7H.js} +4 -4
  25. package/dist/bundle/{chunk-SJ36WSEI.js → chunk-ZX6SWNSR.js} +3 -3
  26. package/dist/bundle/{command-contract-SIXWLKAS.js → command-contract-PLB2JGFJ.js} +2 -2
  27. package/dist/bundle/{entry-SFLEGFSN.js → entry-MUE6HWX3.js} +1 -1
  28. package/dist/bundle/{failure-B33C3BFU.js → failure-6SP64Q66.js} +14 -14
  29. package/dist/bundle/{first-run-ZKDGFY6P.js → first-run-3JYWLJCH.js} +1 -1
  30. package/dist/bundle/{first-screen-IQEU7XF2.js → first-screen-QH34AIFV.js} +3 -3
  31. package/dist/bundle/{mcp-Y4XMDC5Q.js → mcp-QX2D6EXA.js} +6 -6
  32. package/dist/bundle/memo.js +6 -6
  33. package/dist/bundle/{program-DSQWICNB.js → program-LXQLWUAG.js} +1789 -422
  34. package/dist/bundle/{server-IQILK5YP.js → server-L622PMVC.js} +9 -9
  35. package/dist/bundle/{server-ZHFC3PIP.js → server-MVJU7QG4.js} +19 -19
  36. package/dist/bundle/{server-NKI7SVK5.js → server-SJVP2XXD.js} +6 -6
  37. package/dist/bundle/{store-6H4FPFTX.js → store-M5QSIRWJ.js} +1 -1
  38. package/dist/bundle/{store-maintenance-command-IFVWSQMJ.js → store-maintenance-command-PQCO5ICC.js} +5 -5
  39. package/dist/bundle/{update-LR5BVLBD.js → update-MQUCCIBB.js} +15 -15
  40. package/dist/contract-overrides/search.js +2 -2
  41. package/dist/contract-overrides/search.js.map +1 -1
  42. package/dist/discovery/command.d.ts.map +1 -1
  43. package/dist/discovery/command.js +6 -0
  44. package/dist/discovery/command.js.map +1 -1
  45. package/dist/events/command.d.ts +4 -0
  46. package/dist/events/command.d.ts.map +1 -0
  47. package/dist/events/command.js +35 -0
  48. package/dist/events/command.js.map +1 -0
  49. package/dist/events/events.d.ts +52 -0
  50. package/dist/events/events.d.ts.map +1 -0
  51. package/dist/events/events.js +199 -0
  52. package/dist/events/events.js.map +1 -0
  53. package/dist/examples.d.ts.map +1 -1
  54. package/dist/examples.js +90 -3
  55. package/dist/examples.js.map +1 -1
  56. package/dist/finance/command.d.ts +1 -1
  57. package/dist/finance/command.d.ts.map +1 -1
  58. package/dist/finance/command.js +13 -30
  59. package/dist/finance/command.js.map +1 -1
  60. package/dist/finance/contracts-command.d.ts +12 -0
  61. package/dist/finance/contracts-command.d.ts.map +1 -0
  62. package/dist/finance/contracts-command.js +110 -0
  63. package/dist/finance/contracts-command.js.map +1 -0
  64. package/dist/finance/deals-command.d.ts.map +1 -1
  65. package/dist/finance/deals-command.js +5 -4
  66. package/dist/finance/deals-command.js.map +1 -1
  67. package/dist/finance/lines-command.d.ts +37 -0
  68. package/dist/finance/lines-command.d.ts.map +1 -0
  69. package/dist/finance/lines-command.js +70 -0
  70. package/dist/finance/lines-command.js.map +1 -0
  71. package/dist/finance/orders-command.d.ts.map +1 -1
  72. package/dist/finance/orders-command.js +5 -2
  73. package/dist/finance/orders-command.js.map +1 -1
  74. package/dist/finance/products-command.d.ts +12 -0
  75. package/dist/finance/products-command.d.ts.map +1 -0
  76. package/dist/finance/products-command.js +99 -0
  77. package/dist/finance/products-command.js.map +1 -0
  78. package/dist/finance/subscriptions-command.d.ts +12 -0
  79. package/dist/finance/subscriptions-command.d.ts.map +1 -0
  80. package/dist/finance/subscriptions-command.js +153 -0
  81. package/dist/finance/subscriptions-command.js.map +1 -0
  82. package/dist/finance/transactions-command.d.ts +12 -0
  83. package/dist/finance/transactions-command.d.ts.map +1 -0
  84. package/dist/finance/transactions-command.js +137 -0
  85. package/dist/finance/transactions-command.js.map +1 -0
  86. package/dist/finance/wallets-command.d.ts +12 -0
  87. package/dist/finance/wallets-command.d.ts.map +1 -0
  88. package/dist/finance/wallets-command.js +106 -0
  89. package/dist/finance/wallets-command.js.map +1 -0
  90. package/dist/finance/written.d.ts +37 -0
  91. package/dist/finance/written.d.ts.map +1 -0
  92. package/dist/finance/written.js +36 -0
  93. package/dist/finance/written.js.map +1 -0
  94. package/dist/knowledge/command.d.ts.map +1 -1
  95. package/dist/knowledge/command.js +3 -2
  96. package/dist/knowledge/command.js.map +1 -1
  97. package/dist/mcp/permissions.d.ts +1 -1
  98. package/dist/mcp/permissions.d.ts.map +1 -1
  99. package/dist/mcp/permissions.js +1 -0
  100. package/dist/mcp/permissions.js.map +1 -1
  101. package/dist/options.d.ts +2 -0
  102. package/dist/options.d.ts.map +1 -1
  103. package/dist/options.js +2 -0
  104. package/dist/options.js.map +1 -1
  105. package/dist/program.d.ts.map +1 -1
  106. package/dist/program.js +174 -0
  107. package/dist/program.js.map +1 -1
  108. package/dist/reasons.d.ts.map +1 -1
  109. package/dist/reasons.js +24 -0
  110. package/dist/reasons.js.map +1 -1
  111. package/dist/records/import.d.ts +2 -4
  112. package/dist/records/import.d.ts.map +1 -1
  113. package/dist/records/import.js +41 -41
  114. package/dist/records/import.js.map +1 -1
  115. package/dist/records/input.d.ts +20 -0
  116. package/dist/records/input.d.ts.map +1 -0
  117. package/dist/records/input.js +115 -0
  118. package/dist/records/input.js.map +1 -0
  119. package/dist/records/mapping.d.ts +16 -1
  120. package/dist/records/mapping.d.ts.map +1 -1
  121. package/dist/records/mapping.js +24 -11
  122. package/dist/records/mapping.js.map +1 -1
  123. package/dist/records/record-commands.d.ts +8 -0
  124. package/dist/records/record-commands.d.ts.map +1 -0
  125. package/dist/records/record-commands.js +89 -0
  126. package/dist/records/record-commands.js.map +1 -0
  127. package/dist/records/sources.d.ts +48 -0
  128. package/dist/records/sources.d.ts.map +1 -0
  129. package/dist/records/sources.js +72 -0
  130. package/dist/records/sources.js.map +1 -0
  131. package/dist/review/kinds.d.ts +1 -1
  132. package/dist/review/kinds.d.ts.map +1 -1
  133. package/dist/review/kinds.js +4 -0
  134. package/dist/review/kinds.js.map +1 -1
  135. package/dist/review/review.d.ts.map +1 -1
  136. package/dist/review/review.js +4 -0
  137. package/dist/review/review.js.map +1 -1
  138. package/dist/rows.d.ts.map +1 -1
  139. package/dist/rows.js +34 -0
  140. package/dist/rows.js.map +1 -1
  141. package/dist/search/command.d.ts.map +1 -1
  142. package/dist/search/command.js +9 -4
  143. package/dist/search/command.js.map +1 -1
  144. package/dist/search/lane-gates.d.ts +3 -0
  145. package/dist/search/lane-gates.d.ts.map +1 -1
  146. package/dist/search/lane-gates.js +9 -3
  147. package/dist/search/lane-gates.js.map +1 -1
  148. package/dist/search/search.d.ts +3 -1
  149. package/dist/search/search.d.ts.map +1 -1
  150. package/dist/search/search.js +2 -1
  151. package/dist/search/search.js.map +1 -1
  152. package/dist/show/command.d.ts +6 -1
  153. package/dist/show/command.d.ts.map +1 -1
  154. package/dist/show/command.js +49 -4
  155. package/dist/show/command.js.map +1 -1
  156. package/dist/version.d.ts +1 -1
  157. package/dist/version.js +1 -1
  158. package/package.json +1 -1
  159. package/skills/cli-memo/SKILL.md +8 -5
  160. package/skills/cli-memo/topics/money.md +20 -1
  161. package/skills/cli-memo/topics/proposals.md +8 -5
  162. package/skills/cli-memo/topics/search.md +7 -0
  163. package/dist/bundle/chunk-HMJ3D7XE.js +0 -1901
@@ -6,17 +6,17 @@ import {
6
6
  autoState,
7
7
  lastAutoRun,
8
8
  recordAutoRun
9
- } from "./chunk-FD3OQYFL.js";
9
+ } from "./chunk-XPT5PX7H.js";
10
10
  import {
11
11
  installer,
12
12
  latest,
13
13
  upgradeCommand
14
- } from "./chunk-KREN56SX.js";
14
+ } from "./chunk-WINH45XG.js";
15
15
  import {
16
16
  mcpOwnerAllowed,
17
17
  readOnlyAvailability,
18
18
  refuseWritesUnderLock
19
- } from "./chunk-2VDRVJCR.js";
19
+ } from "./chunk-EDBZEHAU.js";
20
20
  import {
21
21
  answers,
22
22
  atDetail,
@@ -27,7 +27,7 @@ import {
27
27
  trackAnswers,
28
28
  wholeList,
29
29
  withStore
30
- } from "./chunk-HMJ3D7XE.js";
30
+ } from "./chunk-T3LVSUNZ.js";
31
31
  import {
32
32
  ATTACHMENT_CHARS,
33
33
  DIALECTS,
@@ -39,6 +39,7 @@ import {
39
39
  configPath,
40
40
  decisionPolicy,
41
41
  dialectOf,
42
+ grantedLevel,
42
43
  hitText,
43
44
  inspectConfig,
44
45
  isReference,
@@ -58,7 +59,7 @@ import {
58
59
  showMail,
59
60
  unsetConfigKey,
60
61
  updateConfig
61
- } from "./chunk-H3COKFXP.js";
62
+ } from "./chunk-FHZKHKBJ.js";
62
63
  import "./chunk-QP3KNC5D.js";
63
64
  import "./chunk-FWRBJAQZ.js";
64
65
  import "./chunk-MWAXS4BX.js";
@@ -66,7 +67,7 @@ import "./chunk-PKUBC2ME.js";
66
67
  import {
67
68
  errorObject,
68
69
  recognisable
69
- } from "./chunk-SJ36WSEI.js";
70
+ } from "./chunk-ZX6SWNSR.js";
70
71
  import {
71
72
  AGENT_INPUT_MAX_CHARS,
72
73
  DISCOVERY_DESCRIPTIONS,
@@ -105,7 +106,7 @@ import {
105
106
  tasksCommand,
106
107
  tasksStatsCommand,
107
108
  withSqliteSidecars
108
- } from "./chunk-TBSWOVM3.js";
109
+ } from "./chunk-FKUA3BTM.js";
109
110
  import "./chunk-RLX5SC2X.js";
110
111
  import "./chunk-SIBQ34LX.js";
111
112
  import {
@@ -114,22 +115,23 @@ import {
114
115
  messageHitItem,
115
116
  noteHitItem,
116
117
  shownOf
117
- } from "./chunk-LK6D26RK.js";
118
+ } from "./chunk-3SCHFNUH.js";
118
119
  import "./chunk-DKO7WEXJ.js";
119
120
  import {
121
+ REASONS as REASONS2,
120
122
  SKILL_TARGETS,
121
123
  skillCommand,
122
124
  skillPath,
123
125
  skillVersion
124
- } from "./chunk-SJ55SMBE.js";
126
+ } from "./chunk-QTF4ZXOL.js";
125
127
  import {
126
128
  recoveryNotes,
127
129
  storeInfo,
128
130
  storeRecoveryCheck,
129
131
  storeRecoveryRun,
130
132
  storeSummary
131
- } from "./chunk-E5JQFEIQ.js";
132
- import "./chunk-3ZXWLFUG.js";
133
+ } from "./chunk-QHNAPLVB.js";
134
+ import "./chunk-VLUDHCCX.js";
133
135
  import {
134
136
  LIST_QUERY_GUIDE,
135
137
  STATUS_SIGNALS,
@@ -147,6 +149,10 @@ import {
147
149
  gatherStoredProject,
148
150
  importEngine,
149
151
  ingest,
152
+ ingestLines,
153
+ ingestVcard,
154
+ isVcard,
155
+ jsonlLines,
150
156
  listQuery,
151
157
  mailTurn,
152
158
  meaningLane,
@@ -155,6 +161,8 @@ import {
155
161
  meetingSearchArguments,
156
162
  meetingSearchMeta,
157
163
  modelGateway,
164
+ nativeField,
165
+ nativeTerms,
158
166
  parseProposalIds,
159
167
  personContext,
160
168
  pickPerson,
@@ -181,7 +189,7 @@ import {
181
189
  termField,
182
190
  typedQuery,
183
191
  withQuery
184
- } from "./chunk-2UCLF4AO.js";
192
+ } from "./chunk-DXTNBVLV.js";
185
193
  import {
186
194
  readBoundedUtf8File,
187
195
  writeFileAtomic
@@ -190,9 +198,9 @@ import {
190
198
  commandsText,
191
199
  inSection,
192
200
  installHelp
193
- } from "./chunk-WDZOEBTE.js";
201
+ } from "./chunk-NH3A5QTW.js";
194
202
  import "./chunk-HTQTIKWP.js";
195
- import "./chunk-6OZ2WI7Y.js";
203
+ import "./chunk-NIJZXGJN.js";
196
204
  import {
197
205
  Command,
198
206
  DEFAULT_TEXT_MODEL,
@@ -219,6 +227,8 @@ import {
219
227
  outputFor,
220
228
  overrideSharedContract,
221
229
  parseDuration,
230
+ progressLine,
231
+ progressOf,
222
232
  proposesOnly,
223
233
  provide,
224
234
  runsDirFor,
@@ -227,15 +237,15 @@ import {
227
237
  snakeKeys,
228
238
  textModels,
229
239
  textModelsFile
230
- } from "./chunk-WDWKG7FJ.js";
240
+ } from "./chunk-PVGK67AJ.js";
231
241
  import "./chunk-SIJA2UYC.js";
232
- import "./chunk-TSKGEK2S.js";
242
+ import "./chunk-LVLFLWGY.js";
233
243
  import {
234
244
  isNewer
235
245
  } from "./chunk-ASWLM74P.js";
236
246
  import "./chunk-6G53ZFUT.js";
237
247
  import "./chunk-FH4P5UQA.js";
238
- import "./chunk-EGI6JHIA.js";
248
+ import "./chunk-NRHF7TQ4.js";
239
249
  import "./chunk-RP6VV35S.js";
240
250
  import "./chunk-RTLQHLHG.js";
241
251
  import {
@@ -256,6 +266,7 @@ import {
256
266
  PROJECT_TASK_FIELDS,
257
267
  PROJECT_TYPES,
258
268
  PROPOSAL_STATUSES,
269
+ RECORDS_SCHEMA_VERSION,
259
270
  REMINDERS_QUERY,
260
271
  SCOPES,
261
272
  TASK_RELATION_KINDS,
@@ -265,10 +276,11 @@ import {
265
276
  contextEvidenceFingerprint,
266
277
  decodeProjectAnnotationSnapshot,
267
278
  entriesOfList,
268
- envelopeOfJsonl,
279
+ envelopeOfText,
269
280
  formatLocator,
270
281
  formatReference,
271
282
  isFolderProvider,
283
+ isImportedProvider,
272
284
  kindOf,
273
285
  looksLikeReference,
274
286
  mailFindingFieldsHelp,
@@ -280,8 +292,11 @@ import {
280
292
  plainQuery,
281
293
  providerNamed,
282
294
  refLabel
283
- } from "./chunk-HGNWJJDT.js";
295
+ } from "./chunk-3YNJBKGV.js";
284
296
  import {
297
+ CATALOG_KINDS,
298
+ CONTRACT_KINDS,
299
+ CONTRACT_STATUSES,
285
300
  DEAL_KINDS,
286
301
  DEAL_ROLES,
287
302
  DEAL_STATUSES,
@@ -298,10 +313,17 @@ import {
298
313
  ORDER_PURPOSES,
299
314
  ORDER_STATUSES,
300
315
  PRIORITY_LABELS,
316
+ SUBSCRIPTION_STATUSES,
301
317
  TASK_STATES,
302
318
  TASK_TYPES,
319
+ TRANSACTION_STATUSES,
320
+ WALLET_KINDS,
303
321
  WORK_TASK_TYPES,
304
322
  createUpcomingMeetingReader,
323
+ dateRange,
324
+ dayBoundary,
325
+ event,
326
+ eventItem,
305
327
  formatMeetingReference,
306
328
  isClosedState,
307
329
  markStoreDamaged,
@@ -342,7 +364,7 @@ import {
342
364
  REASONS,
343
365
  STORE_CLIENT,
344
366
  VERSION
345
- } from "./chunk-XX37LSNV.js";
367
+ } from "./chunk-MYXB2T77.js";
346
368
  import "./chunk-IK6KH3RE.js";
347
369
  import "./chunk-SW6C6WH5.js";
348
370
  import "./chunk-D72URWJE.js";
@@ -499,7 +521,7 @@ var messengers = /* @__PURE__ */ __name((entry) => new CliError("validation_erro
499
521
  var listedOf = /* @__PURE__ */ __name(async (store, value) => {
500
522
  const held = await store.accounts.storedAccounts();
501
523
  const holdsFiles = await filesAccounts(store);
502
- const named4 = /* @__PURE__ */ __name(async (entry) => {
524
+ const named5 = /* @__PURE__ */ __name(async (entry) => {
503
525
  const [provider = "", ...rest] = entry.trim().split(":");
504
526
  const account2 = rest.join(":");
505
527
  if (isFolderProvider(provider) && account2) {
@@ -512,7 +534,7 @@ var listedOf = /* @__PURE__ */ __name(async (store, value) => {
512
534
  return entry.trim();
513
535
  return `email:${(await mailboxOf(store, account2)).account}`;
514
536
  }, "named");
515
- const each = /* @__PURE__ */ __name((entries) => Promise.all(entries.filter((one2) => one2.trim()).map(named4)), "each");
537
+ const each = /* @__PURE__ */ __name((entries) => Promise.all(entries.filter((one2) => one2.trim()).map(named5)), "each");
516
538
  const groups = Object.fromEntries(await Promise.all(Object.entries(await store.accounts.accountGroups()).map(async ([name2, members]) => [name2, await each(members)])));
517
539
  return entriesOfList((await each(value.split(","))).join(","), {
518
540
  held,
@@ -522,9 +544,9 @@ var listedOf = /* @__PURE__ */ __name(async (store, value) => {
522
544
  });
523
545
  }, "listedOf");
524
546
  var sourceListOf = /* @__PURE__ */ __name(async (store, env, value) => {
525
- const listed = await listedOf(store, value);
547
+ const listed2 = await listedOf(store, value);
526
548
  const list = { mail: [], notes: false, documents: false };
527
- for (const { entry, accounts } of listed) {
549
+ for (const { entry, accounts } of listed2) {
528
550
  const word = entry.split(":")[0] ?? "";
529
551
  if (MESSENGERS.has(word))
530
552
  throw messengers(entry);
@@ -672,6 +694,7 @@ var oneOf = /* @__PURE__ */ __name((values) => (value) => {
672
694
  var collect = /* @__PURE__ */ __name((value, previous = []) => [...previous, value], "collect");
673
695
  var readScope = /* @__PURE__ */ __name((command, help = ONE_ACCOUNT_HELP) => sourceOptions(command, help).option("--json", "print JSON; --json=id,title keeps only those fields"), "readScope");
674
696
  var writeScope = /* @__PURE__ */ __name((command, help) => writeOptions(command, help).option("--json", "print JSON; --json=id,title keeps only those fields"), "writeScope");
697
+ var jsonOption = /* @__PURE__ */ __name((command, fields = "ref,title") => command.option("--json", `print JSON; --json=${fields} keeps only those fields`), "jsonOption");
675
698
 
676
699
  // node_modules/.pnpm/@wirecat+cli-core@0.613.0_@wirecat+cli-base@0.82.0_commander@15.0.0_esbuild@0.28.2_type_562287bbc40b862fa82b63f307e02b11/node_modules/@wirecat/cli-core/dist/mail/sender-scores.js
677
700
  var SCORED = "mail_sender_scores";
@@ -724,7 +747,11 @@ var REVIEW_KINDS = [
724
747
  "action",
725
748
  "invoice",
726
749
  "payment",
727
- "order"
750
+ "order",
751
+ "contract",
752
+ "subscription",
753
+ "subscription_price",
754
+ "transaction"
728
755
  ];
729
756
  var BY_ACCOUNT = [MEETING_FINDINGS_KIND, MAIL_FINDINGS_KIND];
730
757
  var reviewRegistry = /* @__PURE__ */ __name((store) => {
@@ -761,22 +788,22 @@ var REVIEW_QUERY = {
761
788
  ]
762
789
  };
763
790
  var filterOf = /* @__PURE__ */ __name(async (store, words) => {
764
- const terms = queryTerms(words, REVIEW_QUERY, "review");
765
- const project = terms.get("project");
766
- const kinds2 = terms.get("kind")?.split(",").map((one2) => one2.trim()).filter(Boolean);
791
+ const terms2 = queryTerms(words, REVIEW_QUERY, "review");
792
+ const project = terms2.get("project");
793
+ const kinds2 = terms2.get("kind")?.split(",").map((one2) => one2.trim()).filter(Boolean);
767
794
  const unknown2 = kinds2?.find((one2) => !REVIEW_KINDS.includes(one2));
768
795
  if (unknown2 !== void 0)
769
796
  throw new CliError("validation_error", `no proposal kind ${unknown2}; kinds: ${REVIEW_KINDS.join(", ")}`, {
770
797
  param: "kind"
771
798
  });
772
- const by = terms.get("by");
773
- const via = terms.get("via");
799
+ const by = terms2.get("by");
800
+ const via = terms2.get("via");
774
801
  return {
775
802
  ...project === void 0 ? {} : { project: await canonicalProject(store, project) },
776
803
  ...kinds2?.length ? { kinds: kinds2 } : {},
777
804
  ...by === void 0 ? {} : { by: by === "agent" || by === "rule" ? by : { bot: by } },
778
805
  ...via === void 0 ? {} : { via },
779
- status: terms.get("status") ?? "proposed"
806
+ status: terms2.get("status") ?? "proposed"
780
807
  };
781
808
  }, "filterOf");
782
809
  var proposerName = /* @__PURE__ */ __name((proposer) => proposer.type === "bot" ? proposer.name : proposer.type === "person" ? "you" : "unknown", "proposerName");
@@ -813,6 +840,10 @@ var titleOf = /* @__PURE__ */ __name((row, label) => {
813
840
  case "invoice":
814
841
  case "payment":
815
842
  case "order":
843
+ case "contract":
844
+ case "subscription":
845
+ case "subscription_price":
846
+ case "transaction":
816
847
  return row.summary ?? subject;
817
848
  default:
818
849
  return object2 === null ? subject : `${subject} \u2192 ${object2}`;
@@ -942,8 +973,8 @@ var reviewText = /* @__PURE__ */ __name((items, hasMore) => {
942
973
  ...item.status === "proposed" ? [] : [item.status]
943
974
  ].join(" ");
944
975
  const why = [item.reason && cut(item.reason, 100), item.evidence[0]].filter(Boolean).join(" \xB7 ");
945
- const parts = (item.parts ?? []).map((part) => `${pad} ${item.id}/${part.id} ${part.kind} ${cut(part.summary, 80)}${part.outcome ? ` ${part.outcome}` : ""}`);
946
- return [head, ...why ? [`${pad} ${why}`] : [], ...parts];
976
+ const parts2 = (item.parts ?? []).map((part) => `${pad} ${item.id}/${part.id} ${part.kind} ${cut(part.summary, 80)}${part.outcome ? ` ${part.outcome}` : ""}`);
977
+ return [head, ...why ? [`${pad} ${why}`] : [], ...parts2];
947
978
  })
948
979
  ]);
949
980
  return [...lines2, `${items.length} shown${hasMore ? ", more with --page" : ""}`].join("\n");
@@ -1043,19 +1074,19 @@ var partsOf = /* @__PURE__ */ __name((action, targetName) => {
1043
1074
  const text3 = [payload.text, payload.title].find((one2) => typeof one2 === "string" && one2.trim() !== "");
1044
1075
  return { verb: action.kind, targetName, text: text3 ?? null };
1045
1076
  }, "partsOf");
1046
- var summaryOf = /* @__PURE__ */ __name((action, parts) => {
1047
- const target = parts.targetName ?? action.target;
1048
- if ("counts" in parts && parts.counts) {
1049
- const { facts, tasks } = parts.counts;
1077
+ var summaryOf = /* @__PURE__ */ __name((action, parts2) => {
1078
+ const target = parts2.targetName ?? action.target;
1079
+ if ("counts" in parts2 && parts2.counts) {
1080
+ const { facts, tasks } = parts2.counts;
1050
1081
  const what = [facts && counted(facts, "fact"), tasks && counted(tasks, "task")].filter(Boolean).join(" and ");
1051
1082
  const word = action.kind === MEETING_FINDINGS_KIND ? "from" : action.target?.startsWith("project:") ? "in" : "about";
1052
1083
  return `Create ${what || "nothing"}${target === null ? "" : ` ${word} ${target}`}`;
1053
1084
  }
1054
- const words = parts.verb.replaceAll("_", " ");
1085
+ const words = parts2.verb.replaceAll("_", " ");
1055
1086
  return [
1056
1087
  `${words.charAt(0).toUpperCase()}${words.slice(1)}`,
1057
1088
  target === null ? "" : ` ${target}`,
1058
- parts.text === null ? "" : `: ${clip(parts.text)}`
1089
+ parts2.text === null ? "" : `: ${clip(parts2.text)}`
1059
1090
  ].join("");
1060
1091
  }, "summaryOf");
1061
1092
  var chatOf = /* @__PURE__ */ __name((reference2) => {
@@ -1118,11 +1149,11 @@ var actionItems = /* @__PURE__ */ __name(async (store, actions, { brief = false
1118
1149
  const project = batch?.project ?? (action.target?.startsWith("project:") ? action.target : null);
1119
1150
  const projectName = project === null ? null : names.get(project) ?? null;
1120
1151
  const targetName = action.target === null ? null : names.get(action.target) ?? null;
1121
- const parts = partsOf(action, targetName);
1152
+ const parts2 = partsOf(action, targetName);
1122
1153
  return {
1123
1154
  ...action,
1124
- summary: summaryOf(action, parts),
1125
- ...parts,
1155
+ summary: summaryOf(action, parts2),
1156
+ ...parts2,
1126
1157
  chatName: action.target === null ? null : chats.get(action.target) ?? null,
1127
1158
  project,
1128
1159
  projectName,
@@ -1170,8 +1201,8 @@ var decideBatch = /* @__PURE__ */ __name(async (store, id, decision) => {
1170
1201
  throw new CliError("validation_error", "the findings changed since they were read; stage a new batch", {
1171
1202
  reason: batch.stale
1172
1203
  });
1173
- const parts = decision.confirm && decision.accept.length ? decision.accept.map((one2) => `${id}/${one2}`) : [id];
1174
- const { decided, refused } = await proposalRegistry(store).decide(parts, decisionOf(decision.confirm, decision.by, decision.reason));
1204
+ const parts2 = decision.confirm && decision.accept.length ? decision.accept.map((one2) => `${id}/${one2}`) : [id];
1205
+ const { decided, refused } = await proposalRegistry(store).decide(parts2, decisionOf(decision.confirm, decision.by, decision.reason));
1175
1206
  const refusal = refused[0];
1176
1207
  if (refusal)
1177
1208
  throw new CliError(refusal.code, refusal.message, { reason: refusal.reason });
@@ -1239,9 +1270,9 @@ var AGENT_LOG_QUERY = {
1239
1270
  ]
1240
1271
  };
1241
1272
  var listAgentActions = /* @__PURE__ */ __name((store, query, limit) => {
1242
- const terms = queryTerms(query, AGENT_LOG_QUERY, "agents list");
1243
- const tool = terms.get("tool");
1244
- const agent = terms.get("agent");
1273
+ const terms2 = queryTerms(query, AGENT_LOG_QUERY, "agents list");
1274
+ const tool = terms2.get("tool");
1275
+ const agent = terms2.get("agent");
1245
1276
  return pageOf("agents list", limit, (most) => store.agentActions.list({
1246
1277
  ...tool === void 0 ? {} : { tool },
1247
1278
  ...agent === void 0 ? {} : { agent },
@@ -1670,7 +1701,7 @@ var allowedPage = /* @__PURE__ */ __name(async (ask, limit, shows) => {
1670
1701
  const { nextOffset: _, ...rest } = first;
1671
1702
  return { ...rest, items: items.slice(0, limit), hasMore: items.length > limit || page.hasMore };
1672
1703
  }, "allowedPage");
1673
- var searchEverywhere = /* @__PURE__ */ __name(async (store, env, { text: text3, limit, only, exact, timezone, plainOrder, shows }) => {
1704
+ var searchEverywhere = /* @__PURE__ */ __name(async (store, env, { text: text3, limit, only, crmKinds, exact, timezone, plainOrder, shows }) => {
1674
1705
  const accounts = await store.accounts.accounts();
1675
1706
  const messenger2 = { app: { ...APP, command: "tg" }, hintCommand: "memo" };
1676
1707
  const ask = /* @__PURE__ */ __name((offset) => searchAll(store, MEMO, {
@@ -1679,6 +1710,7 @@ var searchEverywhere = /* @__PURE__ */ __name(async (store, env, { text: text3,
1679
1710
  env,
1680
1711
  ...offset === void 0 ? {} : { offset },
1681
1712
  ...only === void 0 ? {} : { only },
1713
+ ...crmKinds === void 0 ? {} : { crmKinds },
1682
1714
  ...exact ? { exact: true } : {},
1683
1715
  ...timezone === void 0 ? {} : { timezone }
1684
1716
  }, messenger2, (query) => searchStore(store, MEMO, query, messenger2), meaningLane({ env, store: /* @__PURE__ */ __name(async () => store, "store"), messenger: { app: { command: "memo" } } })), "ask");
@@ -2008,8 +2040,8 @@ var fileLinks = /* @__PURE__ */ __name((source, links, documents) => links.map((
2008
2040
  const at = anchor === null ? {} : { anchor };
2009
2041
  if (isReference(target))
2010
2042
  return { to: target, kind: "links-to", ...at };
2011
- const named4 = notesNamed(source, target, documents);
2012
- return named4.length === 1 ? { to: `document:${named4[0].id}`, kind: "links-to", ...at } : { targetText: posix.basename(target.replace(/\\/g, "/")) || target, kind: "links-to", ...at };
2043
+ const named5 = notesNamed(source, target, documents);
2044
+ return named5.length === 1 ? { to: `document:${named5[0].id}`, kind: "links-to", ...at } : { targetText: posix.basename(target.replace(/\\/g, "/")) || target, kind: "links-to", ...at };
2013
2045
  }), "fileLinks");
2014
2046
 
2015
2047
  // dist/notes/renames.js
@@ -2143,11 +2175,11 @@ var importNotes = /* @__PURE__ */ __name(async (store, folder, { ignore = [], sk
2143
2175
  after.files[id] = `${stamp}${hash}`;
2144
2176
  read.push({ id, path, bytes, hash });
2145
2177
  }
2146
- const listed = /* @__PURE__ */ new Set([
2178
+ const listed2 = /* @__PURE__ */ new Set([
2147
2179
  ...Object.keys(after.files).filter((id) => !after.files[id]?.startsWith(MEMO2)),
2148
2180
  ...[...held].filter((id) => stored.has(id))
2149
2181
  ]);
2150
- const goneHashes = Object.fromEntries([...stored.values()].filter((note) => !listed.has(note.path) && note.contentHash !== null).map((note) => [note.path, note.contentHash]));
2182
+ const goneHashes = Object.fromEntries([...stored.values()].filter((note) => !listed2.has(note.path) && note.contentHash !== null).map((note) => [note.path, note.contentHash]));
2151
2183
  const newHashes = Object.fromEntries(read.filter(({ id }) => !stored.has(id)).map(({ id, hash }) => [id, hash]));
2152
2184
  let renamed = 0;
2153
2185
  for (const move of detectRenames(goneHashes, newHashes)) {
@@ -2197,7 +2229,7 @@ var importNotes = /* @__PURE__ */ __name(async (store, folder, { ignore = [], sk
2197
2229
  changed++;
2198
2230
  }
2199
2231
  onFile(files.length, files.length);
2200
- const gone = [...stored.keys()].filter((id) => !listed.has(id));
2232
+ const gone = [...stored.keys()].filter((id) => !listed2.has(id));
2201
2233
  let deleted = 0;
2202
2234
  let deletionsSkipped;
2203
2235
  if (gone.length >= MIN_DELETIONS_CAPPED && gone.length > stored.size * MAX_DELETED_SHARE) {
@@ -2241,7 +2273,7 @@ var importNotes = /* @__PURE__ */ __name(async (store, folder, { ignore = [], sk
2241
2273
  return {
2242
2274
  folder: folder.path,
2243
2275
  folderId: folder.id,
2244
- notes: listed.size - Object.keys(notReadNow).filter((id) => listed.has(id)).length,
2276
+ notes: listed2.size - Object.keys(notReadNow).filter((id) => listed2.has(id)).length,
2245
2277
  changed,
2246
2278
  renamed,
2247
2279
  deleted,
@@ -2439,9 +2471,9 @@ var anchorOf = /* @__PURE__ */ __name(async (store, uid, source) => {
2439
2471
  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(", ")}`);
2440
2472
  }, "anchorOf");
2441
2473
  var memoContext = /* @__PURE__ */ __name(async (store, reference2, { limit = 20, source } = {}) => {
2442
- const named4 = (await withOwner(store, reference2)).trim();
2443
- if (named4.startsWith("person:")) {
2444
- const anchor = await anchorOf(store, named4.slice("person:".length), source);
2474
+ const named5 = (await withOwner(store, reference2)).trim();
2475
+ if (named5.startsWith("person:")) {
2476
+ const anchor = await anchorOf(store, named5.slice("person:".length), source);
2445
2477
  return memoContext(store, anchor.reference, { limit, source: anchor });
2446
2478
  }
2447
2479
  const [, provider, who] = /^([a-z][a-z0-9-]*):(.+)$/.exec(reference2.trim()) ?? [];
@@ -2507,7 +2539,7 @@ var withOwnMailText = /* @__PURE__ */ __name((context) => {
2507
2539
  // dist/context/command.js
2508
2540
  var MAX_TEXT2 = 160;
2509
2541
  var one = /* @__PURE__ */ __name((message) => message === null ? "\u2014" : `${message.timestamp.slice(0, 16).replace("T", " ")} ${message.provider} ${message.chatTitle ?? message.chatId}: ${message.text.replace(/\s+/g, " ").slice(0, MAX_TEXT2)} ${message.locator}`, "one");
2510
- var eventLine = /* @__PURE__ */ __name((event) => ` ${(event.allDay ? event.startsAt?.slice(0, 10) : event.startsAt?.slice(0, 16).replace("T", " ")) ?? "\u2014"} ${(event.title ?? "untitled").replace(/\s+/g, " ").slice(0, MAX_TEXT2)}${event.location ? ` ${event.location}` : ""} ${event.ref}`, "eventLine");
2542
+ 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");
2511
2543
  var noteLine = /* @__PURE__ */ __name((note) => ` ${note.ref}${note.path ?? note.title ? ` ${note.path ?? note.title}` : ""}`, "noteLine");
2512
2544
  var fileLine = /* @__PURE__ */ __name((file) => ` ${file.ref} ${file.role ?? ""} ${file.title ?? ""} ${file.modifiedAt?.slice(0, 16).replace("T", " ") ?? ""} ${file.url ?? ""}`, "fileLine");
2513
2545
  var contextText = /* @__PURE__ */ __name(({ messages, events, notes: notes2, notRead, tasks, yourNotes, files, proposals }) => {
@@ -3495,7 +3527,7 @@ var search = [
3495
3527
  command: ["search", "all"],
3496
3528
  field: "description",
3497
3529
  before: "search messenger messages and notes in the local store, calendar events when the store holds a calendar, and a meeting account's transcripts when --source names one \u2014 best match first; not mail (the separate memo CLI searches it: memo search mail), tasks, people, memories or projects. Use it when you do not know where something was written; search messages or notes reads one kind with all its fields",
3498
- after: "messages, mail, notes and calendar events ranked together; not people, memories, projects or decisions. A kind you know reads better with its own search, with all its fields",
3530
+ after: "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",
3499
3531
  reason: "Memo searches imported accounts, mail and native notes without a live messenger; its scope, ranking and output controls are explicit provider differences."
3500
3532
  },
3501
3533
  {
@@ -3614,7 +3646,7 @@ var search = [
3614
3646
  },
3615
3647
  {
3616
3648
  flags: "--only <resources>",
3617
- description: "messages,mail,notes,events, separated by commas",
3649
+ description: "messages,mail,notes,events,crm,business, separated by commas",
3618
3650
  takes_value: true,
3619
3651
  mandatory: false
3620
3652
  },
@@ -4081,6 +4113,7 @@ var SECTIONS = [
4081
4113
  ["notes remove", "write"],
4082
4114
  ["notes export", "write"],
4083
4115
  ["mail", "read"],
4116
+ ["events", "read"],
4084
4117
  ["agents", "read"],
4085
4118
  ["answers", "read"],
4086
4119
  ["memories", "write"],
@@ -4095,6 +4128,11 @@ var SECTIONS = [
4095
4128
  ["leads", "organise"],
4096
4129
  ["pipelines", "organise"],
4097
4130
  ["payments", "organise"],
4131
+ ["products", "organise"],
4132
+ ["contracts", "organise"],
4133
+ ["subscriptions", "organise"],
4134
+ ["wallets", "organise"],
4135
+ ["transactions", "organise"],
4098
4136
  ["records", "organise"],
4099
4137
  ["projects", "organise"],
4100
4138
  ["people", "organise"],
@@ -4283,10 +4321,387 @@ var doctorCommand = /* @__PURE__ */ __name((...args) => {
4283
4321
  }, SHELL_OVERRIDES.doctor);
4284
4322
  }, "doctorCommand");
4285
4323
 
4324
+ // node_modules/.pnpm/@wirecat+cli-core@0.613.0_@wirecat+cli-base@0.82.0_commander@15.0.0_esbuild@0.28.2_type_562287bbc40b862fa82b63f307e02b11/node_modules/@wirecat/cli-core/dist/calendar/sync.js
4325
+ var DAY3 = 864e5;
4326
+ var SLOTS_EVERY = 7 * DAY3;
4327
+ var isWindow = /* @__PURE__ */ __name((value) => typeof value?.from === "number" && typeof value.to === "number", "isWindow");
4328
+ var isToken = /* @__PURE__ */ __name((value) => value === null || typeof value === "string", "isToken");
4329
+ var roundOf = /* @__PURE__ */ __name((value) => {
4330
+ if (value === null || value === void 0)
4331
+ return null;
4332
+ const round = value;
4333
+ if (typeof round.full !== "boolean" || !isToken(round.from) || !isWindow(round.window) || typeof round.startedAt !== "number" || typeof round.reset !== "boolean" || !isToken(round.page) || typeof round.listed !== "boolean" || !isToken(round.next) || !Array.isArray(round.series) || round.series.some((id) => typeof id !== "string") || round.everySeries !== void 0 && typeof round.everySeries !== "boolean")
4334
+ return void 0;
4335
+ const { full, from, window, startedAt, reset, page, listed: listed2, next, series, everySeries, unchanged } = round;
4336
+ return {
4337
+ full,
4338
+ from,
4339
+ window,
4340
+ startedAt,
4341
+ reset,
4342
+ page,
4343
+ listed: listed2,
4344
+ next,
4345
+ series,
4346
+ ...everySeries === false ? { everySeries } : {},
4347
+ ...unchanged === true ? { unchanged } : {}
4348
+ };
4349
+ }, "roundOf");
4350
+ var parseCalendarCursor = /* @__PURE__ */ __name((value) => {
4351
+ if (value === null)
4352
+ return null;
4353
+ try {
4354
+ const cursor = JSON.parse(value);
4355
+ if (cursor?.v !== 1 && cursor?.v !== 2 || !isToken(cursor.token) || typeof cursor.fullAt !== "number" || !isWindow(cursor.window))
4356
+ return null;
4357
+ const { token, window, fullAt } = cursor;
4358
+ if (cursor.v === 1)
4359
+ return { v: 2, token, window, fullAt, updatedAt: null, done: 0, round: null };
4360
+ const round = roundOf(cursor.round);
4361
+ if (round === void 0 || cursor.updatedAt !== null && typeof cursor.updatedAt !== "number" || typeof cursor.done !== "number")
4362
+ return null;
4363
+ return {
4364
+ v: 2,
4365
+ token,
4366
+ window,
4367
+ fullAt,
4368
+ updatedAt: cursor.updatedAt ?? null,
4369
+ done: cursor.done,
4370
+ round,
4371
+ ...cursor.restored === true ? { restored: true } : {},
4372
+ ...typeof cursor.slotsTo === "number" ? { slotsTo: cursor.slotsTo } : {}
4373
+ };
4374
+ } catch {
4375
+ return null;
4376
+ }
4377
+ }, "parseCalendarCursor");
4378
+ var calendarStatus = /* @__PURE__ */ __name(async (store, accountId, { profile, now }) => {
4379
+ const items = [];
4380
+ for (const calendar of await store.calendars(accountId)) {
4381
+ if (!calendar.synced || calendar.deletedAt !== null)
4382
+ continue;
4383
+ const cursor = parseCalendarCursor(await store.cursor(calendar.id));
4384
+ const progress = progressOf({
4385
+ job: `calendar ${calendar.id}`,
4386
+ profile,
4387
+ done: cursor?.done ?? 0,
4388
+ complete: cursor !== null && cursor.round === null,
4389
+ ...cursor?.updatedAt == null ? {} : { updatedAt: new Date(cursor.updatedAt).toISOString() },
4390
+ now: new Date(now)
4391
+ });
4392
+ items.push({
4393
+ calendar_id: String(calendar.id),
4394
+ external_id: calendar.externalId,
4395
+ title: calendar.title,
4396
+ round: cursor?.round ? cursor.round.full ? "full" : "changes" : null,
4397
+ ...progress,
4398
+ line: progressLine(progress)
4399
+ });
4400
+ }
4401
+ return { items, page: 1, limit: Math.max(1, items.length), hasMore: false };
4402
+ }, "calendarStatus");
4403
+
4404
+ // node_modules/.pnpm/@wirecat+cli-core@0.613.0_@wirecat+cli-base@0.82.0_commander@15.0.0_esbuild@0.28.2_type_562287bbc40b862fa82b63f307e02b11/node_modules/@wirecat/cli-core/dist/calendar/feeds.js
4405
+ var FEED_LIMITS = { maxBytes: 10 * 1024 * 1024, timeoutMs: 3e4, redirects: 5 };
4406
+
4407
+ // node_modules/.pnpm/@wirecat+cli-core@0.613.0_@wirecat+cli-base@0.82.0_commander@15.0.0_esbuild@0.28.2_type_562287bbc40b862fa82b63f307e02b11/node_modules/@wirecat/cli-core/dist/calendar/reads.js
4408
+ var LIST = "events list";
4409
+ var EVENT_TYPES = [
4410
+ "default",
4411
+ "out-of-office",
4412
+ "focus",
4413
+ "working-location",
4414
+ "birthday",
4415
+ "from-mail",
4416
+ "call"
4417
+ ];
4418
+ var oneSided = /* @__PURE__ */ __name((field2, example) => (node) => {
4419
+ if (node.operator !== "range" || node.upper !== "*")
4420
+ queryError("query.unsupported-operator", node.span, `${field2} takes only an earliest moment, such as ${example}`, {
4421
+ command: LIST,
4422
+ guide: LIST_QUERY_GUIDE
4423
+ });
4424
+ }, "oneSided");
4425
+ var EVENTS_QUERY = {
4426
+ entity: "event",
4427
+ backend: "native",
4428
+ fields: queryFieldsOf(event, {
4429
+ native: ["id", "starts_at", "ends_at", "changed_at", "overlapping", "calendar", "person", "event_type"],
4430
+ negatable: ["event_type"],
4431
+ relations: {
4432
+ event_type: {
4433
+ type: "enum",
4434
+ values: EVENT_TYPES,
4435
+ example: "event_type:default",
4436
+ relation: "events with a copy of this kind; -event_type:<kind> leaves out events with one"
4437
+ },
4438
+ calendar: {
4439
+ type: "kw",
4440
+ example: "calendar:3",
4441
+ relation: "one calendar, by its id, the provider's id or its title"
4442
+ },
4443
+ person: {
4444
+ type: "kw",
4445
+ example: "person:ana@example.com",
4446
+ relation: "events one person attends: an address, or a person id from search"
4447
+ }
4448
+ },
4449
+ examples: {
4450
+ id: "id:42",
4451
+ starts_at: "starts_at:[2026-11-02 TO 2026-11-07}",
4452
+ ends_at: "ends_at>=2026-11-02",
4453
+ changed_at: "changed_at>=2026-10-01",
4454
+ overlapping: "overlapping:true"
4455
+ },
4456
+ validate: {
4457
+ ends_at: oneSided("ends_at", "ends_at>=2026-11-02; for the latest, write starts_at<2026-11-07"),
4458
+ changed_at: oneSided("changed_at", "changed_at>=2026-10-01")
4459
+ }
4460
+ }).map((field2) => field2.native ? {
4461
+ ...field2,
4462
+ operators: field2.type === "time" ? ["term", "range"] : field2.type === "bool" ? ["term"] : ["term", "phrase"]
4463
+ } : field2)
4464
+ };
4465
+ var nameOf = /* @__PURE__ */ __name(({ provider, account: account2 }) => `${provider}:${account2}`, "nameOf");
4466
+ var accountsMeta = /* @__PURE__ */ __name(async (store, accounts, skipped, now) => {
4467
+ const issues = [...skipped];
4468
+ for (const { id, key } of accounts) {
4469
+ if (isImportedProvider(key.provider))
4470
+ continue;
4471
+ const { items } = await calendarStatus(store, id, { profile: nameOf(key), now });
4472
+ if (items.length === 0)
4473
+ issues.push({ code: "not_found", reason: "calendar.unsynced", source: nameOf(key) });
4474
+ else if (items.some(({ state }) => state !== "complete"))
4475
+ issues.push({ code: "not_found", reason: "calendar.sync-incomplete", source: nameOf(key) });
4476
+ }
4477
+ return {
4478
+ accounts: accounts.map(({ key }) => nameOf(key)),
4479
+ complete: issues.length === 0,
4480
+ ...issues.length ? { issues } : {}
4481
+ };
4482
+ }, "accountsMeta");
4483
+
4484
+ // node_modules/.pnpm/@wirecat+cli-core@0.613.0_@wirecat+cli-base@0.82.0_commander@15.0.0_esbuild@0.28.2_type_562287bbc40b862fa82b63f307e02b11/node_modules/@wirecat/cli-core/dist/calendar/writer.js
4485
+ var EVENTS_NOTIFY_KEY = "events.notify";
4486
+ var EVENTS_DELETE_SERIES_KEY = "events.delete.series";
4487
+ var EVENTS_REMIND_HOOK_KEY = "events.remind.hook";
4488
+ var CALENDAR_WRITE_DEFAULTS = {
4489
+ "events.create": "allow",
4490
+ // One import writes a whole file of events, and may change events the calendar already holds under their UIDs.
4491
+ "events.import": "ask",
4492
+ "events.update": "allow",
4493
+ "events.respond": "allow",
4494
+ "events.move": "allow",
4495
+ "events.delete": "ask",
4496
+ [EVENTS_DELETE_SERIES_KEY]: "deny",
4497
+ [EVENTS_NOTIFY_KEY]: "deny",
4498
+ // Not ask: `--yes` answers ask, and anything that can type a gcal command can add it.
4499
+ [EVENTS_REMIND_HOOK_KEY]: "deny"
4500
+ };
4501
+
4502
+ // dist/events/events.js
4503
+ var LIST2 = "events list";
4504
+ var EVENT_TYPES2 = [
4505
+ "default",
4506
+ "out-of-office",
4507
+ "focus",
4508
+ "working-location",
4509
+ "birthday",
4510
+ "from-mail",
4511
+ "call"
4512
+ ];
4513
+ var EVENTS_QUERY2 = {
4514
+ entity: "event",
4515
+ backend: "native",
4516
+ fields: [
4517
+ nativeField({
4518
+ name: "starts_at",
4519
+ type: "time",
4520
+ operators: ["term", "range"],
4521
+ example: "starts_at:[2026-11-02 TO 2026-11-07}"
4522
+ }),
4523
+ termField("account", "kw", 'account:"phone:pixel"', {
4524
+ relation: "one calendar account, provider:account, or every account of a provider"
4525
+ }),
4526
+ termField("calendar", "kw", "calendar:Calls", { relation: "one calendar, by its id or its title" }),
4527
+ termField("event_type", "enum", "event_type:call", {
4528
+ values: EVENT_TYPES2,
4529
+ relation: "events with a copy of this kind; a phone's imported calls are call"
4530
+ })
4531
+ ]
4532
+ };
4533
+ var RECENT_DAYS = 30;
4534
+ var AHEAD_DAYS = 7;
4535
+ var EVENTS_NOTE = `
4536
+ Every calendar account in the store is read, phone imports included. Without starts_at: the last ${RECENT_DAYS} days and the next ${AHEAD_DAYS}. Latest start first.`;
4537
+ var UNTRUSTED = ["title", "description", "location", "in"];
4538
+ var readAccounts = /* @__PURE__ */ __name(async (store) => {
4539
+ const held = await calendarAccounts(store);
4540
+ const stored = await store.accounts.storedAccounts();
4541
+ const read = [];
4542
+ for (const key of held) {
4543
+ const one2 = stored.find(({ provider, account: account2 }) => provider === key.provider && account2 === key.account);
4544
+ if (one2)
4545
+ read.push({ id: one2.id, key, calendars: await store.calendar.calendars(one2.id) });
4546
+ }
4547
+ return read;
4548
+ }, "readAccounts");
4549
+ var narrowed = /* @__PURE__ */ __name((accounts, value) => {
4550
+ const chosen = accounts.filter(({ key }) => accountName(key) === value || key.provider === value);
4551
+ if (chosen.length === 0)
4552
+ throw new CliError("not_found", `account:${value} names no calendar account \u2014 the store holds ${accounts.map(({ key }) => accountName(key)).join(", ") || "none"}`, { reason: "events.account-unknown" });
4553
+ return chosen;
4554
+ }, "narrowed");
4555
+ var calendarOf = /* @__PURE__ */ __name((accounts, value) => {
4556
+ const all = accounts.flatMap((account2) => account2.calendars.map((calendar) => ({ account: account2, calendar })));
4557
+ const byId = all.filter(({ calendar }) => String(calendar.id) === value);
4558
+ const found = byId.length ? byId : all.filter(({ calendar }) => calendar.title === value);
4559
+ if (found.length === 1)
4560
+ return found[0];
4561
+ if (found.length === 0)
4562
+ throw new CliError("not_found", `calendar:${value} names no calendar in the accounts read`);
4563
+ 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(", "));
4564
+ }, "calendarOf");
4565
+ var localDate = /* @__PURE__ */ __name((at, zone) => new Intl.DateTimeFormat("en-CA", { timeZone: zone, year: "numeric", month: "2-digit", day: "2-digit" }).format(at), "localDate");
4566
+ var plusDays = /* @__PURE__ */ __name((date, days2) => {
4567
+ const [year, month, day2] = date.split("-").map(Number);
4568
+ return new Date(Date.UTC(year, month - 1, day2 + days2)).toISOString().slice(0, 10);
4569
+ }, "plusDays");
4570
+ var midnight = /* @__PURE__ */ __name((date, zone) => dayBoundary(date, zone, false, { start: 0, end: date.length }), "midnight");
4571
+ var startsWindow = /* @__PURE__ */ __name((node, zone, now) => {
4572
+ const range = node.operator === "range" ? dateRange(node.value, node.upper ?? "*", node.lower_inclusive !== false, node.upper_inclusive !== false, zone, node.span, now) : dateRange(node.value, node.value, true, true, zone, node.span, now);
4573
+ return {
4574
+ ...range.lower === void 0 ? {} : { lower: range.lower_inclusive ? range.lower : range.lower + 1 },
4575
+ ...range.upper === void 0 ? {} : { upper: range.upper_inclusive ? range.upper + 1 : range.upper }
4576
+ };
4577
+ }, "startsWindow");
4578
+ var dated = /* @__PURE__ */ __name((filter, zone) => {
4579
+ if (filter.from !== void 0)
4580
+ filter.fromDate = localDate(filter.from, zone);
4581
+ if (filter.to !== void 0)
4582
+ filter.toDate = plusDays(localDate(filter.to - 1, zone), 1);
4583
+ if (filter.startsFrom !== void 0) {
4584
+ const date = localDate(filter.startsFrom, zone);
4585
+ filter.startsFromDate = midnight(date, zone) < filter.startsFrom ? plusDays(date, 1) : date;
4586
+ }
4587
+ return filter;
4588
+ }, "dated");
4589
+ var windowMeta = /* @__PURE__ */ __name((filter, zone) => {
4590
+ const since = filter.startsFrom ?? filter.from;
4591
+ return {
4592
+ timezone: zone,
4593
+ window: {
4594
+ ...since === void 0 ? {} : { since: new Date(since).toISOString() },
4595
+ ...filter.to === void 0 ? {} : { until: new Date(filter.to - 1).toISOString() }
4596
+ }
4597
+ };
4598
+ }, "windowMeta");
4599
+ var rowOf = /* @__PURE__ */ __name((details, accounts) => {
4600
+ const live = details.entries.filter(({ deletedAt }) => deletedAt === null);
4601
+ const copies = live.length ? live : details.entries;
4602
+ const held = accounts.flatMap((account2) => account2.calendars.filter(({ id }) => copies.some(({ calendarId }) => calendarId === id)).map((calendar) => ({ account: accountName(account2.key), calendar: calendar.title ?? String(calendar.id) })));
4603
+ return {
4604
+ ...eventItem(details.event),
4605
+ ref: `event:${details.event.id}`,
4606
+ event_type: copies.find(({ eventType }) => eventType !== null)?.eventType ?? "default",
4607
+ accounts: [...new Set(held.map(({ account: account2 }) => account2))],
4608
+ in: held.map(({ account: account2, calendar }) => `${account2}/${calendar}`).join(", "),
4609
+ untrusted: UNTRUSTED
4610
+ };
4611
+ }, "rowOf");
4612
+ var listEvents = /* @__PURE__ */ __name(async (store, words, limit, { now = Date.now(), zone = timezoneOf() } = {}) => {
4613
+ const terms2 = nativeTerms(listQuery(typedQuery(words), EVENTS_QUERY2, LIST2), LIST2);
4614
+ const every = await readAccounts(store);
4615
+ const account2 = terms2.get("account");
4616
+ let accounts = account2 ? narrowed(every, account2.value) : every;
4617
+ const filter = { newest: true };
4618
+ const calendar = terms2.get("calendar");
4619
+ if (calendar) {
4620
+ const found = calendarOf(accounts, calendar.value);
4621
+ accounts = [found.account];
4622
+ filter.calendarId = found.calendar.id;
4623
+ }
4624
+ const kind = terms2.get("event_type");
4625
+ if (kind)
4626
+ filter.eventType = kind.value.toLowerCase();
4627
+ const starts = terms2.get("starts_at");
4628
+ if (starts) {
4629
+ const { lower, upper } = startsWindow(starts, zone, now);
4630
+ if (lower !== void 0)
4631
+ filter.startsFrom = lower;
4632
+ if (upper !== void 0)
4633
+ filter.to = upper;
4634
+ } else {
4635
+ const today2 = localDate(now, zone);
4636
+ filter.from = midnight(plusDays(today2, -RECENT_DAYS), zone);
4637
+ filter.to = midnight(plusDays(today2, AHEAD_DAYS + 1), zone);
4638
+ }
4639
+ dated(filter, zone);
4640
+ const read = accounts.map(({ id, key }) => ({ id, key }));
4641
+ const events = read.length ? await store.calendar.events({ ...filter, accountIds: read.map(({ id }) => id), limit: limit + 1 }) : [];
4642
+ const rows = [];
4643
+ for (const event2 of events.slice(0, limit)) {
4644
+ const details = await store.calendar.event(event2.id);
4645
+ if (details)
4646
+ rows.push(rowOf(details, accounts));
4647
+ }
4648
+ const body = listAnswer(LIST2, { items: rows, limit, has_more: events.length > limit });
4649
+ body.meta = {
4650
+ ...body.meta,
4651
+ ...await accountsMeta(store.calendar, read, [], now),
4652
+ ...windowMeta(filter, zone)
4653
+ };
4654
+ return body;
4655
+ }, "listEvents");
4656
+ var showEvent = /* @__PURE__ */ __name(async (store, reference2) => {
4657
+ const text3 = reference2.replace(/^event:/u, "");
4658
+ if (!/^[1-9]\d*$/u.test(text3))
4659
+ throw new CliError("validation_error", "an event is event:<id>");
4660
+ const details = await store.calendar.event(Number(text3));
4661
+ const accounts = await readAccounts(store);
4662
+ const row = details && rowOf(details, accounts);
4663
+ if (!details || !row?.accounts.length)
4664
+ throw new CliError("not_found", `no event ${text3} in any calendar account`);
4665
+ return {
4666
+ ...row,
4667
+ attendees: details.participants.map(({ email, name: name2, response, organizer }) => ({
4668
+ email,
4669
+ name: name2,
4670
+ response,
4671
+ organizer
4672
+ })),
4673
+ untrusted: [...UNTRUSTED, "attendees.name"]
4674
+ };
4675
+ }, "showEvent");
4676
+ var accountsLine = /* @__PURE__ */ __name((accounts) => accounts.length ? `calendar accounts read: ${accounts.join(", ")}` : "no calendar account in the store", "accountsLine");
4677
+
4678
+ // dist/events/command.js
4679
+ var upTo1000 = /* @__PURE__ */ __name((value) => {
4680
+ const number2 = Number(value);
4681
+ if (!Number.isInteger(number2) || number2 < 1 || number2 > 1e3)
4682
+ throw new InvalidArgumentError("a whole number, 1 to 1000");
4683
+ return number2;
4684
+ }, "upTo1000");
4685
+ var eventsCommand = /* @__PURE__ */ __name((program, streams, env) => {
4686
+ const { print } = answers(program, streams, env);
4687
+ const events = program.command("events").description("calendar events of every account in the store, phone calls included").summary("calendar events and phone calls of every account");
4688
+ withQuery(annotate(events.command("list"), { effects: LOCAL_READ, partial: true }).description("events of every calendar account in the store, latest start first: calendars and imported phone calls").summary("events and phone calls of every account, latest first"), EVENTS_QUERY2).addHelpText("after", EVENTS_NOTE).option("--limit <n>", "events at most, 1\u20131000", upTo1000, 100).option("--json", "print JSON; --json=ref,title keeps only those fields").action(async (words, { json: json5, limit }, command) => {
4689
+ const body = await withStore(env, (store) => listEvents(store, words, limit));
4690
+ const accounts = body.meta?.accounts ?? [];
4691
+ print(json5, body, `${accountsLine(accounts)}
4692
+ ${plainText(body, command)}`);
4693
+ });
4694
+ annotate(events.command("show"), { effects: LOCAL_READ, output: { entity: "event" } }).description("one event: its time, the accounts and calendars that hold it, and its attendees").argument("<ref>", "event:<id>").option("--json", "print JSON; --json=ref,title keeps only those fields").action(async (ref, { json: json5 }) => print(json5, itemAnswer(await withStore(env, (store) => showEvent(store, ref)))));
4695
+ }, "eventsCommand");
4696
+
4286
4697
  // dist/examples.js
4287
4698
  var EXAMPLES = {
4288
4699
  context: ["memo context telegram:'Kai Sample'", "memo context email:kai@example.com --limit 5 --json"],
4289
- show: ["memo show chat:max/500/-1001 document:413", "memo show note:12 msg:telegram/1/77/42 --json"],
4700
+ show: [
4701
+ "memo show chat:max/500/-1001 document:413",
4702
+ "memo show note:12 msg:telegram/1/77/42 --json",
4703
+ "memo show contract:2 invoice:4 --json"
4704
+ ],
4290
4705
  "notes show": ["memo notes show note:12", "memo notes show ~/notes/People/Kai.md --json"],
4291
4706
  "notes list": [
4292
4707
  `memo notes list 'about:"telegram:Kai Sample"'`,
@@ -4451,7 +4866,7 @@ var EXAMPLES = {
4451
4866
  "memo relationships update 12 --role contractor --reason 'builds the site'"
4452
4867
  ],
4453
4868
  "relationships add": [
4454
- "memo relationships add person:3 organization:1 --role cto",
4869
+ "memo relationships add person:3 organization:1 --role employee",
4455
4870
  "memo relationships add project:2 organization:1 --kind related-to --reason 'same client'"
4456
4871
  ],
4457
4872
  "relationships list": ['memo relationships list about:"person:3"', "memo relationships list confirmed:false"],
@@ -4515,6 +4930,11 @@ var EXAMPLES = {
4515
4930
  "memo orders add 'Shop One' 2499.00 RUB --kind personal --title A-1042",
4516
4931
  "memo orders add 'Office Supply' --kind client --organization organization:3"
4517
4932
  ],
4933
+ "events list": [
4934
+ "memo events list event_type:call",
4935
+ "memo events list account:phone:pixel 'starts_at:[2026-11-02 TO 2026-11-07}' --json"
4936
+ ],
4937
+ "events show": ["memo events show event:42"],
4518
4938
  "invoices list": ["memo invoices list project:HRB open:true", "memo invoices list review:proposed --json"],
4519
4939
  "invoices show": ["memo invoices show invoice:4"],
4520
4940
  "invoices add": [
@@ -4524,19 +4944,93 @@ var EXAMPLES = {
4524
4944
  "payments list": ["memo payments list project:HRB direction:in", "memo payments list review:proposed --json"],
4525
4945
  "payments show": ["memo payments show payment:9"],
4526
4946
  "payments add": [
4527
- "memo payments add 25000.00 RUB --kind in --organization organization:3 --occurred-time 2026-11-01 --project HRB"
4947
+ "memo payments add 25000.00 RUB --kind in --organization organization:3 --occurred-time 2026-11-01 --project HRB",
4948
+ "memo payments add 5000.00 RUB --kind out --organization organization:3 --refund-of payment:9"
4528
4949
  ],
4529
4950
  "records import": [
4530
4951
  "memo records import payments.jsonl --account rentals --dry-run",
4531
- "memo records import envelope.json --account rentals --json"
4952
+ "memo records import envelope.json --account rentals --json",
4953
+ "memo records import contacts.vcf --account phone:pixel"
4532
4954
  ],
4533
4955
  "records check": ["memo records check - --account rentals"],
4534
4956
  "records list": [
4535
4957
  "memo records list waiting:true --account sheet:rentals",
4536
- "memo records list type:organization --account sheet:rentals --json"
4958
+ "memo records list type:organization --account sheet:rentals --json",
4959
+ `memo records list 'entity:"organization:3"' deleted:false --account sheet:rentals`
4537
4960
  ],
4538
4961
  "records link": ["memo records link organization:client organization:3 --account sheet:rentals"],
4539
4962
  "payments allocate": ["memo payments allocate payment:9 invoice:4 25000.00"],
4963
+ "products list": ["memo products list kind:service", "memo products list archived:true --json"],
4964
+ "products show": ["memo products show product:4"],
4965
+ "products add": [
4966
+ "memo products add 'Bike rental, month' 10000.00 RUB --kind service --unit month",
4967
+ "memo products add 'Helmet' 2500.00 RUB --sku H-12 --supplier organization:3"
4968
+ ],
4969
+ "products update": [
4970
+ "memo products update product:4 --amount 12000.00 --currency RUB",
4971
+ "memo products update product:4 --archived on"
4972
+ ],
4973
+ "orders lines add": [
4974
+ "memo orders lines add order:3 12 --product product:4",
4975
+ "memo orders lines add order:3 1 Rental, first week --product product:4 --amount 2000.00",
4976
+ "memo orders lines add order:3 2 Helmet --amount 2500.00"
4977
+ ],
4978
+ "orders lines remove": ["memo orders lines remove order:3 2"],
4979
+ "invoices lines add": [
4980
+ "memo invoices lines add invoice:4 1 --product product:4",
4981
+ "memo invoices lines add invoice:4 2 Delivery --amount 1500.00"
4982
+ ],
4983
+ "invoices lines remove": ["memo invoices lines remove invoice:4 2"],
4984
+ "contracts list": ["memo contracts list status:active", "memo contracts list expires:2026-12-31 --json"],
4985
+ "contracts show": ["memo contracts show contract:2"],
4986
+ "contracts add": [
4987
+ "memo contracts add 'Rental agreement' --kind service --start-date 2026-11-01 --end-date 2027-10-31 --auto-renew on --notice-days 30 --amount 120000.00 --currency RUB",
4988
+ "memo contracts add 'NDA with the studio' --kind nda --project HRB"
4989
+ ],
4990
+ "contracts update": [
4991
+ "memo contracts update contract:2 --status terminated",
4992
+ "memo contracts update contract:2 --end-date 2027-12-31"
4993
+ ],
4994
+ "subscriptions list": [
4995
+ "memo subscriptions list status:active direction:payable",
4996
+ "memo subscriptions list renews:2026-12-01 --json"
4997
+ ],
4998
+ "subscriptions show": ["memo subscriptions show subscription:5"],
4999
+ "subscriptions add": [
5000
+ "memo subscriptions add Hosting 990.00 RUB --kind payable --supplier organization:3 --every 1-month --start-date 2026-11-01",
5001
+ "memo subscriptions add 'Bike rental' 10000.00 RUB --kind receivable --customer organization:3 --every 1-month --trial-end-date 2026-11-14 --status trial"
5002
+ ],
5003
+ "subscriptions update": [
5004
+ "memo subscriptions update subscription:5 --status paused",
5005
+ "memo subscriptions update subscription:5 --every 1-year"
5006
+ ],
5007
+ "subscriptions cancel": ["memo subscriptions cancel subscription:5 --occurred-time 2026-11-30"],
5008
+ "subscriptions prices add": ["memo subscriptions prices add subscription:5 1190.00 RUB --start-date 2027-01-01"],
5009
+ "wallets list": ["memo wallets list", "memo wallets list kind:card --json"],
5010
+ "wallets show": ["memo wallets show wallet:2", "memo wallets show wallet:2 --until-time 2026-10-31"],
5011
+ "wallets add": ["memo wallets add 'Main card' RUB --kind card --institution 'Bank One'"],
5012
+ "wallets update": ["memo wallets update wallet:2 --opening-balance 15000.00 --opening-date 2026-01-01"],
5013
+ "transactions list": [
5014
+ `memo transactions list 'wallet:"wallet:2"' status:pending`,
5015
+ "memo transactions list uncategorized:true --json"
5016
+ ],
5017
+ "transactions show": ["memo transactions show transaction:12"],
5018
+ "transactions add": [
5019
+ "memo transactions add wallet:2 500.00 --kind out --occurred-time 2026-11-14 --description 'Coffee shop'",
5020
+ "memo transactions add wallet:2 10000.00 --kind in --payment payment:9"
5021
+ ],
5022
+ "transactions update": [
5023
+ "memo transactions update transaction:12 --status booked",
5024
+ "memo transactions update transaction:12 --payment payment:9"
5025
+ ],
5026
+ "transactions splits add": ["memo transactions splits add transaction:12 300.00 Rent --project HRB"],
5027
+ "transactions splits remove": ["memo transactions splits remove transaction:12 1"],
5028
+ "records show": [
5029
+ "memo records show custom:quote:Q-7 --account example-erp:demo",
5030
+ "memo records show organization:client --account sheet:rentals --json"
5031
+ ],
5032
+ "records delete": ["memo records delete payment:sheet-12 --account sheet:rentals"],
5033
+ "records match": ["memo records match --account sheet:rentals"],
4540
5034
  "payments unlink": ["memo payments unlink payment:9 invoice:4"],
4541
5035
  "facts show": ["memo facts show fact:4 --sources"],
4542
5036
  "facts confirm": ["memo facts confirm fact:4"],
@@ -4606,7 +5100,11 @@ var EXAMPLES = {
4606
5100
  "mcp server start": ["memo mcp server start --public-url https://laptop.example.ts.net"],
4607
5101
  "mcp server status": ["memo mcp server status --json"],
4608
5102
  "mcp server stop": ["memo mcp server stop"],
4609
- "search all": ["memo search all 'budget harbour'", "memo search all 'content:invoice' --only mail,notes --json"],
5103
+ "search all": [
5104
+ "memo search all 'budget harbour'",
5105
+ "memo search all 'content:invoice' --only mail,notes --json",
5106
+ "memo search all 'Rental agreement' --only business"
5107
+ ],
4610
5108
  "search messages": ["memo search messages 'friday meeting has:voice'"],
4611
5109
  "search mail": ["memo search mail 'mailbox:important budget' --source email:me@example.com"],
4612
5110
  "search notes": ["memo search notes budget notes:2", "memo search notes kickoff --project HRB --json"],
@@ -4706,13 +5204,13 @@ var memoryItem = /* @__PURE__ */ __name(({ body, ...memory }) => ({
4706
5204
  updatedAt: memory.updatedAt
4707
5205
  }), "memoryItem");
4708
5206
  var listMemories = /* @__PURE__ */ __name(async (store, query, limit) => {
4709
- const terms = queryTerms(query, MEMORY_QUERY, "memories list");
4710
- const project = terms.get("project");
5207
+ const terms2 = queryTerms(query, MEMORY_QUERY, "memories list");
5208
+ const project = terms2.get("project");
4711
5209
  const filters = {
4712
- ...terms.has("kind") ? { kind: terms.get("kind") } : {},
4713
- ...terms.has("status") ? { status: terms.get("status") } : {},
4714
- ...terms.has("scope") ? { scope: terms.get("scope") } : {},
4715
- ...terms.has("subject") ? { subject: terms.get("subject") } : {},
5210
+ ...terms2.has("kind") ? { kind: terms2.get("kind") } : {},
5211
+ ...terms2.has("status") ? { status: terms2.get("status") } : {},
5212
+ ...terms2.has("scope") ? { scope: terms2.get("scope") } : {},
5213
+ ...terms2.has("subject") ? { subject: terms2.get("subject") } : {},
4716
5214
  ...project === void 0 ? {} : { project: await canonicalProject(store, project) }
4717
5215
  };
4718
5216
  return pageOf("memories list", limit, async (most) => (await store.memories.list({ ...filters, limit: most })).map(memoryItem));
@@ -4766,7 +5264,7 @@ var memoriesCommand = /* @__PURE__ */ __name((program, streams, env) => {
4766
5264
  ...options.supersedes === void 0 ? {} : { supersedes: options.supersedes }
4767
5265
  }, await by))));
4768
5266
  });
4769
- 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: json7, limit }) => run(json7, (store) => listMemories(store, words, limit)));
5267
+ 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)));
4770
5268
  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({
4771
5269
  ...memoryItem(await store.memories.get(ref)),
4772
5270
  ...options.sources ? { sources: await store.memories.sources(ref) } : {}
@@ -4836,13 +5334,13 @@ var factItem = /* @__PURE__ */ __name(({ type, statement, source, confirmedBy, .
4836
5334
  confirmed_by: confirmedBy
4837
5335
  }), "factItem");
4838
5336
  var listFacts = /* @__PURE__ */ __name(async (store, query, limit) => {
4839
- const terms = queryTerms(query, FACT_QUERY, "facts list");
4840
- const project = terms.get("project");
5337
+ const terms2 = queryTerms(query, FACT_QUERY, "facts list");
5338
+ const project = terms2.get("project");
4841
5339
  const filters = {
4842
- ...terms.has("kind") ? { type: terms.get("kind") } : {},
4843
- ...terms.has("status") ? { status: terms.get("status") } : {},
5340
+ ...terms2.has("kind") ? { type: terms2.get("kind") } : {},
5341
+ ...terms2.has("status") ? { status: terms2.get("status") } : {},
4844
5342
  ...project === void 0 ? {} : { project: await canonicalProject(store, project) },
4845
- ...terms.has("subject") ? { subject: terms.get("subject") } : {}
5343
+ ...terms2.has("subject") ? { subject: terms2.get("subject") } : {}
4846
5344
  };
4847
5345
  return pageOf("facts list", limit, async (most) => (await store.facts.list({ ...filters, limit: most })).map(factItem));
4848
5346
  }, "listFacts");
@@ -4884,7 +5382,7 @@ var factsCommand = /* @__PURE__ */ __name((program, streams, env) => {
4884
5382
  ...options.supersedes === void 0 ? {} : { supersedes: options.supersedes }
4885
5383
  }))));
4886
5384
  });
4887
- 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: json7, limit }) => run(json7, (store) => listFacts(store, words, limit)));
5385
+ 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)));
4888
5386
  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({
4889
5387
  ...factItem(await store.facts.get(ref)),
4890
5388
  ...options.sources ? { sources: await store.facts.sources(ref) } : {}
@@ -4914,6 +5412,67 @@ var factsCommand = /* @__PURE__ */ __name((program, streams, env) => {
4914
5412
  ${FORGET_HELP.replace("use invalidate", "use reject or reverse")}`);
4915
5413
  }, "factsCommand");
4916
5414
 
5415
+ // dist/records/sources.js
5416
+ var MOST = 100;
5417
+ var READS = {
5418
+ product: /* @__PURE__ */ __name((store, ref) => store.products.get(ref), "product"),
5419
+ contract: /* @__PURE__ */ __name((store, ref) => store.contracts.get(ref), "contract"),
5420
+ subscription: /* @__PURE__ */ __name((store, ref) => store.subscriptions.get(ref), "subscription"),
5421
+ wallet: /* @__PURE__ */ __name((store, ref) => store.wallets.get(ref), "wallet"),
5422
+ transaction: /* @__PURE__ */ __name((store, ref) => store.transactions.get(ref), "transaction"),
5423
+ invoice: /* @__PURE__ */ __name((store, ref) => store.finance.invoice(ref), "invoice"),
5424
+ payment: /* @__PURE__ */ __name((store, ref) => store.finance.payment(ref), "payment"),
5425
+ order: /* @__PURE__ */ __name((store, ref) => store.orders.get(ref), "order"),
5426
+ deal: /* @__PURE__ */ __name((store, ref) => store.deals.get(ref), "deal"),
5427
+ lead: /* @__PURE__ */ __name((store, ref) => store.deals.get(ref), "lead"),
5428
+ pipeline: /* @__PURE__ */ __name((store, ref) => store.deals.pipeline(ref), "pipeline")
5429
+ };
5430
+ var SOURCED = new Set(Object.keys(READS));
5431
+ var readSourced = /* @__PURE__ */ __name((store, kind, ref) => READS[kind]?.(store, ref), "readSourced");
5432
+ var IMPORT = "import:";
5433
+ var imported = /* @__PURE__ */ __name(({ source, account: account2 }) => (account2 ?? null) !== null || !!source?.startsWith(IMPORT), "imported");
5434
+ var sourceAccounts = /* @__PURE__ */ __name(async (store, { source, account: account2 }) => {
5435
+ if (account2)
5436
+ return [account2];
5437
+ if (!source?.startsWith(IMPORT))
5438
+ return [];
5439
+ const provider = source.slice(IMPORT.length);
5440
+ return (await store.accounts.accounts()).filter((key) => key.provider === provider);
5441
+ }, "sourceAccounts");
5442
+ var named2 = /* @__PURE__ */ __name((key) => ({
5443
+ record: `${key.type}:${key.externalId}`,
5444
+ account: `${key.provider}:${key.account}`
5445
+ }), "named");
5446
+ var sourcesOf = /* @__PURE__ */ __name(async (store, entity) => {
5447
+ const { ref } = entity;
5448
+ const records = [];
5449
+ for (const { provider, account: account2 } of await sourceAccounts(store, entity)) {
5450
+ if (records.length > MOST)
5451
+ break;
5452
+ for (const one2 of await store.records.list({ provider, account: account2, entity: ref, limit: MOST + 1 }))
5453
+ records.push({
5454
+ ...named2(one2),
5455
+ ...one2.flagged ? { flagged: true } : {},
5456
+ ...one2.deletedAt === null ? {} : { deleted: true }
5457
+ });
5458
+ }
5459
+ const incoming = await store.records.incoming({ entity: ref }, { limit: MOST + 1 });
5460
+ return {
5461
+ records: { items: records.slice(0, MOST), hasMore: records.length > MOST },
5462
+ incoming: {
5463
+ items: incoming.slice(0, MOST).map(({ record: record2, role, as }) => ({ ...named2(record2), role, as })),
5464
+ hasMore: incoming.length > MOST
5465
+ }
5466
+ };
5467
+ }, "sourcesOf");
5468
+ var sourcesText = /* @__PURE__ */ __name((ref, { records, incoming }, indent = " ") => [
5469
+ ...records.items.map((one2) => `${indent}from ${one2.account} ${one2.record}${one2.flagged ? " (flagged)" : ""}${one2.deleted ? " (deleted)" : ""}`),
5470
+ ...incoming.items.map((one2) => `${indent}named by ${one2.account} ${one2.record} as ${one2.role}${one2.as === null ? "" : ` (${one2.as})`}`),
5471
+ ...records.hasMore || incoming.hasMore ? [`${indent}more: memo records list entity:${ref} --account <account>`] : []
5472
+ ], "sourcesText");
5473
+ var recordsHidden = /* @__PURE__ */ __name((command) => grantedLevel(command, "records.show") === "deny", "recordsHidden");
5474
+ var withSources = /* @__PURE__ */ __name(async (command, store, item) => recordsHidden(command) ? item : { ...item, sources: await sourcesOf(store, item) }, "withSources");
5475
+
4917
5476
  // dist/finance/finance.js
4918
5477
  var INVOICE_QUERY = {
4919
5478
  entity: "invoice",
@@ -4941,25 +5500,25 @@ var PAYMENT_QUERY = {
4941
5500
  var projectTerm = /* @__PURE__ */ __name(async (store, project) => project === void 0 ? {} : { project: await canonicalProject(store, project) }, "projectTerm");
4942
5501
  var reviewTerm = /* @__PURE__ */ __name((review) => review === void 0 ? {} : { review }, "reviewTerm");
4943
5502
  var listInvoices = /* @__PURE__ */ __name(async (store, words, limit) => {
4944
- const terms = queryTerms(words, INVOICE_QUERY, "invoices list");
5503
+ const terms2 = queryTerms(words, INVOICE_QUERY, "invoices list");
4945
5504
  const filter = {
4946
- ...await projectTerm(store, terms.get("project")),
4947
- ...reviewTerm(terms.get("review")),
4948
- ...terms.has("direction") ? { direction: terms.get("direction") } : {},
4949
- ...terms.has("status") ? { status: terms.get("status") } : {},
4950
- ...terms.has("counterparty") ? { counterparty: terms.get("counterparty") } : {},
4951
- ...terms.has("number") ? { number: terms.get("number") } : {},
4952
- ...terms.has("open") ? { open: terms.get("open") === "true" } : {}
5505
+ ...await projectTerm(store, terms2.get("project")),
5506
+ ...reviewTerm(terms2.get("review")),
5507
+ ...terms2.has("direction") ? { direction: terms2.get("direction") } : {},
5508
+ ...terms2.has("status") ? { status: terms2.get("status") } : {},
5509
+ ...terms2.has("counterparty") ? { counterparty: terms2.get("counterparty") } : {},
5510
+ ...terms2.has("number") ? { number: terms2.get("number") } : {},
5511
+ ...terms2.has("open") ? { open: terms2.get("open") === "true" } : {}
4953
5512
  };
4954
5513
  return pageOf("invoices list", limit, (most) => store.finance.invoices({ ...filter, limit: most }));
4955
5514
  }, "listInvoices");
4956
5515
  var listPayments = /* @__PURE__ */ __name(async (store, words, limit) => {
4957
- const terms = queryTerms(words, PAYMENT_QUERY, "payments list");
5516
+ const terms2 = queryTerms(words, PAYMENT_QUERY, "payments list");
4958
5517
  const filter = {
4959
- ...await projectTerm(store, terms.get("project")),
4960
- ...reviewTerm(terms.get("review")),
4961
- ...terms.has("direction") ? { direction: terms.get("direction") } : {},
4962
- ...terms.has("party") ? { party: terms.get("party") } : {}
5518
+ ...await projectTerm(store, terms2.get("project")),
5519
+ ...reviewTerm(terms2.get("review")),
5520
+ ...terms2.has("direction") ? { direction: terms2.get("direction") } : {},
5521
+ ...terms2.has("party") ? { party: terms2.get("party") } : {}
4963
5522
  };
4964
5523
  return pageOf("payments list", limit, (most) => store.finance.payments({ ...filter, limit: most }));
4965
5524
  }, "listPayments");
@@ -5029,14 +5588,21 @@ var financeText = /* @__PURE__ */ __name((block) => block.length === 0 ? [] : [
5029
5588
  })
5030
5589
  ], "financeText");
5031
5590
 
5032
- // dist/finance/command.js
5033
- var json = /* @__PURE__ */ __name((command) => command.option("--json", "print JSON; --json=ref,title keeps only those fields"), "json");
5591
+ // dist/finance/written.js
5592
+ var json = /* @__PURE__ */ __name((command) => jsonOption(command), "json");
5034
5593
  var PROPOSES = "yours is confirmed at once; an agent's waits as proposed for you in memo review";
5035
- var kindOf2 = /* @__PURE__ */ __name((kind, kinds2) => {
5036
- if (kind === void 0 || !kinds2.includes(kind))
5037
- throw new CliError("validation_error", `--kind is one of ${kinds2.join(", ")}`, { param: "--kind" });
5038
- return kind;
5039
- }, "kindOf");
5594
+ var choice = /* @__PURE__ */ __name((value, allowed, flag) => {
5595
+ if (value === void 0 || !allowed.includes(value))
5596
+ throw new CliError("validation_error", `${flag} is one of ${allowed.join(", ")}`, { param: flag });
5597
+ return value;
5598
+ }, "choice");
5599
+ var needed = /* @__PURE__ */ __name((value, flag, what) => {
5600
+ if (value === void 0 || value.trim() === "")
5601
+ throw new CliError("validation_error", `name ${what}: ${flag}`, { param: flag });
5602
+ return value;
5603
+ }, "needed");
5604
+ var optionalChoice = /* @__PURE__ */ __name((value, allowed, flag) => value === void 0 ? void 0 : choice(value, allowed, flag), "optionalChoice");
5605
+ var onOff = /* @__PURE__ */ __name((value, flag) => value === void 0 ? void 0 : choice(value, ["on", "off"], flag) === "on", "onOff");
5040
5606
  var writtenBy = /* @__PURE__ */ __name(async (store, by, options) => ({
5041
5607
  by,
5042
5608
  ...options.project === void 0 ? {} : { project: await canonicalProject(store, options.project) },
@@ -5045,23 +5611,71 @@ var writtenBy = /* @__PURE__ */ __name(async (store, by, options) => ({
5045
5611
  }), "writtenBy");
5046
5612
  var party = /* @__PURE__ */ __name((command, what) => command.option("--person <uid>", `the person ${what}: person:<id>`).option("--organization <organization>", `the organization ${what}: organization:<id>`), "party");
5047
5613
  var writeMeta = /* @__PURE__ */ __name((command) => byOption(command.option("--project <project>", "the project it belongs to: its key or project:<id>").option("--reason <text>", "why an agent proposes it, for the owner who decides").option("--evidence <ref...>", "what shows it, up to 8: msg:, note:, document: or another reference")), "writeMeta");
5614
+ var given = /* @__PURE__ */ __name((fields) => Object.fromEntries(Object.entries(fields).filter(([, value]) => value !== void 0)), "given");
5615
+
5616
+ // dist/finance/lines-command.js
5617
+ var LINE_PARENTS = {
5618
+ order: {
5619
+ has: "an order that has a currency (orders add with an amount)",
5620
+ shown: "orders show",
5621
+ add: /* @__PURE__ */ __name((store, ref, line3) => store.orders.addLine(ref, line3), "add"),
5622
+ remove: /* @__PURE__ */ __name((store, ref, input) => store.orders.removeLine(ref, input), "remove")
5623
+ },
5624
+ invoice: {
5625
+ has: "an invoice that is not void; the total never falls below what confirmed payments settled",
5626
+ shown: "invoices show",
5627
+ add: /* @__PURE__ */ __name((store, ref, line3) => store.finance.addInvoiceLine(ref, line3), "add"),
5628
+ remove: /* @__PURE__ */ __name((store, ref, input) => store.finance.removeInvoiceLine(ref, input), "remove")
5629
+ }
5630
+ };
5631
+ var lineCommands = /* @__PURE__ */ __name((parent, kind, run, env) => {
5632
+ const { has, shown: shown2, add, remove } = LINE_PARENTS[kind];
5633
+ const one2 = kind === "order" ? "an order" : "an invoice";
5634
+ const who = `you change any ${kind}'s lines; an agent only those of ${one2} it proposed that is still proposed`;
5635
+ const lines2 = parent.command("lines").description(`the lines of ${one2}, each a quantity at a price; its total is their sum. ${who}`).summary(`the lines of ${one2}`);
5636
+ const asker = /* @__PURE__ */ __name((ref) => `change ${ref}'s lines as yours?`, "asker");
5637
+ json(byOption(annotate(lines2.command("add"), {
5638
+ effects: LOCAL_WRITE,
5639
+ output: { entity: kind },
5640
+ literal_after_dashes: true
5641
+ }).option("--product <product>", "the product or service it is: its name and price are copied onto the line").option("--amount <decimal>", "the price of one, such as 10000.00; the product's when left out with --product"))).description(`add a line at the end of ${has}: quantity \xD7 price, and the total becomes the sum of the lines. With --product its name and price are copied, so a later price change leaves the line as it is, and --amount sets another price; without --product, --amount is needed. ${who}`).summary(`add a line to ${one2}`).argument(`<${kind}>`, `${kind}:<id>`).argument("<quantity>", "how many, a decimal such as 12 or 1.5").argument("[description...]", "what the line is, in a few words; the product's name when left out").action(async (ref, quantity, words, options, command) => {
5642
+ if (options.product === void 0)
5643
+ needed(options.amount, "--amount", "the price of one, or --product");
5644
+ const by = await whoRuns(command, env, { asOwner: options.asOwner, question: asker(ref) });
5645
+ await run(options.json, async (store) => itemAnswer(await add(store, ref, {
5646
+ by,
5647
+ quantity,
5648
+ ...given({
5649
+ unitPrice: options.amount,
5650
+ description: words.length > 0 ? words.join(" ") : void 0,
5651
+ product: options.product
5652
+ })
5653
+ })));
5654
+ });
5655
+ json(byOption(annotate(lines2.command("remove"), { effects: LOCAL_WRITE, output: { entity: kind } }))).description(`take a line off ${one2}; the others keep their positions, and the last line stays. ${who}`).summary(`take a line off ${one2}`).argument(`<${kind}>`, `${kind}:<id>`).argument("<position>", `the line's position, from 1, as ${shown2} lists it`, positive).action(async (ref, position, options, command) => {
5656
+ const by = await whoRuns(command, env, { asOwner: options.asOwner, question: asker(ref) });
5657
+ await run(options.json, async (store) => itemAnswer(await remove(store, ref, { position, by })));
5658
+ });
5659
+ }, "lineCommands");
5660
+
5661
+ // dist/finance/command.js
5048
5662
  var financeCommands = /* @__PURE__ */ __name((program, streams, env) => {
5049
5663
  const { run } = answers(program, streams, env);
5050
5664
  const invoices = program.command("invoices").description("invoices you issued or received, with their lines and what paid them; amounts per currency").summary("invoices you issued or received, and what paid them");
5051
- withQuery(json(annotate(invoices.command("list"), { effects: LOCAL_READ })).description("invoices, newest first; review:proposed lists what waits for you"), INVOICE_QUERY).option("--limit <n>", "most invoices, up to 500", positive, 100).action((words, { json: json7, limit }) => run(json7, (store) => listInvoices(store, words, limit)));
5052
- json(annotate(invoices.command("show"), { effects: LOCAL_READ, output: { entity: "invoice" } })).description("one invoice with its lines and the payments allocated to it").argument("<ref>", "invoice:<id>").action((ref, options) => run(options.json, async (store) => itemAnswer(await store.finance.invoice(ref))));
5665
+ withQuery(json(annotate(invoices.command("list"), { effects: LOCAL_READ })).description("invoices, newest first; review:proposed lists what waits for you"), INVOICE_QUERY).option("--limit <n>", "most invoices, up to 500", positive, 100).action((words, { json: json5, limit }) => run(json5, (store) => listInvoices(store, words, limit)));
5666
+ json(annotate(invoices.command("show"), { effects: LOCAL_READ, output: { entity: "invoice" } })).description("one invoice with its lines and the payments allocated to it").argument("<ref>", "invoice:<id>").action((ref, options, command) => run(options.json, async (store) => itemAnswer(await withSources(command, store, await store.finance.invoice(ref)))));
5053
5667
  json(writeMeta(party(annotate(invoices.command("add"), {
5054
5668
  effects: LOCAL_WRITE,
5055
5669
  output: { entity: "invoice" },
5056
5670
  literal_after_dashes: true
5057
- }), "billed or billing").option("--kind <kind>", "receivable (you bill them) or payable (they bill you)").option("--title <title>", "the invoice's number, as printed on it").option("--occurred-time <time>", "the day it was issued, such as 2026-11-01").option("--due <time>", "the day it is due, such as 2026-11-15"))).description(`record an invoice of one line; ${PROPOSES}`).summary("record an invoice; an agent's waits for your review").argument("<amount>", "a decimal, such as 50000.00").argument("<currency>", "ISO 4217, such as RUB").argument("<description...>", "what it bills, in a few words").action(async (amount2, currency, words, options, command) => {
5671
+ }), "billed or billing").option("--kind <kind>", "receivable (you bill them) or payable (they bill you)").option("--title <title>", "the invoice's number, as printed on it").option("--occurred-time <time>", "the day it was issued, such as 2026-11-01").option("--due <time>", "the day it is due, such as 2026-11-15"))).description(`record an invoice of one line, and add more with invoices lines add; ${PROPOSES}`).summary("record an invoice; an agent's waits for your review").argument("<amount>", "a decimal, such as 50000.00").argument("<currency>", "ISO 4217, such as RUB").argument("<description...>", "what it bills, in a few words").action(async (amount2, currency, words, options, command) => {
5058
5672
  const by = await whoRuns(command, env, { asOwner: options.asOwner, question: "record this invoice as yours?" });
5059
5673
  await run(options.json, async (store) => {
5060
5674
  const issueDate = dayOf(options.occurredTime);
5061
5675
  const dueDate = dayOf(options.due);
5062
5676
  return itemAnswer(await store.finance.addInvoice({
5063
5677
  ...await writtenBy(store, by, options),
5064
- direction: kindOf2(options.kind, INVOICE_DIRECTIONS),
5678
+ direction: choice(options.kind, INVOICE_DIRECTIONS, "--kind"),
5065
5679
  counterparty: partyOf(options, true),
5066
5680
  currency,
5067
5681
  lines: [{ description: words.join(" "), amount: amount2 }],
@@ -5071,13 +5685,14 @@ var financeCommands = /* @__PURE__ */ __name((program, streams, env) => {
5071
5685
  }));
5072
5686
  });
5073
5687
  });
5688
+ lineCommands(invoices, "invoice", run, env);
5074
5689
  const payments = program.command("payments").description("money paid to you or by you, and the invoices each payment settles; amounts per currency").summary("money paid to you or by you, and what it settles");
5075
- withQuery(json(annotate(payments.command("list"), { effects: LOCAL_READ })).description("payments, newest first; review:proposed lists what waits for you"), PAYMENT_QUERY).option("--limit <n>", "most payments, up to 500", positive, 100).action((words, { json: json7, limit }) => run(json7, (store) => listPayments(store, words, limit)));
5076
- json(annotate(payments.command("show"), { effects: LOCAL_READ, output: { entity: "payment" } })).description("one payment with the invoices it is allocated to").argument("<ref>", "payment:<id>").action((ref, options) => run(options.json, async (store) => itemAnswer(await store.finance.payment(ref))));
5077
- json(writeMeta(party(annotate(payments.command("add"), { effects: LOCAL_WRITE, output: { entity: "payment" } }), "who paid or was paid").option("--kind <kind>", "in (paid to you) or out (paid by you)").option("--title <title>", "the payment's reference, such as the bank's purpose line").option("--occurred-time <time>", "the day it was paid, such as 2026-11-01; today when left out"))).description(`record a payment; ${PROPOSES}. payments allocate matches it to an invoice`).summary("record a payment; an agent's waits for your review").argument("<amount>", "a decimal, such as 50000.00").argument("<currency>", "ISO 4217, such as RUB").action(async (amount2, currency, options, command) => {
5690
+ withQuery(json(annotate(payments.command("list"), { effects: LOCAL_READ })).description("payments, newest first; review:proposed lists what waits for you"), PAYMENT_QUERY).option("--limit <n>", "most payments, up to 500", positive, 100).action((words, { json: json5, limit }) => run(json5, (store) => listPayments(store, words, limit)));
5691
+ json(annotate(payments.command("show"), { effects: LOCAL_READ, output: { entity: "payment" } })).description("one payment with the invoices it is allocated to").argument("<ref>", "payment:<id>").action((ref, options, command) => run(options.json, async (store) => itemAnswer(await withSources(command, store, await store.finance.payment(ref)))));
5692
+ json(writeMeta(party(annotate(payments.command("add"), { effects: LOCAL_WRITE, output: { entity: "payment" } }), "who paid or was paid").option("--kind <kind>", "in (paid to you) or out (paid by you)").option("--title <title>", "the payment's reference, such as the bank's purpose line").option("--occurred-time <time>", "the day it was paid, such as 2026-11-01; today when left out").option("--refund-of <payment>", "the payment this one gives money back for, going the other way: payment:<id>"))).description(`record a payment, or with --refund-of a refund of one; ${PROPOSES}. payments allocate matches it to an invoice`).summary("record a payment; an agent's waits for your review").argument("<amount>", "a decimal, such as 50000.00").argument("<currency>", "ISO 4217, such as RUB").action(async (amount2, currency, options, command) => {
5078
5693
  const by = await whoRuns(command, env, { asOwner: options.asOwner, question: "record this payment as yours?" });
5079
5694
  await run(options.json, async (store) => {
5080
- const direction = kindOf2(options.kind, MONEY_DIRECTIONS);
5695
+ const direction = choice(options.kind, MONEY_DIRECTIONS, "--kind");
5081
5696
  const counterparty = partyOf(options, false);
5082
5697
  return itemAnswer(await store.finance.addPayment({
5083
5698
  ...await writtenBy(store, by, options),
@@ -5086,7 +5701,8 @@ var financeCommands = /* @__PURE__ */ __name((program, streams, env) => {
5086
5701
  amount: amount2,
5087
5702
  currency,
5088
5703
  date: dayOf(options.occurredTime) ?? today(),
5089
- ...options.title === void 0 ? {} : { reference: options.title }
5704
+ ...options.title === void 0 ? {} : { reference: options.title },
5705
+ ...options.refundOf === void 0 ? {} : { refundOf: options.refundOf }
5090
5706
  }));
5091
5707
  });
5092
5708
  });
@@ -5103,6 +5719,78 @@ var financeCommands = /* @__PURE__ */ __name((program, streams, env) => {
5103
5719
  });
5104
5720
  }, "financeCommands");
5105
5721
 
5722
+ // dist/finance/contracts-command.js
5723
+ var CONTRACT_QUERY = {
5724
+ entity: "contract",
5725
+ backend: "native",
5726
+ fields: [
5727
+ termField("status", "enum", "status:active", { values: CONTRACT_STATUSES }),
5728
+ termField("kind", "enum", "kind:lease", { values: CONTRACT_KINDS }),
5729
+ termField("project", "kw", "project:PMED"),
5730
+ termField("review", "enum", "review:proposed", { values: FINANCE_REVIEWS }),
5731
+ termField("expires", "time", "expires:2026-12-31")
5732
+ ]
5733
+ };
5734
+ var listContracts = /* @__PURE__ */ __name(async (store, words, limit) => {
5735
+ const terms2 = queryTerms(words, CONTRACT_QUERY, "contracts list");
5736
+ const project = terms2.get("project");
5737
+ const filter = given({
5738
+ status: terms2.get("status"),
5739
+ kind: terms2.get("kind"),
5740
+ review: terms2.get("review"),
5741
+ expiresBy: dayOf(terms2.get("expires")),
5742
+ project: project === void 0 ? void 0 : await canonicalProject(store, project)
5743
+ });
5744
+ return pageOf("contracts list", limit, (most) => store.contracts.list({ ...filter, limit: most }));
5745
+ }, "listContracts");
5746
+ var days = /* @__PURE__ */ __name((value) => {
5747
+ const number2 = Number(value);
5748
+ if (!Number.isInteger(number2) || number2 < 0)
5749
+ throw new InvalidArgumentError("a whole number of days, 0 or more");
5750
+ return number2;
5751
+ }, "days");
5752
+ var terms = /* @__PURE__ */ __name((command) => command.option("--kind <kind>", `what it is: ${CONTRACT_KINDS.join(", ")}`).option("--status <state>", `${CONTRACT_STATUSES.join(", ")}; active when left out`).option("--start-date <date>", "the first day it is in force, YYYY-MM-DD").option("--end-date <date>", "the last day it is in force, YYYY-MM-DD; left out, it runs until ended").option("--auto-renew <on|off>", "it renews by itself at its end, or it does not").option("--notice-days <days>", "how many days before its end a party must say it will not go on", days).option("--amount <decimal>", "what it is worth, such as 120000.00, in --currency; with it, an agent's waits for you").option("--currency <code>", "an ISO 4217 code, such as RUB"), "terms");
5753
+ var fieldsOf2 = /* @__PURE__ */ __name((options) => given({
5754
+ status: optionalChoice(options.status, CONTRACT_STATUSES, "--status"),
5755
+ effectiveDate: dayOf(options.startDate),
5756
+ expirationDate: dayOf(options.endDate),
5757
+ autoRenew: onOff(options.autoRenew, "--auto-renew"),
5758
+ noticeDays: options.noticeDays,
5759
+ value: options.amount,
5760
+ currency: options.currency
5761
+ }), "fieldsOf");
5762
+ var VALUED = "one with no amount is written as it is, by anyone; with an amount yours is confirmed at once and an agent's waits as proposed for you in memo review";
5763
+ var contractCommands = /* @__PURE__ */ __name((program, streams, env) => {
5764
+ const { run } = answers(program, streams, env);
5765
+ const contracts = program.command("contracts").description("contracts you work under: their kind, dates, renewal, notice and what they are worth").summary("contracts you work under, with their dates and notice");
5766
+ withQuery(json(annotate(contracts.command("list"), { effects: LOCAL_READ })).description("contracts, newest first; expires:2026-12-31 lists those that end by then"), CONTRACT_QUERY).option("--limit <n>", "most contracts, up to 500", positive, 100).action((words, { json: json5, limit }) => run(json5, (store) => listContracts(store, words, limit)));
5767
+ json(annotate(contracts.command("show"), { effects: LOCAL_READ, output: { entity: "contract" } })).description("one contract with its dates, renewal and the last day to give notice").argument("<contract>", "contract:<id>").action((ref, options, command) => run(options.json, async (store) => itemAnswer(await withSources(command, store, await store.contracts.get(ref)))));
5768
+ json(writeMeta(terms(annotate(contracts.command("add"), {
5769
+ effects: LOCAL_WRITE,
5770
+ output: { entity: "contract" },
5771
+ literal_after_dashes: true
5772
+ })))).description(`record a contract; ${VALUED}`).summary("record a contract").argument("<name>", "what it is called, such as 'Rental agreement'").action(async (name2, options, command) => {
5773
+ const by = await whoRuns(command, env, { asOwner: options.asOwner, question: "record this contract as yours?" });
5774
+ await run(options.json, async (store) => itemAnswer(await store.contracts.add({
5775
+ ...await writtenBy(store, by, options),
5776
+ name: name2,
5777
+ kind: choice(options.kind, CONTRACT_KINDS, "--kind"),
5778
+ ...fieldsOf2(options)
5779
+ })));
5780
+ });
5781
+ json(byOption(terms(annotate(contracts.command("update"), { effects: LOCAL_WRITE, output: { entity: "contract" } })).option("--title <title>", "its new name"))).description("change a contract's dates, status, terms or worth; you change any, an agent only one it proposed that is still proposed, and a confirmed contract's worth only you").summary("change a contract").argument("<contract>", "contract:<id>").action(async (ref, options, command) => {
5782
+ const by = await whoRuns(command, env, { asOwner: options.asOwner, question: `change ${ref} as yours?` });
5783
+ await run(options.json, async (store) => itemAnswer(await store.contracts.update(ref, {
5784
+ by,
5785
+ ...fieldsOf2(options),
5786
+ ...given({
5787
+ name: options.title,
5788
+ kind: optionalChoice(options.kind, CONTRACT_KINDS, "--kind")
5789
+ })
5790
+ })));
5791
+ });
5792
+ }, "contractCommands");
5793
+
5106
5794
  // dist/finance/deals-command.js
5107
5795
  var queryOf = /* @__PURE__ */ __name((entity) => ({
5108
5796
  entity,
@@ -5123,14 +5811,14 @@ var PIPELINE_QUERY = {
5123
5811
  };
5124
5812
  var listDeals = /* @__PURE__ */ __name(async (store, kind, words, limit) => {
5125
5813
  const command = `${kind}s list`;
5126
- const terms = queryTerms(words, QUERIES[kind], command);
5814
+ const terms2 = queryTerms(words, QUERIES[kind], command);
5127
5815
  const filter = {
5128
5816
  kind,
5129
- ...terms.has("project") ? { project: await canonicalProject(store, terms.get("project")) } : {},
5130
- ...terms.has("status") ? { status: terms.get("status") } : {},
5131
- ...terms.has("stage") ? { stage: terms.get("stage") } : {},
5132
- ...terms.has("pipeline") ? { pipeline: terms.get("pipeline") } : {},
5133
- ...terms.has("organization") ? { organization: terms.get("organization") } : {}
5817
+ ...terms2.has("project") ? { project: await canonicalProject(store, terms2.get("project")) } : {},
5818
+ ...terms2.has("status") ? { status: terms2.get("status") } : {},
5819
+ ...terms2.has("stage") ? { stage: terms2.get("stage") } : {},
5820
+ ...terms2.has("pipeline") ? { pipeline: terms2.get("pipeline") } : {},
5821
+ ...terms2.has("organization") ? { organization: terms2.get("organization") } : {}
5134
5822
  };
5135
5823
  return pageOf(command, limit, (most) => store.deals.list({ ...filter, limit: most }));
5136
5824
  }, "listDeals");
@@ -5147,7 +5835,6 @@ var stageOf = /* @__PURE__ */ __name((stage) => {
5147
5835
  const at = stage.lastIndexOf("/");
5148
5836
  return at <= 0 ? { stage } : { pipeline: stage.slice(0, at), stage: stage.slice(at + 1) };
5149
5837
  }, "stageOf");
5150
- var json2 = /* @__PURE__ */ __name((command) => command.option("--json", "print JSON; --json=ref,title keeps only those fields"), "json");
5151
5838
  var WHAT = {
5152
5839
  deal: { one: "deal", hope: "what you hope to sell, such as 'Site for the clinic'" },
5153
5840
  lead: { one: "lead", hope: "who or what came in, such as 'Call from the site'" }
@@ -5155,9 +5842,9 @@ var WHAT = {
5155
5842
  var itemCommands = /* @__PURE__ */ __name((program, kind, run, env) => {
5156
5843
  const { one: one2, hope } = WHAT[kind];
5157
5844
  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");
5158
- withQuery(json2(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: json7, limit }) => run(json7, (store) => listDeals(store, kind, words, limit)));
5159
- json2(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) => run(options.json, async (store) => itemAnswer(await store.deals.get(ref))));
5160
- json2(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) => {
5845
+ 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)));
5846
+ 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)))));
5847
+ 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) => {
5161
5848
  const by = authorOf(env);
5162
5849
  const role = roleOf(options.role);
5163
5850
  await run(options.json, async (store) => {
@@ -5178,11 +5865,11 @@ var itemCommands = /* @__PURE__ */ __name((program, kind, run, env) => {
5178
5865
  }));
5179
5866
  });
5180
5867
  });
5181
- json2(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) => {
5868
+ 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) => {
5182
5869
  const by = authorOf(env);
5183
5870
  await run(options.json, async (store) => itemAnswer(await store.deals.move(ref, { stage, by })));
5184
5871
  });
5185
- json2(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) => {
5872
+ 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) => {
5186
5873
  if (outcome !== "won" && outcome !== "lost")
5187
5874
  throw new CliError("validation_error", `a ${one2} closes as won or lost`, { param: "outcome" });
5188
5875
  const by = authorOf(env);
@@ -5204,19 +5891,19 @@ var funnelText = /* @__PURE__ */ __name((report) => [
5204
5891
  var dealCommands = /* @__PURE__ */ __name((program, streams, env) => {
5205
5892
  const { run, print } = answers(program, streams, env);
5206
5893
  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");
5207
- withQuery(json2(annotate(pipelines.command("list"), { effects: LOCAL_READ })).description("every pipeline with its stages in order and how many open deals or leads stand in each"), PIPELINE_QUERY).summary("every pipeline with its stages").action((words, options) => run(options.json, async (store) => {
5208
- const terms = queryTerms(words, PIPELINE_QUERY, "pipelines list");
5209
- const name2 = terms.get("name")?.toLocaleLowerCase();
5210
- const kind = terms.get("kind");
5894
+ withQuery(json(annotate(pipelines.command("list"), { effects: LOCAL_READ })).description("every pipeline with its stages in order and how many open deals or leads stand in each"), PIPELINE_QUERY).summary("every pipeline with its stages").action((words, options) => run(options.json, async (store) => {
5895
+ const terms2 = queryTerms(words, PIPELINE_QUERY, "pipelines list");
5896
+ const name2 = terms2.get("name")?.toLocaleLowerCase();
5897
+ const kind = terms2.get("kind");
5211
5898
  const all = await store.deals.pipelines(kind === void 0 ? {} : { kind });
5212
5899
  return wholeList("pipelines list", name2 === void 0 ? all : all.filter((one2) => one2.name.toLocaleLowerCase() === name2));
5213
5900
  }));
5214
- json2(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) => {
5901
+ 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) => {
5215
5902
  const since = dayOf(options.sinceTime);
5216
- const report = await withStore(env, (store) => store.deals.pipeline(pipeline, since === void 0 ? {} : { since }));
5903
+ const report = await withStore(env, async (store) => withSources(command, store, await store.deals.pipeline(pipeline, since === void 0 ? {} : { since })));
5217
5904
  print(options.json, itemAnswer(report), funnelText(report));
5218
5905
  });
5219
- json2(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) => {
5906
+ 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) => {
5220
5907
  const kind = options.kind ?? "deal";
5221
5908
  if (!DEAL_KINDS.includes(kind))
5222
5909
  throw new CliError("validation_error", "--kind is deal or lead", { param: "--kind" });
@@ -5275,15 +5962,15 @@ var ORDER_QUERY = {
5275
5962
  ]
5276
5963
  };
5277
5964
  var listOrders = /* @__PURE__ */ __name(async (store, words, limit) => {
5278
- const terms = queryTerms(words, ORDER_QUERY, "orders list");
5965
+ const terms2 = queryTerms(words, ORDER_QUERY, "orders list");
5279
5966
  const filter = {
5280
- ...terms.has("project") ? { project: await canonicalProject(store, terms.get("project")) } : {},
5281
- ...terms.has("status") ? { status: terms.get("status") } : {},
5282
- ...terms.has("purpose") ? { purpose: terms.get("purpose") } : {},
5283
- ...terms.has("review") ? { review: terms.get("review") } : {},
5284
- ...terms.has("customer") ? { customer: terms.get("customer") } : {},
5285
- ...terms.has("supplier") ? { supplierName: terms.get("supplier") } : {},
5286
- ...terms.has("number") ? { number: terms.get("number") } : {}
5967
+ ...terms2.has("project") ? { project: await canonicalProject(store, terms2.get("project")) } : {},
5968
+ ...terms2.has("status") ? { status: terms2.get("status") } : {},
5969
+ ...terms2.has("purpose") ? { purpose: terms2.get("purpose") } : {},
5970
+ ...terms2.has("review") ? { review: terms2.get("review") } : {},
5971
+ ...terms2.has("customer") ? { customer: terms2.get("customer") } : {},
5972
+ ...terms2.has("supplier") ? { supplierName: terms2.get("supplier") } : {},
5973
+ ...terms2.has("number") ? { number: terms2.get("number") } : {}
5287
5974
  };
5288
5975
  return pageOf("orders list", limit, (most) => store.orders.list({ ...filter, limit: most }));
5289
5976
  }, "listOrders");
@@ -5292,13 +5979,12 @@ var oneOf2 = /* @__PURE__ */ __name((value, allowed, flag) => {
5292
5979
  throw new CliError("validation_error", `${flag} is one of ${allowed.join(", ")}`, { param: flag });
5293
5980
  return value;
5294
5981
  }, "oneOf");
5295
- var json3 = /* @__PURE__ */ __name((command) => command.option("--json", "print JSON; --json=ref,title keeps only those fields"), "json");
5296
5982
  var orderCommands = /* @__PURE__ */ __name((program, streams, env) => {
5297
5983
  const { run } = answers(program, streams, env);
5298
5984
  const orders = program.command("orders").description("orders you placed or took, for whom, from which shop, and how far delivery got").summary("orders you placed or took, and how far delivery got");
5299
- withQuery(json3(annotate(orders.command("list"), { effects: LOCAL_READ })).description("orders, newest first; review:proposed is what waits for you"), ORDER_QUERY).option("--limit <n>", "most orders, up to 500", positive, 100).action((words, { json: json7, limit }) => run(json7, (store) => listOrders(store, words, limit)));
5300
- json3(annotate(orders.command("show"), { effects: LOCAL_READ, output: { entity: "order" } })).description("one order with its customer, shop, amount, status and the mail it was read from").argument("<ref>", "order:<id>").action((ref, options) => run(options.json, async (store) => itemAnswer(await store.orders.get(ref))));
5301
- json3(byOption(annotate(orders.command("add"), { effects: LOCAL_WRITE, output: { entity: "order" }, literal_after_dashes: true }).option("--kind <kind>", `why it was ordered: ${ORDER_PURPOSES.join(", ")}`).option("--person <uid>", "whom it is for, when not you: person:<id>").option("--organization <organization>", "whom it is for, when not you: organization:<id>").option("--title <title>", "the shop's order number").option("--occurred-time <time>", "the day it was ordered, such as 2026-11-01").option("--project <project>", "the project it belongs to: its key or project:<id>").option("--reason <text>", "why an agent proposes it, for the owner who decides").option("--evidence <ref...>", "what shows it, up to 8: msg:, note:, document: or another reference"))).description("record a placed order; yours is confirmed at once, an agent's waits as proposed for you in memo review").summary("record an order; an agent's waits for your review").argument("<shop>", "the shop or supplier, as its mail names it").argument("[amount]", "the order's amount, a decimal such as 2499.00").argument("[currency]", "ISO 4217, such as RUB; given with the amount").action(async (shop, amount2, currency, options, command) => {
5985
+ withQuery(json(annotate(orders.command("list"), { effects: LOCAL_READ })).description("orders, newest first; review:proposed is what waits for you"), ORDER_QUERY).option("--limit <n>", "most orders, up to 500", positive, 100).action((words, { json: json5, limit }) => run(json5, (store) => listOrders(store, words, limit)));
5986
+ json(annotate(orders.command("show"), { effects: LOCAL_READ, output: { entity: "order" } })).description("one order with its customer, shop, amount, status and the mail it was read from").argument("<ref>", "order:<id>").action((ref, options, command) => run(options.json, async (store) => itemAnswer(await withSources(command, store, await store.orders.get(ref)))));
5987
+ json(byOption(annotate(orders.command("add"), { effects: LOCAL_WRITE, output: { entity: "order" }, literal_after_dashes: true }).option("--kind <kind>", `why it was ordered: ${ORDER_PURPOSES.join(", ")}`).option("--person <uid>", "whom it is for, when not you: person:<id>").option("--organization <organization>", "whom it is for, when not you: organization:<id>").option("--title <title>", "the shop's order number").option("--occurred-time <time>", "the day it was ordered, such as 2026-11-01").option("--project <project>", "the project it belongs to: its key or project:<id>").option("--reason <text>", "why an agent proposes it, for the owner who decides").option("--evidence <ref...>", "what shows it, up to 8: msg:, note:, document: or another reference"))).description("record a placed order; yours is confirmed at once, an agent's waits as proposed for you in memo review").summary("record an order; an agent's waits for your review").argument("<shop>", "the shop or supplier, as its mail names it").argument("[amount]", "the order's amount, a decimal such as 2499.00").argument("[currency]", "ISO 4217, such as RUB; given with the amount").action(async (shop, amount2, currency, options, command) => {
5302
5988
  const by = await whoRuns(command, env, { asOwner: options.asOwner, question: "record this order as yours?" });
5303
5989
  await run(options.json, async (store) => {
5304
5990
  const customer = partyOf(options, false);
@@ -5318,8 +6004,314 @@ var orderCommands = /* @__PURE__ */ __name((program, streams, env) => {
5318
6004
  }));
5319
6005
  });
5320
6006
  });
6007
+ lineCommands(orders, "order", run, env);
5321
6008
  }, "orderCommands");
5322
6009
 
6010
+ // dist/finance/products-command.js
6011
+ var PRODUCT_QUERY = {
6012
+ entity: "product",
6013
+ backend: "native",
6014
+ fields: [
6015
+ termField("kind", "enum", "kind:service", { values: CATALOG_KINDS }),
6016
+ termField("supplier", "ref", 'supplier:"organization:3"'),
6017
+ termField("archived", "bool", "archived:true"),
6018
+ termField("name", "kw", 'name:"Bike rental"')
6019
+ ]
6020
+ };
6021
+ var listProducts = /* @__PURE__ */ __name(async (store, words, limit) => {
6022
+ const terms2 = queryTerms(words, PRODUCT_QUERY, "products list");
6023
+ const filter = given({
6024
+ kind: terms2.get("kind"),
6025
+ supplier: terms2.get("supplier"),
6026
+ archived: terms2.has("archived") ? terms2.get("archived") === "true" : void 0,
6027
+ name: terms2.get("name")
6028
+ });
6029
+ return pageOf("products list", limit, (most) => store.products.list({ ...filter, limit: most }));
6030
+ }, "listProducts");
6031
+ var productCommands = /* @__PURE__ */ __name((program, streams, env) => {
6032
+ const { run } = answers(program, streams, env);
6033
+ const products = program.command("products").description("goods and services you sell or buy, with their prices; a line that names one copies its price, so a later price change leaves the line as it was").summary("goods and services you sell or buy, with their prices");
6034
+ withQuery(json(annotate(products.command("list"), { effects: LOCAL_READ })).description("products and services, by name; archived:true lists those no longer sold"), PRODUCT_QUERY).option("--limit <n>", "most products, up to 500", positive, 100).action((words, { json: json5, limit }) => run(json5, (store) => listProducts(store, words, limit)));
6035
+ json(annotate(products.command("show"), { effects: LOCAL_READ, output: { entity: "product" } })).description("one product or service with its price, unit, supplier and stock code").argument("<product>", "product:<id>").action((ref, options, command) => run(options.json, async (store) => itemAnswer(await withSources(command, store, await store.products.get(ref)))));
6036
+ json(annotate(products.command("add"), {
6037
+ effects: LOCAL_WRITE,
6038
+ output: { entity: "product" },
6039
+ literal_after_dashes: true
6040
+ }).option("--kind <kind>", `${CATALOG_KINDS.join(" or ")}; product when left out`).option("--unit <text>", "what one of it is counted in, such as hour or month").option("--sku <code>", "the stock code the seller gives it").option("--supplier <party>", "who supplies it, when not you: person:<uid> or organization:<id>").option("--description <text>", "what it is, in a sentence")).description("add a product or service you sell or buy; anyone adds one directly, as a price feeds no total").summary("add a product or service").argument("<name>", "its name, as an invoice or order line prints it").argument("[amount]", "the price of one unit, a decimal such as 10000.00").argument("[currency]", "ISO 4217, such as RUB; given with the amount").action((name2, amount2, currency, options) => run(options.json, async (store) => itemAnswer(await store.products.add({
6041
+ by: authorOf(env),
6042
+ name: name2,
6043
+ ...given({
6044
+ kind: optionalChoice(options.kind, CATALOG_KINDS, "--kind"),
6045
+ unitPrice: amount2,
6046
+ currency,
6047
+ unit: options.unit,
6048
+ sku: options.sku,
6049
+ supplier: options.supplier,
6050
+ description: options.description
6051
+ })
6052
+ }))));
6053
+ json(annotate(products.command("update"), { effects: LOCAL_WRITE, output: { entity: "product" } }).option("--amount <decimal>", "the new price of one unit, such as 12000.00; give --currency with it").option("--currency <code>", "an ISO 4217 code, such as RUB").option("--title <title>", "its new name").option("--unit <text>", "what one of it is counted in, such as hour or month").option("--description <text>", "what it is, in a sentence").option("--archived <on|off>", "on: no longer sold, and lines and subscriptions keep pointing at it; off: sold again")).description("change a product's price, name, unit or description, or archive it; lines already written keep theirs").summary("change or archive a product").argument("<product>", "product:<id>").action((ref, options) => run(options.json, async (store) => {
6054
+ const archived = onOff(options.archived, "--archived");
6055
+ return itemAnswer(await store.products.update(ref, {
6056
+ by: authorOf(env),
6057
+ ...given({
6058
+ name: options.title,
6059
+ unitPrice: options.amount,
6060
+ currency: options.currency,
6061
+ unit: options.unit,
6062
+ description: options.description,
6063
+ archivedDate: archived === void 0 ? void 0 : archived ? today() : null
6064
+ })
6065
+ }));
6066
+ }));
6067
+ }, "productCommands");
6068
+
6069
+ // dist/finance/subscriptions-command.js
6070
+ var SUBSCRIPTION_QUERY = {
6071
+ entity: "subscription",
6072
+ backend: "native",
6073
+ fields: [
6074
+ termField("status", "enum", "status:active", { values: SUBSCRIPTION_STATUSES }),
6075
+ termField("direction", "enum", "direction:payable", { values: INVOICE_DIRECTIONS }),
6076
+ termField("supplier", "ref", 'supplier:"organization:3"'),
6077
+ termField("customer", "ref", 'customer:"organization:3"'),
6078
+ termField("project", "kw", "project:PMED"),
6079
+ termField("review", "enum", "review:proposed", { values: FINANCE_REVIEWS }),
6080
+ termField("renews", "time", "renews:2026-12-01")
6081
+ ]
6082
+ };
6083
+ var listSubscriptions = /* @__PURE__ */ __name(async (store, words, limit) => {
6084
+ const terms2 = queryTerms(words, SUBSCRIPTION_QUERY, "subscriptions list");
6085
+ const project = terms2.get("project");
6086
+ const filter = given({
6087
+ status: terms2.get("status"),
6088
+ direction: terms2.get("direction"),
6089
+ supplier: terms2.get("supplier"),
6090
+ customer: terms2.get("customer"),
6091
+ review: terms2.get("review"),
6092
+ renewsBy: dayOf(terms2.get("renews")),
6093
+ project: project === void 0 ? void 0 : await canonicalProject(store, project)
6094
+ });
6095
+ return pageOf("subscriptions list", limit, (most) => store.subscriptions.list({ ...filter, limit: most }));
6096
+ }, "listSubscriptions");
6097
+ var parts = /* @__PURE__ */ __name((command) => command.option("--status <state>", `${SUBSCRIPTION_STATUSES.join(", ")}; trial needs --trial-end-date`).option("--supplier <party>", "who supplies it: person:<uid> or organization:<id>; you, when you bill it").option("--customer <party>", "who receives it and pays for it: person:<uid> or organization:<id>; you, when you pay").option("--product <product>", "the product or service it is for: product:<id>").option("--contract <contract>", "the contract it runs under: contract:<id>").option("--every <count-unit>", "how often it is charged: a count and a unit, such as 1-month or 1-year").option("--start-date <date>", "the first day it runs, YYYY-MM-DD").option("--trial-end-date <date>", "the day its free trial ends, YYYY-MM-DD"), "parts");
6098
+ var fieldsOf3 = /* @__PURE__ */ __name((options) => given({
6099
+ status: optionalChoice(options.status, SUBSCRIPTION_STATUSES, "--status"),
6100
+ supplier: options.supplier,
6101
+ customer: options.customer,
6102
+ product: options.product,
6103
+ contract: options.contract,
6104
+ every: options.every,
6105
+ startDate: dayOf(options.startDate),
6106
+ trialEndDate: dayOf(options.trialEndDate),
6107
+ endDate: dayOf(options.endDate)
6108
+ }), "fieldsOf");
6109
+ var subscriptionCommands = /* @__PURE__ */ __name((program, streams, env) => {
6110
+ const { run } = answers(program, streams, env);
6111
+ const subscriptions = program.command("subscriptions").description("subscriptions you bill or pay: who supplies it, who pays, how often, and every price it had; a price is never changed, a new one is added").summary("subscriptions you bill or pay, and their prices");
6112
+ withQuery(json(annotate(subscriptions.command("list"), { effects: LOCAL_READ })).description("subscriptions, newest first; renews:2026-12-01 lists those that renew by then"), SUBSCRIPTION_QUERY).option("--limit <n>", "most subscriptions, up to 500", positive, 100).action((words, { json: json5, limit }) => run(json5, (store) => listSubscriptions(store, words, limit)));
6113
+ json(annotate(subscriptions.command("show"), { effects: LOCAL_READ, output: { entity: "subscription" } })).description("one subscription with its parties, dates, current price and every price it had").argument("<subscription>", "subscription:<id>").action((ref, options, command) => run(options.json, async (store) => itemAnswer(await withSources(command, store, await store.subscriptions.get(ref)))));
6114
+ json(writeMeta(parts(annotate(subscriptions.command("add"), {
6115
+ effects: LOCAL_WRITE,
6116
+ output: { entity: "subscription" },
6117
+ literal_after_dashes: true
6118
+ })).option("--kind <kind>", "receivable (you bill it) or payable (you pay it)"))).description(`record a subscription and its first price; ${PROPOSES}`).summary("record a subscription; an agent's waits for your review").argument("<name>", "what it is, such as Hosting").argument("<amount>", "its price for one period, a decimal such as 990.00").argument("<currency>", "ISO 4217, such as RUB").action(async (name2, amount2, currency, options, command) => {
6119
+ const by = await whoRuns(command, env, {
6120
+ asOwner: options.asOwner,
6121
+ question: "record this subscription as yours?"
6122
+ });
6123
+ await run(options.json, async (store) => {
6124
+ const startDate = dayOf(options.startDate) ?? today();
6125
+ return itemAnswer(await store.subscriptions.add({
6126
+ ...await writtenBy(store, by, options),
6127
+ ...fieldsOf3(options),
6128
+ name: name2,
6129
+ direction: choice(options.kind, INVOICE_DIRECTIONS, "--kind"),
6130
+ every: needed(options.every, "--every", "how often it is charged, such as 1-month"),
6131
+ startDate,
6132
+ prices: [{ amount: amount2, currency, effectiveFrom: startDate }]
6133
+ }));
6134
+ });
6135
+ });
6136
+ json(byOption(parts(annotate(subscriptions.command("update"), { effects: LOCAL_WRITE, output: { entity: "subscription" } })).option("--title <title>", "its new name").option("--end-date <date>", "the last day it runs, YYYY-MM-DD"))).description("change a subscription's status, schedule, dates or parties; pause it with --status paused. You change any, an agent only one it proposed that is still proposed. A new price is subscriptions prices add").summary("change a subscription").argument("<subscription>", "subscription:<id>").action(async (ref, options, command) => {
6137
+ const by = await whoRuns(command, env, { asOwner: options.asOwner, question: `change ${ref} as yours?` });
6138
+ await run(options.json, async (store) => itemAnswer(await store.subscriptions.update(ref, { by, ...fieldsOf3(options), ...given({ name: options.title }) })));
6139
+ });
6140
+ json(byOption(annotate(subscriptions.command("cancel"), { effects: LOCAL_WRITE, output: { entity: "subscription" } }).option("--occurred-time <time>", "the day it was cancelled, such as 2026-11-01; today when left out"))).description("mark a subscription cancelled on a day; it stays, with its prices").summary("cancel a subscription").argument("<subscription>", "subscription:<id>").action(async (ref, options, command) => {
6141
+ const by = await whoRuns(command, env, { asOwner: options.asOwner, question: `cancel ${ref} as yours?` });
6142
+ await run(options.json, async (store) => itemAnswer(await store.subscriptions.update(ref, {
6143
+ by,
6144
+ status: "cancelled",
6145
+ cancelledDate: dayOf(options.occurredTime) ?? today()
6146
+ })));
6147
+ });
6148
+ const prices = subscriptions.command("prices").description("the prices a subscription had, each from a day on; one is never changed, a new one is added").summary("a subscription's prices");
6149
+ json(byOption(annotate(prices.command("add"), { effects: LOCAL_WRITE, output: { entity: "subscription_price" } }).option("--start-date <date>", "the first day the price holds, YYYY-MM-DD; the subscription's start when left out").option("--reason <text>", "why an agent proposes it, for the owner who decides"))).description(`add a price from a day on; the earlier ones stay as they were. ${PROPOSES}, and the subscription stays as it is`).summary("add a subscription's new price").argument("<subscription>", "subscription:<id>").argument("<amount>", "the price for one period, a decimal such as 1190.00").argument("<currency>", "ISO 4217, such as RUB").action(async (ref, amount2, currency, options, command) => {
6150
+ const by = await whoRuns(command, env, {
6151
+ asOwner: options.asOwner,
6152
+ question: `add a price to ${ref} as yours?`
6153
+ });
6154
+ await run(options.json, async (store) => itemAnswer(await store.subscriptions.addPrice(ref, {
6155
+ by,
6156
+ amount: amount2,
6157
+ currency,
6158
+ ...given({
6159
+ effectiveFrom: dayOf(options.startDate),
6160
+ reason: by === "owner" ? void 0 : options.reason
6161
+ })
6162
+ })));
6163
+ });
6164
+ }, "subscriptionCommands");
6165
+
6166
+ // dist/finance/transactions-command.js
6167
+ var TRANSACTION_QUERY = {
6168
+ entity: "transaction",
6169
+ backend: "native",
6170
+ fields: [
6171
+ termField("wallet", "ref", 'wallet:"wallet:2"'),
6172
+ termField("direction", "enum", "direction:out", { values: MONEY_DIRECTIONS }),
6173
+ termField("status", "enum", "status:pending", { values: TRANSACTION_STATUSES }),
6174
+ termField("category", "kw", "category:Rent"),
6175
+ termField("project", "kw", "project:PMED"),
6176
+ termField("review", "enum", "review:proposed", { values: FINANCE_REVIEWS }),
6177
+ termField("uncategorized", "bool", "uncategorized:true")
6178
+ ]
6179
+ };
6180
+ var listTransactions = /* @__PURE__ */ __name(async (store, words, limit) => {
6181
+ const terms2 = queryTerms(words, TRANSACTION_QUERY, "transactions list");
6182
+ const project = terms2.get("project");
6183
+ const filter = given({
6184
+ wallet: terms2.get("wallet"),
6185
+ direction: terms2.get("direction"),
6186
+ status: terms2.get("status"),
6187
+ category: terms2.get("category"),
6188
+ review: terms2.get("review"),
6189
+ uncategorized: terms2.has("uncategorized") ? terms2.get("uncategorized") === "true" : void 0,
6190
+ project: project === void 0 ? void 0 : await canonicalProject(store, project)
6191
+ });
6192
+ return pageOf("transactions list", limit, (most) => store.transactions.list({ ...filter, limit: most }));
6193
+ }, "listTransactions");
6194
+ var STATUS_HELP = `${TRANSACTION_STATUSES.join(" or ")}; only a booked one counts in a balance`;
6195
+ var transactionCommands = /* @__PURE__ */ __name((program, streams, env) => {
6196
+ const { run } = answers(program, streams, env);
6197
+ const transactions = program.command("transactions").description("money a wallet's statement shows moving in or out, the payment it settles, and the categories it is split into").summary("money moving in or out of your wallets");
6198
+ withQuery(json(annotate(transactions.command("list"), { effects: LOCAL_READ })).description("transactions, newest first; uncategorized:true lists those not fully split into categories"), TRANSACTION_QUERY).summary("transactions, newest first").option("--limit <n>", "most transactions, up to 500", positive, 100).action((words, { json: json5, limit }) => run(json5, (store) => listTransactions(store, words, limit)));
6199
+ json(annotate(transactions.command("show"), { effects: LOCAL_READ, output: { entity: "transaction" } })).description("one transaction with its wallet, payment, splits and what is not categorized").argument("<transaction>", "transaction:<id>").action((ref, options, command) => run(options.json, async (store) => itemAnswer(await withSources(command, store, await store.transactions.get(ref)))));
6200
+ json(writeMeta(annotate(transactions.command("add"), {
6201
+ effects: LOCAL_WRITE,
6202
+ output: { entity: "transaction" },
6203
+ literal_after_dashes: true
6204
+ }).option("--kind <kind>", "in (money came in) or out (money went out)").option("--occurred-time <time>", "the day the statement shows, such as 2026-11-01; today when left out").option("--description <text>", "what the statement says, as it says it").option("--status <state>", `${STATUS_HELP}; booked when left out`).option("--payment <payment>", "the payment it settles, same amount, currency and direction: payment:<id>"))).description(`record what a wallet's statement shows moved, in the wallet's currency; ${PROPOSES}`).summary("record a transaction; an agent's waits for your review").argument("<wallet>", "wallet:<id>").argument("<amount>", "a decimal above 0, such as 500.00").action(async (wallet, amount2, options, command) => {
6205
+ const by = await whoRuns(command, env, {
6206
+ asOwner: options.asOwner,
6207
+ question: "record this transaction as yours?"
6208
+ });
6209
+ await run(options.json, async (store) => itemAnswer(await store.transactions.add({
6210
+ ...await writtenBy(store, by, options),
6211
+ wallet,
6212
+ amount: amount2,
6213
+ direction: choice(options.kind, MONEY_DIRECTIONS, "--kind"),
6214
+ statementDate: dayOf(options.occurredTime) ?? today(),
6215
+ ...given({
6216
+ status: optionalChoice(options.status, TRANSACTION_STATUSES, "--status"),
6217
+ description: options.description,
6218
+ payment: options.payment
6219
+ })
6220
+ })));
6221
+ });
6222
+ json(byOption(annotate(transactions.command("update"), { effects: LOCAL_WRITE, output: { entity: "transaction" } }).option("--status <state>", STATUS_HELP).option("--payment <payment>", "the payment it settles, same amount, currency and direction: payment:<id>").option("--description <text>", "what the statement says, as it says it"))).description("book a pending transaction, link it to the payment it settles, or fix its text; you change any, an agent only one it proposed that is still proposed").summary("book a transaction or link it to its payment").argument("<transaction>", "transaction:<id>").action(async (ref, options, command) => {
6223
+ const by = await whoRuns(command, env, { asOwner: options.asOwner, question: `change ${ref} as yours?` });
6224
+ await run(options.json, async (store) => itemAnswer(await store.transactions.update(ref, {
6225
+ by,
6226
+ ...given({
6227
+ status: optionalChoice(options.status, TRANSACTION_STATUSES, "--status"),
6228
+ payment: options.payment,
6229
+ description: options.description
6230
+ })
6231
+ })));
6232
+ });
6233
+ const splits = transactions.command("splits").description("the categories a transaction's amount is split into; together never more than the amount, the rest is uncategorized").summary("a transaction's categories");
6234
+ const WHO2 = "you split any transaction; an agent only one it proposed that is still proposed";
6235
+ json(byOption(annotate(splits.command("add"), { effects: LOCAL_WRITE, output: { entity: "transaction" } }).option("--project <project>", "the project this part belongs to: its key or project:<id>"))).description(`put part of a transaction's amount under a category; ${WHO2}`).summary("put part of a transaction under a category").argument("<transaction>", "transaction:<id>").argument("<amount>", "a decimal above 0, such as 120.00").argument("<category...>", "the category, in a word or a few, such as Rent").action(async (ref, amount2, words, options, command) => {
6236
+ const by = await whoRuns(command, env, { asOwner: options.asOwner, question: `split ${ref} as yours?` });
6237
+ await run(options.json, async (store) => itemAnswer(await store.transactions.addSplit(ref, {
6238
+ by,
6239
+ amount: amount2,
6240
+ category: words.join(" "),
6241
+ ...options.project === void 0 ? {} : { project: await canonicalProject(store, options.project) }
6242
+ })));
6243
+ });
6244
+ json(byOption(annotate(splits.command("remove"), { effects: LOCAL_WRITE, output: { entity: "transaction" } }))).description(`take a split off a transaction; its amount is uncategorized again. ${WHO2}`).summary("take a split off a transaction").argument("<transaction>", "transaction:<id>").argument("<position>", "the split's position, from 1, as transactions show lists it", positive).action(async (ref, position, options, command) => {
6245
+ const by = await whoRuns(command, env, { asOwner: options.asOwner, question: `change ${ref}'s splits as yours?` });
6246
+ await run(options.json, async (store) => itemAnswer(await store.transactions.removeSplit(ref, { position, by })));
6247
+ });
6248
+ }, "transactionCommands");
6249
+
6250
+ // dist/finance/wallets-command.js
6251
+ var WALLET_QUERY = {
6252
+ entity: "wallet",
6253
+ backend: "native",
6254
+ fields: [
6255
+ termField("kind", "enum", "kind:card", { values: WALLET_KINDS }),
6256
+ termField("currency", "kw", "currency:RUB")
6257
+ ]
6258
+ };
6259
+ var listWallets = /* @__PURE__ */ __name(async (store, words, limit) => {
6260
+ const terms2 = queryTerms(words, WALLET_QUERY, "wallets list");
6261
+ const filter = given({
6262
+ kind: terms2.get("kind"),
6263
+ currency: terms2.get("currency")
6264
+ });
6265
+ return pageOf("wallets list", limit, (most) => store.wallets.list({ ...filter, limit: most }));
6266
+ }, "listWallets");
6267
+ var sourceSays = /* @__PURE__ */ __name(async (store, wallet) => {
6268
+ if (wallet.openingBalance !== null)
6269
+ return null;
6270
+ for (const { provider, account: account2 } of await sourceAccounts(store, wallet)) {
6271
+ const [record2] = await store.records.list({ provider, account: account2, entity: wallet.ref, limit: 1 });
6272
+ const { opening_balance: balance, opening_date: date } = record2?.fields ?? {};
6273
+ if (record2 && typeof balance === "string")
6274
+ return {
6275
+ openingBalance: balance,
6276
+ openingDate: typeof date === "string" ? date : null,
6277
+ record: `${record2.type}:${record2.externalId}`,
6278
+ account: `${provider}:${account2}`
6279
+ };
6280
+ }
6281
+ return null;
6282
+ }, "sourceSays");
6283
+ var walletCommands = /* @__PURE__ */ __name((program, streams, env) => {
6284
+ const { run } = answers(program, streams, env);
6285
+ const wallets = program.command("wallets").description("bank accounts, cards and cash you keep money in, one currency each; a balance is the opening balance plus confirmed, booked transactions, computed each time").summary("bank accounts, cards and cash, with their balances");
6286
+ withQuery(json(annotate(wallets.command("list"), { effects: LOCAL_READ })).description("wallets with their balances today; kind:card lists the cards"), WALLET_QUERY).option("--limit <n>", "most wallets, up to 500", positive, 100).action((words, { json: json5, limit }) => run(json5, (store) => listWallets(store, words, limit)));
6287
+ json(annotate(wallets.command("show"), { effects: LOCAL_READ, output: { entity: "wallet" } }).option("--until-time <time>", "the balance up to and including this day, such as 2026-10-31; today when left out")).description("one wallet with its balance, and beside it what is pending or proposed and not counted yet; for an imported wallet whose opening balance you have not set, source_says gives the one its source sent").summary("one wallet with its balance and what is pending").argument("<wallet>", "wallet:<id>").action((ref, options, command) => run(options.json, async (store) => {
6288
+ const until = dayOf(options.untilTime);
6289
+ const wallet = await store.wallets.get(ref, until === void 0 ? {} : { until });
6290
+ return itemAnswer(await withSources(command, store, { ...wallet, sourceSays: await sourceSays(store, wallet) }));
6291
+ }));
6292
+ json(annotate(wallets.command("add"), { effects: LOCAL_WRITE, output: { entity: "wallet" }, literal_after_dashes: true }).option("--kind <kind>", `${WALLET_KINDS.join(", ")}; bank when left out`).option("--institution <text>", "the bank or other company that holds it, by name")).description("add a wallet in one currency; anyone adds one directly, and only you set its opening balance, with wallets update").summary("add a bank account, card or cash wallet").argument("<name>", "what you call it, such as 'Main card'").argument("<currency>", "ISO 4217, such as RUB; a bank account in two currencies is two wallets").action((name2, currency, options) => run(options.json, async (store) => itemAnswer(await store.wallets.add({
6293
+ by: authorOf(env),
6294
+ name: name2,
6295
+ currency,
6296
+ ...given({
6297
+ kind: optionalChoice(options.kind, WALLET_KINDS, "--kind"),
6298
+ institution: options.institution
6299
+ })
6300
+ }))));
6301
+ json(byOption(annotate(wallets.command("update"), { effects: LOCAL_WRITE, output: { entity: "wallet" } }).option("--title <title>", "its new name").option("--institution <text>", "the bank or other company that holds it, by name").option("--opening-balance <decimal>", "what it held on --opening-date, such as 1500.50; only you set it").option("--opening-date <date>", "the day of the opening balance, YYYY-MM-DD"))).description("rename a wallet, or set the opening balance its balance counts from; the opening balance is yours alone, an agent is refused").summary("rename a wallet or set its opening balance").argument("<wallet>", "wallet:<id>").action(async (ref, options, command) => {
6302
+ const by = await whoRuns(command, env, { asOwner: options.asOwner, question: `change ${ref} as yours?` });
6303
+ await run(options.json, async (store) => itemAnswer(await store.wallets.update(ref, {
6304
+ by,
6305
+ ...given({
6306
+ name: options.title,
6307
+ institution: options.institution,
6308
+ openingBalance: options.openingBalance,
6309
+ openingDate: dayOf(options.openingDate)
6310
+ })
6311
+ })));
6312
+ });
6313
+ }, "walletCommands");
6314
+
5323
6315
  // dist/findings-input.js
5324
6316
  import { createReadStream, statSync as statSync2 } from "node:fs";
5325
6317
  var FINDINGS_INPUT_HELP = "the findings JSON itself (starts with {), a JSON file, or - for stdin; at most 65536 UTF-8 bytes";
@@ -5349,53 +6341,53 @@ var findingsCommand = /* @__PURE__ */ __name((program, streams, env) => {
5349
6341
  const group = program.command("meetings").description("stored meeting evidence and reviewed findings").command("actions").description("cited meeting facts and project tasks waiting for owner review");
5350
6342
  const { run } = answers(program, streams, env);
5351
6343
  const warn = /* @__PURE__ */ __name((text3) => streams.diagnostic(text3), "warn");
5352
- const scope = /* @__PURE__ */ __name((store, given) => theAccount(store, env, given, warn), "scope");
5353
- const acting = /* @__PURE__ */ __name((store, given) => writeAccount(store, env, given, warn), "acting");
6344
+ const scope = /* @__PURE__ */ __name((store, given2) => theAccount(store, env, given2, warn), "scope");
6345
+ const acting = /* @__PURE__ */ __name((store, given2) => writeAccount(store, env, given2, warn), "acting");
5354
6346
  const options = /* @__PURE__ */ __name((command) => sourceOptions(command, MEETING_ACCOUNT_HELP).option("--json", "print JSON; --json=id,status keeps only those fields"), "options");
5355
6347
  const writes = /* @__PURE__ */ __name((command) => writeOptions(command, MEETING_WRITE_HELP).option("--json", "print JSON; --json=id,status keeps only those fields"), "writes");
5356
- writes(annotate(group.command("add"), { effects: LOCAL_WRITE, output: { entity: "meeting_findings" } })).description("stage cited findings; facts and tasks wait for owner confirmation").argument("<file>", FINDINGS_INPUT_HELP).addHelpText("after", "\nInput: schema_version 1, key, extractor, findings. Every finding names id, kind, project and evidence (reference and fingerprint). Facts name type and statement; tasks name type, title, reason and commitment (explicit or inferred). At most 16 findings, each with 1\u20138 exact cues from Zoom evidence. Optional due_at is a real ISO timestamp with timezone and requires due_evidence; optional assignee is a person reference and requires assignee_evidence. Both support lists cite this finding's cue references.\n").action(async (file, given) => {
6348
+ writes(annotate(group.command("add"), { effects: LOCAL_WRITE, output: { entity: "meeting_findings" } })).description("stage cited findings; facts and tasks wait for owner confirmation").argument("<file>", FINDINGS_INPUT_HELP).addHelpText("after", "\nInput: schema_version 1, key, extractor, findings. Every finding names id, kind, project and evidence (reference and fingerprint). Facts name type and statement; tasks name type, title, reason and commitment (explicit or inferred). At most 16 findings, each with 1\u20138 exact cues from Zoom evidence. Optional due_at is a real ISO timestamp with timezone and requires due_evidence; optional assignee is a person reference and requires assignee_evidence. Both support lists cite this finding's cue references.\n").action(async (file, given2) => {
5357
6349
  const text3 = await readFindingsInput(file, environmentOf(program).stdin ?? process.stdin);
5358
6350
  const input = parseMeetingFindingsJson(text3);
5359
6351
  const author = await whoRuns(program, env, { question: "" });
5360
6352
  const agent = author === "owner" ? { bot: "memo-findings" } : author;
5361
- await run(given.json, async (store) => itemAnswer(await store.meetingFindings.stage(await acting(store, given), input, agent)));
6353
+ await run(given2.json, async (store) => itemAnswer(await store.meetingFindings.stage(await acting(store, given2), input, agent)));
5362
6354
  });
5363
- options(annotate(group.command("show"), { effects: LOCAL_READ, output: { entity: "meeting_findings" } })).description("one findings preview, prior decisions and its review receipt").argument("<id>", "stored findings batch ID").action((id, given) => run(given.json, async (store) => itemAnswer(await store.meetingFindings.get(await scope(store, given), id))));
5364
- withQuery(options(annotate(group.command("list"), { effects: LOCAL_READ, output: { entity: "meeting_findings" } })), FINDINGS_QUERY).description("findings batches in one meeting account, newest first").option("--limit <n>", "batches per page, at most 50", positive, 20).option("--page <n>", "which page, from 1", positive, 1).action((words, given) => run(given.json, async (store) => {
6355
+ options(annotate(group.command("show"), { effects: LOCAL_READ, output: { entity: "meeting_findings" } })).description("one findings preview, prior decisions and its review receipt").argument("<id>", "stored findings batch ID").action((id, given2) => run(given2.json, async (store) => itemAnswer(await store.meetingFindings.get(await scope(store, given2), id))));
6356
+ withQuery(options(annotate(group.command("list"), { effects: LOCAL_READ, output: { entity: "meeting_findings" } })), FINDINGS_QUERY).description("findings batches in one meeting account, newest first").option("--limit <n>", "batches per page, at most 50", positive, 20).option("--page <n>", "which page, from 1", positive, 1).action((words, given2) => run(given2.json, async (store) => {
5365
6357
  const status = queryTerms(words, FINDINGS_QUERY, "meetings actions list").get("status");
5366
- const key = await scope(store, given);
6358
+ const key = await scope(store, given2);
5367
6359
  const found = await store.meetingFindings.list(key, {
5368
- limit: given.limit,
5369
- offset: (given.page - 1) * given.limit,
6360
+ limit: given2.limit,
6361
+ offset: (given2.page - 1) * given2.limit,
5370
6362
  ...status === void 0 ? {} : { status }
5371
6363
  });
5372
6364
  return listAnswer("meetings actions list", {
5373
6365
  items: found.items,
5374
- limit: given.limit,
5375
- page: given.page,
6366
+ limit: given2.limit,
6367
+ page: given2.page,
5376
6368
  has_more: found.hasMore,
5377
- args: { query: words.join(" "), source: accountName(key), limit: given.limit }
6369
+ args: { query: words.join(" "), source: accountName(key), limit: given2.limit }
5378
6370
  });
5379
6371
  }));
5380
6372
  for (const name2 of ["confirm", "reject"]) {
5381
6373
  const command = writes(annotate(group.command(name2), { effects: LOCAL_WRITE, output: { entity: "meeting_findings" } })).description(name2 === "confirm" ? "owner only: create selected findings and reject the other new candidates" : "owner only: reject every new candidate in this batch").argument("<id>", "stored findings batch ID").requiredOption("--fingerprint <hash>", "the exact fingerprint shown in the preview");
5382
6374
  byOption(command);
5383
- const review = /* @__PURE__ */ __name(async (id, given, accept) => {
6375
+ const review = /* @__PURE__ */ __name(async (id, given2, accept) => {
5384
6376
  const key = `meetings.actions.${name2}`;
5385
- const who = await whoRuns(command, env, { asOwner: given.asOwner, question: `${name2} batch ${id} as you?` });
6377
+ const who = await whoRuns(command, env, { asOwner: given2.asOwner, question: `${name2} batch ${id} as you?` });
5386
6378
  const by = who === "owner" ? who : mcpOwnerAllowed(env, key) ? { bot: who.bot, reason: `the owner allows ${key}` } : void 0;
5387
6379
  if (by === void 0)
5388
6380
  throw new CliError("validation_error", "findings confirmation and rejection belong to the owner; agents must leave proposals for review");
5389
- return run(given.json, async (store) => itemAnswer(await store.meetingFindings.review(await acting(store, given), id, {
5390
- fingerprint: given.fingerprint,
6381
+ return run(given2.json, async (store) => itemAnswer(await store.meetingFindings.review(await acting(store, given2), id, {
6382
+ fingerprint: given2.fingerprint,
5391
6383
  accept,
5392
6384
  by
5393
6385
  })));
5394
6386
  }, "review");
5395
6387
  if (name2 === "confirm")
5396
- command.argument("<ids...>", "candidate IDs to accept; other new candidates are rejected").action((id, ids, given) => review(id, given, ids));
6388
+ command.argument("<ids...>", "candidate IDs to accept; other new candidates are rejected").action((id, ids, given2) => review(id, given2, ids));
5397
6389
  else
5398
- command.action((id, given) => review(id, given, []));
6390
+ command.action((id, given2) => review(id, given2, []));
5399
6391
  }
5400
6392
  }, "findingsCommand");
5401
6393
 
@@ -5476,18 +6468,18 @@ var meetingProjectsCommand = /* @__PURE__ */ __name((projects, streams, env) =>
5476
6468
  const key = await (writes ? writeAccount : theAccount)(store, env, options2, warn);
5477
6469
  return work(store, (await canonicalProject(store, project)).slice(8), key);
5478
6470
  }), "execute");
5479
- withQuery(options(annotate(group.command("list"), { effects: LOCAL_READ, output: { entity: "meeting_project" } }).description("meetings linked to a project in one account, or with confirmed:false proposed").argument("<project>", "project reference, key or explicit alias")), MEETING_PROJECTS_QUERY).option("--limit <n>", "meetings per page, at most 500", positive, 50).option("--page <n>", "which page, from 1", positive).action((project, words, given) => execute(project, given, async (store, projectId, key) => {
6471
+ withQuery(options(annotate(group.command("list"), { effects: LOCAL_READ, output: { entity: "meeting_project" } }).description("meetings linked to a project in one account, or with confirmed:false proposed").argument("<project>", "project reference, key or explicit alias")), MEETING_PROJECTS_QUERY).option("--limit <n>", "meetings per page, at most 500", positive, 50).option("--page <n>", "which page, from 1", positive).action((project, words, given2) => execute(project, given2, async (store, projectId, key) => {
5480
6472
  const confirmed = queryTerms(words, MEETING_PROJECTS_QUERY, "projects meetings list").get("confirmed");
5481
- const page = given.page ?? 1;
6473
+ const page = given2.page ?? 1;
5482
6474
  const found = await store.knowledge.meetingProjects(key, {
5483
6475
  projectId,
5484
6476
  confirmed: confirmed === "true",
5485
- limit: given.limit,
5486
- offset: (page - 1) * given.limit
6477
+ limit: given2.limit,
6478
+ offset: (page - 1) * given2.limit
5487
6479
  });
5488
6480
  return listAnswer("projects meetings list", {
5489
6481
  items: found.items,
5490
- limit: given.limit,
6482
+ limit: given2.limit,
5491
6483
  has_more: found.hasMore,
5492
6484
  page,
5493
6485
  args: {
@@ -5497,10 +6489,10 @@ var meetingProjectsCommand = /* @__PURE__ */ __name((projects, streams, env) =>
5497
6489
  }
5498
6490
  });
5499
6491
  }));
5500
- writeOptions(annotate(group.command("link"), { effects: LOCAL_WRITE }).description("link a stored meeting to a project, or confirm a proposed link").argument("<project>", "project reference, key or explicit alias").argument("<meeting-id>", "positive stored meeting id"), MEETING_WRITE_HELP).option("--json", "print JSON; --json=id,title keeps only those fields").option("--fingerprint <hash>", "required when confirming an existing proposal").option("--reason <text>", "why the reviewed meeting belongs to this project").action((project, meeting, given) => execute(project, given, async (store, projectId, key) => itemAnswer(await store.knowledge.linkMeetingProject(key, meeting, projectId, {
6492
+ writeOptions(annotate(group.command("link"), { effects: LOCAL_WRITE }).description("link a stored meeting to a project, or confirm a proposed link").argument("<project>", "project reference, key or explicit alias").argument("<meeting-id>", "positive stored meeting id"), MEETING_WRITE_HELP).option("--json", "print JSON; --json=id,title keeps only those fields").option("--fingerprint <hash>", "required when confirming an existing proposal").option("--reason <text>", "why the reviewed meeting belongs to this project").action((project, meeting, given2) => execute(project, given2, async (store, projectId, key) => itemAnswer(await store.knowledge.linkMeetingProject(key, meeting, projectId, {
5501
6493
  by: "owner",
5502
- ...given.fingerprint === void 0 ? {} : { expectedFingerprint: given.fingerprint },
5503
- ...given.reason === void 0 ? {} : { provenance: given.reason }
6494
+ ...given2.fingerprint === void 0 ? {} : { expectedFingerprint: given2.fingerprint },
6495
+ ...given2.reason === void 0 ? {} : { provenance: given2.reason }
5504
6496
  })), true));
5505
6497
  }, "meetingProjectsCommand");
5506
6498
 
@@ -5588,18 +6580,18 @@ var ACTIONS_QUERY = {
5588
6580
  fields: [termField("status", "enum", "status:proposed", { values: ["proposed", "reviewed"] })],
5589
6581
  defaults: ["status:proposed"]
5590
6582
  };
5591
- var json4 = /* @__PURE__ */ __name((command) => command.option("--json", "print JSON; --json=id,status keeps only those fields"), "json");
6583
+ var json2 = /* @__PURE__ */ __name((command) => command.option("--json", "print JSON; --json=id,status keeps only those fields"), "json");
5592
6584
  var projectActionsCommand = /* @__PURE__ */ __name((projects, streams, env) => {
5593
6585
  const group = projects.command("actions").description("cited key documents and findings an agent proposed for a project, with the evidence to decide them").summary("an agent's proposals for a project, and deciding them");
5594
6586
  const { run } = answers(projects, streams, env);
5595
- json4(annotate(group.command("add"), { effects: LOCAL_WRITE })).description("stage an agent's cited facts and follow-ups about one project for review").argument("<file>", FINDINGS_INPUT_HELP).addHelpText("after", "\nInput: schema_version 1, key, extractor, findings. Every finding names id, kind and evidence: 1\u20138 msg:, document: or note: references with the fingerprint projects evidence or notes show gives. A fact may name a project and a subject (person:, organization:, task: or project:), or neither; a task names its project. Facts name type and statement; tasks name type, title, reason and commitment (explicit or inferred). A due_at or assignee needs due_evidence or assignee_evidence citing this finding's references. A payment names payment {amount, currency, direction to_us|from_us, state paid|expected|cancelled, counterparty, paid_at}: an expected one becomes an invoice and needs a person: or organization: counterparty; a paid or cancelled one names in supersedes the invoice: it settles or voids. At most one project per batch. The same key and input returns the same batch; actions confirm and reject decide it by its id.\n").action(async (file, given, command) => {
6587
+ json2(annotate(group.command("add"), { effects: LOCAL_WRITE })).description("stage an agent's cited facts and follow-ups about one project for review").argument("<file>", FINDINGS_INPUT_HELP).addHelpText("after", "\nInput: schema_version 1, key, extractor, findings. Every finding names id, kind and evidence: 1\u20138 msg:, document: or note: references with the fingerprint projects evidence or notes show gives. A fact may name a project and a subject (person:, organization:, task: or project:), or neither; a task names its project. Facts name type and statement; tasks name type, title, reason and commitment (explicit or inferred). A due_at or assignee needs due_evidence or assignee_evidence citing this finding's references. A payment names payment {amount, currency, direction to_us|from_us, state paid|expected|cancelled, counterparty, paid_at}: an expected one becomes an invoice and needs a person: or organization: counterparty; a paid or cancelled one names in supersedes the invoice: it settles or voids. At most one project per batch. The same key and input returns the same batch; actions confirm and reject decide it by its id.\n").action(async (file, given2, command) => {
5596
6588
  const input = parseEvidenceFindingsJson(await readFindingsInput(file, environmentOf(projects).stdin ?? process.stdin));
5597
6589
  const author = await whoRuns(command, env, { question: "" });
5598
6590
  if (author === "owner")
5599
6591
  throw new CliError("validation_error", "findings are an agent's proposals; record your own with memo facts add");
5600
- await run(given.json, async (store) => itemAnswer(await store.evidenceFindings.stage(input, author)));
6592
+ await run(given2.json, async (store) => itemAnswer(await store.evidenceFindings.stage(input, author)));
5601
6593
  });
5602
- withQuery(json4(answerEntity(annotate(group.command("list"), { effects: LOCAL_READ }), "project_action", union([
6594
+ withQuery(json2(answerEntity(annotate(group.command("list"), { effects: LOCAL_READ }), "project_action", union([
5603
6595
  strictObject({
5604
6596
  kind: literal("key_document"),
5605
6597
  id: string(),
@@ -5620,39 +6612,39 @@ var projectActionsCommand = /* @__PURE__ */ __name((projects, streams, env) => {
5620
6612
  decision: unknown(),
5621
6613
  findings: array(unknown())
5622
6614
  })
5623
- ]))).argument("<project>", "the project's id, project:<id>, key, exact name or alias"), ACTIONS_QUERY).summary("a project's proposals with the evidence to decide them").description("a project's proposed key documents and findings, newest first, with source state, cited text and nearby messages or document paragraphs; key-document text is untracked because no fingerprint was saved").option("--limit <n>", "findings batches per page, at most 50", positive, 10).option("--page <n>", "which page, from 1; key documents come on the first", positive, 1).option("--brief", "only references and source state, without excerpts or nearby text").option("--before-n <n>", "messages or document paragraphs before the citation, at most 5", whole, 2).option("--after-n <n>", "messages or document paragraphs after the citation, at most 5", whole, 2).action((reference2, words, given) => run(given.json, async (store) => {
6615
+ ]))).argument("<project>", "the project's id, project:<id>, key, exact name or alias"), ACTIONS_QUERY).summary("a project's proposals with the evidence to decide them").description("a project's proposed key documents and findings, newest first, with source state, cited text and nearby messages or document paragraphs; key-document text is untracked because no fingerprint was saved").option("--limit <n>", "findings batches per page, at most 50", positive, 10).option("--page <n>", "which page, from 1; key documents come on the first", positive, 1).option("--brief", "only references and source state, without excerpts or nearby text").option("--before-n <n>", "messages or document paragraphs before the citation, at most 5", whole, 2).option("--after-n <n>", "messages or document paragraphs after the citation, at most 5", whole, 2).action((reference2, words, given2) => run(given2.json, async (store) => {
5624
6616
  const status = queryTerms(words, ACTIONS_QUERY, "projects actions list").get("status");
5625
6617
  const project = await projectOf(store, reference2);
5626
6618
  const found = await projectActions(store, project, {
5627
6619
  status,
5628
- limit: given.limit,
5629
- page: given.page,
5630
- brief: given.brief === true,
5631
- before: Math.min(given.beforeN, 5),
5632
- after: Math.min(given.afterN, 5)
6620
+ limit: given2.limit,
6621
+ page: given2.page,
6622
+ brief: given2.brief === true,
6623
+ before: Math.min(given2.beforeN, 5),
6624
+ after: Math.min(given2.afterN, 5)
5633
6625
  });
5634
6626
  return listAnswer("projects actions list", {
5635
6627
  items: found.items,
5636
- limit: given.limit,
5637
- page: given.page,
6628
+ limit: given2.limit,
6629
+ page: given2.page,
5638
6630
  has_more: found.hasMore,
5639
6631
  args: { project: reference2, query: words.join(" ") }
5640
6632
  });
5641
6633
  }));
5642
6634
  for (const name2 of ["confirm", "reject"]) {
5643
- const command = byOption(json4(annotate(group.command(name2), { effects: LOCAL_WRITE })).description(name2 === "confirm" ? "confirm a suggested key document, or create the named findings of a batch and reject its other new ones; an agent decides for you only when agent_decisions is true, and with --reason" : "reject a suggested key document, or every new finding of a batch").summary(name2 === "confirm" ? "confirm a proposal, yours or an agent's with --reason" : "reject a proposal").argument("<project>", "the project's id, project:<id>, key, exact name or alias").argument("<id>", "key:<id> for a key document, or a findings batch number, as projects actions list gives them"));
6635
+ const command = byOption(json2(annotate(group.command(name2), { effects: LOCAL_WRITE })).description(name2 === "confirm" ? "confirm a suggested key document, or create the named findings of a batch and reject its other new ones; an agent decides for you only when agent_decisions is true, and with --reason" : "reject a suggested key document, or every new finding of a batch").summary(name2 === "confirm" ? "confirm a proposal, yours or an agent's with --reason" : "reject a proposal").argument("<project>", "the project's id, project:<id>, key, exact name or alias").argument("<id>", "key:<id> for a key document, or a findings batch number, as projects actions list gives them"));
5644
6636
  if (name2 === "confirm")
5645
6637
  command.argument("[findings...]", "the finding IDs of a batch to create");
5646
6638
  command.option("--fingerprint <hash>", "a findings batch's fingerprint, as projects actions list gives it").option("--reason <text>", "why, in a few words; required when an agent decides for you").action(async (reference2, id, ...rest) => {
5647
6639
  const accept = name2 === "confirm" ? rest[0] : [];
5648
- const given = name2 === "confirm" ? rest[1] : rest[0];
5649
- const by = await deciderOf(command, env, { ...given, question: `${name2} ${id} as you, the owner?` });
5650
- await run(given.json, async (store) => {
6640
+ const given2 = name2 === "confirm" ? rest[1] : rest[0];
6641
+ const by = await deciderOf(command, env, { ...given2, question: `${name2} ${id} as you, the owner?` });
6642
+ await run(given2.json, async (store) => {
5651
6643
  const project = await projectOf(store, reference2);
5652
6644
  return itemAnswer(await decideAction(store, project, id, {
5653
6645
  confirm: name2 === "confirm",
5654
- ...given.fingerprint === void 0 ? {} : { fingerprint: given.fingerprint },
5655
- ...given.reason === void 0 ? {} : { reason: given.reason },
6646
+ ...given2.fingerprint === void 0 ? {} : { fingerprint: given2.fingerprint },
6647
+ ...given2.reason === void 0 ? {} : { reason: given2.reason },
5656
6648
  accept,
5657
6649
  by
5658
6650
  }));
@@ -5984,7 +6976,7 @@ var syncHint = /* @__PURE__ */ __name((chat, since, env, chosen = {}) => {
5984
6976
  }, "syncHint");
5985
6977
 
5986
6978
  // dist/knowledge/relationships-scan.js
5987
- var DAY3 = 864e5;
6979
+ var DAY4 = 864e5;
5988
6980
  var SCAN_STEP = {
5989
6981
  id: "relationships.scan",
5990
6982
  kind: "command",
@@ -6058,7 +7050,7 @@ var relationshipsScanCommand = /* @__PURE__ */ __name((relations, print, env, wa
6058
7050
  if (options.limit > 50)
6059
7051
  throw new CliError("validation_error", "--limit is at most 50", { param: "limit" });
6060
7052
  const window = projectWindowOf(options.sinceTime);
6061
- const since = new Date("days" in window ? Date.now() - window.days * DAY3 : window.after).toISOString();
7053
+ const since = new Date("days" in window ? Date.now() - window.days * DAY4 : window.after).toISOString();
6062
7054
  const written2 = options.yes === true;
6063
7055
  const { body, text: text3 } = await withStore(env, async (store) => {
6064
7056
  const sources = await namedAccounts(store, env, options, warn);
@@ -6106,14 +7098,14 @@ var projectGatherCommand = /* @__PURE__ */ __name((projects, print, env, warn) =
6106
7098
  });
6107
7099
  const since = new Date(found.window.after).toISOString().slice(0, 10);
6108
7100
  const syncs = found.linkedChats.map((one2) => one2.completeness === null || one2.completeness.state === "complete" ? null : chatSync(one2, since, env, chosen));
6109
- const parts = projectAnswerParts(options.sinceTime, found);
7101
+ const parts2 = projectAnswerParts(options.sinceTime, found);
6110
7102
  const blocked = [...new Set(syncs.flatMap((one2) => one2 && one2.command === null ? [one2.why] : []))];
6111
- const missing = [...parts.missing ?? [], ...blocked.map((why) => ({ field: "sync_command", why }))];
6112
- const next = [...parts.next ?? [], ...scan].slice(0, MAX_NEXT_STEPS);
7103
+ const missing = [...parts2.missing ?? [], ...blocked.map((why) => ({ field: "sync_command", why }))];
7104
+ const next = [...parts2.next ?? [], ...scan].slice(0, MAX_NEXT_STEPS);
6113
7105
  print(options.json, itemAnswer({
6114
7106
  ...found,
6115
7107
  linkedChats: found.linkedChats.map((one2, i) => ({ ...one2, syncCommand: syncs[i]?.command ?? null }))
6116
- }, { ...parts, ...missing.length ? { missing } : {}, ...next.length ? { next } : {} }), projectEvidenceText(found, {
7108
+ }, { ...parts2, ...missing.length ? { missing } : {}, ...next.length ? { next } : {} }), projectEvidenceText(found, {
6117
7109
  sync: /* @__PURE__ */ __name((chat, at) => syncHint(chat, at, env, chosen), "sync"),
6118
7110
  showDocument: "memo notes show"
6119
7111
  }));
@@ -6161,7 +7153,7 @@ var projectStatusCommand = /* @__PURE__ */ __name((projects, print, env) => answ
6161
7153
  param: "--compact"
6162
7154
  });
6163
7155
  const chosen = options.syncProfile ?? {};
6164
- const { found, finance, open } = await withStore(env, async (store) => {
7156
+ const { found, finance, open: open2 } = await withStore(env, async (store) => {
6165
7157
  const status = await projectStatus(store, {
6166
7158
  project,
6167
7159
  ...projectWindowOf(options.sinceTime),
@@ -6185,13 +7177,13 @@ var projectStatusCommand = /* @__PURE__ */ __name((projects, print, env) => answ
6185
7177
  print(options.json, itemOf({
6186
7178
  ...item,
6187
7179
  ...finance.length ? { finance } : {},
6188
- ...open.deals.length ? { deals: open.deals } : {},
6189
- ...open.more ? { deals_more: open.more } : {}
7180
+ ...open2.deals.length ? { deals: open2.deals } : {},
7181
+ ...open2.more ? { deals_more: open2.more } : {}
6190
7182
  }, {
6191
7183
  ...next.length ? { next: next.map(asAction) } : {},
6192
7184
  ...gaps.length ? { missing: gaps } : {},
6193
7185
  meta
6194
- }), [projectStatusText(found, hints), ...financeText(finance), ...dealsText(open)].join("\n"), options.compact === true);
7186
+ }), [projectStatusText(found, hints), ...financeText(finance), ...dealsText(open2)].join("\n"), options.compact === true);
6195
7187
  }), "projectStatusCommand");
6196
7188
 
6197
7189
  // dist/knowledge/project-transfer.js
@@ -6363,9 +7355,9 @@ var pending = /* @__PURE__ */ __name(async (store, about) => {
6363
7355
  };
6364
7356
  }, "pending");
6365
7357
  var listRelationships = /* @__PURE__ */ __name(async (store, words) => {
6366
- const terms = queryTerms(words, RELATIONSHIP_QUERY, "relationships list");
6367
- const about = terms.get("about");
6368
- const confirmed = terms.get("confirmed");
7358
+ const terms2 = queryTerms(words, RELATIONSHIP_QUERY, "relationships list");
7359
+ const about = terms2.get("about");
7360
+ const confirmed = terms2.get("confirmed");
6369
7361
  const found = confirmed === "false" ? await pending(store, about) : {
6370
7362
  hasMore: false,
6371
7363
  items: (await store.knowledge.relations(null, about)).filter((one2) => confirmed === void 0 || one2.confirmed).map((one2) => ({ ...one2, status: one2.confirmed ? "confirmed" : "proposed" }))
@@ -6471,7 +7463,7 @@ var knowledgeCommands = /* @__PURE__ */ __name((program, streams, env) => {
6471
7463
  return ownedList("projects key-documents list", options, async (store) => keyDocuments(store, await projectOf(store, project), id === void 0 ? {} : { id }));
6472
7464
  });
6473
7465
  const relations = program.command("relationships").description("relations between people, organizations and projects; never between identities");
6474
- 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, in a few words, such as cto").option("--reason <text>", "why you think so, in a sentence").action(async (from, to, options, command) => {
7466
+ 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("--reason <text>", "why you think so, in a sentence").action(async (from, to, options, command) => {
6475
7467
  const by = await whoRuns(command, env, { asOwner: options.asOwner, question: "state it as yours?" });
6476
7468
  return owned(options, async (store) => {
6477
7469
  const input = {
@@ -6488,7 +7480,7 @@ var knowledgeCommands = /* @__PURE__ */ __name((program, streams, env) => {
6488
7480
  const found = await withStore(env, (store) => listRelationships(store, words));
6489
7481
  print(options.json, listAnswer("relationships list", { items: found.items, limit: found.limit, has_more: found.hasMore }), relationshipsText(found.items));
6490
7482
  });
6491
- byOption(annotate(relations.command("update"), { effects: LOCAL_WRITE }).description("set what a relationship is: its role, 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 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, in a few words; an empty value clears it").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) => {
7483
+ byOption(annotate(relations.command("update"), { effects: LOCAL_WRITE }).description("set what a relationship is: its role, 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 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("--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) => {
6492
7484
  const change = {
6493
7485
  ...options.role === void 0 ? {} : { role: options.role === "" ? null : options.role },
6494
7486
  ...options.purpose === void 0 ? {} : { purpose: options.purpose }
@@ -6580,7 +7572,7 @@ var party2 = /* @__PURE__ */ __name((reference2, name2) => [
6580
7572
  ...name2 && fold3(name2) ? [`name:${fold3(name2)}`] : []
6581
7573
  ], "party");
6582
7574
  var text = /* @__PURE__ */ __name((value) => typeof value === "string" && value.trim() ? value : void 0, "text");
6583
- var present = /* @__PURE__ */ __name((parts) => parts.filter((part) => part !== void 0), "present");
7575
+ var present = /* @__PURE__ */ __name((parts2) => parts2.filter((part) => part !== void 0), "present");
6584
7576
  var keysOf = /* @__PURE__ */ __name((finding) => {
6585
7577
  const raw = finding ?? {};
6586
7578
  const [shop, number2, url, id] = [raw.supplierName, raw.number, raw.sourceUrl, raw.externalId].map(text);
@@ -6712,7 +7704,7 @@ var oneMailboxOf = /* @__PURE__ */ __name(async (store, env, source) => {
6712
7704
  throw new CliError("validation_error", `${source} is not a mailbox \u2014 ${MAIL_SOURCES}`, { param: "source" });
6713
7705
  return key;
6714
7706
  }, "oneMailboxOf");
6715
- var named2 = /* @__PURE__ */ __name((commands2, name2) => {
7707
+ var named3 = /* @__PURE__ */ __name((commands2, name2) => {
6716
7708
  const found = commands2.find((command) => command.name() === name2);
6717
7709
  if (!found)
6718
7710
  throw new Error(`cli-core's mail commands have no ${name2}`);
@@ -6732,10 +7724,10 @@ var mailReviewCommands = /* @__PURE__ */ __name((mail, messages, env) => {
6732
7724
  }
6733
7725
  };
6734
7726
  const shared = mailReadCommands(reads);
6735
- const review = named2(shared, "review");
6736
- const sharedMessages = named2(shared, "messages").commands;
6737
- const acknowledge = named2(sharedMessages, "acknowledge");
6738
- const reset = named2(sharedMessages, "reset");
7727
+ const review = named3(shared, "review");
7728
+ const sharedMessages = named3(shared, "messages").commands;
7729
+ const acknowledge = named3(sharedMessages, "acknowledge");
7730
+ const reset = named3(sharedMessages, "reset");
6739
7731
  for (const command of [review, acknowledge, reset])
6740
7732
  overrideSharedContract(command, "memo holds several mailboxes and no profile, so --source names the one mailbox; its --json is per command.", (one2) => {
6741
7733
  one2.option("--source <accounts>", MAILBOX_HELP).option("--json", "print JSON; --json=id,title keeps only those fields");
@@ -6790,39 +7782,39 @@ var keyed = /* @__PURE__ */ __name((text3, key) => {
6790
7782
  }
6791
7783
  if (!raw || typeof raw !== "object" || Array.isArray(raw))
6792
7784
  return text3;
6793
- const named4 = raw.key;
6794
- if (named4 !== void 0 && named4 !== key)
6795
- throw new CliError("validation_error", `the batch's key ${String(named4)} is not --key ${key}; give the key once`, {
7785
+ const named5 = raw.key;
7786
+ if (named5 !== void 0 && named5 !== key)
7787
+ throw new CliError("validation_error", `the batch's key ${String(named5)} is not --key ${key}; give the key once`, {
6796
7788
  reason: "findings.key-mismatch",
6797
- key: String(named4),
7789
+ key: String(named5),
6798
7790
  given: key
6799
7791
  });
6800
7792
  return JSON.stringify({ ...raw, key });
6801
7793
  }, "keyed");
6802
- var json5 = /* @__PURE__ */ __name((command) => command.option("--json", "print JSON; --json=id,status keeps only those fields"), "json");
7794
+ var json3 = /* @__PURE__ */ __name((command) => command.option("--json", "print JSON; --json=id,status keeps only those fields"), "json");
6803
7795
  var mailFindingsCommand = /* @__PURE__ */ __name((program, mail, streams, env) => {
6804
7796
  const { run } = answers(program, streams, env);
6805
7797
  const findings = mail.command("findings").description("cited tasks, task updates, facts, memories, links, contacts, invoices, payments and orders an agent read in new mail").summary("what an agent read in new mail, cited, waiting for the owner");
6806
- json5(proposesOnly(annotate(findings.command("add"), { effects: LOCAL_WRITE, output: { entity: "mail_findings" } }))).description("stage one mailbox's findings for the owner; nothing is created until the owner confirms").summary("stage one mailbox's findings; the owner confirms them").argument("<file>", FINDINGS_INPUT_HELP).option("--source <accounts>", MAILBOX_HELP).option("--key <key>", "the findings key `mail review --holder` gave in its mail-findings.add step").option("--dry-run", "check the batch as staging would, invoices, payments and orders tried and rolled back, and stage nothing; answers valid and every finding's problem at once").addHelpText("after", INPUT_HELP).action(async (file, given) => {
7798
+ json3(proposesOnly(annotate(findings.command("add"), { effects: LOCAL_WRITE, output: { entity: "mail_findings" } }))).description("stage one mailbox's findings for the owner; nothing is created until the owner confirms").summary("stage one mailbox's findings; the owner confirms them").argument("<file>", FINDINGS_INPUT_HELP).option("--source <accounts>", MAILBOX_HELP).option("--key <key>", "the findings key `mail review --holder` gave in its mail-findings.add step").option("--dry-run", "check the batch as staging would, invoices, payments and orders tried and rolled back, and stage nothing; answers valid and every finding's problem at once").addHelpText("after", INPUT_HELP).action(async (file, given2) => {
6807
7799
  const read = await readFindingsInput(file, environmentOf(program).stdin ?? process.stdin);
6808
- const text3 = keyed(read, given.key);
6809
- const input = given.dryRun ? readMailFindingsJson(text3) : parseMailFindingsJson(text3);
7800
+ const text3 = keyed(read, given2.key);
7801
+ const input = given2.dryRun ? readMailFindingsJson(text3) : parseMailFindingsJson(text3);
6810
7802
  const author = await whoRuns(program, env, { question: "" });
6811
7803
  const agent = author === "owner" ? { bot: "memo-mail-findings" } : author;
6812
- await run(given.json, async (store) => {
6813
- const mailbox = await oneMailboxOf(store, env, given.source);
7804
+ await run(given2.json, async (store) => {
7805
+ const mailbox = await oneMailboxOf(store, env, given2.source);
6814
7806
  const { input: kept, duplicates } = await withoutDuplicates(store, input);
6815
7807
  const noted = duplicates.length ? { duplicates } : {};
6816
7808
  if (duplicates.length > 0 && kept.findings.length === 0)
6817
7809
  return itemAnswer({
6818
- dryRun: Boolean(given.dryRun),
7810
+ dryRun: Boolean(given2.dryRun),
6819
7811
  valid: true,
6820
7812
  staged: false,
6821
7813
  findings: 0,
6822
7814
  problems: [],
6823
7815
  ...noted
6824
7816
  });
6825
- if (!given.dryRun)
7817
+ if (!given2.dryRun)
6826
7818
  return itemAnswer({ ...await store.mailFindings.stage(mailbox, kept, agent), ...noted });
6827
7819
  const checked = await store.mailFindings.check(mailbox, kept, agent);
6828
7820
  const issues = checked.problems.map((one2) => ({
@@ -6833,22 +7825,22 @@ var mailFindingsCommand = /* @__PURE__ */ __name((program, mail, streams, env) =
6833
7825
  return itemAnswer({ dryRun: true, ...checked, ...noted }, issues.length ? { meta: { complete: false, issues } } : void 0);
6834
7826
  });
6835
7827
  });
6836
- json5(annotate(findings.command("show"), { effects: LOCAL_READ, output: { entity: "mail_findings" } })).description("one findings batch: its findings with their evidence, earlier decisions and the review receipt").summary("one findings batch with its evidence and decisions").argument("<id>", "the batch id `mail findings add` or `list` gave").action((id, given) => run(given.json, async (store) => itemAnswer(await store.mailFindings.get(id))));
6837
- withQuery(json5(annotate(findings.command("list"), { effects: LOCAL_READ, output: { entity: "mail_findings" } })), FINDINGS_QUERY2).description("mail findings batches, newest first; status:proposed is what waits for the owner").option("--source <accounts>", "only this mailbox's batches: email:<address>").option("--limit <n>", "batches per page, at most 50", positive, 20).option("--page <n>", "which page, from 1", positive, 1).action((words, given) => run(given.json, async (store) => {
7828
+ json3(annotate(findings.command("show"), { effects: LOCAL_READ, output: { entity: "mail_findings" } })).description("one findings batch: its findings with their evidence, earlier decisions and the review receipt").summary("one findings batch with its evidence and decisions").argument("<id>", "the batch id `mail findings add` or `list` gave").action((id, given2) => run(given2.json, async (store) => itemAnswer(await store.mailFindings.get(id))));
7829
+ withQuery(json3(annotate(findings.command("list"), { effects: LOCAL_READ, output: { entity: "mail_findings" } })), FINDINGS_QUERY2).description("mail findings batches, newest first; status:proposed is what waits for the owner").option("--source <accounts>", "only this mailbox's batches: email:<address>").option("--limit <n>", "batches per page, at most 50", positive, 20).option("--page <n>", "which page, from 1", positive, 1).action((words, given2) => run(given2.json, async (store) => {
6838
7830
  const status = queryTerms(words, FINDINGS_QUERY2, "mail findings list").get("status");
6839
- const account2 = given.source ? await oneMailboxOf(store, env, given.source) : void 0;
7831
+ const account2 = given2.source ? await oneMailboxOf(store, env, given2.source) : void 0;
6840
7832
  const found = await store.mailFindings.list({
6841
- limit: given.limit,
6842
- offset: (given.page - 1) * given.limit,
7833
+ limit: given2.limit,
7834
+ offset: (given2.page - 1) * given2.limit,
6843
7835
  ...account2 === void 0 ? {} : { account: account2 },
6844
7836
  ...status === void 0 ? {} : { status }
6845
7837
  });
6846
7838
  return listAnswer("mail findings list", {
6847
7839
  items: found.items,
6848
- limit: given.limit,
6849
- page: given.page,
7840
+ limit: given2.limit,
7841
+ page: given2.page,
6850
7842
  has_more: found.hasMore,
6851
- args: { query: words.join(" "), ...given.source ? { source: given.source } : {}, limit: given.limit }
7843
+ args: { query: words.join(" "), ...given2.source ? { source: given2.source } : {}, limit: given2.limit }
6852
7844
  });
6853
7845
  }));
6854
7846
  }, "mailFindingsCommand");
@@ -6974,10 +7966,10 @@ var mcpCommandDefinition = /* @__PURE__ */ __name((program, streams, env, create
6974
7966
  }).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) => {
6975
7967
  if (!options.http && (options.port !== void 0 || options.publicUrl !== void 0))
6976
7968
  throw new CliError("validation_error", "--port and --public-url require --http");
6977
- const { createMemoServer } = await import("./server-ZHFC3PIP.js");
7969
+ const { createMemoServer } = await import("./server-MVJU7QG4.js");
6978
7970
  const build = /* @__PURE__ */ __name(() => createMemoServer(env, createProgram2, options.permission), "build");
6979
7971
  if (options.http) {
6980
- const { httpLockFile, mcpUrlOf, portOf, publicUrlOf, serveOverHttp } = await import("./mcp-Y4XMDC5Q.js");
7972
+ const { httpLockFile, mcpUrlOf, portOf, publicUrlOf, serveOverHttp } = await import("./mcp-QX2D6EXA.js");
6981
7973
  const publicUrl = publicUrlOf(options.publicUrl, {
6982
7974
  missing: "--http",
6983
7975
  reaches: "the browser apps reach memo",
@@ -7029,7 +8021,7 @@ var mcpCommandDefinition = /* @__PURE__ */ __name((program, streams, env, create
7029
8021
  });
7030
8022
  });
7031
8023
  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() {
7032
- const { revokeAll } = await import("./mcp-Y4XMDC5Q.js");
8024
+ const { revokeAll } = await import("./mcp-QX2D6EXA.js");
7033
8025
  revokeAll(httpTokenFile(env));
7034
8026
  out.print(this.opts().json, itemAnswer({ revoked: true }));
7035
8027
  });
@@ -7092,28 +8084,28 @@ var readStoredMeetingPassage = /* @__PURE__ */ __name(async (store, env, source,
7092
8084
  // dist/meetings/command.js
7093
8085
  var meetingReadCommands = /* @__PURE__ */ __name((program, streams, env) => {
7094
8086
  const { print } = answers(program, streams, env);
7095
- const source = /* @__PURE__ */ __name((given) => sourceOf(given, (text3) => streams.diagnostic(text3)), "source");
8087
+ const source = /* @__PURE__ */ __name((given2) => sourceOf(given2, (text3) => streams.diagnostic(text3)), "source");
7096
8088
  const output = /* @__PURE__ */ __name((command) => sourceOptions(command, MEETING_ACCOUNT_HELP).option("--json", "print the standard JSON answer"), "output");
7097
8089
  const grammar = createMeetingSearchCommand(program);
7098
8090
  const search2 = overrideSharedContract(grammar, "Memo selects an explicit stored source and uses native tag: queries instead of a tag flag, with command-local JSON output.", (command) => {
7099
8091
  Reflect.set(command, "options", command.options.filter((option) => option.long !== "--tag"));
7100
8092
  output(command);
7101
8093
  });
7102
- search2.action(async (query, given) => {
7103
- const input = meetingHitSearchRequest(query, given);
7104
- const result = await withStore(env, (store) => searchStoredMeetings(store, env, source(given), query, input, meetingSearchArguments(query, given), {
7105
- ...given,
8094
+ search2.action(async (query, given2) => {
8095
+ const input = meetingHitSearchRequest(query, given2);
8096
+ const result = await withStore(env, (store) => searchStoredMeetings(store, env, source(given2), query, input, meetingSearchArguments(query, given2), {
8097
+ ...given2,
7106
8098
  timesReadIn: grammar.getOptionValue("timesReadIn")
7107
8099
  }));
7108
- print(given.json, result);
8100
+ print(given2.json, result);
7109
8101
  });
7110
8102
  overrideSharedContract(createMeetingPassageCommand(program), "Memo passage reads an explicitly selected stored source and exposes command-local JSON output.", (command) => {
7111
8103
  output(command);
7112
- }).action(async (reference2, given) => {
7113
- const format = given.json ? "json" : given.format ?? "text";
7114
- const input = meetingPassageRequest(reference2, { ...given, format });
7115
- const result = await withStore(env, (store) => readStoredMeetingPassage(store, env, source(given), reference2, input));
7116
- print(given.json, itemAnswer(result.packet), result.content);
8104
+ }).action(async (reference2, given2) => {
8105
+ const format = given2.json ? "json" : given2.format ?? "text";
8106
+ const input = meetingPassageRequest(reference2, { ...given2, format });
8107
+ const result = await withStore(env, (store) => readStoredMeetingPassage(store, env, source(given2), reference2, input));
8108
+ print(given2.json, itemAnswer(result.packet), result.content);
7117
8109
  });
7118
8110
  }, "meetingReadCommands");
7119
8111
 
@@ -7126,13 +8118,13 @@ var communicationSource = /* @__PURE__ */ __name(async (store, env, id) => {
7126
8118
  });
7127
8119
  const key = await oneAccountOf(store, env, `${id.slice(0, dot)}:${id.slice(dot + 1)}`, "--context-source");
7128
8120
  const held = await store.accounts.storedAccount(key);
7129
- const listed = entriesOfList(accountName(key), {
8121
+ const listed2 = entriesOfList(accountName(key), {
7130
8122
  held: [held],
7131
8123
  profiles: {},
7132
8124
  groups: {},
7133
8125
  running: { provider: "email", command: "memo" }
7134
8126
  })[0]?.accounts[0];
7135
- const kind = listed?.kind === "messages" ? "message" : listed?.kind === "mail" ? "mail" : void 0;
8127
+ const kind = listed2?.kind === "messages" ? "message" : listed2?.kind === "mail" ? "mail" : void 0;
7136
8128
  if (kind === void 0)
7137
8129
  throw new CliError("validation_error", `${id}: select one stored messenger profile or mailbox`, {
7138
8130
  param: "communications.sources"
@@ -7510,8 +8502,8 @@ var refuseOverMcp = /* @__PURE__ */ __name((options, mcp2) => {
7510
8502
  param: "export"
7511
8503
  });
7512
8504
  }, "refuseOverMcp");
7513
- var textOf = /* @__PURE__ */ __name((options, given) => {
7514
- const sources = [given, options.text, options.textFile].filter((value) => value !== void 0);
8505
+ var textOf = /* @__PURE__ */ __name((options, given2) => {
8506
+ const sources = [given2, options.text, options.textFile].filter((value) => value !== void 0);
7515
8507
  if (sources.length !== 1)
7516
8508
  throw new CliError("validation_error", "give the text once: as an argument, --text or --text-file");
7517
8509
  if (options.textFile !== void 0)
@@ -7575,14 +8567,14 @@ var notesCommandDefinition = /* @__PURE__ */ __name((program, streams, env) => {
7575
8567
  ...answer.backlinks.length ? [`linked from: ${answer.backlinks.map(({ from }) => from).join(", ")}`] : []
7576
8568
  ].join("\n"));
7577
8569
  });
7578
- withQuery(annotate(notes2.command("list"), { effects: LOCAL_READ }).description("notes, newest first"), NOTES_LIST_QUERY).option("--limit <n>", "most notes, at most 500", positive, 20).option("--page <n>", "which page, from 1", positive, 1).option("--json", "print JSON; --json=id,title keeps only those fields").action(async (words, { json: json7, ...paging }) => {
7579
- const terms = queryTerms(words, NOTES_LIST_QUERY, "notes list");
7580
- const about = terms.get("about");
7581
- const source = terms.get("source");
7582
- const search2 = terms.get("text");
7583
- if (about !== void 0 && terms.size > 1)
8570
+ withQuery(annotate(notes2.command("list"), { effects: LOCAL_READ }).description("notes, newest first"), NOTES_LIST_QUERY).option("--limit <n>", "most notes, at most 500", positive, 20).option("--page <n>", "which page, from 1", positive, 1).option("--json", "print JSON; --json=id,title keeps only those fields").action(async (words, { json: json5, ...paging }) => {
8571
+ const terms2 = queryTerms(words, NOTES_LIST_QUERY, "notes list");
8572
+ const about = terms2.get("about");
8573
+ const source = terms2.get("source");
8574
+ const search2 = terms2.get("text");
8575
+ if (about !== void 0 && terms2.size > 1)
7584
8576
  throw new CliError("validation_error", "about: stands alone in notes list: its notes are found through links");
7585
- const options = { ...paging, json: json7 };
8577
+ const options = { ...paging, json: json5 };
7586
8578
  const page = await withNotes(async (store) => listNotes(store, {
7587
8579
  limit: options.limit,
7588
8580
  offset: (options.page - 1) * options.limit,
@@ -7601,9 +8593,9 @@ var notesCommandDefinition = /* @__PURE__ */ __name((program, streams, env) => {
7601
8593
  output: { entity: "note" },
7602
8594
  literal_after_dashes: true
7603
8595
  }).description("write a note of your own about messages, people, projects or other notes").argument("[text]", "the note; or --text, or --text-file").option("--text <text>", "the note").option("--text-file <path>", "read the note from a file; - reads stdin").option("--title <title>", "a title").option("--subject <ref>", "what it is about: <messenger>:<name or id>, msg:, chat:, person:, organization:, project:, task:, note:, document:, meeting:; repeat for more", collect).option("--meeting <id>", "also about this meeting, by its store id, with --account");
7604
- writeOptions(noteAdd, `the account of --meeting: ${MEETING_WRITE_HELP}`).option("--export [dir]", "also write it as a file \u2014 to this folder, or notes.export.dir").option("--format <format>", `the file's format: ${DIALECTS.join(", ")}`, formatOf).option("--json", "print JSON; --json=id,title keeps only those fields").action(async (given, options, command) => {
8596
+ writeOptions(noteAdd, `the account of --meeting: ${MEETING_WRITE_HELP}`).option("--export [dir]", "also write it as a file \u2014 to this folder, or notes.export.dir").option("--format <format>", `the file's format: ${DIALECTS.join(", ")}`, formatOf).option("--json", "print JSON; --json=id,title keeps only those fields").action(async (given2, options, command) => {
7605
8597
  refuseOverMcp(options, isMcpRun(command, env));
7606
- const body = textOf(options, given);
8598
+ const body = textOf(options, given2);
7607
8599
  const value = writeAccountOf(options, (text3) => streams.diagnostic(text3));
7608
8600
  if (options.meeting === void 0 && value !== void 0)
7609
8601
  throw new CliError("validation_error", "--account selects the account of --meeting");
@@ -7884,8 +8876,105 @@ var peopleCommand = /* @__PURE__ */ __name((program, streams, env) => {
7884
8876
  });
7885
8877
  }, "peopleCommand");
7886
8878
 
7887
- // dist/records/import.js
7888
- import { readFile } from "node:fs/promises";
8879
+ // dist/records/input.js
8880
+ import { open } from "node:fs/promises";
8881
+ var PHONE = "phone";
8882
+ var BOM = /^\uFEFF/;
8883
+ var errnoOf = /* @__PURE__ */ __name((error) => typeof error === "object" && error !== null && "code" in error ? String(error.code) : void 0, "errnoOf");
8884
+ var linesOf = /* @__PURE__ */ __name(async (file, stdin) => {
8885
+ if (file === "-")
8886
+ return jsonlLines(stdin);
8887
+ try {
8888
+ const handle = await open(file);
8889
+ if (!(await handle.stat()).isFile()) {
8890
+ await handle.close();
8891
+ throw Object.assign(new Error(`${file} is a folder`), { code: "EISDIR" });
8892
+ }
8893
+ return jsonlLines(handle.createReadStream({ encoding: "utf8" }));
8894
+ } catch (error) {
8895
+ if (errnoOf(error) === "ENOENT")
8896
+ throw new CliError("not_found", `no records file ${file}: give a file that exists, or - for stdin`, {
8897
+ reason: "records.file-missing",
8898
+ path: file
8899
+ });
8900
+ const why = errnoOf(error) === "EISDIR" ? "it is a folder" : errnoOf(error) === "EACCES" ? "no permission" : "unreadable";
8901
+ throw new CliError("validation_error", `the records file ${file} cannot be read: ${why}`, {
8902
+ reason: "records.file-unreadable",
8903
+ path: file,
8904
+ why
8905
+ });
8906
+ }
8907
+ }, "linesOf");
8908
+ var headerOf = /* @__PURE__ */ __name((line3) => {
8909
+ try {
8910
+ const value = JSON.parse(line3);
8911
+ return value && typeof value === "object" && !Array.isArray(value) && !("records" in value) ? value : void 0;
8912
+ } catch {
8913
+ return void 0;
8914
+ }
8915
+ }, "headerOf");
8916
+ var accountIn = /* @__PURE__ */ __name((envelope, given2) => {
8917
+ const provider = envelope?.source?.provider;
8918
+ return typeof provider === "string" && given2.startsWith(`${provider}:`) ? given2.slice(provider.length + 1) : given2;
8919
+ }, "accountIn");
8920
+ var deviceOf = /* @__PURE__ */ __name((given2) => {
8921
+ const at = given2.indexOf(":");
8922
+ if (at < 0)
8923
+ return given2;
8924
+ if (given2.slice(0, at) !== PHONE)
8925
+ throw new CliError("validation_error", "a vCard file holds a phone's contacts: --account phone:<device>", {
8926
+ param: "--account"
8927
+ });
8928
+ return given2.slice(at + 1);
8929
+ }, "deviceOf");
8930
+ var importRecords = /* @__PURE__ */ __name(async (store, { file, stdin, account: account2, dryRun, onIssue }) => {
8931
+ const iterator = (await linesOf(file, stdin))[Symbol.asyncIterator]();
8932
+ const before = [];
8933
+ let next = await iterator.next();
8934
+ while (!next.done && next.value.replace(BOM, "").trim() === "") {
8935
+ before.push(next.value);
8936
+ next = await iterator.next();
8937
+ }
8938
+ async function* rest() {
8939
+ for (let line3 = await iterator.next(); !line3.done; line3 = await iterator.next())
8940
+ yield line3.value;
8941
+ }
8942
+ __name(rest, "rest");
8943
+ const whole2 = /* @__PURE__ */ __name(async (first2) => {
8944
+ const lines2 = [...before, ...first2];
8945
+ for await (const line3 of rest())
8946
+ lines2.push(line3);
8947
+ return lines2.join("\n");
8948
+ }, "whole");
8949
+ if (next.done)
8950
+ return ingest(store, envelopeOfText(before.join("\n")), { account: account2, dryRun, onIssue });
8951
+ const first = next.value.replace(BOM, "");
8952
+ if (isVcard(first)) {
8953
+ const { vcard, ...receipt } = await ingestVcard(store, await whole2([first]), {
8954
+ account: deviceOf(account2),
8955
+ provider: PHONE,
8956
+ batchId: `vcard-${(/* @__PURE__ */ new Date()).toISOString()}`,
8957
+ dryRun,
8958
+ onIssue
8959
+ });
8960
+ return { ...receipt, vcard: vcard.map((one2) => ({ ...one2, card: one2.card + 1 })) };
8961
+ }
8962
+ const header = headerOf(first);
8963
+ if (header !== void 0) {
8964
+ async function* all() {
8965
+ try {
8966
+ yield first;
8967
+ yield* rest();
8968
+ } finally {
8969
+ await iterator.return?.();
8970
+ }
8971
+ }
8972
+ __name(all, "all");
8973
+ return ingestLines(store, all(), { account: accountIn(header, account2), dryRun, onIssue });
8974
+ }
8975
+ const envelope = envelopeOfText(await whole2([first]));
8976
+ return ingest(store, envelope, { account: accountIn(envelope, account2), dryRun, onIssue });
8977
+ }, "importRecords");
7889
8978
 
7890
8979
  // dist/records/mapping.js
7891
8980
  var RECORD_QUERY = {
@@ -7894,7 +8983,11 @@ var RECORD_QUERY = {
7894
8983
  fields: [
7895
8984
  termField("type", "kw", "type:organization"),
7896
8985
  termField("waiting", "bool", "waiting:true"),
7897
- termField("flagged", "bool", "flagged:true")
8986
+ termField("flagged", "bool", "flagged:true"),
8987
+ termField("unmatched", "bool", "unmatched:true"),
8988
+ termField("entity", "ref", 'entity:"organization:3"'),
8989
+ termField("batch", "kw", "batch:2026-11-07"),
8990
+ termField("deleted", "bool", "deleted:true")
7898
8991
  ]
7899
8992
  };
7900
8993
  var sourceOf4 = /* @__PURE__ */ __name((account2) => {
@@ -7907,84 +9000,149 @@ var sourceOf4 = /* @__PURE__ */ __name((account2) => {
7907
9000
  return { provider, account: name2 };
7908
9001
  }, "sourceOf");
7909
9002
  var recordOf = /* @__PURE__ */ __name((record2) => {
7910
- const at = record2.indexOf(":");
7911
- if (at < 1 || at === record2.length - 1)
7912
- throw new CliError("validation_error", `${record2} is not <type>:<external_id>, such as organization:client`, {
7913
- param: "record"
7914
- });
9003
+ const from = record2.startsWith("custom:") ? "custom:".length : 0;
9004
+ const at = record2.indexOf(":", from);
9005
+ if (at <= from || at === record2.length - 1)
9006
+ throw new CliError("validation_error", `${record2} is not <type>:<external_id>, such as organization:client or custom:quote:Q-7`, { param: "record" });
7915
9007
  return { type: record2.slice(0, at), externalId: record2.slice(at + 1) };
7916
9008
  }, "recordOf");
9009
+ var RECORD_HELP = "<type>:<external_id> as the source names it, such as organization:client or custom:quote:Q-7";
7917
9010
  var ACCOUNT_HELP = "the source, <provider>:<account> as the envelope's source names it, such as sheet:rentals";
7918
9011
  var recordMappingCommands = /* @__PURE__ */ __name((records, program, streams, env) => {
7919
9012
  const { run } = answers(program, streams, env);
7920
- withQuery(annotate(records.command("list"), { effects: LOCAL_READ }).description("a source's records, newest first; waiting:true lists those whose invoice or payment waits for records link"), RECORD_QUERY).summary("a source's records; waiting:true lists what needs records link").option("--account <account>", ACCOUNT_HELP).option("--limit <n>", "most records, up to 500", positive, 100).option("--json", "print JSON; --json=type,external_id,entity keeps only those fields").action((words, given) => run(given.json, async (store) => {
7921
- const source = sourceOf4(given.account);
7922
- const terms = queryTerms(words, RECORD_QUERY, "records list");
9013
+ withQuery(annotate(records.command("list"), { effects: LOCAL_READ }).description("a source's records, newest first; waiting:true lists those that wait for a record they name, unmatched:true the people, organizations and projects whose identifiers fit more than one of yours, entity: those mapped to one of your entries"), RECORD_QUERY).summary("a source's records; waiting:true lists what needs records link").option("--account <account>", ACCOUNT_HELP).option("--limit <n>", "most records, up to 500", positive, 100).option("--json", "print JSON; --json=type,external_id,entity keeps only those fields").action((words, given2) => run(given2.json, async (store) => {
9014
+ const source = sourceOf4(given2.account);
9015
+ const terms2 = queryTerms(words, RECORD_QUERY, "records list");
7923
9016
  const filter = {
7924
9017
  ...source,
7925
- ...terms.has("type") ? { type: terms.get("type") } : {},
7926
- ...terms.get("waiting") === "true" ? { waiting: true } : {},
7927
- ...terms.get("flagged") === "true" ? { flagged: true } : {}
9018
+ ...terms2.has("type") ? { type: terms2.get("type") } : {},
9019
+ ...terms2.get("waiting") === "true" ? { waiting: true } : {},
9020
+ ...terms2.get("flagged") === "true" ? { flagged: true } : {},
9021
+ ...terms2.get("unmatched") === "true" ? { unmatched: true } : {},
9022
+ ...terms2.has("entity") ? { entity: terms2.get("entity") } : {},
9023
+ ...terms2.has("batch") ? { batch: terms2.get("batch") } : {},
9024
+ ...terms2.has("deleted") ? { deleted: terms2.get("deleted") === "true" } : {}
7928
9025
  };
7929
- return pageOf("records list", given.limit, (most) => store.records.list({ ...filter, limit: most }));
9026
+ return pageOf("records list", given2.limit, (most) => store.records.list({ ...filter, limit: most }));
7930
9027
  }));
7931
- byOption(annotate(records.command("link"), { effects: LOCAL_WRITE, output: { entity: "source_record" } }).description("say which of your entries a source's record is (organization:client is organization:3); never done by name. Records that waited for it become proposals in memo review. Only you link; an agent is refused").summary("say which of your entries a source's record is").argument("<record>", "<type>:<external_id> as the source names it, such as organization:client").argument("<ref>", "your entry of the same type: person:<id>, organization:<id> or project:<id>").option("--account <account>", ACCOUNT_HELP).option("--json", "print JSON; --json=type,external_id,entity keeps only those fields")).action(async (record2, ref, given, command) => {
7932
- const by = await whoRuns(command, env, { asOwner: given.asOwner, question: `link ${record2} to ${ref} as you?` });
7933
- await run(given.json, async (store) => itemAnswer(await store.records.map({ ...sourceOf4(given.account), ...recordOf(record2) }, ref, by)));
9028
+ byOption(annotate(records.command("link"), { effects: LOCAL_WRITE, output: { entity: "source_record" } }).description("say which of your entries a source's record is (organization:client is organization:3); never done by name. Records that waited for it become proposals in memo review. Only you link; an agent is refused").summary("say which of your entries a source's record is").argument("<record>", RECORD_HELP).argument("<ref>", "your entry of the same type: person:<id>, organization:<id> or project:<id>").option("--account <account>", ACCOUNT_HELP).option("--json", "print JSON; --json=type,external_id,entity keeps only those fields")).action(async (record2, ref, given2, command) => {
9029
+ const by = await whoRuns(command, env, { asOwner: given2.asOwner, question: `link ${record2} to ${ref} as you?` });
9030
+ await run(given2.json, async (store) => itemAnswer(await store.records.map({ ...sourceOf4(given2.account), ...recordOf(record2) }, ref, by)));
7934
9031
  });
7935
9032
  }, "recordMappingCommands");
7936
9033
 
9034
+ // dist/records/record-commands.js
9035
+ var INCOMING = 100;
9036
+ var codeOf = /* @__PURE__ */ __name((reason) => {
9037
+ const code = REASONS2.find((one2) => one2.reason === reason)?.code;
9038
+ return code === void 0 || code === "internal_error" ? "validation_error" : code;
9039
+ }, "codeOf");
9040
+ var storedRecord = /* @__PURE__ */ __name(async (store, account2, record2) => {
9041
+ const key = { ...sourceOf4(account2), ...recordOf(record2) };
9042
+ const found = await store.records.get(key);
9043
+ if (found === void 0)
9044
+ throw new CliError("not_found", `no record ${record2} from ${key.provider}:${key.account}; records list shows them`, {
9045
+ reason: "records.not-stored",
9046
+ record: record2
9047
+ });
9048
+ return found;
9049
+ }, "storedRecord");
9050
+ var matchText = /* @__PURE__ */ __name((run) => [
9051
+ `matched ${run.linked}, created ${run.created}`,
9052
+ ...run.proposed.length ? [`proposed for your review: ${run.proposed.join(" ")}`] : [],
9053
+ ...run.unmatched.map((one2) => `unmatched ${one2.key.type}:${one2.key.externalId}: ${one2.candidates.length ? `could be ${one2.candidates.join(" or ")}` : one2.reason}`),
9054
+ ...run.errors.map((one2) => `refused ${one2.pointer} \xB7 ${one2.message} (${one2.code})`),
9055
+ ...run.truncated ? ["the lists stop at 1000 entries each; the counts are exact"] : []
9056
+ ].join("\n"), "matchText");
9057
+ var recordCommands = /* @__PURE__ */ __name((records, { run, print }, withStore2) => {
9058
+ jsonOption(annotate(records.command("show"), { effects: LOCAL_READ, output: { entity: "source_record" } }).argument("<record>", RECORD_HELP).option("--account <account>", ACCOUNT_HELP), "fields,relations,incoming,entity").description(`one record as its source said it: its fields, the records it names, the records that name it (incoming, the first ${INCOMING}) and the entry made from it`).summary("one record as its source said it").action((record2, given2) => run(given2.json, async (store) => {
9059
+ const found = await storedRecord(store, given2.account, record2);
9060
+ const incoming = await store.records.incoming(found, { limit: INCOMING + 1 });
9061
+ return itemAnswer({
9062
+ ...found,
9063
+ incoming: { items: incoming.slice(0, INCOMING), hasMore: incoming.length > INCOMING }
9064
+ });
9065
+ }));
9066
+ jsonOption(annotate(records.command("delete"), { effects: LOCAL_WRITE, output: { entity: "records_receipt" } }).argument("<record>", RECORD_HELP).option("--account <account>", ACCOUNT_HELP), "deleted,flagged,errors").description("say a source no longer has a record, as an import's delete does: the record is kept as deleted, and the entry made from it stays, flagged for you to reject or keep").summary("mark a source's record deleted").action(async (record2, given2) => {
9067
+ const receipt = await withStore2(async (store) => {
9068
+ const found = await storedRecord(store, given2.account, record2);
9069
+ return ingest(store, {
9070
+ schema_version: RECORDS_SCHEMA_VERSION,
9071
+ source: {
9072
+ provider: found.provider,
9073
+ account: found.account,
9074
+ batch_id: `delete-${(/* @__PURE__ */ new Date()).toISOString()}`
9075
+ },
9076
+ records: [
9077
+ {
9078
+ key: "delete",
9079
+ type: found.type,
9080
+ external_id: found.externalId,
9081
+ operation: "delete",
9082
+ ...found.revision === null ? {} : { revision: found.revision }
9083
+ }
9084
+ ]
9085
+ }, { account: found.account });
9086
+ });
9087
+ const [refused] = receipt.errors;
9088
+ if (refused)
9089
+ throw new CliError(codeOf(refused.code), refused.message, { reason: refused.code });
9090
+ print(given2.json, itemAnswer(receipt), receipt.deleted === 0 ? `${record2} was already deleted` : `deleted ${record2}${receipt.flagged.length ? `; ${receipt.flagged.map((one2) => one2.entity).join(" ")} kept, flagged for you` : ""}`);
9091
+ });
9092
+ jsonOption(annotate(records.command("match"), { effects: LOCAL_WRITE, output: { entity: "records_match" } }).option("--account <account>", ACCOUNT_HELP), "linked,created,unmatched").description("link every waiting person, organization and project of a source to the one entry its e-mail, phone or other identifier names, or make one, as an import does; never by name. Two or more fits wait for records link").summary("match a source's waiting people and organizations").action((given2) => withStore2(async (store) => store.records.match(sourceOf4(given2.account))).then((found) => print(given2.json, itemAnswer(found), matchText(found))));
9093
+ }, "recordCommands");
9094
+
7937
9095
  // dist/records/import.js
7938
- var readAll = /* @__PURE__ */ __name(async (file, stdin) => {
7939
- if (file !== "-")
7940
- return readFile(file, "utf8");
7941
- let text3 = "";
7942
- stdin.setEncoding("utf8");
7943
- for await (const chunk of stdin)
7944
- text3 += chunk;
7945
- return text3;
7946
- }, "readAll");
7947
- var envelopeOf = /* @__PURE__ */ __name((text3) => {
7948
- try {
7949
- const whole2 = JSON.parse(text3);
7950
- if (whole2 && typeof whole2 === "object" && "records" in whole2)
7951
- return whole2;
7952
- } catch {
7953
- }
7954
- return envelopeOfJsonl(text3);
7955
- }, "envelopeOf");
7956
- var accountIn = /* @__PURE__ */ __name((envelope, given) => {
7957
- const provider = envelope?.source?.provider;
7958
- return typeof provider === "string" && given.startsWith(`${provider}:`) ? given.slice(provider.length + 1) : given;
7959
- }, "accountIn");
9096
+ var kindsOf = /* @__PURE__ */ __name((proposed) => [...new Set(proposed.map((ref) => ref.slice(0, ref.indexOf(":"))))], "kindsOf");
9097
+ var pointerOf = /* @__PURE__ */ __name((pointer) => pointer || "/", "pointerOf");
9098
+ var refusedLine = /* @__PURE__ */ __name((one2) => `refused ${pointerOf(one2.pointer)} \xB7 ${one2.message} (${one2.code})`, "refusedLine");
7960
9099
  var receiptText = /* @__PURE__ */ __name((receipt) => [
7961
9100
  `${receipt.dryRun ? "would import" : "imported"} ${receipt.source?.batchId ?? "nothing"}: ${receipt.created} created, ${receipt.updated} updated, ${receipt.unchanged} unchanged, ${receipt.deleted} deleted, ${receipt.refused} refused`,
7962
- ...receipt.proposed.length ? [`proposed for your review (memo review kind:invoice,payment): ${receipt.proposed.join(" ")}`] : [],
9101
+ ...receipt.proposed.length ? [
9102
+ `proposed for your review (memo review list kind:${kindsOf(receipt.proposed).join(",")}): ` + receipt.proposed.join(" ")
9103
+ ] : [],
7963
9104
  ...receipt.waiting.map((one2) => `waiting ${one2.key}: no entity yet for ${one2.missing.join(", ")}`),
9105
+ ...receipt.unmatched.map((one2) => `unmatched ${one2.key}: ${one2.candidates.length ? `could be ${one2.candidates.join(" or ")}` : one2.reason}; you say which with memo records link`),
7964
9106
  ...receipt.flagged.map((one2) => `changed at the source ${one2.key}: ${one2.entity} kept as it was`),
7965
- ...receipt.errors.map((one2) => `refused ${one2.pointer} \xB7 ${one2.message} (${one2.code})`)
9107
+ ...receipt.ignored.map((one2) => `kept as data only ${one2.key} ${one2.pointer} (${one2.reason})`),
9108
+ ...(receipt.vcard ?? []).map((one2) => `notice card ${one2.card}: ${one2.message}`),
9109
+ ...receipt.errors.map(refusedLine),
9110
+ ...receipt.truncated ? ["the lists stop at 1000 entries each; the counts are exact"] : []
7966
9111
  ].join("\n"), "receiptText");
9112
+ var HOLDS_LOCK = "a dry run holds the store's write lock and grows the write-ahead log for its length";
7967
9113
  var recordsCommand = /* @__PURE__ */ __name((program, streams, env) => {
7968
- const { print } = answers(program, streams, env);
7969
- const records = program.command("records").description("what a source said, kept per account; invoices and payments from it wait for your review").summary("what a source said, kept per account");
7970
- const importing = /* @__PURE__ */ __name((command, dryRun) => command.argument("<file>", "a records envelope as JSON, or JSONL (a header line, then a record per line); - for stdin").option("--account <account>", "the source the envelope is for: <provider>:<account> (sheet:rentals) or its source.account alone").option("--json", "print JSON; --json=created,errors keeps only those fields").action(async (file, given) => {
7971
- const account2 = given.account?.trim();
9114
+ const answered = answers(program, streams, env);
9115
+ const { print } = answered;
9116
+ const records = program.command("records").description("what a source said, kept per account; what it says about money waits for your review").summary("what a source said, kept per account");
9117
+ const importing = /* @__PURE__ */ __name((command, dryRun) => command.argument("<file>", "a records envelope as JSON, JSONL (a header line, then a record per line, read as it streams) or a vCard address book (.vcf, into phone:<device>); - for stdin").option("--account <account>", "the source the envelope is for: <provider>:<account> (sheet:rentals) or its source.account alone; phone:<device> for a vCard file").option("--json", "print JSON; --json=created,errors keeps only those fields").action(async (file, given2) => {
9118
+ const account2 = given2.account?.trim();
7972
9119
  if (!account2)
7973
9120
  throw new CliError("validation_error", "name the source account the envelope is for: --account <account>", {
7974
9121
  param: "--account"
7975
9122
  });
7976
- const envelope = envelopeOf(await readAll(file, environmentOf(program).stdin ?? process.stdin));
7977
- const receipt = await withStore(env, (store) => ingest(store, envelope, { account: accountIn(envelope, account2), dryRun: dryRun ?? given.dryRun === true }));
9123
+ const receipt = await withStore(env, (store) => importRecords(store, {
9124
+ file,
9125
+ stdin: environmentOf(program).stdin ?? process.stdin,
9126
+ account: account2,
9127
+ dryRun: dryRun ?? given2.dryRun === true,
9128
+ onIssue: /* @__PURE__ */ __name((issue) => streams.diagnostic(`${refusedLine(issue)}
9129
+ `), "onIssue")
9130
+ }));
7978
9131
  const issues = receipt.errors.map((one2) => ({
7979
9132
  code: "validation_error",
7980
- source: one2.pointer,
9133
+ source: pointerOf(one2.pointer),
7981
9134
  reason: one2.code
7982
9135
  }));
7983
- print(given.json, itemAnswer(receipt, issues.length ? { meta: { complete: false, issues } } : void 0), receiptText(receipt));
9136
+ print(given2.json, itemAnswer(receipt, issues.length ? { meta: { complete: false, issues } } : void 0), receiptText(receipt));
7984
9137
  }), "importing");
7985
- importing(annotate(records.command("import"), { effects: LOCAL_WRITE, output: { entity: "records_receipt" } }).description("bring a source's records into the store, once: the same file twice changes nothing, a lower revision is refused, and an invoice or a payment becomes a proposal for you, never confirmed money").summary("import a source's records; money waits for your review").option("--dry-run", "check and plan the import; write nothing"), void 0);
7986
- importing(annotate(records.command("check"), { effects: LOCAL_READ, output: { entity: "records_receipt" } }).description("what records import would do with the file, as its receipt, writing nothing").summary("check a records file against the store; write nothing"), true);
9138
+ importing(annotate(records.command("import"), { effects: LOCAL_WRITE, output: { entity: "records_receipt" } }).description("bring a source's records into the store, once: the same file twice changes nothing, a lower revision is refused, and anything that feeds money totals becomes a proposal for you, never confirmed money. Each refusal is also printed on stderr as it happens, one line each, past the receipt's 1000").summary("import a source's records; money waits for your review").option("--dry-run", `check and plan the import; write nothing. ${HOLDS_LOCK}`), void 0);
9139
+ importing(
9140
+ // A dry run holds the write lock for its length, so MCP gates it as a write.
9141
+ annotate(records.command("check"), { effects: LOCAL_WRITE, output: { entity: "records_receipt" } }).description(`what records import would do with the file, as its receipt, writing nothing; ${HOLDS_LOCK}`).summary("check a records file against the store; write nothing"),
9142
+ true
9143
+ );
7987
9144
  recordMappingCommands(records, program, streams, env);
9145
+ recordCommands(records, answered, (work) => withStore(env, work));
7988
9146
  }, "recordsCommand");
7989
9147
 
7990
9148
  // dist/digest/known.js
@@ -8084,8 +9242,8 @@ var syncRunsOf = /* @__PURE__ */ __name((env) => {
8084
9242
  };
8085
9243
  }, "syncRunsOf");
8086
9244
  var HOUR = 36e5;
8087
- var DAY4 = 24 * HOUR;
8088
- var QUIET_AFTER = 3 * DAY4;
9245
+ var DAY5 = 24 * HOUR;
9246
+ var QUIET_AFTER = 3 * DAY5;
8089
9247
  var QUIET_GAPS = 3;
8090
9248
  var hours = /* @__PURE__ */ __name((from, now) => Math.max(0, Math.floor((now - from) / HOUR)), "hours");
8091
9249
  var healthOf = /* @__PURE__ */ __name((sync, activity, now) => {
@@ -8107,7 +9265,7 @@ var healthOf = /* @__PURE__ */ __name((sync, activity, now) => {
8107
9265
  };
8108
9266
  if (activity.newest === null || activity.moved30d === 0)
8109
9267
  return void 0;
8110
- const usual = Math.max(QUIET_AFTER, QUIET_GAPS * 30 * DAY4 / activity.moved30d);
9268
+ const usual = Math.max(QUIET_AFTER, QUIET_GAPS * 30 * DAY5 / activity.moved30d);
8111
9269
  if (activity.newest < now - usual)
8112
9270
  return { reason: "quiet", since: new Date(activity.newest).toISOString(), staleHours: hours(activity.newest, now) };
8113
9271
  return void 0;
@@ -8282,13 +9440,13 @@ var countTasks = /* @__PURE__ */ __name(async (store, words) => {
8282
9440
 
8283
9441
  // dist/digest/tasks.js
8284
9442
  var DIGEST_SCHEDULE = "morning-digest";
8285
- var DAY5 = 864e5;
9443
+ var DAY6 = 864e5;
8286
9444
  var previousDigestAt = /* @__PURE__ */ __name((env, now) => {
8287
9445
  const state = resolvePaths({ appName: APP.appName, prefix: APP.envPrefix, env }).state;
8288
9446
  const digest = schedulesOf(state).find((one2) => one2.name === DIGEST_SCHEDULE || one2.kind === "agent" && one2.argv.join(" ").includes(DIGEST_SCHEDULE));
8289
9447
  const last = digest?.last;
8290
9448
  if (!last)
8291
- return new Date(now - DAY5).toISOString();
9449
+ return new Date(now - DAY6).toISOString();
8292
9450
  return last.exitCode === 0 ? last.at : last.failingSince ?? last.at;
8293
9451
  }, "previousDigestAt");
8294
9452
  var dayOf2 = /* @__PURE__ */ __name((zone) => {
@@ -8330,7 +9488,7 @@ var gatherTasks = /* @__PURE__ */ __name(async (store, keys, { now, newSince })
8330
9488
  const zone = timezoneOf();
8331
9489
  const day2 = dayOf2(zone);
8332
9490
  const today2 = day2(now);
8333
- const tomorrow = day2(now + DAY5);
9491
+ const tomorrow = day2(now + DAY6);
8334
9492
  const since = Date.parse(newSince);
8335
9493
  const seen = /* @__PURE__ */ new Map();
8336
9494
  let accounts = 0;
@@ -8376,7 +9534,7 @@ var gatherTasks = /* @__PURE__ */ __name(async (store, keys, { now, newSince })
8376
9534
 
8377
9535
  // dist/digest/digest.js
8378
9536
  var WATCH_TAG = "watch";
8379
- var DAY6 = 864e5;
9537
+ var DAY7 = 864e5;
8380
9538
  var MESSENGERS2 = /* @__PURE__ */ new Set(["telegram", "max", "whatsapp"]);
8381
9539
  var HEALTH_ORDER = HEALTH_REASONS;
8382
9540
  var UNNAMED = "unnamed account";
@@ -8405,8 +9563,8 @@ var labelsOf = /* @__PURE__ */ __name(async (store, keys) => {
8405
9563
  }
8406
9564
  const person = await store.people.personOf({ provider: key.provider, id: key.account });
8407
9565
  const username = person?.identities.find((one2) => one2.provider === key.provider && one2.id === key.account)?.username;
8408
- const given = stored.get(name(key));
8409
- const label = [given && given !== key.account ? given : null, username ? `@${username}` : null].filter(Boolean).join(" ");
9566
+ const given2 = stored.get(name(key));
9567
+ const label = [given2 && given2 !== key.account ? given2 : null, username ? `@${username}` : null].filter(Boolean).join(" ");
8410
9568
  const profile = profileOf(key);
8411
9569
  labels.set(name(key), label || (profile ? `profile ${profile}` : UNNAMED));
8412
9570
  }
@@ -8461,8 +9619,8 @@ var statusLine = /* @__PURE__ */ __name((data) => {
8461
9619
  }, "statusLine");
8462
9620
  var personal = /* @__PURE__ */ __name((newest) => !newest.bulk && !newest.list && !newest.envelope && !newest.demoted, "personal");
8463
9621
  var gatherDigest = /* @__PURE__ */ __name(async (store, env, { since, now = Date.now(), limit, excerpt: excerpt2, owedWithin, newSince }) => {
8464
- const window = (now - since) / DAY6;
8465
- const days = `${Math.max(1, Math.ceil(window))}d`;
9622
+ const window = (now - since) / DAY7;
9623
+ const days2 = `${Math.max(1, Math.ceil(window))}d`;
8466
9624
  const accounts = await store.accounts.accounts();
8467
9625
  const messengers2 = accounts.filter((key) => MESSENGERS2.has(key.provider));
8468
9626
  const mailboxes = accounts.filter((key) => key.provider === "email");
@@ -8518,7 +9676,7 @@ var gatherDigest = /* @__PURE__ */ __name(async (store, env, { since, now = Date
8518
9676
  let mailMoved = 0;
8519
9677
  for (const key of messengers2) {
8520
9678
  const { chats, storedAt } = await store.chats.chatActivity(key, owedSince);
8521
- const month = (await store.chats.chatActivity(key, now - 30 * DAY6)).chats;
9679
+ const month = (await store.chats.chatActivity(key, now - 30 * DAY7)).chats;
8522
9680
  checkHealth(key, {
8523
9681
  newest: month.reduce((most, chat) => Math.max(most ?? 0, Date.parse(chat.lastMessageAt)), null),
8524
9682
  moved30d: month.length
@@ -8544,7 +9702,7 @@ var gatherDigest = /* @__PURE__ */ __name(async (store, env, { since, now = Date
8544
9702
  owedHere++;
8545
9703
  }
8546
9704
  if (owedHere)
8547
- owedNext.push(`memo tasks agenda --source ${name(key)} --unanswered 1m --within ${Math.ceil(owedWithin / DAY6)}d`);
9705
+ owedNext.push(`memo tasks agenda --source ${name(key)} --unanswered 1m --within ${Math.ceil(owedWithin / DAY7)}d`);
8548
9706
  for (const chatId of watched.chats.get(name(key)) ?? []) {
8549
9707
  const page = await store.messages.messages(key, chatId, { limit, since: iso(since) });
8550
9708
  for (const message of page.items)
@@ -8567,12 +9725,12 @@ var gatherDigest = /* @__PURE__ */ __name(async (store, env, { since, now = Date
8567
9725
  }
8568
9726
  for (const key of mailboxes) {
8569
9727
  const stored = await store.accounts.storedAccount(key);
8570
- const threads = await store.mail.threadActivity(stored.id, Math.min(owedSince, now - OWED_DAYS * DAY6));
9728
+ const threads = await store.mail.threadActivity(stored.id, Math.min(owedSince, now - OWED_DAYS * DAY7));
8571
9729
  const ref = /* @__PURE__ */ __name((thread) => formatReference({ type: "chat", provider: "email", account: key.account, chat: thread }), "ref");
8572
9730
  const newest = threads.reduce((most, thread) => Math.max(most, thread.lastEmailAt), 0);
8573
9731
  checkHealth(key, {
8574
9732
  newest: newest || null,
8575
- moved30d: threads.filter((thread) => thread.lastEmailAt >= now - 30 * DAY6).length
9733
+ moved30d: threads.filter((thread) => thread.lastEmailAt >= now - 30 * DAY7).length
8576
9734
  });
8577
9735
  mailMoved += threads.filter((thread) => thread.lastEmailAt >= since && thread.newest !== null && personal(thread.newest)).length;
8578
9736
  coverage.push({
@@ -8629,7 +9787,7 @@ var gatherDigest = /* @__PURE__ */ __name(async (store, env, { since, now = Date
8629
9787
  if (strangers.length)
8630
9788
  unknown2.next.push(`memo mail review --source ${name(key)} --unanswered 1m bulk:false`);
8631
9789
  if (newHere)
8632
- mailNext.push(`memo mail review --source ${name(key)} date>${days} bulk:false`);
9790
+ mailNext.push(`memo mail review --source ${name(key)} date>${days2} bulk:false`);
8633
9791
  }
8634
9792
  for (const uid of watched.people) {
8635
9793
  const person = await store.people.personByUid(uid);
@@ -8703,7 +9861,7 @@ var gatherDigest = /* @__PURE__ */ __name(async (store, env, { since, now = Date
8703
9861
  const isWatched = watched.projects.has(project.id) || watched.projects.has(project.ref);
8704
9862
  if (fresh.length === 0 && !isWatched)
8705
9863
  continue;
8706
- projectNext.push(`memo projects status ${project.key ?? project.ref} --since-time ${days}`);
9864
+ projectNext.push(`memo projects status ${project.key ?? project.ref} --since-time ${days2}`);
8707
9865
  if (fresh.length === 0)
8708
9866
  projects.push({
8709
9867
  item: { ref: project.ref, who: null, at: iso(since), excerpt: project.name, why: "watched project, quiet" }
@@ -8831,21 +9989,21 @@ var sinceOf = /* @__PURE__ */ __name((value, now = Date.now()) => {
8831
9989
  return since;
8832
9990
  }, "sinceOf");
8833
9991
  var reviewAgendaCommand = /* @__PURE__ */ __name((review, print, streams, env) => {
8834
- 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, 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 \`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`).option("--since-time <time>", "how far back: hours or days (12h, 7d) or a start date (2026-11-01)", "1d").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 (given) => {
8835
- if (given.compact && given.json)
9992
+ 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, 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 \`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`).option("--since-time <time>", "how far back: hours or days (12h, 7d) or a start date (2026-11-01)", "1d").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) => {
9993
+ if (given2.compact && given2.json)
8836
9994
  throw new CliError("validation_error", "--compact and --json ask for different output \u2014 pick one", {
8837
9995
  reason: "output.conflict",
8838
9996
  param: "--compact"
8839
9997
  });
8840
- const since = sinceOf(given.sinceTime);
9998
+ const since = sinceOf(given2.sinceTime);
8841
9999
  const gathered = await withStore(env, (store) => gatherDigest(store, env, {
8842
10000
  since,
8843
- limit: given.limit,
8844
- excerpt: given.compact ? 100 : 200,
10001
+ limit: given2.limit,
10002
+ excerpt: given2.compact ? 100 : 200,
8845
10003
  owedWithin: OWED_WITHIN
8846
10004
  }));
8847
- const digest = fitDigest(gathered, given.maxOutputBytes ?? (given.compact ? COMPACT_BYTES : FULL_BYTES));
8848
- if (given.json)
10005
+ const digest = fitDigest(gathered, given2.maxOutputBytes ?? (given2.compact ? COMPACT_BYTES : FULL_BYTES));
10006
+ if (given2.json)
8849
10007
  print(true, itemAnswer(digest));
8850
10008
  else
8851
10009
  streams.data(`${digestText(digest)}
@@ -8908,32 +10066,32 @@ var ROW = {
8908
10066
  ],
8909
10067
  text: ["reason"]
8910
10068
  };
8911
- var json6 = /* @__PURE__ */ __name((command) => command.option("--json", "print JSON; --json=id,title keeps only those fields"), "json");
10069
+ var json4 = /* @__PURE__ */ __name((command) => command.option("--json", "print JSON; --json=id,title keeps only those fields"), "json");
8912
10070
  var reviewCommand = /* @__PURE__ */ __name((program, streams, env) => {
8913
10071
  const { print } = answers(program, streams, env);
8914
10072
  const review = program.command("review").description("every proposal waiting for your decision, across projects: links, key documents, facts, invoices, payments and more").summary("every proposal waiting for your decision, across projects");
8915
- json6(answerEntity(withQuery(annotate(review.command("list", { isDefault: true }), { effects: LOCAL_READ }).description("what waits for the owner's decision, newest first, with titles, who proposed it, why and the evidence").summary("what waits for your decision, newest first, with titles and evidence"), REVIEW_QUERY), "memo_proposal", PROPOSAL, { row: ROW })).option("--limit <n>", "proposals per page, at most 50", positive, 20).option("--page <n>", "which page, from 1", positive, 1).option("--compact", "one line per proposal").action(async (words, given) => {
8916
- if (given.limit > 50)
10073
+ json4(answerEntity(withQuery(annotate(review.command("list", { isDefault: true }), { effects: LOCAL_READ }).description("what waits for the owner's decision, newest first, with titles, who proposed it, why and the evidence").summary("what waits for your decision, newest first, with titles and evidence"), REVIEW_QUERY), "memo_proposal", PROPOSAL, { row: ROW })).option("--limit <n>", "proposals per page, at most 50", positive, 20).option("--page <n>", "which page, from 1", positive, 1).option("--compact", "one line per proposal").action(async (words, given2) => {
10074
+ if (given2.limit > 50)
8917
10075
  throw new CliError("validation_error", "--limit is at most 50", { param: "limit" });
8918
- const found = await withStore(env, (store) => listReview(store, env, words, given));
10076
+ const found = await withStore(env, (store) => listReview(store, env, words, given2));
8919
10077
  const steps = reviewSteps(found.items);
8920
10078
  const body = listAnswer("review list", {
8921
10079
  items: found.items,
8922
- limit: given.limit,
8923
- page: given.page,
10080
+ limit: given2.limit,
10081
+ page: given2.page,
8924
10082
  has_more: found.hasMore,
8925
- args: { query: words.join(" "), limit: given.limit },
10083
+ args: { query: words.join(" "), limit: given2.limit },
8926
10084
  ...steps.length ? { next: steps } : {}
8927
10085
  });
8928
- print(given.json, body, reviewText(found.items, found.hasMore), given.compact);
10086
+ print(given2.json, body, reviewText(found.items, found.hasMore), given2.compact);
8929
10087
  });
8930
- json6(annotate(review.command("show"), { effects: LOCAL_READ })).description("one proposal with its titles, signals and the text around each piece of evidence").argument("<id>", "the proposal's id, as review lists it: 17070, fact:512, memory:88, link:17, payment:4, close:Q-15").option("--brief", "only references and their titles, without excerpts or nearby text").option("--before-n <n>", "messages or document paragraphs before the evidence, at most 5", whole, 2).option("--after-n <n>", "messages or document paragraphs after the evidence, at most 5", whole, 2).option("--compact", "one line, as review prints it").action(async (id, given) => {
10088
+ json4(annotate(review.command("show"), { effects: LOCAL_READ })).description("one proposal with its titles, signals and the text around each piece of evidence").argument("<id>", "the proposal's id, as review lists it: 17070, fact:512, memory:88, link:17, payment:4, close:Q-15").option("--brief", "only references and their titles, without excerpts or nearby text").option("--before-n <n>", "messages or document paragraphs before the evidence, at most 5", whole, 2).option("--after-n <n>", "messages or document paragraphs after the evidence, at most 5", whole, 2).option("--compact", "one line, as review prints it").action(async (id, given2) => {
8931
10089
  const body = await withStore(env, async (store) => {
8932
10090
  const shown2 = await showReview(store, env, id);
8933
10091
  const window = {
8934
- brief: given.brief === true,
8935
- before: Math.min(given.beforeN, 5),
8936
- after: Math.min(given.afterN, 5)
10092
+ brief: given2.brief === true,
10093
+ before: Math.min(given2.beforeN, 5),
10094
+ after: Math.min(given2.afterN, 5)
8937
10095
  };
8938
10096
  const evidence = await Promise.all(shown2.evidence.map(async (one2) => {
8939
10097
  const sender = window.brief ? null : await senderOf(store, one2.ref);
@@ -8946,35 +10104,35 @@ var reviewCommand = /* @__PURE__ */ __name((program, streams, env) => {
8946
10104
  }));
8947
10105
  return itemAnswer({ ...shown2, evidence });
8948
10106
  });
8949
- print(given.json, body, void 0, given.compact);
10107
+ print(given2.json, body, void 0, given2.compact);
8950
10108
  });
8951
10109
  for (const name2 of ["confirm", "reject"]) {
8952
- const command = byOption(json6(annotate(review.command(name2), { effects: LOCAL_WRITE }))).description(name2 === "confirm" ? "confirm proposals by id or range (17070-17079,fact:500-502,17080/f1); each is decided on its own, so a refusal leaves the others decided. An agent decides only with --reason, never its own or a scan's" : "turn proposals down by id or range, with why; each is decided on its own").summary(name2 === "confirm" ? "confirm proposals by id or range; each on its own" : "turn proposals down, with why").argument("<ids...>", name2 === "confirm" ? "ids or ranges as review lists them; 17080/f1 accepts that finding and rejects the batch's others" : "ids or ranges as review lists them; a batch is turned down whole");
10110
+ const command = byOption(json4(annotate(review.command(name2), { effects: LOCAL_WRITE }))).description(name2 === "confirm" ? "confirm proposals by id or range (17070-17079,fact:500-502,17080/f1); each is decided on its own, so a refusal leaves the others decided. An agent decides only with --reason, never its own or a scan's" : "turn proposals down by id or range, with why; each is decided on its own").summary(name2 === "confirm" ? "confirm proposals by id or range; each on its own" : "turn proposals down, with why").argument("<ids...>", name2 === "confirm" ? "ids or ranges as review lists them; 17080/f1 accepts that finding and rejects the batch's others" : "ids or ranges as review lists them; a batch is turned down whole");
8953
10111
  if (name2 === "confirm")
8954
10112
  command.option("--reason <text>", "why, in a few words; required when an agent decides");
8955
10113
  else
8956
10114
  command.requiredOption("--reason <text>", "why it is turned down, in a few words");
8957
10115
  command.option("--compact", "one line per decision");
8958
- command.action(async (words, given) => {
10116
+ command.action(async (words, given2) => {
8959
10117
  const ids = parseProposalIds(words);
8960
10118
  const by = await deciderOf(command, env, {
8961
- ...given,
10119
+ ...given2,
8962
10120
  question: `${name2} ${ids.length} proposal${ids.length === 1 ? "" : "s"} as you, the owner?`
8963
10121
  });
8964
- const result = await withStore(env, (store) => reviewRegistry(store).decide(ids, decisionOf(name2 === "confirm", by, given.reason)));
10122
+ const result = await withStore(env, (store) => reviewRegistry(store).decide(ids, decisionOf(name2 === "confirm", by, given2.reason)));
8965
10123
  const issues = result.refused.map((one2) => ({
8966
10124
  code: one2.code,
8967
10125
  source: one2.id,
8968
10126
  ...one2.reason.includes(".") ? { reason: one2.reason } : {}
8969
10127
  }));
8970
- print(given.json, itemAnswer(result, issues.length ? { meta: { complete: false, issues } } : void 0), decidedText(result), given.compact);
10128
+ print(given2.json, itemAnswer(result, issues.length ? { meta: { complete: false, issues } } : void 0), decidedText(result), given2.compact);
8971
10129
  });
8972
10130
  }
8973
10131
  reviewAgendaCommand(review, print, streams, env);
8974
- json6(answerEntity(annotate(review.command("status"), { effects: LOCAL_READ }), "review_status", REVIEW_STATUS)).summary("since yesterday: new mail, what is owed and waiting, what agents proposed").description("the owner's daily look, with no model call: per mail account the threads with new mail, what you owe and wait for, and how far each agent's processing mark has read; then what was proposed and what waits").option("--since-time <time>", "how far back: hours or days (12h, 7d) or a start date (2026-11-01)", "1d").action(async (given) => {
8975
- const since = sinceOf(given.sinceTime);
10132
+ json4(answerEntity(annotate(review.command("status"), { effects: LOCAL_READ }), "review_status", REVIEW_STATUS)).summary("since yesterday: new mail, what is owed and waiting, what agents proposed").description("the owner's daily look, with no model call: per mail account the threads with new mail, what you owe and wait for, and how far each agent's processing mark has read; then what was proposed and what waits").option("--since-time <time>", "how far back: hours or days (12h, 7d) or a start date (2026-11-01)", "1d").action(async (given2) => {
10133
+ const since = sinceOf(given2.sinceTime);
8976
10134
  const status = await withStore(env, (store) => reviewStatus(store, env, since));
8977
- print(given.json, itemAnswer(status), reviewStatusText(status));
10135
+ print(given2.json, itemAnswer(status), reviewStatusText(status));
8978
10136
  });
8979
10137
  }, "reviewCommand");
8980
10138
 
@@ -8988,10 +10146,10 @@ var embedPerRun = /* @__PURE__ */ __name((env = process.env) => {
8988
10146
  return Math.max(8, Math.min(EMBED_PER_RUN, Math.round(EMBED_PER_RUN * ratio)));
8989
10147
  }, "embedPerRun");
8990
10148
  var missingModel = /* @__PURE__ */ __name((error, env) => {
8991
- const named4 = isCliError(error) ? error.details.model : void 0;
8992
- const id = typeof named4 === "string" ? named4 : chosenTextModel(env).id;
8993
- const terms = textModels(env).find((model) => model.id === id)?.terms;
8994
- return `the ${id} model is not downloaded \u2014 memo models download ${id}${terms ? " --accept-terms" : ""}`;
10149
+ const named5 = isCliError(error) ? error.details.model : void 0;
10150
+ const id = typeof named5 === "string" ? named5 : chosenTextModel(env).id;
10151
+ const terms2 = textModels(env).find((model) => model.id === id)?.terms;
10152
+ return `the ${id} model is not downloaded \u2014 memo models download ${id}${terms2 ? " --accept-terms" : ""}`;
8995
10153
  }, "missingModel");
8996
10154
  var isMissingModel = /* @__PURE__ */ __name((error) => isCliError(error) && error.details.reason === "model.not-downloaded", "isMissingModel");
8997
10155
  var reportOf = /* @__PURE__ */ __name((run) => {
@@ -9023,18 +10181,18 @@ var reportOf = /* @__PURE__ */ __name((run) => {
9023
10181
  ...run.reason === void 0 ? {} : { reason: run.reason }
9024
10182
  };
9025
10183
  }, "reportOf");
9026
- var combinedEnrichment = /* @__PURE__ */ __name((...parts) => {
9027
- const present2 = parts.filter((part) => part !== void 0);
10184
+ var combinedEnrichment = /* @__PURE__ */ __name((...parts2) => {
10185
+ const present2 = parts2.filter((part) => part !== void 0);
9028
10186
  if (present2.length === 0)
9029
10187
  return void 0;
9030
10188
  const rank = { done: 0, stopped: 1, failed: 2 };
9031
10189
  const worst = present2.reduce((a, b) => rank[b.status] > rank[a.status] ? b : a);
9032
- const named4 = present2.find((part) => part.provider !== void 0);
10190
+ const named5 = present2.find((part) => part.provider !== void 0);
9033
10191
  const costs = present2.map((part) => part.costUsd);
9034
10192
  return {
9035
10193
  status: worst.status,
9036
- ...named4?.provider === void 0 ? {} : { provider: named4.provider },
9037
- ...named4?.model === void 0 ? {} : { model: named4.model },
10194
+ ...named5?.provider === void 0 ? {} : { provider: named5.provider },
10195
+ ...named5?.model === void 0 ? {} : { model: named5.model },
9038
10196
  sent: present2.reduce((sum, part) => sum + part.sent, 0),
9039
10197
  enriched: present2.reduce((sum, part) => sum + part.enriched, 0),
9040
10198
  failed: present2.reduce((sum, part) => sum + part.failed, 0),
@@ -9098,10 +10256,10 @@ var embedMailChunks = /* @__PURE__ */ __name(async (store, { embed = true, env,
9098
10256
 
9099
10257
  // dist/progress.js
9100
10258
  var EVERY_MS = 500;
9101
- var progressLine = /* @__PURE__ */ __name((diagnostic, json7, { step, unit, label }) => {
10259
+ var progressLine2 = /* @__PURE__ */ __name((diagnostic, json5, { step, unit, label }) => {
9102
10260
  let last = Number.NEGATIVE_INFINITY;
9103
10261
  return (done, total) => {
9104
- if (!json7)
10262
+ if (!json5)
9105
10263
  return;
9106
10264
  const now = Date.now();
9107
10265
  if (done !== total && now - last < EVERY_MS)
@@ -9228,7 +10386,7 @@ var syncCommand = /* @__PURE__ */ __name((program, streams, env, signal, keyring
9228
10386
  const skip = options.ignore ?? [];
9229
10387
  for (const folder of folders)
9230
10388
  await attempt(`notes ${folder.path}`, async () => {
9231
- const onFile = progressLine(streams.diagnostic, Boolean(options.json), {
10389
+ const onFile = progressLine2(streams.diagnostic, Boolean(options.json), {
9232
10390
  step: "notes",
9233
10391
  unit: "files",
9234
10392
  label: folder.id
@@ -9395,20 +10553,20 @@ var mailTriageInput = /* @__PURE__ */ __name((mailboxes) => async (schedule, run
9395
10553
  if (!holder)
9396
10554
  return void 0;
9397
10555
  const skill2 = await run(["skill", "show", SKILL]);
9398
- const parts = [PREAMBLE, "# The skill", skill2.trim(), "# The review"];
10556
+ const parts2 = [PREAMBLE, "# The skill", skill2.trim(), "# The review"];
9399
10557
  const separator = "\n\n";
9400
- let used = parts.join(separator).length + separator.length * 2;
10558
+ let used = parts2.join(separator).length + separator.length * 2;
9401
10559
  let alone = true;
9402
10560
  for (const address of await mailboxes()) {
9403
10561
  const source = `email:${address}`;
9404
10562
  const review = JSON.parse(await run(["mail", "review", "--holder", holder, "--source", source, `--json=${FIELDS}`]));
9405
10563
  const block = mailboxBlock(source, review, INPUT_BUDGET - used - separator.length, alone);
9406
- parts.push(block);
10564
+ parts2.push(block);
9407
10565
  used += block.length + separator.length;
9408
10566
  if (block.includes("\nemails, one JSON per line:"))
9409
10567
  alone = false;
9410
10568
  }
9411
- return [...parts, ""].join(separator);
10569
+ return [...parts2, ""].join(separator);
9412
10570
  }, "mailTriageInput");
9413
10571
 
9414
10572
  // dist/schedule/command.js
@@ -9454,7 +10612,7 @@ var BRIEF = ["ref", "chat_title", "timestamp", "sender_name", "excerpt", "score"
9454
10612
  var briefHit = /* @__PURE__ */ __name((hit) => Object.fromEntries(BRIEF.flatMap((key) => hit[key] === void 0 || hit[key] === null ? [] : [[key, hit[key]]])), "briefHit");
9455
10613
 
9456
10614
  // dist/search/answers.js
9457
- var named3 = /* @__PURE__ */ __name((accounts) => [
10615
+ var named4 = /* @__PURE__ */ __name((accounts) => [
9458
10616
  ...new Set(accounts.map(({ provider, account: account2 }) => `${provider}:${account2}`))
9459
10617
  ], "named");
9460
10618
  var metaOf2 = /* @__PURE__ */ __name((accounts, skipped = [], heldInPart = false) => {
@@ -9465,7 +10623,7 @@ var metaOf2 = /* @__PURE__ */ __name((accounts, skipped = [], heldInPart = false
9465
10623
  source: one2.source ?? one2.resource ?? ""
9466
10624
  }));
9467
10625
  return {
9468
- accounts: named3(accounts),
10626
+ accounts: named4(accounts),
9469
10627
  ...heldInPart ? { complete: false } : {},
9470
10628
  ...issues.length ? { issues } : {}
9471
10629
  };
@@ -9604,10 +10762,11 @@ var peopleText = /* @__PURE__ */ __name((found) => found.items.map((hit) => [
9604
10762
  ].join("\n")).join("\n") || "nobody found", "peopleText");
9605
10763
 
9606
10764
  // dist/search/command.js
10765
+ var ONLY = ["messages", "mail", "notes", "events", "crm", "business"];
9607
10766
  var onlyOf2 = /* @__PURE__ */ __name((value) => {
9608
10767
  const selected = value.split(",").map((part) => part.trim());
9609
- if (!selected.length || selected.some((part) => !["messages", "mail", "notes", "events"].includes(part)))
9610
- throw new InvalidArgumentError("choose messages,mail,notes,events, separated by commas");
10768
+ if (!selected.length || selected.some((part) => !ONLY.includes(part)))
10769
+ throw new InvalidArgumentError(`choose ${ONLY.join(",")}, separated by commas`);
9611
10770
  return [...new Set(selected)];
9612
10771
  }, "onlyOf");
9613
10772
  var levelOf = /* @__PURE__ */ __name(({ brief, full }) => {
@@ -9626,9 +10785,11 @@ var searchCommandDefinition = /* @__PURE__ */ __name((program, streams, env) =>
9626
10785
  throw new InvalidArgumentError("at most 100");
9627
10786
  return limit;
9628
10787
  }, 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");
9629
- queryOptions(annotate(group.command("all"), { effects: LOCAL_READ, output: { entity: "hit" } }).description("messages, mail, notes and calendar events 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>", "messages,mail,notes,events, 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", `
10788
+ 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", `
9630
10789
  content: narrows a search to the text of files, transcript: to voice transcripts, filename: to file names \u2014 memo search all 'content:invoice'.
9631
10790
  Calendar events come from every calendar gcal stored; an event's title, description and place are written by whoever sent the invitation.
10791
+ crm finds deals and leads by the words of their title only.
10792
+ business finds invoices, payments, orders, contracts, subscriptions, products and wallets by the words of their numbers and names.
9632
10793
  --json: the list is items, each a hit as in tg search all: ref, kind, title, timestamp, excerpt.`).action(async (words, options, command) => {
9633
10794
  const gate = lanesFor(command, options.only);
9634
10795
  const answer = await withStore(env, async (store) => {
@@ -9637,6 +10798,7 @@ Calendar events come from every calendar gcal stored; an event's title, descript
9637
10798
  limit: options.limit,
9638
10799
  ...gate.only === void 0 ? {} : { only: gate.only },
9639
10800
  ...gate.shows === void 0 ? {} : { shows: gate.shows },
10801
+ ...gate.crmKinds === void 0 ? {} : { crmKinds: gate.crmKinds },
9640
10802
  ...options.exact ? { exact: true } : {},
9641
10803
  ...options.plainOrder ? { plainOrder: true } : {},
9642
10804
  ...options.timezone === void 0 ? {} : { timezone: options.timezone }
@@ -9715,8 +10877,8 @@ For an agent: read with --compact, one line per hit with its reference. Never wr
9715
10877
  for (const { source, reason } of answer.skipped)
9716
10878
  streams.diagnostic(`${source} not searched: ${reason}
9717
10879
  `);
9718
- const { limit, page, json: json7, ...rest } = options;
9719
- print(json7, notesAnswer(answer, limit, page, { query: words.join(" "), ...rest }), searchText(answer, (page - 1) * limit));
10880
+ const { limit, page, json: json5, ...rest } = options;
10881
+ print(json5, notesAnswer(answer, limit, page, { query: words.join(" "), ...rest }), searchText(answer, (page - 1) * limit));
9720
10882
  });
9721
10883
  searchMemoriesCommand(group, streams, env);
9722
10884
  annotate(group.command("people"), { effects: LOCAL_READ, output: { entity: "person" } }).description("people whose name, username or alias holds every word, in every account unless --source narrows it; each with its person:<id> for --contact and its identities").summary("people by name across every account").argument("<name...>", "parts of the name, username or alias; case and accents do not matter").option("--source <accounts>", ACCOUNTS_HELP).option("--limit <n>", "most people, at most 100", (value) => {
@@ -9754,16 +10916,39 @@ var LOCAL_OPENS = {
9754
10916
  task: ["memo", "tasks", "show"],
9755
10917
  fact: ["memo", "facts", "show"],
9756
10918
  memory: ["memo", "memories", "show"],
9757
- message: ["memo", "messages", "show"]
10919
+ message: ["memo", "messages", "show"],
10920
+ invoice: ["memo", "invoices", "show"],
10921
+ payment: ["memo", "payments", "show"],
10922
+ order: ["memo", "orders", "show"],
10923
+ deal: ["memo", "deals", "show"],
10924
+ lead: ["memo", "leads", "show"],
10925
+ pipeline: ["memo", "pipelines", "show"],
10926
+ product: ["memo", "products", "show"],
10927
+ contract: ["memo", "contracts", "show"],
10928
+ subscription: ["memo", "subscriptions", "show"],
10929
+ wallet: ["memo", "wallets", "show"],
10930
+ transaction: ["memo", "transactions", "show"],
10931
+ event: ["memo", "events", "show"]
9758
10932
  };
10933
+ var openKeyOf = /* @__PURE__ */ __name((kind) => LOCAL_OPENS[kind]?.slice(1).join("."), "openKeyOf");
10934
+ var refuseDenied = /* @__PURE__ */ __name((command, summaries) => {
10935
+ for (const { ref, kind } of summaries) {
10936
+ const key = openKeyOf(kind);
10937
+ if (key !== void 0 && grantedLevel(command, key) === "deny")
10938
+ throw new CliError("permission_error", `${ref}: memo's MCP server denies ${key}`, {
10939
+ reason: "access.denied",
10940
+ permission: key
10941
+ });
10942
+ }
10943
+ }, "refuseDenied");
9759
10944
  var OTHERS = /* @__PURE__ */ new Set(["message", "chat", "contact", "email", "email_thread", "document", "event", "meeting", "bot"]);
9760
10945
  var ACCOUNT_KEY = /^[a-z][a-z-]*:\S+$/;
9761
- var taskOpen = /* @__PURE__ */ __name((summary, open) => {
9762
- if (summary.kind !== "task" || open.argv === null)
9763
- return open;
9764
- const argv = [...open.argv.slice(0, -1), summary.ref.slice("task:".length)];
10946
+ var taskOpen = /* @__PURE__ */ __name((summary, open2) => {
10947
+ if (summary.kind !== "task" || open2.argv === null)
10948
+ return open2;
10949
+ const argv = [...open2.argv.slice(0, -1), summary.ref.slice("task:".length)];
9765
10950
  return {
9766
- ...open,
10951
+ ...open2,
9767
10952
  argv: summary.in !== null && ACCOUNT_KEY.test(summary.in) ? [...argv, "--source", summary.in] : argv
9768
10953
  };
9769
10954
  }, "taskOpen");
@@ -9773,7 +10958,7 @@ var profilesFor = /* @__PURE__ */ __name((env) => (provider, account2) => {
9773
10958
  return { why: `${provider} names no account here`, profiles: [] };
9774
10959
  return profileFor(provider, account2, env) ?? { why: `memo cannot read which profiles ${provider} has`, profiles: [] };
9775
10960
  }, "profilesFor");
9776
- var showReferences = /* @__PURE__ */ __name(async (store, env, texts) => {
10961
+ var showReferences = /* @__PURE__ */ __name(async (store, env, texts, command) => {
9777
10962
  if (texts.length > MAX_REFS)
9778
10963
  throw new CliError("validation_error", `at most ${MAX_REFS} references at once`);
9779
10964
  for (const text3 of texts)
@@ -9781,8 +10966,10 @@ var showReferences = /* @__PURE__ */ __name(async (store, env, texts) => {
9781
10966
  for (const text3 of texts)
9782
10967
  parseReference(text3);
9783
10968
  const summaries = await store.refs.summaries(texts);
10969
+ if (command !== void 0)
10970
+ refuseDenied(command, [...summaries.values()]);
9784
10971
  const ports = { profilesFor: profilesFor(env), local: LOCAL_OPENS };
9785
- return texts.map((text3) => {
10972
+ const shown2 = texts.map((text3) => {
9786
10973
  const summary = summaries.get(text3) ?? {
9787
10974
  ref: text3,
9788
10975
  kind: "unknown",
@@ -9794,7 +10981,7 @@ var showReferences = /* @__PURE__ */ __name(async (store, env, texts) => {
9794
10981
  tool: null,
9795
10982
  state: "unavailable"
9796
10983
  };
9797
- const open = taskOpen(summary, openOf(summary, ports));
10984
+ const open2 = taskOpen(summary, openOf(summary, ports));
9798
10985
  return {
9799
10986
  ref: summary.ref,
9800
10987
  kind: summary.kind,
@@ -9802,24 +10989,36 @@ var showReferences = /* @__PURE__ */ __name(async (store, env, texts) => {
9802
10989
  in: summary.in,
9803
10990
  at: summary.at,
9804
10991
  provider: summary.provider,
9805
- tool: summary.tool ?? open.argv?.[0] ?? null,
10992
+ tool: summary.tool ?? open2.argv?.[0] ?? null,
9806
10993
  state: summary.state,
9807
- open: { ...open, line: open.argv?.map(shellWord).join(" ") ?? null },
10994
+ open: { ...open2, line: open2.argv?.map(shellWord).join(" ") ?? null },
9808
10995
  ...OTHERS.has(summary.kind) ? { untrusted: ["title", "in"] } : {}
9809
10996
  };
9810
10997
  });
10998
+ const withRecords = command === void 0 || !recordsHidden(command);
10999
+ for (const one2 of shown2) {
11000
+ const entity = one2.state === "available" ? await readSourced(store, one2.kind, one2.ref) : void 0;
11001
+ if (entity === void 0)
11002
+ continue;
11003
+ if (withRecords)
11004
+ one2.sources = await sourcesOf(store, entity);
11005
+ if (imported(entity))
11006
+ one2.untrusted = ["title"];
11007
+ }
11008
+ return shown2;
9811
11009
  }, "showReferences");
9812
11010
  var minute2 = /* @__PURE__ */ __name((at) => at === null ? null : at.slice(0, 16).replace("T", " "), "minute");
9813
11011
  var blockOf = /* @__PURE__ */ __name((one2) => [
9814
11012
  `${one2.ref} ${one2.title ?? ""}`.trimEnd(),
9815
11013
  ` ${[one2.kind, one2.in, one2.state, minute2(one2.at)].filter((part) => part !== null).join(" \xB7 ")}`,
9816
11014
  ` open: ${one2.open.line ?? "none"}`,
9817
- ...one2.open.why === null ? [] : [` ${one2.open.why}`]
11015
+ ...one2.open.why === null ? [] : [` ${one2.open.why}`],
11016
+ ...one2.sources === void 0 ? [] : sourcesText(one2.ref, one2.sources)
9818
11017
  ].join("\n"), "blockOf");
9819
11018
  var showCommand = /* @__PURE__ */ __name((program, streams, env) => {
9820
11019
  const { print } = answers(program, streams, env);
9821
- annotate(program.command("show"), { effects: LOCAL_READ, partial: true }).description("what any reference names, and the command that opens it").argument("<ref...>", "1 to 100 references any WireCat CLI printed: chat:, msg:, note:, document:, person:, task:\u2026").option("--json", "print JSON; --json=ref,title keeps only those fields").action(async (refs, options) => {
9822
- const items = await withStore(env, (store) => showReferences(store, env, refs));
11020
+ annotate(program.command("show"), { effects: LOCAL_READ, partial: true }).description("what any reference names, and the command that opens it").argument("<ref...>", "1 to 100 references any WireCat CLI printed: chat:, msg:, note:, document:, person:, task:\u2026").option("--json", "print JSON; --json=ref,title keeps only those fields").action(async (refs, options, command) => {
11021
+ const items = await withStore(env, (store) => showReferences(store, env, refs, command));
9823
11022
  const gone = items.filter((one2) => one2.state !== "available");
9824
11023
  const body = wholeList("show", items);
9825
11024
  if (gone.length > 0) {
@@ -9908,7 +11107,7 @@ var tagsCommand = /* @__PURE__ */ __name((program, streams, env) => {
9908
11107
  const tags = program.command("tags").description("your labels on stored sources and folders or threads");
9909
11108
  const { print } = answers(program, streams, env);
9910
11109
  const warn = /* @__PURE__ */ __name((text3) => streams.diagnostic(text3), "warn");
9911
- const mutate = /* @__PURE__ */ __name(async (operation, given, { account: account2, ...options }) => {
11110
+ const mutate = /* @__PURE__ */ __name(async (operation, given2, { account: account2, ...options }) => {
9912
11111
  const value = writeAccountOf({ account: account2 }, warn);
9913
11112
  const scoped3 = /* @__PURE__ */ __name(async (store) => value === void 0 ? {} : oneAccountOf(store, env, value, "--account"), "scoped");
9914
11113
  const target = options.note !== void 0 ? options.note.startsWith("document:") ? { type: "document", id: options.note.slice("document:".length) } : { type: "note", id: options.note.replace(/^note:/, "") } : options.person !== void 0 ? { type: "person", id: options.person.replace(/^person:/, "") } : options.organization !== void 0 ? { type: "organization", id: options.organization.replace(/^organization:/, "") } : options.project !== void 0 ? { type: "project", id: options.project } : options.task !== void 0 ? { type: "task", id: options.task.replace(/^task:/, "") } : options.folder !== void 0 ? { type: "folder", id: options.folder, path: options.subfolder ?? null } : void 0;
@@ -9924,7 +11123,7 @@ var tagsCommand = /* @__PURE__ */ __name((program, streams, env) => {
9924
11123
  throw new CliError("not_found", `no folder of notes ${target.id}`, { reason: "folder.not-found" });
9925
11124
  target.id = id;
9926
11125
  }
9927
- const changed = await (operation === "add" ? store.knowledge.addTags : store.knowledge.removeTags)(null, target, given);
11126
+ const changed = await (operation === "add" ? store.knowledge.addTags : store.knowledge.removeTags)(null, target, given2);
9928
11127
  print(options.json, itemAnswer({ target, [operation === "add" ? "added" : "removed"]: changed }), `${operation}: ${changed.join(", ") || "no labels changed"}`);
9929
11128
  });
9930
11129
  return;
@@ -9932,14 +11131,14 @@ var tagsCommand = /* @__PURE__ */ __name((program, streams, env) => {
9932
11131
  if (options.contact !== void 0 || options.meeting !== void 0) {
9933
11132
  await withStore(env, async (store) => {
9934
11133
  const { key, target: target2 } = await selectTarget(store, { ...options, ...await scoped3(store) });
9935
- const changed = await (operation === "add" ? store.knowledge.addTags : store.knowledge.removeTags)(key, target2, given);
11134
+ const changed = await (operation === "add" ? store.knowledge.addTags : store.knowledge.removeTags)(key, target2, given2);
9936
11135
  print(options.json, itemAnswer({ ...key, target: target2, [operation === "add" ? "added" : "removed"]: changed }), `${operation}: ${changed.join(", ") || "no labels changed"}`);
9937
11136
  });
9938
11137
  return;
9939
11138
  }
9940
11139
  if (options.message !== void 0 && value !== void 0)
9941
11140
  throw new CliError("validation_error", "a message locator names its account and chat \u2014 use --message alone");
9942
- const labels = [...new Set(given.map(normalizeTag))];
11141
+ const labels = [...new Set(given2.map(normalizeTag))];
9943
11142
  await withStore(env, async (store) => {
9944
11143
  const selected = sourceTarget({ ...options, ...await scoped3(store) });
9945
11144
  const changed = await (operation === "add" ? store.tags.addTags : store.tags.removeTags)(selected.key, selected.target, labels);
@@ -9955,17 +11154,17 @@ var tagsCommand = /* @__PURE__ */ __name((program, streams, env) => {
9955
11154
  });
9956
11155
  }, "mutate");
9957
11156
  for (const operation of ["add", "remove"])
9958
- targetOptions(annotate(tags.command(operation), { effects: LOCAL_WRITE }).description(operation === "add" ? "put labels on one source" : "remove labels from one source")).action((given, options) => mutate(operation, given, options));
11157
+ targetOptions(annotate(tags.command(operation), { effects: LOCAL_WRITE }).description(operation === "add" ? "put labels on one source" : "remove labels from one source")).action((given2, options) => mutate(operation, given2, options));
9959
11158
  const tagsList = withQuery(annotate(tags.command("list"), { effects: LOCAL_READ, output: { entity: "source_tag" } }).description("list source labels, of every account or of the ones --source names"), TAG_QUERY);
9960
- sourceOptions(tagsList, `only these accounts (default: every one): ${ACCOUNTS_HELP}`).option("--limit <n>", "most labels to show", positive, 100).option("--json", "print JSON; --json=id,title keeps only those fields").action(async (words, given) => {
9961
- const terms = queryTerms(words, TAG_QUERY, "tags list");
9962
- const tag = terms.get("tag");
9963
- const value = sourceOf(given, warn);
11159
+ sourceOptions(tagsList, `only these accounts (default: every one): ${ACCOUNTS_HELP}`).option("--limit <n>", "most labels to show", positive, 100).option("--json", "print JSON; --json=id,title keeps only those fields").action(async (words, given2) => {
11160
+ const terms2 = queryTerms(words, TAG_QUERY, "tags list");
11161
+ const tag = terms2.get("tag");
11162
+ const value = sourceOf(given2, warn);
9964
11163
  const options = {
9965
- limit: given.limit,
9966
- ...given.json === void 0 ? {} : { json: given.json },
11164
+ limit: given2.limit,
11165
+ ...given2.json === void 0 ? {} : { json: given2.json },
9967
11166
  ...tag === void 0 ? {} : { tag: normalizeTag(tag) },
9968
- ...terms.has("type") ? { type: terms.get("type") } : {}
11167
+ ...terms2.has("type") ? { type: terms2.get("type") } : {}
9969
11168
  };
9970
11169
  await withStore(env, async (store) => {
9971
11170
  const keys = value === void 0 ? await store.accounts.accounts() : await accountsOf(store, env, value);
@@ -10040,8 +11239,8 @@ var requireAccount = /* @__PURE__ */ __name((env, warn) => async (_, command) =>
10040
11239
  return;
10041
11240
  if (["show", "update", "claim", "release"].includes(command.name()) && first !== void 0 && await store.tasks.projectTask(first))
10042
11241
  return;
10043
- const listed = (await store.accounts.accounts()).map((key) => `${option} ${key.provider}:${key.account}`).join("; ");
10044
- throw new CliError("validation_error", `give ${option} \u2014 the stored accounts: ${listed || "none yet"}`);
11242
+ const listed2 = (await store.accounts.accounts()).map((key) => `${option} ${key.provider}:${key.account}`).join("; ");
11243
+ throw new CliError("validation_error", `give ${option} \u2014 the stored accounts: ${listed2 || "none yet"}`);
10045
11244
  } finally {
10046
11245
  await store.close();
10047
11246
  }
@@ -10065,7 +11264,7 @@ var sharedTaskCommands = /* @__PURE__ */ __name((program, tasks, streams, env) =
10065
11264
 
10066
11265
  // dist/tasks/tasks.js
10067
11266
  var personRef = /* @__PURE__ */ __name((person) => person.startsWith("person:") ? person : `person:${person}`, "personRef");
10068
- var fieldsOf2 = /* @__PURE__ */ __name((options) => ({
11267
+ var fieldsOf4 = /* @__PURE__ */ __name((options) => ({
10069
11268
  ...options.title === void 0 ? {} : { title: options.title },
10070
11269
  ...options.priority === void 0 ? {} : { priority: options.priority },
10071
11270
  ...options.parent === void 0 ? {} : { parent: options.parent },
@@ -10089,7 +11288,7 @@ var addToProject = /* @__PURE__ */ __name(async (store, env, options) => {
10089
11288
  project: await canonicalProject(store, options.project),
10090
11289
  title: options.title,
10091
11290
  type,
10092
- ...fieldsOf2(options),
11291
+ ...fieldsOf4(options),
10093
11292
  ...options.due === void 0 || options.due === "none" ? {} : { dueAt: options.due },
10094
11293
  ...options.status === void 0 ? {} : { status: options.status },
10095
11294
  ...options.agent === void 0 ? {} : { agent: options.agent }
@@ -10124,7 +11323,7 @@ var addFromSource = /* @__PURE__ */ __name(async (store, env, source, options) =
10124
11323
  ...options.into === void 0 ? {} : { attach: options.into },
10125
11324
  ...options.new ? { new: true } : {}
10126
11325
  }, author);
10127
- const fields = fieldsOf2(options);
11326
+ const fields = fieldsOf4(options);
10128
11327
  if (Object.keys(fields).length === 0 && !options.assignee?.length)
10129
11328
  return answer;
10130
11329
  await store.tasks.edit(answer.task.id, fields, "owner");
@@ -10153,7 +11352,7 @@ var closeTask = /* @__PURE__ */ __name(async (store, env, id, options) => {
10153
11352
  });
10154
11353
  }, "closeTask");
10155
11354
  var updateTask = /* @__PURE__ */ __name(async (store, env, id, options) => {
10156
- const fields = fieldsOf2(options);
11355
+ const fields = fieldsOf4(options);
10157
11356
  const times = {
10158
11357
  ...options.due === void 0 ? {} : { dueAt: options.due },
10159
11358
  ...options.remindTime === void 0 ? {} : { nextCheckAt: options.remindTime }
@@ -10195,15 +11394,15 @@ var moveTask = /* @__PURE__ */ __name((store, env, id, options) => {
10195
11394
  var commentTask = /* @__PURE__ */ __name((store, env, id, text3) => store.tasks.comment(id, text3, authorOf(env)), "commentTask");
10196
11395
  var taskHistory = /* @__PURE__ */ __name(async (store, id) => {
10197
11396
  const owner = (await store.people.owner())?.uid;
10198
- return (await store.tasks.events(id)).map((event) => ({
10199
- at: event.at,
10200
- kind: event.kind,
10201
- by: event.actor && {
10202
- ref: `${event.actor.type}:${event.actor.id}`,
10203
- name: event.actor.name,
10204
- owner: event.actor.type === "person" && String(event.actor.id) === String(owner)
11397
+ return (await store.tasks.events(id)).map((event2) => ({
11398
+ at: event2.at,
11399
+ kind: event2.kind,
11400
+ by: event2.actor && {
11401
+ ref: `${event2.actor.type}:${event2.actor.id}`,
11402
+ name: event2.actor.name,
11403
+ owner: event2.actor.type === "person" && String(event2.actor.id) === String(owner)
10205
11404
  },
10206
- changes: event.changes
11405
+ changes: event2.changes
10207
11406
  }));
10208
11407
  }, "taskHistory");
10209
11408
 
@@ -10282,11 +11481,11 @@ var tasksCommand2 = /* @__PURE__ */ __name((program, streams, env) => {
10282
11481
  const description = command.options.find((option) => option.long === "--description");
10283
11482
  if (description)
10284
11483
  description.description = "the detail, in Markdown; none clears it";
10285
- command.action(async (id, given) => {
10286
- const raw = given;
11484
+ command.action(async (id, given2) => {
11485
+ const raw = given2;
10287
11486
  const options = {
10288
- ...given,
10289
- ...typeof given.description === "string" && given.description.trim().toLowerCase() === "none" ? { description: null } : {},
11487
+ ...given2,
11488
+ ...typeof given2.description === "string" && given2.description.trim().toLowerCase() === "none" ? { description: null } : {},
10290
11489
  priority: raw.priority === "none" ? null : raw.priority,
10291
11490
  parent: raw.parent === null || raw.parent === "none" ? null : raw.parent,
10292
11491
  due: raw.due === "none" ? null : raw.due,
@@ -10337,10 +11536,10 @@ var VOCABULARY_QUERY = {
10337
11536
  ]
10338
11537
  };
10339
11538
  var vocabularyFilter = /* @__PURE__ */ __name((query, command) => {
10340
- const terms = queryTerms(query, VOCABULARY_QUERY, command);
11539
+ const terms2 = queryTerms(query, VOCABULARY_QUERY, command);
10341
11540
  return {
10342
- ...terms.has("kind") ? { kind: terms.get("kind") } : {},
10343
- ...terms.has("scope") ? { scope: terms.get("scope") } : {}
11541
+ ...terms2.has("kind") ? { kind: terms2.get("kind") } : {},
11542
+ ...terms2.has("scope") ? { scope: terms2.get("scope") } : {}
10344
11543
  };
10345
11544
  }, "vocabularyFilter");
10346
11545
 
@@ -10520,6 +11719,10 @@ var OWN_ENTITIES = entityFields({
10520
11719
  "fulfilled_date",
10521
11720
  "invoice",
10522
11721
  "payment",
11722
+ "direction",
11723
+ "contract",
11724
+ "deal",
11725
+ "lines",
10523
11726
  "review",
10524
11727
  "author",
10525
11728
  "model",
@@ -10574,6 +11777,8 @@ var OWN_ENTITIES = entityFields({
10574
11777
  "reference",
10575
11778
  "allocated",
10576
11779
  "unallocated",
11780
+ "refund_of",
11781
+ "subscription",
10577
11782
  "evidence",
10578
11783
  "review",
10579
11784
  "author",
@@ -10596,7 +11801,9 @@ var OWN_ENTITIES = entityFields({
10596
11801
  "revision",
10597
11802
  "fingerprint",
10598
11803
  "relations",
11804
+ "incoming",
10599
11805
  "entity",
11806
+ "created_entity",
10600
11807
  "flagged",
10601
11808
  "batch_id",
10602
11809
  "created_at",
@@ -10614,8 +11821,162 @@ var OWN_ENTITIES = entityFields({
10614
11821
  "proposed",
10615
11822
  "waiting",
10616
11823
  "flagged",
10617
- "errors"
11824
+ "unmatched",
11825
+ "ignored",
11826
+ "vcard",
11827
+ "errors",
11828
+ "truncated"
11829
+ ],
11830
+ product: [
11831
+ "id",
11832
+ "ref",
11833
+ "title",
11834
+ "kind",
11835
+ "name",
11836
+ "sku",
11837
+ "supplier",
11838
+ "unit",
11839
+ "unit_price",
11840
+ "currency",
11841
+ "description",
11842
+ "archived_date",
11843
+ "author",
11844
+ "model",
11845
+ "source",
11846
+ "created_at",
11847
+ "updated_at"
11848
+ ],
11849
+ contract: [
11850
+ "id",
11851
+ "ref",
11852
+ "title",
11853
+ "name",
11854
+ "number",
11855
+ "kind",
11856
+ "status",
11857
+ "signed_date",
11858
+ "effective_date",
11859
+ "expiration_date",
11860
+ "auto_renew",
11861
+ "renewal",
11862
+ "notice_days",
11863
+ "notice_deadline",
11864
+ "terms",
11865
+ "value",
11866
+ "currency",
11867
+ "deal",
11868
+ "review",
11869
+ "author",
11870
+ "model",
11871
+ "confirmed_by",
11872
+ "source",
11873
+ "reason",
11874
+ "evidence",
11875
+ "project",
11876
+ "project_name",
11877
+ "created_at",
11878
+ "updated_at"
11879
+ ],
11880
+ subscription: [
11881
+ "id",
11882
+ "ref",
11883
+ "title",
11884
+ "name",
11885
+ "direction",
11886
+ "supplier",
11887
+ "customer",
11888
+ "product",
11889
+ "contract",
11890
+ "status",
11891
+ "interval",
11892
+ "start_date",
11893
+ "trial_end_date",
11894
+ "next_renewal_date",
11895
+ "cancelled_date",
11896
+ "end_date",
11897
+ "current_price",
11898
+ "prices",
11899
+ "review",
11900
+ "author",
11901
+ "model",
11902
+ "confirmed_by",
11903
+ "source",
11904
+ "reason",
11905
+ "evidence",
11906
+ "project",
11907
+ "project_name",
11908
+ "created_at",
11909
+ "updated_at"
11910
+ ],
11911
+ subscription_price: [
11912
+ "id",
11913
+ "ref",
11914
+ "title",
11915
+ "subscription",
11916
+ "amount",
11917
+ "currency",
11918
+ "effective_from",
11919
+ "review",
11920
+ "author",
11921
+ "reason",
11922
+ "project",
11923
+ "created_at"
11924
+ ],
11925
+ wallet: [
11926
+ "id",
11927
+ "ref",
11928
+ "title",
11929
+ "name",
11930
+ "kind",
11931
+ "currency",
11932
+ "institution",
11933
+ "number_hint",
11934
+ "holder",
11935
+ "opening_balance",
11936
+ "opening_date",
11937
+ "closed_date",
11938
+ "balance",
11939
+ "until",
11940
+ "pending",
11941
+ "source_says",
11942
+ "author",
11943
+ "model",
11944
+ "source",
11945
+ "created_at",
11946
+ "updated_at"
11947
+ ],
11948
+ transaction: [
11949
+ "id",
11950
+ "ref",
11951
+ "title",
11952
+ "wallet",
11953
+ "wallet_name",
11954
+ "direction",
11955
+ "amount",
11956
+ "currency",
11957
+ "status",
11958
+ "statement_date",
11959
+ "booked_date",
11960
+ "description",
11961
+ "counterparty_name",
11962
+ "counterparty",
11963
+ "reference",
11964
+ "payment",
11965
+ "splits",
11966
+ "uncategorized",
11967
+ "review",
11968
+ "author",
11969
+ "model",
11970
+ "confirmed_by",
11971
+ "source",
11972
+ "reason",
11973
+ "evidence",
11974
+ "project",
11975
+ "project_name",
11976
+ "created_at",
11977
+ "updated_at"
10618
11978
  ],
11979
+ records_match: ["linked", "created", "unmatched", "proposed", "errors", "truncated"],
10619
11980
  payment_allocation: ["payment", "invoice", "amount", "currency", "created_at"]
10620
11981
  });
10621
11982
  var SKILL_TOPICS = [
@@ -10667,6 +12028,11 @@ var createProgram = /* @__PURE__ */ __name(({ streams: raw = processStreams, env
10667
12028
  financeCommands(program, streams, env);
10668
12029
  orderCommands(program, streams, env);
10669
12030
  dealCommands(program, streams, env);
12031
+ productCommands(program, streams, env);
12032
+ contractCommands(program, streams, env);
12033
+ subscriptionCommands(program, streams, env);
12034
+ walletCommands(program, streams, env);
12035
+ transactionCommands(program, streams, env);
10670
12036
  recordsCommand(program, streams, env);
10671
12037
  findingsCommand(program, streams, env);
10672
12038
  actionsCommand(program, streams, env);
@@ -10677,6 +12043,7 @@ var createProgram = /* @__PURE__ */ __name(({ streams: raw = processStreams, env
10677
12043
  searchCommand(program, streams, env);
10678
12044
  meetingReadCommands(program, streams, env);
10679
12045
  meetingPreparationCommand(program, streams, env);
12046
+ eventsCommand(program, streams, env);
10680
12047
  askCommand(program, streams, env);
10681
12048
  syncCommand(program, streams, env, signal, keyring);
10682
12049
  storeCommand(program, streams, env);
@@ -10689,10 +12056,10 @@ var createProgram = /* @__PURE__ */ __name(({ streams: raw = processStreams, env
10689
12056
  const skill2 = customizeSharedCommand(skillCommand2(APP, new URL("../skills/cli-memo/SKILL.md", new URL("../program.js", import.meta.url).href)), "Memo installs its own stored-data instructions through its environment, prints the packaged primary skill without filesystem effects, and takes --json on each skill command because it has no global one.", () => {
10690
12057
  const out = answers(program, streams, env);
10691
12058
  const skill3 = skillCommand(APP, new URL("../skills/cli-memo/SKILL.md", new URL("../program.js", import.meta.url).href), (command) => {
10692
- const json7 = command.opts().json === true;
10693
- const renderer = createRenderer({ format: json7 ? "json" : "pretty", color: false, streams });
12059
+ const json5 = command.opts().json === true;
12060
+ const renderer = createRenderer({ format: json5 ? "json" : "pretty", color: false, streams });
10694
12061
  return {
10695
- renderer: json7 ? { ...renderer, result: /* @__PURE__ */ __name((value) => out.print(true, itemAnswer(value)), "result") } : renderer,
12062
+ renderer: json5 ? { ...renderer, result: /* @__PURE__ */ __name((value) => out.print(true, itemAnswer(value)), "result") } : renderer,
10696
12063
  streams,
10697
12064
  env
10698
12065
  };