@wirecat/cli-core 0.564.0 → 0.566.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 (61) hide show
  1. package/CHANGELOG.md +76 -0
  2. package/constants.json +13 -0
  3. package/dist/calendar/busy.d.ts +10 -10
  4. package/dist/calendar/busy.js +9 -9
  5. package/dist/calendar/cli/answers.d.ts +7 -8
  6. package/dist/calendar/cli/answers.js +4 -5
  7. package/dist/calendar/cli/bodies.d.ts +33 -0
  8. package/dist/calendar/cli/bodies.js +52 -0
  9. package/dist/calendar/cli/files.d.ts +8 -0
  10. package/dist/calendar/cli/files.js +41 -0
  11. package/dist/calendar/cli/index.d.ts +58 -51
  12. package/dist/calendar/cli/index.js +311 -284
  13. package/dist/calendar/cli/remind.d.ts +2 -11
  14. package/dist/calendar/cli/remind.js +81 -81
  15. package/dist/calendar/cli/search-all.d.ts +3 -8
  16. package/dist/calendar/cli/search-all.js +47 -42
  17. package/dist/calendar/mcp/index.d.ts +13 -13
  18. package/dist/calendar/prepare.d.ts +1 -1
  19. package/dist/calendar/testing/answers.d.ts +27 -5
  20. package/dist/calendar/testing/answers.js +88 -17
  21. package/dist/calendar/testing/writer.d.ts +1 -0
  22. package/dist/calendar/testing/writer.js +6 -0
  23. package/dist/calendar/writer.d.ts +6 -1
  24. package/dist/calendar/writes.d.ts +3 -1
  25. package/dist/calendar/writes.js +42 -20
  26. package/dist/cli/app-doctor-command.d.ts +7 -13
  27. package/dist/cli/app-doctor-command.js +1 -1
  28. package/dist/cli/config-command.js +1 -1
  29. package/dist/cli/config-issues.d.ts +3 -1
  30. package/dist/cli/config-issues.js +2 -2
  31. package/dist/cli/contract-evidence.d.ts +1 -1
  32. package/dist/cli/early-refusal.d.ts +2 -1
  33. package/dist/cli/early-refusal.js +4 -2
  34. package/dist/cli/entry.d.ts +6 -2
  35. package/dist/cli/entry.js +4 -1
  36. package/dist/cli/envelope.d.ts +2 -2
  37. package/dist/cli/index.d.ts +1 -0
  38. package/dist/cli/index.js +1 -0
  39. package/dist/cli/messenger/store-maintenance-command.d.ts +1 -1
  40. package/dist/cli/permission-keys.d.ts +3 -1
  41. package/dist/cli/permission-keys.js +2 -1
  42. package/dist/cli/preview.d.ts +12 -0
  43. package/dist/cli/preview.js +8 -1
  44. package/dist/cli/settings.d.ts +2 -0
  45. package/dist/cli/settings.js +8 -1
  46. package/dist/constants/index.d.ts +83 -0
  47. package/dist/constants/index.js +77 -0
  48. package/dist/constants/obscure.d.ts +1 -0
  49. package/dist/constants/obscure.js +9 -0
  50. package/dist/errors/reasons.js +15 -1
  51. package/dist/mcp/meeting-preparation.d.ts +1 -1
  52. package/dist/mcp/meeting-project-candidates.d.ts +1 -1
  53. package/dist/mcp/meeting-series-inventory.d.ts +1 -1
  54. package/dist/meetings/mcp/passage.d.ts +1 -1
  55. package/dist/meetings/mcp/project-evidence.d.ts +1 -1
  56. package/dist/meetings/mcp/search.d.ts +1 -1
  57. package/dist/oauth/index.d.ts +1 -1
  58. package/dist/oauth/provider.d.ts +5 -0
  59. package/dist/oauth/storage.js +12 -2
  60. package/dist/services/metadata.d.ts +1 -1
  61. package/package.json +8 -3
@@ -0,0 +1,83 @@
1
+ import * as v from "valibot";
2
+ import type { AppSource, OAuthClient } from "../oauth/provider.js";
3
+ /** cli-core's layer, read after cli-base's and before the tool's. */
4
+ export declare const CORE_CONSTANTS: import("url").URL;
5
+ /** What cli-base's and cli-core's layers hold; a tool extends it with `v.object({ ...constantsSchema.entries, … })`. */
6
+ export declare const constantsSchema: v.ObjectSchema<{
7
+ readonly google: v.ObjectSchema<{
8
+ readonly app: v.ObjectSchema<{
9
+ readonly client_id: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.NonEmptyAction<string, undefined>, v.TransformAction<string, string>]>;
10
+ readonly client_secret: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.TransformAction<string, string>]>, undefined>;
11
+ }, undefined>;
12
+ }, undefined>;
13
+ readonly microsoft: v.ObjectSchema<{
14
+ readonly app: v.ObjectSchema<{
15
+ readonly client_id: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.NonEmptyAction<string, undefined>]>;
16
+ }, undefined>;
17
+ }, undefined>;
18
+ }, undefined>;
19
+ export type Constants = v.InferOutput<typeof constantsSchema>;
20
+ /**
21
+ * The packaged constants, base → core → the tool's `constants.json` when given, read once per process for each tool
22
+ * layer. A tool with constants of its own passes its layer and a schema built on `constantsSchema`; the first call for
23
+ * a layer decides its schema.
24
+ */
25
+ export declare const constants: <TSchema extends v.GenericSchema<unknown, Constants> = typeof constantsSchema>(toolLayer?: URL, schema?: TSchema) => v.InferOutput<TSchema>;
26
+ export interface AppOptions {
27
+ env: NodeJS.ProcessEnv;
28
+ /** The tool's environment prefix: `GCAL` with provider `google` reads `GCAL_GOOGLE_CLIENT_ID` and `_SECRET`. */
29
+ prefix: string;
30
+ /** `--client-id`. A secret for it comes from `<PREFIX>_<PROVIDER>_CLIENT_SECRET`. */
31
+ clientId?: string | undefined;
32
+ /** The account's config key `<provider>.client_id`. A config file never holds the secret: it comes from the env. */
33
+ configClientId?: string | undefined;
34
+ }
35
+ export interface OAuthAppOptions extends AppOptions {
36
+ /** `google`, `microsoft`, `zoom`: names the env variables, upper-cased. */
37
+ provider: string;
38
+ /** WireCat's app from the constants; an empty or missing id means WireCat has none for this provider. */
39
+ wirecat?: {
40
+ client_id?: string | undefined;
41
+ client_secret?: string | undefined;
42
+ } | undefined;
43
+ }
44
+ export interface OAuthApp {
45
+ client: OAuthClient & {
46
+ source: AppSource;
47
+ };
48
+ source: AppSource;
49
+ }
50
+ /**
51
+ * The app a sign-in uses, first match wins (WC-SECR-25): `--client-id`, `<PREFIX>_<PROVIDER>_CLIENT_ID`, the account's
52
+ * `<provider>.client_id`, WireCat's app. A secret without any of the first three ids is a `configuration_error`.
53
+ * Undefined when nothing names an app and WireCat has none.
54
+ */
55
+ export declare const oauthApp: (options: OAuthAppOptions) => OAuthApp | undefined;
56
+ export interface GoogleAppOptions extends AppOptions {
57
+ /** The owner's Desktop client JSON, `--client-file`; it must be private to the owner. */
58
+ clientFile?: string | undefined;
59
+ platform?: NodeJS.Platform;
60
+ /** The tool's own constants, when its layer overrides the app. */
61
+ constants?: Constants;
62
+ }
63
+ /**
64
+ * The Google Desktop app a sign-in uses: `--client-file`, then `oauthApp`'s order. Google treats a Desktop app's
65
+ * secret as public (https://developers.google.com/identity/protocols/oauth2/native-app), so WireCat's ships, obscured,
66
+ * in cli-core's constants.
67
+ */
68
+ export declare const googleApp: (options: GoogleAppOptions) => OAuthApp;
69
+ /** WireCat's Microsoft app is a public client: it has an id and no secret. */
70
+ export declare const microsoftApp: (options: AppOptions & {
71
+ constants?: Constants;
72
+ }) => OAuthApp;
73
+ export interface OAuthClientReport {
74
+ client: "wirecat" | "own" | null;
75
+ source: AppSource | null;
76
+ /** Why there is no app, when `client` is null. */
77
+ reason?: string;
78
+ }
79
+ /** `doctor`'s `oauth_client` for one provider: the app a new sign-in would use; doctor reads no keyring. */
80
+ export declare const oauthClientReport: (app: {
81
+ source?: AppSource | undefined;
82
+ } | undefined, reason?: string) => OAuthClientReport;
83
+ export type { AppSource };
@@ -0,0 +1,77 @@
1
+ import { BASE_CONSTANTS, baseConstantsSchema, CliError, loadConstants } from "@wirecat/cli-base";
2
+ import * as v from "valibot";
3
+ import { readClientFile } from "../oauth/client-file.js";
4
+ import { reveal } from "./obscure.js";
5
+ /** cli-core's layer, read after cli-base's and before the tool's. */
6
+ export const CORE_CONSTANTS = new URL("../../constants.json", import.meta.url);
7
+ /** What cli-base's and cli-core's layers hold; a tool extends it with `v.object({ ...constantsSchema.entries, … })`. */
8
+ export const constantsSchema = v.object({
9
+ ...baseConstantsSchema.entries,
10
+ google: v.object({
11
+ app: v.object({
12
+ client_id: v.pipe(v.string(), v.nonEmpty(), v.transform(reveal)),
13
+ client_secret: v.optional(v.pipe(v.string(), v.transform(reveal))),
14
+ }),
15
+ }),
16
+ microsoft: v.object({ app: v.object({ client_id: v.pipe(v.string(), v.nonEmpty()) }) }),
17
+ });
18
+ const loaded = new Map();
19
+ /**
20
+ * The packaged constants, base → core → the tool's `constants.json` when given, read once per process for each tool
21
+ * layer. A tool with constants of its own passes its layer and a schema built on `constantsSchema`; the first call for
22
+ * a layer decides its schema.
23
+ */
24
+ export const constants = (toolLayer, schema) => {
25
+ const key = toolLayer?.href ?? "";
26
+ if (!loaded.has(key)) {
27
+ const layers = toolLayer ? [BASE_CONSTANTS, CORE_CONSTANTS, toolLayer] : [BASE_CONSTANTS, CORE_CONSTANTS];
28
+ loaded.set(key, loadConstants(layers, schema ?? constantsSchema));
29
+ }
30
+ return loaded.get(key);
31
+ };
32
+ /**
33
+ * The app a sign-in uses, first match wins (WC-SECR-25): `--client-id`, `<PREFIX>_<PROVIDER>_CLIENT_ID`, the account's
34
+ * `<provider>.client_id`, WireCat's app. A secret without any of the first three ids is a `configuration_error`.
35
+ * Undefined when nothing names an app and WireCat has none.
36
+ */
37
+ export const oauthApp = (options) => {
38
+ const { env, prefix, provider } = options;
39
+ const name = `${prefix}_${provider.toUpperCase()}_CLIENT`;
40
+ const clientSecret = env[`${name}_SECRET`];
41
+ const own = [
42
+ [options.clientId, "flag"],
43
+ [env[`${name}_ID`], "env"],
44
+ [options.configClientId, "config"],
45
+ ];
46
+ const [clientId, source] = own.find(([id]) => id) ?? [];
47
+ if (clientId && source)
48
+ return app({ clientId, ...(clientSecret ? { clientSecret } : {}) }, source);
49
+ if (clientSecret)
50
+ throw new CliError("configuration_error", `${name}_SECRET is set without a client id; set ${name}_ID too, or unset it to use WireCat's app`, { reason: "sign-in.secret-without-id" });
51
+ const wirecat = options.wirecat;
52
+ if (!wirecat?.client_id)
53
+ return undefined;
54
+ return app({ clientId: wirecat.client_id, ...(wirecat.client_secret ? { clientSecret: wirecat.client_secret } : {}) }, "constants");
55
+ };
56
+ const app = (client, source) => ({ client: { ...client, source }, source });
57
+ /**
58
+ * The Google Desktop app a sign-in uses: `--client-file`, then `oauthApp`'s order. Google treats a Desktop app's
59
+ * secret as public (https://developers.google.com/identity/protocols/oauth2/native-app), so WireCat's ships, obscured,
60
+ * in cli-core's constants.
61
+ */
62
+ export const googleApp = (options) => {
63
+ const { clientFile, platform } = options;
64
+ if (clientFile)
65
+ return app(readClientFile(clientFile, platform ? { platform } : {}), "flag");
66
+ const wirecat = (options.constants ?? constants()).google.app;
67
+ return oauthApp({ ...options, provider: "google", wirecat });
68
+ };
69
+ /** WireCat's Microsoft app is a public client: it has an id and no secret. */
70
+ export const microsoftApp = (options) => {
71
+ const wirecat = (options.constants ?? constants()).microsoft.app;
72
+ return oauthApp({ ...options, provider: "microsoft", wirecat });
73
+ };
74
+ /** `doctor`'s `oauth_client` for one provider: the app a new sign-in would use; doctor reads no keyring. */
75
+ export const oauthClientReport = (app, reason) => app?.source
76
+ ? { client: app.source === "constants" ? "wirecat" : "own", source: app.source }
77
+ : { client: null, source: null, ...(reason ? { reason } : {}) };
@@ -0,0 +1 @@
1
+ export declare const reveal: (obscured: string) => string;
@@ -0,0 +1,9 @@
1
+ import { createDecipheriv } from "node:crypto";
2
+ // Not protection: anyone holding the package can reveal these. It keeps secret scanners and a casual read from
3
+ // treating WireCat's public Desktop app as a leaked credential, as rclone does for its own app.
4
+ const KEY = Buffer.from("d43012779aa2dded3e98092a3dbcf5d8980c564172f5ce0a5fd0574e5f740339", "hex");
5
+ export const reveal = (obscured) => {
6
+ const bytes = Buffer.from(obscured, "base64url");
7
+ const decipher = createDecipheriv("aes-256-ctr", KEY, bytes.subarray(0, 16));
8
+ return Buffer.concat([decipher.update(bytes.subarray(16)), decipher.final()]).toString("utf8");
9
+ };
@@ -31,6 +31,19 @@ const SIGN_IN = [
31
31
  ["oauth.not-saved", "configuration_error", "the sign-in cannot be saved or read where it is kept"],
32
32
  ["sign-in.client-file-open", "configuration_error", "other users of this computer can read the client file"],
33
33
  ["sign-in.client-file-invalid", "configuration_error", "the file is not a Desktop app OAuth client JSON"],
34
+ ["oauth.scope-missing", "permission_error", "the sign-in lacks a permission this command needs"],
35
+ ["sign-in.client-rejected", "configuration_error", "the provider rejected the OAuth client"],
36
+ ["sign-in.secret-without-id", "configuration_error", "an OAuth client secret is set without its client id"],
37
+ ];
38
+ /** Reasons every CLI over a provider's API raises alike: gcal and drive today. */
39
+ const PROVIDER_API = [
40
+ ["offline.refused", "permission_error", "this command needs the provider; --offline was given"],
41
+ validation("api.unknown-method", "the provider has no method by this name"),
42
+ ["api.disabled", "configuration_error", "the provider's API is turned off for this OAuth project"],
43
+ ["provider.usage-limit", "rate_limited", "the account's usage limit at the provider is reached; wait, do not retry"],
44
+ ["file.not-found", "not_found", "the file named, or its folder, does not exist"],
45
+ validation("file.not-a-file", "the path names a folder or another thing that is not a file"),
46
+ ["file.denied", "permission_error", "the file cannot be opened: permission denied"],
34
47
  ];
35
48
  const OTHERS = [
36
49
  ["query.time-limit", "timeout", "the search took longer than its time limit; the query itself is valid"],
@@ -87,6 +100,7 @@ const OTHERS = [
87
100
  validation("event.repeat-split", "the series cannot be split at this occurrence, or was split there already"),
88
101
  validation("event.repeat-count", "a COUNT series is split only with a rule for its new part"),
89
102
  validation("event.unmovable", "the provider keeps this kind of event on its calendar"),
103
+ validation("event.quick-add-ambiguous", "more than one event could be the one a lost quick add made"),
90
104
  validation("event.text-with-fields", "--text takes the whole event from its line, so no field option goes with it"),
91
105
  validation("calendar.ambiguous", "two or more calendars have this name; name one by its id"),
92
106
  validation("export.too-many", "the query finds more events than one export writes"),
@@ -258,7 +272,7 @@ export const INPUT_FIELD_REASONS = defineReasons([
258
272
  export const REASONS = defineReasons([
259
273
  ...QUERY_REASONS,
260
274
  ...INPUT_FIELD_REASONS,
261
- ...[...QUERY, ...SIGN_IN, ...OTHERS].map(([reason, code, message]) => ({
275
+ ...[...QUERY, ...SIGN_IN, ...PROVIDER_API, ...OTHERS].map(([reason, code, message]) => ({
262
276
  reason,
263
277
  code,
264
278
  message,
@@ -28,7 +28,7 @@ export declare const callMeetingPreparationTool: (read: MeetingPreparationReader
28
28
  }[];
29
29
  structuredContent: {
30
30
  error: {
31
- 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";
31
+ code: "authentication_error" | "cancelled" | "configuration_error" | "confirmation_required" | "conflict" | "internal_error" | "invalid_response" | "network_error" | "not_found" | "outcome_unknown" | "permission_error" | "provider_error" | "provider_unavailable" | "rate_limited" | "timeout" | "validation_error";
32
32
  reason: string;
33
33
  message: string;
34
34
  param?: string | undefined;
@@ -23,7 +23,7 @@ export declare const callMeetingProjectCandidatesTool: (read: StoredMeetingProje
23
23
  }[];
24
24
  structuredContent: {
25
25
  error: {
26
- 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";
26
+ code: "authentication_error" | "cancelled" | "configuration_error" | "confirmation_required" | "conflict" | "internal_error" | "invalid_response" | "network_error" | "not_found" | "outcome_unknown" | "permission_error" | "provider_error" | "provider_unavailable" | "rate_limited" | "timeout" | "validation_error";
27
27
  reason: string;
28
28
  message: string;
29
29
  param?: string | undefined;
@@ -23,7 +23,7 @@ export declare const callMeetingSeriesInventoryTool: (read: MeetingSeriesInvento
23
23
  }[];
24
24
  structuredContent: {
25
25
  error: {
26
- 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";
26
+ code: "authentication_error" | "cancelled" | "configuration_error" | "confirmation_required" | "conflict" | "internal_error" | "invalid_response" | "network_error" | "not_found" | "outcome_unknown" | "permission_error" | "provider_error" | "provider_unavailable" | "rate_limited" | "timeout" | "validation_error";
27
27
  reason: string;
28
28
  message: string;
29
29
  param?: string | undefined;
@@ -57,7 +57,7 @@ export declare const callMeetingPassageTool: (read: MeetingPassageReader, input:
57
57
  }[];
58
58
  structuredContent: {
59
59
  error: {
60
- 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";
60
+ code: "authentication_error" | "cancelled" | "configuration_error" | "confirmation_required" | "conflict" | "internal_error" | "invalid_response" | "network_error" | "not_found" | "outcome_unknown" | "permission_error" | "provider_error" | "provider_unavailable" | "rate_limited" | "timeout" | "validation_error";
61
61
  reason: string;
62
62
  message: string;
63
63
  param?: string | undefined;
@@ -51,7 +51,7 @@ export declare const callMeetingProjectEvidenceTool: (read: MeetingProjectDiscov
51
51
  }[];
52
52
  structuredContent: {
53
53
  error: {
54
- 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";
54
+ code: "authentication_error" | "cancelled" | "configuration_error" | "confirmation_required" | "conflict" | "internal_error" | "invalid_response" | "network_error" | "not_found" | "outcome_unknown" | "permission_error" | "provider_error" | "provider_unavailable" | "rate_limited" | "timeout" | "validation_error";
55
55
  reason: string;
56
56
  message: string;
57
57
  param?: string | undefined;
@@ -94,7 +94,7 @@ export declare const callMeetingSearchTool: (search: MeetingHitSearch, input: un
94
94
  }[];
95
95
  structuredContent: {
96
96
  error: {
97
- 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";
97
+ code: "authentication_error" | "cancelled" | "configuration_error" | "confirmation_required" | "conflict" | "internal_error" | "invalid_response" | "network_error" | "not_found" | "outcome_unknown" | "permission_error" | "provider_error" | "provider_unavailable" | "rate_limited" | "timeout" | "validation_error";
98
98
  reason: string;
99
99
  message: string;
100
100
  param?: string | undefined;
@@ -1,6 +1,6 @@
1
1
  export { type Authorization, type AuthorizeOptions, authorize } from "./authorize.js";
2
2
  export { type ClientFileOptions, readClientFile } from "./client-file.js";
3
3
  export { type SignInOptions, type TokenKeeper, type TokenKeeperOptions, type TokensOptions, tokenKeeper, } from "./keeper.js";
4
- export type { ExchangeContext, OAuthClient, OAuthProvider, RequestContext, TokenSet } from "./provider.js";
4
+ export type { AppSource, ExchangeContext, OAuthClient, OAuthProvider, RequestContext, TokenSet } from "./provider.js";
5
5
  export { requestTokens, revokeToken, TOKEN_LOG_ALLOW, TOKEN_LOG_EVENT } from "./requests.js";
6
6
  export { type CredentialStorageOptions, credentialStorage, driveSessionCodec, type EncodeInput, oauthAccount, type StoredTokens, standardCodec, type TokenCodec, type TokenStorage, zoomTokenCodec, } from "./storage.js";
@@ -3,7 +3,12 @@ import type { Logger } from "@wirecat/cli-base";
3
3
  export interface OAuthClient {
4
4
  clientId: string;
5
5
  clientSecret?: string;
6
+ /** Where the sign-in found the app (WC-SECR-25); saved with the entry, so `doctor` reports the app it used. */
7
+ source?: AppSource;
6
8
  }
9
+ /** `flag`: `--client-file` or `--client-id`; `env`: `<TOOL>_<PROVIDER>_CLIENT_ID`; `config`: the account's
10
+ * `<provider>.client_id`; `constants`: WireCat's app. */
11
+ export type AppSource = "flag" | "env" | "config" | "constants";
7
12
  export interface TokenSet {
8
13
  accessToken?: string;
9
14
  refreshToken: string;
@@ -40,8 +40,9 @@ export const standardCodec = (providerId) => ({
40
40
  throw invalid();
41
41
  if (!Array.isArray(value.scopes) || !value.scopes.every((scope) => typeof scope === "string"))
42
42
  throw invalid();
43
+ const source = text(value.clientSource);
43
44
  return {
44
- client: { clientId },
45
+ client: defined({ clientId, clientSecret: text(value.clientSecret), source }),
45
46
  tokens: defined({
46
47
  accessToken: text(value.accessToken),
47
48
  refreshToken,
@@ -57,6 +58,10 @@ export const standardCodec = (providerId) => ({
57
58
  version: 1,
58
59
  provider: providerId,
59
60
  clientId: client.clientId,
61
+ // Only WireCat's secret, which is public: a later release may ship another default app, and a refresh needs
62
+ // the secret of the app that signed in. An owner's own secret stays where the owner keeps it.
63
+ clientSecret: client.source === "constants" ? client.clientSecret : undefined,
64
+ clientSource: client.source,
60
65
  accessToken: tokens.accessToken,
61
66
  refreshToken: tokens.refreshToken,
62
67
  expiresAt: tokens.expiresAt,
@@ -80,7 +85,11 @@ export const driveSessionCodec = {
80
85
  if (!refreshToken || !clientId || typeof value.principal !== "string")
81
86
  throw invalid();
82
87
  return {
83
- client: defined({ clientId, clientSecret: text(value.clientSecret) }),
88
+ client: defined({
89
+ clientId,
90
+ clientSecret: text(value.clientSecret),
91
+ source: text(value.clientSource),
92
+ }),
84
93
  tokens: defined({
85
94
  accessToken: text(fields.access_token),
86
95
  refreshToken,
@@ -98,6 +107,7 @@ export const driveSessionCodec = {
98
107
  ...extra,
99
108
  clientId: client.clientId,
100
109
  ...(client.clientSecret ? { clientSecret: client.clientSecret } : {}),
110
+ ...(client.source ? { clientSource: client.source } : {}),
101
111
  tokens: defined({
102
112
  ...oldTokens,
103
113
  access_token: tokens.accessToken,
@@ -27,7 +27,7 @@ export declare const metadataService: (deps: ServiceDeps) => {
27
27
  source?: undefined;
28
28
  chatId: string;
29
29
  error: {
30
- code: "authentication_error" | "cancelled" | "configuration_error" | "confirmation_required" | "invalid_response" | "network_error" | "not_found" | "outcome_unknown" | "permission_error" | "provider_error" | "provider_unavailable" | "rate_limited" | "timeout" | "validation_error";
30
+ code: "authentication_error" | "cancelled" | "configuration_error" | "confirmation_required" | "conflict" | "invalid_response" | "network_error" | "not_found" | "outcome_unknown" | "permission_error" | "provider_error" | "provider_unavailable" | "rate_limited" | "timeout" | "validation_error";
31
31
  message: string;
32
32
  };
33
33
  })[];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wirecat/cli-core",
3
- "version": "0.564.0",
3
+ "version": "0.566.0",
4
4
  "description": "The messenger-neutral half of a messaging CLI: domain model, message locators, rendering, name resolution, the SQLite seam, the command skeleton and shared read commands, the send guard, run records and the message store",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Viacheslav Ptsarev",
@@ -19,6 +19,7 @@
19
19
  "packageManager": "pnpm@11.28.8",
20
20
  "files": [
21
21
  "dist",
22
+ "constants.json",
22
23
  "parity.json",
23
24
  "skills",
24
25
  "README.md",
@@ -166,6 +167,10 @@
166
167
  "./oauth": {
167
168
  "types": "./dist/oauth/index.d.ts",
168
169
  "default": "./dist/oauth/index.js"
170
+ },
171
+ "./constants": {
172
+ "types": "./dist/constants/index.d.ts",
173
+ "default": "./dist/constants/index.js"
169
174
  }
170
175
  },
171
176
  "scripts": {
@@ -253,7 +258,7 @@
253
258
  "@types/node": "^22.20.5",
254
259
  "@types/pngjs": "6.0.5",
255
260
  "@vitest/coverage-v8": "^5.0.5",
256
- "@wirecat/cli-base": "0.75.0",
261
+ "@wirecat/cli-base": "0.77.1",
257
262
  "@wirecat/cli-core-legacy-tags": "npm:@wirecat/cli-core@0.414.0",
258
263
  "commander": "15.0.0",
259
264
  "cspell": "10.4.0",
@@ -273,7 +278,7 @@
273
278
  },
274
279
  "peerDependencies": {
275
280
  "@napi-rs/canvas": ">=0.1.69 <2",
276
- "@wirecat/cli-base": ">=0.75.0 <0.76.0",
281
+ "@wirecat/cli-base": ">=0.76.0 <0.78.0",
277
282
  "commander": ">=15"
278
283
  },
279
284
  "bin": {