pake-cli 3.11.2 → 3.11.3

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.
@@ -1,283 +0,0 @@
1
- #!/usr/bin/env node
2
- import { Command } from 'commander';
3
- import { execSync } from 'child_process';
4
- import * as fs from 'fs';
5
- import * as path from 'path';
6
- class CodeReviewGraph {
7
- graph;
8
- constructor() {
9
- this.graph = {
10
- contributors: new Map(),
11
- prs: [],
12
- reviewRelations: new Map(),
13
- timeRange: { start: '', end: '' }
14
- };
15
- }
16
- async build() {
17
- console.log('Analyzing repository data...\n');
18
- await this.analyzeCommits();
19
- await this.analyzePRs();
20
- this.analyzeReviewRelations();
21
- return;
22
- }
23
- async analyzeCommits() {
24
- try {
25
- // Commands are hardcoded internal commands, not user input
26
- const logOutput = execSync('git log --format="%H|%an|%ae|%ad|%s" --date=short -500', { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'ignore'] });
27
- const lines = logOutput.trim().split('\n');
28
- for (const line of lines) {
29
- const parts = line.split('|');
30
- if (parts.length < 5)
31
- continue;
32
- const [, name, email, date] = parts;
33
- if (!this.graph.contributors.has(email)) {
34
- this.graph.contributors.set(email, {
35
- name,
36
- email,
37
- commits: 0,
38
- prsOpened: 0,
39
- prsMerged: 0,
40
- reviewsGiven: 0,
41
- reviewsReceived: 0,
42
- firstCommit: date,
43
- lastCommit: date,
44
- filesChanged: new Set()
45
- });
46
- }
47
- const contributor = this.graph.contributors.get(email);
48
- contributor.commits++;
49
- contributor.lastCommit = date;
50
- if (!this.graph.timeRange.start || date < this.graph.timeRange.start) {
51
- this.graph.timeRange.start = date;
52
- }
53
- if (!this.graph.timeRange.end || date > this.graph.timeRange.end) {
54
- this.graph.timeRange.end = date;
55
- }
56
- }
57
- }
58
- catch (error) {
59
- console.warn('Could not analyze commits:', error.message);
60
- }
61
- }
62
- async analyzePRs() {
63
- try {
64
- const prOutput = execSync('gh pr list --state all --limit 100 --json number,title,author,state,mergedAt,createdAt,mergedBy 2>/dev/null || echo "[]"', { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'ignore'] });
65
- const prs = JSON.parse(prOutput.trim() || '[]');
66
- this.graph.prs = prs;
67
- for (const pr of prs) {
68
- const authorEmail = this.findEmailByUsername(pr.author.login);
69
- if (authorEmail && this.graph.contributors.has(authorEmail)) {
70
- const contributor = this.graph.contributors.get(authorEmail);
71
- contributor.prsOpened++;
72
- if (pr.state === 'MERGED') {
73
- contributor.prsMerged++;
74
- }
75
- }
76
- if (pr.mergedBy?.login) {
77
- const mergerEmail = this.findEmailByUsername(pr.mergedBy.login);
78
- if (mergerEmail && this.graph.contributors.has(mergerEmail)) {
79
- const merger = this.graph.contributors.get(mergerEmail);
80
- merger.reviewsGiven++;
81
- }
82
- }
83
- }
84
- }
85
- catch (error) {
86
- console.warn('Could not analyze PRs:', error.message);
87
- }
88
- }
89
- findEmailByUsername(username) {
90
- const usernameLower = username.toLowerCase();
91
- for (const [email, contributor] of this.graph.contributors) {
92
- if (contributor.name.toLowerCase().includes(usernameLower) ||
93
- email.toLowerCase().includes(usernameLower)) {
94
- return email;
95
- }
96
- }
97
- return null;
98
- }
99
- analyzeReviewRelations() {
100
- for (const pr of this.graph.prs) {
101
- if (pr.mergedBy?.login && pr.author.login !== pr.mergedBy.login) {
102
- const authorKey = pr.author.login;
103
- const mergerKey = pr.mergedBy.login;
104
- if (!this.graph.reviewRelations.has(mergerKey)) {
105
- this.graph.reviewRelations.set(mergerKey, new Map());
106
- }
107
- const relations = this.graph.reviewRelations.get(mergerKey);
108
- relations.set(authorKey, (relations.get(authorKey) || 0) + 1);
109
- }
110
- }
111
- }
112
- generateMermaidGraph() {
113
- const lines = [
114
- '%% Code Review Graph for Pake',
115
- '%% Generated automatically - do not edit manually',
116
- '',
117
- 'flowchart TB',
118
- ' subgraph Contributors["Top Contributors"]'
119
- ];
120
- const sortedContributors = Array.from(this.graph.contributors.values())
121
- .sort((a, b) => b.commits - a.commits)
122
- .slice(0, 15);
123
- const nodeMap = new Map();
124
- let idx = 0;
125
- for (const c of sortedContributors) {
126
- const nodeId = `C${idx}`;
127
- nodeMap.set(c.email, nodeId);
128
- const prBadge = c.prsMerged > 0 ? ` PRs:${c.prsMerged}` : '';
129
- const label = `${c.name}(${c.commits})${prBadge}`;
130
- lines.push(` ${nodeId}["${label}"]`);
131
- idx++;
132
- }
133
- lines.push(' end');
134
- lines.push('');
135
- const addedEdges = new Set();
136
- for (const [reviewer, relations] of this.graph.reviewRelations) {
137
- // reviewer is already a string (the login), not an object
138
- const reviewerEmail = this.findEmailByUsername(reviewer);
139
- if (!reviewerEmail || !nodeMap.has(reviewerEmail))
140
- continue;
141
- const reviewerNode = nodeMap.get(reviewerEmail);
142
- for (const [author, count] of relations) {
143
- // author is already a string (the login)
144
- const authorEmail = this.findEmailByUsername(author);
145
- if (!authorEmail || !nodeMap.has(authorEmail))
146
- continue;
147
- const authorNode = nodeMap.get(authorEmail);
148
- const edgeKey = `${reviewerNode}-${authorNode}`;
149
- if (!addedEdges.has(edgeKey)) {
150
- lines.push(` ${reviewerNode} -.->|"reviews"| ${authorNode}`);
151
- addedEdges.add(edgeKey);
152
- }
153
- }
154
- }
155
- lines.push('');
156
- lines.push(' subgraph Recent_Merges["Recent Merged PRs"]');
157
- const mergedPRs = this.graph.prs
158
- .filter(pr => pr.state === 'MERGED')
159
- .slice(0, 8);
160
- for (let i = 0; i < mergedPRs.length; i++) {
161
- const pr = mergedPRs[i];
162
- const prNode = `PR${i}`;
163
- const title = pr.title.length > 30 ? pr.title.substring(0, 30) + '...' : pr.title;
164
- lines.push(` ${prNode}["#${pr.number}: ${title}"]`);
165
- }
166
- lines.push(' end');
167
- lines.push('');
168
- lines.push(' subgraph Stats["Statistics"]');
169
- lines.push(` TotalContributors["Total Contributors: ${this.graph.contributors.size}"]`);
170
- lines.push(` TotalPRs["Total PRs Analyzed: ${this.graph.prs.length}"]`);
171
- lines.push(` MergedPRs["Merged PRs: ${this.graph.prs.filter(p => p.state === 'MERGED').length}"]`);
172
- lines.push(` TimeRange["Period: ${this.graph.timeRange.start} to ${this.graph.timeRange.end}"]`);
173
- lines.push(' end');
174
- lines.push('');
175
- lines.push(' %% Styling');
176
- lines.push(' classDef contributor fill:#e1f5fe,stroke:#01579b,stroke-width:2px');
177
- lines.push(' classDef reviewer fill:#fff3e0,stroke:#e65100,stroke-width:2px');
178
- lines.push(' classDef pr fill:#e8f5e9,stroke:#2e7d32,stroke-width:1px');
179
- lines.push(' classDef stats fill:#f3e5f5,stroke:#6a1b9a,stroke-width:1px');
180
- for (let i = 0; i < idx; i++) {
181
- lines.push(` class C${i} contributor`);
182
- }
183
- for (let i = 0; i < mergedPRs.length; i++) {
184
- lines.push(` class PR${i} pr`);
185
- }
186
- lines.push(' class TotalContributors,TotalPRs,MergedPRs,TimeRange stats');
187
- return lines.join('\n');
188
- }
189
- generateJSON() {
190
- const contributors = Array.from(this.graph.contributors.values())
191
- .map(c => ({
192
- ...c,
193
- filesChanged: Array.from(c.filesChanged)
194
- }))
195
- .sort((a, b) => b.commits - a.commits);
196
- return {
197
- metadata: {
198
- generatedAt: new Date().toISOString(),
199
- repository: 'tw93/Pake',
200
- timeRange: this.graph.timeRange
201
- },
202
- summary: {
203
- totalContributors: this.graph.contributors.size,
204
- totalPRs: this.graph.prs.length,
205
- mergedPRs: this.graph.prs.filter(p => p.state === 'MERGED').length,
206
- closedPRs: this.graph.prs.filter(p => p.state === 'CLOSED').length,
207
- openPRs: this.graph.prs.filter(p => p.state === 'OPEN').length
208
- },
209
- contributors: contributors.slice(0, 20),
210
- recentPRs: this.graph.prs.slice(0, 20),
211
- reviewRelations: Object.fromEntries(Array.from(this.graph.reviewRelations.entries()).map(([k, v]) => [
212
- k,
213
- Object.fromEntries(v)
214
- ]))
215
- };
216
- }
217
- printSummary() {
218
- console.log('\n===============================================================');
219
- console.log(' Code Review Graph Summary ');
220
- console.log('===============================================================\n');
221
- console.log(`Time Range: ${this.graph.timeRange.start} to ${this.graph.timeRange.end}`);
222
- console.log(`Total Contributors: ${this.graph.contributors.size}`);
223
- console.log(`Total PRs Analyzed: ${this.graph.prs.length}`);
224
- console.log(` Merged: ${this.graph.prs.filter(p => p.state === 'MERGED').length}`);
225
- console.log(` Closed: ${this.graph.prs.filter(p => p.state === 'CLOSED').length}`);
226
- console.log(` Open: ${this.graph.prs.filter(p => p.state === 'OPEN').length}\n`);
227
- console.log('Top Contributors by Commits:');
228
- const sorted = Array.from(this.graph.contributors.values())
229
- .sort((a, b) => b.commits - a.commits)
230
- .slice(0, 10);
231
- for (let i = 0; i < sorted.length; i++) {
232
- const c = sorted[i];
233
- const rank = i === 0 ? '1.' : i === 1 ? '2.' : i === 2 ? '3.' : ' ';
234
- const prInfo = c.prsMerged > 0 ? ` (PRs merged: ${c.prsMerged})` : '';
235
- console.log(` ${rank} ${c.name}: ${c.commits} commits${prInfo}`);
236
- }
237
- if (this.graph.reviewRelations.size > 0) {
238
- console.log('\nReview Relationships (Merger -> Author):');
239
- for (const [reviewer, relations] of this.graph.reviewRelations) {
240
- const relationsStr = Array.from(relations.entries())
241
- .map(([author, count]) => `${author}(${count})`)
242
- .join(', ');
243
- console.log(` ${reviewer} -> ${relationsStr}`);
244
- }
245
- }
246
- console.log('\n');
247
- }
248
- }
249
- const program = new Command();
250
- program
251
- .name('code-review-graph')
252
- .description('Generate code review graph for Pake project')
253
- .version('1.0.0')
254
- .option('-o, --output <path>', 'Output file path', 'code-review-graph.mmd')
255
- .option('-f, --format <format>', 'Output format (mermaid|json)', 'mermaid')
256
- .option('-s, --stdout', 'Print to stdout instead of file', false)
257
- .action(async (options) => {
258
- const graph = new CodeReviewGraph();
259
- await graph.build();
260
- graph.printSummary();
261
- let output;
262
- if (options.format === 'json') {
263
- output = JSON.stringify(graph.generateJSON(), null, 2);
264
- }
265
- else {
266
- output = graph.generateMermaidGraph();
267
- }
268
- if (options.stdout) {
269
- console.log(output);
270
- }
271
- else {
272
- const outputPath = path.resolve(options.output);
273
- fs.writeFileSync(outputPath, output, 'utf-8');
274
- console.log(`Graph saved to: ${outputPath}`);
275
- if (options.format === 'mermaid') {
276
- console.log('\nTo view this graph:');
277
- console.log(' 1. Use GitHub markdown (paste into .md file)');
278
- console.log(' 2. Use VS Code with Mermaid extension');
279
- console.log(' 3. Visit https://mermaid.live/ and paste the content');
280
- }
281
- }
282
- });
283
- program.parse();
@@ -1,45 +0,0 @@
1
- {
2
- "windows": [
3
- {
4
- "url": "https://twitter.com/",
5
- "url_type": "web",
6
- "hide_title_bar": false,
7
- "fullscreen": false,
8
- "width": 1200,
9
- "height": 780,
10
- "resizable": true,
11
- "always_on_top": false,
12
- "dark_mode": false,
13
- "activation_shortcut": "",
14
- "disabled_web_shortcuts": false,
15
- "hide_on_close": true,
16
- "incognito": false,
17
- "enable_wasm": false,
18
- "enable_drag_drop": false,
19
- "maximize": false,
20
- "start_to_tray": false,
21
- "force_internal_navigation": false,
22
- "internal_url_regex": "",
23
- "new_window": false,
24
- "zoom": 100,
25
- "min_width": 0,
26
- "min_height": 0,
27
- "ignore_certificate_errors": false
28
- }
29
- ],
30
- "user_agent": {
31
- "macos": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.2 Safari/605.1.15",
32
- "linux": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36",
33
- "windows": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36"
34
- },
35
- "system_tray": {
36
- "macos": false,
37
- "linux": true,
38
- "windows": true
39
- },
40
- "system_tray_path": "png/icon_512.png",
41
- "inject": [],
42
- "proxy_url": "",
43
- "multi_instance": false,
44
- "multi_window": false
45
- }
@@ -1,46 +0,0 @@
1
- {
2
- "productName": "twitter",
3
- "identifier": "com.pake.ac7d1d0",
4
- "version": "1.0.0",
5
- "app": {
6
- "withGlobalTauri": true,
7
- "security": {
8
- "headers": {},
9
- "csp": null
10
- }
11
- },
12
- "build": {
13
- "frontendDist": "../dist"
14
- },
15
- "bundle": {
16
- "icon": [
17
- "icons/icon.icns"
18
- ],
19
- "active": true,
20
- "targets": [
21
- "app"
22
- ],
23
- "macOS": {
24
- "signingIdentity": "-",
25
- "hardenedRuntime": true,
26
- "entitlements": "entitlements.plist",
27
- "infoPlist": "Info.plist",
28
- "dmg": {
29
- "background": "assets/macos/dmg/background.png",
30
- "windowSize": {
31
- "width": 680,
32
- "height": 420
33
- },
34
- "appPosition": {
35
- "x": 190,
36
- "y": 250
37
- },
38
- "applicationFolderPosition": {
39
- "x": 500,
40
- "y": 250
41
- }
42
- }
43
- }
44
- },
45
- "mainBinaryName": "pake-twitter"
46
- }
@@ -1,12 +0,0 @@
1
- {
2
- "bundle": {
3
- "icon": ["png/weekly_512.png"],
4
- "active": true,
5
- "linux": {
6
- "deb": {
7
- "depends": ["curl", "wget"]
8
- }
9
- },
10
- "targets": ["deb", "appimage"]
11
- }
12
- }
@@ -1,32 +0,0 @@
1
- {
2
- "bundle": {
3
- "icon": [
4
- "icons/icon.icns"
5
- ],
6
- "active": true,
7
- "targets": [
8
- "app"
9
- ],
10
- "macOS": {
11
- "signingIdentity": "-",
12
- "hardenedRuntime": true,
13
- "entitlements": "entitlements.plist",
14
- "infoPlist": "Info.plist",
15
- "dmg": {
16
- "background": "assets/macos/dmg/background.png",
17
- "windowSize": {
18
- "width": 680,
19
- "height": 420
20
- },
21
- "appPosition": {
22
- "x": 190,
23
- "y": 250
24
- },
25
- "applicationFolderPosition": {
26
- "x": 500,
27
- "y": 250
28
- }
29
- }
30
- }
31
- }
32
- }
@@ -1,15 +0,0 @@
1
- {
2
- "bundle": {
3
- "icon": ["png/weekly_256.ico", "png/weekly_32.ico"],
4
- "active": true,
5
- "resources": ["png/weekly_32.ico"],
6
- "targets": ["msi"],
7
- "windows": {
8
- "digestAlgorithm": "sha256",
9
- "wix": {
10
- "language": ["en-US"],
11
- "template": "assets/main.wxs"
12
- }
13
- }
14
- }
15
- }