projex-cli 0.2.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.
Files changed (85) hide show
  1. package/dist/cli.d.ts +6 -0
  2. package/dist/cli.d.ts.map +1 -0
  3. package/dist/cli.js +321 -0
  4. package/dist/cli.js.map +1 -0
  5. package/dist/event-bus.d.ts +35 -0
  6. package/dist/event-bus.d.ts.map +1 -0
  7. package/dist/event-bus.js +71 -0
  8. package/dist/event-bus.js.map +1 -0
  9. package/dist/events/event-bus.d.ts +35 -0
  10. package/dist/events/event-bus.d.ts.map +1 -0
  11. package/dist/events/event-bus.js +71 -0
  12. package/dist/events/event-bus.js.map +1 -0
  13. package/dist/events/index.d.ts +3 -0
  14. package/dist/events/index.d.ts.map +1 -0
  15. package/dist/events/index.js +3 -0
  16. package/dist/events/index.js.map +1 -0
  17. package/dist/events/types.d.ts +143 -0
  18. package/dist/events/types.d.ts.map +1 -0
  19. package/dist/events/types.js +6 -0
  20. package/dist/events/types.js.map +1 -0
  21. package/dist/index.d.ts +11 -0
  22. package/dist/index.d.ts.map +1 -0
  23. package/dist/index.js +12 -0
  24. package/dist/index.js.map +1 -0
  25. package/dist/inference/enricher.d.ts +18 -0
  26. package/dist/inference/enricher.d.ts.map +1 -0
  27. package/dist/inference/enricher.js +290 -0
  28. package/dist/inference/enricher.js.map +1 -0
  29. package/dist/inference/index.d.ts +5 -0
  30. package/dist/inference/index.d.ts.map +1 -0
  31. package/dist/inference/index.js +5 -0
  32. package/dist/inference/index.js.map +1 -0
  33. package/dist/inference/lifecycle-tracker.d.ts +40 -0
  34. package/dist/inference/lifecycle-tracker.d.ts.map +1 -0
  35. package/dist/inference/lifecycle-tracker.js +132 -0
  36. package/dist/inference/lifecycle-tracker.js.map +1 -0
  37. package/dist/inference/portfolio-generator.d.ts +44 -0
  38. package/dist/inference/portfolio-generator.d.ts.map +1 -0
  39. package/dist/inference/portfolio-generator.js +239 -0
  40. package/dist/inference/portfolio-generator.js.map +1 -0
  41. package/dist/inference/project-detector.d.ts +17 -0
  42. package/dist/inference/project-detector.d.ts.map +1 -0
  43. package/dist/inference/project-detector.js +127 -0
  44. package/dist/inference/project-detector.js.map +1 -0
  45. package/dist/ingestion/github-client.d.ts +56 -0
  46. package/dist/ingestion/github-client.d.ts.map +1 -0
  47. package/dist/ingestion/github-client.js +213 -0
  48. package/dist/ingestion/github-client.js.map +1 -0
  49. package/dist/ingestion/github-poller.d.ts +41 -0
  50. package/dist/ingestion/github-poller.d.ts.map +1 -0
  51. package/dist/ingestion/github-poller.js +121 -0
  52. package/dist/ingestion/github-poller.js.map +1 -0
  53. package/dist/ingestion/normalizer.d.ts +41 -0
  54. package/dist/ingestion/normalizer.d.ts.map +1 -0
  55. package/dist/ingestion/normalizer.js +173 -0
  56. package/dist/ingestion/normalizer.js.map +1 -0
  57. package/dist/integrations/analyzer.d.ts +74 -0
  58. package/dist/integrations/analyzer.d.ts.map +1 -0
  59. package/dist/integrations/analyzer.js +287 -0
  60. package/dist/integrations/analyzer.js.map +1 -0
  61. package/dist/integrations/index.d.ts +4 -0
  62. package/dist/integrations/index.d.ts.map +1 -0
  63. package/dist/integrations/index.js +5 -0
  64. package/dist/integrations/index.js.map +1 -0
  65. package/dist/integrations/injectors.d.ts +60 -0
  66. package/dist/integrations/injectors.d.ts.map +1 -0
  67. package/dist/integrations/injectors.js +361 -0
  68. package/dist/integrations/injectors.js.map +1 -0
  69. package/dist/integrations/template-generator.d.ts +45 -0
  70. package/dist/integrations/template-generator.d.ts.map +1 -0
  71. package/dist/integrations/template-generator.js +187 -0
  72. package/dist/integrations/template-generator.js.map +1 -0
  73. package/dist/storage/index.d.ts +2 -0
  74. package/dist/storage/index.d.ts.map +1 -0
  75. package/dist/storage/index.js +2 -0
  76. package/dist/storage/index.js.map +1 -0
  77. package/dist/storage/project-store.d.ts +23 -0
  78. package/dist/storage/project-store.d.ts.map +1 -0
  79. package/dist/storage/project-store.js +107 -0
  80. package/dist/storage/project-store.js.map +1 -0
  81. package/dist/types.d.ts +143 -0
  82. package/dist/types.d.ts.map +1 -0
  83. package/dist/types.js +6 -0
  84. package/dist/types.js.map +1 -0
  85. package/package.json +55 -0
package/dist/cli.d.ts ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Projex CLI - Interactive portfolio inference tool
4
+ */
5
+ export {};
6
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA;;GAEG"}
package/dist/cli.js ADDED
@@ -0,0 +1,321 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Projex CLI - Interactive portfolio inference tool
4
+ */
5
+ import { Command } from 'commander';
6
+ import chalk from 'chalk';
7
+ import ora from 'ora';
8
+ import inquirer from 'inquirer';
9
+ import { existsSync, mkdirSync, writeFileSync, readFileSync } from 'fs';
10
+ import { join } from 'path';
11
+ import { homedir } from 'os';
12
+ import { getEventBus } from './events/event-bus.js';
13
+ import { GitHubPoller } from './ingestion/github-poller.js';
14
+ import { ProjectStore } from './storage/project-store.js';
15
+ import { ProjectDetector } from './inference/project-detector.js';
16
+ import { Enricher } from './inference/enricher.js';
17
+ import { LifecycleTracker } from './inference/lifecycle-tracker.js';
18
+ import { PortfolioGenerator } from './inference/portfolio-generator.js';
19
+ import { DesignAnalyzer } from './integrations/analyzer.js';
20
+ import { TemplateGenerator } from './integrations/template-generator.js';
21
+ import { createInjector } from './integrations/injectors.js';
22
+ const CONFIG_DIR = join(homedir(), '.projex');
23
+ const CONFIG_FILE = join(CONFIG_DIR, 'config.json');
24
+ const program = new Command();
25
+ program
26
+ .name('projex')
27
+ .description('Automatically infer projects from GitHub and generate portfolio entries')
28
+ .version('0.2.0');
29
+ // ============================================================================
30
+ // Setup command
31
+ // ============================================================================
32
+ program
33
+ .command('setup')
34
+ .description('Interactive setup wizard')
35
+ .action(async () => {
36
+ console.log(chalk.cyan.bold('\n🚀 Projex Setup\n'));
37
+ const answers = await inquirer.prompt([
38
+ {
39
+ type: 'input',
40
+ name: 'username',
41
+ message: 'GitHub username:',
42
+ validate: (input) => input.length > 0 || 'Username is required',
43
+ },
44
+ {
45
+ type: 'password',
46
+ name: 'token',
47
+ message: 'GitHub personal access token:',
48
+ validate: (input) => input.startsWith('ghp_') || input.startsWith('github_pat_') || 'Token should start with ghp_ or github_pat_',
49
+ },
50
+ {
51
+ type: 'input',
52
+ name: 'portfolioPath',
53
+ message: 'Path to your portfolio folder:',
54
+ validate: (input) => existsSync(input) || 'Path does not exist',
55
+ },
56
+ {
57
+ type: 'confirm',
58
+ name: 'autoCommit',
59
+ message: 'Auto-commit changes to git?',
60
+ default: false,
61
+ },
62
+ {
63
+ type: 'number',
64
+ name: 'pollingInterval',
65
+ message: 'Polling interval (minutes):',
66
+ default: 60,
67
+ },
68
+ ]);
69
+ const config = {
70
+ github: {
71
+ token: answers.token,
72
+ username: answers.username,
73
+ pollingIntervalMinutes: answers.pollingInterval,
74
+ },
75
+ inference: {
76
+ completionThresholdDays: 90,
77
+ minCommitsForCompletion: 10,
78
+ },
79
+ storage: {
80
+ dataDir: CONFIG_DIR,
81
+ },
82
+ };
83
+ // Save config
84
+ if (!existsSync(CONFIG_DIR)) {
85
+ mkdirSync(CONFIG_DIR, { recursive: true });
86
+ }
87
+ const configWithPortfolio = {
88
+ ...config,
89
+ portfolio: {
90
+ path: answers.portfolioPath,
91
+ autoCommit: answers.autoCommit,
92
+ },
93
+ };
94
+ writeFileSync(CONFIG_FILE, JSON.stringify(configWithPortfolio, null, 2));
95
+ console.log(chalk.green('\n✅ Configuration saved to ~/.projex/config.json'));
96
+ console.log(chalk.dim('Run `projex scan` to detect your projects.\n'));
97
+ });
98
+ // ============================================================================
99
+ // Scan command
100
+ // ============================================================================
101
+ program
102
+ .command('scan')
103
+ .description('Scan GitHub for projects')
104
+ .action(async () => {
105
+ const config = loadConfig();
106
+ if (!config)
107
+ return;
108
+ const spinner = ora('Connecting to GitHub...').start();
109
+ try {
110
+ const { store, poller, lifecycleTracker, portfolioGenerator } = initializeEngine(config);
111
+ spinner.text = 'Fetching repositories...';
112
+ const events = await poller.poll();
113
+ spinner.text = 'Checking for completed projects...';
114
+ const completed = lifecycleTracker.checkForCompletedProjects();
115
+ spinner.text = 'Generating portfolio drafts...';
116
+ const drafts = portfolioGenerator.generatePendingDrafts();
117
+ spinner.succeed('Scan complete!');
118
+ const projects = store.getAllProjects();
119
+ console.log(chalk.dim(`\nFound ${projects.length} projects:\n`));
120
+ for (const project of projects) {
121
+ const statusIcon = getStatusIcon(project.status);
122
+ const tech = project.techStack.slice(0, 3).map(t => t.name).join(', ');
123
+ console.log(` ${statusIcon} ${chalk.bold(project.displayName)}`);
124
+ console.log(chalk.dim(` ${project.id}`));
125
+ if (tech)
126
+ console.log(chalk.cyan(` ${tech}`));
127
+ console.log('');
128
+ }
129
+ if (drafts.length > 0) {
130
+ console.log(chalk.yellow(`\n📝 ${drafts.length} new portfolio drafts ready for review.`));
131
+ console.log(chalk.dim('Run `projex drafts` to see them.\n'));
132
+ }
133
+ }
134
+ catch (error) {
135
+ spinner.fail('Scan failed');
136
+ console.error(chalk.red(error));
137
+ }
138
+ });
139
+ // ============================================================================
140
+ // Drafts command
141
+ // ============================================================================
142
+ program
143
+ .command('drafts')
144
+ .description('List pending portfolio drafts')
145
+ .action(async () => {
146
+ const config = loadConfig();
147
+ if (!config)
148
+ return;
149
+ const store = new ProjectStore(config);
150
+ const projects = store.getProjectsNeedingReview();
151
+ if (projects.length === 0) {
152
+ console.log(chalk.dim('\nNo drafts pending review.'));
153
+ console.log(chalk.dim('Run `projex scan` to detect projects.\n'));
154
+ return;
155
+ }
156
+ console.log(chalk.cyan.bold(`\n📝 ${projects.length} Drafts Pending Review\n`));
157
+ for (const project of projects) {
158
+ const draft = project.portfolioDraft;
159
+ if (!draft)
160
+ continue;
161
+ console.log(chalk.bold(draft.title));
162
+ console.log(chalk.dim(` ${draft.tagline}`));
163
+ console.log(` ${draft.description.slice(0, 100)}...`);
164
+ console.log(chalk.cyan(` Tech: ${draft.techStack.join(', ')}`));
165
+ console.log(chalk.dim(` ID: ${project.id}\n`));
166
+ }
167
+ console.log(chalk.dim('Use `projex approve <id>` to approve a draft.\n'));
168
+ });
169
+ // ============================================================================
170
+ // Approve command
171
+ // ============================================================================
172
+ program
173
+ .command('approve <projectId>')
174
+ .description('Approve a portfolio draft and inject into portfolio')
175
+ .action(async (projectId) => {
176
+ const config = loadConfig();
177
+ if (!config)
178
+ return;
179
+ const spinner = ora('Loading project...').start();
180
+ try {
181
+ const store = new ProjectStore(config);
182
+ const project = store.getProject(projectId);
183
+ if (!project) {
184
+ spinner.fail(`Project not found: ${projectId}`);
185
+ return;
186
+ }
187
+ if (!project.portfolioDraft) {
188
+ spinner.fail('This project has no draft to approve');
189
+ return;
190
+ }
191
+ // Analyze portfolio
192
+ spinner.text = 'Analyzing portfolio design...';
193
+ const portfolioPath = config.portfolio?.path;
194
+ if (!portfolioPath) {
195
+ spinner.fail('No portfolio path configured. Run `projex setup` first.');
196
+ return;
197
+ }
198
+ const analyzer = new DesignAnalyzer(portfolioPath);
199
+ const analysis = await analyzer.analyze();
200
+ // Generate card
201
+ spinner.text = 'Generating project card...';
202
+ const generator = new TemplateGenerator(analysis);
203
+ const card = generator.generate(project);
204
+ // Inject into portfolio
205
+ spinner.text = 'Injecting into portfolio...';
206
+ const injector = createInjector(portfolioPath, analysis, {
207
+ autoCommit: config.portfolio?.autoCommit ?? false,
208
+ createBackup: true,
209
+ });
210
+ const result = await injector.inject(card, projectId);
211
+ if (result.success) {
212
+ // Mark as approved
213
+ const portfolioGenerator = new PortfolioGenerator(store);
214
+ portfolioGenerator.approveDraft(projectId);
215
+ spinner.succeed('Project approved and added to portfolio!');
216
+ console.log(chalk.dim(` File: ${result.file}`));
217
+ if (result.backup) {
218
+ console.log(chalk.dim(` Backup: ${result.backup}`));
219
+ }
220
+ }
221
+ else {
222
+ spinner.fail(`Injection failed: ${result.message}`);
223
+ }
224
+ }
225
+ catch (error) {
226
+ spinner.fail('Approval failed');
227
+ console.error(chalk.red(error));
228
+ }
229
+ });
230
+ // ============================================================================
231
+ // List command
232
+ // ============================================================================
233
+ program
234
+ .command('list')
235
+ .description('List all detected projects')
236
+ .action(async () => {
237
+ const config = loadConfig();
238
+ if (!config)
239
+ return;
240
+ const store = new ProjectStore(config);
241
+ const projects = store.getAllProjects();
242
+ if (projects.length === 0) {
243
+ console.log(chalk.dim('\nNo projects found. Run `projex scan` first.\n'));
244
+ return;
245
+ }
246
+ console.log(chalk.cyan.bold(`\n📦 ${projects.length} Projects\n`));
247
+ const grouped = {
248
+ ACTIVE: projects.filter(p => p.status === 'ACTIVE'),
249
+ LIKELY_COMPLETED: projects.filter(p => p.status === 'LIKELY_COMPLETED'),
250
+ COMPLETED: projects.filter(p => p.status === 'COMPLETED'),
251
+ ARCHIVED: projects.filter(p => p.status === 'ARCHIVED'),
252
+ };
253
+ for (const [status, group] of Object.entries(grouped)) {
254
+ if (group.length === 0)
255
+ continue;
256
+ console.log(chalk.bold(`${getStatusIcon(status)} ${status} (${group.length})`));
257
+ for (const p of group) {
258
+ console.log(chalk.dim(` - ${p.displayName}`));
259
+ }
260
+ console.log('');
261
+ }
262
+ });
263
+ // ============================================================================
264
+ // Export command
265
+ // ============================================================================
266
+ program
267
+ .command('export')
268
+ .description('Export approved portfolios as JSON')
269
+ .option('-o, --output <file>', 'Output file', 'portfolios.json')
270
+ .action(async (options) => {
271
+ const config = loadConfig();
272
+ if (!config)
273
+ return;
274
+ const store = new ProjectStore(config);
275
+ const portfolioGenerator = new PortfolioGenerator(store);
276
+ const approved = store.getApprovedPortfolios();
277
+ const entries = approved
278
+ .map(p => portfolioGenerator.getFinalPortfolioEntry(p.id))
279
+ .filter(Boolean);
280
+ writeFileSync(options.output, JSON.stringify(entries, null, 2));
281
+ console.log(chalk.green(`\n✅ Exported ${entries.length} entries to ${options.output}\n`));
282
+ });
283
+ // ============================================================================
284
+ // Helpers
285
+ // ============================================================================
286
+ function loadConfig() {
287
+ if (!existsSync(CONFIG_FILE)) {
288
+ console.log(chalk.yellow('\n⚠️ Not configured. Run `projex setup` first.\n'));
289
+ return null;
290
+ }
291
+ try {
292
+ const content = readFileSync(CONFIG_FILE, 'utf-8');
293
+ return JSON.parse(content);
294
+ }
295
+ catch (error) {
296
+ console.error(chalk.red('Failed to load config:'), error);
297
+ return null;
298
+ }
299
+ }
300
+ function initializeEngine(config) {
301
+ const eventBus = getEventBus();
302
+ const store = new ProjectStore(config);
303
+ const poller = new GitHubPoller(config, eventBus);
304
+ const detector = new ProjectDetector(store, eventBus);
305
+ const enricher = new Enricher(store, eventBus);
306
+ const lifecycleTracker = new LifecycleTracker(store, eventBus, config);
307
+ const portfolioGenerator = new PortfolioGenerator(store);
308
+ return { store, poller, detector, enricher, lifecycleTracker, portfolioGenerator };
309
+ }
310
+ function getStatusIcon(status) {
311
+ const icons = {
312
+ ACTIVE: '🔵',
313
+ LIKELY_COMPLETED: '🟡',
314
+ COMPLETED: '🟢',
315
+ ARCHIVED: '📦',
316
+ IGNORED: '⚫',
317
+ };
318
+ return icons[status] || '❓';
319
+ }
320
+ program.parse();
321
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Simple in-memory event bus with pub/sub pattern.
3
+ * Events are processed synchronously in subscription order.
4
+ */
5
+ import type { SignalEvent, EventType } from './types.js';
6
+ type EventHandler<T extends SignalEvent = SignalEvent> = (event: T) => void | Promise<void>;
7
+ export declare class EventBus {
8
+ private subscriptions;
9
+ private eventLog;
10
+ private subscriptionIdCounter;
11
+ /**
12
+ * Subscribe to specific event types or all events ('*')
13
+ */
14
+ subscribe(eventTypes: EventType[] | '*', handler: EventHandler): () => void;
15
+ /**
16
+ * Publish an event to all matching subscribers
17
+ */
18
+ publish(event: SignalEvent): Promise<void>;
19
+ /**
20
+ * Get event history (useful for debugging/replay)
21
+ */
22
+ getEventLog(): readonly SignalEvent[];
23
+ /**
24
+ * Clear event log (for testing)
25
+ */
26
+ clearLog(): void;
27
+ /**
28
+ * Get subscription count (for diagnostics)
29
+ */
30
+ getSubscriptionCount(): number;
31
+ }
32
+ export declare function getEventBus(): EventBus;
33
+ export declare function resetEventBus(): void;
34
+ export {};
35
+ //# sourceMappingURL=event-bus.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-bus.d.ts","sourceRoot":"","sources":["../src/event-bus.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAEzD,KAAK,YAAY,CAAC,CAAC,SAAS,WAAW,GAAG,WAAW,IAAI,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAQ5F,qBAAa,QAAQ;IACjB,OAAO,CAAC,aAAa,CAAsB;IAC3C,OAAO,CAAC,QAAQ,CAAqB;IACrC,OAAO,CAAC,qBAAqB,CAAK;IAElC;;OAEG;IACH,SAAS,CACL,UAAU,EAAE,SAAS,EAAE,GAAG,GAAG,EAC7B,OAAO,EAAE,YAAY,GACtB,MAAM,IAAI;IAWb;;OAEG;IACG,OAAO,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAkBhD;;OAEG;IACH,WAAW,IAAI,SAAS,WAAW,EAAE;IAIrC;;OAEG;IACH,QAAQ,IAAI,IAAI;IAIhB;;OAEG;IACH,oBAAoB,IAAI,MAAM;CAGjC;AAKD,wBAAgB,WAAW,IAAI,QAAQ,CAKtC;AAED,wBAAgB,aAAa,IAAI,IAAI,CAEpC"}
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Simple in-memory event bus with pub/sub pattern.
3
+ * Events are processed synchronously in subscription order.
4
+ */
5
+ export class EventBus {
6
+ subscriptions = [];
7
+ eventLog = [];
8
+ subscriptionIdCounter = 0;
9
+ /**
10
+ * Subscribe to specific event types or all events ('*')
11
+ */
12
+ subscribe(eventTypes, handler) {
13
+ const id = `sub_${++this.subscriptionIdCounter}`;
14
+ const subscription = { id, eventTypes, handler };
15
+ this.subscriptions.push(subscription);
16
+ // Return unsubscribe function
17
+ return () => {
18
+ this.subscriptions = this.subscriptions.filter(s => s.id !== id);
19
+ };
20
+ }
21
+ /**
22
+ * Publish an event to all matching subscribers
23
+ */
24
+ async publish(event) {
25
+ this.eventLog.push(event);
26
+ const matchingSubscriptions = this.subscriptions.filter(sub => {
27
+ if (sub.eventTypes === '*')
28
+ return true;
29
+ return sub.eventTypes.includes(event.eventType);
30
+ });
31
+ // Process handlers sequentially to maintain order
32
+ for (const sub of matchingSubscriptions) {
33
+ try {
34
+ await sub.handler(event);
35
+ }
36
+ catch (error) {
37
+ console.error(`[EventBus] Error in handler for ${event.eventType}:`, error);
38
+ }
39
+ }
40
+ }
41
+ /**
42
+ * Get event history (useful for debugging/replay)
43
+ */
44
+ getEventLog() {
45
+ return this.eventLog;
46
+ }
47
+ /**
48
+ * Clear event log (for testing)
49
+ */
50
+ clearLog() {
51
+ this.eventLog = [];
52
+ }
53
+ /**
54
+ * Get subscription count (for diagnostics)
55
+ */
56
+ getSubscriptionCount() {
57
+ return this.subscriptions.length;
58
+ }
59
+ }
60
+ // Singleton instance for the application
61
+ let globalEventBus = null;
62
+ export function getEventBus() {
63
+ if (!globalEventBus) {
64
+ globalEventBus = new EventBus();
65
+ }
66
+ return globalEventBus;
67
+ }
68
+ export function resetEventBus() {
69
+ globalEventBus = null;
70
+ }
71
+ //# sourceMappingURL=event-bus.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-bus.js","sourceRoot":"","sources":["../src/event-bus.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAYH,MAAM,OAAO,QAAQ;IACT,aAAa,GAAmB,EAAE,CAAC;IACnC,QAAQ,GAAkB,EAAE,CAAC;IAC7B,qBAAqB,GAAG,CAAC,CAAC;IAElC;;OAEG;IACH,SAAS,CACL,UAA6B,EAC7B,OAAqB;QAErB,MAAM,EAAE,GAAG,OAAO,EAAE,IAAI,CAAC,qBAAqB,EAAE,CAAC;QACjD,MAAM,YAAY,GAAiB,EAAE,EAAE,EAAE,UAAU,EAAE,OAAO,EAAE,CAAC;QAC/D,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QAEtC,8BAA8B;QAC9B,OAAO,GAAG,EAAE;YACR,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;QACrE,CAAC,CAAC;IACN,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,OAAO,CAAC,KAAkB;QAC5B,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAE1B,MAAM,qBAAqB,GAAG,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE;YAC1D,IAAI,GAAG,CAAC,UAAU,KAAK,GAAG;gBAAE,OAAO,IAAI,CAAC;YACxC,OAAO,GAAG,CAAC,UAAU,CAAC,QAAQ,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;QACpD,CAAC,CAAC,CAAC;QAEH,kDAAkD;QAClD,KAAK,MAAM,GAAG,IAAI,qBAAqB,EAAE,CAAC;YACtC,IAAI,CAAC;gBACD,MAAM,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;YAC7B,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACb,OAAO,CAAC,KAAK,CAAC,mCAAmC,KAAK,CAAC,SAAS,GAAG,EAAE,KAAK,CAAC,CAAC;YAChF,CAAC;QACL,CAAC;IACL,CAAC;IAED;;OAEG;IACH,WAAW;QACP,OAAO,IAAI,CAAC,QAAQ,CAAC;IACzB,CAAC;IAED;;OAEG;IACH,QAAQ;QACJ,IAAI,CAAC,QAAQ,GAAG,EAAE,CAAC;IACvB,CAAC;IAED;;OAEG;IACH,oBAAoB;QAChB,OAAO,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC;IACrC,CAAC;CACJ;AAED,yCAAyC;AACzC,IAAI,cAAc,GAAoB,IAAI,CAAC;AAE3C,MAAM,UAAU,WAAW;IACvB,IAAI,CAAC,cAAc,EAAE,CAAC;QAClB,cAAc,GAAG,IAAI,QAAQ,EAAE,CAAC;IACpC,CAAC;IACD,OAAO,cAAc,CAAC;AAC1B,CAAC;AAED,MAAM,UAAU,aAAa;IACzB,cAAc,GAAG,IAAI,CAAC;AAC1B,CAAC"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Simple in-memory event bus with pub/sub pattern.
3
+ * Events are processed synchronously in subscription order.
4
+ */
5
+ import type { SignalEvent, EventType } from './types.js';
6
+ type EventHandler<T extends SignalEvent = SignalEvent> = (event: T) => void | Promise<void>;
7
+ export declare class EventBus {
8
+ private subscriptions;
9
+ private eventLog;
10
+ private subscriptionIdCounter;
11
+ /**
12
+ * Subscribe to specific event types or all events ('*')
13
+ */
14
+ subscribe(eventTypes: EventType[] | '*', handler: EventHandler): () => void;
15
+ /**
16
+ * Publish an event to all matching subscribers
17
+ */
18
+ publish(event: SignalEvent): Promise<void>;
19
+ /**
20
+ * Get event history (useful for debugging/replay)
21
+ */
22
+ getEventLog(): readonly SignalEvent[];
23
+ /**
24
+ * Clear event log (for testing)
25
+ */
26
+ clearLog(): void;
27
+ /**
28
+ * Get subscription count (for diagnostics)
29
+ */
30
+ getSubscriptionCount(): number;
31
+ }
32
+ export declare function getEventBus(): EventBus;
33
+ export declare function resetEventBus(): void;
34
+ export {};
35
+ //# sourceMappingURL=event-bus.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-bus.d.ts","sourceRoot":"","sources":["../../src/events/event-bus.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAEzD,KAAK,YAAY,CAAC,CAAC,SAAS,WAAW,GAAG,WAAW,IAAI,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAQ5F,qBAAa,QAAQ;IACjB,OAAO,CAAC,aAAa,CAAsB;IAC3C,OAAO,CAAC,QAAQ,CAAqB;IACrC,OAAO,CAAC,qBAAqB,CAAK;IAElC;;OAEG;IACH,SAAS,CACL,UAAU,EAAE,SAAS,EAAE,GAAG,GAAG,EAC7B,OAAO,EAAE,YAAY,GACtB,MAAM,IAAI;IAWb;;OAEG;IACG,OAAO,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAkBhD;;OAEG;IACH,WAAW,IAAI,SAAS,WAAW,EAAE;IAIrC;;OAEG;IACH,QAAQ,IAAI,IAAI;IAIhB;;OAEG;IACH,oBAAoB,IAAI,MAAM;CAGjC;AAKD,wBAAgB,WAAW,IAAI,QAAQ,CAKtC;AAED,wBAAgB,aAAa,IAAI,IAAI,CAEpC"}
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Simple in-memory event bus with pub/sub pattern.
3
+ * Events are processed synchronously in subscription order.
4
+ */
5
+ export class EventBus {
6
+ subscriptions = [];
7
+ eventLog = [];
8
+ subscriptionIdCounter = 0;
9
+ /**
10
+ * Subscribe to specific event types or all events ('*')
11
+ */
12
+ subscribe(eventTypes, handler) {
13
+ const id = `sub_${++this.subscriptionIdCounter}`;
14
+ const subscription = { id, eventTypes, handler };
15
+ this.subscriptions.push(subscription);
16
+ // Return unsubscribe function
17
+ return () => {
18
+ this.subscriptions = this.subscriptions.filter(s => s.id !== id);
19
+ };
20
+ }
21
+ /**
22
+ * Publish an event to all matching subscribers
23
+ */
24
+ async publish(event) {
25
+ this.eventLog.push(event);
26
+ const matchingSubscriptions = this.subscriptions.filter(sub => {
27
+ if (sub.eventTypes === '*')
28
+ return true;
29
+ return sub.eventTypes.includes(event.eventType);
30
+ });
31
+ // Process handlers sequentially to maintain order
32
+ for (const sub of matchingSubscriptions) {
33
+ try {
34
+ await sub.handler(event);
35
+ }
36
+ catch (error) {
37
+ console.error(`[EventBus] Error in handler for ${event.eventType}:`, error);
38
+ }
39
+ }
40
+ }
41
+ /**
42
+ * Get event history (useful for debugging/replay)
43
+ */
44
+ getEventLog() {
45
+ return this.eventLog;
46
+ }
47
+ /**
48
+ * Clear event log (for testing)
49
+ */
50
+ clearLog() {
51
+ this.eventLog = [];
52
+ }
53
+ /**
54
+ * Get subscription count (for diagnostics)
55
+ */
56
+ getSubscriptionCount() {
57
+ return this.subscriptions.length;
58
+ }
59
+ }
60
+ // Singleton instance for the application
61
+ let globalEventBus = null;
62
+ export function getEventBus() {
63
+ if (!globalEventBus) {
64
+ globalEventBus = new EventBus();
65
+ }
66
+ return globalEventBus;
67
+ }
68
+ export function resetEventBus() {
69
+ globalEventBus = null;
70
+ }
71
+ //# sourceMappingURL=event-bus.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-bus.js","sourceRoot":"","sources":["../../src/events/event-bus.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAYH,MAAM,OAAO,QAAQ;IACT,aAAa,GAAmB,EAAE,CAAC;IACnC,QAAQ,GAAkB,EAAE,CAAC;IAC7B,qBAAqB,GAAG,CAAC,CAAC;IAElC;;OAEG;IACH,SAAS,CACL,UAA6B,EAC7B,OAAqB;QAErB,MAAM,EAAE,GAAG,OAAO,EAAE,IAAI,CAAC,qBAAqB,EAAE,CAAC;QACjD,MAAM,YAAY,GAAiB,EAAE,EAAE,EAAE,UAAU,EAAE,OAAO,EAAE,CAAC;QAC/D,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QAEtC,8BAA8B;QAC9B,OAAO,GAAG,EAAE;YACR,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;QACrE,CAAC,CAAC;IACN,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,OAAO,CAAC,KAAkB;QAC5B,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAE1B,MAAM,qBAAqB,GAAG,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE;YAC1D,IAAI,GAAG,CAAC,UAAU,KAAK,GAAG;gBAAE,OAAO,IAAI,CAAC;YACxC,OAAO,GAAG,CAAC,UAAU,CAAC,QAAQ,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;QACpD,CAAC,CAAC,CAAC;QAEH,kDAAkD;QAClD,KAAK,MAAM,GAAG,IAAI,qBAAqB,EAAE,CAAC;YACtC,IAAI,CAAC;gBACD,MAAM,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;YAC7B,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACb,OAAO,CAAC,KAAK,CAAC,mCAAmC,KAAK,CAAC,SAAS,GAAG,EAAE,KAAK,CAAC,CAAC;YAChF,CAAC;QACL,CAAC;IACL,CAAC;IAED;;OAEG;IACH,WAAW;QACP,OAAO,IAAI,CAAC,QAAQ,CAAC;IACzB,CAAC;IAED;;OAEG;IACH,QAAQ;QACJ,IAAI,CAAC,QAAQ,GAAG,EAAE,CAAC;IACvB,CAAC;IAED;;OAEG;IACH,oBAAoB;QAChB,OAAO,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC;IACrC,CAAC;CACJ;AAED,yCAAyC;AACzC,IAAI,cAAc,GAAoB,IAAI,CAAC;AAE3C,MAAM,UAAU,WAAW;IACvB,IAAI,CAAC,cAAc,EAAE,CAAC;QAClB,cAAc,GAAG,IAAI,QAAQ,EAAE,CAAC;IACpC,CAAC;IACD,OAAO,cAAc,CAAC;AAC1B,CAAC;AAED,MAAM,UAAU,aAAa;IACzB,cAAc,GAAG,IAAI,CAAC;AAC1B,CAAC"}
@@ -0,0 +1,3 @@
1
+ export * from './types.js';
2
+ export * from './event-bus.js';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/events/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,gBAAgB,CAAC"}
@@ -0,0 +1,3 @@
1
+ export * from './types.js';
2
+ export * from './event-bus.js';
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/events/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,gBAAgB,CAAC"}