@wirecat/cli-core 0.562.0 → 0.564.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.
- package/CHANGELOG.md +139 -0
- package/dist/calendar/mcp/index.d.ts +12 -12
- package/dist/cli/config-command.js +18 -1
- package/dist/cli/envelope.js +13 -1
- package/dist/cli/execution.js +1 -0
- package/dist/cli/messenger/archive-commands.js +17 -0
- package/dist/cli/messenger/catch-up-answers.d.ts +5 -0
- package/dist/cli/messenger/catch-up-answers.js +3 -0
- package/dist/cli/messenger/reply-stats-command.d.ts +4 -0
- package/dist/cli/messenger/reply-stats-command.js +57 -0
- package/dist/cli/messenger/search-answers.d.ts +1 -0
- package/dist/cli/messenger/search-answers.js +1 -1
- package/dist/cli/messenger/search-command.js +8 -0
- package/dist/cli/messenger/stats-answers.d.ts +6 -3
- package/dist/cli/messenger/stats-answers.js +39 -9
- package/dist/cli/messenger/stats-command.js +5 -0
- package/dist/cli/messenger/tasks-command.js +35 -14
- package/dist/cli/output-budget.d.ts +26 -0
- package/dist/cli/output-budget.js +73 -0
- package/dist/cli/program.js +14 -1
- package/dist/cli/settings.d.ts +5 -0
- package/dist/cli/settings.js +88 -5
- package/dist/cli/shared-command-exports.d.ts +8 -0
- package/dist/conversations/mail-text.d.ts +6 -0
- package/dist/conversations/mail-text.js +73 -0
- package/dist/domain/admin-statistics.d.ts +5 -0
- package/dist/domain/admin-statistics.js +4 -3
- package/dist/domain/calendar.d.ts +2 -0
- package/dist/domain/calendar.js +6 -0
- package/dist/entities/chat-stats.d.ts +16 -2
- package/dist/entities/chat-stats.js +18 -3
- package/dist/entities/index.d.ts +80 -802
- package/dist/entities/index.js +26 -16
- package/dist/entities/mail-counts.d.ts +15 -0
- package/dist/entities/mail-counts.js +16 -0
- package/dist/entities/meeting.d.ts +1 -1
- package/dist/entities/meeting.js +1 -1
- package/dist/entities/reply-stats.d.ts +33 -0
- package/dist/entities/reply-stats.js +19 -0
- package/dist/entities/store-records.d.ts +8 -0
- package/dist/entities/store-records.js +8 -0
- package/dist/errors/reasons.d.ts +1 -1
- package/dist/errors/reasons.js +7 -3
- package/dist/mail/attachments.d.ts +15 -2
- package/dist/mail/attachments.js +19 -3
- package/dist/mail/cli/index.d.ts +22 -1
- package/dist/mail/cli/index.js +28 -4
- package/dist/mail/cli/review.d.ts +5 -2
- package/dist/mail/cli/review.js +58 -43
- package/dist/mail/index.d.ts +4 -0
- package/dist/mail/index.js +4 -0
- package/dist/mail/partial.d.ts +3 -1
- package/dist/mail/partial.js +2 -2
- package/dist/mail/retry.d.ts +3 -1
- package/dist/mail/retry.js +3 -3
- package/dist/mail/stats.d.ts +50 -0
- package/dist/mail/stats.js +60 -0
- package/dist/mail/sync-types.d.ts +3 -0
- package/dist/mail/sync.js +5 -3
- package/dist/mail/whole.d.ts +28 -0
- package/dist/mail/whole.js +70 -0
- package/dist/meetings/index.d.ts +2 -2
- package/dist/meetings/index.js +2 -2
- package/dist/meetings/mcp/index.d.ts +15 -15
- package/dist/meetings/read-answers.d.ts +22 -1
- package/dist/meetings/read-answers.js +38 -0
- package/dist/meetings/stats.d.ts +44 -0
- package/dist/meetings/stats.js +77 -7
- package/dist/search/lucene/registry.js +2 -1
- package/dist/search/question-plan.d.ts +16 -0
- package/dist/search/question-plan.js +34 -0
- package/dist/services/events-search.d.ts +5 -1
- package/dist/services/events-search.js +10 -4
- package/dist/services/index.d.ts +3 -1
- package/dist/services/index.js +3 -1
- package/dist/services/meeting-stats.d.ts +12 -1
- package/dist/services/meeting-stats.js +12 -0
- package/dist/services/messages-discovery.d.ts +1 -5
- package/dist/services/messages-discovery.js +5 -18
- package/dist/services/messages-meaning.js +25 -3
- package/dist/services/messages.js +4 -3
- package/dist/services/notes-search.d.ts +5 -1
- package/dist/services/notes-search.js +16 -5
- package/dist/services/proposal-tasks.js +3 -12
- package/dist/services/proposals/ids.d.ts +2 -2
- package/dist/services/proposals/ids.js +5 -3
- package/dist/services/proposals/kinds/action.js +3 -2
- package/dist/services/proposals/kinds/findings.d.ts +1 -1
- package/dist/services/proposals/kinds/findings.js +1 -1
- package/dist/services/proposals/kinds/meeting-findings.d.ts +7 -0
- package/dist/services/proposals/kinds/meeting-findings.js +73 -0
- package/dist/services/proposals/kinds/task-close.d.ts +7 -0
- package/dist/services/proposals/kinds/task-close.js +76 -0
- package/dist/services/proposals/registry.js +12 -4
- package/dist/services/proposals/types.d.ts +2 -0
- package/dist/services/reply-stats.d.ts +48 -0
- package/dist/services/reply-stats.js +137 -0
- package/dist/services/search-all.d.ts +5 -0
- package/dist/services/search-all.js +47 -14
- package/dist/services/task-stats.d.ts +41 -0
- package/dist/services/task-stats.js +126 -0
- package/dist/services/tasks.d.ts +17 -4
- package/dist/services/tasks.js +31 -14
- package/dist/store/chats.d.ts +3 -1
- package/dist/store/chats.js +6 -0
- package/dist/store/decisions.d.ts +16 -11
- package/dist/store/decisions.js +11 -2
- package/dist/store/exports.d.ts +1 -1
- package/dist/store/exports.js +1 -1
- package/dist/store/index.d.ts +5 -4
- package/dist/store/index.js +3 -3
- package/dist/store/queries.d.ts +4 -0
- package/dist/store/queries.js +3 -0
- package/dist/store/sqlite/completeness.d.ts +17 -0
- package/dist/store/sqlite/completeness.js +49 -13
- package/dist/store/sqlite/email-locations.d.ts +4 -0
- package/dist/store/sqlite/email-locations.js +26 -11
- package/dist/store/sqlite/lucene-fields.d.ts +2 -0
- package/dist/store/sqlite/lucene-fields.js +5 -1
- package/dist/store/sqlite/lucene-groups.d.ts +15 -0
- package/dist/store/sqlite/lucene-groups.js +21 -0
- package/dist/store/sqlite/lucene.d.ts +2 -9
- package/dist/store/sqlite/lucene.js +1 -12
- package/dist/store/sqlite/mail-findings.js +1 -1
- package/dist/store/sqlite/meeting-findings.js +1 -1
- package/dist/store/sqlite/meeting-stats.d.ts +2 -0
- package/dist/store/sqlite/meeting-stats.js +27 -1
- package/dist/store/sqlite/proposed-actions.d.ts +2 -0
- package/dist/store/sqlite/proposed-actions.js +24 -17
- package/dist/store/sqlite/reply-times.d.ts +57 -0
- package/dist/store/sqlite/reply-times.js +113 -0
- package/dist/store/sqlite/retention.js +2 -7
- package/dist/store/sqlite/task-board.js +2 -0
- package/dist/store/sqlite/task-stats.d.ts +32 -0
- package/dist/store/sqlite/task-stats.js +45 -0
- package/dist/store/sqlite/tasks.d.ts +2 -1
- package/dist/store/sqlite/tasks.js +2 -0
- package/dist/store/sqlite/work-tasks.d.ts +12 -2
- package/dist/store/sqlite/work-tasks.js +35 -26
- package/dist/store/store.d.ts +1 -0
- package/package.json +1 -1
- package/parity.json +37 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,145 @@ Notable changes to `@wirecat/cli-core` (`@wirecat/cli-messaging` up to 0.261.0,
|
|
|
5
5
|
minor version may break callers, and says how under "Changed — may break callers". `pnpm docs:check` checks the
|
|
6
6
|
shape of this file.
|
|
7
7
|
|
|
8
|
+
## Unreleased
|
|
9
|
+
|
|
10
|
+
## 0.564.0 — 05.11.2026
|
|
11
|
+
|
|
12
|
+
### Changed — may break callers
|
|
13
|
+
|
|
14
|
+
- **`search all` ranks its sources as one list** (MEMO-37). Each source's hit at one rank used to get the same score,
|
|
15
|
+
so the sources took turns in the order they were read (messages, mail, notes, events). Now hits at the same rank
|
|
16
|
+
are ordered by cosine, since one model scores every source; a hit meaning did not find comes after those it did.
|
|
17
|
+
Each source's own order is kept. Without the model nothing changes. `search notes` and `search events` hits found
|
|
18
|
+
by meaning carry `meaning_score`, the cosine.
|
|
19
|
+
- **tg, max and wa `search all` change with the bump, with no code change in them.** Mail is searched by meaning when
|
|
20
|
+
the store holds mail, a question's message found both by words and by meaning gets one vote, and once vectors
|
|
21
|
+
exist the hits at one rank are ordered by meaning score.
|
|
22
|
+
- **`search all` searches mail by meaning too** (MEMO-38). Mail was only ever searched by words there, though its
|
|
23
|
+
threads had vectors. The meaning lane now reads a mail account's thread vectors through the mail store, and
|
|
24
|
+
`search all` fuses them with the word hits as it does for messages; the answer says how in `mail`. For a question,
|
|
25
|
+
a mail or message found by words gets no second vote from meaning, as in notes.
|
|
26
|
+
- **`search all` finds records for a question typed as a sentence.** When the text is a question in natural language
|
|
27
|
+
and not `exact`, messages and mail go through discovery (as `search messages --discover`), and notes and calendar
|
|
28
|
+
events search any of the question's content words, ranked by the store. Before, every word had to be in one record,
|
|
29
|
+
so a question found nothing (MEMO-36). tg, max and wa still ask the messenger's server with the question as typed.
|
|
30
|
+
For a question, a note found by both words and meaning gets one vote, not two, so notes found by words alone are not
|
|
31
|
+
buried. Plain words, query syntax and `exact` are searched strictly, as before. `searchNotes` and `searchEvents`
|
|
32
|
+
take `discover`.
|
|
33
|
+
|
|
34
|
+
### Added
|
|
35
|
+
|
|
36
|
+
- **The proposal registry reviews meeting findings and task close suggestions.** `proposalRegistry` registers
|
|
37
|
+
`meeting_findings` (a meeting's staged batch, decided part by part as in `meetings actions confirm`) and
|
|
38
|
+
`task_close` (an agent's suggested close, id `close:<task key>`; confirming closes the task as suggested, rejecting
|
|
39
|
+
clears the suggestion). Both are owner only: `isOwnerOnlyKind` now names `task_close` too, so `mayDecide` refuses an
|
|
40
|
+
agent by the row's kind. `parseProposalIds` takes a task key after a prefix (`close:Q-15`). Moved from cli-memo,
|
|
41
|
+
which registered both itself; a host that registers a kind of the same name now gets `configuration_error`.
|
|
42
|
+
|
|
43
|
+
- **A mail CLI's `messages show` can read an email again when a sync's limit left its attachment unread.**
|
|
44
|
+
`mailReadCommands` takes `whole(command, store, mailbox, emailId)`; with it the command is a fetch, reads such an
|
|
45
|
+
email from the server before it answers (`readEmailWhole`), and shows the new text. When that read fails it shows
|
|
46
|
+
the stored email with `meta.complete: false` and an issue `mail.attachments-unread`. Without `whole` nothing changes.
|
|
47
|
+
`readEmailWhole`'s body and text limits, reader and clock now default as sync's do.
|
|
48
|
+
- **`has:transcript` in the messages query language** finds a voice message that has a transcription, so
|
|
49
|
+
`stats messages show --by day -- has:transcript date>=30d` counts transcribed voice messages per day. In mail it
|
|
50
|
+
finds nothing.
|
|
51
|
+
- **`store chats status`** counts the account's searchable chats of every kind, channels included, by how much of each
|
|
52
|
+
the archive holds: `{ chats, fetched, partial, never, oldest_message_at }`. `fetched` is held back to the first
|
|
53
|
+
message, up to date and without gaps; `never` has no fetch recorded and no message held; the rest is `partial`,
|
|
54
|
+
including WhatsApp chats whose history was pushed. One statement over the store, no list of chats. tg, max and wa
|
|
55
|
+
get it with the bump.
|
|
56
|
+
- **Meeting counts per day, week or series.** `readMeetingCounts` (services) and `store.meetings.meetingCounts`
|
|
57
|
+
answer meetings, minutes, mean minutes and meetings with a transcript, in total and per row, over the same
|
|
58
|
+
selection as `readMeetingStats`, reading `meetings` alone through `meetings_by_time`. `meetingCountsItem` and the
|
|
59
|
+
`meeting_counts` entity are the answer, for zoom-cli's `stats meetings history`. A meeting with no end counts in
|
|
60
|
+
`meetings`, not in `minutes`. `MeetingStatsStore` gains `meetingCounts`; only cli-core's own store implements it.
|
|
61
|
+
- **`stats tasks show` counts by chat, meeting or project, over a period.** `--by meeting` keys a row by the meeting a
|
|
62
|
+
task came from (`meeting:<account>/<meeting>`); `--by project` reads the owner's project tasks, every project
|
|
63
|
+
(`project:<id>`). A query after `--` takes the task query's fields and `created` for the period: `created` counts
|
|
64
|
+
the tasks opened in it, `closed` those closed in it, `open` is always open now (`-- created>=30d`). The item gains
|
|
65
|
+
`created`, `closed`, `median_close_ms` and `mean_open_age_ms`; each row gains `key`, `name` (chat title, meeting
|
|
66
|
+
title, project name), `created`, `closed` and `mean_open_age_ms`. Rows of `--by chat` keep `chat`; the others have
|
|
67
|
+
none. `--timezone` places calendar days such as `created>=today`.
|
|
68
|
+
- **`created:` in the project task query** (`PROJECT_TASK_FIELDS`), beside `closed:`: `created>=30d`.
|
|
69
|
+
- **`mailStats` from `./mail`**: stored mail received and sent per calendar day, week (by its Monday) or sender, for
|
|
70
|
+
the `search mail` query, counts only and no search recorded; `mailStatsItem` turns it into the new `mail_counts`
|
|
71
|
+
entity, `{ by, received, sent, rows: [{ key, name, received, sent }] }`. By sender it counts received mail only.
|
|
72
|
+
- **`mailOwnText(body)` (`@wirecat/cli-core/mail`): what an email says itself, without quoted earlier mail and the
|
|
73
|
+
signature.** It drops `>` lines, cuts at a reply header ("On … wrote:", "Le … a écrit :", "Am … schrieb …:",
|
|
74
|
+
"… написал(а):", Gmail's Russian "<address>:") and at an Outlook From/Sent block in English, German, French, Spanish
|
|
75
|
+
and Russian, and drops the `-- ` signature, sign-offs and mobile footers. A forwarded message stays whole; an email
|
|
76
|
+
that is only a quote keeps its body.
|
|
77
|
+
|
|
78
|
+
### Security
|
|
79
|
+
|
|
80
|
+
- **`review --holder` gives each email's own text** (`mailOwnText`), so an agent's model does not read earlier mail
|
|
81
|
+
or signatures. The fingerprint a finding cites is still taken over the stored body; other reads show the whole text.
|
|
82
|
+
- **Review and inbox items say which fields others wrote** (WC-SECR-21): `summaryOf` items, and so every catch-up
|
|
83
|
+
answer and each mail `review` item, carry `untrusted` (`SUMMARY_UNTRUSTED`: chat title, sender name, text,
|
|
84
|
+
transcript, attachment names); a mail review item adds the email's subject and the names in its headers, as search
|
|
85
|
+
hits do. The `message.summary` entity takes the field.
|
|
86
|
+
|
|
87
|
+
## 0.563.0 — 03.11.2026
|
|
88
|
+
|
|
89
|
+
### Changed — may break callers
|
|
90
|
+
|
|
91
|
+
- **Mail sync reads attachments up to 10 MB a file by default, and can skip them.** Until now every attachment was
|
|
92
|
+
read, whatever its size; at the next bump a file over 10 MB is no longer read into the index unless the caller
|
|
93
|
+
passes a policy. `MailSyncOptions.attachments` takes a `MailAttachmentPolicy` (`read`, `maxBytes`); left out it is
|
|
94
|
+
`DEFAULT_ATTACHMENT_POLICY`. A file the policy leaves is stored with its name, type and size but no text, with
|
|
95
|
+
`extractionError` `not-read` or `too-large` (`POLICY_SKIPS`), and the run's `attachments` log says the same.
|
|
96
|
+
Partial completion and `retryAttachments` follow it too.
|
|
97
|
+
- **Moving a task to another project moves its subtasks with it.** `tasks.edit(id, { project })` on a task with
|
|
98
|
+
subtasks no longer refuses with `task.has-subtasks`; that reason is gone. Every subtask, all the way down, takes the
|
|
99
|
+
next key in the new project and keeps its parent, and its old key still finds it. The answer names them as
|
|
100
|
+
`movedSubtasks: [{ from, to }]`, old key and new; the field is left out when nothing moved with the task. A subtask
|
|
101
|
+
moved on its own still needs `parent: null` in the same edit (`task.is-subtask`).
|
|
102
|
+
|
|
103
|
+
- **Owner-only proposals refuse an agent on every decide path.** `mayDecide` and `assertMayDecide` now read
|
|
104
|
+
the row's stored `kind`: a `mail_findings` or `meeting_findings` row is the owner's alone, whatever
|
|
105
|
+
`agent_decisions` says. The registry's `get` and `list` rows carry `ownerOnly` from their kind, and the generic
|
|
106
|
+
action kind marks a stored findings row too, so a host checking `assertMayDecide(await registry.get(id), …)` is
|
|
107
|
+
refused. `approveAsTask` and `proposedActions.approve` / `reject` refuse a mail findings batch as they refuse
|
|
108
|
+
meeting and evidence findings (`mail-findings.dedicated-review`), and the generic action kind no longer lists any
|
|
109
|
+
findings batch. Meeting findings were open to another agent with a reason before; now only the owner reviews them.
|
|
110
|
+
|
|
111
|
+
### Added
|
|
112
|
+
|
|
113
|
+
- **An answer over the output cap says what to run instead (WC-OUT-22).** The `output.too-large` failure now names up
|
|
114
|
+
to two reads, both safe to run unasked: the same command line with `--compact`, when the command declares a row and
|
|
115
|
+
was not compact already, and the same line with a `--limit` scaled down to fit. The lines are rebuilt from the
|
|
116
|
+
words the caller typed, never from the answer. The failure also carries `needed_bytes`.
|
|
117
|
+
- **A JSON answer over 256 KiB adds one step to the compact form.** The answer is still printed whole. Nothing is
|
|
118
|
+
added when the answer already names two steps, over MCP, or for a command with no declared row.
|
|
119
|
+
- **`search messages --chat` and `search all --chat` say how to search one chat:** `chat:<chat>` in the query.
|
|
120
|
+
|
|
121
|
+
- **`readEmailWhole` reads one stored email again from its mail server, every attachment of it with no limit.** It
|
|
122
|
+
saves the new text on the email as a sync does, keeping its mailboxes, flags and rule, and answers each attachment's
|
|
123
|
+
bytes for the caller to save. Gmail's email is found by id, another server's at its stored place.
|
|
124
|
+
`store.mail.emailPlace(accountId, externalId)` gives an email's thread and stored places.
|
|
125
|
+
- **`stats messages responses`**: how fast replies come in one-to-one chats, the owner's (`--who me`) or the other
|
|
126
|
+
side's (`--who others`): count, median, p90, mean and four time buckets, in total or `--by day` in `--timezone`.
|
|
127
|
+
Several messages in a row followed by one answer are one reply, timed from the first. Reads by index, so all time
|
|
128
|
+
works on a large store; the query after `--` takes `date:`, `chat:` and `kind:` only.
|
|
129
|
+
- **`stats messages waiting`**: how many chats wait on the owner — a one-to-one chat whose newest message is a
|
|
130
|
+
question, or a group whose newest message mentions or replies to the owner — with the messages since the owner
|
|
131
|
+
last wrote, the oldest of them, and the split by kind. Muted or archived one-to-one chats are left out, as in
|
|
132
|
+
`inbox`.
|
|
133
|
+
- **tg, max, wa, mail, gcal and drive's config file holds every shared setting with its default.** A first run now
|
|
134
|
+
writes all of them into `defaults`, not five; `config set` and `config unset` add the missing ones (but not the one
|
|
135
|
+
just unset); and the new `<cli> config migrate` fills an existing file. Your values, their order and unknown keys
|
|
136
|
+
stay; a file without `defaults` gets that section, and no other section is created. `config show` gives each of
|
|
137
|
+
these settings its `default` and `description`, and no longer creates the file when there is none. `settingsFor`
|
|
138
|
+
returns `declaredSettings` and `migrate(path)`; `extension.settings` declares a CLI's own (cli-base WC-CMD-30).
|
|
139
|
+
Settings with no single default (`timeout_ms`, `color`, `requests_per_minute`, the embedding model) and objects
|
|
140
|
+
(`permissions`, `models`) are left out.
|
|
141
|
+
- **`MailReads.mount`: the steps a mail review hands on name where the host mounted it.** A host that mounts `review`
|
|
142
|
+
and `messages acknowledge` elsewhere passes their paths and the option naming the mailbox — memo passes
|
|
143
|
+
`review: "mail review"`, `conversation: null` (it mounts no thread read) and `mailbox: { option: "source", value }`
|
|
144
|
+
— and `next` names those paths and `--source email:<account>`. `mailReviewSteps(mount)` gives the definitions for
|
|
145
|
+
a host's step checks; a mail CLI leaves it out, and its step lines carry the profile as before.
|
|
146
|
+
|
|
8
147
|
## 0.562.0 — 03.11.2026
|
|
9
148
|
|
|
10
149
|
### Added
|
|
@@ -10,13 +10,13 @@ export declare const calendarTools: ({
|
|
|
10
10
|
inputSchema: {
|
|
11
11
|
type: string;
|
|
12
12
|
properties: {
|
|
13
|
+
limit?: undefined;
|
|
13
14
|
account_id: {
|
|
14
15
|
type: string;
|
|
15
16
|
minimum: number;
|
|
16
17
|
};
|
|
17
18
|
query?: undefined;
|
|
18
19
|
timezone?: undefined;
|
|
19
|
-
limit?: undefined;
|
|
20
20
|
page?: undefined;
|
|
21
21
|
event?: undefined;
|
|
22
22
|
} | {
|
|
@@ -45,9 +45,9 @@ export declare const calendarTools: ({
|
|
|
45
45
|
};
|
|
46
46
|
event?: undefined;
|
|
47
47
|
} | {
|
|
48
|
+
limit?: undefined;
|
|
48
49
|
query?: undefined;
|
|
49
50
|
timezone?: undefined;
|
|
50
|
-
limit?: undefined;
|
|
51
51
|
page?: undefined;
|
|
52
52
|
event: {
|
|
53
53
|
type: string;
|
|
@@ -58,9 +58,9 @@ export declare const calendarTools: ({
|
|
|
58
58
|
minimum: number;
|
|
59
59
|
};
|
|
60
60
|
} | {
|
|
61
|
+
limit?: undefined;
|
|
61
62
|
query?: undefined;
|
|
62
63
|
timezone?: undefined;
|
|
63
|
-
limit?: undefined;
|
|
64
64
|
page?: undefined;
|
|
65
65
|
event?: undefined;
|
|
66
66
|
account_id?: undefined;
|
|
@@ -80,13 +80,13 @@ export declare const calendarTools: ({
|
|
|
80
80
|
inputSchema: {
|
|
81
81
|
type: string;
|
|
82
82
|
properties: {
|
|
83
|
+
limit?: undefined;
|
|
83
84
|
account_id: {
|
|
84
85
|
type: string;
|
|
85
86
|
minimum: number;
|
|
86
87
|
};
|
|
87
88
|
query?: undefined;
|
|
88
89
|
timezone?: undefined;
|
|
89
|
-
limit?: undefined;
|
|
90
90
|
page?: undefined;
|
|
91
91
|
event?: undefined;
|
|
92
92
|
} | {
|
|
@@ -115,9 +115,9 @@ export declare const calendarTools: ({
|
|
|
115
115
|
};
|
|
116
116
|
event?: undefined;
|
|
117
117
|
} | {
|
|
118
|
+
limit?: undefined;
|
|
118
119
|
query?: undefined;
|
|
119
120
|
timezone?: undefined;
|
|
120
|
-
limit?: undefined;
|
|
121
121
|
page?: undefined;
|
|
122
122
|
event: {
|
|
123
123
|
type: string;
|
|
@@ -128,9 +128,9 @@ export declare const calendarTools: ({
|
|
|
128
128
|
minimum: number;
|
|
129
129
|
};
|
|
130
130
|
} | {
|
|
131
|
+
limit?: undefined;
|
|
131
132
|
query?: undefined;
|
|
132
133
|
timezone?: undefined;
|
|
133
|
-
limit?: undefined;
|
|
134
134
|
page?: undefined;
|
|
135
135
|
event?: undefined;
|
|
136
136
|
account_id?: undefined;
|
|
@@ -150,13 +150,13 @@ export declare const calendarTools: ({
|
|
|
150
150
|
inputSchema: {
|
|
151
151
|
type: string;
|
|
152
152
|
properties: {
|
|
153
|
+
limit?: undefined;
|
|
153
154
|
account_id: {
|
|
154
155
|
type: string;
|
|
155
156
|
minimum: number;
|
|
156
157
|
};
|
|
157
158
|
query?: undefined;
|
|
158
159
|
timezone?: undefined;
|
|
159
|
-
limit?: undefined;
|
|
160
160
|
page?: undefined;
|
|
161
161
|
event?: undefined;
|
|
162
162
|
} | {
|
|
@@ -185,9 +185,9 @@ export declare const calendarTools: ({
|
|
|
185
185
|
};
|
|
186
186
|
event?: undefined;
|
|
187
187
|
} | {
|
|
188
|
+
limit?: undefined;
|
|
188
189
|
query?: undefined;
|
|
189
190
|
timezone?: undefined;
|
|
190
|
-
limit?: undefined;
|
|
191
191
|
page?: undefined;
|
|
192
192
|
event: {
|
|
193
193
|
type: string;
|
|
@@ -198,9 +198,9 @@ export declare const calendarTools: ({
|
|
|
198
198
|
minimum: number;
|
|
199
199
|
};
|
|
200
200
|
} | {
|
|
201
|
+
limit?: undefined;
|
|
201
202
|
query?: undefined;
|
|
202
203
|
timezone?: undefined;
|
|
203
|
-
limit?: undefined;
|
|
204
204
|
page?: undefined;
|
|
205
205
|
event?: undefined;
|
|
206
206
|
account_id?: undefined;
|
|
@@ -220,13 +220,13 @@ export declare const calendarTools: ({
|
|
|
220
220
|
inputSchema: {
|
|
221
221
|
type: string;
|
|
222
222
|
properties: {
|
|
223
|
+
limit?: undefined;
|
|
223
224
|
account_id: {
|
|
224
225
|
type: string;
|
|
225
226
|
minimum: number;
|
|
226
227
|
};
|
|
227
228
|
query?: undefined;
|
|
228
229
|
timezone?: undefined;
|
|
229
|
-
limit?: undefined;
|
|
230
230
|
page?: undefined;
|
|
231
231
|
event?: undefined;
|
|
232
232
|
} | {
|
|
@@ -255,9 +255,9 @@ export declare const calendarTools: ({
|
|
|
255
255
|
};
|
|
256
256
|
event?: undefined;
|
|
257
257
|
} | {
|
|
258
|
+
limit?: undefined;
|
|
258
259
|
query?: undefined;
|
|
259
260
|
timezone?: undefined;
|
|
260
|
-
limit?: undefined;
|
|
261
261
|
page?: undefined;
|
|
262
262
|
event: {
|
|
263
263
|
type: string;
|
|
@@ -268,9 +268,9 @@ export declare const calendarTools: ({
|
|
|
268
268
|
minimum: number;
|
|
269
269
|
};
|
|
270
270
|
} | {
|
|
271
|
+
limit?: undefined;
|
|
271
272
|
query?: undefined;
|
|
272
273
|
timezone?: undefined;
|
|
273
|
-
limit?: undefined;
|
|
274
274
|
page?: undefined;
|
|
275
275
|
event?: undefined;
|
|
276
276
|
account_id?: undefined;
|
|
@@ -30,6 +30,7 @@ export const configCommand = (app, config, { permissionKey = config.permissions,
|
|
|
30
30
|
const bot = this.opts().bot === true;
|
|
31
31
|
const context = baseContext(this, (flags, options) => config.resolveSettings(flags, {
|
|
32
32
|
...options,
|
|
33
|
+
readOnly: true,
|
|
33
34
|
needsProfile: false,
|
|
34
35
|
withIssues: true,
|
|
35
36
|
...(bot ? { kind: "bot" } : {}),
|
|
@@ -48,7 +49,13 @@ export const configCommand = (app, config, { permissionKey = config.permissions,
|
|
|
48
49
|
paths_overridden: overridden,
|
|
49
50
|
settings: [...config.allSettings, "command_timeout_ms"]
|
|
50
51
|
.filter((setting) => bot || setting !== "read_other_bots")
|
|
51
|
-
.map((setting) =>
|
|
52
|
+
.map((setting) => {
|
|
53
|
+
const declared = config.declaredSettings.find(({ key }) => key === `defaults.${setting}`);
|
|
54
|
+
return {
|
|
55
|
+
...sourced(settings, setting),
|
|
56
|
+
...(declared ? { default: declared.default, description: declared.description } : {}),
|
|
57
|
+
};
|
|
58
|
+
}),
|
|
52
59
|
store_settings: await storeSettings(env),
|
|
53
60
|
}));
|
|
54
61
|
for (const issue of [
|
|
@@ -144,9 +151,19 @@ export const configCommand = (app, config, { permissionKey = config.permissions,
|
|
|
144
151
|
}));
|
|
145
152
|
});
|
|
146
153
|
}
|
|
154
|
+
command.addCommand(migrateCommand(app, config));
|
|
147
155
|
command.addCommand(repairCommand(app, config));
|
|
148
156
|
return command;
|
|
149
157
|
};
|
|
158
|
+
const migrateCommand = (app, config) => profileFree(grantsAuthority(annotate(new Command("migrate"), { effects: LOCAL_WRITE, examples: [`${app.command} config migrate`] })))
|
|
159
|
+
.description("write each setting the file lacks at its default, keeping yours")
|
|
160
|
+
.action(function () {
|
|
161
|
+
const context = baseContext(this, (flags, options) => config.resolveSettings(flags, { ...options, needsProfile: false, withIssues: true }));
|
|
162
|
+
const file = context.settings.configPath;
|
|
163
|
+
const added = config.migrate(file);
|
|
164
|
+
renderAnswer(this, context, itemOf({ config_file: file, added }));
|
|
165
|
+
context.renderer.note(added.length > 0 ? `added ${added.join(", ")} to ${file}` : `${file} already has every setting`);
|
|
166
|
+
});
|
|
150
167
|
/**
|
|
151
168
|
* Mends JSON syntax with one reading and keeps every value (NEED-2178): no network, no AI, since the file may hold
|
|
152
169
|
* keys. Anything else is refused with nothing changed.
|
package/dist/cli/envelope.js
CHANGED
|
@@ -5,6 +5,7 @@ import * as v from "valibot";
|
|
|
5
5
|
import { currentRun } from "../runs/scope.js";
|
|
6
6
|
import { compactText, entityRows, rowShapeOf, rowsOfEntity, TEXT_CHARS } from "./compact.js";
|
|
7
7
|
import { environmentOf, setExitCode } from "./context.js";
|
|
8
|
+
import { largeAnswerSteps, SOFT_OUTPUT_BYTES } from "./output-budget.js";
|
|
8
9
|
import { withoutProviderRefs } from "./provider-refs.js";
|
|
9
10
|
import { nextStep, rootOf, runnable, stepLine, withLines, withSafety } from "./steps.js";
|
|
10
11
|
/** Every answer: a list or one thing, with items of `item` — any value where the command declares no entity. */
|
|
@@ -131,6 +132,16 @@ export const sealed = (value) => {
|
|
|
131
132
|
};
|
|
132
133
|
/** The steps a compact answer prints, each rerunning in the compact form the caller chose. */
|
|
133
134
|
const compactSteps = (root, steps) => steps.map((step) => step.kind === "command" ? { ...step, line: `${step.line ?? stepLine(root, step)} ${COMPACT_FLAG}` } : step);
|
|
135
|
+
/** A JSON answer past the soft budget, printed whole, with one more step: the same read in the compact form. */
|
|
136
|
+
const withLargeAnswerStep = (command, body) => {
|
|
137
|
+
if ((body.next?.length ?? 0) >= MAX_NEXT_STEPS)
|
|
138
|
+
return body;
|
|
139
|
+
const added = largeAnswerSteps(command);
|
|
140
|
+
if (added.length === 0 || Buffer.byteLength(JSON.stringify(body)) <= SOFT_OUTPUT_BYTES)
|
|
141
|
+
return body;
|
|
142
|
+
const root = rootOf(command);
|
|
143
|
+
return { ...body, next: [...(body.next ?? []), ...withLines(root, runnable(root, added))] };
|
|
144
|
+
};
|
|
134
145
|
/** An answer as JSON lines: one line per item, then the end line. One thing is a list of one that has no more. */
|
|
135
146
|
const linesOf = (body) => jsonlOf("items" in body ? body : { items: [body.item], page: { mode: "page", limit: 1, has_more: false }, meta: body.meta });
|
|
136
147
|
/** An answer as JSON-lines records, for a writer that streams objects: one per item, then the end record. */
|
|
@@ -151,9 +162,10 @@ export const renderAnswer = (command, { renderer, format, streams, compact, full
|
|
|
151
162
|
const kept = withoutProviderRefs({ ...body, ...(next.length > 0 ? { next } : {}) });
|
|
152
163
|
if (next.length === 0)
|
|
153
164
|
delete kept.next;
|
|
154
|
-
const
|
|
165
|
+
const sealedBody = sealed(kept);
|
|
155
166
|
const environment = environmentOf(command);
|
|
156
167
|
const drawn = compact && !environment.agent;
|
|
168
|
+
const whole = format === "json" && !drawn && !environment.agent ? withLargeAnswerStep(command, sealedBody) : sealedBody;
|
|
157
169
|
if (drawn) {
|
|
158
170
|
const lined = whole.next ? { ...whole, next: compactSteps(root, whole.next) } : whole;
|
|
159
171
|
const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
package/dist/cli/execution.js
CHANGED
|
@@ -116,6 +116,7 @@ export const execution = (streams, { timeoutMs, fields, maxOutputBytes = DEFAULT
|
|
|
116
116
|
reason: "output.too-large",
|
|
117
117
|
max_bytes: maxOutputBytes,
|
|
118
118
|
emitted_bytes: bytes,
|
|
119
|
+
needed_bytes: bytes + size,
|
|
119
120
|
partial_output: bytes > 0,
|
|
120
121
|
});
|
|
121
122
|
bytes += size;
|
|
@@ -26,6 +26,7 @@ export const storeCommand = (messenger) => {
|
|
|
26
26
|
const store = new Command("store")
|
|
27
27
|
.description("the local store of messages")
|
|
28
28
|
.addCommand(statusCommand(messenger))
|
|
29
|
+
.addCommand(storedChatsCommand(messenger))
|
|
29
30
|
.addCommand(gapsCommand(messenger))
|
|
30
31
|
.addCommand(jobsCommand(messenger))
|
|
31
32
|
.addCommand(exportCommand(messenger))
|
|
@@ -35,6 +36,7 @@ export const storeCommand = (messenger) => {
|
|
|
35
36
|
const examples = {
|
|
36
37
|
backup: "./backup.db",
|
|
37
38
|
check: "",
|
|
39
|
+
"chats status": "",
|
|
38
40
|
clear: "--left --dry-run",
|
|
39
41
|
"copies delete": "messages_copy_1",
|
|
40
42
|
decrypt: "./backup.enc --output ./restored.db",
|
|
@@ -93,6 +95,21 @@ const statusCommand = (messenger) => annotate(new Command("status"), { output: {
|
|
|
93
95
|
.map((skip) => ` ${skip.title ?? skip.chatId} ${skip.messages} messages ${skip.reason}`)
|
|
94
96
|
.join("\n"));
|
|
95
97
|
});
|
|
98
|
+
/** `store status` summed over the account's chats, for a count of what the archive holds without a list of them. */
|
|
99
|
+
const storedChatsCommand = (messenger) => {
|
|
100
|
+
const chats = new Command("chats").description("the account's chats as the store holds them");
|
|
101
|
+
annotate(chats.command("status"), { output: { entity: "chat_coverage" }, effects: LOCAL_READ })
|
|
102
|
+
.summary("how many chats the archive holds in full, in part, or not at all")
|
|
103
|
+
.description("over this account's searchable chats of every kind, channels included: fetched (back to the first message, " +
|
|
104
|
+
"up to date, no gaps), partial, never (no fetch recorded and no message held), and the oldest message held; " +
|
|
105
|
+
"reads the store only")
|
|
106
|
+
.action(async function () {
|
|
107
|
+
const context = messengerContext(this, messenger);
|
|
108
|
+
const coverage = await context.withStore((store, account) => store.chats.chatCoverage(account));
|
|
109
|
+
renderAnswer(this, context, itemOf(snakeKeys(coverage)));
|
|
110
|
+
});
|
|
111
|
+
return chats;
|
|
112
|
+
};
|
|
96
113
|
const LISTED = 20;
|
|
97
114
|
/** Titles are the owner's: these lines go to a person's terminal, never into an error message. */
|
|
98
115
|
const leftLines = (left) => {
|
|
@@ -18,6 +18,8 @@ type Read = Message & {
|
|
|
18
18
|
chatTitle?: string | null;
|
|
19
19
|
};
|
|
20
20
|
/** One message of a catch-up answer: the fields `inbox` and `review` show, for every messenger and for mail. */
|
|
21
|
+
/** Written by others, and by the owner, so an agent quotes it and never follows it (WC-SECR-21). */
|
|
22
|
+
export declare const SUMMARY_UNTRUSTED: string[];
|
|
21
23
|
export declare const summaryOf: (message: Read, reader: AccountKey) => {
|
|
22
24
|
ref: string;
|
|
23
25
|
chat_id: string;
|
|
@@ -61,6 +63,7 @@ export declare const summaryOf: (message: Read, reader: AccountKey) => {
|
|
|
61
63
|
url?: string | undefined;
|
|
62
64
|
}[][] | undefined;
|
|
63
65
|
}[];
|
|
66
|
+
untrusted: string[];
|
|
64
67
|
};
|
|
65
68
|
export declare const inboxAnswer: (inbox: Inbox, hearing: Hearing | undefined, reader: AccountKey, transcribe: boolean, meta?: Partial<Meta>) => import("../envelope.js").ListBody<{
|
|
66
69
|
ref: string;
|
|
@@ -105,6 +108,7 @@ export declare const inboxAnswer: (inbox: Inbox, hearing: Hearing | undefined, r
|
|
|
105
108
|
url?: string | undefined;
|
|
106
109
|
}[][] | undefined;
|
|
107
110
|
}[];
|
|
111
|
+
untrusted: string[];
|
|
108
112
|
}>;
|
|
109
113
|
/** What `review --offline` cannot see. */
|
|
110
114
|
export declare const OFFLINE_REVIEW = "offline: only what was already synced to the local store; run review without --offline for the rest";
|
|
@@ -160,5 +164,6 @@ export declare const reviewAnswer: (found: Review, hearing: Hearing | undefined,
|
|
|
160
164
|
url?: string | undefined;
|
|
161
165
|
}[][] | undefined;
|
|
162
166
|
}[];
|
|
167
|
+
untrusted: string[];
|
|
163
168
|
}>;
|
|
164
169
|
export {};
|
|
@@ -34,6 +34,8 @@ export const catchUpQuery = (words, registry, command) => {
|
|
|
34
34
|
};
|
|
35
35
|
};
|
|
36
36
|
/** One message of a catch-up answer: the fields `inbox` and `review` show, for every messenger and for mail. */
|
|
37
|
+
/** Written by others, and by the owner, so an agent quotes it and never follows it (WC-SECR-21). */
|
|
38
|
+
export const SUMMARY_UNTRUSTED = ["chat_title", "sender_name", "text", "transcript", "attachments.name"];
|
|
37
39
|
export const summaryOf = (message, reader) => {
|
|
38
40
|
const { ref, chat_id, chat_title, timestamp, sender_name, sender_is_me, outgoing, text, transcript, attachments } = messageItem(message, reader);
|
|
39
41
|
return {
|
|
@@ -47,6 +49,7 @@ export const summaryOf = (message, reader) => {
|
|
|
47
49
|
text,
|
|
48
50
|
...(transcript === undefined ? {} : { transcript }),
|
|
49
51
|
attachments,
|
|
52
|
+
untrusted: SUMMARY_UNTRUSTED,
|
|
50
53
|
};
|
|
51
54
|
};
|
|
52
55
|
const nameOf = (chat) => chat.title ?? chat.id;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { annotate } from "@wirecat/cli-base/commands";
|
|
2
|
+
import { Command, Option } from "commander";
|
|
3
|
+
import { LOCAL_READ } from "../effects.js";
|
|
4
|
+
import { renderAnswer } from "../envelope.js";
|
|
5
|
+
import { messengerContext } from "./context.js";
|
|
6
|
+
import { refuseJsonl, responsesAnswer, waitingAnswer } from "./stats-answers.js";
|
|
7
|
+
const QUERY = "date:, chat: and kind: terms, AND-ed — date>=30d, date:[60d TO 30d]; none reads all time";
|
|
8
|
+
const GUIDE = "Guide: https://github.com/WireCatLabs/cli-core/blob/main/docs/rankings.md#reply-times-and-chats-waiting-on-you";
|
|
9
|
+
const minutes = (ms) => (ms === null ? "—" : `${Math.round(ms / 60_000)} min`);
|
|
10
|
+
export const replyResponsesCommand = (messenger) => annotate(new Command("responses"), { effects: LOCAL_READ, output: { entity: "response_times" } })
|
|
11
|
+
.summary("how fast replies come in one-to-one chats: median, p90, mean and buckets")
|
|
12
|
+
.description("how long the owner took to answer (--who me), or the other side took to answer the owner (--who others), in " +
|
|
13
|
+
"one-to-one chats — the local store only. Several messages in a row followed by one answer count as one " +
|
|
14
|
+
"reply, timed from the first unanswered message; the day of a row is the day of the reply")
|
|
15
|
+
.argument("[query...]", QUERY)
|
|
16
|
+
.addOption(new Option("--who <side>", "whose replies: the owner's or the other side's").choices(["me", "others"]))
|
|
17
|
+
.addOption(new Option("--by <group>", "one row per calendar day of the reply, or none").choices(["day", "total"]))
|
|
18
|
+
.option("--timezone <zone>", "the IANA timezone for calendar days and date: bounds")
|
|
19
|
+
.option("--source <accounts>", "every account of this messenger held in the store; personal, bots or all")
|
|
20
|
+
.addHelpText("after", GUIDE)
|
|
21
|
+
.action(async function (words) {
|
|
22
|
+
const context = messengerContext(this, messenger);
|
|
23
|
+
refuseJsonl(context.format);
|
|
24
|
+
const { who, by, timezone, source } = this.opts();
|
|
25
|
+
const found = await context.withServices((services) => services.replyStats.responses({
|
|
26
|
+
who: who ?? "me",
|
|
27
|
+
by: by ?? "total",
|
|
28
|
+
...(words.length ? { text: words.join(" ") } : {}),
|
|
29
|
+
...(timezone === undefined ? {} : { timezone }),
|
|
30
|
+
...(source === undefined ? {} : { source }),
|
|
31
|
+
}));
|
|
32
|
+
renderAnswer(this, context, responsesAnswer(found), () => [
|
|
33
|
+
`${found.replies} replies · median ${minutes(found.medianMs)} · p90 ${minutes(found.p90Ms)} · mean ${minutes(found.meanMs)}`,
|
|
34
|
+
...found.rows.map((row) => `${row.key} ${row.replies} replies · median ${minutes(row.medianMs)}`),
|
|
35
|
+
"",
|
|
36
|
+
].join("\n"));
|
|
37
|
+
});
|
|
38
|
+
export const replyWaitingCommand = (messenger) => annotate(new Command("waiting"), { effects: LOCAL_READ, output: { entity: "waiting_chats" } })
|
|
39
|
+
.summary("chats whose newest message asks the owner something")
|
|
40
|
+
.description("how many chats wait on the owner — the local store only: a one-to-one chat whose newest message is a " +
|
|
41
|
+
"question, or a group whose newest message mentions the owner or replies to them. Muted or archived " +
|
|
42
|
+
"one-to-one chats are left out, as inbox leaves them out; date: bounds the newest message's time")
|
|
43
|
+
.argument("[query...]", QUERY)
|
|
44
|
+
.option("--timezone <zone>", "the IANA timezone for date: bounds")
|
|
45
|
+
.option("--source <accounts>", "every account of this messenger held in the store; personal, bots or all")
|
|
46
|
+
.addHelpText("after", GUIDE)
|
|
47
|
+
.action(async function (words) {
|
|
48
|
+
const context = messengerContext(this, messenger);
|
|
49
|
+
refuseJsonl(context.format);
|
|
50
|
+
const { timezone, source } = this.opts();
|
|
51
|
+
const found = await context.withServices((services) => services.replyStats.waiting({
|
|
52
|
+
...(words.length ? { text: words.join(" ") } : {}),
|
|
53
|
+
...(timezone === undefined ? {} : { timezone }),
|
|
54
|
+
...(source === undefined ? {} : { source }),
|
|
55
|
+
}));
|
|
56
|
+
renderAnswer(this, context, waitingAnswer(found), () => `${found.chats} chats wait on you (${found.byKind.private} one-to-one, ${found.byKind.group} groups) · ${found.messages} messages${found.oldestAt ? ` · oldest ${found.oldestAt}` : ""}\n`);
|
|
57
|
+
});
|
|
@@ -18,6 +18,7 @@ export type NoteHitItem = InferOutput<(typeof ENTITIES)["note.hit"]>;
|
|
|
18
18
|
export type HitItem = InferOutput<(typeof ENTITIES)["hit"]>;
|
|
19
19
|
/** The page a `--page` asks for, as the offset the search services take. */
|
|
20
20
|
export declare const offsetOf: (page: number | undefined, limit: number) => number | undefined;
|
|
21
|
+
export declare const MAIL_HIT_UNTRUSTED: string[];
|
|
21
22
|
export declare const messageHitItem: (hit: FoundMessage, query?: string) => MessageHitItem;
|
|
22
23
|
/**
|
|
23
24
|
* What the store holds of a chat that is not complete, in words. A chat that reaches its first message is only
|
|
@@ -5,6 +5,7 @@ import { SAVE_HELP } from "../../meetings/index.js";
|
|
|
5
5
|
import { searchNotesOf } from "../../services/notes-search.js";
|
|
6
6
|
import { LOCAL_READ, REMOTE_READ } from "../effects.js";
|
|
7
7
|
import { renderAnswer } from "../envelope.js";
|
|
8
|
+
import { withOptionHints } from "../option-hints.js";
|
|
8
9
|
import { positiveCount } from "../paging.js";
|
|
9
10
|
import { runsSearchCommand } from "../runs/search-command.js";
|
|
10
11
|
import { commandAt } from "../steps.js";
|
|
@@ -193,5 +194,12 @@ export const searchCommand = (messenger, { topics = false } = {}) => {
|
|
|
193
194
|
if (command)
|
|
194
195
|
annotate(command, { examples: [`${messenger.app.command} personal search ${path} ${args}`] });
|
|
195
196
|
}
|
|
197
|
+
for (const path of ["all", "messages"]) {
|
|
198
|
+
const command = commandAt(search, path);
|
|
199
|
+
if (command)
|
|
200
|
+
withOptionHints(command, {
|
|
201
|
+
"--chat": `search in one chat with chat:<chat> in the query: search ${path} 'chat:<chat> words'`,
|
|
202
|
+
});
|
|
203
|
+
}
|
|
196
204
|
return search;
|
|
197
205
|
};
|
|
@@ -8,9 +8,10 @@ import type { AdminEvidenceFound, AdminFound } from "../../services/admin-statis
|
|
|
8
8
|
import type { ChatStats } from "../../services/chat-stats.js";
|
|
9
9
|
import type { MessageStats } from "../../services/messages-search.js";
|
|
10
10
|
import type { RankingFound } from "../../services/rankings.js";
|
|
11
|
+
import type { ReplyTimes, Waiting } from "../../services/reply-stats.js";
|
|
11
12
|
import type { RetentionService } from "../../services/retention.js";
|
|
13
|
+
import type { TaskStats } from "../../services/task-stats.js";
|
|
12
14
|
import type { AccountKey, RankedEvidence } from "../../store/store.js";
|
|
13
|
-
import type { GroupStats } from "../../tasks/index.js";
|
|
14
15
|
import { type ItemBody, type ListBody } from "../envelope.js";
|
|
15
16
|
type Of<T extends keyof typeof ENTITIES> = InferOutput<(typeof ENTITIES)[T]>;
|
|
16
17
|
type RetentionFound = Awaited<ReturnType<RetentionService["report"]>>;
|
|
@@ -70,6 +71,8 @@ export declare const refuseJsonl: (format: string) => void;
|
|
|
70
71
|
export declare const chatStatsAnswer: (stats: ChatStats, account: AccountKey, meta?: Partial<Meta>) => ItemBody<Of<"chat_stats">>;
|
|
71
72
|
/** Said where the store has kept no join, leave or other chat event for the chat: a 0 would read as nobody joined. */
|
|
72
73
|
export declare const MEMBERS_UNRECORDED = "joins and leaves are not recorded for this chat yet, so they are not counted";
|
|
73
|
-
/** `stats tasks show`, CLI and MCP alike. */
|
|
74
|
-
export declare const taskStatsAnswer: (
|
|
74
|
+
/** `stats tasks show`, CLI and MCP alike. A row of `--by chat` also names its chat as `chat`, as it always has. */
|
|
75
|
+
export declare const taskStatsAnswer: (stats: TaskStats, account: AccountKey) => ItemBody<Of<"task_stats">>;
|
|
76
|
+
export declare const responsesAnswer: (found: ReplyTimes) => ItemBody<Of<"response_times">>;
|
|
77
|
+
export declare const waitingAnswer: (found: Waiting) => ItemBody<Of<"waiting_chats">>;
|
|
75
78
|
export {};
|