cognitive-workflow-mcp 1.1.0

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/bin/cli.js ADDED
@@ -0,0 +1,286 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { Command } from 'commander';
4
+ import { analyzeCommits } from '../src/analyzer.js';
5
+ import { generateDashboard } from '../src/generator.js';
6
+ import { configureTerminals } from '../src/configurator.js';
7
+ import { getInsights } from '../src/insights.js';
8
+ import { readFile, access, copyFile, mkdir } from 'fs/promises';
9
+ import { fileURLToPath } from 'url';
10
+ import { dirname, join } from 'path';
11
+ import { execSync } from 'child_process';
12
+ import { existsSync } from 'fs';
13
+
14
+ const __filename = fileURLToPath(import.meta.url);
15
+ const __dirname = dirname(__filename);
16
+ const packageJson = JSON.parse(
17
+ await readFile(join(__dirname, '../package.json'), 'utf-8')
18
+ );
19
+
20
+ // ============================================================================
21
+ // POSTINSTALL: Show welcome + open dashboard
22
+ // ============================================================================
23
+ if (process.argv.includes('--postinstall')) {
24
+ const colors = {
25
+ reset: '\x1b[0m',
26
+ bold: '\x1b[1m',
27
+ blue: '\x1b[34m',
28
+ green: '\x1b[32m',
29
+ yellow: '\x1b[33m',
30
+ purple: '\x1b[35m',
31
+ cyan: '\x1b[36m',
32
+ };
33
+
34
+ console.log(`
35
+ ${colors.purple}${colors.bold}
36
+ ╔════════════════════════════════════════════════════════════╗
37
+ ║ ║
38
+ ║ ████████╗██╗ ██╗███████╗████████╗ █████╗ ██████╗ ██████╗ ║
39
+ ║ ╚══██╔══╝██║ ██║██╔════╝╚══██╔══╝██╔══██╗██╔════╝██╔═══██╗ ║
40
+ ║ ██║ ███████║█████╗ ██║ ███████║██║ ██║ ██║ ║
41
+ ║ ██║ ██╔══██║██╔══╝ ██║ ██╔══██║██║ ██║ ██║ ║
42
+ ║ ██║ ██║ ██║███████╗ ██║ ██║ ██║╚██████╗╚██████╔╝ ║
43
+ ║ ╚═╝ ╚═╝ ╚═╝╚══════╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═════╝ ║
44
+ ║ ║
45
+ ║ Transform Your Terminal Into a Mental Palace ║
46
+ ╚════════════════════════════════════════════════════════════╝
47
+ ${colors.reset}
48
+ ${colors.green}✓ Cognitive Workflow MCP installed successfully!${colors.reset}
49
+
50
+ ${colors.bold}The 6 Cognitive Identities:${colors.reset}
51
+
52
+ ${colors.blue}🔨 Builder${colors.reset} feat, fix, refactor → iTerm2
53
+ ${colors.yellow}🔍 Discoverer${colors.reset} docs, research → WezTerm
54
+ ${colors.green}⚙️ Operator${colors.reset} chore, deploy, ops → Kitty
55
+ ${colors.cyan}📚 Teacher${colors.reset} blog, content → Terminal
56
+ ${colors.purple}🎯 Strategist${colors.reset} strategy, planning → VS Code
57
+ ${colors.purple}🧪 Experimenter${colors.reset} experiment, poc → Cursor
58
+
59
+ ${colors.bold}Quick Start:${colors.reset}
60
+
61
+ ${colors.cyan}cognitive-workflow analyze${colors.reset} Analyze your git commits
62
+ ${colors.cyan}cognitive-workflow generate${colors.reset} Generate dashboard HTML
63
+ ${colors.cyan}cognitive-workflow dashboard${colors.reset} Open included dashboard
64
+
65
+ ${colors.bold}The Principle:${colors.reset} Tool = Identity = Mindset
66
+
67
+ ${colors.bold}Learn more:${colors.reset} ${colors.cyan}https://thetacoach.biz/thetacog${colors.reset}
68
+ `);
69
+
70
+ // Copy bundled dashboard to .workflow if it doesn't exist
71
+ const bundledDashboard = join(__dirname, '../.workflow/cognitive-dashboard-enhanced.html');
72
+ const localWorkflow = join(process.cwd(), '.workflow');
73
+ const localDashboard = join(localWorkflow, 'cognitive-dashboard.html');
74
+
75
+ if (existsSync(bundledDashboard) && !existsSync(localDashboard)) {
76
+ try {
77
+ await mkdir(localWorkflow, { recursive: true });
78
+ await copyFile(bundledDashboard, localDashboard);
79
+ console.log(`${colors.green}✓ Dashboard copied to .workflow/cognitive-dashboard.html${colors.reset}\n`);
80
+ } catch (e) {
81
+ // Silent fail - user can run generate command
82
+ }
83
+ }
84
+
85
+ process.exit(0);
86
+ }
87
+
88
+ const program = new Command();
89
+
90
+ program
91
+ .name('cognitive-workflow')
92
+ .description('Manage identity-based cognitive workflows with terminal integration')
93
+ .version(packageJson.version);
94
+
95
+ program
96
+ .command('analyze')
97
+ .description('Analyze git commit history and categorize by cognitive identity')
98
+ .option('-d, --days <number>', 'Days of history to analyze', '60')
99
+ .option('-o, --output <path>', 'Save results to file')
100
+ .action(async (options) => {
101
+ console.log('🔍 Analyzing commit history...\n');
102
+
103
+ const analysis = await analyzeCommits(parseInt(options.days));
104
+
105
+ console.log(`📊 Total commits: ${analysis.totalCommits}`);
106
+ console.log(`📅 Period: ${analysis.daysAnalyzed} days\n`);
107
+
108
+ console.log('🎯 Cognitive Identity Distribution:\n');
109
+ for (const [identity, data] of Object.entries(analysis.identities)) {
110
+ const emoji = getIdentityEmoji(identity);
111
+ console.log(`${emoji} ${capitalize(identity).padEnd(15)} ${data.commits} commits (${data.percentage}%)`);
112
+ }
113
+
114
+ console.log('\n💡 Insights:\n');
115
+ for (const insight of analysis.insights) {
116
+ console.log(` • ${insight.message}`);
117
+ }
118
+
119
+ if (options.output) {
120
+ const { writeFile } = await import('fs/promises');
121
+ await writeFile(options.output, JSON.stringify(analysis, null, 2));
122
+ console.log(`\n✅ Results saved to ${options.output}`);
123
+ }
124
+ });
125
+
126
+ program
127
+ .command('generate')
128
+ .description('Generate HTML dashboard and room pages')
129
+ .option('-o, --output <directory>', 'Output directory', '.workflow')
130
+ .option('--no-open', 'Do not open dashboard after generation')
131
+ .action(async (options) => {
132
+ console.log('🎨 Generating cognitive workflow dashboard...\n');
133
+
134
+ const result = await generateDashboard(options.output, options.open);
135
+
136
+ console.log('✅ Generated files:');
137
+ for (const file of result.filesCreated) {
138
+ console.log(` • ${file}`);
139
+ }
140
+
141
+ if (options.open) {
142
+ console.log(`\n🌐 Opening dashboard: ${result.dashboardUrl}`);
143
+ }
144
+ });
145
+
146
+ program
147
+ .command('configure')
148
+ .description('Configure terminal application mappings')
149
+ .action(async () => {
150
+ console.log('⚙️ Configuring terminal mappings...\n');
151
+
152
+ // Interactive configuration (would use inquirer or prompts)
153
+ console.log('This would open an interactive configurator.');
154
+ console.log('For now, edit .cognitive-workflow.json manually.');
155
+ });
156
+
157
+ program
158
+ .command('insights')
159
+ .description('Get insights about your cognitive work patterns')
160
+ .action(async () => {
161
+ console.log('💡 Analyzing work patterns...\n');
162
+
163
+ const insights = await getInsights(true);
164
+
165
+ console.log(`🎯 Dominant Identity: ${capitalize(insights.dominantIdentity)}`);
166
+ console.log(`⚖️ Balance Score: ${(insights.balanceScore * 100).toFixed(0)}%\n`);
167
+
168
+ if (insights.recommendations.length > 0) {
169
+ console.log('📋 Recommendations:\n');
170
+ for (const rec of insights.recommendations) {
171
+ console.log(` • ${rec}`);
172
+ }
173
+ }
174
+ });
175
+
176
+ program
177
+ .command('open')
178
+ .description('Open the cognitive workflow dashboard (local .workflow folder)')
179
+ .action(async () => {
180
+ const dashboardPath = join(process.cwd(), '.workflow', 'cognitive-dashboard.html');
181
+ openFile(dashboardPath);
182
+ });
183
+
184
+ program
185
+ .command('dashboard')
186
+ .description('Open the bundled cognitive dashboard (included with package)')
187
+ .option('-r, --room <name>', 'Open specific room (builder, discoverer, operator, teacher, strategist, experimenter)')
188
+ .action(async (options) => {
189
+ const workflowDir = join(__dirname, '../.workflow');
190
+
191
+ let file = 'cognitive-dashboard-enhanced.html';
192
+ if (options.room) {
193
+ const room = options.room.toLowerCase();
194
+ const validRooms = ['builder', 'discoverer', 'operator', 'teacher', 'strategist', 'experimenter'];
195
+ if (validRooms.includes(room)) {
196
+ file = `bucket-${room}.html`;
197
+ } else {
198
+ console.error(`❌ Unknown room: ${room}`);
199
+ console.log(` Valid rooms: ${validRooms.join(', ')}`);
200
+ process.exit(1);
201
+ }
202
+ }
203
+
204
+ const dashboardPath = join(workflowDir, file);
205
+
206
+ if (!existsSync(dashboardPath)) {
207
+ console.error(`❌ Dashboard not found: ${dashboardPath}`);
208
+ console.log(' Opening web version instead...');
209
+ openFile('https://thetacoach.biz/thetacog');
210
+ return;
211
+ }
212
+
213
+ console.log(`🌐 Opening ${options.room ? `${options.room} room` : 'dashboard'}...`);
214
+ openFile(dashboardPath);
215
+ });
216
+
217
+ program
218
+ .command('rooms')
219
+ .description('List all cognitive rooms/identities')
220
+ .action(() => {
221
+ console.log(`
222
+ 🏗️ The 6 Cognitive Identities (Rooms)
223
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
224
+
225
+ 🔨 Builder "I am building. I am shipping. I am solving."
226
+ Triggers: feat, fix, refactor, perf
227
+ Terminal: iTerm2
228
+
229
+ 🔍 Discoverer "I am exploring. I am researching. I am learning."
230
+ Triggers: docs, research, analysis
231
+ Terminal: WezTerm
232
+
233
+ ⚙️ Operator "I am executing. I am deploying. I am maintaining."
234
+ Triggers: chore, deploy, ops
235
+ Terminal: Kitty
236
+
237
+ 📚 Teacher "I am explaining. I am teaching. I am sharing."
238
+ Triggers: blog, content, tutorial
239
+ Terminal: Terminal.app
240
+
241
+ 🎯 Strategist "I am positioning. I am planning. I am deciding."
242
+ Triggers: strategy, planning
243
+ Terminal: VS Code
244
+
245
+ 🧪 Experimenter "I am testing. I am prototyping. I am breaking."
246
+ Triggers: experiment, prototype, poc
247
+ Terminal: Cursor
248
+
249
+ Open a specific room:
250
+ cognitive-workflow dashboard --room builder
251
+ cognitive-workflow dashboard --room discoverer
252
+ `);
253
+ });
254
+
255
+ program.parse();
256
+
257
+ function openFile(path) {
258
+ try {
259
+ const platform = process.platform;
260
+ if (platform === 'darwin') {
261
+ execSync(`open "${path}"`);
262
+ } else if (platform === 'win32') {
263
+ execSync(`start "" "${path}"`);
264
+ } else {
265
+ execSync(`xdg-open "${path}" || sensible-browser "${path}"`);
266
+ }
267
+ } catch (error) {
268
+ console.log(`Open this URL in your browser:\n ${path}`);
269
+ }
270
+ }
271
+
272
+ function getIdentityEmoji(identity) {
273
+ const emojis = {
274
+ builder: '🏗️',
275
+ discoverer: '🔬',
276
+ operator: '🎩',
277
+ teacher: '📣',
278
+ strategist: '🗺️',
279
+ experimenter: '🧪'
280
+ };
281
+ return emojis[identity] || '📌';
282
+ }
283
+
284
+ function capitalize(str) {
285
+ return str.charAt(0).toUpperCase() + str.slice(1);
286
+ }
package/package.json ADDED
@@ -0,0 +1,57 @@
1
+ {
2
+ "name": "cognitive-workflow-mcp",
3
+ "version": "1.1.0",
4
+ "description": "Transform your terminal into a mental palace. Cognitive workspaces that ground your workflow through git commit analysis. Tool = Identity = Mindset.",
5
+ "main": "src/index.js",
6
+ "bin": {
7
+ "cognitive-workflow": "bin/cli.js",
8
+ "thetacog": "bin/cli.js"
9
+ },
10
+ "type": "module",
11
+ "files": [
12
+ "src/",
13
+ "bin/",
14
+ ".workflow/",
15
+ "README.md"
16
+ ],
17
+ "scripts": {
18
+ "start": "node src/index.js",
19
+ "cli": "node bin/cli.js",
20
+ "dashboard": "node bin/cli.js dashboard",
21
+ "postinstall": "node bin/cli.js --postinstall",
22
+ "test": "node --test src/**/*.test.js"
23
+ },
24
+ "keywords": [
25
+ "mcp",
26
+ "cognitive-workflow",
27
+ "terminal",
28
+ "identity",
29
+ "mental-palace",
30
+ "productivity",
31
+ "git-analysis",
32
+ "commit-categorization",
33
+ "thetacog",
34
+ "thetacoach",
35
+ "fim",
36
+ "claude"
37
+ ],
38
+ "author": "ThetaDriven <elias@thetadriven.com>",
39
+ "license": "MIT",
40
+ "homepage": "https://thetacoach.biz/thetacog",
41
+ "dependencies": {
42
+ "@modelcontextprotocol/sdk": "^0.5.0",
43
+ "simple-git": "^3.25.0",
44
+ "commander": "^12.0.0"
45
+ },
46
+ "repository": {
47
+ "type": "git",
48
+ "url": "https://github.com/wiber/thetadrivencoach.git",
49
+ "directory": "packages/cognitive-workflow-mcp"
50
+ },
51
+ "publishConfig": {
52
+ "access": "public"
53
+ },
54
+ "engines": {
55
+ "node": ">=18.0.0"
56
+ }
57
+ }
@@ -0,0 +1,194 @@
1
+ import simpleGit from 'simple-git';
2
+
3
+ /**
4
+ * Identity patterns for commit categorization
5
+ */
6
+ const IDENTITY_PATTERNS = {
7
+ builder: {
8
+ keywords: ['feat', 'fix', 'refactor', 'perf', 'build', 'style', 'ui', 'component'],
9
+ paths: ['src/', 'lib/', 'components/', 'pages/', 'app/'],
10
+ description: 'Hands-on implementation and feature building'
11
+ },
12
+ discoverer: {
13
+ keywords: ['docs', 'research', 'analysis', 'study', 'investigate', 'explore', 'book'],
14
+ paths: ['docs/', 'research/', 'notes/', 'books/', 'papers/'],
15
+ description: 'Deep research and first principles thinking'
16
+ },
17
+ operator: {
18
+ keywords: ['chore', 'deploy', 'ops', 'ci', 'cd', 'release', 'config', 'env'],
19
+ paths: ['config/', '.github/', 'scripts/', 'deploy/'],
20
+ description: 'Operations, deployment, and business management'
21
+ },
22
+ teacher: {
23
+ keywords: ['blog', 'content', 'tutorial', 'guide', 'example', 'demo', 'explain'],
24
+ paths: ['blog/', 'content/', 'examples/', 'tutorials/'],
25
+ description: 'Teaching, content creation, and public communication'
26
+ },
27
+ strategist: {
28
+ keywords: ['strategy', 'planning', 'positioning', 'marketing', 'competitor', 'market'],
29
+ paths: ['strategy/', 'planning/', 'marketing/'],
30
+ description: 'Strategic planning and competitive analysis'
31
+ },
32
+ experimenter: {
33
+ keywords: ['experiment', 'prototype', 'poc', 'test', 'try', 'spike', 'wip'],
34
+ paths: ['experiments/', 'prototypes/', 'playground/'],
35
+ description: 'Rapid prototyping and hypothesis testing'
36
+ }
37
+ };
38
+
39
+ /**
40
+ * Analyzes git commit history and categorizes commits by cognitive identity
41
+ *
42
+ * @param {number} daysBack - Number of days of history to analyze
43
+ * @returns {Promise<Object>} Analysis results with commit categorization
44
+ */
45
+ export async function analyzeCommits(daysBack = 60) {
46
+ const git = simpleGit();
47
+
48
+ // Get commit history
49
+ const since = new Date(Date.now() - daysBack * 24 * 60 * 60 * 1000).toISOString();
50
+ const log = await git.log(['--since', since, '--all']);
51
+
52
+ const commits = log.all;
53
+ const totalCommits = commits.length;
54
+
55
+ // Categorize commits
56
+ const categorized = {
57
+ builder: [],
58
+ discoverer: [],
59
+ operator: [],
60
+ teacher: [],
61
+ strategist: [],
62
+ experimenter: []
63
+ };
64
+
65
+ for (const commit of commits) {
66
+ const message = commit.message.toLowerCase();
67
+ const identity = categorizeCommit(commit, message);
68
+ categorized[identity].push(commit);
69
+ }
70
+
71
+ // Calculate statistics
72
+ const identities = {};
73
+ for (const [identity, commits] of Object.entries(categorized)) {
74
+ const count = commits.length;
75
+ const percentage = Math.round((count / totalCommits) * 100);
76
+ const commitsPerDay = (count / daysBack).toFixed(2);
77
+
78
+ identities[identity] = {
79
+ commits: count,
80
+ percentage,
81
+ commitsPerDay: parseFloat(commitsPerDay),
82
+ description: IDENTITY_PATTERNS[identity].description,
83
+ recentCommits: commits.slice(0, 10).map(c => ({
84
+ hash: c.hash.substring(0, 8),
85
+ message: c.message,
86
+ date: c.date,
87
+ author: c.author_name
88
+ }))
89
+ };
90
+ }
91
+
92
+ // Sort identities by commit count
93
+ const sortedIdentities = Object.entries(identities)
94
+ .sort((a, b) => b[1].commits - a[1].commits)
95
+ .reduce((acc, [key, value]) => {
96
+ acc[key] = value;
97
+ return acc;
98
+ }, {});
99
+
100
+ // Generate insights
101
+ const insights = generateInsights(sortedIdentities, totalCommits);
102
+
103
+ return {
104
+ totalCommits,
105
+ daysAnalyzed: daysBack,
106
+ identities: sortedIdentities,
107
+ insights,
108
+ generatedAt: new Date().toISOString()
109
+ };
110
+ }
111
+
112
+ /**
113
+ * Categorizes a single commit into a cognitive identity
114
+ */
115
+ function categorizeCommit(commit, messageLower) {
116
+ // Check each identity's patterns
117
+ for (const [identity, patterns] of Object.entries(IDENTITY_PATTERNS)) {
118
+ // Check keywords in message
119
+ const keywordMatch = patterns.keywords.some(kw => messageLower.includes(kw));
120
+
121
+ // Get changed files for this commit (if available)
122
+ const files = commit.diff?.files || [];
123
+ const pathMatch = files.some(file =>
124
+ patterns.paths.some(path => file.file.includes(path))
125
+ );
126
+
127
+ if (keywordMatch || pathMatch) {
128
+ return identity;
129
+ }
130
+ }
131
+
132
+ // Default to builder if no clear match
133
+ return 'builder';
134
+ }
135
+
136
+ /**
137
+ * Generates insights about work patterns
138
+ */
139
+ function generateInsights(identities, totalCommits) {
140
+ const insights = [];
141
+
142
+ // Dominant identity
143
+ const dominant = Object.entries(identities)[0];
144
+ if (dominant) {
145
+ insights.push({
146
+ type: 'dominant',
147
+ message: `${capitalize(dominant[0])} is your dominant mode (${dominant[1].percentage}%)`,
148
+ identity: dominant[0]
149
+ });
150
+ }
151
+
152
+ // Balance score (how evenly distributed)
153
+ const percentages = Object.values(identities).map(i => i.percentage);
154
+ const idealPercentage = 100 / 6; // 16.67% if perfectly balanced
155
+ const balanceScore = 1 - (percentages.reduce((sum, p) => sum + Math.abs(p - idealPercentage), 0) / 100);
156
+
157
+ insights.push({
158
+ type: 'balance',
159
+ message: `Work balance score: ${(balanceScore * 100).toFixed(0)}%`,
160
+ score: balanceScore
161
+ });
162
+
163
+ // Underutilized identities
164
+ const underutilized = Object.entries(identities)
165
+ .filter(([_, data]) => data.percentage < 5)
166
+ .map(([identity]) => identity);
167
+
168
+ if (underutilized.length > 0) {
169
+ insights.push({
170
+ type: 'underutilized',
171
+ message: `Consider more ${underutilized.map(capitalize).join(', ')} time`,
172
+ identities: underutilized
173
+ });
174
+ }
175
+
176
+ // Productivity patterns
177
+ const highActivity = Object.entries(identities)
178
+ .filter(([_, data]) => data.commitsPerDay > 1)
179
+ .map(([identity]) => identity);
180
+
181
+ if (highActivity.length > 0) {
182
+ insights.push({
183
+ type: 'high-activity',
184
+ message: `High activity in ${highActivity.map(capitalize).join(', ')}`,
185
+ identities: highActivity
186
+ });
187
+ }
188
+
189
+ return insights;
190
+ }
191
+
192
+ function capitalize(str) {
193
+ return str.charAt(0).toUpperCase() + str.slice(1);
194
+ }
@@ -0,0 +1,63 @@
1
+ import { readFile, writeFile } from 'fs/promises';
2
+ import { join } from 'path';
3
+
4
+ const CONFIG_FILE = '.cognitive-workflow.json';
5
+
6
+ /**
7
+ * Configures terminal application mappings
8
+ *
9
+ * @param {Object} mappings - Terminal assignments per identity
10
+ * @returns {Promise<Object>} Configuration result
11
+ */
12
+ export async function configureTerminals(mappings) {
13
+ const configPath = join(process.cwd(), CONFIG_FILE);
14
+
15
+ let config = {};
16
+
17
+ // Load existing config if it exists
18
+ try {
19
+ const existing = await readFile(configPath, 'utf-8');
20
+ config = JSON.parse(existing);
21
+ } catch (error) {
22
+ // File doesn't exist, start fresh
23
+ }
24
+
25
+ // Update terminal mappings
26
+ config.terminals = {
27
+ ...config.terminals,
28
+ ...mappings
29
+ };
30
+
31
+ // Save config
32
+ await writeFile(configPath, JSON.stringify(config, null, 2));
33
+
34
+ return {
35
+ configured: true,
36
+ terminals: config.terminals,
37
+ configPath
38
+ };
39
+ }
40
+
41
+ /**
42
+ * Gets current terminal configuration
43
+ */
44
+ export async function getTerminalConfig() {
45
+ const configPath = join(process.cwd(), CONFIG_FILE);
46
+
47
+ try {
48
+ const config = await readFile(configPath, 'utf-8');
49
+ return JSON.parse(config);
50
+ } catch (error) {
51
+ // Return defaults
52
+ return {
53
+ terminals: {
54
+ builder: 'iTerm2',
55
+ discoverer: 'WezTerm',
56
+ operator: 'Kitty',
57
+ teacher: 'Terminal',
58
+ strategist: 'VSCode',
59
+ experimenter: 'Cursor'
60
+ }
61
+ };
62
+ }
63
+ }
@@ -0,0 +1,65 @@
1
+ import { mkdir, writeFile } from 'fs/promises';
2
+ import { join } from 'path';
3
+ import { exec } from 'child_process';
4
+ import { promisify } from 'util';
5
+ import { analyzeCommits } from './analyzer.js';
6
+ import { getDashboardTemplate, getRoomTemplate } from './templates.js';
7
+
8
+ const execAsync = promisify(exec);
9
+
10
+ /**
11
+ * Generates HTML dashboard and room pages
12
+ *
13
+ * @param {string} outputDir - Output directory path
14
+ * @param {boolean} openAfter - Whether to open dashboard after generation
15
+ * @returns {Promise<Object>} Generation results
16
+ */
17
+ export async function generateDashboard(outputDir = '.workflow', openAfter = true) {
18
+ // Ensure output directory exists
19
+ await mkdir(outputDir, { recursive: true });
20
+
21
+ // Analyze commits
22
+ const analysis = await analyzeCommits(60);
23
+
24
+ // Generate central dashboard
25
+ const dashboardHtml = getDashboardTemplate(analysis);
26
+ const dashboardPath = join(outputDir, 'cognitive-dashboard.html');
27
+ await writeFile(dashboardPath, dashboardHtml);
28
+
29
+ const filesCreated = [dashboardPath];
30
+
31
+ // Generate room pages for each identity
32
+ const identities = ['builder', 'discoverer', 'operator', 'teacher', 'strategist', 'experimenter'];
33
+
34
+ for (const identity of identities) {
35
+ const identityData = analysis.identities[identity];
36
+ const roomHtml = getRoomTemplate(identity, identityData, analysis.totalCommits);
37
+ const roomPath = join(outputDir, `bucket-${identity}.html`);
38
+ await writeFile(roomPath, roomHtml);
39
+ filesCreated.push(roomPath);
40
+ }
41
+
42
+ const result = {
43
+ filesCreated,
44
+ dashboardUrl: `file://${join(process.cwd(), dashboardPath)}`,
45
+ analysis: {
46
+ totalCommits: analysis.totalCommits,
47
+ identities: Object.keys(analysis.identities).map(id => ({
48
+ name: id,
49
+ commits: analysis.identities[id].commits,
50
+ percentage: analysis.identities[id].percentage
51
+ }))
52
+ }
53
+ };
54
+
55
+ // Open dashboard if requested
56
+ if (openAfter) {
57
+ try {
58
+ await execAsync(`open "${join(process.cwd(), dashboardPath)}"`);
59
+ } catch (error) {
60
+ console.error('Could not open dashboard automatically:', error.message);
61
+ }
62
+ }
63
+
64
+ return result;
65
+ }