@wirecat/cli-core 0.410.0 → 0.412.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 (113) hide show
  1. package/CHANGELOG.md +44 -0
  2. package/dist/cli/bot/command.js +4 -3
  3. package/dist/cli/bot/messages-sync.d.ts +7 -0
  4. package/dist/cli/bot/{store.js → messages-sync.js} +4 -5
  5. package/dist/cli/bot/port.d.ts +4 -4
  6. package/dist/cli/bot/setup.js +11 -5
  7. package/dist/cli/commands-command.js +18 -12
  8. package/dist/cli/config-command.js +1 -0
  9. package/dist/cli/contract-evidence.d.ts +26 -0
  10. package/dist/cli/contract-evidence.js +58 -0
  11. package/dist/cli/contract-templates.d.ts +4 -0
  12. package/dist/cli/contract-templates.js +83 -0
  13. package/dist/cli/discovery-descriptions.d.ts +4 -0
  14. package/dist/cli/discovery-descriptions.js +4 -0
  15. package/dist/cli/index.d.ts +21 -55
  16. package/dist/cli/index.js +18 -55
  17. package/dist/cli/messenger/chat-answers.d.ts +1 -1
  18. package/dist/cli/messenger/chat-answers.js +1 -1
  19. package/dist/cli/messenger/chat-lists.d.ts +1 -1
  20. package/dist/cli/messenger/chats-command.js +3 -0
  21. package/dist/cli/messenger/contacts-command.js +23 -15
  22. package/dist/cli/messenger/guard-commands.d.ts +5 -1
  23. package/dist/cli/messenger/guard-commands.js +5 -3
  24. package/dist/cli/messenger/messages-press-command.js +4 -1
  25. package/dist/cli/messenger/models-command.js +3 -11
  26. package/dist/cli/messenger/records-command.js +1 -1
  27. package/dist/cli/messenger/store-maintenance-command.d.ts +1 -1
  28. package/dist/cli/messenger/tasks-command.js +14 -4
  29. package/dist/cli/model-catalogue-command.d.ts +15 -0
  30. package/dist/cli/model-catalogue-command.js +110 -0
  31. package/dist/cli/moved.js +1 -0
  32. package/dist/cli/program.js +2 -0
  33. package/dist/cli/runs/search-command.js +2 -3
  34. package/dist/cli/runs/search-query.d.ts +1 -1
  35. package/dist/cli/runs/search-query.js +18 -2
  36. package/dist/cli/runs/search.d.ts +2 -1
  37. package/dist/cli/runs/search.js +4 -3
  38. package/dist/cli/settings.d.ts +2 -0
  39. package/dist/cli/settings.js +5 -1
  40. package/dist/cli/shared-command-exports.d.ts +644 -0
  41. package/dist/cli/shared-command-exports.js +114 -0
  42. package/dist/cli/shared-contracts.d.ts +1 -0
  43. package/dist/cli/shared-contracts.js +1 -0
  44. package/dist/domain/providers.d.ts +25 -3
  45. package/dist/domain/providers.js +89 -5
  46. package/dist/entities/chat.d.ts +3 -3
  47. package/dist/entities/chat.js +2 -2
  48. package/dist/entities/contact-context.d.ts +8 -8
  49. package/dist/entities/contact.d.ts +4 -4
  50. package/dist/entities/index.d.ts +40 -13
  51. package/dist/entities/index.js +5 -1
  52. package/dist/entities/knowledge-lists.d.ts +28 -0
  53. package/dist/entities/knowledge-lists.js +29 -0
  54. package/dist/entities/list-results.d.ts +1 -1
  55. package/dist/entities/list-results.js +1 -1
  56. package/dist/entities/send-attempt.d.ts +0 -1
  57. package/dist/entities/send-attempt.js +0 -1
  58. package/dist/errors/reasons.d.ts +1 -1
  59. package/dist/errors/reasons.js +7 -0
  60. package/dist/index.d.ts +1 -0
  61. package/dist/index.js +1 -0
  62. package/dist/meetings/cli/index.d.ts +1 -1
  63. package/dist/meetings/cli/index.js +25 -9
  64. package/dist/meetings/cli/passage.d.ts +0 -1
  65. package/dist/meetings/cli/passage.js +5 -3
  66. package/dist/meetings/cli/project-evidence.js +3 -2
  67. package/dist/meetings/cli/search.d.ts +2 -2
  68. package/dist/meetings/cli/search.js +9 -7
  69. package/dist/meetings/event-query.d.ts +1 -0
  70. package/dist/meetings/event-query.js +15 -0
  71. package/dist/meetings/index.d.ts +1 -0
  72. package/dist/meetings/index.js +1 -0
  73. package/dist/meetings/store.d.ts +2 -0
  74. package/dist/meetings/testing/memory.js +5 -0
  75. package/dist/search/account-list.d.ts +5 -2
  76. package/dist/search/account-list.js +27 -11
  77. package/dist/search/query.js +3 -1
  78. package/dist/sends/permission-aliases.js +1 -0
  79. package/dist/services/documents/knowledge.d.ts +5 -3
  80. package/dist/services/documents/knowledge.js +4 -4
  81. package/dist/services/meeting-links.d.ts +3 -1
  82. package/dist/services/meeting-links.js +2 -2
  83. package/dist/services/messages-search.js +15 -3
  84. package/dist/services/search-all.js +5 -2
  85. package/dist/services/tasks.d.ts +2 -0
  86. package/dist/services/tasks.js +6 -4
  87. package/dist/store/accounts.d.ts +3 -0
  88. package/dist/store/accounts.js +2 -0
  89. package/dist/store/exports.d.ts +1 -0
  90. package/dist/store/exports.js +1 -0
  91. package/dist/store/index.d.ts +3 -1
  92. package/dist/store/index.js +2 -0
  93. package/dist/store/knowledge-query.d.ts +6 -0
  94. package/dist/store/knowledge-query.js +34 -0
  95. package/dist/store/providers.d.ts +7 -0
  96. package/dist/store/providers.js +5 -0
  97. package/dist/store/sqlite/events.d.ts +2 -1
  98. package/dist/store/sqlite/events.js +16 -1
  99. package/dist/store/sqlite/knowledge.d.ts +5 -4
  100. package/dist/store/sqlite/knowledge.js +50 -17
  101. package/dist/store/sqlite/mail-rules.d.ts +2 -1
  102. package/dist/store/sqlite/mail-rules.js +12 -2
  103. package/dist/store/sqlite/meetings.js +3 -0
  104. package/dist/store/sqlite/notes.d.ts +11 -5
  105. package/dist/store/sqlite/notes.js +9 -2
  106. package/dist/store/sqlite/open-store.js +2 -0
  107. package/dist/store/sqlite/providers.d.ts +12 -0
  108. package/dist/store/sqlite/providers.js +45 -0
  109. package/dist/store/sqlite/tags.d.ts +1 -1
  110. package/dist/store/sqlite/tags.js +3 -3
  111. package/package.json +3 -3
  112. package/parity.json +92 -111
  113. package/dist/cli/bot/store.d.ts +0 -7
package/CHANGELOG.md CHANGED
@@ -5,6 +5,50 @@ Notable changes to `@wirecat/cli-core` (`@wirecat/cli-messaging` up to 0.261.0,
5
5
  minor version may break callers, and says how under "Changed — may break callers". `pnpm docs:check` checks the
6
6
  shape of this file.
7
7
 
8
+
9
+ ## 0.412.0 — 24.10.2026
10
+
11
+ ### Added
12
+
13
+ - **A stored provider registry** (available from cli-core 0.413.0). `registerProvider(store, { name, kind, aliases, command })` (from `@wirecat/cli-core/store`) writes a CLI's entry into `store_settings` under the key `providers`; every store handle loads the stored entries when it opens, so `kindOf`, `providerNamed` and `--source` in every CLI know a provider cli-core does not list. The built-ins stay the seed. `useProviders(entries)`, `kindIn(provider)`, `providerNamed`, `kindOf`, `providers()`, `KINDS` and `PROVIDERS` are exported from `@wirecat/cli-core`. Two entries that disagree on a kind, or an alias another provider has, are a `validation_error` naming both; a stored entry that clashes with a built-in is left out when the store opens, so it never stops the store opening.
14
+ - **Knowledge lists filter at their native readers.** Organizations, projects, reminders and mail rules accept optional queries before SQL list bounds. Document tags and links accept native selectors, and meeting-link reads can select one URL before aggregation. Existing unfiltered calls keep their behavior.
15
+
16
+ ### Changed — may break callers
17
+
18
+ - **A provider no registry entry names is skipped, never searched as messages** (available from cli-core 0.413.0). `search messages`, `search all` and `--source` lists report each of its accounts under `skipped` with the reason "unknown provider — run its CLI once" (code `not_found`). The account the search runs as is still read, whatever its provider. `kindOf` keeps its signature and its `messages` default; `kindIn` answers `undefined` for such a provider. `ListedAccount.kind` is now `Kind | undefined`.
19
+ - **`KINDS` and `Kind` gain `events`** (available from cli-core 0.413.0). No search reads events yet; `--source events` says so.
20
+ - **`bot store fetch` is now `bot messages sync`, and the `bot store` group is gone** (tg and max). It does what the personal `messages sync` does, so it carries the same name; `store` is for the local database. The old path answers with a pointer to the new one, and a saved `permissions.bot.store.fetch` is refused until it is renamed to `permissions.bot.messages.sync`. A CLI that customizes the command must move its override to the new path.
21
+
22
+ ### Fixed
23
+
24
+ - **`config set` and `config unset` work while a moved permission key is saved.** Every other command still refuses the old key and names its replacement; `config unset permissions.<old>` and `config set permissions.<new>` now fix it instead of failing with the same error.
25
+ - **`tasks update <task> --parent none` clears the parent.** The CLI keeps the sentinel through option parsing and converts it to null when building the plan, so Commander cannot turn it into an empty task id.
26
+
27
+ ## 0.411.0 — 24.10.2026
28
+
29
+ ### Added
30
+
31
+ - **Stored events accept native queries on id, origin and timestamps.** SQLite applies filters before returning rows; stores without query support refuse a filtered request.
32
+ - **Shared task updates include project priority and parent.** Project tasks can be updated without choosing a messenger account.
33
+
34
+ - **`commands info --json` exports schemas, declared error reasons and explicit contract overrides.** Providers with
35
+ their own program shell use `addContractInfo`; field-only declarations are labelled separately from typed schemas.
36
+ - **Provider model catalogues share `modelCatalogueCommand`.** Providers choose supported kinds and bind output,
37
+ environment and offline policy; native query filtering, model receipts and verified downloads stay in core.
38
+
39
+
40
+ ### Changed — may break callers
41
+
42
+ - **Contact activity and diagnostic run times filter through native queries.** Use `contacts events <person> scope:work 'at:[2026-10-01 TO 2026-10-31]'` and `search runs 'started_at>=7d'` instead of their time/scope flags. Time bounds reach the native readers before pagination, and continuations preserve the query.
43
+ - **Webhook setup adds another address with `--append`.** `--add <chat>` keeps its folder-edit meaning. Webhook answers omit an unrestricted or unknown type list instead of emitting `types: null`.
44
+
45
+ - **Unknown chat rosters are omitted instead of returned as `members: null`.** An empty array means a known empty roster. Send-attempt output exposes only `operation_id`; legacy journal entries remain readable.
46
+ - **Stored meeting topic labels use `--topic-name`.** `--topic` remains the messenger forum-topic id. Update meeting-search invocations and continuations to the unambiguous name.
47
+
48
+ - **Core-owned command contracts reject silent edits after construction.** Use `overrideSharedContract` with a
49
+ specific reason and a callback before modifying an inherited definition. Exact before/after values remain visible
50
+ in contract discovery. Independent shell replacements pin static, reviewed declarations, so new Core defaults cannot be silently omitted. Provider-only commands may extend groups; inherited leaves retain their contracts.
51
+
8
52
  ## 0.410.0 — 24.10.2026
9
53
 
10
54
  ### Added
@@ -16,12 +16,12 @@ import { botExamples } from "./examples.js";
16
16
  import { BOT_CHATS_QUERY, BOT_PROFILES_QUERY, botChatFilter, botProfileName } from "./list-queries.js";
17
17
  import { botMcpCommand } from "./mcp.js";
18
18
  import { botCan, botIdOf, botMessagesCommand } from "./messages.js";
19
+ import { botMessagesSyncCommand } from "./messages-sync.js";
19
20
  import { botModerateCommand, botRulesCommand } from "./moderation.js";
20
21
  import { addBotCopyReads, botContactsCommand, botSearchCommand } from "./people.js";
21
22
  import { BOT_ACTIONS } from "./port.js";
22
23
  import { registryProfiles } from "./registry.js";
23
24
  import { botCallbacksCommand, botMenuCommand, botWebhooksCommand } from "./setup.js";
24
- import { botStoreCommand } from "./store.js";
25
25
  import { BotTokenStore } from "./token.js";
26
26
  import { botWatchCommand } from "./watch.js";
27
27
  /** Where each of the messenger's other secrets comes from, `null` when it is not set; never the value. */
@@ -105,6 +105,7 @@ const authCommand = (bot, tokenVariable) => {
105
105
  return auth;
106
106
  };
107
107
  const meCommand = (bot) => annotate(new Command("me"), { effects: REMOTE_READ, examples: botExamples(bot, "me") })
108
+ .summary("the bot this profile's token belongs to")
108
109
  .description("the bot this profile's token belongs to: id, name and username")
109
110
  .action(async function () {
110
111
  const context = online(botContext(this, bot), this);
@@ -288,6 +289,8 @@ const chatsCommand = (bot) => {
288
289
  */
289
290
  const withCopyReads = (messages, bot) => {
290
291
  addBotCopyReads(messages, bot);
292
+ if (bot.fetching)
293
+ messages.addCommand(botMessagesSyncCommand(bot, bot.fetching));
291
294
  return messages;
292
295
  };
293
296
  export const botCommand = (bot) => {
@@ -309,7 +312,5 @@ export const botCommand = (bot) => {
309
312
  .addCommand(botContactsCommand(bot));
310
313
  if (bot.identity)
311
314
  command.addCommand(meCommand(bot));
312
- if (bot.fetching)
313
- command.addCommand(botStoreCommand(bot, bot.fetching));
314
315
  return bot.mcp ? command.addCommand(botMcpCommand(bot)) : command;
315
316
  };
@@ -0,0 +1,7 @@
1
+ import { Command } from "commander";
2
+ import type { BotMessenger } from "./port.js";
3
+ /**
4
+ * `bot messages sync`: a chat's history into the bot's local copy, newest to oldest and resumable, as the
5
+ * personal `messages sync` does. Mounted for a messenger whose Bot API pages back through a chat.
6
+ */
7
+ export declare const botMessagesSyncCommand: (bot: BotMessenger, fetching: NonNullable<BotMessenger["fetching"]>) => Command;
@@ -16,12 +16,11 @@ const wholeNumber = (value) => {
16
16
  return parsed;
17
17
  };
18
18
  /**
19
- * `bot store fetch`: a chat's history into the bot's local copy, newest to oldest and resumable, as the
19
+ * `bot messages sync`: a chat's history into the bot's local copy, newest to oldest and resumable, as the
20
20
  * personal `messages sync` does. Mounted for a messenger whose Bot API pages back through a chat.
21
21
  */
22
- export const botStoreCommand = (bot, fetching) => {
23
- const command = new Command("store").description("the bot's local copy on this machine");
24
- const fetch = annotate(command.command("fetch"), { effects: FETCH })
22
+ export const botMessagesSyncCommand = (bot, fetching) => {
23
+ const fetch = annotate(new Command("sync"), { effects: FETCH })
25
24
  .description("fetch a chat's history into the bot's local copy, newest first; run it again to continue")
26
25
  .argument("<chat>", "a chat id, or the title of a chat this bot has seen")
27
26
  .option("--limit <n>", `at most this many messages in this run; ${fetching.maxPages * fetching.page} if not given`, wholeNumber)
@@ -85,5 +84,5 @@ export const botStoreCommand = (bot, fetching) => {
85
84
  stop.release();
86
85
  }
87
86
  });
88
- return command;
87
+ return fetch;
89
88
  };
@@ -53,7 +53,7 @@ export interface BotHistory {
53
53
  messages: Message[];
54
54
  more: boolean;
55
55
  }>;
56
- /** One page back from `before` (or from now), newest first: what `bot store fetch` walks. */
56
+ /** One page back from `before` (or from now), newest first: what `bot messages sync` walks. */
57
57
  historyBefore(chat: BotChatRef, window: {
58
58
  limit: number;
59
59
  before?: string;
@@ -250,7 +250,7 @@ export interface BotNativeApi {
250
250
  export interface BotConnectOptions {
251
251
  stop?: AbortSignal;
252
252
  events?: EventSink;
253
- /** Only `bot store fetch` asks for a history reader; other commands stay on the Bot API. */
253
+ /** Only `bot messages sync` asks for a history reader; other commands stay on the Bot API. */
254
254
  history?: {
255
255
  from?: string;
256
256
  pauseMs: number;
@@ -267,7 +267,7 @@ export interface BotMessenger {
267
267
  name?: string;
268
268
  /** The admin rights `--can` offers; every shared one when unset. */
269
269
  adminRights?: readonly AdminRight[];
270
- /** Whether `bot webhooks set --add` keeps the other addresses; a messenger with one address has no `--add`. */
270
+ /** Whether `bot webhooks set --append` keeps the other addresses; a messenger with one address has no `--add`. */
271
271
  manyWebhooks?: boolean;
272
272
  /** Secrets beside the token, each set with `bot auth set --secret <name>`; none when unset. */
273
273
  secrets?: readonly BotSecret[];
@@ -295,7 +295,7 @@ export interface BotMessenger {
295
295
  readSecret?: (command: Command, prompt: string) => Promise<string>;
296
296
  /** What kind of chat a stored message came from; without it a positive id is a dialog, a negative one a group. */
297
297
  chatKindOf?: (hit: StoredHit) => ChatKind;
298
- /** How its history pages, for `bot store fetch`, which is mounted only when this is set. */
298
+ /** How its history pages, for `bot messages sync`, which is mounted only when this is set. */
299
299
  /** `from`: the help of `--until-id`, the message the fetch starts at; the option is mounted only when set. */
300
300
  fetching?: Fetching & {
301
301
  from?: string;
@@ -121,7 +121,10 @@ export const botWebhooksCommand = (bot) => {
121
121
  const context = online(botContext(this, bot), this);
122
122
  await context.run(async (events) => {
123
123
  const adapter = await context.authenticated({ events });
124
- renderAnswer(this, context, wholeList("bot webhooks list", (await botCan(adapter, "webhooks", bot, "list its webhooks")()).map(snakeKeys)));
124
+ renderAnswer(this, context, wholeList("bot webhooks list", (await botCan(adapter, "webhooks", bot, "list its webhooks")()).map(({ url, types }) => ({
125
+ url,
126
+ ...(types == null ? {} : { types }),
127
+ }))));
125
128
  });
126
129
  });
127
130
  const set = annotate(command.command("set"), {
@@ -133,7 +136,7 @@ export const botWebhooksCommand = (bot) => {
133
136
  .option("--types <types>", "only these update types, comma-separated, in the messenger's words")
134
137
  .option("--secret-stdin", "a secret the messenger sends back with each update — asked for, or read from a pipe");
135
138
  if (bot.manyWebhooks)
136
- set.option("--add", "keep the webhooks already set and add this one beside them");
139
+ set.option("--append", "keep the webhooks already set and add this one beside them");
137
140
  set.action(async function (url) {
138
141
  const context = online(botContext(this, bot), this);
139
142
  const options = this.opts();
@@ -141,10 +144,10 @@ export const botWebhooksCommand = (bot) => {
141
144
  const adapter = await context.authenticated({ events });
142
145
  const list = botCan(adapter, "webhooks", bot, "list its webhooks");
143
146
  const others = (await list()).filter((one) => one.url !== url);
144
- if (others.length > 0 && !options.add) {
147
+ if (others.length > 0 && !options.append) {
145
148
  throw new CliError("confirmation_required", `this bot already sends its updates to ${others.map((one) => one.url).join(", ")} — ` +
146
149
  `remove it first with \`${context.words} webhooks delete <url>\`` +
147
- (bot.manyWebhooks ? ", or give --add to get every update at both" : ""));
150
+ (bot.manyWebhooks ? ", or give --append to get every update at both" : ""));
148
151
  }
149
152
  const types = typesOf(options.types);
150
153
  const setWebhook = botCan(adapter, "setWebhook", bot, "set a webhook");
@@ -170,7 +173,10 @@ export const botWebhooksCommand = (bot) => {
170
173
  const adapter = await context.authenticated({ events });
171
174
  const remove = botCan(adapter, "deleteWebhook", bot, "delete a webhook");
172
175
  await botWrite(context, "bot.webhooks.delete", () => remove(url));
173
- renderAnswer(this, context, wholeList("bot webhooks list", (await botCan(adapter, "webhooks", bot, "list its webhooks")()).map(snakeKeys)));
176
+ renderAnswer(this, context, wholeList("bot webhooks list", (await botCan(adapter, "webhooks", bot, "list its webhooks")()).map(({ url, types }) => ({
177
+ url,
178
+ ...(types == null ? {} : { types }),
179
+ }))));
174
180
  });
175
181
  });
176
182
  return command;
@@ -4,6 +4,8 @@ import { CRASH_CODE } from "@wirecat/cli-base/standards";
4
4
  import { Command } from "commander";
5
5
  import { commandContract, commandPathOf, findCommand } from "./command-contract.js";
6
6
  import { environmentOf, outputFor } from "./context.js";
7
+ import { contractEvidence } from "./contract-evidence.js";
8
+ import { DISCOVERY_DESCRIPTIONS } from "./discovery-descriptions.js";
7
9
  import { NO_EFFECTS } from "./effects.js";
8
10
  import { renderDocument } from "./envelope.js";
9
11
  import { commandsText } from "./help/commands-text.js";
@@ -19,7 +21,7 @@ export const CONTRACT = 3;
19
21
  */
20
22
  export const commandsCommand = (app) => {
21
23
  const command = annotate(new Command("commands"), { effects: NO_EFFECTS })
22
- .description("every command by section, one line each; --json: the contract, one path per call")
24
+ .description(DISCOVERY_DESCRIPTIONS.commands)
23
25
  .hook("preAction", (_command, action) => {
24
26
  if (action.optsWithGlobals().jsonl)
25
27
  throw new CliError("validation_error", "command discovery is one JSON object — use --json", {
@@ -59,22 +61,26 @@ export const commandsCommand = (app) => {
59
61
  effects: NO_EFFECTS,
60
62
  examples: [`${app.command} commands info messages list`],
61
63
  })
62
- .description("one command's argv and result schemas, effects, permissions and retry guidance")
63
- .argument("<path...>", "one command path, for example: stats messages show")
64
+ .description(DISCOVERY_DESCRIPTIONS.info)
65
+ .argument("[path...]", "one command path; without one, export schemas, error reasons and explicit overrides")
64
66
  .action(function (path) {
65
67
  renderDocument(outputFor(this), {
66
68
  cli: app.command,
67
69
  version: app.version,
68
70
  contract: CONTRACT,
69
- ...commandContract(findCommand(rootOf(this), path)),
70
- ...(() => {
71
- const found = findCommand(rootOf(this), path);
72
- const availability = environmentOf(this).discoveryAvailability?.({
73
- ...metaOf(found),
74
- path: commandPathOf(found),
75
- });
76
- return availability ? { availability } : {};
77
- })(),
71
+ ...(path.length
72
+ ? {
73
+ ...commandContract(findCommand(rootOf(this), path)),
74
+ ...(() => {
75
+ const found = findCommand(rootOf(this), path);
76
+ const availability = environmentOf(this).discoveryAvailability?.({
77
+ ...metaOf(found),
78
+ path: commandPathOf(found),
79
+ });
80
+ return availability ? { availability } : {};
81
+ })(),
82
+ }
83
+ : contractEvidence(rootOf(this), app.errors ? { errors: app.errors } : {})),
78
84
  });
79
85
  }));
80
86
  return command;
@@ -64,6 +64,7 @@ export const configCommand = (app, config, { permissionKey } = {}) => {
64
64
  const context = baseContext(this, (flags, options) => config.resolveSettings(flags, {
65
65
  ...options,
66
66
  needsProfile: !everyone && setting !== "default_profile" && !isStoreSetting(setting),
67
+ skipMovedPermissions: true,
67
68
  }));
68
69
  const { settings, renderer, env } = context;
69
70
  if (isStoreSetting(setting)) {
@@ -0,0 +1,26 @@
1
+ import type { Command } from "commander";
2
+ import { type AppErrors } from "../errors/reasons.js";
3
+ import type { JsonFieldsResolver } from "./json-fields.js";
4
+ export interface ContractEvidenceOptions {
5
+ fields?: JsonFieldsResolver;
6
+ errors?: AppErrors;
7
+ }
8
+ export declare const contractEvidence: (root: Command, { fields, errors }?: ContractEvidenceOptions) => {
9
+ schemas: {
10
+ [k: string]: {
11
+ $schema: string;
12
+ };
13
+ };
14
+ contracts: Record<string, unknown>;
15
+ field_only: string[];
16
+ reasons: readonly {
17
+ reason: string;
18
+ code: "authentication_error" | "cancelled" | "configuration_error" | "confirmation_required" | "internal_error" | "invalid_response" | "network_error" | "not_found" | "outcome_unknown" | "permission_error" | "provider_error" | "provider_unavailable" | "rate_limited" | "timeout" | "validation_error";
19
+ message: string;
20
+ details: string[];
21
+ step?: string | undefined;
22
+ }[] | undefined;
23
+ overrides: import("@wirecat/cli-base/commands").SharedContractOverride[];
24
+ };
25
+ /** Same discovery endpoint for the shared runner and providers with their own output/context adapters. */
26
+ export declare const addContractInfo: (root: Command, output: (value: unknown) => void, options?: ContractEvidenceOptions) => Command;
@@ -0,0 +1,58 @@
1
+ import { CliError } from "@wirecat/cli-base";
2
+ import { annotate, describeProgram, flatten } from "@wirecat/cli-base/commands";
3
+ import { jsonSchemaOf } from "@wirecat/cli-base/standards";
4
+ import { entityDefinitions } from "../entities/index.js";
5
+ import { failureContext } from "../errors/reasons.js";
6
+ import { answerEntitySchema } from "./answer-entity.js";
7
+ import { commandContract, findCommand, SCHEMA_DIALECT } from "./command-contract.js";
8
+ import { DISCOVERY_DESCRIPTIONS } from "./discovery-descriptions.js";
9
+ import { NO_EFFECTS } from "./effects.js";
10
+ import { sharedContractOverrides, sharedContracts } from "./shared-contracts.js";
11
+ export const contractEvidence = (root, { fields, errors } = {}) => {
12
+ const schemas = { ...entityDefinitions() };
13
+ const fieldOnly = [];
14
+ for (const info of flatten(describeProgram(root))) {
15
+ if (!info.output)
16
+ continue;
17
+ const name = info.output.view ? `${info.output.entity}.${info.output.view}` : info.output.entity;
18
+ const command = findCommand(root, info.path);
19
+ const schema = answerEntitySchema(command);
20
+ if (schema)
21
+ schemas[name] = jsonSchemaOf(schema);
22
+ else if (schemas[name] === undefined) {
23
+ const names = fields?.(command);
24
+ if (names) {
25
+ schemas[name] = {
26
+ type: "object",
27
+ properties: Object.fromEntries(names.map((name) => [name, {}])),
28
+ additionalProperties: false,
29
+ };
30
+ fieldOnly.push(name);
31
+ }
32
+ }
33
+ }
34
+ return {
35
+ schemas: Object.fromEntries(Object.entries(schemas).map(([name, schema]) => [name, { $schema: SCHEMA_DIALECT, ...schema }])),
36
+ contracts: sharedContracts(root),
37
+ field_only: [...new Set(fieldOnly)].sort(),
38
+ reasons: failureContext(errors).reasons,
39
+ overrides: sharedContractOverrides(root),
40
+ };
41
+ };
42
+ /** Same discovery endpoint for the shared runner and providers with their own output/context adapters. */
43
+ export const addContractInfo = (root, output, options = {}) => {
44
+ const commands = root.commands.find((command) => command.name() === "commands");
45
+ if (!commands)
46
+ throw new CliError("configuration_error", "contract discovery needs the commands group");
47
+ const info = commands.commands.find((command) => command.name() === "info") ?? commands.command("info");
48
+ annotate(info, { effects: NO_EFFECTS, examples: [`${root.name()} commands info --json`] });
49
+ if (info.registeredArguments.length === 0)
50
+ info.argument("[path...]", "one command path; without one, schemas, error reasons and explicit overrides");
51
+ if (!info.options.some((option) => option.long === "--json") &&
52
+ !root.options.some((option) => option.long === "--json"))
53
+ info.option("--json", "print JSON");
54
+ info
55
+ .description(DISCOVERY_DESCRIPTIONS.info)
56
+ .action((path) => output(path.length ? commandContract(findCommand(root, path)) : contractEvidence(root, options)));
57
+ return info;
58
+ };
@@ -0,0 +1,4 @@
1
+ import { Command } from "commander";
2
+ import type { AppIdentity } from "../ports/app.js";
3
+ /** Construction-only defaults for a CLI that explicitly binds an independent source or transport. */
4
+ export declare const sharedCommandTemplate: (app: AppIdentity, name: "commands" | "doctor" | "mcp" | "search" | "notes" | "session" | "setup" | "meetings") => Command;
@@ -0,0 +1,83 @@
1
+ import { CliError } from "@wirecat/cli-base";
2
+ import { annotate, sharedCommand } from "@wirecat/cli-base/commands";
3
+ import { Command } from "commander";
4
+ import { note } from "../entities/note.js";
5
+ import { addMeetingCommands } from "../meetings/cli/index.js";
6
+ import { commandsCommand } from "./commands-command.js";
7
+ import { LOCAL_READ, LOCAL_WRITE, NO_EFFECTS, REMOTE_WRITE } from "./effects.js";
8
+ import { unfilteredQuery, withQuery } from "./list-query.js";
9
+ import { doctorCommand } from "./messenger/doctor-command.js";
10
+ import { mcpCommand } from "./messenger/mcp-command.js";
11
+ import { searchCommand } from "./messenger/search-command.js";
12
+ import { settingsFor } from "./settings.js";
13
+ /** Construction-only defaults for a CLI that explicitly binds an independent source or transport. */
14
+ export const sharedCommandTemplate = (app, name) => {
15
+ const unavailable = () => {
16
+ throw new CliError("configuration_error", "a command contract template cannot execute");
17
+ };
18
+ const messenger = {
19
+ app,
20
+ provider: app.command,
21
+ chatArgument: "a stored chat id or name",
22
+ topics: false,
23
+ history: "store",
24
+ resolveSettings: settingsFor(app).resolveSettings,
25
+ connect: async () => unavailable(),
26
+ };
27
+ const command = sharedCommand(() => {
28
+ if (name === "commands")
29
+ return commandsCommand(app);
30
+ if (name === "doctor")
31
+ return doctorCommand(messenger);
32
+ if (name === "mcp")
33
+ return mcpCommand(messenger);
34
+ if (name === "search")
35
+ return searchCommand(messenger);
36
+ if (name === "meetings") {
37
+ const root = new Command(app.command);
38
+ addMeetingCommands(root, {
39
+ get store() {
40
+ return unavailable();
41
+ },
42
+ accountId: 0,
43
+ write: unavailable,
44
+ });
45
+ const meetings = root.commands.find((command) => command.name() === "meetings");
46
+ if (!meetings)
47
+ return unavailable();
48
+ return meetings;
49
+ }
50
+ if (name === "setup")
51
+ return annotate(new Command("setup"), { effects: REMOTE_WRITE, lifetime: "interactive", mcp: false })
52
+ .description("set up the account and connect an agent")
53
+ .option("--agent <agent>", "install instructions for this agent")
54
+ .option("--method <method>", "login method");
55
+ if (name === "session") {
56
+ const session = annotate(new Command("session"), { effects: NO_EFFECTS, mcp: false }).description("link this account, or end its login");
57
+ annotate(session.command("start"), { effects: REMOTE_WRITE, lifetime: "interactive" })
58
+ .description("link this account")
59
+ .argument("[method]", "login method");
60
+ annotate(session.command("end"), { effects: REMOTE_WRITE }).description("end this account's login");
61
+ return session;
62
+ }
63
+ const notes = annotate(new Command("notes"), { effects: NO_EFFECTS }).description("notes kept in the shared store");
64
+ withQuery(annotate(notes.command("list"), { effects: LOCAL_READ, output: { entity: "note" } }).description("list stored notes"), unfilteredQuery("note", note));
65
+ annotate(notes.command("show"), { effects: LOCAL_READ, output: { entity: "note" } })
66
+ .description("show one note")
67
+ .argument("<note>", "stored note reference");
68
+ annotate(notes.command("add"), { effects: LOCAL_WRITE, output: { entity: "note" } })
69
+ .description("write a note")
70
+ .argument("<text>", "note text")
71
+ .option("--subject <ref>", "stored resource the note describes");
72
+ annotate(notes.command("edit"), { effects: LOCAL_WRITE, output: { entity: "note" } })
73
+ .description("change a note")
74
+ .argument("<note>", "stored note reference")
75
+ .argument("<text>", "replacement text");
76
+ annotate(notes.command("remove"), { effects: LOCAL_WRITE })
77
+ .description("remove a note")
78
+ .argument("<note>", "stored note reference");
79
+ return notes;
80
+ })();
81
+ command.hook("preAction", unavailable);
82
+ return command;
83
+ };
@@ -0,0 +1,4 @@
1
+ export declare const DISCOVERY_DESCRIPTIONS: Readonly<{
2
+ commands: "every command by section; --json prints its contract, one path per call";
3
+ info: "one command contract, or all schemas, error reasons and explicit overrides";
4
+ }>;
@@ -0,0 +1,4 @@
1
+ export const DISCOVERY_DESCRIPTIONS = Object.freeze({
2
+ commands: "every command by section; --json prints its contract, one path per call",
3
+ info: "one command contract, or all schemas, error reasons and explicit overrides",
4
+ });
@@ -37,108 +37,74 @@ export { openRequestTask } from "../services/task-rules.js";
37
37
  export { TASK_PAIR_QUERY, TASK_QUERY } from "../services/tasks.js";
38
38
  export { type AgentPolicy, type AgentTask, type EvaluationResult, evaluateAgent, type Observation, } from "./agent-evaluation.js";
39
39
  export { answerEntity } from "./answer-entity.js";
40
- export { botAdminsCommand, botMembersCommand } from "./bot/admins.js";
41
- export { type ApiCommandInput, type ApiCommands, generatedApiCommand } from "./bot/api.js";
40
+ export type { ApiCommandInput, ApiCommands } from "./bot/api.js";
42
41
  export { apiFlagOf, apiJson, apiOptionKey, apiPlainJson, checkApiBody, checkApiParameter, parseApiJson, readApiBody, } from "./bot/api-input.js";
43
42
  export { prepareRpcApiBody, type RpcApiBody } from "./bot/api-rpc.js";
44
- export { botCommand } from "./bot/command.js";
45
43
  export { type BotContext, botContext, botWords } from "./bot/context.js";
46
44
  export { type BotCopy, botCopy } from "./bot/copy.js";
47
- export { botMcpCommand } from "./bot/mcp.js";
48
- export { botCan, botIdOf, botMessagesCommand } from "./bot/messages.js";
45
+ export { botCan, botIdOf } from "./bot/messages.js";
49
46
  export { BOT_ACTIONS, type BotAction, type BotAdapter, type BotCallbacks, type BotChatAdmin, type BotChatAdmins, type BotChatMembers, type BotChatRef, type BotChatTools, type BotConnectOptions, type BotEvent, type BotHistory, type BotMcp, type BotMenu, type BotMenuEntry, type BotMessaging, type BotMessenger, type BotNativeApi, type BotNotice, type BotPeople, type BotPress, type BotSecret, type BotSendOptions, type BotUpdates, type BotUpdatesPage, type BotWebhook, type BotWebhookAnswer, type BotWebhookIntake, type BotWebhookRequest, type BotWebhooks, } from "./bot/port.js";
50
47
  export { botFiles, botsDirectory, ChatRegistry, registryProfiles, type SeenChat } from "./bot/registry.js";
51
48
  export { BotTokenStore, type BotTokenStoreOptions } from "./bot/token.js";
52
49
  export { PressLog, UpdatesCursor } from "./bot/updates.js";
53
50
  export type { CommandAvailability, DiscoveredCommand } from "./command-availability.js";
54
51
  export { commandContract, type JsonSchema, SCHEMA_DIALECT } from "./command-contract.js";
55
- export { CONTRACT, commandsCommand } from "./commands-command.js";
56
- export { configCommand, refuseUnknownKey } from "./config-command.js";
52
+ export { CONTRACT } from "./commands-command.js";
53
+ export { refuseUnknownKey } from "./config-command.js";
57
54
  export { loadSnakeCaseConfig } from "./config-keys.js";
58
55
  export { type AgentRun, type BaseContext, type BaseEnvironment, baseContext, environmentOf, outputFor, provide, secretInputOf, } from "./context.js";
56
+ export { addContractInfo, type ContractEvidenceOptions, contractEvidence } from "./contract-evidence.js";
57
+ export { sharedCommandTemplate } from "./contract-templates.js";
59
58
  export { type Closeable, withDeadline } from "./deadline.js";
60
59
  export { DEFAULT_CONFIG, ensureDefaultConfig } from "./default-config.js";
60
+ export { DISCOVERY_DESCRIPTIONS } from "./discovery-descriptions.js";
61
61
  export { changesAuthority, changesAuthorityAt, changesAuthorityNow, 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";
62
62
  export { type AnswerOutput, answerSchema, type Body, type ItemBody, isBody, itemAnswer, itemOf, jsonlRecords, judgedAnswer, type ListBody, type ListInput, listOf, metaNow, printItem, renderAnswer, sealed, snakeKeys, snakeKeysKeeping, } from "./envelope.js";
63
63
  export { withAbort } from "./execution.js";
64
64
  export { askSetupQuestions, asksAtStart, type FirstRun, type FirstRunIo, LANGUAGES, setupAtStart, systemLanguage, } from "./first-run.js";
65
- export { checkGuide, checkStep, type GuideOptions, type GuideReference, type GuideStep, guideCommand, loadScenarios, MEMO_SCENARIOS, type Scenario, shellProblems, } from "./guide.js";
65
+ export { checkGuide, checkStep, type GuideOptions, type GuideReference, type GuideStep, loadScenarios, MEMO_SCENARIOS, type Scenario, shellProblems, } from "./guide.js";
66
66
  export { type CommandHelp, commandHelp, commandHelpMarkdown, commandHelpText, exampleReport, type NextChoice, nextUsually, } from "./help/command-help.js";
67
67
  export { commandsText } from "./help/commands-text.js";
68
- export { type FirstScreen, type FirstScreenLine, firstScreen, installHelp, WIRECAT_TOOLS, } from "./help/first-screen.js";
68
+ export { type FirstScreen, type FirstScreenLine, firstScreen, installHelp, WIRECAT_TOOLS } from "./help/first-screen.js";
69
69
  export { type HelpSection, inSection, SECTIONS } from "./help/sections.js";
70
70
  export { bufferedInput, type InputPolicy, inputPolicy, MAX_BUFFERED_INPUT, MAX_SECRET_INPUT, provideInputPolicy, } from "./input-policy.js";
71
71
  export { answerFields, checkJson, type EntityFields, entityFields, type JsonFieldsResolver, type JsonRequest, liftJson, } from "./json-fields.js";
72
72
  export { commandPath, LIST_QUERY_GUIDE, listQuery, nativeField, nativeTerms, pagedList, pageOf, type QueryWords, queryArgument, queryHelp, queryTerms, searchText, termField, timeBounds, typedQuery, unfilteredQuery, withQuery, } from "./list-query.js";
73
- export { addMeetingBatchCommand, formatMeetingBatch, prepareMeetingBatch } from "./meeting-batch.js";
73
+ export { formatMeetingBatch, prepareMeetingBatch } from "./meeting-batch.js";
74
74
  export { meetingEvidenceItem, meetingPersonContextItem } from "./meeting-evidence-answer.js";
75
75
  export { parseEvidenceFindingsJson, parseMeetingFindingsJson } from "./meeting-findings-input.js";
76
76
  export { meetingPreparationAnswer } from "./meeting-preparation-answer.js";
77
- export { addMeetingPreparationCommand } from "./meeting-preparation-command.js";
78
77
  export { type MeetingPreparationReader, meetingPreparationInput, readMeetingPreparation, } from "./meeting-preparation-read.js";
79
- export { addMeetingProjectCandidatesCommand } from "./meeting-project-candidates-command.js";
80
78
  export { readMeetingProjectCandidates } from "./meeting-project-candidates-read.js";
81
79
  export { meetingResultItem } from "./meeting-results.js";
82
- export { addMeetingSeriesInventoryCommand } from "./meeting-series-inventory-command.js";
83
80
  export { type MeetingSeriesInventoryReader, readMeetingSeriesInventory } from "./meeting-series-inventory-read.js";
84
- export { accountCommand } from "./messenger/account-command.js";
85
81
  export { accountFileFor, profilesHere, rememberAccount } from "./messenger/accounts.js";
86
- export { storeCommand } from "./messenger/archive-commands.js";
87
- export { attachmentsCommand } from "./messenger/attachments-command.js";
88
- export { chatsCommand } from "./messenger/chats-command.js";
89
- export { markReadCommand } from "./messenger/chats-read-command.js";
90
- export { type CompletionOptions, completeCommand } from "./messenger/complete-command.js";
91
- export { contactsCommand } from "./messenger/contacts-command.js";
82
+ export type { CompletionOptions } from "./messenger/complete-command.js";
92
83
  export { type ConnectOptions, connectFor, type Messenger, type MessengerContext, messengerContext, type ReadConnection, type StoredMessages, } from "./messenger/context.js";
93
- export { conversationsCommand } from "./messenger/conversations-command.js";
94
- export { doctorCommand } from "./messenger/doctor-command.js";
95
- export { floodCommand } from "./messenger/flood-command.js";
96
- export { recipientsCommand, sendsCommand } from "./messenger/guard-commands.js";
97
- export { imagesCommand } from "./messenger/images-command.js";
98
- export { inboxCommand } from "./messenger/inbox.js";
99
84
  export { COMMAND_NEEDS } from "./messenger/lacks.js";
100
- export { httpTokenFile, type McpEnvironment, mcpCommand, serverEntry } from "./messenger/mcp-command.js";
101
- export { mentionsCommand } from "./messenger/mentions-command.js";
85
+ export { httpTokenFile, type McpEnvironment, serverEntry } from "./messenger/mcp-command.js";
102
86
  export { type MessageItem, messageItem, type ReadMessage } from "./messenger/message-items.js";
103
- export { messagesCommand, sendCommand } from "./messenger/messages-command.js";
104
- export { deleteCommand } from "./messenger/messages-delete-command.js";
105
- export { editCommand } from "./messenger/messages-edit-command.js";
106
- export { forwardCommand } from "./messenger/messages-forward-command.js";
107
- export { pinCommand, starCommands, unpinCommand } from "./messenger/messages-pin-command.js";
108
- export { metadataCommand } from "./messenger/metadata-command.js";
109
- export { modelsCommand } from "./messenger/models-command.js";
110
- export { pollsCommand } from "./messenger/polls-command.js";
111
87
  export { type ModeProblem, type PrivateFiles, privateFiles, withSqliteSidecars } from "./messenger/private-files.js";
112
- export { reactionsCommand } from "./messenger/reactions-command.js";
113
- export { callsCommand, stickersCommand } from "./messenger/records-command.js";
114
- export { repliesCommand } from "./messenger/replies-command.js";
115
88
  export { buildReport as buildDoctorReport, type Report as DoctorReport, type ReportContext as DoctorReportContext, reportFileName as doctorReportFileName, } from "./messenger/report.js";
116
- export { reviewCommand } from "./messenger/review.js";
117
- export { scheduleCommand } from "./messenger/schedule-command.js";
118
89
  export { allAnswer, allHitItem, type HitItem, type MessageHitItem, messageHitItem, type NoteHitItem, noteHitItem, } from "./messenger/search-answers.js";
119
- export { searchCommand } from "./messenger/search-command.js";
120
- export { SEARCHES_QUERY, searchesCommand } from "./messenger/searches-command.js";
121
- export { serveCommand, servingProfiles } from "./messenger/serve-command.js";
90
+ export { SEARCHES_QUERY } from "./messenger/searches-command.js";
91
+ export { servingProfiles } from "./messenger/serve-command.js";
122
92
  export { DAY_MS, FIRST_FETCH_MS, type MemberFetches, memberFetches } from "./messenger/serve-members.js";
123
93
  export { STEMS_EVERY_MS, STEMS_SLICE_MS, type StemFills, stemFills } from "./messenger/serve-stems.js";
124
- export { type Running, type ServerOptions, type ServerProcess, type ServerSystem, serverCommand, } from "./messenger/server-command.js";
125
- export { statsCommand } from "./messenger/stats-command.js";
94
+ export type { Running, ServerOptions, ServerProcess, ServerSystem } from "./messenger/server-command.js";
126
95
  export { storeSummary } from "./messenger/store-maintenance-command.js";
127
96
  export { type Saving, stored } from "./messenger/stored.js";
128
- export { tagsCommand } from "./messenger/tags-command.js";
129
- export { tasksCommand, tasksStatsCommand } from "./messenger/tasks-command.js";
130
- export { topicsCommand } from "./messenger/topics-command.js";
131
- export { watchCommand } from "./messenger/watch-command.js";
97
+ export { MODEL_CATALOGUE_QUERY, type ModelCatalogueOptions } from "./model-catalogue-command.js";
132
98
  export { window, withPaging } from "./paging.js";
133
- export { knownBeside, knownPermissionKeys, type PermissionKeyOf, unknownPermissionKeys, } from "./permission-keys.js";
134
- export { asFirstWord, commandWords, liftProfile, refuseCommandName, rootOf, usableProfileName, } from "./profile.js";
99
+ export { knownBeside, knownPermissionKeys, type PermissionKeyOf, unknownPermissionKeys } from "./permission-keys.js";
100
+ export { asFirstWord, commandWords, liftProfile, refuseCommandName, rootOf, usableProfileName } from "./profile.js";
135
101
  export { createProgram, type ProgramDefinition, type ProgramOptions, type RunOptions, run } from "./program.js";
136
102
  export { fieldsOf, projectFields } from "./result-fields.js";
137
- export { runsCommand } from "./runs/command.js";
138
103
  export { type Config, type Configuration, count, first, flag, fromFile, type GlobalFlags, NONE_NAMED, type ProfileKind, plain, type ResolveOptions, type Settings, type SettingsExtension, type SettingsExtensionContext, type Source, settingsFor, } from "./settings.js";
139
104
  export { type PermissionAnswer, readSetupAnswers, type SetupAnswers, setupPermissionCeiling } from "./setup-answers.js";
140
105
  export { AGENTS, type Agent, agentFor, screenFor } from "./setup-screen.js";
141
- export { skillCommand } from "./skill-command.js";
106
+ 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";
107
+ export { assertSharedContracts, customizeSharedCommand, hasSharedContract, overrideSharedContract, type SharedContractOverride, sharedContractOverrides, sharedContracts, } from "./shared-contracts.js";
142
108
  export { runnable, withSafety } from "./steps.js";
143
109
  export { changeStoreSetting, isStoreSetting, STORE_SETTINGS, storeSettings } from "./store-settings.js";
144
- export { restartServers, type UpgradeContext, upgradeCommand } from "./upgrade-command.js";
110
+ export { restartServers, type UpgradeContext } from "./upgrade-command.js";