@agentforge/tools 0.16.70 → 0.16.72

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
@@ -788,7 +788,7 @@ function getDefaultSlackClient() {
788
788
  }
789
789
  };
790
790
  }
791
- function createSendSlackMessageTool(getSlackClient, logger18) {
791
+ function createSendSlackMessageTool(getSlackClient, logger19) {
792
792
  return toolBuilder().name("send-slack-message").description("Send a message to a Slack channel for team communication and notifications").category(ToolCategory.WEB).tags(["slack", "messaging", "communication"]).usageNotes(
793
793
  "Use this for general team communication. For notifications with @mentions, consider using notify-slack instead. Use get-slack-channels first if you need to find the right channel."
794
794
  ).suggests(["get-slack-channels"]).schema(
@@ -797,7 +797,7 @@ function createSendSlackMessageTool(getSlackClient, logger18) {
797
797
  message: z.string().describe("Message content to send")
798
798
  })
799
799
  ).implementSafe(async ({ channel, message }) => {
800
- logger18.info("send-slack-message called", { channel, messageLength: message.length });
800
+ logger19.info("send-slack-message called", { channel, messageLength: message.length });
801
801
  try {
802
802
  const { client: slack, config } = getSlackClient();
803
803
  const result = await slack.chat.postMessage({
@@ -806,7 +806,7 @@ function createSendSlackMessageTool(getSlackClient, logger18) {
806
806
  username: config.botName,
807
807
  icon_emoji: config.botIcon
808
808
  });
809
- logger18.info("send-slack-message result", {
809
+ logger19.info("send-slack-message result", {
810
810
  ...result.channel ? { channel: result.channel } : {},
811
811
  ...result.ts ? { timestamp: result.ts } : {},
812
812
  messageLength: message.length,
@@ -819,7 +819,7 @@ function createSendSlackMessageTool(getSlackClient, logger18) {
819
819
  message_id: result.ts
820
820
  };
821
821
  } catch (error) {
822
- logger18.error("send-slack-message failed", {
822
+ logger19.error("send-slack-message failed", {
823
823
  channel,
824
824
  error: error.message,
825
825
  data: error.data
@@ -828,7 +828,7 @@ function createSendSlackMessageTool(getSlackClient, logger18) {
828
828
  }
829
829
  }).build();
830
830
  }
831
- function createNotifySlackTool(getSlackClient, logger18) {
831
+ function createNotifySlackTool(getSlackClient, logger19) {
832
832
  return toolBuilder().name("notify-slack").description("Send a notification to a Slack channel with optional @mentions for urgent alerts").category(ToolCategory.WEB).tags(["slack", "notification", "alert"]).usageNotes(
833
833
  "Use this for urgent notifications that require @mentions. For general messages without mentions, use send-slack-message instead."
834
834
  ).suggests(["get-slack-channels"]).schema(
@@ -838,7 +838,7 @@ function createNotifySlackTool(getSlackClient, logger18) {
838
838
  mentions: z.array(z.string()).optional().describe("List of usernames to mention (without @)")
839
839
  })
840
840
  ).implementSafe(async ({ channel, message, mentions = [] }) => {
841
- logger18.info("notify-slack called", {
841
+ logger19.info("notify-slack called", {
842
842
  channel,
843
843
  messageLength: message.length,
844
844
  mentionCount: mentions.length
@@ -852,7 +852,7 @@ function createNotifySlackTool(getSlackClient, logger18) {
852
852
  username: config.botName,
853
853
  icon_emoji: config.botIcon
854
854
  });
855
- logger18.info("notify-slack result", {
855
+ logger19.info("notify-slack result", {
856
856
  ...result.channel ? { channel: result.channel } : {},
857
857
  ...result.ts ? { timestamp: result.ts } : {},
858
858
  mentions: mentions.length
@@ -866,7 +866,7 @@ function createNotifySlackTool(getSlackClient, logger18) {
866
866
  };
867
867
  }).build();
868
868
  }
869
- function createGetSlackChannelsTool(getSlackClient, logger18) {
869
+ function createGetSlackChannelsTool(getSlackClient, logger19) {
870
870
  return toolBuilder().name("get-slack-channels").description("Get a list of available Slack channels to find the right channel for messaging").category(ToolCategory.WEB).tags(["slack", "channels", "list"]).usageNotes(
871
871
  "Use this first to discover available channels before sending messages. Helps ensure you are sending to the correct channel."
872
872
  ).follows(["send-slack-message", "notify-slack"]).schema(
@@ -874,7 +874,7 @@ function createGetSlackChannelsTool(getSlackClient, logger18) {
874
874
  include_private: z.boolean().optional().describe("Include private channels (default: false)")
875
875
  })
876
876
  ).implementSafe(async ({ include_private = false }) => {
877
- logger18.info("get-slack-channels called", { include_private });
877
+ logger19.info("get-slack-channels called", { include_private });
878
878
  const { client: slack } = getSlackClient();
879
879
  const publicChannels = await slack.conversations.list({
880
880
  types: "public_channel",
@@ -888,7 +888,7 @@ function createGetSlackChannelsTool(getSlackClient, logger18) {
888
888
  });
889
889
  allChannels = [...allChannels, ...privateChannels.channels || []];
890
890
  }
891
- logger18.info("get-slack-channels result", {
891
+ logger19.info("get-slack-channels result", {
892
892
  channelCount: allChannels.length,
893
893
  includePrivate: include_private
894
894
  });
@@ -903,7 +903,7 @@ function createGetSlackChannelsTool(getSlackClient, logger18) {
903
903
  };
904
904
  }).build();
905
905
  }
906
- function createGetSlackMessagesTool(getSlackClient, logger18) {
906
+ function createGetSlackMessagesTool(getSlackClient, logger19) {
907
907
  return toolBuilder().name("get-slack-messages").description("Retrieve message history from a Slack channel to read recent conversations").category(ToolCategory.WEB).tags(["slack", "messages", "history", "read"]).usageNotes(
908
908
  "Use this to read recent messages from a channel. Use get-slack-channels first if you need to find the channel ID. Returns messages in reverse chronological order (newest first)."
909
909
  ).suggests(["get-slack-channels"]).schema(
@@ -912,7 +912,7 @@ function createGetSlackMessagesTool(getSlackClient, logger18) {
912
912
  limit: z.number().int().min(1).max(100).optional().describe("Number of messages to retrieve (default: 20, max: 100)")
913
913
  })
914
914
  ).implementSafe(async ({ channel, limit = 20 }) => {
915
- logger18.info("get-slack-messages called", { channel, limit });
915
+ logger19.info("get-slack-messages called", { channel, limit });
916
916
  try {
917
917
  const { client: slack } = getSlackClient();
918
918
  let channelId = channel;
@@ -923,7 +923,7 @@ function createGetSlackMessagesTool(getSlackClient, logger18) {
923
923
  });
924
924
  const found = channels.channels?.find((c) => c.name === channel);
925
925
  if (!found) {
926
- logger18.error("get-slack-messages: channel not found", { channel });
926
+ logger19.error("get-slack-messages: channel not found", { channel });
927
927
  throw new Error(
928
928
  `Channel '${channel}' not found. Use get-slack-channels to see available channels.`
929
929
  );
@@ -935,7 +935,7 @@ function createGetSlackMessagesTool(getSlackClient, logger18) {
935
935
  limit: Math.min(limit, 100)
936
936
  // Cap at 100 for performance
937
937
  });
938
- logger18.info("get-slack-messages result", {
938
+ logger19.info("get-slack-messages result", {
939
939
  channel: channelId,
940
940
  messageCount: result.messages?.length || 0,
941
941
  limit
@@ -953,7 +953,7 @@ function createGetSlackMessagesTool(getSlackClient, logger18) {
953
953
  })) || []
954
954
  };
955
955
  } catch (error) {
956
- logger18.error("get-slack-messages failed", {
956
+ logger19.error("get-slack-messages failed", {
957
957
  channel,
958
958
  error: error.message,
959
959
  data: error.data
@@ -1034,12 +1034,12 @@ function getAuthHeader() {
1034
1034
  const auth2 = Buffer.from(`${ATLASSIAN_EMAIL}:${ATLASSIAN_API_KEY}`).toString("base64");
1035
1035
  return `Basic ${auth2}`;
1036
1036
  }
1037
- function createSearchConfluenceTool(getAuth, getAuthHeader2, logger18) {
1037
+ function createSearchConfluenceTool(getAuth, getAuthHeader2, logger19) {
1038
1038
  return toolBuilder().name("search-confluence").description("Search for pages in Confluence using keywords or CQL (Confluence Query Language). Returns matching pages with titles, IDs, and excerpts.").category(ToolCategory.WEB).tag("confluence").tag("search").tag("knowledge-base").usageNotes("Use this to find relevant documentation, policies, or information in Confluence. You can search by keywords or use CQL for advanced queries (e.g., 'space=AI AND type=page'). Use get-confluence-page to retrieve full content of specific pages.").suggests(["get-confluence-page"]).schema(z.object({
1039
1039
  query: z.string().describe("Search query or CQL expression (e.g., 'payment processing' or 'space=BL3 AND title~payment')"),
1040
1040
  limit: z.number().optional().describe("Maximum number of results to return (default: 10, max: 25)")
1041
1041
  })).implement(async ({ query, limit = 10 }) => {
1042
- logger18.info("search-confluence called", { query, limit });
1042
+ logger19.info("search-confluence called", { query, limit });
1043
1043
  try {
1044
1044
  const { ATLASSIAN_SITE_URL } = getAuth();
1045
1045
  const response = await axios16.get(`${ATLASSIAN_SITE_URL}/wiki/rest/api/content/search`, {
@@ -1064,13 +1064,13 @@ function createSearchConfluenceTool(getAuth, getAuthHeader2, logger18) {
1064
1064
  lastModified: page.version?.when || ""
1065
1065
  }));
1066
1066
  if (results.length === 0) {
1067
- logger18.warn("search-confluence returned NO RESULTS - this is a valid outcome, agent should not retry", {
1067
+ logger19.warn("search-confluence returned NO RESULTS - this is a valid outcome, agent should not retry", {
1068
1068
  query,
1069
1069
  limit,
1070
1070
  totalSize: response.data.totalSize
1071
1071
  });
1072
1072
  } else {
1073
- logger18.info("search-confluence result", {
1073
+ logger19.info("search-confluence result", {
1074
1074
  query,
1075
1075
  resultCount: results.length,
1076
1076
  totalSize: response.data.totalSize,
@@ -1085,7 +1085,7 @@ function createSearchConfluenceTool(getAuth, getAuthHeader2, logger18) {
1085
1085
  results
1086
1086
  });
1087
1087
  } catch (error) {
1088
- logger18.error("search-confluence error", {
1088
+ logger19.error("search-confluence error", {
1089
1089
  query,
1090
1090
  error: error.response?.data?.message || error.message,
1091
1091
  status: error.response?.status
@@ -1097,11 +1097,11 @@ function createSearchConfluenceTool(getAuth, getAuthHeader2, logger18) {
1097
1097
  }
1098
1098
  }).build();
1099
1099
  }
1100
- function createGetConfluencePageTool(getAuth, getAuthHeader2, logger18) {
1100
+ function createGetConfluencePageTool(getAuth, getAuthHeader2, logger19) {
1101
1101
  return toolBuilder().name("get-confluence-page").description("Get the full content of a specific Confluence page by its ID. Returns the page title, content (in storage format), space, and metadata.").category(ToolCategory.WEB).tag("confluence").tag("page").tag("content").usageNotes("Use this after search-confluence to retrieve the full content of a specific page. The page ID can be found in search results.").requires(["search-confluence"]).schema(z.object({
1102
1102
  page_id: z.string().describe("The Confluence page ID (from search results)")
1103
1103
  })).implement(async ({ page_id }) => {
1104
- logger18.info("get-confluence-page called", { page_id });
1104
+ logger19.info("get-confluence-page called", { page_id });
1105
1105
  try {
1106
1106
  const { ATLASSIAN_SITE_URL } = getAuth();
1107
1107
  const response = await axios16.get(`${ATLASSIAN_SITE_URL}/wiki/rest/api/content/${page_id}`, {
@@ -1114,7 +1114,7 @@ function createGetConfluencePageTool(getAuth, getAuthHeader2, logger18) {
1114
1114
  }
1115
1115
  });
1116
1116
  const page = response.data;
1117
- logger18.info("get-confluence-page result", {
1117
+ logger19.info("get-confluence-page result", {
1118
1118
  page_id,
1119
1119
  title: page.title,
1120
1120
  space: page.space?.name,
@@ -1136,7 +1136,7 @@ function createGetConfluencePageTool(getAuth, getAuthHeader2, logger18) {
1136
1136
  }
1137
1137
  });
1138
1138
  } catch (error) {
1139
- logger18.error("get-confluence-page error", {
1139
+ logger19.error("get-confluence-page error", {
1140
1140
  page_id,
1141
1141
  error: error.response?.data?.message || error.message,
1142
1142
  status: error.response?.status
@@ -1148,11 +1148,11 @@ function createGetConfluencePageTool(getAuth, getAuthHeader2, logger18) {
1148
1148
  }
1149
1149
  }).build();
1150
1150
  }
1151
- function createListConfluenceSpacesTool(getAuth, getAuthHeader2, logger18) {
1151
+ function createListConfluenceSpacesTool(getAuth, getAuthHeader2, logger19) {
1152
1152
  return toolBuilder().name("list-confluence-spaces").description("List all available Confluence spaces. Returns space names, keys, types, and descriptions to help identify where to search for information.").category(ToolCategory.WEB).tag("confluence").tag("spaces").tag("list").usageNotes("Use this first to discover available spaces before searching. Helps narrow down searches to specific areas (e.g., 'AI', 'BL3', 'Finance').").follows(["search-confluence"]).schema(z.object({
1153
1153
  limit: z.number().optional().describe("Maximum number of spaces to return (default: 25)")
1154
1154
  })).implement(async ({ limit = 25 }) => {
1155
- logger18.info("list-confluence-spaces called", { limit });
1155
+ logger19.info("list-confluence-spaces called", { limit });
1156
1156
  try {
1157
1157
  const { ATLASSIAN_SITE_URL } = getAuth();
1158
1158
  const response = await axios16.get(`${ATLASSIAN_SITE_URL}/wiki/rest/api/space`, {
@@ -1171,7 +1171,7 @@ function createListConfluenceSpacesTool(getAuth, getAuthHeader2, logger18) {
1171
1171
  description: space.description?.plain?.value || "",
1172
1172
  url: `${ATLASSIAN_SITE_URL}/wiki${space._links.webui}`
1173
1173
  }));
1174
- logger18.info("list-confluence-spaces result", {
1174
+ logger19.info("list-confluence-spaces result", {
1175
1175
  spaceCount: spaces.length,
1176
1176
  spaceKeys: spaces.map((s) => s.key).slice(0, 5)
1177
1177
  // Log first 5 space keys
@@ -1182,7 +1182,7 @@ function createListConfluenceSpacesTool(getAuth, getAuthHeader2, logger18) {
1182
1182
  spaces
1183
1183
  });
1184
1184
  } catch (error) {
1185
- logger18.error("list-confluence-spaces error", {
1185
+ logger19.error("list-confluence-spaces error", {
1186
1186
  error: error.response?.data?.message || error.message,
1187
1187
  status: error.response?.status
1188
1188
  });
@@ -1193,12 +1193,12 @@ function createListConfluenceSpacesTool(getAuth, getAuthHeader2, logger18) {
1193
1193
  }
1194
1194
  }).build();
1195
1195
  }
1196
- function createGetSpacePagesTool(getAuth, getAuthHeader2, logger18) {
1196
+ function createGetSpacePagesTool(getAuth, getAuthHeader2, logger19) {
1197
1197
  return toolBuilder().name("get-space-pages").description("Get all pages from a specific Confluence space by space key. Useful for browsing content in a particular area.").category(ToolCategory.WEB).tag("confluence").tag("space").tag("pages").usageNotes("Use this to explore all pages in a specific space. Get the space key from list-confluence-spaces first.").requires(["list-confluence-spaces"]).schema(z.object({
1198
1198
  space_key: z.string().describe("The space key (e.g., 'AI', 'BL3', 'FIN')"),
1199
1199
  limit: z.number().optional().describe("Maximum number of pages to return (default: 25)")
1200
1200
  })).implement(async ({ space_key, limit = 25 }) => {
1201
- logger18.info("get-space-pages called", { space_key, limit });
1201
+ logger19.info("get-space-pages called", { space_key, limit });
1202
1202
  try {
1203
1203
  const { ATLASSIAN_SITE_URL } = getAuth();
1204
1204
  const response = await axios16.get(`${ATLASSIAN_SITE_URL}/wiki/rest/api/content`, {
@@ -1220,12 +1220,12 @@ function createGetSpacePagesTool(getAuth, getAuthHeader2, logger18) {
1220
1220
  lastModified: page.version?.when || ""
1221
1221
  }));
1222
1222
  if (pages.length === 0) {
1223
- logger18.warn("get-space-pages returned NO PAGES - this is a valid outcome, agent should not retry", {
1223
+ logger19.warn("get-space-pages returned NO PAGES - this is a valid outcome, agent should not retry", {
1224
1224
  space_key,
1225
1225
  limit
1226
1226
  });
1227
1227
  } else {
1228
- logger18.info("get-space-pages result", {
1228
+ logger19.info("get-space-pages result", {
1229
1229
  space_key,
1230
1230
  pageCount: pages.length,
1231
1231
  titles: pages.map((p) => p.title).slice(0, 3)
@@ -1239,7 +1239,7 @@ function createGetSpacePagesTool(getAuth, getAuthHeader2, logger18) {
1239
1239
  pages
1240
1240
  });
1241
1241
  } catch (error) {
1242
- logger18.error("get-space-pages error", {
1242
+ logger19.error("get-space-pages error", {
1243
1243
  space_key,
1244
1244
  error: error.response?.data?.message || error.message,
1245
1245
  status: error.response?.status
@@ -1251,14 +1251,14 @@ function createGetSpacePagesTool(getAuth, getAuthHeader2, logger18) {
1251
1251
  }
1252
1252
  }).build();
1253
1253
  }
1254
- function createCreateConfluencePageTool(getAuth, getAuthHeader2, logger18) {
1254
+ function createCreateConfluencePageTool(getAuth, getAuthHeader2, logger19) {
1255
1255
  return toolBuilder().name("create-confluence-page").description("Create a new page in a Confluence space. Requires space key, page title, and content (in HTML storage format).").category(ToolCategory.WEB).tag("confluence").tag("create").tag("write").usageNotes("Use this to create new documentation pages. Content should be in Confluence storage format (HTML). Get the space key from list-confluence-spaces first. Be mindful of creating duplicate pages.").requires(["list-confluence-spaces"]).schema(z.object({
1256
1256
  space_key: z.string().describe("The space key where the page will be created (e.g., 'AI', 'BL3')"),
1257
1257
  title: z.string().describe("The title of the new page"),
1258
1258
  content: z.string().describe("The page content in HTML format (Confluence storage format)"),
1259
1259
  parent_page_id: z.string().optional().describe("Optional parent page ID to create this as a child page")
1260
1260
  })).implement(async ({ space_key, title, content, parent_page_id }) => {
1261
- logger18.info("create-confluence-page called", { space_key, title, hasParent: !!parent_page_id });
1261
+ logger19.info("create-confluence-page called", { space_key, title, hasParent: !!parent_page_id });
1262
1262
  try {
1263
1263
  const { ATLASSIAN_SITE_URL } = getAuth();
1264
1264
  const pageData = {
@@ -1285,7 +1285,7 @@ function createCreateConfluencePageTool(getAuth, getAuthHeader2, logger18) {
1285
1285
  }
1286
1286
  }
1287
1287
  );
1288
- logger18.info("create-confluence-page result", {
1288
+ logger19.info("create-confluence-page result", {
1289
1289
  page_id: response.data.id,
1290
1290
  title: response.data.title,
1291
1291
  space: space_key
@@ -1301,7 +1301,7 @@ function createCreateConfluencePageTool(getAuth, getAuthHeader2, logger18) {
1301
1301
  }
1302
1302
  });
1303
1303
  } catch (error) {
1304
- logger18.error("create-confluence-page error", {
1304
+ logger19.error("create-confluence-page error", {
1305
1305
  space_key,
1306
1306
  title,
1307
1307
  error: error.response?.data?.message || error.message,
@@ -1314,13 +1314,13 @@ function createCreateConfluencePageTool(getAuth, getAuthHeader2, logger18) {
1314
1314
  }
1315
1315
  }).build();
1316
1316
  }
1317
- function createUpdateConfluencePageTool(getAuth, getAuthHeader2, logger18) {
1317
+ function createUpdateConfluencePageTool(getAuth, getAuthHeader2, logger19) {
1318
1318
  return toolBuilder().name("update-confluence-page").description("Update an existing Confluence page's content. Requires page ID, new title, and new content.").category(ToolCategory.WEB).tag("confluence").tag("update").tag("write").usageNotes("Use this to update existing documentation. You must provide the page ID (from search results). The tool will automatically handle version incrementing. Always get the current page content first to avoid overwriting important information.").requires(["get-confluence-page"]).schema(z.object({
1319
1319
  page_id: z.string().describe("The ID of the page to update"),
1320
1320
  title: z.string().describe("The new title for the page"),
1321
1321
  content: z.string().describe("The new content in HTML format (Confluence storage format)")
1322
1322
  })).implement(async ({ page_id, title, content }) => {
1323
- logger18.info("update-confluence-page called", { page_id, title });
1323
+ logger19.info("update-confluence-page called", { page_id, title });
1324
1324
  try {
1325
1325
  const { ATLASSIAN_SITE_URL } = getAuth();
1326
1326
  const getResponse = await axios16.get(
@@ -1353,7 +1353,7 @@ function createUpdateConfluencePageTool(getAuth, getAuthHeader2, logger18) {
1353
1353
  }
1354
1354
  }
1355
1355
  );
1356
- logger18.info("update-confluence-page result", {
1356
+ logger19.info("update-confluence-page result", {
1357
1357
  page_id,
1358
1358
  title: updateResponse.data.title,
1359
1359
  previousVersion: currentVersion,
@@ -1370,7 +1370,7 @@ function createUpdateConfluencePageTool(getAuth, getAuthHeader2, logger18) {
1370
1370
  }
1371
1371
  });
1372
1372
  } catch (error) {
1373
- logger18.error("update-confluence-page error", {
1373
+ logger19.error("update-confluence-page error", {
1374
1374
  page_id,
1375
1375
  title,
1376
1376
  error: error.response?.data?.message || error.message,
@@ -1383,12 +1383,12 @@ function createUpdateConfluencePageTool(getAuth, getAuthHeader2, logger18) {
1383
1383
  }
1384
1384
  }).build();
1385
1385
  }
1386
- function createArchiveConfluencePageTool(getAuth, getAuthHeader2, logger18) {
1386
+ function createArchiveConfluencePageTool(getAuth, getAuthHeader2, logger19) {
1387
1387
  return toolBuilder().name("archive-confluence-page").description("Archive a Confluence page by moving it to trash. The page can be restored by space admins. Note: UI may require a note explaining why the page was archived.").category(ToolCategory.WEB).tag("confluence").tag("archive").tag("delete").usageNotes("Use this to archive outdated or obsolete documentation. The page is moved to trash, not permanently deleted. Space admins can restore it if needed. Be very careful - only archive pages that are truly obsolete.").conflicts(["create-confluence-page"]).schema(z.object({
1388
1388
  page_id: z.string().describe("The ID of the page to archive"),
1389
1389
  reason: z.string().optional().describe("Optional reason for archiving (for audit trail)")
1390
1390
  })).implement(async ({ page_id, reason }) => {
1391
- logger18.info("archive-confluence-page called", {
1391
+ logger19.info("archive-confluence-page called", {
1392
1392
  page_id,
1393
1393
  ...reason ? { reason } : {}
1394
1394
  });
@@ -1422,7 +1422,7 @@ function createArchiveConfluencePageTool(getAuth, getAuthHeader2, logger18) {
1422
1422
  }
1423
1423
  }
1424
1424
  );
1425
- logger18.info("archive-confluence-page result", {
1425
+ logger19.info("archive-confluence-page result", {
1426
1426
  page_id,
1427
1427
  title: pageData.title,
1428
1428
  previousVersion: currentVersion,
@@ -1440,7 +1440,7 @@ function createArchiveConfluencePageTool(getAuth, getAuthHeader2, logger18) {
1440
1440
  }
1441
1441
  });
1442
1442
  } catch (error) {
1443
- logger18.error("archive-confluence-page error", {
1443
+ logger19.error("archive-confluence-page error", {
1444
1444
  page_id,
1445
1445
  error: error.response?.data?.message || error.message,
1446
1446
  status: error.response?.status
@@ -4168,19 +4168,19 @@ var ConnectionState = /* @__PURE__ */ ((ConnectionState2) => {
4168
4168
  ConnectionState2["ERROR"] = "error";
4169
4169
  return ConnectionState2;
4170
4170
  })(ConnectionState || {});
4171
- function cancelPendingReconnection(timer, logger18, vendor, message) {
4171
+ function cancelPendingReconnection(timer, logger19, vendor, message) {
4172
4172
  if (!timer) {
4173
4173
  return null;
4174
4174
  }
4175
- logger18.debug(message, { vendor });
4175
+ logger19.debug(message, { vendor });
4176
4176
  clearTimeout(timer);
4177
4177
  return null;
4178
4178
  }
4179
- async function waitForInFlightConnection(promise, logger18, vendor, phase) {
4179
+ async function waitForInFlightConnection(promise, logger19, vendor, phase) {
4180
4180
  if (!promise) {
4181
4181
  return null;
4182
4182
  }
4183
- logger18.debug(`Waiting for in-flight connection attempt to complete before ${phase}`, {
4183
+ logger19.debug(`Waiting for in-flight connection attempt to complete before ${phase}`, {
4184
4184
  vendor
4185
4185
  });
4186
4186
  try {
@@ -4197,9 +4197,9 @@ function shutdownClient(vendor, client) {
4197
4197
  client.close();
4198
4198
  }
4199
4199
  }
4200
- function scheduleReconnection(context, logger18) {
4200
+ function scheduleReconnection(context, logger19) {
4201
4201
  if (context.reconnectionConfig.maxAttempts > 0 && context.reconnectionAttempts >= context.reconnectionConfig.maxAttempts) {
4202
- logger18.error("Max reconnection attempts reached", {
4202
+ logger19.error("Max reconnection attempts reached", {
4203
4203
  vendor: context.vendor,
4204
4204
  attempts: context.reconnectionAttempts,
4205
4205
  maxAttempts: context.reconnectionConfig.maxAttempts
@@ -4213,7 +4213,7 @@ function scheduleReconnection(context, logger18) {
4213
4213
  const nextAttempt = context.reconnectionAttempts + 1;
4214
4214
  context.setReconnectionAttempts(nextAttempt);
4215
4215
  context.setState("reconnecting" /* RECONNECTING */);
4216
- logger18.info("Scheduling reconnection attempt", {
4216
+ logger19.info("Scheduling reconnection attempt", {
4217
4217
  vendor: context.vendor,
4218
4218
  attempt: nextAttempt,
4219
4219
  maxAttempts: context.reconnectionConfig.maxAttempts,
@@ -4227,7 +4227,7 @@ function scheduleReconnection(context, logger18) {
4227
4227
  const timer = setTimeout(async () => {
4228
4228
  context.setReconnectionTimer(null);
4229
4229
  try {
4230
- logger18.info("Attempting reconnection", {
4230
+ logger19.info("Attempting reconnection", {
4231
4231
  vendor: context.vendor,
4232
4232
  attempt: nextAttempt
4233
4233
  });
@@ -4237,7 +4237,7 @@ function scheduleReconnection(context, logger18) {
4237
4237
  context.setConnectPromise(promise);
4238
4238
  await promise;
4239
4239
  } catch (error) {
4240
- logger18.error("Reconnection attempt failed", {
4240
+ logger19.error("Reconnection attempt failed", {
4241
4241
  vendor: context.vendor,
4242
4242
  attempt: nextAttempt,
4243
4243
  error: error instanceof Error ? error.message : String(error)
@@ -4248,17 +4248,17 @@ function scheduleReconnection(context, logger18) {
4248
4248
  }
4249
4249
 
4250
4250
  // src/data/relational/connection/connection-cleanup.ts
4251
- async function cleanupConnectionResources(vendor, client, clearConnection, logger18) {
4251
+ async function cleanupConnectionResources(vendor, client, clearConnection, logger19) {
4252
4252
  if (!client) {
4253
4253
  return;
4254
4254
  }
4255
- logger18.debug("Cleaning up cancelled connection", {
4255
+ logger19.debug("Cleaning up cancelled connection", {
4256
4256
  vendor
4257
4257
  });
4258
4258
  try {
4259
4259
  await shutdownClient(vendor, client);
4260
4260
  } catch (error) {
4261
- logger18.debug("Error during cancelled connection cleanup", {
4261
+ logger19.debug("Error during cancelled connection cleanup", {
4262
4262
  vendor,
4263
4263
  error: error instanceof Error ? error.message : String(error)
4264
4264
  });
@@ -4266,10 +4266,10 @@ async function cleanupConnectionResources(vendor, client, clearConnection, logge
4266
4266
  clearConnection();
4267
4267
  }
4268
4268
  }
4269
- async function closeManagedConnection(runtime, logger18) {
4269
+ async function closeManagedConnection(runtime, logger19) {
4270
4270
  const client = runtime.getClient();
4271
4271
  if (client) {
4272
- logger18.info("Closing database connection", {
4272
+ logger19.info("Closing database connection", {
4273
4273
  vendor: runtime.vendor,
4274
4274
  state: runtime.getState()
4275
4275
  });
@@ -4277,12 +4277,12 @@ async function closeManagedConnection(runtime, logger18) {
4277
4277
  await shutdownClient(runtime.vendor, client);
4278
4278
  runtime.setState("disconnected" /* DISCONNECTED */);
4279
4279
  runtime.emitDisconnected();
4280
- logger18.debug("Database connection closed successfully", {
4280
+ logger19.debug("Database connection closed successfully", {
4281
4281
  vendor: runtime.vendor,
4282
4282
  state: runtime.getState()
4283
4283
  });
4284
4284
  } catch (error) {
4285
- logger18.error("Error closing database connection", {
4285
+ logger19.error("Error closing database connection", {
4286
4286
  vendor: runtime.vendor,
4287
4287
  error: error instanceof Error ? error.message : String(error),
4288
4288
  state: runtime.getState()
@@ -4455,11 +4455,11 @@ async function initializeSQLiteConnection(connection) {
4455
4455
  }
4456
4456
 
4457
4457
  // src/data/relational/connection/connection-initialization.ts
4458
- async function initializeManagedConnection(runtime, logger18) {
4458
+ async function initializeManagedConnection(runtime, logger19) {
4459
4459
  const startTime = Date.now();
4460
4460
  const currentGeneration = runtime.getConnectionGeneration();
4461
4461
  if (runtime.getState() === "connected" /* CONNECTED */ && runtime.getClient()) {
4462
- logger18.warn("Re-initializing an already connected manager; emitting disconnected before cleanup", {
4462
+ logger19.warn("Re-initializing an already connected manager; emitting disconnected before cleanup", {
4463
4463
  vendor: runtime.vendor
4464
4464
  });
4465
4465
  runtime.setState("disconnected" /* DISCONNECTED */);
@@ -4471,11 +4471,11 @@ async function initializeManagedConnection(runtime, logger18) {
4471
4471
  runtime.setClient(null);
4472
4472
  runtime.setDb(null);
4473
4473
  },
4474
- logger18
4474
+ logger19
4475
4475
  );
4476
4476
  }
4477
4477
  runtime.setState("connecting" /* CONNECTING */);
4478
- logger18.info("Initializing database connection", {
4478
+ logger19.info("Initializing database connection", {
4479
4479
  vendor: runtime.vendor,
4480
4480
  connectionType: typeof runtime.config.connection,
4481
4481
  state: runtime.getState()
@@ -4485,7 +4485,7 @@ async function initializeManagedConnection(runtime, logger18) {
4485
4485
  runtime.setClient(initialized.client);
4486
4486
  runtime.setDb(initialized.db);
4487
4487
  if (currentGeneration !== runtime.getConnectionGeneration()) {
4488
- logger18.debug("Connection cancelled during initialization", {
4488
+ logger19.debug("Connection cancelled during initialization", {
4489
4489
  vendor: runtime.vendor,
4490
4490
  currentGeneration,
4491
4491
  newGeneration: runtime.getConnectionGeneration()
@@ -4497,18 +4497,18 @@ async function initializeManagedConnection(runtime, logger18) {
4497
4497
  runtime.setClient(null);
4498
4498
  runtime.setDb(null);
4499
4499
  },
4500
- logger18
4500
+ logger19
4501
4501
  );
4502
4502
  runtime.setState("disconnected" /* DISCONNECTED */);
4503
4503
  throw new Error("Connection cancelled during initialization");
4504
4504
  }
4505
- logger18.debug("Validating connection health", { vendor: runtime.vendor });
4505
+ logger19.debug("Validating connection health", { vendor: runtime.vendor });
4506
4506
  const healthy = await runtime.isHealthy();
4507
4507
  if (!healthy) {
4508
4508
  throw new Error(`Failed to establish healthy connection to ${runtime.vendor} database`);
4509
4509
  }
4510
4510
  if (currentGeneration !== runtime.getConnectionGeneration()) {
4511
- logger18.debug("Connection cancelled during health check", {
4511
+ logger19.debug("Connection cancelled during health check", {
4512
4512
  vendor: runtime.vendor,
4513
4513
  currentGeneration,
4514
4514
  newGeneration: runtime.getConnectionGeneration()
@@ -4520,7 +4520,7 @@ async function initializeManagedConnection(runtime, logger18) {
4520
4520
  runtime.setClient(null);
4521
4521
  runtime.setDb(null);
4522
4522
  },
4523
- logger18
4523
+ logger19
4524
4524
  );
4525
4525
  runtime.setState("disconnected" /* DISCONNECTED */);
4526
4526
  throw new Error("Connection cancelled during health check");
@@ -4528,7 +4528,7 @@ async function initializeManagedConnection(runtime, logger18) {
4528
4528
  runtime.setState("connected" /* CONNECTED */);
4529
4529
  runtime.emitConnected();
4530
4530
  runtime.resetReconnectionAttempts();
4531
- logger18.info("Database connection initialized successfully", {
4531
+ logger19.info("Database connection initialized successfully", {
4532
4532
  vendor: runtime.vendor,
4533
4533
  duration: Date.now() - startTime,
4534
4534
  state: runtime.getState()
@@ -4549,7 +4549,7 @@ async function initializeManagedConnection(runtime, logger18) {
4549
4549
  if (runtime.errorListenerCount() > 0) {
4550
4550
  runtime.emitError(normalizedError);
4551
4551
  }
4552
- logger18.error(errorMessage, {
4552
+ logger19.error(errorMessage, {
4553
4553
  vendor: runtime.vendor,
4554
4554
  error: normalizedError.message,
4555
4555
  duration: Date.now() - startTime,
@@ -4562,13 +4562,13 @@ async function initializeManagedConnection(runtime, logger18) {
4562
4562
  runtime.setClient(null);
4563
4563
  runtime.setDb(null);
4564
4564
  },
4565
- logger18
4565
+ logger19
4566
4566
  );
4567
4567
  if (runtime.getReconnectionConfig().enabled && currentGeneration === runtime.getConnectionGeneration()) {
4568
4568
  runtime.scheduleReconnection();
4569
4569
  }
4570
4570
  } else {
4571
- logger18.debug("Connection initialization cancelled", {
4571
+ logger19.debug("Connection initialization cancelled", {
4572
4572
  vendor: runtime.vendor,
4573
4573
  duration: Date.now() - startTime,
4574
4574
  state: runtime.getState()
@@ -4586,17 +4586,17 @@ function isSqliteNonQueryError(error) {
4586
4586
  const hasNonQueryMessage = error.message.includes("does not return data");
4587
4587
  return isSqliteOrTypeError && hasNonQueryMessage;
4588
4588
  }
4589
- async function checkConnectionHealth(args, logger18) {
4589
+ async function checkConnectionHealth(args, logger19) {
4590
4590
  if (!args.db || !args.client) {
4591
- logger18.debug("Health check failed: connection not initialized", { vendor: args.vendor });
4591
+ logger19.debug("Health check failed: connection not initialized", { vendor: args.vendor });
4592
4592
  return false;
4593
4593
  }
4594
4594
  try {
4595
4595
  await args.execute(sql`SELECT 1`);
4596
- logger18.debug("Health check passed", { vendor: args.vendor });
4596
+ logger19.debug("Health check passed", { vendor: args.vendor });
4597
4597
  return true;
4598
4598
  } catch (error) {
4599
- logger18.debug("Health check failed", {
4599
+ logger19.debug("Health check failed", {
4600
4600
  vendor: args.vendor,
4601
4601
  error: error instanceof Error ? error.message : String(error)
4602
4602
  });
@@ -4639,8 +4639,8 @@ function getConnectionPoolMetrics(vendor, client) {
4639
4639
  }
4640
4640
 
4641
4641
  // src/data/relational/connection/query-execution.ts
4642
- async function executeQuery(context, query, logger18) {
4643
- logger18.debug("Executing SQL query", {
4642
+ async function executeQuery(context, query, logger19) {
4643
+ logger19.debug("Executing SQL query", {
4644
4644
  vendor: context.vendor
4645
4645
  });
4646
4646
  if (context.vendor === "sqlite") {
@@ -6767,16 +6767,24 @@ function findTable(schema, tableName) {
6767
6767
  function formatTableName(table) {
6768
6768
  return table.schema ? `${table.schema}.${table.name}` : table.name;
6769
6769
  }
6770
- var logger13 = createLogger("agentforge:tools:data:relational:type-mapper");
6770
+
6771
+ // src/data/relational/schema/type-mapper-normalization.ts
6772
+ function normaliseDbType(raw) {
6773
+ let type = raw.toLowerCase().trim();
6774
+ type = type.replace(/\[\]$/, "");
6775
+ type = type.replace(/\([\d,\s]+\)/, "");
6776
+ type = type.replace(/\s+unsigned$/, "");
6777
+ return type.trim();
6778
+ }
6779
+
6780
+ // src/data/relational/schema/type-mapper-vendor-maps.ts
6771
6781
  var POSTGRES_TYPE_MAP = {
6772
- // Numeric
6773
6782
  smallint: "number",
6774
6783
  integer: "number",
6775
6784
  int: "number",
6776
6785
  int2: "number",
6777
6786
  int4: "number",
6778
6787
  int8: "string",
6779
- // bigint → string to avoid JS precision loss
6780
6788
  bigint: "string",
6781
6789
  serial: "number",
6782
6790
  bigserial: "string",
@@ -6786,10 +6794,8 @@ var POSTGRES_TYPE_MAP = {
6786
6794
  "double precision": "number",
6787
6795
  float8: "number",
6788
6796
  numeric: "string",
6789
- // arbitrary precision → string
6790
6797
  decimal: "string",
6791
6798
  money: "string",
6792
- // Text
6793
6799
  text: "string",
6794
6800
  "character varying": "string",
6795
6801
  varchar: "string",
@@ -6797,10 +6803,8 @@ var POSTGRES_TYPE_MAP = {
6797
6803
  character: "string",
6798
6804
  name: "string",
6799
6805
  citext: "string",
6800
- // Boolean
6801
6806
  boolean: "boolean",
6802
6807
  bool: "boolean",
6803
- // Date / time
6804
6808
  date: "string",
6805
6809
  timestamp: "string",
6806
6810
  "timestamp with time zone": "string",
@@ -6811,19 +6815,14 @@ var POSTGRES_TYPE_MAP = {
6811
6815
  "time without time zone": "string",
6812
6816
  timetz: "string",
6813
6817
  interval: "string",
6814
- // JSON
6815
6818
  json: "unknown",
6816
6819
  jsonb: "unknown",
6817
- // Binary
6818
6820
  bytea: "Buffer",
6819
- // UUID
6820
6821
  uuid: "string",
6821
- // Network
6822
6822
  inet: "string",
6823
6823
  cidr: "string",
6824
6824
  macaddr: "string",
6825
6825
  macaddr8: "string",
6826
- // Geometric (represented as strings)
6827
6826
  point: "string",
6828
6827
  line: "string",
6829
6828
  lseg: "string",
@@ -6831,21 +6830,18 @@ var POSTGRES_TYPE_MAP = {
6831
6830
  path: "string",
6832
6831
  polygon: "string",
6833
6832
  circle: "string",
6834
- // Other
6835
6833
  xml: "string",
6836
6834
  tsvector: "string",
6837
6835
  tsquery: "string",
6838
6836
  oid: "number"
6839
6837
  };
6840
6838
  var MYSQL_TYPE_MAP = {
6841
- // Numeric
6842
6839
  tinyint: "number",
6843
6840
  smallint: "number",
6844
6841
  mediumint: "number",
6845
6842
  int: "number",
6846
6843
  integer: "number",
6847
6844
  bigint: "string",
6848
- // precision
6849
6845
  float: "number",
6850
6846
  double: "number",
6851
6847
  "double precision": "number",
@@ -6853,7 +6849,6 @@ var MYSQL_TYPE_MAP = {
6853
6849
  dec: "string",
6854
6850
  numeric: "string",
6855
6851
  bit: "number",
6856
- // Text
6857
6852
  char: "string",
6858
6853
  varchar: "string",
6859
6854
  tinytext: "string",
@@ -6862,40 +6857,32 @@ var MYSQL_TYPE_MAP = {
6862
6857
  longtext: "string",
6863
6858
  enum: "string",
6864
6859
  set: "string",
6865
- // Boolean (MySQL uses tinyint(1))
6866
6860
  boolean: "boolean",
6867
6861
  bool: "boolean",
6868
- // Binary
6869
6862
  binary: "Buffer",
6870
6863
  varbinary: "Buffer",
6871
6864
  tinyblob: "Buffer",
6872
6865
  blob: "Buffer",
6873
6866
  mediumblob: "Buffer",
6874
6867
  longblob: "Buffer",
6875
- // Date / time
6876
6868
  date: "string",
6877
6869
  datetime: "string",
6878
6870
  timestamp: "string",
6879
6871
  time: "string",
6880
6872
  year: "number",
6881
- // JSON
6882
6873
  json: "unknown",
6883
- // Spatial (represented as strings)
6884
6874
  geometry: "string",
6885
6875
  point: "string",
6886
6876
  linestring: "string",
6887
6877
  polygon: "string"
6888
6878
  };
6889
6879
  var SQLITE_TYPE_MAP = {
6890
- // SQLite has dynamic typing with 5 storage classes.
6891
- // The declared type is advisory; these are the common declared types.
6892
6880
  integer: "number",
6893
6881
  int: "number",
6894
6882
  tinyint: "number",
6895
6883
  smallint: "number",
6896
6884
  mediumint: "number",
6897
6885
  bigint: "number",
6898
- // SQLite stores as 64-bit int, JS number is safe up to 2^53
6899
6886
  real: "number",
6900
6887
  double: "number",
6901
6888
  "double precision": "number",
@@ -6903,7 +6890,6 @@ var SQLITE_TYPE_MAP = {
6903
6890
  numeric: "number",
6904
6891
  decimal: "number",
6905
6892
  boolean: "number",
6906
- // SQLite stores booleans as 0/1
6907
6893
  text: "string",
6908
6894
  varchar: "string",
6909
6895
  char: "string",
@@ -6918,13 +6904,16 @@ var SQLITE_TYPE_MAP = {
6918
6904
  timestamp: "string",
6919
6905
  json: "unknown"
6920
6906
  };
6921
- var VENDOR_MAPS = {
6907
+ var VENDOR_TYPE_MAPS = {
6922
6908
  postgresql: POSTGRES_TYPE_MAP,
6923
6909
  mysql: MYSQL_TYPE_MAP,
6924
6910
  sqlite: SQLITE_TYPE_MAP
6925
6911
  };
6912
+
6913
+ // src/data/relational/schema/type-mapper.ts
6914
+ var logger13 = createLogger("agentforge:tools:data:relational:type-mapper");
6926
6915
  function mapColumnType(vendor, dbType, nullable = false) {
6927
- const typeMap = VENDOR_MAPS[vendor];
6916
+ const typeMap = VENDOR_TYPE_MAPS[vendor];
6928
6917
  if (!typeMap) {
6929
6918
  return { tsType: "unknown", nullable, dbType, notes: `Unsupported vendor: ${vendor}` };
6930
6919
  }
@@ -6935,18 +6924,20 @@ function mapColumnType(vendor, dbType, nullable = false) {
6935
6924
  result.notes = `No explicit mapping for "${dbType}"; defaulting to unknown`;
6936
6925
  logger13.debug("Unmapped database type", { vendor, dbType, normalised });
6937
6926
  }
6938
- if ((normalised === "bigint" || normalised === "int8" || normalised === "bigserial") && (vendor === "postgresql" || vendor === "mysql")) {
6927
+ if (usesStringPrecisionFallback(vendor, normalised)) {
6939
6928
  result.notes = "Mapped to string to avoid JavaScript number precision loss for 64-bit integers";
6940
6929
  }
6941
6930
  return result;
6942
6931
  }
6943
6932
  function mapSchemaTypes(vendor, columns) {
6944
6933
  const result = /* @__PURE__ */ new Map();
6945
- for (const col of columns) {
6946
- if (!result.has(col.table)) {
6947
- result.set(col.table, /* @__PURE__ */ new Map());
6934
+ for (const column of columns) {
6935
+ let tableColumns = result.get(column.table);
6936
+ if (!tableColumns) {
6937
+ tableColumns = /* @__PURE__ */ new Map();
6938
+ result.set(column.table, tableColumns);
6948
6939
  }
6949
- result.get(col.table).set(col.name, mapColumnType(vendor, col.type, col.nullable));
6940
+ tableColumns.set(column.name, mapColumnType(vendor, column.type, column.nullable));
6950
6941
  }
6951
6942
  logger13.debug("Schema type mapping complete", {
6952
6943
  vendor,
@@ -6956,14 +6947,10 @@ function mapSchemaTypes(vendor, columns) {
6956
6947
  return result;
6957
6948
  }
6958
6949
  function getVendorTypeMap(vendor) {
6959
- return { ...VENDOR_MAPS[vendor] };
6950
+ return { ...VENDOR_TYPE_MAPS[vendor] };
6960
6951
  }
6961
- function normaliseDbType(raw) {
6962
- let type = raw.toLowerCase().trim();
6963
- type = type.replace(/\[\]$/, "");
6964
- type = type.replace(/\([\d,\s]+\)/, "");
6965
- type = type.replace(/\s+unsigned$/, "");
6966
- return type.trim();
6952
+ function usesStringPrecisionFallback(vendor, normalised) {
6953
+ return (normalised === "bigint" || normalised === "int8" || normalised === "bigserial") && (vendor === "postgresql" || vendor === "mysql");
6967
6954
  }
6968
6955
  var logger14 = createLogger("agentforge:tools:data:relational:schema-diff");
6969
6956
  function diffSchemas(before, after) {
@@ -6995,15 +6982,15 @@ function diffSchemas(before, after) {
6995
6982
  }
6996
6983
  tableDiffs.push(diff);
6997
6984
  }
6998
- for (const cd of colDiffs) {
6999
- if (cd.type === "added") columnsAdded++;
7000
- else if (cd.type === "removed") columnsRemoved++;
6985
+ for (const columnDiff of colDiffs) {
6986
+ if (columnDiff.type === "added") columnsAdded++;
6987
+ else if (columnDiff.type === "removed") columnsRemoved++;
7001
6988
  else columnsChanged++;
7002
6989
  }
7003
6990
  }
7004
- const tablesAdded = tableDiffs.filter((d) => d.type === "added").length;
7005
- const tablesRemoved = tableDiffs.filter((d) => d.type === "removed").length;
7006
- const tablesChanged = tableDiffs.filter((d) => d.type === "changed").length;
6991
+ const tablesAdded = tableDiffs.filter((diff) => diff.type === "added").length;
6992
+ const tablesRemoved = tableDiffs.filter((diff) => diff.type === "removed").length;
6993
+ const tablesChanged = tableDiffs.filter((diff) => diff.type === "changed").length;
7007
6994
  const identical = tableDiffs.length === 0;
7008
6995
  logger14.debug("Schema diff computed", {
7009
6996
  identical,
@@ -7017,58 +7004,10 @@ function diffSchemas(before, after) {
7017
7004
  summary: { tablesAdded, tablesRemoved, tablesChanged, columnsAdded, columnsRemoved, columnsChanged }
7018
7005
  };
7019
7006
  }
7020
- function exportSchemaToJson(schema) {
7021
- return JSON.stringify(schema, sortedReplacer, 2);
7022
- }
7023
- function importSchemaFromJson(json) {
7024
- const parsed = JSON.parse(json);
7025
- if (!parsed || typeof parsed !== "object") {
7026
- throw new Error("Invalid schema JSON: expected an object");
7027
- }
7028
- const obj = parsed;
7029
- if (!obj.vendor || typeof obj.vendor !== "string") {
7030
- throw new Error('Invalid schema JSON: missing or invalid "vendor" field');
7031
- }
7032
- if (!Array.isArray(obj.tables)) {
7033
- throw new Error('Invalid schema JSON: missing or invalid "tables" array');
7034
- }
7035
- if (!obj.generatedAt || typeof obj.generatedAt !== "string") {
7036
- throw new Error('Invalid schema JSON: missing or invalid "generatedAt" field');
7037
- }
7038
- for (const table of obj.tables) {
7039
- if (!table || typeof table !== "object") {
7040
- throw new Error("Invalid schema JSON: each table must be an object");
7041
- }
7042
- if (!table.name || typeof table.name !== "string") {
7043
- throw new Error('Invalid schema JSON: each table must have a "name" string');
7044
- }
7045
- if (!Array.isArray(table.columns)) {
7046
- throw new Error(`Invalid schema JSON: table "${table.name}" missing "columns" array`);
7047
- }
7048
- if (!Array.isArray(table.primaryKey)) {
7049
- throw new Error(`Invalid schema JSON: table "${table.name}" missing "primaryKey" array`);
7050
- }
7051
- }
7052
- logger14.debug("Schema imported from JSON", {
7053
- vendor: obj.vendor,
7054
- tableCount: obj.tables.length
7055
- });
7056
- return parsed;
7057
- }
7058
- function sortedReplacer(_key, value) {
7059
- if (value && typeof value === "object" && !Array.isArray(value)) {
7060
- const sorted = {};
7061
- for (const k of Object.keys(value).sort()) {
7062
- sorted[k] = value[k];
7063
- }
7064
- return sorted;
7065
- }
7066
- return value;
7067
- }
7068
7007
  function tableMap(tables) {
7069
7008
  const map = /* @__PURE__ */ new Map();
7070
- for (const t of tables) {
7071
- map.set(formatName(t).toLowerCase(), t);
7009
+ for (const table of tables) {
7010
+ map.set(formatName(table).toLowerCase(), table);
7072
7011
  }
7073
7012
  return map;
7074
7013
  }
@@ -7079,43 +7018,113 @@ function diffColumns(before, after) {
7079
7018
  const diffs = [];
7080
7019
  const beforeMap = /* @__PURE__ */ new Map();
7081
7020
  const afterMap = /* @__PURE__ */ new Map();
7082
- for (const c of before) beforeMap.set(c.name.toLowerCase(), c);
7083
- for (const c of after) afterMap.set(c.name.toLowerCase(), c);
7084
- for (const [key] of beforeMap) {
7021
+ for (const column of before) beforeMap.set(column.name.toLowerCase(), column);
7022
+ for (const column of after) afterMap.set(column.name.toLowerCase(), column);
7023
+ for (const [key, beforeColumn] of beforeMap) {
7085
7024
  if (!afterMap.has(key)) {
7086
- diffs.push({ column: beforeMap.get(key).name, type: "removed" });
7025
+ diffs.push({ column: beforeColumn.name, type: "removed" });
7087
7026
  }
7088
7027
  }
7089
- for (const [key] of afterMap) {
7028
+ for (const [key, afterColumn] of afterMap) {
7090
7029
  if (!beforeMap.has(key)) {
7091
- diffs.push({ column: afterMap.get(key).name, type: "added" });
7030
+ diffs.push({ column: afterColumn.name, type: "added" });
7092
7031
  }
7093
7032
  }
7094
- for (const [key, beforeCol] of beforeMap) {
7095
- const afterCol = afterMap.get(key);
7096
- if (!afterCol) continue;
7033
+ for (const [key, beforeColumn] of beforeMap) {
7034
+ const afterColumn = afterMap.get(key);
7035
+ if (!afterColumn) continue;
7097
7036
  const changes = [];
7098
- if (beforeCol.type.toLowerCase() !== afterCol.type.toLowerCase()) {
7099
- changes.push({ property: "type", before: beforeCol.type, after: afterCol.type });
7100
- }
7101
- if (beforeCol.isNullable !== afterCol.isNullable) {
7102
- changes.push({ property: "isNullable", before: beforeCol.isNullable, after: afterCol.isNullable });
7037
+ if (beforeColumn.type.toLowerCase() !== afterColumn.type.toLowerCase()) {
7038
+ changes.push({ property: "type", before: beforeColumn.type, after: afterColumn.type });
7039
+ }
7040
+ if (beforeColumn.isNullable !== afterColumn.isNullable) {
7041
+ changes.push({
7042
+ property: "isNullable",
7043
+ before: beforeColumn.isNullable,
7044
+ after: afterColumn.isNullable
7045
+ });
7103
7046
  }
7104
- if (beforeCol.isPrimaryKey !== afterCol.isPrimaryKey) {
7105
- changes.push({ property: "isPrimaryKey", before: beforeCol.isPrimaryKey, after: afterCol.isPrimaryKey });
7047
+ if (beforeColumn.isPrimaryKey !== afterColumn.isPrimaryKey) {
7048
+ changes.push({
7049
+ property: "isPrimaryKey",
7050
+ before: beforeColumn.isPrimaryKey,
7051
+ after: afterColumn.isPrimaryKey
7052
+ });
7106
7053
  }
7107
- if (String(beforeCol.defaultValue) !== String(afterCol.defaultValue)) {
7108
- changes.push({ property: "defaultValue", before: beforeCol.defaultValue, after: afterCol.defaultValue });
7054
+ if (String(beforeColumn.defaultValue) !== String(afterColumn.defaultValue)) {
7055
+ changes.push({
7056
+ property: "defaultValue",
7057
+ before: beforeColumn.defaultValue,
7058
+ after: afterColumn.defaultValue
7059
+ });
7109
7060
  }
7110
7061
  if (changes.length > 0) {
7111
- diffs.push({ column: beforeCol.name, type: "changed", changes });
7062
+ diffs.push({ column: beforeColumn.name, type: "changed", changes });
7112
7063
  }
7113
7064
  }
7114
7065
  return diffs;
7115
7066
  }
7116
- function arraysEqual(a, b) {
7117
- if (a.length !== b.length) return false;
7118
- return a.every((v, i) => v === b[i]);
7067
+ function arraysEqual(before, after) {
7068
+ if (before.length !== after.length) return false;
7069
+ return before.every((value, index) => value === after[index]);
7070
+ }
7071
+ var logger15 = createLogger("agentforge:tools:data:relational:schema-diff");
7072
+ function exportSchemaToJson(schema) {
7073
+ return JSON.stringify(schema, sortedReplacer, 2);
7074
+ }
7075
+ function importSchemaFromJson(json) {
7076
+ const parsed = JSON.parse(json);
7077
+ validateSchemaJson(parsed);
7078
+ const schema = parsed;
7079
+ logger15.debug("Schema imported from JSON", {
7080
+ vendor: schema.vendor,
7081
+ tableCount: schema.tables.length
7082
+ });
7083
+ return schema;
7084
+ }
7085
+ function validateSchemaJson(parsed) {
7086
+ if (!parsed || typeof parsed !== "object") {
7087
+ throw new Error("Invalid schema JSON: expected an object");
7088
+ }
7089
+ const schema = parsed;
7090
+ if (!schema.vendor || typeof schema.vendor !== "string") {
7091
+ throw new Error('Invalid schema JSON: missing or invalid "vendor" field');
7092
+ }
7093
+ if (!Array.isArray(schema.tables)) {
7094
+ throw new Error('Invalid schema JSON: missing or invalid "tables" array');
7095
+ }
7096
+ if (!schema.generatedAt || typeof schema.generatedAt !== "string") {
7097
+ throw new Error('Invalid schema JSON: missing or invalid "generatedAt" field');
7098
+ }
7099
+ for (const table of schema.tables) {
7100
+ validateTableJson(table);
7101
+ }
7102
+ }
7103
+ function validateTableJson(table) {
7104
+ if (!table || typeof table !== "object") {
7105
+ throw new Error("Invalid schema JSON: each table must be an object");
7106
+ }
7107
+ const record = table;
7108
+ if (!record.name || typeof record.name !== "string") {
7109
+ throw new Error('Invalid schema JSON: each table must have a "name" string');
7110
+ }
7111
+ if (!Array.isArray(record.columns)) {
7112
+ throw new Error(`Invalid schema JSON: table "${record.name}" missing "columns" array`);
7113
+ }
7114
+ if (!Array.isArray(record.primaryKey)) {
7115
+ throw new Error(`Invalid schema JSON: table "${record.name}" missing "primaryKey" array`);
7116
+ }
7117
+ }
7118
+ function sortedReplacer(_key, value) {
7119
+ if (value && typeof value === "object" && !Array.isArray(value)) {
7120
+ const record = value;
7121
+ const sorted = {};
7122
+ for (const key of Object.keys(record).sort()) {
7123
+ sorted[key] = record[key];
7124
+ }
7125
+ return sorted;
7126
+ }
7127
+ return value;
7119
7128
  }
7120
7129
  var relationalQuerySchema = z.object({
7121
7130
  sql: z.string().describe("SQL query string to execute"),
@@ -7346,7 +7355,7 @@ function isSafeValidationError(error) {
7346
7355
  }
7347
7356
 
7348
7357
  // src/data/relational/tools/relational-select/executor.ts
7349
- var logger15 = createLogger("agentforge:tools:data:relational:select");
7358
+ var logger16 = createLogger("agentforge:tools:data:relational:select");
7350
7359
  function toSelectQueryInput(input) {
7351
7360
  return {
7352
7361
  table: input.table,
@@ -7360,7 +7369,7 @@ function toSelectQueryInput(input) {
7360
7369
  }
7361
7370
  async function executeSelect(manager, input, context) {
7362
7371
  const startTime = Date.now();
7363
- logger15.debug("Building SELECT query", {
7372
+ logger16.debug("Building SELECT query", {
7364
7373
  vendor: input.vendor,
7365
7374
  table: input.table,
7366
7375
  hasWhere: !!input.where,
@@ -7378,7 +7387,7 @@ async function executeSelect(manager, input, context) {
7378
7387
  };
7379
7388
  const streamInput = toSelectQueryInput(input);
7380
7389
  if (input.streaming.benchmark) {
7381
- logger15.warn("Streaming benchmark enabled; SELECT will execute up to three times (result + benchmark regular + benchmark streaming).", {
7390
+ logger16.warn("Streaming benchmark enabled; SELECT will execute up to three times (result + benchmark regular + benchmark streaming).", {
7382
7391
  vendor: input.vendor,
7383
7392
  table: input.table,
7384
7393
  chunkSize: streamOptions.chunkSize ?? DEFAULT_CHUNK_SIZE,
@@ -7389,7 +7398,7 @@ async function executeSelect(manager, input, context) {
7389
7398
  const streamResult = await executeStreamingSelect(executor, streamInput, streamOptions);
7390
7399
  const benchmark = input.streaming.benchmark ? await benchmarkStreamingSelectMemory(executor, streamInput, streamOptions) : void 0;
7391
7400
  const executionTime2 = Date.now() - startTime;
7392
- logger15.debug("Streaming SELECT query executed successfully", {
7401
+ logger16.debug("Streaming SELECT query executed successfully", {
7393
7402
  vendor: input.vendor,
7394
7403
  table: input.table,
7395
7404
  rowCount: streamResult.rowCount,
@@ -7418,7 +7427,7 @@ async function executeSelect(manager, input, context) {
7418
7427
  const executionTime = Date.now() - startTime;
7419
7428
  const rows = Array.isArray(result) ? result : result.rows || [];
7420
7429
  const rowCount = rows.length;
7421
- logger15.debug("SELECT query executed successfully", {
7430
+ logger16.debug("SELECT query executed successfully", {
7422
7431
  vendor: input.vendor,
7423
7432
  table: input.table,
7424
7433
  rowCount,
@@ -7431,7 +7440,7 @@ async function executeSelect(manager, input, context) {
7431
7440
  };
7432
7441
  } catch (error) {
7433
7442
  const executionTime = Date.now() - startTime;
7434
- logger15.error("SELECT query execution failed", {
7443
+ logger16.error("SELECT query execution failed", {
7435
7444
  vendor: input.vendor,
7436
7445
  table: input.table,
7437
7446
  error: error instanceof Error ? error.message : String(error),
@@ -9001,7 +9010,7 @@ function isSafeGetSchemaValidationError(error) {
9001
9010
  }
9002
9011
 
9003
9012
  // src/data/relational/tools/relational-get-schema.ts
9004
- var logger16 = createLogger("agentforge:tools:data:relational:get-schema");
9013
+ var logger17 = createLogger("agentforge:tools:data:relational:get-schema");
9005
9014
  function buildSchemaCacheKey(vendor, connectionString, database) {
9006
9015
  const databaseScope = database ?? "default";
9007
9016
  const connectionHash = createHash("sha256").update(connectionString).digest("hex");
@@ -9073,7 +9082,7 @@ var relationalGetSchema = toolBuilder().name("relational-get-schema").displayNam
9073
9082
  summary
9074
9083
  };
9075
9084
  } catch (error) {
9076
- logger16.error("Schema introspection failed", {
9085
+ logger17.error("Schema introspection failed", {
9077
9086
  vendor: input.vendor,
9078
9087
  hasTablesFilter: Array.isArray(input.tables),
9079
9088
  tablesFilterCount: input.tables?.length ?? 0,
@@ -10239,7 +10248,7 @@ var AskHumanInputSchema = z.object({
10239
10248
  suggestions: z.array(z.string()).optional().describe("Suggested responses for the human")
10240
10249
  });
10241
10250
  var logLevel3 = process.env.LOG_LEVEL?.toLowerCase() || LogLevel.INFO;
10242
- var logger17 = createLogger("agentforge:tools:agent:ask-human", { level: logLevel3 });
10251
+ var logger18 = createLogger("agentforge:tools:agent:ask-human", { level: logLevel3 });
10243
10252
  function isRecord2(value) {
10244
10253
  return typeof value === "object" && value !== null;
10245
10254
  }
@@ -10304,7 +10313,7 @@ function createAskHumanTool() {
10304
10313
  suggestions: validatedInput.suggestions,
10305
10314
  status: "pending"
10306
10315
  };
10307
- logger17.debug("About to call interrupt()", {
10316
+ logger18.debug("About to call interrupt()", {
10308
10317
  humanRequest: {
10309
10318
  id: humanRequest.id,
10310
10319
  question: humanRequest.question,
@@ -10320,13 +10329,13 @@ function createAskHumanTool() {
10320
10329
  let response;
10321
10330
  try {
10322
10331
  response = interrupt(humanRequest);
10323
- logger17.debug("interrupt() returned successfully", {
10332
+ logger18.debug("interrupt() returned successfully", {
10324
10333
  responseType: typeof response,
10325
10334
  hasResponse: response != null,
10326
10335
  ...typeof response === "string" ? { responseLength: response.length } : {}
10327
10336
  });
10328
10337
  } catch (error) {
10329
- logger17.debug("interrupt() threw error (expected for GraphInterrupt)", {
10338
+ logger18.debug("interrupt() threw error (expected for GraphInterrupt)", {
10330
10339
  ...error && typeof error === "object" && "constructor" in error ? { errorType: error.constructor?.name } : {},
10331
10340
  error: error instanceof Error ? error.message : String(error)
10332
10341
  });