@wirecat/cli-core 0.555.0 → 0.557.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 (68) hide show
  1. package/CHANGELOG.md +59 -0
  2. package/dist/cli/config-command.js +64 -2
  3. package/dist/cli/config-issues.d.ts +2 -0
  4. package/dist/cli/config-issues.js +11 -3
  5. package/dist/cli/config-repair.d.ts +26 -0
  6. package/dist/cli/config-repair.js +252 -0
  7. package/dist/cli/messenger/tasks-analysis-command.d.ts +8 -0
  8. package/dist/cli/messenger/tasks-analysis-command.js +184 -0
  9. package/dist/cli/messenger/tasks-command.js +11 -2
  10. package/dist/cli/steps.js +10 -0
  11. package/dist/domain/finance.d.ts +40 -0
  12. package/dist/domain/finance.js +39 -0
  13. package/dist/domain/money.d.ts +29 -0
  14. package/dist/domain/money.js +98 -0
  15. package/dist/domain/ref-summaries.js +2 -0
  16. package/dist/domain/references.d.ts +1 -1
  17. package/dist/domain/references.js +2 -0
  18. package/dist/entities/index.d.ts +64 -2
  19. package/dist/entities/index.js +5 -2
  20. package/dist/entities/task-results.d.ts +72 -0
  21. package/dist/entities/task-results.js +40 -1
  22. package/dist/errors/reasons.d.ts +1 -1
  23. package/dist/errors/reasons.js +24 -0
  24. package/dist/index.d.ts +2 -0
  25. package/dist/index.js +2 -0
  26. package/dist/mail/cli/index.d.ts +1 -0
  27. package/dist/mail/cli/index.js +3 -0
  28. package/dist/mail/cli/marks.d.ts +26 -0
  29. package/dist/mail/cli/marks.js +51 -0
  30. package/dist/mail/cli/review.js +70 -1
  31. package/dist/mail/index.d.ts +1 -0
  32. package/dist/mail/index.js +1 -0
  33. package/dist/mail/marks.d.ts +56 -0
  34. package/dist/mail/marks.js +178 -0
  35. package/dist/meetings/mcp/index.d.ts +15 -15
  36. package/dist/sends/permissions.js +1 -0
  37. package/dist/services/proposals/kinds/finance.d.ts +4 -0
  38. package/dist/services/proposals/kinds/finance.js +40 -0
  39. package/dist/services/proposals/registry.js +3 -0
  40. package/dist/services/task-analysis.d.ts +58 -0
  41. package/dist/services/task-analysis.js +125 -0
  42. package/dist/store/exports.d.ts +2 -2
  43. package/dist/store/index.d.ts +2 -1
  44. package/dist/store/sqlite/email-activity.d.ts +31 -0
  45. package/dist/store/sqlite/email-activity.js +38 -0
  46. package/dist/store/sqlite/emails.d.ts +2 -0
  47. package/dist/store/sqlite/emails.js +1 -0
  48. package/dist/store/sqlite/entity-types.d.ts +2 -0
  49. package/dist/store/sqlite/entity-types.js +2 -0
  50. package/dist/store/sqlite/finance.d.ts +199 -0
  51. package/dist/store/sqlite/finance.js +514 -0
  52. package/dist/store/sqlite/knowledge.js +3 -1
  53. package/dist/store/sqlite/manifest.js +2 -0
  54. package/dist/store/sqlite/migrations.generated.js +35 -0
  55. package/dist/store/sqlite/ref-summaries.js +33 -0
  56. package/dist/store/sqlite/schema.d.ts +1043 -0
  57. package/dist/store/sqlite/schema.js +98 -0
  58. package/dist/store/sqlite/task-analysis-marks.d.ts +7 -0
  59. package/dist/store/sqlite/task-analysis-marks.js +27 -0
  60. package/dist/store/sqlite/things.js +2 -0
  61. package/dist/store/store.d.ts +3 -0
  62. package/dist/store/store.js +5 -0
  63. package/dist/store/sync.d.ts +5 -1
  64. package/dist/store/sync.js +4 -0
  65. package/dist/store/types.d.ts +25 -0
  66. package/package.json +1 -1
  67. package/parity.json +29 -0
  68. package/skills/follow-ups/SKILL.md +22 -2
@@ -0,0 +1,184 @@
1
+ import { annotate } from "@wirecat/cli-base/commands";
2
+ import { formatLocator } from "../../domain/locator.js";
3
+ import { storedChatId } from "../../services/message-resolution.js";
4
+ import { momentOf } from "../../services/moment.js";
5
+ import { ANALYSIS_PAGE, ANALYSIS_PAGE_MAX, acknowledgeTaskAnalysis, taskAnalysisList, unanalysedMessages, } from "../../services/task-analysis.js";
6
+ import { TASK_QUERY } from "../../services/tasks.js";
7
+ import { actorOf } from "../author.js";
8
+ import { destroysNothing, LOCAL_READ, LOCAL_WRITE } from "../effects.js";
9
+ import { itemOf, renderAnswer } from "../envelope.js";
10
+ import { listQuery, pagedList, pageOf, typedQuery } from "../list-query.js";
11
+ import { positiveCount } from "../paging.js";
12
+ import { nextStep } from "../steps.js";
13
+ import { messengerContext, refuseLocalWrite } from "./context.js";
14
+ const when = (at) => (at === null ? "—" : at.slice(0, 16).replace("T", " "));
15
+ const sinceOf = (typed) => typed === undefined ? undefined : new Date(momentOf(typed, "--since-time")).toISOString();
16
+ const markItem = (mark) => ({
17
+ chat: mark.chatId,
18
+ from: mark.from,
19
+ through: mark.through,
20
+ through_id: mark.throughId,
21
+ by: mark.by,
22
+ checked_at: mark.checkedAt,
23
+ checked_through: mark.checkedThrough,
24
+ at: mark.at,
25
+ });
26
+ const analysisItem = (chat) => ({
27
+ chat: chat.chatId,
28
+ title: chat.title,
29
+ kind: chat.kind,
30
+ newest_at: chat.newestAt,
31
+ mark: chat.mark === null ? null : markItem(chat.mark),
32
+ waiting: chat.waiting,
33
+ late: chat.late,
34
+ untrusted: ["title"],
35
+ });
36
+ /**
37
+ * Each chat's own point of reading for tasks (`../../services/task-analysis.ts`): how far it was read, what waits, and
38
+ * the step that moves it. Apart from `inbox --new`, `review --new` and the messenger's read state, which other
39
+ * readers move.
40
+ */
41
+ export const analysisCommands = (tasks, messenger) => {
42
+ const tool = messenger.app.command;
43
+ annotate(tasks.command("status"), {
44
+ output: { entity: "task_analysis" },
45
+ effects: LOCAL_READ,
46
+ examples: [`${tool} personal tasks status`],
47
+ })
48
+ .summary("how far each chat was read for tasks, and how much waits")
49
+ .description("every chat that can hold your tasks — not a channel or Saved Messages — with the point its messages were read " +
50
+ "for tasks through, who read them, how many stored messages wait after it, and how many arrived late inside " +
51
+ "the stretch already read (history fetched afterwards). Its own point: reading a chat, marking it read, " +
52
+ "inbox --new and review --new never move it; tasks acknowledge does. Reads only the local store")
53
+ .option("--limit <n>", "how many chats", positiveCount("--limit"))
54
+ .action(async function () {
55
+ const context = messengerContext(this, messenger);
56
+ const { limit, offset } = pageOf(context.settings);
57
+ const chats = await context.withStore((store, account) => taskAnalysisList(store, account), {
58
+ name: "tasks status",
59
+ });
60
+ const shown = chats.slice(offset, offset + limit);
61
+ renderAnswer(this, context, pagedList("tasks status", context.settings, {
62
+ items: shown.map(analysisItem),
63
+ has_more: chats.length > offset + limit,
64
+ }), () => shown.length === 0
65
+ ? ""
66
+ : `${shown
67
+ .map((one) => `${(one.title ?? one.chatId).slice(0, 30).padEnd(30)} read through ${when(one.mark?.through ?? null)}` +
68
+ ` ${one.waiting} waiting${one.late > 0 ? `, ${one.late} late` : ""}`)
69
+ .join("\n")}\n`);
70
+ });
71
+ annotate(tasks.command("review"), {
72
+ output: { entity: "task_review" },
73
+ effects: LOCAL_READ,
74
+ examples: [`${tool} personal tasks review <chat>`, `${tool} personal tasks review <chat> --since-time 30d`],
75
+ })
76
+ .summary("a chat's stored messages not yet read for tasks, with its open tasks")
77
+ .description("the stored messages after the chat's task point, oldest first, and the chat's open tasks, so one read can open " +
78
+ "new tasks and update or close the old ones. A chat never read starts 14 days back. Moves nothing: when done, " +
79
+ "tasks acknowledge <chat> <through> records it. Reads only the local store; messages sync or backfill fetch " +
80
+ "what it lacks")
81
+ .argument("<chat>", messenger.chatArgument)
82
+ .option("--limit <n>", `how many messages (default ${ANALYSIS_PAGE}, ${ANALYSIS_PAGE_MAX} with --since-time; at most ${ANALYSIS_PAGE_MAX})`, positiveCount("--limit"))
83
+ .option("--since-time <time>", "read again from this ISO 8601 time, or 30d ago, whatever the point says; what the point already passed only " +
84
+ "updates and closes tasks, unless tasks add is given --open-new")
85
+ .action(async function (chat) {
86
+ const context = messengerContext(this, messenger);
87
+ const { sinceTime, ...options } = this.opts();
88
+ const since = sinceOf(sinceTime);
89
+ // A read again clears late messages only when one acknowledge covers the whole stretch, so it takes one page.
90
+ const limit = options.limit ?? (since === undefined ? ANALYSIS_PAGE : ANALYSIS_PAGE_MAX);
91
+ const { id, page, sourceOf } = await context.withStore(async (store, account) => {
92
+ const id = await storedChatId(messenger, chat, store, account, { includeLeft: true });
93
+ return {
94
+ id,
95
+ page: await unanalysedMessages(store, account, id, {
96
+ limit: Math.min(limit, ANALYSIS_PAGE_MAX),
97
+ ...(since === undefined ? {} : { since }),
98
+ }),
99
+ sourceOf: (message) => formatLocator({ ...account, chat: id, message }),
100
+ };
101
+ }, { name: "tasks review" });
102
+ const open = await context.withServices((services) => services.tasks.list({
103
+ query: listQuery(typedQuery([`chat:${JSON.stringify(id)}`, "state:open"]), TASK_QUERY, "tasks review"),
104
+ limit: 100,
105
+ offset: 0,
106
+ }));
107
+ const last = page.messages.at(-1);
108
+ renderAnswer(this, context, itemOf({
109
+ chat: id,
110
+ from: page.from,
111
+ mark: page.mark === null ? null : markItem(page.mark),
112
+ late: page.late,
113
+ has_more: page.more,
114
+ through: last ? sourceOf(last.id) : null,
115
+ messages: page.messages.map((one) => ({
116
+ ref: sourceOf(one.id),
117
+ at: one.timestamp,
118
+ sender: one.senderName,
119
+ outgoing: one.outgoing === true,
120
+ reply_to: one.replyTo?.id ?? one.replyToId ?? null,
121
+ text: one.text,
122
+ })),
123
+ open_tasks: open.items.map(({ key = null, kind, title, source_message }) => ({
124
+ key,
125
+ kind,
126
+ title,
127
+ source: source_message,
128
+ })),
129
+ untrusted: ["messages.text", "messages.sender"],
130
+ }, {
131
+ next: last && !(since !== undefined && page.more)
132
+ ? [
133
+ nextStep("tasks.acknowledge", {
134
+ args: { chat: id, message: last.id, since_time: since },
135
+ values: { shown: page.messages.length },
136
+ }),
137
+ ]
138
+ : [],
139
+ }), () => [
140
+ `from ${when(page.from)}: ${page.messages.length} message(s)${page.more ? ", more after them" : ""}` +
141
+ (page.late > 0
142
+ ? `; ${page.late} arrived late inside the stretch read: --since-time ${page.mark?.from} reads it again`
143
+ : ""),
144
+ ...page.messages.map((one) => ` ${when(one.timestamp)} ${one.outgoing ? "you" : (one.senderName ?? "?")}: ${one.text.replace(/\s+/g, " ").slice(0, 100)}`),
145
+ `open tasks (${open.items.length})`,
146
+ ...open.items.map((task) => ` ${task.key} ${task.kind} ${task.title ?? ""}`),
147
+ ...(since !== undefined && page.more
148
+ ? [
149
+ `this read again does not reach the point in one page: acknowledging it moves nothing and late ` +
150
+ "messages stay until a later version pages a read again (tell the owner)",
151
+ ]
152
+ : last
153
+ ? [`done reading: ${tool} tasks acknowledge ${id} ${last.id}`]
154
+ : []),
155
+ "",
156
+ ].join("\n"));
157
+ });
158
+ destroysNothing(annotate(tasks.command("acknowledge"), {
159
+ output: { entity: "task_analysis_mark" },
160
+ effects: LOCAL_WRITE,
161
+ examples: [`${tool} personal tasks acknowledge <chat> <message>`],
162
+ }))
163
+ .summary("record that a chat was read for tasks through a message")
164
+ .description("moves the chat's task point to this message once its tasks are opened, updated or closed; it never moves " +
165
+ "back. With --since-time, the read started there: a read again from the start of the stretch clears what " +
166
+ "arrived late inside it")
167
+ .argument("<chat>", messenger.chatArgument)
168
+ .argument("<message>", "the id of the last message read, as tasks review shows it")
169
+ .option("--since-time <time>", "where the read started, when tasks review was given --since-time")
170
+ .action(async function (chat, message) {
171
+ const context = messengerContext(this, messenger);
172
+ refuseLocalWrite(context, messenger.app.command, "tasks.acknowledge");
173
+ const { sinceTime } = this.opts();
174
+ const since = sinceOf(sinceTime);
175
+ const by = actorOf(this);
176
+ const { mark, moved } = await context.withStore(async (store, account) => {
177
+ const id = await storedChatId(messenger, chat, store, account, { includeLeft: true });
178
+ return acknowledgeTaskAnalysis(store, account, id, message, { by, ...(since === undefined ? {} : { since }) });
179
+ }, { name: "tasks acknowledge" });
180
+ renderAnswer(this, context, itemOf({ ...markItem(mark), moved }), () => moved
181
+ ? `read for tasks from ${when(mark.from)} through ${when(mark.through)}\n`
182
+ : `already read through ${when(mark.through)}; the point stays\n`);
183
+ });
184
+ };
@@ -5,6 +5,7 @@ import { readOnlyLockOf, readOnlyRefusal } from "../../ports/app.js";
5
5
  import { AGENDA_QUERY, agendaItem } from "../../services/agenda.js";
6
6
  import { storedChatId } from "../../services/message-resolution.js";
7
7
  import { aheadOf, momentOf } from "../../services/moment.js";
8
+ import { refuseAlreadyRead } from "../../services/task-analysis.js";
8
9
  import { unlistedNote } from "../../services/task-categories.js";
9
10
  import { ARRIVAL_WINDOW, applyTaskRulesToChats } from "../../services/task-rules.js";
10
11
  import { CLAIM_LEASE_MS, closedStateOf, TASK_PAIR_QUERY, TASK_QUERY, taskLinkKindOf, taskTypeOf, } from "../../services/tasks.js";
@@ -18,6 +19,7 @@ import { positiveCount } from "../paging.js";
18
19
  import { messengerContext, refuseLocalWrite } from "./context.js";
19
20
  import { coverageGaps } from "./search-answers.js";
20
21
  import { refuseJsonl, taskStatsAnswer } from "./stats-answers.js";
22
+ import { analysisCommands } from "./tasks-analysis-command.js";
21
23
  const line = ({ id, key, state, kind, group, createdAt, message, note }) => [
22
24
  key ?? id.slice(0, 8),
23
25
  state.padEnd(9),
@@ -175,11 +177,17 @@ export const tasksCommand = (messenger) => {
175
177
  .requiredOption("--type <type>", "the task's type: question, request, mention or promise", taskTypeOf)
176
178
  .requiredOption("--category <name>", categoryHelp)
177
179
  .option("--into <id>", "when tasks add listed tasks that may be the same job: link the message to this one instead of opening a task")
178
- .option("--new", "when tasks add listed tasks that may be the same job: open the task anyway"), "send Alex the API token").action(async function (message) {
180
+ .option("--new", "when tasks add listed tasks that may be the same job: open the task anyway")
181
+ .option("--open-new", "open a task from a message the chat's task point already passed (a read again with tasks review " +
182
+ "--since-time); without it such a read only updates and closes tasks"), "send Alex the API token").action(async function (message) {
179
183
  const context = messengerContext(this, messenger);
180
184
  refuseLocalWrite(context, messenger.app.command, "tasks.add");
181
185
  const options = this.opts();
182
- const { into, new: anyway, ...rest } = options;
186
+ const { into, new: anyway, openNew, ...rest } = options;
187
+ if (!openNew)
188
+ await context.withStore((store, account) => refuseAlreadyRead(store, account, message), {
189
+ name: "tasks add",
190
+ });
183
191
  const plan = planFrom(rest);
184
192
  const { task, created, attached, review, followUpOf, card: planned, } = await context.withServices((services) => services.tasks.add(message, options.type, writerOf(this), plan, {
185
193
  ...(into === undefined ? {} : { attach: into }),
@@ -440,6 +448,7 @@ export const tasksCommand = (messenger) => {
440
448
  }, { name: "tasks scan" });
441
449
  renderAnswer(this, context, listOf("tasks scan", { items: passes.map(snakeKeys), limit: passes.length, has_more: false }), () => `${passes.map((pass) => applyText(pass, yes, tool)).join("\n")}\n`);
442
450
  });
451
+ analysisCommands(tasks, messenger);
443
452
  destroysNothing(annotate(tasks.command("claim"), {
444
453
  output: { entity: "task_card" },
445
454
  effects: LOCAL_WRITE,
package/dist/cli/steps.js CHANGED
@@ -209,6 +209,16 @@ export const STEPS = defineSteps([
209
209
  args: [],
210
210
  why: "serve still runs an older version; a restart runs the one installed now",
211
211
  },
212
+ {
213
+ id: "tasks.acknowledge",
214
+ command: "tasks acknowledge",
215
+ args: [
216
+ { name: "chat", required: true },
217
+ { name: "message", required: true },
218
+ { name: "since_time", required: false },
219
+ ],
220
+ why: "once the tasks these {shown} messages hold are opened, updated or closed, so the next review starts after them",
221
+ },
212
222
  {
213
223
  id: "search.meetings",
214
224
  command: "*",
@@ -0,0 +1,40 @@
1
+ export declare const INVOICE_DIRECTIONS: readonly ["receivable", "payable"];
2
+ export declare const INVOICE_STATUSES: readonly ["draft", "issued", "partly_paid", "paid", "void"];
3
+ /** `in` is money to the owner, `out` money from the owner. */
4
+ export declare const MONEY_DIRECTIONS: readonly ["in", "out"];
5
+ /** The owner's entry is confirmed at once; an agent's or an import's waits as proposed. */
6
+ export declare const FINANCE_REVIEWS: readonly ["proposed", "confirmed", "rejected"];
7
+ export type InvoiceDirection = (typeof INVOICE_DIRECTIONS)[number];
8
+ export type InvoiceStatus = (typeof INVOICE_STATUSES)[number];
9
+ export type MoneyDirection = (typeof MONEY_DIRECTIONS)[number];
10
+ export type FinanceReview = (typeof FINANCE_REVIEWS)[number];
11
+ /** An invoice's status from what confirmed payments settle; `draft` and `void` are the owner's and stay. */
12
+ export declare const settledStatus: (current: InvoiceStatus, total: number, paid: number) => InvoiceStatus;
13
+ export interface InvoiceTitleFields {
14
+ id: number;
15
+ number: string | null;
16
+ direction: InvoiceDirection;
17
+ total: number;
18
+ currency: string;
19
+ counterpartyName: string | null;
20
+ dueDate: string | null;
21
+ status: InvoiceStatus;
22
+ review: FinanceReview;
23
+ }
24
+ /** "42 · 50 000.00 RUB to ООО Ромашка, due 15.11 (partly paid)": a ref summary's title, which `refLabel` prefixes. */
25
+ export declare const invoiceLine: (invoice: InvoiceTitleFields) => string;
26
+ export interface PaymentTitleFields {
27
+ direction: MoneyDirection;
28
+ amount: number;
29
+ currency: string;
30
+ /** Who paid the owner, or whom the owner paid. */
31
+ partyName: string | null;
32
+ date: string;
33
+ review: FinanceReview;
34
+ }
35
+ /** "50 000.00 RUB from ООО Ромашка, 14.11 (proposed)". */
36
+ export declare const paymentLine: (payment: PaymentTitleFields) => string;
37
+ /** "Invoice 42 · 50 000.00 RUB to ООО Ромашка, due 15.11 (partly paid)". */
38
+ export declare const invoiceTitle: (invoice: InvoiceTitleFields) => string;
39
+ /** "Payment · 50 000.00 RUB from ООО Ромашка, 14.11 (proposed)". */
40
+ export declare const paymentEntryTitle: (payment: PaymentTitleFields) => string;
@@ -0,0 +1,39 @@
1
+ import { moneyLabel } from "./money.js";
2
+ export const INVOICE_DIRECTIONS = ["receivable", "payable"];
3
+ export const INVOICE_STATUSES = ["draft", "issued", "partly_paid", "paid", "void"];
4
+ /** `in` is money to the owner, `out` money from the owner. */
5
+ export const MONEY_DIRECTIONS = ["in", "out"];
6
+ /** The owner's entry is confirmed at once; an agent's or an import's waits as proposed. */
7
+ export const FINANCE_REVIEWS = ["proposed", "confirmed", "rejected"];
8
+ /** An invoice's status from what confirmed payments settle; `draft` and `void` are the owner's and stay. */
9
+ export const settledStatus = (current, total, paid) => {
10
+ if (current === "draft" || current === "void")
11
+ return current;
12
+ if (paid <= 0)
13
+ return "issued";
14
+ return paid < total ? "partly_paid" : "paid";
15
+ };
16
+ const dayMonth = (date) => (date === null ? null : `${date.slice(8, 10)}.${date.slice(5, 7)}`);
17
+ const notes = (...words) => {
18
+ const kept = words.filter((word) => word !== null);
19
+ return kept.length === 0 ? "" : ` (${kept.join(", ")})`;
20
+ };
21
+ /** "42 · 50 000.00 RUB to ООО Ромашка, due 15.11 (partly paid)": a ref summary's title, which `refLabel` prefixes. */
22
+ export const invoiceLine = (invoice) => {
23
+ const party = invoice.counterpartyName === null
24
+ ? ""
25
+ : `${invoice.direction === "receivable" ? " to" : " from"} ${invoice.counterpartyName}`;
26
+ const due = invoice.dueDate === null ? "" : `, due ${dayMonth(invoice.dueDate)}`;
27
+ return (`${invoice.number ?? `#${invoice.id}`} · ${moneyLabel(invoice.total, invoice.currency)}${party}${due}` +
28
+ notes(invoice.status.replace("_", " "), invoice.review === "confirmed" ? null : invoice.review));
29
+ };
30
+ /** "50 000.00 RUB from ООО Ромашка, 14.11 (proposed)". */
31
+ export const paymentLine = (payment) => {
32
+ const party = payment.partyName === null ? "" : `${payment.direction === "in" ? " from" : " to"} ${payment.partyName}`;
33
+ return (`${moneyLabel(payment.amount, payment.currency)}${party}, ${dayMonth(payment.date)}` +
34
+ notes(payment.review === "confirmed" ? null : payment.review));
35
+ };
36
+ /** "Invoice 42 · 50 000.00 RUB to ООО Ромашка, due 15.11 (partly paid)". */
37
+ export const invoiceTitle = (invoice) => `Invoice ${invoiceLine(invoice)}`;
38
+ /** "Payment · 50 000.00 RUB from ООО Ромашка, 14.11 (proposed)". */
39
+ export const paymentEntryTitle = (payment) => `Payment · ${paymentLine(payment)}`;
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Minor-unit digits per ISO 4217 for the currencies the store keeps money in. A currency outside the list is refused
3
+ * rather than guessed: a wrong scale would store every amount 100 times off.
4
+ */
5
+ export declare const CURRENCY_SCALES: Readonly<Record<string, number>>;
6
+ /** An exact amount as callers read and write it: a decimal string with the currency's scale, never a float. */
7
+ export interface Money {
8
+ amount: string;
9
+ currency: string;
10
+ }
11
+ /** A non-negative decimal as an integer of `scale` decimal places; `undefined` when it is not one. */
12
+ export declare const parseDecimal: (text: string, scale: number) => bigint | undefined;
13
+ export declare const formatDecimal: (units: bigint | number, scale: number) => string;
14
+ /** `50000.00` as `50 000.00`: groups of three in the whole part, as a list prints an amount. */
15
+ export declare const groupDigits: (decimal: string) => string;
16
+ export declare const currencyOf: (text: unknown) => string;
17
+ export declare const scaleOf: (currency: string) => number;
18
+ /** Minor units of `currency` for a decimal string such as "50000.00"; refuses more decimals than the currency has. */
19
+ export declare const minorUnits: (amount: unknown, currency: string, what?: string) => number;
20
+ export declare const moneyOf: (units: number, currency: string) => Money;
21
+ /** "50 000.00 RUB". */
22
+ export declare const moneyLabel: (units: number, currency: string) => string;
23
+ /** A quantity such as "1.5" (hours, days), kept as text: at most 3 decimals, more than 0. */
24
+ export declare const quantityOf: (text: unknown) => {
25
+ text: string;
26
+ thousandths: bigint;
27
+ };
28
+ /** Quantity times unit price in minor units, half rounded up. */
29
+ export declare const lineUnits: (thousandths: bigint, unitPrice: number) => number;
@@ -0,0 +1,98 @@
1
+ import { CliError } from "@wirecat/cli-base";
2
+ /**
3
+ * Minor-unit digits per ISO 4217 for the currencies the store keeps money in. A currency outside the list is refused
4
+ * rather than guessed: a wrong scale would store every amount 100 times off.
5
+ */
6
+ export const CURRENCY_SCALES = {
7
+ AED: 2,
8
+ AMD: 2,
9
+ AUD: 2,
10
+ BHD: 3,
11
+ BYN: 2,
12
+ CAD: 2,
13
+ CHF: 2,
14
+ CLP: 0,
15
+ CNY: 2,
16
+ CZK: 2,
17
+ DKK: 2,
18
+ EUR: 2,
19
+ GBP: 2,
20
+ GEL: 2,
21
+ HUF: 2,
22
+ ILS: 2,
23
+ INR: 2,
24
+ ISK: 0,
25
+ JPY: 0,
26
+ KGS: 2,
27
+ KRW: 0,
28
+ KWD: 3,
29
+ KZT: 2,
30
+ NOK: 2,
31
+ PLN: 2,
32
+ RSD: 2,
33
+ RUB: 2,
34
+ SEK: 2,
35
+ THB: 2,
36
+ TRY: 2,
37
+ UAH: 2,
38
+ USD: 2,
39
+ UZS: 2,
40
+ VND: 0,
41
+ };
42
+ const refuse = (message, reason) => {
43
+ throw new CliError("validation_error", message, { reason });
44
+ };
45
+ const DECIMAL = /^(\d{1,15})(?:\.(\d+))?$/;
46
+ /** A non-negative decimal as an integer of `scale` decimal places; `undefined` when it is not one. */
47
+ export const parseDecimal = (text, scale) => {
48
+ const match = DECIMAL.exec(text.trim());
49
+ if (!match || (match[2] ?? "").length > scale)
50
+ return undefined;
51
+ return BigInt(`${match[1]}${(match[2] ?? "").padEnd(scale, "0")}`);
52
+ };
53
+ export const formatDecimal = (units, scale) => {
54
+ const digits = BigInt(units)
55
+ .toString()
56
+ .padStart(scale + 1, "0");
57
+ return scale === 0 ? digits : `${digits.slice(0, -scale)}.${digits.slice(-scale)}`;
58
+ };
59
+ /** `50000.00` as `50 000.00`: groups of three in the whole part, as a list prints an amount. */
60
+ export const groupDigits = (decimal) => {
61
+ const [whole = "0", fraction] = decimal.split(".");
62
+ const grouped = whole.replace(/\B(?=(\d{3})+(?!\d))/g, " ");
63
+ return fraction === undefined ? grouped : `${grouped}.${fraction}`;
64
+ };
65
+ export const currencyOf = (text) => {
66
+ const code = typeof text === "string" ? text.trim().toUpperCase() : "";
67
+ if (CURRENCY_SCALES[code] === undefined)
68
+ return refuse(`${typeof text === "string" && text.trim() ? text.trim() : "an empty currency"} is not a currency the store keeps; ` +
69
+ `use one of ${Object.keys(CURRENCY_SCALES).join(", ")}`, "money.currency");
70
+ return code;
71
+ };
72
+ export const scaleOf = (currency) => CURRENCY_SCALES[currencyOf(currency)];
73
+ /** Minor units of `currency` for a decimal string such as "50000.00"; refuses more decimals than the currency has. */
74
+ export const minorUnits = (amount, currency, what = "an amount") => {
75
+ const scale = scaleOf(currency);
76
+ const units = typeof amount === "string" ? parseDecimal(amount, scale) : undefined;
77
+ if (units === undefined || units > BigInt(Number.MAX_SAFE_INTEGER))
78
+ return refuse(`${what} is a decimal string with at most ${scale} decimal${scale === 1 ? "" : "s"} for ${currency}, ` +
79
+ `such as "${formatDecimal(5_000 * 10 ** scale, scale)}"`, "money.amount");
80
+ return Number(units);
81
+ };
82
+ export const moneyOf = (units, currency) => ({
83
+ amount: formatDecimal(units, scaleOf(currency)),
84
+ currency,
85
+ });
86
+ /** "50 000.00 RUB". */
87
+ export const moneyLabel = (units, currency) => `${groupDigits(formatDecimal(units, scaleOf(currency)))} ${currency}`;
88
+ const QUANTITY_SCALE = 3;
89
+ /** A quantity such as "1.5" (hours, days), kept as text: at most 3 decimals, more than 0. */
90
+ export const quantityOf = (text) => {
91
+ const thousandths = typeof text === "string" ? parseDecimal(text, QUANTITY_SCALE) : undefined;
92
+ if (thousandths === undefined || thousandths === 0n)
93
+ return refuse('a quantity is a decimal string above 0 with at most 3 decimals, such as "1.5"', "money.quantity");
94
+ const plain = formatDecimal(thousandths, QUANTITY_SCALE).replace(/\.?0+$/, "");
95
+ return { text: plain, thousandths };
96
+ };
97
+ /** Quantity times unit price in minor units, half rounded up. */
98
+ export const lineUnits = (thousandths, unitPrice) => Number((thousandths * BigInt(unitPrice) + 500n) / 1000n);
@@ -49,6 +49,8 @@ const WORDS = {
49
49
  memory: "Memory",
50
50
  fact: "Fact",
51
51
  bot: "Bot",
52
+ invoice: "Invoice",
53
+ payment: "Payment",
52
54
  email: "Email",
53
55
  email_thread: "Email thread",
54
56
  unknown: "Unknown",
@@ -33,7 +33,7 @@ export type Reference = {
33
33
  * Things named by their store id (a task also by its key or the task package's id). `entity` is the name
34
34
  * before organizations and projects: it still parses, so an old file's reference resolves as not found.
35
35
  */
36
- export declare const SIMPLE_REFERENCES: readonly ["note", "document", "person", "organization", "project", "task", "memory", "fact", "bot", "event", "entity"];
36
+ export declare const SIMPLE_REFERENCES: readonly ["note", "document", "person", "organization", "project", "task", "memory", "fact", "bot", "event", "invoice", "payment", "entity"];
37
37
  export type SimpleReference = (typeof SIMPLE_REFERENCES)[number];
38
38
  export type RefKindName = Exclude<Reference["type"], "entity">;
39
39
  export interface RefKindSpec<R extends Reference = Reference> {
@@ -16,6 +16,8 @@ export const SIMPLE_REFERENCES = [
16
16
  "fact",
17
17
  "bot",
18
18
  "event",
19
+ "invoice",
20
+ "payment",
19
21
  "entity",
20
22
  ];
21
23
  const malformed = (text, shape) => new CliError("validation_error", `"${singleLine(text)}" is not a reference — expected ${shape}`, {
@@ -81,14 +81,14 @@ import { automaticTags, tagChange } from "./tag-change.js";
81
81
  import { tagging } from "./tagging.js";
82
82
  import { task } from "./task.js";
83
83
  import { taskPair } from "./task-pair.js";
84
- import { taskCard, taskCategories, taskClosed, taskCreated, taskLinks, taskMerge, taskScan, taskSimilar, taskUnmerge } from "./task-results.js";
84
+ import { taskAnalysis, taskAnalysisMark, taskCard, taskCategories, taskClosed, taskCreated, taskLinks, taskMerge, taskScan, taskSimilar, taskUnmerge } from "./task-results.js";
85
85
  import { topic } from "./topic.js";
86
86
  /**
87
87
  * One schema per thing a command can answer with. A command returns an entity or one of its views — a
88
88
  * subset of its fields, never a renamed one. Commands move onto these one by one; until then, a schema
89
89
  * is the target, not a description of today's output.
90
90
  */
91
- export { account, accountChange, accountPrivacy, accountPrivacyChange, accountProfile, accountSession, adminReport, agenda, analysisConsent, analysisConsentRevocation, attachment, attachmentBytes, attachmentExtraction, attachmentTextChange, automaticTags, botAdmin, botMenuEntry, botProfile, botSeenChat, botTemplate, botWebhook, cachedChatMetadata, callRecord, chart, chat, chatAdminChange, chatArchive, chatEvent, chatFolderChange, chatFolderOrder, chatFolderRemoval, chatGroupChange, chatInspection, chatInvite, chatInviteChange, chatMembersChange, chatMembersFetch, chatMetadata, chatMetadataRefresh, chatModeration, chatMuting, chatPin, chatRead, chatRemoval, chatRequestChange, chatRules, chatSender, chatStats, chatTracking, chatUnread, contact, contactActivity, contactAlias, contactCheck, contactContext, contactImport, contactLookup, contactNote, contactNoteRemoval, contactPreparation, contactStateChange, contactSync, contactUpdate, conversation, conversationBatch, conversationBatchStatus, conversationBuildResult, conversationChange, conversationDetails, conversationEmbedding, conversationEmbeddingStatus, conversationHit, conversationPreparation, conversationReadiness, counterRefresh, counters, document, documentLink, endedAccountSessions, evidence, evidencePacket, fact, folder, hit, identity, imageEmbedding, inviteLink, job, joinRequest, linkedPerson, mediaArchive, mediaArchiveCheck, mediaArchiveMove, mediaArchiveTimer, meeting, meetingProjectCandidates, meetingSeriesInventory, member, memory, mention, mentionDecision, mentionDetails, mentionDomain, mentionRebuild, message, messageContext, messageCounts, messageDeletion, messageDownload, messageEvent, messageLink, messageLinks, messagePin, messageStar, messageSync, messageTranscript, messageWrite, model, modelKey, note, officialStats, organization, person, place, poll, pollChange, pollVote, project, ranking, reaction, reactionChange, recipient, recipientAdded, recipientChange, recipientOff, recipientRemoved, recordedRun, reference, relationship, reminder, removedModelKey, retention, runDetails, runHit, runLocation, savedSearch, scheduledJob, searchHistoryClear, sendAttempt, serveSummary, stickerInventory, storeBackup, storeChatStatus, storeCheck, storeClear, storeCopyRemoval, storeDecrypt, storedModelKey, storeExport, storeGapPlan, storeGapRepair, storeInfo, storeJobCancel, storeJobClear, storeJobDetails, storeJobRetry, storeMigration, storeReindex, storeRepair, storeReset, storeRestore, storeTable, tagChange, tagging, task, taskCard, taskCategories, taskClosed, taskCreated, taskLinks, taskMerge, taskPair, taskScan, taskSimilar, taskStats, taskUnmerge, topic, topicIcon, trackedChat, trackedChatHistory, watchedMessage, watchItem, };
91
+ export { account, accountChange, accountPrivacy, accountPrivacyChange, accountProfile, accountSession, adminReport, agenda, analysisConsent, analysisConsentRevocation, attachment, attachmentBytes, attachmentExtraction, attachmentTextChange, automaticTags, botAdmin, botMenuEntry, botProfile, botSeenChat, botTemplate, botWebhook, cachedChatMetadata, callRecord, chart, chat, chatAdminChange, chatArchive, chatEvent, chatFolderChange, chatFolderOrder, chatFolderRemoval, chatGroupChange, chatInspection, chatInvite, chatInviteChange, chatMembersChange, chatMembersFetch, chatMetadata, chatMetadataRefresh, chatModeration, chatMuting, chatPin, chatRead, chatRemoval, chatRequestChange, chatRules, chatSender, chatStats, chatTracking, chatUnread, contact, contactActivity, contactAlias, contactCheck, contactContext, contactImport, contactLookup, contactNote, contactNoteRemoval, contactPreparation, contactStateChange, contactSync, contactUpdate, conversation, conversationBatch, conversationBatchStatus, conversationBuildResult, conversationChange, conversationDetails, conversationEmbedding, conversationEmbeddingStatus, conversationHit, conversationPreparation, conversationReadiness, counterRefresh, counters, document, documentLink, endedAccountSessions, evidence, evidencePacket, fact, folder, hit, identity, imageEmbedding, inviteLink, job, joinRequest, linkedPerson, mediaArchive, mediaArchiveCheck, mediaArchiveMove, mediaArchiveTimer, meeting, meetingProjectCandidates, meetingSeriesInventory, member, memory, mention, mentionDecision, mentionDetails, mentionDomain, mentionRebuild, message, messageContext, messageCounts, messageDeletion, messageDownload, messageEvent, messageLink, messageLinks, messagePin, messageStar, messageSync, messageTranscript, messageWrite, model, modelKey, note, officialStats, organization, person, place, poll, pollChange, pollVote, project, ranking, reaction, reactionChange, recipient, recipientAdded, recipientChange, recipientOff, recipientRemoved, recordedRun, reference, relationship, reminder, removedModelKey, retention, runDetails, runHit, runLocation, savedSearch, scheduledJob, searchHistoryClear, sendAttempt, serveSummary, stickerInventory, storeBackup, storeChatStatus, storeCheck, storeClear, storeCopyRemoval, storeDecrypt, storedModelKey, storeExport, storeGapPlan, storeGapRepair, storeInfo, storeJobCancel, storeJobClear, storeJobDetails, storeJobRetry, storeMigration, storeReindex, storeRepair, storeReset, storeRestore, storeTable, tagChange, tagging, task, taskAnalysis, taskAnalysisMark, taskCard, taskCategories, taskClosed, taskCreated, taskLinks, taskMerge, taskPair, taskScan, taskSimilar, taskStats, taskUnmerge, topic, topicIcon, trackedChat, trackedChatHistory, watchedMessage, watchItem, };
92
92
  export declare const ENTITIES: {
93
93
  readonly meeting_ingestion: v.StrictObjectSchema<{
94
94
  readonly meetings: v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 0, undefined>]>;
@@ -5696,6 +5696,68 @@ export declare const ENTITIES: {
5696
5696
  readonly category: v.NullableSchema<v.StringSchema<undefined>, undefined>;
5697
5697
  }, undefined>, undefined>;
5698
5698
  }, undefined>;
5699
+ readonly task_analysis: v.StrictObjectSchema<{
5700
+ readonly chat: v.StringSchema<undefined>;
5701
+ readonly title: v.NullableSchema<v.StringSchema<undefined>, undefined>;
5702
+ readonly kind: v.StringSchema<undefined>;
5703
+ readonly newest_at: v.NullableSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time in UTC">, v.EndsWithAction<string, "Z", "an ISO 8601 time in UTC, ending in `Z`">]>, undefined>;
5704
+ readonly mark: v.NullableSchema<v.StrictObjectSchema<{
5705
+ readonly chat: v.StringSchema<undefined>;
5706
+ readonly from: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time in UTC">, v.EndsWithAction<string, "Z", "an ISO 8601 time in UTC, ending in `Z`">]>;
5707
+ readonly through: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time in UTC">, v.EndsWithAction<string, "Z", "an ISO 8601 time in UTC, ending in `Z`">]>;
5708
+ readonly through_id: v.StringSchema<undefined>;
5709
+ readonly by: v.StringSchema<undefined>;
5710
+ readonly checked_at: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time in UTC">, v.EndsWithAction<string, "Z", "an ISO 8601 time in UTC, ending in `Z`">]>;
5711
+ readonly checked_through: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time in UTC">, v.EndsWithAction<string, "Z", "an ISO 8601 time in UTC, ending in `Z`">]>;
5712
+ readonly at: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time in UTC">, v.EndsWithAction<string, "Z", "an ISO 8601 time in UTC, ending in `Z`">]>;
5713
+ }, undefined>, undefined>;
5714
+ readonly waiting: v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 0, undefined>]>;
5715
+ readonly late: v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 0, undefined>]>;
5716
+ readonly untrusted: v.OptionalSchema<v.ArraySchema<v.StringSchema<undefined>, undefined>, undefined>;
5717
+ }, undefined>;
5718
+ readonly task_analysis_mark: v.StrictObjectSchema<{
5719
+ readonly chat: v.StringSchema<undefined>;
5720
+ readonly from: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time in UTC">, v.EndsWithAction<string, "Z", "an ISO 8601 time in UTC, ending in `Z`">]>;
5721
+ readonly through: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time in UTC">, v.EndsWithAction<string, "Z", "an ISO 8601 time in UTC, ending in `Z`">]>;
5722
+ readonly through_id: v.StringSchema<undefined>;
5723
+ readonly by: v.StringSchema<undefined>;
5724
+ readonly checked_at: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time in UTC">, v.EndsWithAction<string, "Z", "an ISO 8601 time in UTC, ending in `Z`">]>;
5725
+ readonly checked_through: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time in UTC">, v.EndsWithAction<string, "Z", "an ISO 8601 time in UTC, ending in `Z`">]>;
5726
+ readonly at: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time in UTC">, v.EndsWithAction<string, "Z", "an ISO 8601 time in UTC, ending in `Z`">]>;
5727
+ readonly moved: v.BooleanSchema<undefined>;
5728
+ }, undefined>;
5729
+ readonly task_review: v.StrictObjectSchema<{
5730
+ readonly chat: v.StringSchema<undefined>;
5731
+ readonly from: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time in UTC">, v.EndsWithAction<string, "Z", "an ISO 8601 time in UTC, ending in `Z`">]>;
5732
+ readonly mark: v.NullableSchema<v.StrictObjectSchema<{
5733
+ readonly chat: v.StringSchema<undefined>;
5734
+ readonly from: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time in UTC">, v.EndsWithAction<string, "Z", "an ISO 8601 time in UTC, ending in `Z`">]>;
5735
+ readonly through: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time in UTC">, v.EndsWithAction<string, "Z", "an ISO 8601 time in UTC, ending in `Z`">]>;
5736
+ readonly through_id: v.StringSchema<undefined>;
5737
+ readonly by: v.StringSchema<undefined>;
5738
+ readonly checked_at: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time in UTC">, v.EndsWithAction<string, "Z", "an ISO 8601 time in UTC, ending in `Z`">]>;
5739
+ readonly checked_through: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time in UTC">, v.EndsWithAction<string, "Z", "an ISO 8601 time in UTC, ending in `Z`">]>;
5740
+ readonly at: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time in UTC">, v.EndsWithAction<string, "Z", "an ISO 8601 time in UTC, ending in `Z`">]>;
5741
+ }, undefined>, undefined>;
5742
+ readonly late: v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 0, undefined>]>;
5743
+ readonly has_more: v.BooleanSchema<undefined>;
5744
+ readonly through: v.NullableSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.RegexAction<string, "a reference such as `note:42`">]>, undefined>;
5745
+ readonly messages: v.ArraySchema<v.StrictObjectSchema<{
5746
+ readonly ref: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.RegexAction<string, "a reference such as `note:42`">]>;
5747
+ readonly at: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time in UTC">, v.EndsWithAction<string, "Z", "an ISO 8601 time in UTC, ending in `Z`">]>;
5748
+ readonly sender: v.NullableSchema<v.StringSchema<undefined>, undefined>;
5749
+ readonly outgoing: v.BooleanSchema<undefined>;
5750
+ readonly reply_to: v.NullableSchema<v.StringSchema<undefined>, undefined>;
5751
+ readonly text: v.StringSchema<undefined>;
5752
+ }, undefined>, undefined>;
5753
+ readonly open_tasks: v.ArraySchema<v.StrictObjectSchema<{
5754
+ readonly key: v.NullableSchema<v.StringSchema<undefined>, undefined>;
5755
+ readonly kind: v.StringSchema<undefined>;
5756
+ readonly title: v.NullableSchema<v.StringSchema<undefined>, undefined>;
5757
+ readonly source: v.NullableSchema<v.StringSchema<undefined>, undefined>;
5758
+ }, undefined>, undefined>;
5759
+ readonly untrusted: v.OptionalSchema<v.ArraySchema<v.StringSchema<undefined>, undefined>, undefined>;
5760
+ }, undefined>;
5699
5761
  readonly fact: v.StrictObjectSchema<{
5700
5762
  readonly ref: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.RegexAction<string, "a reference such as `note:42`">]>;
5701
5763
  readonly id: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>]>;
@@ -87,14 +87,14 @@ import { automaticTags, tagChange } from "./tag-change.js";
87
87
  import { tagging } from "./tagging.js";
88
88
  import { task } from "./task.js";
89
89
  import { taskPair } from "./task-pair.js";
90
- import { taskCard, taskCategories, taskClosed, taskCreated, taskLinks, taskMerge, taskScan, taskSimilar, taskUnmerge, } from "./task-results.js";
90
+ import { taskAnalysis, taskAnalysisMark, taskAnalysisMarkMoved, taskCard, taskCategories, taskClosed, taskCreated, taskLinks, taskMerge, taskReview, taskScan, taskSimilar, taskUnmerge, } from "./task-results.js";
91
91
  import { topic } from "./topic.js";
92
92
  /**
93
93
  * One schema per thing a command can answer with. A command returns an entity or one of its views — a
94
94
  * subset of its fields, never a renamed one. Commands move onto these one by one; until then, a schema
95
95
  * is the target, not a description of today's output.
96
96
  */
97
- export { account, accountChange, accountPrivacy, accountPrivacyChange, accountProfile, accountSession, adminReport, agenda, analysisConsent, analysisConsentRevocation, attachment, attachmentBytes, attachmentExtraction, attachmentTextChange, automaticTags, botAdmin, botMenuEntry, botProfile, botSeenChat, botTemplate, botWebhook, cachedChatMetadata, callRecord, chart, chat, chatAdminChange, chatArchive, chatEvent, chatFolderChange, chatFolderOrder, chatFolderRemoval, chatGroupChange, chatInspection, chatInvite, chatInviteChange, chatMembersChange, chatMembersFetch, chatMetadata, chatMetadataRefresh, chatModeration, chatMuting, chatPin, chatRead, chatRemoval, chatRequestChange, chatRules, chatSender, chatStats, chatTracking, chatUnread, contact, contactActivity, contactAlias, contactCheck, contactContext, contactImport, contactLookup, contactNote, contactNoteRemoval, contactPreparation, contactStateChange, contactSync, contactUpdate, conversation, conversationBatch, conversationBatchStatus, conversationBuildResult, conversationChange, conversationDetails, conversationEmbedding, conversationEmbeddingStatus, conversationHit, conversationPreparation, conversationReadiness, counterRefresh, counters, document, documentLink, endedAccountSessions, evidence, evidencePacket, fact, folder, hit, identity, imageEmbedding, inviteLink, job, joinRequest, linkedPerson, mediaArchive, mediaArchiveCheck, mediaArchiveMove, mediaArchiveTimer, meeting, meetingProjectCandidates, meetingSeriesInventory, member, memory, mention, mentionDecision, mentionDetails, mentionDomain, mentionRebuild, message, messageContext, messageCounts, messageDeletion, messageDownload, messageEvent, messageLink, messageLinks, messagePin, messageStar, messageSync, messageTranscript, messageWrite, model, modelKey, note, officialStats, organization, person, place, poll, pollChange, pollVote, project, ranking, reaction, reactionChange, recipient, recipientAdded, recipientChange, recipientOff, recipientRemoved, recordedRun, reference, relationship, reminder, removedModelKey, retention, runDetails, runHit, runLocation, savedSearch, scheduledJob, searchHistoryClear, sendAttempt, serveSummary, stickerInventory, storeBackup, storeChatStatus, storeCheck, storeClear, storeCopyRemoval, storeDecrypt, storedModelKey, storeExport, storeGapPlan, storeGapRepair, storeInfo, storeJobCancel, storeJobClear, storeJobDetails, storeJobRetry, storeMigration, storeReindex, storeRepair, storeReset, storeRestore, storeTable, tagChange, tagging, task, taskCard, taskCategories, taskClosed, taskCreated, taskLinks, taskMerge, taskPair, taskScan, taskSimilar, taskStats, taskUnmerge, topic, topicIcon, trackedChat, trackedChatHistory, watchedMessage, watchItem, };
97
+ export { account, accountChange, accountPrivacy, accountPrivacyChange, accountProfile, accountSession, adminReport, agenda, analysisConsent, analysisConsentRevocation, attachment, attachmentBytes, attachmentExtraction, attachmentTextChange, automaticTags, botAdmin, botMenuEntry, botProfile, botSeenChat, botTemplate, botWebhook, cachedChatMetadata, callRecord, chart, chat, chatAdminChange, chatArchive, chatEvent, chatFolderChange, chatFolderOrder, chatFolderRemoval, chatGroupChange, chatInspection, chatInvite, chatInviteChange, chatMembersChange, chatMembersFetch, chatMetadata, chatMetadataRefresh, chatModeration, chatMuting, chatPin, chatRead, chatRemoval, chatRequestChange, chatRules, chatSender, chatStats, chatTracking, chatUnread, contact, contactActivity, contactAlias, contactCheck, contactContext, contactImport, contactLookup, contactNote, contactNoteRemoval, contactPreparation, contactStateChange, contactSync, contactUpdate, conversation, conversationBatch, conversationBatchStatus, conversationBuildResult, conversationChange, conversationDetails, conversationEmbedding, conversationEmbeddingStatus, conversationHit, conversationPreparation, conversationReadiness, counterRefresh, counters, document, documentLink, endedAccountSessions, evidence, evidencePacket, fact, folder, hit, identity, imageEmbedding, inviteLink, job, joinRequest, linkedPerson, mediaArchive, mediaArchiveCheck, mediaArchiveMove, mediaArchiveTimer, meeting, meetingProjectCandidates, meetingSeriesInventory, member, memory, mention, mentionDecision, mentionDetails, mentionDomain, mentionRebuild, message, messageContext, messageCounts, messageDeletion, messageDownload, messageEvent, messageLink, messageLinks, messagePin, messageStar, messageSync, messageTranscript, messageWrite, model, modelKey, note, officialStats, organization, person, place, poll, pollChange, pollVote, project, ranking, reaction, reactionChange, recipient, recipientAdded, recipientChange, recipientOff, recipientRemoved, recordedRun, reference, relationship, reminder, removedModelKey, retention, runDetails, runHit, runLocation, savedSearch, scheduledJob, searchHistoryClear, sendAttempt, serveSummary, stickerInventory, storeBackup, storeChatStatus, storeCheck, storeClear, storeCopyRemoval, storeDecrypt, storedModelKey, storeExport, storeGapPlan, storeGapRepair, storeInfo, storeJobCancel, storeJobClear, storeJobDetails, storeJobRetry, storeMigration, storeReindex, storeRepair, storeReset, storeRestore, storeTable, tagChange, tagging, task, taskAnalysis, taskAnalysisMark, taskCard, taskCategories, taskClosed, taskCreated, taskLinks, taskMerge, taskPair, taskScan, taskSimilar, taskStats, taskUnmerge, topic, topicIcon, trackedChat, trackedChatHistory, watchedMessage, watchItem, };
98
98
  export const ENTITIES = {
99
99
  sync_progress: syncProgress,
100
100
  ...MEETING_RESULT_ENTITIES,
@@ -233,6 +233,9 @@ export const ENTITIES = {
233
233
  task_unmerge: taskUnmerge,
234
234
  task_categories: taskCategories,
235
235
  task_scan: taskScan,
236
+ task_analysis: taskAnalysis,
237
+ task_analysis_mark: taskAnalysisMarkMoved,
238
+ task_review: taskReview,
236
239
  fact,
237
240
  memory,
238
241
  meeting,