- Delete unused dataMerger, formatter, Device model, dead service exports, and the empty agents/ + .gitkeep placeholders. - Extract STORE_MODES and MDM device-type filters into a shared constants.js. - Anchor bot regexes (^help|^store|^analyze) so "analyze store 305" no longer fires both handlers; replace catch-all noise. - Hoist inline require() calls in integrations to top-of-file imports. - Harden WebSocket server: Authorization header support, single-agent enforcement, bounded pending requests, server-level error handler, coalesced cache refresh in Meraki client. - Wrap Meraki/MDM network calls with withRetry; add request timeouts. - Migrate all console.* calls onto utils/logger.js (LOG_LEVEL aware); drive Webex framework logLevel from env. - Refactor storeDetail.js: shared renderClientLine + buildMdmSection helpers cut duplication roughly in half. - Refresh README structure, document LOG_LEVEL, add npm run agent script, add jest testMatch + new tests (handlers, HealthReport, Store, ws). Verified: npm run lint clean, 7 suites / 31 tests passing. Co-authored-by: Cursor <cursoragent@cursor.com>
147 lines
5.2 KiB
JavaScript
147 lines
5.2 KiB
JavaScript
const { getStoreDetail } = require('../integrations/storeDetail');
|
|
const { getStoreHealth } = require('../integrations/storeHealth');
|
|
const { parseStoreNumber } = require('../utils/validate');
|
|
const { STORE_MODES } = require('../constants');
|
|
const logger = require('../utils/logger');
|
|
|
|
function parseStoreCommand(text) {
|
|
const storeNumber = parseStoreNumber(text);
|
|
if (!storeNumber) return { storeNumber: null, mode: null };
|
|
|
|
const lower = text.toLowerCase();
|
|
let mode = STORE_MODES.DEFAULT;
|
|
|
|
if (lower.includes(' pos')) mode = STORE_MODES.POS;
|
|
else if (lower.includes(' ios') || lower.includes(' iphone')) mode = STORE_MODES.IOS;
|
|
|
|
return { storeNumber, mode };
|
|
}
|
|
|
|
async function handleStoreCommand(bot, trigger) {
|
|
const { storeNumber, mode } = parseStoreCommand(trigger.message.text);
|
|
|
|
if (!storeNumber) {
|
|
return bot.say(
|
|
'markdown',
|
|
'Usage: `store <number>`\n\nExample: `store 305`\n\nOptions:\n• `store 305` — info + network + server\n• `store 305 pos` — POS systems\n• `store 305 ios` — iOS devices\n\nType `help store` for more details.'
|
|
);
|
|
}
|
|
|
|
const modeLabel =
|
|
mode === STORE_MODES.POS ? 'POS' : mode === STORE_MODES.IOS ? 'iOS' : 'Overview';
|
|
bot.say('markdown', `🔍 Analyzing Store **${storeNumber}** (${modeLabel})...`);
|
|
|
|
try {
|
|
const report = await getStoreDetail(storeNumber, mode);
|
|
const sections = report.split(/\n\n(?=\*\*)/);
|
|
|
|
for (let i = 0; i < sections.length; i++) {
|
|
const section = sections[i].trim();
|
|
if (section) {
|
|
await bot.say('markdown', section);
|
|
if (i < sections.length - 1) await new Promise(r => setTimeout(r, 400));
|
|
}
|
|
}
|
|
} catch (err) {
|
|
logger.error('Store analysis error', { storeNumber, error: err.message });
|
|
bot.say('markdown', `❌ Error analyzing store **${storeNumber}**:\n${err.message}`);
|
|
}
|
|
}
|
|
|
|
async function handleAnalyzeCommand(bot, trigger) {
|
|
const { storeNumber, mode } = parseStoreCommand(trigger.message.text);
|
|
|
|
if (!storeNumber) {
|
|
return bot.say(
|
|
'markdown',
|
|
'Usage: `analyze <number>`\n\nExample: `analyze 305`\n\nOptions:\n• `analyze 305` — full health summary\n• `analyze 305 pos` — POS health (broken only)\n• `analyze 305 ios` — iOS health (broken only)\n\nType `help analyze` for more details.'
|
|
);
|
|
}
|
|
|
|
const modeLabel =
|
|
mode === STORE_MODES.POS ? 'POS' : mode === STORE_MODES.IOS ? 'iOS' : 'Overview';
|
|
bot.say('markdown', `🔍 Running Health Analysis for Store **${storeNumber}** (${modeLabel})...`);
|
|
|
|
try {
|
|
const health = await getStoreHealth(storeNumber, mode);
|
|
|
|
if (health && health.summary) {
|
|
let output = health.summary;
|
|
|
|
// For sub-modes or analyze, only show broken components
|
|
if (mode !== STORE_MODES.DEFAULT) {
|
|
const lines = output.split('\n');
|
|
const issueStart = lines.findIndex(l => l.includes('Issues Detected') || l.includes('⚠️'));
|
|
if (issueStart > -1) {
|
|
output =
|
|
lines.slice(0, issueStart + 1).join('\n') +
|
|
'\n' +
|
|
lines
|
|
.slice(issueStart + 1)
|
|
.filter(l => l.trim().startsWith('-'))
|
|
.join('\n');
|
|
}
|
|
}
|
|
|
|
bot.say('markdown', output);
|
|
} else {
|
|
bot.say('markdown', '✅ Analysis completed, but no summary was generated.');
|
|
}
|
|
} catch (err) {
|
|
logger.error('Store health analysis error', { storeNumber, error: err.message });
|
|
bot.say('markdown', `❌ Error analyzing store **${storeNumber}**:\n${err.message}`);
|
|
}
|
|
}
|
|
|
|
async function handleHelpCommand(bot, trigger) {
|
|
const text = trigger.message.text.toLowerCase().trim();
|
|
|
|
let response;
|
|
|
|
if (text.includes('store')) {
|
|
response = `**Store Commands**
|
|
|
|
• \`store <number>\` — Store info/details, active network devices, and the store server
|
|
• \`store <number> pos\` — Store server, registers, mobile registers, printers, and payment terminals
|
|
• \`store <number> ios\` — All iOS devices
|
|
|
|
**Tip:** Type the command without a number for usage examples.`;
|
|
} else if (text.includes('analyze')) {
|
|
response = `**Analyze Commands** (shows only broken components for sub-modes)
|
|
|
|
• \`analyze <number>\` — Overall health summary
|
|
• \`analyze <number> pos\` — POS health (only issues)
|
|
• \`analyze <number> ios\` — iOS health (only issues)
|
|
|
|
**Tip:** Type the command without a number for usage examples.`;
|
|
} else {
|
|
response = `**NetAnalyzer Help**
|
|
|
|
Available Commands:
|
|
|
|
**Store Commands:**
|
|
• \`store <number>\` — Store info/details, active network devices, and the store server
|
|
• \`store <number> pos\` — Store server, registers, mobile registers, printers, and payment terminals
|
|
• \`store <number> ios\` — All iOS devices
|
|
|
|
**Analyze Commands:**
|
|
• \`analyze <number>\` — Overall health summary
|
|
• \`analyze <number> pos\` — POS health (broken components only)
|
|
• \`analyze <number> ios\` — iOS health (broken components only)
|
|
|
|
**Tips:**
|
|
• Most commands work in both group spaces and 1:1 chats.
|
|
• Type a command without a number for usage examples.
|
|
• Use \`help store\` or \`help analyze\` for more details.
|
|
• Try \`store 782\` or \`analyze 782\` to get started.`;
|
|
}
|
|
|
|
bot.say('markdown', response);
|
|
}
|
|
|
|
module.exports = {
|
|
handleStoreCommand,
|
|
handleAnalyzeCommand,
|
|
handleHelpCommand,
|
|
parseStoreCommand,
|
|
};
|