Files
dss/dss-claude-plugin/hooks/scripts/session-summary.js
Digital Production Factory 276ed71f31 Initial commit: Clean DSS implementation
Migrated from design-system-swarm with fresh git history.
Old project history preserved in /home/overbits/apps/design-system-swarm

Core components:
- MCP Server (Python FastAPI with mcp 1.23.1)
- Claude Plugin (agents, commands, skills, strategies, hooks, core)
- DSS Backend (dss-mvp1 - token translation, Figma sync)
- Admin UI (Node.js/React)
- Server (Node.js/Express)
- Storybook integration (dss-mvp1/.storybook)

Self-contained configuration:
- All paths relative or use DSS_BASE_PATH=/home/overbits/dss
- PYTHONPATH configured for dss-mvp1 and dss-claude-plugin
- .env file with all configuration
- Claude plugin uses ${CLAUDE_PLUGIN_ROOT} for portability

Migration completed: $(date)
🤖 Clean migration with full functionality preserved
2025-12-09 18:45:48 -03:00

195 lines
4.8 KiB
JavaScript
Executable File

#!/usr/bin/env node
/**
* DSS Session Summary Hook
* Generates a summary report at the end of each Claude Code session.
* Written from scratch for DSS.
*/
const fs = require('fs');
const path = require('path');
const { execSync } = require('child_process');
// Configuration
const DEFAULT_CONFIG = {
session_summary: {
enabled: true,
output_file: '.dss-session-summary.md',
include_git_diff: true,
include_file_list: true,
max_diff_lines: 100
}
};
function loadConfig() {
const configPath = path.join(process.env.HOME || '', '.dss', 'hooks-config.json');
try {
if (fs.existsSync(configPath)) {
const userConfig = JSON.parse(fs.readFileSync(configPath, 'utf8'));
return { ...DEFAULT_CONFIG, ...userConfig };
}
} catch (e) {
// Use defaults
}
return DEFAULT_CONFIG;
}
function getGitInfo() {
const info = {
branch: '',
status: '',
diff: '',
modifiedFiles: []
};
try {
// Check if in git repo
execSync('git rev-parse --is-inside-work-tree', { stdio: 'pipe' });
// Get branch
info.branch = execSync('git branch --show-current', { encoding: 'utf8' }).trim();
// Get status
info.status = execSync('git status --short', { encoding: 'utf8' }).trim();
// Get modified files
const statusLines = info.status.split('\n').filter(Boolean);
info.modifiedFiles = statusLines.map(line => {
const parts = line.trim().split(/\s+/);
return {
status: parts[0],
file: parts.slice(1).join(' ')
};
});
// Get diff summary
try {
info.diff = execSync('git diff --stat', { encoding: 'utf8' }).trim();
} catch (e) {
info.diff = '';
}
} catch (e) {
// Not a git repo or git not available
}
return info;
}
function getSessionStats() {
// Try to read from session state if available
const stats = {
startTime: new Date().toISOString(),
filesModified: 0,
linesAdded: 0,
linesRemoved: 0
};
try {
// Get diff stats from git
const diffStat = execSync('git diff --numstat', { encoding: 'utf8' });
const lines = diffStat.trim().split('\n').filter(Boolean);
for (const line of lines) {
const [added, removed] = line.split('\t');
stats.linesAdded += parseInt(added) || 0;
stats.linesRemoved += parseInt(removed) || 0;
stats.filesModified++;
}
} catch (e) {
// Git not available
}
return stats;
}
function generateReport(config) {
const summaryConfig = config.session_summary || {};
const gitInfo = getGitInfo();
const stats = getSessionStats();
const timestamp = new Date().toLocaleString();
const lines = [];
lines.push('# DSS Session Summary');
lines.push(`\n**Generated:** ${timestamp}`);
if (gitInfo.branch) {
lines.push(`**Branch:** ${gitInfo.branch}`);
}
lines.push('\n## Changes Overview');
lines.push('');
lines.push(`- Files modified: ${stats.filesModified}`);
lines.push(`- Lines added: +${stats.linesAdded}`);
lines.push(`- Lines removed: -${stats.linesRemoved}`);
if (summaryConfig.include_file_list && gitInfo.modifiedFiles.length > 0) {
lines.push('\n## Modified Files');
lines.push('');
lines.push('| Status | File |');
lines.push('|--------|------|');
const statusLabels = {
'M': 'Modified',
'A': 'Added',
'D': 'Deleted',
'R': 'Renamed',
'??': 'Untracked'
};
for (const file of gitInfo.modifiedFiles.slice(0, 20)) {
const label = statusLabels[file.status] || file.status;
lines.push(`| ${label} | ${file.file} |`);
}
if (gitInfo.modifiedFiles.length > 20) {
lines.push(`| ... | +${gitInfo.modifiedFiles.length - 20} more files |`);
}
}
if (summaryConfig.include_git_diff && gitInfo.diff) {
lines.push('\n## Diff Summary');
lines.push('');
lines.push('```');
const diffLines = gitInfo.diff.split('\n');
const maxLines = summaryConfig.max_diff_lines || 100;
lines.push(diffLines.slice(0, maxLines).join('\n'));
if (diffLines.length > maxLines) {
lines.push(`... (${diffLines.length - maxLines} more lines)`);
}
lines.push('```');
}
lines.push('\n---');
lines.push('*Generated by DSS Session Summary Hook*');
return lines.join('\n');
}
function main() {
const config = loadConfig();
if (!config.session_summary?.enabled) {
process.exit(0);
}
try {
const report = generateReport(config);
const outputFile = config.session_summary.output_file || '.dss-session-summary.md';
const outputPath = path.join(process.cwd(), outputFile);
fs.writeFileSync(outputPath, report, 'utf8');
// Output confirmation
console.log(JSON.stringify({
systemMessage: `Session summary saved to ${outputFile}`,
continue: true
}));
} catch (e) {
// Fail silently
}
process.exit(0);
}
main();