@wirecat/cli-core 0.400.0 → 0.402.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 +39 -0
- package/README.md +1 -1
- package/dist/cli/bot/api.js +5 -2
- package/dist/cli/bot/store.js +1 -1
- package/dist/cli/config-command.js +13 -7
- package/dist/cli/context.d.ts +2 -0
- package/dist/cli/index.d.ts +2 -1
- package/dist/cli/index.js +2 -1
- package/dist/cli/meeting-evidence-answer.d.ts +46 -0
- package/dist/cli/meeting-evidence-answer.js +22 -0
- package/dist/cli/meeting-preparation-answer.js +1 -13
- package/dist/cli/messenger/account-sessions-command.js +0 -2
- package/dist/cli/messenger/archive-commands.js +1 -1
- package/dist/cli/messenger/doctor-command.js +0 -1
- package/dist/cli/messenger/message-writes.d.ts +192 -2
- package/dist/cli/messenger/message-writes.js +6 -2
- package/dist/cli/messenger/messages-send-command.js +9 -6
- package/dist/cli/messenger/models-command.js +0 -3
- package/dist/cli/messenger/records-command.js +0 -2
- package/dist/cli/messenger/review.js +1 -1
- package/dist/cli/messenger/schedule-command.js +2 -2
- package/dist/cli/messenger/search-answers.js +2 -0
- package/dist/cli/messenger/server-command.js +0 -3
- package/dist/cli/messenger/store-maintenance-command.d.ts +1 -1
- package/dist/cli/messenger/store-maintenance-command.js +7 -7
- package/dist/cli/messenger/stored.js +4 -1
- package/dist/cli/messenger/tasks-command.js +10 -6
- package/dist/cli/program.js +5 -1
- package/dist/documents/index.d.ts +1 -0
- package/dist/documents/index.js +1 -0
- package/dist/entities/hit.d.ts +4 -0
- package/dist/entities/hit.js +4 -0
- package/dist/entities/index.d.ts +285 -0
- package/dist/entities/index.js +5 -1
- package/dist/entities/meeting-evidence.d.ts +86 -0
- package/dist/entities/meeting-evidence.js +25 -0
- package/dist/entities/meeting-preparation-parts.d.ts +14 -0
- package/dist/entities/meeting-preparation-parts.js +15 -13
- package/dist/entities/meeting.d.ts +1 -1
- package/dist/entities/meeting.js +1 -1
- package/dist/entities/message-write.d.ts +187 -0
- package/dist/entities/message-write.js +2 -0
- package/dist/errors/reasons.js +2 -0
- package/dist/mcp/agent.js +12 -6
- package/dist/meetings/cli/index.js +3 -1
- package/dist/meetings/index.d.ts +1 -1
- package/dist/meetings/index.js +1 -1
- package/dist/meetings/mcp/index.d.ts +15 -15
- package/dist/meetings/read-answers.d.ts +18 -0
- package/dist/meetings/read-answers.js +30 -0
- package/dist/ports/messenger.d.ts +10 -1
- package/dist/search/dictionary.d.ts +20 -0
- package/dist/search/dictionary.js +106 -0
- package/dist/sends/guard.d.ts +1 -1
- package/dist/sends/guard.js +9 -5
- package/dist/sends/journal.d.ts +1 -1
- package/dist/sends/permissions.d.ts +10 -1
- package/dist/sends/permissions.js +43 -1
- package/dist/sends/upload.d.ts +4 -4
- package/dist/sends/upload.js +24 -20
- package/dist/services/documents/mirrors.d.ts +98 -0
- package/dist/services/documents/mirrors.js +144 -0
- package/dist/services/messages.js +1 -0
- package/dist/services/search-all-meetings.js +21 -8
- package/dist/services/task-rules.d.ts +1 -1
- package/dist/services/tasks.d.ts +2 -2
- package/dist/services/tasks.js +1 -1
- package/dist/store/sqlite/drizzle/bun.js +3 -3
- package/dist/store/sqlite/drizzle/bun.js.map +1 -1
- package/dist/store/sqlite/drizzle/core.js +2 -2
- package/dist/store/sqlite/drizzle/core.js.map +1 -1
- package/dist/store/sqlite/drizzle/node.js +3 -3
- package/dist/store/sqlite/drizzle/node.js.map +1 -1
- package/dist/store/sqlite/drizzle/{shared-O7CTKP45.js → shared-HKXF6HKX.js} +57 -57
- package/dist/store/sqlite/drizzle/{shared-O7CTKP45.js.map → shared-HKXF6HKX.js.map} +1 -1
- package/dist/store/sqlite/transcript-query.js +15 -5
- package/package.json +4 -2
- package/parity.json +6 -3
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,32 @@ shape of this file.
|
|
|
7
7
|
|
|
8
8
|
## Unreleased
|
|
9
9
|
|
|
10
|
+
## 0.402.0 — 24.10.2026
|
|
11
|
+
|
|
12
|
+
### Changed — may break callers
|
|
13
|
+
|
|
14
|
+
- **MCP offers `bot api`, behind `bot.api`.** The generated `bot api <operation>` commands (raw calls to Bot API methods, which skip the send guard and the bot's recipient list) are bot MCP tools again, offered only where the profile sets `permissions.bot.api` to `allow`; it is `deny` by default for an MCP server, so nothing changes until the owner turns it on, and a broader `bot: allow` does not lift it. A call made after the owner turned it off is refused naming the key and the terminal command; an agent cannot set the key through `config set` (the guard on `permissions.mcp…` covers `permissions.bot.api`). Breaking for a CLI: `generatedApiCommand` no longer marks the group `mcp: false`, and each operation now declares effects (`remote: read` or `write`), so `commands --json` shows them and a catalogue built with `toolsFromCommands` without `levels` lists the operations; update a pinned bot catalogue and a document that lists what MCP leaves out. Under `<PREFIX>_READ_ONLY` a write operation now refuses on the command line too. The command line's `bot api` is otherwise unchanged.
|
|
15
|
+
|
|
16
|
+
### Fixed
|
|
17
|
+
|
|
18
|
+
- **Voice-note search no longer turns an English word into another real English word.** A word in a transcript widens to the spellings speech recognition garbles only past a dictionary of its language: Russian as before, and now English and Spanish, following the store's word-form languages (`search_stemmers`). Before, «cost» also found «cast». A Latin word with no dictionary for its language, and English and Spanish number words, no longer widen.
|
|
19
|
+
|
|
20
|
+
## 0.401.0 — 24.10.2026
|
|
21
|
+
|
|
22
|
+
### Changed — may break callers
|
|
23
|
+
|
|
24
|
+
- **`events list` writes times as ISO 8601 and ids as strings**, as every other answer does: `starts_at`, `ends_at`, `deleted_at`, `created_at` and `updated_at` were epoch milliseconds, `id` and `event_series_id` numbers. No field is gone.
|
|
25
|
+
|
|
26
|
+
- **List duplicate-task pairs explicitly.** Use `tasks duplicates list [query...]` in CLI and MCP calls. The bare `tasks duplicates` group shows help or refuses in machine mode; it no longer reads the store. Reject and defer remain under that group.
|
|
27
|
+
|
|
28
|
+
### Fixed
|
|
29
|
+
|
|
30
|
+
- **`search all` pages meeting matches.** With a meeting account in the search, `--page 2` repeated the meetings of the first page, and `has_more` could be false while meeting matches remained. The merged list is now read as deep as the page and cut, so pages follow on and `has_more` holds.
|
|
31
|
+
|
|
32
|
+
### Added
|
|
33
|
+
|
|
34
|
+
- **Meeting answers keep what they knew.** A `search all` meeting hit carries its `scope` (transcript, chat or summary) and its stored line `id`, so two passages of one meeting stay apart. New entities `meeting_evidence`, `meeting_person_context` and `event`; `cli` exports `allAnswer`, `meetingEvidenceItem` and `meetingPersonContextItem`.
|
|
35
|
+
|
|
10
36
|
## 0.400.0 — 24.10.2026
|
|
11
37
|
|
|
12
38
|
### Fixed
|
|
@@ -21,6 +47,17 @@ shape of this file.
|
|
|
21
47
|
|
|
22
48
|
### Added
|
|
23
49
|
|
|
50
|
+
- **Album sends.** `messages send` takes `--photo` and `--file` more than once, and its MCP tool takes a list for
|
|
51
|
+
`photo` and `file`; together they go as one album, photos first. Each photo or file counts as one send toward the
|
|
52
|
+
hourly limit. An adapter returns every message of the album as `Sent.messages`, and `--json` answers with a
|
|
53
|
+
`messages` list beside `message`, which stays the first. A messenger that cannot send an album refuses it before
|
|
54
|
+
anything goes. A single attachment sends and answers as before.
|
|
55
|
+
|
|
56
|
+
- **Mirror runner for folder sync.** `syncMirrors` syncs each of a CLI's mirrors both ways under one lock and reports
|
|
57
|
+
a partly failed mirror as a `mirror.partial` issue; `fileMirrorState`, `mirrorId`, `mirrorStatus` and
|
|
58
|
+
`conflictReport` are the state file, id, local plan and conflict report drive-cli's `mirrors` used, moved here so
|
|
59
|
+
other CLIs can mirror folders and a watcher can reuse the same run.
|
|
60
|
+
|
|
24
61
|
- **Meeting answer schemas.** `review`, `mentions list`, `stats meetings show` and `top`, `meetings people`, `meetings passage` and `meetings task-proposal` declare their answer entities (`meeting_review`, `meeting_link`, `meeting_stats`, `meeting_speaker`, `meeting_participants`, `meeting_passage`, `meeting_task_proposal`) for field discovery and projection. `meetings/` exports the item builders the meeting CLIs share: `meetingReviewItem`, `meetingLinkItem`, `meetingStatsItem`, `meetingSpeakerItem`.
|
|
25
62
|
|
|
26
63
|
- **Listener answers declare their fields.** Live messages and events, and the final serve summary, expose exact schemas for discovery and cross-CLI output contracts. Provider-only attachment references stay private.
|
|
@@ -79,6 +116,8 @@ shape of this file.
|
|
|
79
116
|
|
|
80
117
|
### Changed — may break callers
|
|
81
118
|
|
|
119
|
+
- **MCP offers the writes no permission level stopped before.** `store backup|restore|migrate|repair|reset|clear|decrypt`, `store copies delete`, `server start|stop|restart`, model downloads, `schedule run|exec`, `doctor report create`, `account sessions end`, `chats delete|clear` and `bot store fetch` are MCP tools, each limited by a key named after its path (`store.reset`, `server.start`, `schedule.run`…), `ask` by default; set one to `deny` to keep an agent from it. `server`, `models`, `schedule`, `doctor` and `images` are now valid roots of a permission key. Command-line behaviour is unchanged. What to change in a CLI: a pinned MCP catalogue and a document listing what MCP leaves out.
|
|
120
|
+
|
|
82
121
|
- **Watch uses the shared JSONL contract.** Read each message or event from `{ type: "item", data }` and wait for the final `type: "end"` record. Message and event fields are snake_case, message values use the canonical read shape with references, and live counter observations remain available. Normal stops and timeouts finish complete; a source failure finishes incomplete and returns its failure code. Update readers of the old raw lines.
|
|
83
122
|
|
|
84
123
|
- **MCP offers the commands that change what a later run may do, behind `mcp.authority`.** `config set|unset`, `schedule command|agent|remove`, auto-reply rules and consents, recipients, chat rules, `server install`, `skill install`, model keys, media archive timers and `flood clear` are MCP tools again, offered only where the profile sets `permissions.mcp.authority` to `allow`; it is `deny` by default, so nothing changes until the owner turns it on. An agent cannot change that key through `config set`. What to change in a CLI: `grantsAuthority` no longer adds `mcp: false`, so `commands --json` no longer marks these commands, and a catalogue built with `toolsFromCommands` without `levels` lists them; update a pinned catalogue and a document that lists what MCP leaves out. A command of the CLI's own marked `grantsAuthority` (max `recipients add`) is gated the same way. A caller of `createBotServer` passes `authority: changesAuthorityAt(root)` to hide them; without it they are listed and refuse when called.
|
package/README.md
CHANGED
|
@@ -178,7 +178,7 @@ or a launchd agent.
|
|
|
178
178
|
- **A permission level per command path:** deny, readonly, ask or allow. The most specific key wins, and a built-in
|
|
179
179
|
default can only tighten what the owner set. No level lets an agent delete for everyone.
|
|
180
180
|
- **A recipient list and an hourly limit** for sends, and a journal of every attempt that records the length of the
|
|
181
|
-
text, never the text.
|
|
181
|
+
text, never the text. Each photo or file of an album counts as one send.
|
|
182
182
|
- **A send id across retries.** A write whose outcome is unknown is never retried automatically; a retry under the
|
|
183
183
|
same send id cannot send twice.
|
|
184
184
|
- **Deletion asks first,** at most ten messages at a time.
|
package/dist/cli/bot/api.js
CHANGED
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
import { CliError } from "@wirecat/cli-base";
|
|
2
2
|
import { annotate } from "@wirecat/cli-base/commands";
|
|
3
3
|
import { Command, Option } from "commander";
|
|
4
|
+
import { REMOTE_READ, REMOTE_WRITE } from "../effects.js";
|
|
4
5
|
import { apiFlagOf, apiOptionKey, readApiBody } from "./api-input.js";
|
|
5
6
|
export const generatedApiCommand = (api) => {
|
|
6
|
-
const group =
|
|
7
|
+
const group = new Command("api").description(api.description ?? "every operation of the official Bot API, generated from its schema");
|
|
7
8
|
group.option("--store-token <profile>", "keep a returned authentication token only in this bot profile's OS keyring; never print it");
|
|
8
9
|
for (const operation of api.operations) {
|
|
9
10
|
const binding = operation.binding.kind === "http"
|
|
10
11
|
? `${operation.binding.method} ${operation.binding.path}`
|
|
11
12
|
: operation.binding.name;
|
|
12
|
-
const command = new Command(operation.command)
|
|
13
|
+
const command = annotate(new Command(operation.command), {
|
|
14
|
+
effects: operation.effect === "read" ? REMOTE_READ : REMOTE_WRITE,
|
|
15
|
+
}).description(`${operation.summary ?? operation.id} — ${operation.effect} (${binding})`);
|
|
13
16
|
for (const parameter of operation.parameters) {
|
|
14
17
|
if (parameter.sensitive)
|
|
15
18
|
continue;
|
package/dist/cli/bot/store.js
CHANGED
|
@@ -20,7 +20,7 @@ const wholeNumber = (value) => {
|
|
|
20
20
|
* personal `messages sync` does. Mounted for a messenger whose Bot API pages back through a chat.
|
|
21
21
|
*/
|
|
22
22
|
export const botStoreCommand = (bot, fetching) => {
|
|
23
|
-
const command =
|
|
23
|
+
const command = new Command("store").description("the bot's local copy on this machine");
|
|
24
24
|
const fetch = annotate(command.command("fetch"), { effects: FETCH })
|
|
25
25
|
.description("fetch a chat's history into the bot's local copy, newest first; run it again to continue")
|
|
26
26
|
.argument("<chat>", "a chat id, or the title of a chat this bot has seen")
|
|
@@ -2,7 +2,7 @@ import { CliError, pathsAreOverridden } from "@wirecat/cli-base";
|
|
|
2
2
|
import { annotate } from "@wirecat/cli-base/commands";
|
|
3
3
|
import { Command } from "commander";
|
|
4
4
|
import { envName } from "../ports/app.js";
|
|
5
|
-
import { AUTHORITY_KEY } from "../sends/permissions.js";
|
|
5
|
+
import { AUTHORITY_KEY, BOT_API_KEY } from "../sends/permissions.js";
|
|
6
6
|
import { loadSnakeCaseConfig } from "./config-keys.js";
|
|
7
7
|
import { baseContext, environmentOf } from "./context.js";
|
|
8
8
|
import { grantsAuthority, LOCAL_READ, LOCAL_WRITE } from "./effects.js";
|
|
@@ -96,7 +96,7 @@ export const configCommand = (app, config, { permissionKey } = {}) => {
|
|
|
96
96
|
throw new CliError("permission_error", `this process is locked to profile ${settings.profile} (${lock}) — ${setting === "default_profile" ? setting : "--defaults"} changes other profiles`);
|
|
97
97
|
}
|
|
98
98
|
if (environmentOf(this).agent)
|
|
99
|
-
|
|
99
|
+
refuseGuardedKey(setting, action === "set" ? String(given) : undefined);
|
|
100
100
|
if (action === "set")
|
|
101
101
|
refuseUnknownKey(this, setting, String(given), permissionKey);
|
|
102
102
|
const saved = config.changeSetting(settings.configPath, {
|
|
@@ -137,10 +137,11 @@ export const refuseUnknownKey = (command, setting, value, permissionKey) => {
|
|
|
137
137
|
}
|
|
138
138
|
};
|
|
139
139
|
/**
|
|
140
|
-
* An agent may hold `mcp.authority` and change other settings, but never the key that let it in: on any
|
|
141
|
-
* the defaults, or by replacing `permissions` whole. Only the owner, in a terminal, turns it on or off
|
|
140
|
+
* An agent may hold `mcp.authority` or `bot.api` and change other settings, but never the key that let it in: on any
|
|
141
|
+
* profile, in the defaults, or by replacing `permissions` whole. Only the owner, in a terminal, turns it on or off
|
|
142
|
+
* (NEED-1662, NEED-1679).
|
|
142
143
|
*/
|
|
143
|
-
const
|
|
144
|
+
const refuseGuardedKey = (setting, value) => {
|
|
144
145
|
const keys = setting.startsWith("permissions.")
|
|
145
146
|
? [setting.slice("permissions.".length)]
|
|
146
147
|
: setting === "permissions"
|
|
@@ -148,9 +149,14 @@ const refuseAuthorityKey = (setting, value) => {
|
|
|
148
149
|
? ["mcp"]
|
|
149
150
|
: objectKeys(value)
|
|
150
151
|
: [];
|
|
151
|
-
|
|
152
|
+
const guarded = keys.some((key) => key === BOT_API_KEY || key.startsWith(`${BOT_API_KEY}.`))
|
|
153
|
+
? BOT_API_KEY
|
|
154
|
+
: keys.some((key) => key === "mcp" || key.startsWith("mcp."))
|
|
155
|
+
? AUTHORITY_KEY
|
|
156
|
+
: undefined;
|
|
157
|
+
if (!guarded)
|
|
152
158
|
return;
|
|
153
|
-
throw new CliError("permission_error", `an agent cannot change permissions.${
|
|
159
|
+
throw new CliError("permission_error", `an agent cannot change permissions.${guarded} — the owner sets it in a terminal`, { permission: guarded });
|
|
154
160
|
};
|
|
155
161
|
/** The keys of a `permissions` object given whole; anything else is left to the schema to refuse. */
|
|
156
162
|
const objectKeys = (value) => {
|
package/dist/cli/context.d.ts
CHANGED
|
@@ -87,6 +87,8 @@ export interface AgentRun {
|
|
|
87
87
|
overrides?: readonly string[];
|
|
88
88
|
/** The server's levels allow `mcp.authority`: a command that changes what a later run may do may run. */
|
|
89
89
|
authority?: boolean;
|
|
90
|
+
/** The server's levels allow `bot.api`: a raw Bot API call, past the send guard, may run. */
|
|
91
|
+
botApi?: boolean;
|
|
90
92
|
}
|
|
91
93
|
export interface RelayedRun {
|
|
92
94
|
/** The profile serve holds; a command for another is refused before it touches the connection. */
|
package/dist/cli/index.d.ts
CHANGED
|
@@ -65,6 +65,7 @@ export { bufferedInput, type InputPolicy, inputPolicy, MAX_BUFFERED_INPUT, MAX_S
|
|
|
65
65
|
export { answerFields, checkJson, type EntityFields, entityFields, type JsonFieldsResolver, type JsonRequest, liftJson, } from "./json-fields.js";
|
|
66
66
|
export { commandPath, LIST_QUERY_GUIDE, listQuery, nativeField, nativeTerms, pagedList, pageOf, type QueryWords, queryArgument, queryHelp, queryTerms, searchText, termField, timeBounds, typedQuery, unfilteredQuery, withQuery, } from "./list-query.js";
|
|
67
67
|
export { addMeetingBatchCommand, formatMeetingBatch, prepareMeetingBatch } from "./meeting-batch.js";
|
|
68
|
+
export { meetingEvidenceItem, meetingPersonContextItem } from "./meeting-evidence-answer.js";
|
|
68
69
|
export { parseEvidenceFindingsJson, parseMeetingFindingsJson } from "./meeting-findings-input.js";
|
|
69
70
|
export { meetingPreparationAnswer } from "./meeting-preparation-answer.js";
|
|
70
71
|
export { addMeetingPreparationCommand } from "./meeting-preparation-command.js";
|
|
@@ -106,7 +107,7 @@ export { callsCommand, stickersCommand } from "./messenger/records-command.js";
|
|
|
106
107
|
export { repliesCommand } from "./messenger/replies-command.js";
|
|
107
108
|
export { reviewCommand } from "./messenger/review.js";
|
|
108
109
|
export { scheduleCommand } from "./messenger/schedule-command.js";
|
|
109
|
-
export { allHitItem, type HitItem, type MessageHitItem, messageHitItem, type NoteHitItem, noteHitItem, } from "./messenger/search-answers.js";
|
|
110
|
+
export { allAnswer, allHitItem, type HitItem, type MessageHitItem, messageHitItem, type NoteHitItem, noteHitItem, } from "./messenger/search-answers.js";
|
|
110
111
|
export { searchCommand } from "./messenger/search-command.js";
|
|
111
112
|
export { SEARCHES_QUERY, searchesCommand } from "./messenger/searches-command.js";
|
|
112
113
|
export { serveCommand, servingProfiles } from "./messenger/serve-command.js";
|
package/dist/cli/index.js
CHANGED
|
@@ -60,6 +60,7 @@ export { bufferedInput, inputPolicy, MAX_BUFFERED_INPUT, MAX_SECRET_INPUT, provi
|
|
|
60
60
|
export { answerFields, checkJson, entityFields, liftJson, } from "./json-fields.js";
|
|
61
61
|
export { commandPath, LIST_QUERY_GUIDE, listQuery, nativeField, nativeTerms, pagedList, pageOf, queryArgument, queryHelp, queryTerms, searchText, termField, timeBounds, typedQuery, unfilteredQuery, withQuery, } from "./list-query.js";
|
|
62
62
|
export { addMeetingBatchCommand, formatMeetingBatch, prepareMeetingBatch } from "./meeting-batch.js";
|
|
63
|
+
export { meetingEvidenceItem, meetingPersonContextItem } from "./meeting-evidence-answer.js";
|
|
63
64
|
export { parseEvidenceFindingsJson, parseMeetingFindingsJson } from "./meeting-findings-input.js";
|
|
64
65
|
export { meetingPreparationAnswer } from "./meeting-preparation-answer.js";
|
|
65
66
|
export { addMeetingPreparationCommand } from "./meeting-preparation-command.js";
|
|
@@ -101,7 +102,7 @@ export { callsCommand, stickersCommand } from "./messenger/records-command.js";
|
|
|
101
102
|
export { repliesCommand } from "./messenger/replies-command.js";
|
|
102
103
|
export { reviewCommand } from "./messenger/review.js";
|
|
103
104
|
export { scheduleCommand } from "./messenger/schedule-command.js";
|
|
104
|
-
export { allHitItem, messageHitItem, noteHitItem, } from "./messenger/search-answers.js";
|
|
105
|
+
export { allAnswer, allHitItem, messageHitItem, noteHitItem, } from "./messenger/search-answers.js";
|
|
105
106
|
export { searchCommand } from "./messenger/search-command.js";
|
|
106
107
|
export { SEARCHES_QUERY, searchesCommand } from "./messenger/searches-command.js";
|
|
107
108
|
export { serveCommand, servingProfiles } from "./messenger/serve-command.js";
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { MeetingEvidencePacket, PersonMeetingContext } from "../services/index.js";
|
|
2
|
+
/** A meeting evidence packet with `ref`, `offset_ms` and string ids, as every answer that carries one names them. */
|
|
3
|
+
export declare const mapEvidence: (evidence: MeetingEvidencePacket) => {
|
|
4
|
+
schemaVersion: 1;
|
|
5
|
+
kind: "meeting";
|
|
6
|
+
source: string;
|
|
7
|
+
fingerprint: string;
|
|
8
|
+
limits: {
|
|
9
|
+
cues: number;
|
|
10
|
+
bytes: number;
|
|
11
|
+
maxReadBytes: number;
|
|
12
|
+
maxTranscriptPages: number;
|
|
13
|
+
};
|
|
14
|
+
contentBytes: number;
|
|
15
|
+
coverage: {
|
|
16
|
+
provided: number;
|
|
17
|
+
included: number;
|
|
18
|
+
omitted: number | null;
|
|
19
|
+
providedExact: boolean;
|
|
20
|
+
nextReference: string | null;
|
|
21
|
+
transcriptPages: number;
|
|
22
|
+
skippedUnavailable: number;
|
|
23
|
+
hasMore: boolean;
|
|
24
|
+
truncatedBy: "cues" | "bytes" | "transcripts" | null;
|
|
25
|
+
input: "bounded-meeting-pages";
|
|
26
|
+
archiveCompleteness: "unknown";
|
|
27
|
+
nextTranscriptId: string | null;
|
|
28
|
+
};
|
|
29
|
+
items: {
|
|
30
|
+
fingerprint: string;
|
|
31
|
+
contentHash: string | null;
|
|
32
|
+
position: number;
|
|
33
|
+
endMs: number;
|
|
34
|
+
speakerName: string | null;
|
|
35
|
+
text: string;
|
|
36
|
+
revision: "current" | "superseded";
|
|
37
|
+
ref: string;
|
|
38
|
+
offsetMs: number;
|
|
39
|
+
transcriptId: string | null;
|
|
40
|
+
speakerParticipantId: string | null;
|
|
41
|
+
}[];
|
|
42
|
+
};
|
|
43
|
+
/** `meetings evidence`: the `meeting_evidence` entity. */
|
|
44
|
+
export declare const meetingEvidenceItem: (evidence: MeetingEvidencePacket) => unknown;
|
|
45
|
+
/** `meetings context`: the `meeting_person_context` entity. */
|
|
46
|
+
export declare const meetingPersonContextItem: (context: PersonMeetingContext) => unknown;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { snakeKeys } from "./envelope.js";
|
|
2
|
+
const id = (value) => (value === null ? null : String(value));
|
|
3
|
+
const mapCue = ({ reference, startMs, ...cue }) => ({
|
|
4
|
+
...cue,
|
|
5
|
+
ref: reference,
|
|
6
|
+
offsetMs: startMs,
|
|
7
|
+
transcriptId: id(cue.transcriptId),
|
|
8
|
+
speakerParticipantId: id(cue.speakerParticipantId),
|
|
9
|
+
});
|
|
10
|
+
/** A meeting evidence packet with `ref`, `offset_ms` and string ids, as every answer that carries one names them. */
|
|
11
|
+
export const mapEvidence = (evidence) => ({
|
|
12
|
+
...evidence,
|
|
13
|
+
coverage: { ...evidence.coverage, nextTranscriptId: id(evidence.coverage.nextTranscriptId) },
|
|
14
|
+
items: evidence.items.map(mapCue),
|
|
15
|
+
});
|
|
16
|
+
/** `meetings evidence`: the `meeting_evidence` entity. */
|
|
17
|
+
export const meetingEvidenceItem = (evidence) => snakeKeys(mapEvidence(evidence));
|
|
18
|
+
/** `meetings context`: the `meeting_person_context` entity. */
|
|
19
|
+
export const meetingPersonContextItem = (context) => snakeKeys({
|
|
20
|
+
...context,
|
|
21
|
+
items: context.items.map(({ reference, cues, ...item }) => ({ ...item, ref: reference, cues: cues.map(mapCue) })),
|
|
22
|
+
});
|
|
@@ -3,6 +3,7 @@ import * as v from "valibot";
|
|
|
3
3
|
import { meetingPreparation } from "../entities/index.js";
|
|
4
4
|
import { itemOf, metaNow, sealed, snakeKeys } from "./envelope.js";
|
|
5
5
|
import { mapPreparationCommunications } from "./meeting-communications.js";
|
|
6
|
+
import { mapEvidence } from "./meeting-evidence-answer.js";
|
|
6
7
|
import { boundMeetingPreparationItem } from "./meeting-preparation-budget.js";
|
|
7
8
|
import { mapPreparationProjectEvidence } from "./meeting-preparation-projects.js";
|
|
8
9
|
const id = (value) => (value === null ? null : String(value));
|
|
@@ -17,19 +18,6 @@ const mapMeeting = (meeting) => {
|
|
|
17
18
|
updatedAt: at(meeting.updatedAt),
|
|
18
19
|
};
|
|
19
20
|
};
|
|
20
|
-
const mapEvidence = (evidence) => {
|
|
21
|
-
return {
|
|
22
|
-
...evidence,
|
|
23
|
-
coverage: { ...evidence.coverage, nextTranscriptId: id(evidence.coverage.nextTranscriptId) },
|
|
24
|
-
items: evidence.items.map(({ reference, startMs, ...cue }) => ({
|
|
25
|
-
...cue,
|
|
26
|
-
ref: reference,
|
|
27
|
-
offsetMs: startMs,
|
|
28
|
-
transcriptId: id(cue.transcriptId),
|
|
29
|
-
speakerParticipantId: id(cue.speakerParticipantId),
|
|
30
|
-
})),
|
|
31
|
-
};
|
|
32
|
-
};
|
|
33
21
|
export const meetingPreparationAnswer = (packet) => {
|
|
34
22
|
const candidate = packet.upcoming.candidate;
|
|
35
23
|
const mapped = snakeKeys({
|
|
@@ -23,11 +23,9 @@ export const accountSessionsCommand = (messenger) => {
|
|
|
23
23
|
const found = await context.withMessenger((adapter) => capability(adapter, "sessions", "list the account's sessions")());
|
|
24
24
|
renderAnswer(this, context, wholeList("account sessions list", found.map(sessionAnswer)));
|
|
25
25
|
});
|
|
26
|
-
// No MCP tool, at any permission level: it logs the owner out of the phone.
|
|
27
26
|
sessions.addCommand(annotate(new Command("end"), {
|
|
28
27
|
effects: REMOTE_WRITE,
|
|
29
28
|
output: { entity: "ended_account_sessions" },
|
|
30
|
-
mcp: false,
|
|
31
29
|
examples: [`${tool} account sessions end --others`],
|
|
32
30
|
})
|
|
33
31
|
.description("log out every other device, your phone included; this one stays")
|
|
@@ -93,7 +93,7 @@ const leftLines = (left) => {
|
|
|
93
93
|
* store is not offered. The refusal names the chats to a person but keeps them out of its message,
|
|
94
94
|
* which a scheduled run's `last.json` keeps.
|
|
95
95
|
*/
|
|
96
|
-
const clearCommand = (messenger) => annotate(new Command("clear"), { output: { entity: "store_clear" }, effects: LOCAL_WRITE
|
|
96
|
+
const clearCommand = (messenger) => annotate(new Command("clear"), { output: { entity: "store_clear" }, effects: LOCAL_WRITE })
|
|
97
97
|
.description("delete from the store the chats this account has left, with their messages")
|
|
98
98
|
.option("--left", "the chats this account has left — the only thing this clears")
|
|
99
99
|
.option("--allow-dangerous", "yes, delete — it cannot be undone, and a chat you left cannot be fetched again")
|
|
@@ -76,7 +76,6 @@ const reportCommand = (messenger) => {
|
|
|
76
76
|
});
|
|
77
77
|
destroysNothing(annotate(report.command("create"), {
|
|
78
78
|
effects: LOCAL_WRITE,
|
|
79
|
-
mcp: false,
|
|
80
79
|
examples: [`${app.command} personal doctor report create --output ./problem-report.json`],
|
|
81
80
|
}))
|
|
82
81
|
.description("write a problem report to a file, and say where to send it")
|
|
@@ -4,14 +4,16 @@ interface Written {
|
|
|
4
4
|
operationId: string;
|
|
5
5
|
sendId?: string;
|
|
6
6
|
message: Message;
|
|
7
|
+
messages?: Message[];
|
|
7
8
|
scheduledFor?: string;
|
|
8
9
|
}
|
|
9
10
|
/**
|
|
10
11
|
* A send, forward or edit: the message as it now stands, with its `operation_id` — for a send, the id a repeat
|
|
11
|
-
* passes as `--operation-id` so it cannot make a second copy.
|
|
12
|
+
* passes as `--operation-id` so it cannot make a second copy. An album adds `messages`, every one it made, in order;
|
|
13
|
+
* `message` stays its first, so a reader of one message reads an album as before. A scheduled message gets a new id when it goes out,
|
|
12
14
|
* so its next step is the list that shows it, never a retry.
|
|
13
15
|
*/
|
|
14
|
-
export declare const writtenAnswer: ({ operationId, sendId, message, scheduledFor }: Written, reader: AccountKey) => import("../envelope.js").ItemBody<{
|
|
16
|
+
export declare const writtenAnswer: ({ operationId, sendId, message, messages, scheduledFor }: Written, reader: AccountKey) => import("../envelope.js").ItemBody<{
|
|
15
17
|
operation_id: string;
|
|
16
18
|
message: {
|
|
17
19
|
ref: string;
|
|
@@ -201,6 +203,194 @@ export declare const writtenAnswer: ({ operationId, sendId, message, scheduledFo
|
|
|
201
203
|
[x: string]: unknown;
|
|
202
204
|
} | undefined;
|
|
203
205
|
};
|
|
206
|
+
messages?: {
|
|
207
|
+
ref: string;
|
|
208
|
+
id: string;
|
|
209
|
+
provider?: string | undefined;
|
|
210
|
+
account?: string | undefined;
|
|
211
|
+
chat_id: string;
|
|
212
|
+
chat_title?: string | null | undefined;
|
|
213
|
+
sender_id: string | null;
|
|
214
|
+
sender_name: string | null;
|
|
215
|
+
sender_username?: string | undefined;
|
|
216
|
+
sender_is_chat?: boolean | undefined;
|
|
217
|
+
mentions?: string[] | undefined;
|
|
218
|
+
timestamp: string;
|
|
219
|
+
edited_at: string | null;
|
|
220
|
+
text: string;
|
|
221
|
+
transcript?: string | undefined;
|
|
222
|
+
anchor?: boolean | undefined;
|
|
223
|
+
excerpt?: string | undefined;
|
|
224
|
+
matched_in?: "context" | "file" | "filename" | "picture" | "text" | "transcript" | undefined;
|
|
225
|
+
score?: number | undefined;
|
|
226
|
+
match?: "beginnings" | "corrected" | "words" | undefined;
|
|
227
|
+
corrections?: {
|
|
228
|
+
from: string;
|
|
229
|
+
to: string[];
|
|
230
|
+
}[] | undefined;
|
|
231
|
+
found_in?: "archive" | "both" | "server" | undefined;
|
|
232
|
+
discovery?: {
|
|
233
|
+
coverage: number;
|
|
234
|
+
matched_terms: string[];
|
|
235
|
+
missing_terms: string[];
|
|
236
|
+
parent?: string | undefined;
|
|
237
|
+
} | undefined;
|
|
238
|
+
context?: {
|
|
239
|
+
ref: string;
|
|
240
|
+
timestamp: string;
|
|
241
|
+
sender_name: string | null;
|
|
242
|
+
text: string;
|
|
243
|
+
}[] | undefined;
|
|
244
|
+
outgoing: boolean | null;
|
|
245
|
+
attachments: {
|
|
246
|
+
message?: string | undefined;
|
|
247
|
+
kind: string;
|
|
248
|
+
position?: number | undefined;
|
|
249
|
+
url?: string | undefined;
|
|
250
|
+
name?: string | undefined;
|
|
251
|
+
title?: string | undefined;
|
|
252
|
+
mime?: string | undefined;
|
|
253
|
+
size?: number | undefined;
|
|
254
|
+
width?: number | undefined;
|
|
255
|
+
height?: number | undefined;
|
|
256
|
+
duration?: number | undefined;
|
|
257
|
+
text?: string | undefined;
|
|
258
|
+
extraction?: {
|
|
259
|
+
origin: string;
|
|
260
|
+
extractor: string;
|
|
261
|
+
chars: number;
|
|
262
|
+
error?: string | undefined;
|
|
263
|
+
} | undefined;
|
|
264
|
+
local_path?: string | undefined;
|
|
265
|
+
buttons?: {
|
|
266
|
+
kind: "app" | "callback" | "chat" | "clipboard" | "contact" | "link" | "location" | "message" | "other";
|
|
267
|
+
text: string;
|
|
268
|
+
url?: string | undefined;
|
|
269
|
+
}[][] | undefined;
|
|
270
|
+
}[];
|
|
271
|
+
reply_to: {
|
|
272
|
+
id: string;
|
|
273
|
+
sender_id: string | null;
|
|
274
|
+
sender_name: string | null;
|
|
275
|
+
timestamp: string | null;
|
|
276
|
+
text: string;
|
|
277
|
+
attachments: {
|
|
278
|
+
message?: string | undefined;
|
|
279
|
+
kind: string;
|
|
280
|
+
position?: number | undefined;
|
|
281
|
+
url?: string | undefined;
|
|
282
|
+
name?: string | undefined;
|
|
283
|
+
title?: string | undefined;
|
|
284
|
+
mime?: string | undefined;
|
|
285
|
+
size?: number | undefined;
|
|
286
|
+
width?: number | undefined;
|
|
287
|
+
height?: number | undefined;
|
|
288
|
+
duration?: number | undefined;
|
|
289
|
+
text?: string | undefined;
|
|
290
|
+
extraction?: {
|
|
291
|
+
origin: string;
|
|
292
|
+
extractor: string;
|
|
293
|
+
chars: number;
|
|
294
|
+
error?: string | undefined;
|
|
295
|
+
} | undefined;
|
|
296
|
+
local_path?: string | undefined;
|
|
297
|
+
buttons?: {
|
|
298
|
+
kind: "app" | "callback" | "chat" | "clipboard" | "contact" | "link" | "location" | "message" | "other";
|
|
299
|
+
text: string;
|
|
300
|
+
url?: string | undefined;
|
|
301
|
+
}[][] | undefined;
|
|
302
|
+
}[];
|
|
303
|
+
outgoing: boolean | null;
|
|
304
|
+
} | null;
|
|
305
|
+
reply_to_id?: string | undefined;
|
|
306
|
+
forwarded_from: {
|
|
307
|
+
id: string;
|
|
308
|
+
sender_id: string | null;
|
|
309
|
+
sender_name: string | null;
|
|
310
|
+
timestamp: string | null;
|
|
311
|
+
text: string;
|
|
312
|
+
attachments: {
|
|
313
|
+
message?: string | undefined;
|
|
314
|
+
kind: string;
|
|
315
|
+
position?: number | undefined;
|
|
316
|
+
url?: string | undefined;
|
|
317
|
+
name?: string | undefined;
|
|
318
|
+
title?: string | undefined;
|
|
319
|
+
mime?: string | undefined;
|
|
320
|
+
size?: number | undefined;
|
|
321
|
+
width?: number | undefined;
|
|
322
|
+
height?: number | undefined;
|
|
323
|
+
duration?: number | undefined;
|
|
324
|
+
text?: string | undefined;
|
|
325
|
+
extraction?: {
|
|
326
|
+
origin: string;
|
|
327
|
+
extractor: string;
|
|
328
|
+
chars: number;
|
|
329
|
+
error?: string | undefined;
|
|
330
|
+
} | undefined;
|
|
331
|
+
local_path?: string | undefined;
|
|
332
|
+
buttons?: {
|
|
333
|
+
kind: "app" | "callback" | "chat" | "clipboard" | "contact" | "link" | "location" | "message" | "other";
|
|
334
|
+
text: string;
|
|
335
|
+
url?: string | undefined;
|
|
336
|
+
}[][] | undefined;
|
|
337
|
+
}[];
|
|
338
|
+
outgoing: boolean | null;
|
|
339
|
+
} | null;
|
|
340
|
+
thread_id?: string | undefined;
|
|
341
|
+
thread_root_id?: string | undefined;
|
|
342
|
+
reactions?: {
|
|
343
|
+
counts: {
|
|
344
|
+
reaction: string;
|
|
345
|
+
count: number;
|
|
346
|
+
}[];
|
|
347
|
+
mine: string | null;
|
|
348
|
+
total: number;
|
|
349
|
+
} | null | undefined;
|
|
350
|
+
scheduled_for?: string | undefined;
|
|
351
|
+
starred?: true | undefined;
|
|
352
|
+
delivery?: "delivered" | "read" | undefined;
|
|
353
|
+
email?: {
|
|
354
|
+
subject: string | null;
|
|
355
|
+
from: {
|
|
356
|
+
name: string | null;
|
|
357
|
+
address: string;
|
|
358
|
+
ref: string | null;
|
|
359
|
+
} | null;
|
|
360
|
+
to: {
|
|
361
|
+
name: string | null;
|
|
362
|
+
address: string;
|
|
363
|
+
ref: string | null;
|
|
364
|
+
}[];
|
|
365
|
+
cc: {
|
|
366
|
+
name: string | null;
|
|
367
|
+
address: string;
|
|
368
|
+
ref: string | null;
|
|
369
|
+
}[];
|
|
370
|
+
bcc: {
|
|
371
|
+
name: string | null;
|
|
372
|
+
address: string;
|
|
373
|
+
ref: string | null;
|
|
374
|
+
}[];
|
|
375
|
+
reply_addresses: {
|
|
376
|
+
name: string | null;
|
|
377
|
+
address: string;
|
|
378
|
+
ref: string | null;
|
|
379
|
+
}[];
|
|
380
|
+
labels: string[];
|
|
381
|
+
thread: string;
|
|
382
|
+
read: boolean | null;
|
|
383
|
+
flagged: boolean | null;
|
|
384
|
+
sender_score?: {
|
|
385
|
+
score: number;
|
|
386
|
+
signals: string[];
|
|
387
|
+
demoted?: true | undefined;
|
|
388
|
+
} | undefined;
|
|
389
|
+
} | undefined;
|
|
390
|
+
provider_metadata?: {
|
|
391
|
+
[x: string]: unknown;
|
|
392
|
+
} | undefined;
|
|
393
|
+
}[] | undefined;
|
|
204
394
|
scheduled_for?: string | undefined;
|
|
205
395
|
}>;
|
|
206
396
|
/**
|
|
@@ -4,12 +4,16 @@ import { nextStep } from "../steps.js";
|
|
|
4
4
|
import { messageItem } from "./message-items.js";
|
|
5
5
|
/**
|
|
6
6
|
* A send, forward or edit: the message as it now stands, with its `operation_id` — for a send, the id a repeat
|
|
7
|
-
* passes as `--operation-id` so it cannot make a second copy.
|
|
7
|
+
* passes as `--operation-id` so it cannot make a second copy. An album adds `messages`, every one it made, in order;
|
|
8
|
+
* `message` stays its first, so a reader of one message reads an album as before. A scheduled message gets a new id when it goes out,
|
|
8
9
|
* so its next step is the list that shows it, never a retry.
|
|
9
10
|
*/
|
|
10
|
-
export const writtenAnswer = ({ operationId, sendId, message, scheduledFor }, reader) => itemOf({
|
|
11
|
+
export const writtenAnswer = ({ operationId, sendId, message, messages, scheduledFor }, reader) => itemOf({
|
|
11
12
|
operation_id: sendId ?? operationId,
|
|
12
13
|
message: messageItem(message, reader),
|
|
14
|
+
...(messages === undefined || messages.length < 2
|
|
15
|
+
? {}
|
|
16
|
+
: { messages: messages.map((one) => messageItem(one, reader)) }),
|
|
13
17
|
...(scheduledFor === undefined ? {} : { scheduled_for: scheduledFor }),
|
|
14
18
|
}, scheduledFor === undefined ? {} : { next: [nextStep("messages.scheduled", { args: { chat: message.chatId } })] });
|
|
15
19
|
/**
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { CliError } from "@wirecat/cli-base";
|
|
2
2
|
import { annotate } from "@wirecat/cli-base/commands";
|
|
3
|
-
import { Command } from "commander";
|
|
3
|
+
import { Command, Option } from "commander";
|
|
4
4
|
import { sendTime } from "../../domain/send-time.js";
|
|
5
5
|
import { threadIdOf } from "../../domain/thread.js";
|
|
6
6
|
import { typedSendAs } from "../../sends/send-as.js";
|
|
@@ -15,6 +15,9 @@ import { readAll } from "./stdin.js";
|
|
|
15
15
|
* of what this profile tried to send, and it never holds the text.
|
|
16
16
|
*/
|
|
17
17
|
export const HTML_HELP = "the text is HTML: <b>, <i>, <a href>, <code>";
|
|
18
|
+
const collect = (value, previous) => [...previous, value];
|
|
19
|
+
/** The empty list as its default is what tells the MCP tool to take a list for it. */
|
|
20
|
+
const repeatable = (flags, description) => new Option(flags, description).argParser(collect).default([], "none");
|
|
18
21
|
export const sendCommand = (messenger) => {
|
|
19
22
|
const send = annotate(new Command("send"), {
|
|
20
23
|
examples: [`${messenger.app.command} personal messages send "Book club" "The meeting starts at 10."`],
|
|
@@ -38,9 +41,9 @@ export const sendCommand = (messenger) => {
|
|
|
38
41
|
send
|
|
39
42
|
.option("--no-preview", "no preview card for a link in the text")
|
|
40
43
|
.option("--md", "read this messenger's Markdown; see its formatting guide for supported syntax")
|
|
41
|
-
.
|
|
42
|
-
.
|
|
43
|
-
.option("--as-file", "send
|
|
44
|
+
.addOption(repeatable("--file <file>", "attach a file; the text becomes its caption; repeat it for an album"))
|
|
45
|
+
.addOption(repeatable("--photo <file>", "attach a .jpg, .png or .webp as a photo; the text becomes its caption; repeat it for an album"))
|
|
46
|
+
.option("--as-file", "send each --file as a file to download, a video included")
|
|
44
47
|
.option("--voice <file>", "send an Ogg Opus file as a voice message, alone, with no text")
|
|
45
48
|
.addOption(ownerOnlyOption("--allow-any-file", "send a file even from credential folders or this CLI's own folders"));
|
|
46
49
|
if (messenger.scheduledSends !== false)
|
|
@@ -76,8 +79,8 @@ const sendText = async (command, messenger, chat, text) => {
|
|
|
76
79
|
throw new CliError("validation_error", "--comment-to needs the post's message id");
|
|
77
80
|
const read = { app: messenger.app, env: context.env, anyFile: allowAnyFile === true };
|
|
78
81
|
const attachments = await readAttachments({
|
|
79
|
-
|
|
80
|
-
|
|
82
|
+
photo,
|
|
83
|
+
file,
|
|
81
84
|
...(voice === undefined ? {} : { voice }),
|
|
82
85
|
...(text === undefined ? {} : { text }),
|
|
83
86
|
asFile: asFile === true,
|
|
@@ -76,7 +76,6 @@ export const modelsCommand = (messenger) => {
|
|
|
76
76
|
});
|
|
77
77
|
});
|
|
78
78
|
reachesOtherService(annotate(audio.command("download"), {
|
|
79
|
-
mcp: false,
|
|
80
79
|
effects: FETCH,
|
|
81
80
|
output: { entity: "model" },
|
|
82
81
|
examples: [`${tool} models audio download parakeet-v3`],
|
|
@@ -124,7 +123,6 @@ export const modelsCommand = (messenger) => {
|
|
|
124
123
|
});
|
|
125
124
|
});
|
|
126
125
|
reachesOtherService(annotate(text.command("download"), {
|
|
127
|
-
mcp: false,
|
|
128
126
|
effects: FETCH,
|
|
129
127
|
output: { entity: "model" },
|
|
130
128
|
examples: [`${tool} models text download ${DEFAULT_TEXT_MODEL}`],
|
|
@@ -197,7 +195,6 @@ export const imageModelsCommand = (messenger) => {
|
|
|
197
195
|
});
|
|
198
196
|
});
|
|
199
197
|
reachesOtherService(annotate(image.command("download"), {
|
|
200
|
-
mcp: false,
|
|
201
198
|
effects: FETCH,
|
|
202
199
|
output: { entity: "model" },
|
|
203
200
|
examples: [`${tool} images models download ${DEFAULT_IMAGE_MODEL}`],
|