@wirecat/cli-core 0.470.0 → 0.472.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.
Files changed (62) hide show
  1. package/CHANGELOG.md +37 -0
  2. package/dist/cli/app-doctor-command.d.ts +107 -0
  3. package/dist/cli/app-doctor-command.js +101 -0
  4. package/dist/cli/app-mcp-command.d.ts +23 -0
  5. package/dist/cli/app-mcp-command.js +49 -0
  6. package/dist/cli/index.d.ts +4 -2
  7. package/dist/cli/index.js +2 -1
  8. package/dist/cli/messenger/mcp-command.d.ts +29 -3
  9. package/dist/cli/messenger/mcp-command.js +59 -39
  10. package/dist/cli/shared-command-exports.d.ts +348 -0
  11. package/dist/cli/shared-command-exports.js +4 -0
  12. package/dist/errors/reasons.js +1 -0
  13. package/dist/mail/bulk.d.ts +7 -0
  14. package/dist/mail/bulk.js +3 -0
  15. package/dist/mail/facts.d.ts +9 -0
  16. package/dist/mail/facts.js +22 -0
  17. package/dist/mail/folders.d.ts +10 -0
  18. package/dist/mail/folders.js +13 -0
  19. package/dist/mail/gone.d.ts +20 -0
  20. package/dist/mail/gone.js +53 -0
  21. package/dist/mail/headers.d.ts +43 -0
  22. package/dist/mail/headers.js +88 -0
  23. package/dist/mail/index.d.ts +17 -0
  24. package/dist/mail/index.js +16 -0
  25. package/dist/mail/parse.d.ts +24 -0
  26. package/dist/mail/parse.js +79 -0
  27. package/dist/mail/presets.d.ts +30 -0
  28. package/dist/mail/presets.js +95 -0
  29. package/dist/mail/probe.d.ts +49 -0
  30. package/dist/mail/probe.js +81 -0
  31. package/dist/mail/resume.d.ts +61 -0
  32. package/dist/mail/resume.js +61 -0
  33. package/dist/mail/rule-input.d.ts +14 -0
  34. package/dist/mail/rule-input.js +32 -0
  35. package/dist/mail/rule-tags.d.ts +40 -0
  36. package/dist/mail/rule-tags.js +87 -0
  37. package/dist/mail/rules.d.ts +83 -0
  38. package/dist/mail/rules.js +108 -0
  39. package/dist/mail/score.d.ts +67 -0
  40. package/dist/mail/score.js +174 -0
  41. package/dist/mail/sender-scores.d.ts +30 -0
  42. package/dist/mail/sender-scores.js +96 -0
  43. package/dist/mail/source.d.ts +67 -0
  44. package/dist/mail/source.js +1 -0
  45. package/dist/mail/stored.d.ts +7 -0
  46. package/dist/mail/stored.js +36 -0
  47. package/dist/mail/sync.d.ts +91 -0
  48. package/dist/mail/sync.js +572 -0
  49. package/dist/mail/testing/contract.d.ts +20 -0
  50. package/dist/mail/testing/contract.js +106 -0
  51. package/dist/mail/testing/fake.d.ts +61 -0
  52. package/dist/mail/testing/fake.js +136 -0
  53. package/dist/mail/testing/index.d.ts +2 -0
  54. package/dist/mail/testing/index.js +2 -0
  55. package/dist/mcp/agent.js +14 -2
  56. package/dist/mcp/app-server.d.ts +42 -0
  57. package/dist/mcp/app-server.js +162 -0
  58. package/dist/mcp/instructions.d.ts +12 -0
  59. package/dist/mcp/instructions.js +23 -0
  60. package/dist/mcp/server.d.ts +4 -0
  61. package/dist/mcp/server.js +2 -2
  62. package/package.json +12 -1
package/CHANGELOG.md CHANGED
@@ -7,6 +7,43 @@ shape of this file.
7
7
 
8
8
  ## Unreleased
9
9
 
10
+ ## 0.472.0 — 28.10.2026
11
+
12
+ ### Added
13
+
14
+ - **`./mail` and `./mail/testing` — the mail engine, moved from memo.** `MailSource` (the port a mail CLI's adapter
15
+ implements), `syncMail(source, store, options)` (resume points per folder, rules, deletions with a safety stop,
16
+ envelopes, attachment text, `index` for the caller's embedding), `scoreSenders`, the rules and the parser. The account
17
+ key `{ provider: "email", account: <address> }` and the sync-state keys (`mail_resume:<folder>`, `mail_folder_scope`,
18
+ `mail_coverage`, `mail_sender_scores`) are memo's, so a mailbox memo imported continues where it stopped. `./mail/testing`
19
+ has a Gmail-shaped in-memory source and the contract every adapter must pass. See `docs/dev/MAIL.md`. Mail is now
20
+ fetched by its own source tool, not by the knowledge tool: `TOOL-BOUNDARIES.md` and `STANDARD.md` say so.
21
+
22
+ ## 0.471.0 — 27.10.2026
23
+
24
+ ### Added
25
+
26
+ - **`appMcpCommand(app, configuration, { name, untrusted, permissionExample, skill?, signedIn? })` — the shared
27
+ `mcp` for a CLI that is not a messenger** (gcal, drive and zoom each had their own): `mcp serve | revoke | server
28
+ start|stop|status | config | add | check`, the same commands, flags and answers as a messenger's `mcpCommand`,
29
+ with `--profiles <names|all>` (no profile is ever picked), `--http`, `--port`, `--public-url` and `--permission`
30
+ (a key no command checks is refused). Every command of the program is a tool behind `<cli>_tools_search`,
31
+ `<cli>_read` and `<cli>_write`, run in this process through the CLI's own `run`, under the profile's permissions
32
+ and its `configuration.permissions` keys; `mcp` itself is left out. The instructions come from the new
33
+ `appInstructions`, which requires the kinds of text other people wrote (`untrusted`, WC-MCP-11). Both kinds of
34
+ CLI now build the group from one `mcpGroup(host: McpHost)`.
35
+ - **`appDoctorCommand(app, configuration, { oauthClient? })` — the shared `doctor` for a CLI that is not a
36
+ messenger**: version, runtime, paths, `store: { path, exists }`, `oauth_client` (`wirecat` or `own`, or the
37
+ error), `read_only`, `profile_lock`, the config file with its issues — permission keys no command checks
38
+ included — the profiles and the config file's modes. It opens no keyring, store or network. `appDoctorReport` is
39
+ the same report for a CLI that renders its own.
40
+
41
+ ### Fixed
42
+
43
+ - **Each MCP call has its own `run_id`.** A command an agent ran through `<cli>_read` or `<cli>_write`
44
+ (`runCommandForAgent`) answered with the server process's run id, so two calls of one session had the same
45
+ `meta.run_id`. Each call now runs in a run of its own, `mcp <command>`, keeping the caller's trace.
46
+
10
47
  ## 0.470.0 — 27.10.2026
11
48
 
12
49
  ### Changed — may break callers
@@ -0,0 +1,107 @@
1
+ import { Command } from "commander";
2
+ import { type AppIdentity } from "../ports/app.js";
3
+ import type { Configuration } from "./settings.js";
4
+ export interface AppDoctorOptions {
5
+ /**
6
+ * Which OAuth client the CLI signs in with — WireCat's or one of the owner's own — read from the environment and
7
+ * files only. A throw is reported as its message.
8
+ */
9
+ oauthClient?: (env: NodeJS.ProcessEnv) => {
10
+ client: "wirecat" | "own";
11
+ };
12
+ }
13
+ /**
14
+ * Run when everything else is broken, so a problem in the config file or the OAuth setting is a field, never a throw.
15
+ * It reads no keyring, opens no store and calls no service: each can hang or prompt. `fixes` are the `chmod` commands
16
+ * that make the config private; they go to stderr, not into the answer.
17
+ */
18
+ export declare const appDoctorReport: (app: AppIdentity, configuration: Configuration, env: NodeJS.ProcessEnv, command: Command, options?: AppDoctorOptions) => {
19
+ report: {
20
+ version: string;
21
+ runtime: {
22
+ node: string;
23
+ platform: NodeJS.Platform;
24
+ };
25
+ paths: {
26
+ config: string;
27
+ state: string;
28
+ cache: string;
29
+ };
30
+ store: {
31
+ path: string;
32
+ exists: boolean;
33
+ };
34
+ oauth_client?: {
35
+ client: "wirecat" | "own" | null;
36
+ error?: string;
37
+ } | undefined;
38
+ read_only: string | null;
39
+ profile_lock: string | null;
40
+ config: {
41
+ path: string;
42
+ found: boolean;
43
+ issues: import("./config-issues.js").ConfigIssue[];
44
+ };
45
+ profiles: string[];
46
+ files: {
47
+ checked: false;
48
+ reason: string;
49
+ } | {
50
+ checked: true;
51
+ ok: boolean;
52
+ problems: {
53
+ path: string;
54
+ mode: string;
55
+ want: string;
56
+ }[];
57
+ };
58
+ };
59
+ fixes: string[] | never[];
60
+ } | {
61
+ report: {
62
+ version: string;
63
+ runtime: {
64
+ node: string;
65
+ platform: NodeJS.Platform;
66
+ };
67
+ paths: {
68
+ config: string;
69
+ state: string;
70
+ cache: string;
71
+ };
72
+ store: {
73
+ path: string;
74
+ exists: boolean;
75
+ };
76
+ oauth_client?: {
77
+ client: "wirecat" | "own" | null;
78
+ error?: string;
79
+ } | undefined;
80
+ read_only: string | null;
81
+ profile_lock: string | null;
82
+ config: {
83
+ path: string;
84
+ found: boolean;
85
+ issues: never[];
86
+ };
87
+ settings: {
88
+ error: string;
89
+ };
90
+ profiles: null;
91
+ files: {
92
+ checked: false;
93
+ reason: string;
94
+ } | {
95
+ checked: true;
96
+ ok: boolean;
97
+ problems: {
98
+ path: string;
99
+ mode: string;
100
+ want: string;
101
+ }[];
102
+ };
103
+ };
104
+ fixes: string[] | never[];
105
+ };
106
+ /** `doctor` for a CLI that is not a messenger: gcal, drive, zoom. A messenger's is `doctorCommand(messenger)`. */
107
+ export declare const appDoctorCommand: (app: AppIdentity, configuration: Configuration, options?: AppDoctorOptions) => Command;
@@ -0,0 +1,101 @@
1
+ import { existsSync } from "node:fs";
2
+ import { dirname, resolve } from "node:path";
3
+ import { CliError, configFilePath, resolvePaths } from "@wirecat/cli-base";
4
+ import { annotate } from "@wirecat/cli-base/commands";
5
+ import { Command } from "commander";
6
+ import { envName, readOnlyLockOf } from "../ports/app.js";
7
+ import { storePath } from "../store/path.js";
8
+ import { environmentOf, outputFor } from "./context.js";
9
+ import { LOCAL_READ } from "./effects.js";
10
+ import { itemOf, renderAnswer } from "./envelope.js";
11
+ import { privateFiles } from "./messenger/private-files.js";
12
+ import { unknownPermissionIssues } from "./permission-keys.js";
13
+ import { profileFree } from "./profile.js";
14
+ const failure = (error) => {
15
+ if (error instanceof CliError)
16
+ return error.message;
17
+ throw error;
18
+ };
19
+ const configFiles = (path) => {
20
+ const files = privateFiles({ files: [path], dirs: [dirname(path)] });
21
+ if (!files.checked)
22
+ return { files, fixes: [] };
23
+ return {
24
+ files: { ...files, problems: files.problems.map(({ path, mode, want }) => ({ path, mode, want })) },
25
+ fixes: files.problems.map((problem) => problem.fix),
26
+ };
27
+ };
28
+ /**
29
+ * Run when everything else is broken, so a problem in the config file or the OAuth setting is a field, never a throw.
30
+ * It reads no keyring, opens no store and calls no service: each can hang or prompt. `fixes` are the `chmod` commands
31
+ * that make the config private; they go to stderr, not into the answer.
32
+ */
33
+ export const appDoctorReport = (app, configuration, env, command, options = {}) => {
34
+ const paths = resolvePaths({ appName: app.appName, prefix: app.envPrefix, env });
35
+ const store = resolve(storePath(env));
36
+ let oauth;
37
+ if (options.oauthClient)
38
+ try {
39
+ oauth = options.oauthClient(env);
40
+ }
41
+ catch (error) {
42
+ oauth = { client: null, error: failure(error) };
43
+ }
44
+ const common = {
45
+ version: app.version,
46
+ runtime: { node: process.versions.node, platform: process.platform },
47
+ paths: { config: paths.config, state: paths.state, cache: paths.cache },
48
+ store: { path: store, exists: existsSync(store) },
49
+ ...(oauth ? { oauth_client: oauth } : {}),
50
+ read_only: readOnlyLockOf(app, env) ?? null,
51
+ profile_lock: env[envName(app, "PROFILE_LOCK")]?.trim() || null,
52
+ };
53
+ try {
54
+ const settings = configuration.resolveSettings({}, { env, readOnly: true, needsProfile: false, withIssues: true });
55
+ const { files, fixes } = configFiles(settings.configPath);
56
+ return {
57
+ report: {
58
+ ...common,
59
+ config: {
60
+ path: settings.configPath,
61
+ found: settings.configFound,
62
+ issues: [
63
+ ...(settings.configIssues ?? []),
64
+ ...unknownPermissionIssues(command, settings, app.command, configuration.permissions),
65
+ ],
66
+ },
67
+ profiles: settings.configuredProfiles,
68
+ files,
69
+ },
70
+ fixes,
71
+ };
72
+ }
73
+ catch (error) {
74
+ const file = configFilePath(paths.config);
75
+ const { files, fixes } = configFiles(file);
76
+ return {
77
+ report: {
78
+ ...common,
79
+ config: { path: file, found: existsSync(file), issues: [] },
80
+ settings: { error: failure(error) },
81
+ profiles: null,
82
+ files,
83
+ },
84
+ fixes,
85
+ };
86
+ }
87
+ };
88
+ /** `doctor` for a CLI that is not a messenger: gcal, drive, zoom. A messenger's is `doctorCommand(messenger)`. */
89
+ export const appDoctorCommand = (app, configuration, options = {}) => profileFree(annotate(new Command("doctor"), {
90
+ effects: LOCAL_READ,
91
+ examples: [`${app.command} doctor`, `${app.command} doctor --json`],
92
+ }))
93
+ .description("check this installation: version, paths, config, profiles, store; no keyring or network")
94
+ .action(function () {
95
+ const env = environmentOf(this).env ?? process.env;
96
+ const { report, fixes } = appDoctorReport(app, configuration, env, this, options);
97
+ const output = outputFor(this);
98
+ renderAnswer(this, output, itemOf(report));
99
+ for (const fix of fixes)
100
+ output.renderer.note(`to make it private: ${fix}`);
101
+ });
@@ -0,0 +1,23 @@
1
+ import type { Command } from "commander";
2
+ import type { AppServerOptions } from "../mcp/app-server.js";
3
+ import type { AppIdentity } from "../ports/app.js";
4
+ import type { Configuration } from "./settings.js";
5
+ export interface AppMcpOptions {
6
+ /** `Google Calendar`: what the instructions call the service. */
7
+ name: string;
8
+ /** The kinds of text other people wrote that the answers carry: `event titles, descriptions, attendee names`. */
9
+ untrusted: AppServerOptions["untrusted"];
10
+ /** One of the CLI's permission keys for `--permission`'s help: `calendar.events.delete=deny`. */
11
+ permissionExample: string;
12
+ skill?: URL;
13
+ /** What the CLI alone knows stops a command for a profile, such as an OAuth grant without the scope. */
14
+ availability?: AppServerOptions["availability"];
15
+ /** Whether the profile can reach the service, read from disk; left out, `mcp check` does not say. */
16
+ signedIn?: (profile: string, env: NodeJS.ProcessEnv) => boolean;
17
+ }
18
+ /**
19
+ * `mcp serve | revoke | server | config | add | check` for a CLI that is not a messenger — the same commands, flags
20
+ * and answers as a messenger's `mcpCommand`, with `--profiles` and `--permission`, served by the CLI's own program
21
+ * (`createAppServer`). gcal, drive and zoom mount this instead of an `mcp` of their own.
22
+ */
23
+ export declare const appMcpCommand: (app: AppIdentity, configuration: Configuration, options: AppMcpOptions) => Command;
@@ -0,0 +1,49 @@
1
+ import { baseContext } from "./context.js";
2
+ import { mcpGroup } from "./messenger/mcp-command.js";
3
+ import { refuseUnknownPermissionKeys } from "./permission-keys.js";
4
+ /**
5
+ * `mcp serve | revoke | server | config | add | check` for a CLI that is not a messenger — the same commands, flags
6
+ * and answers as a messenger's `mcpCommand`, with `--profiles` and `--permission`, served by the CLI's own program
7
+ * (`createAppServer`). gcal, drive and zoom mount this instead of an `mcp` of their own.
8
+ */
9
+ export const appMcpCommand = (app, configuration, options) => {
10
+ const server = () => ({
11
+ app,
12
+ name: options.name,
13
+ untrusted: options.untrusted,
14
+ resolveSettings: configuration.resolveSettings,
15
+ permissions: configuration.permissions,
16
+ ...(options.skill ? { skill: options.skill } : {}),
17
+ ...(options.availability ? { availability: options.availability } : {}),
18
+ });
19
+ // `mcp serve` has no key of its own, so the shared check before a run never looks at the keys --permission names.
20
+ const checked = (self, context) => refuseUnknownPermissionKeys(self, context.settings, app.command, configuration.permissions);
21
+ const host = {
22
+ app,
23
+ name: options.name,
24
+ resolveSettings: configuration.resolveSettings,
25
+ context: (self, given) => baseContext(self, (flags, resolve) => configuration.resolveSettings(flags, { ...resolve, needsProfile: given?.needsProfile ?? true })),
26
+ permissionExample: options.permissionExample,
27
+ serveStdio: async (self, context) => {
28
+ checked(self, context);
29
+ const { serveAppOverStdio } = await import("../mcp/app-server.js");
30
+ await serveAppOverStdio(self, context, server());
31
+ },
32
+ serveHttp: async (self, context, http) => {
33
+ checked(self, context);
34
+ const { serveAppOverHttp } = await import("../mcp/app-server.js");
35
+ await serveAppOverHttp(self, context, server(), http);
36
+ },
37
+ instructions: async (profiles) => {
38
+ const { appInstructions } = await import("../mcp/instructions.js");
39
+ return appInstructions({
40
+ command: app.command,
41
+ name: options.name,
42
+ profile: profiles,
43
+ untrusted: options.untrusted,
44
+ });
45
+ },
46
+ signedIn: (_self, profile, env) => options.signedIn?.(profile, env),
47
+ };
48
+ return mcpGroup(host);
49
+ };
@@ -40,6 +40,8 @@ export { TASK_PAIR_QUERY, TASK_QUERY } from "../services/tasks.js";
40
40
  export { answerStdinOption, type Need, type SignInSteps, type SignInStepsOptions, signInSteps, } from "../terminal/sign-in-steps.js";
41
41
  export { type AgentPolicy, type AgentTask, type EvaluationResult, evaluateAgent, type Observation, } from "./agent-evaluation.js";
42
42
  export { answerEntity } from "./answer-entity.js";
43
+ export { type AppDoctorOptions, appDoctorReport } from "./app-doctor-command.js";
44
+ export type { AppMcpOptions } from "./app-mcp-command.js";
43
45
  export type { ApiCommandInput, ApiCommands } from "./bot/api.js";
44
46
  export { apiFlagOf, apiJson, apiOptionKey, apiPlainJson, checkApiBody, checkApiParameter, parseApiJson, readApiBody, } from "./bot/api-input.js";
45
47
  export { prepareRpcApiBody, type RpcApiBody } from "./bot/api-rpc.js";
@@ -90,7 +92,7 @@ export { terminalAsker } from "./messenger/ask.js";
90
92
  export type { CompletionOptions } from "./messenger/complete-command.js";
91
93
  export { type ConnectOptions, connectFor, type Messenger, type MessengerContext, messengerContext, type ProfileState, type ReadConnection, type StoredMessages, } from "./messenger/context.js";
92
94
  export { COMMAND_NEEDS } from "./messenger/lacks.js";
93
- export { httpTokenFile, type McpEnvironment, serverEntry } from "./messenger/mcp-command.js";
95
+ export { httpTokenFile, type McpEnvironment, type McpHost, serverEntry } from "./messenger/mcp-command.js";
94
96
  export { type MessageItem, messageItem, type ReadMessage } from "./messenger/message-items.js";
95
97
  export { type ModeProblem, type PrivateFiles, privateFiles, withSqliteSidecars } from "./messenger/private-files.js";
96
98
  export { buildReport as buildDoctorReport, type Report as DoctorReport, type ReportContext as DoctorReportContext, reportFileName as doctorReportFileName, } from "./messenger/report.js";
@@ -111,7 +113,7 @@ export { fieldsOf, projectFields } from "./result-fields.js";
111
113
  export { type Config, type Configuration, count, first, flag, fromFile, type GlobalFlags, NONE_NAMED, namedProfile, type ProfileKind, plain, type ResolveOptions, type Settings, type SettingsExtension, type SettingsExtensionContext, type Source, settingsFor, } from "./settings.js";
112
114
  export { type PermissionAnswer, readSetupAnswers, type SetupAnswers, setupPermissionCeiling } from "./setup-answers.js";
113
115
  export { AGENTS, type Agent, agentFor, screenFor } from "./setup-screen.js";
114
- export { accountCommand, addMeetingBatchCommand, addMeetingPreparationCommand, addMeetingProjectCandidatesCommand, addMeetingSeriesInventoryCommand, attachmentsCommand, botAdminsCommand, botCommand, botMcpCommand, botMembersCommand, botMessagesCommand, callsCommand, chatsCommand, commandsCommand, completeCommand, configCommand, contactsCommand, conversationsCommand, deleteCommand, doctorCommand, editCommand, floodCommand, forwardCommand, generatedApiCommand, guideCommand, imagesCommand, inboxCommand, markReadCommand, mcpCommand, mentionsCommand, messagesCommand, metadataCommand, modelCatalogueCommand, modelsCommand, pinCommand, pollsCommand, reactionsCommand, recipientsCommand, repliesCommand, reviewCommand, runsCommand, scheduleCommand, searchCommand, searchesCommand, sendCommand, sendsCommand, serveCommand, serverCommand, skillCommand, starCommands, statsCommand, stickersCommand, storeCommand, tagsCommand, tasksCommand, tasksStatsCommand, topicsCommand, unpinCommand, upgradeCommand, watchCommand, } from "./shared-command-exports.js";
116
+ export { accountCommand, addMeetingBatchCommand, addMeetingPreparationCommand, addMeetingProjectCandidatesCommand, addMeetingSeriesInventoryCommand, appDoctorCommand, appMcpCommand, attachmentsCommand, botAdminsCommand, botCommand, botMcpCommand, botMembersCommand, botMessagesCommand, callsCommand, chatsCommand, commandsCommand, completeCommand, configCommand, contactsCommand, conversationsCommand, deleteCommand, doctorCommand, editCommand, floodCommand, forwardCommand, generatedApiCommand, guideCommand, imagesCommand, inboxCommand, markReadCommand, mcpCommand, mentionsCommand, messagesCommand, metadataCommand, modelCatalogueCommand, modelsCommand, pinCommand, pollsCommand, reactionsCommand, recipientsCommand, repliesCommand, reviewCommand, runsCommand, scheduleCommand, searchCommand, searchesCommand, sendCommand, sendsCommand, serveCommand, serverCommand, skillCommand, starCommands, statsCommand, stickersCommand, storeCommand, tagsCommand, tasksCommand, tasksStatsCommand, topicsCommand, unpinCommand, upgradeCommand, watchCommand, } from "./shared-command-exports.js";
115
117
  export { assertSharedContracts, customizeSharedCommand, hasSharedContract, overrideSharedContract, type SharedContractOverride, sharedContractOverrides, sharedContracts, } from "./shared-contracts.js";
116
118
  export { runnable, withSafety } from "./steps.js";
117
119
  export { type StoreInfo, sharedStoreCommand, storeInfo, storeInfoCommand } from "./store-info.js";
package/dist/cli/index.js CHANGED
@@ -35,6 +35,7 @@ export { TASK_PAIR_QUERY, TASK_QUERY } from "../services/tasks.js";
35
35
  export { answerStdinOption, signInSteps, } from "../terminal/sign-in-steps.js";
36
36
  export { evaluateAgent, } from "./agent-evaluation.js";
37
37
  export { answerEntity } from "./answer-entity.js";
38
+ export { appDoctorReport } from "./app-doctor-command.js";
38
39
  export { apiFlagOf, apiJson, apiOptionKey, apiPlainJson, checkApiBody, checkApiParameter, parseApiJson, readApiBody, } from "./bot/api-input.js";
39
40
  export { prepareRpcApiBody } from "./bot/api-rpc.js";
40
41
  export { botContext, botWords } from "./bot/context.js";
@@ -102,7 +103,7 @@ export { fieldsOf, projectFields } from "./result-fields.js";
102
103
  export { count, first, flag, fromFile, NONE_NAMED, namedProfile, plain, settingsFor, } from "./settings.js";
103
104
  export { readSetupAnswers, setupPermissionCeiling } from "./setup-answers.js";
104
105
  export { AGENTS, agentFor, screenFor } from "./setup-screen.js";
105
- export { accountCommand, addMeetingBatchCommand, addMeetingPreparationCommand, addMeetingProjectCandidatesCommand, addMeetingSeriesInventoryCommand, attachmentsCommand, botAdminsCommand, botCommand, botMcpCommand, botMembersCommand, botMessagesCommand, callsCommand, chatsCommand, commandsCommand, completeCommand, configCommand, contactsCommand, conversationsCommand, deleteCommand, doctorCommand, editCommand, floodCommand, forwardCommand, generatedApiCommand, guideCommand, imagesCommand, inboxCommand, markReadCommand, mcpCommand, mentionsCommand, messagesCommand, metadataCommand, modelCatalogueCommand, modelsCommand, pinCommand, pollsCommand, reactionsCommand, recipientsCommand, repliesCommand, reviewCommand, runsCommand, scheduleCommand, searchCommand, searchesCommand, sendCommand, sendsCommand, serveCommand, serverCommand, skillCommand, starCommands, statsCommand, stickersCommand, storeCommand, tagsCommand, tasksCommand, tasksStatsCommand, topicsCommand, unpinCommand, upgradeCommand, watchCommand, } from "./shared-command-exports.js";
106
+ export { accountCommand, addMeetingBatchCommand, addMeetingPreparationCommand, addMeetingProjectCandidatesCommand, addMeetingSeriesInventoryCommand, appDoctorCommand, appMcpCommand, attachmentsCommand, botAdminsCommand, botCommand, botMcpCommand, botMembersCommand, botMessagesCommand, callsCommand, chatsCommand, commandsCommand, completeCommand, configCommand, contactsCommand, conversationsCommand, deleteCommand, doctorCommand, editCommand, floodCommand, forwardCommand, generatedApiCommand, guideCommand, imagesCommand, inboxCommand, markReadCommand, mcpCommand, mentionsCommand, messagesCommand, metadataCommand, modelCatalogueCommand, modelsCommand, pinCommand, pollsCommand, reactionsCommand, recipientsCommand, repliesCommand, reviewCommand, runsCommand, scheduleCommand, searchCommand, searchesCommand, sendCommand, sendsCommand, serveCommand, serverCommand, skillCommand, starCommands, statsCommand, stickersCommand, storeCommand, tagsCommand, tasksCommand, tasksStatsCommand, topicsCommand, unpinCommand, upgradeCommand, watchCommand, } from "./shared-command-exports.js";
106
107
  export { assertSharedContracts, customizeSharedCommand, hasSharedContract, overrideSharedContract, sharedContractOverrides, sharedContracts, } from "./shared-contracts.js";
107
108
  export { runnable, withSafety } from "./steps.js";
108
109
  export { sharedStoreCommand, storeInfo, storeInfoCommand } from "./store-info.js";
@@ -1,9 +1,10 @@
1
1
  import { type ChildProcessWithoutNullStreams } from "node:child_process";
2
2
  import { Command } from "commander";
3
3
  import type { ServerSystem } from "../../background/system.js";
4
+ import type { HttpOptions } from "../../mcp/http/serve.js";
4
5
  import { type AppIdentity } from "../../ports/app.js";
5
- import { type BaseEnvironment } from "../context.js";
6
- import { type Settings } from "../settings.js";
6
+ import { type BaseContext, type BaseEnvironment } from "../context.js";
7
+ import { type GlobalFlags, type ResolveOptions, type Settings } from "../settings.js";
7
8
  import { type Messenger } from "./context.js";
8
9
  /** Where the running CLI really lives; a test hands in its own. */
9
10
  export interface McpEnvironment extends BaseEnvironment {
@@ -38,7 +39,7 @@ export interface ProfileSet {
38
39
  * takes the place of `<PREFIX>_PROFILE`; under `<PREFIX>_PROFILE_LOCK` it may name the locked profile only
39
40
  * (WC-ACCT-5).
40
41
  */
41
- export declare const servedProfiles: (self: Command, messenger: Messenger, { settings, env }: {
42
+ export declare const servedProfiles: (self: Command, messenger: Pick<Messenger, "app" | "resolveSettings">, { settings, env }: {
42
43
  settings: Pick<Settings, "profile" | "sources" | "profilesHere">;
43
44
  env: NodeJS.ProcessEnv;
44
45
  }, given: string | undefined, words: string) => {
@@ -48,7 +49,32 @@ export declare const servedProfiles: (self: Command, messenger: Messenger, { set
48
49
  };
49
50
  /** Where `mcp serve --http` keeps the hashes of the tokens it issued — per profile, in the state folder. */
50
51
  export declare const httpTokenFile: (app: AppIdentity, profile: string, env: NodeJS.ProcessEnv) => string;
52
+ /**
53
+ * What the `mcp` group needs of the CLI it serves. A messenger serves through its one connection (`messengerHost`);
54
+ * a CLI that is not a messenger through its own program (`appMcpCommand`). The commands, flags and answers are the
55
+ * same in both, so every WireCat CLI has one `mcp`.
56
+ */
57
+ export interface McpHost {
58
+ app: AppIdentity;
59
+ /** `Telegram`, `Google Calendar`: what the instructions call the service. */
60
+ name: string;
61
+ resolveSettings: (flags: GlobalFlags, options?: ResolveOptions) => Settings;
62
+ context: (self: Command, options?: {
63
+ needsProfile?: boolean;
64
+ }) => BaseContext;
65
+ /** A permission key of this CLI for `--permission`'s help: `messages.send=deny`. */
66
+ permissionExample: string;
67
+ serveStdio: (self: Command, context: BaseContext) => Promise<void>;
68
+ serveHttp: (self: Command, context: BaseContext, http: Omit<HttpOptions, "onCode" | "onError" | "appName">) => Promise<void>;
69
+ /** The instructions of the server of several profiles, whose tools each take `profile`. */
70
+ instructions: (profiles: readonly string[]) => string | Promise<string>;
71
+ /** Whether the profile can reach the service; `undefined` where the CLI cannot tell without connecting. */
72
+ signedIn: (self: Command, profile: string, env: NodeJS.ProcessEnv) => boolean | undefined;
73
+ /** A profile that is a bot, or not signed in here; the server of several profiles leaves bots out. */
74
+ profileState?: Messenger["profileState"];
75
+ }
51
76
  export declare const mcpCommand: (messenger: Messenger) => Command;
77
+ export declare const mcpGroup: (host: McpHost) => Command;
52
78
  /** How the startup and status lines name a set, so the owner sees which accounts an agent reaches. */
53
79
  export declare const profileSetLabel: (set: ProfileSet) => string;
54
80
  /**