@sendbird/cli 0.0.0-stage → 0.3.0-alpha.1

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 (182) hide show
  1. package/.claude-plugin/plugin.json +11 -0
  2. package/.codex-plugin/plugin.json +33 -0
  3. package/LICENSE +13 -0
  4. package/NOTICE.md +1105 -0
  5. package/PROVENANCE.md +15 -0
  6. package/README.md +457 -2
  7. package/dist/acl.d.ts +2 -0
  8. package/dist/acl.js +12 -0
  9. package/dist/acl.js.map +1 -0
  10. package/dist/billing-plan.d.ts +68 -0
  11. package/dist/billing-plan.js +235 -0
  12. package/dist/billing-plan.js.map +1 -0
  13. package/dist/browser.d.ts +1 -0
  14. package/dist/browser.js +20 -0
  15. package/dist/browser.js.map +1 -0
  16. package/dist/calls-catalog.d.ts +79 -0
  17. package/dist/calls-catalog.js +322 -0
  18. package/dist/calls-catalog.js.map +1 -0
  19. package/dist/calls-credits.d.ts +31 -0
  20. package/dist/calls-credits.js +224 -0
  21. package/dist/calls-credits.js.map +1 -0
  22. package/dist/calls-trial.d.ts +45 -0
  23. package/dist/calls-trial.js +77 -0
  24. package/dist/calls-trial.js.map +1 -0
  25. package/dist/calls.d.ts +10 -0
  26. package/dist/calls.js +470 -0
  27. package/dist/calls.js.map +1 -0
  28. package/dist/catalog.d.ts +67 -0
  29. package/dist/catalog.js +784 -0
  30. package/dist/catalog.js.map +1 -0
  31. package/dist/cli.d.ts +6 -0
  32. package/dist/cli.js +502 -0
  33. package/dist/cli.js.map +1 -0
  34. package/dist/core.d.ts +86 -0
  35. package/dist/core.js +531 -0
  36. package/dist/core.js.map +1 -0
  37. package/dist/diagnostics.d.ts +206 -0
  38. package/dist/diagnostics.js +664 -0
  39. package/dist/diagnostics.js.map +1 -0
  40. package/dist/discovery.d.ts +700 -0
  41. package/dist/discovery.js +838 -0
  42. package/dist/discovery.js.map +1 -0
  43. package/dist/docs.d.ts +31 -0
  44. package/dist/docs.js +137 -0
  45. package/dist/docs.js.map +1 -0
  46. package/dist/features.d.ts +131 -0
  47. package/dist/features.js +227 -0
  48. package/dist/features.js.map +1 -0
  49. package/dist/generated-api.d.ts +116 -0
  50. package/dist/generated-api.js +118 -0
  51. package/dist/generated-api.js.map +1 -0
  52. package/dist/human-format.d.ts +40 -0
  53. package/dist/human-format.js +205 -0
  54. package/dist/human-format.js.map +1 -0
  55. package/dist/human-list.d.ts +2 -0
  56. package/dist/human-list.js +368 -0
  57. package/dist/human-list.js.map +1 -0
  58. package/dist/human-output.d.ts +10 -0
  59. package/dist/human-output.js +1351 -0
  60. package/dist/human-output.js.map +1 -0
  61. package/dist/human-pro.d.ts +3 -0
  62. package/dist/human-pro.js +201 -0
  63. package/dist/human-pro.js.map +1 -0
  64. package/dist/human-progress.d.ts +5 -0
  65. package/dist/human-progress.js +49 -0
  66. package/dist/human-progress.js.map +1 -0
  67. package/dist/local.d.ts +42 -0
  68. package/dist/local.js +707 -0
  69. package/dist/local.js.map +1 -0
  70. package/dist/oauth-callback.d.ts +3 -0
  71. package/dist/oauth-callback.js +66 -0
  72. package/dist/oauth-callback.js.map +1 -0
  73. package/dist/oauth-lock.d.ts +6 -0
  74. package/dist/oauth-lock.js +212 -0
  75. package/dist/oauth-lock.js.map +1 -0
  76. package/dist/oauth.d.ts +32 -0
  77. package/dist/oauth.js +493 -0
  78. package/dist/oauth.js.map +1 -0
  79. package/dist/presentation.d.ts +208 -0
  80. package/dist/presentation.js +156 -0
  81. package/dist/presentation.js.map +1 -0
  82. package/dist/pro-api-catalog.d.ts +24 -0
  83. package/dist/pro-api-catalog.js +619 -0
  84. package/dist/pro-api-catalog.js.map +1 -0
  85. package/dist/pro-api.d.ts +10 -0
  86. package/dist/pro-api.js +338 -0
  87. package/dist/pro-api.js.map +1 -0
  88. package/dist/project.d.ts +34 -0
  89. package/dist/project.js +62 -0
  90. package/dist/project.js.map +1 -0
  91. package/dist/recovery.d.ts +41 -0
  92. package/dist/recovery.js +417 -0
  93. package/dist/recovery.js.map +1 -0
  94. package/dist/runner.d.ts +47 -0
  95. package/dist/runner.js +603 -0
  96. package/dist/runner.js.map +1 -0
  97. package/dist/sdk-catalog.d.ts +69 -0
  98. package/dist/sdk-catalog.js +527 -0
  99. package/dist/sdk-catalog.js.map +1 -0
  100. package/dist/sdk-config.d.ts +19 -0
  101. package/dist/sdk-config.js +85 -0
  102. package/dist/sdk-config.js.map +1 -0
  103. package/dist/sdk-dto.d.ts +244 -0
  104. package/dist/sdk-dto.js +98 -0
  105. package/dist/sdk-dto.js.map +1 -0
  106. package/dist/sdk-limits.d.ts +2 -0
  107. package/dist/sdk-limits.js +3 -0
  108. package/dist/sdk-limits.js.map +1 -0
  109. package/dist/sdk-node-file-reader.d.ts +6 -0
  110. package/dist/sdk-node-file-reader.js +38 -0
  111. package/dist/sdk-node-file-reader.js.map +1 -0
  112. package/dist/sdk-pro-catalog.d.ts +22 -0
  113. package/dist/sdk-pro-catalog.js +234 -0
  114. package/dist/sdk-pro-catalog.js.map +1 -0
  115. package/dist/sdk-pro-runtime.d.ts +31 -0
  116. package/dist/sdk-pro-runtime.js +293 -0
  117. package/dist/sdk-pro-runtime.js.map +1 -0
  118. package/dist/sdk-query.d.ts +10 -0
  119. package/dist/sdk-query.js +29 -0
  120. package/dist/sdk-query.js.map +1 -0
  121. package/dist/sdk-runtime.d.ts +15 -0
  122. package/dist/sdk-runtime.js +685 -0
  123. package/dist/sdk-runtime.js.map +1 -0
  124. package/dist/sdk-worker.d.ts +1 -0
  125. package/dist/sdk-worker.js +26 -0
  126. package/dist/sdk-worker.js.map +1 -0
  127. package/dist/sdk.d.ts +29 -0
  128. package/dist/sdk.js +346 -0
  129. package/dist/sdk.js.map +1 -0
  130. package/dist/search-engine.d.ts +17 -0
  131. package/dist/search-engine.js +54 -0
  132. package/dist/search-engine.js.map +1 -0
  133. package/dist/search-intents.d.ts +2 -0
  134. package/dist/search-intents.js +98 -0
  135. package/dist/search-intents.js.map +1 -0
  136. package/dist/search.d.ts +7 -0
  137. package/dist/search.js +58 -0
  138. package/dist/search.js.map +1 -0
  139. package/dist/secret-output.d.ts +2 -0
  140. package/dist/secret-output.js +108 -0
  141. package/dist/secret-output.js.map +1 -0
  142. package/dist/shell.d.ts +3 -0
  143. package/dist/shell.js +14 -0
  144. package/dist/shell.js.map +1 -0
  145. package/dist/skills.d.ts +210 -0
  146. package/dist/skills.js +374 -0
  147. package/dist/skills.js.map +1 -0
  148. package/dist/value-semantics.d.ts +70 -0
  149. package/dist/value-semantics.js +173 -0
  150. package/dist/value-semantics.js.map +1 -0
  151. package/dist/version.d.ts +1 -0
  152. package/dist/version.js +3 -0
  153. package/dist/version.js.map +1 -0
  154. package/dist/windows.d.ts +4 -0
  155. package/dist/windows.js +136 -0
  156. package/dist/windows.js.map +1 -0
  157. package/dist/workflows.d.ts +228 -0
  158. package/dist/workflows.js +1207 -0
  159. package/dist/workflows.js.map +1 -0
  160. package/package.json +86 -4
  161. package/plugin.json +22 -0
  162. package/references/agent-guide.json +196 -0
  163. package/references/commands.md +247 -0
  164. package/references/dashboard-inventory.json +14796 -0
  165. package/references/docs-index.json +2709 -0
  166. package/references/sdk-commands.json +15065 -0
  167. package/references/workflows.json +1246 -0
  168. package/skills/sendbird/SKILL.md +96 -0
  169. package/skills/sendbird/agents/openai.yaml +4 -0
  170. package/skills/sendbird/references/build-chat-app.md +49 -0
  171. package/skills/sendbird/references/client-guide.md +34 -0
  172. package/skills/sendbird/references/client-plugin-bridge.md +77 -0
  173. package/skills/sendbird/references/client-plugin-install.md +39 -0
  174. package/skills/sendbird/references/operational-checks.md +35 -0
  175. package/skills/sendbird/references/pro-capabilities.md +52 -0
  176. package/skills/sendbird/scripts/client-guide.mjs +283 -0
  177. package/skills/sendbird/scripts/client-plugin-bridge.mjs +703 -0
  178. package/skills/sendbird-setup/SKILL.md +18 -0
  179. package/skills/sendbird-setup/agents/openai.yaml +4 -0
  180. package/skills/sendbird-setup/references/onboarding.md +73 -0
  181. package/skills/sendbird-setup/scripts/install-cli.mjs +447 -0
  182. package/skills/sendbird-setup/scripts/npm-run.mjs +34 -0
package/dist/local.js ADDED
@@ -0,0 +1,707 @@
1
+ import { setupContextSummary } from "./human-output.js";
2
+ import { skillCommand } from "./skills.js";
3
+ import { diagnose } from "./diagnostics.js";
4
+ import { input, password, select } from "@inquirer/prompts";
5
+ import { z } from "zod";
6
+ import { readFileSync } from "node:fs";
7
+ import { CliError, encodeSegment, config, saveConfig, profile, updateProfile, getSecret, request, parse, } from "./core.js";
8
+ import { transport, verify, checkAppOrg, context, execute, definition, } from "./runner.js";
9
+ import { loginOAuth, logoutOAuth } from "./oauth.js";
10
+ import { createProject, readProject } from "./project.js";
11
+ export const localCommands = [
12
+ ...[
13
+ {
14
+ name: "skills install",
15
+ description: "Register the bundled CLI Skill for Claude Code or Codex, offline",
16
+ fields: ["agent", "scope"],
17
+ example: "sendbird skills install --agent claude --scope project --dry-run",
18
+ },
19
+ {
20
+ name: "skills status",
21
+ description: "Inspect local Skill registrations and versions; host loading is unverified",
22
+ fields: ["agent", "scope"],
23
+ example: "sendbird skills status",
24
+ },
25
+ {
26
+ name: "skills show",
27
+ description: "Read the bundled CLI Skill and its reference paths without installing",
28
+ fields: [],
29
+ example: "sendbird --json skills show",
30
+ },
31
+ {
32
+ name: "skills remove",
33
+ description: "Remove only an unchanged Skill registered by this CLI",
34
+ fields: ["agent", "scope"],
35
+ example: "sendbird skills remove --agent claude --scope project --yes",
36
+ },
37
+ ],
38
+ {
39
+ name: "project status",
40
+ description: "Read the local non-secret Sendbird project marker",
41
+ fields: [],
42
+ example: "sendbird project status",
43
+ },
44
+ {
45
+ name: "project init",
46
+ description: "Create sendbird.json from the selected app context for project and Agent discovery",
47
+ fields: [],
48
+ example: "sendbird --app-id APP_ID project init --yes",
49
+ },
50
+ {
51
+ name: "app sdk-config",
52
+ description: "Discover app-bound SDK API/WebSocket endpoints without returning credentials",
53
+ fields: [],
54
+ example: "sendbird --profile staging --app-id APP_ID app sdk-config --raw > sdk-config.json",
55
+ },
56
+ {
57
+ name: "auth login",
58
+ description: "Log in through environment-bound browser OAuth",
59
+ fields: ["method"],
60
+ example: "sendbird --profile staging auth login --method oauth",
61
+ },
62
+ {
63
+ name: "auth signup",
64
+ description: "Sign up in Dashboard, then return to CLI via browser OAuth",
65
+ fields: [],
66
+ example: "sendbird --profile staging auth signup",
67
+ },
68
+ {
69
+ name: "auth verify-email",
70
+ description: "Verify the signed-in account using a private email link or token file",
71
+ fields: ["token-file"],
72
+ example: "sendbird auth verify-email --token-file ./verification-link.txt",
73
+ },
74
+ {
75
+ name: "auth resend-verification",
76
+ description: "Resend the signed-in account's email verification message",
77
+ fields: [],
78
+ example: "sendbird auth resend-verification",
79
+ },
80
+ {
81
+ name: "auth status",
82
+ description: "Validate current session and show granted permissions",
83
+ fields: [],
84
+ example: "sendbird auth status",
85
+ },
86
+ {
87
+ name: "auth logout",
88
+ description: "Revoke saved OAuth tokens",
89
+ fields: [],
90
+ example: "sendbird auth logout",
91
+ },
92
+ {
93
+ name: "profile",
94
+ description: "Show the selected profile and saved active profile",
95
+ fields: [],
96
+ example: "sendbird profile",
97
+ },
98
+ {
99
+ name: "profile list",
100
+ description: "List saved environment profiles",
101
+ fields: [],
102
+ example: "sendbird profile list",
103
+ },
104
+ {
105
+ name: "profile create",
106
+ description: "Create a prod/staging profile",
107
+ fields: ["name", "env"],
108
+ example: "sendbird profile create --name staging --env staging",
109
+ },
110
+ {
111
+ name: "profile use",
112
+ description: "Select a profile",
113
+ fields: ["name"],
114
+ example: "sendbird profile use --name staging",
115
+ },
116
+ {
117
+ name: "profile delete",
118
+ description: "Revoke saved credentials and delete a profile",
119
+ fields: ["name"],
120
+ example: "sendbird profile delete --name demo --yes",
121
+ },
122
+ {
123
+ name: "org use",
124
+ description: "Verify organization access and select it; clears selected app",
125
+ fields: ["id"],
126
+ example: "sendbird org use --id ORG_UID",
127
+ },
128
+ {
129
+ name: "org clear",
130
+ description: "Clear the saved organization, app and region selection",
131
+ fields: [],
132
+ example: "sendbird org clear",
133
+ },
134
+ {
135
+ name: "org region list",
136
+ description: "List Chat regions available to the selected organization",
137
+ fields: [],
138
+ example: "sendbird org region list",
139
+ },
140
+ {
141
+ name: "org region use",
142
+ description: "Select a Chat region for future app creation",
143
+ fields: ["id"],
144
+ example: "sendbird org region use --id us-1",
145
+ },
146
+ {
147
+ name: "app use",
148
+ description: "Verify application access and select it",
149
+ fields: ["id"],
150
+ example: "sendbird app use --id APP_ID",
151
+ },
152
+ {
153
+ name: "app clear",
154
+ description: "Clear the saved application selection",
155
+ fields: [],
156
+ example: "sendbird app clear",
157
+ },
158
+ {
159
+ name: "doctor",
160
+ description: "Inspect account, Pro plan, feature evidence and optional command prerequisites without mutations",
161
+ fields: ["command", "type", "id", "as-user", "region"],
162
+ example: "sendbird doctor",
163
+ },
164
+ {
165
+ name: "setup",
166
+ description: "Guided login, org/app selection and optional default context saving",
167
+ fields: [],
168
+ example: "sendbird setup",
169
+ },
170
+ ];
171
+ export const setupSchema = z.object({
172
+ profile: z.string(),
173
+ environment: z.enum(["prod", "staging"]),
174
+ org_id: z.string(),
175
+ app_id: z.string(),
176
+ app_region: z.string().nullable(),
177
+ region: z.string().nullable(),
178
+ defaults_saved: z.boolean(),
179
+ active_profile: z.string(),
180
+ next_argv: z.array(z.string()).min(1),
181
+ agent_setup_next: z.array(z.string()),
182
+ });
183
+ function required(value, key) {
184
+ return parse(z.string().min(1), value ?? undefined);
185
+ }
186
+ function needTTY() {
187
+ if (!process.stdin.isTTY || !process.stderr.isTTY)
188
+ throw new CliError("E_INPUT", "Interactive input requires a terminal. Use explicit file options for headless login.", 2);
189
+ }
190
+ const promptConfig = { output: process.stderr };
191
+ export async function login(fields, opts) {
192
+ const p = profile(opts.profile);
193
+ if (fields.method && fields.method !== "oauth")
194
+ throw new CliError("E_INPUT", "Only --method oauth is supported", 2);
195
+ if (Object.keys(fields).some((key) => key !== "method"))
196
+ throw new CliError("E_INPUT", "Password and cookie login options are no longer supported", 2);
197
+ const who = await loginOAuth(p.name, p.env, {
198
+ onUrl: (url) => process.stderr.write(`Open this URL to authorize Sendbird CLI: ${url}\n`),
199
+ });
200
+ // A different account must never inherit the previous account's defaults.
201
+ updateProfile(p.name, {
202
+ orgId: undefined,
203
+ appId: undefined,
204
+ region: undefined,
205
+ });
206
+ return {
207
+ authenticated: true,
208
+ profile: p.name,
209
+ user: who.user,
210
+ method: "oauth",
211
+ };
212
+ }
213
+ export async function signup(_fields, opts) {
214
+ const p = profile(opts.profile);
215
+ if (getSecret(p.name))
216
+ throw new CliError("E_AUTH", "This profile is already authenticated; use another profile or log out first", 4);
217
+ const who = await loginOAuth(p.name, p.env, {
218
+ entry: "signup",
219
+ // A new account needs time to complete the web form and consent screen.
220
+ timeoutMs: 10 * 60_000,
221
+ onUrl: (url) => process.stderr.write(`Open this URL to sign up: ${url}\n`),
222
+ });
223
+ updateProfile(p.name, {
224
+ orgId: undefined,
225
+ appId: undefined,
226
+ region: undefined,
227
+ });
228
+ return {
229
+ registered: true,
230
+ authenticated: true,
231
+ method: "oauth",
232
+ profile: p.name,
233
+ user: who.user,
234
+ next: ["sendbird setup"],
235
+ };
236
+ }
237
+ function verificationToken(value, env) {
238
+ const trimmed = value.trim();
239
+ if (!trimmed)
240
+ throw new CliError("E_INPUT", "Verification token is empty", 2);
241
+ if (!/^https?:\/\//i.test(trimmed))
242
+ return trimmed;
243
+ let url;
244
+ try {
245
+ url = new URL(trimmed);
246
+ }
247
+ catch {
248
+ throw new CliError("E_INPUT", "Invalid verification link", 2);
249
+ }
250
+ const dashboardOrigins = env === "prod"
251
+ ? ["https://dashboard.sendbird.com"]
252
+ : [
253
+ "https://dashboard-dev.sendbird.com",
254
+ "https://dashboard.stg.sendbirdtest.com",
255
+ ];
256
+ if (!dashboardOrigins.includes(url.origin) ||
257
+ url.pathname !== "/auth/verify_email")
258
+ throw new CliError("E_INPUT", "Verification link is not for this Dashboard environment", 2);
259
+ const token = url.searchParams.get("email_verification_token");
260
+ if (!token)
261
+ throw new CliError("E_INPUT", "Verification link has no token", 2);
262
+ return token;
263
+ }
264
+ async function verifyEmail(fields, opts) {
265
+ const p = profile(opts.profile);
266
+ if (opts.dryRun)
267
+ return {
268
+ method: "GET",
269
+ path: "/dashboard_api/profiles/verify_user_email/",
270
+ token: "[REDACTED]",
271
+ sent: false,
272
+ };
273
+ const source = fields.tokenFile
274
+ ? readFileSync(fields.tokenFile, "utf8")
275
+ : (needTTY(),
276
+ await password({ message: "Email verification link or token:", mask: true }, promptConfig));
277
+ const token = verificationToken(source, p.env);
278
+ try {
279
+ await request(transport(opts), {
280
+ method: "GET",
281
+ path: "/dashboard_api/profiles/verify_user_email/",
282
+ query: { token },
283
+ });
284
+ }
285
+ catch (error) {
286
+ // Gate's verification URL is a one-use mutation despite its GET method.
287
+ // A lost response or already-used token requires a status read before retry.
288
+ if (!(error instanceof CliError) ||
289
+ !["E_NETWORK", "E_VALIDATION"].includes(error.code))
290
+ throw error;
291
+ try {
292
+ const current = await verify(transport(opts));
293
+ if (current.user
294
+ ?.email_verified === true)
295
+ return { email_verified: true, profile: p.name };
296
+ }
297
+ catch {
298
+ /* Preserve the original uncertain verification outcome. */
299
+ }
300
+ if (error.code === "E_NETWORK")
301
+ throw new CliError("E_NETWORK", "Email verification outcome is unknown; check auth status before retrying", 7);
302
+ throw error;
303
+ }
304
+ const who = await verify(transport(opts));
305
+ if (who.user?.email_verified !==
306
+ true)
307
+ throw new CliError("E_SCHEMA", "Email verification was not reflected in account status", 8);
308
+ return { email_verified: true, profile: p.name };
309
+ }
310
+ async function availableRegions(opts, t) {
311
+ const p = profile(opts.profile);
312
+ const orgId = opts.orgId ?? p.orgId;
313
+ if (!orgId)
314
+ throw new CliError("E_CONTEXT", "Select an organization first", 2);
315
+ const org = (await request(t ?? transport(opts), {
316
+ method: "GET",
317
+ path: `/dashboard_api/organizations/${encodeSegment(orgId)}/`,
318
+ }));
319
+ if (org.uid !== orgId)
320
+ throw new CliError("E_SCHEMA", "Organization region response has a different ID", 8);
321
+ const regions = Object.entries(org.regions ?? {}).map(([id, region]) => ({
322
+ id,
323
+ name: region.name ?? id,
324
+ available: region.allowed === true && region.allow_app_creation === true,
325
+ }));
326
+ return { orgId, regions };
327
+ }
328
+ export async function local(name, f, opts) {
329
+ if (name.startsWith("skills "))
330
+ return skillCommand(name.slice(7), f, opts);
331
+ // Local handlers can revoke credentials or persist context. Never label an
332
+ // executed side effect as a preview: unsupported previews fail before I/O.
333
+ if (opts.dryRun &&
334
+ ![
335
+ "profile",
336
+ "profile list",
337
+ "project status",
338
+ "auth verify-email",
339
+ "auth resend-verification",
340
+ ].includes(name))
341
+ throw new CliError("E_INPUT", "This command does not support --dry-run; no action was performed. Use --help or --example to inspect it", 2);
342
+ if (name === "project status") {
343
+ const project = readProject();
344
+ return project
345
+ ? { linked: true, path: "./sendbird.json", project }
346
+ : {
347
+ linked: false,
348
+ path: "./sendbird.json",
349
+ next: ["sendbird --app-id APP_ID project init --yes"],
350
+ };
351
+ }
352
+ if (name === "project init") {
353
+ if (!opts.yes)
354
+ throw new CliError("E_CONFIRMATION", "Creating sendbird.json requires --yes; it stores no credentials", 2);
355
+ const resolved = context(opts);
356
+ if (!resolved.appId)
357
+ throw new CliError("E_CONTEXT", "Select an application or pass --app-id before creating sendbird.json", 2);
358
+ const selected = profile(opts.profile);
359
+ return createProject({
360
+ app_id: resolved.appId,
361
+ ...(resolved.orgId ? { org_id: resolved.orgId } : {}),
362
+ ...(resolved.region ? { region: resolved.region } : {}),
363
+ profile: selected.name,
364
+ });
365
+ }
366
+ if (name === "profile") {
367
+ const c = config();
368
+ const selected = profile(opts.profile);
369
+ return {
370
+ current: selected.name,
371
+ active: c.active,
372
+ source: opts.profile
373
+ ? "--profile"
374
+ : process.env.SENDBIRD_PROFILE
375
+ ? "SENDBIRD_PROFILE"
376
+ : "saved active",
377
+ environment: selected.env,
378
+ org_id: selected.orgId ?? null,
379
+ app_id: selected.appId ?? null,
380
+ region: selected.region ?? null,
381
+ };
382
+ }
383
+ if (name === "profile list")
384
+ return config();
385
+ if (name === "profile create") {
386
+ const name = parse(z
387
+ .string()
388
+ .min(1)
389
+ .max(64)
390
+ .regex(/^[a-zA-Z0-9][a-zA-Z0-9_-]*$/)
391
+ .refine((name) => !/[\r\n\0]/.test(name)), f.name);
392
+ const env = parse(z.enum(["prod", "staging"]), f.env);
393
+ const c = config();
394
+ if (c.profiles[name])
395
+ throw new CliError("E_CONFLICT", "Profile already exists", 5);
396
+ c.profiles[name] = { env };
397
+ saveConfig(c);
398
+ return { name, env };
399
+ }
400
+ if (name === "profile use") {
401
+ const p = profile(required(f.name, "name"));
402
+ const c = config();
403
+ c.active = p.name;
404
+ saveConfig(c);
405
+ return { active: p.name };
406
+ }
407
+ if (name === "profile delete") {
408
+ const selected = profile(required(f.name, "name"));
409
+ const c = config();
410
+ if (Object.keys(c.profiles).length === 1)
411
+ throw new CliError("E_CONFLICT", "Cannot delete the last profile", 5);
412
+ if (!opts.yes)
413
+ throw new CliError("E_CONFIRM", "Deleting a profile revokes its saved login; rerun with --yes", 2);
414
+ const revocation = await logoutOAuth(selected.name);
415
+ delete c.profiles[selected.name];
416
+ if (c.active === selected.name)
417
+ c.active = c.profiles.prod ? "prod" : Object.keys(c.profiles).sort()[0];
418
+ saveConfig(c);
419
+ return { deleted: selected.name, active: c.active, ...revocation };
420
+ }
421
+ if (name === "auth login")
422
+ return login(f, opts);
423
+ if (name === "auth signup")
424
+ return signup(f, opts);
425
+ const p = profile(opts.profile);
426
+ opts = { ...opts, profile: p.name };
427
+ if (name === "app clear" || name === "org clear") {
428
+ if (opts.orgId || opts.appId)
429
+ throw new CliError("E_INPUT", "Clear changes saved context; omit one-command --org-id and --app-id overrides", 2);
430
+ updateProfile(p.name, name === "app clear"
431
+ ? { appId: undefined }
432
+ : { orgId: undefined, appId: undefined, region: undefined });
433
+ return {
434
+ profile: p.name,
435
+ cleared: name === "app clear" ? ["app"] : ["organization", "app", "region"],
436
+ };
437
+ }
438
+ if (name === "auth verify-email")
439
+ return verifyEmail(f, opts);
440
+ if (name === "auth resend-verification") {
441
+ if (opts.dryRun)
442
+ return {
443
+ method: "POST",
444
+ path: "/dashboard_api/profiles/resend_email_verification_mail/",
445
+ sent: false,
446
+ };
447
+ await request(transport(opts), {
448
+ method: "POST",
449
+ path: "/dashboard_api/profiles/resend_email_verification_mail/",
450
+ body: {},
451
+ });
452
+ return { verification_email_sent: true };
453
+ }
454
+ if (name === "auth logout") {
455
+ const revoked = await logoutOAuth(p.name);
456
+ updateProfile(p.name, {
457
+ orgId: undefined,
458
+ appId: undefined,
459
+ region: undefined,
460
+ });
461
+ return { logged_out: true, ...revoked };
462
+ }
463
+ if (name === "app sdk-config") {
464
+ const { discoverSdkConfig } = await import("./sdk-config.js");
465
+ return discoverSdkConfig(opts);
466
+ }
467
+ if (name === "auth status") {
468
+ const who = await verify(transport(opts));
469
+ const method = "oauth";
470
+ if (f.summary)
471
+ return {
472
+ authenticated: true,
473
+ profile: p.name,
474
+ environment: p.env,
475
+ method,
476
+ user: { id: who.user?.user_id, email: who.user?.email },
477
+ organizations: (who.organizations ?? (who.organization ? [who.organization] : [])).map((o) => ({ uid: o.uid, name: o.name })),
478
+ role: {
479
+ name: who.role?.name,
480
+ is_predefined: who.role?.is_predefined,
481
+ permissions: who.role?.permissions,
482
+ },
483
+ };
484
+ return {
485
+ authenticated: true,
486
+ profile: p.name,
487
+ method,
488
+ ...who,
489
+ };
490
+ }
491
+ if (name === "org use") {
492
+ const id = required(f.id, "id");
493
+ await request(transport(opts), {
494
+ method: "GET",
495
+ path: `/dashboard_api/organizations/${encodeSegment(id)}/`,
496
+ });
497
+ updateProfile(p.name, { orgId: id, appId: undefined, region: undefined });
498
+ return { org_id: id, app_id: null, region: null };
499
+ }
500
+ if (name === "org region list") {
501
+ const { orgId, regions } = await availableRegions(opts);
502
+ return {
503
+ org_id: orgId,
504
+ selected_region: orgId === p.orgId ? (p.region ?? null) : null,
505
+ regions,
506
+ };
507
+ }
508
+ if (name === "org region use") {
509
+ const id = required(f.id, "id");
510
+ const { orgId, regions } = await availableRegions(opts);
511
+ if (orgId !== p.orgId)
512
+ throw new CliError("E_CONTEXT", "Select the organization with org use before saving its region", 2);
513
+ if (!regions.some((region) => region.id === id && region.available))
514
+ throw new CliError("E_REGION", "Region is unavailable for Chat app creation", 5);
515
+ updateProfile(p.name, { region: id });
516
+ return { org_id: orgId, region: id };
517
+ }
518
+ if (name === "app use") {
519
+ const id = required(f.id, "id");
520
+ const t = transport(opts);
521
+ const app = await checkAppOrg(t, id, opts.orgId ?? p.orgId);
522
+ const uid = app.organization?.uid;
523
+ let selectedOrg = uid ?? opts.orgId ?? p.orgId;
524
+ if (!selectedOrg) {
525
+ const who = await verify(t);
526
+ const organizations = who.organizations ?? (who.organization ? [who.organization] : []);
527
+ if (organizations.length !== 1 ||
528
+ typeof organizations[0]?.uid !== "string")
529
+ throw new CliError("E_CONTEXT", "Select an organization before selecting the app", 2);
530
+ selectedOrg = organizations[0].uid;
531
+ await checkAppOrg(t, id, selectedOrg);
532
+ }
533
+ updateProfile(p.name, {
534
+ appId: id,
535
+ orgId: selectedOrg,
536
+ ...(p.orgId && selectedOrg !== p.orgId ? { region: undefined } : {}),
537
+ });
538
+ return { app_id: id, org_id: selectedOrg };
539
+ }
540
+ if (name === "doctor")
541
+ return diagnose(opts, f);
542
+ if (name === "setup") {
543
+ needTTY();
544
+ process.stderr.write(`Sendbird setup: profile ${p.name} (${p.env})\n`);
545
+ try {
546
+ await verify(transport(opts));
547
+ }
548
+ catch (e) {
549
+ if (!(e instanceof CliError) || e.code !== "E_AUTH")
550
+ throw e;
551
+ const entry = await select({
552
+ message: "Account",
553
+ choices: [
554
+ { name: "Sign in", value: "login" },
555
+ { name: "Create a Sendbird account", value: "signup" },
556
+ ],
557
+ }, promptConfig);
558
+ if (entry === "signup")
559
+ await signup({}, opts);
560
+ else
561
+ await login({}, opts);
562
+ }
563
+ const setupTransport = transport(opts);
564
+ if (setupTransport.env !== p.env)
565
+ throw new CliError("E_CONTEXT", "Profile environment changed during setup; rerun setup", 2);
566
+ const list = (await execute(definition("org list"), {}, opts, setupTransport));
567
+ const orgId = await select({
568
+ message: "Organization",
569
+ choices: [
570
+ ...list.organizations.map((o) => ({
571
+ name: o.name ?? o.organization_name ?? o.uid,
572
+ value: o.uid,
573
+ })),
574
+ ...(list.organizations.length === 0
575
+ ? [{ name: "Create organization", value: "__new" }]
576
+ : []),
577
+ ],
578
+ }, promptConfig);
579
+ let selectedOrg = orgId;
580
+ if (orgId === "__new") {
581
+ const name = await input({ message: "Organization name:" }, promptConfig);
582
+ const result = (await execute(definition("org create"), { body: { organization_name: name } }, opts, setupTransport));
583
+ selectedOrg = result.organizations[0]?.uid;
584
+ if (!selectedOrg)
585
+ throw new CliError("E_SCHEMA", "Created organization; select its ID with org use", 8);
586
+ }
587
+ // Resolve selections in memory. Do not partially replace saved defaults
588
+ // while the user is still choosing or can cancel the wizard.
589
+ const scoped = { ...opts, project: false, orgId: selectedOrg };
590
+ const { regions } = await availableRegions(scoped, setupTransport);
591
+ let selectedRegion;
592
+ let appId;
593
+ let offset = 0;
594
+ let createNew = false;
595
+ while (!appId && !createNew) {
596
+ const page = (await execute(definition("app list"), { query: { offset, limit: 20 } }, scoped, setupTransport));
597
+ const choice = await select({
598
+ message: "Application",
599
+ choices: [
600
+ ...page.results.map((a) => ({
601
+ name: `${a.app_name ?? a.app_id} (${a.app_id})`,
602
+ value: `app:${a.app_id}`,
603
+ })),
604
+ ...(page.next ? [{ name: "Next page", value: "__more" }] : []),
605
+ { name: "Enter an existing application ID", value: "__manual" },
606
+ { name: "Create Chat application", value: "__new" },
607
+ ],
608
+ }, promptConfig);
609
+ if (choice === "__more") {
610
+ offset += 20;
611
+ continue;
612
+ }
613
+ if (choice === "__manual")
614
+ appId = await input({ message: "Application ID:" }, promptConfig);
615
+ else if (choice === "__new")
616
+ createNew = true;
617
+ else
618
+ appId = choice.slice(4);
619
+ }
620
+ if (createNew) {
621
+ const appName = await input({ message: "Application name:" }, promptConfig);
622
+ const choices = regions
623
+ .filter((r) => r.available)
624
+ .map((r) => ({ name: `${r.name} (${r.id})`, value: r.id }));
625
+ if (!choices.length)
626
+ throw new CliError("E_REGION", "No Chat region available for app creation; inspect org get or contact support", 5);
627
+ selectedRegion = await select({ message: "Chat region", choices }, promptConfig);
628
+ const result = (await execute(definition("app create"), { body: { app_name: appName, region: selectedRegion } }, scoped, setupTransport));
629
+ appId = result.application.app_id;
630
+ }
631
+ const selectedApp = required(appId, "appId");
632
+ const app = await checkAppOrg(setupTransport, selectedApp, selectedOrg);
633
+ const appRegion = typeof app.region === "string" ? app.region : null;
634
+ if (!createNew) {
635
+ const choices = regions
636
+ .filter((r) => r.available)
637
+ .map((r) => ({ name: `${r.name} (${r.id})`, value: r.id }));
638
+ if (choices.length) {
639
+ const chosen = await select({
640
+ message: "Default region for future Chat apps (does not move this app)",
641
+ choices: [
642
+ ...choices,
643
+ { name: "Do not set a default region", value: "__none" },
644
+ ],
645
+ default: choices.some((r) => r.value === appRegion)
646
+ ? appRegion
647
+ : "__none",
648
+ }, promptConfig);
649
+ selectedRegion = chosen === "__none" ? undefined : chosen;
650
+ }
651
+ }
652
+ const selection = {
653
+ profile: p.name,
654
+ environment: p.env,
655
+ org_id: selectedOrg,
656
+ app_id: selectedApp,
657
+ app_region: appRegion,
658
+ region: selectedRegion ?? null,
659
+ };
660
+ process.stderr.write(setupContextSummary(selection) + "\n");
661
+ const decision = await select({
662
+ message: "Save these as your defaults?",
663
+ choices: [
664
+ {
665
+ name: "Save organization, app and region, and make this profile active",
666
+ value: "save",
667
+ },
668
+ { name: "Finish without changing selection defaults", value: "skip" },
669
+ ],
670
+ default: "save",
671
+ }, promptConfig);
672
+ const saved = decision === "save";
673
+ if (saved) {
674
+ // Read again so unrelated profiles changed during setup are retained.
675
+ const latest = config();
676
+ if (latest.profiles[p.name]?.env !== p.env)
677
+ throw new CliError("E_CONTEXT", "Profile changed during setup; rerun setup before saving defaults", 2);
678
+ latest.profiles[p.name] = {
679
+ ...latest.profiles[p.name],
680
+ orgId: selectedOrg,
681
+ appId: selectedApp,
682
+ region: selectedRegion,
683
+ };
684
+ latest.active = p.name;
685
+ saveConfig(latest);
686
+ }
687
+ const nextArgv = [
688
+ "sendbird",
689
+ "--profile",
690
+ p.name,
691
+ "--org-id",
692
+ selectedOrg,
693
+ "--app-id",
694
+ selectedApp,
695
+ "doctor",
696
+ ];
697
+ return setupSchema.parse({
698
+ ...selection,
699
+ defaults_saved: saved,
700
+ active_profile: config().active,
701
+ next_argv: nextArgv,
702
+ agent_setup_next: ["sendbird", "skills", "status"],
703
+ });
704
+ }
705
+ throw new CliError("E_COMMAND", "Unknown command", 2);
706
+ }
707
+ //# sourceMappingURL=local.js.map