@gravity-rail/cli 0.53.1 → 0.55.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
@@ -33,15 +33,16 @@ import {
33
33
  startAccountPhoneVerify,
34
34
  stderr,
35
35
  unwrapItems
36
- } from "./chunk-FQMZ2EBF.js";
36
+ } from "./chunk-WCMXS5CL.js";
37
37
  import {
38
38
  AGUIClient,
39
39
  formatTimestamp,
40
40
  getErrorMessage,
41
41
  getTextDelta,
42
+ isRecord,
42
43
  performOAuthFlow,
43
44
  selectFromList
44
- } from "./chunk-FSY2BM4J.js";
45
+ } from "./chunk-BQ3WBHSA.js";
45
46
  import {
46
47
  AuthRequiredError,
47
48
  CLIError,
@@ -257,6 +258,9 @@ function commandNeedsJsonBody(cmd, parsedArgs) {
257
258
  }
258
259
  return false;
259
260
  }
261
+ if (cmd.acceptsJsonInput === true) {
262
+ return true;
263
+ }
260
264
  if (parsedArgs.data !== void 0 || parsedArgs.file !== void 0) {
261
265
  return true;
262
266
  }
@@ -1050,7 +1054,7 @@ var CommandRegistry = class {
1050
1054
  lines.push(" Requires: --allow-write");
1051
1055
  }
1052
1056
  const action = cmd.path[cmd.path.length - 1] ?? "";
1053
- const showsJsonHints = action === "create" || action === "update" || cmd.args?.some((a) => a.name === "data" || a.name === "file");
1057
+ const showsJsonHints = action === "create" || action === "update" || cmd.args?.some((a) => a.name === "data");
1054
1058
  if (cmd.args && cmd.args.length > 0) {
1055
1059
  lines.push("", "Arguments:");
1056
1060
  for (const arg of cmd.args) {
@@ -1380,6 +1384,8 @@ Optional
1380
1384
  chatModelConfig (object|null) Chat model overrides (temperature, thinking, \u2026)
1381
1385
  realtimeModelId (string|null) Voice/realtime model (see \`gr ai-models realtime\`)
1382
1386
  e.g. "xai:realtime:voice-agent-2" (Grok Voice Think Fast 2)
1387
+ or opt in to "xai:realtime:voice-agent-3" (Grok Voice
1388
+ 3.0; not yet cleared for strict-routing workflows)
1383
1389
  Native models auto-fill tts=native + default voice when
1384
1390
  realtimeModelConfig is omitted.
1385
1391
  realtimeModelConfig (object|null) Realtime config. Native example:
@@ -1401,6 +1407,10 @@ One-shot workflow voice WITHOUT creating an agent (preferred for "use Grok Voice
1401
1407
  gr workflows update --id <wf> -d '{"realtimeModelId":"xai:realtime:voice-agent-2"}'
1402
1408
  gr workflows publish --workflow-id <wf>
1403
1409
 
1410
+ Opt a workflow into Grok Voice 3.0 (same xAI voices as 2.0; not the default):
1411
+ gr workflows update --id <wf> -d '{"realtimeModelId":"xai:realtime:voice-agent-3"}'
1412
+ gr workflows publish --workflow-id <wf>
1413
+
1404
1414
  List models:
1405
1415
  gr ai-models chat | realtime | voice
1406
1416
  `;
@@ -1430,6 +1440,7 @@ ${AGENT_FIELD_REFERENCE}`,
1430
1440
  ],
1431
1441
  updateExamples: [
1432
1442
  `gr agents update --id 42 -d '{"realtimeModelId":"xai:realtime:voice-agent-2"}'`,
1443
+ `gr agents update --id 42 -d '{"realtimeModelId":"xai:realtime:voice-agent-3"}'`,
1433
1444
  "gr agents update --id 42 --file agent.json"
1434
1445
  ]
1435
1446
  })
@@ -3158,6 +3169,9 @@ Assistant / models (live on the DRAFT revision \u2014 publish to go live)
3158
3169
  update: null = voice off
3159
3170
  One-shot voice example:
3160
3171
  {"realtimeModelId":"xai:realtime:voice-agent-2"}
3172
+ Opt in to Grok Voice 3.0 (not the default; not yet
3173
+ cleared for routingMode "strict"):
3174
+ {"realtimeModelId":"xai:realtime:voice-agent-3"}
3161
3175
  A native model named WITHOUT a config gets
3162
3176
  tts=native + the provider fallback voice
3163
3177
  (xAI \u2192 xai:voice:eve, not cosmo). Explicit config:
@@ -3224,6 +3238,24 @@ var NOTE_COLUMNS = [
3224
3238
  },
3225
3239
  COL.created()
3226
3240
  ];
3241
+ var CONFIG_HEALTH_COLUMNS = [
3242
+ { header: "SEVERITY", getValue: (item) => String(item.severity ?? "") },
3243
+ { header: "CODE", getValue: (item) => String(item.code ?? "") },
3244
+ { header: "SUBJECT", getValue: (item) => String(item.subject?.type ?? "") },
3245
+ {
3246
+ header: "SUBJECT-ID",
3247
+ getValue: (item) => String(item.subject?.id ?? "")
3248
+ },
3249
+ {
3250
+ header: "TASK",
3251
+ getValue: (item) => String(item.remediation?.focus?.taskId ?? "")
3252
+ },
3253
+ {
3254
+ header: "MESSAGE",
3255
+ getValue: (item) => String(item.message ?? ""),
3256
+ maxWidth: 80
3257
+ }
3258
+ ];
3227
3259
  var CONTRIBUTOR_COLUMNS = [
3228
3260
  COL.id(),
3229
3261
  {
@@ -3424,6 +3456,26 @@ var workflowsDomain = {
3424
3456
  outputData(result2, ctx);
3425
3457
  }
3426
3458
  },
3459
+ // Config health (draft revision)
3460
+ {
3461
+ path: ["workflows", "validate-config"],
3462
+ description: "Report the workflow's configuration health issues (draft revision) \u2014 the same findings the editor shows",
3463
+ requiresWorkspace: true,
3464
+ args: [{ name: "id", description: "Workflow ID", required: true }],
3465
+ handler: async ({ ctx, workspace, args }) => {
3466
+ const result2 = await requireAuth(ctx).apiClient.getWorkflowConfigValidation(
3467
+ workspace,
3468
+ requireNumber(args, "id")
3469
+ );
3470
+ if (ctx.outputFormat === "json" || ctx.outputFormat === "jsonl") {
3471
+ outputData(result2, ctx);
3472
+ } else {
3473
+ outputData(result2.configHealthIssues ?? [], ctx, CONFIG_HEALTH_COLUMNS);
3474
+ stderr(`issues=${(result2.configHealthIssues ?? []).length}
3475
+ `);
3476
+ }
3477
+ }
3478
+ },
3427
3479
  // Diagram
3428
3480
  {
3429
3481
  path: ["workflows", "diagram"],
@@ -3894,6 +3946,17 @@ ${WORKFLOW_FIELD_REFERENCE}`,
3894
3946
  import { writeFile } from "fs/promises";
3895
3947
  import { extractWorkspaceExportJson } from "@gravity-rail/sdk/helpers";
3896
3948
 
3949
+ // src/lib/workspace-labels.ts
3950
+ function parseLabelList(value) {
3951
+ if (value === void 0 || value === null || value === false) return [];
3952
+ const raw = Array.isArray(value) ? value.map(String) : [String(value)];
3953
+ const labels = raw.flatMap((entry) => entry.split(",")).map((entry) => entry.trim()).filter((entry) => entry.length > 0);
3954
+ if (labels.length === 0 && raw.some((entry) => entry.trim().length > 0)) {
3955
+ throw new CLIError("--labels must name at least one label");
3956
+ }
3957
+ return labels;
3958
+ }
3959
+
3897
3960
  // src/lib/workspace-timezone.ts
3898
3961
  function normalizeIanaTimeZone(value) {
3899
3962
  const trimmed = value.trim();
@@ -4698,11 +4761,16 @@ var workspacesDomain = {
4698
4761
  {
4699
4762
  name: "timezone",
4700
4763
  description: "IANA time zone (e.g. America/New_York). The create API does not take one, so the command waits for provisioning to finish and then sets it with a follow-up update. Without it the workspace has no timezone and Journey send windows and Routines run in UTC."
4764
+ },
4765
+ {
4766
+ name: "labels",
4767
+ description: "Comma-separated workspace labels to apply right after creation (e.g. production,sponsor-acme). Labels the organization has not used before are created. Webhook endpoints that select on these labels start covering the workspace at once."
4701
4768
  }
4702
4769
  ],
4703
4770
  examples: [
4704
4771
  'gr workspaces create --org <org-uuid> --name "Front Desk"',
4705
- 'gr workspaces create --org <org-uuid> --name "Front Desk" --timezone America/Chicago'
4772
+ 'gr workspaces create --org <org-uuid> --name "Front Desk" --timezone America/Chicago',
4773
+ 'gr workspaces create --org <org-uuid> --name "Front Desk" --labels production,sponsor-acme'
4706
4774
  ],
4707
4775
  handler: async ({ ctx, args }) => {
4708
4776
  const orgUuid = args.org ?? args["org-uuid"];
@@ -4710,6 +4778,7 @@ var workspacesDomain = {
4710
4778
  if (!orgUuid) throw new CLIError("Missing required argument: --org <org-uuid>");
4711
4779
  if (!name) throw new CLIError("Missing required argument: --name");
4712
4780
  const timezone = typeof args.timezone === "string" ? normalizeIanaTimeZone(args.timezone) : void 0;
4781
+ const labels = parseLabelList(args.labels);
4713
4782
  const payload = { name };
4714
4783
  if (args.slug) payload.slug = String(args.slug);
4715
4784
  if (args.template) payload.templateWorkspaceUuid = String(args.template);
@@ -4726,6 +4795,18 @@ var workspacesDomain = {
4726
4795
  }
4727
4796
  throw err;
4728
4797
  }
4798
+ if (labels.length > 0) {
4799
+ try {
4800
+ await client3.setWorkspaceLabels(orgUuid, result2.uuid, { labels });
4801
+ } catch (err) {
4802
+ const reason = err instanceof Error ? err.message : String(err);
4803
+ throw new CLIError(
4804
+ `Workspace ${result2.uuid} was created but its labels were not set: ${reason}
4805
+ Apply them with:
4806
+ gr org workspaces labels set --org ${orgUuid} --workspace-uuid ${result2.uuid} --labels ${labels.join(",")} --allow-write`
4807
+ );
4808
+ }
4809
+ }
4729
4810
  if (timezone) {
4730
4811
  const wsUuid = result2.uuid;
4731
4812
  stderr(`Waiting for workspace ${wsUuid} to finish provisioning...`);
@@ -7242,6 +7323,73 @@ function parseIdList(value) {
7242
7323
  return num;
7243
7324
  });
7244
7325
  }
7326
+ function toGrantEntry(grant) {
7327
+ return { granteeMemberId: grant.granteeMemberId, accessMode: grant.accessMode };
7328
+ }
7329
+ var SHARING_COLUMNS = [
7330
+ { header: "ACCESS", getValue: (item) => item.access },
7331
+ {
7332
+ header: "SHAREABLE",
7333
+ getValue: (item) => String(item.shareable ?? "")
7334
+ },
7335
+ { header: "OWNER", getValue: (item) => String(item.ownerId ?? "") },
7336
+ { header: "GRANTS", getValue: (item) => String(item.grants.length) },
7337
+ {
7338
+ header: "ROLES",
7339
+ getValue: (item) => (item.roleAssociations ?? []).map((role) => role.memberRoleName).join(", ")
7340
+ }
7341
+ ];
7342
+ function sharingCommands(spec) {
7343
+ const { prefix, entityName, getMethod, updateMethod } = spec;
7344
+ const idArg2 = { name: "id", description: `${entityName} ID`, required: true };
7345
+ const cli = ["gr", ...prefix, "sharing"].join(" ");
7346
+ return [
7347
+ {
7348
+ path: [...prefix, "sharing", "get"],
7349
+ description: `Show a ${entityName}'s access level, grants and role associations`,
7350
+ requiresWorkspace: true,
7351
+ args: [idArg2],
7352
+ examples: [`${cli} get -w $WID --id 12`],
7353
+ handler: async ({ ctx, workspace, args }) => {
7354
+ const state = await requireAuth(ctx).apiClient[getMethod](
7355
+ workspace,
7356
+ requireNumber(args, "id")
7357
+ );
7358
+ outputData(state, ctx, SHARING_COLUMNS);
7359
+ }
7360
+ },
7361
+ {
7362
+ path: [...prefix, "sharing", "set"],
7363
+ description: `Change a ${entityName}'s sharing. The API replaces the whole sharing state, so this command reads the current state first and overrides only the keys you pass \u2014 omitting "grants" or "roleAssociations" keeps the existing ones rather than clearing them. Pass them explicitly (e.g. "grants": []) to replace.`,
7364
+ mutates: true,
7365
+ requiresWorkspace: true,
7366
+ args: [idArg2],
7367
+ examples: [
7368
+ `${cli} set -w $WID --id 12 --allow-write -d '{"access":"workspace"}'`,
7369
+ `${cli} set -w $WID --id 12 --allow-write -d '{"access":"private","grants":[]}'`
7370
+ ],
7371
+ handler: async ({ ctx, workspace, args, data }) => {
7372
+ if (data === void 0 || data === null || typeof data !== "object") {
7373
+ throw new CLIError(
7374
+ `Provide the fields to change as JSON via --data, --file, or stdin (e.g. '{"access":"workspace"}')`
7375
+ );
7376
+ }
7377
+ const patch = data;
7378
+ const client3 = requireAuth(ctx).apiClient;
7379
+ const id = requireNumber(args, "id");
7380
+ const current = await client3[getMethod](workspace, id);
7381
+ const next = {
7382
+ access: patch.access ?? current.access,
7383
+ shareable: patch.shareable ?? current.shareable ?? null,
7384
+ grants: patch.grants ?? current.grants.map(toGrantEntry),
7385
+ roleAssociations: patch.roleAssociations ?? current.roleAssociations ?? []
7386
+ };
7387
+ const state = await client3[updateMethod](workspace, id, next);
7388
+ outputData(state, ctx, SHARING_COLUMNS);
7389
+ }
7390
+ }
7391
+ ];
7392
+ }
7245
7393
  var COLUMNS10 = [
7246
7394
  COL.id(),
7247
7395
  COL.name(),
@@ -7403,6 +7551,18 @@ ${FILE_FIELD_REFERENCE}`
7403
7551
  outputData(results, ctx, folderSearchColumns(results));
7404
7552
  }
7405
7553
  },
7554
+ ...sharingCommands({
7555
+ prefix: ["files", "folders"],
7556
+ entityName: "folder",
7557
+ getMethod: "getFolderSharing",
7558
+ updateMethod: "updateFolderSharing"
7559
+ }),
7560
+ ...sharingCommands({
7561
+ prefix: ["files"],
7562
+ entityName: "file",
7563
+ getMethod: "getFileSharing",
7564
+ updateMethod: "updateFileSharing"
7565
+ }),
7406
7566
  // Labels sub-resource
7407
7567
  ...crudCommands({
7408
7568
  prefix: ["files", "labels"],
@@ -9311,7 +9471,7 @@ var OBS_COLUMNS = [
9311
9471
  ];
9312
9472
  var metricsDomain = {
9313
9473
  name: "metrics",
9314
- description: "Customer-defined outcome metrics (CEL expression or LLM rubric) with time-series readout",
9474
+ description: "Customer-defined outcome metrics (CEL expression, LLM rubric, Member cohort count, or an aggregate over Form records) with time-series readout",
9315
9475
  commands: [
9316
9476
  ...crudCommands({
9317
9477
  prefix: ["metrics"],
@@ -9324,14 +9484,16 @@ var metricsDomain = {
9324
9484
  columns: COLUMNS11,
9325
9485
  paginationSupport: "full",
9326
9486
  createExamples: [
9327
- `yarn gr metrics create -w $WID --allow-write --data '{"name":"SMS Channel Rate","metricType":"expression","celExpression":"chat.channel == \\"phone-sms\\"","unit":"rate"}'`,
9328
- `yarn gr metrics create -w $WID --allow-write --data '{"name":"Qualified Engagement","metricType":"rubric","evaluationPrompt":"Did the user show buying intent?","unit":"rate"}'`
9487
+ `yarn gr metrics create -w $WID --allow-write --data '{"name":"SMS Channel Rate","metricType":"expression","celExpression":"chat.channel == \\"phone-sms\\"","unit":"rate","workflowIds":[]}'`,
9488
+ `yarn gr metrics create -w $WID --allow-write --data '{"name":"Qualified Engagement","metricType":"rubric","evaluationPrompt":"Did the user show buying intent?","unit":"rate","workflowIds":[]}'`,
9489
+ `yarn gr metrics create -w $WID --allow-write --data '{"name":"HRV daily average","metricType":"record_aggregate","source":"data_record","sourceConfig":{"record":{"dataType":"daily_readings","aggregation":"avg","field":"record.hrv","dateField":"record.measured_on","groupBy":"record.athlete"}},"targetValue":65}'`,
9490
+ `yarn gr metrics create -w $WID --allow-write --data '{"name":"Open lab results","metricType":"record_aggregate","source":"data_record","sourceConfig":{"record":{"dataType":"lab_results","aggregation":"count","where":{"kind":"compare","field":"record.status","op":"eq","value":"open"}}}}'`
9329
9491
  ],
9330
- createHelp: "Create a metric definition. metricType is expression (CEL) or rubric (LLM). MVP source is chat only."
9492
+ createHelp: `Create a metric definition. metricType is expression (CEL) or rubric (LLM) for one reading per chat (pass workflowIds, [] for every workflow); filter_count for the daily size of a saved Member filter (source "member_filter", kind "gauge", sourceConfig.memberFilterId); or record_aggregate for an aggregate over a Form's records, computed from the records each time the series is read (source "data_record", sourceConfig.record). sourceConfig.record takes dataType (Form id or slug), aggregation (count | countDistinct | sum | avg | min | max), field (record.<fieldSlug>; required for all but count, a number field for sum/avg/min/max), dateField (a date or datetime field, default record.createdAt), where (Query IR predicate, see "yarn gr queries syntax") and groupBy (record.<fieldSlug>, one series per value). A record metric needs records:read to save and to read, and records:admin when it names an adminOnly field.`
9331
9493
  }),
9332
9494
  {
9333
9495
  path: ["metrics", "observations"],
9334
- description: "List raw observations for a metric in a date range (may include PHI reason)",
9496
+ description: "List raw observations for a metric in a date range (may include PHI reason). Not available for record_aggregate metrics, which store none: read their series",
9335
9497
  args: [
9336
9498
  { name: "id", required: true, description: "Metric ID" },
9337
9499
  {
@@ -9369,7 +9531,7 @@ var metricsDomain = {
9369
9531
  },
9370
9532
  {
9371
9533
  path: ["metrics", "series"],
9372
- description: "Time-bucketed aggregation for a metric (numeric only)",
9534
+ description: "Time-bucketed aggregation for a metric. A record_aggregate metric is computed from its Form records on each call and, with groupBy, also returns one series per group",
9373
9535
  args: [
9374
9536
  { name: "id", required: true, description: "Metric ID" },
9375
9537
  {
@@ -9385,7 +9547,7 @@ var metricsDomain = {
9385
9547
  { name: "bucket", description: "day | week (default day)" },
9386
9548
  {
9387
9549
  name: "aggregation",
9388
- description: "avg | sum | count | rate | last | passes (default varies by metric)"
9550
+ description: "avg | sum | count | rate | last | passes (default varies by metric). Omit for a record_aggregate metric: its definition names the aggregation"
9389
9551
  }
9390
9552
  ],
9391
9553
  requiresWorkspace: true,
@@ -9565,8 +9727,10 @@ function buildModelEvalBatchJobs(scenarios, models, rounds, warmup, realtimeMode
9565
9727
  var REALTIME_AUDIO_USD_PER_MIN = {
9566
9728
  "xai:realtime:voice-agent": 0.05,
9567
9729
  // Grok Voice Think Fast 1
9568
- "xai:realtime:voice-agent-2": 0.08
9569
- // Grok Voice Think Fast 2
9730
+ "xai:realtime:voice-agent-2": 0.08,
9731
+ // Grok Voice Think Fast 2 (pinned grok-voice-2.0)
9732
+ "xai:realtime:voice-agent-3": 0.08
9733
+ // Grok Voice 3.0 — same audio rate as 2.0
9570
9734
  };
9571
9735
  var DEFAULT_REALTIME_AUDIO_USD_PER_MIN = 0.08;
9572
9736
  var EST_AUDIO_MIN_PER_RUN = 3;
@@ -10396,6 +10560,87 @@ var qualificationsDomain = {
10396
10560
  ]
10397
10561
  };
10398
10562
 
10563
+ // src/domains/data-reports.ts
10564
+ function parseRecordScope(value) {
10565
+ if (value === void 0) return void 0;
10566
+ if (value === "currentMember" || value === "allRecords") return value;
10567
+ throw new CLIError("--record-scope must be currentMember or allRecords");
10568
+ }
10569
+ function parseParameters(value) {
10570
+ if (value === void 0) return void 0;
10571
+ let parsed;
10572
+ try {
10573
+ parsed = typeof value === "string" ? JSON.parse(value) : value;
10574
+ } catch {
10575
+ throw new CLIError("--parameters must be a JSON object");
10576
+ }
10577
+ if (!isRecord(parsed)) throw new CLIError("--parameters must be a JSON object");
10578
+ const values = {};
10579
+ for (const [name, parameter] of Object.entries(parsed)) {
10580
+ if (typeof parameter !== "boolean" && typeof parameter !== "number" && typeof parameter !== "string") {
10581
+ throw new CLIError(`--parameters value for '${name}' must be a boolean, number or string`);
10582
+ }
10583
+ values[name] = parameter;
10584
+ }
10585
+ return values;
10586
+ }
10587
+ function buildPreviewRequest(data, args) {
10588
+ if (!isRecord(data)) {
10589
+ throw new CLIError("Report JSON required (--data, --file, or stdin)");
10590
+ }
10591
+ let request;
10592
+ if ("report" in data) {
10593
+ if (!isRecord(data.report)) {
10594
+ throw new CLIError("The request's 'report' must be a JSON object");
10595
+ }
10596
+ request = { ...data };
10597
+ } else if ("dataTypeUuid" in data && "query" in data) {
10598
+ request = { report: data };
10599
+ } else {
10600
+ throw new CLIError(
10601
+ "Body must be a request with a 'report' object, or a bare report with dataTypeUuid and query"
10602
+ );
10603
+ }
10604
+ const recordScope = parseRecordScope(args["record-scope"]);
10605
+ if (recordScope) request.recordScope = recordScope;
10606
+ const parameters = parseParameters(args["parameters"]);
10607
+ if (parameters) request.parameters = parameters;
10608
+ return request;
10609
+ }
10610
+ var dataReportsDomain = {
10611
+ name: "data-reports",
10612
+ description: "Form Reports: preview a report as the Agent would run it",
10613
+ commands: [
10614
+ {
10615
+ path: ["data-reports", "preview"],
10616
+ description: "Run a Form Reports report, saved or not, as the signed-in Member and show the rows or groups the Agent would get. Rows return at most 50 per call and aggregates at most 200 groups. Needs the agents:write and records:read scopes.",
10617
+ requiresWorkspace: true,
10618
+ acceptsJsonInput: true,
10619
+ args: [
10620
+ {
10621
+ name: "record-scope",
10622
+ description: "currentMember (default) limits the report to the signed-in Member's records; allRecords covers every record that Member may read",
10623
+ required: false
10624
+ },
10625
+ {
10626
+ name: "parameters",
10627
+ description: `Parameter values as a JSON object, e.g. '{"days":7}'. Omitted parameters use their defaults`,
10628
+ required: false
10629
+ }
10630
+ ],
10631
+ examples: [
10632
+ `yarn gr data-reports preview -w $UUID --record-scope allRecords --parameters '{"days":7}' --file report.json`,
10633
+ `yarn gr data-reports preview -w $UUID --data '{"report":{"name":"recent","description":"Latest rows","dataTypeUuid":"<form uuid>","query":{"sort":[{"field":"record.createdAt","dir":"desc"}],"limit":5}},"recordScope":"allRecords"}'`
10634
+ ],
10635
+ handler: async ({ ctx, workspace, args, data }) => {
10636
+ const request = buildPreviewRequest(data, args);
10637
+ const result2 = await requireAuth(ctx).apiClient.previewDataReport(workspace, request);
10638
+ outputSingle(result2, ctx);
10639
+ }
10640
+ }
10641
+ ]
10642
+ };
10643
+
10399
10644
  // src/domains/queries.ts
10400
10645
  var FIELD_COLUMNS2 = [
10401
10646
  { header: "PATH", getValue: (f) => f.path ?? "" },
@@ -11325,6 +11570,9 @@ var abilitiesDomain = {
11325
11570
  description: "Allow creation before required app connections are configured"
11326
11571
  }
11327
11572
  ],
11573
+ examples: [
11574
+ 'yarn gr abilities enable --ability-type integration:data_reports --workflow-id 12 -w $UUID --data \'{"recordScope":"currentMember","reports":[{"name":"recent_entries","description":"The latest entries for this Member","dataTypeUuid":"<form uuid>","query":{"sort":[{"field":"record.createdAt","dir":"desc"}],"limit":5}}]}\' # Form Reports: no app editor; try a report first with `yarn gr data-reports preview`'
11575
+ ],
11328
11576
  handler: async ({ ctx, workspace, args, data }) => {
11329
11577
  const abilityType = args["ability-type"];
11330
11578
  if (typeof abilityType !== "string") throw new CLIError("--ability-type is required");
@@ -11850,7 +12098,8 @@ var NO_UUID_LOOKUP = /* @__PURE__ */ new Set([
11850
12098
  "import",
11851
12099
  "invoice",
11852
12100
  "workspace_config",
11853
- "data_record"
12101
+ "data_record",
12102
+ "recording"
11854
12103
  ]);
11855
12104
  var HYDRATORS = {
11856
12105
  workspace: async ({ client: client3 }, ref) => (await client3.getWorkspace(ref.uuid)).name,
@@ -12675,7 +12924,7 @@ var aiModelsDomain = {
12675
12924
  },
12676
12925
  {
12677
12926
  path: ["ai-models", "realtime"],
12678
- description: "List realtime/voice stacks (use as realtimeModelId). e.g. xai:realtime:voice-agent-2 = Grok Voice Think Fast 2",
12927
+ description: "List realtime/voice stacks (use as realtimeModelId). e.g. xai:realtime:voice-agent-2 = Grok Voice Think Fast 2 (default); xai:realtime:voice-agent-3 = Grok Voice 3.0 (explicit opt-in)",
12679
12928
  requiresWorkspace: false,
12680
12929
  handler: async ({ ctx }) => {
12681
12930
  const result2 = await requireAuth(ctx).apiClient.getRealtimeModels();
@@ -14788,6 +15037,17 @@ var ORG_WEBHOOK_COLUMNS = [
14788
15037
  header: "WORKSPACES",
14789
15038
  getValue: (item) => item.limitedToWorkspaces ? item.workspaceUuids.join(",") : "all (organization-wide)",
14790
15039
  maxWidth: 80
15040
+ },
15041
+ {
15042
+ // A workspace is covered when it carries ALL of these labels (in
15043
+ // addition to the explicit WORKSPACES).
15044
+ header: "LABELS",
15045
+ getValue: (item) => (item.labelSelector ?? []).map((label) => label.slug).join("+"),
15046
+ maxWidth: 60
15047
+ },
15048
+ {
15049
+ header: "RECENT FAILURES",
15050
+ getValue: (item) => (item.recentFailures ?? []).map((failure) => `${failure.failureClass} (${failure.count})`).join(", ")
14791
15051
  }
14792
15052
  ];
14793
15053
  function requireWebhookEndpointUuid(args) {
@@ -14822,9 +15082,298 @@ function webhookStatusCommand(action) {
14822
15082
  }
14823
15083
  };
14824
15084
  }
15085
+ var ORG_WORKSPACE_COLUMNS = [
15086
+ { header: "UUID", getValue: (item) => item.uuid },
15087
+ { header: "NAME", getValue: (item) => item.name, maxWidth: 40 },
15088
+ { header: "SLUG", getValue: (item) => item.slug },
15089
+ { header: "STATUS", getValue: (item) => String(item.status) },
15090
+ { header: "TIMEZONE", getValue: (item) => item.timezone ?? "-" },
15091
+ { header: "CREATED", getValue: (item) => item.createdAt }
15092
+ ];
15093
+ var orgWorkspaceCommands = [
15094
+ {
15095
+ path: ["org", "workspaces", "list"],
15096
+ description: "List every workspace in an organization, newest page first (read-only). Prefer this over `gr workspaces list --org` for anything fleet-wide: that command reads an unpaginated endpoint and sees only the first page of workspaces. Use --all to fetch the complete list.",
15097
+ requiresWorkspace: false,
15098
+ args: [
15099
+ ORG_UUID_ARG2,
15100
+ { name: "page", description: "Page number (default: 1)" },
15101
+ { name: "page-size", description: "Page size" },
15102
+ { name: "all", description: "Fetch all pages", isFlag: true },
15103
+ { name: "search", description: "Filter by name or slug (server-side)" }
15104
+ ],
15105
+ examples: [
15106
+ "yarn gr org workspaces list --org $ORG_UUID --all",
15107
+ "yarn gr org workspaces list --org $ORG_UUID --search gastro -o json"
15108
+ ],
15109
+ handler: async (hctx) => {
15110
+ const orgRef = requireOrgRef(hctx.args);
15111
+ const pag = parsePaginationArgs(hctx.args);
15112
+ const search = typeof hctx.args.search === "string" ? hctx.args.search : void 0;
15113
+ const client3 = requireAuth(hctx.ctx).apiClient;
15114
+ if (pag.all) {
15115
+ const allItems = await fetchAllPages(
15116
+ ({ page, pageSize }) => client3.getOrganizationWorkspaces(orgRef, {
15117
+ page,
15118
+ pageSize,
15119
+ ...search ? { search } : {}
15120
+ })
15121
+ );
15122
+ outputData(allItems, hctx.ctx, ORG_WORKSPACE_COLUMNS);
15123
+ return;
15124
+ }
15125
+ const options = {};
15126
+ if (pag.page) options.page = pag.page;
15127
+ if (pag.pageSize) options.pageSize = pag.pageSize;
15128
+ if (search) options.search = search;
15129
+ const result2 = await client3.getOrganizationWorkspaces(orgRef, options);
15130
+ outputData(listResult(result2, true), hctx.ctx, ORG_WORKSPACE_COLUMNS);
15131
+ }
15132
+ }
15133
+ ];
15134
+ function requireArg2(args, name) {
15135
+ const value = args[name];
15136
+ if (typeof value !== "string" || !value.trim()) {
15137
+ throw new CLIError(`Missing required argument: --${name}`);
15138
+ }
15139
+ return value.trim();
15140
+ }
15141
+ function optionalArg(args, name) {
15142
+ const value = args[name];
15143
+ if (value === void 0) return void 0;
15144
+ if (typeof value !== "string" || !value.trim()) {
15145
+ throw new CLIError(`Invalid argument: --${name}`);
15146
+ }
15147
+ return value.trim();
15148
+ }
15149
+ var DELIVERY_LOG_COLUMNS = [
15150
+ { header: "EVENT", getValue: (item) => item.eventType },
15151
+ { header: "STATUS", getValue: (item) => item.status },
15152
+ { header: "DEDUPE KEY", getValue: (item) => item.dedupeKey, maxWidth: 48 },
15153
+ { header: "OCCURRED", getValue: (item) => item.occurredAt },
15154
+ { header: "ATTEMPTS", getValue: (item) => String(item.attempts) },
15155
+ { header: "LAST FAILURE", getValue: (item) => item.lastFailureClass || "\u2014" }
15156
+ ];
14825
15157
  var webhookCommands = [
14826
15158
  webhookStatusCommand("pause"),
14827
15159
  webhookStatusCommand("resume"),
15160
+ {
15161
+ path: ["org", "webhooks", "create"],
15162
+ description: "Create an organization webhook endpoint. The signing secret is printed once in this response and is not shown again. Requires organization admin access.",
15163
+ mutates: true,
15164
+ requiresWorkspace: false,
15165
+ args: [
15166
+ ORG_UUID_ARG2,
15167
+ { name: "name", description: "Endpoint name", required: true },
15168
+ { name: "url", description: "HTTPS endpoint URL", required: true },
15169
+ {
15170
+ name: "event-type",
15171
+ description: "Subscribed event type (repeat for more than one)",
15172
+ required: true,
15173
+ repeatable: true
15174
+ },
15175
+ {
15176
+ name: "workspace-uuid",
15177
+ description: "Limit coverage to this workspace (repeatable). Omit to cover every workspace in the organization.",
15178
+ repeatable: true
15179
+ },
15180
+ {
15181
+ name: "signing-secret",
15182
+ description: "Client-supplied signing secret. Omit to have one generated."
15183
+ }
15184
+ ],
15185
+ examples: [
15186
+ 'yarn gr org webhooks create --org $ORG_UUID --name "Rysun" --url https://example.com/hook --event-type data_record.created --allow-write'
15187
+ ],
15188
+ handler: async (hctx) => {
15189
+ const eventTypes = repeatedValues(hctx.args, "event-type");
15190
+ if (eventTypes.length === 0) {
15191
+ throw new CLIError("Missing required argument: --event-type");
15192
+ }
15193
+ const signingSecret = optionalArg(hctx.args, "signing-secret");
15194
+ const created = await requireAuth(hctx.ctx).apiClient.createOrgWebhookEndpoint(
15195
+ requireOrgRef(hctx.args),
15196
+ {
15197
+ name: requireArg2(hctx.args, "name"),
15198
+ url: requireArg2(hctx.args, "url"),
15199
+ eventTypes,
15200
+ workspaceUuids: repeatedValues(hctx.args, "workspace-uuid"),
15201
+ ...signingSecret ? { signingSecret } : {}
15202
+ }
15203
+ );
15204
+ hint(hctx.ctx, ["Signing secret is in this response and is not shown again."]);
15205
+ outputSingle(created, hctx.ctx);
15206
+ }
15207
+ },
15208
+ {
15209
+ path: ["org", "webhooks", "update"],
15210
+ description: "Update an organization webhook endpoint. A rotated signing secret is not echoed. Requires organization admin access.",
15211
+ mutates: true,
15212
+ requiresWorkspace: false,
15213
+ args: [
15214
+ ORG_UUID_ARG2,
15215
+ { name: "endpoint-uuid", aliases: ["id"], description: "Endpoint UUID", required: true },
15216
+ { name: "name", description: "New endpoint name" },
15217
+ { name: "url", description: "New HTTPS endpoint URL" },
15218
+ {
15219
+ name: "event-type",
15220
+ description: "Replace the subscription list (repeat for more than one)",
15221
+ repeatable: true
15222
+ },
15223
+ {
15224
+ name: "workspace-uuid",
15225
+ description: "Replace workspace coverage with this workspace (repeatable)",
15226
+ repeatable: true
15227
+ },
15228
+ {
15229
+ name: "all-workspaces",
15230
+ description: "Cover every workspace in the organization",
15231
+ isFlag: true
15232
+ },
15233
+ { name: "status", description: "active or paused" },
15234
+ {
15235
+ name: "signing-secret",
15236
+ description: "Rotate the signing secret. The new value is not printed."
15237
+ }
15238
+ ],
15239
+ examples: [
15240
+ "yarn gr org webhooks update --org $ORG_UUID --endpoint-uuid $ENDPOINT_UUID --status paused --allow-write"
15241
+ ],
15242
+ handler: async (hctx) => {
15243
+ const workspaceUuids = repeatedValues(hctx.args, "workspace-uuid");
15244
+ const allWorkspaces = hctx.args["all-workspaces"] === true;
15245
+ if (allWorkspaces && workspaceUuids.length > 0) {
15246
+ throw new CLIError("Pass either --all-workspaces or --workspace-uuid, not both");
15247
+ }
15248
+ const eventTypes = repeatedValues(hctx.args, "event-type");
15249
+ const status = optionalArg(hctx.args, "status");
15250
+ if (status !== void 0 && status !== "active" && status !== "paused") {
15251
+ throw new CLIError("--status must be active or paused");
15252
+ }
15253
+ const signingSecret = optionalArg(hctx.args, "signing-secret");
15254
+ const data = {};
15255
+ const name = optionalArg(hctx.args, "name");
15256
+ const url = optionalArg(hctx.args, "url");
15257
+ if (name) data.name = name;
15258
+ if (url) data.url = url;
15259
+ if (eventTypes.length > 0) data.eventTypes = eventTypes;
15260
+ if (allWorkspaces) data.workspaceUuids = [];
15261
+ else if (workspaceUuids.length > 0) data.workspaceUuids = workspaceUuids;
15262
+ if (status) data.status = status;
15263
+ if (signingSecret) data.signingSecret = signingSecret;
15264
+ if (Object.keys(data).length === 0) {
15265
+ throw new CLIError("Nothing to update");
15266
+ }
15267
+ const result2 = await requireAuth(hctx.ctx).apiClient.updateOrgWebhookEndpoint(
15268
+ requireOrgRef(hctx.args),
15269
+ requireWebhookEndpointUuid(hctx.args),
15270
+ data
15271
+ );
15272
+ const { signingSecret: _rotatedSecret, ...printable } = result2;
15273
+ outputSingle(printable, hctx.ctx, ORG_WEBHOOK_COLUMNS);
15274
+ }
15275
+ },
15276
+ {
15277
+ path: ["org", "webhooks", "test-send"],
15278
+ description: "Send one test payload to an endpoint. Writes no delivery row. Requires organization admin access.",
15279
+ mutates: true,
15280
+ requiresWorkspace: false,
15281
+ args: [
15282
+ ORG_UUID_ARG2,
15283
+ { name: "endpoint-uuid", aliases: ["id"], description: "Endpoint UUID", required: true },
15284
+ { name: "event-type", description: "Event type to send", required: true },
15285
+ {
15286
+ name: "payload",
15287
+ description: "JSON object to send instead of the server sample"
15288
+ }
15289
+ ],
15290
+ examples: [
15291
+ "yarn gr org webhooks test-send --org $ORG_UUID --endpoint-uuid $ENDPOINT_UUID --event-type data_record.created --allow-write"
15292
+ ],
15293
+ handler: async (hctx) => {
15294
+ const rawPayload = optionalArg(hctx.args, "payload");
15295
+ let payload;
15296
+ if (rawPayload !== void 0) {
15297
+ let parsed;
15298
+ try {
15299
+ parsed = JSON.parse(rawPayload);
15300
+ } catch {
15301
+ throw new CLIError("--payload must be a JSON object");
15302
+ }
15303
+ if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
15304
+ throw new CLIError("--payload must be a JSON object");
15305
+ }
15306
+ payload = parsed;
15307
+ }
15308
+ const result2 = await requireAuth(hctx.ctx).apiClient.testOrgWebhookEndpoint(
15309
+ requireOrgRef(hctx.args),
15310
+ requireWebhookEndpointUuid(hctx.args),
15311
+ {
15312
+ eventType: requireArg2(hctx.args, "event-type"),
15313
+ ...payload ? { payload } : {}
15314
+ }
15315
+ );
15316
+ outputSingle(result2, hctx.ctx);
15317
+ }
15318
+ },
15319
+ {
15320
+ path: ["org", "webhooks", "deliveries"],
15321
+ description: "Delivery log for one organization webhook endpoint. Event type, status, dedupe key, occurred-at, attempt count, and last failure class. The event envelope is not printed.",
15322
+ requiresWorkspace: false,
15323
+ args: [
15324
+ ORG_UUID_ARG2,
15325
+ { name: "endpoint-uuid", aliases: ["id"], description: "Endpoint UUID", required: true },
15326
+ { name: "limit", description: "Page size (default 50)" }
15327
+ ],
15328
+ examples: ["yarn gr org webhooks deliveries --org $ORG_UUID --endpoint-uuid $ENDPOINT_UUID"],
15329
+ handler: async (hctx) => {
15330
+ const limitRaw = optionalArg(hctx.args, "limit");
15331
+ let limit = 50;
15332
+ if (limitRaw !== void 0) {
15333
+ limit = Number(limitRaw);
15334
+ if (!Number.isInteger(limit) || limit < 1) {
15335
+ throw new CLIError("--limit must be a positive integer");
15336
+ }
15337
+ }
15338
+ const page = await requireAuth(hctx.ctx).apiClient.listOrgWebhookEndpointDeliveries(
15339
+ requireOrgRef(hctx.args),
15340
+ requireWebhookEndpointUuid(hctx.args),
15341
+ limit
15342
+ );
15343
+ const rows = page.items.map((item) => {
15344
+ const latest = item.attempts.at(-1);
15345
+ return {
15346
+ eventType: item.eventType,
15347
+ status: item.status,
15348
+ dedupeKey: item.dedupeKey,
15349
+ occurredAt: item.occurredAt,
15350
+ attempts: item.attempts.length,
15351
+ lastFailureClass: latest?.failureClass ?? latest?.errorType ?? ""
15352
+ };
15353
+ });
15354
+ outputData(rows, hctx.ctx, DELIVERY_LOG_COLUMNS);
15355
+ }
15356
+ },
15357
+ {
15358
+ path: ["org", "webhooks", "discard-pending"],
15359
+ description: "Expire a paused or disabled endpoint's pending deliveries so a resume does not re-send a backlog the receiver keeps rejecting. Dead-lettered deliveries are untouched; expired ones stay replayable. Requires organization admin access.",
15360
+ mutates: true,
15361
+ requiresWorkspace: false,
15362
+ args: [
15363
+ ORG_UUID_ARG2,
15364
+ { name: "endpoint-uuid", aliases: ["id"], description: "Endpoint UUID", required: true }
15365
+ ],
15366
+ examples: [
15367
+ "yarn gr org webhooks discard-pending --org $ORG_UUID --endpoint-uuid $ENDPOINT_UUID --allow-write"
15368
+ ],
15369
+ handler: async (hctx) => {
15370
+ const result2 = await requireAuth(hctx.ctx).apiClient.discardPendingOrgWebhookDeliveries(
15371
+ requireOrgRef(hctx.args),
15372
+ requireWebhookEndpointUuid(hctx.args)
15373
+ );
15374
+ outputSingle(result2, hctx.ctx);
15375
+ }
15376
+ },
14828
15377
  {
14829
15378
  path: ["org", "webhooks", "list"],
14830
15379
  description: "List an organization's webhook endpoints (read-only). Each row carries the destination host fingerprint and a masked signing secret, never the URL or a usable secret.",
@@ -14857,9 +15406,93 @@ var webhookCommands = [
14857
15406
  }
14858
15407
  }
14859
15408
  ];
15409
+ var WORKSPACE_LABEL_COLUMNS = [
15410
+ { header: "SLUG", getValue: (item) => item.slug },
15411
+ { header: "NAME", getValue: (item) => item.name },
15412
+ { header: "WORKSPACES", getValue: (item) => String(item.workspaceCount) },
15413
+ { header: "WEBHOOK SELECTORS", getValue: (item) => String(item.webhookSelectorCount) },
15414
+ { header: "UUID", getValue: (item) => item.uuid }
15415
+ ];
15416
+ var LABEL_SUMMARY_COLUMNS = [
15417
+ { header: "SLUG", getValue: (item) => item.slug },
15418
+ { header: "NAME", getValue: (item) => item.name },
15419
+ { header: "UUID", getValue: (item) => item.uuid }
15420
+ ];
15421
+ function requireWorkspaceUuidArg(args) {
15422
+ const value = args["workspace-uuid"] ?? args.workspace;
15423
+ if (typeof value !== "string" || !value.trim()) {
15424
+ throw new CLIError("Missing required argument: --workspace-uuid");
15425
+ }
15426
+ return value.trim();
15427
+ }
15428
+ var WORKSPACE_UUID_ARG = {
15429
+ name: "workspace-uuid",
15430
+ aliases: ["workspace"],
15431
+ description: "Workspace UUID (a workspace of this organization)",
15432
+ required: true
15433
+ };
15434
+ var workspaceLabelCommands = [
15435
+ {
15436
+ path: ["org", "labels", "list"],
15437
+ description: "List the organization's workspace labels, with how many workspaces carry each and how many webhook label selectors require it",
15438
+ requiresWorkspace: false,
15439
+ args: [ORG_UUID_ARG2],
15440
+ examples: ["yarn gr org labels list --org $ORG_UUID -o json"],
15441
+ handler: async (hctx) => {
15442
+ const result2 = await requireAuth(hctx.ctx).apiClient.listWorkspaceLabels(
15443
+ requireOrgRef(hctx.args)
15444
+ );
15445
+ outputData(result2, hctx.ctx, WORKSPACE_LABEL_COLUMNS);
15446
+ }
15447
+ },
15448
+ {
15449
+ path: ["org", "workspaces", "labels", "get"],
15450
+ description: "Show the labels one workspace of the organization carries",
15451
+ requiresWorkspace: false,
15452
+ args: [ORG_UUID_ARG2, WORKSPACE_UUID_ARG],
15453
+ examples: [
15454
+ "yarn gr org workspaces labels get --org $ORG_UUID --workspace-uuid $WORKSPACE_UUID -o json"
15455
+ ],
15456
+ handler: async (hctx) => {
15457
+ const result2 = await requireAuth(hctx.ctx).apiClient.getWorkspaceLabels(
15458
+ requireOrgRef(hctx.args),
15459
+ requireWorkspaceUuidArg(hctx.args)
15460
+ );
15461
+ outputData(result2.labels, hctx.ctx, LABEL_SUMMARY_COLUMNS);
15462
+ }
15463
+ },
15464
+ {
15465
+ path: ["org", "workspaces", "labels", "set"],
15466
+ description: "Replace a workspace's labels with exactly the given set. Requires organization admin access. Labels the organization has not used before are created. Webhook endpoints selecting on these labels start or stop covering the workspace immediately.",
15467
+ mutates: true,
15468
+ requiresWorkspace: false,
15469
+ args: [
15470
+ ORG_UUID_ARG2,
15471
+ WORKSPACE_UUID_ARG,
15472
+ {
15473
+ name: "labels",
15474
+ description: "Comma-separated label slugs; pass an empty string to remove all labels",
15475
+ required: true
15476
+ }
15477
+ ],
15478
+ examples: [
15479
+ "yarn gr org workspaces labels set --org $ORG_UUID --workspace-uuid $WORKSPACE_UUID --labels production,sponsor-acme --allow-write"
15480
+ ],
15481
+ handler: async (hctx) => {
15482
+ const raw = hctx.args.labels;
15483
+ if (raw === void 0) throw new CLIError("Missing required argument: --labels");
15484
+ const result2 = await requireAuth(hctx.ctx).apiClient.setWorkspaceLabels(
15485
+ requireOrgRef(hctx.args),
15486
+ requireWorkspaceUuidArg(hctx.args),
15487
+ { labels: raw === "" ? [] : parseLabelList(raw) }
15488
+ );
15489
+ outputData(result2.labels, hctx.ctx, LABEL_SUMMARY_COLUMNS);
15490
+ }
15491
+ }
15492
+ ];
14860
15493
  var orgDomain = {
14861
15494
  name: "org",
14862
- description: "Organization membership, domains, and webhook endpoints",
15495
+ description: "Organization membership, domains, webhook endpoints, and workspace labels",
14863
15496
  commands: [
14864
15497
  {
14865
15498
  path: ["org", "list"],
@@ -14884,7 +15517,9 @@ var orgDomain = {
14884
15517
  }
14885
15518
  },
14886
15519
  ...domainCommands,
15520
+ ...orgWorkspaceCommands,
14887
15521
  ...webhookCommands,
15522
+ ...workspaceLabelCommands,
14888
15523
  orgMemberUpdateCommand()
14889
15524
  ]
14890
15525
  };
@@ -20528,6 +21163,71 @@ var ENCOUNTER_RUN_COLUMNS = [
20528
21163
  getValue: (item) => summarizeReasons(item.attribution?.collections, "errorReasonCounts")
20529
21164
  }
20530
21165
  ];
21166
+ var ONBOARDING_START_COLUMNS = [
21167
+ { header: "MODE", getValue: (item) => item.mode ?? "" },
21168
+ { header: "WORKFLOW ID", getValue: (item) => item.workflowId ?? "" },
21169
+ { header: "RUN ID", getValue: (item) => item.runId ?? "" }
21170
+ ];
21171
+ var ONBOARDING_PAIR_COLUMNS = [
21172
+ { header: "DEPARTMENT", getValue: (item) => String(item.departmentId ?? "") },
21173
+ { header: "PATIENT STATUS", getValue: (item) => item.patientStatus ?? "" },
21174
+ { header: "STATUS", getValue: (item) => item.status ?? "" },
21175
+ { header: "STOP REASON", getValue: (item) => item.stopReason ?? "" },
21176
+ { header: "GEN", getValue: (item) => String(item.generation ?? "") },
21177
+ { header: "NEXT OFFSET", getValue: (item) => String(item.nextOffset ?? "") },
21178
+ { header: "PAGES (RUN)", getValue: (item) => String(item.pagesDone ?? 0) },
21179
+ { header: "~FETCHED", getValue: (item) => String(item.totals?.fetched ?? 0) },
21180
+ { header: "~APPLIED", getValue: (item) => String(item.totals?.applied ?? 0) },
21181
+ { header: "~SKIPPED", getValue: (item) => String(item.totals?.skipped ?? 0) },
21182
+ { header: "~FAILED", getValue: (item) => String(item.totals?.failed ?? 0) },
21183
+ { header: "RUN ID", getValue: (item) => item.runId ?? "" }
21184
+ ];
21185
+ var RESUMABLE_PAIR_STATUSES = /* @__PURE__ */ new Set([
21186
+ "failed",
21187
+ "aborted",
21188
+ "truncated",
21189
+ "pending",
21190
+ "running",
21191
+ "waiting"
21192
+ ]);
21193
+ function onboardingStatusLines(status, connectionId) {
21194
+ const lines = [];
21195
+ const execution = status.execution;
21196
+ if (execution) {
21197
+ const failure = execution.failureCode ? ` (failure: ${execution.failureCode})` : "";
21198
+ lines.push(
21199
+ `Temporal execution: ${execution.workflowId} run ${execution.runId ?? "-"} \u2014 ${execution.status}${failure}`
21200
+ );
21201
+ } else {
21202
+ lines.push("Temporal execution: none recorded");
21203
+ }
21204
+ if (status.waitingUntil) {
21205
+ lines.push(
21206
+ `Waiting for the operator window (21:00\u201308:00 America/New_York) until ${status.waitingUntil}`
21207
+ );
21208
+ }
21209
+ if (status.preview) {
21210
+ const previewPairs = status.preview.pairs ?? [];
21211
+ const admitted = previewPairs.reduce((n, p) => n + (p.totals?.admitted ?? 0), 0);
21212
+ const notAdmitted = previewPairs.reduce(
21213
+ (n, p) => n + (p.totals?.notAdmitted ?? 0),
21214
+ 0
21215
+ );
21216
+ lines.push(
21217
+ `Latest preview: ${previewPairs.length} pair(s), ~${admitted} admission-eligible (incl. already-linked), ~${notAdmitted} not admitted (read-only)`
21218
+ );
21219
+ }
21220
+ lines.push("Counts are approximate.");
21221
+ const unfinished = (status.pairs ?? []).some(
21222
+ (p) => p.inCurrentCohort && RESUMABLE_PAIR_STATUSES.has(p.status) && p.runId
21223
+ );
21224
+ if (unfinished && execution?.status !== "running") {
21225
+ lines.push(
21226
+ `Unfinished pairs continue only on an explicit resume: gr fhir-connections onboarding-import start --id ${connectionId} --resume --allow-write`
21227
+ );
21228
+ }
21229
+ return lines;
21230
+ }
20531
21231
  var fhirConnectionsDomain = {
20532
21232
  name: "fhir-connections",
20533
21233
  description: "Manage FHIR connections",
@@ -20573,8 +21273,8 @@ var fhirConnectionsDomain = {
20573
21273
  ],
20574
21274
  examples: [
20575
21275
  "fhir-connections encounter-sync runs --id 12",
20576
- "fhir-connections encounter-sync runs --id 12 --output json",
20577
- "fhir-connections encounter-sync runs --id 12 --limit 5 --output json"
21276
+ "fhir-connections encounter-sync runs --id 12 --output-format json",
21277
+ "fhir-connections encounter-sync runs --id 12 --limit 5 --output-format json"
20578
21278
  ],
20579
21279
  handler: async ({ ctx, workspace, args }) => {
20580
21280
  const limit = args["limit"] ? Number(args["limit"]) : 20;
@@ -20585,6 +21285,77 @@ var fhirConnectionsDomain = {
20585
21285
  );
20586
21286
  outputData(runs, ctx, ENCOUNTER_RUN_COLUMNS);
20587
21287
  }
21288
+ },
21289
+ {
21290
+ // athenahealth onboarding import (PR-C): one explicit, audited
21291
+ // operator execution per connection, at most 50 pages per pair per
21292
+ // run. Thin over the SDK; the server decides everything.
21293
+ path: ["fhir-connections", "onboarding-import", "start"],
21294
+ description: "Start an athenahealth onboarding import (or --resume / --override / --dry-run preview)",
21295
+ requiresWorkspace: true,
21296
+ mutates: true,
21297
+ args: [
21298
+ { name: "id", description: "FHIR connection ID", required: true },
21299
+ {
21300
+ name: "dry-run",
21301
+ description: "Preview: read and classify admission only, write no Members",
21302
+ isFlag: true
21303
+ },
21304
+ {
21305
+ name: "resume",
21306
+ description: "Continue unfinished (failed, truncated, aborted) pairs at their stored frontier",
21307
+ isFlag: true
21308
+ },
21309
+ {
21310
+ name: "override",
21311
+ description: "Rescan completed pairs from offset 0 under a new generation",
21312
+ isFlag: true
21313
+ }
21314
+ ],
21315
+ examples: [
21316
+ "fhir-connections onboarding-import start --id 12 --dry-run --allow-write",
21317
+ "fhir-connections onboarding-import start --id 12 --allow-write",
21318
+ "fhir-connections onboarding-import start --id 12 --resume --allow-write"
21319
+ ],
21320
+ handler: async ({ ctx, workspace, args }) => {
21321
+ const connectionId = requireNumber(args, "id");
21322
+ const started = await requireAuth(ctx).apiClient.fhirStartOnboardingImport(
21323
+ workspace,
21324
+ connectionId,
21325
+ {
21326
+ dryRun: args["dry-run"] === true,
21327
+ resume: args["resume"] === true,
21328
+ override: args["override"] === true
21329
+ }
21330
+ );
21331
+ outputSingle(started, ctx, ONBOARDING_START_COLUMNS);
21332
+ hint(ctx, [
21333
+ `Started. Follow progress with: gr fhir-connections onboarding-import status --id ${connectionId}`
21334
+ ]);
21335
+ }
21336
+ },
21337
+ {
21338
+ path: ["fhir-connections", "onboarding-import", "status"],
21339
+ description: "Show athenahealth onboarding-import progress and its Temporal execution (read-only)",
21340
+ requiresWorkspace: true,
21341
+ args: [{ name: "id", description: "FHIR connection ID", required: true }],
21342
+ examples: [
21343
+ "fhir-connections onboarding-import status --id 12",
21344
+ "fhir-connections onboarding-import status --id 12 --output-format json"
21345
+ ],
21346
+ handler: async ({ ctx, workspace, args }) => {
21347
+ const connectionId = requireNumber(args, "id");
21348
+ const status = await requireAuth(ctx).apiClient.fhirGetOnboardingImportStatus(
21349
+ workspace,
21350
+ connectionId
21351
+ );
21352
+ if (ctx.jq || (ctx.outputFormat ?? "table") !== "table") {
21353
+ outputSingle(status, ctx);
21354
+ return;
21355
+ }
21356
+ outputData(status.pairs, ctx, ONBOARDING_PAIR_COLUMNS);
21357
+ hint(ctx, onboardingStatusLines(status, connectionId));
21358
+ }
20588
21359
  }
20589
21360
  ]
20590
21361
  };
@@ -20920,15 +21691,18 @@ var hubspotDomain = {
20920
21691
  mutates: true,
20921
21692
  requiresWorkspace: true,
20922
21693
  examples: [
20923
- "# HubSpot setup is a 4-step flow \u2014 this command is step 1:",
21694
+ "# When the response shows platformAppAvailable=true, the workspace connects through",
21695
+ "# the shared Gravity Rail HubSpot app: install, then authorize. That's all.",
21696
+ "gr hubspot install -w <ws> --allow-write",
21697
+ "gr hubspot authorize -w <ws> --allow-write # then open the returned authorizeUrl",
21698
+ "",
21699
+ "# To use your own HubSpot app instead (a Projects-platform app; HubSpot no longer",
21700
+ "# allows new private or developer apps):",
20924
21701
  '# 1. install -> creates the connection; the response includes the OAuth "callbackUrl"',
20925
- "# 2. in HubSpot: create a private/developer app whose Redirect URL is that callbackUrl,",
20926
- "# with CRM scopes (contacts/companies/deals read+write). Copy the Client ID + Secret.",
21702
+ "# 2. in HubSpot: give your app that callbackUrl as a Redirect URL, with CRM scopes",
21703
+ "# (contacts/companies/deals read+write). Copy the Client ID + Secret.",
20927
21704
  "# 3. configure -> save that Client ID / Secret",
20928
- '# 4. authorize -> returns an "authorizeUrl"; open it to grant access. status then',
20929
- "# reports configured=true and connected=true.",
20930
- "",
20931
- "gr hubspot install -w <ws> --allow-write",
21705
+ '# 4. authorize -> returns an "authorizeUrl"; open it to grant access.',
20932
21706
  "gr hubspot status -w <ws> # read back callbackUrl + configured/connected",
20933
21707
  `gr hubspot configure -w <ws> --allow-write -d '{"clientId":"...","clientSecret":"..."}'`,
20934
21708
  "gr hubspot authorize -w <ws> --allow-write # then open the returned authorizeUrl"
@@ -21939,6 +22713,7 @@ function registerPublicDomains(registry) {
21939
22713
  registry.register(calendarsDomain);
21940
22714
  registry.register(qualificationsDomain);
21941
22715
  registry.register(queriesDomain);
22716
+ registry.register(dataReportsDomain);
21942
22717
  registry.register(personasDomain);
21943
22718
  registry.register(metricsDomain);
21944
22719
  registry.register(journeysDomain);
@@ -26429,7 +27204,7 @@ var topLevelCommands = [
26429
27204
  mutates: true,
26430
27205
  args: [{ name: "phone", description: "E.164 phone number (optional; prompts if omitted)" }],
26431
27206
  handler: async (hctx) => {
26432
- const { accountVerifyPhoneCommand } = await import("./account-verify-phone-ABHHHGCC.js");
27207
+ const { accountVerifyPhoneCommand } = await import("./account-verify-phone-4ZN7NJGW.js");
26433
27208
  await accountVerifyPhoneCommand(hctx);
26434
27209
  }
26435
27210
  },