lua-cli 3.22.0 → 3.23.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/index.js CHANGED
@@ -879,6 +879,27 @@ function isAllowedReviewableExecuteTool(tool) {
879
879
  function isReviewableMcpSendTool(tool) {
880
880
  return tool.length > REVIEWABLE_MCP_SEND_TOOL_SUFFIX.length && tool.endsWith(REVIEWABLE_MCP_SEND_TOOL_SUFFIX);
881
881
  }
882
+ function mcpActionTokens(action) {
883
+ return action.replace(/([a-z0-9])([A-Z])/g, "$1 $2").toLowerCase().split(/[^a-z0-9]+/).filter(Boolean);
884
+ }
885
+ function isReviewableMcpDraftTool(tool) {
886
+ const sep4 = tool.indexOf("_");
887
+ if (sep4 <= 0 || sep4 >= tool.length - 1) return false;
888
+ const action = tool.slice(sep4 + 1);
889
+ const tokens = mcpActionTokens(action);
890
+ if (!tokens.includes("draft") && !tokens.includes("drafts")) return false;
891
+ return !MCP_TOOL_READ_VERB_RE.test(action);
892
+ }
893
+ function isMcpDraftCreateTool(tool) {
894
+ if (!isReviewableMcpDraftTool(tool)) return false;
895
+ const tokens = mcpActionTokens(tool.slice(tool.indexOf("_") + 1));
896
+ return tokens[0] === "draft" || tokens.some((t) => MCP_DRAFT_CREATE_VERBS.has(t));
897
+ }
898
+ function mcpSendSiblingForDraftTool(tool, availableToolIds) {
899
+ const sibling = `${tool.split("_")[0]}${REVIEWABLE_MCP_SEND_TOOL_SUFFIX}`;
900
+ for (const id of availableToolIds) if (id === sibling) return sibling;
901
+ return void 0;
902
+ }
882
903
  function isReviewableExecuteTool(tool) {
883
904
  return isAllowedReviewableExecuteTool(tool) || isReviewableMcpSendTool(tool);
884
905
  }
@@ -1118,7 +1139,23 @@ function foldRichPartsIntoMessages(messages, records, makeMessage, sameTurnGroup
1118
1139
  function buildDefaultPersona(agentName) {
1119
1140
  return DEFAULT_PERSONA_GUIDE.replace(AGENT_NAME_TOKEN, () => agentName || "My Agent");
1120
1141
  }
1121
- var __defProp2, __name2, REVIEWABLE_ACTION_EXECUTE_TOOL_ALLOWLIST, REVIEWABLE_MCP_SEND_TOOL_SUFFIX, NON_INTERACTIVE_CHANNELS, RICH_PARTS_MESSAGE_ID_PREFIX, SCREENSHOT_MESSAGE_ID_PREFIX, BROWSER_COMMANDS, BROWSER_COMMAND_NAMES, REASONING_EFFORT_VALUES, AGENT_NAME_TOKEN, DEFAULT_PERSONA_GUIDE, AGENT_LOG_SOURCES, VoiceNameSchema, PluginProviderSchema, RealtimeProviderSchema, PluginClassSchema, ModelDescriptorSchema, InferenceModelSchema, PluginModelSchema, RealtimeModelSchema, LuaVoiceModelSchema, TurnDetectionSchema, InterruptionSchema, BuiltinAudioClipSchema, AudioConfigSchema, BackgroundAudioEntrySchema, BackgroundAudioSchema, LuaVoiceConfigInnerSchema, LuaVoiceConfigSchema, LuaVoiceRefSchema;
1142
+ function resolveLuaJobTimeoutSeconds(timeout) {
1143
+ const resolved = timeout ?? LUA_JOB_DEFAULT_TIMEOUT_SECONDS;
1144
+ if (!Number.isInteger(resolved)) {
1145
+ throw new TypeError("LuaJob `timeout` must be an integer number of seconds.");
1146
+ }
1147
+ if (resolved < LUA_JOB_MIN_TIMEOUT_SECONDS || resolved > LUA_JOB_MAX_TIMEOUT_SECONDS) {
1148
+ throw new RangeError(`LuaJob \`timeout\` must be between ${LUA_JOB_MIN_TIMEOUT_SECONDS} and ${LUA_JOB_MAX_TIMEOUT_SECONDS} seconds.`);
1149
+ }
1150
+ return resolved;
1151
+ }
1152
+ function normalizeLuaJobExecutionTimeoutSeconds(timeout) {
1153
+ if (typeof timeout !== "number" || !Number.isFinite(timeout)) {
1154
+ return LUA_JOB_DEFAULT_TIMEOUT_SECONDS;
1155
+ }
1156
+ return Math.min(Math.max(timeout, LUA_JOB_MIN_TIMEOUT_SECONDS), LUA_JOB_MAX_TIMEOUT_SECONDS);
1157
+ }
1158
+ var __defProp2, __name2, REVIEWABLE_ACTION_EXECUTE_TOOL_ALLOWLIST, REVIEWABLE_MCP_SEND_TOOL_SUFFIX, MCP_TOOL_READ_VERB_RE, MCP_DRAFT_CREATE_VERBS, NON_INTERACTIVE_CHANNELS, RICH_PARTS_MESSAGE_ID_PREFIX, SCREENSHOT_MESSAGE_ID_PREFIX, BROWSER_COMMANDS, BROWSER_COMMAND_NAMES, REASONING_EFFORT_VALUES, AGENT_NAME_TOKEN, DEFAULT_PERSONA_GUIDE, AGENT_LOG_SOURCES, VoiceNameSchema, PluginProviderSchema, RealtimeProviderSchema, PluginClassSchema, ModelDescriptorSchema, InferenceModelSchema, PluginModelSchema, RealtimeModelSchema, LuaVoiceModelSchema, TurnDetectionSchema, InterruptionSchema, BuiltinAudioClipSchema, AudioConfigSchema, BackgroundAudioEntrySchema, BackgroundAudioSchema, LuaVoiceConfigInnerSchema, LuaVoiceConfigSchema, LuaVoiceRefSchema, LUA_JOB_DEFAULT_TIMEOUT_SECONDS, LUA_JOB_MIN_TIMEOUT_SECONDS, LUA_JOB_MAX_TIMEOUT_SECONDS;
1122
1159
  var init_dist = __esm({
1123
1160
  "../shared-types/dist/index.mjs"() {
1124
1161
  "use strict";
@@ -1152,6 +1189,26 @@ var init_dist = __esm({
1152
1189
  REVIEWABLE_MCP_SEND_TOOL_SUFFIX = "_create_messaging_message";
1153
1190
  __name(isReviewableMcpSendTool, "isReviewableMcpSendTool");
1154
1191
  __name2(isReviewableMcpSendTool, "isReviewableMcpSendTool");
1192
+ MCP_TOOL_READ_VERB_RE = /^(list|get|search|read|fetch|find|query|describe|count|retrieve|lookup|show|view)(_|[A-Z0-9]|$)/;
1193
+ __name(mcpActionTokens, "mcpActionTokens");
1194
+ __name2(mcpActionTokens, "mcpActionTokens");
1195
+ __name(isReviewableMcpDraftTool, "isReviewableMcpDraftTool");
1196
+ __name2(isReviewableMcpDraftTool, "isReviewableMcpDraftTool");
1197
+ MCP_DRAFT_CREATE_VERBS = /* @__PURE__ */ new Set([
1198
+ "create",
1199
+ "compose",
1200
+ "make",
1201
+ "new",
1202
+ "save",
1203
+ "add",
1204
+ "write",
1205
+ "stage",
1206
+ "prepare"
1207
+ ]);
1208
+ __name(isMcpDraftCreateTool, "isMcpDraftCreateTool");
1209
+ __name2(isMcpDraftCreateTool, "isMcpDraftCreateTool");
1210
+ __name(mcpSendSiblingForDraftTool, "mcpSendSiblingForDraftTool");
1211
+ __name2(mcpSendSiblingForDraftTool, "mcpSendSiblingForDraftTool");
1155
1212
  __name(isReviewableExecuteTool, "isReviewableExecuteTool");
1156
1213
  __name2(isReviewableExecuteTool, "isReviewableExecuteTool");
1157
1214
  NON_INTERACTIVE_CHANNELS = [
@@ -1184,11 +1241,11 @@ var init_dist = __esm({
1184
1241
  },
1185
1242
  {
1186
1243
  name: "session_open",
1187
- description: "Open/attach a browser session (its own cookies/auth). Args: url?, headed?, profile?, confirmActions?."
1244
+ description: "Open/attach a browser session (its own cookies/auth). Args: url?, headed?, profile?, confirmActions?. Only use the browser when the user explicitly asked for it, or said yes when you asked. For reading a page's content use fetchUrl first."
1188
1245
  },
1189
1246
  {
1190
1247
  name: "navigate",
1191
- description: "Navigate the session to a URL. Args: url, waitUntil?."
1248
+ description: "Navigate the session to a URL. Args: url, waitUntil?. Only use the browser when the user explicitly asked for it, or said yes when you asked. For reading a page's content use fetchUrl first."
1192
1249
  },
1193
1250
  {
1194
1251
  name: "back",
@@ -1701,6 +1758,13 @@ Feel free to add, remove, or rename sections. Your persona can be a single parag
1701
1758
  voiceId: z.string().min(1),
1702
1759
  version: z.string().optional()
1703
1760
  });
1761
+ LUA_JOB_DEFAULT_TIMEOUT_SECONDS = 300;
1762
+ LUA_JOB_MIN_TIMEOUT_SECONDS = 1;
1763
+ LUA_JOB_MAX_TIMEOUT_SECONDS = 600;
1764
+ __name(resolveLuaJobTimeoutSeconds, "resolveLuaJobTimeoutSeconds");
1765
+ __name2(resolveLuaJobTimeoutSeconds, "resolveLuaJobTimeoutSeconds");
1766
+ __name(normalizeLuaJobExecutionTimeoutSeconds, "normalizeLuaJobExecutionTimeoutSeconds");
1767
+ __name2(normalizeLuaJobExecutionTimeoutSeconds, "normalizeLuaJobExecutionTimeoutSeconds");
1704
1768
  }
1705
1769
  });
1706
1770
 
@@ -11034,6 +11098,8 @@ var init_user_instance = __esm({
11034
11098
  "data",
11035
11099
  "userAPI",
11036
11100
  "update",
11101
+ "patch",
11102
+ "unset",
11037
11103
  "clear",
11038
11104
  "toJSON",
11039
11105
  "_luaProfile"
@@ -11112,9 +11178,27 @@ var init_user_instance = __esm({
11112
11178
  this.data = response;
11113
11179
  return this.data;
11114
11180
  } catch (error) {
11115
- throw new Error("Failed to update user data");
11181
+ throw new Error("Failed to update user data", {
11182
+ cause: error
11183
+ });
11184
+ }
11185
+ }
11186
+ async patch(mutation) {
11187
+ try {
11188
+ const response = await this.userAPI.patch(mutation);
11189
+ this.data = response;
11190
+ return this.data;
11191
+ } catch (error) {
11192
+ throw new Error("Failed to patch user data", {
11193
+ cause: error
11194
+ });
11116
11195
  }
11117
11196
  }
11197
+ async unset(...fields) {
11198
+ return this.patch({
11199
+ unset: fields
11200
+ });
11201
+ }
11118
11202
  /**
11119
11203
  * Clears all user data for the current user
11120
11204
  * @returns Promise resolving to true if clearing was successful
@@ -11123,9 +11207,12 @@ var init_user_instance = __esm({
11123
11207
  async clear() {
11124
11208
  try {
11125
11209
  await this.userAPI.clear();
11210
+ this.data = {};
11126
11211
  return true;
11127
11212
  } catch (error) {
11128
- throw new Error("Failed to clear user data");
11213
+ throw new Error("Failed to clear user data", {
11214
+ cause: error
11215
+ });
11129
11216
  }
11130
11217
  }
11131
11218
  /**
@@ -11138,7 +11225,9 @@ var init_user_instance = __esm({
11138
11225
  await this.userAPI.update(this.data);
11139
11226
  return true;
11140
11227
  } catch (error) {
11141
- throw new Error("Failed to save user data");
11228
+ throw new Error("Failed to save user data", {
11229
+ cause: error
11230
+ });
11142
11231
  }
11143
11232
  }
11144
11233
  /**
@@ -11152,7 +11241,9 @@ var init_user_instance = __esm({
11152
11241
  await this.userAPI.sendMessage(messages);
11153
11242
  return true;
11154
11243
  } catch (error) {
11155
- throw new Error("Failed to send message");
11244
+ throw new Error("Failed to send message", {
11245
+ cause: error
11246
+ });
11156
11247
  }
11157
11248
  }
11158
11249
  //get chat history
@@ -11160,7 +11251,9 @@ var init_user_instance = __esm({
11160
11251
  try {
11161
11252
  return await this.userAPI.getChatHistory();
11162
11253
  } catch (error) {
11163
- throw new Error("Failed to get chat history");
11254
+ throw new Error("Failed to get chat history", {
11255
+ cause: error
11256
+ });
11164
11257
  }
11165
11258
  }
11166
11259
  };
@@ -12576,6 +12669,8 @@ var init_data_entry_instance = __esm({
12576
12669
  "score",
12577
12670
  "customDataAPI",
12578
12671
  "update",
12672
+ "patch",
12673
+ "unset",
12579
12674
  "delete",
12580
12675
  "toJSON"
12581
12676
  ];
@@ -12667,9 +12762,33 @@ var init_data_entry_instance = __esm({
12667
12762
  };
12668
12763
  return this.data;
12669
12764
  } catch (error) {
12670
- throw new Error("Failed to update custom data entry");
12765
+ throw new Error("Failed to update custom data entry", {
12766
+ cause: error
12767
+ });
12768
+ }
12769
+ }
12770
+ async patch(mutation) {
12771
+ try {
12772
+ await this.customDataAPI.patch(this.collectionName, this.id, mutation);
12773
+ this.data = {
12774
+ ...this.data,
12775
+ ...mutation.set ?? {}
12776
+ };
12777
+ for (const field of mutation.unset ?? []) {
12778
+ delete this.data[field];
12779
+ }
12780
+ return this.data;
12781
+ } catch (error) {
12782
+ throw new Error("Failed to patch custom data entry", {
12783
+ cause: error
12784
+ });
12671
12785
  }
12672
12786
  }
12787
+ async unset(...fields) {
12788
+ return this.patch({
12789
+ unset: fields
12790
+ });
12791
+ }
12673
12792
  /**
12674
12793
  * Deletes the custom data entry
12675
12794
  * @returns Promise resolving to true if deletion was successful
@@ -12680,7 +12799,9 @@ var init_data_entry_instance = __esm({
12680
12799
  await this.customDataAPI.delete(this.collectionName, this.id);
12681
12800
  return true;
12682
12801
  } catch (error) {
12683
- throw new Error("Failed to delete custom data entry");
12802
+ throw new Error("Failed to delete custom data entry", {
12803
+ cause: error
12804
+ });
12684
12805
  }
12685
12806
  }
12686
12807
  /**
@@ -12694,7 +12815,9 @@ var init_data_entry_instance = __esm({
12694
12815
  await this.customDataAPI.update(this.collectionName, this.id, this.data, searchText);
12695
12816
  return true;
12696
12817
  } catch (error) {
12697
- throw new Error("Failed to save data entry");
12818
+ throw new Error("Failed to save data entry", {
12819
+ cause: error
12820
+ });
12698
12821
  }
12699
12822
  }
12700
12823
  };
@@ -12805,6 +12928,15 @@ var init_custom_data_api_service = __esm({
12805
12928
  }
12806
12929
  throw new Error(response.error?.message || "Failed to update custom data entry");
12807
12930
  }
12931
+ async patch(collectionName, entryId, mutation) {
12932
+ const response = await this.httpPatch(`/developer/agents/${this.agentId}/custom-data/${collectionName}/${entryId}`, mutation, {
12933
+ Authorization: `Bearer ${this.apiKey}`
12934
+ });
12935
+ if (response.success && response.data) {
12936
+ return response.data;
12937
+ }
12938
+ throw new Error(response.error?.message || "Failed to patch custom data entry");
12939
+ }
12808
12940
  /**
12809
12941
  * Performs semantic search on custom data entries using text similarity
12810
12942
  * @param collectionName - The name of the collection to search within
@@ -13261,8 +13393,10 @@ var init_developer_api_service = __esm({
13261
13393
  * @param email - The email address to look up
13262
13394
  * @returns Promise resolving to an ApiResponse containing the profile, or null if not found
13263
13395
  */
13264
- async getUserProfileByEmail(email) {
13265
- return this.httpGet(`/developer/user/profile/email/${encodeURIComponent(email)}`, {
13396
+ async getUserProfileByEmail(email, agentId) {
13397
+ const path18 = `/developer/user/profile/email/${encodeURIComponent(email)}`;
13398
+ const scopedPath = agentId ? `${path18}?agentId=${encodeURIComponent(agentId)}` : path18;
13399
+ return this.httpGet(scopedPath, {
13266
13400
  Authorization: `Bearer ${this.apiKey}`
13267
13401
  });
13268
13402
  }
@@ -13271,9 +13405,11 @@ var init_developer_api_service = __esm({
13271
13405
  * @param phone - The phone number to look up (with or without + prefix)
13272
13406
  * @returns Promise resolving to an ApiResponse containing the profile, or null if not found
13273
13407
  */
13274
- async getUserProfileByPhone(phone) {
13408
+ async getUserProfileByPhone(phone, agentId) {
13275
13409
  const normalizedPhone = phone.replace(/^\+/, "");
13276
- return this.httpGet(`/developer/user/profile/phone/${normalizedPhone}`, {
13410
+ const path18 = `/developer/user/profile/phone/${normalizedPhone}`;
13411
+ const scopedPath = agentId ? `${path18}?agentId=${encodeURIComponent(agentId)}` : path18;
13412
+ return this.httpGet(scopedPath, {
13277
13413
  Authorization: `Bearer ${this.apiKey}`
13278
13414
  });
13279
13415
  }
@@ -13813,22 +13949,28 @@ var init_user_data_api_service = __esm({
13813
13949
  init_http_client();
13814
13950
  init_user_instance();
13815
13951
  init_lazy_instances();
13816
- UserDataApi = class extends HttpClient {
13952
+ UserDataApi = class _UserDataApi extends HttpClient {
13817
13953
  static {
13818
13954
  __name(this, "UserDataApi");
13819
13955
  }
13820
13956
  apiKey;
13821
13957
  agentId;
13958
+ targetUserId;
13822
13959
  /**
13823
13960
  * Creates an instance of UserDataApi
13824
13961
  * @param baseUrl - The base URL for the API
13825
13962
  * @param apiKey - The API key for authentication
13826
13963
  * @param agentId - The unique identifier of the agent
13827
13964
  */
13828
- constructor(baseUrl, apiKey, agentId) {
13965
+ constructor(baseUrl, apiKey, agentId, targetUserId) {
13829
13966
  super(baseUrl);
13830
13967
  this.apiKey = apiKey;
13831
13968
  this.agentId = agentId;
13969
+ this.targetUserId = targetUserId;
13970
+ }
13971
+ get dataPath() {
13972
+ const base = `/developer/user/data/agent/${this.agentId}`;
13973
+ return this.targetUserId ? `${base}/user/${encodeURIComponent(this.targetUserId)}` : base;
13832
13974
  }
13833
13975
  /**
13834
13976
  * Retrieves user data by userId, email, or phone.
@@ -13847,7 +13989,7 @@ var init_user_data_api_service = __esm({
13847
13989
  }
13848
13990
  let url = `/developer/user/data/agent/${this.agentId}`;
13849
13991
  if (userId) {
13850
- url += `/user/${userId}`;
13992
+ url += `/user/${encodeURIComponent(userId)}`;
13851
13993
  }
13852
13994
  const response = await this.httpGet(url, {
13853
13995
  Authorization: `Bearer ${this.apiKey}`
@@ -13857,7 +13999,8 @@ var init_user_data_api_service = __esm({
13857
13999
  }
13858
14000
  const profile = response.data?._luaProfile;
13859
14001
  const { _luaProfile, ...data } = response.data || {};
13860
- return new UserDataInstance(this, data, profile);
14002
+ const scopedApi = userId ? new _UserDataApi(this.baseUrl, this.apiKey, this.agentId, userId) : this;
14003
+ return new UserDataInstance(scopedApi, data, profile);
13861
14004
  }
13862
14005
  /**
13863
14006
  * Resolves email or phone to user profile via DeveloperApi
@@ -13868,11 +14011,11 @@ var init_user_data_api_service = __esm({
13868
14011
  try {
13869
14012
  const developerApi = await getDeveloperInstance();
13870
14013
  if (options.email) {
13871
- const response = await developerApi.getUserProfileByEmail(options.email);
14014
+ const response = await developerApi.getUserProfileByEmail(options.email, this.agentId);
13872
14015
  return response.success ? response.data ?? null : null;
13873
14016
  }
13874
14017
  if (options.phone) {
13875
- const response = await developerApi.getUserProfileByPhone(options.phone);
14018
+ const response = await developerApi.getUserProfileByPhone(options.phone, this.agentId);
13876
14019
  return response.success ? response.data ?? null : null;
13877
14020
  }
13878
14021
  } catch (error) {
@@ -13890,7 +14033,7 @@ var init_user_data_api_service = __esm({
13890
14033
  * @throws Error if the update fails or the request is unsuccessful
13891
14034
  */
13892
14035
  async update(data) {
13893
- const response = await this.httpPut(`/developer/user/data/agent/${this.agentId}`, data, {
14036
+ const response = await this.httpPut(this.dataPath, data, {
13894
14037
  Authorization: `Bearer ${this.apiKey}`
13895
14038
  });
13896
14039
  if (!response.success) {
@@ -13899,13 +14042,23 @@ var init_user_data_api_service = __esm({
13899
14042
  const { _luaProfile, ...cleanData } = response.data || {};
13900
14043
  return cleanData;
13901
14044
  }
14045
+ async patch(mutation) {
14046
+ const response = await this.httpPatch(this.dataPath, mutation, {
14047
+ Authorization: `Bearer ${this.apiKey}`
14048
+ });
14049
+ if (!response.success) {
14050
+ throw new Error(response.error?.message || "Failed to patch user data");
14051
+ }
14052
+ const { _luaProfile, ...cleanData } = response.data || {};
14053
+ return cleanData;
14054
+ }
13902
14055
  /**
13903
14056
  * Clears all user data for the current user and specific agent
13904
14057
  * @returns Promise resolving to an empty object upon successful deletion
13905
14058
  * @throws Error if the clear operation fails or the request is unsuccessful
13906
14059
  */
13907
14060
  async clear() {
13908
- const response = await this.httpDelete(`/developer/user/data/agent/${this.agentId}`, {
14061
+ const response = await this.httpDelete(this.dataPath, {
13909
14062
  Authorization: `Bearer ${this.apiKey}`
13910
14063
  });
13911
14064
  if (!response.success) {
@@ -40625,6 +40778,7 @@ __name(deleteServerInteractive, "deleteServerInteractive");
40625
40778
  init_cli();
40626
40779
  init_constants();
40627
40780
  import http from "http";
40781
+ import { randomBytes } from "crypto";
40628
40782
  import { URL as URL2 } from "url";
40629
40783
  import open5 from "open";
40630
40784
  init_command_utils();
@@ -40666,18 +40820,14 @@ var UnifiedToApi = class extends HttpClient {
40666
40820
  async getAuthUrl(integrationType, options) {
40667
40821
  const params = new URLSearchParams();
40668
40822
  params.append("integrationType", integrationType);
40823
+ params.append("agentId", options.agentId);
40669
40824
  params.append("successRedirect", options.successRedirect);
40670
40825
  params.append("failureRedirect", options.failureRedirect);
40671
40826
  if (options.scopes && options.scopes.length > 0) {
40672
40827
  params.append("scopes", options.scopes.join(","));
40673
40828
  }
40674
- if (options.state) {
40675
- params.append("state", options.state);
40676
- }
40677
- if (options.externalXref) {
40678
- params.append("externalXref", options.externalXref);
40679
- }
40680
- return this.httpGet(`/developer/unifiedto/auth-url?${params.toString()}`, {
40829
+ params.append("state", options.state);
40830
+ return this.httpGet(`/developer/unifiedto/auth-url/v2?${params.toString()}`, {
40681
40831
  Authorization: `Bearer ${this.apiKey}`
40682
40832
  });
40683
40833
  }
@@ -40823,7 +40973,8 @@ var UnifiedToApi = class extends HttpClient {
40823
40973
  // src/commands/integrations.ts
40824
40974
  init_analytics();
40825
40975
  var CALLBACK_PORT = 19837;
40826
- var CALLBACK_URL = `http://localhost:${CALLBACK_PORT}/callback`;
40976
+ var CALLBACK_HOST = "127.0.0.1";
40977
+ var CALLBACK_URL = `http://${CALLBACK_HOST}:${CALLBACK_PORT}/callback`;
40827
40978
  var AGENT_WEBHOOK_URL = `${BASE_URLS.API}/webhook/unifiedto/data`;
40828
40979
  var DEFAULT_VIRTUAL_WEBHOOK_INTERVAL = 1;
40829
40980
  async function fetchAvailableIntegrations(unifiedToApi, agentId) {
@@ -40842,22 +40993,50 @@ async function fetchAvailableIntegrations(unifiedToApi, agentId) {
40842
40993
  }));
40843
40994
  }
40844
40995
  __name(fetchAvailableIntegrations, "fetchAvailableIntegrations");
40845
- function startCallbackServer(timeoutMs = 3e5) {
40996
+ function createOAuthState() {
40997
+ return randomBytes(32).toString("base64url");
40998
+ }
40999
+ __name(createOAuthState, "createOAuthState");
41000
+ function escapeHtml(value) {
41001
+ return value.replace(/[&<>"']/g, (character) => {
41002
+ const escaped = {
41003
+ "&": "&amp;",
41004
+ "<": "&lt;",
41005
+ ">": "&gt;",
41006
+ '"': "&quot;",
41007
+ "'": "&#039;"
41008
+ };
41009
+ return escaped[character];
41010
+ });
41011
+ }
41012
+ __name(escapeHtml, "escapeHtml");
41013
+ function startCallbackServer(expectedState, timeoutMs = 3e5) {
40846
41014
  return new Promise((resolve6) => {
40847
41015
  let resolved = false;
40848
41016
  const server = http.createServer((req, res) => {
40849
41017
  if (resolved) return;
40850
41018
  const reqUrl = new URL2(req.url || "/", `http://localhost:${CALLBACK_PORT}`);
40851
41019
  if (reqUrl.pathname === "/callback") {
41020
+ const returnedState = reqUrl.searchParams.get("state");
41021
+ if (returnedState !== expectedState) {
41022
+ res.writeHead(400, {
41023
+ "Content-Type": "text/plain; charset=utf-8",
41024
+ "Cache-Control": "no-store",
41025
+ "X-Content-Type-Options": "nosniff"
41026
+ });
41027
+ res.end("Invalid OAuth state");
41028
+ return;
41029
+ }
40852
41030
  const connectionId = reqUrl.searchParams.get("id");
40853
41031
  const error = reqUrl.searchParams.get("error");
40854
41032
  const logId = reqUrl.searchParams.get("log_id");
40855
41033
  const integrationType = reqUrl.searchParams.get("type");
40856
41034
  resolved = true;
40857
41035
  if (error) {
40858
- const logIdHtml = logId ? `<p style="color: #888; font-size: 0.85em;">Log ID: <code>${logId}</code></p>` : "";
41036
+ const logIdHtml = logId ? `<p style="color: #888; font-size: 0.85em;">Log ID: <code>${escapeHtml(logId)}</code></p>` : "";
40859
41037
  res.writeHead(200, {
40860
- "Content-Type": "text/html"
41038
+ "Content-Type": "text/html; charset=utf-8",
41039
+ "Cache-Control": "no-store"
40861
41040
  });
40862
41041
  res.end(`
40863
41042
  <!DOCTYPE html>
@@ -40866,7 +41045,7 @@ function startCallbackServer(timeoutMs = 3e5) {
40866
41045
  <body style="font-family: system-ui; display: flex; justify-content: center; align-items: center; height: 100vh; margin: 0; background: #1a1a2e;">
40867
41046
  <div style="text-align: center; color: white; max-width: 500px; padding: 0 20px;">
40868
41047
  <h1 style="color: #ff6b6b;">Connection Failed</h1>
40869
- <p style="color: #ccc;">Error: ${error}</p>
41048
+ <p style="color: #ccc;">Authentication failed. Return to the terminal for details.</p>
40870
41049
  ${logIdHtml}
40871
41050
  <p style="color: #888;">You can close this window and try again.</p>
40872
41051
  </div>
@@ -40881,7 +41060,8 @@ function startCallbackServer(timeoutMs = 3e5) {
40881
41060
  });
40882
41061
  } else if (connectionId) {
40883
41062
  res.writeHead(200, {
40884
- "Content-Type": "text/html"
41063
+ "Content-Type": "text/html; charset=utf-8",
41064
+ "Cache-Control": "no-store"
40885
41065
  });
40886
41066
  res.end(`
40887
41067
  <!DOCTYPE html>
@@ -40915,7 +41095,7 @@ function startCallbackServer(timeoutMs = 3e5) {
40915
41095
  res.end("Not found");
40916
41096
  }
40917
41097
  });
40918
- server.listen(CALLBACK_PORT, () => {
41098
+ server.listen(CALLBACK_PORT, CALLBACK_HOST, () => {
40919
41099
  });
40920
41100
  setTimeout(() => {
40921
41101
  if (!resolved) {
@@ -41616,22 +41796,13 @@ Available triggers for ${selectedIntegration.name}:`);
41616
41796
  writeInfo(`Note: Could not fetch available triggers (${error.message})`);
41617
41797
  }
41618
41798
  writeProgress("\u{1F504} Preparing authorization...");
41619
- const state = Buffer.from(JSON.stringify({
41620
- agentId: context.agentId,
41621
- integration: selectedIntegration.value,
41622
- authMethod,
41623
- timestamp: Date.now()
41624
- })).toString("base64");
41625
- const externalXref = JSON.stringify({
41626
- agentId: context.agentId,
41627
- userId: context.userId
41628
- });
41799
+ const state = createOAuthState();
41629
41800
  const authUrlResult = await context.unifiedToApi.getAuthUrl(selectedIntegration.value, {
41801
+ agentId: context.agentId,
41630
41802
  successRedirect: CALLBACK_URL,
41631
41803
  failureRedirect: CALLBACK_URL,
41632
41804
  scopes: authMethod === "oauth" ? selectedScopes : void 0,
41633
- state,
41634
- externalXref
41805
+ state
41635
41806
  });
41636
41807
  if (!authUrlResult.success || !authUrlResult.data) {
41637
41808
  writeError(`\u274C Failed to get authorization URL: ${authUrlResult.error?.message || "Unknown error"}`);
@@ -41647,7 +41818,7 @@ Integration: ${selectedIntegration.name}`);
41647
41818
  \u{1F4CB} Authorization URL (copy if browser doesn't open):
41648
41819
  ${authUrl}
41649
41820
  `);
41650
- const callbackPromise = startCallbackServer(3e5);
41821
+ const callbackPromise = startCallbackServer(state, 3e5);
41651
41822
  try {
41652
41823
  await open5(authUrl);
41653
41824
  writeInfo("\u{1F310} Browser opened - please complete the authorization");
@@ -42049,22 +42220,13 @@ Available scopes for ${selectedIntegration.name}:`);
42049
42220
  writeError(`\u274C Failed to remove old connection: ${error.message}`);
42050
42221
  return;
42051
42222
  }
42052
- const state = Buffer.from(JSON.stringify({
42053
- agentId: context.agentId,
42054
- integration: selectedIntegration.value,
42055
- authMethod: "oauth",
42056
- timestamp: Date.now()
42057
- })).toString("base64");
42058
- const externalXref = JSON.stringify({
42059
- agentId: context.agentId,
42060
- userId: context.userId
42061
- });
42223
+ const state = createOAuthState();
42062
42224
  const authUrlResult = await context.unifiedToApi.getAuthUrl(selectedIntegration.value, {
42225
+ agentId: context.agentId,
42063
42226
  successRedirect: CALLBACK_URL,
42064
42227
  failureRedirect: CALLBACK_URL,
42065
42228
  scopes: selectedScopes,
42066
- state,
42067
- externalXref
42229
+ state
42068
42230
  });
42069
42231
  if (!authUrlResult.success || !authUrlResult.data) {
42070
42232
  writeError(`\u274C Failed to get authorization URL: ${authUrlResult.error?.message || "Unknown error"}`);
@@ -42078,7 +42240,7 @@ Available scopes for ${selectedIntegration.name}:`);
42078
42240
  \u{1F4CB} Authorization URL (copy if browser doesn't open):
42079
42241
  ${authUrl}
42080
42242
  `);
42081
- const callbackPromise = startCallbackServer(3e5);
42243
+ const callbackPromise = startCallbackServer(state, 3e5);
42082
42244
  try {
42083
42245
  await open5(authUrl);
42084
42246
  writeInfo("\u{1F310} Browser opened - please complete the authorization");