@wirecat/cli-core 0.398.0 → 0.400.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 +106 -0
- package/dist/analysis/consents.d.ts +11 -6
- package/dist/analysis/consents.js +5 -2
- 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 +6 -2
- 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/config-command.js +20 -1
- package/dist/cli/context.d.ts +2 -0
- package/dist/cli/context.js +1 -1
- package/dist/cli/effects.d.ts +4 -1
- package/dist/cli/effects.js +10 -2
- package/dist/cli/embedding-choice.d.ts +2 -1
- package/dist/cli/embedding-choice.js +4 -1
- package/dist/cli/index.d.ts +1 -1
- package/dist/cli/index.js +1 -1
- package/dist/cli/json-fields.js +12 -1
- package/dist/cli/messenger/account-command.js +15 -6
- package/dist/cli/messenger/account-profile-query.d.ts +2 -0
- package/dist/cli/messenger/account-profile-query.js +13 -0
- package/dist/cli/messenger/account-sessions-command.js +1 -0
- package/dist/cli/messenger/admin-commands.js +30 -21
- package/dist/cli/messenger/admin-contacts-command.js +6 -3
- package/dist/cli/messenger/admin-folders-command.js +5 -5
- package/dist/cli/messenger/admin-moderation-command.js +4 -4
- package/dist/cli/messenger/admin-statistics-command.js +6 -14
- package/dist/cli/messenger/analysis-consents-query.d.ts +5 -0
- package/dist/cli/messenger/analysis-consents-query.js +20 -0
- package/dist/cli/messenger/archive-commands.js +3 -3
- package/dist/cli/messenger/attachments-command.js +3 -0
- package/dist/cli/messenger/backfill-command.js +5 -4
- 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/chat-queries.d.ts +1 -0
- package/dist/cli/messenger/chat-queries.js +12 -2
- package/dist/cli/messenger/chats-command.js +2 -2
- package/dist/cli/messenger/chats-documents-command.js +7 -5
- package/dist/cli/messenger/chats-members-command.js +7 -3
- package/dist/cli/messenger/chats-read-command.js +1 -1
- package/dist/cli/messenger/chats-stats-command.js +1 -1
- package/dist/cli/messenger/chats-tracking-command.js +14 -6
- package/dist/cli/messenger/contacts-command.js +11 -7
- package/dist/cli/messenger/context.d.ts +2 -0
- package/dist/cli/messenger/conversations-command.js +47 -29
- package/dist/cli/messenger/doctor-command.js +5 -1
- package/dist/cli/messenger/document-links-query.d.ts +2 -0
- package/dist/cli/messenger/document-links-query.js +9 -0
- package/dist/cli/messenger/download-command.js +1 -0
- package/dist/cli/messenger/flood-command.d.ts +2 -2
- package/dist/cli/messenger/flood-command.js +3 -3
- package/dist/cli/messenger/gaps-command.js +2 -2
- package/dist/cli/messenger/guard-commands.js +35 -13
- package/dist/cli/messenger/hearing-command.d.ts +1 -1
- package/dist/cli/messenger/hearing-command.js +1 -1
- package/dist/cli/messenger/images-command.js +1 -0
- package/dist/cli/messenger/inbox.js +6 -4
- package/dist/cli/messenger/media-archive-command.js +2 -0
- package/dist/cli/messenger/media-archive-move-command.js +1 -0
- package/dist/cli/messenger/media-archive-timer-command.js +1 -1
- package/dist/cli/messenger/mentions-command.js +15 -2
- package/dist/cli/messenger/messages-command.js +2 -0
- package/dist/cli/messenger/messages-delete-command.js +1 -0
- package/dist/cli/messenger/messages-edit-command.js +1 -0
- package/dist/cli/messenger/messages-evidence-command.js +3 -1
- package/dist/cli/messenger/messages-forward-command.js +1 -0
- package/dist/cli/messenger/messages-pin-command.js +3 -0
- package/dist/cli/messenger/messages-send-command.js +1 -0
- package/dist/cli/messenger/messages-stats-command.js +1 -1
- package/dist/cli/messenger/metadata-command.js +7 -2
- package/dist/cli/messenger/models-command.js +10 -2
- package/dist/cli/messenger/polls-command.js +4 -0
- package/dist/cli/messenger/private-people-command.js +8 -6
- package/dist/cli/messenger/rankings-command.js +6 -11
- package/dist/cli/messenger/reactions-command.js +2 -0
- package/dist/cli/messenger/recipients-query.d.ts +5 -0
- package/dist/cli/messenger/recipients-query.js +18 -0
- package/dist/cli/messenger/records-command.js +13 -6
- 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/search-command.js +3 -1
- package/dist/cli/messenger/searches-command.js +6 -2
- package/dist/cli/messenger/sends-query.d.ts +5 -0
- package/dist/cli/messenger/sends-query.js +33 -0
- package/dist/cli/messenger/serve-command.js +1 -0
- package/dist/cli/messenger/serve-relay.d.ts +1 -0
- package/dist/cli/messenger/statistics-query.d.ts +14 -0
- package/dist/cli/messenger/statistics-query.js +143 -0
- package/dist/cli/messenger/stats-command.js +6 -6
- package/dist/cli/messenger/store-maintenance-command.d.ts +1 -1
- package/dist/cli/messenger/store-maintenance-command.js +10 -10
- package/dist/cli/messenger/tags-command.js +18 -6
- package/dist/cli/messenger/tasks-command.js +47 -8
- package/dist/cli/messenger/transcribe-command.js +2 -1
- package/dist/cli/messenger/watch-answers.d.ts +6 -0
- package/dist/cli/messenger/watch-answers.js +69 -0
- package/dist/cli/messenger/watch-command.d.ts +1 -1
- package/dist/cli/messenger/watch-command.js +56 -7
- package/dist/cli/program.js +5 -1
- package/dist/cli/runs/command.js +25 -38
- package/dist/cli/runs/query.d.ts +5 -0
- package/dist/cli/runs/query.js +32 -0
- package/dist/cli/runs/search-command.d.ts +4 -0
- package/dist/cli/runs/search-command.js +27 -0
- package/dist/cli/runs/search-query.d.ts +4 -0
- package/dist/cli/runs/search-query.js +50 -0
- package/dist/cli/runs/search.d.ts +2 -1
- package/dist/cli/runs/search.js +6 -6
- package/dist/domain/attachments.js +9 -1
- package/dist/domain/rankings-options.js +3 -3
- package/dist/entities/account-change.d.ts +89 -0
- package/dist/entities/account-change.js +20 -0
- package/dist/entities/account-profile.d.ts +7 -0
- package/dist/entities/account-profile.js +8 -0
- package/dist/entities/analysis-consent.d.ts +9 -0
- package/dist/entities/analysis-consent.js +4 -0
- package/dist/entities/attachment-results.d.ts +96 -0
- package/dist/entities/attachment-results.js +31 -0
- package/dist/entities/batch-result.d.ts +27 -0
- package/dist/entities/batch-result.js +18 -0
- package/dist/entities/chat-admin.d.ts +234 -0
- package/dist/entities/chat-admin.js +84 -0
- package/dist/entities/chat-change.d.ts +25 -0
- package/dist/entities/chat-change.js +11 -0
- package/dist/entities/chat-metadata.d.ts +34 -0
- package/dist/entities/chat-metadata.js +15 -0
- package/dist/entities/chat-moderation.d.ts +44 -0
- package/dist/entities/chat-moderation.js +37 -0
- package/dist/entities/chat-tracking.d.ts +26 -0
- package/dist/entities/chat-tracking.js +23 -0
- package/dist/entities/contact-activity.d.ts +52 -0
- package/dist/entities/contact-activity.js +42 -0
- package/dist/entities/contact-context.d.ts +1568 -0
- package/dist/entities/contact-context.js +191 -0
- package/dist/entities/contact-write.d.ts +22 -0
- package/dist/entities/contact-write.js +6 -0
- package/dist/entities/conversation-preparation.d.ts +63 -0
- package/dist/entities/conversation-preparation.js +23 -0
- package/dist/entities/conversation-results.d.ts +567 -0
- package/dist/entities/conversation-results.js +94 -0
- package/dist/entities/document-link.d.ts +13 -0
- package/dist/entities/document-link.js +11 -0
- package/dist/entities/extraction-report.d.ts +95 -0
- package/dist/entities/extraction-report.js +34 -0
- package/dist/entities/image-embedding.d.ts +9 -0
- package/dist/entities/image-embedding.js +10 -0
- package/dist/entities/index.d.ts +8006 -1928
- package/dist/entities/index.js +174 -3
- package/dist/entities/listener.d.ts +2150 -0
- package/dist/entities/listener.js +46 -0
- package/dist/entities/media-archive.d.ts +43 -0
- package/dist/entities/media-archive.js +32 -0
- package/dist/entities/meeting-task-proposal.d.ts +14 -0
- package/dist/entities/meeting-task-proposal.js +19 -0
- package/dist/entities/meeting.d.ts +1 -1
- package/dist/entities/meeting.js +1 -1
- package/dist/entities/mention.d.ts +63 -0
- package/dist/entities/mention.js +44 -0
- package/dist/entities/message-change.d.ts +19 -0
- package/dist/entities/message-change.js +6 -0
- package/dist/entities/message-context.d.ts +617 -0
- package/dist/entities/message-context.js +20 -0
- package/dist/entities/message-read.d.ts +73 -0
- package/dist/entities/message-read.js +58 -0
- package/dist/entities/message-transfer.d.ts +379 -0
- package/dist/entities/message-transfer.js +83 -0
- package/dist/entities/message-write.d.ts +191 -0
- package/dist/entities/message-write.js +8 -0
- package/dist/entities/model-key.d.ts +14 -0
- package/dist/entities/model-key.js +10 -0
- package/dist/entities/poll.d.ts +40 -0
- package/dist/entities/poll.js +16 -0
- package/dist/entities/private-contact.d.ts +10 -0
- package/dist/entities/private-contact.js +4 -0
- package/dist/entities/reaction-change.d.ts +7 -0
- package/dist/entities/reaction-change.js +8 -0
- package/dist/entities/recipient.d.ts +29 -0
- package/dist/entities/recipient.js +11 -0
- package/dist/entities/recorded-run.d.ts +103 -0
- package/dist/entities/recorded-run.js +44 -0
- package/dist/entities/saved-search.d.ts +4 -0
- package/dist/entities/saved-search.js +2 -0
- package/dist/entities/send-attempt.d.ts +31 -0
- package/dist/entities/send-attempt.js +29 -0
- package/dist/entities/store-maintenance.d.ts +319 -0
- package/dist/entities/store-maintenance.js +145 -0
- package/dist/entities/store-records.d.ts +442 -0
- package/dist/entities/store-records.js +99 -0
- package/dist/entities/tag-change.d.ts +74 -0
- package/dist/entities/tag-change.js +31 -0
- package/dist/entities/task-pair.d.ts +31 -0
- package/dist/entities/task-pair.js +23 -0
- package/dist/entities/task-results.d.ts +524 -0
- package/dist/entities/task-results.js +142 -0
- package/dist/errors/reasons.js +1 -0
- package/dist/mcp/agent.d.ts +3 -1
- package/dist/mcp/agent.js +9 -6
- package/dist/mcp/bot/server.d.ts +2 -0
- package/dist/mcp/bot/server.js +1 -0
- package/dist/mcp/prompts.js +8 -2
- package/dist/mcp/server.js +3 -1
- package/dist/mcp/tools/attachments.js +1 -0
- package/dist/meetings/cli/index.js +1 -1
- package/dist/meetings/cli/passage.js +1 -0
- package/dist/meetings/index.d.ts +2 -1
- package/dist/meetings/index.js +1 -0
- package/dist/meetings/links.d.ts +16 -0
- package/dist/meetings/mcp/index.d.ts +15 -15
- package/dist/meetings/read-answers.d.ts +167 -0
- package/dist/meetings/read-answers.js +183 -0
- package/dist/runs/run.d.ts +10 -2
- package/dist/runs/run.js +11 -3
- package/dist/sends/journal.d.ts +8 -1
- package/dist/sends/journal.js +9 -2
- package/dist/sends/permissions.d.ts +5 -1
- package/dist/sends/permissions.js +11 -1
- package/dist/sends/recipients.d.ts +8 -0
- package/dist/sends/recipients.js +9 -0
- package/dist/services/admin-statistics.js +3 -3
- package/dist/services/chat-documents.d.ts +1 -0
- package/dist/services/chat-documents.js +9 -3
- package/dist/services/chats.d.ts +1 -1
- package/dist/services/chats.js +5 -2
- package/dist/services/meeting-links.d.ts +2 -17
- package/dist/store/exports.d.ts +1 -1
- package/dist/store/exports.js +1 -1
- package/dist/store/messages.d.ts +3 -1
- package/dist/store/messages.js +2 -2
- package/dist/store/roster.d.ts +4 -1
- package/dist/store/roster.js +2 -2
- package/dist/store/sqlite/chats.d.ts +12 -0
- package/dist/store/sqlite/chats.js +1 -0
- package/dist/store/sqlite/document-links.d.ts +1 -1
- package/dist/store/sqlite/document-links.js +5 -5
- package/dist/store/sqlite/involvements.js +2 -1
- package/dist/store/sqlite/roster.d.ts +2 -1
- package/dist/store/sqlite/roster.js +3 -2
- package/package.json +3 -3
- package/parity.json +76 -108
package/dist/cli/bot/people.js
CHANGED
|
@@ -11,6 +11,7 @@ import { messageItem } from "../messenger/message-items.js";
|
|
|
11
11
|
import { positiveCount } from "../paging.js";
|
|
12
12
|
import { asFirstWord } from "../profile.js";
|
|
13
13
|
import { botContext } from "./context.js";
|
|
14
|
+
import { botExamples } from "./examples.js";
|
|
14
15
|
import { botCan } from "./messages.js";
|
|
15
16
|
import { ChatRegistry, registryProfiles } from "./registry.js";
|
|
16
17
|
/** What "common chats" rests on: who has written where in this copy, not who is a member. */
|
|
@@ -122,13 +123,16 @@ const cardOf = async (store, context, bot, who, across, limit) => {
|
|
|
122
123
|
};
|
|
123
124
|
/** `bot contacts show`: one person this bot has seen write, from the local copy. */
|
|
124
125
|
export const botContactsCommand = (bot) => {
|
|
125
|
-
const command = new Command("contacts")
|
|
126
|
-
|
|
126
|
+
const command = new Command("contacts")
|
|
127
|
+
.description(`people this bot has seen write — from the local copy on this machine, never asking ${bot.name ?? "the messenger"} unless told to`)
|
|
128
|
+
.summary("the people this bot has seen write, from the local copy");
|
|
129
|
+
acrossOptions(annotate(command.command("show"), { effects: REMOTE_READ, examples: botExamples(bot, "contacts show @ann") }))
|
|
127
130
|
.argument("<who>", "an id, @username or part of a name")
|
|
128
131
|
.option("--limit <n>", "how many messages from the private chat", positiveCount("--limit"))
|
|
129
132
|
.option("--sync-first", "read the private chat with them again from the messenger first — one request")
|
|
130
133
|
.description("one person: the chats they wrote in (with their last message there) and the latest messages of their " +
|
|
131
134
|
"private chat with the bot")
|
|
135
|
+
.summary("one person: the chats they wrote in and their chat with the bot")
|
|
132
136
|
.action(async function (who, options) {
|
|
133
137
|
const context = botContext(this, bot);
|
|
134
138
|
const across = { allBots: options.allBots === true, bots: options.bots ?? [] };
|
|
@@ -186,7 +190,10 @@ const search = (context, bot, text, from, options) => {
|
|
|
186
190
|
/** `bot search messages`: the messages this bot's local copy holds. */
|
|
187
191
|
export const botSearchCommand = (bot) => {
|
|
188
192
|
const group = new Command("search").description("find what this bot's local copy holds, by text");
|
|
189
|
-
acrossOptions(annotate(group.command("messages"), {
|
|
193
|
+
acrossOptions(annotate(group.command("messages"), {
|
|
194
|
+
effects: REMOTE_READ,
|
|
195
|
+
examples: botExamples(bot, "search messages refund", "search messages invoice --from @ann"),
|
|
196
|
+
}))
|
|
190
197
|
.argument("[query...]", "the words to find")
|
|
191
198
|
.option("--limit <n>", "how many", positiveCount("--limit"))
|
|
192
199
|
.option("--page <n>", "which page, starting at 1", positiveCount("--page"))
|
|
@@ -195,6 +202,7 @@ export const botSearchCommand = (bot) => {
|
|
|
195
202
|
.description("search the messages this bot has read, sent or received on this machine — the local copy only, best " +
|
|
196
203
|
'match first; a Lucene query: every word must appear; "a phrase", -word, a OR b, from: chat: date: has:; ' +
|
|
197
204
|
"by text, by --from, or both")
|
|
205
|
+
.summary("search the messages this bot has seen, in the local copy, by text")
|
|
198
206
|
.action(async function (query, options) {
|
|
199
207
|
const context = botContext(this, bot);
|
|
200
208
|
const limit = options.limit ?? context.settings.limit;
|
|
@@ -222,12 +230,16 @@ export const botSearchCommand = (bot) => {
|
|
|
222
230
|
};
|
|
223
231
|
/** `bot messages between`, over the local copy, added to the shared `messages` group. */
|
|
224
232
|
export const addBotCopyReads = (messages, bot) => {
|
|
225
|
-
acrossOptions(annotate(messages.command("between"), {
|
|
233
|
+
acrossOptions(annotate(messages.command("between"), {
|
|
234
|
+
effects: REMOTE_READ,
|
|
235
|
+
examples: botExamples(bot, "messages between @ann @bob"),
|
|
236
|
+
}))
|
|
226
237
|
.argument("<people...>", "two or more people — an id, @username or part of a name each")
|
|
227
238
|
.option("--limit <n>", "how many of the latest messages from each chat", positiveCount("--limit"))
|
|
228
239
|
.description("what two or more people wrote in the chats they have all written in — from the local copy, grouped by " +
|
|
229
240
|
"chat, oldest first; --limit counts per chat. Common chats are the ones this copy saw each of them " +
|
|
230
241
|
`write in, not a member list from ${bot.name ?? "the messenger"}`)
|
|
242
|
+
.summary("what two or more people wrote in the chats they share, from the local copy")
|
|
231
243
|
.action(async function (references, options) {
|
|
232
244
|
const context = botContext(this, bot);
|
|
233
245
|
if (references.length < 2)
|
package/dist/cli/bot/setup.js
CHANGED
|
@@ -7,6 +7,7 @@ import { REMOTE_READ, REMOTE_WRITE } from "../effects.js";
|
|
|
7
7
|
import { itemOf, renderAnswer, snakeKeys } from "../envelope.js";
|
|
8
8
|
import { wholeList } from "../messenger/chat-answers.js";
|
|
9
9
|
import { botContext, online } from "./context.js";
|
|
10
|
+
import { botExamples } from "./examples.js";
|
|
10
11
|
import { botCan } from "./messages.js";
|
|
11
12
|
import { botFiles } from "./registry.js";
|
|
12
13
|
import { PressLog } from "./updates.js";
|
|
@@ -30,7 +31,7 @@ const botWrite = (context, key, write) => guardedWrite(context.guard(), { operat
|
|
|
30
31
|
/** `bot commands`: the menu people see when they type `/`. */
|
|
31
32
|
export const botMenuCommand = (bot) => {
|
|
32
33
|
const command = new Command("commands").description("the bot's command menu — what people see after /");
|
|
33
|
-
annotate(command.command("list"), { effects: REMOTE_READ })
|
|
34
|
+
annotate(command.command("list"), { effects: REMOTE_READ, examples: botExamples(bot, "commands list") })
|
|
34
35
|
.description("the commands in the menu now")
|
|
35
36
|
.action(async function () {
|
|
36
37
|
const context = online(botContext(this, bot), this);
|
|
@@ -48,13 +49,19 @@ export const botMenuCommand = (bot) => {
|
|
|
48
49
|
renderAnswer(command, context, wholeList("bot commands list", entries));
|
|
49
50
|
});
|
|
50
51
|
};
|
|
51
|
-
annotate(command.command("set"), {
|
|
52
|
+
annotate(command.command("set"), {
|
|
53
|
+
effects: REMOTE_WRITE,
|
|
54
|
+
examples: botExamples(bot, 'commands set "start=Begin here" "help=What I can do"'),
|
|
55
|
+
})
|
|
52
56
|
.description("replace the whole menu: each command as name=description, e.g. start=Begin")
|
|
53
57
|
.argument("<commands...>", "name=description, one per command")
|
|
54
58
|
.action(async function (typed) {
|
|
55
59
|
await replace(this, typed.map(entryOf), "bot.commands.set");
|
|
56
60
|
});
|
|
57
|
-
annotate(command.command("clear"), {
|
|
61
|
+
annotate(command.command("clear"), {
|
|
62
|
+
effects: REMOTE_WRITE,
|
|
63
|
+
examples: botExamples(bot, "commands clear"),
|
|
64
|
+
})
|
|
58
65
|
.description("empty the menu")
|
|
59
66
|
.action(async function () {
|
|
60
67
|
await replace(this, [], "bot.commands.clear");
|
|
@@ -62,9 +69,13 @@ export const botMenuCommand = (bot) => {
|
|
|
62
69
|
return command;
|
|
63
70
|
};
|
|
64
71
|
/** `bot callbacks`: answers to the buttons people press under the bot's messages. */
|
|
65
|
-
export const botCallbacksCommand = (bot) => new Command("callbacks").description("answers to the buttons people press under the bot's messages").addCommand(annotate(new Command("answer"), {
|
|
72
|
+
export const botCallbacksCommand = (bot) => new Command("callbacks").description("answers to the buttons people press under the bot's messages").addCommand(annotate(new Command("answer"), {
|
|
73
|
+
effects: REMOTE_WRITE,
|
|
74
|
+
examples: botExamples(bot, 'callbacks answer 4385 --notification "Saved"'),
|
|
75
|
+
})
|
|
66
76
|
.description("answer a pressed button by its callback id: --notification shows the person a one-time note, " +
|
|
67
77
|
"--text replaces the message the button was on")
|
|
78
|
+
.summary("answer a pressed button: a note to that person, or new message text")
|
|
68
79
|
.argument("<callback>", "the callback id `bot watch` printed")
|
|
69
80
|
.option("--text <text>", "the message's new text")
|
|
70
81
|
.option("--notification <text>", "a note only the person who pressed sees")
|
|
@@ -97,8 +108,10 @@ export const botCallbacksCommand = (bot) => new Command("callbacks").description
|
|
|
97
108
|
}));
|
|
98
109
|
/** `bot webhooks`: where the messenger pushes this bot's updates instead of being polled. */
|
|
99
110
|
export const botWebhooksCommand = (bot) => {
|
|
100
|
-
const command = new Command("webhooks")
|
|
101
|
-
|
|
111
|
+
const command = new Command("webhooks")
|
|
112
|
+
.description("where the messenger pushes this bot's updates — while one is set, `bot watch` gets nothing")
|
|
113
|
+
.summary("where the messenger pushes this bot's updates");
|
|
114
|
+
annotate(command.command("list"), { effects: REMOTE_READ, examples: botExamples(bot, "webhooks list") })
|
|
102
115
|
.description("the webhooks this bot has")
|
|
103
116
|
.action(async function () {
|
|
104
117
|
const context = online(botContext(this, bot), this);
|
|
@@ -107,7 +120,10 @@ export const botWebhooksCommand = (bot) => {
|
|
|
107
120
|
renderAnswer(this, context, wholeList("bot webhooks list", (await botCan(adapter, "webhooks", bot, "list its webhooks")()).map(snakeKeys)));
|
|
108
121
|
});
|
|
109
122
|
});
|
|
110
|
-
const set = annotate(command.command("set"), {
|
|
123
|
+
const set = annotate(command.command("set"), {
|
|
124
|
+
effects: REMOTE_WRITE,
|
|
125
|
+
examples: botExamples(bot, "webhooks set https://bot.example.ts.net/"),
|
|
126
|
+
})
|
|
111
127
|
.description("send this bot's updates to an HTTPS address; refused while another is set")
|
|
112
128
|
.argument("<url>", "the HTTPS address")
|
|
113
129
|
.option("--types <types>", "only these update types, comma-separated, in the messenger's words")
|
|
@@ -138,7 +154,10 @@ export const botWebhooksCommand = (bot) => {
|
|
|
138
154
|
renderAnswer(this, context, wholeList("bot webhooks list", (await list()).map(snakeKeys)));
|
|
139
155
|
});
|
|
140
156
|
});
|
|
141
|
-
annotate(command.command("delete"), {
|
|
157
|
+
annotate(command.command("delete"), {
|
|
158
|
+
effects: REMOTE_WRITE,
|
|
159
|
+
examples: botExamples(bot, "webhooks delete https://bot.example.ts.net/"),
|
|
160
|
+
})
|
|
142
161
|
.description("stop sending updates to this address; with none left, `bot watch` works again")
|
|
143
162
|
.argument("<url>", "the address")
|
|
144
163
|
.action(async function (url) {
|
package/dist/cli/bot/watch.js
CHANGED
|
@@ -7,6 +7,7 @@ import { environmentOf } from "../context.js";
|
|
|
7
7
|
import { REMOTE_WRITE } from "../effects.js";
|
|
8
8
|
import { withoutProviderRefs } from "../provider-refs.js";
|
|
9
9
|
import { botContext, online } from "./context.js";
|
|
10
|
+
import { botExamples } from "./examples.js";
|
|
10
11
|
import { botCan, botIdOf } from "./messages.js";
|
|
11
12
|
import { botFiles } from "./registry.js";
|
|
12
13
|
import { PressLog, UpdatesCursor } from "./updates.js";
|
|
@@ -83,8 +84,13 @@ const keep = async (command, context, bot, botId, events, senders) => {
|
|
|
83
84
|
* With `--public-url` the messenger pushes each batch to a local receiver behind the owner's tunnel
|
|
84
85
|
* instead, and a batch is acknowledged only once kept, so the messenger sends again what was not.
|
|
85
86
|
*/
|
|
86
|
-
export const botWatchCommand = (bot) => annotate(new Command("watch"), {
|
|
87
|
+
export const botWatchCommand = (bot) => annotate(new Command("watch"), {
|
|
88
|
+
effects: REMOTE_WRITE,
|
|
89
|
+
lifetime: "persistent",
|
|
90
|
+
examples: botExamples(bot, "watch --jsonl", "watch --events"),
|
|
91
|
+
})
|
|
87
92
|
.description("print new messages as they arrive and keep them, until Ctrl-C or --timeout (either ends it normally)")
|
|
93
|
+
.summary("print new messages as they arrive and keep them, until Ctrl-C")
|
|
88
94
|
.option("--events", "also edits, deletions, buttons pressed and people coming and going; every line names its event")
|
|
89
95
|
.option("--types <types>", "only these update types, comma-separated, in the messenger's words")
|
|
90
96
|
.option("--public-url <url>", "receive by webhook at your tunnel's https address instead of polling, e.g. https://<name>.ts.net")
|
|
@@ -2,8 +2,9 @@ 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
6
|
import { loadSnakeCaseConfig } from "./config-keys.js";
|
|
6
|
-
import { baseContext } from "./context.js";
|
|
7
|
+
import { baseContext, environmentOf } from "./context.js";
|
|
7
8
|
import { grantsAuthority, LOCAL_READ, LOCAL_WRITE } from "./effects.js";
|
|
8
9
|
import { itemOf, renderAnswer } from "./envelope.js";
|
|
9
10
|
import { knownBeside, knownPermissionKeys } from "./permission-keys.js";
|
|
@@ -94,6 +95,8 @@ export const configCommand = (app, config, { permissionKey } = {}) => {
|
|
|
94
95
|
// The defaults are every other profile's settings too, and default_profile picks one of them.
|
|
95
96
|
throw new CliError("permission_error", `this process is locked to profile ${settings.profile} (${lock}) — ${setting === "default_profile" ? setting : "--defaults"} changes other profiles`);
|
|
96
97
|
}
|
|
98
|
+
if (environmentOf(this).agent)
|
|
99
|
+
refuseAuthorityKey(setting, action === "set" ? String(given) : undefined);
|
|
97
100
|
if (action === "set")
|
|
98
101
|
refuseUnknownKey(this, setting, String(given), permissionKey);
|
|
99
102
|
const saved = config.changeSetting(settings.configPath, {
|
|
@@ -133,6 +136,22 @@ export const refuseUnknownKey = (command, setting, value, permissionKey) => {
|
|
|
133
136
|
(beside.length > 0 ? ` — the known ones there are ${beside.join(", ")}` : ""));
|
|
134
137
|
}
|
|
135
138
|
};
|
|
139
|
+
/**
|
|
140
|
+
* An agent may hold `mcp.authority` and change other settings, but never the key that let it in: on any profile, in
|
|
141
|
+
* the defaults, or by replacing `permissions` whole. Only the owner, in a terminal, turns it on or off (NEED-1662).
|
|
142
|
+
*/
|
|
143
|
+
const refuseAuthorityKey = (setting, value) => {
|
|
144
|
+
const keys = setting.startsWith("permissions.")
|
|
145
|
+
? [setting.slice("permissions.".length)]
|
|
146
|
+
: setting === "permissions"
|
|
147
|
+
? value === undefined
|
|
148
|
+
? ["mcp"]
|
|
149
|
+
: objectKeys(value)
|
|
150
|
+
: [];
|
|
151
|
+
if (!keys.some((key) => key === "mcp" || key.startsWith("mcp.")))
|
|
152
|
+
return;
|
|
153
|
+
throw new CliError("permission_error", `an agent cannot change permissions.${AUTHORITY_KEY} — the owner sets it in a terminal`, { permission: AUTHORITY_KEY });
|
|
154
|
+
};
|
|
136
155
|
/** The keys of a `permissions` object given whole; anything else is left to the schema to refuse. */
|
|
137
156
|
const objectKeys = (value) => {
|
|
138
157
|
try {
|
package/dist/cli/context.d.ts
CHANGED
|
@@ -85,6 +85,8 @@ export interface AgentRun {
|
|
|
85
85
|
failure: (error: ErrorObject) => void;
|
|
86
86
|
/** The server's own stricter levels, `key=level`, as `mcp --permission` takes them; they never loosen. */
|
|
87
87
|
overrides?: readonly string[];
|
|
88
|
+
/** The server's levels allow `mcp.authority`: a command that changes what a later run may do may run. */
|
|
89
|
+
authority?: boolean;
|
|
88
90
|
}
|
|
89
91
|
export interface RelayedRun {
|
|
90
92
|
/** The profile serve holds; a command for another is refused before it touches the connection. */
|
package/dist/cli/context.js
CHANGED
|
@@ -72,7 +72,7 @@ export const baseContext = (command, resolveSettings) => {
|
|
|
72
72
|
run: (body, { unbounded = false, name } = {}) => environment.app
|
|
73
73
|
? recorded({
|
|
74
74
|
app: environment.app,
|
|
75
|
-
// An agent's run is named `mcp <command>`, so `runs
|
|
75
|
+
// An agent's run is named `mcp <command>`, so `search runs` and `sends list` tell it from the owner's.
|
|
76
76
|
command: name ?? `${environment.agent ? "mcp " : ""}${commandPath(command)}`,
|
|
77
77
|
profile: settings.profile,
|
|
78
78
|
record: settings.record,
|
package/dist/cli/effects.d.ts
CHANGED
|
@@ -14,13 +14,16 @@ export declare const NO_EFFECTS: Effects;
|
|
|
14
14
|
/**
|
|
15
15
|
* Marks a local write that changes what a later run may do: a schedule, a setting, the recipient list, an
|
|
16
16
|
* auto-reply, an agent's setup. `<PREFIX>_READ_ONLY` refuses it, or an agent under the lock could hand an
|
|
17
|
-
* unlocked run the send it may not make itself (SEC-47). For the same reason
|
|
17
|
+
* unlocked run the send it may not make itself (SEC-47). For the same reason an MCP server offers it only where the
|
|
18
|
+
* profile allows `mcp.authority`, which is off until the owner turns it on (NEED-1662).
|
|
18
19
|
* `unless` names a flag that makes the run only look (`upgrade --check`), which the lock lets through.
|
|
19
20
|
*/
|
|
20
21
|
export declare const grantsAuthority: <T extends Command>(command: T, { unless }?: {
|
|
21
22
|
unless?: string;
|
|
22
23
|
}) => T;
|
|
23
24
|
export declare const changesAuthority: (command: Command) => boolean;
|
|
25
|
+
/** `changesAuthority` by command path under `root`, as an MCP catalogue asks it; an unknown path is not one. */
|
|
26
|
+
export declare const changesAuthorityAt: (root: Command) => (path: readonly string[]) => boolean;
|
|
24
27
|
export declare const changesAuthorityNow: (command: Command) => boolean;
|
|
25
28
|
/**
|
|
26
29
|
* Marks a command that links or unlinks the account — `session start`, `session end`, a setup that logs in. It never
|
package/dist/cli/effects.js
CHANGED
|
@@ -16,14 +16,22 @@ const AUTHORITY = new WeakMap();
|
|
|
16
16
|
/**
|
|
17
17
|
* Marks a local write that changes what a later run may do: a schedule, a setting, the recipient list, an
|
|
18
18
|
* auto-reply, an agent's setup. `<PREFIX>_READ_ONLY` refuses it, or an agent under the lock could hand an
|
|
19
|
-
* unlocked run the send it may not make itself (SEC-47). For the same reason
|
|
19
|
+
* unlocked run the send it may not make itself (SEC-47). For the same reason an MCP server offers it only where the
|
|
20
|
+
* profile allows `mcp.authority`, which is off until the owner turns it on (NEED-1662).
|
|
20
21
|
* `unless` names a flag that makes the run only look (`upgrade --check`), which the lock lets through.
|
|
21
22
|
*/
|
|
22
23
|
export const grantsAuthority = (command, { unless } = {}) => {
|
|
23
24
|
AUTHORITY.set(command, unless);
|
|
24
|
-
return
|
|
25
|
+
return command;
|
|
25
26
|
};
|
|
26
27
|
export const changesAuthority = (command) => AUTHORITY.has(command);
|
|
28
|
+
/** `changesAuthority` by command path under `root`, as an MCP catalogue asks it; an unknown path is not one. */
|
|
29
|
+
export const changesAuthorityAt = (root) => (path) => {
|
|
30
|
+
let at = root;
|
|
31
|
+
for (const word of path)
|
|
32
|
+
at = at?.commands.find((one) => one.name() === word);
|
|
33
|
+
return at !== undefined && changesAuthority(at);
|
|
34
|
+
};
|
|
27
35
|
export const changesAuthorityNow = (command) => {
|
|
28
36
|
if (!AUTHORITY.has(command))
|
|
29
37
|
return false;
|
|
@@ -3,6 +3,7 @@ import { type AISettings } from "../analysis/settings.js";
|
|
|
3
3
|
import { type AppIdentity } from "../ports/app.js";
|
|
4
4
|
import type { ModelChoice } from "../services/embeddings.js";
|
|
5
5
|
export interface ModelOptions {
|
|
6
|
+
embeddingProvider?: string;
|
|
6
7
|
model?: string;
|
|
7
8
|
provider?: string;
|
|
8
9
|
baseUrl?: string;
|
|
@@ -10,7 +11,7 @@ export interface ModelOptions {
|
|
|
10
11
|
concurrency?: number;
|
|
11
12
|
}
|
|
12
13
|
/** A local model id, or a remote model with its key from `models text key set`. */
|
|
13
|
-
export declare const embeddingChoice: ({ model, provider, baseUrl, dims, concurrency }: ModelOptions, app: AppIdentity, settings: AISettings, env: NodeJS.ProcessEnv, { needKey, keyring }?: {
|
|
14
|
+
export declare const embeddingChoice: ({ model, provider, embeddingProvider, baseUrl, dims, concurrency }: ModelOptions, app: AppIdentity, settings: AISettings, env: NodeJS.ProcessEnv, { needKey, keyring }?: {
|
|
14
15
|
needKey?: boolean;
|
|
15
16
|
keyring?: KeyringStore | undefined;
|
|
16
17
|
}) => ModelChoice;
|
|
@@ -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");
|
package/dist/cli/index.d.ts
CHANGED
|
@@ -53,7 +53,7 @@ export { loadSnakeCaseConfig } from "./config-keys.js";
|
|
|
53
53
|
export { type AgentRun, type BaseContext, type BaseEnvironment, baseContext, environmentOf, outputFor, provide, secretInputOf, } from "./context.js";
|
|
54
54
|
export { type Closeable, withDeadline } from "./deadline.js";
|
|
55
55
|
export { DEFAULT_CONFIG, ensureDefaultConfig } from "./default-config.js";
|
|
56
|
-
export { changesAuthority, destroysNothing, FETCH, grantsAuthority, isLogin, isOtherServiceCall, isStoreChange, judgedEffects, judgedTargets, LOCAL_READ, LOCAL_WRITE, logsInOrOut, NO_EFFECTS, ownerOnlyOption, REMOTE_READ, REMOTE_WRITE, reachesOtherService, refuseUnderReadOnly, } from "./effects.js";
|
|
56
|
+
export { changesAuthority, changesAuthorityAt, destroysNothing, FETCH, grantsAuthority, isLogin, isOtherServiceCall, isStoreChange, judgedEffects, judgedTargets, LOCAL_READ, LOCAL_WRITE, logsInOrOut, NO_EFFECTS, ownerOnlyOption, REMOTE_READ, REMOTE_WRITE, reachesOtherService, refuseUnderReadOnly, } from "./effects.js";
|
|
57
57
|
export { type AnswerOutput, answerSchema, type Body, type ItemBody, itemAnswer, itemOf, jsonlRecords, judgedAnswer, type ListBody, type ListInput, listOf, metaNow, printItem, renderAnswer, sealed, snakeKeys, snakeKeysKeeping, } from "./envelope.js";
|
|
58
58
|
export { withAbort } from "./execution.js";
|
|
59
59
|
export { checkGuide, checkStep, type GuideOptions, type GuideReference, type GuideStep, guideCommand, loadScenarios, MEMO_SCENARIOS, type Scenario, shellProblems, } from "./guide.js";
|
package/dist/cli/index.js
CHANGED
|
@@ -48,7 +48,7 @@ export { loadSnakeCaseConfig } from "./config-keys.js";
|
|
|
48
48
|
export { baseContext, environmentOf, outputFor, provide, secretInputOf, } from "./context.js";
|
|
49
49
|
export { withDeadline } from "./deadline.js";
|
|
50
50
|
export { DEFAULT_CONFIG, ensureDefaultConfig } from "./default-config.js";
|
|
51
|
-
export { changesAuthority, destroysNothing, FETCH, grantsAuthority, isLogin, isOtherServiceCall, isStoreChange, judgedEffects, judgedTargets, LOCAL_READ, LOCAL_WRITE, logsInOrOut, NO_EFFECTS, ownerOnlyOption, REMOTE_READ, REMOTE_WRITE, reachesOtherService, refuseUnderReadOnly, } from "./effects.js";
|
|
51
|
+
export { changesAuthority, changesAuthorityAt, destroysNothing, FETCH, grantsAuthority, isLogin, isOtherServiceCall, isStoreChange, judgedEffects, judgedTargets, LOCAL_READ, LOCAL_WRITE, logsInOrOut, NO_EFFECTS, ownerOnlyOption, REMOTE_READ, REMOTE_WRITE, reachesOtherService, refuseUnderReadOnly, } from "./effects.js";
|
|
52
52
|
export { answerSchema, itemAnswer, itemOf, jsonlRecords, judgedAnswer, listOf, metaNow, printItem, renderAnswer, sealed, snakeKeys, snakeKeysKeeping, } from "./envelope.js";
|
|
53
53
|
export { withAbort } from "./execution.js";
|
|
54
54
|
export { checkGuide, checkStep, guideCommand, loadScenarios, MEMO_SCENARIOS, shellProblems, } from "./guide.js";
|
package/dist/cli/json-fields.js
CHANGED
|
@@ -21,6 +21,17 @@ export const entityFields = (table) => {
|
|
|
21
21
|
return name !== undefined && Object.hasOwn(table, name) ? namesOf(table[name]) : undefined;
|
|
22
22
|
};
|
|
23
23
|
};
|
|
24
|
+
const schemaFields = (schema) => {
|
|
25
|
+
if (typeof schema !== "object" || schema === null)
|
|
26
|
+
return undefined;
|
|
27
|
+
if ("entries" in schema && typeof schema.entries === "object" && schema.entries !== null)
|
|
28
|
+
return Object.keys(schema.entries);
|
|
29
|
+
if ("type" in schema && schema.type === "union" && "options" in schema && Array.isArray(schema.options)) {
|
|
30
|
+
const branches = schema.options.map(schemaFields);
|
|
31
|
+
return branches.every((fields) => fields !== undefined) ? [...new Set(branches.flat())] : undefined;
|
|
32
|
+
}
|
|
33
|
+
return undefined;
|
|
34
|
+
};
|
|
24
35
|
/** The fields of the answer a command declares (`annotate(…, { output })`); nothing until it declares one. */
|
|
25
36
|
export const answerFields = (command, resolve) => {
|
|
26
37
|
const own = resolve?.(command);
|
|
@@ -28,7 +39,7 @@ export const answerFields = (command, resolve) => {
|
|
|
28
39
|
return [...own];
|
|
29
40
|
const name = declaredEntity(command);
|
|
30
41
|
const schema = name === undefined ? undefined : ENTITIES[name];
|
|
31
|
-
return
|
|
42
|
+
return schemaFields(schema);
|
|
32
43
|
};
|
|
33
44
|
const PATHS = /^[a-z][a-z0-9_]*(\.[a-z][a-z0-9_]*)*(,[a-z][a-z0-9_]*(\.[a-z][a-z0-9_]*)*)*$/;
|
|
34
45
|
const topOf = (fields, known) => fields.split(",").map((path) => {
|
|
@@ -6,7 +6,9 @@ import { storePath } from "../../store/path.js";
|
|
|
6
6
|
import { openStore } from "../../store/store.js";
|
|
7
7
|
import { REMOTE_READ, REMOTE_WRITE } from "../effects.js";
|
|
8
8
|
import { itemOf, renderAnswer } from "../envelope.js";
|
|
9
|
+
import { queryTerms, withQuery } from "../list-query.js";
|
|
9
10
|
import { NONE_NAMED } from "../settings.js";
|
|
11
|
+
import { ACCOUNT_PROFILES_QUERY } from "./account-profile-query.js";
|
|
10
12
|
import { accountSessionsCommand } from "./account-sessions-command.js";
|
|
11
13
|
import { recalledAccount } from "./accounts.js";
|
|
12
14
|
import { photoHelp, readProfilePhoto } from "./admin-commands.js";
|
|
@@ -18,16 +20,19 @@ export const accountCommand = (messenger) => {
|
|
|
18
20
|
const tool = `${messenger.app.command} personal`;
|
|
19
21
|
const account = new Command("account")
|
|
20
22
|
.description("the logged-in account")
|
|
21
|
-
.addCommand(annotate(new Command("list"), { effects: REMOTE_READ, examples: [`${tool} account list`] })
|
|
23
|
+
.addCommand(withQuery(annotate(new Command("list"), { effects: REMOTE_READ, examples: [`${tool} account list`] }), ACCOUNT_PROFILES_QUERY)
|
|
22
24
|
.summary("profiles on this computer and their signed-in accounts")
|
|
23
25
|
.description("every profile on this computer, and the account each is logged in as; asks the messenger nothing")
|
|
24
|
-
.action(async function () {
|
|
26
|
+
.action(async function (words) {
|
|
27
|
+
const terms = queryTerms(words, ACCOUNT_PROFILES_QUERY, "account list");
|
|
25
28
|
const context = messengerContext(this, messenger, { needsProfile: false });
|
|
26
29
|
const { app, provider } = messenger;
|
|
27
30
|
const current = context.settings.sources.profile === NONE_NAMED ? undefined : context.settings.profile;
|
|
28
|
-
const profiles = [
|
|
29
|
-
|
|
30
|
-
|
|
31
|
+
const profiles = [...new Set([...(current === undefined ? [] : [current]), ...context.settings.profilesHere])]
|
|
32
|
+
.filter((profile) => terms.get("profile") === undefined || profile === terms.get("profile"))
|
|
33
|
+
.filter((profile) => terms.get("current") === undefined ||
|
|
34
|
+
(profile === current) === (terms.get("current")?.toLowerCase() === "true"))
|
|
35
|
+
.sort();
|
|
31
36
|
const store = existsSync(storePath(context.env))
|
|
32
37
|
? await openStore({ env: context.env }).catch(() => undefined)
|
|
33
38
|
: undefined;
|
|
@@ -61,7 +66,11 @@ export const accountCommand = (messenger) => {
|
|
|
61
66
|
const account = await context.withMessenger((connection) => connection.me());
|
|
62
67
|
renderAnswer(this, context, itemOf(accountAnswer(messenger.provider, whole ? account : maskedAccount(account))));
|
|
63
68
|
}))
|
|
64
|
-
.addCommand(annotate(new Command("update"), {
|
|
69
|
+
.addCommand(annotate(new Command("update"), {
|
|
70
|
+
effects: REMOTE_WRITE,
|
|
71
|
+
output: { entity: "account_change" },
|
|
72
|
+
examples: [`${tool} account update --first-name Alex`],
|
|
73
|
+
})
|
|
65
74
|
.description("change the name, the description or the photo everyone sees on your profile")
|
|
66
75
|
.option("--first-name <name>", "your first name")
|
|
67
76
|
.option("--last-name <name>", "your last name")
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { queryFieldsOf } from "@wirecat/cli-base/query";
|
|
2
|
+
import { accountProfile } from "../../entities/index.js";
|
|
3
|
+
export const ACCOUNT_PROFILES_QUERY = {
|
|
4
|
+
entity: "account_profile",
|
|
5
|
+
backend: "native",
|
|
6
|
+
fields: queryFieldsOf(accountProfile, {
|
|
7
|
+
native: ["profile", "current"],
|
|
8
|
+
examples: { profile: "profile:work", current: "current:true" },
|
|
9
|
+
}).map((field) => ({
|
|
10
|
+
...field,
|
|
11
|
+
operators: field.operators.filter((operator) => operator === "term" || operator === "phrase"),
|
|
12
|
+
})),
|
|
13
|
+
};
|
|
@@ -26,6 +26,7 @@ export const accountSessionsCommand = (messenger) => {
|
|
|
26
26
|
// No MCP tool, at any permission level: it logs the owner out of the phone.
|
|
27
27
|
sessions.addCommand(annotate(new Command("end"), {
|
|
28
28
|
effects: REMOTE_WRITE,
|
|
29
|
+
output: { entity: "ended_account_sessions" },
|
|
29
30
|
mcp: false,
|
|
30
31
|
examples: [`${tool} account sessions end --others`],
|
|
31
32
|
})
|
|
@@ -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") {
|
|
@@ -57,7 +57,7 @@ export const readProfilePhoto = (messenger, path, env) => readUpload("photo", pa
|
|
|
57
57
|
});
|
|
58
58
|
const updateCommand = (messenger) => {
|
|
59
59
|
const keys = messenger.groupSettings ?? GROUP_SETTINGS;
|
|
60
|
-
const update = annotate(new Command("update"), { effects: REMOTE_WRITE })
|
|
60
|
+
const update = annotate(new Command("update"), { output: { entity: "chat_group_change" }, effects: REMOTE_WRITE })
|
|
61
61
|
.summary("change a group or channel's profile and settings")
|
|
62
62
|
.description("rename a group or channel, change its description, or turn one of its settings on or off")
|
|
63
63
|
.argument("<chat>", messenger.chatArgument)
|
|
@@ -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();
|
|
@@ -85,7 +93,7 @@ const updateCommand = (messenger) => {
|
|
|
85
93
|
};
|
|
86
94
|
const linkCommand = (messenger) => {
|
|
87
95
|
const link = new Command("link").description("a group's invite link");
|
|
88
|
-
annotate(link.command("show"), { effects: REMOTE_READ })
|
|
96
|
+
annotate(link.command("show"), { output: { entity: "chat_invite" }, effects: REMOTE_READ })
|
|
89
97
|
.description("the invite link, if you may see it")
|
|
90
98
|
.argument("<chat>", messenger.chatArgument)
|
|
91
99
|
.action(async function (chat) {
|
|
@@ -93,7 +101,7 @@ const linkCommand = (messenger) => {
|
|
|
93
101
|
renderItem(this, context, await context.withServices((services) => services.admin.link(chat)));
|
|
94
102
|
});
|
|
95
103
|
if (messenger.inviteLinkCreate !== false)
|
|
96
|
-
link.addCommand(annotate(new Command("create"), { effects: REMOTE_WRITE })
|
|
104
|
+
link.addCommand(annotate(new Command("create"), { output: { entity: "chat_invite_change" }, effects: REMOTE_WRITE })
|
|
97
105
|
.description("make another invite link; nobody is told until you share it")
|
|
98
106
|
.argument("<chat>", messenger.chatArgument)
|
|
99
107
|
.option("--approval", "who joins by it asks first, and an admin lets them in; it then has no use limit")
|
|
@@ -124,7 +132,7 @@ const linkCommand = (messenger) => {
|
|
|
124
132
|
].join(" ")));
|
|
125
133
|
}));
|
|
126
134
|
if (messenger.inviteLinkRevoke !== false)
|
|
127
|
-
link.addCommand(annotate(new Command("revoke"), { effects: REMOTE_WRITE })
|
|
135
|
+
link.addCommand(annotate(new Command("revoke"), { output: { entity: "chat_invite_change" }, effects: REMOTE_WRITE })
|
|
128
136
|
.description("stop one link; for the group's own link, the answer is the new one")
|
|
129
137
|
.argument("<chat>", messenger.chatArgument)
|
|
130
138
|
.argument("<link>", "the link, as `chats link list` shows it")
|
|
@@ -133,7 +141,7 @@ const linkCommand = (messenger) => {
|
|
|
133
141
|
renderItem(this, context, await context.withServices((services) => services.admin.revokeLink(chat, link)));
|
|
134
142
|
}));
|
|
135
143
|
if (messenger.inviteLinkUpdate === true)
|
|
136
|
-
link.addCommand(annotate(new Command("update"), { effects: REMOTE_WRITE })
|
|
144
|
+
link.addCommand(annotate(new Command("update"), { output: { entity: "chat_invite_change" }, effects: REMOTE_WRITE })
|
|
137
145
|
.description("change one of your invite links, the group's own one too")
|
|
138
146
|
.argument("<chat>", messenger.chatArgument)
|
|
139
147
|
.argument("<link>", "the link, as `chats link list` shows it")
|
|
@@ -150,7 +158,7 @@ const linkCommand = (messenger) => {
|
|
|
150
158
|
...(maxUses === undefined ? {} : { maxUses }),
|
|
151
159
|
})));
|
|
152
160
|
}));
|
|
153
|
-
link.addCommand(annotate(new Command("reset"), { effects: REMOTE_WRITE })
|
|
161
|
+
link.addCommand(annotate(new Command("reset"), { output: { entity: "chat_group_change" }, effects: REMOTE_WRITE })
|
|
154
162
|
.description("replace the invite link; the old one stops working")
|
|
155
163
|
.argument("<chat>", messenger.chatArgument)
|
|
156
164
|
.action(async function (chat) {
|
|
@@ -163,7 +171,7 @@ const adminsCommand = (messenger) => {
|
|
|
163
171
|
const offered = messenger.adminRights ?? ADMIN_RIGHTS;
|
|
164
172
|
const admins = new Command("admins").description("give or take back a member's admin rights");
|
|
165
173
|
const picks = messenger.pickAdminRights !== false;
|
|
166
|
-
const add = annotate(new Command("add"), { effects: REMOTE_WRITE })
|
|
174
|
+
const add = annotate(new Command("add"), { output: { entity: "chat_admin_change" }, effects: REMOTE_WRITE })
|
|
167
175
|
.summary(picks ? "make a member an admin with these rights" : "make a member an admin, with every right")
|
|
168
176
|
.description(picks
|
|
169
177
|
? "make a member an admin with these rights"
|
|
@@ -177,7 +185,7 @@ const adminsCommand = (messenger) => {
|
|
|
177
185
|
const rights = picks ? rightsOf(offered, this.opts().can) : [...offered];
|
|
178
186
|
renderItem(this, context, await context.withServices((services) => services.admin.addAdmin(chat, person, rights)));
|
|
179
187
|
}));
|
|
180
|
-
admins.addCommand(annotate(new Command("remove"), { effects: REMOTE_WRITE })
|
|
188
|
+
admins.addCommand(annotate(new Command("remove"), { output: { entity: "chat_admin_change" }, effects: REMOTE_WRITE })
|
|
181
189
|
.description("take an admin's rights back; they stay a member")
|
|
182
190
|
.argument("<chat>", messenger.chatArgument)
|
|
183
191
|
.argument("<person>", "an id, or part of a name")
|
|
@@ -210,18 +218,19 @@ 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"],
|
|
216
225
|
]) {
|
|
217
|
-
const answer = annotate(new Command(verb), { effects: REMOTE_WRITE })
|
|
226
|
+
const answer = annotate(new Command(verb), { output: { entity: "chat_request_change" }, effects: REMOTE_WRITE })
|
|
218
227
|
.description(help)
|
|
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();
|
|
@@ -238,7 +247,7 @@ const requestsCommand = (messenger) => {
|
|
|
238
247
|
};
|
|
239
248
|
/** `chats create`, `join`, `leave`, `update` and `link`: the help text is max-cli's, the one both tools say (standard, help rule 2). */
|
|
240
249
|
export const groupCommands = (messenger) => [
|
|
241
|
-
annotate(new Command("create"), { effects: REMOTE_WRITE })
|
|
250
|
+
annotate(new Command("create"), { output: { entity: "chat_group_change" }, effects: REMOTE_WRITE })
|
|
242
251
|
.description("create a group or a channel; the people added are told")
|
|
243
252
|
.argument("<title>", "the group's name")
|
|
244
253
|
.argument("[person...]", "people to add: an id, or part of a name")
|
|
@@ -248,14 +257,14 @@ export const groupCommands = (messenger) => [
|
|
|
248
257
|
const { channel } = this.opts();
|
|
249
258
|
renderItem(this, context, await context.withServices((services) => services.admin.create({ title, people, channel: channel === true })));
|
|
250
259
|
}),
|
|
251
|
-
annotate(new Command("join"), { effects: REMOTE_WRITE })
|
|
260
|
+
annotate(new Command("join"), { output: { entity: "chat_group_change" }, effects: REMOTE_WRITE })
|
|
252
261
|
.description("join a group or channel by its link; the others in it see that you joined")
|
|
253
262
|
.argument("<link>", `an invite link, or a public one`)
|
|
254
263
|
.action(async function (link) {
|
|
255
264
|
const context = messengerContext(this, messenger);
|
|
256
265
|
renderItem(this, context, await context.withServices((services) => services.admin.join(link)));
|
|
257
266
|
}),
|
|
258
|
-
annotate(new Command("leave"), { effects: REMOTE_WRITE })
|
|
267
|
+
annotate(new Command("leave"), { output: { entity: "chat_removal" }, effects: REMOTE_WRITE })
|
|
259
268
|
.description("leave a group or channel; the others in it see that you left")
|
|
260
269
|
.argument("<chat>", messenger.chatArgument)
|
|
261
270
|
.action(async function (chat) {
|