@wirecat/cli-core 0.398.0 → 0.399.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 +24 -0
- package/dist/cli/analysis-choice.d.ts +1 -0
- package/dist/cli/analysis-choice.js +3 -0
- package/dist/cli/bot/admins.js +14 -4
- package/dist/cli/bot/command.js +38 -16
- package/dist/cli/bot/examples.d.ts +3 -0
- package/dist/cli/bot/examples.js +2 -0
- package/dist/cli/bot/mcp.js +4 -1
- package/dist/cli/bot/messages.js +17 -6
- package/dist/cli/bot/moderation.js +16 -4
- package/dist/cli/bot/people.js +16 -4
- package/dist/cli/bot/setup.js +27 -8
- package/dist/cli/bot/watch.js +7 -1
- package/dist/cli/embedding-choice.d.ts +2 -1
- package/dist/cli/embedding-choice.js +4 -1
- package/dist/cli/messenger/admin-commands.js +18 -9
- package/dist/cli/messenger/catch-up-answers.d.ts +2 -1
- package/dist/cli/messenger/catch-up-answers.js +6 -2
- package/dist/cli/messenger/chats-stats-command.js +1 -1
- package/dist/cli/messenger/contacts-command.js +2 -2
- package/dist/cli/messenger/context.d.ts +2 -0
- package/dist/cli/messenger/conversations-command.js +27 -13
- package/dist/cli/messenger/hearing-command.d.ts +1 -1
- package/dist/cli/messenger/hearing-command.js +1 -1
- package/dist/cli/messenger/inbox.js +6 -4
- package/dist/cli/messenger/messages-stats-command.js +1 -1
- package/dist/cli/messenger/metadata-command.js +1 -1
- package/dist/cli/messenger/private-people-command.js +5 -3
- package/dist/cli/messenger/replies-edit-command.d.ts +1 -1
- package/dist/cli/messenger/replies-edit-command.js +13 -5
- package/dist/cli/messenger/retention-command.js +1 -1
- package/dist/cli/messenger/review.js +6 -4
- package/dist/cli/messenger/searches-command.js +1 -1
- package/dist/cli/messenger/serve-relay.d.ts +1 -0
- package/dist/cli/messenger/stats-command.js +1 -1
- package/dist/cli/messenger/tags-command.js +11 -5
- package/dist/cli/messenger/transcribe-command.js +1 -1
- package/dist/mcp/prompts.js +8 -2
- package/package.json +3 -3
- package/parity.json +68 -42
|
@@ -6,7 +6,10 @@ import { isLocal, remoteModel } from "../embeddings/remote.js";
|
|
|
6
6
|
import { readOnlyLockOf, readOnlyRefusal } from "../ports/app.js";
|
|
7
7
|
import { typedCommand } from "../runs/scope.js";
|
|
8
8
|
/** A local model id, or a remote model with its key from `models text key set`. */
|
|
9
|
-
export const embeddingChoice = ({ model, provider, baseUrl, dims, concurrency }, app, settings, env, { needKey = true, keyring } = {}) => {
|
|
9
|
+
export const embeddingChoice = ({ model, provider, embeddingProvider, baseUrl, dims, concurrency }, app, settings, env, { needKey = true, keyring } = {}) => {
|
|
10
|
+
if (embeddingProvider !== undefined && provider !== undefined)
|
|
11
|
+
throw new CliError("validation_error", "give --embedding-provider or its legacy --provider spelling, not both");
|
|
12
|
+
provider = embeddingProvider ?? provider;
|
|
10
13
|
const flagsChooseProvider = (provider !== undefined && provider !== (settings.embeddingProvider ?? "local")) ||
|
|
11
14
|
(baseUrl !== undefined && baseUrl.replace(/\/+$/, "") !== settings.embeddingBaseUrl?.replace(/\/+$/, ""));
|
|
12
15
|
provider ??= flagsChooseProvider ? "openai" : (settings.embeddingProvider ?? "local");
|
|
@@ -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 { parseDuration } from "../../domain/duration.js";
|
|
5
5
|
import { ADMIN_RIGHTS, GROUP_SETTINGS, } from "../../domain/models.js";
|
|
6
6
|
import { readUpload, typesText } from "../../sends/upload.js";
|
|
@@ -22,19 +22,19 @@ const SETTING_FLAGS = {
|
|
|
22
22
|
onlyAdminsSend: ["only-admins-send <on|off>", "only admins may send messages"],
|
|
23
23
|
onlyAdminsEditInfo: ["only-admins-edit-info <on|off>", "only admins may change the name, photo and description"],
|
|
24
24
|
disappearingSeconds: [
|
|
25
|
-
"disappear-
|
|
25
|
+
"disappear-after <duration|off>",
|
|
26
26
|
"new messages disappear this long after sending: 24h, 7d, 90d; off keeps them",
|
|
27
27
|
],
|
|
28
28
|
};
|
|
29
29
|
const flagOf = (key) => `--${SETTING_FLAGS[key][0].split(" ")[0]}`;
|
|
30
|
-
/** Where commander puts the flag's value: `--disappear-
|
|
30
|
+
/** Where commander puts the flag's value: `--disappear-after` is `disappearAfter`, not the setting's own name. */
|
|
31
31
|
const optionKey = (key) => flagOf(key)
|
|
32
32
|
.slice(2)
|
|
33
33
|
.replace(/-(\w)/g, (_, letter) => letter.toUpperCase());
|
|
34
34
|
const settingsOf = (keys, options) => {
|
|
35
35
|
const changes = {};
|
|
36
36
|
for (const key of keys) {
|
|
37
|
-
const value = options[optionKey(key)];
|
|
37
|
+
const value = options[optionKey(key)] ?? (key === "disappearingSeconds" ? options.disappearTime : undefined);
|
|
38
38
|
if (value === undefined)
|
|
39
39
|
continue;
|
|
40
40
|
if (key === "disappearingSeconds") {
|
|
@@ -67,8 +67,16 @@ const updateCommand = (messenger) => {
|
|
|
67
67
|
update.option("--photo <file>", `a new photo for it — ${photoHelp(messenger)}`);
|
|
68
68
|
if (messenger.groupPhotoRemoval === true)
|
|
69
69
|
update.option("--remove-photo", "take its photo away; not with --photo");
|
|
70
|
-
for (const key of keys)
|
|
71
|
-
|
|
70
|
+
for (const key of keys) {
|
|
71
|
+
const option = new Option(`--${SETTING_FLAGS[key][0]}`, SETTING_FLAGS[key][1]);
|
|
72
|
+
if (key === "disappearingSeconds")
|
|
73
|
+
option.conflicts("disappearTime");
|
|
74
|
+
update.addOption(option);
|
|
75
|
+
}
|
|
76
|
+
if (keys.includes("disappearingSeconds"))
|
|
77
|
+
update.addOption(new Option("--disappear-time <duration|off>", "compatibility alias for --disappear-after")
|
|
78
|
+
.hideHelp()
|
|
79
|
+
.conflicts("disappearAfter"));
|
|
72
80
|
return update.action(async function (chat) {
|
|
73
81
|
const context = messengerContext(this, messenger);
|
|
74
82
|
const { title, description, photo, removePhoto, ...rest } = this.opts();
|
|
@@ -210,6 +218,7 @@ const requestsCommand = (messenger) => {
|
|
|
210
218
|
renderAnswer(this, context, body, lines(({ person_id, name, username, requested_at }) => [person_id, name ?? "", username ? `@${username}` : "", requested_at ?? ""].join(" ")));
|
|
211
219
|
}));
|
|
212
220
|
const everyone = messenger.joinRequestsAll !== false;
|
|
221
|
+
const byLink = everyone && messenger.joinRequestsByLink !== false;
|
|
213
222
|
for (const [verb, accept, help] of [
|
|
214
223
|
["accept", true, "let them in; the group sees them join"],
|
|
215
224
|
["decline", false, "turn the request away"],
|
|
@@ -219,9 +228,9 @@ const requestsCommand = (messenger) => {
|
|
|
219
228
|
.argument("<chat>", messenger.chatArgument)
|
|
220
229
|
.argument(everyone ? "[person]" : "<person>", "who asked: an id from `chats requests list`");
|
|
221
230
|
if (everyone)
|
|
222
|
-
answer
|
|
223
|
-
|
|
224
|
-
|
|
231
|
+
answer.option("--all", "every pending request, counted against the hourly limit first");
|
|
232
|
+
if (byLink)
|
|
233
|
+
answer.option("--link <link>", "with --all: only the requests made by this invite link");
|
|
225
234
|
requests.addCommand(answer.action(async function (chat, person) {
|
|
226
235
|
const context = messengerContext(this, messenger);
|
|
227
236
|
const { all, link } = this.opts();
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Meta } from "@wirecat/cli-base/standards";
|
|
2
|
-
import type { Inbox, Review } from "../../domain/models.js";
|
|
2
|
+
import type { ChatKind, Inbox, Review } from "../../domain/models.js";
|
|
3
3
|
import { type Hearing } from "../../speech/hearing.js";
|
|
4
4
|
import type { AccountKey } from "../../store/store.js";
|
|
5
5
|
import { type QueryWords } from "../list-query.js";
|
|
@@ -11,6 +11,7 @@ export declare const REVIEW_QUERY: import("@wirecat/cli-base/query").QueryRegist
|
|
|
11
11
|
export declare const catchUpQuery: (words: QueryWords, registry: typeof INBOX_QUERY, command: string) => {
|
|
12
12
|
since?: number;
|
|
13
13
|
chat?: string;
|
|
14
|
+
kinds?: ChatKind[];
|
|
14
15
|
meta?: Partial<Meta>;
|
|
15
16
|
};
|
|
16
17
|
export declare const inboxAnswer: (inbox: Inbox, hearing: Hearing | undefined, reader: AccountKey, transcribe: boolean, meta?: Partial<Meta>) => import("../envelope.js").ListBody<{
|
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
import { defineQuery, queryError } from "@wirecat/cli-base/query";
|
|
2
|
+
import { kindsOf } from "../../services/inbox.js";
|
|
2
3
|
import { heard, hearingMissing } from "../../speech/hearing.js";
|
|
3
4
|
import { listOf } from "../envelope.js";
|
|
4
5
|
import { listQuery, nativeField, nativeTerms, timeBounds, typedQuery } from "../list-query.js";
|
|
5
6
|
import { nextStep } from "../steps.js";
|
|
6
7
|
import { messageItem } from "./message-items.js";
|
|
7
8
|
const date = nativeField({ name: "date", type: "time", operators: ["range"], example: "date>2h" });
|
|
9
|
+
const kind = nativeField({ name: "kind", type: "kw", operators: ["term", "phrase"], example: "kind:group,channel" });
|
|
8
10
|
/** Where `inbox` starts reading: everything after a time. */
|
|
9
|
-
export const INBOX_QUERY = defineQuery({ entity: "message", backend: "native", fields: [date] });
|
|
11
|
+
export const INBOX_QUERY = defineQuery({ entity: "message", backend: "native", fields: [date, kind] });
|
|
10
12
|
/** Where `review` starts, and the one chat it reads. */
|
|
11
13
|
export const REVIEW_QUERY = defineQuery({
|
|
12
14
|
entity: "message",
|
|
13
15
|
backend: "native",
|
|
14
|
-
fields: [date, nativeField({ name: "chat", type: "kw", operators: ["term", "phrase"], example: "chat:7" })],
|
|
16
|
+
fields: [date, kind, nativeField({ name: "chat", type: "kw", operators: ["term", "phrase"], example: "chat:7" })],
|
|
15
17
|
});
|
|
16
18
|
/** The query's start and chat. A catch-up reads forward from one point, so an end is refused. */
|
|
17
19
|
export const catchUpQuery = (words, registry, command) => {
|
|
@@ -23,9 +25,11 @@ export const catchUpQuery = (words, registry, command) => {
|
|
|
23
25
|
command,
|
|
24
26
|
});
|
|
25
27
|
const chat = terms.get("chat")?.value;
|
|
28
|
+
const kinds = terms.get("kind")?.value;
|
|
26
29
|
return {
|
|
27
30
|
...(since === undefined ? {} : { since }),
|
|
28
31
|
...(chat === undefined ? {} : { chat }),
|
|
32
|
+
...(kinds === undefined ? {} : { kinds: kindsOf(kinds, "kind:") }),
|
|
29
33
|
...(meta === undefined ? {} : { meta }),
|
|
30
34
|
};
|
|
31
35
|
};
|
|
@@ -14,7 +14,7 @@ export const statsCommand = (messenger) => annotate(new Command("show"), { effec
|
|
|
14
14
|
`joins and leaves — counted from the local store; ${messenger.history === "store" ? "joins and leaves too" : "joins and leaves are asked of the messenger"}`)
|
|
15
15
|
.argument("<chat>", messenger.chatArgument)
|
|
16
16
|
.option("--since-time <time>", `ISO 8601, or 2h / 1d ago; ${EVENTS_DAYS} days ago if not given`)
|
|
17
|
-
.option("--by <
|
|
17
|
+
.option("--by <group>", "also one row per calendar day or week (weeks start on Monday)", periodOf)
|
|
18
18
|
.option("--timezone <zone>", "the IANA timezone for calendar days")
|
|
19
19
|
.action(async function (chat) {
|
|
20
20
|
const context = messengerContext(this, messenger);
|
|
@@ -297,8 +297,8 @@ export const contactsCommand = (messenger) => {
|
|
|
297
297
|
link: '"Alex Example" zoom:101',
|
|
298
298
|
list: "--limit 10",
|
|
299
299
|
lookup: "",
|
|
300
|
-
"notes add": '"Alex Example" --file ./note.txt',
|
|
301
|
-
"notes edit": '"Alex Example" 1 --revision 1 --file ./note.txt',
|
|
300
|
+
"notes add": '"Alex Example" --text-file ./note.txt',
|
|
301
|
+
"notes edit": '"Alex Example" 1 --revision 1 --text-file ./note.txt',
|
|
302
302
|
"notes list": '"Alex Example"',
|
|
303
303
|
"notes remove": '"Alex Example" 1',
|
|
304
304
|
"notes show": '"Alex Example" 1',
|
|
@@ -158,6 +158,8 @@ export interface Messenger extends ServiceMessenger {
|
|
|
158
158
|
inviteLinkUpdate?: boolean;
|
|
159
159
|
/** Whether every pending join request is answered at once — `chats requests accept --all`; yes when unset. */
|
|
160
160
|
joinRequestsAll?: boolean;
|
|
161
|
+
/** Whether `--all` can take only the requests made by one invite link — `--link`; yes when unset. */
|
|
162
|
+
joinRequestsByLink?: boolean;
|
|
161
163
|
/** Whether a channel post can be commented on — `messages send --comment-to`; yes when unset. */
|
|
162
164
|
channelComments?: boolean;
|
|
163
165
|
/** Whether people added can be shown the messages from before they came — `members add --history`; yes when unset. */
|
|
@@ -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 { analysisConsents } from "../../analysis/consents.js";
|
|
5
5
|
import { openAnalysis, providerIdentity } from "../../analysis/provider.js";
|
|
6
6
|
import { runAnalysis } from "../../analysis/runner.js";
|
|
@@ -39,7 +39,10 @@ export const conversationsCommand = (messenger) => {
|
|
|
39
39
|
"chat that changed since its build and every group never built; never asks the messenger")
|
|
40
40
|
.option("--chat <chat>", messenger.chatArgument)
|
|
41
41
|
.option("--analyze", "link batches using the configured analysis provider; requires --chat and remembers consent for this chat/provider")
|
|
42
|
-
.
|
|
42
|
+
.addOption(new Option("--analysis-provider <provider>", "analysis: agent, openai or anthropic").conflicts("provider"))
|
|
43
|
+
.addOption(new Option("--provider <provider>", "compatibility alias for --analysis-provider")
|
|
44
|
+
.hideHelp()
|
|
45
|
+
.conflicts("analysisProvider"))
|
|
43
46
|
.option("--model <model>", "analysis model; overrides analysis_model")
|
|
44
47
|
.option("--base-url <url>", "analysis API endpoint; overrides analysis_base_url")
|
|
45
48
|
.option("--size <n>", "analysis answer messages per batch, 10–200; default 50", positiveCount("--size"))
|
|
@@ -95,7 +98,8 @@ export const conversationsCommand = (messenger) => {
|
|
|
95
98
|
renderAnswer(this, context, itemOf(snakeKeys(result)));
|
|
96
99
|
return;
|
|
97
100
|
}
|
|
98
|
-
if (options.
|
|
101
|
+
if (options.analysisProvider !== undefined ||
|
|
102
|
+
options.provider !== undefined ||
|
|
99
103
|
options.model !== undefined ||
|
|
100
104
|
options.baseUrl !== undefined ||
|
|
101
105
|
options.size !== undefined ||
|
|
@@ -247,18 +251,19 @@ export const conversationsCommand = (messenger) => {
|
|
|
247
251
|
.summary("remove an agent's saved conversation-link answers")
|
|
248
252
|
.description("drop your agent's answers for a chat, or only one model's; messages are never touched")
|
|
249
253
|
.requiredOption("--chat <chat>", messenger.chatArgument)
|
|
250
|
-
.
|
|
254
|
+
.addOption(new Option("--answer-model <model>", "only the stored answers this model gave").conflicts("model"))
|
|
255
|
+
.addOption(new Option("--model <model>", "compatibility alias for --answer-model").hideHelp().conflicts("answerModel"))
|
|
251
256
|
.action(async function () {
|
|
252
|
-
const { chat, model } = this.opts();
|
|
257
|
+
const { chat, model, answerModel } = this.opts();
|
|
253
258
|
const context = messengerContext(this, messenger);
|
|
254
259
|
refuseLocalWrite(context, messenger.app.command, LINKS_KEY);
|
|
255
|
-
const cleared = await context.withServices((services) => services.conversations.clearAnswers(chat, model));
|
|
260
|
+
const cleared = await context.withServices((services) => services.conversations.clearAnswers(chat, answerModel ?? model));
|
|
256
261
|
renderAnswer(this, context, itemOf(cleared), () => `${cleared.cleared} answers dropped\n`);
|
|
257
262
|
});
|
|
258
263
|
const embed = withModelOptions(reachesOtherService(annotate(new Command("embed"), { effects: REMOTE_WRITE }))
|
|
259
264
|
.summary("prepare conversation vectors for meaning search")
|
|
260
265
|
.description("compute a vector for each chunk of a chat's conversations for search by meaning — on this machine, or " +
|
|
261
|
-
"with --provider through a service and your key; resumes where it stopped; without --chat, every " +
|
|
266
|
+
"with --embedding-provider through a service and your key; resumes where it stopped; without --chat, every " +
|
|
262
267
|
"built chat with chunks left, on this machine only")
|
|
263
268
|
.option("--chat <chat>", messenger.chatArgument))
|
|
264
269
|
.option("--threads <n>", "local: threads in all (default: min(8, cores))", positiveCount("--threads"))
|
|
@@ -324,7 +329,10 @@ export const conversationsCommand = (messenger) => {
|
|
|
324
329
|
const chat = chatOf(options);
|
|
325
330
|
const context = messengerContext(this, messenger);
|
|
326
331
|
refuseLocalWrite(context, messenger.app.command, EMBED_KEY);
|
|
327
|
-
const given = options.model !== undefined ||
|
|
332
|
+
const given = options.model !== undefined ||
|
|
333
|
+
options.embeddingProvider !== undefined ||
|
|
334
|
+
options.provider !== undefined ||
|
|
335
|
+
options.baseUrl !== undefined;
|
|
328
336
|
const model = given ? choiceOf(options, messenger, context, { needKey: false }) : undefined;
|
|
329
337
|
const cleared = await context.withServices((services) => services.embeddings.clear(chat, model));
|
|
330
338
|
renderAnswer(this, context, itemOf(cleared), () => `${cleared.cleared} vectors dropped\n`);
|
|
@@ -365,16 +373,19 @@ export const conversationsCommand = (messenger) => {
|
|
|
365
373
|
annotate(consents.command("revoke"), { effects: LOCAL_WRITE })
|
|
366
374
|
.description("forget analysis permissions so the next analysis asks again")
|
|
367
375
|
.option("--chat <chat>", "revoke only this chat's consents; defaults to every chat")
|
|
368
|
-
.
|
|
376
|
+
.addOption(new Option("--consent-provider <identity>", "exact provider identity from consents list; defaults to every provider").conflicts("provider"))
|
|
377
|
+
.addOption(new Option("--provider <identity>", "compatibility alias for --consent-provider")
|
|
378
|
+
.hideHelp()
|
|
379
|
+
.conflicts("consentProvider"))
|
|
369
380
|
.action(async function () {
|
|
370
|
-
const { chat, provider } = this.opts();
|
|
381
|
+
const { chat, provider, consentProvider } = this.opts();
|
|
371
382
|
const context = messengerContext(this, messenger);
|
|
372
383
|
refuseLocalWrite(context, messenger.app.command, LINKS_KEY);
|
|
373
384
|
await context.withStore(async (store, account) => {
|
|
374
385
|
const chatId = chat === undefined
|
|
375
386
|
? undefined
|
|
376
387
|
: (await servicesFor(storedDeps(messenger, store, account, context.guard)).conversations.batchStatus(chat, BATCH_SIZE.default)).chat;
|
|
377
|
-
await analysisConsents(store, account).revoke(chatId, provider);
|
|
388
|
+
await analysisConsents(store, account).revoke(chatId, consentProvider ?? provider);
|
|
378
389
|
});
|
|
379
390
|
renderAnswer(this, context, itemOf({ revoked: true }));
|
|
380
391
|
});
|
|
@@ -393,7 +404,10 @@ const chatOf = ({ chat }) => {
|
|
|
393
404
|
};
|
|
394
405
|
const withModelOptions = (command) => command
|
|
395
406
|
.option("--model <model>", "local: a model id from `models text list` (default: e5-small); remote: the provider's model")
|
|
396
|
-
.
|
|
407
|
+
.addOption(new Option("--embedding-provider <provider>", "embedding provider: local or openai; flags override profile settings").conflicts("provider"))
|
|
408
|
+
.addOption(new Option("--provider <provider>", "compatibility alias for --embedding-provider")
|
|
409
|
+
.hideHelp()
|
|
410
|
+
.conflicts("embeddingProvider"))
|
|
397
411
|
.option("--base-url <url>", "a server with OpenAI's /v1/embeddings: Gemini, Jina, or Ollama and LM Studio on this machine")
|
|
398
412
|
.option("--dims <n>", "remote: the vector size — needed with --base-url; shortens an OpenAI model's", positiveCount("--dims"));
|
|
399
413
|
/** How much one run over many chats may do: the owner's machine, not a background job, pays for it. */
|
|
@@ -412,7 +426,7 @@ const bounds = ({ maxChats, maxChunks }) => ({
|
|
|
412
426
|
/** Work nobody named chat by chat never sends chat text off the machine. */
|
|
413
427
|
const localOnly = (model, what) => {
|
|
414
428
|
if (typeof model !== "string") {
|
|
415
|
-
throw new CliError("validation_error", `${what} uses the model on this machine only — drop --provider and --base-url, or embed one chat with --chat`);
|
|
429
|
+
throw new CliError("validation_error", `${what} uses the model on this machine only — drop --embedding-provider and --base-url, or embed one chat with --chat`);
|
|
416
430
|
}
|
|
417
431
|
};
|
|
418
432
|
const renderRefreshed = (command, context, refreshed) => {
|
|
@@ -2,7 +2,7 @@ import type { Message } from "../../domain/models.js";
|
|
|
2
2
|
import { type Hearing } from "../../speech/hearing.js";
|
|
3
3
|
import type { Messenger, MessengerContext, ReadConnection } from "./context.js";
|
|
4
4
|
export declare const TRANSCRIBE_OPTION: readonly ["--transcribe", "turn voice messages not heard yet into text — by the messenger where it can, else by a model on this machine; can take minutes"];
|
|
5
|
-
export declare const MODEL_OPTION: readonly ["--model <
|
|
5
|
+
export declare const MODEL_OPTION: readonly ["--model <model>", "which downloaded speech model hears them, with --transcribe; `models audio list` shows them"];
|
|
6
6
|
/**
|
|
7
7
|
* Kept transcripts on every read; new ones with `--transcribe`, using the read's connection when
|
|
8
8
|
* supplied. It is released before local recognition. `undefined` when there is no voice message, and then no file is opened.
|
|
@@ -5,7 +5,7 @@ export const TRANSCRIBE_OPTION = [
|
|
|
5
5
|
"turn voice messages not heard yet into text — by the messenger where it can, else by a model on this machine; can take minutes",
|
|
6
6
|
];
|
|
7
7
|
export const MODEL_OPTION = [
|
|
8
|
-
"--model <
|
|
8
|
+
"--model <model>",
|
|
9
9
|
"which downloaded speech model hears them, with --transcribe; `models audio list` shows them",
|
|
10
10
|
];
|
|
11
11
|
/**
|
|
@@ -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 { renderMessages } from "../../render/messages.js";
|
|
5
5
|
import { CHAT_KINDS } from "../../services/chats.js";
|
|
6
6
|
import { kindsOf } from "../../services/inbox.js";
|
|
@@ -41,7 +41,7 @@ export const inboxCommand = (messenger) => annotate(new Command("inbox"), {
|
|
|
41
41
|
.option("--new", "what arrived since the last check, each message once — for scheduled runs")
|
|
42
42
|
.option("--limit <n>", "at most this many per chat, the newest", positiveCount("--limit"))
|
|
43
43
|
.option("--all", "muted and archived chats too — left out unless they mention you or reply to you")
|
|
44
|
-
.
|
|
44
|
+
.addOption(new Option("--kind <kinds>", `compatibility spelling for kind:; ${CHAT_KINDS.join(", ")}`).hideHelp())
|
|
45
45
|
.option(...TRANSCRIBE_OPTION)
|
|
46
46
|
.option(...MODEL_OPTION)
|
|
47
47
|
.addHelpText("after", "To mark a chat read, use `chats mark-read <chat>`. The other side sees it.")
|
|
@@ -51,8 +51,10 @@ export const inboxCommand = (messenger) => annotate(new Command("inbox"), {
|
|
|
51
51
|
const context = messengerContext(this, messenger);
|
|
52
52
|
const { app } = messenger;
|
|
53
53
|
const { settings, renderer, format, env } = context;
|
|
54
|
-
const
|
|
55
|
-
|
|
54
|
+
const { since, meta, kinds: queriedKinds } = catchUpQuery(query, INBOX_QUERY, "inbox");
|
|
55
|
+
if (kind !== undefined && queriedKinds !== undefined)
|
|
56
|
+
throw new CliError("validation_error", "give kind: or its legacy --kind spelling, not both");
|
|
57
|
+
const kinds = queriedKinds ?? (kind === undefined ? undefined : kindsOf(kind));
|
|
56
58
|
if (fresh && since !== undefined)
|
|
57
59
|
throw new CliError("validation_error", "--new keeps its own point — not with a date in the query");
|
|
58
60
|
const saved = fresh && since === undefined
|
|
@@ -12,7 +12,7 @@ export const messagesStatsCommand = (messenger) => syncOptions(annotate(new Comm
|
|
|
12
12
|
.summary("count stored messages by chat, sender, day or hour")
|
|
13
13
|
.description(`how many stored messages match, by chat, sender, day or hour — the local store only${syncsFirst(messenger) ? "; optionally fetches new messages with --sync-first" : ""}`)
|
|
14
14
|
.argument("[query...]", "a strict Lucene query, as for search messages; none counts every stored message; with --saved, more words AND-ed to it")
|
|
15
|
-
.option("--by <
|
|
15
|
+
.option("--by <group>", "count by chat, sender, day or hour (default: chat)", groupingOf)
|
|
16
16
|
.option("--chat <chat>", `only this chat — the same as chat: in the query; ${messenger.chatArgument}`)
|
|
17
17
|
.option("--source <accounts>", "every account of this messenger held in the store; personal, bots or all — the same as in: in the query")
|
|
18
18
|
.option("--limit <n>", "how many rows", positiveCount("--limit"))
|
|
@@ -23,7 +23,7 @@ export const metadataCommand = (messenger) => {
|
|
|
23
23
|
.description("fetch group and channel descriptions again and cache them")
|
|
24
24
|
.option("--chat <chat>", "stored group/channel; repeat for several", (value, previous) => [...previous, value], [])
|
|
25
25
|
.option("--only-missing", "only chats with no metadata yet; without --chat, every stored group/channel")
|
|
26
|
-
.option("--limit <
|
|
26
|
+
.option("--limit <n>", "process at most 1–500 chats", positiveCount("--limit"), 50)
|
|
27
27
|
.action(async function () {
|
|
28
28
|
const context = messengerContext(this, messenger);
|
|
29
29
|
refuseLocalWrite(context, messenger.app.command, "metadata.refresh");
|
|
@@ -54,10 +54,11 @@ export const privatePeopleCommands = (messenger) => {
|
|
|
54
54
|
output: { entity: "contact_note" },
|
|
55
55
|
}), { name: "text", description: "the note's text" })
|
|
56
56
|
.description(name === "add"
|
|
57
|
-
? "add a private note on a person from stdin or --file; never sent"
|
|
57
|
+
? "add a private note on a person from stdin or --text-file; never sent"
|
|
58
58
|
: "replace a note's text; --revision must match the one you read")
|
|
59
59
|
.argument("<person>", "the person's id, reference or known name")
|
|
60
|
-
.addOption(ownerOnlyOption("--file <path>", "read note text from a file; omitted or - reads stdin"))
|
|
60
|
+
.addOption(ownerOnlyOption("--text-file <path>", "read note text from a file; omitted or - reads stdin").conflicts("file"))
|
|
61
|
+
.addOption(ownerOnlyOption("--file <path>", "compatibility alias for --text-file").hideHelp().conflicts("textFile"));
|
|
61
62
|
if (name === "edit")
|
|
62
63
|
command
|
|
63
64
|
.argument("<id>", "the note id from contacts notes list")
|
|
@@ -65,7 +66,8 @@ export const privatePeopleCommands = (messenger) => {
|
|
|
65
66
|
command.action(async function (person, id) {
|
|
66
67
|
const context = messengerContext(this, messenger);
|
|
67
68
|
refuseLocalWrite(context, messenger.app.command, `contacts.notes.${name}`);
|
|
68
|
-
const { file, revision } = this.opts();
|
|
69
|
+
const { textFile, file: legacyFile, revision, } = this.opts();
|
|
70
|
+
const file = textFile ?? legacyFile;
|
|
69
71
|
const text = file === undefined || file === "-" ? await readAll(context.stdin) : await readFile(file, "utf8");
|
|
70
72
|
const version = Number(revision);
|
|
71
73
|
if (name === "edit" && (!Number.isSafeInteger(version) || version < 1))
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Command } from "commander";
|
|
2
2
|
import { type Messenger } from "./context.js";
|
|
3
|
-
export declare const REPLY_EDIT_OPTIONS: readonly [readonly ["--do <actions>", "actions: reply, task, or both, comma-separated"], readonly ["--kinds <kinds>", "chat kinds: dialog, group; comma-separated, empty for any"], readonly ["--allow-chats <ids>", "only these chat ids, comma-separated; empty for any"], readonly ["--deny-chats <ids>", "leave these chat ids out, comma-separated; empty clears"], readonly ["--words <words>", "match any of these whole words, comma-separated; empty clears"], readonly ["--question", "match only questions"], readonly ["--no-question", "do not require a question"], readonly ["--mentions-me", "require a mention of you or a reply to you"], readonly ["--no-mentions-me", "do not require a mention of you or a reply to you"], readonly ["--allow-people <ids>", "only these sender ids, comma-separated; empty for any"], readonly ["--deny-people <ids>", "leave these sender ids out, comma-separated; empty clears"], readonly ["--contacts-only", "match only contacts"], readonly ["--no-contacts-only", "do not require a contact"], readonly ["--template <text>", "the reply template"], readonly ["--
|
|
3
|
+
export declare const REPLY_EDIT_OPTIONS: readonly [readonly ["--do <actions>", "actions: reply, task, or both, comma-separated"], readonly ["--kinds <kinds>", "chat kinds: dialog, group; comma-separated, empty for any"], readonly ["--allow-chats <ids>", "only these chat ids, comma-separated; empty for any"], readonly ["--deny-chats <ids>", "leave these chat ids out, comma-separated; empty clears"], readonly ["--words <words>", "match any of these whole words, comma-separated; empty clears"], readonly ["--question", "match only questions"], readonly ["--no-question", "do not require a question"], readonly ["--mentions-me", "require a mention of you or a reply to you"], readonly ["--no-mentions-me", "do not require a mention of you or a reply to you"], readonly ["--allow-people <ids>", "only these sender ids, comma-separated; empty for any"], readonly ["--deny-people <ids>", "leave these sender ids out, comma-separated; empty clears"], readonly ["--contacts-only", "match only contacts"], readonly ["--no-contacts-only", "do not require a contact"], readonly ["--template <text>", "the reply template"], readonly ["--template-mode <mode>", "legacy template mode: fill-only or may-reword; use ai blocks instead"], readonly ["--as-reply", "send as a reply to the matched message"], readonly ["--no-as-reply", "send without linking to the matched message"], readonly ["--per-chat <limit>", "at most this many per chat, such as 1/12h"], readonly ["--per-person <limit>", "at most this many per person, such as 1/1d"], readonly ["--outside <hours>", "answer outside this 24-hour window, such as 09:00-19:00"], readonly ["--days <days>", "days of the working window, such as mon-fri or sat,sun"], readonly ["--timezone <zone>", "the IANA timezone for the working window"], readonly ["--no-hours", "clear the working window"]];
|
|
4
4
|
export declare const REPLY_AUDIENCE_OPTIONS: readonly [readonly ["--reply <mode>", "answer all or only listed senders and chats: all, listed"], readonly ["--allow-people <ids>", "replace allowed sender ids, comma-separated; empty clears"], readonly ["--allow-chats <ids>", "replace allowed chat ids, comma-separated; empty clears"], readonly ["--deny-people <ids>", "replace denied sender ids, comma-separated; empty clears; deny wins"], readonly ["--deny-chats <ids>", "replace denied chat ids, comma-separated; empty clears; deny wins"]];
|
|
5
5
|
export declare const addReplyEditors: (replies: Command, messenger: Messenger) => void;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { annotate } from "@wirecat/cli-base/commands";
|
|
2
|
-
import { Command } from "commander";
|
|
2
|
+
import { Command, Option } from "commander";
|
|
3
3
|
import { addRule, editAudience, editRule, switchRule } from "../../replies/edit.js";
|
|
4
4
|
import { audienceWarnings, repliesPathFor } from "../../replies/rules.js";
|
|
5
5
|
import { grantsAuthority, LOCAL_WRITE } from "../effects.js";
|
|
@@ -20,7 +20,7 @@ export const REPLY_EDIT_OPTIONS = [
|
|
|
20
20
|
["--contacts-only", "match only contacts"],
|
|
21
21
|
["--no-contacts-only", "do not require a contact"],
|
|
22
22
|
["--template <text>", "the reply template"],
|
|
23
|
-
["--
|
|
23
|
+
["--template-mode <mode>", "legacy template mode: fill-only or may-reword; use ai blocks instead"],
|
|
24
24
|
["--as-reply", "send as a reply to the matched message"],
|
|
25
25
|
["--no-as-reply", "send without linking to the matched message"],
|
|
26
26
|
["--per-chat <limit>", "at most this many per chat, such as 1/12h"],
|
|
@@ -59,8 +59,13 @@ export const addReplyEditors = (replies, messenger) => {
|
|
|
59
59
|
const edit = grantsAuthority(annotate(new Command("edit"), { effects: LOCAL_WRITE }))
|
|
60
60
|
.description("change only the named fields of a reply rule; lists replace the whole list")
|
|
61
61
|
.argument("<id>", "the rule's id");
|
|
62
|
-
for (const [flag, help] of REPLY_EDIT_OPTIONS)
|
|
63
|
-
|
|
62
|
+
for (const [flag, help] of REPLY_EDIT_OPTIONS) {
|
|
63
|
+
const option = new Option(flag, help);
|
|
64
|
+
if (flag === "--template-mode <mode>")
|
|
65
|
+
option.conflicts("model");
|
|
66
|
+
edit.addOption(option);
|
|
67
|
+
}
|
|
68
|
+
edit.addOption(new Option("--model <mode>", "compatibility alias for --template-mode").hideHelp().conflicts("templateMode"));
|
|
64
69
|
// Commander gives negated-only flags a true default; omission must preserve the saved field.
|
|
65
70
|
edit.action(function (id) {
|
|
66
71
|
const options = this.opts();
|
|
@@ -68,7 +73,10 @@ export const addReplyEditors = (replies, messenger) => {
|
|
|
68
73
|
delete options.hours;
|
|
69
74
|
const context = messengerContext(this, messenger);
|
|
70
75
|
const { settings, env } = context;
|
|
71
|
-
renderItem(this, context, editRule(repliesPathFor(messenger.app, settings.profile, env), messenger.provider, id,
|
|
76
|
+
renderItem(this, context, editRule(repliesPathFor(messenger.app, settings.profile, env), messenger.provider, id, {
|
|
77
|
+
...options,
|
|
78
|
+
model: options.templateMode ?? options.model,
|
|
79
|
+
}));
|
|
72
80
|
});
|
|
73
81
|
replies.addCommand(edit);
|
|
74
82
|
const audience = grantsAuthority(annotate(new Command("audience"), { effects: LOCAL_WRITE })).description("show the reply audience, who the rules may answer, or replace its named fields; a new file answers everyone a rule matches");
|
|
@@ -13,7 +13,7 @@ export const retentionCommand = (messenger) => annotate(new Command("retention")
|
|
|
13
13
|
.option("--until-time <time>", "joining period ends at this time; now by default")
|
|
14
14
|
.option("--checkpoints <durations>", "up to 10 increasing joining ages, comma separated; 1d,7d,30d by default")
|
|
15
15
|
.option("--within <duration>", "activity and early departure window after joining; 7d by default")
|
|
16
|
-
.addOption(new Option("--by <
|
|
16
|
+
.addOption(new Option("--by <group>", "group joining dates by calendar day or Monday week").choices(["day", "week"]))
|
|
17
17
|
.option("--timezone <zone>", "IANA timezone for joining cohorts")
|
|
18
18
|
.option("--limit <n>", "cohorts and member evidence, 1–100", positiveCount("--limit"))
|
|
19
19
|
.action(async function (chat) {
|
|
@@ -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 { parseDuration } from "../../domain/duration.js";
|
|
5
5
|
import { renderMessages } from "../../render/messages.js";
|
|
6
6
|
import { CHAT_KINDS } from "../../services/chats.js";
|
|
@@ -34,7 +34,7 @@ export const reviewCommand = (messenger) => annotate(new Command("review"), {
|
|
|
34
34
|
.description("every message, yours too, in chats that changed since a point — for reviewing who owes what")
|
|
35
35
|
.addHelpText("after", queryHelp(REVIEW_QUERY))
|
|
36
36
|
.argument("[query...]", `where the last review ended and which chat: date>2h, chat:"Book club"; ${REVIEW_DAYS} days ago if no date`)
|
|
37
|
-
.
|
|
37
|
+
.addOption(new Option("--kind <kinds>", `compatibility spelling for kind:; ${CHAT_KINDS.join(", ")}`).hideHelp())
|
|
38
38
|
.option("--unanswered [duration]", `only questions to you or a group's admins that nobody answered, asked at least this long ago — 4h, 1d; ${UNANSWERED_HOURS}h if not given`)
|
|
39
39
|
.option("--all", "muted and archived chats too — left out unless they mention you or reply to you")
|
|
40
40
|
.option(...TRANSCRIBE_OPTION)
|
|
@@ -47,7 +47,9 @@ export const reviewCommand = (messenger) => annotate(new Command("review"), {
|
|
|
47
47
|
const hearWith = modelWith(options.transcribe, options.model);
|
|
48
48
|
const context = messengerContext(this, messenger);
|
|
49
49
|
const { settings, renderer, format, env } = context;
|
|
50
|
-
const { since: from, chat, meta } = catchUpQuery(query, REVIEW_QUERY, "review");
|
|
50
|
+
const { since: from, chat, meta, kinds: queriedKinds } = catchUpQuery(query, REVIEW_QUERY, "review");
|
|
51
|
+
if (options.kind !== undefined && queriedKinds !== undefined)
|
|
52
|
+
throw new CliError("validation_error", "give kind: or its legacy --kind spelling, not both");
|
|
51
53
|
if (options.new && (from !== undefined || options.unanswered !== undefined)) {
|
|
52
54
|
// An open question stays open: moving past it would drop it from the next review.
|
|
53
55
|
throw new CliError("validation_error", "--new keeps its own point — not with a date or --unanswered");
|
|
@@ -62,7 +64,7 @@ export const reviewCommand = (messenger) => annotate(new Command("review"), {
|
|
|
62
64
|
: undefined;
|
|
63
65
|
const since = from ?? saved?.first ?? reviewStart();
|
|
64
66
|
const hours = options.unanswered === undefined ? undefined : unansweredHours(options.unanswered);
|
|
65
|
-
const kinds = options.kind === undefined ? undefined : kindsOf(options.kind);
|
|
67
|
+
const kinds = queriedKinds ?? (options.kind === undefined ? undefined : kindsOf(options.kind));
|
|
66
68
|
let hearing;
|
|
67
69
|
const transcribe = options.transcribe === true;
|
|
68
70
|
const { found, reader } = await context.withServices(async (services, connect) => {
|
|
@@ -45,7 +45,7 @@ export const searchesCommand = (messenger) => {
|
|
|
45
45
|
.option("--exact", "bare words and quotes match their exact form only, as exact:word does; text: still matches every form")
|
|
46
46
|
.option("--context <n>", "messages before and after each hit", wholeCount)
|
|
47
47
|
.option("--timezone <zone>", "the IANA timezone for calendar date boundaries")
|
|
48
|
-
.option("--by <
|
|
48
|
+
.option("--by <group>", "count by chat, sender, day or hour for stats messages show --saved", groupingOf)
|
|
49
49
|
.option("--selection <json>", "save the resolved parent ranking query and options from a drilldown")
|
|
50
50
|
.option("--replace", "overwrite a saved search of the same name")
|
|
51
51
|
.action(async function (name, words) {
|
|
@@ -78,6 +78,7 @@ export declare const serveRelay: (command: Command, messenger: Messenger) => {
|
|
|
78
78
|
inviteLinkRevoke?: boolean;
|
|
79
79
|
inviteLinkUpdate?: boolean;
|
|
80
80
|
joinRequestsAll?: boolean;
|
|
81
|
+
joinRequestsByLink?: boolean;
|
|
81
82
|
channelComments?: boolean;
|
|
82
83
|
addsWithHistory?: boolean;
|
|
83
84
|
adminRights?: readonly import("../../domain/models.js").AdminRight[];
|
|
@@ -49,7 +49,7 @@ export const statsCommand = (messenger, loadRenderer = chartRenderer) => {
|
|
|
49
49
|
.description("a chart's data from a chat's statistics, and optionally a dark SVG or PNG image")
|
|
50
50
|
.argument("<chat>", messenger.chatArgument)
|
|
51
51
|
.option("--chart-kind <messages|active|membership>", "what to draw: messages, active authors, or joins and leaves", chartKindOf, "messages")
|
|
52
|
-
.option("--by <
|
|
52
|
+
.option("--by <group>", "one point per calendar day or week (weeks start on Monday)", chartPeriodOf, "day")
|
|
53
53
|
.option("--since-time <time>", `ISO 8601, or 2h / 1d ago; ${EVENTS_DAYS} days ago if not given`)
|
|
54
54
|
.option("--timezone <zone>", "the IANA timezone for calendar days")
|
|
55
55
|
.option("--output <file>", "write a dark image to a new .svg or .png file")
|
|
@@ -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 { TAGGING_QUERY } from "../../services/tags.js";
|
|
5
5
|
import { changesStore, FETCH, LOCAL_READ, LOCAL_WRITE } from "../effects.js";
|
|
6
6
|
import { itemOf, renderAnswer, snakeKeys } from "../envelope.js";
|
|
@@ -23,7 +23,7 @@ const describe = ({ type, chatId, personId, messageId, taskId }) => type === "ch
|
|
|
23
23
|
const line = (one) => `${one.tag} ${one.type} ${one.name ?? ""} (${one.target})`;
|
|
24
24
|
const sourceOf = (value) => {
|
|
25
25
|
if (value !== "manual" && value !== "auto")
|
|
26
|
-
throw new CliError("validation_error", "--
|
|
26
|
+
throw new CliError("validation_error", "--claim takes manual or auto");
|
|
27
27
|
return value;
|
|
28
28
|
};
|
|
29
29
|
/** The owner's labels, in the local store only: `tag:` in a search finds what they label. */
|
|
@@ -35,7 +35,7 @@ export const tagsCommand = (messenger) => {
|
|
|
35
35
|
changesStore(annotate(tags.command("auto"), { effects: FETCH, examples: [`${tool} tags auto --chat "Book club" --dry-run`] }))
|
|
36
36
|
.description("derive local group/channel tags from cached metadata using keyword rules")
|
|
37
37
|
.option("--chat <chat>", "a stored group/channel; repeat to select several", (value, previous) => [...previous, value], [])
|
|
38
|
-
.option("--limit <
|
|
38
|
+
.option("--limit <n>", "process at most 1–500 chats", positiveCount("--limit"), 50)
|
|
39
39
|
.option("--sync-first", "read current descriptions from the messenger before classifying")
|
|
40
40
|
.option("--dry-run", "preview cached classification without changing the store")
|
|
41
41
|
.action(async function () {
|
|
@@ -62,12 +62,18 @@ export const tagsCommand = (messenger) => {
|
|
|
62
62
|
effects: LOCAL_WRITE,
|
|
63
63
|
examples: [`${tool} tags remove reading --chat "Book club"`],
|
|
64
64
|
}).description("take tags off one chat, person, message or task"), messenger, "untag")
|
|
65
|
-
.
|
|
65
|
+
.addOption(new Option("--claim <claim>", "remove only this ownership claim: manual or auto")
|
|
66
|
+
.argParser(sourceOf)
|
|
67
|
+
.conflicts("source"))
|
|
68
|
+
.addOption(new Option("--source <manual|auto>", "compatibility alias for --claim")
|
|
69
|
+
.argParser(sourceOf)
|
|
70
|
+
.hideHelp()
|
|
71
|
+
.conflicts("claim"))
|
|
66
72
|
.action(async function (given) {
|
|
67
73
|
const context = messengerContext(this, messenger);
|
|
68
74
|
refuseLocalWrite(context, messenger.app.command, "tags.remove");
|
|
69
75
|
const target = this.opts();
|
|
70
|
-
const done = await context.withServices((services) => services.tags.remove(target, given, this.opts().source));
|
|
76
|
+
const done = await context.withServices((services) => services.tags.remove(target, given, this.opts().claim ?? this.opts().source));
|
|
71
77
|
renderAnswer(this, context, itemOf(snakeKeys(done)), () => done.removed.length ? `${describe(done.target)}: ${done.removed.join(", ")} removed\n` : "");
|
|
72
78
|
if (done.unchanged.length && context.format === "pretty")
|
|
73
79
|
context.renderer.note(`not there: ${done.unchanged.join(", ")}`);
|
|
@@ -17,7 +17,7 @@ export const transcribeSubcommand = (messages, messenger) => annotate(messages.c
|
|
|
17
17
|
.argument("<chat>", messenger.chatArgument)
|
|
18
18
|
.argument("<message>", "the id of a voice message")
|
|
19
19
|
.option("--local", "use the model on this machine, never the messenger")
|
|
20
|
-
.option("--model <
|
|
20
|
+
.option("--model <model>", "which downloaded model; implies --local (`models audio list`)")
|
|
21
21
|
.action(async function (chat, messageId) {
|
|
22
22
|
const context = messengerContext(this, messenger);
|
|
23
23
|
const choice = {
|
package/dist/mcp/prompts.js
CHANGED
|
@@ -42,9 +42,15 @@ export const registerPrompts = (server, { command, name }) => {
|
|
|
42
42
|
?.split(",")
|
|
43
43
|
.map((one) => one.trim())
|
|
44
44
|
.filter((one) => one.length > 0);
|
|
45
|
+
const query = [
|
|
46
|
+
kinds?.length ? `kind:${JSON.stringify(kinds.join(","))}` : "",
|
|
47
|
+
mode === undefined || mode === "unread" || mode === "new" ? "" : after(mode),
|
|
48
|
+
]
|
|
49
|
+
.filter(Boolean)
|
|
50
|
+
.join(" ");
|
|
45
51
|
const args = {
|
|
46
|
-
...(
|
|
47
|
-
...(mode ===
|
|
52
|
+
...(query ? { query } : {}),
|
|
53
|
+
...(mode === "new" ? { new: true } : {}),
|
|
48
54
|
};
|
|
49
55
|
return asked([
|
|
50
56
|
`Catch me up on ${name}. Call ${call(`${command}_read`, "inbox", args)} once.`,
|