129 lines
3.5 KiBLFS
JavaScript
129 lines
3.5 KiBLFS
JavaScript
#!/usr/bin/env node
|
|
|
|
import { appendFileSync, existsSync, mkdirSync } from 'fs';
|
|
import { fileURLToPath } from 'url';
|
|
import { dirname, join } from 'path';
|
|
|
|
const __filename = fileURLToPath(import.meta.url);
|
|
const __dirname = dirname(__filename);
|
|
|
|
// Log file is in the skill root directory, not in scripts/
|
|
const SKILL_ROOT = join(__dirname, '..');
|
|
const LOG_FILE = join(SKILL_ROOT, 'action-log.jsonl');
|
|
|
|
/**
|
|
* Ensure the log file directory exists
|
|
*/
|
|
function ensureLogDirectory() {
|
|
const logDir = dirname(LOG_FILE);
|
|
if (!existsSync(logDir)) {
|
|
mkdirSync(logDir, { recursive: true });
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Log an action to the log file
|
|
* @param {string} action - The action type (e.g., 'search', 'send', 'label')
|
|
* @param {Object} params - The parameters used for the action
|
|
* @param {Object} result - The result of the action
|
|
* @param {Object} metadata - Additional metadata (e.g., account, duration)
|
|
*/
|
|
export function logAction(action, params, result, metadata = {}) {
|
|
ensureLogDirectory();
|
|
|
|
const logEntry = {
|
|
timestamp: new Date().toISOString(),
|
|
action,
|
|
params: sanitizeParams(params),
|
|
result: sanitizeResult(result),
|
|
metadata: {
|
|
...metadata,
|
|
skill: 'gmail'
|
|
}
|
|
};
|
|
|
|
try {
|
|
// Append as JSON Lines format (one JSON object per line)
|
|
appendFileSync(LOG_FILE, JSON.stringify(logEntry) + '\n', 'utf8');
|
|
} catch (error) {
|
|
// Don't fail the main action if logging fails
|
|
console.error('Warning: Failed to write to action log:', error.message);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Sanitize parameters to remove sensitive data and limit size
|
|
*/
|
|
function sanitizeParams(params) {
|
|
const sanitized = { ...params };
|
|
|
|
// Remove sensitive fields
|
|
const sensitiveFields = ['password', 'token', 'access_token', 'refresh_token'];
|
|
sensitiveFields.forEach(field => {
|
|
if (sanitized[field]) {
|
|
sanitized[field] = '[REDACTED]';
|
|
}
|
|
});
|
|
|
|
// Truncate very long string values
|
|
Object.keys(sanitized).forEach(key => {
|
|
if (typeof sanitized[key] === 'string' && sanitized[key].length > 1000) {
|
|
sanitized[key] = sanitized[key].substring(0, 1000) + '... [truncated]';
|
|
}
|
|
});
|
|
|
|
return sanitized;
|
|
}
|
|
|
|
/**
|
|
* Sanitize result to limit size while keeping useful information
|
|
*/
|
|
function sanitizeResult(result) {
|
|
const sanitized = { ...result };
|
|
|
|
// Keep success status and counts
|
|
if (sanitized.success !== undefined) {
|
|
// Success is important
|
|
}
|
|
|
|
if (sanitized.count !== undefined || sanitized.total !== undefined) {
|
|
// Counts are useful
|
|
}
|
|
|
|
// For message/email results, keep summary info but limit details
|
|
if (sanitized.messages && Array.isArray(sanitized.messages)) {
|
|
sanitized.messageCount = sanitized.messages.length;
|
|
// Keep only essential fields from first few messages
|
|
sanitized.messageSummary = sanitized.messages.slice(0, 3).map(msg => ({
|
|
id: msg.id,
|
|
threadId: msg.threadId,
|
|
from: msg.from,
|
|
subject: msg.subject,
|
|
date: msg.date,
|
|
labels: msg.labels
|
|
}));
|
|
delete sanitized.messages;
|
|
}
|
|
|
|
// For label results
|
|
if (sanitized.labels && Array.isArray(sanitized.labels)) {
|
|
sanitized.labelCount = sanitized.labels.length;
|
|
sanitized.labelNames = sanitized.labels.map(l => l.name || l.id).slice(0, 10);
|
|
delete sanitized.labels;
|
|
}
|
|
|
|
// Truncate error messages
|
|
if (sanitized.error && sanitized.error.length > 500) {
|
|
sanitized.error = sanitized.error.substring(0, 500) + '... [truncated]';
|
|
}
|
|
|
|
return sanitized;
|
|
}
|
|
|
|
/**
|
|
* Get the log file path (useful for scripts that want to reference it)
|
|
*/
|
|
export function getLogFilePath() {
|
|
return LOG_FILE;
|
|
}
|