@selleragent/sa-admin 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.tsbuildinfo +1 -0
- package/dist/auth.d.ts +73 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +313 -0
- package/dist/auth.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +1199 -0
- package/dist/cli.js.map +1 -0
- package/dist/context.d.ts +19 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +46 -0
- package/dist/context.js.map +1 -0
- package/dist/help.d.ts +2 -0
- package/dist/help.d.ts.map +1 -0
- package/dist/help.js +469 -0
- package/dist/help.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -0
- package/dist/project.d.ts +120 -0
- package/dist/project.d.ts.map +1 -0
- package/dist/project.js +241 -0
- package/dist/project.js.map +1 -0
- package/dist/provisioning.d.ts +27 -0
- package/dist/provisioning.d.ts.map +1 -0
- package/dist/provisioning.js +55 -0
- package/dist/provisioning.js.map +1 -0
- package/dist/render.d.ts +3 -0
- package/dist/render.d.ts.map +1 -0
- package/dist/render.js +14 -0
- package/dist/render.js.map +1 -0
- package/dist/rollout.d.ts +231 -0
- package/dist/rollout.d.ts.map +1 -0
- package/dist/rollout.js +971 -0
- package/dist/rollout.js.map +1 -0
- package/package.json +40 -0
package/dist/cli.js
ADDED
|
@@ -0,0 +1,1199 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
const promises_1 = require("node:fs/promises");
|
|
5
|
+
const node_path_1 = require("node:path");
|
|
6
|
+
const client_sdk_1 = require("@selleragent/client-sdk");
|
|
7
|
+
const auth_1 = require("./auth");
|
|
8
|
+
const context_1 = require("./context");
|
|
9
|
+
const help_1 = require("./help");
|
|
10
|
+
const provisioning_1 = require("./provisioning");
|
|
11
|
+
const rollout_1 = require("./rollout");
|
|
12
|
+
const project_1 = require("./project");
|
|
13
|
+
const render_1 = require("./render");
|
|
14
|
+
function flagValue(args, name) {
|
|
15
|
+
const index = args.indexOf(name);
|
|
16
|
+
return index >= 0 ? args[index + 1] ?? null : null;
|
|
17
|
+
}
|
|
18
|
+
function flagValues(args, name) {
|
|
19
|
+
const values = [];
|
|
20
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
21
|
+
if (args[index] === name && args[index + 1]) {
|
|
22
|
+
values.push(args[index + 1]);
|
|
23
|
+
index += 1;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return values;
|
|
27
|
+
}
|
|
28
|
+
function hasFlag(args, name) {
|
|
29
|
+
return args.includes(name);
|
|
30
|
+
}
|
|
31
|
+
function normalizeTelegramUsername(value) {
|
|
32
|
+
if (!value) {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
const normalized = value.trim().replace(/^@/, '');
|
|
36
|
+
return normalized.length > 0 ? normalized : null;
|
|
37
|
+
}
|
|
38
|
+
function extractCommandTokens(args) {
|
|
39
|
+
const tokens = [];
|
|
40
|
+
for (const arg of args) {
|
|
41
|
+
if (arg.startsWith('-')) {
|
|
42
|
+
break;
|
|
43
|
+
}
|
|
44
|
+
tokens.push(arg);
|
|
45
|
+
}
|
|
46
|
+
return tokens;
|
|
47
|
+
}
|
|
48
|
+
function normalizeCommandTokens(tokens) {
|
|
49
|
+
if (tokens[0] === 'telegram-bots') {
|
|
50
|
+
return ['telegram', 'integrations', ...tokens.slice(1)];
|
|
51
|
+
}
|
|
52
|
+
if (tokens[0] === 'telegram-business-accounts') {
|
|
53
|
+
return ['telegram', 'business-accounts', ...tokens.slice(1)];
|
|
54
|
+
}
|
|
55
|
+
if (tokens[0] === 'emp' && tokens[1] === 'telegram') {
|
|
56
|
+
return ['telegram', 'employees', ...tokens.slice(2)];
|
|
57
|
+
}
|
|
58
|
+
return tokens;
|
|
59
|
+
}
|
|
60
|
+
function resolveProfileSlug(args, manifestBusinessSlug) {
|
|
61
|
+
return flagValue(args, '--business-profile-slug') ?? manifestBusinessSlug;
|
|
62
|
+
}
|
|
63
|
+
function resolveScopedBusinessSlug(args, manifestBusinessSlug, options = {}) {
|
|
64
|
+
const explicit = flagValue(args, '--business-profile-slug');
|
|
65
|
+
if (explicit) {
|
|
66
|
+
return explicit;
|
|
67
|
+
}
|
|
68
|
+
if (options.allowGlobal && hasFlag(args, '--global')) {
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
return options.defaultToManifest === false ? null : manifestBusinessSlug;
|
|
72
|
+
}
|
|
73
|
+
function resolveRuntimeProviderScope(args) {
|
|
74
|
+
const explicit = flagValue(args, '--scope');
|
|
75
|
+
if (explicit === 'global' || explicit === 'business') {
|
|
76
|
+
return explicit;
|
|
77
|
+
}
|
|
78
|
+
return hasFlag(args, '--global') ? 'global' : null;
|
|
79
|
+
}
|
|
80
|
+
async function resolveIntegrationKey(context, args) {
|
|
81
|
+
const explicit = flagValue(args, '--integration-key');
|
|
82
|
+
if (explicit) {
|
|
83
|
+
return explicit;
|
|
84
|
+
}
|
|
85
|
+
const declarations = await (0, project_1.loadTelegramBotDeclarations)(context);
|
|
86
|
+
const compatibleDeclarations = declarations.filter((entry) => entry.environmentMatches);
|
|
87
|
+
if (compatibleDeclarations.length === 1) {
|
|
88
|
+
return compatibleDeclarations[0].integrationKey;
|
|
89
|
+
}
|
|
90
|
+
throw new Error('This command requires --integration-key when the current repo declares zero or multiple compatible Telegram integrations for the active environment.');
|
|
91
|
+
}
|
|
92
|
+
async function writeYamlSnapshot(path, content) {
|
|
93
|
+
await (0, promises_1.mkdir)((0, node_path_1.dirname)(path), { recursive: true });
|
|
94
|
+
await (0, promises_1.writeFile)(path, content, 'utf8');
|
|
95
|
+
}
|
|
96
|
+
async function resolveVersionId(input) {
|
|
97
|
+
const versions = await input.client.businessProfiles.listVersions({
|
|
98
|
+
businessProfileSlug: input.businessProfileSlug
|
|
99
|
+
});
|
|
100
|
+
if (input.specifier === 'latest') {
|
|
101
|
+
const latest = versions.versions.at(-1);
|
|
102
|
+
if (!latest) {
|
|
103
|
+
throw new Error(`No versions found for ${input.businessProfileSlug}.`);
|
|
104
|
+
}
|
|
105
|
+
return {
|
|
106
|
+
versionId: latest.versionId,
|
|
107
|
+
versions
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
if (input.specifier === 'active') {
|
|
111
|
+
const profile = await input.client.businessProfiles.get({
|
|
112
|
+
businessProfileSlug: input.businessProfileSlug
|
|
113
|
+
});
|
|
114
|
+
if (!profile.activeVersion) {
|
|
115
|
+
throw new Error(`No active version found for ${input.businessProfileSlug}.`);
|
|
116
|
+
}
|
|
117
|
+
return {
|
|
118
|
+
versionId: profile.activeVersion.versionId,
|
|
119
|
+
versions
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
return {
|
|
123
|
+
versionId: input.specifier,
|
|
124
|
+
versions
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
async function resolveVerifiedBy(context) {
|
|
128
|
+
const whoami = await (0, auth_1.resolveWhoAmI)(context);
|
|
129
|
+
return whoami.accessContext?.operator?.email ?? null;
|
|
130
|
+
}
|
|
131
|
+
async function handleProfileCommand(input) {
|
|
132
|
+
const { args, subcommand, context, outputMode } = input;
|
|
133
|
+
if (subcommand === 'validate') {
|
|
134
|
+
(0, render_1.renderOutput)(await (0, project_1.validateProfileProject)(context), outputMode);
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
if (subcommand === 'upload') {
|
|
138
|
+
const prepared = await (0, project_1.buildProfileBundleForUpload)(context);
|
|
139
|
+
const auth = await (0, auth_1.resolveAuthenticatedClient)({
|
|
140
|
+
context
|
|
141
|
+
});
|
|
142
|
+
const result = await auth.client.businessProfiles.uploadBundle({
|
|
143
|
+
bundle: prepared.bundle,
|
|
144
|
+
activateOnUpload: hasFlag(args, '--activate'),
|
|
145
|
+
targetEnvironment: context.environment,
|
|
146
|
+
sourceRepositoryUrl: prepared.sourceRepositoryUrl,
|
|
147
|
+
sourceCommitSha: prepared.sourceCommitSha,
|
|
148
|
+
resolvedSecrets: prepared.resolvedSecrets
|
|
149
|
+
});
|
|
150
|
+
(0, render_1.renderOutput)({
|
|
151
|
+
...result,
|
|
152
|
+
authMode: auth.authMode,
|
|
153
|
+
projectRoot: context.root.rootDir,
|
|
154
|
+
manifestPath: context.root.manifestPath,
|
|
155
|
+
sourceRepositoryUrl: prepared.sourceRepositoryUrl,
|
|
156
|
+
sourceCommitSha: prepared.sourceCommitSha,
|
|
157
|
+
resolvedBaseUrl: context.baseUrl,
|
|
158
|
+
targetEnvironment: context.environment
|
|
159
|
+
}, outputMode);
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
if (subcommand === 'download') {
|
|
163
|
+
const auth = await (0, auth_1.resolveAuthenticatedClient)({
|
|
164
|
+
context
|
|
165
|
+
});
|
|
166
|
+
const businessProfileSlug = resolveProfileSlug(args, context.manifest.business_slug);
|
|
167
|
+
const result = await auth.client.businessProfiles.downloadBundle({
|
|
168
|
+
businessProfileSlug,
|
|
169
|
+
versionId: flagValue(args, '--version-id')
|
|
170
|
+
});
|
|
171
|
+
const outputDir = (0, node_path_1.resolve)(context.root.rootDir, flagValue(args, '--output-dir') ?? '.');
|
|
172
|
+
await (0, project_1.writeDownloadedProfileBundle)({
|
|
173
|
+
rootDir: outputDir,
|
|
174
|
+
bundle: result.bundle
|
|
175
|
+
});
|
|
176
|
+
(0, render_1.renderOutput)({
|
|
177
|
+
...result,
|
|
178
|
+
authMode: auth.authMode,
|
|
179
|
+
outputDir,
|
|
180
|
+
resolvedBaseUrl: context.baseUrl
|
|
181
|
+
}, outputMode);
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
if (subcommand === 'activate') {
|
|
185
|
+
const specifier = flagValue(args, '--version') ?? flagValue(args, '--version-id');
|
|
186
|
+
if (!specifier) {
|
|
187
|
+
throw new Error('profile activate requires --version <latest|active|version-id>.');
|
|
188
|
+
}
|
|
189
|
+
const auth = await (0, auth_1.resolveAuthenticatedClient)({
|
|
190
|
+
context
|
|
191
|
+
});
|
|
192
|
+
const businessProfileSlug = resolveProfileSlug(args, context.manifest.business_slug);
|
|
193
|
+
const resolvedVersion = await resolveVersionId({
|
|
194
|
+
client: auth.client,
|
|
195
|
+
businessProfileSlug,
|
|
196
|
+
specifier
|
|
197
|
+
});
|
|
198
|
+
const result = await auth.client.businessProfiles.activateVersion({
|
|
199
|
+
businessProfileSlug,
|
|
200
|
+
versionId: resolvedVersion.versionId
|
|
201
|
+
});
|
|
202
|
+
(0, render_1.renderOutput)({
|
|
203
|
+
...result,
|
|
204
|
+
authMode: auth.authMode,
|
|
205
|
+
requestedVersion: specifier
|
|
206
|
+
}, outputMode);
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
if (subcommand === 'status') {
|
|
210
|
+
const auth = await (0, auth_1.resolveAuthenticatedClient)({
|
|
211
|
+
context
|
|
212
|
+
});
|
|
213
|
+
const businessProfileSlug = resolveProfileSlug(args, context.manifest.business_slug);
|
|
214
|
+
const [profile, versions, members] = await Promise.all([
|
|
215
|
+
auth.client.businessProfiles.get({
|
|
216
|
+
businessProfileSlug
|
|
217
|
+
}),
|
|
218
|
+
auth.client.businessProfiles.listVersions({
|
|
219
|
+
businessProfileSlug
|
|
220
|
+
}),
|
|
221
|
+
auth.client.businessProfiles.listMembers({
|
|
222
|
+
businessProfileSlug
|
|
223
|
+
})
|
|
224
|
+
]);
|
|
225
|
+
(0, render_1.renderOutput)({
|
|
226
|
+
profile: profile.profile,
|
|
227
|
+
activeVersion: profile.activeVersion,
|
|
228
|
+
versionsCount: versions.versions.length,
|
|
229
|
+
membersCount: members.members.length,
|
|
230
|
+
authMode: auth.authMode
|
|
231
|
+
}, outputMode);
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
if (subcommand === 'versions') {
|
|
235
|
+
const auth = await (0, auth_1.resolveAuthenticatedClient)({
|
|
236
|
+
context
|
|
237
|
+
});
|
|
238
|
+
const businessProfileSlug = resolveProfileSlug(args, context.manifest.business_slug);
|
|
239
|
+
const versions = await auth.client.businessProfiles.listVersions({
|
|
240
|
+
businessProfileSlug
|
|
241
|
+
});
|
|
242
|
+
(0, render_1.renderOutput)({
|
|
243
|
+
...versions,
|
|
244
|
+
authMode: auth.authMode
|
|
245
|
+
}, outputMode);
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
throw new Error(`Unknown profile command: ${subcommand ?? '(missing)'}.`);
|
|
249
|
+
}
|
|
250
|
+
async function handleTelegramIntegrationsCommand(input) {
|
|
251
|
+
const { args, action, context, outputMode } = input;
|
|
252
|
+
if (action === 'upload') {
|
|
253
|
+
const prepared = await (0, project_1.buildProfileBundleForUpload)(context);
|
|
254
|
+
const auth = await (0, auth_1.resolveAuthenticatedClient)({ context });
|
|
255
|
+
const secretByIntegration = new Map(prepared.resolvedSecrets.map((entry) => [entry.integrationKey, entry]));
|
|
256
|
+
const results = [];
|
|
257
|
+
const skipped = [];
|
|
258
|
+
for (const declaration of prepared.declarations) {
|
|
259
|
+
if (!declaration.environmentMatches) {
|
|
260
|
+
skipped.push({
|
|
261
|
+
integrationKey: declaration.integrationKey,
|
|
262
|
+
environments: declaration.environments,
|
|
263
|
+
reason: 'skipped_by_environment'
|
|
264
|
+
});
|
|
265
|
+
continue;
|
|
266
|
+
}
|
|
267
|
+
const resolvedSecrets = secretByIntegration.get(declaration.integrationKey);
|
|
268
|
+
results.push(await auth.client.integrations.upsertTelegramBot({
|
|
269
|
+
businessProfileSlug: context.manifest.business_slug,
|
|
270
|
+
integrationKey: declaration.integrationKey,
|
|
271
|
+
label: declaration.label,
|
|
272
|
+
mode: declaration.mode,
|
|
273
|
+
enabled: declaration.enabled,
|
|
274
|
+
webhookPath: declaration.webhookPath,
|
|
275
|
+
...(declaration.allowDirectCommands !== undefined
|
|
276
|
+
? { allowDirectCommands: declaration.allowDirectCommands }
|
|
277
|
+
: {}),
|
|
278
|
+
...(declaration.allowDebugCommands !== undefined
|
|
279
|
+
? { allowDebugCommands: declaration.allowDebugCommands }
|
|
280
|
+
: {}),
|
|
281
|
+
channelAccountId: declaration.channelAccountId ?? null,
|
|
282
|
+
botUsername: declaration.botUsername ?? null,
|
|
283
|
+
telegramBotId: declaration.telegramBotId ?? null,
|
|
284
|
+
...(resolvedSecrets?.botToken !== undefined ? { botToken: resolvedSecrets.botToken } : {}),
|
|
285
|
+
...(resolvedSecrets?.webhookSecret !== undefined
|
|
286
|
+
? { webhookSecret: resolvedSecrets.webhookSecret }
|
|
287
|
+
: {})
|
|
288
|
+
}));
|
|
289
|
+
}
|
|
290
|
+
(0, render_1.renderOutput)({
|
|
291
|
+
authMode: auth.authMode,
|
|
292
|
+
count: results.length,
|
|
293
|
+
skippedCount: skipped.length,
|
|
294
|
+
items: results,
|
|
295
|
+
skipped
|
|
296
|
+
}, outputMode);
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
299
|
+
if (action === 'status' || action === 'download') {
|
|
300
|
+
const auth = await (0, auth_1.resolveAuthenticatedClient)({ context });
|
|
301
|
+
const items = await auth.client.integrations.listTelegramBots({
|
|
302
|
+
businessProfileSlug: resolveProfileSlug(args, context.manifest.business_slug)
|
|
303
|
+
});
|
|
304
|
+
if (action === 'download') {
|
|
305
|
+
const outputFile = (0, node_path_1.resolve)(context.root.rootDir, flagValue(args, '--output-file') ?? '.sa-admin/downloads/telegram-bots.yaml');
|
|
306
|
+
await writeYamlSnapshot(outputFile, (0, project_1.buildTelegramBotSnapshotYaml)({
|
|
307
|
+
integrations: items.items.map((entry) => ({
|
|
308
|
+
integration_key: entry.integrationKey,
|
|
309
|
+
label: entry.label,
|
|
310
|
+
business_profile_slug: entry.businessProfileSlug,
|
|
311
|
+
mode: entry.mode,
|
|
312
|
+
enabled: entry.enabled,
|
|
313
|
+
webhook_path: entry.webhookPath,
|
|
314
|
+
allow_direct_commands: entry.allowDirectCommands,
|
|
315
|
+
allow_debug_commands: entry.allowDebugCommands,
|
|
316
|
+
channel_account_id: entry.channelAccountId,
|
|
317
|
+
bot_username: entry.botUsername,
|
|
318
|
+
telegram_bot_id: entry.telegramBotId,
|
|
319
|
+
has_bot_token: entry.hasBotToken,
|
|
320
|
+
has_webhook_secret: entry.hasWebhookSecret,
|
|
321
|
+
bot_token_key_id: entry.botTokenKeyId,
|
|
322
|
+
webhook_secret_key_id: entry.webhookSecretKeyId
|
|
323
|
+
}))
|
|
324
|
+
}));
|
|
325
|
+
(0, render_1.renderOutput)({
|
|
326
|
+
authMode: auth.authMode,
|
|
327
|
+
count: items.items.length,
|
|
328
|
+
outputFile,
|
|
329
|
+
items: items.items
|
|
330
|
+
}, outputMode);
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
333
|
+
(0, render_1.renderOutput)({
|
|
334
|
+
authMode: auth.authMode,
|
|
335
|
+
count: items.items.length,
|
|
336
|
+
items: items.items
|
|
337
|
+
}, outputMode);
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
340
|
+
if (action === 'verify') {
|
|
341
|
+
const auth = await (0, auth_1.resolveAuthenticatedClient)({ context });
|
|
342
|
+
const integrationKey = await resolveIntegrationKey(context, args);
|
|
343
|
+
(0, render_1.renderOutput)({
|
|
344
|
+
authMode: auth.authMode,
|
|
345
|
+
...(await auth.client.integrations.verifyTelegramIntegration({ integrationKey }))
|
|
346
|
+
}, outputMode);
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
349
|
+
if (action === 'sync-webhook') {
|
|
350
|
+
const auth = await (0, auth_1.resolveAuthenticatedClient)({ context });
|
|
351
|
+
const integrationKey = await resolveIntegrationKey(context, args);
|
|
352
|
+
(0, render_1.renderOutput)({
|
|
353
|
+
authMode: auth.authMode,
|
|
354
|
+
...(await auth.client.integrations.syncTelegramWebhook({ integrationKey }))
|
|
355
|
+
}, outputMode);
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
358
|
+
if (action === 'sync-commands') {
|
|
359
|
+
const auth = await (0, auth_1.resolveAuthenticatedClient)({ context });
|
|
360
|
+
const integrationKey = await resolveIntegrationKey(context, args);
|
|
361
|
+
(0, render_1.renderOutput)({
|
|
362
|
+
authMode: auth.authMode,
|
|
363
|
+
...(await auth.client.integrations.syncTelegramCommands({ integrationKey }))
|
|
364
|
+
}, outputMode);
|
|
365
|
+
return;
|
|
366
|
+
}
|
|
367
|
+
if (action === 'reconcile') {
|
|
368
|
+
const auth = await (0, auth_1.resolveAuthenticatedClient)({ context });
|
|
369
|
+
const integrationKey = await resolveIntegrationKey(context, args);
|
|
370
|
+
(0, render_1.renderOutput)({
|
|
371
|
+
authMode: auth.authMode,
|
|
372
|
+
...(await auth.client.integrations.reconcileTelegramIntegration({ integrationKey }))
|
|
373
|
+
}, outputMode);
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
376
|
+
if (action === 'migrate-legacy-default') {
|
|
377
|
+
const auth = await (0, auth_1.resolveAuthenticatedClient)({ context });
|
|
378
|
+
const newIntegrationKey = flagValue(args, '--new-integration-key');
|
|
379
|
+
if (!newIntegrationKey) {
|
|
380
|
+
throw new Error('telegram integrations migrate-legacy-default requires --new-integration-key.');
|
|
381
|
+
}
|
|
382
|
+
(0, render_1.renderOutput)({
|
|
383
|
+
authMode: auth.authMode,
|
|
384
|
+
...(await auth.client.integrations.migrateLegacyTelegramDefault({
|
|
385
|
+
oldIntegrationKey: flagValue(args, '--old-integration-key') ?? 'telegram-default',
|
|
386
|
+
newIntegrationKey,
|
|
387
|
+
webhookPath: flagValue(args, '--webhook-path') ?? null
|
|
388
|
+
}))
|
|
389
|
+
}, outputMode);
|
|
390
|
+
return;
|
|
391
|
+
}
|
|
392
|
+
throw new Error(`Unknown telegram integrations command: ${action ?? '(missing)'}.`);
|
|
393
|
+
}
|
|
394
|
+
async function handleTelegramBusinessAccountsCommand(input) {
|
|
395
|
+
const { args, action, context, outputMode } = input;
|
|
396
|
+
if (action === 'status' || action === 'download') {
|
|
397
|
+
const auth = await (0, auth_1.resolveAuthenticatedClient)({ context });
|
|
398
|
+
const items = await auth.client.integrations.listTelegramBusinessAccounts({
|
|
399
|
+
businessProfileSlug: resolveProfileSlug(args, context.manifest.business_slug),
|
|
400
|
+
integrationKey: flagValue(args, '--integration-key')
|
|
401
|
+
});
|
|
402
|
+
if (action === 'download') {
|
|
403
|
+
const outputFile = (0, node_path_1.resolve)(context.root.rootDir, flagValue(args, '--output-file') ?? '.sa-admin/downloads/telegram-business-accounts.yaml');
|
|
404
|
+
await writeYamlSnapshot(outputFile, (0, project_1.buildTelegramBusinessAccountSnapshotYaml)({
|
|
405
|
+
items: items.items.map((entry) => ({
|
|
406
|
+
business_connection_id: entry.businessConnectionId,
|
|
407
|
+
integration_key: entry.integrationKey,
|
|
408
|
+
business_profile_slug: entry.businessProfileSlug,
|
|
409
|
+
telegram_user_id: entry.telegramUserId,
|
|
410
|
+
user_chat_id: entry.userChatId,
|
|
411
|
+
can_reply: entry.canReply,
|
|
412
|
+
is_enabled: entry.isEnabled,
|
|
413
|
+
binding_status: entry.bindingStatus,
|
|
414
|
+
metadata: entry.metadata,
|
|
415
|
+
first_seen_at: entry.firstSeenAt,
|
|
416
|
+
last_seen_at: entry.lastSeenAt
|
|
417
|
+
}))
|
|
418
|
+
}));
|
|
419
|
+
(0, render_1.renderOutput)({
|
|
420
|
+
authMode: auth.authMode,
|
|
421
|
+
count: items.items.length,
|
|
422
|
+
outputFile,
|
|
423
|
+
items: items.items
|
|
424
|
+
}, outputMode);
|
|
425
|
+
return;
|
|
426
|
+
}
|
|
427
|
+
(0, render_1.renderOutput)({
|
|
428
|
+
authMode: auth.authMode,
|
|
429
|
+
count: items.items.length,
|
|
430
|
+
items: items.items
|
|
431
|
+
}, outputMode);
|
|
432
|
+
return;
|
|
433
|
+
}
|
|
434
|
+
const businessConnectionId = flagValue(args, '--business-connection-id');
|
|
435
|
+
if (!businessConnectionId) {
|
|
436
|
+
throw new Error(`telegram business-accounts ${action ?? '(missing)'} requires --business-connection-id.`);
|
|
437
|
+
}
|
|
438
|
+
const auth = await (0, auth_1.resolveAuthenticatedClient)({ context });
|
|
439
|
+
const actorEmail = await resolveVerifiedBy(context);
|
|
440
|
+
if (action === 'approve') {
|
|
441
|
+
(0, render_1.renderOutput)({
|
|
442
|
+
authMode: auth.authMode,
|
|
443
|
+
...(await auth.client.integrations.approveTelegramBusinessAccount({
|
|
444
|
+
businessConnectionId,
|
|
445
|
+
approvedBy: actorEmail,
|
|
446
|
+
note: flagValue(args, '--note')
|
|
447
|
+
}))
|
|
448
|
+
}, outputMode);
|
|
449
|
+
return;
|
|
450
|
+
}
|
|
451
|
+
if (action === 'block') {
|
|
452
|
+
(0, render_1.renderOutput)({
|
|
453
|
+
authMode: auth.authMode,
|
|
454
|
+
...(await auth.client.integrations.blockTelegramBusinessAccount({
|
|
455
|
+
businessConnectionId,
|
|
456
|
+
blockedBy: actorEmail,
|
|
457
|
+
note: flagValue(args, '--note')
|
|
458
|
+
}))
|
|
459
|
+
}, outputMode);
|
|
460
|
+
return;
|
|
461
|
+
}
|
|
462
|
+
if (action === 'refresh') {
|
|
463
|
+
(0, render_1.renderOutput)({
|
|
464
|
+
authMode: auth.authMode,
|
|
465
|
+
...(await auth.client.integrations.refreshTelegramBusinessAccount({
|
|
466
|
+
businessConnectionId
|
|
467
|
+
}))
|
|
468
|
+
}, outputMode);
|
|
469
|
+
return;
|
|
470
|
+
}
|
|
471
|
+
throw new Error(`Unknown telegram business-accounts command: ${action ?? '(missing)'}.`);
|
|
472
|
+
}
|
|
473
|
+
async function handleTelegramEmployeesCommand(input) {
|
|
474
|
+
const { args, action, context, outputMode } = input;
|
|
475
|
+
const auth = await (0, auth_1.resolveAuthenticatedClient)({ context });
|
|
476
|
+
const verifiedBy = await resolveVerifiedBy(context);
|
|
477
|
+
if (action === 'observed') {
|
|
478
|
+
const items = await auth.client.integrations.listTelegramObservedUsers({
|
|
479
|
+
businessProfileSlug: resolveProfileSlug(args, context.manifest.business_slug),
|
|
480
|
+
integrationKey: flagValue(args, '--integration-key'),
|
|
481
|
+
username: normalizeTelegramUsername(flagValue(args, '--username')),
|
|
482
|
+
telegramUserId: flagValue(args, '--telegram-user-id')
|
|
483
|
+
});
|
|
484
|
+
(0, render_1.renderOutput)({
|
|
485
|
+
authMode: auth.authMode,
|
|
486
|
+
count: items.items.length,
|
|
487
|
+
items: items.items
|
|
488
|
+
}, outputMode);
|
|
489
|
+
return;
|
|
490
|
+
}
|
|
491
|
+
if (action === 'bindings') {
|
|
492
|
+
const items = await auth.client.integrations.listTelegramEmployeeBindings({
|
|
493
|
+
operatorEmail: flagValue(args, '--email'),
|
|
494
|
+
telegramUserId: flagValue(args, '--telegram-user-id')
|
|
495
|
+
});
|
|
496
|
+
(0, render_1.renderOutput)({
|
|
497
|
+
authMode: auth.authMode,
|
|
498
|
+
count: items.items.length,
|
|
499
|
+
items: items.items
|
|
500
|
+
}, outputMode);
|
|
501
|
+
return;
|
|
502
|
+
}
|
|
503
|
+
if (action === 'verify') {
|
|
504
|
+
const operatorEmail = flagValue(args, '--email');
|
|
505
|
+
const username = normalizeTelegramUsername(flagValue(args, '--username'));
|
|
506
|
+
if (!operatorEmail || !username) {
|
|
507
|
+
throw new Error('telegram employees verify requires --email and --username.');
|
|
508
|
+
}
|
|
509
|
+
const observed = await auth.client.integrations.listTelegramObservedUsers({
|
|
510
|
+
businessProfileSlug: resolveProfileSlug(args, context.manifest.business_slug),
|
|
511
|
+
integrationKey: flagValue(args, '--integration-key'),
|
|
512
|
+
username
|
|
513
|
+
});
|
|
514
|
+
if (observed.items.length === 0) {
|
|
515
|
+
throw new Error(`No observed Telegram user found for @${username}. Ask the user to write to the bot first or check the username.`);
|
|
516
|
+
}
|
|
517
|
+
if (observed.items.length > 1) {
|
|
518
|
+
throw new Error(`Username @${username} matched multiple observed users. Narrow the lookup with --integration-key or bind by --telegram-user-id.`);
|
|
519
|
+
}
|
|
520
|
+
const match = observed.items[0];
|
|
521
|
+
const result = await auth.client.integrations.bindTelegramEmployee({
|
|
522
|
+
operatorEmail,
|
|
523
|
+
telegramUserId: match.telegramUserId,
|
|
524
|
+
telegramChatId: match.telegramChatId,
|
|
525
|
+
telegramUsernameSnapshot: match.usernameSnapshot,
|
|
526
|
+
verifiedBy
|
|
527
|
+
});
|
|
528
|
+
(0, render_1.renderOutput)({
|
|
529
|
+
authMode: auth.authMode,
|
|
530
|
+
matchedObservation: match,
|
|
531
|
+
...result
|
|
532
|
+
}, outputMode);
|
|
533
|
+
return;
|
|
534
|
+
}
|
|
535
|
+
if (action === 'bind') {
|
|
536
|
+
const operatorEmail = flagValue(args, '--email');
|
|
537
|
+
const telegramUserId = flagValue(args, '--telegram-user-id');
|
|
538
|
+
if (!operatorEmail || !telegramUserId) {
|
|
539
|
+
throw new Error('telegram employees bind requires --email and --telegram-user-id.');
|
|
540
|
+
}
|
|
541
|
+
(0, render_1.renderOutput)({
|
|
542
|
+
authMode: auth.authMode,
|
|
543
|
+
...(await auth.client.integrations.bindTelegramEmployee({
|
|
544
|
+
operatorEmail,
|
|
545
|
+
telegramUserId,
|
|
546
|
+
telegramChatId: flagValue(args, '--telegram-chat-id'),
|
|
547
|
+
telegramUsernameSnapshot: normalizeTelegramUsername(flagValue(args, '--username')),
|
|
548
|
+
verifiedBy
|
|
549
|
+
}))
|
|
550
|
+
}, outputMode);
|
|
551
|
+
return;
|
|
552
|
+
}
|
|
553
|
+
if (action === 'revoke') {
|
|
554
|
+
const telegramUserId = flagValue(args, '--telegram-user-id');
|
|
555
|
+
if (!telegramUserId) {
|
|
556
|
+
throw new Error('telegram employees revoke requires --telegram-user-id.');
|
|
557
|
+
}
|
|
558
|
+
(0, render_1.renderOutput)({
|
|
559
|
+
authMode: auth.authMode,
|
|
560
|
+
...(await auth.client.integrations.revokeTelegramEmployeeBinding({
|
|
561
|
+
telegramUserId,
|
|
562
|
+
verifiedBy
|
|
563
|
+
}))
|
|
564
|
+
}, outputMode);
|
|
565
|
+
return;
|
|
566
|
+
}
|
|
567
|
+
if (action === 'status') {
|
|
568
|
+
const telegramUserId = flagValue(args, '--telegram-user-id');
|
|
569
|
+
if (!telegramUserId) {
|
|
570
|
+
throw new Error('telegram employees status requires --telegram-user-id.');
|
|
571
|
+
}
|
|
572
|
+
(0, render_1.renderOutput)({
|
|
573
|
+
authMode: auth.authMode,
|
|
574
|
+
...(await auth.client.integrations.getTelegramEmployeeBindingStatus({
|
|
575
|
+
telegramUserId
|
|
576
|
+
}))
|
|
577
|
+
}, outputMode);
|
|
578
|
+
return;
|
|
579
|
+
}
|
|
580
|
+
if (action === 'resync') {
|
|
581
|
+
const telegramUserId = flagValue(args, '--telegram-user-id');
|
|
582
|
+
if (!telegramUserId) {
|
|
583
|
+
throw new Error('telegram employees resync requires --telegram-user-id.');
|
|
584
|
+
}
|
|
585
|
+
(0, render_1.renderOutput)({
|
|
586
|
+
authMode: auth.authMode,
|
|
587
|
+
...(await auth.client.integrations.resyncTelegramEmployeeCommands({
|
|
588
|
+
telegramUserId
|
|
589
|
+
}))
|
|
590
|
+
}, outputMode);
|
|
591
|
+
return;
|
|
592
|
+
}
|
|
593
|
+
throw new Error(`Unknown telegram employees command: ${action ?? '(missing)'}.`);
|
|
594
|
+
}
|
|
595
|
+
async function handleRuntimeProvidersCommand(input) {
|
|
596
|
+
const { args, action, context, outputMode } = input;
|
|
597
|
+
const auth = await (0, auth_1.resolveAuthenticatedClient)({ context });
|
|
598
|
+
const scope = resolveRuntimeProviderScope(args);
|
|
599
|
+
const businessProfileSlug = scope === 'global'
|
|
600
|
+
? null
|
|
601
|
+
: resolveScopedBusinessSlug(args, context.manifest.business_slug, {
|
|
602
|
+
allowGlobal: true,
|
|
603
|
+
defaultToManifest: true
|
|
604
|
+
});
|
|
605
|
+
if (action === 'status') {
|
|
606
|
+
const items = await auth.client.runtime.listProviders({
|
|
607
|
+
...(scope ? { scope } : {}),
|
|
608
|
+
businessProfileSlug
|
|
609
|
+
});
|
|
610
|
+
const diagnostics = await auth.client.ops.getDiagnostics({
|
|
611
|
+
businessProfileSlug,
|
|
612
|
+
entityKind: 'runtime_provider',
|
|
613
|
+
entityId: null
|
|
614
|
+
});
|
|
615
|
+
(0, render_1.renderOutput)({
|
|
616
|
+
authMode: auth.authMode,
|
|
617
|
+
providers: items.items,
|
|
618
|
+
snapshots: diagnostics.snapshots
|
|
619
|
+
}, outputMode);
|
|
620
|
+
return;
|
|
621
|
+
}
|
|
622
|
+
if (action === 'refresh') {
|
|
623
|
+
const providerKey = flagValue(args, '--provider-key');
|
|
624
|
+
if (!providerKey) {
|
|
625
|
+
throw new Error('runtime providers refresh requires --provider-key.');
|
|
626
|
+
}
|
|
627
|
+
(0, render_1.renderOutput)({
|
|
628
|
+
authMode: auth.authMode,
|
|
629
|
+
...(await auth.client.ops.refreshRuntimeProvider({
|
|
630
|
+
providerKey,
|
|
631
|
+
businessProfileSlug
|
|
632
|
+
}))
|
|
633
|
+
}, outputMode);
|
|
634
|
+
return;
|
|
635
|
+
}
|
|
636
|
+
if (action === 'reconcile') {
|
|
637
|
+
(0, render_1.renderOutput)({
|
|
638
|
+
authMode: auth.authMode,
|
|
639
|
+
...(await auth.client.runtime.reconcileProviders({
|
|
640
|
+
businessProfileSlug,
|
|
641
|
+
providerKey: flagValue(args, '--provider-key')
|
|
642
|
+
}))
|
|
643
|
+
}, outputMode);
|
|
644
|
+
return;
|
|
645
|
+
}
|
|
646
|
+
throw new Error(`Unknown runtime providers command: ${action ?? '(missing)'}.`);
|
|
647
|
+
}
|
|
648
|
+
async function handleRuntimeRoutingCommand(input) {
|
|
649
|
+
const { args, action, context, outputMode } = input;
|
|
650
|
+
const auth = await (0, auth_1.resolveAuthenticatedClient)({ context });
|
|
651
|
+
const businessProfileSlug = resolveScopedBusinessSlug(args, context.manifest.business_slug, {
|
|
652
|
+
allowGlobal: true,
|
|
653
|
+
defaultToManifest: true
|
|
654
|
+
});
|
|
655
|
+
const stage = flagValue(args, '--stage');
|
|
656
|
+
if (action === 'status') {
|
|
657
|
+
const configured = await auth.client.runtime.listRoutingProfiles({
|
|
658
|
+
businessProfileSlug,
|
|
659
|
+
...(stage ? { stage } : {})
|
|
660
|
+
});
|
|
661
|
+
const diagnostics = await auth.client.ops.getDiagnostics({
|
|
662
|
+
businessProfileSlug,
|
|
663
|
+
entityKind: 'runtime_routing',
|
|
664
|
+
entityId: null
|
|
665
|
+
});
|
|
666
|
+
const stages = stage
|
|
667
|
+
? [stage]
|
|
668
|
+
: ['reply', 'analysis', 'review', 'summary'];
|
|
669
|
+
const effectiveProfiles = [];
|
|
670
|
+
for (const stageKey of stages) {
|
|
671
|
+
try {
|
|
672
|
+
const result = await auth.client.runtime.getEffectiveRoutingProfile({
|
|
673
|
+
businessProfileSlug,
|
|
674
|
+
stage: stageKey
|
|
675
|
+
});
|
|
676
|
+
effectiveProfiles.push(result.profile);
|
|
677
|
+
}
|
|
678
|
+
catch { }
|
|
679
|
+
}
|
|
680
|
+
(0, render_1.renderOutput)({
|
|
681
|
+
authMode: auth.authMode,
|
|
682
|
+
configuredProfiles: configured.items,
|
|
683
|
+
effectiveProfiles,
|
|
684
|
+
snapshots: diagnostics.snapshots
|
|
685
|
+
}, outputMode);
|
|
686
|
+
return;
|
|
687
|
+
}
|
|
688
|
+
if (action === 'reconcile') {
|
|
689
|
+
(0, render_1.renderOutput)({
|
|
690
|
+
authMode: auth.authMode,
|
|
691
|
+
...(await auth.client.runtime.reconcileRoutingVisibility({
|
|
692
|
+
businessProfileSlug,
|
|
693
|
+
stage
|
|
694
|
+
}))
|
|
695
|
+
}, outputMode);
|
|
696
|
+
return;
|
|
697
|
+
}
|
|
698
|
+
throw new Error(`Unknown runtime routing command: ${action ?? '(missing)'}.`);
|
|
699
|
+
}
|
|
700
|
+
async function handleRuntimeUsageCommand(input) {
|
|
701
|
+
const { args, action, context, outputMode } = input;
|
|
702
|
+
if (action !== 'summary') {
|
|
703
|
+
throw new Error(`Unknown runtime usage command: ${action ?? '(missing)'}.`);
|
|
704
|
+
}
|
|
705
|
+
const auth = await (0, auth_1.resolveAuthenticatedClient)({ context });
|
|
706
|
+
const businessProfileSlug = resolveScopedBusinessSlug(args, context.manifest.business_slug, {
|
|
707
|
+
allowGlobal: true,
|
|
708
|
+
defaultToManifest: true
|
|
709
|
+
});
|
|
710
|
+
(0, render_1.renderOutput)({
|
|
711
|
+
authMode: auth.authMode,
|
|
712
|
+
...(await auth.client.runtime.getUsageSummary({
|
|
713
|
+
businessProfileSlug,
|
|
714
|
+
from: flagValue(args, '--from'),
|
|
715
|
+
to: flagValue(args, '--to')
|
|
716
|
+
}))
|
|
717
|
+
}, outputMode);
|
|
718
|
+
}
|
|
719
|
+
async function handleRuntimeFallbacksCommand(input) {
|
|
720
|
+
const { args, action, context, outputMode } = input;
|
|
721
|
+
if (action !== 'list') {
|
|
722
|
+
throw new Error(`Unknown runtime fallbacks command: ${action ?? '(missing)'}.`);
|
|
723
|
+
}
|
|
724
|
+
const auth = await (0, auth_1.resolveAuthenticatedClient)({ context });
|
|
725
|
+
const businessProfileSlug = resolveScopedBusinessSlug(args, context.manifest.business_slug, {
|
|
726
|
+
allowGlobal: true,
|
|
727
|
+
defaultToManifest: true
|
|
728
|
+
});
|
|
729
|
+
(0, render_1.renderOutput)({
|
|
730
|
+
authMode: auth.authMode,
|
|
731
|
+
...(await auth.client.runtime.listFallbackEvents({
|
|
732
|
+
businessProfileSlug,
|
|
733
|
+
stage: flagValue(args, '--stage') ??
|
|
734
|
+
null,
|
|
735
|
+
limit: Number(flagValue(args, '--limit') ?? '50')
|
|
736
|
+
}))
|
|
737
|
+
}, outputMode);
|
|
738
|
+
}
|
|
739
|
+
async function executeBackupCommand(input) {
|
|
740
|
+
const { args, action, context, outputMode } = input;
|
|
741
|
+
const auth = await (0, auth_1.resolveAuthenticatedClient)({ context });
|
|
742
|
+
if (action === 'create') {
|
|
743
|
+
const backupKind = flagValue(args, '--backup-kind') ??
|
|
744
|
+
'manual_emergency';
|
|
745
|
+
const sourceKind = flagValue(args, '--source-kind') ??
|
|
746
|
+
(context.environment === 'beta'
|
|
747
|
+
? 'beta_rollout'
|
|
748
|
+
: context.environment === 'production' || context.environment === 'prod'
|
|
749
|
+
? 'prod_rollout'
|
|
750
|
+
: 'local_drill');
|
|
751
|
+
(0, render_1.renderOutput)({
|
|
752
|
+
authMode: auth.authMode,
|
|
753
|
+
...(await auth.client.ops.createBackupArtifact({
|
|
754
|
+
environment: context.environment,
|
|
755
|
+
backupKind,
|
|
756
|
+
sourceKind,
|
|
757
|
+
notes: flagValue(args, '--notes')
|
|
758
|
+
}))
|
|
759
|
+
}, outputMode);
|
|
760
|
+
return;
|
|
761
|
+
}
|
|
762
|
+
if (action === 'list') {
|
|
763
|
+
(0, render_1.renderOutput)({
|
|
764
|
+
authMode: auth.authMode,
|
|
765
|
+
...(await auth.client.ops.listBackupArtifacts({
|
|
766
|
+
environment: context.environment,
|
|
767
|
+
backupKind: flagValue(args, '--backup-kind') ?? null
|
|
768
|
+
}))
|
|
769
|
+
}, outputMode);
|
|
770
|
+
return;
|
|
771
|
+
}
|
|
772
|
+
if (action === 'inspect') {
|
|
773
|
+
const backupId = flagValue(args, '--backup-id');
|
|
774
|
+
if (!backupId) {
|
|
775
|
+
throw new Error('backup inspect requires --backup-id.');
|
|
776
|
+
}
|
|
777
|
+
(0, render_1.renderOutput)({
|
|
778
|
+
authMode: auth.authMode,
|
|
779
|
+
...(await auth.client.ops.getBackupArtifact({
|
|
780
|
+
backupId
|
|
781
|
+
}))
|
|
782
|
+
}, outputMode);
|
|
783
|
+
return;
|
|
784
|
+
}
|
|
785
|
+
throw new Error(`Unknown backup command: ${action ?? '(missing)'}.`);
|
|
786
|
+
}
|
|
787
|
+
async function executeRestoreCommand(input) {
|
|
788
|
+
const { args, action, context, outputMode } = input;
|
|
789
|
+
const auth = await (0, auth_1.resolveAuthenticatedClient)({ context });
|
|
790
|
+
if (action === 'run') {
|
|
791
|
+
const backupId = flagValue(args, '--backup-id');
|
|
792
|
+
if (!backupId) {
|
|
793
|
+
throw new Error('restore run requires --backup-id.');
|
|
794
|
+
}
|
|
795
|
+
(0, render_1.renderOutput)({
|
|
796
|
+
authMode: auth.authMode,
|
|
797
|
+
...(await auth.client.ops.runRestoreDrill({
|
|
798
|
+
backupId,
|
|
799
|
+
targetKind: 'isolated_in_memory',
|
|
800
|
+
targetEnvironment: context.environment,
|
|
801
|
+
startedBy: auth.accessContext?.operator?.email ?? null,
|
|
802
|
+
notes: flagValue(args, '--notes')
|
|
803
|
+
}))
|
|
804
|
+
}, outputMode);
|
|
805
|
+
return;
|
|
806
|
+
}
|
|
807
|
+
if (action === 'list') {
|
|
808
|
+
(0, render_1.renderOutput)({
|
|
809
|
+
authMode: auth.authMode,
|
|
810
|
+
...(await auth.client.ops.listRestoreDrills({
|
|
811
|
+
backupId: flagValue(args, '--backup-id')
|
|
812
|
+
}))
|
|
813
|
+
}, outputMode);
|
|
814
|
+
return;
|
|
815
|
+
}
|
|
816
|
+
if (action === 'inspect') {
|
|
817
|
+
const restoreDrillId = flagValue(args, '--restore-drill-id');
|
|
818
|
+
if (!restoreDrillId) {
|
|
819
|
+
throw new Error('restore inspect requires --restore-drill-id.');
|
|
820
|
+
}
|
|
821
|
+
(0, render_1.renderOutput)({
|
|
822
|
+
authMode: auth.authMode,
|
|
823
|
+
...(await auth.client.ops.getRestoreDrill({
|
|
824
|
+
restoreDrillId
|
|
825
|
+
}))
|
|
826
|
+
}, outputMode);
|
|
827
|
+
return;
|
|
828
|
+
}
|
|
829
|
+
throw new Error(`Unknown restore command: ${action ?? '(missing)'}.`);
|
|
830
|
+
}
|
|
831
|
+
async function handleBackupCommand(input) {
|
|
832
|
+
await executeBackupCommand({
|
|
833
|
+
args: input.args,
|
|
834
|
+
action: input.subcommand,
|
|
835
|
+
context: input.context,
|
|
836
|
+
outputMode: input.outputMode
|
|
837
|
+
});
|
|
838
|
+
}
|
|
839
|
+
async function handleRestoreCommand(input) {
|
|
840
|
+
await executeRestoreCommand({
|
|
841
|
+
args: input.args,
|
|
842
|
+
action: input.subcommand,
|
|
843
|
+
context: input.context,
|
|
844
|
+
outputMode: input.outputMode
|
|
845
|
+
});
|
|
846
|
+
}
|
|
847
|
+
async function handleRolloutCommand(input) {
|
|
848
|
+
const { args, subcommand, context, outputMode } = input;
|
|
849
|
+
if (subcommand === 'preflight') {
|
|
850
|
+
(0, render_1.renderOutput)(await (0, rollout_1.inspectRolloutPreflight)({ context }), outputMode);
|
|
851
|
+
return;
|
|
852
|
+
}
|
|
853
|
+
if (subcommand === 'migrate') {
|
|
854
|
+
(0, render_1.renderOutput)(await (0, rollout_1.runRolloutMigrate)({ context }), outputMode);
|
|
855
|
+
return;
|
|
856
|
+
}
|
|
857
|
+
if (subcommand === 'promote-profile') {
|
|
858
|
+
(0, render_1.renderOutput)(await (0, rollout_1.runRolloutPromoteProfile)({ context }), outputMode);
|
|
859
|
+
return;
|
|
860
|
+
}
|
|
861
|
+
if (subcommand === 'finalize-telegram') {
|
|
862
|
+
(0, render_1.renderOutput)(await (0, rollout_1.runRolloutFinalizeTelegram)({ context }), outputMode);
|
|
863
|
+
return;
|
|
864
|
+
}
|
|
865
|
+
if (subcommand === 'promote') {
|
|
866
|
+
(0, render_1.renderOutput)(await (0, rollout_1.runRolloutPromote)({
|
|
867
|
+
context,
|
|
868
|
+
notes: flagValue(args, '--notes')
|
|
869
|
+
}), outputMode);
|
|
870
|
+
return;
|
|
871
|
+
}
|
|
872
|
+
if (subcommand === 'verify') {
|
|
873
|
+
(0, render_1.renderOutput)(await (0, rollout_1.runRolloutVerify)({
|
|
874
|
+
context,
|
|
875
|
+
rolloutId: flagValue(args, '--rollout-id')
|
|
876
|
+
}), outputMode);
|
|
877
|
+
return;
|
|
878
|
+
}
|
|
879
|
+
if (subcommand === 'verdict') {
|
|
880
|
+
(0, render_1.renderOutput)(await (0, rollout_1.inspectReleaseVerdict)({
|
|
881
|
+
context,
|
|
882
|
+
verificationId: flagValue(args, '--verification-id'),
|
|
883
|
+
rolloutId: flagValue(args, '--rollout-id')
|
|
884
|
+
}), outputMode);
|
|
885
|
+
return;
|
|
886
|
+
}
|
|
887
|
+
if (subcommand === 'evidence') {
|
|
888
|
+
(0, render_1.renderOutput)(await (0, rollout_1.inspectReleaseEvidence)({
|
|
889
|
+
context,
|
|
890
|
+
verificationId: flagValue(args, '--verification-id'),
|
|
891
|
+
rolloutId: flagValue(args, '--rollout-id')
|
|
892
|
+
}), outputMode);
|
|
893
|
+
return;
|
|
894
|
+
}
|
|
895
|
+
if (subcommand === 'list') {
|
|
896
|
+
(0, render_1.renderOutput)(await (0, rollout_1.listRecordedRollouts)({
|
|
897
|
+
context,
|
|
898
|
+
environment: flagValue(args, '--environment') ?? context.environment,
|
|
899
|
+
businessProfileSlug: resolveScopedBusinessSlug(args, context.manifest.business_slug, {
|
|
900
|
+
allowGlobal: true,
|
|
901
|
+
defaultToManifest: true
|
|
902
|
+
})
|
|
903
|
+
}), outputMode);
|
|
904
|
+
return;
|
|
905
|
+
}
|
|
906
|
+
if (subcommand === 'inspect') {
|
|
907
|
+
const rolloutId = flagValue(args, '--rollout-id');
|
|
908
|
+
if (!rolloutId) {
|
|
909
|
+
throw new Error('rollout inspect requires --rollout-id.');
|
|
910
|
+
}
|
|
911
|
+
(0, render_1.renderOutput)(await (0, rollout_1.inspectRecordedRollout)({
|
|
912
|
+
context,
|
|
913
|
+
rolloutId
|
|
914
|
+
}), outputMode);
|
|
915
|
+
return;
|
|
916
|
+
}
|
|
917
|
+
throw new Error(`Unknown rollout command: ${subcommand ?? '(missing)'}.`);
|
|
918
|
+
}
|
|
919
|
+
async function handleDbCommand(input) {
|
|
920
|
+
const { args, subcommand, action, context, outputMode } = input;
|
|
921
|
+
const auth = await (0, auth_1.resolveAuthenticatedClient)({ context });
|
|
922
|
+
if (subcommand === 'migrations') {
|
|
923
|
+
if (action === 'status') {
|
|
924
|
+
(0, render_1.renderOutput)({
|
|
925
|
+
authMode: auth.authMode,
|
|
926
|
+
...(await auth.client.ops.getSchemaStatus({}))
|
|
927
|
+
}, outputMode);
|
|
928
|
+
return;
|
|
929
|
+
}
|
|
930
|
+
if (action === 'apply') {
|
|
931
|
+
(0, render_1.renderOutput)({
|
|
932
|
+
authMode: auth.authMode,
|
|
933
|
+
...(await auth.client.ops.applySchemaMigrations({
|
|
934
|
+
appliedBy: auth.accessContext?.operator?.email ?? null,
|
|
935
|
+
sourceKind: context.environment === 'beta'
|
|
936
|
+
? 'beta_rollout'
|
|
937
|
+
: context.environment === 'production' || context.environment === 'prod'
|
|
938
|
+
? 'prod_rollout'
|
|
939
|
+
: 'local_bootstrap'
|
|
940
|
+
}))
|
|
941
|
+
}, outputMode);
|
|
942
|
+
return;
|
|
943
|
+
}
|
|
944
|
+
throw new Error(`Unknown db migrations command: ${action ?? '(missing)'}.`);
|
|
945
|
+
}
|
|
946
|
+
if (subcommand === 'backups') {
|
|
947
|
+
await executeBackupCommand({ args, action, context, outputMode });
|
|
948
|
+
return;
|
|
949
|
+
}
|
|
950
|
+
if (subcommand === 'restore-drills') {
|
|
951
|
+
await executeRestoreCommand({ args, action, context, outputMode });
|
|
952
|
+
return;
|
|
953
|
+
}
|
|
954
|
+
throw new Error(`Unknown db command: ${subcommand ?? '(missing)'}.`);
|
|
955
|
+
}
|
|
956
|
+
async function handleDiagnosticsCommand(input) {
|
|
957
|
+
const { args, subcommand, context, outputMode } = input;
|
|
958
|
+
const auth = await (0, auth_1.resolveAuthenticatedClient)({ context });
|
|
959
|
+
const businessProfileSlug = resolveScopedBusinessSlug(args, context.manifest.business_slug, {
|
|
960
|
+
allowGlobal: true,
|
|
961
|
+
defaultToManifest: true
|
|
962
|
+
});
|
|
963
|
+
if (subcommand === 'readiness') {
|
|
964
|
+
(0, render_1.renderOutput)({
|
|
965
|
+
authMode: auth.authMode,
|
|
966
|
+
...(await auth.client.ops.getReadiness({
|
|
967
|
+
businessProfileSlug
|
|
968
|
+
}))
|
|
969
|
+
}, outputMode);
|
|
970
|
+
return;
|
|
971
|
+
}
|
|
972
|
+
if (subcommand === 'snapshots') {
|
|
973
|
+
(0, render_1.renderOutput)({
|
|
974
|
+
authMode: auth.authMode,
|
|
975
|
+
...(await auth.client.ops.getDiagnostics({
|
|
976
|
+
businessProfileSlug,
|
|
977
|
+
entityKind: flagValue(args, '--entity-kind') ?? null,
|
|
978
|
+
entityId: flagValue(args, '--entity-id')
|
|
979
|
+
}))
|
|
980
|
+
}, outputMode);
|
|
981
|
+
return;
|
|
982
|
+
}
|
|
983
|
+
throw new Error(`Unknown diagnostics command: ${subcommand ?? '(missing)'}.`);
|
|
984
|
+
}
|
|
985
|
+
async function handleReconcileCommand(input) {
|
|
986
|
+
const { args, subcommand, context, outputMode } = input;
|
|
987
|
+
const auth = await (0, auth_1.resolveAuthenticatedClient)({ context });
|
|
988
|
+
if (subcommand === 'business') {
|
|
989
|
+
(0, render_1.renderOutput)({
|
|
990
|
+
authMode: auth.authMode,
|
|
991
|
+
...(await auth.client.ops.reconcileBusiness({
|
|
992
|
+
businessProfileSlug: resolveProfileSlug(args, context.manifest.business_slug)
|
|
993
|
+
}))
|
|
994
|
+
}, outputMode);
|
|
995
|
+
return;
|
|
996
|
+
}
|
|
997
|
+
if (subcommand === 'integration') {
|
|
998
|
+
const integrationKey = await resolveIntegrationKey(context, args);
|
|
999
|
+
(0, render_1.renderOutput)({
|
|
1000
|
+
authMode: auth.authMode,
|
|
1001
|
+
...(await auth.client.integrations.reconcileTelegramIntegration({ integrationKey }))
|
|
1002
|
+
}, outputMode);
|
|
1003
|
+
return;
|
|
1004
|
+
}
|
|
1005
|
+
if (subcommand === 'provider') {
|
|
1006
|
+
const businessProfileSlug = resolveScopedBusinessSlug(args, context.manifest.business_slug, {
|
|
1007
|
+
allowGlobal: true,
|
|
1008
|
+
defaultToManifest: true
|
|
1009
|
+
});
|
|
1010
|
+
(0, render_1.renderOutput)({
|
|
1011
|
+
authMode: auth.authMode,
|
|
1012
|
+
...(await auth.client.runtime.reconcileProviders({
|
|
1013
|
+
businessProfileSlug,
|
|
1014
|
+
providerKey: flagValue(args, '--provider-key')
|
|
1015
|
+
}))
|
|
1016
|
+
}, outputMode);
|
|
1017
|
+
return;
|
|
1018
|
+
}
|
|
1019
|
+
if (subcommand === 'routing') {
|
|
1020
|
+
const businessProfileSlug = resolveScopedBusinessSlug(args, context.manifest.business_slug, {
|
|
1021
|
+
allowGlobal: true,
|
|
1022
|
+
defaultToManifest: true
|
|
1023
|
+
});
|
|
1024
|
+
(0, render_1.renderOutput)({
|
|
1025
|
+
authMode: auth.authMode,
|
|
1026
|
+
...(await auth.client.runtime.reconcileRoutingVisibility({
|
|
1027
|
+
businessProfileSlug,
|
|
1028
|
+
stage: flagValue(args, '--stage') ??
|
|
1029
|
+
null
|
|
1030
|
+
}))
|
|
1031
|
+
}, outputMode);
|
|
1032
|
+
return;
|
|
1033
|
+
}
|
|
1034
|
+
if (subcommand === 'employee') {
|
|
1035
|
+
const telegramUserId = flagValue(args, '--telegram-user-id');
|
|
1036
|
+
if (!telegramUserId) {
|
|
1037
|
+
throw new Error('reconcile employee requires --telegram-user-id.');
|
|
1038
|
+
}
|
|
1039
|
+
(0, render_1.renderOutput)({
|
|
1040
|
+
authMode: auth.authMode,
|
|
1041
|
+
...(await auth.client.integrations.resyncTelegramEmployeeCommands({
|
|
1042
|
+
telegramUserId
|
|
1043
|
+
}))
|
|
1044
|
+
}, outputMode);
|
|
1045
|
+
return;
|
|
1046
|
+
}
|
|
1047
|
+
throw new Error(`Unknown reconcile command: ${subcommand ?? '(missing)'}.`);
|
|
1048
|
+
}
|
|
1049
|
+
async function handleAuthCommand(input) {
|
|
1050
|
+
const { args, subcommand, context, outputMode } = input;
|
|
1051
|
+
if (subcommand === 'login') {
|
|
1052
|
+
const email = flagValue(args, '--email');
|
|
1053
|
+
if (!email) {
|
|
1054
|
+
throw new Error('auth login requires --email.');
|
|
1055
|
+
}
|
|
1056
|
+
const result = await (0, auth_1.loginAdminSession)({
|
|
1057
|
+
context,
|
|
1058
|
+
email,
|
|
1059
|
+
nextPath: flagValue(args, '--next-path'),
|
|
1060
|
+
timeoutSeconds: Number(flagValue(args, '--timeout-seconds') ?? '180'),
|
|
1061
|
+
openBrowser: !hasFlag(args, '--no-browser')
|
|
1062
|
+
});
|
|
1063
|
+
(0, render_1.renderOutput)({
|
|
1064
|
+
authMode: 'employee_login',
|
|
1065
|
+
state: result.state,
|
|
1066
|
+
accessContext: result.accessContext,
|
|
1067
|
+
intent: result.intent,
|
|
1068
|
+
userCode: result.userCode,
|
|
1069
|
+
verificationUri: result.verificationUri,
|
|
1070
|
+
verificationUriComplete: result.verificationUriComplete,
|
|
1071
|
+
browserOpened: result.browserOpened,
|
|
1072
|
+
pollCount: result.pollCount
|
|
1073
|
+
}, outputMode);
|
|
1074
|
+
return;
|
|
1075
|
+
}
|
|
1076
|
+
if (subcommand === 'logout') {
|
|
1077
|
+
(0, render_1.renderOutput)(await (0, auth_1.logoutAdminSession)(context), outputMode);
|
|
1078
|
+
return;
|
|
1079
|
+
}
|
|
1080
|
+
if (subcommand === 'session') {
|
|
1081
|
+
(0, render_1.renderOutput)(await (0, auth_1.inspectSessionState)(context), outputMode);
|
|
1082
|
+
return;
|
|
1083
|
+
}
|
|
1084
|
+
if (subcommand === 'preflight') {
|
|
1085
|
+
(0, render_1.renderOutput)(await (0, provisioning_1.inspectAuthPreflight)(context), outputMode);
|
|
1086
|
+
return;
|
|
1087
|
+
}
|
|
1088
|
+
if (subcommand === 'seed-policy') {
|
|
1089
|
+
const preflight = await (0, provisioning_1.inspectAuthPreflight)(context);
|
|
1090
|
+
(0, render_1.renderOutput)({
|
|
1091
|
+
environment: context.environment,
|
|
1092
|
+
provisioningPolicy: preflight.provisioningPolicy
|
|
1093
|
+
}, outputMode);
|
|
1094
|
+
return;
|
|
1095
|
+
}
|
|
1096
|
+
if (subcommand === 'whoami') {
|
|
1097
|
+
(0, render_1.renderOutput)(await (0, auth_1.resolveWhoAmI)(context), outputMode);
|
|
1098
|
+
return;
|
|
1099
|
+
}
|
|
1100
|
+
throw new Error(`Unknown auth command: ${subcommand ?? '(missing)'}.`);
|
|
1101
|
+
}
|
|
1102
|
+
async function main() {
|
|
1103
|
+
const args = process.argv.slice(2);
|
|
1104
|
+
const rawCommandTokens = extractCommandTokens(args);
|
|
1105
|
+
const normalizedCommandTokens = normalizeCommandTokens(rawCommandTokens[0] === 'help' ? rawCommandTokens.slice(1) : rawCommandTokens);
|
|
1106
|
+
if (rawCommandTokens.length === 0 ||
|
|
1107
|
+
rawCommandTokens[0] === 'help' ||
|
|
1108
|
+
hasFlag(args, '--help')) {
|
|
1109
|
+
process.stdout.write((0, help_1.renderHelpPage)(normalizedCommandTokens));
|
|
1110
|
+
return;
|
|
1111
|
+
}
|
|
1112
|
+
const outputMode = hasFlag(args, '--json') ? 'json' : 'pretty';
|
|
1113
|
+
const explicitCwd = flagValue(args, '--cwd');
|
|
1114
|
+
const context = await (0, context_1.resolveSaAdminContext)({
|
|
1115
|
+
...(explicitCwd ? { cwd: explicitCwd } : {}),
|
|
1116
|
+
baseUrl: flagValue(args, '--base-url'),
|
|
1117
|
+
environment: flagValue(args, '--environment'),
|
|
1118
|
+
envFiles: flagValues(args, '--env-file')
|
|
1119
|
+
});
|
|
1120
|
+
const command = normalizedCommandTokens[0] ?? null;
|
|
1121
|
+
const subcommand = normalizedCommandTokens[1] ?? null;
|
|
1122
|
+
const action = normalizedCommandTokens[2] ?? null;
|
|
1123
|
+
if (command === 'profile') {
|
|
1124
|
+
await handleProfileCommand({ args, subcommand, context, outputMode });
|
|
1125
|
+
return;
|
|
1126
|
+
}
|
|
1127
|
+
if (command === 'db') {
|
|
1128
|
+
await handleDbCommand({ args, subcommand, action, context, outputMode });
|
|
1129
|
+
return;
|
|
1130
|
+
}
|
|
1131
|
+
if (command === 'backup') {
|
|
1132
|
+
await handleBackupCommand({ args, subcommand, context, outputMode });
|
|
1133
|
+
return;
|
|
1134
|
+
}
|
|
1135
|
+
if (command === 'restore') {
|
|
1136
|
+
await handleRestoreCommand({ args, subcommand, context, outputMode });
|
|
1137
|
+
return;
|
|
1138
|
+
}
|
|
1139
|
+
if (command === 'telegram') {
|
|
1140
|
+
if (subcommand === 'integrations') {
|
|
1141
|
+
await handleTelegramIntegrationsCommand({ args, action, context, outputMode });
|
|
1142
|
+
return;
|
|
1143
|
+
}
|
|
1144
|
+
if (subcommand === 'business-accounts') {
|
|
1145
|
+
await handleTelegramBusinessAccountsCommand({ args, action, context, outputMode });
|
|
1146
|
+
return;
|
|
1147
|
+
}
|
|
1148
|
+
if (subcommand === 'employees') {
|
|
1149
|
+
await handleTelegramEmployeesCommand({ args, action, context, outputMode });
|
|
1150
|
+
return;
|
|
1151
|
+
}
|
|
1152
|
+
}
|
|
1153
|
+
if (command === 'runtime') {
|
|
1154
|
+
if (subcommand === 'providers') {
|
|
1155
|
+
await handleRuntimeProvidersCommand({ args, action, context, outputMode });
|
|
1156
|
+
return;
|
|
1157
|
+
}
|
|
1158
|
+
if (subcommand === 'routing') {
|
|
1159
|
+
await handleRuntimeRoutingCommand({ args, action, context, outputMode });
|
|
1160
|
+
return;
|
|
1161
|
+
}
|
|
1162
|
+
if (subcommand === 'usage') {
|
|
1163
|
+
await handleRuntimeUsageCommand({ args, action, context, outputMode });
|
|
1164
|
+
return;
|
|
1165
|
+
}
|
|
1166
|
+
if (subcommand === 'fallbacks') {
|
|
1167
|
+
await handleRuntimeFallbacksCommand({ args, action, context, outputMode });
|
|
1168
|
+
return;
|
|
1169
|
+
}
|
|
1170
|
+
}
|
|
1171
|
+
if (command === 'diagnostics') {
|
|
1172
|
+
await handleDiagnosticsCommand({ args, subcommand, context, outputMode });
|
|
1173
|
+
return;
|
|
1174
|
+
}
|
|
1175
|
+
if (command === 'reconcile') {
|
|
1176
|
+
await handleReconcileCommand({ args, subcommand, context, outputMode });
|
|
1177
|
+
return;
|
|
1178
|
+
}
|
|
1179
|
+
if (command === 'rollout') {
|
|
1180
|
+
await handleRolloutCommand({ args, subcommand, context, outputMode });
|
|
1181
|
+
return;
|
|
1182
|
+
}
|
|
1183
|
+
if (command === 'auth') {
|
|
1184
|
+
await handleAuthCommand({ args, subcommand, context, outputMode });
|
|
1185
|
+
return;
|
|
1186
|
+
}
|
|
1187
|
+
process.stdout.write((0, help_1.renderHelpPage)([]));
|
|
1188
|
+
process.exitCode = 1;
|
|
1189
|
+
}
|
|
1190
|
+
main().catch((error) => {
|
|
1191
|
+
if (error instanceof client_sdk_1.PlatformClientError) {
|
|
1192
|
+
process.stderr.write(`${error.code}${error.status ? ` [${error.status}]` : ''}: ${error.message}\n`);
|
|
1193
|
+
}
|
|
1194
|
+
else {
|
|
1195
|
+
process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`);
|
|
1196
|
+
}
|
|
1197
|
+
process.exitCode = 1;
|
|
1198
|
+
});
|
|
1199
|
+
//# sourceMappingURL=cli.js.map
|