@gravity-rail/cli 0.7.2 → 0.8.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/gr.js CHANGED
@@ -1,18 +1,22 @@
1
1
  #!/usr/bin/env node
2
- import { createRequire } from 'module';
2
+ import { createRequire } from 'node:module';
3
+ import { fileURLToPath } from 'node:url';
4
+ import { dirname } from 'node:path';
3
5
  import fs, { readFileSync, existsSync, mkdirSync, writeFileSync, createWriteStream, chmodSync, unlinkSync } from 'fs';
4
- import path3, { join, resolve, dirname } from 'path';
6
+ import path3, { join, resolve, dirname as dirname$1 } from 'path';
5
7
  import { createServer } from 'http';
6
- import { randomBytes, createHash } from 'crypto';
8
+ import { randomUUID, randomBytes, createHash } from 'crypto';
7
9
  import { execSync, execFile, exec, spawn, spawnSync } from 'child_process';
8
10
  import * as readline from 'readline';
9
11
  import readline__default from 'readline';
10
12
  import os, { homedir } from 'os';
11
- import * as readline6 from 'readline/promises';
13
+ import * as readline5 from 'readline/promises';
12
14
  import { stdout, stdin } from 'process';
13
15
  import { EventEmitter } from 'events';
14
16
 
15
17
  const require$1 = createRequire(import.meta.url);
18
+ const __filename$1 = fileURLToPath(import.meta.url);
19
+ dirname(__filename$1);
16
20
 
17
21
  var __create = Object.create;
18
22
  var __defProp = Object.defineProperty;
@@ -73,6 +77,16 @@ function handleError(err) {
73
77
  process.stderr.write(
74
78
  `
75
79
  Hint: Run "gr login" to authenticate, or set GRAVITY_RAIL_API_KEY for non-interactive use.
80
+ `
81
+ );
82
+ }
83
+ if ("statusCode" in err && err.statusCode === 403 && process.env.GRAVITY_RAIL_SANDBOX === "1") {
84
+ process.stderr.write(
85
+ `
86
+ Hint: This is a write/admin operation and the sandbox token lacks the required scope.
87
+ Re-run the exec tool with the needed write scope, e.g.:
88
+ exec(code="<your gr command>", language="bash", scopes=["datatypes:write"])
89
+ Common scopes: datatypes:write, workflows:write, members:write, automations:admin, agents:write
76
90
  `
77
91
  );
78
92
  }
@@ -2671,7 +2685,7 @@ var init_libphonenumber_js = __esm({
2671
2685
  }
2672
2686
  });
2673
2687
 
2674
- // ../sdk/dist/chunk-WXSLDWIA.js
2688
+ // ../sdk/dist/chunk-ML55PVP7.js
2675
2689
  function getCookieValue(name) {
2676
2690
  if (typeof document === "undefined") return void 0;
2677
2691
  const cookies = document.cookie.split(";");
@@ -2725,6 +2739,41 @@ function sanitizePhoneForBackend(phoneNumber) {
2725
2739
  }
2726
2740
  return phoneNumber;
2727
2741
  }
2742
+ function isUuid(value) {
2743
+ return /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(value);
2744
+ }
2745
+ async function dataToBytes(data) {
2746
+ if (typeof data === "string") {
2747
+ return new TextEncoder().encode(data);
2748
+ }
2749
+ if (data instanceof Uint8Array) {
2750
+ return data;
2751
+ }
2752
+ if (data instanceof ArrayBuffer) {
2753
+ return new Uint8Array(data);
2754
+ }
2755
+ if (ArrayBuffer.isView(data)) {
2756
+ return new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
2757
+ }
2758
+ if (typeof Blob !== "undefined" && data instanceof Blob) {
2759
+ return new Uint8Array(await data.arrayBuffer());
2760
+ }
2761
+ throw new Error("Unsupported file data type");
2762
+ }
2763
+ function bytesToBase64(bytes) {
2764
+ if (typeof btoa === "function") {
2765
+ const chunkSize = 32768;
2766
+ let binary = "";
2767
+ for (let i = 0; i < bytes.length; i += chunkSize) {
2768
+ binary += String.fromCharCode(...bytes.subarray(i, i + chunkSize));
2769
+ }
2770
+ return btoa(binary);
2771
+ }
2772
+ if (typeof Buffer !== "undefined") {
2773
+ return Buffer.from(bytes).toString("base64");
2774
+ }
2775
+ throw new Error("No base64 encoder is available in this runtime");
2776
+ }
2728
2777
  function getOAuthPath(providerSlug, action) {
2729
2778
  if (providerSlug === "google_calendar") {
2730
2779
  return `oauth/google/calendar/${action}`;
@@ -2822,6 +2871,22 @@ function createApiModules(apiKey, baseUrl3, customFetch) {
2822
2871
  workspaces: new WorkspacesApi(apiKey, baseUrl3, customFetch)
2823
2872
  };
2824
2873
  }
2874
+ function createWorkspaceClient(root, workspaceUuid) {
2875
+ return new Proxy(
2876
+ { root, workspaceUuid },
2877
+ {
2878
+ get(target, prop, receiver) {
2879
+ if (prop in target) return Reflect.get(target, prop, receiver);
2880
+ if (typeof prop !== "string" || !WORKSPACE_METHOD_NAME_SET.has(prop)) {
2881
+ return void 0;
2882
+ }
2883
+ const value = root[prop];
2884
+ if (typeof value !== "function") return void 0;
2885
+ return (...args) => value.call(root, workspaceUuid, ...args);
2886
+ }
2887
+ }
2888
+ );
2889
+ }
2825
2890
  function bindAccessGrantsMethods(target, accessGrants) {
2826
2891
  target.getMyReceivedGrants = accessGrants.getMyReceivedGrants.bind(accessGrants);
2827
2892
  target.getMyGivenGrants = accessGrants.getMyGivenGrants.bind(accessGrants);
@@ -2846,6 +2911,8 @@ function bindAgentsMethods(target, agents) {
2846
2911
  target.deleteAgent = agents.deleteAgent.bind(agents);
2847
2912
  target.archiveAgent = agents.archiveAgent.bind(agents);
2848
2913
  target.unarchiveAgent = agents.unarchiveAgent.bind(agents);
2914
+ target.resolveAgentTools = agents.resolveAgentTools.bind(agents);
2915
+ target.listAgentAbilities = agents.listAgentAbilities.bind(agents);
2849
2916
  }
2850
2917
  function bindTasksMethods(target, tasks, abilities) {
2851
2918
  target.getTasks = tasks.getTasks.bind(tasks);
@@ -2857,6 +2924,11 @@ function bindTasksMethods(target, tasks, abilities) {
2857
2924
  target.unarchiveTask = tasks.unarchiveTask.bind(tasks);
2858
2925
  target.cloneTask = tasks.cloneTask.bind(tasks);
2859
2926
  target.getAbilityTypes = abilities.getAbilityTypes.bind(abilities);
2927
+ target.getAbilityType = abilities.getAbilityType.bind(abilities);
2928
+ target.listAbilities = abilities.listAbilities.bind(abilities);
2929
+ target.createAbility = abilities.createAbility.bind(abilities);
2930
+ target.updateAbility = abilities.updateAbility.bind(abilities);
2931
+ target.deleteAbility = abilities.deleteAbility.bind(abilities);
2860
2932
  }
2861
2933
  function bindChatsMethods(target, chats) {
2862
2934
  target.getChats = chats.getChats.bind(chats);
@@ -2904,6 +2976,7 @@ function bindChatsMethods(target, chats) {
2904
2976
  target.getChatFilterCount = chats.getChatFilterCount.bind(chats);
2905
2977
  }
2906
2978
  function bindCallsMethods(target, calls, cel) {
2979
+ target.getPhoneCalls = calls.getPhoneCalls.bind(calls);
2907
2980
  target.initiateCall = calls.initiateCall.bind(calls);
2908
2981
  target.getVoiceToken = calls.getVoiceToken.bind(calls);
2909
2982
  target.getMessageTiming = calls.getMessageTiming.bind(calls);
@@ -2912,6 +2985,7 @@ function bindCallsMethods(target, calls, cel) {
2912
2985
  function bindDataTypesMethods(target, dataTypes) {
2913
2986
  target.getDataTypes = dataTypes.getDataTypes.bind(dataTypes);
2914
2987
  target.getDataType = dataTypes.getDataType.bind(dataTypes);
2988
+ target.getDataTypeByUuid = dataTypes.getDataTypeByUuid.bind(dataTypes);
2915
2989
  target.getDataTypeBySlug = dataTypes.getDataTypeBySlug.bind(dataTypes);
2916
2990
  target.createDataType = dataTypes.createDataType.bind(dataTypes);
2917
2991
  target.updateDataType = dataTypes.updateDataType.bind(dataTypes);
@@ -3138,6 +3212,7 @@ function bindFilesMethods(target, files) {
3138
3212
  target.getFiles = files.getFiles.bind(files);
3139
3213
  target.getFile = files.getFile.bind(files);
3140
3214
  target.createFile = files.createFile.bind(files);
3215
+ target.uploadFile = files.uploadFile.bind(files);
3141
3216
  target.updateFile = files.updateFile.bind(files);
3142
3217
  target.deleteFile = files.deleteFile.bind(files);
3143
3218
  target.convertFile = files.convertFile.bind(files);
@@ -3378,6 +3453,8 @@ function bindBillingMethods(target, apiKeys, subscriptions, reports) {
3378
3453
  target.updateSubscription = subscriptions.updateSubscription.bind(subscriptions);
3379
3454
  target.addWorkspaceToSubscription = subscriptions.addWorkspaceToSubscription.bind(subscriptions);
3380
3455
  target.purchaseCredits = subscriptions.purchaseCredits.bind(subscriptions);
3456
+ target.createCheckoutSession = subscriptions.createCheckoutSession.bind(subscriptions);
3457
+ target.listSelfServeProducts = subscriptions.listSelfServeProducts.bind(subscriptions);
3381
3458
  target.getAIUsageReport = reports.getAIUsageReport.bind(reports);
3382
3459
  target.getSMSUsageReport = reports.getSMSUsageReport.bind(reports);
3383
3460
  target.getPhoneUsageReport = reports.getPhoneUsageReport.bind(reports);
@@ -3571,6 +3648,7 @@ function bindIntegrationsMethods(target, mondayIntegration, discordBots, slackAp
3571
3648
  target.updatePlatformApp = appConnections.updatePlatformApp.bind(appConnections);
3572
3649
  target.deletePlatformApp = appConnections.deletePlatformApp.bind(appConnections);
3573
3650
  target.listConnectionMemberFieldKeys = appConnections.listConnectionMemberFieldKeys.bind(appConnections);
3651
+ target.setDefaultGooglePlatformAccount = appConnections.setDefaultGooglePlatformAccount.bind(appConnections);
3574
3652
  }
3575
3653
  function bindOperatorMethods(target, operatorGroups) {
3576
3654
  target.getOperatorGroups = operatorGroups.getOperatorGroups.bind(operatorGroups);
@@ -3604,6 +3682,8 @@ function bindOrgMethods(target, org) {
3604
3682
  target.updateBusinessProfile = org.updateBusinessProfile.bind(org);
3605
3683
  target.submitBusinessProfile = org.submitBusinessProfile.bind(org);
3606
3684
  target.cancelBusinessProfile = org.cancelBusinessProfile.bind(org);
3685
+ target.createOrganizationWorkspace = org.createOrganizationWorkspace.bind(org);
3686
+ target.getOrgBillingCustomer = org.getOrgBillingCustomer.bind(org);
3607
3687
  }
3608
3688
  function bindPronunciationsMethods(target, pronunciations) {
3609
3689
  target.getPronunciationEntries = pronunciations.getPronunciationEntries.bind(pronunciations);
@@ -3642,6 +3722,10 @@ function bindJourneysMethods(target, journeys) {
3642
3722
  target.reenrollMember = journeys.reenrollMember.bind(journeys);
3643
3723
  target.deleteEnrollment = journeys.deleteEnrollment.bind(journeys);
3644
3724
  target.getMemberJourneys = journeys.getMemberJourneys.bind(journeys);
3725
+ target.getStepMembers = journeys.getStepMembers.bind(journeys);
3726
+ target.getStepMemberCounts = journeys.getStepMemberCounts.bind(journeys);
3727
+ target.advanceStep = journeys.advanceStep.bind(journeys);
3728
+ target.skipStep = journeys.skipStep.bind(journeys);
3645
3729
  target.testRunJourney = journeys.testRunJourney.bind(journeys);
3646
3730
  target.getJourneyNotes = journeys.getJourneyNotes.bind(journeys);
3647
3731
  target.createJourneyNote = journeys.createJourneyNote.bind(journeys);
@@ -3711,9 +3795,9 @@ function bindSupportRequestMethods(target, supportRequests) {
3711
3795
  target.closeWorkspaceSupportRequest = supportRequests.closeWorkspaceSupportRequest.bind(supportRequests);
3712
3796
  target.clickWorkspaceSupportRequestResource = supportRequests.clickWorkspaceSupportRequestResource.bind(supportRequests);
3713
3797
  }
3714
- var ApiError, BaseApiClient, AbilitiesApi, AccessGrantsApi, AgentTasksApi, AgentsApi, AIModelsApi, ApiKeysApi, AppsApi, AssignmentsApi, VoiceApi, AuthApi, BuildersApi, CalendarsApi, CallsApi, CELApi, ChatsApi, ConfluenceApi, CustomToolkitsApi, DataTypesApi, DiscordBotsApi, SlackAppsApi, EventsApi, FeaturesApi, FhirConnectionsApi, HealthieApi, FilesApi, InboxesApi, InquiriesApi, AppConnectionsApi, McpServersApi, MembersApi, MilestonesApi, MondayIntegrationApi, NotificationRulesApi, OperatorApi, OrgApi, OAuthConnectionsApi, OAuthApi, PhoneNumbersApi, PronunciationsApi, PromptsApi, PersonasApi, QualificationsApi, ReportsApi, SalesforceApi, ConnectionSyncApi, HubspotApi, SitesApi, SubscriptionsApi, SupportRequestsApi, CustomersApi, ResellersApi, SupervisorsApi, TasksApi, TemplatesApi, ToolkitsApi, JourneysApi, WorkflowsApi, WorkflowNotesApi, EventRuleEventType, WorkspaceInvitationsApi, WorkspacesApi, TeamsAppsApi, ExperimentsApi, GravityRailClient, CHAT_TYPES, BUILTIN_ASSISTANT_CHAT_TYPES;
3715
- var init_chunk_WXSLDWIA = __esm({
3716
- "../sdk/dist/chunk-WXSLDWIA.js"() {
3798
+ var ApiError, BaseApiClient, AbilitiesApi, AccessGrantsApi, AgentTasksApi, AgentsApi, AIModelsApi, ApiKeysApi, AppsApi, AssignmentsApi, VoiceApi, AuthApi, BuildersApi, CalendarsApi, CallsApi, CELApi, ChatsApi, ConfluenceApi, CustomToolkitsApi, DataTypesApi, DiscordBotsApi, SlackAppsApi, EventsApi, FeaturesApi, FhirConnectionsApi, HealthieApi, FilesApi, InboxesApi, InquiriesApi, AppConnectionsApi, McpServersApi, MembersApi, MilestonesApi, MondayIntegrationApi, NotificationRulesApi, OperatorApi, OrgApi, OAuthConnectionsApi, OAuthApi, PhoneNumbersApi, PronunciationsApi, PromptsApi, PersonasApi, QualificationsApi, ReportsApi, SalesforceApi, ConnectionSyncApi, HubspotApi, SitesApi, SubscriptionsApi, SupportRequestsApi, CustomersApi, ResellersApi, SupervisorsApi, TasksApi, TemplatesApi, ToolkitsApi, JourneysApi, WorkflowsApi, WorkflowNotesApi, EventRuleEventType, WorkspaceInvitationsApi, WorkspacesApi, TeamsAppsApi, ExperimentsApi, WORKSPACE_METHOD_NAMES, WORKSPACE_METHOD_NAME_SET, GravityRailClient, CHAT_TYPES, BUILTIN_ASSISTANT_CHAT_TYPES;
3799
+ var init_chunk_ML55PVP7 = __esm({
3800
+ "../sdk/dist/chunk-ML55PVP7.js"() {
3717
3801
  init_libphonenumber_js();
3718
3802
  ApiError = class extends Error {
3719
3803
  statusCode;
@@ -4129,10 +4213,52 @@ ${formattedErrors}`, response.status);
4129
4213
  };
4130
4214
  AbilitiesApi = class extends BaseApiClient {
4131
4215
  /**
4132
- * List all available ability types from the registry.
4216
+ * List available ability types from the registry.
4217
+ * Pass includeSystem to also return auto-injected system abilities.
4133
4218
  */
4134
- async getAbilityTypes(wid) {
4135
- return this.fetch(`w/${wid}/abilities/types`);
4219
+ async getAbilityTypes(wid, options = {}) {
4220
+ const params = new URLSearchParams();
4221
+ if (options.includeSystem) params.append("includeSystem", "true");
4222
+ const qs = params.toString() ? `?${params.toString()}` : "";
4223
+ return this.fetch(`w/${wid}/abilities/types${qs}`);
4224
+ }
4225
+ /** Get the full spec for a single ability type by slug. */
4226
+ async getAbilityType(wid, slug) {
4227
+ return this.fetch(
4228
+ `w/${wid}/abilities/types/${encodeURIComponent(slug)}`
4229
+ );
4230
+ }
4231
+ /**
4232
+ * List configured ability instances for a workflow or task scope.
4233
+ * Exactly one of workflowId / taskId must be provided.
4234
+ */
4235
+ async listAbilities(wid, options) {
4236
+ const params = new URLSearchParams();
4237
+ if (options.workflowId !== void 0)
4238
+ params.append("workflowId", options.workflowId.toString());
4239
+ if (options.taskId !== void 0)
4240
+ params.append("taskId", options.taskId.toString());
4241
+ return this.fetch(`w/${wid}/abilities?${params}`);
4242
+ }
4243
+ /** Create (enable) a configured ability on a workflow or task scope. */
4244
+ async createAbility(wid, body) {
4245
+ return this.fetch(`w/${wid}/abilities`, {
4246
+ method: "POST",
4247
+ body: JSON.stringify(body)
4248
+ });
4249
+ }
4250
+ /** Update a configured ability (configure / enable / disable) by UUID. */
4251
+ async updateAbility(wid, abilityUuid, body) {
4252
+ return this.fetch(`w/${wid}/abilities/${abilityUuid}`, {
4253
+ method: "PATCH",
4254
+ body: JSON.stringify(body)
4255
+ });
4256
+ }
4257
+ /** Delete a configured ability instance by UUID. */
4258
+ async deleteAbility(wid, abilityUuid) {
4259
+ return this.fetch(`w/${wid}/abilities/${abilityUuid}`, {
4260
+ method: "DELETE"
4261
+ });
4136
4262
  }
4137
4263
  };
4138
4264
  AccessGrantsApi = class extends BaseApiClient {
@@ -4285,6 +4411,25 @@ ${formattedErrors}`, response.status);
4285
4411
  method: "POST"
4286
4412
  });
4287
4413
  }
4414
+ /** Resolve runtime tools for an agent on a simulated channel. */
4415
+ async resolveAgentTools(wid, id, options) {
4416
+ const params = new URLSearchParams();
4417
+ params.append("channel", options.channel);
4418
+ if (options.taskId !== void 0) params.append("taskId", options.taskId.toString());
4419
+ if (options.taskUuid !== void 0) params.append("taskUuid", options.taskUuid);
4420
+ return this.fetch(`w/${wid}/agents/${id}/resolve-tools?${params}`);
4421
+ }
4422
+ /**
4423
+ * List the configured abilities effective for an agent via a task's workflow.
4424
+ * Requires taskId because abilities are scoped to workflows/tasks, not agents.
4425
+ */
4426
+ async listAgentAbilities(wid, id, options) {
4427
+ const params = new URLSearchParams();
4428
+ params.append("taskId", options.taskId.toString());
4429
+ return this.fetch(
4430
+ `w/${wid}/agents/${id}/abilities?${params}`
4431
+ );
4432
+ }
4288
4433
  };
4289
4434
  AIModelsApi = class extends BaseApiClient {
4290
4435
  /**
@@ -4340,7 +4485,11 @@ ${formattedErrors}`, response.status);
4340
4485
  return this.fetch(url);
4341
4486
  }
4342
4487
  /**
4343
- * Get available speech-to-text models
4488
+ * Get available speech-to-text models.
4489
+ *
4490
+ * Returns the per-shape `STTModelsResponse` so callers see `languages` and
4491
+ * `capabilities` on each model (the chat-shape `AIModelsResponse` it used
4492
+ * to return doesn't include either).
4344
4493
  */
4345
4494
  async getSTTModels(provider) {
4346
4495
  const searchParams = new URLSearchParams();
@@ -5187,6 +5336,23 @@ ${formattedErrors}`, response.status);
5187
5336
  }
5188
5337
  };
5189
5338
  CallsApi = class extends BaseApiClient {
5339
+ /** List workspace phone calls with optional filtering. */
5340
+ async getPhoneCalls(wid, options = {}) {
5341
+ const params = new URLSearchParams();
5342
+ if (options.page) params.set("page", String(options.page));
5343
+ if (options.pageSize) params.set("pageSize", String(options.pageSize));
5344
+ if (options.phoneNumberId !== void 0)
5345
+ params.set("phoneNumberId", String(options.phoneNumberId));
5346
+ if (options.chatId !== void 0) params.set("chatId", String(options.chatId));
5347
+ if (options.workflowId !== void 0) params.set("workflowId", String(options.workflowId));
5348
+ if (options.status) params.set("status", options.status);
5349
+ if (options.inbound !== void 0) params.set("inbound", String(options.inbound));
5350
+ if (options.dateFrom) params.set("dateFrom", options.dateFrom);
5351
+ if (options.dateTo) params.set("dateTo", options.dateTo);
5352
+ return this.fetch(
5353
+ `w/${wid}/calls${params.toString() ? `?${params.toString()}` : ""}`
5354
+ );
5355
+ }
5190
5356
  /** Initiate a new outbound call. */
5191
5357
  async initiateCall(wid, request) {
5192
5358
  return this.fetch(`w/${wid}/call`, {
@@ -5701,10 +5867,17 @@ ${formattedErrors}`, response.status);
5701
5867
  const queryString = params.toString();
5702
5868
  return this.fetch(`w/${wid}/data-types${queryString ? `?${queryString}` : ""}`);
5703
5869
  }
5704
- /** Get a single data type by ID. */
5870
+ /** Get a single data type by numeric ID, or by UUID when a UUID string is supplied. */
5705
5871
  async getDataType(wid, id) {
5872
+ if (typeof id === "string" && isUuid(id)) {
5873
+ return this.getDataTypeByUuid(wid, id);
5874
+ }
5706
5875
  return this.fetch(`w/${wid}/data-types/${id}`);
5707
5876
  }
5877
+ /** Get a single data type by UUID. */
5878
+ async getDataTypeByUuid(wid, uuid) {
5879
+ return this.fetch(`w/${wid}/data-types/${uuid}`);
5880
+ }
5708
5881
  /** Get a single data type by its slug. */
5709
5882
  async getDataTypeBySlug(wid, slug) {
5710
5883
  return this.fetch(`w/${wid}/data-types/slug/${slug}`);
@@ -6589,6 +6762,25 @@ ${formattedErrors}`, response.status);
6589
6762
  body: JSON.stringify(file)
6590
6763
  });
6591
6764
  }
6765
+ /** Upload in-memory file content through the API's database-backed file path. */
6766
+ async uploadFile(wid, request) {
6767
+ const mimeType = request.mimeType ?? "application/octet-stream";
6768
+ const bytes = await dataToBytes(request.data);
6769
+ return this.createFile(wid, {
6770
+ title: request.title ?? request.filename,
6771
+ filename: request.filename,
6772
+ description: request.description,
6773
+ mimeType,
6774
+ folderId: request.folderId,
6775
+ siteId: request.siteId,
6776
+ dataBase64: bytesToBase64(bytes),
6777
+ externalId: request.externalId,
6778
+ oauthCredentialUuid: request.oauthCredentialUuid,
6779
+ access: request.access,
6780
+ labelIds: request.labelIds,
6781
+ overwrite: request.overwrite
6782
+ });
6783
+ }
6592
6784
  /** Update an existing file's metadata. */
6593
6785
  async updateFile(wid, id, file) {
6594
6786
  return this.fetch(`w/${wid}/files/${id}`, {
@@ -7014,6 +7206,12 @@ ${formattedErrors}`, response.status);
7014
7206
  * values are intentionally never exposed. Operators can also add a
7015
7207
  * new key via the UI's "Add custom field key" free-text action.
7016
7208
  */
7209
+ async setDefaultGooglePlatformAccount(wid, connectionUuid, credentialUuid) {
7210
+ return this.fetch(
7211
+ `w/${wid}/app-connections/google/platform-apps/${connectionUuid}/accounts/${credentialUuid}/default`,
7212
+ { method: "POST" }
7213
+ );
7214
+ }
7017
7215
  async listConnectionMemberFieldKeys(wid, connectionId) {
7018
7216
  return this.fetch(
7019
7217
  `w/${wid}/app-connections/${connectionId}/member-field-keys`
@@ -9295,6 +9493,28 @@ ${formattedErrors}`, response.status);
9295
9493
  async getSubscriptions() {
9296
9494
  return this.fetch("subscriptions");
9297
9495
  }
9496
+ /**
9497
+ * Create a Stripe Checkout session to purchase an organization plan.
9498
+ * Returns the checkout URL to open in a browser. The organization, billing
9499
+ * customer, and subscription are created on payment by the checkout
9500
+ * completion handler.
9501
+ */
9502
+ async createCheckoutSession(productId, planPeriod = "month") {
9503
+ return this.fetch(`subscriptions/checkout-session`, {
9504
+ method: "POST",
9505
+ credentials: "include",
9506
+ body: JSON.stringify({ productId, planPeriod }),
9507
+ headers: { "Content-Type": "application/json" }
9508
+ });
9509
+ }
9510
+ /**
9511
+ * List self-service, purchasable plans (org or workspace). Only plans with a
9512
+ * paid Stripe price are returned. No auth required.
9513
+ */
9514
+ async listSelfServeProducts(productType2) {
9515
+ const qs = productType2 ? `?product_type=${productType2}` : "";
9516
+ return this.fetch(`products/self-service${qs}`);
9517
+ }
9298
9518
  /** List all subscriptions associated with a workspace. */
9299
9519
  async getWorkspaceSubscriptions(wid) {
9300
9520
  return this.fetch(`w/${wid}/subscriptions`);
@@ -9335,6 +9555,10 @@ ${formattedErrors}`, response.status);
9335
9555
  }
9336
9556
  });
9337
9557
  }
9558
+ /** List line items for a subscription. */
9559
+ async getSubscriptionItems(subscriptionId) {
9560
+ return this.fetch(`subscriptions/${subscriptionId}/items`);
9561
+ }
9338
9562
  /** Purchase extra credits on a subscription (org-level). */
9339
9563
  async purchaseCredits(subscriptionId, amountCents) {
9340
9564
  return this.fetch(`subscriptions/${subscriptionId}/purchase-credits`, {
@@ -9558,6 +9782,12 @@ ${formattedErrors}`, response.status);
9558
9782
  if (options.workflowId) {
9559
9783
  params.append("workflow_id", options.workflowId.toString());
9560
9784
  }
9785
+ if (options.sortBy) {
9786
+ params.append("sortBy", options.sortBy);
9787
+ }
9788
+ if (options.sortOrder) {
9789
+ params.append("sortOrder", options.sortOrder);
9790
+ }
9561
9791
  return this.fetch(
9562
9792
  `w/${wid}/tasks${params.toString() ? `?${params.toString()}` : ""}`
9563
9793
  );
@@ -9828,6 +10058,36 @@ ${formattedErrors}`, response.status);
9828
10058
  async getMemberJourneys(wid, memberId) {
9829
10059
  return this.fetch(`w/${wid}/journeys/by-member/${memberId}`);
9830
10060
  }
10061
+ /** List members currently or historically associated with one journey step. */
10062
+ async getStepMembers(wid, journeyId, stepUuid, params = {}) {
10063
+ const qs = new URLSearchParams();
10064
+ if (params.status) qs.set("status", params.status);
10065
+ if (params.mode) qs.set("mode", params.mode);
10066
+ if (params.page) qs.set("page", String(params.page));
10067
+ if (params.pageSize) qs.set("pageSize", String(params.pageSize));
10068
+ const query = qs.toString();
10069
+ return this.fetch(
10070
+ `w/${wid}/journeys/${journeyId}/steps/${stepUuid}/members${query ? `?${query}` : ""}`
10071
+ );
10072
+ }
10073
+ /** Get member counts by status for each journey step. */
10074
+ async getStepMemberCounts(wid, journeyId) {
10075
+ return this.fetch(`w/${wid}/journeys/${journeyId}/step-member-counts`);
10076
+ }
10077
+ /** Advance a journey step in the current execution context. */
10078
+ async advanceStep(wid, journeyId, stepUuid, data = {}) {
10079
+ return this.fetch(
10080
+ `w/${wid}/journeys/${journeyId}/steps/${stepUuid}/advance`,
10081
+ { method: "POST", body: JSON.stringify(data) }
10082
+ );
10083
+ }
10084
+ /** Skip a journey step in the current execution context. */
10085
+ async skipStep(wid, journeyId, stepUuid, data = {}) {
10086
+ return this.fetch(
10087
+ `w/${wid}/journeys/${journeyId}/steps/${stepUuid}/skip`,
10088
+ { method: "POST", body: JSON.stringify(data) }
10089
+ );
10090
+ }
9831
10091
  /**
9832
10092
  * Dry-run heartbeat CEL evaluation for an enrolled member.
9833
10093
  *
@@ -9890,9 +10150,17 @@ ${formattedErrors}`, response.status);
9890
10150
  `w/${wid}/workflows/activity/batch?${params.toString()}`
9891
10151
  );
9892
10152
  }
9893
- /** Get the Mermaid diagram representation of a workflow. */
9894
- async getWorkflowDiagram(wid, id) {
9895
- return this.fetch(`w/${wid}/workflows/${id}/diagram`);
10153
+ /**
10154
+ * Get the Mermaid diagram representation of a workflow.
10155
+ *
10156
+ * By default only active tasks are rendered. Pass `includeArchived: true`
10157
+ * to also render archived tasks (distinctly styled). `taskCount` is always
10158
+ * the total (active + archived); `archivedTaskCount` breaks out the archived
10159
+ * portion so the active count can be derived.
10160
+ */
10161
+ async getWorkflowDiagram(wid, id, options = {}) {
10162
+ const query = options.includeArchived ? "?include_archived=true" : "";
10163
+ return this.fetch(`w/${wid}/workflows/${id}/diagram${query}`);
9896
10164
  }
9897
10165
  /**
9898
10166
  * Get workflow thumbnail URL.
@@ -10795,6 +11063,703 @@ ${formattedErrors}`, response.status);
10795
11063
  );
10796
11064
  }
10797
11065
  };
11066
+ WORKSPACE_METHOD_NAMES = [
11067
+ "activateWorkflowVersion",
11068
+ "addGroupMember",
11069
+ "advanceStep",
11070
+ "approveWorkspaceInvitation",
11071
+ "archiveAgent",
11072
+ "archiveChat",
11073
+ "archiveDataType",
11074
+ "archiveJourney",
11075
+ "archiveMember",
11076
+ "archivePhoneNumber",
11077
+ "archiveStep",
11078
+ "archiveTask",
11079
+ "archiveWorkflow",
11080
+ "authorizeMondayConnection",
11081
+ "autoCreateDataTypeFromBoard",
11082
+ "blockWorkspaceInvitation",
11083
+ "bookHealthieAppointment",
11084
+ "buildWorkspace",
11085
+ "bulkLinkMembersToHubspot",
11086
+ "bulkLinkMembersToMonday",
11087
+ "bulkLinkMembersToSalesforce",
11088
+ "cancelAgentTask",
11089
+ "cancelAssignment",
11090
+ "cancelCalendarEvent",
11091
+ "cancelCredentialUpdateInvite",
11092
+ "checkAvailability",
11093
+ "checkSiteDomainAvailability",
11094
+ "checkSiteSlugAvailability",
11095
+ "clearConnectionMemberExclusion",
11096
+ "clearMemberSwitch",
11097
+ "clickWorkspaceSupportRequestResource",
11098
+ "cloneDataType",
11099
+ "cloneTask",
11100
+ "cloneWorkflow",
11101
+ "closeWorkspaceSupportRequest",
11102
+ "commentOnWorkspaceSupportRequest",
11103
+ "configureConfluence",
11104
+ "configureHealthie",
11105
+ "configureHubspot",
11106
+ "configureMondayConnection",
11107
+ "configureSalesforce",
11108
+ "convertEmail",
11109
+ "convertFile",
11110
+ "crawlSite",
11111
+ "createAbility",
11112
+ "createAccessGrant",
11113
+ "createAgent",
11114
+ "createApiKey",
11115
+ "createAssignment",
11116
+ "createCalendar",
11117
+ "createCalendarEvent",
11118
+ "createCalendarSchedule",
11119
+ "createChat",
11120
+ "createChatCompletion",
11121
+ "createChatFilter",
11122
+ "createChatLabel",
11123
+ "createClientWorkspace",
11124
+ "createConnection",
11125
+ "createCustomTool",
11126
+ "createCustomToolkit",
11127
+ "createDataRecord",
11128
+ "createDataType",
11129
+ "createDiscordBot",
11130
+ "createEventRule",
11131
+ "createEventType",
11132
+ "createExperiment",
11133
+ "createExperimentAssignment",
11134
+ "createExperimentGroup",
11135
+ "createFhirConnection",
11136
+ "createFile",
11137
+ "createFileLabel",
11138
+ "createFolder",
11139
+ "createGoal",
11140
+ "createInbox",
11141
+ "createJourney",
11142
+ "createJourneyNote",
11143
+ "createMcpServer",
11144
+ "createMemberField",
11145
+ "createMemberFilter",
11146
+ "createMemberLabel",
11147
+ "createMemberMemory",
11148
+ "createMemberRole",
11149
+ "createMenuItem",
11150
+ "createMilestone",
11151
+ "createNotificationRule",
11152
+ "createOperatorGroup",
11153
+ "createPage",
11154
+ "createPersona",
11155
+ "createPhoneNumber",
11156
+ "createProduct",
11157
+ "createRoutine",
11158
+ "createScenario",
11159
+ "createSignup",
11160
+ "createSite",
11161
+ "createSlackApp",
11162
+ "createSnippet",
11163
+ "createStep",
11164
+ "createSupervisor",
11165
+ "createTask",
11166
+ "createTeamsApp",
11167
+ "createWorkflow",
11168
+ "createWorkflowContributor",
11169
+ "createWorkflowFromTemplate",
11170
+ "createWorkflowNote",
11171
+ "createWorkflowOutboundVoiceChat",
11172
+ "createWorkspaceMember",
11173
+ "createWorkspaceSupportRequest",
11174
+ "deactivateWorkflowVersion",
11175
+ "deleteAbility",
11176
+ "deleteAgent",
11177
+ "deleteAssignment",
11178
+ "deleteCalendar",
11179
+ "deleteCalendarEvent",
11180
+ "deleteCalendarSchedule",
11181
+ "deleteChat",
11182
+ "deleteChatFilter",
11183
+ "deleteChatLabel",
11184
+ "deleteClientWorkspace",
11185
+ "deleteConfluence",
11186
+ "deleteConnection",
11187
+ "deleteCustomTool",
11188
+ "deleteCustomToolkit",
11189
+ "deleteDataRecord",
11190
+ "deleteDataType",
11191
+ "deleteDiscordBot",
11192
+ "deleteEnrollment",
11193
+ "deleteEventRule",
11194
+ "deleteEventType",
11195
+ "deleteExperiment",
11196
+ "deleteExperimentAssignment",
11197
+ "deleteExperimentGroup",
11198
+ "deleteFhirConnection",
11199
+ "deleteFile",
11200
+ "deleteFileLabel",
11201
+ "deleteFolder",
11202
+ "deleteGoal",
11203
+ "deleteHubspot",
11204
+ "deleteInbox",
11205
+ "deleteJourneyNote",
11206
+ "deleteMcpServer",
11207
+ "deleteMember",
11208
+ "deleteMemberField",
11209
+ "deleteMemberFilter",
11210
+ "deleteMemberLabel",
11211
+ "deleteMemberMemory",
11212
+ "deleteMemberRole",
11213
+ "deleteMenuItem",
11214
+ "deleteMilestone",
11215
+ "deleteMondayConnection",
11216
+ "deleteNotificationRule",
11217
+ "deleteOperatorGroup",
11218
+ "deletePage",
11219
+ "deletePersona",
11220
+ "deletePlatformApp",
11221
+ "deleteProduct",
11222
+ "deleteRoutine",
11223
+ "deleteSalesforce",
11224
+ "deleteScenario",
11225
+ "deleteSite",
11226
+ "deleteSlackApp",
11227
+ "deleteSnippet",
11228
+ "deleteSupervisor",
11229
+ "deleteTask",
11230
+ "deleteTeamsApp",
11231
+ "deleteWorkflow",
11232
+ "deleteWorkflowContributor",
11233
+ "deleteWorkflowNote",
11234
+ "deleteWorkspace",
11235
+ "deleteWorkspaceInvitationAdmin",
11236
+ "denyWorkspaceInvitation",
11237
+ "describeSalesforceObject",
11238
+ "diffWorkflowVersions",
11239
+ "disableConfluence",
11240
+ "disableCustomToolkit",
11241
+ "disableHubspot",
11242
+ "disableMcpServer",
11243
+ "disableMondayConnection",
11244
+ "disableSalesforce",
11245
+ "disconnectConfluence",
11246
+ "disconnectHubspot",
11247
+ "disconnectMondayConnection",
11248
+ "disconnectPresence",
11249
+ "disconnectSalesforce",
11250
+ "discoverOAuthMetadata",
11251
+ "dismissAllNotifications",
11252
+ "dismissNotification",
11253
+ "downloadEmailAttachment",
11254
+ "enableConfluence",
11255
+ "enableCustomToolkit",
11256
+ "enableHubspot",
11257
+ "enableMcpServer",
11258
+ "enableMondayConnection",
11259
+ "enablePlatformApp",
11260
+ "enableSalesforce",
11261
+ "endTestChatRun",
11262
+ "enrollMembers",
11263
+ "evaluateTestChatRun",
11264
+ "executeAssignmentTool",
11265
+ "expireAnonymousMember",
11266
+ "exportChat",
11267
+ "exportChats",
11268
+ "exportMembers",
11269
+ "exportWorkspace",
11270
+ "fetchVoicemailAudio",
11271
+ "fhirBackfillEncounterSync",
11272
+ "fhirCreateEncounter",
11273
+ "fhirCsvImportApply",
11274
+ "fhirCsvImportInspect",
11275
+ "fhirFetchCareTeam",
11276
+ "fhirFetchEncounters",
11277
+ "fhirGetCsvImportRunItems",
11278
+ "fhirGetCsvImportRuns",
11279
+ "fhirGetCsvImportSettings",
11280
+ "fhirGetEncounterSyncRuns",
11281
+ "fhirGetEncounterSyncStatus",
11282
+ "fhirImportPatient",
11283
+ "fhirLinkMember",
11284
+ "fhirListLinkedMembers",
11285
+ "fhirRefreshEncounterPatient",
11286
+ "fhirRunEncounterSync",
11287
+ "fhirSearchLocations",
11288
+ "fhirSearchPatients",
11289
+ "fhirSearchPractitioners",
11290
+ "fhirSyncMember",
11291
+ "fhirUnlinkMember",
11292
+ "fhirUpdateCsvImportSettings",
11293
+ "fhirUpdateEncounterSync",
11294
+ "findOrCreateDMChat",
11295
+ "generateFileUploadUrl",
11296
+ "generateICalToken",
11297
+ "generateSiteMediaUploadUrl",
11298
+ "getAIUsageReport",
11299
+ "getAbilityType",
11300
+ "getAbilityTypes",
11301
+ "getAccessGrant",
11302
+ "getAccessGrants",
11303
+ "getAgent",
11304
+ "getAgentTask",
11305
+ "getAgentTaskMessages",
11306
+ "getAgentTasks",
11307
+ "getAgents",
11308
+ "getAnonymousResolution",
11309
+ "getAnonymousResolutions",
11310
+ "getApiKeys",
11311
+ "getArchiveBlockers",
11312
+ "getAssignment",
11313
+ "getAssignmentCelContext",
11314
+ "getAssignmentMessages",
11315
+ "getAssignmentTask",
11316
+ "getAssignmentTaskDetail",
11317
+ "getAssignmentTools",
11318
+ "getAssignments",
11319
+ "getAvailableActions",
11320
+ "getAvailablePhoneNumbers",
11321
+ "getAvailableSlots",
11322
+ "getBoardColumns",
11323
+ "getBoardGroups",
11324
+ "getBoards",
11325
+ "getBusinessHoursStatus",
11326
+ "getCalendar",
11327
+ "getCalendarEvent",
11328
+ "getCalendarEvents",
11329
+ "getCalendarSchedules",
11330
+ "getCalendars",
11331
+ "getCelContext",
11332
+ "getChat",
11333
+ "getChatAssignmentTasks",
11334
+ "getChatEmails",
11335
+ "getChatFilter",
11336
+ "getChatFilterByUuid",
11337
+ "getChatFilterCount",
11338
+ "getChatFilters",
11339
+ "getChatLabel",
11340
+ "getChatLabelByUuid",
11341
+ "getChatLabels",
11342
+ "getChatMessages",
11343
+ "getChatPhoneCalls",
11344
+ "getChatSkills",
11345
+ "getChatTodos",
11346
+ "getChatTokenUsage",
11347
+ "getChatToolCallMessages",
11348
+ "getChatTools",
11349
+ "getChats",
11350
+ "getChatsDailyCreationStats",
11351
+ "getChatsNeedsResponse",
11352
+ "getClientWorkspace",
11353
+ "getConfluenceStatus",
11354
+ "getConnectionSyncCapabilities",
11355
+ "getConnectionSyncCheckpoint",
11356
+ "getConnectionSyncConfig",
11357
+ "getCredentialUpdateInvites",
11358
+ "getCurrentMember",
11359
+ "getCurrentUserInfo",
11360
+ "getCustomToolkit",
11361
+ "getCustomToolkits",
11362
+ "getDataRecord",
11363
+ "getDataRecordChanges",
11364
+ "getDataRecords",
11365
+ "getDataType",
11366
+ "getDataTypeByUuid",
11367
+ "getDataTypeBySlug",
11368
+ "getDataTypes",
11369
+ "getDiscordBot",
11370
+ "getDiscordBotAccounts",
11371
+ "getDiscordBotByUuid",
11372
+ "getDiscordBots",
11373
+ "getDiscordGuilds",
11374
+ "getDiscordThreads",
11375
+ "getEventRule",
11376
+ "getEventRules",
11377
+ "getEventType",
11378
+ "getEventTypes",
11379
+ "getExperiment",
11380
+ "getExperimentStats",
11381
+ "getExperiments",
11382
+ "getFhirConnection",
11383
+ "getFhirConnectionByUuid",
11384
+ "getFhirConnections",
11385
+ "getFieldIndexStatus",
11386
+ "getFile",
11387
+ "getFileLabel",
11388
+ "getFileLabelByUuid",
11389
+ "getFileLabels",
11390
+ "getFileSharing",
11391
+ "getFiles",
11392
+ "getFirstRunState",
11393
+ "getFolder",
11394
+ "getFolderSharing",
11395
+ "getFolders",
11396
+ "getGoogleCalendarStatus",
11397
+ "getHealthieAvailableSlots",
11398
+ "getHealthieReconciliationMatches",
11399
+ "getHealthieStatus",
11400
+ "getHubspotContactProperties",
11401
+ "getHubspotManagedRules",
11402
+ "getHubspotReconciliationMatches",
11403
+ "getHubspotStatus",
11404
+ "getHubspotSyncLogs",
11405
+ "getHubspotTransformPresets",
11406
+ "getICalFeedUrl",
11407
+ "getInbox",
11408
+ "getInboxEmail",
11409
+ "getInboxEmails",
11410
+ "getInboxThreads",
11411
+ "getInboxes",
11412
+ "getJourney",
11413
+ "getJourneyHealth",
11414
+ "getJourneyMembers",
11415
+ "getJourneyNotes",
11416
+ "getJourneys",
11417
+ "getLinkablePhones",
11418
+ "getLinkedHealthieMembers",
11419
+ "getLinkedHubspotMembers",
11420
+ "getLinkedMondayMembers",
11421
+ "getLinkedRecords",
11422
+ "getLinkedSalesforceMembers",
11423
+ "getLiveOperators",
11424
+ "getMcpServer",
11425
+ "getMcpServerPrompts",
11426
+ "getMcpServerResources",
11427
+ "getMcpServerTools",
11428
+ "getMcpServers",
11429
+ "getMemberExperiments",
11430
+ "getMemberFieldDefinitions",
11431
+ "getMemberFields",
11432
+ "getMemberFilter",
11433
+ "getMemberFilterCount",
11434
+ "getMemberFilters",
11435
+ "getMemberGrants",
11436
+ "getMemberJourneys",
11437
+ "getMemberLabel",
11438
+ "getMemberLabelByUuid",
11439
+ "getMemberLabels",
11440
+ "getMemberMemories",
11441
+ "getMemberRecordCounts",
11442
+ "getMemberRole",
11443
+ "getMemberRoleByUuid",
11444
+ "getMemberRoles",
11445
+ "getMemberSyncSummary",
11446
+ "getMemberUsage",
11447
+ "getMembersMessageActivity",
11448
+ "getMenuItems",
11449
+ "getMessageTiming",
11450
+ "getMilestone",
11451
+ "getMilestones",
11452
+ "getMondayConnectionBoardColumns",
11453
+ "getMondayConnectionBoardGroups",
11454
+ "getMondayConnectionBoards",
11455
+ "getMondayConnectionStatus",
11456
+ "getMondayReconciliationMatches",
11457
+ "getMondaySyncConfig",
11458
+ "getMyCredentials",
11459
+ "getMyGivenGrants",
11460
+ "getMyReceivedGrants",
11461
+ "getNotification",
11462
+ "getNotificationRules",
11463
+ "getNotifications",
11464
+ "getOperatorChatMessages",
11465
+ "getOperatorGroup",
11466
+ "getOperatorGroups",
11467
+ "getOrCreateQualificationForWorkflow",
11468
+ "getOwnedMembers",
11469
+ "getPage",
11470
+ "getPageBySlug",
11471
+ "getPersona",
11472
+ "getPhoneCalls",
11473
+ "getPhoneNumber",
11474
+ "getPhoneNumberCalls",
11475
+ "getPhoneNumberMessages",
11476
+ "getPhoneNumberVoicemails",
11477
+ "getPhoneNumbers",
11478
+ "getPhoneUsageReport",
11479
+ "getPlatformApp",
11480
+ "getPresenceStatus",
11481
+ "getProducts",
11482
+ "getPublicFile",
11483
+ "getPublicFolder",
11484
+ "getPublicFolderFiles",
11485
+ "getPublicProducts",
11486
+ "getQualification",
11487
+ "getQualifications",
11488
+ "getResellerWorkspaces",
11489
+ "getRoutine",
11490
+ "getRoutineRuns",
11491
+ "getRoutines",
11492
+ "getRuleExecutions",
11493
+ "getSMSUsageReport",
11494
+ "getSalesforceReconciliationMatches",
11495
+ "getSalesforceStatus",
11496
+ "getSalesforceSyncConfig",
11497
+ "getScenario",
11498
+ "getSite",
11499
+ "getSiteByUuid",
11500
+ "getSiteCounts",
11501
+ "getSiteMenu",
11502
+ "getSitePages",
11503
+ "getSiteRenderedMenu",
11504
+ "getSiteRenderedPage",
11505
+ "getSites",
11506
+ "getSlackApp",
11507
+ "getSlackAppAccounts",
11508
+ "getSlackApps",
11509
+ "getSlackInstallations",
11510
+ "getSlackThreads",
11511
+ "getSnippet",
11512
+ "getStepMemberCounts",
11513
+ "getStepMembers",
11514
+ "getSupervisor",
11515
+ "getSupervisors",
11516
+ "getSyncRunItems",
11517
+ "getSyncRuns",
11518
+ "getTask",
11519
+ "getTaskChats",
11520
+ "getTasks",
11521
+ "getTeamsApp",
11522
+ "getTeamsAppAccounts",
11523
+ "getTeamsApps",
11524
+ "getTeamsConversations",
11525
+ "getTeamsInstallations",
11526
+ "getTemplateContext",
11527
+ "getTestChatRun",
11528
+ "getThreadEmails",
11529
+ "getTool",
11530
+ "getToolCallNames",
11531
+ "getToolkits",
11532
+ "getUnreadNotificationCount",
11533
+ "getUsageDashboard",
11534
+ "getVariableRegistry",
11535
+ "getVoiceToken",
11536
+ "getVoiceUsageReport",
11537
+ "getWebhookLogs",
11538
+ "getWorkflow",
11539
+ "getWorkflowAccessValidation",
11540
+ "getWorkflowActivity",
11541
+ "getWorkflowConfigValidation",
11542
+ "getWorkflowContributors",
11543
+ "getWorkflowDeletionPreview",
11544
+ "getWorkflowDiagram",
11545
+ "getWorkflowNotes",
11546
+ "getWorkflowRouteDryRun",
11547
+ "getWorkflowTaskAssignmentStats",
11548
+ "getWorkflowTemplates",
11549
+ "getWorkflowThumbnailUrl",
11550
+ "getWorkflowVersion",
11551
+ "getWorkflowVersionActive",
11552
+ "getWorkflowVersions",
11553
+ "getWorkflows",
11554
+ "getWorkflowsActivityBatch",
11555
+ "getWorkspace",
11556
+ "getWorkspaceBuilder",
11557
+ "getWorkspaceBuilders",
11558
+ "getWorkspaceCounts",
11559
+ "getWorkspaceDefaults",
11560
+ "getWorkspaceEmailDomains",
11561
+ "getWorkspaceMember",
11562
+ "getWorkspaceMembers",
11563
+ "getWorkspaceNotices",
11564
+ "getWorkspaceProduct",
11565
+ "getWorkspaceSiteDomains",
11566
+ "getWorkspaceSubscriptions",
11567
+ "getWorkspaceSupportRequest",
11568
+ "getWorkspaceThemes",
11569
+ "importFromBoard",
11570
+ "importHubspotMembers",
11571
+ "importMembers",
11572
+ "importSalesforceMembers",
11573
+ "importWorkspace",
11574
+ "initiateCall",
11575
+ "initiateOutboundCall",
11576
+ "inspectPrompt",
11577
+ "inviteMemberCredentialUpdate",
11578
+ "inviteToWorkspace",
11579
+ "leaveWorkspace",
11580
+ "linkCalendarToGoogle",
11581
+ "linkCalendarToHealthie",
11582
+ "linkMemberToHealthie",
11583
+ "linkMemberToHubspot",
11584
+ "linkMemberToMonday",
11585
+ "linkMemberToSalesforce",
11586
+ "linkPhoneNumber",
11587
+ "listAbilities",
11588
+ "listAgentAbilities",
11589
+ "listAppConnections",
11590
+ "listAvailableAppConnections",
11591
+ "listConfluencePages",
11592
+ "listConfluenceSpaces",
11593
+ "listConnectionMemberFieldKeys",
11594
+ "setDefaultGooglePlatformAccount",
11595
+ "listGoogleCalendars",
11596
+ "listHealthieAppointmentTypes",
11597
+ "listHealthiePatients",
11598
+ "listHealthieProviders",
11599
+ "listPersonas",
11600
+ "listPushSubscriptions",
11601
+ "listScenarios",
11602
+ "listSnippets",
11603
+ "listTestChatRuns",
11604
+ "listWorkspaceInvitationsAdmin",
11605
+ "listWorkspaceSupportRequests",
11606
+ "markEmailAsRead",
11607
+ "markEmailAsUnread",
11608
+ "markNotificationAsRead",
11609
+ "previewImportWorkspace",
11610
+ "previewSchedule",
11611
+ "previewTTS",
11612
+ "previewTemplate",
11613
+ "previewThinkingSound",
11614
+ "previewWorkspaceImport",
11615
+ "provisionClientWorkspace",
11616
+ "publishWorkflowVersion",
11617
+ "rateMessage",
11618
+ "reenrollMember",
11619
+ "registerLinkedRolesMetadata",
11620
+ "registerPushSubscription",
11621
+ "registerSlashCommands",
11622
+ "reindexFolder",
11623
+ "releasePhoneNumber",
11624
+ "removeFileRole",
11625
+ "removeFolderRole",
11626
+ "removeGroupMember",
11627
+ "reorderEventRules",
11628
+ "reorderMenuItems",
11629
+ "replyToEmail",
11630
+ "requestPhoneNumber",
11631
+ "requestWorkspaceMembership",
11632
+ "resetRoutineRuns",
11633
+ "resolveAccessGrant",
11634
+ "resolveAgentTools",
11635
+ "resolveAnonymousMember",
11636
+ "revokeAccessGrant",
11637
+ "revokeApiKey",
11638
+ "revokeICalToken",
11639
+ "runRoutine",
11640
+ "searchEventRules",
11641
+ "searchFolder",
11642
+ "searchHubspotRecords",
11643
+ "searchSalesforceRecords",
11644
+ "selectCurrentAssignmentTask",
11645
+ "sendAssistantMessage",
11646
+ "sendChatMessage",
11647
+ "sendOperatorMessage",
11648
+ "siteGoogleOAuthInitiate",
11649
+ "siteSendEmailCode",
11650
+ "siteSendPhoneCode",
11651
+ "siteSignup",
11652
+ "siteVerifyCode",
11653
+ "skipStep",
11654
+ "startConfluenceOAuth",
11655
+ "startHubspotOAuth",
11656
+ "startSalesforceOAuth",
11657
+ "startSyncRun",
11658
+ "startTestChatRun",
11659
+ "summarizeChat",
11660
+ "switchMember",
11661
+ "syncCalendarWithGoogle",
11662
+ "syncCalendarWithHealthie",
11663
+ "testFhirConnection",
11664
+ "testMcpServerConnection",
11665
+ "testMondayConnection",
11666
+ "testRunJourney",
11667
+ "toggleFieldIndex",
11668
+ "unarchiveAgent",
11669
+ "unarchiveChat",
11670
+ "unarchiveDataType",
11671
+ "unarchiveMember",
11672
+ "unarchiveTask",
11673
+ "unarchiveWorkflow",
11674
+ "unenrollMembers",
11675
+ "unlinkCalendarFromGoogle",
11676
+ "unlinkCalendarFromHealthie",
11677
+ "unlinkCredential",
11678
+ "unlinkMemberFromHealthie",
11679
+ "unlinkMemberFromHubspot",
11680
+ "unlinkMemberFromMonday",
11681
+ "unlinkMemberFromSalesforce",
11682
+ "unregisterPushSubscription",
11683
+ "updateAbility",
11684
+ "updateAgent",
11685
+ "updateAssignment",
11686
+ "updateCalendar",
11687
+ "updateCalendarEvent",
11688
+ "updateCalendarSchedule",
11689
+ "updateChat",
11690
+ "updateChatFilter",
11691
+ "updateChatLabel",
11692
+ "updateChatMute",
11693
+ "updateChatNeedsResponse",
11694
+ "updateClientWorkspace",
11695
+ "updateConnection",
11696
+ "updateConnectionSyncConfig",
11697
+ "updateCurrentMember",
11698
+ "updateCustomTool",
11699
+ "updateCustomToolkit",
11700
+ "updateDataRecord",
11701
+ "updateDataType",
11702
+ "updateDiscordBot",
11703
+ "updateEventAttendee",
11704
+ "updateEventRule",
11705
+ "updateEventType",
11706
+ "updateExperiment",
11707
+ "updateExperimentAssignment",
11708
+ "updateExperimentGroup",
11709
+ "updateFhirConnection",
11710
+ "updateFile",
11711
+ "updateFileLabel",
11712
+ "updateFileRoles",
11713
+ "updateFileSharing",
11714
+ "updateFirstRunState",
11715
+ "updateFolder",
11716
+ "updateFolderRoles",
11717
+ "updateFolderSharing",
11718
+ "updateGoal",
11719
+ "updateInbox",
11720
+ "updateJourney",
11721
+ "updateJourneyNote",
11722
+ "updateMcpServer",
11723
+ "updateMember",
11724
+ "updateMemberField",
11725
+ "updateMemberFilter",
11726
+ "updateMemberLabel",
11727
+ "updateMemberRole",
11728
+ "updateMenuItem",
11729
+ "updateMilestone",
11730
+ "updateMondaySyncConfig",
11731
+ "updateNotificationRule",
11732
+ "updateOperatorGroup",
11733
+ "updatePage",
11734
+ "updatePersona",
11735
+ "updatePhoneNumber",
11736
+ "updatePlatformApp",
11737
+ "updateProduct",
11738
+ "updateRoutine",
11739
+ "updateSalesforceSyncConfig",
11740
+ "updateScenario",
11741
+ "updateSite",
11742
+ "updateSlackApp",
11743
+ "updateSnippet",
11744
+ "updateStep",
11745
+ "updateSupervisor",
11746
+ "updateTask",
11747
+ "updateTeamsApp",
11748
+ "uploadFile",
11749
+ "updateVoicemailStatus",
11750
+ "updateWorkflow",
11751
+ "updateWorkflowContributor",
11752
+ "updateWorkflowNote",
11753
+ "updateWorkflowVersion",
11754
+ "updateWorkspace",
11755
+ "updateWorkspaceDefaults",
11756
+ "updateWorkspaceInvitationAdmin",
11757
+ "updateWorkspaceThemes",
11758
+ "upsertDataRecord",
11759
+ "validateDataTypeSlug",
11760
+ "validateWorkflowName"
11761
+ ];
11762
+ WORKSPACE_METHOD_NAME_SET = new Set(WORKSPACE_METHOD_NAMES);
10798
11763
  GravityRailClient = class {
10799
11764
  // WorkspaceInvitations is exposed publicly for backward compatibility
10800
11765
  workspaceInvitations;
@@ -10810,6 +11775,11 @@ ${formattedErrors}`, response.status);
10810
11775
  unarchiveTask;
10811
11776
  cloneTask;
10812
11777
  getAbilityTypes;
11778
+ getAbilityType;
11779
+ listAbilities;
11780
+ createAbility;
11781
+ updateAbility;
11782
+ deleteAbility;
10813
11783
  // Chats API
10814
11784
  getChats;
10815
11785
  getChat;
@@ -10855,6 +11825,7 @@ ${formattedErrors}`, response.status);
10855
11825
  deleteChatFilter;
10856
11826
  getChatFilterCount;
10857
11827
  // Calls API
11828
+ getPhoneCalls;
10858
11829
  initiateCall;
10859
11830
  getVoiceToken;
10860
11831
  getMessageTiming;
@@ -10862,6 +11833,7 @@ ${formattedErrors}`, response.status);
10862
11833
  // Data Types API
10863
11834
  getDataTypes;
10864
11835
  getDataType;
11836
+ getDataTypeByUuid;
10865
11837
  getDataTypeBySlug;
10866
11838
  createDataType;
10867
11839
  updateDataType;
@@ -10946,6 +11918,8 @@ ${formattedErrors}`, response.status);
10946
11918
  deleteAgent;
10947
11919
  archiveAgent;
10948
11920
  unarchiveAgent;
11921
+ resolveAgentTools;
11922
+ listAgentAbilities;
10949
11923
  // Qualifications API
10950
11924
  getQualifications;
10951
11925
  getQualification;
@@ -10988,6 +11962,10 @@ ${formattedErrors}`, response.status);
10988
11962
  reenrollMember;
10989
11963
  deleteEnrollment;
10990
11964
  getMemberJourneys;
11965
+ getStepMembers;
11966
+ getStepMemberCounts;
11967
+ advanceStep;
11968
+ skipStep;
10991
11969
  testRunJourney;
10992
11970
  getJourneyNotes;
10993
11971
  createJourneyNote;
@@ -11096,6 +12074,8 @@ ${formattedErrors}`, response.status);
11096
12074
  updateBusinessProfile;
11097
12075
  submitBusinessProfile;
11098
12076
  cancelBusinessProfile;
12077
+ createOrganizationWorkspace;
12078
+ getOrgBillingCustomer;
11099
12079
  getVapidPublicKey;
11100
12080
  registerPushSubscription;
11101
12081
  unregisterPushSubscription;
@@ -11203,6 +12183,7 @@ ${formattedErrors}`, response.status);
11203
12183
  getFiles;
11204
12184
  getFile;
11205
12185
  createFile;
12186
+ uploadFile;
11206
12187
  updateFile;
11207
12188
  deleteFile;
11208
12189
  convertFile;
@@ -11423,6 +12404,8 @@ ${formattedErrors}`, response.status);
11423
12404
  updateSubscription;
11424
12405
  addWorkspaceToSubscription;
11425
12406
  purchaseCredits;
12407
+ createCheckoutSession;
12408
+ listSelfServeProducts;
11426
12409
  getAIUsageReport;
11427
12410
  getSMSUsageReport;
11428
12411
  getPhoneUsageReport;
@@ -11625,6 +12608,7 @@ ${formattedErrors}`, response.status);
11625
12608
  updatePlatformApp;
11626
12609
  deletePlatformApp;
11627
12610
  listConnectionMemberFieldKeys;
12611
+ setDefaultGooglePlatformAccount;
11628
12612
  // Pronunciations API
11629
12613
  getPronunciationEntries;
11630
12614
  createPronunciationEntry;
@@ -11738,6 +12722,20 @@ ${formattedErrors}`, response.status);
11738
12722
  bindResellersMethods(this, apis.resellers);
11739
12723
  bindSupportRequestMethods(this, apis.supportRequests);
11740
12724
  }
12725
+ /**
12726
+ * Return a workspace-scoped client facade.
12727
+ *
12728
+ * Methods on the returned client are the same public SDK methods, but with
12729
+ * the workspace UUID pre-bound:
12730
+ *
12731
+ * ```ts
12732
+ * const workspace = client.workspace("workspace-uuid");
12733
+ * await workspace.getAccessGrants({ status: "approved" });
12734
+ * ```
12735
+ */
12736
+ workspace(workspaceUuid) {
12737
+ return createWorkspaceClient(this, workspaceUuid);
12738
+ }
11741
12739
  /**
11742
12740
  * Set the handler for enhanced authentication requirements (RFC 9470 Step-Up Auth).
11743
12741
  * This handler is called when a 401 response includes WWW-Authenticate header
@@ -11850,10 +12848,23 @@ var init_chunk_QS6ZRQUZ = __esm({
11850
12848
  });
11851
12849
 
11852
12850
  // ../sdk/dist/index.js
12851
+ var SEARCHABLE_EVENT_RULE_SOURCE_FIELDS;
11853
12852
  var init_dist = __esm({
11854
12853
  "../sdk/dist/index.js"() {
11855
- init_chunk_WXSLDWIA();
12854
+ init_chunk_ML55PVP7();
11856
12855
  init_chunk_QS6ZRQUZ();
12856
+ SEARCHABLE_EVENT_RULE_SOURCE_FIELDS = [
12857
+ "taskId",
12858
+ "dataTypeId",
12859
+ "routineId",
12860
+ "workflowId",
12861
+ "journeyStepId"
12862
+ ];
12863
+ [
12864
+ ...SEARCHABLE_EVENT_RULE_SOURCE_FIELDS,
12865
+ "calendarId",
12866
+ "calendarEventTypeId"
12867
+ ];
11857
12868
  }
11858
12869
  });
11859
12870
  function detectWorktreePorts() {
@@ -11865,7 +12876,7 @@ function detectWorktreePorts() {
11865
12876
  overridePath = candidate;
11866
12877
  break;
11867
12878
  }
11868
- const parent = dirname(dir);
12879
+ const parent = dirname$1(dir);
11869
12880
  if (parent === dir) break;
11870
12881
  dir = parent;
11871
12882
  }
@@ -12468,46 +13479,6 @@ function formatTimestamp(isoString) {
12468
13479
  if (diff < 6048e5) return `${Math.floor(diff / 864e5)}d ago`;
12469
13480
  return date.toLocaleDateString();
12470
13481
  }
12471
- function wrapText(text, width = 70) {
12472
- const words = text.split(" ");
12473
- const lines = [];
12474
- let currentLine = "";
12475
- for (const word of words) {
12476
- if (currentLine.length + word.length + 1 <= width) {
12477
- currentLine += (currentLine ? " " : "") + word;
12478
- } else {
12479
- if (currentLine) lines.push(currentLine);
12480
- currentLine = word;
12481
- }
12482
- }
12483
- if (currentLine) lines.push(currentLine);
12484
- return lines;
12485
- }
12486
- function printMessage(content, role, indent = " ") {
12487
- const roleColors = {
12488
- user: "\x1B[34m",
12489
- // Blue
12490
- assistant: "\x1B[32m",
12491
- // Green
12492
- system: "\x1B[90m"
12493
- // Gray
12494
- };
12495
- const resetColor = "\x1B[0m";
12496
- const color = roleColors[role] || resetColor;
12497
- const label = role === "user" ? "You" : role === "assistant" ? "Assistant" : "System";
12498
- console.log(`${indent}${color}[${label}]${resetColor}`);
12499
- const lines = content.split("\n");
12500
- for (const line of lines) {
12501
- const wrapped = wrapText(line, 70);
12502
- for (const wrappedLine of wrapped) {
12503
- console.log(`${indent} ${wrappedLine}`);
12504
- }
12505
- }
12506
- console.log("");
12507
- }
12508
- function clearScreen() {
12509
- process.stdout.write("\x1B[2J\x1B[H");
12510
- }
12511
13482
  var NEW_ITEM_MARKER;
12512
13483
  var init_ui = __esm({
12513
13484
  "src/cli-utils/ui.ts"() {
@@ -16612,11 +17583,11 @@ var require_util2 = __commonJS({
16612
17583
  var { isUint8Array } = __require("util/types");
16613
17584
  var { webidl } = require_webidl();
16614
17585
  var supportedHashes = [];
16615
- var crypto;
17586
+ var crypto2;
16616
17587
  try {
16617
- crypto = __require("crypto");
17588
+ crypto2 = __require("crypto");
16618
17589
  const possibleRelevantHashes = ["sha256", "sha384", "sha512"];
16619
- supportedHashes = crypto.getHashes().filter((hash) => possibleRelevantHashes.includes(hash));
17590
+ supportedHashes = crypto2.getHashes().filter((hash) => possibleRelevantHashes.includes(hash));
16620
17591
  } catch {
16621
17592
  }
16622
17593
  function responseURL(response) {
@@ -16888,7 +17859,7 @@ var require_util2 = __commonJS({
16888
17859
  }
16889
17860
  }
16890
17861
  function bytesMatch(bytes, metadataList) {
16891
- if (crypto === void 0) {
17862
+ if (crypto2 === void 0) {
16892
17863
  return true;
16893
17864
  }
16894
17865
  const parsedMetadata = parseMetadata(metadataList);
@@ -16903,7 +17874,7 @@ var require_util2 = __commonJS({
16903
17874
  for (const item of metadata) {
16904
17875
  const algorithm = item.algo;
16905
17876
  const expectedValue = item.hash;
16906
- let actualValue = crypto.createHash(algorithm).update(bytes).digest("base64");
17877
+ let actualValue = crypto2.createHash(algorithm).update(bytes).digest("base64");
16907
17878
  if (actualValue[actualValue.length - 1] === "=") {
16908
17879
  if (actualValue[actualValue.length - 2] === "=") {
16909
17880
  actualValue = actualValue.slice(0, -2);
@@ -17961,8 +18932,8 @@ var require_body = __commonJS({
17961
18932
  var { multipartFormDataParser } = require_formdata_parser();
17962
18933
  var random;
17963
18934
  try {
17964
- const crypto = __require("crypto");
17965
- random = (max) => crypto.randomInt(0, max);
18935
+ const crypto2 = __require("crypto");
18936
+ random = (max) => crypto2.randomInt(0, max);
17966
18937
  } catch {
17967
18938
  random = (max) => Math.floor(Math.random(max));
17968
18939
  }
@@ -27210,7 +28181,7 @@ var require_util4 = __commonJS({
27210
28181
  var { serializeAMimeType, parseMIMEType } = require_data_url();
27211
28182
  var { types } = __require("util");
27212
28183
  var { StringDecoder } = __require("string_decoder");
27213
- var { btoa } = __require("buffer");
28184
+ var { btoa: btoa2 } = __require("buffer");
27214
28185
  var staticPropertyDescriptors = {
27215
28186
  enumerable: true,
27216
28187
  writable: false,
@@ -27302,9 +28273,9 @@ var require_util4 = __commonJS({
27302
28273
  dataURL += ";base64,";
27303
28274
  const decoder = new StringDecoder("latin1");
27304
28275
  for (const chunk of bytes) {
27305
- dataURL += btoa(decoder.write(chunk));
28276
+ dataURL += btoa2(decoder.write(chunk));
27306
28277
  }
27307
- dataURL += btoa(decoder.end());
28278
+ dataURL += btoa2(decoder.end());
27308
28279
  return dataURL;
27309
28280
  }
27310
28281
  case "Text": {
@@ -29290,13 +30261,13 @@ var require_frame = __commonJS({
29290
30261
  "../../node_modules/undici/lib/web/websocket/frame.js"(exports$1, module) {
29291
30262
  var { maxUnsigned16Bit } = require_constants5();
29292
30263
  var BUFFER_SIZE = 16386;
29293
- var crypto;
30264
+ var crypto2;
29294
30265
  var buffer = null;
29295
30266
  var bufIdx = BUFFER_SIZE;
29296
30267
  try {
29297
- crypto = __require("crypto");
30268
+ crypto2 = __require("crypto");
29298
30269
  } catch {
29299
- crypto = {
30270
+ crypto2 = {
29300
30271
  // not full compatibility, but minimum.
29301
30272
  randomFillSync: function randomFillSync(buffer2, _offset, _size) {
29302
30273
  for (let i = 0; i < buffer2.length; ++i) {
@@ -29309,7 +30280,7 @@ var require_frame = __commonJS({
29309
30280
  function generateMask() {
29310
30281
  if (bufIdx === BUFFER_SIZE) {
29311
30282
  bufIdx = 0;
29312
- crypto.randomFillSync(buffer ??= Buffer.allocUnsafe(BUFFER_SIZE), 0, BUFFER_SIZE);
30283
+ crypto2.randomFillSync(buffer ??= Buffer.allocUnsafe(BUFFER_SIZE), 0, BUFFER_SIZE);
29313
30284
  }
29314
30285
  return [buffer[bufIdx++], buffer[bufIdx++], buffer[bufIdx++], buffer[bufIdx++]];
29315
30286
  }
@@ -29380,9 +30351,9 @@ var require_connection = __commonJS({
29380
30351
  var { Headers: Headers2, getHeadersList } = require_headers();
29381
30352
  var { getDecodeSplit } = require_util2();
29382
30353
  var { WebsocketFrameSend } = require_frame();
29383
- var crypto;
30354
+ var crypto2;
29384
30355
  try {
29385
- crypto = __require("crypto");
30356
+ crypto2 = __require("crypto");
29386
30357
  } catch {
29387
30358
  }
29388
30359
  function establishWebSocketConnection(url, protocols, client, ws, onEstablish, options) {
@@ -29402,7 +30373,7 @@ var require_connection = __commonJS({
29402
30373
  const headersList = getHeadersList(new Headers2(options.headers));
29403
30374
  request.headersList = headersList;
29404
30375
  }
29405
- const keyValue = crypto.randomBytes(16).toString("base64");
30376
+ const keyValue = crypto2.randomBytes(16).toString("base64");
29406
30377
  request.headersList.append("sec-websocket-key", keyValue);
29407
30378
  request.headersList.append("sec-websocket-version", "13");
29408
30379
  for (const protocol of protocols) {
@@ -29432,7 +30403,7 @@ var require_connection = __commonJS({
29432
30403
  return;
29433
30404
  }
29434
30405
  const secWSAccept = response.headersList.get("Sec-WebSocket-Accept");
29435
- const digest = crypto.createHash("sha1").update(keyValue + uid).digest("base64");
30406
+ const digest = crypto2.createHash("sha1").update(keyValue + uid).digest("base64");
29436
30407
  if (secWSAccept !== digest) {
29437
30408
  failWebsocketConnection(ws, "Incorrect hash received in Sec-WebSocket-Accept header.");
29438
30409
  return;
@@ -29973,9 +30944,9 @@ var require_sender = __commonJS({
29973
30944
  constructor(socket) {
29974
30945
  this.#socket = socket;
29975
30946
  }
29976
- add(item, cb, hint) {
29977
- if (hint !== sendHints.blob) {
29978
- const frame = createFrame(item, hint);
30947
+ add(item, cb, hint2) {
30948
+ if (hint2 !== sendHints.blob) {
30949
+ const frame = createFrame(item, hint2);
29979
30950
  if (!this.#running) {
29980
30951
  this.#socket.write(frame, cb);
29981
30952
  } else {
@@ -29991,7 +30962,7 @@ var require_sender = __commonJS({
29991
30962
  const node = {
29992
30963
  promise: item.arrayBuffer().then((ab) => {
29993
30964
  node.promise = null;
29994
- node.frame = createFrame(ab, hint);
30965
+ node.frame = createFrame(ab, hint2);
29995
30966
  }),
29996
30967
  callback: cb,
29997
30968
  frame: null
@@ -30015,11 +30986,11 @@ var require_sender = __commonJS({
30015
30986
  this.#running = false;
30016
30987
  }
30017
30988
  };
30018
- function createFrame(data, hint) {
30019
- return new WebsocketFrameSend(toBuffer(data, hint)).createFrame(hint === sendHints.string ? opcodes.TEXT : opcodes.BINARY);
30989
+ function createFrame(data, hint2) {
30990
+ return new WebsocketFrameSend(toBuffer(data, hint2)).createFrame(hint2 === sendHints.string ? opcodes.TEXT : opcodes.BINARY);
30020
30991
  }
30021
- function toBuffer(data, hint) {
30022
- switch (hint) {
30992
+ function toBuffer(data, hint2) {
30993
+ switch (hint2) {
30023
30994
  case sendHints.string:
30024
30995
  return Buffer.from(data);
30025
30996
  case sendHints.arrayBuffer:
@@ -31164,32 +32135,31 @@ function createPinnedFetch(apiUrl, apiIp) {
31164
32135
  }
31165
32136
  function withAuditHeaders(fetchFn, headers2) {
31166
32137
  const { chatId, sessionId, toolCallId } = headers2;
31167
- if (chatId === void 0 && !sessionId && !toolCallId) {
31168
- return fetchFn;
31169
- }
31170
32138
  return async (input2, init) => {
31171
32139
  const reqHeaders = new Headers(init?.headers);
32140
+ const dynamicToolCallId = globalThis.__GRAVITY_RAIL_TOOL_CALL_ID__ || (typeof process !== "undefined" ? process.env.GRAVITY_RAIL_TOOL_CALL_ID : void 0);
31172
32141
  if (chatId !== void 0) {
31173
32142
  reqHeaders.set("X-GR-Chat-Id", String(chatId));
31174
32143
  }
31175
32144
  if (sessionId) {
31176
32145
  reqHeaders.set("X-GR-Session-Id", sessionId);
31177
32146
  }
31178
- if (toolCallId) {
31179
- reqHeaders.set("X-GR-Tool-Call-Id", toolCallId);
32147
+ if (dynamicToolCallId || toolCallId) {
32148
+ reqHeaders.set("X-GR-Tool-Call-Id", dynamicToolCallId || toolCallId || "");
31180
32149
  }
31181
32150
  return fetchFn(input2, { ...init, headers: reqHeaders });
31182
32151
  };
31183
32152
  }
31184
32153
  function createSandboxFetchFromEnv(apiUrl) {
31185
- const apiIp = process.env.GRAVITY_RAIL_API_IP;
32154
+ const env = typeof process !== "undefined" ? process.env : {};
32155
+ const apiIp = env.GRAVITY_RAIL_API_IP;
31186
32156
  let fetchFn = createPinnedFetch(apiUrl, apiIp);
31187
- const chatIdRaw = process.env.GRAVITY_RAIL_CHAT_ID;
32157
+ const chatIdRaw = env.GRAVITY_RAIL_CHAT_ID;
31188
32158
  const chatId = chatIdRaw ? Number(chatIdRaw) : void 0;
31189
32159
  return withAuditHeaders(fetchFn, {
31190
32160
  chatId: chatId !== void 0 && Number.isFinite(chatId) ? chatId : void 0,
31191
- sessionId: process.env.GRAVITY_RAIL_SESSION_ID,
31192
- toolCallId: process.env.GRAVITY_RAIL_TOOL_CALL_ID
32161
+ sessionId: env.GRAVITY_RAIL_SESSION_ID,
32162
+ toolCallId: env.GRAVITY_RAIL_TOOL_CALL_ID
31193
32163
  });
31194
32164
  }
31195
32165
  var import_undici;
@@ -31271,7 +32241,7 @@ var init_context = __esm({
31271
32241
  });
31272
32242
 
31273
32243
  // src/lib/concierge-api.ts
31274
- function baseUrl2(ctx) {
32244
+ function baseUrl(ctx) {
31275
32245
  return `${ctx.envConfig.apiUrl}/api/v2/concierge`;
31276
32246
  }
31277
32247
  function authHeaders(ctx) {
@@ -31302,13 +32272,13 @@ function toCamelMessage(raw) {
31302
32272
  };
31303
32273
  }
31304
32274
  async function listConciergeChats(ctx) {
31305
- const res = await fetch(`${baseUrl2(ctx)}/chats`, { headers: authHeaders(ctx) });
32275
+ const res = await fetch(`${baseUrl(ctx)}/chats`, { headers: authHeaders(ctx) });
31306
32276
  if (!res.ok) throw new Error(`Failed to list concierge chats: ${res.status}`);
31307
32277
  const data = await res.json();
31308
32278
  return data.map(toCamelChat);
31309
32279
  }
31310
32280
  async function createConciergeChat(ctx, title) {
31311
- const res = await fetch(`${baseUrl2(ctx)}/chats`, {
32281
+ const res = await fetch(`${baseUrl(ctx)}/chats`, {
31312
32282
  method: "POST",
31313
32283
  headers: authHeaders(ctx),
31314
32284
  body: JSON.stringify({ title: null })
@@ -31317,15 +32287,18 @@ async function createConciergeChat(ctx, title) {
31317
32287
  return toCamelChat(await res.json());
31318
32288
  }
31319
32289
  async function getConciergeChat(ctx, chatId) {
31320
- const res = await fetch(`${baseUrl2(ctx)}/chats/${chatId}`, { headers: authHeaders(ctx) });
32290
+ const res = await fetch(`${baseUrl(ctx)}/chats/${chatId}`, { headers: authHeaders(ctx) });
31321
32291
  if (!res.ok) throw new Error(`Failed to get concierge chat ${chatId}: ${res.status}`);
31322
32292
  return toCamelChat(await res.json());
31323
32293
  }
31324
- async function originateConciergeCall(ctx, kind = "concierge_setup") {
31325
- const res = await fetch(`${baseUrl2(ctx)}/calls`, {
32294
+ async function originateConciergeCall(ctx, kind = "concierge_setup", outboundMessage, clientSurface) {
32295
+ const body = { kind };
32296
+ if (outboundMessage) body.outbound_message = outboundMessage;
32297
+ body.client_surface = clientSurface;
32298
+ const res = await fetch(`${baseUrl(ctx)}/calls`, {
31326
32299
  method: "POST",
31327
32300
  headers: authHeaders(ctx),
31328
- body: JSON.stringify({ kind })
32301
+ body: JSON.stringify(body)
31329
32302
  });
31330
32303
  if (res.status === 412) {
31331
32304
  throw new Error("Your account phone is not verified. Run `gr account verify-phone` first.");
@@ -31337,7 +32310,7 @@ async function originateConciergeCall(ctx, kind = "concierge_setup") {
31337
32310
  return await res.json();
31338
32311
  }
31339
32312
  async function originateConciergeSms(ctx, kind = "concierge_setup") {
31340
- const res = await fetch(`${baseUrl2(ctx)}/sms`, {
32313
+ const res = await fetch(`${baseUrl(ctx)}/sms`, {
31341
32314
  method: "POST",
31342
32315
  headers: authHeaders(ctx),
31343
32316
  body: JSON.stringify({ kind })
@@ -31374,7 +32347,7 @@ async function confirmAccountPhoneVerify(ctx, code) {
31374
32347
  }
31375
32348
  }
31376
32349
  async function getConciergeChatMessages(ctx, chatId) {
31377
- const res = await fetch(`${baseUrl2(ctx)}/chats/${chatId}/messages`, {
32350
+ const res = await fetch(`${baseUrl(ctx)}/chats/${chatId}/messages`, {
31378
32351
  headers: authHeaders(ctx)
31379
32352
  });
31380
32353
  if (!res.ok)
@@ -31410,7 +32383,7 @@ async function accountVerifyPhoneCommand(hctx) {
31410
32383
  );
31411
32384
  }
31412
32385
  async function promptLine(question) {
31413
- const rl = readline6.createInterface({ input: stdin, output: stdout });
32386
+ const rl = readline5.createInterface({ input: stdin, output: stdout });
31414
32387
  try {
31415
32388
  return await rl.question(question) ?? "";
31416
32389
  } finally {
@@ -31884,6 +32857,11 @@ var CommandRegistry = class {
31884
32857
  const key = cmd.path.join(" ");
31885
32858
  this.commands.set(key, cmd);
31886
32859
  }
32860
+ registerCommands(commands3) {
32861
+ for (const cmd of commands3) {
32862
+ this.registerCommand(cmd);
32863
+ }
32864
+ }
31887
32865
  /** Resolve command words to a CommandDef using longest-match.
31888
32866
  * Supports {param} path segments that match any word and extract as pathParams. */
31889
32867
  resolve(words) {
@@ -31916,6 +32894,7 @@ var CommandRegistry = class {
31916
32894
  }
31917
32895
  /** Generate help text. If prefix given, show commands under that prefix. */
31918
32896
  getHelp(prefix) {
32897
+ const inSandbox = process.env.GRAVITY_RAIL_SANDBOX === "1";
31919
32898
  if (!prefix || prefix.length === 0) {
31920
32899
  return this.getTopLevelHelp();
31921
32900
  }
@@ -31952,18 +32931,21 @@ var CommandRegistry = class {
31952
32931
  `, "Commands:"];
31953
32932
  for (const cmd of matching.sort((a, b) => a.path.join(" ").localeCompare(b.path.join(" ")))) {
31954
32933
  const subPath = cmd.path.slice(prefix.length).join(" ") || cmd.path[cmd.path.length - 1];
31955
- lines.push(` ${subPath.padEnd(28)} ${cmd.description}`);
32934
+ const description = inSandbox ? sandboxHelpText(cmd.description) : cmd.description;
32935
+ lines.push(` ${subPath.padEnd(28)} ${description}`);
31956
32936
  }
31957
32937
  return lines.join("\n") + "\n";
31958
32938
  }
31959
32939
  getCommandHelp(cmd) {
31960
32940
  const cmdStr = cmd.path.join(" ");
31961
- const lines = [`${cmd.description}
32941
+ const inSandbox = process.env.GRAVITY_RAIL_SANDBOX === "1";
32942
+ const description = inSandbox ? sandboxHelpText(cmd.description) : cmd.description;
32943
+ const lines = [`${description}
31962
32944
  `, `Usage: gr ${cmdStr} [options]`];
31963
- if (cmd.requiresWorkspace) {
32945
+ if (cmd.requiresWorkspace && !inSandbox) {
31964
32946
  lines.push(" Requires: -w <workspace-uuid> (or --realm <workspace>/<member> in dev)");
31965
32947
  }
31966
- if (cmd.mutates) {
32948
+ if (cmd.mutates && !inSandbox) {
31967
32949
  lines.push(" Requires: --allow-write");
31968
32950
  }
31969
32951
  const action = cmd.path[cmd.path.length - 1] ?? "";
@@ -31985,7 +32967,7 @@ var CommandRegistry = class {
31985
32967
  if (cmd.examples && cmd.examples.length > 0) {
31986
32968
  lines.push("", "Examples:");
31987
32969
  for (const ex of cmd.examples) {
31988
- lines.push(` ${ex}`);
32970
+ lines.push(` ${inSandbox ? sandboxExample(ex) : ex}`);
31989
32971
  }
31990
32972
  }
31991
32973
  return lines.join("\n") + "\n";
@@ -32000,38 +32982,50 @@ var CommandRegistry = class {
32000
32982
  }
32001
32983
  getTopLevelHelp() {
32002
32984
  const lines = ["Usage: gr <command> [options]\n", "Commands:"];
32985
+ const inSandbox = process.env.GRAVITY_RAIL_SANDBOX === "1";
32003
32986
  const seen = /* @__PURE__ */ new Set();
32004
32987
  for (const domain of this.domains) {
32005
32988
  if (!seen.has(domain.name)) {
32006
32989
  seen.add(domain.name);
32007
- lines.push(` ${domain.name.padEnd(28)} ${domain.description}`);
32990
+ const description = inSandbox ? sandboxHelpText(domain.description) : domain.description;
32991
+ lines.push(` ${domain.name.padEnd(28)} ${description}`);
32008
32992
  }
32009
32993
  }
32010
32994
  for (const [, cmd] of this.commands) {
32011
32995
  const topWord = cmd.path[0];
32012
32996
  if (!seen.has(topWord) && cmd.path.length === 1) {
32013
32997
  seen.add(topWord);
32014
- lines.push(` ${topWord.padEnd(28)} ${cmd.description}`);
32998
+ const description = inSandbox ? sandboxHelpText(cmd.description) : cmd.description;
32999
+ lines.push(` ${topWord.padEnd(28)} ${description}`);
32015
33000
  }
32016
33001
  }
32017
- lines.push(
33002
+ const globalOptions = [
32018
33003
  "",
32019
33004
  "Global Options:",
32020
- " --env <env> Environment: dev, staging, prod (default: dev)",
32021
- " --realm <ws>/<member> Dev auth shortcut (dev only; sets -w automatically)",
32022
- " --api-url <url> API base URL (or GRAVITY_RAIL_API_URL)",
32023
- " -w, --workspace <uuid> Workspace UUID",
33005
+ ...!inSandbox ? [
33006
+ " --env <env> Environment: dev, staging, prod (default: dev)",
33007
+ " --realm <ws>/<member> Dev auth shortcut (dev only; sets -w automatically)",
33008
+ " --api-url <url> API base URL (or GRAVITY_RAIL_API_URL)",
33009
+ " -w, --workspace <uuid> Workspace UUID"
33010
+ ] : [],
32024
33011
  " -d, --data <json> JSON body (create/update and other write commands)",
32025
33012
  " -f, --file <path> JSON body from file",
32026
- " --allow-write Required for create/update/delete/archive",
33013
+ ...!inSandbox ? [" --allow-write Required for create/update/delete/archive"] : [],
32027
33014
  " -o, --output-format <fmt> Output format: json, jsonl, table (default: auto)",
32028
33015
  " -v, --verbose Verbose output to stderr",
32029
33016
  " --help Show help",
32030
33017
  " --version Show version"
32031
- );
33018
+ ];
33019
+ lines.push(...globalOptions);
32032
33020
  return lines.join("\n") + "\n";
32033
33021
  }
32034
33022
  };
33023
+ function sandboxHelpText(text) {
33024
+ return text.replace(/\byarn gr\b/g, "gr").replace(/\s--allow-write\b/g, "").replace(/\s--realm\s+(?:"[^"]+"|'[^']+'|<[^>]+>|\S+)/g, "").replace(/\s-w\s+(?:"[^"]+"|'[^']+'|<[^>]+>|\S+)/g, "");
33025
+ }
33026
+ function sandboxExample(example) {
33027
+ return sandboxHelpText(example);
33028
+ }
32035
33029
 
32036
33030
  // src/lib/types.ts
32037
33031
  function requireString(args, key) {
@@ -32054,8 +33048,8 @@ function requireNumberFrom(args, ...keys) {
32054
33048
  if (!isNaN(num)) return num;
32055
33049
  }
32056
33050
  }
32057
- const hint = keys.map((k) => `--${k}`).join(" or ");
32058
- throw new Error(`Missing required argument: ${hint}`);
33051
+ const hint2 = keys.map((k) => `--${k}`).join(" or ");
33052
+ throw new Error(`Missing required argument: ${hint2}`);
32059
33053
  }
32060
33054
 
32061
33055
  // src/domains/agent-tasks.ts
@@ -32195,7 +33189,45 @@ var agentTasksDomain = {
32195
33189
 
32196
33190
  // src/domains/agents.ts
32197
33191
  init_output();
33192
+ init_context();
33193
+ init_errors();
32198
33194
  var COLUMNS = [COL.id(), COL.uuid(), COL.name(), COL.status(), COL.created()];
33195
+ var TOOL_COLUMNS = [
33196
+ COL.name(),
33197
+ { header: "DESCRIPTION", getValue: (item) => (item.description ?? "").slice(0, 60) }
33198
+ ];
33199
+ var ABILITY_COLUMNS = [
33200
+ COL.uuid(),
33201
+ { header: "ABILITY-TYPE", getValue: (item) => item.abilityType ?? "" },
33202
+ COL.enabled(),
33203
+ { header: "CEL-CONDITION", getValue: (item) => item.celCondition ?? "" }
33204
+ ];
33205
+ function requireAbilityScope(args) {
33206
+ const hasWorkflow = typeof args["workflow-id"] === "string";
33207
+ const hasTask = typeof args["task-id"] === "string";
33208
+ if (hasWorkflow === hasTask) {
33209
+ throw new CLIError(
33210
+ "Specify exactly one of --workflow-id or --task-id. Abilities are scoped to a workflow or task, not to the agent row itself."
33211
+ );
33212
+ }
33213
+ if (hasTask) {
33214
+ const taskId = Number(args["task-id"]);
33215
+ if (isNaN(taskId)) throw new CLIError("--task-id must be a number");
33216
+ return { taskId };
33217
+ }
33218
+ const workflowId = Number(args["workflow-id"]);
33219
+ if (isNaN(workflowId)) throw new CLIError("--workflow-id must be a number");
33220
+ return { workflowId };
33221
+ }
33222
+ function normalizeChannel(channel) {
33223
+ const aliases = {
33224
+ phone: "phone-voice",
33225
+ voice: "phone-voice",
33226
+ sms: "phone-sms",
33227
+ web: "web-chat"
33228
+ };
33229
+ return aliases[channel] ?? channel;
33230
+ }
32199
33231
  var agentsDomain = {
32200
33232
  name: "agents",
32201
33233
  description: "Manage agents",
@@ -32211,8 +33243,163 @@ var agentsDomain = {
32211
33243
  archiveMethod: "archiveAgent",
32212
33244
  unarchiveMethod: "unarchiveAgent",
32213
33245
  columns: COLUMNS,
32214
- paginationSupport: "full"
32215
- })
33246
+ paginationSupport: "full",
33247
+ 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)\nAbilities are NOT set here \u2014 they live on a workflow/task scope; use `gr agents abilities` to manage them.",
33248
+ updateExamples: [
33249
+ `gr agents update --id 42 --data '{"name":"Scheduler","temperature":0.4}'`,
33250
+ "gr agents update --id 42 --file agent.json"
33251
+ ]
33252
+ }),
33253
+ {
33254
+ path: ["agents", "resolve-tools"],
33255
+ description: "Show resolved runtime tools for an agent in a channel context. Channel accepts canonical values (phone-voice, web-voice, phone-sms, web-chat) or shorthand aliases: phone -> phone-voice, voice -> phone-voice, sms -> phone-sms, web -> web-chat. Unknown values are passed through unchanged. When neither --task-id nor --task-uuid is supplied the agent's workflow start task is used.",
33256
+ requiresWorkspace: true,
33257
+ args: [
33258
+ { name: "id", description: "Agent ID", required: true },
33259
+ {
33260
+ name: "channel",
33261
+ description: "Channel to simulate. Canonical: phone-voice, web-voice, phone-sms, web-chat. Aliases: phone|voice -> phone-voice, sms -> phone-sms, web -> web-chat.",
33262
+ required: true
33263
+ },
33264
+ {
33265
+ name: "task-id",
33266
+ description: "Numeric task ID whose workflow abilities to resolve. Omit to use the workflow start task (or supply --task-uuid instead).",
33267
+ required: false
33268
+ },
33269
+ {
33270
+ name: "task-uuid",
33271
+ description: "Task UUID as an alternative to --task-id. Omit to use the workflow start task.",
33272
+ required: false
33273
+ }
33274
+ ],
33275
+ handler: async ({ ctx, workspace, args }) => {
33276
+ const rawTaskId = args["task-id"];
33277
+ const rawTaskUuid = args["task-uuid"];
33278
+ if (rawTaskId !== void 0 && rawTaskUuid !== void 0) {
33279
+ throw new Error("Provide at most one of --task-id or --task-uuid, not both");
33280
+ }
33281
+ const options = {
33282
+ channel: normalizeChannel(String(args.channel))
33283
+ };
33284
+ if (typeof rawTaskId === "string") {
33285
+ const n = Number(rawTaskId);
33286
+ if (isNaN(n)) throw new Error("Argument --task-id must be a number");
33287
+ options.taskId = n;
33288
+ }
33289
+ if (typeof rawTaskUuid === "string") {
33290
+ options.taskUuid = rawTaskUuid;
33291
+ }
33292
+ const result2 = await requireAuth(ctx).apiClient.resolveAgentTools(
33293
+ workspace,
33294
+ requireNumber(args, "id"),
33295
+ options
33296
+ );
33297
+ const tools = result2.tools ?? result2;
33298
+ outputData(Array.isArray(tools) ? tools : [tools], ctx, TOOL_COLUMNS);
33299
+ }
33300
+ },
33301
+ {
33302
+ path: ["agents", "abilities", "list"],
33303
+ description: "Show the abilities effective for an agent on a task (read-only). Requires --task-id because abilities are resolved through the task's workflow, not stored on the agent row.",
33304
+ requiresWorkspace: true,
33305
+ columns: ABILITY_COLUMNS,
33306
+ args: [
33307
+ { name: "id", description: "Agent ID", required: true },
33308
+ {
33309
+ name: "task-id",
33310
+ description: "Task ID whose workflow abilities to list",
33311
+ required: true
33312
+ }
33313
+ ],
33314
+ handler: async ({ ctx, workspace, args }) => {
33315
+ const result2 = await requireAuth(ctx).apiClient.listAgentAbilities(
33316
+ workspace,
33317
+ requireNumber(args, "id"),
33318
+ { taskId: requireNumber(args, "task-id") }
33319
+ );
33320
+ outputData(result2, ctx, ABILITY_COLUMNS);
33321
+ }
33322
+ },
33323
+ {
33324
+ path: ["agents", "abilities", "enable"],
33325
+ description: "Enable (create) an ability on a workflow or task scope. Requires exactly one of --workflow-id or --task-id \u2014 abilities are scoped to a workflow/task, never to the agent row. Provide initial --config JSON inline or via --data/--file.",
33326
+ mutates: true,
33327
+ requiresWorkspace: true,
33328
+ args: [
33329
+ { name: "ability-type", description: "Ability type slug (e.g. 'communication:send_sms')", required: true },
33330
+ { name: "workflow-id", description: "Workflow scope (mutually exclusive with --task-id)" },
33331
+ { name: "task-id", description: "Task scope (mutually exclusive with --workflow-id)" }
33332
+ ],
33333
+ examples: [
33334
+ "gr agents abilities enable --workflow-id 7 --ability-type tools:web_search",
33335
+ `gr agents abilities enable --task-id 12 --ability-type integration:data_access --data '{"dataTypeUuid":"..."}'`
33336
+ ],
33337
+ handler: async ({ ctx, workspace, args, data }) => {
33338
+ const abilityType = args["ability-type"];
33339
+ if (typeof abilityType !== "string") {
33340
+ throw new CLIError("--ability-type is required");
33341
+ }
33342
+ const scope = requireAbilityScope(args);
33343
+ const config = data && typeof data === "object" ? data : {};
33344
+ const body = {
33345
+ abilityType,
33346
+ config,
33347
+ ...scope
33348
+ };
33349
+ const result2 = await requireAuth(ctx).apiClient.createAbility(workspace, body);
33350
+ outputSingle(result2, ctx, ABILITY_COLUMNS);
33351
+ }
33352
+ },
33353
+ {
33354
+ path: ["agents", "abilities", "disable"],
33355
+ description: "Disable an ability instance by UUID (sets enabled=false, keeps config). Use `gr agents abilities list` to find the UUID.",
33356
+ mutates: true,
33357
+ requiresWorkspace: true,
33358
+ args: [{ name: "uuid", description: "Ability instance UUID", required: true }],
33359
+ handler: async ({ ctx, workspace, args }) => {
33360
+ const uuid = args.uuid;
33361
+ if (typeof uuid !== "string") throw new CLIError("--uuid is required");
33362
+ const result2 = await requireAuth(ctx).apiClient.updateAbility(workspace, uuid, {
33363
+ enabled: false
33364
+ });
33365
+ outputSingle(result2, ctx, ABILITY_COLUMNS);
33366
+ }
33367
+ },
33368
+ {
33369
+ path: ["agents", "abilities", "configure"],
33370
+ description: "Update an ability instance by UUID. Pass --data/--file JSON to merge into config, and/or --enabled true|false to toggle. config is merged with the existing config server-side.",
33371
+ mutates: true,
33372
+ requiresWorkspace: true,
33373
+ args: [
33374
+ { name: "uuid", description: "Ability instance UUID", required: true },
33375
+ { name: "enabled", description: "Set enabled state (true|false)" }
33376
+ ],
33377
+ examples: [
33378
+ `gr agents abilities configure --uuid <uuid> --data '{"canForward":true}'`,
33379
+ "gr agents abilities configure --uuid <uuid> --enabled true"
33380
+ ],
33381
+ handler: async ({ ctx, workspace, args, data }) => {
33382
+ const uuid = args.uuid;
33383
+ if (typeof uuid !== "string") throw new CLIError("--uuid is required");
33384
+ const body = {};
33385
+ if (data && typeof data === "object") {
33386
+ body.config = data;
33387
+ }
33388
+ if (typeof args.enabled === "string") {
33389
+ if (args.enabled !== "true" && args.enabled !== "false") {
33390
+ throw new CLIError("--enabled must be true or false");
33391
+ }
33392
+ body.enabled = args.enabled === "true";
33393
+ }
33394
+ if (Object.keys(body).length === 0) {
33395
+ throw new CLIError(
33396
+ "Nothing to update: provide --data config and/or --enabled"
33397
+ );
33398
+ }
33399
+ const result2 = await requireAuth(ctx).apiClient.updateAbility(workspace, uuid, body);
33400
+ outputSingle(result2, ctx, ABILITY_COLUMNS);
33401
+ }
33402
+ }
32216
33403
  ]
32217
33404
  };
32218
33405
 
@@ -32220,6 +33407,7 @@ var agentsDomain = {
32220
33407
  init_output();
32221
33408
  init_cli_utils();
32222
33409
  init_context();
33410
+ init_concierge_api();
32223
33411
  var COLUMNS2 = [
32224
33412
  COL.id(),
32225
33413
  COL.uuid(),
@@ -32440,21 +33628,47 @@ var chatsDomain = {
32440
33628
  // Inspect (aggregated debug view)
32441
33629
  {
32442
33630
  path: ["chats", "inspect"],
32443
- description: "Inspect a chat with messages, assignment state, and data records",
32444
- requiresWorkspace: true,
33631
+ description: "Inspect a chat with messages, assignment state, and data records. Omit -w for concierge (account-level) chats.",
33632
+ requiresWorkspace: false,
32445
33633
  args: [{ name: "id", description: "Chat ID", required: true }],
32446
33634
  handler: async ({ ctx, workspace, args }) => {
32447
33635
  const chatId = requireNumber(args, "id");
32448
- const [chat, messages, ws] = await Promise.all([
32449
- requireAuth(ctx).apiClient.getChat(workspace, chatId),
32450
- requireAuth(ctx).apiClient.getChatMessages(workspace, chatId),
32451
- requireAuth(ctx).apiClient.getWorkspace(workspace)
32452
- ]);
32453
- const isHipaa = ws.features?.includes("hipaa_compliance");
33636
+ const authed = requireAuth(ctx);
32454
33637
  const truncate2 = (content) => {
32455
33638
  const text = typeof content === "string" ? content : JSON.stringify(content);
32456
33639
  return text.slice(0, 200);
32457
33640
  };
33641
+ if (!workspace) {
33642
+ const [chat2, messages2] = await Promise.all([
33643
+ getConciergeChat(authed, chatId),
33644
+ getConciergeChatMessages(authed, chatId)
33645
+ ]);
33646
+ outputSingle(
33647
+ {
33648
+ chat: {
33649
+ id: chat2.id,
33650
+ uuid: chat2.uuid,
33651
+ title: chat2.title,
33652
+ chatType: chat2.chatType,
33653
+ threadId: chat2.threadId,
33654
+ createdAt: chat2.createdAt
33655
+ },
33656
+ messages: messages2.map((m) => ({
33657
+ id: m.id,
33658
+ role: m.role,
33659
+ content: truncate2(m.content)
33660
+ }))
33661
+ },
33662
+ ctx
33663
+ );
33664
+ return;
33665
+ }
33666
+ const [chat, messages, ws] = await Promise.all([
33667
+ authed.apiClient.getChat(workspace, chatId),
33668
+ authed.apiClient.getChatMessages(workspace, chatId),
33669
+ authed.apiClient.getWorkspace(workspace)
33670
+ ]);
33671
+ const isHipaa = ws.features?.includes("hipaa_compliance");
32458
33672
  const result2 = {
32459
33673
  chat: {
32460
33674
  id: chat.id,
@@ -32474,10 +33688,7 @@ var chatsDomain = {
32474
33688
  };
32475
33689
  const assignmentId = chat.assignmentId;
32476
33690
  if (assignmentId) {
32477
- const assignment = await requireAuth(ctx).apiClient.getAssignment(
32478
- workspace,
32479
- assignmentId
32480
- );
33691
+ const assignment = await authed.apiClient.getAssignment(workspace, assignmentId);
32481
33692
  result2.assignment = {
32482
33693
  id: assignment.id,
32483
33694
  status: assignment.status,
@@ -32735,10 +33946,7 @@ var memberRolesDomain = {
32735
33946
  updateMethod: "updateMemberRole",
32736
33947
  deleteMethod: "deleteMemberRole",
32737
33948
  columns: ROLE_COLUMNS2,
32738
- createExamples: [
32739
- "gr member-roles list -w $WID",
32740
- "gr member-roles get -w $WID --id 2"
32741
- ]
33949
+ createExamples: ["gr member-roles list -w $WID", "gr member-roles get -w $WID --id 2"]
32742
33950
  })
32743
33951
  };
32744
33952
 
@@ -32749,10 +33957,13 @@ var COLUMNS4 = [
32749
33957
  COL.id(),
32750
33958
  COL.uuid(),
32751
33959
  COL.name(),
32752
- COL.status(),
33960
+ // TaskResponse has no `status` field — it has `archived`. Surface that
33961
+ // directly so active vs archived is visible in the default table (relevant
33962
+ // once --include-archived mixes both into the listing).
33963
+ { header: "STATUS", getValue: (item) => item.archived ? "archived" : "active" },
32753
33964
  {
32754
33965
  header: "WORKFLOW",
32755
- getValue: (item) => item.workflow_name ?? String(item.workflow_id ?? "")
33966
+ getValue: (item) => String(item.workflowId ?? "")
32756
33967
  },
32757
33968
  COL.created()
32758
33969
  ];
@@ -32770,7 +33981,21 @@ var tasksDomain = {
32770
33981
  deleteMethod: "deleteTask",
32771
33982
  archiveMethod: "archiveTask",
32772
33983
  unarchiveMethod: "unarchiveTask",
32773
- columns: COLUMNS4
33984
+ columns: COLUMNS4,
33985
+ // `tasks list` is workspace-wide by default. Filter to one workflow
33986
+ // with --workflow-id, and opt into archived tasks with
33987
+ // --include-archived (active-only by default, matching the backend).
33988
+ listArgs: [
33989
+ {
33990
+ name: "workflow-id",
33991
+ description: "Filter tasks to a single workflow by ID"
33992
+ },
33993
+ {
33994
+ name: "include-archived",
33995
+ description: "Include archived tasks in the listing",
33996
+ isFlag: true
33997
+ }
33998
+ ]
32774
33999
  }),
32775
34000
  {
32776
34001
  path: ["tasks", "clone"],
@@ -32830,9 +34055,18 @@ var COLUMNS5 = [
32830
34055
  COL.id(),
32831
34056
  COL.uuid(),
32832
34057
  COL.name(),
32833
- { header: "TASKS", getValue: (item) => String(item.taskCount ?? "") },
34058
+ // taskCount is the total (active + archived). Show the active count as the
34059
+ // headline number — matching `tasks list` — and call out archived tasks
34060
+ // separately so the table never overstates how many tasks actually run.
34061
+ { header: "TASKS", getValue: (item) => formatTaskCount(item) },
32834
34062
  COL.created()
32835
34063
  ];
34064
+ function formatTaskCount(item) {
34065
+ const total = Number(item.taskCount ?? 0);
34066
+ const archived = Number(item.archivedTaskCount ?? 0);
34067
+ const active = total - archived;
34068
+ return archived > 0 ? `${active} (+${archived} archived)` : String(active);
34069
+ }
32836
34070
  var NOTE_COLUMNS = [
32837
34071
  COL.id(),
32838
34072
  { header: "TITLE", getValue: (item) => item.title ?? "" },
@@ -32933,13 +34167,21 @@ var workflowsDomain = {
32933
34167
  // Diagram
32934
34168
  {
32935
34169
  path: ["workflows", "diagram"],
32936
- description: "Get workflow diagram",
34170
+ description: "Get workflow diagram (active tasks only by default)",
32937
34171
  requiresWorkspace: true,
32938
- args: [{ name: "id", description: "Workflow ID", required: true }],
34172
+ args: [
34173
+ { name: "id", description: "Workflow ID", required: true },
34174
+ {
34175
+ name: "include-archived",
34176
+ description: "Render archived tasks (distinctly styled) too",
34177
+ isFlag: true
34178
+ }
34179
+ ],
32939
34180
  handler: async ({ ctx, workspace, args }) => {
32940
34181
  const result2 = await requireAuth(ctx).apiClient.getWorkflowDiagram(
32941
34182
  workspace,
32942
- requireNumber(args, "id")
34183
+ requireNumber(args, "id"),
34184
+ { includeArchived: args["include-archived"] === true }
32943
34185
  );
32944
34186
  outputSingle(result2, ctx);
32945
34187
  }
@@ -33462,28 +34704,64 @@ var workspacesDomain = {
33462
34704
  outputSingle(result2, ctx, COLUMNS7);
33463
34705
  }
33464
34706
  },
33465
- // Create a workspace via the public endpoint
34707
+ // Provision a workspace under an organization's active subscription.
33466
34708
  {
33467
34709
  path: ["workspaces", "create"],
33468
- description: "Create a workspace",
34710
+ description: "Provision a workspace in an organization (requires an active subscription)",
33469
34711
  mutates: true,
33470
34712
  requiresWorkspace: false,
33471
- handler: async ({ ctx, data }) => {
33472
- if (!data) throw new CLIError("JSON data required (--data, --file, or stdin)");
33473
- const payload = data;
33474
- if (!payload.organizationId) {
34713
+ args: [
34714
+ {
34715
+ name: "org",
34716
+ aliases: ["org-uuid"],
34717
+ description: "Organization UUID",
34718
+ required: true
34719
+ },
34720
+ { name: "product", description: "Workspace plan product ID", required: true },
34721
+ { name: "name", description: "Workspace name", required: true },
34722
+ { name: "period", description: "Billing period: 'month' or 'year'", default: "month" },
34723
+ { name: "slug", description: "Workspace slug (optional)" },
34724
+ { name: "template", description: "Template workspace UUID to clone (optional)" }
34725
+ ],
34726
+ examples: ['gr workspaces create --org <org-uuid> --product 14 --name "Front Desk"'],
34727
+ handler: async ({ ctx, args }) => {
34728
+ const orgUuid = args.org ?? args["org-uuid"];
34729
+ const name = args.name;
34730
+ const productRaw = args.product;
34731
+ if (!orgUuid) throw new CLIError("Missing required argument: --org <org-uuid>");
34732
+ if (!name) throw new CLIError("Missing required argument: --name");
34733
+ if (!productRaw) {
33475
34734
  throw new CLIError(
33476
- `organizationId is required in --data (e.g. --data '{"organizationId": 1, "name": "My Workspace"}')`
34735
+ "Missing required argument: --product\nList workspace plans with: gr billing products --type workspace"
33477
34736
  );
33478
34737
  }
34738
+ const payload = {
34739
+ name,
34740
+ productId: Number(productRaw),
34741
+ planPeriod: args.period || "month"
34742
+ };
34743
+ if (args.slug) payload.slug = args.slug;
34744
+ if (args.template) payload.templateWorkspaceUuid = args.template;
33479
34745
  try {
33480
- const result2 = await requireAuth(ctx).apiClient.createWorkspace(payload);
34746
+ const result2 = await requireAuth(ctx).apiClient.createOrganizationWorkspace(
34747
+ orgUuid,
34748
+ payload
34749
+ );
33481
34750
  outputSingle(result2, ctx, COLUMNS7);
34751
+ if ((ctx.outputFormat ?? "table") === "table") {
34752
+ const wsUuid = result2?.uuid ?? "<workspace-uuid>";
34753
+ process.stdout.write(
34754
+ `
34755
+ Provisioning started. Watch it come up with:
34756
+ gr workspaces get -w ${wsUuid}
34757
+ `
34758
+ );
34759
+ }
33482
34760
  } catch (err) {
33483
34761
  const statusCode = err?.statusCode;
33484
- if (statusCode === 405) {
34762
+ if (statusCode === 400) {
33485
34763
  throw new CLIError(
33486
- '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)'
34764
+ "Could not create the workspace. The organization needs an active, paid subscription first.\n gr billing products --type org # pick an org plan\n gr billing checkout --product <id> # pay up front\n gr billing status # confirm it is active"
33487
34765
  );
33488
34766
  }
33489
34767
  throw err;
@@ -33985,7 +35263,7 @@ var MESSAGE_COLUMNS4 = [
33985
35263
  COL.created()
33986
35264
  ];
33987
35265
  var TASK_COLUMNS = [COL.id(), COL.name(), COL.status()];
33988
- var TOOL_COLUMNS = [
35266
+ var TOOL_COLUMNS2 = [
33989
35267
  COL.name(),
33990
35268
  { header: "DESCRIPTION", getValue: (item) => (item.description ?? "").slice(0, 60) }
33991
35269
  ];
@@ -34093,7 +35371,7 @@ var assignmentsDomain = {
34093
35371
  requireNumber(args, "assignment-id")
34094
35372
  );
34095
35373
  const tools = result2.tools ?? result2;
34096
- outputData(Array.isArray(tools) ? tools : [tools], ctx, TOOL_COLUMNS);
35374
+ outputData(Array.isArray(tools) ? tools : [tools], ctx, TOOL_COLUMNS2);
34097
35375
  }
34098
35376
  }
34099
35377
  ]
@@ -34549,35 +35827,24 @@ Common optional
34549
35827
  Scope (set exactly one when objectType requires it)
34550
35828
  routineId, workflowId, taskId, dataTypeId, journeyStepId, calendarId, ...
34551
35829
 
34552
- chat:create actionParams (outbound voice/SMS)
34553
- {"workflowId":<id>,"channel":"phone-voice"|"phone-sms","phoneNumberId":<id>,
34554
- "inboxId":<optional>,"assistantEnabled":<bool>}
35830
+ chat:create actionParams (outbound voice/SMS \u2014 starts a workflow chat)
35831
+ {"workflowUUID":"<workflow-uuid>","channel":"phone-voice"|"phone-sms",
35832
+ "phoneNumberUUID":"<uuid>","inboxUUID":"<optional-uuid>","assistantEnabled":<bool>}
35833
+ Keys are UUID strings: workflowUUID (not workflowId), phoneNumberUUID (not
35834
+ phoneNumberId), inboxUUID (not inboxId). Unknown keys are rejected.
35835
+
35836
+ sms:send actionParams (send an SMS, or start an SMS workflow chat)
35837
+ One-off text: {"phoneNumberUUID":"<from-number-uuid>","messageTemplate":"Hi {{name}} \u2026"}
35838
+ Workflow chat: {"phoneNumberUUID":"<from-number-uuid>","workflowUUID":"<workflow-uuid>",
35839
+ "initialUserMessage":"<optional seed>"}
35840
+ phoneNumberUUID (the from-number) is required. The message body is messageTemplate
35841
+ (supports {{record/member}} template vars) \u2014 there is no "body"/"message" key.
35842
+ Provide messageTemplate for a one-off text, OR workflowUUID to start a chat.
34555
35843
 
34556
35844
  member:label actionParams
34557
35845
  {"addLabelIds":["<uuid>"],"removeLabelIds":["<uuid>"]}
34558
35846
  `;
34559
35847
 
34560
- // src/lib/routines/field-help.ts
34561
- var ROUTINE_FIELD_REFERENCE = `
34562
- Field reference for --data JSON (create/update):
34563
-
34564
- Core
34565
- name (string) Display name
34566
- workflowId (number) Workflow run when the routine fires
34567
- targetMemberId (number) Member who receives the scheduled outreach
34568
-
34569
- Schedule
34570
- scheduleEnabled (bool) Master on/off for the cron trigger
34571
- scheduleMode (string) "CRON" (only mode today)
34572
- cronString (string) Standard cron, e.g. "0 7 * * *"
34573
- timezone (string, optional) IANA name, e.g. "America/Los_Angeles"
34574
- Defaults to workspace timezone, else UTC
34575
-
34576
- Visibility / lifecycle
34577
- archived (bool) Archive flag on update
34578
- event rules Use gr events rules create \u2014 not inline here
34579
- `;
34580
-
34581
35848
  // src/domains/events.ts
34582
35849
  var RULE_COLUMNS = [
34583
35850
  COL.id(),
@@ -34585,15 +35852,6 @@ var RULE_COLUMNS = [
34585
35852
  { header: "EVENT", getValue: (item) => item.eventType ?? "" },
34586
35853
  { header: "ACTIVE", getValue: (item) => String(item.active ?? "") }
34587
35854
  ];
34588
- var ROUTINE_COLUMNS = [
34589
- COL.id(),
34590
- COL.name(),
34591
- { header: "MODE", getValue: (item) => item.scheduleMode ?? "" },
34592
- { header: "CRON", getValue: (item) => item.cronString ?? "" },
34593
- { header: "TZ", getValue: (item) => item.timezone ?? "UTC" },
34594
- { header: "ENABLED", getValue: (item) => String(item.scheduleEnabled ?? "") },
34595
- { header: "NEXT RUN", getValue: (item) => item.nextRun ?? "" }
34596
- ];
34597
35855
  var eventRulesCrudNoList = crudCommands({
34598
35856
  prefix: ["events", "rules"],
34599
35857
  entityName: "event rule",
@@ -34617,8 +35875,8 @@ ${EVENT_RULE_FIELD_REFERENCE}`,
34617
35875
  `gr events rules create -w $WID --allow-write --data '{"name":"AM voice check-in",`,
34618
35876
  ' "objectType":"routine","eventType":"routine:triggered","actionType":"chat:create",',
34619
35877
  ' "routineId":<routine-id>,',
34620
- ' "actionParams":{"workflowId":<workflow-id>,"channel":"phone-voice",',
34621
- ` "phoneNumberId":<workspace-phone-id>}}'`,
35878
+ ' "actionParams":{"workflowUUID":"<workflow-uuid>","channel":"phone-voice",',
35879
+ ` "phoneNumberUUID":"<workspace-phone-uuid>"}}'`,
34622
35880
  "",
34623
35881
  ' PM SMS variant: use "channel":"phone-sms" and a second rule on the same routineId.',
34624
35882
  " Prereq: org phone assigned + gr phone-numbers link; workflow published with start task.",
@@ -34756,74 +36014,6 @@ var eventsDomain = {
34756
36014
  const result2 = await requireAuth(ctx).apiClient.searchEventRules(workspace, opts);
34757
36015
  outputData(result2, ctx, RULE_COLUMNS);
34758
36016
  }
34759
- },
34760
- // Routines
34761
- ...crudCommands({
34762
- prefix: ["routines"],
34763
- entityName: "routine",
34764
- listMethod: "getRoutines",
34765
- getMethod: "getRoutine",
34766
- createMethod: "createRoutine",
34767
- updateMethod: "updateRoutine",
34768
- deleteMethod: "deleteRoutine",
34769
- paginationSupport: "full",
34770
- columns: ROUTINE_COLUMNS,
34771
- createHelp: `Create a routine
34772
-
34773
- ${ROUTINE_FIELD_REFERENCE}`,
34774
- updateHelp: `Update a routine
34775
-
34776
- ${ROUTINE_FIELD_REFERENCE}`,
34777
- createExamples: [
34778
- "Daily 7am check-in in the member\u2019s timezone (cron is interpreted in `timezone`):",
34779
- `gr routines create -w $WID --allow-write --data '{"name":"AM check-in",`,
34780
- ' "scheduleEnabled":true,"scheduleMode":"CRON","cronString":"0 7 * * *",',
34781
- ` "timezone":"America/Los_Angeles","targetMemberId":1,"workflowId":2}'`,
34782
- " (timezone is an IANA name; omit it to default to the workspace timezone, else UTC.",
34783
- ' Without it, "0 7 * * *" fires at 07:00 UTC, not 7am local.)'
34784
- ]
34785
- }),
34786
- {
34787
- path: ["routines", "run"],
34788
- description: "Run a routine now",
34789
- mutates: true,
34790
- requiresWorkspace: true,
34791
- args: [{ name: "id", description: "Routine ID", required: true }],
34792
- handler: async ({ ctx, workspace, args, data }) => {
34793
- const result2 = await requireAuth(ctx).apiClient.runRoutine(
34794
- workspace,
34795
- requireNumber(args, "id"),
34796
- data ?? {}
34797
- );
34798
- outputSingle(result2, ctx);
34799
- }
34800
- },
34801
- {
34802
- path: ["routines", "runs", "list"],
34803
- description: "List runs for a routine",
34804
- requiresWorkspace: true,
34805
- args: [
34806
- {
34807
- name: "id",
34808
- description: "Routine ID (aligns with routines get/run/update/delete)"
34809
- },
34810
- { name: "status", description: "Filter by run status" },
34811
- { name: "page", description: "Page number (1-indexed)" },
34812
- { name: "page-size", description: "Page size (max 100)" }
34813
- ],
34814
- handler: async ({ ctx, workspace, args }) => {
34815
- const routineId = args.id ? requireNumber(args, "id") : void 0;
34816
- const page = args.page ? requireNumber(args, "page") : void 0;
34817
- const pageSize = args["page-size"] ? requireNumber(args, "page-size") : void 0;
34818
- const status = args.status ?? void 0;
34819
- const result2 = await requireAuth(ctx).apiClient.getRoutineRuns(workspace, {
34820
- ...routineId !== void 0 ? { routineId } : {},
34821
- ...page !== void 0 ? { page } : {},
34822
- ...pageSize !== void 0 ? { pageSize } : {},
34823
- ...status ? { status } : {}
34824
- });
34825
- outputData(result2, ctx);
34826
- }
34827
36017
  }
34828
36018
  ]
34829
36019
  };
@@ -35218,11 +36408,11 @@ var ACTION_COLUMNS = [
35218
36408
  { header: "ACTIVE", getValue: (item) => String(item.active ?? "") },
35219
36409
  { header: "CONDITIONS", getValue: (item) => (item.conditions ?? "").slice(0, 40) }
35220
36410
  ];
35221
- function baseUrl(ctx, wid) {
36411
+ function baseUrl2(ctx, wid) {
35222
36412
  return `${ctx.envConfig.apiUrl}/api/v2/w/${wid}/journeys`;
35223
36413
  }
35224
36414
  function notesUrl(ctx, wid, journeyId) {
35225
- return `${baseUrl(ctx, wid)}/${journeyId}/notes`;
36415
+ return `${baseUrl2(ctx, wid)}/${journeyId}/notes`;
35226
36416
  }
35227
36417
  function headers(ctx) {
35228
36418
  return {
@@ -35289,7 +36479,7 @@ var journeysDomain = {
35289
36479
  requiresWorkspace: true,
35290
36480
  examples: ["gr journeys list -w $WID --env staging"],
35291
36481
  handler: async ({ ctx, workspace }) => {
35292
- const result2 = await apiGet(requireAuth(ctx), baseUrl(requireAuth(ctx), workspace));
36482
+ const result2 = await apiGet(requireAuth(ctx), baseUrl2(requireAuth(ctx), workspace));
35293
36483
  outputData(listResult(result2, false), ctx, JOURNEY_COLUMNS);
35294
36484
  }
35295
36485
  },
@@ -35302,7 +36492,7 @@ var journeysDomain = {
35302
36492
  const id = requireString(args, "id");
35303
36493
  const result2 = await apiGet(
35304
36494
  requireAuth(ctx),
35305
- `${baseUrl(requireAuth(ctx), workspace)}/${id}`
36495
+ `${baseUrl2(requireAuth(ctx), workspace)}/${id}`
35306
36496
  );
35307
36497
  outputSingle(result2, ctx, JOURNEY_COLUMNS);
35308
36498
  }
@@ -35322,7 +36512,7 @@ var journeysDomain = {
35322
36512
  if (!data) throw new CLIError("JSON data required (--data, --file, or stdin)");
35323
36513
  const result2 = await apiPost(
35324
36514
  requireAuth(ctx),
35325
- baseUrl(requireAuth(ctx), workspace),
36515
+ baseUrl2(requireAuth(ctx), workspace),
35326
36516
  data
35327
36517
  );
35328
36518
  outputSingle(result2, ctx, JOURNEY_COLUMNS);
@@ -35340,7 +36530,7 @@ var journeysDomain = {
35340
36530
  const id = requireString(args, "id");
35341
36531
  const result2 = await apiPut(
35342
36532
  requireAuth(ctx),
35343
- `${baseUrl(requireAuth(ctx), workspace)}/${id}`,
36533
+ `${baseUrl2(requireAuth(ctx), workspace)}/${id}`,
35344
36534
  data
35345
36535
  );
35346
36536
  outputSingle(result2, ctx, JOURNEY_COLUMNS);
@@ -35354,7 +36544,7 @@ var journeysDomain = {
35354
36544
  args: [{ name: "id", description: "Journey ID", required: true }],
35355
36545
  handler: async ({ ctx, workspace, args }) => {
35356
36546
  const id = requireString(args, "id");
35357
- await apiDelete(requireAuth(ctx), `${baseUrl(requireAuth(ctx), workspace)}/${id}`);
36547
+ await apiDelete(requireAuth(ctx), `${baseUrl2(requireAuth(ctx), workspace)}/${id}`);
35358
36548
  process.stdout.write(`Archived journey ${id}
35359
36549
  `);
35360
36550
  }
@@ -35370,7 +36560,7 @@ var journeysDomain = {
35370
36560
  const id = requireString(args, "id");
35371
36561
  const result2 = await apiGet(
35372
36562
  requireAuth(ctx),
35373
- `${baseUrl(requireAuth(ctx), workspace)}/${id}`
36563
+ `${baseUrl2(requireAuth(ctx), workspace)}/${id}`
35374
36564
  );
35375
36565
  outputData(result2?.steps ?? [], ctx, STEP_COLUMNS);
35376
36566
  }
@@ -35395,7 +36585,7 @@ var journeysDomain = {
35395
36585
  const journeyId = requireString(args, "journey-id");
35396
36586
  const result2 = await apiPost(
35397
36587
  requireAuth(ctx),
35398
- `${baseUrl(requireAuth(ctx), workspace)}/${journeyId}/steps`,
36588
+ `${baseUrl2(requireAuth(ctx), workspace)}/${journeyId}/steps`,
35399
36589
  data
35400
36590
  );
35401
36591
  outputSingle(result2, ctx, STEP_COLUMNS);
@@ -35416,7 +36606,7 @@ var journeysDomain = {
35416
36606
  const stepId = requireString(args, "id");
35417
36607
  const result2 = await apiPut(
35418
36608
  requireAuth(ctx),
35419
- `${baseUrl(requireAuth(ctx), workspace)}/${journeyId}/steps/${stepId}`,
36609
+ `${baseUrl2(requireAuth(ctx), workspace)}/${journeyId}/steps/${stepId}`,
35420
36610
  data
35421
36611
  );
35422
36612
  outputSingle(result2, ctx, STEP_COLUMNS);
@@ -35436,7 +36626,7 @@ var journeysDomain = {
35436
36626
  const stepId = requireString(args, "id");
35437
36627
  await apiDelete(
35438
36628
  requireAuth(ctx),
35439
- `${baseUrl(requireAuth(ctx), workspace)}/${journeyId}/steps/${stepId}`
36629
+ `${baseUrl2(requireAuth(ctx), workspace)}/${journeyId}/steps/${stepId}`
35440
36630
  );
35441
36631
  process.stdout.write(`Archived step ${stepId}
35442
36632
  `);
@@ -35453,7 +36643,7 @@ var journeysDomain = {
35453
36643
  const id = requireString(args, "id");
35454
36644
  const result2 = await apiGet(
35455
36645
  requireAuth(ctx),
35456
- `${baseUrl(requireAuth(ctx), workspace)}/${id}`
36646
+ `${baseUrl2(requireAuth(ctx), workspace)}/${id}`
35457
36647
  );
35458
36648
  const seen = /* @__PURE__ */ new Set();
35459
36649
  const connections = [];
@@ -35497,7 +36687,7 @@ var journeysDomain = {
35497
36687
  const journeyId = requireString(args, "journey-id");
35498
36688
  const result2 = await apiPost(
35499
36689
  requireAuth(ctx),
35500
- `${baseUrl(requireAuth(ctx), workspace)}/${journeyId}/connections`,
36690
+ `${baseUrl2(requireAuth(ctx), workspace)}/${journeyId}/connections`,
35501
36691
  data
35502
36692
  );
35503
36693
  outputSingle(result2, ctx, CONNECTION_COLUMNS);
@@ -35518,7 +36708,7 @@ var journeysDomain = {
35518
36708
  const connId = requireString(args, "id");
35519
36709
  const result2 = await apiPut(
35520
36710
  requireAuth(ctx),
35521
- `${baseUrl(requireAuth(ctx), workspace)}/${journeyId}/connections/${connId}`,
36711
+ `${baseUrl2(requireAuth(ctx), workspace)}/${journeyId}/connections/${connId}`,
35522
36712
  data
35523
36713
  );
35524
36714
  outputSingle(result2, ctx, CONNECTION_COLUMNS);
@@ -35538,7 +36728,7 @@ var journeysDomain = {
35538
36728
  const connId = requireString(args, "id");
35539
36729
  await apiDelete(
35540
36730
  requireAuth(ctx),
35541
- `${baseUrl(requireAuth(ctx), workspace)}/${journeyId}/connections/${connId}`
36731
+ `${baseUrl2(requireAuth(ctx), workspace)}/${journeyId}/connections/${connId}`
35542
36732
  );
35543
36733
  process.stdout.write(`Deleted connection ${connId}
35544
36734
  `);
@@ -35555,7 +36745,7 @@ var journeysDomain = {
35555
36745
  const id = requireString(args, "id");
35556
36746
  const result2 = await apiGet(
35557
36747
  requireAuth(ctx),
35558
- `${baseUrl(requireAuth(ctx), workspace)}/${id}`
36748
+ `${baseUrl2(requireAuth(ctx), workspace)}/${id}`
35559
36749
  );
35560
36750
  outputData(result2?.goals ?? [], ctx, GOAL_COLUMNS);
35561
36751
  }
@@ -35578,7 +36768,7 @@ var journeysDomain = {
35578
36768
  const journeyId = requireString(args, "journey-id");
35579
36769
  const result2 = await apiPost(
35580
36770
  requireAuth(ctx),
35581
- `${baseUrl(requireAuth(ctx), workspace)}/${journeyId}/goals`,
36771
+ `${baseUrl2(requireAuth(ctx), workspace)}/${journeyId}/goals`,
35582
36772
  data
35583
36773
  );
35584
36774
  outputSingle(result2, ctx, GOAL_COLUMNS);
@@ -35599,7 +36789,7 @@ var journeysDomain = {
35599
36789
  const goalId = requireString(args, "id");
35600
36790
  const result2 = await apiPut(
35601
36791
  requireAuth(ctx),
35602
- `${baseUrl(requireAuth(ctx), workspace)}/${journeyId}/goals/${goalId}`,
36792
+ `${baseUrl2(requireAuth(ctx), workspace)}/${journeyId}/goals/${goalId}`,
35603
36793
  data
35604
36794
  );
35605
36795
  outputSingle(result2, ctx, GOAL_COLUMNS);
@@ -35619,7 +36809,7 @@ var journeysDomain = {
35619
36809
  const goalId = requireString(args, "id");
35620
36810
  await apiDelete(
35621
36811
  requireAuth(ctx),
35622
- `${baseUrl(requireAuth(ctx), workspace)}/${journeyId}/goals/${goalId}`
36812
+ `${baseUrl2(requireAuth(ctx), workspace)}/${journeyId}/goals/${goalId}`
35623
36813
  );
35624
36814
  process.stdout.write(`Deleted goal ${goalId}
35625
36815
  `);
@@ -35643,7 +36833,7 @@ var journeysDomain = {
35643
36833
  const id = requireString(args, "id");
35644
36834
  const result2 = await apiPost(
35645
36835
  requireAuth(ctx),
35646
- `${baseUrl(requireAuth(ctx), workspace)}/${id}/enroll`,
36836
+ `${baseUrl2(requireAuth(ctx), workspace)}/${id}/enroll`,
35647
36837
  data
35648
36838
  );
35649
36839
  outputData(listResult(result2, false), ctx, MEMBER_JOURNEY_COLUMNS);
@@ -35663,7 +36853,7 @@ var journeysDomain = {
35663
36853
  const id = requireString(args, "id");
35664
36854
  await apiPost(
35665
36855
  requireAuth(ctx),
35666
- `${baseUrl(requireAuth(ctx), workspace)}/${id}/unenroll`,
36856
+ `${baseUrl2(requireAuth(ctx), workspace)}/${id}/unenroll`,
35667
36857
  data
35668
36858
  );
35669
36859
  process.stdout.write(`Unenrolled member(s) from journey ${id}
@@ -35681,7 +36871,7 @@ var journeysDomain = {
35681
36871
  const id = requireString(args, "id");
35682
36872
  const result2 = await apiPost(
35683
36873
  requireAuth(ctx),
35684
- `${baseUrl(requireAuth(ctx), workspace)}/${id}/reenroll`,
36874
+ `${baseUrl2(requireAuth(ctx), workspace)}/${id}/reenroll`,
35685
36875
  data
35686
36876
  );
35687
36877
  outputSingle(result2, ctx, MEMBER_JOURNEY_COLUMNS);
@@ -35701,7 +36891,7 @@ var journeysDomain = {
35701
36891
  const memberId = requireString(args, "member-id");
35702
36892
  await apiDelete(
35703
36893
  requireAuth(ctx),
35704
- `${baseUrl(requireAuth(ctx), workspace)}/${journeyId}/members/${memberId}`
36894
+ `${baseUrl2(requireAuth(ctx), workspace)}/${journeyId}/members/${memberId}`
35705
36895
  );
35706
36896
  process.stdout.write(
35707
36897
  `Deleted enrollment for member ${memberId} from journey ${journeyId}
@@ -35718,7 +36908,7 @@ var journeysDomain = {
35718
36908
  const journeyId = requireString(args, "journey-id");
35719
36909
  const result2 = await apiGet(
35720
36910
  requireAuth(ctx),
35721
- `${baseUrl(requireAuth(ctx), workspace)}/${journeyId}/members`
36911
+ `${baseUrl2(requireAuth(ctx), workspace)}/${journeyId}/members`
35722
36912
  );
35723
36913
  outputData(listResult(result2, false), ctx, MEMBER_JOURNEY_COLUMNS);
35724
36914
  }
@@ -35732,7 +36922,7 @@ var journeysDomain = {
35732
36922
  const memberId = requireString(args, "member-id");
35733
36923
  const result2 = await apiGet(
35734
36924
  requireAuth(ctx),
35735
- `${baseUrl(requireAuth(ctx), workspace)}/by-member/${memberId}`
36925
+ `${baseUrl2(requireAuth(ctx), workspace)}/by-member/${memberId}`
35736
36926
  );
35737
36927
  outputData(listResult(result2, false), ctx, MEMBER_JOURNEY_COLUMNS);
35738
36928
  }
@@ -35759,7 +36949,7 @@ var journeysDomain = {
35759
36949
  const stepId = requireString(args, "id");
35760
36950
  const result2 = await apiPost(
35761
36951
  requireAuth(ctx),
35762
- `${baseUrl(requireAuth(ctx), workspace)}/${journeyId}/steps/${stepId}/advance`,
36952
+ `${baseUrl2(requireAuth(ctx), workspace)}/${journeyId}/steps/${stepId}/advance`,
35763
36953
  data ?? {}
35764
36954
  );
35765
36955
  outputSingle(result2, ctx, MEMBER_STEP_COLUMNS);
@@ -35782,7 +36972,7 @@ var journeysDomain = {
35782
36972
  const stepId = requireString(args, "id");
35783
36973
  const result2 = await apiPost(
35784
36974
  requireAuth(ctx),
35785
- `${baseUrl(requireAuth(ctx), workspace)}/${journeyId}/steps/${stepId}/skip`,
36975
+ `${baseUrl2(requireAuth(ctx), workspace)}/${journeyId}/steps/${stepId}/skip`,
35786
36976
  data ?? {}
35787
36977
  );
35788
36978
  outputSingle(result2, ctx, MEMBER_STEP_COLUMNS);
@@ -35813,7 +37003,7 @@ var journeysDomain = {
35813
37003
  if (d.pageSize) qs.set("pageSize", String(d.pageSize));
35814
37004
  }
35815
37005
  const query = qs.toString();
35816
- const url = `${baseUrl(requireAuth(ctx), workspace)}/${journeyId}/steps/${stepId}/members${query ? `?${query}` : ""}`;
37006
+ const url = `${baseUrl2(requireAuth(ctx), workspace)}/${journeyId}/steps/${stepId}/members${query ? `?${query}` : ""}`;
35817
37007
  const result2 = await apiGet(requireAuth(ctx), url);
35818
37008
  const STEP_MEMBER_COLS = [
35819
37009
  { header: "MEMBER_ID", getValue: (item) => String(item.memberId ?? "") },
@@ -35836,7 +37026,7 @@ var journeysDomain = {
35836
37026
  const id = requireString(args, "id");
35837
37027
  const result2 = await apiGet(
35838
37028
  requireAuth(ctx),
35839
- `${baseUrl(requireAuth(ctx), workspace)}/${id}/step-member-counts`
37029
+ `${baseUrl2(requireAuth(ctx), workspace)}/${id}/step-member-counts`
35840
37030
  );
35841
37031
  const COUNT_COLS = [
35842
37032
  { header: "STEP_ID", getValue: (item) => String(item.stepId ?? "") },
@@ -36454,6 +37644,178 @@ var sitesDomain = {
36454
37644
  }
36455
37645
  ]
36456
37646
  };
37647
+ init_output();
37648
+ init_context();
37649
+ init_errors();
37650
+ var ATTACHED_COLUMNS = [
37651
+ { header: "UUID", getValue: (item) => item.uuid ?? "" },
37652
+ { header: "TYPE", getValue: (item) => item.abilityType ?? "" },
37653
+ { header: "ENABLED", getValue: (item) => item.enabled === false ? "" : "yes" },
37654
+ { header: "CEL", getValue: (item) => item.celCondition ?? "" }
37655
+ ];
37656
+ function toAbilityData(a) {
37657
+ return {
37658
+ uuid: a.uuid,
37659
+ abilityType: a.abilityType,
37660
+ config: a.config ?? {},
37661
+ enabled: a.enabled ?? true,
37662
+ ...a.celCondition ? { celCondition: a.celCondition } : {}
37663
+ };
37664
+ }
37665
+ var TYPE_COLUMNS = [
37666
+ { header: "SLUG", getValue: (item) => item.slug ?? "" },
37667
+ { header: "TITLE", getValue: (item) => item.title ?? "" },
37668
+ { header: "CATEGORY", getValue: (item) => item.category ?? "" },
37669
+ {
37670
+ header: "CHANNELS",
37671
+ // null channels means "all channels" — show that explicitly so an empty
37672
+ // cell never reads as "no channels".
37673
+ getValue: (item) => Array.isArray(item.channels) ? item.channels.join(",") : "all"
37674
+ },
37675
+ { header: "SINGLETON", getValue: (item) => item.singleton ? "yes" : "" },
37676
+ { header: "FEATURE-GATE", getValue: (item) => item.requiredFeature ?? "" }
37677
+ ];
37678
+ var abilitiesDomain = {
37679
+ name: "abilities",
37680
+ description: "Inspect ability types and attach/detach them on a task",
37681
+ commands: [
37682
+ {
37683
+ path: ["abilities", "list"],
37684
+ description: "List builtin ability types with their channel constraints and param specs. Table shows SLUG, TITLE, CATEGORY, CHANNELS (all = every channel), SINGLETON, FEATURE-GATE; use -o json for full specs including the params JSON Schema.",
37685
+ requiresWorkspace: true,
37686
+ columns: TYPE_COLUMNS,
37687
+ args: [
37688
+ {
37689
+ name: "include-system",
37690
+ description: "Also list auto-injected system abilities (hidden by default)",
37691
+ isFlag: true
37692
+ }
37693
+ ],
37694
+ handler: async (hctx) => {
37695
+ const includeSystem = hctx.args["include-system"] === true;
37696
+ const result2 = await requireAuth(hctx.ctx).apiClient.getAbilityTypes(
37697
+ hctx.workspace,
37698
+ includeSystem ? { includeSystem: true } : {}
37699
+ );
37700
+ outputData(result2.types ?? [], hctx.ctx, TYPE_COLUMNS);
37701
+ }
37702
+ },
37703
+ {
37704
+ path: ["abilities", "get"],
37705
+ description: "Show the full spec for one ability type: title, description, category, channels, singleton/system flags, required feature, and the JSON Schema of its params model.",
37706
+ requiresWorkspace: true,
37707
+ args: [
37708
+ {
37709
+ name: "name",
37710
+ aliases: ["slug"],
37711
+ description: "Ability type slug (e.g. 'communication:phone_call_tools')",
37712
+ required: true
37713
+ }
37714
+ ],
37715
+ handler: async (hctx) => {
37716
+ const slug = hctx.args.name ?? hctx.args.slug;
37717
+ if (!slug) throw new CLIError("--name is required");
37718
+ const result2 = await requireAuth(hctx.ctx).apiClient.getAbilityType(
37719
+ hctx.workspace,
37720
+ slug
37721
+ );
37722
+ outputSingle(result2, hctx.ctx);
37723
+ }
37724
+ },
37725
+ {
37726
+ path: ["abilities", "attached"],
37727
+ description: "List a task's task-specific abilities (excludes workflow-inherited).",
37728
+ requiresWorkspace: true,
37729
+ columns: ATTACHED_COLUMNS,
37730
+ args: [{ name: "task", description: "Task ID", required: true }],
37731
+ handler: async (hctx) => {
37732
+ const task = await requireAuth(hctx.ctx).apiClient.getTask(
37733
+ hctx.workspace,
37734
+ requireNumber(hctx.args, "task")
37735
+ );
37736
+ outputData(task.abilities ?? [], hctx.ctx, ATTACHED_COLUMNS);
37737
+ }
37738
+ },
37739
+ {
37740
+ path: ["abilities", "attach"],
37741
+ description: "Attach an ability to a task. Reads the task, appends the new ability (generating its uuid), and saves \u2014 so existing abilities aren't lost. Find slugs via 'gr abilities list' and the config schema via 'gr abilities get'.",
37742
+ mutates: true,
37743
+ requiresWorkspace: true,
37744
+ args: [
37745
+ { name: "task", description: "Task ID to attach to", required: true },
37746
+ {
37747
+ name: "type",
37748
+ aliases: ["ability-type", "slug"],
37749
+ description: "Ability type slug, e.g. 'integration:data_access'",
37750
+ required: true
37751
+ },
37752
+ {
37753
+ name: "config",
37754
+ description: `Ability config as a JSON object, e.g. '{"pauseOnEscalate":true}'`
37755
+ },
37756
+ { name: "cel", description: "Optional CEL activation condition" },
37757
+ {
37758
+ name: "disabled",
37759
+ description: "Attach in a disabled state (default: enabled)",
37760
+ isFlag: true
37761
+ }
37762
+ ],
37763
+ handler: async (hctx) => {
37764
+ const api = requireAuth(hctx.ctx).apiClient;
37765
+ const taskId = requireNumber(hctx.args, "task");
37766
+ const abilityType = hctx.args.type ?? hctx.args["ability-type"] ?? hctx.args.slug;
37767
+ if (!abilityType) throw new CLIError("--type is required (an ability type slug)");
37768
+ let config = {};
37769
+ if (hctx.args.config) {
37770
+ try {
37771
+ config = JSON.parse(hctx.args.config);
37772
+ } catch {
37773
+ throw new CLIError("--config must be a valid JSON object");
37774
+ }
37775
+ }
37776
+ const task = await api.getTask(hctx.workspace, taskId);
37777
+ const existing = (task.abilities ?? []).map(toAbilityData);
37778
+ const next = {
37779
+ uuid: randomUUID(),
37780
+ abilityType,
37781
+ config,
37782
+ enabled: hctx.args.disabled !== true,
37783
+ ...hctx.args.cel ? { celCondition: hctx.args.cel } : {}
37784
+ };
37785
+ const updated = await api.updateTask(hctx.workspace, taskId, {
37786
+ abilities: [...existing, next]
37787
+ });
37788
+ outputData(updated.abilities ?? [], hctx.ctx, ATTACHED_COLUMNS);
37789
+ }
37790
+ },
37791
+ {
37792
+ path: ["abilities", "detach"],
37793
+ description: "Detach an ability from a task by its uuid (from `gr abilities attached`). Re-saves the remaining task-specific abilities so the rest are preserved.",
37794
+ mutates: true,
37795
+ requiresWorkspace: true,
37796
+ args: [
37797
+ { name: "task", description: "Task ID", required: true },
37798
+ { name: "uuid", description: "UUID of the attached ability to remove", required: true }
37799
+ ],
37800
+ handler: async (hctx) => {
37801
+ const api = requireAuth(hctx.ctx).apiClient;
37802
+ const taskId = requireNumber(hctx.args, "task");
37803
+ const uuid = hctx.args.uuid;
37804
+ if (!uuid) throw new CLIError("--uuid is required");
37805
+ const task = await api.getTask(hctx.workspace, taskId);
37806
+ const existing = task.abilities ?? [];
37807
+ const remaining = existing.filter((a) => a.uuid !== uuid).map(toAbilityData);
37808
+ if (remaining.length === existing.length) {
37809
+ throw new CLIError(`No attached ability with uuid '${uuid}' on task ${taskId}`);
37810
+ }
37811
+ const updated = await api.updateTask(hctx.workspace, taskId, {
37812
+ abilities: remaining
37813
+ });
37814
+ outputData(updated.abilities ?? [], hctx.ctx, ATTACHED_COLUMNS);
37815
+ }
37816
+ }
37817
+ ]
37818
+ };
36457
37819
 
36458
37820
  // src/domains/access-grants.ts
36459
37821
  init_output();
@@ -36530,6 +37892,7 @@ var accessGrantsDomain = {
36530
37892
  {
36531
37893
  path: ["access-grants", "resolve"],
36532
37894
  description: "Resolve an access grant",
37895
+ mutates: true,
36533
37896
  requiresWorkspace: true,
36534
37897
  args: [{ name: "id", description: "Access grant ID", required: true }],
36535
37898
  handler: async ({ ctx, workspace, args, data }) => {
@@ -36986,6 +38349,151 @@ var authManageDomain = {
36986
38349
  ]
36987
38350
  };
36988
38351
 
38352
+ // src/domains/billing.ts
38353
+ init_context();
38354
+ init_output();
38355
+ function priceSummary(product) {
38356
+ const plans = product.plans ?? {};
38357
+ const abbr = { month: "mo", year: "yr", quarter: "qtr" };
38358
+ const parts = [];
38359
+ for (const [period, plan] of Object.entries(plans)) {
38360
+ const cents = plan?.costPerPeriod ?? 0;
38361
+ if (!plan?.stripePriceId) continue;
38362
+ parts.push(`$${(cents / 100).toFixed(0)}/${abbr[period] ?? period}`);
38363
+ }
38364
+ return parts.join(", ") || "\u2014";
38365
+ }
38366
+ var PRODUCT_COLUMNS2 = [
38367
+ { header: "ID", getValue: (p) => String(p.id ?? "") },
38368
+ { header: "NAME", getValue: (p) => p.name ?? "" },
38369
+ { header: "TYPE", getValue: (p) => String(p.productType ?? "") },
38370
+ { header: "PRICE", getValue: (p) => priceSummary(p) },
38371
+ {
38372
+ header: "TRIAL",
38373
+ getValue: (p) => {
38374
+ const days = p.trialPeriodDays ?? 0;
38375
+ return days > 0 ? `${days}d` : "\u2014";
38376
+ }
38377
+ }
38378
+ ];
38379
+ var SUBSCRIPTION_COLUMNS = [
38380
+ COL.id(),
38381
+ COL.status(),
38382
+ { header: "PLAN", getValue: (s) => String(s.plan_name ?? s.productName ?? s.plan ?? "") },
38383
+ { header: "PERIOD", getValue: (s) => String(s.planPeriod ?? s.plan_period ?? "") },
38384
+ {
38385
+ header: "ORG",
38386
+ getValue: (s) => String(s.organizationUuid ?? s.customerOrganizationUuid ?? "")
38387
+ }
38388
+ ];
38389
+ function isTable(ctx) {
38390
+ return (ctx.outputFormat ?? "table") === "table";
38391
+ }
38392
+ function hint(ctx, lines) {
38393
+ if (!isTable(ctx)) return;
38394
+ process.stdout.write("\n" + lines.join("\n") + "\n");
38395
+ }
38396
+ function productType(args) {
38397
+ const t = args.type ?? args["product-type"];
38398
+ if (t === "org" || t === "workspace") return t;
38399
+ return void 0;
38400
+ }
38401
+ var billingDomain = {
38402
+ name: "billing",
38403
+ description: "Browse plans, start checkout, and check subscription status",
38404
+ commands: [
38405
+ {
38406
+ path: ["billing", "products"],
38407
+ description: "List self-service plans you can purchase",
38408
+ requiresWorkspace: false,
38409
+ args: [
38410
+ {
38411
+ name: "type",
38412
+ description: "Filter by plan type: 'org' or 'workspace'"
38413
+ }
38414
+ ],
38415
+ examples: ["gr billing products --type org"],
38416
+ handler: async ({ ctx, args }) => {
38417
+ const products = await requireAuth(ctx).apiClient.listSelfServeProducts(
38418
+ productType(args)
38419
+ );
38420
+ outputData(products, ctx, PRODUCT_COLUMNS2);
38421
+ if (products.length === 0) {
38422
+ hint(ctx, ["No purchasable plans found. (Free plans are not sold via the CLI.)"]);
38423
+ } else {
38424
+ hint(ctx, [
38425
+ "Next \u2014 buy an organization plan to get started:",
38426
+ " gr billing checkout --product <id> [--period month|year]"
38427
+ ]);
38428
+ }
38429
+ }
38430
+ },
38431
+ {
38432
+ path: ["billing", "checkout"],
38433
+ description: "Get a Stripe payment link to purchase an organization plan",
38434
+ mutates: true,
38435
+ requiresWorkspace: false,
38436
+ args: [
38437
+ { name: "product", description: "Product ID of the org plan to buy", required: true },
38438
+ { name: "period", description: "Billing period: 'month' or 'year'", default: "month" }
38439
+ ],
38440
+ examples: ["gr billing checkout --product 12 --period month"],
38441
+ handler: async ({ ctx, args }) => {
38442
+ const productId = Number(requireString(args, "product"));
38443
+ const period = args.period || "month";
38444
+ const result2 = await requireAuth(ctx).apiClient.createCheckoutSession(
38445
+ productId,
38446
+ period
38447
+ );
38448
+ if (isTable(ctx)) {
38449
+ process.stdout.write(
38450
+ `
38451
+ \u{1F4B3} Open this link in a browser to complete payment:
38452
+
38453
+ ${result2.checkoutUrl}
38454
+
38455
+ Once payment succeeds, your organization and subscription are created automatically.
38456
+ Then check it landed:
38457
+ gr billing status
38458
+ `
38459
+ );
38460
+ } else {
38461
+ outputSingle(result2, ctx);
38462
+ }
38463
+ }
38464
+ },
38465
+ {
38466
+ path: ["billing", "status"],
38467
+ description: "Show your subscriptions and what to do next",
38468
+ requiresWorkspace: false,
38469
+ examples: ["gr billing status"],
38470
+ handler: async ({ ctx }) => {
38471
+ const subs = await requireAuth(ctx).apiClient.getSubscriptions();
38472
+ outputData(subs, ctx, SUBSCRIPTION_COLUMNS);
38473
+ const active = subs.find(
38474
+ (s) => ["active", "trialing"].includes(String(s.status ?? s.subscriptionStatus ?? ""))
38475
+ );
38476
+ if (!active) {
38477
+ hint(ctx, [
38478
+ "No active subscription yet. To get started:",
38479
+ " gr billing products --type org # pick a plan",
38480
+ " gr billing checkout --product <id> # pay up front"
38481
+ ]);
38482
+ return;
38483
+ }
38484
+ const orgUuid = String(
38485
+ active.organizationUuid ?? active.customerOrganizationUuid ?? "<org-uuid>"
38486
+ );
38487
+ hint(ctx, [
38488
+ "You have an active subscription. Add a workspace:",
38489
+ " gr billing products --type workspace # pick a workspace plan",
38490
+ ` gr workspaces create --org ${orgUuid} --product <id> --name "My Workspace"`
38491
+ ]);
38492
+ }
38493
+ }
38494
+ ]
38495
+ };
38496
+
36989
38497
  // src/domains/billing-portal.ts
36990
38498
  init_errors();
36991
38499
  init_output();
@@ -37139,7 +38647,7 @@ init_errors();
37139
38647
  init_output();
37140
38648
  init_context();
37141
38649
  var COLUMNS17 = [COL.id(), COL.name(), COL.description(), COL.enabled()];
37142
- var TOOL_COLUMNS2 = [COL.id(), COL.name(), COL.description()];
38650
+ var TOOL_COLUMNS3 = [COL.id(), COL.name(), COL.description()];
37143
38651
  var customToolkitsDomain = {
37144
38652
  name: "custom-toolkits",
37145
38653
  description: "Manage custom toolkits and their tools",
@@ -37197,7 +38705,7 @@ var customToolkitsDomain = {
37197
38705
  toolkitId,
37198
38706
  data
37199
38707
  );
37200
- outputSingle(result2, ctx, TOOL_COLUMNS2);
38708
+ outputSingle(result2, ctx, TOOL_COLUMNS3);
37201
38709
  }
37202
38710
  },
37203
38711
  {
@@ -37219,7 +38727,7 @@ var customToolkitsDomain = {
37219
38727
  toolId,
37220
38728
  data
37221
38729
  );
37222
- outputSingle(result2, ctx, TOOL_COLUMNS2);
38730
+ outputSingle(result2, ctx, TOOL_COLUMNS3);
37223
38731
  }
37224
38732
  },
37225
38733
  {
@@ -38459,6 +39967,50 @@ function parseCallerRole(value) {
38459
39967
  }
38460
39968
  return VALID_CALLER_ROLES.has(value) ? value : void 0;
38461
39969
  }
39970
+ var PERMISSION_USE2 = 1;
39971
+ function evaluateWorkflowMemberRoleAccess(memberRoleId, memberRoleAccess) {
39972
+ if (memberRoleAccess === void 0) {
39973
+ return { outcome: "skip", detail: "workflow memberRoleAccess not available" };
39974
+ }
39975
+ if (memberRoleAccess.length === 0) {
39976
+ return { outcome: "allow", detail: "no workflow role restrictions configured" };
39977
+ }
39978
+ if (memberRoleId === void 0) {
39979
+ return {
39980
+ outcome: "skip",
39981
+ detail: "caller member role unknown \u2014 cannot evaluate role gate"
39982
+ };
39983
+ }
39984
+ const hasUse = memberRoleAccess.some(
39985
+ (entry) => entry.memberRoleId === memberRoleId && (entry.accessMode & PERMISSION_USE2) === PERMISSION_USE2
39986
+ );
39987
+ if (hasUse) {
39988
+ return { outcome: "allow", detail: `memberRoleId=${memberRoleId} has USE on workflow` };
39989
+ }
39990
+ return {
39991
+ outcome: "deny",
39992
+ detail: `memberRoleId=${memberRoleId} lacks USE in workflow memberRoleAccess`
39993
+ };
39994
+ }
39995
+ function parseWorkflowMemberRoleAccess(workflow) {
39996
+ const raw = workflow.memberRoleAccess;
39997
+ if (!Array.isArray(raw)) {
39998
+ return [];
39999
+ }
40000
+ const entries = [];
40001
+ for (const item of raw) {
40002
+ if (!item || typeof item !== "object") {
40003
+ continue;
40004
+ }
40005
+ const row = item;
40006
+ const memberRoleId = typeof row.memberRoleId === "number" ? row.memberRoleId : Number(row.memberRoleId);
40007
+ const accessMode = typeof row.accessMode === "number" ? row.accessMode : Number(row.accessMode);
40008
+ if (Number.isFinite(memberRoleId) && Number.isFinite(accessMode)) {
40009
+ entries.push({ memberRoleId, accessMode });
40010
+ }
40011
+ }
40012
+ return entries;
40013
+ }
38462
40014
  function inferCallerRole(phone, opts) {
38463
40015
  if (opts.asRole) {
38464
40016
  return opts.asRole;
@@ -38585,6 +40137,32 @@ function simulateInboundRouting(phone, opts = {}) {
38585
40137
  return finish("no_inbound_workflow", false, true, steps, recommendations, callerRole);
38586
40138
  }
38587
40139
  steps.push({ step: "inbound_workflow", outcome: "ok", detail: `workflowId=${workflowId}` });
40140
+ const callerMemberRoleId = callerRole === "member" ? opts.matchedMemberRoleId : callerRole === "anonymous" ? phone.anonymousMemberRoleId ?? void 0 : void 0;
40141
+ const roleAccess = evaluateWorkflowMemberRoleAccess(
40142
+ callerMemberRoleId,
40143
+ opts.workflowMemberRoleAccess
40144
+ );
40145
+ if (roleAccess.outcome === "deny") {
40146
+ steps.push({
40147
+ step: "workflow_member_role_access",
40148
+ outcome: "reject",
40149
+ detail: roleAccess.detail
40150
+ });
40151
+ recommendations.push(
40152
+ "Grant the caller's member role USE access on the inbound workflow (workflow memberRoleAccess or `gr member-roles update` workflowAccess)"
40153
+ );
40154
+ return finish("workflow_member_role_denied", false, true, steps, recommendations, callerRole);
40155
+ }
40156
+ steps.push({
40157
+ step: "workflow_member_role_access",
40158
+ outcome: roleAccess.outcome === "skip" ? "skipped" : "ok",
40159
+ detail: roleAccess.detail
40160
+ });
40161
+ if (roleAccess.outcome === "skip" && callerMemberRoleId === void 0 && opts.workflowMemberRoleAccess !== void 0 && opts.workflowMemberRoleAccess.length > 0) {
40162
+ recommendations.push(
40163
+ "Workflow has member role restrictions but caller memberRoleId was not resolved \u2014 re-run with --as +E.164 (caller phone) so the role gate can be evaluated against real data"
40164
+ );
40165
+ }
38588
40166
  steps.push({ step: "chat_create", outcome: "create_phone_voice_chat" });
38589
40167
  steps.push({ step: "assistant", outcome: "connect_media_stream" });
38590
40168
  return finish("ai_voice_chat", true, true, steps, recommendations, callerRole);
@@ -38601,6 +40179,7 @@ function finish(code, createsChat, createsPhoneCall, steps, recommendations, cal
38601
40179
  voicemail_record: "Record voicemail",
38602
40180
  play_message_hangup: "Play off-hours message, hang up",
38603
40181
  no_inbound_workflow: "Play unavailable message (no inbound workflow)",
40182
+ workflow_member_role_denied: "Reject \u2014 caller member role lacks workflow USE (memberRoleAccess)",
38604
40183
  ai_voice_chat: "Create chat + connect AI voice"
38605
40184
  };
38606
40185
  return {
@@ -38652,9 +40231,22 @@ function formatPhoneNumberBehaviorMatrix(phone, outboundUsers, warnings = collec
38652
40231
  lines.push(`UUID: ${phone.uuid} | Mapped: ${phone.isMapped ? "yes" : "no"}`);
38653
40232
  lines.push("");
38654
40233
  lines.push("## Channels");
38655
- lines.push(` Voice: ${phone.enableVoice ? "on" : "off"} SMS: ${phone.enableSms ? "on" : "off"} WhatsApp: ${phone.enableWhatsApp ? "on" : "off"}`);
40234
+ lines.push(
40235
+ ` Voice: ${phone.enableVoice ? "on" : "off"} SMS: ${phone.enableSms ? "on" : "off"} WhatsApp: ${phone.enableWhatsApp ? "on" : "off"}`
40236
+ );
38656
40237
  lines.push(` Assistant: ${phone.assistantEnabled ? "on" : "off"}`);
38657
40238
  lines.push("");
40239
+ if (phone.enableVoice) {
40240
+ lines.push("## Channel defaults (auto-injected on voice)");
40241
+ lines.push(
40242
+ " Voice channels auto-add the hang_up_call tool (system:voice_channel);"
40243
+ );
40244
+ lines.push(
40245
+ " it is not listed by `gr agents abilities list`. See `gr abilities get"
40246
+ );
40247
+ lines.push(" --name communication:phone_call_tools` for the voice ability spec.");
40248
+ lines.push("");
40249
+ }
38658
40250
  lines.push("## Inbound route");
38659
40251
  lines.push(
38660
40252
  ` defaultWorkflowId (inbound): ${phone.defaultWorkflowId ?? "null"} restartDelay: ${phone.restartDelay ?? "null"}s`
@@ -38735,9 +40327,7 @@ async function findOutboundPhoneUsers(client, workspace, phone) {
38735
40327
  }
38736
40328
  page += 1;
38737
40329
  if (page > 50) {
38738
- process.stderr.write(
38739
- "Warning: event-rules lookup truncated at 5000 results (50 pages)\n"
38740
- );
40330
+ process.stderr.write("Warning: event-rules lookup truncated at 5000 results (50 pages)\n");
38741
40331
  break;
38742
40332
  }
38743
40333
  }
@@ -38756,7 +40346,9 @@ function normalizeCallerE164(phone) {
38756
40346
  var MEMBER_SEARCH_PAGE_SIZE = 100;
38757
40347
  async function resolveMemberByCallerPhone(client, workspace, callerE164) {
38758
40348
  const normalized = normalizeCallerE164(callerE164);
38759
- const candidates = [normalized, callerE164.trim()].filter(
40349
+ const digits = callerE164.replace(/\D/g, "");
40350
+ const nsn = digits.length === 11 && digits.startsWith("1") ? digits.slice(1) : digits;
40351
+ const candidates = [normalized, callerE164.trim(), digits, nsn].filter(
38760
40352
  (v, i, arr) => Boolean(v) && arr.indexOf(v) === i
38761
40353
  );
38762
40354
  const matchInRows = (rows) => {
@@ -38801,6 +40393,25 @@ async function resolveMemberByCallerPhone(client, workspace, callerE164) {
38801
40393
  return void 0;
38802
40394
  }
38803
40395
 
40396
+ // src/lib/phone-numbers/workflow-role-access.ts
40397
+ async function loadInboundWorkflowMemberRoleAccess(client, workspace, defaultWorkflowId) {
40398
+ const workflowId = typeof defaultWorkflowId === "number" ? defaultWorkflowId : defaultWorkflowId === null || defaultWorkflowId === void 0 ? void 0 : Number(defaultWorkflowId);
40399
+ if (workflowId === void 0 || !Number.isFinite(workflowId)) {
40400
+ return void 0;
40401
+ }
40402
+ try {
40403
+ const workflow = await client.getWorkflow(workspace, workflowId);
40404
+ return parseWorkflowMemberRoleAccess(workflow);
40405
+ } catch (err) {
40406
+ const reason = err instanceof Error ? err.message : String(err);
40407
+ process.stderr.write(
40408
+ `[diagnose] Could not fetch workflow ${workflowId} memberRoleAccess \u2014 role gate will be skipped (${reason})
40409
+ `
40410
+ );
40411
+ return void 0;
40412
+ }
40413
+ }
40414
+
38804
40415
  // src/domains/phone-numbers.ts
38805
40416
  function asPhoneRecord(value) {
38806
40417
  return value;
@@ -38859,9 +40470,8 @@ var phoneNumbersDomain = {
38859
40470
  const client = requireAuth(ctx).apiClient;
38860
40471
  const id = requireNumber(args, "id");
38861
40472
  const phone = asPhoneRecord(await client.getPhoneNumber(workspace, id));
38862
- if (args.raw) {
38863
- process.stdout.write(`${JSON.stringify(phone, null, 2)}
38864
- `);
40473
+ if (args.raw || ctx.outputFormat !== "table") {
40474
+ outputSingle(phone, ctx);
38865
40475
  return;
38866
40476
  }
38867
40477
  const outboundUsers = await findOutboundPhoneUsers(client, workspace, phone);
@@ -39035,21 +40645,34 @@ Setup complete: id=${phone.id} uuid=${phone.uuid}
39035
40645
  const asRole = parseCallerRole(args["as-role"]);
39036
40646
  let hasMemberMatch = asRole === "member";
39037
40647
  let matchedMemberId;
40648
+ let matchedMemberRoleId;
39038
40649
  let matchedMemberPhoneType;
39039
40650
  if (!asRole && typeof args.as === "string") {
39040
40651
  const match = await resolveMemberByCallerPhone(client, workspace, args.as);
39041
40652
  if (match) {
39042
40653
  hasMemberMatch = true;
39043
40654
  matchedMemberId = match.memberId;
40655
+ matchedMemberRoleId = match.memberRoleId;
39044
40656
  matchedMemberPhoneType = match.phoneType;
39045
40657
  }
39046
40658
  }
40659
+ const workflowMemberRoleAccess = await loadInboundWorkflowMemberRoleAccess(
40660
+ client,
40661
+ workspace,
40662
+ phone.defaultWorkflowId
40663
+ );
39047
40664
  const sim = simulateInboundRouting(phone, {
39048
40665
  asRole,
39049
40666
  hasMemberMatch,
39050
40667
  matchedMemberId,
39051
- matchedMemberPhoneType
40668
+ matchedMemberRoleId,
40669
+ matchedMemberPhoneType,
40670
+ workflowMemberRoleAccess
39052
40671
  });
40672
+ if (ctx.outputFormat !== "table") {
40673
+ outputSingle({ phoneNumberId: id, simulation: sim }, ctx);
40674
+ return;
40675
+ }
39053
40676
  process.stdout.write(`${formatRoutingSimulation(sim, phone)}
39054
40677
  `);
39055
40678
  }
@@ -39071,10 +40694,28 @@ Setup complete: id=${phone.id} uuid=${phone.uuid}
39071
40694
  const id = requireNumber(args, "id");
39072
40695
  const role = requireCallerRole(args, "as-role");
39073
40696
  const phone = asPhoneRecord(await client.getPhoneNumber(workspace, id));
40697
+ const workflowMemberRoleAccess = await loadInboundWorkflowMemberRoleAccess(
40698
+ client,
40699
+ workspace,
40700
+ phone.defaultWorkflowId
40701
+ );
39074
40702
  const sim = simulateInboundRouting(phone, {
39075
40703
  asRole: role,
39076
- hasMemberMatch: role === "member"
40704
+ hasMemberMatch: role === "member",
40705
+ workflowMemberRoleAccess
39077
40706
  });
40707
+ if (ctx.outputFormat !== "table") {
40708
+ outputSingle(
40709
+ {
40710
+ phoneNumberId: id,
40711
+ callerRole: role,
40712
+ finalBehavior: sim.finalBehavior,
40713
+ simulation: sim
40714
+ },
40715
+ ctx
40716
+ );
40717
+ return;
40718
+ }
39078
40719
  process.stdout.write(
39079
40720
  `If a caller in role "${role}" dials this line right now:
39080
40721
  \u2192 ${sim.finalBehavior}
@@ -39100,17 +40741,26 @@ ${formatRoutingSimulation(sim, phone)}
39100
40741
  const asRole = parseCallerRole(args["as-role"]);
39101
40742
  let hasMemberMatch = asRole === "member";
39102
40743
  let matchedMemberId;
40744
+ let matchedMemberRoleId;
39103
40745
  if (!asRole && typeof args.as === "string") {
39104
40746
  const match = await resolveMemberByCallerPhone(client, workspace, args.as);
39105
40747
  if (match) {
39106
40748
  hasMemberMatch = true;
39107
40749
  matchedMemberId = match.memberId;
40750
+ matchedMemberRoleId = match.memberRoleId;
39108
40751
  }
39109
40752
  }
40753
+ const workflowMemberRoleAccess = await loadInboundWorkflowMemberRoleAccess(
40754
+ client,
40755
+ workspace,
40756
+ phone.defaultWorkflowId
40757
+ );
39110
40758
  const sim = simulateInboundRouting(phone, {
39111
40759
  asRole,
39112
40760
  hasMemberMatch,
39113
- matchedMemberId
40761
+ matchedMemberId,
40762
+ matchedMemberRoleId,
40763
+ workflowMemberRoleAccess
39114
40764
  });
39115
40765
  process.stdout.write(
39116
40766
  `${JSON.stringify({ phoneNumberId: id, simulation: sim }, null, 2)}
@@ -39154,11 +40804,15 @@ ${formatRoutingSimulation(sim, phone)}
39154
40804
  { inbound: true }
39155
40805
  );
39156
40806
  const inbound = result2.items ?? [];
39157
- process.stdout.write(`Inbound calls (most recent page): ${inbound.length} shown
40807
+ if (ctx.outputFormat === "table") {
40808
+ process.stdout.write(`Inbound calls (most recent page): ${inbound.length} shown
39158
40809
  `);
39159
- process.stdout.write(
39160
- "Tip: gr phone-numbers diagnose --id <id> --as +1\u2026 simulates routing without a live call.\n"
39161
- );
40810
+ process.stdout.write(
40811
+ "Tip: gr phone-numbers diagnose --id <id> --as +1\u2026 simulates routing without a live call.\n"
40812
+ );
40813
+ } else {
40814
+ stderr2(`Inbound calls (most recent page): ${inbound.length} shown`);
40815
+ }
39162
40816
  outputData(inbound, ctx);
39163
40817
  }
39164
40818
  },
@@ -39539,6 +41193,119 @@ var reportsDomain = {
39539
41193
  ]
39540
41194
  };
39541
41195
 
41196
+ // src/domains/routines.ts
41197
+ init_output();
41198
+ init_context();
41199
+
41200
+ // src/lib/routines/field-help.ts
41201
+ var ROUTINE_FIELD_REFERENCE = `
41202
+ Field reference for --data JSON (create/update):
41203
+
41204
+ Core
41205
+ name (string) Display name
41206
+ workflowId (number) Workflow run when the routine fires
41207
+ targetMemberId (number) Member who receives the scheduled outreach
41208
+
41209
+ Schedule
41210
+ scheduleEnabled (bool) Master on/off for the cron trigger
41211
+ scheduleMode (string) "CRON" (only mode today)
41212
+ cronString (string) Standard cron, e.g. "0 7 * * *"
41213
+ timezone (string, optional) IANA name, e.g. "America/Los_Angeles"
41214
+ Defaults to workspace timezone, else UTC
41215
+
41216
+ Visibility / lifecycle
41217
+ archived (bool) Archive flag on update
41218
+ event rules Use gr events rules create \u2014 not inline here
41219
+ `;
41220
+
41221
+ // src/domains/routines.ts
41222
+ var ROUTINE_COLUMNS = [
41223
+ COL.id(),
41224
+ COL.name(),
41225
+ { header: "MODE", getValue: (item) => item.scheduleMode ?? "" },
41226
+ { header: "CRON", getValue: (item) => item.cronString ?? "" },
41227
+ { header: "TZ", getValue: (item) => item.timezone ?? "UTC" },
41228
+ { header: "ENABLED", getValue: (item) => String(item.scheduleEnabled ?? "") },
41229
+ { header: "NEXT RUN", getValue: (item) => item.nextRun ?? "" }
41230
+ ];
41231
+ var routinesDomain = {
41232
+ name: "routines",
41233
+ description: "Schedule recurring outbound (e.g. a daily SMS/voice check-in via cron)",
41234
+ commands: [
41235
+ ...crudCommands({
41236
+ prefix: ["routines"],
41237
+ entityName: "routine",
41238
+ listMethod: "getRoutines",
41239
+ getMethod: "getRoutine",
41240
+ createMethod: "createRoutine",
41241
+ updateMethod: "updateRoutine",
41242
+ deleteMethod: "deleteRoutine",
41243
+ paginationSupport: "full",
41244
+ columns: ROUTINE_COLUMNS,
41245
+ createHelp: `Create a routine
41246
+
41247
+ ${ROUTINE_FIELD_REFERENCE}`,
41248
+ updateHelp: `Update a routine
41249
+
41250
+ ${ROUTINE_FIELD_REFERENCE}`,
41251
+ createExamples: [
41252
+ "Daily 7am check-in in the member\u2019s timezone (cron is interpreted in `timezone`):",
41253
+ `gr routines create -w $WID --allow-write --data '{"name":"AM check-in",`,
41254
+ ' "scheduleEnabled":true,"scheduleMode":"CRON","cronString":"0 7 * * *",',
41255
+ ` "timezone":"America/Los_Angeles","targetMemberId":1,"workflowId":2}'`,
41256
+ " (timezone is an IANA name; omit it to default to the workspace timezone, else UTC.",
41257
+ ' Without it, "0 7 * * *" fires at 07:00 UTC, not 7am local.)',
41258
+ "",
41259
+ "To actually send via SMS/voice, pair the routine with an event rule:",
41260
+ ' gr events rules create \u2014 objectType "routine", eventType "routine:triggered",',
41261
+ ' actionType "chat:create". See `gr events --help`.'
41262
+ ]
41263
+ }),
41264
+ {
41265
+ path: ["routines", "run"],
41266
+ description: "Run a routine now",
41267
+ mutates: true,
41268
+ requiresWorkspace: true,
41269
+ args: [{ name: "id", description: "Routine ID", required: true }],
41270
+ handler: async ({ ctx, workspace, args, data }) => {
41271
+ const result2 = await requireAuth(ctx).apiClient.runRoutine(
41272
+ workspace,
41273
+ requireNumber(args, "id"),
41274
+ data ?? {}
41275
+ );
41276
+ outputSingle(result2, ctx);
41277
+ }
41278
+ },
41279
+ {
41280
+ path: ["routines", "runs", "list"],
41281
+ description: "List runs for a routine",
41282
+ requiresWorkspace: true,
41283
+ args: [
41284
+ {
41285
+ name: "id",
41286
+ description: "Routine ID (aligns with routines get/run/update/delete)"
41287
+ },
41288
+ { name: "status", description: "Filter by run status" },
41289
+ { name: "page", description: "Page number (1-indexed)" },
41290
+ { name: "page-size", description: "Page size (max 100)" }
41291
+ ],
41292
+ handler: async ({ ctx, workspace, args }) => {
41293
+ const routineId = args.id ? requireNumber(args, "id") : void 0;
41294
+ const page = args.page ? requireNumber(args, "page") : void 0;
41295
+ const pageSize = args["page-size"] ? requireNumber(args, "page-size") : void 0;
41296
+ const status = args.status ?? void 0;
41297
+ const result2 = await requireAuth(ctx).apiClient.getRoutineRuns(workspace, {
41298
+ ...routineId !== void 0 ? { routineId } : {},
41299
+ ...page !== void 0 ? { page } : {},
41300
+ ...pageSize !== void 0 ? { pageSize } : {},
41301
+ ...status ? { status } : {}
41302
+ });
41303
+ outputData(result2, ctx);
41304
+ }
41305
+ }
41306
+ ]
41307
+ };
41308
+
39542
41309
  // src/domains/subscriptions.ts
39543
41310
  init_output();
39544
41311
  init_context();
@@ -41438,11 +43205,13 @@ function registerPublicDomains(registry) {
41438
43205
  registry.register(sitesDomain);
41439
43206
  registry.register(filesDomain);
41440
43207
  registry.register(eventsDomain);
43208
+ registry.register(routinesDomain);
41441
43209
  registry.register(experimentsDomain);
41442
43210
  registry.register(calendarsDomain);
41443
43211
  registry.register(qualificationsDomain);
41444
43212
  registry.register(personasDomain);
41445
43213
  registry.register(journeysDomain);
43214
+ registry.register(abilitiesDomain);
41446
43215
  registry.register(phoneNumbersDomain);
41447
43216
  registry.register(inboxesDomain);
41448
43217
  registry.register(operatorGroupsDomain);
@@ -41455,6 +43224,7 @@ function registerPublicDomains(registry) {
41455
43224
  registry.register(mcpServersDomain);
41456
43225
  registry.register(apiKeysDomain);
41457
43226
  registry.register(subscriptionsDomain);
43227
+ registry.register(billingDomain);
41458
43228
  registry.register(supportDomain);
41459
43229
  registry.register(reportsDomain);
41460
43230
  registry.register(aiModelsDomain);
@@ -41480,9 +43250,6 @@ function registerPublicDomains(registry) {
41480
43250
  registry.register(billingPortalDomain);
41481
43251
  }
41482
43252
 
41483
- // src/lib.ts
41484
- init_concierge_api();
41485
-
41486
43253
  // src/commands/auth-browser.ts
41487
43254
  init_output();
41488
43255
  async function authBrowserCommand(ctx, args) {
@@ -41527,11 +43294,10 @@ function openUrl(url) {
41527
43294
  });
41528
43295
  }
41529
43296
 
41530
- // src/commands/concierge.ts
43297
+ // src/commands/manage.ts
41531
43298
  init_cli_utils();
41532
- init_concierge_api();
41533
- init_context();
41534
43299
  init_errors();
43300
+ init_context();
41535
43301
  function buildCliConciergeAppContext() {
41536
43302
  const shell = process.env.SHELL ? path3.basename(process.env.SHELL) : void 0;
41537
43303
  return {
@@ -41841,24 +43607,42 @@ async function runConciergeAguiLoop(client, initialMessages, onEvent, opts) {
41841
43607
  if (!hitlPayload) {
41842
43608
  break;
41843
43609
  }
41844
- const next = await handleCliHitlInterrupt(hitlPayload, {
41845
- allowWrite: opts.allowWrite,
41846
- autoApprove: opts.autoApprove,
41847
- trustCwd: opts.trustCwd,
41848
- trustDir: opts.trustDir,
41849
- nonInteractive: opts.nonInteractive
41850
- });
43610
+ opts.onHitlPromptStart?.();
43611
+ let next;
43612
+ try {
43613
+ next = await handleCliHitlInterrupt(hitlPayload, {
43614
+ allowWrite: opts.allowWrite,
43615
+ autoApprove: opts.autoApprove,
43616
+ trustCwd: opts.trustCwd,
43617
+ trustDir: opts.trustDir,
43618
+ nonInteractive: opts.nonInteractive
43619
+ });
43620
+ } finally {
43621
+ opts.onHitlPromptEnd?.();
43622
+ }
41851
43623
  if (!next) {
41852
43624
  process.stderr.write(
41853
43625
  " [HITL] Unsupported interrupt in CLI \u2014 open app.gravityrail.com/setup to continue.\n"
41854
43626
  );
41855
- break;
43627
+ return {
43628
+ streamText,
43629
+ hasToolCalls,
43630
+ unsupportedHitl: normalizeUnsupportedHitl(hitlPayload)
43631
+ };
41856
43632
  }
41857
43633
  resume = next;
41858
43634
  streamText = "";
41859
43635
  }
41860
43636
  return { streamText, hasToolCalls };
41861
43637
  }
43638
+ function normalizeUnsupportedHitl(raw) {
43639
+ const payload = raw && typeof raw === "object" ? raw : {};
43640
+ return {
43641
+ type: typeof payload.type === "string" ? payload.type : void 0,
43642
+ interruptId: typeof payload.interrupt_id === "string" ? payload.interrupt_id : void 0,
43643
+ payload
43644
+ };
43645
+ }
41862
43646
 
41863
43647
  // src/lib/chat-session.ts
41864
43648
  init_errors();
@@ -42116,6 +43900,19 @@ function isToolCall(item) {
42116
43900
  function isToolResult(item) {
42117
43901
  return "kind" in item && item.kind === "tool_result";
42118
43902
  }
43903
+ function toolResultLooksFailed(content) {
43904
+ const trimmed = content.trim();
43905
+ if (!trimmed) return false;
43906
+ if (/^error[:\s]/i.test(trimmed)) return true;
43907
+ try {
43908
+ const parsed = JSON.parse(trimmed);
43909
+ if (parsed.ok === false) return true;
43910
+ if (typeof parsed.error === "string" && parsed.error.length > 0) return true;
43911
+ if (typeof parsed.status === "string" && parsed.status.toLowerCase() === "error") return true;
43912
+ } catch {
43913
+ }
43914
+ return false;
43915
+ }
42119
43916
  function getTruncationLabel(reason, truncatedAtMs) {
42120
43917
  const timeStr = truncatedAtMs ? ` at ${(truncatedAtMs / 1e3).toFixed(1)}s` : "";
42121
43918
  switch (reason) {
@@ -42149,6 +43946,8 @@ var CLEAR_EOL = `${CSI}K`;
42149
43946
  var RESET = `${CSI}0m`;
42150
43947
  var MOUSE_ON = `${CSI}?1000h${CSI}?1006h`;
42151
43948
  var MOUSE_OFF = `${CSI}?1000l${CSI}?1006l`;
43949
+ var BRACKETED_PASTE_ON = `${CSI}?2004h`;
43950
+ var BRACKETED_PASTE_OFF = `${CSI}?2004l`;
42152
43951
  var BLUE = `${CSI}34m`;
42153
43952
  var GREEN = `${CSI}32m`;
42154
43953
  var GRAY = `${CSI}90m`;
@@ -42157,6 +43956,11 @@ var ORANGE = `${CSI}38;5;208m`;
42157
43956
  var LIGHT_BLUE = `${CSI}38;5;117m`;
42158
43957
  var DIM = `${CSI}2m`;
42159
43958
  var DIM_ITALIC_GRAY = `${CSI}2;3;90m`;
43959
+ var RED = `${CSI}31m`;
43960
+ var CYAN = `${CSI}36m`;
43961
+ var MAX_INPUT_ROWS = 6;
43962
+ var INPUT_LABEL = "You: ";
43963
+ var INPUT_LABEL_WIDTH = 5;
42160
43964
  function moveTo(row, col) {
42161
43965
  return `${CSI}${row};${col}H`;
42162
43966
  }
@@ -42181,6 +43985,11 @@ var ChatTUI = class {
42181
43985
  // Escape sequence accumulator for raw stdin parsing
42182
43986
  escBuf = "";
42183
43987
  escTimer = null;
43988
+ // Run / inference status (title bar)
43989
+ runState = "idle";
43990
+ activeToolName = "";
43991
+ pausedForPrompt = false;
43992
+ turnInProgress = false;
42184
43993
  constructor(options) {
42185
43994
  this.options = options;
42186
43995
  this.debugPanelVisible = !!options.debug;
@@ -42192,8 +44001,8 @@ var ChatTUI = class {
42192
44001
  // ─── Lifecycle ──────────────────────────────────────────────────────
42193
44002
  start() {
42194
44003
  this.updateDimensions();
42195
- process.stdout.write(ALT_SCREEN_ON + MOUSE_ON);
42196
- process.stdout.write(`${CSI}1;${Math.max(1, this.rows - 2)}r`);
44004
+ process.stdout.write(ALT_SCREEN_ON + MOUSE_ON + BRACKETED_PASTE_ON);
44005
+ this.applyScrollRegion();
42197
44006
  process.stdin.setEncoding("utf8");
42198
44007
  if (process.stdin.isTTY) process.stdin.setRawMode(true);
42199
44008
  process.stdin.on("data", this.onData);
@@ -42236,6 +44045,7 @@ var ChatTUI = class {
42236
44045
  streamStart() {
42237
44046
  this.isStreaming = true;
42238
44047
  this.streamContent = "";
44048
+ this.runState = "streaming";
42239
44049
  this.scrollOffset = 0;
42240
44050
  this.dirty();
42241
44051
  }
@@ -42251,8 +44061,42 @@ var ChatTUI = class {
42251
44061
  this.streamContent = "";
42252
44062
  this.dirty();
42253
44063
  }
44064
+ runStarted() {
44065
+ this.turnInProgress = true;
44066
+ this.runState = "thinking";
44067
+ this.activeToolName = "";
44068
+ this.dirty();
44069
+ }
44070
+ runFinished() {
44071
+ this.turnInProgress = false;
44072
+ this.runState = "idle";
44073
+ this.activeToolName = "";
44074
+ this.dirty();
44075
+ }
44076
+ /** Temporarily leave alt-screen for an external prompt (HITL). */
44077
+ pauseForPrompt() {
44078
+ if (!this.started || this.pausedForPrompt) return;
44079
+ this.pausedForPrompt = true;
44080
+ process.stdin.removeListener("data", this.onData);
44081
+ if (process.stdin.isTTY) process.stdin.setRawMode(false);
44082
+ process.stdout.write(
44083
+ `${MOUSE_OFF}${BRACKETED_PASTE_OFF}${CSI}r${ALT_SCREEN_OFF}${SHOW_CURSOR}`
44084
+ );
44085
+ }
44086
+ /** Re-enter alt-screen after an external prompt. */
44087
+ resumeAfterPrompt() {
44088
+ if (!this.started || !this.pausedForPrompt) return;
44089
+ this.pausedForPrompt = false;
44090
+ process.stdout.write(ALT_SCREEN_ON + MOUSE_ON + BRACKETED_PASTE_ON);
44091
+ this.applyScrollRegion();
44092
+ if (process.stdin.isTTY) process.stdin.setRawMode(true);
44093
+ process.stdin.on("data", this.onData);
44094
+ this.render();
44095
+ }
42254
44096
  toolCallStart(id, name) {
42255
44097
  this.items.push({ kind: "tool_call", id, name, args: "", done: false });
44098
+ this.runState = "tool_running";
44099
+ this.activeToolName = name;
42256
44100
  this.dirty();
42257
44101
  }
42258
44102
  toolCallArgs(id, delta) {
@@ -42305,7 +44149,12 @@ var ChatTUI = class {
42305
44149
  this.dirty();
42306
44150
  }
42307
44151
  toolCallResult(toolCallId, toolName, content) {
42308
- this.items.push({ kind: "tool_result", toolCallId, toolName, content });
44152
+ const failed = toolResultLooksFailed(content);
44153
+ this.items.push({ kind: "tool_result", toolCallId, toolName, content, failed });
44154
+ if (!this.isStreaming) {
44155
+ this.runState = "thinking";
44156
+ this.activeToolName = "";
44157
+ }
42309
44158
  this.dirty();
42310
44159
  }
42311
44160
  /** Find the tool name for a given tool call ID */
@@ -42358,7 +44207,9 @@ var ChatTUI = class {
42358
44207
  this.scheduleRender();
42359
44208
  }
42360
44209
  restoreTerminal = () => {
42361
- process.stdout.write(`${MOUSE_OFF}${CSI}r${ALT_SCREEN_OFF}${SHOW_CURSOR}`);
44210
+ process.stdout.write(
44211
+ `${MOUSE_OFF}${BRACKETED_PASTE_OFF}${CSI}r${ALT_SCREEN_OFF}${SHOW_CURSOR}`
44212
+ );
42362
44213
  };
42363
44214
  updateDimensions() {
42364
44215
  this.rows = process.stdout.rows || 24;
@@ -42374,11 +44225,32 @@ var ChatTUI = class {
42374
44225
  if (!this.debugVisible) return 0;
42375
44226
  return this.cols - this.chatWidth() - 1;
42376
44227
  }
44228
+ titleRows() {
44229
+ return this.options.title || this.options.subtitle ? 1 : 0;
44230
+ }
44231
+ inputRows() {
44232
+ const lines = this.inputBuffer.split("\n").length;
44233
+ return Math.min(MAX_INPUT_ROWS, Math.max(1, lines));
44234
+ }
44235
+ footerRows() {
44236
+ return 1 + this.inputRows();
44237
+ }
44238
+ messageAreaTop() {
44239
+ return 1 + this.titleRows();
44240
+ }
44241
+ messageAreaBottom() {
44242
+ return this.rows - this.footerRows();
44243
+ }
44244
+ applyScrollRegion() {
44245
+ const top = this.messageAreaTop();
44246
+ const bottom = Math.max(top, this.messageAreaBottom());
44247
+ process.stdout.write(`${CSI}${top};${bottom}r`);
44248
+ }
42377
44249
  scrollHeight() {
42378
- return Math.max(1, this.rows - 2);
44250
+ return Math.max(1, this.messageAreaBottom() - this.messageAreaTop() + 1);
42379
44251
  }
42380
44252
  pageSize() {
42381
- return Math.max(1, this.rows - 4);
44253
+ return Math.max(1, this.scrollHeight() - 2);
42382
44254
  }
42383
44255
  // ─── Scroll ───────────────────────────────────────────────────────
42384
44256
  scrollUp(lines) {
@@ -42444,6 +44316,11 @@ var ChatTUI = class {
42444
44316
  }
42445
44317
  /** Handle a parsed CSI sequence: params is everything between \x1B[ and the final char */
42446
44318
  handleCSI(params, code) {
44319
+ if (params === "201~") {
44320
+ this.scrollToBottom();
44321
+ this.dirty();
44322
+ return;
44323
+ }
42447
44324
  if (params.startsWith("<") && (code === "M" || code === "m")) {
42448
44325
  if (code === "m") return;
42449
44326
  const parts = params.slice(1).split(";");
@@ -42525,22 +44402,31 @@ var ChatTUI = class {
42525
44402
  this.handleEnter();
42526
44403
  return;
42527
44404
  }
44405
+ if (code === 10) {
44406
+ this.inputBuffer += "\n";
44407
+ this.dirty();
44408
+ return;
44409
+ }
42528
44410
  if (code === 127 || code === 8) {
42529
44411
  if (this.inputBuffer.length > 0) {
42530
44412
  this.inputBuffer = this.inputBuffer.slice(0, -1);
42531
- this.renderInputLine();
44413
+ this.dirty();
42532
44414
  }
42533
44415
  return;
42534
44416
  }
42535
44417
  if (code < 32) return;
42536
44418
  this.inputBuffer += ch;
42537
- this.renderInputLine();
44419
+ this.dirty();
42538
44420
  }
42539
44421
  handleEnter() {
44422
+ if (this.turnInProgress) {
44423
+ this.dirty();
44424
+ return;
44425
+ }
42540
44426
  const text = this.inputBuffer.trim();
42541
44427
  this.inputBuffer = "";
42542
44428
  if (!text) {
42543
- this.renderInputLine();
44429
+ this.dirty();
42544
44430
  return;
42545
44431
  }
42546
44432
  if (text.toLowerCase() === "exit" || text.toLowerCase() === "quit") {
@@ -42557,7 +44443,7 @@ var ChatTUI = class {
42557
44443
  // ─── Events ───────────────────────────────────────────────────────
42558
44444
  onResize = () => {
42559
44445
  this.updateDimensions();
42560
- process.stdout.write(`${CSI}1;${Math.max(1, this.rows - 2)}r`);
44446
+ this.applyScrollRegion();
42561
44447
  this.displayLinesCache = null;
42562
44448
  this.debugLinesCache = null;
42563
44449
  this.render();
@@ -42599,19 +44485,24 @@ var ChatTUI = class {
42599
44485
  visible = displayLines.slice(start, end);
42600
44486
  }
42601
44487
  const buf = [HIDE_CURSOR];
44488
+ const msgTop = this.messageAreaTop();
44489
+ if (this.titleRows()) {
44490
+ buf.push(moveTo(1, 1), this.buildTitleBar(), CLEAR_EOL);
44491
+ }
42602
44492
  if (this.debugVisible) {
42603
- this.renderSplitScreen(buf, visible, sh);
44493
+ this.renderSplitScreen(buf, visible, sh, msgTop);
42604
44494
  } else {
42605
44495
  for (let i = 0; i < sh; i++) {
42606
- buf.push(moveTo(i + 1, 1), visible[i] || "", CLEAR_EOL);
44496
+ buf.push(moveTo(msgTop + i, 1), visible[i] || "", CLEAR_EOL);
42607
44497
  }
42608
44498
  }
42609
- buf.push(moveTo(this.rows - 1, 1), this.buildSeparator(), CLEAR_EOL);
42610
- buf.push(moveTo(this.rows, 1), `${BLUE}You:${RESET} ${this.inputBuffer}${CLEAR_EOL}`);
44499
+ const sepRow = this.rows - this.inputRows();
44500
+ buf.push(moveTo(sepRow, 1), this.buildSeparator(), CLEAR_EOL);
44501
+ this.renderInputArea(buf, sepRow + 1);
42611
44502
  buf.push(SHOW_CURSOR);
42612
44503
  process.stdout.write(buf.join(""));
42613
44504
  }
42614
- renderSplitScreen(buf, chatVisible, sh) {
44505
+ renderSplitScreen(buf, chatVisible, sh, msgTop = 1) {
42615
44506
  const cw = this.chatWidth();
42616
44507
  const dw = this.debugWidth();
42617
44508
  const divCol = cw + 1;
@@ -42627,21 +44518,68 @@ var ChatTUI = class {
42627
44518
  const chatLine = truncateAnsi(chatVisible[i] || "", cw);
42628
44519
  const debugLine = truncateAnsi(debugVisible[i] || "", dw);
42629
44520
  buf.push(
42630
- moveTo(i + 1, 1),
44521
+ moveTo(msgTop + i, 1),
42631
44522
  chatLine,
42632
44523
  CLEAR_EOL,
42633
44524
  // clear to end handles rest, but we need to position divider
42634
- moveTo(i + 1, divCol),
44525
+ moveTo(msgTop + i, divCol),
42635
44526
  `${DIM}\u2502${RESET}`,
42636
44527
  debugLine
42637
44528
  );
42638
44529
  buf.push(CLEAR_EOL);
42639
44530
  }
42640
44531
  }
42641
- renderInputLine() {
42642
- process.stdout.write(
42643
- `${moveTo(this.rows, 1)}${BLUE}You:${RESET} ${this.inputBuffer}${CLEAR_EOL}`
42644
- );
44532
+ renderInputArea(buf, startRow) {
44533
+ const inputRows = this.inputRows();
44534
+ const width = this.chatWidth();
44535
+ const contentWidth = Math.max(1, width - INPUT_LABEL_WIDTH);
44536
+ const inputLines = this.wrapInputLines(this.inputBuffer, contentWidth, inputRows);
44537
+ for (let i = 0; i < inputRows; i++) {
44538
+ const row = startRow + i;
44539
+ const line = inputLines[i] ?? "";
44540
+ const prefix = i === 0 ? `${BLUE}${INPUT_LABEL}${RESET} ` : " ".repeat(INPUT_LABEL_WIDTH);
44541
+ buf.push(moveTo(row, 1), prefix, line, CLEAR_EOL);
44542
+ }
44543
+ }
44544
+ wrapInputLines(text, maxWidth, maxRows) {
44545
+ const rawLines = text.split("\n");
44546
+ const wrapped = [];
44547
+ for (const raw of rawLines) {
44548
+ for (const wl of this.wrapText(raw, maxWidth)) {
44549
+ wrapped.push(wl);
44550
+ }
44551
+ }
44552
+ if (!wrapped.length) wrapped.push("");
44553
+ if (wrapped.length > maxRows) {
44554
+ const trimmed = wrapped.slice(wrapped.length - maxRows);
44555
+ trimmed[0] = "\u2026" + trimmed[0].slice(1);
44556
+ return trimmed;
44557
+ }
44558
+ return wrapped;
44559
+ }
44560
+ buildTitleBar() {
44561
+ const parts = [];
44562
+ if (this.options.title) {
44563
+ parts.push(`${CYAN}${this.options.title}${RESET}`);
44564
+ }
44565
+ if (this.options.subtitle) {
44566
+ parts.push(`${DIM}${this.options.subtitle}${RESET}`);
44567
+ }
44568
+ let status = "";
44569
+ switch (this.runState) {
44570
+ case "thinking":
44571
+ status = `${YELLOW}Thinking\u2026${RESET}`;
44572
+ break;
44573
+ case "tool_running":
44574
+ status = `${YELLOW}Running ${this.activeToolName}\u2026${RESET}`;
44575
+ break;
44576
+ case "streaming":
44577
+ status = `${GREEN}Writing\u2026${RESET}`;
44578
+ break;
44579
+ }
44580
+ if (status) parts.push(status);
44581
+ const line = parts.join(` ${DIM}|${RESET} `);
44582
+ return truncateAnsi(line, this.cols);
42645
44583
  }
42646
44584
  // ─── Separator ────────────────────────────────────────────────────
42647
44585
  buildSeparator() {
@@ -42656,6 +44594,7 @@ var ChatTUI = class {
42656
44594
  if (this.options.debug) {
42657
44595
  hints.push(`^D ${this.debugPanelVisible ? "hide" : "show"} debug`);
42658
44596
  }
44597
+ hints.push("Enter send");
42659
44598
  const lineWidth = Math.min(this.cols, 60);
42660
44599
  if (!hints.length) {
42661
44600
  return `${GRAY}${"\u2500".repeat(lineWidth)}${RESET}`;
@@ -42686,8 +44625,9 @@ var ChatTUI = class {
42686
44625
  return lines;
42687
44626
  }
42688
44627
  appendToolCallLines(lines, tc, width) {
42689
- const status = tc.done ? "Called" : "Calling";
42690
- const summary = ` ${GRAY}${status} ${tc.name}${tc.done ? "" : "..."}${RESET}`;
44628
+ const status = tc.done ? "\u2713" : "\u2026";
44629
+ const verb = tc.done ? "Called" : "Calling";
44630
+ const summary = ` ${tc.done ? GREEN : YELLOW}${status}${RESET} ${GRAY}${verb} ${tc.name}${RESET}`;
42691
44631
  if (!this.expandDetails) {
42692
44632
  lines.push(summary);
42693
44633
  return;
@@ -42708,14 +44648,15 @@ var ChatTUI = class {
42708
44648
  }
42709
44649
  }
42710
44650
  appendToolResultLines(lines, tr, width) {
44651
+ const mark = tr.failed ? `${RED}\u2717${RESET}` : `${GREEN}\u2713${RESET}`;
42711
44652
  if (!this.expandDetails) {
42712
- const maxLen = width - 10;
44653
+ const maxLen = width - 12;
42713
44654
  const preview = tr.content.replace(/\n/g, " ").slice(0, maxLen);
42714
44655
  const truncated = preview.length < tr.content.length ? "..." : "";
42715
- lines.push(` ${GRAY}\u2192 ${tr.toolName}: ${preview}${truncated}${RESET}`);
44656
+ lines.push(` ${mark} ${GRAY}${tr.toolName}: ${preview}${truncated}${RESET}`);
42716
44657
  return;
42717
44658
  }
42718
- lines.push(` ${GRAY}\u2192 ${tr.toolName} result:${RESET}`);
44659
+ lines.push(` ${mark} ${GRAY}${tr.toolName} result:${RESET}`);
42719
44660
  let formatted = tr.content;
42720
44661
  try {
42721
44662
  formatted = JSON.stringify(JSON.parse(tr.content), null, 2);
@@ -42767,7 +44708,12 @@ var ChatTUI = class {
42767
44708
  const labelWidth = 12;
42768
44709
  const indent = " ".repeat(labelWidth);
42769
44710
  if (!this.streamContent) {
42770
- lines.push(label);
44711
+ if (this.runState === "thinking" || this.runState === "tool_running") {
44712
+ const hint2 = this.runState === "tool_running" && this.activeToolName ? `Running ${this.activeToolName}\u2026` : "Thinking\u2026";
44713
+ lines.push(`${label}${YELLOW}${hint2}${RESET}`);
44714
+ } else {
44715
+ lines.push(label);
44716
+ }
42771
44717
  return;
42772
44718
  }
42773
44719
  let first = true;
@@ -42884,6 +44830,58 @@ function buildDebugSummary(_direction, msg) {
42884
44830
  }
42885
44831
  return type;
42886
44832
  }
44833
+
44834
+ // src/lib/agui-tui-events.ts
44835
+ init_agui();
44836
+ function handleAguiEvent(tui, event) {
44837
+ const type = event.type?.toLowerCase() ?? "";
44838
+ switch (type) {
44839
+ case "run_started":
44840
+ tui.runStarted();
44841
+ break;
44842
+ case "run_finished":
44843
+ tui.runFinished();
44844
+ break;
44845
+ case "text_message_start":
44846
+ tui.streamStart();
44847
+ break;
44848
+ case "text_message_content": {
44849
+ const delta = getTextDelta(event);
44850
+ if (delta) tui.streamDelta(delta);
44851
+ break;
44852
+ }
44853
+ case "text_message_end":
44854
+ tui.streamEnd();
44855
+ break;
44856
+ case "tool_call_start":
44857
+ tui.toolCallStart(
44858
+ event.toolCallId ?? "",
44859
+ event.toolCallName ?? event.name ?? "tool"
44860
+ );
44861
+ break;
44862
+ case "tool_call_args":
44863
+ if (event.toolCallId && event.delta) {
44864
+ tui.toolCallArgs(event.toolCallId, event.delta);
44865
+ }
44866
+ break;
44867
+ case "tool_call_end":
44868
+ if (event.toolCallId) tui.toolCallEnd(event.toolCallId);
44869
+ break;
44870
+ case "tool_call_result": {
44871
+ const toolCallId = event.toolCallId ?? "";
44872
+ const toolName = tui.findToolCallName(toolCallId);
44873
+ const content = typeof event.content === "string" ? event.content : typeof event.result === "string" ? event.result : JSON.stringify(event.result ?? event.content ?? "");
44874
+ tui.toolCallResult(toolCallId, toolName, content);
44875
+ break;
44876
+ }
44877
+ case "run_error": {
44878
+ const errorMsg = getErrorMessage(event);
44879
+ if (errorMsg) tui.showError(errorMsg);
44880
+ tui.runFinished();
44881
+ break;
44882
+ }
44883
+ }
44884
+ }
42887
44885
  var SAMPLE_RATE = 24e3;
42888
44886
  var MIC_CHUNK_BYTES = 4800;
42889
44887
  function checkSoxAvailable() {
@@ -43199,6 +45197,7 @@ var AudioPlayer = class extends EventEmitter {
43199
45197
  };
43200
45198
 
43201
45199
  // src/lib/chat-session.ts
45200
+ var HITL_INTERRUPT_EXIT_CODE = 3;
43202
45201
  async function runChatSession(session, args) {
43203
45202
  const debug = !!args.debug;
43204
45203
  const isVoice = !!args.voice;
@@ -43228,6 +45227,14 @@ async function runChatSession(session, args) {
43228
45227
  function vadMode(args) {
43229
45228
  return typeof args.vad === "string" ? args.vad : "server";
43230
45229
  }
45230
+ function sanitizeInterruptForStdout(result2) {
45231
+ const url = typeof result2.payload.url === "string" ? result2.payload.url : void 0;
45232
+ return {
45233
+ type: result2.type,
45234
+ interrupt_id: result2.interruptId,
45235
+ url
45236
+ };
45237
+ }
43231
45238
  async function singleTurnChatSession(session, message, debug, autoApprove = false, allowWrite = false) {
43232
45239
  const aguiClient = new AGUIClient({
43233
45240
  baseUrl: session.ctx.envConfig.apiUrl,
@@ -43247,18 +45254,34 @@ async function singleTurnChatSession(session, message, debug, autoApprove = fals
43247
45254
  `);
43248
45255
  }
43249
45256
  };
43250
- const { streamText, hasToolCalls } = await runConciergeAguiLoop(
45257
+ const { streamText, hasToolCalls, unsupportedHitl } = await runConciergeAguiLoop(
43251
45258
  aguiClient,
43252
45259
  [{ role: "user", content: message }],
43253
45260
  onEvent,
43254
45261
  {
43255
45262
  autoApprove,
43256
45263
  allowWrite: allowWrite || !!session.allowWrite,
45264
+ debug,
43257
45265
  trustCwd: session.trustCwd,
43258
45266
  trustDir: session.trustDir,
43259
45267
  nonInteractive: true
43260
45268
  }
43261
45269
  );
45270
+ if (unsupportedHitl) {
45271
+ const jsonPayload = JSON.stringify({
45272
+ error: "hitl_interrupt",
45273
+ message: "A human-in-the-loop interrupt requires out-of-band action before the operation can continue.",
45274
+ resume: {
45275
+ chatId: session.chatId,
45276
+ chatUuid: session.chatUuid,
45277
+ interruptId: unsupportedHitl.interruptId
45278
+ },
45279
+ interrupt: sanitizeInterruptForStdout(unsupportedHitl)
45280
+ });
45281
+ process.stdout.write(`${jsonPayload}
45282
+ `);
45283
+ throw new CLIError("HITL interrupt requires out-of-band handling", HITL_INTERRUPT_EXIT_CODE);
45284
+ }
43262
45285
  if (streamText) {
43263
45286
  process.stdout.write(`\x1B[32mAssistant:\x1B[0m ${streamText}
43264
45287
  `);
@@ -43303,99 +45326,81 @@ async function interactiveChatSession(session, debug, autoApprove, allowWrite) {
43303
45326
  model: session.model,
43304
45327
  appContext: session.appContext
43305
45328
  });
43306
- clearScreen();
43307
- console.log("=".repeat(60));
43308
- console.log(session.label);
43309
- console.log("=".repeat(60));
43310
- console.log(`Chat: ${session.chatTitle}`);
43311
- console.log("Type your message and press Enter. Type 'exit' or Ctrl+C to quit.");
43312
- console.log("=".repeat(60));
43313
- console.log("");
43314
45329
  const existingMessages = await session.loadMessages();
43315
- if (existingMessages.length > 0) {
43316
- console.log("\x1B[90m--- Previous messages ---\x1B[0m\n");
43317
- for (const msg of existingMessages.slice(-10)) {
43318
- const text = typeof msg.content === "string" ? msg.content : "";
43319
- if (text && text.trim()) {
43320
- printMessage(text, msg.role);
45330
+ const history = buildHistory(existingMessages);
45331
+ const conversationMessages = buildConversationMessages(existingMessages);
45332
+ let tui;
45333
+ const sendTurn = async (text) => {
45334
+ conversationMessages.push({ role: "user", content: text });
45335
+ let assistantContent = "";
45336
+ try {
45337
+ tui.runStarted();
45338
+ const { streamText } = await runConciergeAguiLoop(
45339
+ aguiClient,
45340
+ conversationMessages,
45341
+ (event) => {
45342
+ handleAguiEvent(tui, event);
45343
+ const type = event.type?.toLowerCase() ?? "";
45344
+ if (type === "text_message_content" && event.delta) {
45345
+ assistantContent += event.delta;
45346
+ }
45347
+ const errorMsg = getErrorMessage(event);
45348
+ if (errorMsg) tui.showError(errorMsg);
45349
+ },
45350
+ {
45351
+ autoApprove,
45352
+ allowWrite: allowWrite || !!session.allowWrite,
45353
+ debug,
45354
+ trustCwd: session.trustCwd,
45355
+ trustDir: session.trustDir,
45356
+ onHitlPromptStart: () => tui.pauseForPrompt(),
45357
+ onHitlPromptEnd: () => tui.resumeAfterPrompt()
45358
+ }
45359
+ );
45360
+ if (streamText && !assistantContent) {
45361
+ assistantContent = streamText;
45362
+ }
45363
+ if (assistantContent) {
45364
+ conversationMessages.push({ role: "assistant", content: assistantContent });
43321
45365
  }
45366
+ } catch (error) {
45367
+ tui.showError(error instanceof Error ? error.message : String(error));
45368
+ } finally {
45369
+ tui.runFinished();
43322
45370
  }
43323
- console.log("\x1B[90m--- End of history ---\x1B[0m\n");
43324
- }
43325
- const conversationMessages = [];
43326
- for (const msg of existingMessages.slice(-10)) {
45371
+ };
45372
+ await new Promise((resolve2) => {
45373
+ tui = new ChatTUI({
45374
+ title: session.label,
45375
+ subtitle: session.chatTitle,
45376
+ onSend: (text) => {
45377
+ void sendTurn(text);
45378
+ },
45379
+ onExit: () => {
45380
+ tui.stop();
45381
+ resolve2();
45382
+ },
45383
+ debug,
45384
+ env: session.ctx.env
45385
+ });
45386
+ tui.loadHistory(history);
45387
+ tui.start();
45388
+ });
45389
+ }
45390
+ function buildConversationMessages(messages) {
45391
+ const out = [];
45392
+ for (const msg of messages) {
43327
45393
  const text = typeof msg.content === "string" ? msg.content : "";
43328
- if (text && text.trim() && (msg.role === "user" || msg.role === "assistant")) {
43329
- conversationMessages.push({ role: msg.role, content: text });
45394
+ if (text.trim() && (msg.role === "user" || msg.role === "assistant")) {
45395
+ out.push({ role: msg.role, content: text });
43330
45396
  }
43331
45397
  }
43332
- const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
43333
- return new Promise((resolve2) => {
43334
- const prompt = () => {
43335
- rl.question("\x1B[34mYou:\x1B[0m ", async (input2) => {
43336
- const trimmed = input2.trim();
43337
- if (!trimmed) {
43338
- prompt();
43339
- return;
43340
- }
43341
- if (trimmed.toLowerCase() === "exit" || trimmed.toLowerCase() === "quit") {
43342
- console.log("\nGoodbye!");
43343
- rl.close();
43344
- return;
43345
- }
43346
- conversationMessages.push({ role: "user", content: trimmed });
43347
- process.stdout.write("\n\x1B[32mAssistant:\x1B[0m ");
43348
- let assistantContent = "";
43349
- try {
43350
- const { streamText } = await runConciergeAguiLoop(
43351
- aguiClient,
43352
- conversationMessages,
43353
- (event) => {
43354
- const delta = getTextDelta(event);
43355
- if (delta) {
43356
- process.stdout.write(delta);
43357
- assistantContent += delta;
43358
- }
43359
- const errorMsg = getErrorMessage(event);
43360
- if (errorMsg) console.log(`
43361
- \x1B[31mError: ${errorMsg}\x1B[0m`);
43362
- },
43363
- {
43364
- autoApprove,
43365
- allowWrite: allowWrite || !!session.allowWrite,
43366
- debug,
43367
- trustCwd: session.trustCwd,
43368
- trustDir: session.trustDir
43369
- }
43370
- );
43371
- if (streamText && !assistantContent) {
43372
- assistantContent = streamText;
43373
- process.stdout.write(streamText);
43374
- }
43375
- if (assistantContent) {
43376
- conversationMessages.push({ role: "assistant", content: assistantContent });
43377
- }
43378
- console.log("\n");
43379
- } catch (error) {
43380
- console.log(
43381
- `
43382
- \x1B[31mError: ${error instanceof Error ? error.message : error}\x1B[0m
43383
- `
43384
- );
43385
- }
43386
- prompt();
43387
- });
43388
- };
43389
- rl.on("close", () => {
43390
- console.log("\nGoodbye!");
43391
- resolve2();
43392
- });
43393
- prompt();
43394
- });
45398
+ return out;
43395
45399
  }
43396
- function buildHistory(messages) {
45400
+ function buildHistory(messages, limit) {
43397
45401
  const history = [];
43398
- for (const msg of messages.slice(-30)) {
45402
+ const slice = limit ? messages.slice(-limit) : messages;
45403
+ for (const msg of slice) {
43399
45404
  const text = typeof msg.content === "string" ? msg.content : "";
43400
45405
  if (msg.role === "user" || msg.role === "assistant") {
43401
45406
  if (text.trim()) {
@@ -43467,7 +45472,7 @@ async function realtimeChatSession(session, vad, debug) {
43467
45472
  throw new CLIError(`Failed to connect: ${err instanceof Error ? err.message : err}`);
43468
45473
  }
43469
45474
  const existingMessages = await session.loadMessages();
43470
- const history = buildHistory(existingMessages);
45475
+ const history = buildHistory(existingMessages, 30);
43471
45476
  const tui = new ChatTUI({
43472
45477
  onSend: (text) => {
43473
45478
  client.sendTextMessage(text);
@@ -43532,7 +45537,7 @@ Connecting to ${session.label.toLowerCase()}...
43532
45537
  throw new CLIError(`Failed to connect: ${err instanceof Error ? err.message : err}`);
43533
45538
  }
43534
45539
  const existingMessages = await session.loadMessages();
43535
- const history = buildHistory(existingMessages);
45540
+ const history = buildHistory(existingMessages, 30);
43536
45541
  const mic = new MicCapture((pcm16) => {
43537
45542
  if (!client.isConnected()) return;
43538
45543
  client.sendAudio(pcm16);
@@ -43627,15 +45632,173 @@ async function listAudioDevices() {
43627
45632
  }
43628
45633
  }
43629
45634
 
45635
+ // src/lib/chat-history.ts
45636
+ var PAGE_SIZE = 100;
45637
+ var HARD_CAP = 2e3;
45638
+ async function loadAllChatMessages(ctx, workspaceUuid, chatId) {
45639
+ const items = [];
45640
+ let offset = 0;
45641
+ while (items.length < HARD_CAP) {
45642
+ const batch = await ctx.apiClient.getChatMessages(workspaceUuid, chatId, PAGE_SIZE, offset).catch(() => []);
45643
+ if (!batch.length) break;
45644
+ items.push(...batch);
45645
+ if (batch.length < PAGE_SIZE) break;
45646
+ offset += batch.length;
45647
+ }
45648
+ return items;
45649
+ }
45650
+
45651
+ // src/commands/manage.ts
45652
+ async function manageCommand(hctx) {
45653
+ const ctx = requireAuth(hctx.ctx);
45654
+ const { workspace, args } = hctx;
45655
+ const asMember = typeof args["as-member"] === "string" ? args["as-member"] : void 0;
45656
+ const chatIdArg = typeof args["chat-id"] === "string" ? args["chat-id"] : void 0;
45657
+ const message = typeof args.message === "string" ? args.message : void 0;
45658
+ const chat = await getOrCreateChat(ctx, workspace, chatIdArg, asMember, "manager", !!message);
45659
+ const session = buildWorkspaceSession(ctx, workspace, chat, "Workspace Manager", {
45660
+ appContext: buildCliConciergeAppContext(),
45661
+ allowWrite: true,
45662
+ trustCwd: !!args["trust-cwd"],
45663
+ trustDir: typeof args["trust-dir"] === "string" ? args["trust-dir"] : void 0
45664
+ });
45665
+ process.stderr.write(`Chat #${session.chatId}
45666
+ `);
45667
+ await runChatSession(session, args);
45668
+ process.stderr.write(`Chat #${session.chatId}
45669
+ `);
45670
+ }
45671
+ async function chatCommand(hctx) {
45672
+ const ctx = requireAuth(hctx.ctx);
45673
+ const { workspace, args } = hctx;
45674
+ const chatIdArg = typeof args["chat-id"] === "string" ? args["chat-id"] : void 0;
45675
+ const workflowId = typeof args.workflow === "string" ? args.workflow : void 0;
45676
+ const memberId = typeof args.member === "string" ? args.member : void 0;
45677
+ let chat;
45678
+ if (chatIdArg) {
45679
+ const id = Number(chatIdArg);
45680
+ if (isNaN(id)) throw new CLIError("--chat-id must be a number");
45681
+ chat = await ctx.apiClient.getChat(workspace, id);
45682
+ } else if (workflowId) {
45683
+ chat = await createAssignmentChat(ctx.apiClient, workspace, Number(workflowId), memberId);
45684
+ } else if (memberId) {
45685
+ chat = await createMemberChat(ctx.apiClient, workspace, memberId);
45686
+ } else {
45687
+ throw new CLIError(
45688
+ 'Specify --workflow <id>, --member <id>, or --chat-id <id>.\nUse "gr manage" for workspace manager chats.'
45689
+ );
45690
+ }
45691
+ const session = buildWorkspaceSession(ctx, workspace, chat, "Chat");
45692
+ await runChatSession(session, args);
45693
+ }
45694
+ function buildWorkspaceSession(ctx, workspace, chat, label, extra) {
45695
+ const wsBase = ctx.envConfig.apiUrl.replace(/^https:/, "wss:").replace(/^http:/, "ws:");
45696
+ return {
45697
+ ctx,
45698
+ workspaceUuid: workspace,
45699
+ chatId: chat.id,
45700
+ chatUuid: chat.uuid,
45701
+ chatTitle: chat.title || chat.uuid,
45702
+ aguiEndpointUrl: `${ctx.envConfig.apiUrl}/api/v2/w/${workspace}/web-chat/${chat.id}/chat/agui`,
45703
+ wsUrl: `${wsBase}/api/v2/w/${workspace}/realtime/stream-ws`,
45704
+ loadMessages: () => loadAllChatMessages(ctx, workspace, chat.id),
45705
+ label,
45706
+ model: "manager",
45707
+ ...extra
45708
+ };
45709
+ }
45710
+ async function getOrCreateChat(ctx, workspace, chatIdArg, asMemberId, chatType, skipSelection = false) {
45711
+ if (chatIdArg) {
45712
+ const chatId = Number(chatIdArg);
45713
+ if (isNaN(chatId)) throw new CLIError("--chat-id must be a number");
45714
+ return ctx.apiClient.getChat(workspace, chatId);
45715
+ }
45716
+ if (skipSelection) {
45717
+ return createManagerChat(ctx.apiClient, workspace, asMemberId);
45718
+ }
45719
+ const chatsResponse = await ctx.apiClient.getChats(workspace, {
45720
+ chatType,
45721
+ sortBy: "updatedAt",
45722
+ sortOrder: "desc",
45723
+ pageSize: 20
45724
+ });
45725
+ const chats = chatsResponse.items || [];
45726
+ const { item: selectedChat, isNew } = await selectFromList(chats, {
45727
+ title: "Select a chat or create a new one",
45728
+ labelFn: (chat) => chat.title || `Chat ${chat.uuid.slice(0, 8)}...`,
45729
+ detailFn: (chat) => {
45730
+ const time = formatTimestamp(chat.updatedAt);
45731
+ const msgCount = chat.messageCount || 0;
45732
+ return `${msgCount} msg${msgCount !== 1 ? "s" : ""} - ${time}`;
45733
+ },
45734
+ emptyMessage: "No existing chats.",
45735
+ allowNew: true,
45736
+ newLabel: "+ Start new chat"
45737
+ });
45738
+ if (!selectedChat && !isNew) {
45739
+ throw new CLIError("No chat selected.");
45740
+ }
45741
+ if (isNew) {
45742
+ return createManagerChat(ctx.apiClient, workspace, asMemberId);
45743
+ }
45744
+ return selectedChat;
45745
+ }
45746
+ async function createManagerChat(apiClient, workspace, asMemberId) {
45747
+ const data = {
45748
+ chatType: "manager",
45749
+ channel: "web-chat"
45750
+ };
45751
+ if (asMemberId) {
45752
+ data.memberId = Number(asMemberId);
45753
+ }
45754
+ const chat = await apiClient.createChat(workspace, data);
45755
+ process.stderr.write(`Created chat #${chat.id}
45756
+ `);
45757
+ return chat;
45758
+ }
45759
+ async function createAssignmentChat(apiClient, workspace, workflowId, asMemberId) {
45760
+ if (isNaN(workflowId)) throw new CLIError("--workflow must be a number");
45761
+ const data = {
45762
+ chatType: "assignment",
45763
+ channel: "web-chat",
45764
+ workflowId
45765
+ };
45766
+ if (asMemberId) {
45767
+ data.memberId = Number(asMemberId);
45768
+ }
45769
+ const chat = await apiClient.createChat(workspace, data);
45770
+ process.stderr.write(`Created assignment chat #${chat.id} (workflow ${workflowId})
45771
+ `);
45772
+ return chat;
45773
+ }
45774
+ async function createMemberChat(apiClient, workspace, memberId) {
45775
+ const id = Number(memberId);
45776
+ if (isNaN(id)) throw new CLIError("--member must be a number");
45777
+ const data = {
45778
+ chatType: "member",
45779
+ channel: "web-chat",
45780
+ memberId: id
45781
+ };
45782
+ const chat = await apiClient.createChat(workspace, data);
45783
+ process.stderr.write(`Created DM chat #${chat.id} (member ${memberId})
45784
+ `);
45785
+ return chat;
45786
+ }
45787
+
43630
45788
  // src/commands/concierge.ts
45789
+ init_cli_utils();
45790
+ init_concierge_api();
45791
+ init_context();
45792
+ init_errors();
43631
45793
  async function conciergeOutboundCommand(hctx) {
43632
45794
  const ctx = requireAuth(hctx.ctx);
43633
45795
  const { args } = hctx;
45796
+ const message = typeof args.message === "string" ? args.message : void 0;
43634
45797
  if (args.call && args.sms) {
43635
45798
  throw new CLIError("--call and --sms are mutually exclusive");
43636
45799
  }
43637
45800
  if (args.call) {
43638
- const result2 = await originateConciergeCall(ctx);
45801
+ const result2 = await originateConciergeCall(ctx, "concierge_setup", message, "cli");
43639
45802
  process.stderr.write(
43640
45803
  `Concierge call started. callSid=${result2.callSid} startedAt=${result2.startedAt}
43641
45804
  `
@@ -43726,6 +45889,63 @@ async function getOrCreateConciergeChat(ctx, chatIdArg, skipSelection) {
43726
45889
  return selectedChat;
43727
45890
  }
43728
45891
 
45892
+ // src/commands/dev.ts
45893
+ init_errors();
45894
+ init_output();
45895
+ async function devImportLocalCommand(ctx, workspace) {
45896
+ stderr2(`Exporting workspace ${workspace}...`);
45897
+ const exportData = await ctx.apiClient.exportWorkspace(workspace);
45898
+ stderr2("Export successful!");
45899
+ stderr2(` Workflows: ${(exportData.workflows || []).length}`);
45900
+ stderr2(` Tasks: ${(exportData.tasks || []).length}`);
45901
+ stderr2(` Data Types: ${(exportData.dataTypes || []).length}`);
45902
+ stderr2(` Sites: ${(exportData.sites || []).length}`);
45903
+ const slug = workspace.slice(0, 8);
45904
+ const importCacheDir = join(ctx.credentialsManager.getCacheDir(), "imports");
45905
+ if (!existsSync(importCacheDir)) {
45906
+ mkdirSync(importCacheDir, { recursive: true });
45907
+ }
45908
+ const filename = `ws-${slug}-${workspace}.json`;
45909
+ const filepath = join(importCacheDir, filename);
45910
+ writeFileSync(filepath, JSON.stringify(exportData, null, 2));
45911
+ stderr2(`Saved to: ${filepath}`);
45912
+ stderr2("Running dev:restore...");
45913
+ const rootDir = findProjectRoot();
45914
+ const relativePath = filepath.replace(rootDir + "/", "");
45915
+ try {
45916
+ const result2 = execSync(`yarn dev:restore ${relativePath}`, {
45917
+ cwd: rootDir,
45918
+ stdio: "pipe",
45919
+ encoding: "utf-8"
45920
+ });
45921
+ process.stderr.write(result2);
45922
+ const failed = result2.includes("Failed/Skipped: ") && !result2.includes("Failed/Skipped: 0") || result2.includes("Successfully restored: 0");
45923
+ if (failed) throw new CLIError("Import failed");
45924
+ } catch (error) {
45925
+ if (error instanceof CLIError) throw error;
45926
+ const execError = error;
45927
+ if (execError.stdout) process.stderr.write(execError.stdout);
45928
+ if (execError.stderr) process.stderr.write(execError.stderr);
45929
+ throw new CLIError("dev:restore failed");
45930
+ }
45931
+ stderr2(`Import complete: ${workspace}`);
45932
+ }
45933
+ function findProjectRoot() {
45934
+ let dir = process.cwd();
45935
+ while (dir !== "/") {
45936
+ const pkgPath = join(dir, "package.json");
45937
+ if (existsSync(pkgPath)) {
45938
+ try {
45939
+ const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
45940
+ if (pkg.workspaces) return dir;
45941
+ } catch {
45942
+ }
45943
+ }
45944
+ dir = join(dir, "..");
45945
+ }
45946
+ return process.cwd();
45947
+ }
45948
+
43729
45949
  // src/commands/get-started.ts
43730
45950
  init_context();
43731
45951
  var WEB_SETUP = "https://app.gravityrail.com/setup";
@@ -43826,63 +46046,6 @@ async function getStartedCommand(hctx) {
43826
46046
  process.stdout.write(LLM_GUIDE);
43827
46047
  }
43828
46048
 
43829
- // src/commands/dev.ts
43830
- init_errors();
43831
- init_output();
43832
- async function devImportLocalCommand(ctx, workspace) {
43833
- stderr2(`Exporting workspace ${workspace}...`);
43834
- const exportData = await ctx.apiClient.exportWorkspace(workspace);
43835
- stderr2("Export successful!");
43836
- stderr2(` Workflows: ${(exportData.workflows || []).length}`);
43837
- stderr2(` Tasks: ${(exportData.tasks || []).length}`);
43838
- stderr2(` Data Types: ${(exportData.dataTypes || []).length}`);
43839
- stderr2(` Sites: ${(exportData.sites || []).length}`);
43840
- const slug = workspace.slice(0, 8);
43841
- const importCacheDir = join(ctx.credentialsManager.getCacheDir(), "imports");
43842
- if (!existsSync(importCacheDir)) {
43843
- mkdirSync(importCacheDir, { recursive: true });
43844
- }
43845
- const filename = `ws-${slug}-${workspace}.json`;
43846
- const filepath = join(importCacheDir, filename);
43847
- writeFileSync(filepath, JSON.stringify(exportData, null, 2));
43848
- stderr2(`Saved to: ${filepath}`);
43849
- stderr2("Running dev:restore...");
43850
- const rootDir = findProjectRoot();
43851
- const relativePath = filepath.replace(rootDir + "/", "");
43852
- try {
43853
- const result2 = execSync(`yarn dev:restore ${relativePath}`, {
43854
- cwd: rootDir,
43855
- stdio: "pipe",
43856
- encoding: "utf-8"
43857
- });
43858
- process.stderr.write(result2);
43859
- const failed = result2.includes("Failed/Skipped: ") && !result2.includes("Failed/Skipped: 0") || result2.includes("Successfully restored: 0");
43860
- if (failed) throw new CLIError("Import failed");
43861
- } catch (error) {
43862
- if (error instanceof CLIError) throw error;
43863
- const execError = error;
43864
- if (execError.stdout) process.stderr.write(execError.stdout);
43865
- if (execError.stderr) process.stderr.write(execError.stderr);
43866
- throw new CLIError("dev:restore failed");
43867
- }
43868
- stderr2(`Import complete: ${workspace}`);
43869
- }
43870
- function findProjectRoot() {
43871
- let dir = process.cwd();
43872
- while (dir !== "/") {
43873
- const pkgPath = join(dir, "package.json");
43874
- if (existsSync(pkgPath)) {
43875
- try {
43876
- const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
43877
- if (pkg.workspaces) return dir;
43878
- } catch {
43879
- }
43880
- }
43881
- dir = join(dir, "..");
43882
- }
43883
- return process.cwd();
43884
- }
43885
-
43886
46049
  // src/commands/login.ts
43887
46050
  init_dist();
43888
46051
  init_cli_utils();
@@ -43902,146 +46065,6 @@ async function logoutCommand(ctx) {
43902
46065
  stderr2(`Credentials cleared for ${ctx.env}`);
43903
46066
  }
43904
46067
 
43905
- // src/commands/manage.ts
43906
- init_cli_utils();
43907
- init_errors();
43908
- init_context();
43909
- async function manageCommand(hctx) {
43910
- const ctx = requireAuth(hctx.ctx);
43911
- const { workspace, args } = hctx;
43912
- const asMember = typeof args["as-member"] === "string" ? args["as-member"] : void 0;
43913
- const chatIdArg = typeof args["chat-id"] === "string" ? args["chat-id"] : void 0;
43914
- const message = typeof args.message === "string" ? args.message : void 0;
43915
- const chat = await getOrCreateChat(ctx, workspace, chatIdArg, asMember, "manager", !!message);
43916
- const session = buildWorkspaceSession(ctx, workspace, chat, "Workspace Manager", {
43917
- appContext: buildCliConciergeAppContext(),
43918
- allowWrite: true,
43919
- trustCwd: !!args["trust-cwd"],
43920
- trustDir: typeof args["trust-dir"] === "string" ? args["trust-dir"] : void 0
43921
- });
43922
- process.stderr.write(`Chat #${session.chatId}
43923
- `);
43924
- await runChatSession(session, args);
43925
- process.stderr.write(`Chat #${session.chatId}
43926
- `);
43927
- }
43928
- async function chatCommand(hctx) {
43929
- const ctx = requireAuth(hctx.ctx);
43930
- const { workspace, args } = hctx;
43931
- const chatIdArg = typeof args["chat-id"] === "string" ? args["chat-id"] : void 0;
43932
- const workflowId = typeof args.workflow === "string" ? args.workflow : void 0;
43933
- const memberId = typeof args.member === "string" ? args.member : void 0;
43934
- let chat;
43935
- if (chatIdArg) {
43936
- const id = Number(chatIdArg);
43937
- if (isNaN(id)) throw new CLIError("--chat-id must be a number");
43938
- chat = await ctx.apiClient.getChat(workspace, id);
43939
- } else if (workflowId) {
43940
- chat = await createAssignmentChat(ctx.apiClient, workspace, Number(workflowId), memberId);
43941
- } else if (memberId) {
43942
- chat = await createMemberChat(ctx.apiClient, workspace, memberId);
43943
- } else {
43944
- throw new CLIError(
43945
- 'Specify --workflow <id>, --member <id>, or --chat-id <id>.\nUse "gr manage" for workspace manager chats.'
43946
- );
43947
- }
43948
- const session = buildWorkspaceSession(ctx, workspace, chat, "Chat");
43949
- await runChatSession(session, args);
43950
- }
43951
- function buildWorkspaceSession(ctx, workspace, chat, label, extra) {
43952
- const wsBase = ctx.envConfig.apiUrl.replace(/^https:/, "wss:").replace(/^http:/, "ws:");
43953
- return {
43954
- ctx,
43955
- workspaceUuid: workspace,
43956
- chatId: chat.id,
43957
- chatUuid: chat.uuid,
43958
- chatTitle: chat.title || chat.uuid,
43959
- aguiEndpointUrl: `${ctx.envConfig.apiUrl}/api/v2/w/${workspace}/web-chat/${chat.id}/chat/agui`,
43960
- wsUrl: `${wsBase}/api/v2/w/${workspace}/realtime/stream-ws`,
43961
- loadMessages: () => ctx.apiClient.getChatMessages(workspace, chat.id, 50).catch(() => []),
43962
- label,
43963
- model: "manager",
43964
- ...extra
43965
- };
43966
- }
43967
- async function getOrCreateChat(ctx, workspace, chatIdArg, asMemberId, chatType, skipSelection = false) {
43968
- if (chatIdArg) {
43969
- const chatId = Number(chatIdArg);
43970
- if (isNaN(chatId)) throw new CLIError("--chat-id must be a number");
43971
- return ctx.apiClient.getChat(workspace, chatId);
43972
- }
43973
- if (skipSelection) {
43974
- return createManagerChat(ctx.apiClient, workspace, asMemberId);
43975
- }
43976
- const chatsResponse = await ctx.apiClient.getChats(workspace, {
43977
- chatType,
43978
- sortBy: "updatedAt",
43979
- sortOrder: "desc",
43980
- pageSize: 20
43981
- });
43982
- const chats = chatsResponse.items || [];
43983
- const { item: selectedChat, isNew } = await selectFromList(chats, {
43984
- title: "Select a chat or create a new one",
43985
- labelFn: (chat) => chat.title || `Chat ${chat.uuid.slice(0, 8)}...`,
43986
- detailFn: (chat) => {
43987
- const time = formatTimestamp(chat.updatedAt);
43988
- const msgCount = chat.messageCount || 0;
43989
- return `${msgCount} msg${msgCount !== 1 ? "s" : ""} - ${time}`;
43990
- },
43991
- emptyMessage: "No existing chats.",
43992
- allowNew: true,
43993
- newLabel: "+ Start new chat"
43994
- });
43995
- if (!selectedChat && !isNew) {
43996
- throw new CLIError("No chat selected.");
43997
- }
43998
- if (isNew) {
43999
- return createManagerChat(ctx.apiClient, workspace, asMemberId);
44000
- }
44001
- return selectedChat;
44002
- }
44003
- async function createManagerChat(apiClient, workspace, asMemberId) {
44004
- const data = {
44005
- chatType: "manager",
44006
- channel: "web-chat"
44007
- };
44008
- if (asMemberId) {
44009
- data.memberId = Number(asMemberId);
44010
- }
44011
- const chat = await apiClient.createChat(workspace, data);
44012
- process.stderr.write(`Created chat #${chat.id}
44013
- `);
44014
- return chat;
44015
- }
44016
- async function createAssignmentChat(apiClient, workspace, workflowId, asMemberId) {
44017
- if (isNaN(workflowId)) throw new CLIError("--workflow must be a number");
44018
- const data = {
44019
- chatType: "assignment",
44020
- channel: "web-chat",
44021
- workflowId
44022
- };
44023
- if (asMemberId) {
44024
- data.memberId = Number(asMemberId);
44025
- }
44026
- const chat = await apiClient.createChat(workspace, data);
44027
- process.stderr.write(`Created assignment chat #${chat.id} (workflow ${workflowId})
44028
- `);
44029
- return chat;
44030
- }
44031
- async function createMemberChat(apiClient, workspace, memberId) {
44032
- const id = Number(memberId);
44033
- if (isNaN(id)) throw new CLIError("--member must be a number");
44034
- const data = {
44035
- chatType: "member",
44036
- channel: "web-chat",
44037
- memberId: id
44038
- };
44039
- const chat = await apiClient.createChat(workspace, data);
44040
- process.stderr.write(`Created DM chat #${chat.id} (member ${memberId})
44041
- `);
44042
- return chat;
44043
- }
44044
-
44045
46068
  // src/commands/organizations.ts
44046
46069
  init_output();
44047
46070
  var COLUMNS34 = [
@@ -44072,26 +46095,26 @@ async function whoamiCommand(ctx) {
44072
46095
  outputSingle(account, ctx, columns);
44073
46096
  }
44074
46097
 
44075
- // src/register-special-commands.ts
46098
+ // src/top-level-commands.ts
44076
46099
  init_context();
44077
- function registerSpecialCommands(registry) {
44078
- registry.registerCommand({
46100
+ var topLevelCommands = [
46101
+ {
44079
46102
  path: ["login"],
44080
46103
  description: "Authenticate via OAuth",
44081
46104
  requiresAuth: false,
44082
46105
  handler: async ({ ctx }) => {
44083
46106
  await loginCommand(ctx);
44084
46107
  }
44085
- });
44086
- registry.registerCommand({
46108
+ },
46109
+ {
44087
46110
  path: ["logout"],
44088
46111
  description: "Clear cached credentials",
44089
46112
  requiresAuth: false,
44090
46113
  handler: async ({ ctx }) => {
44091
46114
  await logoutCommand(ctx);
44092
46115
  }
44093
- });
44094
- registry.registerCommand({
46116
+ },
46117
+ {
44095
46118
  path: ["auth", "browser"],
44096
46119
  description: "Open an authenticated browser session using CLI credentials",
44097
46120
  args: [
@@ -44100,8 +46123,8 @@ function registerSpecialCommands(registry) {
44100
46123
  handler: async ({ ctx, args }) => {
44101
46124
  await authBrowserCommand(requireAuth(ctx), args);
44102
46125
  }
44103
- });
44104
- registry.registerCommand({
46126
+ },
46127
+ {
44105
46128
  path: ["manage"],
44106
46129
  description: "Interactive workspace manager chat (text, realtime, or voice)",
44107
46130
  requiresWorkspace: true,
@@ -44135,8 +46158,8 @@ function registerSpecialCommands(registry) {
44135
46158
  handler: async (hctx) => {
44136
46159
  await manageCommand(hctx);
44137
46160
  }
44138
- });
44139
- registry.registerCommand({
46161
+ },
46162
+ {
44140
46163
  path: ["chat"],
44141
46164
  description: "Chat with a workflow, member, or existing chat (text, realtime, or voice)",
44142
46165
  requiresWorkspace: true,
@@ -44162,8 +46185,8 @@ function registerSpecialCommands(registry) {
44162
46185
  handler: async (hctx) => {
44163
46186
  await chatCommand(hctx);
44164
46187
  }
44165
- });
44166
- registry.registerCommand({
46188
+ },
46189
+ {
44167
46190
  path: ["get-started"],
44168
46191
  description: "Bootstrap instructions for new users and LLM agents",
44169
46192
  requiresAuth: false,
@@ -44181,8 +46204,8 @@ function registerSpecialCommands(registry) {
44181
46204
  handler: async (hctx) => {
44182
46205
  await getStartedCommand(hctx);
44183
46206
  }
44184
- });
44185
- registry.registerCommand({
46207
+ },
46208
+ {
44186
46209
  path: ["setup"],
44187
46210
  description: "Alias for get-started \u2014 bootstrap instructions",
44188
46211
  requiresAuth: false,
@@ -44193,8 +46216,8 @@ function registerSpecialCommands(registry) {
44193
46216
  handler: async (hctx) => {
44194
46217
  await getStartedCommand(hctx);
44195
46218
  }
44196
- });
44197
- registry.registerCommand({
46219
+ },
46220
+ {
44198
46221
  path: ["concierge"],
44199
46222
  description: "Call or SMS your verified phone via the Concierge (server-side)",
44200
46223
  requiresWorkspace: false,
@@ -44206,8 +46229,8 @@ function registerSpecialCommands(registry) {
44206
46229
  handler: async (hctx) => {
44207
46230
  await conciergeOutboundCommand(hctx);
44208
46231
  }
44209
- });
44210
- registry.registerCommand({
46232
+ },
46233
+ {
44211
46234
  path: ["account", "verify-phone"],
44212
46235
  description: "Verify your account phone for concierge chat --call / --sms",
44213
46236
  requiresWorkspace: false,
@@ -44217,8 +46240,8 @@ function registerSpecialCommands(registry) {
44217
46240
  const { accountVerifyPhoneCommand: accountVerifyPhoneCommand2 } = await Promise.resolve().then(() => (init_account_verify_phone(), account_verify_phone_exports));
44218
46241
  await accountVerifyPhoneCommand2(hctx);
44219
46242
  }
44220
- });
44221
- registry.registerCommand({
46243
+ },
46244
+ {
44222
46245
  path: ["concierge", "chat"],
44223
46246
  description: "Interactive concierge chat (text, realtime, or voice)",
44224
46247
  requiresWorkspace: false,
@@ -44236,7 +46259,11 @@ function registerSpecialCommands(registry) {
44236
46259
  description: "SMS your verified account phone (server-side)",
44237
46260
  isFlag: true
44238
46261
  },
44239
- { name: "message", alias: "m", description: "Single-turn: send one message and exit" },
46262
+ {
46263
+ name: "message",
46264
+ alias: "m",
46265
+ description: 'Single-turn: send one message and exit. With --call: the "why I am calling" anchor for the opening self-introduction.'
46266
+ },
44240
46267
  { name: "chat-id", description: "Resume an existing chat by numeric ID" },
44241
46268
  { name: "vad", description: "Voice activity detection: server (default) or client" },
44242
46269
  { name: "list-devices", description: "List audio devices and exit", isFlag: true },
@@ -44261,48 +46288,51 @@ function registerSpecialCommands(registry) {
44261
46288
  handler: async (hctx) => {
44262
46289
  await conciergeCommand(hctx);
44263
46290
  }
44264
- });
44265
- registry.registerCommand({
46291
+ },
46292
+ {
44266
46293
  path: ["dev", "import-local"],
44267
46294
  description: "Import remote workspace locally",
44268
46295
  requiresWorkspace: true,
44269
46296
  handler: async ({ ctx, workspace }) => {
44270
46297
  await devImportLocalCommand(requireAuth(ctx), workspace);
44271
46298
  }
44272
- });
44273
- registry.registerCommand({
46299
+ },
46300
+ {
44274
46301
  path: ["whoami"],
44275
46302
  description: "Show current user info",
44276
46303
  handler: async ({ ctx }) => {
44277
46304
  await whoamiCommand(requireAuth(ctx));
44278
46305
  }
44279
- });
44280
- registry.registerCommand({
46306
+ },
46307
+ {
44281
46308
  path: ["organizations", "list"],
44282
46309
  description: "List organizations",
44283
46310
  handler: async ({ ctx }) => {
44284
46311
  await organizationsListCommand(requireAuth(ctx));
44285
46312
  }
44286
- });
44287
- registry.registerCommand({
46313
+ },
46314
+ {
44288
46315
  path: ["orgs", "list"],
44289
46316
  description: "List organizations",
44290
46317
  handler: async ({ ctx }) => {
44291
46318
  await organizationsListCommand(requireAuth(ctx));
44292
46319
  }
44293
- });
44294
- }
46320
+ }
46321
+ ];
46322
+
46323
+ // src/lib.ts
46324
+ init_concierge_api();
44295
46325
 
44296
46326
  // package.json
44297
46327
  var package_default = {
44298
- version: "0.7.2"};
46328
+ version: "0.8.0"};
44299
46329
 
44300
46330
  // src/gr.ts
44301
46331
  var VERSION = package_default.version;
44302
46332
  function createRegistry() {
44303
46333
  const registry = new CommandRegistry();
44304
46334
  registerPublicDomains(registry);
44305
- registerSpecialCommands(registry);
46335
+ registry.registerCommands(topLevelCommands);
44306
46336
  return registry;
44307
46337
  }
44308
46338
  function parseGlobalOptions(argv) {
@@ -44409,7 +46439,8 @@ async function main() {
44409
46439
  workspace: ""
44410
46440
  };
44411
46441
  }
44412
- if (cmd.mutates && !opts.allowWrite) {
46442
+ const inSandbox = process.env.GRAVITY_RAIL_SANDBOX === "1";
46443
+ if (cmd.mutates && !opts.allowWrite && !inSandbox) {
44413
46444
  process.stderr.write(
44414
46445
  `Error: "${commandWords.join(" ")}" is a write operation. Pass --allow-write to execute.
44415
46446
  `