@gravity-rail/cli 0.6.0 → 0.7.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/README.md +28 -0
- package/dist/account-verify-phone-4LRJZT5I.js +36 -0
- package/dist/account-verify-phone-4LRJZT5I.js.map +1 -0
- package/dist/chunk-3EO4COHB.js +14202 -0
- package/dist/chunk-3EO4COHB.js.map +1 -0
- package/dist/chunk-QVG4L6BE.js +2199 -0
- package/dist/chunk-QVG4L6BE.js.map +1 -0
- package/dist/concierge-ZOG7YFWQ.js +6 -0
- package/dist/concierge-ZOG7YFWQ.js.map +1 -0
- package/dist/gr.js +7181 -22883
- package/dist/gr.js.map +1 -1
- package/dist/lib.d.ts +43 -1
- package/dist/lib.js +597 -9
- package/dist/lib.js.map +1 -1
- package/package.json +2 -2
package/dist/lib.js
CHANGED
|
@@ -305,6 +305,25 @@ var AdminApi = class extends BaseApiClient {
|
|
|
305
305
|
method: "POST"
|
|
306
306
|
});
|
|
307
307
|
}
|
|
308
|
+
// Proactive Support: outbound (us→customer) requests + resources
|
|
309
|
+
async createOutboundSupportRequestAsAdmin(data) {
|
|
310
|
+
return this.fetch("admin/support-requests/outbound", {
|
|
311
|
+
method: "POST",
|
|
312
|
+
body: JSON.stringify(data)
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
async attachSupportRequestResourceAsAdmin(uuid, data) {
|
|
316
|
+
return this.fetch(`admin/support-requests/${uuid}/resources`, {
|
|
317
|
+
method: "POST",
|
|
318
|
+
body: JSON.stringify(data)
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
async revokeSupportRequestResourceAsAdmin(uuid, resourceUuid) {
|
|
322
|
+
return this.fetch(
|
|
323
|
+
`admin/support-requests/${uuid}/resources/${resourceUuid}/revoke`,
|
|
324
|
+
{ method: "POST" }
|
|
325
|
+
);
|
|
326
|
+
}
|
|
308
327
|
// Admin Accounts API
|
|
309
328
|
async getAccounts(options) {
|
|
310
329
|
const params = new URLSearchParams();
|
|
@@ -318,6 +337,8 @@ var AdminApi = class extends BaseApiClient {
|
|
|
318
337
|
if (options.isActive !== void 0) params.append("isActive", options.isActive.toString());
|
|
319
338
|
if (options.organizationId !== void 0)
|
|
320
339
|
params.append("organizationId", options.organizationId.toString());
|
|
340
|
+
if (options.workspaceId !== void 0)
|
|
341
|
+
params.append("workspaceId", options.workspaceId.toString());
|
|
321
342
|
if (options.pendingDeletion !== void 0)
|
|
322
343
|
params.append("pendingDeletion", options.pendingDeletion.toString());
|
|
323
344
|
return this.fetch(`admin/accounts?${params.toString()}`);
|
|
@@ -1454,6 +1475,9 @@ function bindAdminMethods(target, admin) {
|
|
|
1454
1475
|
target.updateSupportRequestStatusAsAdmin = admin.updateSupportRequestStatusAsAdmin.bind(admin);
|
|
1455
1476
|
target.updateSupportRequestAttributesAsAdmin = admin.updateSupportRequestAttributesAsAdmin.bind(admin);
|
|
1456
1477
|
target.createSupportRequestLinearIssueAsAdmin = admin.createSupportRequestLinearIssueAsAdmin.bind(admin);
|
|
1478
|
+
target.createOutboundSupportRequestAsAdmin = admin.createOutboundSupportRequestAsAdmin.bind(admin);
|
|
1479
|
+
target.attachSupportRequestResourceAsAdmin = admin.attachSupportRequestResourceAsAdmin.bind(admin);
|
|
1480
|
+
target.revokeSupportRequestResourceAsAdmin = admin.revokeSupportRequestResourceAsAdmin.bind(admin);
|
|
1457
1481
|
target.getAccounts = admin.getAccounts.bind(admin);
|
|
1458
1482
|
target.getAccountDetails = admin.getAccountDetails.bind(admin);
|
|
1459
1483
|
target.getAccountByUuid = admin.getAccountByUuid.bind(admin);
|
|
@@ -1626,6 +1650,9 @@ var ApiClient = class extends GravityRailClient {
|
|
|
1626
1650
|
updateSupportRequestStatusAsAdmin;
|
|
1627
1651
|
updateSupportRequestAttributesAsAdmin;
|
|
1628
1652
|
createSupportRequestLinearIssueAsAdmin;
|
|
1653
|
+
createOutboundSupportRequestAsAdmin;
|
|
1654
|
+
attachSupportRequestResourceAsAdmin;
|
|
1655
|
+
revokeSupportRequestResourceAsAdmin;
|
|
1629
1656
|
getAccounts;
|
|
1630
1657
|
getAccountDetails;
|
|
1631
1658
|
getAccountByUuid;
|
|
@@ -2120,7 +2147,9 @@ async function tryTokenRefresh(ctx, creds) {
|
|
|
2120
2147
|
return { ...ctx, accessToken: refreshed.accessToken, apiClient };
|
|
2121
2148
|
}
|
|
2122
2149
|
function createContext(opts) {
|
|
2123
|
-
const
|
|
2150
|
+
const baseConfig = getEnvironmentConfig(opts.env);
|
|
2151
|
+
const apiUrl = opts.apiUrl || process.env.GRAVITY_RAIL_API_URL || baseConfig.apiUrl;
|
|
2152
|
+
const envConfig = apiUrl === baseConfig.apiUrl ? baseConfig : { ...baseConfig, apiUrl };
|
|
2124
2153
|
const credentialsManager = new CredentialsManager(homedir(), envConfig.apiUrl);
|
|
2125
2154
|
return {
|
|
2126
2155
|
env: opts.env,
|
|
@@ -2206,6 +2235,40 @@ async function createPublicAuthenticatedContext(opts) {
|
|
|
2206
2235
|
|
|
2207
2236
|
// src/lib/input.ts
|
|
2208
2237
|
import { readFileSync as readFileSync2 } from "fs";
|
|
2238
|
+
var JSON_BODY_ACTIONS = /* @__PURE__ */ new Set([
|
|
2239
|
+
"create",
|
|
2240
|
+
"update",
|
|
2241
|
+
"import",
|
|
2242
|
+
"enroll",
|
|
2243
|
+
"unenroll",
|
|
2244
|
+
"reenroll",
|
|
2245
|
+
"advance",
|
|
2246
|
+
"skip",
|
|
2247
|
+
"send",
|
|
2248
|
+
"review",
|
|
2249
|
+
"submit-answer",
|
|
2250
|
+
"start-scenario",
|
|
2251
|
+
"update-status"
|
|
2252
|
+
]);
|
|
2253
|
+
function commandNeedsJsonBody(cmd, parsedArgs) {
|
|
2254
|
+
if (parsedArgs.data !== void 0 || parsedArgs.file !== void 0) {
|
|
2255
|
+
return true;
|
|
2256
|
+
}
|
|
2257
|
+
if (cmd.args?.some((a) => a.name === "data" || a.name === "file")) {
|
|
2258
|
+
return true;
|
|
2259
|
+
}
|
|
2260
|
+
if (!cmd.mutates) {
|
|
2261
|
+
return false;
|
|
2262
|
+
}
|
|
2263
|
+
const action = cmd.path[cmd.path.length - 1] ?? "";
|
|
2264
|
+
if (JSON_BODY_ACTIONS.has(action)) {
|
|
2265
|
+
return true;
|
|
2266
|
+
}
|
|
2267
|
+
if (action === "send" || action === "cancel" && cmd.path.length > 1) {
|
|
2268
|
+
return true;
|
|
2269
|
+
}
|
|
2270
|
+
return false;
|
|
2271
|
+
}
|
|
2209
2272
|
async function readJsonInput(args) {
|
|
2210
2273
|
const dataStr = args.data;
|
|
2211
2274
|
const filePath = args.file;
|
|
@@ -2272,6 +2335,99 @@ function readStdinIfPiped() {
|
|
|
2272
2335
|
});
|
|
2273
2336
|
}
|
|
2274
2337
|
|
|
2338
|
+
// src/lib/phone-voice.ts
|
|
2339
|
+
var FAILED_TERMINATION_REASONS = /* @__PURE__ */ new Set([
|
|
2340
|
+
"failed",
|
|
2341
|
+
"busy",
|
|
2342
|
+
"no-answer",
|
|
2343
|
+
"canceled",
|
|
2344
|
+
"timeout",
|
|
2345
|
+
"error"
|
|
2346
|
+
]);
|
|
2347
|
+
var SEED_PHONE_PATTERN = /^\+1212555010\d$/;
|
|
2348
|
+
function sleep(ms) {
|
|
2349
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
2350
|
+
}
|
|
2351
|
+
function latestOutboundCall(calls) {
|
|
2352
|
+
return calls.filter((c) => !c.inbound).sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime())[0];
|
|
2353
|
+
}
|
|
2354
|
+
function isTerminalFailure(call) {
|
|
2355
|
+
if (call.status === "ERROR") {
|
|
2356
|
+
return true;
|
|
2357
|
+
}
|
|
2358
|
+
const reason = call.terminationReason ?? "";
|
|
2359
|
+
return FAILED_TERMINATION_REASONS.has(reason);
|
|
2360
|
+
}
|
|
2361
|
+
function formatOutboundCallFailure(call, memberId) {
|
|
2362
|
+
const reason = call.terminationReason ?? call.status;
|
|
2363
|
+
const lines = [`Outbound call failed (phoneCallId=${call.id}, terminationReason=${reason}).`];
|
|
2364
|
+
if (reason === "failed") {
|
|
2365
|
+
lines.push(
|
|
2366
|
+
"Twilio rejected the dial \u2014 common causes: invalid/unverified callee number, trial account restrictions, or unreachable DEV_TUNNEL_URL for the answer URL."
|
|
2367
|
+
);
|
|
2368
|
+
}
|
|
2369
|
+
lines.push(
|
|
2370
|
+
`Update the callee phone: gr members update --id ${memberId} --data '{"phone":"+1YOUR_MOBILE"}' --allow-write`
|
|
2371
|
+
);
|
|
2372
|
+
return lines.join("\n");
|
|
2373
|
+
}
|
|
2374
|
+
function isLikelySeedPhoneNumber(phone) {
|
|
2375
|
+
return SEED_PHONE_PATTERN.test(phone);
|
|
2376
|
+
}
|
|
2377
|
+
async function waitForOutboundPhoneCallOutcome(client, workspaceUuid, chatId, memberId, options) {
|
|
2378
|
+
const timeoutMs = options?.timeoutMs ?? 2e4;
|
|
2379
|
+
const intervalMs = options?.intervalMs ?? 500;
|
|
2380
|
+
const deadline = Date.now() + timeoutMs;
|
|
2381
|
+
while (Date.now() < deadline) {
|
|
2382
|
+
const calls2 = await client.getChatPhoneCalls(workspaceUuid, chatId);
|
|
2383
|
+
const outbound2 = latestOutboundCall(calls2);
|
|
2384
|
+
if (!outbound2) {
|
|
2385
|
+
await sleep(intervalMs);
|
|
2386
|
+
continue;
|
|
2387
|
+
}
|
|
2388
|
+
if (isTerminalFailure(outbound2)) {
|
|
2389
|
+
throw new CLIError(formatOutboundCallFailure(outbound2, memberId));
|
|
2390
|
+
}
|
|
2391
|
+
if (outbound2.status === "STARTED") {
|
|
2392
|
+
return outbound2;
|
|
2393
|
+
}
|
|
2394
|
+
if (outbound2.status === "FINISHED") {
|
|
2395
|
+
return outbound2;
|
|
2396
|
+
}
|
|
2397
|
+
await sleep(intervalMs);
|
|
2398
|
+
}
|
|
2399
|
+
const calls = await client.getChatPhoneCalls(workspaceUuid, chatId);
|
|
2400
|
+
const outbound = latestOutboundCall(calls);
|
|
2401
|
+
if (!outbound) {
|
|
2402
|
+
throw new CLIError(
|
|
2403
|
+
`Outbound call was not initiated for chat ${chatId}. Check API logs, DEV_TUNNEL_URL, and that ngrok points at https://api.gravityrail.test:5054.`
|
|
2404
|
+
);
|
|
2405
|
+
}
|
|
2406
|
+
if (isTerminalFailure(outbound)) {
|
|
2407
|
+
throw new CLIError(formatOutboundCallFailure(outbound, memberId));
|
|
2408
|
+
}
|
|
2409
|
+
throw new CLIError(
|
|
2410
|
+
`Timed out after ${timeoutMs / 1e3}s waiting for outbound call result (phoneCallId=${outbound.id}, status=${outbound.status}). The call may still be ringing \u2014 check Twilio console or gr chats phone-calls.`
|
|
2411
|
+
);
|
|
2412
|
+
}
|
|
2413
|
+
async function resolveVoicePhoneNumberId(client, workspaceUuid, explicitId) {
|
|
2414
|
+
if (explicitId !== void 0) {
|
|
2415
|
+
return explicitId;
|
|
2416
|
+
}
|
|
2417
|
+
const defaults = await client.getWorkspaceDefaults(workspaceUuid);
|
|
2418
|
+
if (defaults.defaultPhoneNumberId) {
|
|
2419
|
+
return defaults.defaultPhoneNumberId;
|
|
2420
|
+
}
|
|
2421
|
+
const numbers = await client.getPhoneNumbers(workspaceUuid);
|
|
2422
|
+
const voiceLine = numbers.find((n) => n.enableVoice !== false && !n.isArchived);
|
|
2423
|
+
if (!voiceLine) {
|
|
2424
|
+
throw new CLIError(
|
|
2425
|
+
"No voice-enabled phone number in workspace \u2014 run: yarn dev:twilio-ngrok dev.<you> -w <slug> or pass --phone-number-id"
|
|
2426
|
+
);
|
|
2427
|
+
}
|
|
2428
|
+
return voiceLine.id;
|
|
2429
|
+
}
|
|
2430
|
+
|
|
2275
2431
|
// src/lib/crud.ts
|
|
2276
2432
|
function crudCommands(config) {
|
|
2277
2433
|
const {
|
|
@@ -2379,6 +2535,7 @@ function crudCommands(config) {
|
|
|
2379
2535
|
mutates: true,
|
|
2380
2536
|
args: [{ name: "id", description: `${entityName} ID`, required: true }],
|
|
2381
2537
|
requiresWorkspace,
|
|
2538
|
+
...config.updateExamples ? { examples: config.updateExamples } : {},
|
|
2382
2539
|
handler: async (hctx) => {
|
|
2383
2540
|
if (!hctx.data) throw new CLIError("JSON data required (--data, --file, or stdin)");
|
|
2384
2541
|
const id = resolveId(hctx);
|
|
@@ -2801,11 +2958,13 @@ var CommandRegistry = class {
|
|
|
2801
2958
|
const lines = [`${cmd.description}
|
|
2802
2959
|
`, `Usage: gr ${cmdStr} [options]`];
|
|
2803
2960
|
if (cmd.requiresWorkspace) {
|
|
2804
|
-
lines.push(" Requires: -w <workspace-uuid>");
|
|
2961
|
+
lines.push(" Requires: -w <workspace-uuid> (or --realm <workspace>/<member> in dev)");
|
|
2805
2962
|
}
|
|
2806
2963
|
if (cmd.mutates) {
|
|
2807
2964
|
lines.push(" Requires: --allow-write");
|
|
2808
2965
|
}
|
|
2966
|
+
const action = cmd.path[cmd.path.length - 1] ?? "";
|
|
2967
|
+
const showsJsonHints = action === "create" || action === "update" || cmd.args?.some((a) => a.name === "data" || a.name === "file");
|
|
2809
2968
|
if (cmd.args && cmd.args.length > 0) {
|
|
2810
2969
|
lines.push("", "Arguments:");
|
|
2811
2970
|
for (const arg of cmd.args) {
|
|
@@ -2814,6 +2973,12 @@ var CommandRegistry = class {
|
|
|
2814
2973
|
lines.push(` ${flag.padEnd(28)} ${arg.description}${req}`);
|
|
2815
2974
|
}
|
|
2816
2975
|
}
|
|
2976
|
+
if (showsJsonHints) {
|
|
2977
|
+
lines.push("", "JSON body (one of):");
|
|
2978
|
+
lines.push(" -d, --data <json> Inline JSON");
|
|
2979
|
+
lines.push(" -f, --file <path> JSON file");
|
|
2980
|
+
lines.push(" stdin Pipe JSON when not a TTY");
|
|
2981
|
+
}
|
|
2817
2982
|
if (cmd.examples && cmd.examples.length > 0) {
|
|
2818
2983
|
lines.push("", "Examples:");
|
|
2819
2984
|
for (const ex of cmd.examples) {
|
|
@@ -2842,6 +3007,12 @@ var CommandRegistry = class {
|
|
|
2842
3007
|
"",
|
|
2843
3008
|
"Global Options:",
|
|
2844
3009
|
" --env <env> Environment: dev, staging, prod (default: dev)",
|
|
3010
|
+
" --realm <ws>/<member> Dev auth shortcut (dev only; sets -w automatically)",
|
|
3011
|
+
" --api-url <url> API base URL (or GRAVITY_RAIL_API_URL)",
|
|
3012
|
+
" -w, --workspace <uuid> Workspace UUID",
|
|
3013
|
+
" -d, --data <json> JSON body (create/update and other write commands)",
|
|
3014
|
+
" -f, --file <path> JSON body from file",
|
|
3015
|
+
" --allow-write Required for create/update/delete/archive",
|
|
2845
3016
|
" -o, --output-format <fmt> Output format: json, jsonl, table (default: auto)",
|
|
2846
3017
|
" -v, --verbose Verbose output to stderr",
|
|
2847
3018
|
" --help Show help",
|
|
@@ -3368,7 +3539,11 @@ var membersDomain = {
|
|
|
3368
3539
|
deleteMethod: "deleteMember",
|
|
3369
3540
|
archiveMethod: "archiveMember",
|
|
3370
3541
|
unarchiveMethod: "unarchiveMember",
|
|
3371
|
-
columns: COLUMNS3
|
|
3542
|
+
columns: COLUMNS3,
|
|
3543
|
+
updateExamples: [
|
|
3544
|
+
`yarn gr members update -w $UUID --id 2 --data '{"phone":"+15551234567"}' --allow-write`,
|
|
3545
|
+
"yarn gr members update --realm acme-demo/acme-admin --id 2 --file /tmp/member.json --allow-write"
|
|
3546
|
+
]
|
|
3372
3547
|
}),
|
|
3373
3548
|
// Current member
|
|
3374
3549
|
{
|
|
@@ -4188,8 +4363,18 @@ var workspacesDomain = {
|
|
|
4188
4363
|
`organizationId is required in --data (e.g. --data '{"organizationId": 1, "name": "My Workspace"}')`
|
|
4189
4364
|
);
|
|
4190
4365
|
}
|
|
4191
|
-
|
|
4192
|
-
|
|
4366
|
+
try {
|
|
4367
|
+
const result = await requireAuth(ctx).apiClient.createWorkspace(payload);
|
|
4368
|
+
outputSingle(result, ctx, COLUMNS7);
|
|
4369
|
+
} catch (err) {
|
|
4370
|
+
const statusCode = err?.statusCode;
|
|
4371
|
+
if (statusCode === 405) {
|
|
4372
|
+
throw new CLIError(
|
|
4373
|
+
'Creating a workspace directly is not supported \u2014 provisioning runs through the concierge (it handles product selection and billing).\nNext: gr concierge chat --allow-write --message "Create a new workspace"\nThen: gr workspaces list (to get the new workspace UUID for -w)'
|
|
4374
|
+
);
|
|
4375
|
+
}
|
|
4376
|
+
throw err;
|
|
4377
|
+
}
|
|
4193
4378
|
}
|
|
4194
4379
|
},
|
|
4195
4380
|
// Defaults
|
|
@@ -5226,11 +5411,14 @@ var RULE_COLUMNS = [
|
|
|
5226
5411
|
{ header: "EVENT", getValue: (item) => item.eventType ?? "" },
|
|
5227
5412
|
{ header: "ACTIVE", getValue: (item) => String(item.active ?? "") }
|
|
5228
5413
|
];
|
|
5229
|
-
var
|
|
5414
|
+
var ROUTINE_COLUMNS = [
|
|
5230
5415
|
COL.id(),
|
|
5231
5416
|
COL.name(),
|
|
5232
|
-
{ header: "
|
|
5233
|
-
|
|
5417
|
+
{ header: "MODE", getValue: (item) => item.scheduleMode ?? "" },
|
|
5418
|
+
{ header: "CRON", getValue: (item) => item.cronString ?? "" },
|
|
5419
|
+
{ header: "TZ", getValue: (item) => item.timezone ?? "UTC" },
|
|
5420
|
+
{ header: "ENABLED", getValue: (item) => String(item.scheduleEnabled ?? "") },
|
|
5421
|
+
{ header: "NEXT RUN", getValue: (item) => item.nextRun ?? "" }
|
|
5234
5422
|
];
|
|
5235
5423
|
var eventRulesCrudNoList = crudCommands({
|
|
5236
5424
|
prefix: ["events", "rules"],
|
|
@@ -5399,7 +5587,15 @@ var eventsDomain = {
|
|
|
5399
5587
|
updateMethod: "updateRoutine",
|
|
5400
5588
|
deleteMethod: "deleteRoutine",
|
|
5401
5589
|
paginationSupport: "full",
|
|
5402
|
-
columns:
|
|
5590
|
+
columns: ROUTINE_COLUMNS,
|
|
5591
|
+
createExamples: [
|
|
5592
|
+
"Daily 7am check-in in the member\u2019s timezone (cron is interpreted in `timezone`):",
|
|
5593
|
+
`gr routines create -w $WID --allow-write --data '{"name":"AM check-in",`,
|
|
5594
|
+
' "scheduleEnabled":true,"scheduleMode":"CRON","cronString":"0 7 * * *",',
|
|
5595
|
+
` "timezone":"America/Los_Angeles","targetMemberId":1,"workflowId":2}'`,
|
|
5596
|
+
" (timezone is an IANA name; omit it to default to the workspace timezone, else UTC.",
|
|
5597
|
+
' Without it, "0 7 * * *" fires at 07:00 UTC, not 7am local.)'
|
|
5598
|
+
]
|
|
5403
5599
|
}),
|
|
5404
5600
|
{
|
|
5405
5601
|
path: ["routines", "run"],
|
|
@@ -5446,6 +5642,232 @@ var eventsDomain = {
|
|
|
5446
5642
|
]
|
|
5447
5643
|
};
|
|
5448
5644
|
|
|
5645
|
+
// src/domains/experiments.ts
|
|
5646
|
+
var EXPERIMENT_COLUMNS = [
|
|
5647
|
+
COL.id(),
|
|
5648
|
+
{ header: "UUID", getValue: (item) => (item.uuid ?? "").slice(0, 8) },
|
|
5649
|
+
{ header: "SLUG", getValue: (item) => item.slug ?? "" },
|
|
5650
|
+
COL.name(),
|
|
5651
|
+
COL.status(),
|
|
5652
|
+
{
|
|
5653
|
+
header: "ASSIGNED",
|
|
5654
|
+
getValue: (item) => item.assignmentCount != null ? String(item.assignmentCount) : "0"
|
|
5655
|
+
},
|
|
5656
|
+
COL.created()
|
|
5657
|
+
];
|
|
5658
|
+
var GROUP_COLUMNS = [
|
|
5659
|
+
COL.id(),
|
|
5660
|
+
{ header: "SLUG", getValue: (item) => item.slug ?? "" },
|
|
5661
|
+
COL.name(),
|
|
5662
|
+
{
|
|
5663
|
+
header: "WEIGHT",
|
|
5664
|
+
getValue: (item) => item.allocationWeight != null ? String(item.allocationWeight) : ""
|
|
5665
|
+
},
|
|
5666
|
+
{
|
|
5667
|
+
header: "CONTROL",
|
|
5668
|
+
getValue: (item) => item.isControl ? "yes" : ""
|
|
5669
|
+
},
|
|
5670
|
+
{ header: "ORDER", getValue: (item) => String(item.order ?? "") }
|
|
5671
|
+
];
|
|
5672
|
+
var STATS_COLUMNS = [
|
|
5673
|
+
{ header: "GROUP_ID", getValue: (item) => String(item.groupId ?? "") },
|
|
5674
|
+
{ header: "SLUG", getValue: (item) => item.groupSlug ?? "" },
|
|
5675
|
+
{ header: "NAME", getValue: (item) => item.groupName ?? "" },
|
|
5676
|
+
{
|
|
5677
|
+
header: "CONTROL",
|
|
5678
|
+
getValue: (item) => item.isControl ? "yes" : ""
|
|
5679
|
+
},
|
|
5680
|
+
{
|
|
5681
|
+
header: "ASSIGNED",
|
|
5682
|
+
getValue: (item) => item.assignedCount != null ? String(item.assignedCount) : "0"
|
|
5683
|
+
},
|
|
5684
|
+
{
|
|
5685
|
+
header: "EXPOSED",
|
|
5686
|
+
getValue: (item) => item.exposedCount != null ? String(item.exposedCount) : "0"
|
|
5687
|
+
}
|
|
5688
|
+
];
|
|
5689
|
+
var MEMBER_ASSIGNMENT_COLUMNS = [
|
|
5690
|
+
COL.id(),
|
|
5691
|
+
{
|
|
5692
|
+
header: "EXPERIMENT",
|
|
5693
|
+
getValue: (item) => item.experimentSlug ?? String(item.experimentId ?? "")
|
|
5694
|
+
},
|
|
5695
|
+
{
|
|
5696
|
+
header: "GROUP",
|
|
5697
|
+
getValue: (item) => item.groupSlug ?? String(item.groupId ?? "")
|
|
5698
|
+
},
|
|
5699
|
+
{ header: "ASSIGNED", getValue: (item) => item.assignedAt ?? "" },
|
|
5700
|
+
{ header: "SOURCE", getValue: (item) => item.assignmentSource ?? "" }
|
|
5701
|
+
];
|
|
5702
|
+
var experimentsDomain = {
|
|
5703
|
+
name: "experiments",
|
|
5704
|
+
description: "Manage member A/B experiments, groups, and reporting",
|
|
5705
|
+
commands: [
|
|
5706
|
+
{
|
|
5707
|
+
path: ["experiments", "list"],
|
|
5708
|
+
description: "List experiments",
|
|
5709
|
+
requiresWorkspace: true,
|
|
5710
|
+
args: [
|
|
5711
|
+
...LIST_PAGINATION_ARGS,
|
|
5712
|
+
{
|
|
5713
|
+
name: "include-archived",
|
|
5714
|
+
description: "Include archived experiments",
|
|
5715
|
+
required: false
|
|
5716
|
+
}
|
|
5717
|
+
],
|
|
5718
|
+
handler: async ({ ctx, workspace, args }) => {
|
|
5719
|
+
const includeArchived = args["include-archived"] === "true";
|
|
5720
|
+
const pag = parsePaginationArgs(args);
|
|
5721
|
+
const result = await requireAuth(ctx).apiClient.getExperiments(workspace, {
|
|
5722
|
+
...pag.page ? { page: pag.page } : {},
|
|
5723
|
+
...pag.pageSize ? { pageSize: pag.pageSize } : {},
|
|
5724
|
+
includeArchived
|
|
5725
|
+
});
|
|
5726
|
+
outputData(listResult(result, true), ctx, EXPERIMENT_COLUMNS);
|
|
5727
|
+
}
|
|
5728
|
+
},
|
|
5729
|
+
{
|
|
5730
|
+
path: ["experiments", "get"],
|
|
5731
|
+
description: "Get an experiment by ID",
|
|
5732
|
+
requiresWorkspace: true,
|
|
5733
|
+
args: [{ name: "id", description: "Experiment ID", required: true }],
|
|
5734
|
+
handler: async ({ ctx, workspace, args }) => {
|
|
5735
|
+
const result = await requireAuth(ctx).apiClient.getExperiment(
|
|
5736
|
+
workspace,
|
|
5737
|
+
requireNumber(args, "id")
|
|
5738
|
+
);
|
|
5739
|
+
outputSingle(result, ctx);
|
|
5740
|
+
}
|
|
5741
|
+
},
|
|
5742
|
+
{
|
|
5743
|
+
path: ["experiments", "create"],
|
|
5744
|
+
description: "Create a draft experiment (pass JSON via --data)",
|
|
5745
|
+
mutates: true,
|
|
5746
|
+
requiresWorkspace: true,
|
|
5747
|
+
handler: async ({ ctx, workspace, data }) => {
|
|
5748
|
+
if (!data) throw new CLIError("JSON data required (--data, --file, or stdin)");
|
|
5749
|
+
const result = await requireAuth(ctx).apiClient.createExperiment(
|
|
5750
|
+
workspace,
|
|
5751
|
+
data
|
|
5752
|
+
);
|
|
5753
|
+
outputSingle(result, ctx, EXPERIMENT_COLUMNS);
|
|
5754
|
+
}
|
|
5755
|
+
},
|
|
5756
|
+
{
|
|
5757
|
+
path: ["experiments", "update"],
|
|
5758
|
+
description: "Update an experiment (pass JSON via --data)",
|
|
5759
|
+
mutates: true,
|
|
5760
|
+
requiresWorkspace: true,
|
|
5761
|
+
args: [{ name: "id", description: "Experiment ID", required: true }],
|
|
5762
|
+
handler: async ({ ctx, workspace, args, data }) => {
|
|
5763
|
+
if (!data) throw new CLIError("JSON data required (--data, --file, or stdin)");
|
|
5764
|
+
const result = await requireAuth(ctx).apiClient.updateExperiment(
|
|
5765
|
+
workspace,
|
|
5766
|
+
requireNumber(args, "id"),
|
|
5767
|
+
data
|
|
5768
|
+
);
|
|
5769
|
+
outputSingle(result, ctx, EXPERIMENT_COLUMNS);
|
|
5770
|
+
}
|
|
5771
|
+
},
|
|
5772
|
+
{
|
|
5773
|
+
path: ["experiments", "delete"],
|
|
5774
|
+
description: "Delete a draft experiment or archive a running one",
|
|
5775
|
+
mutates: true,
|
|
5776
|
+
requiresWorkspace: true,
|
|
5777
|
+
args: [{ name: "id", description: "Experiment ID", required: true }],
|
|
5778
|
+
handler: async ({ ctx, workspace, args }) => {
|
|
5779
|
+
const result = await requireAuth(ctx).apiClient.deleteExperiment(
|
|
5780
|
+
workspace,
|
|
5781
|
+
requireNumber(args, "id")
|
|
5782
|
+
);
|
|
5783
|
+
process.stdout.write(`${result.status} experiment ${args["id"]}
|
|
5784
|
+
`);
|
|
5785
|
+
}
|
|
5786
|
+
},
|
|
5787
|
+
{
|
|
5788
|
+
path: ["experiments", "stats"],
|
|
5789
|
+
description: "Get assignment and exposure counts by group",
|
|
5790
|
+
requiresWorkspace: true,
|
|
5791
|
+
args: [{ name: "id", description: "Experiment ID", required: true }],
|
|
5792
|
+
handler: async ({ ctx, workspace, args }) => {
|
|
5793
|
+
const result = await requireAuth(ctx).apiClient.getExperimentStats(
|
|
5794
|
+
workspace,
|
|
5795
|
+
requireNumber(args, "id")
|
|
5796
|
+
);
|
|
5797
|
+
outputData(result.groups, ctx, STATS_COLUMNS);
|
|
5798
|
+
}
|
|
5799
|
+
},
|
|
5800
|
+
{
|
|
5801
|
+
path: ["experiments", "groups", "create"],
|
|
5802
|
+
description: "Create a group on an experiment (pass JSON via --data)",
|
|
5803
|
+
mutates: true,
|
|
5804
|
+
requiresWorkspace: true,
|
|
5805
|
+
args: [{ name: "experiment-id", description: "Experiment ID", required: true }],
|
|
5806
|
+
handler: async ({ ctx, workspace, args, data }) => {
|
|
5807
|
+
if (!data) throw new CLIError("JSON data required (--data, --file, or stdin)");
|
|
5808
|
+
const result = await requireAuth(ctx).apiClient.createExperimentGroup(
|
|
5809
|
+
workspace,
|
|
5810
|
+
requireNumber(args, "experiment-id"),
|
|
5811
|
+
data
|
|
5812
|
+
);
|
|
5813
|
+
outputSingle(result, ctx, GROUP_COLUMNS);
|
|
5814
|
+
}
|
|
5815
|
+
},
|
|
5816
|
+
{
|
|
5817
|
+
path: ["experiments", "groups", "update"],
|
|
5818
|
+
description: "Update a group (pass JSON via --data)",
|
|
5819
|
+
mutates: true,
|
|
5820
|
+
requiresWorkspace: true,
|
|
5821
|
+
args: [
|
|
5822
|
+
{ name: "experiment-id", description: "Experiment ID", required: true },
|
|
5823
|
+
{ name: "group-id", description: "Group ID", required: true }
|
|
5824
|
+
],
|
|
5825
|
+
handler: async ({ ctx, workspace, args, data }) => {
|
|
5826
|
+
if (!data) throw new CLIError("JSON data required (--data, --file, or stdin)");
|
|
5827
|
+
const result = await requireAuth(ctx).apiClient.updateExperimentGroup(
|
|
5828
|
+
workspace,
|
|
5829
|
+
requireNumber(args, "experiment-id"),
|
|
5830
|
+
requireNumber(args, "group-id"),
|
|
5831
|
+
data
|
|
5832
|
+
);
|
|
5833
|
+
outputSingle(result, ctx, GROUP_COLUMNS);
|
|
5834
|
+
}
|
|
5835
|
+
},
|
|
5836
|
+
{
|
|
5837
|
+
path: ["experiments", "groups", "delete"],
|
|
5838
|
+
description: "Delete a group with no member assignments",
|
|
5839
|
+
mutates: true,
|
|
5840
|
+
requiresWorkspace: true,
|
|
5841
|
+
args: [
|
|
5842
|
+
{ name: "experiment-id", description: "Experiment ID", required: true },
|
|
5843
|
+
{ name: "group-id", description: "Group ID", required: true }
|
|
5844
|
+
],
|
|
5845
|
+
handler: async ({ ctx, workspace, args }) => {
|
|
5846
|
+
await requireAuth(ctx).apiClient.deleteExperimentGroup(
|
|
5847
|
+
workspace,
|
|
5848
|
+
requireNumber(args, "experiment-id"),
|
|
5849
|
+
requireNumber(args, "group-id")
|
|
5850
|
+
);
|
|
5851
|
+
process.stdout.write(`Deleted group ${args["group-id"]}
|
|
5852
|
+
`);
|
|
5853
|
+
}
|
|
5854
|
+
},
|
|
5855
|
+
{
|
|
5856
|
+
path: ["experiments", "members", "list"],
|
|
5857
|
+
description: "List experiment assignments for a member",
|
|
5858
|
+
requiresWorkspace: true,
|
|
5859
|
+
args: [{ name: "member-id", description: "Member ID", required: true }],
|
|
5860
|
+
handler: async ({ ctx, workspace, args }) => {
|
|
5861
|
+
const result = await requireAuth(ctx).apiClient.getMemberExperiments(
|
|
5862
|
+
workspace,
|
|
5863
|
+
requireNumber(args, "member-id")
|
|
5864
|
+
);
|
|
5865
|
+
outputData(result, ctx, MEMBER_ASSIGNMENT_COLUMNS);
|
|
5866
|
+
}
|
|
5867
|
+
}
|
|
5868
|
+
]
|
|
5869
|
+
};
|
|
5870
|
+
|
|
5449
5871
|
// src/domains/files.ts
|
|
5450
5872
|
var COLUMNS11 = [
|
|
5451
5873
|
COL.id(),
|
|
@@ -7502,6 +7924,58 @@ async function getConciergeChat(ctx, chatId) {
|
|
|
7502
7924
|
if (!res.ok) throw new Error(`Failed to get concierge chat ${chatId}: ${res.status}`);
|
|
7503
7925
|
return toCamelChat(await res.json());
|
|
7504
7926
|
}
|
|
7927
|
+
async function originateConciergeCall(ctx, kind = "concierge_setup") {
|
|
7928
|
+
const res = await fetch(`${baseUrl2(ctx)}/calls`, {
|
|
7929
|
+
method: "POST",
|
|
7930
|
+
headers: authHeaders(ctx),
|
|
7931
|
+
body: JSON.stringify({ kind })
|
|
7932
|
+
});
|
|
7933
|
+
if (res.status === 412) {
|
|
7934
|
+
throw new Error("Your account phone is not verified. Run `gr account verify-phone` first.");
|
|
7935
|
+
}
|
|
7936
|
+
if (!res.ok) {
|
|
7937
|
+
const detail = await res.text();
|
|
7938
|
+
throw new Error(`Failed to start concierge call: ${res.status} ${detail}`);
|
|
7939
|
+
}
|
|
7940
|
+
return await res.json();
|
|
7941
|
+
}
|
|
7942
|
+
async function originateConciergeSms(ctx, kind = "concierge_setup") {
|
|
7943
|
+
const res = await fetch(`${baseUrl2(ctx)}/sms`, {
|
|
7944
|
+
method: "POST",
|
|
7945
|
+
headers: authHeaders(ctx),
|
|
7946
|
+
body: JSON.stringify({ kind })
|
|
7947
|
+
});
|
|
7948
|
+
if (res.status === 412) {
|
|
7949
|
+
throw new Error("Your account phone is not verified. Run `gr account verify-phone` first.");
|
|
7950
|
+
}
|
|
7951
|
+
if (!res.ok) {
|
|
7952
|
+
const detail = await res.text();
|
|
7953
|
+
throw new Error(`Failed to start concierge SMS: ${res.status} ${detail}`);
|
|
7954
|
+
}
|
|
7955
|
+
return await res.json();
|
|
7956
|
+
}
|
|
7957
|
+
async function startAccountPhoneVerify(ctx, phone) {
|
|
7958
|
+
const res = await fetch(`${ctx.envConfig.apiUrl}/api/v2/account/phone/verify/start`, {
|
|
7959
|
+
method: "POST",
|
|
7960
|
+
headers: authHeaders(ctx),
|
|
7961
|
+
body: JSON.stringify({ phone })
|
|
7962
|
+
});
|
|
7963
|
+
if (!res.ok) {
|
|
7964
|
+
const detail = await res.text();
|
|
7965
|
+
throw new Error(`Failed to send verification code: ${res.status} ${detail}`);
|
|
7966
|
+
}
|
|
7967
|
+
}
|
|
7968
|
+
async function confirmAccountPhoneVerify(ctx, code) {
|
|
7969
|
+
const res = await fetch(`${ctx.envConfig.apiUrl}/api/v2/account/phone/verify/confirm`, {
|
|
7970
|
+
method: "POST",
|
|
7971
|
+
headers: authHeaders(ctx),
|
|
7972
|
+
body: JSON.stringify({ code })
|
|
7973
|
+
});
|
|
7974
|
+
if (!res.ok) {
|
|
7975
|
+
const detail = await res.text();
|
|
7976
|
+
throw new Error(`Failed to confirm verification code: ${res.status} ${detail}`);
|
|
7977
|
+
}
|
|
7978
|
+
}
|
|
7505
7979
|
async function getConciergeChatMessages(ctx, chatId) {
|
|
7506
7980
|
const res = await fetch(`${baseUrl2(ctx)}/chats/${chatId}/messages`, {
|
|
7507
7981
|
headers: authHeaders(ctx)
|
|
@@ -9234,6 +9708,64 @@ var supportDomain = {
|
|
|
9234
9708
|
const result = wid ? await client.commentOnWorkspaceSupportRequest(wid, id, payload) : orgUuid ? await client.commentOnOrgSupportRequest(orgUuid, id, payload) : await client.commentOnSupportRequest(id, payload);
|
|
9235
9709
|
outputSingle(result, ctx, SUPPORT_COLUMNS);
|
|
9236
9710
|
}
|
|
9711
|
+
},
|
|
9712
|
+
{
|
|
9713
|
+
path: ["support", "close"],
|
|
9714
|
+
description: "Close one of your support requests (workspace-scoped)",
|
|
9715
|
+
mutates: true,
|
|
9716
|
+
args: [
|
|
9717
|
+
{ name: "workspace", aliases: ["w"], description: "Workspace UUID", required: true },
|
|
9718
|
+
{ name: "id", aliases: ["uuid"], description: "Support request UUID", required: true },
|
|
9719
|
+
{ name: "reason", description: "Optional close reason" }
|
|
9720
|
+
],
|
|
9721
|
+
handler: async ({ ctx, args, workspace, data }) => {
|
|
9722
|
+
const client = requireAuth(ctx).apiClient;
|
|
9723
|
+
const id = requireString(args, "id");
|
|
9724
|
+
const wid = args.workspace ?? workspace;
|
|
9725
|
+
if (!wid) throw new Error("--workspace is required to close a support request");
|
|
9726
|
+
const input = data ?? {};
|
|
9727
|
+
const reason = input.reason ?? args.reason;
|
|
9728
|
+
const result = await client.closeWorkspaceSupportRequest(
|
|
9729
|
+
wid,
|
|
9730
|
+
id,
|
|
9731
|
+
reason ? { reason } : {}
|
|
9732
|
+
);
|
|
9733
|
+
outputSingle(result, ctx, SUPPORT_COLUMNS);
|
|
9734
|
+
}
|
|
9735
|
+
},
|
|
9736
|
+
{
|
|
9737
|
+
path: ["support", "resource-click"],
|
|
9738
|
+
description: "Record a click on a pushed resource (consume + track usefulness)",
|
|
9739
|
+
mutates: true,
|
|
9740
|
+
args: [
|
|
9741
|
+
{ name: "workspace", aliases: ["w"], description: "Workspace UUID", required: true },
|
|
9742
|
+
{ name: "id", aliases: ["uuid"], description: "Support request UUID", required: true },
|
|
9743
|
+
{
|
|
9744
|
+
name: "resource-uuid",
|
|
9745
|
+
description: "UUID of the resource that was opened",
|
|
9746
|
+
required: true
|
|
9747
|
+
},
|
|
9748
|
+
{
|
|
9749
|
+
name: "resulting-chat-uuid",
|
|
9750
|
+
description: "Manager Chat UUID a manager_prompt opened (links resource\u2192chat)"
|
|
9751
|
+
}
|
|
9752
|
+
],
|
|
9753
|
+
handler: async ({ ctx, args, workspace, data }) => {
|
|
9754
|
+
const client = requireAuth(ctx).apiClient;
|
|
9755
|
+
const id = requireString(args, "id");
|
|
9756
|
+
const resourceUuid = requireString(args, "resource-uuid");
|
|
9757
|
+
const wid = args.workspace ?? workspace;
|
|
9758
|
+
if (!wid) throw new Error("--workspace is required to click a resource");
|
|
9759
|
+
const input = data ?? {};
|
|
9760
|
+
const resultingChatUuid = input.resultingChatUuid ?? args["resulting-chat-uuid"];
|
|
9761
|
+
const result = await client.clickWorkspaceSupportRequestResource(
|
|
9762
|
+
wid,
|
|
9763
|
+
id,
|
|
9764
|
+
resourceUuid,
|
|
9765
|
+
resultingChatUuid ? { resultingChatUuid } : {}
|
|
9766
|
+
);
|
|
9767
|
+
outputSingle(result, ctx, SUPPORT_COLUMNS);
|
|
9768
|
+
}
|
|
9237
9769
|
}
|
|
9238
9770
|
]
|
|
9239
9771
|
};
|
|
@@ -10805,6 +11337,7 @@ function registerPublicDomains(registry) {
|
|
|
10805
11337
|
registry.register(sitesDomain);
|
|
10806
11338
|
registry.register(filesDomain);
|
|
10807
11339
|
registry.register(eventsDomain);
|
|
11340
|
+
registry.register(experimentsDomain);
|
|
10808
11341
|
registry.register(calendarsDomain);
|
|
10809
11342
|
registry.register(qualificationsDomain);
|
|
10810
11343
|
registry.register(personasDomain);
|
|
@@ -13018,9 +13551,45 @@ async function listAudioDevices() {
|
|
|
13018
13551
|
}
|
|
13019
13552
|
|
|
13020
13553
|
// src/commands/concierge.ts
|
|
13554
|
+
async function conciergeOutboundCommand(hctx) {
|
|
13555
|
+
const ctx = requireAuth(hctx.ctx);
|
|
13556
|
+
const { args } = hctx;
|
|
13557
|
+
if (args.call && args.sms) {
|
|
13558
|
+
throw new CLIError("--call and --sms are mutually exclusive");
|
|
13559
|
+
}
|
|
13560
|
+
if (args.call) {
|
|
13561
|
+
const result = await originateConciergeCall(ctx);
|
|
13562
|
+
process.stderr.write(
|
|
13563
|
+
`Concierge call started. callSid=${result.callSid} startedAt=${result.startedAt}
|
|
13564
|
+
`
|
|
13565
|
+
);
|
|
13566
|
+
return;
|
|
13567
|
+
}
|
|
13568
|
+
if (args.sms) {
|
|
13569
|
+
const result = await originateConciergeSms(ctx);
|
|
13570
|
+
process.stderr.write(
|
|
13571
|
+
`Concierge SMS started. messageSid=${result.messageSid} conversationId=${result.conversationId}
|
|
13572
|
+
`
|
|
13573
|
+
);
|
|
13574
|
+
return;
|
|
13575
|
+
}
|
|
13576
|
+
throw new CLIError(
|
|
13577
|
+
"Use `gr concierge chat --call`, `gr concierge chat --sms`, or `gr concierge chat` for interactive mode."
|
|
13578
|
+
);
|
|
13579
|
+
}
|
|
13021
13580
|
async function conciergeCommand(hctx) {
|
|
13022
13581
|
const ctx = requireAuth(hctx.ctx);
|
|
13023
13582
|
const { args } = hctx;
|
|
13583
|
+
if (args.call || args.sms) {
|
|
13584
|
+
if (args.call && args.sms) {
|
|
13585
|
+
throw new CLIError("--call and --sms are mutually exclusive");
|
|
13586
|
+
}
|
|
13587
|
+
if (args.voice || args.realtime) {
|
|
13588
|
+
throw new CLIError("--call/--sms cannot be combined with --voice or --realtime");
|
|
13589
|
+
}
|
|
13590
|
+
await conciergeOutboundCommand(hctx);
|
|
13591
|
+
return;
|
|
13592
|
+
}
|
|
13024
13593
|
const chatIdArg = typeof args["chat-id"] === "string" ? args["chat-id"] : void 0;
|
|
13025
13594
|
const message = typeof args.message === "string" ? args.message : void 0;
|
|
13026
13595
|
const chat = await getOrCreateConciergeChat(ctx, chatIdArg, !!message);
|
|
@@ -13154,6 +13723,16 @@ After directory trust + \`--allow-write\`, the concierge can use \`read_local_fi
|
|
|
13154
13723
|
|
|
13155
13724
|
## Verify success
|
|
13156
13725
|
\`gr workspaces list\` then \`gr workflows list -w <uuid>\` or \`gr agents list -w <uuid>\`
|
|
13726
|
+
|
|
13727
|
+
## Local phone / voice QA (monorepo dev)
|
|
13728
|
+
\`\`\`bash
|
|
13729
|
+
yarn dev:twilio-ngrok --start-ngrok --url gravityrail.ngrok.io dev.<you> -w acme-demo
|
|
13730
|
+
yarn gr phone setup
|
|
13731
|
+
yarn gr account verify-phone --phone +1\u2026 --allow-write --realm superadmin
|
|
13732
|
+
yarn gr concierge chat --call --allow-write --realm superadmin
|
|
13733
|
+
yarn gr phone outbound --realm acme-demo/acme-admin --workflow-id 1 --allow-write
|
|
13734
|
+
\`\`\`
|
|
13735
|
+
See \`.claude/skills/phone-voice-qa/SKILL.md\` and \`./scripts/e2e-voice-phone-matrix.sh\`.
|
|
13157
13736
|
`;
|
|
13158
13737
|
async function getStartedCommand(hctx) {
|
|
13159
13738
|
const format = hctx.args.format ?? hctx.args.agent;
|
|
@@ -13418,7 +13997,10 @@ export {
|
|
|
13418
13997
|
authBrowserCommand,
|
|
13419
13998
|
buildCliConciergeAppContext,
|
|
13420
13999
|
chatCommand,
|
|
14000
|
+
commandNeedsJsonBody,
|
|
13421
14001
|
conciergeCommand,
|
|
14002
|
+
conciergeOutboundCommand,
|
|
14003
|
+
confirmAccountPhoneVerify,
|
|
13422
14004
|
createAuthenticatedContext,
|
|
13423
14005
|
createConciergeChat,
|
|
13424
14006
|
createContext,
|
|
@@ -13437,6 +14019,7 @@ export {
|
|
|
13437
14019
|
handleError,
|
|
13438
14020
|
isCursorPaginatedResponse,
|
|
13439
14021
|
isDirectoryTrusted,
|
|
14022
|
+
isLikelySeedPhoneNumber,
|
|
13440
14023
|
isListResult,
|
|
13441
14024
|
isPagePaginatedResponse,
|
|
13442
14025
|
isPaginatedResponse,
|
|
@@ -13446,6 +14029,8 @@ export {
|
|
|
13446
14029
|
logoutCommand,
|
|
13447
14030
|
manageCommand,
|
|
13448
14031
|
organizationsListCommand,
|
|
14032
|
+
originateConciergeCall,
|
|
14033
|
+
originateConciergeSms,
|
|
13449
14034
|
outputData,
|
|
13450
14035
|
outputSingle,
|
|
13451
14036
|
parseArgs,
|
|
@@ -13456,9 +14041,12 @@ export {
|
|
|
13456
14041
|
requireDirectoryTrust,
|
|
13457
14042
|
requireNumber,
|
|
13458
14043
|
requireString,
|
|
14044
|
+
resolveVoicePhoneNumberId,
|
|
13459
14045
|
simpleCrudCommands,
|
|
14046
|
+
startAccountPhoneVerify,
|
|
13460
14047
|
stderr,
|
|
13461
14048
|
unwrapItems,
|
|
14049
|
+
waitForOutboundPhoneCallOutcome,
|
|
13462
14050
|
whoamiCommand
|
|
13463
14051
|
};
|
|
13464
14052
|
//# sourceMappingURL=lib.js.map
|