UNPKG

pms-analysis-reports-mcp-server

Version:

PMS analysis reports server handling maintenance reports, equipment analysis, compliance tracking, and performance metrics with ERP access for data extraction

761 lines 33.8 kB
import { getTypesenseClient } from "../../utils/typesense.js"; import { fetchQADetails, getDataLink, getArtifact, updateTypesenseFilterWithCompanyImos } from "../../utils/helper_functions.js"; import { isValidImoForCompany } from "../../utils/imoUtils.js"; import { getConfig } from "../../utils/config.js"; import { DatabaseManager } from "../../utils/mongodb.js"; import { logger } from "../../index.js"; // Helper function to get documents from hits function getDocumentsFromHits(hits) { return hits.map((hit) => hit.document); } export class PmsToolHandler { constructor() { this.typesenseClient = getTypesenseClient(); } async getVesselPmsHistoricalData(args) { logger.info("getVesselPmsHistoricalData called", args); const imo = args.imo; const machineryName = args.machinery_name; const startDate = args.start_date; const endDate = args.end_date; if (!imo || !machineryName) { throw new Error("imo and machinery_name are required. Only the following properties are allowed: imo, machinery_name, start_date, end_date. Please check the tool schema for getVesselPmsHistoricalData for the allowed properties."); } const mongodbEtlDevDataDbName = process.env.MONGODB_ETL_DEV_DATA_DB_NAME || process.env.mongodbEtlDevDataDbName || 'syia-etl-dev'; const mongodbEtlDevDataUri = process.env.MONGODB_ETL_DEV_DATA_URI || process.env.mongodbEtlDevDataUri || ''; const dbManager = new DatabaseManager(); await dbManager.initializeDatabase(mongodbEtlDevDataDbName, mongodbEtlDevDataUri); try { // Validate IMO for company const config = getConfig(); const companyName = config.companyName; const finalDbName = process.env.GROUP_DETAILS_DB_NAME || process.env.FLEET_DISTRIBUTION_DB_NAME || process.env.COMPANY_DB_NAME || ''; const finalMongoUri = process.env.GROUP_DETAILS_MONGO_URI || process.env.FLEET_DISTRIBUTION_MONGO_URI || process.env.COMPANY_DB_URI || ''; if (companyName && finalDbName && finalMongoUri) { const isValid = await isValidImoForCompany(imo, companyName, finalDbName, finalMongoUri); if (!isValid) { const errorResponse = { type: "text", text: JSON.stringify({ error: `IMO ${imo} is not authorized for company ${companyName}`, message: "Access denied: This vessel IMO is not associated with your company." }) }; return [errorResponse]; } } // Fetch component name from Typesense let filterBy = `imo:${imo}`; filterBy = await updateTypesenseFilterWithCompanyImos(filterBy); const typesenseQuery = { q: machineryName, query_by: "jobTitle,component", filter_by: filterBy, include_fields: "component,imo" }; const typesenseResults = await this.typesenseClient.collections("pms").documents().search(typesenseQuery); if (!typesenseResults || !typesenseResults.hits || typesenseResults.hits.length === 0) { const noDataResponse = { type: "text", text: JSON.stringify({ message: `Component name not found for vessel ${imo}` }) }; return [noDataResponse]; } // Get unique component names from documents that match the TypesenseDocument type const componentNames = [...new Set(typesenseResults.hits .map((hit) => hit.document) .filter((doc) => doc.component && doc.imo) .map((doc) => doc.component))]; // Build MongoDB query const mongodbQuery = { imo: parseInt(imo.toString()), component: { $in: componentNames } }; // Add date range if provided if (startDate || endDate) { mongodbQuery.jobDoneDate = {}; if (startDate) { mongodbQuery.jobDoneDate.$gte = new Date(startDate); } if (endDate) { mongodbQuery.jobDoneDate.$lte = new Date(endDate); } } const projection = { _id: 0 }; const db = dbManager.getDb(); // Get data from both collections const latestResults = await db.collection("pms_job_summary").find(mongodbQuery, { projection }).toArray(); const historicalResults = await db.collection("pms_job_summary_historical_data").find(mongodbQuery, { projection }).toArray(); // Combine and sort results const combinedResults = [...latestResults, ...historicalResults] .sort((a, b) => new Date(b.jobDoneDate || 0).getTime() - new Date(a.jobDoneDate || 0).getTime()); // Format dates const dateFields = ['createdAt', 'createdAtIst', 'jobDueDate', 'jobDoneDate']; combinedResults.forEach((result) => { dateFields.forEach(field => { if (result[field]) { result[field] = new Date(result[field]).toISOString().split('T')[0]; } }); }); if (combinedResults.length === 0) { const noDataResponse = { type: "text", text: JSON.stringify({ message: `No PMS job data found for ${machineryName} for the given date range` }) }; return [noDataResponse]; } // Get vessel name const vesselName = combinedResults.find(r => r.vesselName)?.vesselName || ""; // Generate data link and store in MongoDB const dataLink = await getDataLink(combinedResults); // await insertDataLinkToMongoDB( // dataLink, // "PMS Historical Data", // sessionId, // imo.toString(), // vesselName, // mongodbEtlDevDataDbName, // mongodbEtlDevDataUri // ); // Generate artifact data const artifactData = getArtifact("get_vessel_pms_historical_data", dataLink); const content = { type: "text", text: JSON.stringify(combinedResults, null, 2) }; const artifact = { type: "text", text: JSON.stringify(artifactData, null, 2) }; return [content, artifact]; } catch (error) { logger.error("Error getting vessel PMS historical data:", error); throw new Error(`Error getting vessel PMS historical data: ${error instanceof Error ? error.message : String(error)}`); } finally { await dbManager.closeDatabase(); } } async getMonthEndFormSubmissionStatus(args) { logger.info("getMonthEndFormSubmissionStatus called", args); const imo = args.imo; if (!imo) { throw new Error("imo is required. Only the following properties are allowed: imo. Please check the tool schema for getMonthEndFormSubmissionStatus for the allowed properties."); } const mongodbEtlDevDataDbName = process.env.MONGODB_ETL_DEV_DATA_DB_NAME || process.env.mongodbEtlDevDataDbName || 'syia-etl-dev'; const mongodbEtlDevDataUri = process.env.MONGODB_ETL_DEV_DATA_URI || process.env.mongodbEtlDevDataUri || ''; try { // Get data from QnA - Q No.65 for Month End Form Submission Status const result = await fetchQADetails(imo, 65, mongodbEtlDevDataDbName, mongodbEtlDevDataUri); // // Insert data link to MongoDB if available // if (result.link) { // await insertDataLinkToMongoDB( // result.link, // "month end form submission status", // sessionId, // imo.toString(), // result.vesselName || "", // mongodbEtlDevDataDbName, // mongodbEtlDevDataUri // ); // } // Generate artifact data const artifactData = getArtifact("get_month_end_form_submission_status", result.link || ""); const content = { type: "text", text: JSON.stringify(result, null, 2) }; const artifact = { type: "text", text: JSON.stringify(artifactData, null, 2) }; return [content, artifact]; } catch (error) { logger.error("Error getting month end form submission status:", error); throw new Error(`Error getting month end form submission status: ${error instanceof Error ? error.message : String(error)}`); } } async getHistoricalFormSubmissionStatus(args) { logger.info("getHistoricalFormSubmissionStatus called", args); const imo = args.imo; if (!imo) { throw new Error("imo is required. Only the following properties are allowed: imo. Please check the tool schema for getHistoricalFormSubmissionStatus for the allowed properties."); } const mongodbEtlDevDataDbName = process.env.MONGODB_ETL_DEV_DATA_DB_NAME || process.env.mongodbEtlDevDataDbName || 'syia-etl-dev'; const mongodbEtlDevDataUri = process.env.MONGODB_ETL_DEV_DATA_URI || process.env.mongodbEtlDevDataUri || ''; try { // Get data from QnA - Q No.66 for Historical Form Submission Status const result = await fetchQADetails(imo, 66, mongodbEtlDevDataDbName, mongodbEtlDevDataUri); // // Insert data link to MongoDB if available // if (result.link) { // await insertDataLinkToMongoDB( // result.link, // "historical form submission status", // sessionId, // imo.toString(), // result.vesselName || "", // mongodbEtlDevDataDbName, // mongodbEtlDevDataUri // ); // } // Generate artifact data const artifactData = getArtifact("get_historical_form_submission_status", result.link || ""); const content = { type: "text", text: JSON.stringify(result, null, 2) }; const artifact = { type: "text", text: JSON.stringify(artifactData, null, 2) }; return [content, artifact]; } catch (error) { logger.error("Error getting historical form submission status:", error); throw new Error(`Error getting historical form submission status: ${error instanceof Error ? error.message : String(error)}`); } } async getFleetPmsWeeklyOverview(args) { logger.info("getFleetPmsWeeklyOverview called", args); const mongodbEtlDevDataDbName = process.env.MONGODB_ETL_DEV_DATA_DB_NAME || process.env.mongodbEtlDevDataDbName || 'syia-etl-dev'; const mongodbEtlDevDataUri = process.env.MONGODB_ETL_DEV_DATA_URI || process.env.mongodbEtlDevDataUri || ''; try { const imo = args.imo; if (!imo) { throw new Error("imo is required. Only the following properties are allowed: imo. Please check the tool schema for getFleetPmsWeeklyOverview for the allowed properties."); } // Fetch QA details for question 114 (Fleet PMS Weekly Overview) let result; try { result = await fetchQADetails(imo, 114, mongodbEtlDevDataDbName, mongodbEtlDevDataUri); } catch (error) { // If no fuel bunker details found, return appropriate message const noDataResponse = { type: "text", text: "No fuel bunker details found for this vessel." }; return [noDataResponse]; } // Get link and vessel name for MongoDB const dataLink = result.link ?? ""; const vesselName = result.vesselName || ""; // // Insert the data link to mongodb collection // await insertDataLinkToMongoDB( // dataLink, // "fleet pms weekly overview", // sessionId, // imo, // vesselName, // mongodbEtlDevDataDbName, // mongodbEtlDevDataUri // ); // Format results as JSON const formattedText = JSON.stringify(result, null, 2); // Create artifact const artifactData = getArtifact("get_fleet_pms_weekly_overview", dataLink); const content = { type: "text", text: formattedText }; const artifact = { type: "text", text: JSON.stringify(artifactData, null, 2) }; return [content, artifact]; } catch (error) { logger.error("Error in getFleetPmsWeeklyOverview", { error }); throw new Error(`Error retrieving fleet pms weekly overview: ${error instanceof Error ? error.message : String(error)}`); } } async getMonthEndConsolidatedTechnicalReport(args) { logger.info("getMonthEndConsolidatedTechnicalReport called", args); const imo = args.imo; if (!imo) { throw new Error("imo is required. Only the following properties are allowed: imo. Please check the tool schema for getMonthEndConsolidatedTechnicalReport for the allowed properties."); } const mongodbEtlDevDataDbName = process.env.MONGODB_ETL_DEV_DATA_DB_NAME || process.env.mongodbEtlDevDataDbName || 'syia-etl-dev'; const mongodbEtlDevDataUri = process.env.MONGODB_ETL_DEV_DATA_URI || process.env.mongodbEtlDevDataUri || ''; try { // Get data from QnA - Q No.80 for Month End Consolidated Technical Report const result = await fetchQADetails(imo, 80, mongodbEtlDevDataDbName, mongodbEtlDevDataUri); // // Insert data link to MongoDB if available // if (result.link) { // await insertDataLinkToMongoDB( // result.link, // "month end consolidated technical report", // sessionId, // imo.toString(), // result.vesselName || "", // mongodbEtlDevDataDbName, // mongodbEtlDevDataUri // ); // } // Generate artifact data const artifactData = getArtifact("get_month_end_consolidated_technical_report", result.link || ""); const content = { type: "text", text: JSON.stringify(result, null, 2) }; const artifact = { type: "text", text: JSON.stringify(artifactData, null, 2) }; return [content, artifact]; } catch (error) { logger.error("Error getting month end consolidated technical report:", error); throw new Error(`Error getting month end consolidated technical report: ${error instanceof Error ? error.message : String(error)}`); } } async getFleetMonthEndTechnicalFormsStatus(args) { logger.info("getFleetMonthEndTechnicalFormsStatus called", args); const mongodbEtlDevDataDbName = process.env.mongodbEtlDevDataDbName || 'syia-etl-dev'; const mongodbEtlDevDataUri = process.env.mongodbEtlDevDataUri || ''; try { const imo = args.imo; if (!imo) { throw new Error("imo is required. Only the following properties are allowed: imo. Please check the tool schema for getFleetMonthEndTechnicalFormsStatus for the allowed properties."); } // Fetch QA details for question 81 (Fleet Month End Technical Forms Status) let result; try { result = await fetchQADetails(imo, 81, mongodbEtlDevDataDbName, mongodbEtlDevDataUri); } catch (error) { // If no fuel bunker details found, return appropriate message const noDataResponse = { type: "text", text: "No fuel bunker details found for this vessel." }; return [noDataResponse]; } // Get link and vessel name for MongoDB const dataLink = result.link ?? ""; const vesselName = result.vesselName || ""; // // Insert the data link to mongodb collection // // await insertDataLinkToMongoDB( // dataLink, // "fleet month end technical forms status", // sessionId, // imo, // vesselName, // mongodbEtlDevDataDbName, // mongodbEtlDevDataUri // ); // Format results as JSON const formattedText = JSON.stringify(result, null, 2); // Create artifact const artifactData = getArtifact("get_fleet_month_end_technical_forms_status", dataLink); const content = { type: "text", text: formattedText }; const artifact = { type: "text", text: JSON.stringify(artifactData, null, 2) }; return [content, artifact]; } catch (error) { logger.error("Error in getFleetMonthEndTechnicalFormsStatus", { error }); throw new Error(`Error retrieving fleet month end technical forms status: ${error instanceof Error ? error.message : String(error)}`); } } } // export async function listPmsJobsByCategoryAndStatus(args: PmsJobsByCategoryArgs): Promise<ToolResponse> { // logger.info("Executing list_pms_jobs_by_category_and_status", { args }); // // try { // const imo = args.imo; // const jobCategory = args.jobCategory; // const jobStatus = args.jobStatus; // const perPage = args.per_page || 250; // const sessionId = args.session_id || "testing"; // // if (!imo || !jobCategory || !jobStatus) { // throw new Error("IMO number, job category, and job status are required"); // } // // const collection = "pms"; // // const includeFields = "imo,vesselName,jobTitle,component,jobDueDate,jobDoneDate,jobCode,defermentRequestedDate,jobCategory,scheduledOverhaulInterval,currentCounter,defermentApplied,jobStatus,currentStatus,remainingHrsNextOverhaul,remainingDaysNextOverhaul"; // // const query = { // q: "*", // filter_by: `imo:${imo} && jobCategory:${jobCategory} && jobStatus:${jobStatus}`, // per_page: perPage, // include_fields: includeFields // }; // // // Execute the search // logger.info(`Searching for ${jobCategory} PMS jobs with status ${jobStatus} for vessel ${imo}`); // const results = await getTypesenseClient().collections(collection).documents().search(query); // // const hits = results.hits || []; // const filteredHits = []; // // for (const hit of hits as TypesenseHit[]) { // const documentData = convertPmsDates(hit.document || {}); // filteredHits.push({ // id: documentData.id, // score: hit.text_match || 0, // document: documentData // }); // } // // // Get documents for data link // const documents = getDocumentsFromHits(hits); // // Get vessel name from hits // let vesselName = ""; // // Get data link // const dataLink = await getDataLink(documents); // await insertDataLinkToMongoDB( // dataLink, // 'Maintenance Summary', // sessionId, // imo, // vesselName // ); // // try { // vesselName = (hits[0]?.document as any)?.vesselName || ""; // } catch (error) { // vesselName = ""; // } // // // Format the results // const formattedResults = { // found: results.found || 0, // out_of: results.out_of || 0, // page: results.page || 1, // hits: filteredHits // }; // // // Create artifact // const artifactData = getArtifact("list_pms_jobs_by_category_and_status", dataLink); // // const content: TextContent = { // type: "text", // text: JSON.stringify(formattedResults, null, 2) // }; // // const artifact: TextContent = { // type: "text", // text: JSON.stringify(artifactData, null, 2) // }; // // return [content, artifact]; // } catch (error) { // logger.error("Error in listPmsJobsByCategoryAndStatus", { error }); // const errorResponse: TextContent = { // type: "text", // text: `Error retrieving PMS jobs: ${error instanceof Error ? error.message : String(error)}` // }; // return [errorResponse]; // } // } // export async function listPmsJobsForComponent(args: PmsJobsForComponentArgs): Promise<ToolResponse> { // logger.info("Executing list_pms_jobs_for_component", { args }); // // try { // const imo = args.imo; // const component = args.component; // const perPage = args.per_page || 250; // const sessionId = args.session_id || "testing"; // // if (!imo || !component) { // throw new Error("IMO number and component name are required"); // } // // const collection = "pms"; // // const includeFields = "imo,vesselName,jobTitle,component,jobDueDate,jobDoneDate,jobCode,defermentRequestedDate,jobCategory,scheduledOverhaulInterval,currentCounter,defermentApplied,jobStatus,currentStatus,remainingHrsNextOverhaul,remainingDaysNextOverhaul"; // // const query = { // q: "*", // filter_by: `imo:${imo} && component:${component}`, // sort_by: "jobDueDate:asc", // per_page: perPage, // include_fields: includeFields // }; // // // Execute the search // logger.info(`Searching for PMS jobs for component '${component}' on vessel ${imo}`); // const results = await getTypesenseClient().collections(collection).documents().search(query); // // const hits = results.hits || []; // const filteredHits = []; // // for (const hit of hits as TypesenseHit[]) { // const documentData = convertPmsDates(hit.document || {}); // filteredHits.push({ // id: documentData.id, // score: hit.text_match || 0, // document: documentData // }); // } // // // Get documents for data link // const documents = getDocumentsFromHits(hits); // // // Get data link // const dataLink = await getDataLink(documents); // // // Get vessel name from hits // let vesselName = ""; // try { // vesselName = (hits[0]?.document as any)?.vesselName || ""; // } catch (error) { // vesselName = ""; // } // // // Insert the data link to mongodb collection // const linkHeader = `pms jobs for component ${component}`; // await insertDataLinkToMongoDB(dataLink, linkHeader, sessionId, imo, vesselName); // // // Format the results // const formattedResults = { // found: results.found || 0, // out_of: results.out_of || 0, // page: results.page || 1, // hits: filteredHits // }; // // // Create artifact // const artifactData = getArtifact("list_pms_jobs_for_component", dataLink); // // const content: TextContent = { // type: "text", // text: JSON.stringify(formattedResults, null, 2) // }; // // const artifact: TextContent = { // type: "text", // text: JSON.stringify(artifactData, null, 2) // }; // // return [content, artifact]; // } catch (error) { // logger.error("Error in listPmsJobsForComponent", { error }); // const errorResponse: TextContent = { // type: "text", // text: `Error retrieving PMS jobs: ${error instanceof Error ? error.message : String(error)}` // }; // return [errorResponse]; // } // } // // // export async function listPmsJobsForComponentDueWithin(args: PmsJobsForComponentDueWithinArgs): Promise<ToolResponse> { // logger.info("Executing list_pms_jobs_for_component_due_within", { args }); // // try { // const imo = args.imo; // const component = args.component; // const days = args.days; // const perPage = args.per_page || 250; // const sessionId = args.session_id || "testing"; // // if (!imo || !component || days === undefined || days === null) { // throw new Error("IMO number, component name, and days are required"); // } // // // Calculate future date based on days // const futureDate = new Date(); // futureDate.setDate(futureDate.getDate() + days); // const futureTs = Math.floor(futureDate.getTime() / 1000); // // const collection = "pms"; // // const includeFields = "imo,vesselName,jobTitle,component,jobDueDate,jobDoneDate,jobCode,defermentRequestedDate,jobCategory,scheduledOverhaulInterval,currentCounter,defermentApplied,jobStatus,currentStatus,remainingHrsNextOverhaul,remainingDaysNextOverhaul"; // // const query = { // q: "*", // filter_by: `imo:${imo} && component:${component} && jobDueDate:<${futureTs}`, // sort_by: "jobDueDate:asc", // per_page: perPage, // include_fields: includeFields // }; // // // Execute the search // logger.info(`Searching for PMS jobs for component '${component}' due within ${days} days on vessel ${imo}`); // const results = await getTypesenseClient().collections(collection).documents().search(query); // // const hits = results.hits || []; // const filteredHits = []; // // for (const hit of hits as TypesenseHit[]) { // const documentData = convertPmsDates(hit.document || {}); // filteredHits.push({ // id: documentData.id, // score: hit.text_match || 0, // document: documentData // }); // } // // // Get documents for data link // const documents = getDocumentsFromHits(hits); // // // Get data link // const dataLink = await getDataLink(documents); // // // Get vessel name from hits // let vesselName = ""; // try { // vesselName = (hits[0]?.document as any)?.vesselName || ""; // } catch (error) { // vesselName = ""; // } // // // Insert the data link to mongodb collection // const linkHeader = `pms jobs for component ${component} due within ${days} days`; // await insertDataLinkToMongoDB(dataLink, linkHeader, sessionId, imo, vesselName); // // // Format the results // const formattedResults = { // found: results.found || 0, // out_of: results.out_of || 0, // page: results.page || 1, // hits: filteredHits // }; // // // Create human-readable date for the title // const futureDateStr = futureDate.toISOString().split('T')[0]; // YYYY-MM-DD format // // // Create artifact // const artifactData = getArtifact("list_pms_jobs_for_component_due_within", dataLink); // // const content: TextContent = { // type: "text", // text: JSON.stringify(formattedResults, null, 2) // }; // // const artifact: TextContent = { // type: "text", // text: JSON.stringify(artifactData, null, 2) // }; // // return [content, artifact]; // } catch (error) { // logger.error("Error in listPmsJobsForComponentDueWithin", { error }); // const errorResponse: TextContent = { // type: "text", // text: `Error retrieving PMS jobs: ${error instanceof Error ? error.message : String(error)}` // }; // return [errorResponse]; // } // } // // // // export async function listOverduePmsJobs(args: OverduePmsJobsArgs): Promise<ToolResponse> { // logger.info("Executing list_overdue_pms_jobs", { args }); // // try { // const imo = args.imo; // const jobCategory = args.jobCategory; // const perPage = args.per_page || 50; // const sessionId = args.session_id || "testing"; // // if (!imo) { // throw new Error("IMO number is required"); // } // // // Build the filter string // let filterBy = `imo:${imo}&&jobStatus:OVERDUE`; // if (jobCategory) { // filterBy += `&&jobCategory:${jobCategory}`; // } // // // Set up search parameters // const searchParameters = { // q: "*", // filter_by: filterBy, // sort_by: "jobDueDate:asc", // per_page: perPage, // include_fields: "imo,vesselName,jobTitle,jobCategory,intervalType,jobDueDate,jobDoneDate,remainingDaysNextOverhaul,remainingHrsNextOverhaul,defermentApplied,defermentStatus,defermentRequestedDate" // }; // // // Execute search using TypesenseClient // const results = await getTypesenseClient().collections("pms").documents().search(searchParameters); // // const hits = results.hits || []; // const filteredHits = []; // // for (const hit of hits as TypesenseHit[]) { // let documentData = hit.document || {}; // // Convert dates if needed // documentData = convertPmsDates(documentData); // filteredHits.push({ // id: documentData.id, // score: hit.text_match || 0, // document: documentData // }); // } // // // Get documents for data link // const documents = filteredHits.map(hit => hit.document); // // // Get data link // const dataLink = await getDataLink(documents); // // // Get vessel name from hits // let vesselName = ""; // try { // vesselName = (hits[0]?.document as any)?.vesselName || ""; // } catch (error) { // vesselName = ""; // } // // // Insert the data link to mongodb collection // const linkHeader = `overdue pms jobs${jobCategory ? ` for ${jobCategory}` : ''}`; // await insertDataLinkToMongoDB(dataLink, linkHeader, sessionId, imo, vesselName); // // if (hits.length === 0) { // const noDataResponse: TextContent = { // type: "text", // text: "No overdue PMS jobs found." // }; // return [noDataResponse]; // } // // // Format the results // const formattedResults = { // found: results.found || 0, // out_of: results.out_of || 0, // page: results.page || 1, // hits: filteredHits // }; // // // Convert the results to JSON string // const formattedText = JSON.stringify(formattedResults, null, 2); // // // Create artifact // const artifactData = getArtifact("list_overdue_pms_jobs", dataLink); // // const content: TextContent = { // type: "text", // text: formattedText // }; // const artifact: TextContent = { // type: "text", // text: JSON.stringify(artifactData, null, 2) // }; // return [content, artifact]; // // } catch (error) { // logger.error("Error in listOverduePmsJobs", { error }); // const errorResponse: TextContent = { // type: "text", // text: `Error fetching overdue PMS jobs: ${error instanceof Error ? error.message : String(error)}` // }; // return [errorResponse]; // } //# sourceMappingURL=pmsTools.js.map