@wirecat/cli-core 0.294.0 → 0.296.0

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 (167) hide show
  1. package/README.md +1 -0
  2. package/dist/cli/bot/mcp.js +1 -1
  3. package/dist/cli/bot/mcp.js.map +1 -1
  4. package/dist/cli/bot/watch.js +1 -1
  5. package/dist/cli/bot/watch.js.map +1 -1
  6. package/dist/cli/messenger/backfill-command.js +1 -1
  7. package/dist/cli/messenger/backfill-command.js.map +1 -1
  8. package/dist/cli/messenger/mcp-command.js +1 -1
  9. package/dist/cli/messenger/mcp-command.js.map +1 -1
  10. package/dist/cli/messenger/serve-command.js +1 -1
  11. package/dist/cli/messenger/serve-command.js.map +1 -1
  12. package/dist/cli/messenger/store-maintenance-command.d.ts +1 -1
  13. package/dist/cli/messenger/tasks-command.d.ts.map +1 -1
  14. package/dist/cli/messenger/tasks-command.js +75 -13
  15. package/dist/cli/messenger/tasks-command.js.map +1 -1
  16. package/dist/cli/messenger/watch-command.js +1 -1
  17. package/dist/cli/messenger/watch-command.js.map +1 -1
  18. package/dist/cli/program.d.ts.map +1 -1
  19. package/dist/cli/program.js +4 -5
  20. package/dist/cli/program.js.map +1 -1
  21. package/dist/cli/store-settings.d.ts +13 -0
  22. package/dist/cli/store-settings.d.ts.map +1 -1
  23. package/dist/cli/store-settings.js +76 -8
  24. package/dist/cli/store-settings.js.map +1 -1
  25. package/dist/documents/catalog.d.ts +3 -0
  26. package/dist/documents/catalog.d.ts.map +1 -0
  27. package/dist/documents/catalog.js +18 -0
  28. package/dist/documents/catalog.js.map +1 -0
  29. package/dist/documents/index.d.ts +10 -0
  30. package/dist/documents/index.d.ts.map +1 -0
  31. package/dist/documents/index.js +8 -0
  32. package/dist/documents/index.js.map +1 -0
  33. package/dist/documents/model.d.ts +117 -0
  34. package/dist/documents/model.d.ts.map +1 -0
  35. package/dist/documents/model.js +2 -0
  36. package/dist/documents/model.js.map +1 -0
  37. package/dist/documents/scope.d.ts +3 -0
  38. package/dist/documents/scope.d.ts.map +1 -0
  39. package/dist/documents/scope.js +15 -0
  40. package/dist/documents/scope.js.map +1 -0
  41. package/dist/documents.d.ts +1 -0
  42. package/dist/documents.d.ts.map +1 -1
  43. package/dist/documents.js +1 -0
  44. package/dist/documents.js.map +1 -1
  45. package/dist/domain/task-categories.d.ts +15 -2
  46. package/dist/domain/task-categories.d.ts.map +1 -1
  47. package/dist/domain/task-categories.js +649 -26
  48. package/dist/domain/task-categories.js.map +1 -1
  49. package/dist/entities/agenda.d.ts +14 -1
  50. package/dist/entities/agenda.d.ts.map +1 -1
  51. package/dist/entities/agenda.js +6 -1
  52. package/dist/entities/agenda.js.map +1 -1
  53. package/dist/entities/index.d.ts +19 -1
  54. package/dist/entities/index.d.ts.map +1 -1
  55. package/dist/entities/task.d.ts +19 -0
  56. package/dist/entities/task.d.ts.map +1 -1
  57. package/dist/entities/task.js +11 -0
  58. package/dist/entities/task.js.map +1 -1
  59. package/dist/errors/reasons.d.ts +1 -1
  60. package/dist/errors/reasons.d.ts.map +1 -1
  61. package/dist/errors/reasons.js +12 -1
  62. package/dist/errors/reasons.js.map +1 -1
  63. package/dist/mcp/tools/tasks.d.ts.map +1 -1
  64. package/dist/mcp/tools/tasks.js +46 -18
  65. package/dist/mcp/tools/tasks.js.map +1 -1
  66. package/dist/search/task-signature.d.ts.map +1 -1
  67. package/dist/search/task-signature.js +32 -6
  68. package/dist/search/task-signature.js.map +1 -1
  69. package/dist/search/task-similarity.d.ts +15 -2
  70. package/dist/search/task-similarity.d.ts.map +1 -1
  71. package/dist/search/task-similarity.js +29 -10
  72. package/dist/search/task-similarity.js.map +1 -1
  73. package/dist/services/agenda.d.ts +7 -2
  74. package/dist/services/agenda.d.ts.map +1 -1
  75. package/dist/services/agenda.js +11 -0
  76. package/dist/services/agenda.js.map +1 -1
  77. package/dist/services/documents/extraction.d.ts +13 -0
  78. package/dist/services/documents/extraction.d.ts.map +1 -0
  79. package/dist/services/documents/extraction.js +37 -0
  80. package/dist/services/documents/extraction.js.map +1 -0
  81. package/dist/services/documents/ingestion.d.ts +29 -0
  82. package/dist/services/documents/ingestion.d.ts.map +1 -0
  83. package/dist/services/documents/ingestion.js +125 -0
  84. package/dist/services/documents/ingestion.js.map +1 -0
  85. package/dist/services/documents/knowledge.d.ts +58 -0
  86. package/dist/services/documents/knowledge.d.ts.map +1 -0
  87. package/dist/services/documents/knowledge.js +143 -0
  88. package/dist/services/documents/knowledge.js.map +1 -0
  89. package/dist/services/documents/plan.d.ts +11 -0
  90. package/dist/services/documents/plan.d.ts.map +1 -0
  91. package/dist/services/documents/plan.js +200 -0
  92. package/dist/services/documents/plan.js.map +1 -0
  93. package/dist/services/documents/ports.d.ts +24 -0
  94. package/dist/services/documents/ports.d.ts.map +1 -0
  95. package/dist/services/documents/ports.js +2 -0
  96. package/dist/services/documents/ports.js.map +1 -0
  97. package/dist/services/documents/proposals.d.ts +38 -0
  98. package/dist/services/documents/proposals.d.ts.map +1 -0
  99. package/dist/services/documents/proposals.js +52 -0
  100. package/dist/services/documents/proposals.js.map +1 -0
  101. package/dist/services/documents/sync.d.ts +24 -0
  102. package/dist/services/documents/sync.d.ts.map +1 -0
  103. package/dist/services/documents/sync.js +217 -0
  104. package/dist/services/documents/sync.js.map +1 -0
  105. package/dist/services/task-categories.d.ts +5 -2
  106. package/dist/services/task-categories.d.ts.map +1 -1
  107. package/dist/services/task-categories.js +37 -14
  108. package/dist/services/task-categories.js.map +1 -1
  109. package/dist/services/tasks.d.ts +38 -12
  110. package/dist/services/tasks.d.ts.map +1 -1
  111. package/dist/services/tasks.js +83 -17
  112. package/dist/services/tasks.js.map +1 -1
  113. package/dist/store/index.d.ts +1 -0
  114. package/dist/store/index.d.ts.map +1 -1
  115. package/dist/store/index.js +1 -0
  116. package/dist/store/index.js.map +1 -1
  117. package/dist/store/sqlite/lucene.d.ts.map +1 -1
  118. package/dist/store/sqlite/lucene.js +5 -2
  119. package/dist/store/sqlite/lucene.js.map +1 -1
  120. package/dist/store/sqlite/manifest.d.ts.map +1 -1
  121. package/dist/store/sqlite/manifest.js +1 -0
  122. package/dist/store/sqlite/manifest.js.map +1 -1
  123. package/dist/store/sqlite/migrations.generated.d.ts.map +1 -1
  124. package/dist/store/sqlite/migrations.generated.js +13 -0
  125. package/dist/store/sqlite/migrations.generated.js.map +1 -1
  126. package/dist/store/sqlite/schema.d.ts +112 -0
  127. package/dist/store/sqlite/schema.d.ts.map +1 -1
  128. package/dist/store/sqlite/schema.js +8 -0
  129. package/dist/store/sqlite/schema.js.map +1 -1
  130. package/dist/store/sqlite/task-candidates.d.ts +2 -0
  131. package/dist/store/sqlite/task-candidates.d.ts.map +1 -1
  132. package/dist/store/sqlite/task-candidates.js +76 -32
  133. package/dist/store/sqlite/task-candidates.js.map +1 -1
  134. package/dist/store/sqlite/task-category-settings.d.ts +3 -1
  135. package/dist/store/sqlite/task-category-settings.d.ts.map +1 -1
  136. package/dist/store/sqlite/task-category-settings.js +11 -1
  137. package/dist/store/sqlite/task-category-settings.js.map +1 -1
  138. package/dist/store/sqlite/task-close-store.d.ts +24 -0
  139. package/dist/store/sqlite/task-close-store.d.ts.map +1 -0
  140. package/dist/store/sqlite/task-close-store.js +57 -0
  141. package/dist/store/sqlite/task-close-store.js.map +1 -0
  142. package/dist/store/sqlite/task-close.d.ts +35 -0
  143. package/dist/store/sqlite/task-close.d.ts.map +1 -0
  144. package/dist/store/sqlite/task-close.js +68 -0
  145. package/dist/store/sqlite/task-close.js.map +1 -0
  146. package/dist/store/sqlite/task-pairs.d.ts +14 -4
  147. package/dist/store/sqlite/task-pairs.d.ts.map +1 -1
  148. package/dist/store/sqlite/task-pairs.js +31 -5
  149. package/dist/store/sqlite/task-pairs.js.map +1 -1
  150. package/dist/store/sqlite/task-relations.d.ts.map +1 -1
  151. package/dist/store/sqlite/task-relations.js +4 -1
  152. package/dist/store/sqlite/task-relations.js.map +1 -1
  153. package/dist/store/sqlite/tasks.d.ts +7 -2
  154. package/dist/store/sqlite/tasks.d.ts.map +1 -1
  155. package/dist/store/sqlite/tasks.js +18 -5
  156. package/dist/store/sqlite/tasks.js.map +1 -1
  157. package/dist/store/sqlite/work-tasks.d.ts +6 -1
  158. package/dist/store/sqlite/work-tasks.d.ts.map +1 -1
  159. package/dist/store/sqlite/work-tasks.js +8 -0
  160. package/dist/store/sqlite/work-tasks.js.map +1 -1
  161. package/dist/store/store.d.ts +1 -0
  162. package/dist/store/store.d.ts.map +1 -1
  163. package/dist/store/store.js +1 -0
  164. package/dist/store/store.js.map +1 -1
  165. package/package.json +3 -3
  166. package/parity.json +34 -0
  167. package/skills/follow-ups/SKILL.md +2 -1
@@ -2,13 +2,573 @@ import { CliError, singleLine } from "@wirecat/cli-base";
2
2
  /**
3
3
  * The fixed list a task's category comes from. One list, so "finance", "payments" and "деньги" never coexist;
4
4
  * `other` is what a rule picks when no trigger word matches.
5
+ *
6
+ * Order matters: a rule takes the category with the most trigger hits and gives a tie to the earlier one, so narrow
7
+ * categories come first, the generic actions (money, documents, meeting) after them, and work and personal last.
8
+ * A trigger of several words counts each word on its own, so every trigger here is one word, and none stems to a
9
+ * common word (`billing` → bill, `staging` → stage, `друг` → другой).
5
10
  */
6
11
  export const DEFAULT_TASK_CATEGORIES = [
12
+ {
13
+ name: "taxes",
14
+ meaning: "tax returns, the accountant, the tax office",
15
+ triggers: {
16
+ en: ["tax", "taxes", "accountant", "vat", "hmrc"],
17
+ ru: ["налог", "налоговая", "декларация", "бухгалтер", "ндфл", "ифнс", "вычет"],
18
+ es: ["impuesto", "impuestos", "hacienda", "iva", "irpf", "gestor", "gestoría"],
19
+ },
20
+ },
21
+ {
22
+ name: "investments",
23
+ meaning: "stocks, funds, crypto, a broker",
24
+ triggers: {
25
+ en: [
26
+ "invest",
27
+ "investment",
28
+ "investments",
29
+ "stocks",
30
+ "broker",
31
+ "brokerage",
32
+ "portfolio",
33
+ "crypto",
34
+ "etf",
35
+ "dividend",
36
+ "dividends",
37
+ ],
38
+ ru: ["инвестиции", "инвестировать", "брокер", "облигации", "портфель", "крипта", "криптовалюта", "дивиденды"],
39
+ es: ["inversión", "invertir", "bróker", "dividendos", "cripto", "bolsa"],
40
+ },
41
+ },
42
+ {
43
+ name: "subscriptions",
44
+ meaning: "a service subscription to start, cancel or renew",
45
+ triggers: {
46
+ en: ["subscription", "subscriptions", "subscribe", "unsubscribe", "renewal", "membership", "trial"],
47
+ ru: ["подписка", "подписку", "абонентская", "абонемент", "продление"],
48
+ es: ["suscripción", "suscribirse", "renovación", "membresía"],
49
+ },
50
+ },
51
+ {
52
+ name: "bills",
53
+ meaning: "a recurring bill: utilities, phone, internet",
54
+ triggers: {
55
+ en: ["utility", "utilities", "electricity", "heating"],
56
+ ru: ["коммуналка", "коммунальные", "электричество", "газ", "квитанция", "показания"],
57
+ es: ["recibo", "recibos", "suministro", "suministros", "electricidad"],
58
+ },
59
+ },
60
+ {
61
+ name: "donations",
62
+ meaning: "a donation, a fundraiser, a charity",
63
+ triggers: {
64
+ en: ["donate", "donation", "donations", "charity", "fundraiser", "crowdfunding", "patreon"],
65
+ ru: ["пожертвование", "пожертвовать", "благотворительность", "донат", "фонд"],
66
+ es: ["donación", "donar", "benéfico", "beneficencia", "ong"],
67
+ },
68
+ },
69
+ {
70
+ name: "insurance",
71
+ meaning: "an insurance policy or claim",
72
+ triggers: {
73
+ en: ["insurance", "insurer", "insured", "coverage"],
74
+ ru: ["страховка", "страховая", "страхование", "полис", "осаго", "каско", "дмс"],
75
+ es: ["aseguradora", "póliza", "siniestro", "mutua"],
76
+ },
77
+ },
78
+ {
79
+ name: "bank",
80
+ meaning: "cards, bank accounts, wire transfers, a bank's request",
81
+ triggers: {
82
+ en: ["bank", "banking", "card", "iban", "swift", "wire", "overdraft"],
83
+ ru: ["банк", "карта", "карту", "реквизиты", "выписка", "iban", "swift"],
84
+ es: ["banco", "tarjeta", "iban", "swift"],
85
+ },
86
+ },
87
+ {
88
+ name: "civic",
89
+ meaning: "voting, a petition, a census, jury duty, the local council",
90
+ triggers: {
91
+ en: ["vote", "voting", "election", "elections", "petition", "census", "jury", "ballot"],
92
+ ru: ["выборы", "голосование", "проголосовать", "петиция", "перепись", "депутат"],
93
+ es: ["elecciones", "votar", "votación", "censo", "referéndum"],
94
+ },
95
+ },
96
+ {
97
+ name: "government",
98
+ meaning: "a visa, residence, a permit, an appointment at a public office",
99
+ triggers: {
100
+ en: ["visa", "residence", "permit", "embassy", "consulate", "passport", "citizenship", "nie"],
101
+ ru: [
102
+ "виза",
103
+ "внж",
104
+ "гражданство",
105
+ "посольство",
106
+ "консульство",
107
+ "госуслуги",
108
+ "мфц",
109
+ "паспорт",
110
+ "загранпаспорт",
111
+ "прописка",
112
+ ],
113
+ es: [
114
+ "visado",
115
+ "residencia",
116
+ "extranjería",
117
+ "empadronamiento",
118
+ "padrón",
119
+ "ayuntamiento",
120
+ "consulado",
121
+ "embajada",
122
+ "pasaporte",
123
+ "nie",
124
+ ],
125
+ },
126
+ },
127
+ {
128
+ name: "legal",
129
+ meaning: "a lawyer, a notary, a court or a dispute",
130
+ triggers: {
131
+ en: ["lawyer", "attorney", "notary", "court", "lawsuit", "dispute", "legal"],
132
+ ru: ["юрист", "адвокат", "нотариус", "иск", "претензия", "доверенность", "судебный"],
133
+ es: ["abogado", "notario", "juzgado", "demanda", "tribunal", "litigio"],
134
+ },
135
+ },
136
+ {
137
+ name: "hiring",
138
+ meaning: "candidates, interviews, job offers",
139
+ triggers: {
140
+ en: ["candidate", "candidates", "interview", "hire", "hiring", "recruiter", "vacancy", "resume", "cv"],
141
+ ru: ["кандидат", "собеседование", "вакансия", "резюме", "оффер", "найм", "рекрутер"],
142
+ es: ["candidato", "entrevista", "vacante", "currículum", "contratación"],
143
+ },
144
+ },
145
+ {
146
+ name: "sales",
147
+ meaning: "leads, deals, quotes",
148
+ triggers: {
149
+ en: ["quote", "pipeline", "prospect", "crm", "sales"],
150
+ ru: ["лид", "лиды", "сделка", "продажи", "коммерческое"],
151
+ es: ["venta", "ventas", "presupuesto"],
152
+ },
153
+ },
154
+ {
155
+ name: "partners",
156
+ meaning: "a partnership or an integration with another company",
157
+ triggers: {
158
+ en: ["partner", "partners", "partnership", "integration", "affiliate", "reseller"],
159
+ ru: ["партнёр", "партнёры", "партнёрство", "интеграция"],
160
+ es: ["socio", "alianza", "integración", "colaboración"],
161
+ },
162
+ },
163
+ {
164
+ name: "support",
165
+ meaning: "a user's or customer's problem to solve",
166
+ triggers: {
167
+ en: ["support", "complaint", "helpdesk", "outage"],
168
+ ru: ["поддержка", "жалоба", "обращение", "тикет"],
169
+ es: ["soporte", "incidencia", "queja", "reclamación"],
170
+ },
171
+ },
172
+ {
173
+ name: "security",
174
+ meaning: "a hacked account, a scam, 2FA, a leak or breach",
175
+ triggers: {
176
+ en: ["hacked", "hack", "scam", "phishing", "breach", "2fa", "malware", "fraud", "spam"],
177
+ ru: ["взлом", "взломали", "мошенники", "мошенничество", "фишинг", "утечка", "спам"],
178
+ es: ["hackeado", "estafa", "fraude", "phishing", "suplantación"],
179
+ },
180
+ },
181
+ {
182
+ name: "access",
183
+ meaning: "a login, password, key, invite or permission to give or get",
184
+ triggers: {
185
+ en: ["access", "password", "credentials", "invite", "permission", "key", "keys", "token", "vpn"],
186
+ ru: ["доступ", "пароль", "логин", "ключ", "ключи", "приглашение", "аккаунт"],
187
+ es: ["acceso", "contraseña", "llave", "llaves", "clave", "invitación", "permiso"],
188
+ },
189
+ },
190
+ {
191
+ name: "tech",
192
+ meaning: "code, servers, bugs, builds, deploys",
193
+ triggers: {
194
+ en: [
195
+ "bug",
196
+ "deploy",
197
+ "deployment",
198
+ "server",
199
+ "build",
200
+ "code",
201
+ "merge",
202
+ "crash",
203
+ "flaky",
204
+ "database",
205
+ "api",
206
+ "release",
207
+ "prod",
208
+ ],
209
+ ru: ["баг", "деплой", "сервер", "сборка", "код", "пулреквест", "прод", "релиз"],
210
+ es: ["fallo", "servidor", "despliegue", "código"],
211
+ },
212
+ },
213
+ {
214
+ name: "media",
215
+ meaning: "the press, a journalist, a podcast or an interview for the media",
216
+ triggers: {
217
+ en: ["press", "journalist", "podcast", "media"],
218
+ ru: ["журналист", "пресса", "сми", "подкаст", "интервью", "редакция"],
219
+ es: ["prensa", "periodista", "podcast", "entrevistarte"],
220
+ },
221
+ },
222
+ {
223
+ name: "marketing",
224
+ meaning: "campaigns, ads, SEO, newsletters, social media",
225
+ triggers: {
226
+ en: ["marketing", "campaign", "ads", "advertising", "seo", "promo", "newsletter", "instagram"],
227
+ ru: ["маркетинг", "реклама", "рекламу", "таргет", "кампания", "рассылка", "продвижение"],
228
+ es: ["marketing", "campaña", "publicidad", "anuncio", "anuncios", "boletín"],
229
+ },
230
+ },
231
+ {
232
+ name: "design",
233
+ meaning: "UI, mockups, a logo or a brand to design or review",
234
+ triggers: {
235
+ en: ["design", "designer", "mockup", "mockups", "logo", "brand", "branding", "figma", "wireframe", "ui", "ux"],
236
+ ru: ["дизайн", "дизайнер", "макет", "макеты", "логотип", "фигма", "брендинг"],
237
+ es: ["diseño", "diseñador", "logotipo", "maqueta", "marca"],
238
+ },
239
+ },
240
+ {
241
+ name: "research",
242
+ meaning: "research, a survey, an analysis or a benchmark",
243
+ triggers: {
244
+ en: ["research", "survey", "benchmark", "analysis", "experiment", "dataset"],
245
+ ru: ["исследование", "опрос", "бенчмарк", "эксперимент", "датасет"],
246
+ es: ["investigación", "encuesta", "experimento"],
247
+ },
248
+ },
249
+ {
250
+ name: "content",
251
+ meaning: "posts, articles, videos to write, film or review",
252
+ triggers: {
253
+ en: ["article", "blog", "video", "draft", "copywriting"],
254
+ ru: ["пост", "блог", "видео", "ролик", "черновик"],
255
+ es: ["artículo", "publicación", "vídeo", "video", "borrador"],
256
+ },
257
+ },
258
+ {
259
+ name: "vendors",
260
+ meaning: "a supplier, contractor or agency you pay for a service",
261
+ triggers: {
262
+ en: ["vendor", "vendors", "supplier", "suppliers", "contractor", "freelancer", "agency", "outsourcing"],
263
+ ru: ["поставщик", "подрядчик", "фрилансер", "агентство", "исполнитель"],
264
+ es: ["proveedor", "proveedores", "contratista", "agencia"],
265
+ },
266
+ },
267
+ {
268
+ name: "car",
269
+ meaning: "the car: repairs, parking, fines, inspection",
270
+ triggers: {
271
+ en: ["car", "parking", "mechanic", "garage", "tyres", "tires", "mot"],
272
+ ru: ["машина", "авто", "парковка", "штраф", "гибдд", "шиномонтаж", "техосмотр"],
273
+ es: ["coche", "aparcamiento", "multa", "taller", "itv", "neumáticos"],
274
+ },
275
+ },
276
+ {
277
+ name: "travel",
278
+ meaning: "flights, trains, hotels, trips",
279
+ triggers: {
280
+ en: ["flight", "flights", "hotel", "airport", "trip", "train", "airbnb", "boarding"],
281
+ ru: ["рейс", "перелёт", "самолёт", "гостиница", "отель", "аэропорт", "поезд", "поездка", "командировка"],
282
+ es: ["vuelo", "vuelos", "hotel", "aeropuerto", "viaje", "tren"],
283
+ },
284
+ },
285
+ {
286
+ name: "pets",
287
+ meaning: "a pet: the vet, food, a sitter, walks",
288
+ triggers: {
289
+ en: ["pet", "pets", "vet", "dog", "cat", "puppy", "kitten", "grooming"],
290
+ ru: ["ветеринар", "ветклиника", "собака", "собаку", "кошка", "кот", "щенок", "котёнок", "груминг"],
291
+ es: ["veterinario", "perro", "gato", "mascota", "cachorro"],
292
+ },
293
+ },
294
+ {
295
+ name: "fitness",
296
+ meaning: "the gym, training, a sport",
297
+ triggers: {
298
+ en: ["gym", "workout", "trainer", "yoga", "pilates", "fitness", "marathon", "swimming"],
299
+ ru: ["спортзал", "тренировка", "тренер", "йога", "фитнес", "бассейн", "пробежка"],
300
+ es: ["gimnasio", "entrenador", "entrenamiento", "yoga", "pilates", "piscina"],
301
+ },
302
+ },
303
+ {
304
+ name: "beauty",
305
+ meaning: "a haircut, nails, cosmetics, a salon",
306
+ triggers: {
307
+ en: ["haircut", "hairdresser", "barber", "salon", "manicure", "nails", "cosmetics", "spa"],
308
+ ru: ["парикмахер", "стрижка", "маникюр", "косметолог", "барбершоп", "салон", "косметика"],
309
+ es: ["peluquería", "peluquero", "manicura", "uñas", "estética", "cosmética"],
310
+ },
311
+ },
312
+ {
313
+ name: "health",
314
+ meaning: "doctors, prescriptions, medicines",
315
+ triggers: {
316
+ en: ["doctor", "dentist", "clinic", "hospital", "prescription", "pharmacy", "medicine", "medicines", "vitamins"],
317
+ ru: [
318
+ "врач",
319
+ "стоматолог",
320
+ "окулист",
321
+ "кардиолог",
322
+ "больница",
323
+ "поликлиника",
324
+ "лекарство",
325
+ "лекарства",
326
+ "рецепт",
327
+ "аптека",
328
+ "анализы",
329
+ "витамины",
330
+ ],
331
+ es: ["médico", "dentista", "clínica", "hospital", "receta", "farmacia", "medicamento"],
332
+ },
333
+ },
334
+ {
335
+ name: "education",
336
+ meaning: "courses, books, languages, studies at school or university",
337
+ triggers: {
338
+ en: ["course", "lesson", "tutor", "university", "exam", "homework", "study"],
339
+ ru: ["курсы", "урок", "репетитор", "университет", "экзамен", "учёба", "лекция", "книга"],
340
+ es: ["curso", "universidad", "examen", "libro", "idioma"],
341
+ },
342
+ },
343
+ {
344
+ name: "celebrations",
345
+ meaning: "a birthday, wedding, anniversary or holiday to plan or mark",
346
+ triggers: {
347
+ en: ["birthday", "anniversary", "christmas", "celebration", "celebrate"],
348
+ ru: ["рождения", "свадьба", "юбилей", "годовщина", "праздник", "праздновать"],
349
+ es: ["cumpleaños", "boda", "aniversario", "navidad", "celebrar", "celebración"],
350
+ },
351
+ },
352
+ {
353
+ name: "childcare",
354
+ meaning: "a nanny, a babysitter, kindergarten, kids' clubs",
355
+ triggers: {
356
+ en: ["nanny", "babysitter", "babysitting", "kindergarten", "daycare", "nursery"],
357
+ ru: ["няня", "садик", "детсад", "кружок", "продлёнка"],
358
+ es: ["niñera", "guardería", "canguro", "extraescolares"],
359
+ },
360
+ },
361
+ {
362
+ name: "elder-care",
363
+ meaning: "care for an older relative: a carer, a care home",
364
+ triggers: {
365
+ en: ["carer", "caregiver", "eldercare", "elderly"],
366
+ ru: ["сиделка", "пансионат", "пожилой", "пожилых"],
367
+ es: ["cuidadora", "cuidador", "geriátrico", "mayores"],
368
+ },
369
+ },
370
+ {
371
+ name: "family",
372
+ meaning: "kids, school, parents and relatives",
373
+ triggers: {
374
+ en: [
375
+ "mum",
376
+ "mom",
377
+ "dad",
378
+ "kids",
379
+ "kid",
380
+ "school",
381
+ "grandma",
382
+ "grandpa",
383
+ "wife",
384
+ "husband",
385
+ "daughter",
386
+ "parents",
387
+ ],
388
+ ru: [
389
+ "мама",
390
+ "папа",
391
+ "бабушка",
392
+ "дедушка",
393
+ "дети",
394
+ "ребёнок",
395
+ "сын",
396
+ "дочь",
397
+ "муж",
398
+ "жена",
399
+ "школа",
400
+ "учитель",
401
+ "класс",
402
+ "родители",
403
+ "родительское",
404
+ "дневник",
405
+ "тётя",
406
+ ],
407
+ es: ["mamá", "papá", "hijos", "hijo", "hija", "colegio", "abuela", "abuelo", "padres", "niños"],
408
+ },
409
+ },
410
+ {
411
+ name: "real-estate",
412
+ meaning: "buying, selling or letting a property; a mortgage",
413
+ triggers: {
414
+ en: ["mortgage", "property", "realtor", "tenant", "tenants"],
415
+ ru: ["ипотека", "недвижимость", "риелтор", "риэлтор", "арендатор", "арендаторы"],
416
+ es: ["hipoteca", "inmobiliaria", "inmueble", "compraventa", "tasación", "inquilino"],
417
+ },
418
+ },
419
+ {
420
+ name: "moving",
421
+ meaning: "moving house: movers, boxes, a new address",
422
+ triggers: {
423
+ en: ["movers", "relocation", "relocate", "removals"],
424
+ ru: ["переезд", "переехать", "переезжаем", "грузчики"],
425
+ es: ["mudanza", "mudarse", "mudanzas"],
426
+ },
427
+ },
428
+ {
429
+ name: "home",
430
+ meaning: "the flat: repairs, rent, the landlord, neighbours",
431
+ triggers: {
432
+ en: [
433
+ "flat",
434
+ "apartment",
435
+ "landlord",
436
+ "rent",
437
+ "plumber",
438
+ "leak",
439
+ "electrician",
440
+ "neighbours",
441
+ "boiler",
442
+ "intercom",
443
+ "repair",
444
+ ],
445
+ ru: [
446
+ "квартира",
447
+ "аренда",
448
+ "ремонт",
449
+ "сантехник",
450
+ "протечка",
451
+ "электрик",
452
+ "соседи",
453
+ "подъезд",
454
+ "домофон",
455
+ "подвал",
456
+ "чердак",
457
+ "этаж",
458
+ "коридор",
459
+ "жильцы",
460
+ ],
461
+ es: ["piso", "alquiler", "casero", "fontanero", "avería", "vecinos", "portal", "reforma", "calefacción"],
462
+ },
463
+ },
464
+ {
465
+ name: "delivery",
466
+ meaning: "a parcel, order or courier to send, track or collect",
467
+ triggers: {
468
+ en: ["delivery", "deliver", "parcel", "package", "shipment", "ship", "courier", "tracking", "pickup", "order"],
469
+ ru: ["доставка", "посылка", "курьер", "трек", "выдачи", "сдэк", "озон", "заказ"],
470
+ es: ["entrega", "paquete", "envío", "pedido", "mensajero", "repartidor", "correos"],
471
+ },
472
+ },
473
+ {
474
+ name: "devices",
475
+ meaning: "a phone, laptop or gadget to buy, fix or set up",
476
+ triggers: {
477
+ en: ["laptop", "iphone", "smartphone", "printer", "router", "charger", "headphones", "macbook", "gadget"],
478
+ ru: ["ноутбук", "смартфон", "айфон", "принтер", "роутер", "зарядка", "наушники", "макбук", "гаджет"],
479
+ es: ["portátil", "impresora", "cargador", "auriculares", "router", "smartphone"],
480
+ },
481
+ },
482
+ {
483
+ name: "food",
484
+ meaning: "groceries, cooking, a restaurant",
485
+ triggers: {
486
+ en: ["groceries", "restaurant", "cook", "cooking", "recipe", "takeaway"],
487
+ ru: ["продукты", "ресторан", "столик", "готовить", "кулинария"],
488
+ es: ["restaurante", "comida", "cocinar", "mercadona"],
489
+ },
490
+ },
491
+ {
492
+ name: "shopping",
493
+ meaning: "things to buy",
494
+ triggers: {
495
+ en: ["buy", "purchase", "shop", "shopping"],
496
+ ru: ["купить", "покупка", "магазин"],
497
+ es: ["comprar", "compra", "tienda", "supermercado"],
498
+ },
499
+ },
500
+ {
501
+ name: "hobbies",
502
+ meaning: "a hobby: music, photography, crafts, a game you play",
503
+ triggers: {
504
+ en: ["hobby", "guitar", "piano", "photography", "painting", "knitting", "fishing", "chess"],
505
+ ru: ["хобби", "гитара", "фортепиано", "рисование", "фотография", "рыбалка", "шахматы"],
506
+ es: ["afición", "guitarra", "piano", "fotografía", "pintura", "pesca", "ajedrez"],
507
+ },
508
+ },
509
+ {
510
+ name: "entertainment",
511
+ meaning: "films, series, concerts, games, shows",
512
+ triggers: {
513
+ en: ["film", "movie", "cinema", "series", "concert", "game", "theatre", "theater", "netflix"],
514
+ ru: ["фильм", "сериал", "концерт", "игра", "театр", "спектакль", "матч", "кинотеатр"],
515
+ es: ["película", "cine", "serie", "concierto", "juego", "teatro"],
516
+ },
517
+ },
518
+ {
519
+ name: "events",
520
+ meaning: "an event, tickets, a venue, an RSVP",
521
+ triggers: {
522
+ en: ["event", "tickets", "ticket", "rsvp", "venue", "conference", "festival", "party", "reservation"],
523
+ ru: ["мероприятие", "билеты", "конференция", "фестиваль", "вечеринка"],
524
+ es: ["evento", "entradas", "fiesta", "congreso", "conferencia"],
525
+ },
526
+ },
527
+ {
528
+ name: "religion",
529
+ meaning: "church, a service, a religious holiday or rite",
530
+ triggers: {
531
+ en: ["church", "mosque", "synagogue", "temple", "prayer", "priest", "baptism"],
532
+ ru: ["церковь", "храм", "батюшка", "молитва", "крещение", "литургия"],
533
+ es: ["iglesia", "misa", "parroquia", "bautizo", "sacerdote"],
534
+ },
535
+ },
536
+ {
537
+ name: "community",
538
+ meaning: "a group or club you run or help: members, moderation, admin work",
539
+ triggers: {
540
+ en: ["community", "club", "members", "volunteer", "moderator"],
541
+ ru: ["сообщество", "клуб", "участники", "модерация", "волонтёр"],
542
+ es: ["comunidad", "voluntario", "miembros"],
543
+ },
544
+ },
545
+ {
546
+ name: "intro",
547
+ meaning: "introduce people, or ask for an introduction",
548
+ triggers: {
549
+ en: ["intro", "introduce", "introduction", "referral"],
550
+ ru: ["познакомить", "познакомь", "знакомство"],
551
+ es: ["presentarte", "presentaros"],
552
+ },
553
+ },
7
554
  {
8
555
  name: "money",
9
556
  meaning: "pay, invoice, refund, a price or a debt",
10
557
  triggers: {
11
- en: ["pay", "payment", "invoice", "bill", "refund", "price", "money", "transfer", "debt", "salary", "cost"],
558
+ en: [
559
+ "pay",
560
+ "payment",
561
+ "invoice",
562
+ "refund",
563
+ "price",
564
+ "money",
565
+ "transfer",
566
+ "debt",
567
+ "owe",
568
+ "cost",
569
+ "reimburse",
570
+ "expenses",
571
+ ],
12
572
  ru: [
13
573
  "оплата",
14
574
  "оплатить",
@@ -21,64 +581,127 @@ export const DEFAULT_TASK_CATEGORIES = [
21
581
  "цена",
22
582
  "стоимость",
23
583
  "возврат",
584
+ "вернуть",
585
+ "скинуться",
24
586
  ],
25
587
  es: ["pagar", "pago", "factura", "dinero", "transferencia", "deuda", "precio", "reembolso", "cobrar"],
26
588
  },
27
589
  },
28
590
  {
29
591
  name: "documents",
30
- meaning: "a file, contract, scan, form or signature to send or receive",
592
+ meaning: "a contract, scan, form or signature to send or receive",
593
+ triggers: {
594
+ en: [
595
+ "document",
596
+ "documents",
597
+ "contract",
598
+ "scan",
599
+ "sign",
600
+ "signature",
601
+ "form",
602
+ "certificate",
603
+ "pdf",
604
+ "agreement",
605
+ "nda",
606
+ ],
607
+ ru: ["документ", "договор", "скан", "подписать", "подпись", "анкета", "справка", "акт", "согласие", "протокол"],
608
+ es: ["documento", "contrato", "escaneo", "firmar", "firma", "formulario", "certificado"],
609
+ },
610
+ },
611
+ {
612
+ name: "admin",
613
+ meaning: "office admin: supplies, errands, paperwork with no closer area",
31
614
  triggers: {
32
- en: ["document", "contract", "file", "scan", "sign", "signature", "form", "passport", "certificate", "pdf"],
33
- ru: ["документ", "договор", "файл", "скан", "подписать", "подпись", "паспорт", "справка", "анкета", "акт"],
34
- es: ["documento", "contrato", "archivo", "escaneo", "firmar", "firma", "formulario", "pasaporte", "certificado"],
615
+ en: ["admin", "paperwork", "errand", "errands", "stationery", "supplies"],
616
+ ru: ["канцелярия", "канцтовары", "поручение", "бумажки"],
617
+ es: ["papeleo", "recado", "recados", "gestiones"],
35
618
  },
36
619
  },
37
620
  {
38
621
  name: "meeting",
39
622
  meaning: "a call, meeting or appointment to arrange or attend",
40
623
  triggers: {
41
- en: ["meeting", "meet", "call", "appointment", "schedule", "zoom", "reschedule", "agenda"],
42
- ru: ["встреча", "встретиться", "созвон", "созвониться", "звонок", "приём", "запись", "перенести"],
43
- es: ["reunión", "reunirse", "llamada", "cita", "quedar", "agenda", "videollamada"],
624
+ en: ["meeting", "meet", "call", "appointment", "schedule", "zoom", "reschedule", "agenda", "sync", "standup"],
625
+ ru: ["встреча", "встретиться", "созвон", "созвониться", "звонок", "позвонить", "собрание"],
626
+ es: ["reunión", "reunirse", "llamada", "cita", "agenda", "videollamada"],
44
627
  },
45
628
  },
46
629
  {
47
- name: "delivery",
48
- meaning: "a parcel, order or shipment to send, track or collect",
630
+ name: "clients",
631
+ meaning: "a client's request, a proposal, a client follow-up",
49
632
  triggers: {
50
- en: ["delivery", "deliver", "parcel", "package", "shipment", "ship", "order", "courier", "tracking", "pickup"],
51
- ru: ["доставка", "доставить", "посылка", "заказ", "курьер", "отправить", "отправка", "трек", "забрать"],
52
- es: ["entrega", "entregar", "paquete", "envío", "enviar", "pedido", "mensajero", "recoger"],
633
+ en: ["client", "clients", "customer", "proposal"],
634
+ ru: ["клиент", "заказчик"],
635
+ es: ["cliente", "propuesta"],
53
636
  },
54
637
  },
55
638
  {
56
- name: "access",
57
- meaning: "a login, password, key, invite or permission to give or get",
639
+ name: "projects",
640
+ meaning: "deliverables, deadlines, launches",
641
+ triggers: {
642
+ en: ["project", "deadline", "launch", "milestone", "deliverable", "roadmap", "sprint"],
643
+ ru: ["проект", "дедлайн", "запуск", "спринт"],
644
+ es: ["proyecto", "lanzamiento", "plazo"],
645
+ },
646
+ },
647
+ {
648
+ name: "team",
649
+ meaning: "colleagues, reviews, one-to-ones, time off",
650
+ triggers: {
651
+ en: ["team", "colleague", "colleagues", "vacation", "onboarding", "manager"],
652
+ ru: ["команда", "коллега", "коллеги", "отпуск", "онбординг", "руководитель"],
653
+ es: ["equipo", "compañero", "vacaciones"],
654
+ },
655
+ },
656
+ {
657
+ name: "follow-up",
658
+ meaning: "you wait for someone: chase them",
659
+ triggers: {
660
+ en: ["remind", "reminder", "chase", "nudge", "followup"],
661
+ ru: ["напоминаю", "напомнить", "напоминание", "пинг"],
662
+ es: ["recordatorio", "recordar"],
663
+ },
664
+ },
665
+ {
666
+ name: "reply",
667
+ meaning: "someone waits for your answer",
668
+ triggers: {
669
+ en: ["reply", "respond", "answer"],
670
+ ru: ["ответь", "ответить", "ответ"],
671
+ es: ["responder", "respuesta", "contestar", "contesta"],
672
+ },
673
+ },
674
+ {
675
+ name: "work",
676
+ meaning: "a job task with no closer category",
58
677
  triggers: {
59
- en: ["access", "password", "login", "account", "key", "token", "invite", "permission", "credentials"],
60
- ru: ["доступ", "пароль", "логин", "аккаунт", "ключ", "токен", "приглашение", "права"],
61
- es: ["acceso", "contraseña", "usuario", "cuenta", "clave", "invitación", "permiso"],
678
+ en: ["work", "job", "office", "task"],
679
+ ru: ["работа", "офис", "задача", "начальник"],
680
+ es: ["trabajo", "oficina", "tarea", "jefe"],
62
681
  },
63
682
  },
64
683
  {
65
684
  name: "personal",
66
- meaning: "family, friends, health, a gift or a favour",
685
+ meaning: "friends, gifts, favours",
67
686
  triggers: {
68
- en: ["birthday", "gift", "family", "mum", "mom", "dad", "doctor", "health", "favour", "favor", "party"],
69
- ru: ["день рождения", "подарок", "семья", "мама", "папа", "врач", "здоровье", "просьба", "праздник"],
70
- es: ["cumpleaños", "regalo", "familia", "mamá", "papá", "médico", "salud", "favor", "fiesta"],
687
+ en: ["friend", "friends", "gift", "favour", "favor"],
688
+ ru: ["подруга", "подарок", "просьба", "друзья"],
689
+ es: ["amigo", "amiga", "regalo", "favor"],
71
690
  },
72
691
  },
73
692
  { name: "other", meaning: "none of the above", triggers: { en: [], ru: [], es: [] } },
74
693
  ];
75
694
  export const FALLBACK_CATEGORY = "other";
695
+ /** One line per unlisted category that says how to find and move its tasks; none when every category is listed. */
696
+ export const unlistedNote = (unlisted, tool) => unlisted.map(({ name, open, total }) => `${total} task${total === 1 ? "" : "s"} (${open} open) still use ${name}, which is not in the list: ` +
697
+ `${tool} tasks list category:${name} shows them, ${tool} tasks plan <id> --category <name> moves one`);
76
698
  const LANGUAGES = ["en", "ru", "es"];
77
699
  const NAME = /^[a-z][a-z0-9-]{0,29}$/;
700
+ const MAX_CATEGORIES = 80;
78
701
  /**
79
702
  * One category as `config set task_categories.<name>` takes it: `<meaning> | <words>`. A word may say its language
80
- * (`es:vuelo`); one that does not is Russian when written in Cyrillic, English otherwise — the rule stems every word
81
- * by its script, so the language only labels it.
703
+ * (`es:vuelo`); one that does not is Russian when written in Cyrillic, English otherwise. Only `es:` words are also
704
+ * matched by their Spanish stem, in a message that reads as Spanish.
82
705
  */
83
706
  export const parseTaskCategory = (name, value) => {
84
707
  const named = name.trim().toLowerCase();
@@ -115,8 +738,8 @@ export const withTaskCategory = (list, name, value) => {
115
738
  const category = parseTaskCategory(named, value);
116
739
  if (list.some((one) => one.name === named))
117
740
  return list.map((one) => (one.name === named ? category : one));
118
- if (list.length >= 30)
119
- throw new CliError("validation_error", "the category list takes up to 30 categories");
741
+ if (list.length >= MAX_CATEGORIES)
742
+ throw new CliError("validation_error", `the category list takes up to ${MAX_CATEGORIES} categories`);
120
743
  const fallback = list.findIndex((one) => one.name === FALLBACK_CATEGORY);
121
744
  return fallback < 0 ? [...list, category] : [...list.slice(0, fallback), category, ...list.slice(fallback)];
122
745
  };