@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.cjs +218 -209
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +16 -37
- package/dist/index.d.ts +16 -37
- package/dist/index.js +218 -209
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -788,7 +788,7 @@ function getDefaultSlackClient() {
|
|
|
788
788
|
}
|
|
789
789
|
};
|
|
790
790
|
}
|
|
791
|
-
function createSendSlackMessageTool(getSlackClient,
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
4171
|
+
function cancelPendingReconnection(timer, logger19, vendor, message) {
|
|
4172
4172
|
if (!timer) {
|
|
4173
4173
|
return null;
|
|
4174
4174
|
}
|
|
4175
|
-
|
|
4175
|
+
logger19.debug(message, { vendor });
|
|
4176
4176
|
clearTimeout(timer);
|
|
4177
4177
|
return null;
|
|
4178
4178
|
}
|
|
4179
|
-
async function waitForInFlightConnection(promise,
|
|
4179
|
+
async function waitForInFlightConnection(promise, logger19, vendor, phase) {
|
|
4180
4180
|
if (!promise) {
|
|
4181
4181
|
return null;
|
|
4182
4182
|
}
|
|
4183
|
-
|
|
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,
|
|
4200
|
+
function scheduleReconnection(context, logger19) {
|
|
4201
4201
|
if (context.reconnectionConfig.maxAttempts > 0 && context.reconnectionAttempts >= context.reconnectionConfig.maxAttempts) {
|
|
4202
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
4251
|
+
async function cleanupConnectionResources(vendor, client, clearConnection, logger19) {
|
|
4252
4252
|
if (!client) {
|
|
4253
4253
|
return;
|
|
4254
4254
|
}
|
|
4255
|
-
|
|
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
|
-
|
|
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,
|
|
4269
|
+
async function closeManagedConnection(runtime, logger19) {
|
|
4270
4270
|
const client = runtime.getClient();
|
|
4271
4271
|
if (client) {
|
|
4272
|
-
|
|
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
|
-
|
|
4280
|
+
logger19.debug("Database connection closed successfully", {
|
|
4281
4281
|
vendor: runtime.vendor,
|
|
4282
4282
|
state: runtime.getState()
|
|
4283
4283
|
});
|
|
4284
4284
|
} catch (error) {
|
|
4285
|
-
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
4474
|
+
logger19
|
|
4475
4475
|
);
|
|
4476
4476
|
}
|
|
4477
4477
|
runtime.setState("connecting" /* CONNECTING */);
|
|
4478
|
-
|
|
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
|
-
|
|
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
|
-
|
|
4500
|
+
logger19
|
|
4501
4501
|
);
|
|
4502
4502
|
runtime.setState("disconnected" /* DISCONNECTED */);
|
|
4503
4503
|
throw new Error("Connection cancelled during initialization");
|
|
4504
4504
|
}
|
|
4505
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
4565
|
+
logger19
|
|
4566
4566
|
);
|
|
4567
4567
|
if (runtime.getReconnectionConfig().enabled && currentGeneration === runtime.getConnectionGeneration()) {
|
|
4568
4568
|
runtime.scheduleReconnection();
|
|
4569
4569
|
}
|
|
4570
4570
|
} else {
|
|
4571
|
-
|
|
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,
|
|
4589
|
+
async function checkConnectionHealth(args, logger19) {
|
|
4590
4590
|
if (!args.db || !args.client) {
|
|
4591
|
-
|
|
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
|
-
|
|
4596
|
+
logger19.debug("Health check passed", { vendor: args.vendor });
|
|
4597
4597
|
return true;
|
|
4598
4598
|
} catch (error) {
|
|
4599
|
-
|
|
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,
|
|
4643
|
-
|
|
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
|
-
|
|
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
|
|
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 =
|
|
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 ((
|
|
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
|
|
6946
|
-
|
|
6947
|
-
|
|
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
|
-
|
|
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 { ...
|
|
6950
|
+
return { ...VENDOR_TYPE_MAPS[vendor] };
|
|
6960
6951
|
}
|
|
6961
|
-
function
|
|
6962
|
-
|
|
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
|
|
6999
|
-
if (
|
|
7000
|
-
else if (
|
|
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((
|
|
7005
|
-
const tablesRemoved = tableDiffs.filter((
|
|
7006
|
-
const tablesChanged = tableDiffs.filter((
|
|
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
|
|
7071
|
-
map.set(formatName(
|
|
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
|
|
7083
|
-
for (const
|
|
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:
|
|
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:
|
|
7030
|
+
diffs.push({ column: afterColumn.name, type: "added" });
|
|
7092
7031
|
}
|
|
7093
7032
|
}
|
|
7094
|
-
for (const [key,
|
|
7095
|
-
const
|
|
7096
|
-
if (!
|
|
7033
|
+
for (const [key, beforeColumn] of beforeMap) {
|
|
7034
|
+
const afterColumn = afterMap.get(key);
|
|
7035
|
+
if (!afterColumn) continue;
|
|
7097
7036
|
const changes = [];
|
|
7098
|
-
if (
|
|
7099
|
-
changes.push({ property: "type", before:
|
|
7100
|
-
}
|
|
7101
|
-
if (
|
|
7102
|
-
changes.push({
|
|
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 (
|
|
7105
|
-
changes.push({
|
|
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(
|
|
7108
|
-
changes.push({
|
|
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:
|
|
7062
|
+
diffs.push({ column: beforeColumn.name, type: "changed", changes });
|
|
7112
7063
|
}
|
|
7113
7064
|
}
|
|
7114
7065
|
return diffs;
|
|
7115
7066
|
}
|
|
7116
|
-
function arraysEqual(
|
|
7117
|
-
if (
|
|
7118
|
-
return
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
});
|