work-chronicler 0.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.
Files changed (112) hide show
  1. package/README.md +432 -0
  2. package/bin/mcp.js +6 -0
  3. package/bin/work-chronicler.js +3 -0
  4. package/dist/cli/analyzer/classifier.d.ts +31 -0
  5. package/dist/cli/analyzer/classifier.d.ts.map +1 -0
  6. package/dist/cli/analyzer/classifier.js +171 -0
  7. package/dist/cli/analyzer/index.d.ts +5 -0
  8. package/dist/cli/analyzer/index.d.ts.map +1 -0
  9. package/dist/cli/analyzer/index.js +4 -0
  10. package/dist/cli/analyzer/projects.d.ts +10 -0
  11. package/dist/cli/analyzer/projects.d.ts.map +1 -0
  12. package/dist/cli/analyzer/projects.js +228 -0
  13. package/dist/cli/analyzer/stats.d.ts +30 -0
  14. package/dist/cli/analyzer/stats.d.ts.map +1 -0
  15. package/dist/cli/analyzer/stats.js +80 -0
  16. package/dist/cli/analyzer/timeline.d.ts +6 -0
  17. package/dist/cli/analyzer/timeline.d.ts.map +1 -0
  18. package/dist/cli/analyzer/timeline.js +224 -0
  19. package/dist/cli/commands/analyze.d.ts +3 -0
  20. package/dist/cli/commands/analyze.d.ts.map +1 -0
  21. package/dist/cli/commands/analyze.js +216 -0
  22. package/dist/cli/commands/fetch/all.d.ts +3 -0
  23. package/dist/cli/commands/fetch/all.d.ts.map +1 -0
  24. package/dist/cli/commands/fetch/all.js +91 -0
  25. package/dist/cli/commands/fetch/github.d.ts +3 -0
  26. package/dist/cli/commands/fetch/github.d.ts.map +1 -0
  27. package/dist/cli/commands/fetch/github.js +39 -0
  28. package/dist/cli/commands/fetch/jira.d.ts +3 -0
  29. package/dist/cli/commands/fetch/jira.d.ts.map +1 -0
  30. package/dist/cli/commands/fetch/jira.js +39 -0
  31. package/dist/cli/commands/filter.d.ts +3 -0
  32. package/dist/cli/commands/filter.d.ts.map +1 -0
  33. package/dist/cli/commands/filter.js +247 -0
  34. package/dist/cli/commands/init.d.ts +3 -0
  35. package/dist/cli/commands/init.d.ts.map +1 -0
  36. package/dist/cli/commands/init.js +47 -0
  37. package/dist/cli/commands/link.d.ts +3 -0
  38. package/dist/cli/commands/link.d.ts.map +1 -0
  39. package/dist/cli/commands/link.js +25 -0
  40. package/dist/cli/commands/mcp.d.ts +3 -0
  41. package/dist/cli/commands/mcp.d.ts.map +1 -0
  42. package/dist/cli/commands/mcp.js +43 -0
  43. package/dist/cli/commands/status.d.ts +3 -0
  44. package/dist/cli/commands/status.d.ts.map +1 -0
  45. package/dist/cli/commands/status.js +28 -0
  46. package/dist/cli/fetchers/github.d.ts +20 -0
  47. package/dist/cli/fetchers/github.d.ts.map +1 -0
  48. package/dist/cli/fetchers/github.js +345 -0
  49. package/dist/cli/fetchers/jira.d.ts +20 -0
  50. package/dist/cli/fetchers/jira.d.ts.map +1 -0
  51. package/dist/cli/fetchers/jira.js +268 -0
  52. package/dist/cli/index.d.ts +3 -0
  53. package/dist/cli/index.d.ts.map +1 -0
  54. package/dist/cli/index.js +43 -0
  55. package/dist/cli/linker/index.d.ts +17 -0
  56. package/dist/cli/linker/index.d.ts.map +1 -0
  57. package/dist/cli/linker/index.js +129 -0
  58. package/dist/cli/prompts/index.d.ts +61 -0
  59. package/dist/cli/prompts/index.d.ts.map +1 -0
  60. package/dist/cli/prompts/index.js +258 -0
  61. package/dist/core/config/loader.d.ts +61 -0
  62. package/dist/core/config/loader.d.ts.map +1 -0
  63. package/dist/core/config/loader.js +146 -0
  64. package/dist/core/config/schema.d.ts +587 -0
  65. package/dist/core/config/schema.d.ts.map +1 -0
  66. package/dist/core/config/schema.js +95 -0
  67. package/dist/core/index.d.ts +5 -0
  68. package/dist/core/index.d.ts.map +1 -0
  69. package/dist/core/index.js +7 -0
  70. package/dist/core/storage/index.d.ts +4 -0
  71. package/dist/core/storage/index.d.ts.map +1 -0
  72. package/dist/core/storage/index.js +3 -0
  73. package/dist/core/storage/paths.d.ts +85 -0
  74. package/dist/core/storage/paths.d.ts.map +1 -0
  75. package/dist/core/storage/paths.js +110 -0
  76. package/dist/core/storage/reader.d.ts +69 -0
  77. package/dist/core/storage/reader.d.ts.map +1 -0
  78. package/dist/core/storage/reader.js +181 -0
  79. package/dist/core/storage/writer.d.ts +41 -0
  80. package/dist/core/storage/writer.d.ts.map +1 -0
  81. package/dist/core/storage/writer.js +50 -0
  82. package/dist/core/types/index.d.ts +5 -0
  83. package/dist/core/types/index.d.ts.map +1 -0
  84. package/dist/core/types/index.js +4 -0
  85. package/dist/core/types/pr.d.ts +75 -0
  86. package/dist/core/types/pr.d.ts.map +1 -0
  87. package/dist/core/types/pr.js +35 -0
  88. package/dist/core/types/project.d.ts +450 -0
  89. package/dist/core/types/project.d.ts.map +1 -0
  90. package/dist/core/types/project.js +75 -0
  91. package/dist/core/types/ticket.d.ts +51 -0
  92. package/dist/core/types/ticket.d.ts.map +1 -0
  93. package/dist/core/types/ticket.js +17 -0
  94. package/dist/core/types/timeline.d.ts +1177 -0
  95. package/dist/core/types/timeline.d.ts.map +1 -0
  96. package/dist/core/types/timeline.js +100 -0
  97. package/dist/mcp/index.d.ts +15 -0
  98. package/dist/mcp/index.d.ts.map +1 -0
  99. package/dist/mcp/index.js +26 -0
  100. package/dist/mcp/server.d.ts +22 -0
  101. package/dist/mcp/server.d.ts.map +1 -0
  102. package/dist/mcp/server.js +584 -0
  103. package/dist/mcp/tools/get-stats.d.ts +26 -0
  104. package/dist/mcp/tools/get-stats.d.ts.map +1 -0
  105. package/dist/mcp/tools/get-stats.js +64 -0
  106. package/dist/mcp/tools/search-prs.d.ts +18 -0
  107. package/dist/mcp/tools/search-prs.d.ts.map +1 -0
  108. package/dist/mcp/tools/search-prs.js +44 -0
  109. package/dist/mcp/tools/search-tickets.d.ts +19 -0
  110. package/dist/mcp/tools/search-tickets.d.ts.map +1 -0
  111. package/dist/mcp/tools/search-tickets.js +49 -0
  112. package/package.json +79 -0
package/README.md ADDED
@@ -0,0 +1,432 @@
1
+ # work-chronicler
2
+
3
+ Gather, analyze, and summarize your work history from GitHub PRs, JIRA tickets and other documents for performance reviews, resumes or self-evaluation.
4
+
5
+ ## The Problem
6
+
7
+ Performance review time rolls around and you need to:
8
+ - Remember everything you accomplished in the past year
9
+ - Write compelling bullet points for your self-review
10
+ - Update your resume with recent achievements
11
+
12
+ But you didn't take notes, and now you're scrolling through months of PRs trying to piece together what you did.
13
+
14
+ ## The Solution
15
+
16
+ `work-chronicler` fetches your PR descriptions and JIRA tickets, stores them locally as searchable markdown files, and provides AI-ready tooling to analyze and summarize your work.
17
+
18
+ ## Quick Start
19
+
20
+ ### Local Development (this repo)
21
+
22
+ Use `pnpm cli` instead of `work-chronicler`:
23
+
24
+ ```bash
25
+ pnpm install
26
+ pnpm cli init
27
+ pnpm cli fetch:all
28
+ ```
29
+
30
+ ### Published Package Usage
31
+
32
+ After the package is published to npm:
33
+
34
+ ```bash
35
+ # Install globally
36
+ npm install -g work-chronicler
37
+
38
+ # Create a dedicated directory for your work history
39
+ mkdir ~/work-history
40
+ cd ~/work-history
41
+
42
+ # Initialize - creates .env and work-chronicler.yaml in current directory
43
+ work-chronicler init
44
+
45
+ # Edit .env with your tokens:
46
+ # GITHUB_TOKEN=ghp_xxxx
47
+ # JIRA_EMAIL=you@company.com
48
+ # JIRA_TOKEN=xxxx
49
+
50
+ # Edit work-chronicler.yaml with your GitHub username, orgs, and JIRA config
51
+
52
+ # Fetch your work history
53
+ work-chronicler fetch:all
54
+
55
+ # Analyze and generate stats
56
+ work-chronicler analyze --projects --timeline
57
+
58
+ # Check what you have
59
+ work-chronicler status
60
+ ```
61
+
62
+ All data is stored in the current directory under `work-log/`. You can version control this directory or keep it private.
63
+
64
+ ## Usage
65
+
66
+ All commands operate on the current directory. The CLI looks for `work-chronicler.yaml` in the current directory first, then falls back to `~/.config/work-chronicler/config.yaml`.
67
+
68
+ ```bash
69
+ # Create config files (.env and work-chronicler.yaml)
70
+ work-chronicler init
71
+
72
+ # Fetch from GitHub and JIRA
73
+ work-chronicler fetch:all
74
+
75
+ # Cross-reference PRs ↔ tickets
76
+ work-chronicler link
77
+
78
+ # Generate analysis files
79
+ work-chronicler analyze --projects --timeline
80
+
81
+ # Check status
82
+ work-chronicler status
83
+ ```
84
+
85
+ > **Note**: For local development in this repo, prefix all commands with `pnpm cli` (e.g., `pnpm cli init`).
86
+
87
+ ## Directory Structure
88
+
89
+ After fetching, your data is organized like this:
90
+
91
+ ```
92
+ work-log/
93
+ ├── pull-requests/
94
+ │ └── <org-name>/
95
+ │ └── <repo-name>/
96
+ │ ├── 2024-01-15_123.md
97
+ │ └── 2024-02-20_456.md
98
+ ├── jira/
99
+ │ └── <org-name>/
100
+ │ └── <project-key>/
101
+ │ ├── PROJ-100.md
102
+ │ └── PROJ-101.md
103
+ ├── performance-reviews/ # Add your own review docs here
104
+ ├── .analysis/ # Generated analysis
105
+ │ ├── stats.json # Impact breakdown, repo stats, etc.
106
+ │ ├── projects.json # Detected project groupings
107
+ │ └── timeline.json # Chronological view by week/month
108
+ └── filtered/ # Filtered subset (from filter command)
109
+ ├── pull-requests/
110
+ ├── jira/
111
+ └── .analysis/
112
+ ```
113
+
114
+ ## CLI Commands
115
+
116
+ | Command | Description |
117
+ |---------|-------------|
118
+ | `init` | Create a new config file |
119
+ | `fetch:github` | Fetch PRs from GitHub |
120
+ | `fetch:jira` | Fetch tickets from JIRA |
121
+ | `fetch:all` | Fetch both PRs and JIRA tickets |
122
+ | `link` | Cross-reference PRs and JIRA tickets |
123
+ | `analyze` | Classify PRs by impact and generate stats |
124
+ | `filter` | Filter work-log to a subset based on criteria |
125
+ | `status` | Show current state of fetched data |
126
+ | `mcp` | Start the MCP server for AI assistant integration |
127
+
128
+ ### Analyze Command
129
+
130
+ Classifies PRs into four impact tiers and generates statistics:
131
+
132
+ ```bash
133
+ # Interactive mode - prompts what to generate (tag-prs, projects, timeline)
134
+ work-chronicler analyze
135
+
136
+ # Run all analysis at once
137
+ work-chronicler analyze --all
138
+
139
+ # Or run specific analysis:
140
+ work-chronicler analyze --tag-prs # Tag PRs with impact levels
141
+ work-chronicler analyze --projects # Detect project groupings
142
+ work-chronicler analyze --timeline # Generate chronological timeline
143
+
144
+ # Analyze full work-log even if filtered/ exists
145
+ work-chronicler analyze --full
146
+ ```
147
+
148
+ **Impact Tiers:**
149
+ - **flagship**: Large initiatives (500+ lines or 15+ files), migrations, platform changes
150
+ - **major**: Significant features (200+ lines or 8+ files), `feat:` or `refactor:` commits
151
+ - **standard**: Regular work, bug fixes, `fix:` or `test:` commits
152
+ - **minor**: Small changes (<20 lines), docs, chores, dependency updates
153
+
154
+ **Project Detection:**
155
+
156
+ The `--projects` flag groups related PRs and tickets into projects based on shared JIRA ticket references. PRs that reference the same ticket are grouped together as a project. PRs without ticket references remain unassigned.
157
+
158
+ Output is written to `.analysis/projects.json`.
159
+
160
+ **Timeline View:**
161
+
162
+ The `--timeline` flag generates a chronological view of your work:
163
+ - Groups PRs and tickets by ISO week and month
164
+ - Shows weekly/monthly stats (PR count, ticket count, additions/deletions)
165
+ - Identifies busiest week and month
166
+ - Tracks impact distribution over time
167
+
168
+ Output is written to `.analysis/timeline.json`.
169
+
170
+ ### Filter Command
171
+
172
+ Create a filtered subset of your work-log:
173
+
174
+ ```bash
175
+ # Interactive mode (prompts for filter options)
176
+ work-chronicler filter
177
+
178
+ # Filter by organization (useful for separating work vs personal)
179
+ work-chronicler filter --org my-work-org
180
+ work-chronicler filter --exclude-org personal-github
181
+
182
+ # Filter by repository
183
+ work-chronicler filter --repo my-org/important-repo
184
+ work-chronicler filter --exclude-repo my-org/experimental-repo
185
+
186
+ # Exclude minor PRs
187
+ work-chronicler filter --exclude-impact minor
188
+
189
+ # Only major+ merged PRs
190
+ work-chronicler filter --min-impact major --merged-only
191
+
192
+ # Only PRs linked to tickets with 100+ lines changed
193
+ work-chronicler filter --linked-only --min-loc 100
194
+
195
+ # Combine filters (e.g., work PRs that are major+)
196
+ work-chronicler filter --org my-work-org --min-impact major
197
+
198
+ # Clear filtered data
199
+ work-chronicler filter --clear
200
+ ```
201
+
202
+ Filtered files are written to `work-log/filtered/` with their own analysis (stats, projects, timeline).
203
+
204
+ ### Interactive Prompts
205
+
206
+ Most commands will prompt for options when run without flags:
207
+
208
+ - **fetch:github/jira/all** - Prompts whether to use cache mode if data already exists
209
+ - **analyze** - Prompts what to generate (tag-prs, projects, timeline) and whether to use filtered data
210
+ - **filter** - Prompts for all filter options
211
+
212
+ Use flags like `--cache`, `--all`, `--full`, etc. to skip prompts in scripts.
213
+
214
+ ## Configuration
215
+
216
+ See [work-chronicler.example.yaml](work-chronicler.example.yaml) for a complete example.
217
+
218
+ ### GitHub Token
219
+
220
+ Create a personal access token at https://github.com/settings/tokens with the `repo` scope (or `public_repo` for public repos only).
221
+
222
+ ### JIRA Token
223
+
224
+ Create an API token at https://id.atlassian.com/manage-profile/security/api-tokens
225
+
226
+ ## MCP Server
227
+
228
+ work-chronicler includes an MCP (Model Context Protocol) server that exposes your work history to AI assistants like Claude Desktop and Cursor.
229
+
230
+ ### Setup
231
+
232
+ 1. First, fetch and analyze your data:
233
+ ```bash
234
+ work-chronicler fetch:all
235
+ work-chronicler analyze --projects --timeline
236
+ ```
237
+
238
+ 2. Configure your AI assistant.
239
+
240
+ The MCP server needs to find your `work-chronicler.yaml` config. Use the `WORK_CHRONICLER_DIR` environment variable to point to your work history directory.
241
+
242
+ **Published Package** (installed via npm):
243
+
244
+ Use `npx work-chronicler mcp` which runs through the CLI. This is the recommended approach for installed packages.
245
+
246
+ **Claude Desktop** (`~/Library/Application Support/Claude/claude_desktop_config.json`):
247
+ ```json
248
+ {
249
+ "mcpServers": {
250
+ "work-chronicler": {
251
+ "command": "npx",
252
+ "args": ["work-chronicler", "mcp"],
253
+ "env": {
254
+ "WORK_CHRONICLER_DIR": "/Users/you/work-history"
255
+ }
256
+ }
257
+ }
258
+ }
259
+ ```
260
+
261
+ **Cursor** (`.cursor/mcp.json` in your project):
262
+ ```json
263
+ {
264
+ "mcpServers": {
265
+ "work-chronicler": {
266
+ "command": "npx",
267
+ "args": ["work-chronicler", "mcp"],
268
+ "env": {
269
+ "WORK_CHRONICLER_DIR": "/Users/you/work-history"
270
+ }
271
+ }
272
+ }
273
+ }
274
+ ```
275
+
276
+ **Local Development** (running from source):
277
+
278
+ For local development, use `node bin/mcp.js` which starts the MCP server directly without CLI overhead. This is faster for development iteration.
279
+
280
+ ```json
281
+ {
282
+ "mcpServers": {
283
+ "work-chronicler": {
284
+ "command": "node",
285
+ "args": ["/path/to/work-chronicler/bin/mcp.js"],
286
+ "env": {
287
+ "WORK_CHRONICLER_DIR": "/path/to/work-chronicler"
288
+ }
289
+ }
290
+ }
291
+ }
292
+ ```
293
+
294
+ > **Note:** Replace `/path/to/work-chronicler` with your actual project path. Run `pnpm build` first to generate the dist files.
295
+
296
+ Alternatively, you can use the CLI approach for local development too:
297
+ ```json
298
+ {
299
+ "mcpServers": {
300
+ "work-chronicler": {
301
+ "command": "node",
302
+ "args": ["/path/to/work-chronicler/bin/work-chronicler.js", "mcp"],
303
+ "env": {
304
+ "WORK_CHRONICLER_DIR": "/path/to/work-chronicler"
305
+ }
306
+ }
307
+ }
308
+ }
309
+ ```
310
+
311
+ 3. Restart your AI assistant to load the MCP server.
312
+
313
+ **Environment Variables:**
314
+ - `WORK_CHRONICLER_DIR` - Directory containing your `work-chronicler.yaml`
315
+ - `WORK_CHRONICLER_CONFIG` - Full path to config file (alternative to DIR)
316
+
317
+ ### Available Tools
318
+
319
+ | Tool | Description |
320
+ |------|-------------|
321
+ | `search_prs` | Search PRs by date range, repo, keywords, impact level, or state |
322
+ | `search_tickets` | Search JIRA tickets by project, status, or keywords |
323
+ | `get_linked_work` | Get a PR with its linked JIRA tickets (or vice versa) |
324
+ | `list_repos` | List all repositories with statistics |
325
+ | `get_stats` | Get summary statistics (reads from stats.json or computes on-the-fly) |
326
+ | `get_projects` | Get detected project groupings with confidence levels |
327
+ | `get_timeline` | Get chronological timeline of work grouped by week or month |
328
+
329
+ ### Example Prompts
330
+
331
+ Once configured, you can ask your AI assistant:
332
+
333
+ - "Show me my flagship PRs from last quarter"
334
+ - "What projects did I work on with high confidence groupings?"
335
+ - "Find all my work related to authentication"
336
+ - "Summarize my work from January to March"
337
+ - "What was my busiest week?"
338
+
339
+ ### CLI Commands
340
+
341
+ ```bash
342
+ # Show MCP server info
343
+ work-chronicler mcp --info
344
+
345
+ # Start MCP server (stdio transport)
346
+ work-chronicler mcp
347
+ ```
348
+
349
+ ## Project Structure
350
+
351
+ ```
352
+ work-chronicler/
353
+ ├── src/
354
+ │ ├── cli/ # CLI application (Commander)
355
+ │ │ ├── commands/ # CLI commands
356
+ │ │ ├── fetchers/ # GitHub and JIRA fetchers
357
+ │ │ ├── linker/ # Cross-reference linking
358
+ │ │ ├── analyzer/ # Impact analysis
359
+ │ │ └── prompts/ # Interactive prompts
360
+ │ ├── mcp/ # MCP server for AI assistants
361
+ │ └── core/ # Shared types, config, storage
362
+ │ ├── config/ # Config loading and schema
363
+ │ ├── storage/ # Markdown file reader/writer
364
+ │ └── types/ # Zod schemas and types
365
+ ├── bin/ # CLI entry point
366
+ └── tools/
367
+ └── git-hooks/ # Git hook management
368
+ ```
369
+
370
+ ## Development
371
+
372
+ ```bash
373
+ # Install dependencies
374
+ pnpm install
375
+
376
+ # Build all packages
377
+ pnpm build
378
+
379
+ # Run type checking
380
+ pnpm type-check
381
+
382
+ # Run linting
383
+ pnpm lint
384
+
385
+ # Run tests
386
+ pnpm test
387
+ ```
388
+
389
+ ## Publishing
390
+
391
+ The package is published to npm as `work-chronicler`.
392
+
393
+ ### Release Process
394
+
395
+ 1. Update the version in `package.json`
396
+ 2. Commit and push to main
397
+ 3. Create and push a version tag:
398
+ ```bash
399
+ git tag v0.1.0
400
+ git push origin v0.1.0
401
+ ```
402
+ 4. The GitHub Action will automatically publish to npm
403
+
404
+ ### Manual Publishing
405
+
406
+ ```bash
407
+ # Build the package
408
+ pnpm build
409
+
410
+ # Dry run to verify what will be published
411
+ pnpm publish --dry-run --no-git-checks
412
+
413
+ # Publish (requires NPM_TOKEN or npm login)
414
+ pnpm publish --access public --no-git-checks
415
+ ```
416
+
417
+ ## Roadmap
418
+
419
+ - [x] **Analysis commands**: Categorize work by size/impact (4-tier classification)
420
+ - [x] **Project detection**: Group related PRs/tickets into initiatives
421
+ - [x] **Timeline view**: Chronological view of work grouped by week/month
422
+ - [x] **MCP server**: Full implementation for AI assistant integration
423
+ - [ ] **AI summarization**: Claude/Cursor commands + CLI commands for summaries
424
+ - [ ] **Supporting documents**: Import past reviews, resumes, notes for context
425
+ - [ ] **Google Docs integration**: Import performance review docs
426
+ - [ ] **Linear support**: Alternative to JIRA
427
+ - [ ] **Notion integration**: Import from Notion
428
+ - [ ] **Incremental sync**: Only fetch new/updated items
429
+
430
+ ## License
431
+
432
+ MIT
package/bin/mcp.js ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { createServer, startServer } from '../dist/mcp/server.js';
4
+
5
+ const ctx = await createServer();
6
+ await startServer(ctx);
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+
3
+ import '../dist/cli/index.js';
@@ -0,0 +1,31 @@
1
+ import type { AnalysisConfig, PRImpact, PullRequest } from '../../core/index.js';
2
+ /**
3
+ * Default thresholds for impact classification
4
+ */
5
+ export declare const DEFAULT_THRESHOLDS: {
6
+ minor: {
7
+ maxLines: number;
8
+ maxFiles: number;
9
+ };
10
+ major: {
11
+ minLines: number;
12
+ minFiles: number;
13
+ };
14
+ flagship: {
15
+ minLines: number;
16
+ minFiles: number;
17
+ };
18
+ };
19
+ /**
20
+ * Classify a PR's impact level based on its characteristics
21
+ */
22
+ export declare function classifyPRImpact(pr: PullRequest, config?: AnalysisConfig): PRImpact;
23
+ /**
24
+ * Get a human-readable description of what the impact means
25
+ */
26
+ export declare function getImpactDescription(impact: PRImpact): string;
27
+ /**
28
+ * Impact level hierarchy for comparison (higher = more significant)
29
+ */
30
+ export declare const IMPACT_HIERARCHY: Record<PRImpact, number>;
31
+ //# sourceMappingURL=classifier.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"classifier.d.ts","sourceRoot":"","sources":["../../../src/cli/analyzer/classifier.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAEzE;;GAEG;AACH,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;CAI9B,CAAC;AAkFF;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,EAAE,EAAE,WAAW,EACf,MAAM,CAAC,EAAE,cAAc,GACtB,QAAQ,CAiFV;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,QAAQ,GAAG,MAAM,CAe7D;AAED;;GAEG;AACH,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,QAAQ,EAAE,MAAM,CAKrD,CAAC"}
@@ -0,0 +1,171 @@
1
+ /**
2
+ * Default thresholds for impact classification
3
+ */
4
+ export const DEFAULT_THRESHOLDS = {
5
+ minor: { maxLines: 20, maxFiles: 3 },
6
+ major: { minLines: 200, minFiles: 8 },
7
+ flagship: { minLines: 500, minFiles: 15 },
8
+ };
9
+ /**
10
+ * Conventional commit prefixes and their default impact
11
+ */
12
+ const CONVENTIONAL_COMMIT_MAP = {
13
+ // Minor by default (can be upgraded by size)
14
+ chore: 'minor',
15
+ docs: 'minor',
16
+ style: 'minor',
17
+ ci: 'minor',
18
+ build: 'minor',
19
+ // Standard by default
20
+ fix: 'standard',
21
+ test: 'standard',
22
+ perf: 'standard',
23
+ // Major by default (can be upgraded to flagship by size)
24
+ feat: 'major',
25
+ refactor: 'major',
26
+ };
27
+ /**
28
+ * Patterns that indicate minor/low-value PRs (checked after conventional commits)
29
+ */
30
+ const MINOR_PATTERNS = [
31
+ /^fix\s*typo/i,
32
+ /^typo/i,
33
+ /^update\s+deps?/i,
34
+ /^bump\s+/i,
35
+ /^\[chore\]/i,
36
+ /^update\s+dependencies/i,
37
+ /^dependency\s+update/i,
38
+ /^renovate/i,
39
+ /^dependabot/i,
40
+ ];
41
+ const MINOR_LABELS = [
42
+ 'dependencies',
43
+ 'chore',
44
+ 'maintenance',
45
+ 'renovate',
46
+ 'dependabot',
47
+ ];
48
+ /**
49
+ * Patterns that indicate major work (checked after conventional commits)
50
+ */
51
+ const MAJOR_PATTERNS = [/^\[feat\]/i, /^add\s+/i, /^implement\s+/i, /^new\s+/i];
52
+ /**
53
+ * Patterns that indicate flagship/breaking work
54
+ */
55
+ const FLAGSHIP_PATTERNS = [
56
+ /breaking/i,
57
+ /platform/i,
58
+ /architect/i,
59
+ /migration/i,
60
+ /redesign/i,
61
+ /overhaul/i,
62
+ /rewrite/i,
63
+ ];
64
+ /**
65
+ * Extract conventional commit type from PR title
66
+ * Handles: "feat: message", "feat(scope): message", "[feat] message"
67
+ */
68
+ function extractConventionalType(title) {
69
+ // Match "type:" or "type(scope):"
70
+ const conventionalMatch = title.match(/^(\w+)(?:\([^)]*\))?:\s*/i);
71
+ if (conventionalMatch?.[1]) {
72
+ return conventionalMatch[1].toLowerCase();
73
+ }
74
+ // Match "[type]"
75
+ const bracketMatch = title.match(/^\[(\w+)\]/i);
76
+ if (bracketMatch?.[1]) {
77
+ return bracketMatch[1].toLowerCase();
78
+ }
79
+ return null;
80
+ }
81
+ /**
82
+ * Classify a PR's impact level based on its characteristics
83
+ */
84
+ export function classifyPRImpact(pr, config) {
85
+ const thresholds = {
86
+ minor: { ...DEFAULT_THRESHOLDS.minor, ...config?.thresholds?.minor },
87
+ major: { ...DEFAULT_THRESHOLDS.major, ...config?.thresholds?.major },
88
+ flagship: {
89
+ ...DEFAULT_THRESHOLDS.flagship,
90
+ ...config?.thresholds?.flagship,
91
+ },
92
+ };
93
+ const totalLines = pr.additions + pr.deletions;
94
+ const title = pr.title;
95
+ // Check size thresholds first for flagship
96
+ const isFlagshipSize = (thresholds.flagship.minLines &&
97
+ totalLines >= thresholds.flagship.minLines) ||
98
+ (thresholds.flagship.minFiles &&
99
+ pr.changedFiles >= thresholds.flagship.minFiles);
100
+ // Check flagship patterns
101
+ const hasFlagshipPattern = FLAGSHIP_PATTERNS.some((p) => p.test(title));
102
+ if (isFlagshipSize || hasFlagshipPattern) {
103
+ return 'flagship';
104
+ }
105
+ // Check conventional commit type
106
+ const conventionalType = extractConventionalType(title);
107
+ let baseImpact = null;
108
+ if (conventionalType && conventionalType in CONVENTIONAL_COMMIT_MAP) {
109
+ baseImpact = CONVENTIONAL_COMMIT_MAP[conventionalType] ?? null;
110
+ }
111
+ // Check for minor patterns and labels
112
+ const hasMinorPattern = MINOR_PATTERNS.some((p) => p.test(title));
113
+ const hasMinorLabel = pr.labels.some((label) => MINOR_LABELS.includes(label.toLowerCase()));
114
+ // Check size for minor
115
+ const isMinorSize = thresholds.minor.maxLines &&
116
+ totalLines <= thresholds.minor.maxLines &&
117
+ thresholds.minor.maxFiles &&
118
+ pr.changedFiles <= thresholds.minor.maxFiles;
119
+ // If conventional commit says minor, or patterns say minor with small size
120
+ if (baseImpact === 'minor' ||
121
+ ((hasMinorPattern || hasMinorLabel) && isMinorSize)) {
122
+ return 'minor';
123
+ }
124
+ // Very small changes are minor regardless
125
+ if (totalLines <= 10 && pr.changedFiles <= 2) {
126
+ return 'minor';
127
+ }
128
+ // Check for major size
129
+ const isMajorSize = (thresholds.major.minLines && totalLines >= thresholds.major.minLines) ||
130
+ (thresholds.major.minFiles && pr.changedFiles >= thresholds.major.minFiles);
131
+ // Check for major patterns
132
+ const hasMajorPattern = MAJOR_PATTERNS.some((p) => p.test(title));
133
+ // If conventional commit says major, or patterns/size indicate major
134
+ if (baseImpact === 'major' || isMajorSize || hasMajorPattern) {
135
+ return 'major';
136
+ }
137
+ // If conventional commit gave us a base impact, use it
138
+ if (baseImpact) {
139
+ return baseImpact;
140
+ }
141
+ // Everything else is standard
142
+ return 'standard';
143
+ }
144
+ /**
145
+ * Get a human-readable description of what the impact means
146
+ */
147
+ export function getImpactDescription(impact) {
148
+ switch (impact) {
149
+ case 'flagship':
150
+ return 'Large initiatives, platform changes, or multi-PR efforts';
151
+ case 'major':
152
+ return 'Significant features, larger refactors, or architectural work';
153
+ case 'standard':
154
+ return 'Regular feature work, bug fixes, and moderate changes';
155
+ case 'minor':
156
+ return 'Small fixes, typos, docs, or dependency updates';
157
+ default: {
158
+ const _exhaustive = impact;
159
+ return _exhaustive;
160
+ }
161
+ }
162
+ }
163
+ /**
164
+ * Impact level hierarchy for comparison (higher = more significant)
165
+ */
166
+ export const IMPACT_HIERARCHY = {
167
+ minor: 0,
168
+ standard: 1,
169
+ major: 2,
170
+ flagship: 3,
171
+ };
@@ -0,0 +1,5 @@
1
+ export { classifyPRImpact, DEFAULT_THRESHOLDS, getImpactDescription, IMPACT_HIERARCHY, } from './classifier.js';
2
+ export { detectProjects } from './projects.js';
3
+ export { type AnalysisStats, generateStats } from './stats.js';
4
+ export { generateTimeline } from './timeline.js';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/cli/analyzer/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,EAChB,kBAAkB,EAClB,oBAAoB,EACpB,gBAAgB,GACjB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EAAE,KAAK,aAAa,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC5D,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC"}
@@ -0,0 +1,4 @@
1
+ export { classifyPRImpact, DEFAULT_THRESHOLDS, getImpactDescription, IMPACT_HIERARCHY, } from './classifier.js';
2
+ export { detectProjects } from './projects.js';
3
+ export { generateStats } from './stats.js';
4
+ export { generateTimeline } from './timeline.js';
@@ -0,0 +1,10 @@
1
+ import type { JiraTicketFile, ProjectsAnalysis, PullRequestFile } from '../../core/index.js';
2
+ /**
3
+ * Detect project groupings from PRs and tickets
4
+ *
5
+ * Projects are detected based on shared JIRA ticket references.
6
+ * PRs that reference the same ticket are grouped together.
7
+ * PRs without ticket references are not grouped into projects.
8
+ */
9
+ export declare function detectProjects(prs: PullRequestFile[], tickets: JiraTicketFile[], since: string, until: string): ProjectsAnalysis;
10
+ //# sourceMappingURL=projects.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"projects.d.ts","sourceRoot":"","sources":["../../../src/cli/analyzer/projects.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,cAAc,EAGd,gBAAgB,EAChB,eAAe,EAChB,MAAM,aAAa,CAAC;AAiFrB;;;;;;GAMG;AACH,wBAAgB,cAAc,CAC5B,GAAG,EAAE,eAAe,EAAE,EACtB,OAAO,EAAE,cAAc,EAAE,EACzB,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,GACZ,gBAAgB,CA0LlB"}