@wirecat/cli-core 0.400.0 → 0.401.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 +29 -0
- package/README.md +1 -1
- package/dist/cli/bot/store.js +1 -1
- 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/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 +8 -4
- 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/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 +1 -1
- package/dist/sends/permissions.js +31 -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/package.json +2 -2
- package/parity.json +6 -3
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,22 @@ shape of this file.
|
|
|
7
7
|
|
|
8
8
|
## Unreleased
|
|
9
9
|
|
|
10
|
+
## 0.401.0 — 24.10.2026
|
|
11
|
+
|
|
12
|
+
### Changed — may break callers
|
|
13
|
+
|
|
14
|
+
- **`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.
|
|
15
|
+
|
|
16
|
+
- **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.
|
|
17
|
+
|
|
18
|
+
### Fixed
|
|
19
|
+
|
|
20
|
+
- **`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.
|
|
21
|
+
|
|
22
|
+
### Added
|
|
23
|
+
|
|
24
|
+
- **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`.
|
|
25
|
+
|
|
10
26
|
## 0.400.0 — 24.10.2026
|
|
11
27
|
|
|
12
28
|
### Fixed
|
|
@@ -21,6 +37,17 @@ shape of this file.
|
|
|
21
37
|
|
|
22
38
|
### Added
|
|
23
39
|
|
|
40
|
+
- **Album sends.** `messages send` takes `--photo` and `--file` more than once, and its MCP tool takes a list for
|
|
41
|
+
`photo` and `file`; together they go as one album, photos first. Each photo or file counts as one send toward the
|
|
42
|
+
hourly limit. An adapter returns every message of the album as `Sent.messages`, and `--json` answers with a
|
|
43
|
+
`messages` list beside `message`, which stays the first. A messenger that cannot send an album refuses it before
|
|
44
|
+
anything goes. A single attachment sends and answers as before.
|
|
45
|
+
|
|
46
|
+
- **Mirror runner for folder sync.** `syncMirrors` syncs each of a CLI's mirrors both ways under one lock and reports
|
|
47
|
+
a partly failed mirror as a `mirror.partial` issue; `fileMirrorState`, `mirrorId`, `mirrorStatus` and
|
|
48
|
+
`conflictReport` are the state file, id, local plan and conflict report drive-cli's `mirrors` used, moved here so
|
|
49
|
+
other CLIs can mirror folders and a watcher can reuse the same run.
|
|
50
|
+
|
|
24
51
|
- **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
52
|
|
|
26
53
|
- **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 +106,8 @@ shape of this file.
|
|
|
79
106
|
|
|
80
107
|
### Changed — may break callers
|
|
81
108
|
|
|
109
|
+
- **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.
|
|
110
|
+
|
|
82
111
|
- **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
112
|
|
|
84
113
|
- **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/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")
|
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}`],
|
|
@@ -85,7 +85,6 @@ export const chatDeletionCommands = (messenger) => [
|
|
|
85
85
|
annotate(new Command("delete"), {
|
|
86
86
|
output: { entity: "chat_removal" },
|
|
87
87
|
effects: REMOTE_WRITE,
|
|
88
|
-
mcp: false,
|
|
89
88
|
examples: [`${messenger.app.command} personal chats delete "Book club"`],
|
|
90
89
|
})
|
|
91
90
|
.description("delete a chat from this account; the others in it keep it and its messages")
|
|
@@ -98,7 +97,6 @@ export const chatDeletionCommands = (messenger) => [
|
|
|
98
97
|
annotate(new Command("clear"), {
|
|
99
98
|
output: { entity: "chat_removal" },
|
|
100
99
|
effects: REMOTE_WRITE,
|
|
101
|
-
mcp: false,
|
|
102
100
|
examples: [`${messenger.app.command} personal chats clear "Book club"`],
|
|
103
101
|
})
|
|
104
102
|
.description("delete every message in a chat for this account; the others in it keep theirs")
|
|
@@ -113,7 +113,7 @@ const notes = (found, pretty, renderer) => {
|
|
|
113
113
|
renderer.note(`${chat.title ?? chat.id}: its admins are not known, so only your answers count`);
|
|
114
114
|
if (found.tasks && found.tasks.added + found.tasks.closed > 0)
|
|
115
115
|
renderer.note(`tasks: ${found.tasks.added} opened, ${found.tasks.closed} closed by the rules` +
|
|
116
|
-
(found.tasks.review > 0 ? `, ${found.tasks.review} pair(s) to review — tasks duplicates` : ""));
|
|
116
|
+
(found.tasks.review > 0 ? `, ${found.tasks.review} pair(s) to review — tasks duplicates list` : ""));
|
|
117
117
|
if (found.partial && pretty)
|
|
118
118
|
renderer.warn(PARTIAL_NOTE);
|
|
119
119
|
if (found.offline && pretty)
|
|
@@ -192,7 +192,7 @@ export const scheduleCommand = (messenger) => {
|
|
|
192
192
|
.join("\n");
|
|
193
193
|
});
|
|
194
194
|
});
|
|
195
|
-
annotate(command.command("run"), { effects: REMOTE_WRITE
|
|
195
|
+
annotate(command.command("run"), { effects: REMOTE_WRITE })
|
|
196
196
|
.description("run a schedule now, as its timer would, and wait for it")
|
|
197
197
|
.argument("<name>")
|
|
198
198
|
.action(async function (name) {
|
|
@@ -216,7 +216,7 @@ export const scheduleCommand = (messenger) => {
|
|
|
216
216
|
rmSync(file, { force: true });
|
|
217
217
|
say({ name, removed: true }, [`Removed ${name}.`]);
|
|
218
218
|
});
|
|
219
|
-
annotate(command.command("exec"), { effects: REMOTE_WRITE
|
|
219
|
+
annotate(command.command("exec"), { effects: REMOTE_WRITE })
|
|
220
220
|
.description("what a timer runs, given the schedule's file; to run one by hand, use run")
|
|
221
221
|
.argument("<file>")
|
|
222
222
|
.action(async function (file) {
|
|
@@ -185,7 +185,6 @@ export const serverCommand = (messenger, options = {}) => {
|
|
|
185
185
|
const withIdle = (sub) => options.idle ? sub.option("--idle <duration>", "stop after this long with nobody using it — 15m, 1h") : sub;
|
|
186
186
|
withIdle(destroysNothing(annotate(command.command("start"), {
|
|
187
187
|
effects: LOCAL_WRITE,
|
|
188
|
-
mcp: false,
|
|
189
188
|
examples: [`${app.command} personal server start`],
|
|
190
189
|
}))
|
|
191
190
|
.summary("start this profile's background server")
|
|
@@ -194,7 +193,6 @@ export const serverCommand = (messenger, options = {}) => {
|
|
|
194
193
|
});
|
|
195
194
|
destroysNothing(annotate(command.command("stop"), {
|
|
196
195
|
effects: LOCAL_WRITE,
|
|
197
|
-
mcp: false,
|
|
198
196
|
examples: [`${app.command} personal server stop`],
|
|
199
197
|
}))
|
|
200
198
|
.description("stop this profile's serve — through the unit if it runs under one")
|
|
@@ -202,7 +200,6 @@ export const serverCommand = (messenger, options = {}) => {
|
|
|
202
200
|
await stop(prepare(this));
|
|
203
201
|
});
|
|
204
202
|
withIdle(destroysNothing(annotate(command.command("restart"), {
|
|
205
|
-
mcp: false,
|
|
206
203
|
effects: LOCAL_WRITE,
|
|
207
204
|
examples: [`${app.command} personal server restart`],
|
|
208
205
|
})).description("stop it and start it again")).action(async function () {
|
|
@@ -2,9 +2,9 @@ import { Command } from "commander";
|
|
|
2
2
|
import type { Messenger } from "./context.js";
|
|
3
3
|
/** `doctor`'s short summary of the store. Must answer for a broken file, so an error is a field. */
|
|
4
4
|
export declare const storeSummary: (env: NodeJS.ProcessEnv) => Promise<{
|
|
5
|
-
error?: undefined;
|
|
6
5
|
path: string;
|
|
7
6
|
exists: boolean;
|
|
7
|
+
error?: undefined;
|
|
8
8
|
} | {
|
|
9
9
|
path: string;
|
|
10
10
|
exists: boolean;
|