@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
@@ -0,0 +1,1351 @@
1
+ import { humanValueSemantics } from "./value-semantics.js";
2
+ import { proOutput } from "./human-pro.js";
3
+ import { redact, secretValues } from "./core.js";
4
+ import { clean, paragraph, clip, commandLine, countLabel, fieldLabel, localTime, primary, record, row, table, titleCase, valueText, view, width, } from "./human-format.js";
5
+ import { listOutput } from "./human-list.js";
6
+ /** Shared wizard summary: all prompt details stay on stderr, including in JSON mode. */
7
+ export function setupContextSummary(selection, options = {}) {
8
+ const ctx = view({
9
+ ...options,
10
+ color: false,
11
+ width: options.width ?? process.stderr.columns ?? process.stdout.columns,
12
+ });
13
+ return [
14
+ "Review setup defaults",
15
+ row("Profile", selection.profile, ctx),
16
+ row("Environment", selection.environment, ctx),
17
+ row("Organization UID", selection.org_id, ctx),
18
+ row("App ID", selection.app_id, ctx),
19
+ row("App region", selection.app_region ?? "Not reported", ctx),
20
+ row("Default region", selection.region ?? "Not selected", ctx),
21
+ ...paragraph("Saving makes this profile active. Explicit flags and environment variables still take precedence. Sign-in and resources created above are kept even if you skip saving; reauthentication may reset the old account context.", ctx),
22
+ ].join("\n");
23
+ }
24
+ function detailRows(command, result, target, ctx) {
25
+ const details = [];
26
+ const notes = [];
27
+ let heading = titleCase(entity(command));
28
+ const add = (label, value) => {
29
+ if (value !== undefined && value !== null && value !== "")
30
+ details.push([label, value]);
31
+ };
32
+ switch (command) {
33
+ case "calls settings push get":
34
+ heading = "Calls Push availability";
35
+ add("App", result.app_id ?? target.app_id);
36
+ add("Calls enabled", result.is_calls_enabled ?? "Unknown");
37
+ add("Region", result.region);
38
+ add("Flag source", result.calls_flag_source);
39
+ add("Calls API", "Verify regional access with calls settings general get");
40
+ add("Shared Push enabled", result.push_enabled ?? "Unknown");
41
+ add("Policy", "The shared switch is read-only here");
42
+ break;
43
+ case "calls settings general get":
44
+ heading = "Calls General settings";
45
+ for (const [key, label] of Object.entries({
46
+ relay_method: "Relay",
47
+ direct_call_cloud_recording_enabled: "Direct recording",
48
+ group_call_cloud_recording_enabled: "Group recording",
49
+ direct_call_recording_video: "Recording video",
50
+ direct_call_recording_display_timestamp: "Timestamp overlay",
51
+ direct_call_recording_timestamp_timezone: "Timezone",
52
+ }))
53
+ add(label, key === "direct_call_recording_timestamp_timezone" &&
54
+ record(result.general)?.[key] === ""
55
+ ? "Default"
56
+ : key === "relay_method" && record(result.general)?.[key] === "turn"
57
+ ? "Server relay only (turn)"
58
+ : key === "relay_method" &&
59
+ record(result.general)?.[key] === "stun&turn"
60
+ ? "P2P first, relay fallback (stun&turn)"
61
+ : record(result.general)?.[key]);
62
+ break;
63
+ case "calls settings webhook get":
64
+ case "calls settings chat-integration get": {
65
+ const key = command.includes("webhook") ? "webhook" : "chat_integration";
66
+ const settings = record(result[key]) ?? {};
67
+ heading =
68
+ key === "webhook" ? "Calls Webhook settings" : "Calls Chat integration";
69
+ add("Enabled", settings.enabled);
70
+ add("URL", settings.url);
71
+ add("Enabled events", Array.isArray(settings.enabled_events)
72
+ ? settings.enabled_events.join(", ") || "None"
73
+ : undefined);
74
+ add("Available events", Array.isArray(settings.all_webhook_categories ??
75
+ settings.all_chat_integration_categories)
76
+ ? (settings.all_webhook_categories ??
77
+ settings.all_chat_integration_categories)
78
+ : undefined);
79
+ break;
80
+ }
81
+ case "profile":
82
+ heading = `Profile ${valueText(result.current)}`;
83
+ add("Environment", result.environment);
84
+ add("Active", result.active);
85
+ if (result.current !== result.active)
86
+ add("Selection", result.source);
87
+ add("Organization UID", result.org_id);
88
+ add("App", result.app_id);
89
+ add("Region", result.region);
90
+ break;
91
+ case "project status": {
92
+ const project = record(result.project);
93
+ heading = project
94
+ ? "Sendbird project linked"
95
+ : "No Sendbird project link";
96
+ add("File", result.path);
97
+ if (project) {
98
+ add("App ID", project.app_id);
99
+ add("Organization UID", project.org_id);
100
+ add("Region", project.region);
101
+ add("Profile", project.profile);
102
+ }
103
+ if (Array.isArray(result.next) && result.next.length)
104
+ add("Next", result.next[0]);
105
+ break;
106
+ }
107
+ case "auth status": {
108
+ const user = record(result.user);
109
+ const role = record(result.role);
110
+ heading = `Signed in${user?.email ? ` as ${clean(user.email)}` : ""}`;
111
+ add("Profile", result.profile);
112
+ add("Environment", result.environment);
113
+ add("Role", role?.name);
114
+ const permissions = role?.permissions;
115
+ if (Array.isArray(permissions) &&
116
+ permissions.every((p) => typeof p === "string")) {
117
+ const unique = [...new Set(permissions)];
118
+ add("Permissions", unique.length ? `${unique.length} returned` : "None returned");
119
+ for (const permission of unique.slice(0, 12))
120
+ notes.push(...paragraph(`- ${permission}`, ctx));
121
+ if (unique.length > 12)
122
+ notes.push(...paragraph(`${unique.length - 12} more permissions; use auth status --json for the complete list.`, ctx));
123
+ }
124
+ else
125
+ add("Permissions", "Not reported");
126
+ notes.push(...paragraph("Role permissions reported by the server; command access also depends on the target and API policy.", ctx));
127
+ add("Organizations", Array.isArray(result.organizations)
128
+ ? result.organizations.length
129
+ : record(result.organization)
130
+ ? 1
131
+ : undefined);
132
+ if (Array.isArray(result.organizations) &&
133
+ result.organizations.length === 1)
134
+ add("Organization", record(result.organizations[0])?.name);
135
+ else if (record(result.organization))
136
+ add("Organization", record(result.organization)?.name);
137
+ break;
138
+ }
139
+ case "doctor":
140
+ if (Array.isArray(result.checks))
141
+ return diagnosticLines(result, ctx);
142
+ heading = "Dashboard access verified";
143
+ add("Profile", result.profile);
144
+ add("Organization UID", result.org_id ?? "Not selected");
145
+ add("App", result.app_id ?? "Not selected");
146
+ add("Role", record(result.role)?.name);
147
+ if (Array.isArray(result.next) && result.next.length)
148
+ add("Next", result.next[0]);
149
+ break;
150
+ case "app auth-policy get":
151
+ heading = "Chat access-token policy";
152
+ add("Token policy", result.guest_user_policy);
153
+ break;
154
+ case "app get": {
155
+ heading = `Application ${valueText(result.app_name ?? result.app_id)}`;
156
+ add("App ID", result.app_id ?? target.app_id);
157
+ add("Region", result.region);
158
+ add("Plan", result.plan);
159
+ add("Token policy", result.guest_user_policy);
160
+ add("SDK family", result.is_delight_region === true ? "Delight" : "Standard");
161
+ const features = record(result.current_premium_features);
162
+ for (const [label, key] of [
163
+ ["Supergroup", "super_group_channel"],
164
+ ["Reactions", "reactions"],
165
+ ["Poll", "poll"],
166
+ ]) {
167
+ const reported = features?.[key];
168
+ add(label, reported === true
169
+ ? "Reported enabled"
170
+ : reported === false
171
+ ? "Reported disabled"
172
+ : "Not reported");
173
+ }
174
+ notes.push(...paragraph("Feature source: current_premium_features (plan snapshot). Runtime access has not been tested; these values do not prove support or denial. Use doctor for separate plan, activation and access checks.", ctx));
175
+ break;
176
+ }
177
+ case "chat user get":
178
+ heading = `User ${valueText(result.nickname ?? result.user_id)}`;
179
+ add("User ID", result.user_id ?? target.user_id);
180
+ add("Active", result.is_active);
181
+ add("Online", result.is_online);
182
+ add("Metadata keys", record(result.metadata)
183
+ ? Object.keys(record(result.metadata)).length
184
+ : undefined);
185
+ add("Created", typeof result.created_at === "number"
186
+ ? localTime(result.created_at)
187
+ : undefined);
188
+ break;
189
+ case "chat channel get":
190
+ heading = `${titleCase(valueText(target.channel_type || (result.is_super ? "supergroup" : "group")))} channel ${valueText(result.name || result.channel_url)}`;
191
+ add("Channel URL", result.channel_url ?? target.channel_url);
192
+ add("Members", result.member_count);
193
+ add("Public", result.is_public);
194
+ add("Frozen", result.freeze);
195
+ add("Created", typeof result.created_at === "number"
196
+ ? localTime(result.created_at)
197
+ : undefined);
198
+ break;
199
+ case "chat sdk status":
200
+ heading = `Connected as ${valueText(record(result.user)?.user_id ?? target.actor_user_id)}`;
201
+ add("App", result.app_id ?? target.app_id);
202
+ break;
203
+ case "chat sdk message translate": {
204
+ heading = `Translated message ${valueText(result.message_id ?? target.message_id)}`;
205
+ add("Channel", result.channel_url ?? target.channel_url);
206
+ add("Original", result.message);
207
+ for (const [language, text] of Object.entries(record(result.translations) ?? {}))
208
+ add(clean(language), text);
209
+ break;
210
+ }
211
+ case "chat message get":
212
+ heading = `Message ${valueText(result.message_id ?? target.message_id)}`;
213
+ add("Sender", record(result.sender)?.user_id);
214
+ add("Channel", result.channel_url ?? target.channel_url);
215
+ add("Message", result.message);
216
+ add("Mention type", result.mention_type);
217
+ if (Array.isArray(result.mentioned_user_ids))
218
+ add("Mentioned users", result.mentioned_user_ids.join(", ") || "None");
219
+ add("File requires SDK auth", result.requires_auth);
220
+ add("Created", typeof result.created_at === "number"
221
+ ? localTime(result.created_at)
222
+ : undefined);
223
+ break;
224
+ default: {
225
+ const ignored = new Set([
226
+ "attrs",
227
+ "plans",
228
+ "access_token",
229
+ "api_token",
230
+ "session_tokens",
231
+ "profile_url",
232
+ "current_premium_features",
233
+ "current_core_features",
234
+ "created_by",
235
+ ]);
236
+ if (command === "org get") {
237
+ add("Organization UID", result.uid);
238
+ ignored.add("uid");
239
+ }
240
+ for (const [key, value] of Object.entries(result)) {
241
+ if (ignored.has(key))
242
+ continue;
243
+ if (["string", "number", "boolean"].includes(typeof value))
244
+ add(fieldLabel(key), value);
245
+ if (details.length >= 8)
246
+ break;
247
+ }
248
+ if (!details.length && result !== null)
249
+ add("Result", Object.keys(result).length
250
+ ? `${Object.keys(result).length} fields; use --json for details`
251
+ : "No data returned");
252
+ }
253
+ }
254
+ return [
255
+ ctx.color.bold(clip(heading, ctx.width - 2)),
256
+ ...details.map(([label, value]) => row(label, value, ctx)),
257
+ ...notes,
258
+ ];
259
+ }
260
+ const verbs = {
261
+ init: "Linked",
262
+ create: "Created",
263
+ delete: "Deleted",
264
+ revoke: "Revoked",
265
+ issue: "Issued",
266
+ send: "Sent",
267
+ file: "Sent",
268
+ reply: "Sent",
269
+ invite: "Invited",
270
+ update: "Updated",
271
+ set: "Updated",
272
+ rename: "Renamed",
273
+ use: "Selected",
274
+ clear: "Cleared",
275
+ activate: "Activated",
276
+ deactivate: "Deactivated",
277
+ submit: "Submitted",
278
+ accept: "Accepted",
279
+ decline: "Declined",
280
+ join: "Joined",
281
+ leave: "Left",
282
+ login: "Signed in",
283
+ logout: "Signed out",
284
+ signup: "Signed up",
285
+ "verify-email": "Verified email",
286
+ "resend-verification": "Sent verification email",
287
+ "send-now": "Sent",
288
+ cancel: "Canceled",
289
+ pin: "Pinned",
290
+ unpin: "Unpinned",
291
+ freeze: "Froze",
292
+ unfreeze: "Unfroze",
293
+ mute: "Muted",
294
+ unmute: "Unmuted",
295
+ ban: "Banned",
296
+ unban: "Unbanned",
297
+ read: "Marked read",
298
+ };
299
+ export function entity(command) {
300
+ if (command.startsWith("calls settings "))
301
+ return `Calls ${command.split(" ")[2]} settings`;
302
+ if (command.startsWith("calls push "))
303
+ return "Calls push credentials";
304
+ if (command.startsWith("project "))
305
+ return "project";
306
+ if (command.startsWith("chat sdk message scheduled "))
307
+ return "scheduled message";
308
+ if (command.startsWith("chat sdk message "))
309
+ return "message";
310
+ if (command.startsWith("chat sdk user push "))
311
+ return "push notifications";
312
+ if (command.startsWith("chat sdk user invitation "))
313
+ return "invitation preference";
314
+ if (command.startsWith("chat sdk channel count-preference "))
315
+ return "unread count preference";
316
+ if (command.startsWith("chat sdk channel snooze "))
317
+ return "snooze";
318
+ if (command.startsWith("chat sdk channel "))
319
+ return "channel";
320
+ if (command.startsWith("chat message "))
321
+ return "message";
322
+ if (command.startsWith("chat channel metadata "))
323
+ return "channel metadata";
324
+ if (command.startsWith("chat channel members "))
325
+ return "members";
326
+ if (command.startsWith("chat channel "))
327
+ return "channel";
328
+ if (command.startsWith("chat user token "))
329
+ return "user access token";
330
+ if (command.startsWith("chat user metadata "))
331
+ return "user metadata";
332
+ if (command.startsWith("chat user "))
333
+ return "user";
334
+ if (command.startsWith("app feature "))
335
+ return "application feature";
336
+ if (command.startsWith("app auth-policy "))
337
+ return "authentication policy";
338
+ if (command.startsWith("app "))
339
+ return "application";
340
+ if (command.startsWith("org region "))
341
+ return "region";
342
+ if (command.startsWith("org "))
343
+ return "organization";
344
+ if (command.startsWith("profile "))
345
+ return "profile";
346
+ if (command.startsWith("support ticket "))
347
+ return "support ticket";
348
+ return command.split(" ").slice(0, -1).join(" ") || "request";
349
+ }
350
+ function receipt(value, ctx) {
351
+ const command = value.command.replace(/^sendbird /, "");
352
+ const result = record(value.result) ?? {};
353
+ const target = value.target;
354
+ const action = command.slice(command.lastIndexOf(" ") + 1);
355
+ const verb = verbs[action] ?? "Completed";
356
+ const kind = entity(command);
357
+ const identity = command.startsWith("chat message ")
358
+ ? (result.message_id ?? target.message_id)
359
+ : command.startsWith("chat channel ")
360
+ ? (result.channel_url ?? target.channel_url)
361
+ : command.startsWith("chat user ")
362
+ ? (result.user_id ?? target.user_id)
363
+ : command === "app create"
364
+ ? (record(result.application)?.app_id ?? target.app_id)
365
+ : command === "org create"
366
+ ? ((Array.isArray(result.organizations)
367
+ ? record(result.organizations[0])?.uid
368
+ : undefined) ?? target.org_id)
369
+ : command === "app use"
370
+ ? (result.app_id ?? target.app_id)
371
+ : command === "org use"
372
+ ? (result.org_id ?? target.org_id)
373
+ : command === "org region use"
374
+ ? result.region
375
+ : command.startsWith("profile ")
376
+ ? (result.name ?? result.active ?? result.deleted)
377
+ : undefined;
378
+ let headline = `${verb} ${kind}${identity ? ` ${clean(identity)}` : ""}`;
379
+ if (command === "chat channel create" && target.channel_type)
380
+ headline = `Created ${titleCase(clean(target.channel_type))} channel ${valueText(identity)}`;
381
+ if (command === "org clear")
382
+ headline = "Cleared organization, app and region";
383
+ if (command === "app clear")
384
+ headline = "Cleared application selection";
385
+ if (command === "auth login" && record(result.user)?.email)
386
+ headline = `Signed in as ${clean(record(result.user)?.email)}`;
387
+ if (command === "auth logout")
388
+ headline = "Signed out";
389
+ if (command === "auth signup")
390
+ headline = "Signed in after signup";
391
+ if (command === "auth verify-email")
392
+ headline = "Verified email";
393
+ if (command === "auth resend-verification")
394
+ headline = "Sent verification email";
395
+ if (command === "setup")
396
+ headline =
397
+ result.defaults_saved === false
398
+ ? "Chat setup checked"
399
+ : "Chat setup complete";
400
+ if (command === "project init")
401
+ headline = "Linked Sendbird project";
402
+ if (command === "chat channel members invite")
403
+ headline = `Invited members to ${valueText(target.channel_url)}`;
404
+ if (command === "calls activate")
405
+ headline = "Calls activation accepted";
406
+ const lines = [
407
+ `${ctx.color.green("✓")} ${ctx.color.bold(clip(headline, ctx.width - 2))}`,
408
+ ];
409
+ const trial = record(result.calls_trial);
410
+ if (trial) {
411
+ lines.push(row("Free trial", titleCase(clean(trial.status)), ctx));
412
+ lines.push(...paragraph(trial.note, ctx));
413
+ if (trial.code)
414
+ lines.push(row("Trial code", trial.code, ctx));
415
+ const next = Array.isArray(trial.next) ? record(trial.next[0]) : undefined;
416
+ lines.push(row("Next", Array.isArray(next?.argv)
417
+ ? commandLine(next.argv)
418
+ : "sendbird calls credits list", ctx, 300));
419
+ }
420
+ if (command.startsWith("chat message ") && typeof result.message === "string")
421
+ lines.push(row("Message", result.message, ctx));
422
+ if (command.startsWith("chat message ")) {
423
+ if (result.mention_type)
424
+ lines.push(row("Mention", result.mention_type, ctx));
425
+ if (Array.isArray(result.mentioned_user_ids))
426
+ lines.push(row("Mentioned users", result.mentioned_user_ids.join(", ") || "None", ctx));
427
+ if (Array.isArray(result.meta_arrays))
428
+ lines.push(row("Meta-array keys", result.meta_arrays
429
+ .map((v) => record(v)?.key)
430
+ .filter(Boolean)
431
+ .join(", ") || "None", ctx));
432
+ }
433
+ if (command === "app auth-policy set")
434
+ lines.push(row("Token policy", result.guest_user_policy, ctx));
435
+ if (command === "app create" && record(result.application)?.app_name)
436
+ lines.push(row("Name", record(result.application)?.app_name, ctx));
437
+ if (command === "org create" && Array.isArray(result.organizations))
438
+ lines.push(row("Organization", primary(result.organizations[0]) || target.org_id, ctx));
439
+ if (target.channel_url && !command.startsWith("chat channel "))
440
+ lines.push(row("Channel", target.channel_url, ctx));
441
+ if (target.app_id &&
442
+ !["app create", "app use", "project init"].includes(command))
443
+ lines.push(row("App", target.app_id, ctx));
444
+ if (command.startsWith("calls ")) {
445
+ if (command === "calls activate") {
446
+ const readback = record(result.readback);
447
+ lines.push(row("Activation", readback.status === "matches"
448
+ ? "Enabled (read back)"
449
+ : readback.status === "mismatch"
450
+ ? "Not confirmed; inspect app state"
451
+ : "Readback unavailable; registration accepted", ctx));
452
+ lines.push(row("Next", "sendbird calls settings push get", ctx));
453
+ if (!trial)
454
+ lines.push(row("Credits", "No trial credits claimed or credits purchased", ctx), row("Next", "sendbird calls credits list", ctx));
455
+ return lines;
456
+ }
457
+ if (result.configuration_id)
458
+ lines.push(row("Configuration", result.configuration_id, ctx));
459
+ const readback = record(result.readback);
460
+ if (readback) {
461
+ lines.push(row("Readback", readback.status === "read_completed"
462
+ ? "Settings read again"
463
+ : "Unavailable; write was accepted", ctx));
464
+ const settings = record(readback.settings);
465
+ if (settings && command.startsWith("calls settings "))
466
+ lines.push(...detailRows(command.replace(/ set$/, " get"), settings, target, ctx));
467
+ lines.push(row("Next", Array.isArray(readback.next) &&
468
+ record(readback.next[0]) &&
469
+ Array.isArray(record(readback.next[0]).argv)
470
+ ? commandLine(record(readback.next[0]).argv)
471
+ : command.startsWith("calls push ")
472
+ ? `sendbird calls push list --push-type ${valueText(result.push_type ?? "TYPE")}`
473
+ : `sendbird ${command.replace(/ set$/, " get")}`, ctx));
474
+ }
475
+ }
476
+ if (command === "setup") {
477
+ if (target.org_id)
478
+ lines.push(row("Organization UID", target.org_id, ctx));
479
+ if (result.profile)
480
+ lines.push(row("Profile", result.profile, ctx));
481
+ if (result.environment)
482
+ lines.push(row("Environment", result.environment, ctx));
483
+ if ("region" in result)
484
+ lines.push(row("Default region", result.region ?? "Not selected", ctx));
485
+ if ("defaults_saved" in result)
486
+ lines.push(row("Defaults", result.defaults_saved
487
+ ? "Saved; profile is active"
488
+ : "Not saved; use the explicit next command", ctx));
489
+ lines.push(row("Next", Array.isArray(result.next_argv)
490
+ ? commandLine(result.next_argv.map(String))
491
+ : "sendbird doctor", ctx), row("Agent skills", "sendbird skills status", ctx));
492
+ }
493
+ if (command === "project init") {
494
+ lines.push(row("File", result.path, ctx));
495
+ lines.push(row("App ID", record(result.project)?.app_id, ctx));
496
+ }
497
+ if (command === "auth logout" && result.remote_revocation === "unknown")
498
+ lines.push(` ${ctx.color.yellow("!")} Remote token revocation is uncertain.`);
499
+ if (Array.isArray(result.next) && result.next.length)
500
+ lines.push(row("Next", result.next[0], ctx));
501
+ return lines;
502
+ }
503
+ function preview(value, ctx) {
504
+ const command = value.command.replace(/^sendbird /, "");
505
+ const result = record(value.result) ?? {};
506
+ const request = record(result.request);
507
+ const target = value.target;
508
+ const action = command.slice(command.lastIndexOf(" ") + 1);
509
+ const imperative = {
510
+ create: "Create",
511
+ delete: "Delete",
512
+ set: "Update",
513
+ update: "Update",
514
+ send: "Send",
515
+ invite: "Invite",
516
+ revoke: "Revoke",
517
+ issue: "Issue",
518
+ "claim-trial": "Request free trial for",
519
+ list: "List",
520
+ search: "Search",
521
+ get: "Get",
522
+ join: "Join",
523
+ leave: "Leave",
524
+ };
525
+ const kind = command === "chat channel create" && target.channel_type
526
+ ? `${titleCase(clean(target.channel_type))} channel`
527
+ : entity(command);
528
+ const lines = [
529
+ ctx.color.bold(`Preview · ${imperative[action] ?? titleCase(action)} ${kind}`),
530
+ ];
531
+ if (command.startsWith("calls credits "))
532
+ lines.push(row("Organization", target.org_id, ctx));
533
+ if (target.app_id)
534
+ lines.push(row("App", target.app_id, ctx));
535
+ if (target.channel_url)
536
+ lines.push(row("Channel", target.channel_url, ctx));
537
+ if (target.user_id)
538
+ lines.push(row("User", target.user_id, ctx));
539
+ if (request?.method && request.path)
540
+ lines.push(row("Request", `${request.method} ${request.path}`, ctx, 200));
541
+ if (result.mode === "dashboard_handoff") {
542
+ lines.push(row("Requested", result.requested_plan, ctx));
543
+ lines.push(` ${ctx.color.dim("Offline billing preview; no quote, eligibility check or subscription change.")}`);
544
+ }
545
+ if (record(result.calls_trial))
546
+ lines.push(row("Free trial", "After activation: check eligibility, then request trial; no calls made in this preview", ctx));
547
+ if (result.sdk)
548
+ lines.push(row("SDK", result.sdk, ctx, 200));
549
+ for (const [scope, fields] of [
550
+ ["body", request?.body ?? result.body],
551
+ ["query", request?.query],
552
+ ["params", result.params],
553
+ ]) {
554
+ const source = record(fields);
555
+ if (!source)
556
+ continue;
557
+ for (const [key, item] of Object.entries(source).slice(0, 7))
558
+ lines.push(row(fieldLabel(key), Array.isArray(item) ? item.join(", ") : item, ctx));
559
+ if (Object.keys(source).length > 7)
560
+ lines.push(` ${ctx.color.dim(`More ${scope} fields: --json`)}`);
561
+ }
562
+ if ((command === "app feature set" ||
563
+ command === "calls credits claim-trial") &&
564
+ result.note)
565
+ lines.push(...paragraph(result.note, ctx));
566
+ lines.push(` ${ctx.color.dim("No request sent. Access and remote state were not checked.")}`);
567
+ return lines;
568
+ }
569
+ function profileList(result, ctx) {
570
+ const profiles = record(result.profiles) ?? {};
571
+ const entries = Object.entries(profiles).map(([name, value]) => ({
572
+ name,
573
+ ...record(value),
574
+ }));
575
+ const lines = [
576
+ ctx.color.bold(countLabel(entries.length, "profile")),
577
+ row("Active", result.active, ctx),
578
+ ];
579
+ lines.push(...table(entries, [
580
+ { label: "Profile", value: (r) => r.name, max: 30 },
581
+ { label: "Environment", value: (r) => r.env, max: 18 },
582
+ {
583
+ label: "Organization",
584
+ value: (r) => (r.orgId ? "Selected" : "—"),
585
+ max: 18,
586
+ },
587
+ { label: "App", value: (r) => (r.appId ? "Selected" : "—"), max: 13 },
588
+ ], ctx));
589
+ return lines;
590
+ }
591
+ function billingUsageRead(command, result, target, ctx) {
592
+ const targetRows = [
593
+ ...(target.org_id ? [row("Organization UID", target.org_id, ctx)] : []),
594
+ ...(target.app_id ? [row("App", target.app_id, ctx)] : []),
595
+ ];
596
+ if ([
597
+ "billing plan check",
598
+ "billing plan change",
599
+ "billing plan verify",
600
+ ].includes(command)) {
601
+ const handoff = record(result.handoff);
602
+ const organization = record(result.organization);
603
+ const current = record(result.current_subscription);
604
+ const future = record(result.future_subscription);
605
+ const reviewReasons = {
606
+ sales_contract: "Current plan uses a sales contract",
607
+ aws_marketplace: "Billing is managed through AWS Marketplace",
608
+ sales_plan: "Requested plan requires Sales",
609
+ shopify_billing: "Billing is managed through Shopify",
610
+ legacy_organization: "Legacy organization needs Dashboard review",
611
+ managed_payment: "Payment is managed by your account team",
612
+ scheduled_subscription: "A subscription change is already scheduled",
613
+ cancellation_scheduled: "Cancellation is already scheduled",
614
+ already_current: "Requested plan is already current",
615
+ dashboard_selection_required: "Select this plan in Dashboard",
616
+ payment_method_required: "Register a payment method in Dashboard",
617
+ organization_inactive: "Organization is inactive",
618
+ subscription_type_requires_review: "Current contract type needs review",
619
+ };
620
+ const observed = {
621
+ current: "Current subscription",
622
+ scheduled: "Scheduled subscription",
623
+ not_reflected: "No matching subscription yet",
624
+ };
625
+ return [
626
+ ctx.color.bold(command === "billing plan verify"
627
+ ? "Chat plan status checked"
628
+ : "Chat plan change requires Dashboard confirmation"),
629
+ ...targetRows,
630
+ ...(organization ? [row("Name", organization.name, ctx)] : []),
631
+ row("Requested", result.requested_plan, ctx),
632
+ row("Current", current?.subscription_name ?? "None", ctx),
633
+ row("Scheduled", future?.subscription_name ?? "None", ctx),
634
+ ...(result.change_state
635
+ ? [
636
+ row("Observed state", observed[String(result.change_state)] ?? result.change_state, ctx),
637
+ ]
638
+ : []),
639
+ ...(result.selection_state
640
+ ? [
641
+ row("Selection", result.selection_state === "catalog_candidate"
642
+ ? "Catalog candidate; confirm in Dashboard"
643
+ : "Dashboard review required", ctx),
644
+ ]
645
+ : []),
646
+ ...(Array.isArray(result.reasons)
647
+ ? result.reasons.map((reason) => row("Review required", reviewReasons[String(reason)] ?? reason, ctx))
648
+ : []),
649
+ ...(typeof result.card_present === "boolean"
650
+ ? [row("Card registered", result.card_present, ctx)]
651
+ : []),
652
+ ...(handoff
653
+ ? [
654
+ row("Dashboard", handoff.url, ctx),
655
+ row("Action", handoff.instruction ??
656
+ "Review the organization, price and effective date in Dashboard", ctx),
657
+ ]
658
+ : []),
659
+ ` ${ctx.color.dim("No subscription change was submitted by this command.")}`,
660
+ row("Next", result.next, ctx),
661
+ ];
662
+ }
663
+ if (command === "billing plan current") {
664
+ const current = record(result.current_subscription);
665
+ const future = record(result.future_subscription);
666
+ return [
667
+ ctx.color.bold("Chat subscription"),
668
+ ...targetRows,
669
+ row("Current", current?.display_name ?? current?.subscription_name ?? "None", ctx),
670
+ ...(current
671
+ ? [
672
+ row("Plan key", current.subscription_name, ctx),
673
+ row("Type", current.subscription_type, ctx),
674
+ row("Auto-renewal", current.auto_renewal, ctx),
675
+ row("Next billing", current.next_billing_date ?? "Not provided", ctx),
676
+ ]
677
+ : []),
678
+ row("Scheduled", future?.display_name ?? future?.subscription_name ?? "None", ctx),
679
+ ...(future
680
+ ? [
681
+ row("Effective", future.apply_date ?? future.start_date ?? "Not provided", ctx),
682
+ ]
683
+ : []),
684
+ ];
685
+ }
686
+ if (command === "billing plan list") {
687
+ const plans = Object.entries(result).map(([key, value]) => {
688
+ const entry = record(value);
689
+ const plan = record(entry?.plan);
690
+ return {
691
+ key,
692
+ cycle: entry?.billing_cycle_months,
693
+ mau: record(plan?.mau)?.purchased_units,
694
+ };
695
+ });
696
+ return [
697
+ ctx.color.bold(plans.length
698
+ ? countLabel(plans.length, "catalog plan")
699
+ : "No catalog plans returned."),
700
+ ...targetRows,
701
+ ...table(plans.slice(0, 12), [
702
+ { label: "Plan key", value: (r) => r.key, max: 38 },
703
+ { label: "Cycle (months)", value: (r) => r.cycle, max: 18 },
704
+ { label: "MAU", value: (r) => r.mau, max: 15 },
705
+ ], ctx),
706
+ ...(plans.length > 12
707
+ ? [row("More", "Use --json for the full catalog", ctx)]
708
+ : []),
709
+ ` ${ctx.color.dim("Catalog entries are not eligibility decisions or price quotes.")}`,
710
+ ];
711
+ }
712
+ if (command === "usage chat org") {
713
+ const data = Array.isArray(result.data)
714
+ ? result.data.map(record).filter((r) => r !== undefined)
715
+ : [];
716
+ return [
717
+ ctx.color.bold(data.length
718
+ ? countLabel(data.length, "Chat usage month")
719
+ : "No Chat usage found for these months."),
720
+ ...targetRows,
721
+ ...table(data.slice(0, 12), [
722
+ { label: "Month", value: (r) => r.record_month, max: 12 },
723
+ { label: "MAU", value: (r) => r.mau, max: 15 },
724
+ { label: "Peak conn", value: (r) => r.pc, max: 15 },
725
+ {
726
+ label: "Avg storage (bytes)",
727
+ value: (r) => r.avg_file_storage,
728
+ max: 24,
729
+ },
730
+ ], ctx),
731
+ ...(data.length > 12
732
+ ? [row("More", "Use --json for every month and feature", ctx)]
733
+ : []),
734
+ ];
735
+ }
736
+ if (command === "usage chat app") {
737
+ const data = record(result.data) ?? {};
738
+ const metrics = [
739
+ "mau",
740
+ "pc",
741
+ "upload_traffic",
742
+ "avg_file_storage",
743
+ "file_storage",
744
+ ]
745
+ .map((key) => ({ key, value: record(data[key]) }))
746
+ .filter((entry) => entry.value !== undefined);
747
+ return [
748
+ ctx.color.bold("Application Chat usage"),
749
+ ...targetRows,
750
+ row("Updated", data.updated_dt ?? "Not provided", ctx),
751
+ ...table(metrics, [
752
+ { label: "Feature", value: (r) => r.key, max: 24 },
753
+ { label: "App", value: (r) => record(r.value)?.usage, max: 16 },
754
+ {
755
+ label: "Other apps",
756
+ value: (r) => record(r.value)?.others_usage,
757
+ max: 18,
758
+ },
759
+ { label: "Quota", value: (r) => record(r.value)?.quota, max: 16 },
760
+ ], ctx),
761
+ ` ${ctx.color.dim("Units vary by feature; use --json for source values and all fields.")}`,
762
+ ];
763
+ }
764
+ if (command === "usage calls org") {
765
+ if (Array.isArray(result.data)) {
766
+ const apps = result.data;
767
+ return [
768
+ ctx.color.bold(apps.length
769
+ ? `${countLabel(apps.length, "application")} with voice/video usage`
770
+ : "No voice/video usage found."),
771
+ ...targetRows,
772
+ ...apps
773
+ .slice(0, 12)
774
+ .flatMap((app) => [
775
+ row("Application", app.app_name, ctx),
776
+ row("App ID", app.app_id, ctx),
777
+ row("Seconds", app.usage, ctx),
778
+ row("Credits", app.used_credit, ctx),
779
+ row("Calls enabled", app.call_enabled, ctx),
780
+ ]),
781
+ ...(apps.length > 12
782
+ ? [row("More", "Use --json for every application", ctx)]
783
+ : []),
784
+ ` ${ctx.color.dim("The source can include Live usage; this is not a Chat subscription charge.")}`,
785
+ ];
786
+ }
787
+ const data = record(result.data) ?? {};
788
+ const types = Object.entries(data).map(([key, value]) => ({
789
+ key,
790
+ value: record(value),
791
+ }));
792
+ return [
793
+ ctx.color.bold(types.length
794
+ ? countLabel(types.length, "voice/video usage type")
795
+ : "No voice/video usage found."),
796
+ ...targetRows,
797
+ ...table(types.slice(0, 12), [
798
+ { label: "Type", value: (r) => r.key, max: 40 },
799
+ { label: "Seconds", value: (r) => record(r.value)?.usage, max: 18 },
800
+ {
801
+ label: "Credits",
802
+ value: (r) => record(r.value)?.used_credit,
803
+ max: 18,
804
+ },
805
+ ], ctx),
806
+ ...(types.length > 12
807
+ ? [row("More", "Use --json for every type", ctx)]
808
+ : []),
809
+ ` ${ctx.color.dim("The source can include Live usage; this is not a Chat subscription charge.")}`,
810
+ ];
811
+ }
812
+ if (command === "usage calls app") {
813
+ const data = record(result.data) ?? {};
814
+ return [
815
+ ctx.color.bold("Application voice/video usage"),
816
+ ...targetRows,
817
+ row("Seconds", data.usage, ctx),
818
+ row("Credits used", data.used_credit, ctx),
819
+ row("Org credits", data.org_credit, ctx),
820
+ row("Org remaining", data.org_remaining_credit, ctx),
821
+ ` ${ctx.color.dim("Source totals may include Live. Use --json for all fields.")}`,
822
+ ];
823
+ }
824
+ if (command === "usage calls trend") {
825
+ const data = record(result.data) ?? {};
826
+ const calls = Array.isArray(data.calls)
827
+ ? data.calls.map(record).filter((r) => r !== undefined)
828
+ : [];
829
+ return [
830
+ ctx.color.bold(calls.length
831
+ ? countLabel(calls.length, "Calls usage period")
832
+ : "No Calls usage found for this period."),
833
+ ...targetRows,
834
+ ...table(calls.slice(0, 12), [
835
+ { label: "Period", value: (r) => r.record_date, max: 18 },
836
+ { label: "Seconds", value: (r) => r.usage, max: 18 },
837
+ { label: "Credits", value: (r) => r.used_credit, max: 18 },
838
+ ], ctx),
839
+ ...(calls.length > 12
840
+ ? [row("More", "Use --json for every period", ctx)]
841
+ : []),
842
+ ` ${ctx.color.dim("Calls only here; --json retains total and Live series.")}`,
843
+ ];
844
+ }
845
+ if (command === "usage calls app-trend") {
846
+ const periods = Array.isArray(result.data)
847
+ ? result.data.map(record).filter((item) => item !== undefined)
848
+ : [];
849
+ return [
850
+ ctx.color.bold(periods.length
851
+ ? countLabel(periods.length, "voice/video usage period")
852
+ : "No voice/video usage found for this app and period."),
853
+ ...targetRows,
854
+ ...table(periods.slice(0, 12), [
855
+ { label: "Period", value: (r) => r.record_date, max: 18 },
856
+ { label: "Updated", value: (r) => r.updated_dt, max: 27 },
857
+ {
858
+ label: "Usage types",
859
+ value: (r) => Object.values(r).filter((item) => record(item)?.usage !== undefined).length,
860
+ max: 15,
861
+ },
862
+ ], ctx),
863
+ ` ${ctx.color.dim("Use --json for seconds and credits by type, including any Live usage.")}`,
864
+ ];
865
+ }
866
+ }
867
+ export function humanOperation(value, options = {}) {
868
+ const ctx = view(options);
869
+ const secrets = secretValues(value.result);
870
+ const safeValue = {
871
+ ...value,
872
+ target: redact(value.target, secrets),
873
+ result: redact(value.result, secrets),
874
+ };
875
+ const command = safeValue.command.replace(/^sendbird /, "");
876
+ if (safeValue.status !== "preview")
877
+ safeValue.result = humanValueSemantics(command, safeValue.result);
878
+ const result = record(safeValue.result) ?? {};
879
+ if (command.startsWith("skills ")) {
880
+ const lines = [];
881
+ if (command === "skills show") {
882
+ lines.push(ctx.color.bold("Sendbird CLI Skill"), row("Path", result.path, ctx), "", clean(result.content));
883
+ if (Array.isArray(result.references))
884
+ for (const path of result.references)
885
+ lines.push(row("Path", path, ctx));
886
+ }
887
+ else if (Array.isArray(result.installations)) {
888
+ lines.push(ctx.color.bold("Sendbird CLI Skill registrations"), row("CLI version", result.bundled_version, ctx));
889
+ for (const item of result.installations) {
890
+ const r = record(item) ?? {};
891
+ lines.push("", ctx.color.bold(`${clean(r.agent)} · ${clean(r.scope)}`), row("State", clean(r.state).replaceAll("_", " "), ctx), row("Version", r.version ?? "—", ctx), row("Path", r.path ?? "Unavailable", ctx));
892
+ const transaction = record(r.transaction);
893
+ if (transaction?.lock_present)
894
+ lines.push(...paragraph("A registration lock exists; work may be active or interrupted. Inspect before manual recovery.", ctx));
895
+ if (Array.isArray(transaction?.backup_paths))
896
+ for (const path of transaction.backup_paths)
897
+ lines.push(row("Path", path, ctx));
898
+ }
899
+ }
900
+ else {
901
+ const state = clean(result.state).replaceAll("_", " ");
902
+ lines.push(ctx.color.bold(safeValue.status === "preview"
903
+ ? `Preview CLI Skill registration · ${state}`
904
+ : ({
905
+ installed: "Registered Sendbird CLI Skill",
906
+ updated: "Updated Sendbird CLI Skill",
907
+ current: "CLI Skill already current",
908
+ removed: "Removed CLI Skill registration",
909
+ absent: "No CLI Skill registered at this location",
910
+ }[String(result.state)] ?? `CLI Skill · ${state}`)), row("Agent", result.agent, ctx), row("Scope", result.scope, ctx), row("Path", result.path, ctx), row("Version", result.version, ctx), row("Host loading", "Not verified", ctx));
911
+ }
912
+ lines.push(...paragraph(result.note, ctx), ...paragraph(result.next, ctx));
913
+ return lines.join("\n");
914
+ }
915
+ if (safeValue.status === "preview")
916
+ return preview(safeValue, ctx).join("\n");
917
+ if (command.startsWith("calls credits ")) {
918
+ const lines = [
919
+ ctx.color.bold(command.endsWith("list")
920
+ ? "Calls voucher history"
921
+ : "Free Calls trial request accepted"),
922
+ row("Organization", result.org_id, ctx),
923
+ ];
924
+ const entries = (Array.isArray(result.vouchers) ? result.vouchers : [result.voucher])
925
+ .map(record)
926
+ .filter((entry) => Boolean(entry));
927
+ if (!entries.length)
928
+ lines.push(result.total === 0
929
+ ? " No voucher history returned."
930
+ : " Voucher details not returned.");
931
+ for (const entry of entries) {
932
+ const voucher = entry;
933
+ lines.push(row("Voucher", voucher.voucher_id, ctx), row("Status", voucher.status, ctx), row("Credits", voucher.credit, ctx), row("Carried credits", voucher.transferred_credit, ctx), row("Used credits", voucher.used_credit, ctx), row("Balance", voucher.remaining_credit, ctx), row("Started", voucher.started_at ? localTime(voucher.started_at) : "Not started", ctx), row("Expires", voucher.expires_at ? localTime(voucher.expires_at) : "Not provided", ctx));
934
+ }
935
+ const readback = record(result.readback);
936
+ if (readback)
937
+ lines.push(row("Readback", readback.status, ctx), ...paragraph(readback.note, ctx));
938
+ else
939
+ lines.push(...paragraph(result.note, ctx));
940
+ if (typeof result.next_offset === "number")
941
+ lines.push(row("Next offset", result.next_offset, ctx));
942
+ lines.push(...paragraph("Check status and expiry. A balance alone does not prove active credit or call availability.", ctx));
943
+ if (command.endsWith("claim-trial")) {
944
+ const next = Array.isArray(readback?.next)
945
+ ? readback.next
946
+ .map(record)
947
+ .find((step) => Array.isArray(step?.argv) &&
948
+ step.argv.length > 0 &&
949
+ step.argv.every((arg) => typeof arg === "string"))
950
+ : undefined;
951
+ lines.push(row("Next", next
952
+ ? commandLine(next.argv)
953
+ : "sendbird calls credits list", ctx));
954
+ }
955
+ return lines.join("\n");
956
+ }
957
+ if (command.startsWith("app feature ")) {
958
+ const lines = [
959
+ ctx.color.bold(command.endsWith("list")
960
+ ? "Application feature settings"
961
+ : "Feature change accepted"),
962
+ row("App", safeValue.target.app_id, ctx),
963
+ ];
964
+ if (command.endsWith("list")) {
965
+ lines.push(...table(result.features ?? [], [
966
+ { label: "Feature", value: (r) => r.feature, min: 30, max: 34 },
967
+ {
968
+ label: "Enabled",
969
+ value: (r) => r.enabled === null ? "Unknown" : r.enabled ? "Yes" : "No",
970
+ min: 10,
971
+ max: 12,
972
+ },
973
+ ], ctx));
974
+ }
975
+ else {
976
+ lines.push(row("Feature", result.feature, ctx), row("Requested", result.requested_enabled === true ? "Enabled" : "Disabled", ctx));
977
+ const readback = record(result.readback);
978
+ lines.push(row("Readback", readback?.status === "matches"
979
+ ? "Requested settings observed"
980
+ : readback?.status === "mismatch"
981
+ ? "Different settings observed; inspect before another change"
982
+ : "Unavailable; write was accepted", ctx));
983
+ if (result.feature === "advanced_profanity_filter" &&
984
+ result.requested_enabled === true)
985
+ lines.push(...paragraph("The basic profanity filter was also requested off, matching Dashboard behavior.", ctx));
986
+ const next = Array.isArray(readback?.next)
987
+ ? record(readback.next[0])
988
+ : undefined;
989
+ if (Array.isArray(next?.argv))
990
+ lines.push(...paragraph("Verify: " + commandLine(next.argv), ctx));
991
+ }
992
+ lines.push(...paragraph(result.note, ctx));
993
+ return lines.join("\n");
994
+ }
995
+ const pro = proOutput(command, result, safeValue.target, safeValue.status === "accepted", ctx);
996
+ if (pro)
997
+ return pro.join("\n");
998
+ if (safeValue.status === "accepted" ||
999
+ (safeValue.status === "succeeded" &&
1000
+ (command === "setup" ||
1001
+ /\b(create|use|clear|delete|init|login|logout|signup|verify-email|resend-verification)$/.test(command))))
1002
+ return receipt(safeValue, ctx).join("\n");
1003
+ if (command === "profile list")
1004
+ return profileList(result, ctx).join("\n");
1005
+ const billingUsage = billingUsageRead(command, result, safeValue.target, ctx);
1006
+ if (billingUsage)
1007
+ return billingUsage.join("\n");
1008
+ const listed = listOutput(command, result, safeValue.target, ctx);
1009
+ if (listed)
1010
+ return listed.join("\n");
1011
+ if (command === "chat channel watch" || safeValue.status === "completed") {
1012
+ const lines = [`${ctx.color.green("✓")} ${ctx.color.bold("Stream ended")}`];
1013
+ if (safeValue.target.channel_url)
1014
+ lines.push(row("Channel", safeValue.target.channel_url, ctx));
1015
+ if (result.reason)
1016
+ lines.push(row("Reason", result.reason, ctx));
1017
+ if (typeof result.events === "number")
1018
+ lines.push(row("Events", result.events, ctx));
1019
+ return lines.join("\n");
1020
+ }
1021
+ return detailRows(command, result, safeValue.target, ctx).join("\n");
1022
+ }
1023
+ export function humanEvent(command, value, options = {}) {
1024
+ const ctx = view(options);
1025
+ const event = record(value) ?? {};
1026
+ const channel = record(event.channel);
1027
+ const data = record(event.data);
1028
+ const name = clean(event.event || "event").replaceAll("_", " ");
1029
+ const context = [
1030
+ event.channel_url ?? channel?.channel_url,
1031
+ data?.message_id ? `message ${data.message_id}` : undefined,
1032
+ ]
1033
+ .filter(Boolean)
1034
+ .map(clean);
1035
+ return `${ctx.color.dim("•")} ${ctx.color.bold(name)}${context.length ? ` · ${context.join(" · ")}` : ""}`;
1036
+ }
1037
+ function discovery(value, ctx) {
1038
+ if (value.__human_view === "example") {
1039
+ const shell = clean(value.shell);
1040
+ return [
1041
+ ctx.color.bold(`Example · ${clean(value.command)}`),
1042
+ ` ${shell}`,
1043
+ ` ${ctx.color.dim("Replace placeholder IDs. --example --json returns the structured input.")}`,
1044
+ ];
1045
+ }
1046
+ if (value.__human_view === "schema") {
1047
+ const schema = JSON.stringify(value.schema, null, 2);
1048
+ return [
1049
+ ctx.color.bold(`Response schema · ${clean(value.command)}`),
1050
+ ...schema.split("\n").map((line) => ` ${line}`),
1051
+ ];
1052
+ }
1053
+ if (typeof value.entrypoint === "string" && Array.isArray(value.discovery)) {
1054
+ const steps = value.discovery
1055
+ .map(record)
1056
+ .filter((item) => item !== undefined);
1057
+ return [
1058
+ ctx.color.bold("Sendbird Chat CLI"),
1059
+ " Manage Chat resources and verify user messaging.",
1060
+ row("Get started", "sendbird setup", ctx),
1061
+ row("Agent skills", "sendbird skills status", ctx),
1062
+ row("Staging app hosts", "sendbird --profile staging --app-id APP_ID app sdk-config --raw", ctx),
1063
+ ...steps
1064
+ .slice(0, 3)
1065
+ .map((item) => row(clean(item.purpose).split(" ").slice(0, 2).join(" "), commandLine(item.argv), ctx, 140)),
1066
+ ` ${ctx.color.dim("For agents: sendbird --json agent")}`,
1067
+ ];
1068
+ }
1069
+ if (typeof value.command === "string" && Array.isArray(value.flags)) {
1070
+ const lines = [ctx.color.bold(clean(value.command))];
1071
+ if (value.description)
1072
+ lines.push(` ${clean(value.description)}`);
1073
+ if (value.authentication)
1074
+ lines.push(row("Authentication", value.authentication, ctx));
1075
+ if (Array.isArray(value.required) && value.required.length)
1076
+ lines.push(row("Required", value.required.join(", "), ctx));
1077
+ const example = record(value.example);
1078
+ const meanings = record(value.value_semantics);
1079
+ if (Array.isArray(meanings?.fields))
1080
+ lines.push(row("Value meanings", `${meanings.fields.length} fields; use --json describe`, ctx));
1081
+ if (typeof example?.shell === "string") {
1082
+ lines.push(` ${ctx.color.dim("Example")}`);
1083
+ lines.push(` ${clean(example.shell)}`);
1084
+ }
1085
+ if (Array.isArray(value.constraints) && value.constraints.length)
1086
+ lines.push(` ${ctx.color.dim("Notes")} ${clip(value.constraints[0], ctx.width - 11)}`);
1087
+ lines.push(` ${ctx.color.dim("Use --json describe for schemas and every flag.")}`);
1088
+ return lines;
1089
+ }
1090
+ if (Array.isArray(value.commands)) {
1091
+ const rows = value.commands
1092
+ .map(record)
1093
+ .filter((item) => item !== undefined);
1094
+ const total = typeof value.total === "number" ? value.total : rows.length;
1095
+ const shown = rows.slice(0, 10);
1096
+ return [
1097
+ ctx.color.bold(countLabel(total, "command")),
1098
+ ...(total > rows.length
1099
+ ? [row("Showing", `${Math.min(rows.length, 10)} of ${total}`, ctx)]
1100
+ : []),
1101
+ ...(ctx.width < 80
1102
+ ? shown.flatMap((item) => [
1103
+ ` ${ctx.color.bold(clean(item.command))}`,
1104
+ ` ${ctx.color.dim(clip(item.description, ctx.width - 6))}`,
1105
+ ])
1106
+ : table(shown, [
1107
+ { label: "Command", value: (r) => r.command, max: 55, min: 52 },
1108
+ {
1109
+ label: "Description",
1110
+ value: (r) => r.description,
1111
+ max: 55,
1112
+ min: 20,
1113
+ },
1114
+ ], ctx)),
1115
+ ` ${ctx.color.dim("Search: sendbird commands --compact --search task words")}`,
1116
+ ];
1117
+ }
1118
+ if (Array.isArray(value.workflows)) {
1119
+ const rows = value.workflows
1120
+ .map(record)
1121
+ .filter((item) => item !== undefined);
1122
+ return [
1123
+ ctx.color.bold(countLabel(rows.length, "workflow")),
1124
+ ...table(rows, [
1125
+ { label: "ID", value: (r) => r.id, max: 30 },
1126
+ { label: "Purpose", value: (r) => r.title, max: 55 },
1127
+ ], ctx),
1128
+ ` ${ctx.color.dim("Inspect: sendbird workflows WORKFLOW_ID")}`,
1129
+ ];
1130
+ }
1131
+ if (Array.isArray(value.steps) && typeof value.id === "string") {
1132
+ const steps = value.steps
1133
+ .map(record)
1134
+ .filter((item) => item !== undefined);
1135
+ const lines = [ctx.color.bold(clean(value.title ?? value.id))];
1136
+ if (value.description)
1137
+ lines.push(` ${clean(value.description)}`);
1138
+ lines.push(` ${ctx.color.dim("Plan only; no requests sent.")}`);
1139
+ for (const [index, step] of steps.entries()) {
1140
+ lines.push(` ${index + 1}. ${ctx.color.bold(clean(step.id))}`);
1141
+ if (Array.isArray(step.argv))
1142
+ lines.push(` ${commandLine(step.argv)}`);
1143
+ }
1144
+ return lines;
1145
+ }
1146
+ if (Array.isArray(value.results) && typeof value.query === "string") {
1147
+ const rows = value.results
1148
+ .map(record)
1149
+ .filter((item) => item !== undefined);
1150
+ const total = typeof value.total === "number" ? value.total : rows.length;
1151
+ const lines = [
1152
+ ctx.color.bold(rows.length
1153
+ ? `${total} documentation results for “${clean(value.query)}”`
1154
+ : `No documentation results for “${clean(value.query)}”.`),
1155
+ ];
1156
+ if (rows.length) {
1157
+ if (ctx.width < 90 || rows.some((item) => width(clean(item.id)) > 50))
1158
+ lines.push(...rows.flatMap((item) => [
1159
+ ` ${ctx.color.bold(clean(item.title))}`,
1160
+ ` ${ctx.color.dim("ID")} ${clean(item.id)}`,
1161
+ ]));
1162
+ else
1163
+ lines.push(...table(rows, [
1164
+ { label: "Title", value: (r) => r.title, max: 36 },
1165
+ { label: "Section ID", value: (r) => r.id, max: 50 },
1166
+ ], ctx));
1167
+ }
1168
+ if (typeof value.next_offset === "number")
1169
+ lines.push(row("More", `--offset ${value.next_offset}`, ctx));
1170
+ return lines;
1171
+ }
1172
+ }
1173
+ /** Bounded, semantic terminal rendering. Machine JSON never calls this module. */
1174
+ export function humanValue(value, options = {}) {
1175
+ if (typeof value === "string")
1176
+ return value;
1177
+ if (value === null || value === undefined)
1178
+ return "No data returned.";
1179
+ const ctx = view(options);
1180
+ if (Array.isArray(value)) {
1181
+ const rows = value.map(record).filter((item) => item !== undefined);
1182
+ return rows.length
1183
+ ? table(rows.slice(0, 10), Object.keys(rows[0])
1184
+ .slice(0, 3)
1185
+ .map((key) => ({
1186
+ label: titleCase(key.replaceAll("_", " ")),
1187
+ value: (r) => r[key],
1188
+ })), ctx).join("\n")
1189
+ : "No items found.";
1190
+ }
1191
+ const data = record(redact(value, secretValues(value)));
1192
+ if (!data)
1193
+ return clean(value);
1194
+ if (data.ok === true &&
1195
+ typeof data.command === "string" &&
1196
+ typeof data.status === "string" &&
1197
+ "result" in data)
1198
+ return humanOperation(data, options);
1199
+ if (data.ok === true &&
1200
+ data.type === "event" &&
1201
+ typeof data.command === "string")
1202
+ return humanEvent(data.command.replace(/^sendbird /, ""), data.event, options);
1203
+ const specialized = discovery(data, ctx);
1204
+ if (specialized)
1205
+ return specialized.join("\n");
1206
+ const lines = [ctx.color.bold("Result")];
1207
+ for (const [key, item] of Object.entries(data).slice(0, 10)) {
1208
+ if (Array.isArray(item))
1209
+ lines.push(row(titleCase(key), countLabel(item.length, key.endsWith("s") ? key.slice(0, -1) : "item"), ctx));
1210
+ else if (record(item))
1211
+ lines.push(row(titleCase(key), `${Object.keys(record(item)).length} fields`, ctx));
1212
+ else
1213
+ lines.push(row(titleCase(key), item, ctx));
1214
+ }
1215
+ return lines.join("\n");
1216
+ }
1217
+ export function humanFailure(value, options = {}) {
1218
+ const ctx = view(options, true);
1219
+ value = record(redact(value, secretValues(value))) ?? {};
1220
+ const message = clean(value.message) || "Command failed";
1221
+ // Reasons and safe next actions must remain readable on narrow terminals.
1222
+ const lines = paragraph(message, ctx).map((line, index) => index === 0 ? `${ctx.color.red("✗")} ${ctx.color.bold(line.trim())}` : line);
1223
+ if (typeof value.command === "string")
1224
+ lines.push(row("Command", value.command, ctx));
1225
+ if (typeof value.code === "string")
1226
+ lines.push(row("Code", value.code, ctx));
1227
+ const details = record(value.details);
1228
+ if (typeof details?.status === "number")
1229
+ lines.push(row("HTTP", details.status, ctx));
1230
+ if (Array.isArray(value.details))
1231
+ for (const issue of value.details.slice(0, 3)) {
1232
+ const detail = record(issue);
1233
+ if (!detail)
1234
+ continue;
1235
+ const path = Array.isArray(detail.path) ? detail.path.join(".") : "Input";
1236
+ lines.push(row(clean(path || "Input"), detail.message, ctx));
1237
+ }
1238
+ if (value.outcome_unknown === true)
1239
+ lines.push(` ${ctx.color.yellow("!")} Outcome uncertain. Read the resource before retrying.`);
1240
+ const recovery = record(value.recovery);
1241
+ const recoveryTarget = record(recovery?.target);
1242
+ if (typeof value.mutation_state === "string")
1243
+ lines.push(row("Request", {
1244
+ not_attempted: "Change was not attempted",
1245
+ rejected: "Server rejected the change",
1246
+ unknown: "May have reached the server",
1247
+ acknowledged: "Server acknowledged; final result needs verification",
1248
+ }[value.mutation_state] ?? value.mutation_state, ctx));
1249
+ if (recoveryTarget) {
1250
+ if (recoveryTarget.profile)
1251
+ lines.push(row("Profile", recoveryTarget.profile, ctx));
1252
+ if (recoveryTarget.app_id)
1253
+ lines.push(row("App", recoveryTarget.app_id, ctx));
1254
+ if (recoveryTarget.actor_user_id)
1255
+ lines.push(row("Actor", recoveryTarget.actor_user_id, ctx));
1256
+ }
1257
+ if (typeof recovery?.note === "string")
1258
+ lines.push(...paragraph(recovery.note, ctx));
1259
+ if (recovery)
1260
+ lines.push(" A missing result is inconclusive. Do not repeat the change automatically.");
1261
+ const next = Array.isArray(value.next)
1262
+ ? value.next.map(record).filter((item) => item !== undefined)
1263
+ : [];
1264
+ const describes = (item) => Array.isArray(item.argv) && item.argv.includes("describe");
1265
+ next.sort((a, b) => Number(describes(a)) - Number(describes(b)));
1266
+ const commands = next
1267
+ .slice(0, 2)
1268
+ .map((item) => item.argv)
1269
+ .filter((argv) => Array.isArray(argv) && argv.every((part) => typeof part === "string"));
1270
+ if (commands.length) {
1271
+ lines.push(` ${ctx.color.dim(commands.length === 1 ? "Next" : "Next steps")}`);
1272
+ for (const argv of commands)
1273
+ lines.push(` ${commandLine(argv)}`);
1274
+ }
1275
+ return lines.join("\n");
1276
+ }
1277
+ /** Keep observations and runtime conclusions separate in the terminal view. */
1278
+ function diagnosticLines(result, ctx) {
1279
+ const lines = [
1280
+ ctx.color.bold("Sendbird diagnostics"),
1281
+ row("Profile", result.profile, ctx),
1282
+ row("Environment", result.environment, ctx),
1283
+ row("Organization UID", result.org_id ?? "Not selected", ctx),
1284
+ row("App", result.app_id ?? "Not selected", ctx),
1285
+ row("Role", record(result.role)?.name ?? "Unknown", ctx),
1286
+ ];
1287
+ const sub = record(result.subscription);
1288
+ lines.push(row("Chat plan", sub?.display_name ?? sub?.name ?? "Unknown", ctx));
1289
+ if (sub?.name)
1290
+ lines.push(row("Subscription", sub.name, ctx));
1291
+ const assessment = record(result.assessment);
1292
+ if (assessment) {
1293
+ lines.push(row("Command", assessment.command, ctx), row("Preflight", assessment.status === "allowed"
1294
+ ? "Read verified"
1295
+ : assessment.status === "denied"
1296
+ ? "Prerequisite denied"
1297
+ : "Needs verification", ctx));
1298
+ if (assessment.resource_id)
1299
+ lines.push(row("Resource", assessment.resource_id, ctx));
1300
+ }
1301
+ const checks = result.checks
1302
+ .map(record)
1303
+ .filter((r) => Boolean(r));
1304
+ lines.push("", ...table(checks, [
1305
+ { label: "Check", value: (r) => r.id, max: 24 },
1306
+ { label: "Status", value: (r) => r.status, min: 10, max: 10 },
1307
+ { label: "Reason", value: (r) => r.reason, max: 64, min: 24 },
1308
+ ], ctx));
1309
+ if (Array.isArray(result.features) && result.features.length) {
1310
+ const value = (x) => x === true ? "Yes" : x === false ? "No" : "?";
1311
+ lines.push("", ctx.color.bold("Feature evidence (runtime not tested)"), ...table(result.features.map(record).filter((r) => Boolean(r)), [
1312
+ { label: "Feature", value: (r) => r.feature, max: 22 },
1313
+ { label: "Plan", value: (r) => value(r.entitlement), max: 8 },
1314
+ {
1315
+ label: "Enabled API",
1316
+ value: (r) => value(r.reported_enabled),
1317
+ min: 13,
1318
+ max: 13,
1319
+ },
1320
+ {
1321
+ label: "Detail API",
1322
+ value: (r) => value(r.detail_snapshot),
1323
+ max: 12,
1324
+ },
1325
+ ], ctx), ...paragraph("Plan = entitlement. API columns = reported settings. No does not establish runtime denial; Insight/runtime may need separate verification.", ctx));
1326
+ }
1327
+ if (Array.isArray(result.limits) && result.limits.length) {
1328
+ lines.push("", ctx.color.bold("Configured limits (source units)"), ...table(result.limits.map(record).filter((r) => Boolean(r)), [
1329
+ { label: "Metric", value: (r) => r.metric, max: 28 },
1330
+ { label: "Included", value: (r) => r.included_units ?? "?", max: 16 },
1331
+ {
1332
+ label: "Hard limit",
1333
+ value: (r) => r.configured_hard_limit ?? "?",
1334
+ max: 18,
1335
+ },
1336
+ ], ctx), ...paragraph("These are plan configuration values, not remaining usage, a price quote, or a guarantee of unlimited API requests.", ctx));
1337
+ }
1338
+ const capacity = record(result.app_capacity);
1339
+ if (capacity)
1340
+ lines.push(row("Apps", `${capacity.count ?? "?"} / ${capacity.maximum ?? "?"}`, ctx));
1341
+ if (Array.isArray(result.regions) && result.regions.length)
1342
+ lines.push("", ctx.color.bold("Organization regions"), ...table(result.regions.map(record).filter((r) => Boolean(r)), [
1343
+ { label: "Region", value: (r) => r.id, max: 22 },
1344
+ { label: "Family", value: (r) => r.family, max: 12 },
1345
+ { label: "Create", value: (r) => r.available ?? "?", max: 10 },
1346
+ { label: "Calls", value: (r) => r.calls ?? "?", max: 10 },
1347
+ ], ctx));
1348
+ lines.push("", ...paragraph("Read-only diagnosis: no feature activation, SDK connection or mutation probe. Use --json for full evidence and unresolved conditions.", ctx));
1349
+ return lines;
1350
+ }
1351
+ //# sourceMappingURL=human-output.js.map