@gravity-rail/cli 0.14.0 → 0.16.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/lib.js CHANGED
@@ -15,6 +15,7 @@ import {
15
15
  formatPaginationWarning,
16
16
  getConciergeChat,
17
17
  getConciergeChatMessages,
18
+ hint,
18
19
  isCursorPaginatedResponse,
19
20
  isListResult,
20
21
  isPagePaginatedResponse,
@@ -31,7 +32,7 @@ import {
31
32
  startAccountPhoneVerify,
32
33
  stderr,
33
34
  unwrapItems
34
- } from "./chunk-M4XMXS5D.js";
35
+ } from "./chunk-EITDLX75.js";
35
36
  import {
36
37
  AGUIClient,
37
38
  formatTimestamp,
@@ -1214,6 +1215,43 @@ var agentTasksDomain = {
1214
1215
 
1215
1216
  // src/domains/agents.ts
1216
1217
  var COLUMNS = [COL.id(), COL.uuid(), COL.name(), COL.status(), COL.created()];
1218
+ var AGENT_FIELD_REFERENCE = `
1219
+ Field reference for --data JSON (create/update):
1220
+
1221
+ Required on create
1222
+ name (string) Display name
1223
+ chatModelId (string) Text chat model ID (see \`gr ai-models chat\`)
1224
+ e.g. "aws:bedrock:claude-4-5-haiku"
1225
+
1226
+ Optional
1227
+ description (string) Short summary shown in listings
1228
+ systemPrompt (string) Base instructions / identity
1229
+ chatModelConfig (object|null) Chat model overrides (temperature, thinking, \u2026)
1230
+ realtimeModelId (string|null) Voice/realtime model (see \`gr ai-models realtime\`)
1231
+ e.g. "xai:realtime:voice-agent-2" (Grok Voice Think Fast 2)
1232
+ Native models auto-fill tts=native + default voice when
1233
+ realtimeModelConfig is omitted.
1234
+ realtimeModelConfig (object|null) Realtime config. Native example:
1235
+ {"ttsModel":"native","voiceModel":"xai:voice:eve"}
1236
+ Composable (custom:realtime:composable) needs
1237
+ voiceModel + ttsModel + inferenceModel.
1238
+ memberRoleId (number) Role id (omit to use the default Agent role)
1239
+ email / phone / externalId Optional contact fields
1240
+ labelIds (number[]) Member label ids
1241
+ codeInterpreterEnabled (bool)
1242
+ maxDailyActions (number|null)
1243
+
1244
+ Attach an agent\u2019s models/identity to a workflow (draft), then publish:
1245
+ gr workflows update --id <wf> -d '{"copyFromAgentId": <agentId>}'
1246
+ gr workflows publish --id <wf>
1247
+
1248
+ One-shot workflow voice WITHOUT creating an agent (preferred for "use Grok Voice 2"):
1249
+ gr workflows update --id <wf> -d '{"realtimeModelId":"xai:realtime:voice-agent-2"}'
1250
+ gr workflows publish --id <wf>
1251
+
1252
+ List models:
1253
+ gr ai-models chat | realtime | voice
1254
+ `;
1217
1255
  var agentsDomain = {
1218
1256
  name: "agents",
1219
1257
  description: "Manage agents",
@@ -1230,9 +1268,16 @@ var agentsDomain = {
1230
1268
  unarchiveMethod: "unarchiveAgent",
1231
1269
  columns: COLUMNS,
1232
1270
  paginationSupport: "full",
1233
- updateHelp: "Update an agent. Body schema (JSON via --data/--file/stdin), all fields optional:\n name string display name\n description string short summary shown in listings\n systemPrompt string base instructions for the agent\n model string AI model slug (see `gr ai-models list`)\n temperature number sampling temperature (0-2)\n avatarFileId number workspace file ID for the avatar\n config object AgentConfig overrides (advanced)\nWorkflow abilities are managed with `gr abilities`.",
1271
+ createHelp: `Create an agent
1272
+ ${AGENT_FIELD_REFERENCE}`,
1273
+ updateHelp: `Update an agent. All fields optional.
1274
+ ${AGENT_FIELD_REFERENCE}`,
1275
+ createExamples: [
1276
+ `gr agents create -d '{"name":"Support","chatModelId":"aws:bedrock:claude-4-5-haiku","realtimeModelId":"xai:realtime:voice-agent-2"}'`,
1277
+ "gr agents create --file agent.json"
1278
+ ],
1234
1279
  updateExamples: [
1235
- `gr agents update --id 42 --data '{"name":"Scheduler","temperature":0.4}'`,
1280
+ `gr agents update --id 42 -d '{"realtimeModelId":"xai:realtime:voice-agent-2"}'`,
1236
1281
  "gr agents update --id 42 --file agent.json"
1237
1282
  ]
1238
1283
  })
@@ -2204,8 +2249,26 @@ Core
2204
2249
  name (string) Display name
2205
2250
  description (string, optional)
2206
2251
  defaultPhoneNumberId (number|null) Outbound caller ID (workspace phone id)
2252
+ defaultInboxId (number|null) Default inbox for inbound messaging
2207
2253
  permissions (object, optional) Workflow-level permission flags
2208
2254
 
2255
+ Assistant / models (live on the DRAFT revision \u2014 publish to go live)
2256
+ assistantName (string) Display name for the workflow assistant
2257
+ assistantIdentity (string) Persona / identity instructions
2258
+ chatModelId (string) Text chat model (see \`gr ai-models chat\`)
2259
+ chatModelConfig (object|null) Chat model overrides
2260
+ realtimeModelId (string|null) Voice/realtime model (see \`gr ai-models realtime\`)
2261
+ One-shot voice example:
2262
+ {"realtimeModelId":"xai:realtime:voice-agent-2"}
2263
+ Native models auto-fill tts=native + default voice
2264
+ (xAI \u2192 xai:voice:eve). Optional explicit config:
2265
+ {"realtimeModelId":"xai:realtime:voice-agent-2",
2266
+ "realtimeModelConfig":{"ttsModel":"native",
2267
+ "voiceModel":"xai:voice:ara"}}
2268
+ realtimeModelConfig (object|null) Realtime config; omit for provider defaults
2269
+ copyFromAgentId (number) Copy full assistant settings from an agent
2270
+ copyFromWorkflowRevisionId (number) Copy assistant settings from a revision
2271
+
2209
2272
  Member role access (memberRoleAccess)
2210
2273
  Array of objects, NOT bare role ids:
2211
2274
  [{"memberRoleId": 6, "accessMode": 1}]
@@ -2231,6 +2294,9 @@ Use the dedicated commands:
2231
2294
  workflows revisions edit Branch a published revision back into the draft
2232
2295
  workflows revisions diff Compare two revisions
2233
2296
  workflows revisions update Edit a revision's label / publish notes
2297
+
2298
+ After changing assistant/realtime fields, publish so live traffic picks them up:
2299
+ gr workflows publish --id <workflowId>
2234
2300
  `;
2235
2301
 
2236
2302
  // src/domains/workflows.ts
@@ -2857,7 +2923,15 @@ var COLUMNS6 = [
2857
2923
  COL.status(),
2858
2924
  COL.created()
2859
2925
  ];
2860
- var PRODUCT_COLUMNS = [COL.id(), COL.uuid(), COL.name(), COL.status()];
2926
+ var PRODUCT_COLUMNS = [
2927
+ COL.id(),
2928
+ COL.uuid(),
2929
+ COL.name(),
2930
+ COL.status(),
2931
+ // The plan a flow picks when it cannot ask (the signup funnel's workspace step,
2932
+ // for one). One per type per catalogue — see `gr workspaces products set-default`.
2933
+ { header: "DEFAULT", getValue: (item) => item.isDefault ? "yes" : "\u2014" }
2934
+ ];
2861
2935
  var INVITATION_COLUMNS = [
2862
2936
  COL.id(),
2863
2937
  { header: "EMAIL", getValue: (item) => item.email ?? "" },
@@ -3293,6 +3367,40 @@ Provisioning started. Watch it come up with:
3293
3367
  outputSingle(result2, ctx, PRODUCT_COLUMNS);
3294
3368
  }
3295
3369
  },
3370
+ {
3371
+ path: ["workspaces", "products", "set-default"],
3372
+ description: "Make a plan the one flows pick when they can't ask",
3373
+ mutates: true,
3374
+ requiresWorkspace: true,
3375
+ args: [
3376
+ { name: "id", description: "Product ID", required: true },
3377
+ {
3378
+ name: "unset",
3379
+ description: "Clear the flag instead, leaving the catalogue with no default",
3380
+ isFlag: true
3381
+ }
3382
+ ],
3383
+ examples: [
3384
+ "gr workspaces products set-default --id 21",
3385
+ "gr workspaces products set-default --id 21 --unset"
3386
+ ],
3387
+ handler: async ({ ctx, args, workspace }) => {
3388
+ const id = requireNumber(args, "id");
3389
+ const isDefault = !args["unset"];
3390
+ const result2 = await requireAuth(ctx).apiClient.updateProduct(workspace, id, {
3391
+ isDefault
3392
+ });
3393
+ outputSingle(result2, ctx, PRODUCT_COLUMNS);
3394
+ hint(ctx, [
3395
+ isDefault ? "Any other plan of this type in the catalogue is no longer the default." : (
3396
+ // Only this plan's flag is cleared. Claiming the catalogue now has
3397
+ // no default would be wrong when a different plan holds it — the
3398
+ // response cannot tell us whether this one was the holder.
3399
+ "This plan no longer holds the default flag. Check which plan does:\n gr workspaces products list"
3400
+ )
3401
+ ]);
3402
+ }
3403
+ },
3296
3404
  // Invitations — workspace-scoped admin methods
3297
3405
  {
3298
3406
  path: ["workspaces", "invitations", "list"],
@@ -7468,7 +7576,7 @@ var COLUMNS14 = [
7468
7576
  ];
7469
7577
  var aiModelsDomain = {
7470
7578
  name: "ai-models",
7471
- description: "List available AI models",
7579
+ description: `List available AI models (chat, realtime/voice stacks, speaker voices). Use realtime ids as workflow/agent realtimeModelId; voice ids go in realtimeModelConfig.voiceModel. One-shot workflow voice: gr workflows update -d '{"realtimeModelId":"xai:realtime:voice-agent-2"}' then publish.`,
7472
7580
  commands: [
7473
7581
  {
7474
7582
  path: ["ai-models", "list"],
@@ -7481,7 +7589,7 @@ var aiModelsDomain = {
7481
7589
  },
7482
7590
  {
7483
7591
  path: ["ai-models", "chat"],
7484
- description: "List chat models",
7592
+ description: "List chat models (use as chatModelId on agents/workflows)",
7485
7593
  requiresWorkspace: false,
7486
7594
  handler: async ({ ctx }) => {
7487
7595
  const result2 = await requireAuth(ctx).apiClient.getChatModels();
@@ -7490,7 +7598,7 @@ var aiModelsDomain = {
7490
7598
  },
7491
7599
  {
7492
7600
  path: ["ai-models", "realtime"],
7493
- description: "List realtime models",
7601
+ description: "List realtime/voice stacks (use as realtimeModelId). e.g. xai:realtime:voice-agent-2 = Grok Voice Think Fast 2",
7494
7602
  requiresWorkspace: false,
7495
7603
  handler: async ({ ctx }) => {
7496
7604
  const result2 = await requireAuth(ctx).apiClient.getRealtimeModels();
@@ -7499,7 +7607,7 @@ var aiModelsDomain = {
7499
7607
  },
7500
7608
  {
7501
7609
  path: ["ai-models", "voice"],
7502
- description: "List voice models",
7610
+ description: "List speaker voices (use as realtimeModelConfig.voiceModel). Match provider to the realtime model (xai:voice:* with xAI realtime)",
7503
7611
  requiresWorkspace: false,
7504
7612
  handler: async ({ ctx }) => {
7505
7613
  const result2 = await requireAuth(ctx).apiClient.getVoiceModels();
@@ -7911,6 +8019,13 @@ var PRODUCT_COLUMNS2 = [
7911
8019
  const days = p.trialPeriodDays ?? 0;
7912
8020
  return days > 0 ? `${days}d` : "\u2014";
7913
8021
  }
8022
+ },
8023
+ // Which plan a flow picks when it cannot ask — the signup funnel's workspace
8024
+ // step, for one. Invisible without this: the flag decides what customers get
8025
+ // started on, so reading the catalogue should show it.
8026
+ {
8027
+ header: "DEFAULT",
8028
+ getValue: (p) => p.isDefault ? "yes" : "\u2014"
7914
8029
  }
7915
8030
  ];
7916
8031
  var SUBSCRIPTION_COLUMNS = [
@@ -7935,10 +8050,6 @@ var CONTRACT_BEARING_STATUSES = /* @__PURE__ */ new Set([
7935
8050
  function isTable(ctx) {
7936
8051
  return (ctx.outputFormat ?? "table") === "table";
7937
8052
  }
7938
- function hint(ctx, lines) {
7939
- if (!isTable(ctx)) return;
7940
- process.stdout.write("\n" + lines.join("\n") + "\n");
7941
- }
7942
8053
  function productType(args) {
7943
8054
  const t = args.type ?? args["product-type"];
7944
8055
  if (t === "org" || t === "workspace") return t;
@@ -9801,7 +9912,41 @@ function simulateInboundRouting(phone, opts = {}) {
9801
9912
  steps.push({ step: "inbound_call_handling", outcome: "play_message" });
9802
9913
  return finish("play_message_hangup", false, false, steps, recommendations, callerRole);
9803
9914
  }
9804
- steps.push({ step: "inbound_call_handling", outcome: "ai_path" });
9915
+ if (inboundCallHandling === "ring_operators") {
9916
+ const operatorGroupId = phone.operatorGroupId;
9917
+ const ringWorkflowId = phone.defaultWorkflowId;
9918
+ if (!operatorGroupId || ringWorkflowId === null || ringWorkflowId === void 0) {
9919
+ steps.push({
9920
+ step: "inbound_call_handling",
9921
+ outcome: "ai_path",
9922
+ detail: "ring_operators skipped \u2014 needs BOTH operatorGroupId and defaultWorkflowId"
9923
+ });
9924
+ recommendations.push(
9925
+ "ring_operators is configured but inert: set operatorGroupId (gr operator-groups list -w $WID) and defaultWorkflowId, or the line silently answers with AI"
9926
+ );
9927
+ } else {
9928
+ const noAnswer = phone.operatorNoAnswerAction ?? "voicemail";
9929
+ const timeout = phone.operatorRingTimeoutSeconds ?? 30;
9930
+ steps.push({
9931
+ step: "inbound_call_handling",
9932
+ outcome: "ring_operators",
9933
+ detail: `group=${operatorGroupId} timeout=${timeout}s no_answer=${noAnswer}`
9934
+ });
9935
+ steps.push({
9936
+ step: "operator_presence",
9937
+ outcome: "runtime_dependent",
9938
+ detail: `live operators are resolved at call time \u2014 not simulatable. If none are live, or none answer within ${timeout}s, the call falls back to: ${noAnswer}`
9939
+ });
9940
+ if (noAnswer === "ai") {
9941
+ recommendations.push(
9942
+ "operatorNoAnswerAction=ai \u2014 an unanswered ring lands on the AI assistant, so callers may reach the AI rather than voicemail"
9943
+ );
9944
+ }
9945
+ return finish("ring_operators", true, true, steps, recommendations, callerRole);
9946
+ }
9947
+ } else {
9948
+ steps.push({ step: "inbound_call_handling", outcome: "ai_path" });
9949
+ }
9805
9950
  const workflowId = phone.defaultWorkflowId;
9806
9951
  if (workflowId === null || workflowId === void 0) {
9807
9952
  steps.push({
@@ -9859,7 +10004,8 @@ function finish(code, createsChat, createsPhoneCall, steps, recommendations, cal
9859
10004
  fax_receive: "Create fax chat + receive document",
9860
10005
  no_inbound_workflow: "Play unavailable message (no inbound workflow)",
9861
10006
  workflow_member_role_denied: "Reject \u2014 caller member role lacks workflow USE (memberRoleAccess)",
9862
- ai_voice_chat: "Create chat + connect AI voice"
10007
+ ai_voice_chat: "Create chat + connect AI voice",
10008
+ ring_operators: "Ring live operators (falls back if none answer)"
9863
10009
  };
9864
10010
  return {
9865
10011
  callerRole: callerRole ?? "unknown",
@@ -14066,7 +14212,7 @@ var widgetDomainsDomain = {
14066
14212
  }
14067
14213
  ],
14068
14214
  examples: [
14069
- "gr widget-domains enable -w $WID --domain <uuid> --widgets chat,operator --allow-write",
14215
+ "gr widget-domains enable -w $WID --domain <uuid> --widgets chat,operator-tools --allow-write",
14070
14216
  "gr widget-domains enable -w $WID --domain <uuid> --widgets chat --allow-subdomains --port 4444 --allow-write"
14071
14217
  ],
14072
14218
  handler: async ({ ctx, workspace, args }) => {
@@ -19390,7 +19536,7 @@ var topLevelCommands = [
19390
19536
  mutates: true,
19391
19537
  args: [{ name: "phone", description: "E.164 phone number (optional; prompts if omitted)" }],
19392
19538
  handler: async (hctx) => {
19393
- const { accountVerifyPhoneCommand } = await import("./account-verify-phone-UA5OUOOR.js");
19539
+ const { accountVerifyPhoneCommand } = await import("./account-verify-phone-Q2NIRSX4.js");
19394
19540
  await accountVerifyPhoneCommand(hctx);
19395
19541
  }
19396
19542
  },