openspec-stat 1.0.0 → 1.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.
@@ -21,6 +21,7 @@ export var StatsAggregator = /*#__PURE__*/function () {
21
21
  key: "aggregate",
22
22
  value: function aggregate(analyses, since, until, branches, filterAuthor) {
23
23
  var authorStatsMap = new Map();
24
+ var proposalStatsMap = new Map();
24
25
  var _iterator = _createForOfIteratorHelper(analyses),
25
26
  _step;
26
27
  try {
@@ -52,17 +53,44 @@ export var StatsAggregator = /*#__PURE__*/function () {
52
53
  stats.deletions += analysis.totalDeletions;
53
54
  stats.netChanges += analysis.netChanges;
54
55
  stats.codeFilesChanged += analysis.codeFiles.length;
55
- var _iterator3 = _createForOfIteratorHelper(analysis.openspecProposals),
56
- _step3;
56
+ var _iterator4 = _createForOfIteratorHelper(analysis.openspecProposals),
57
+ _step4;
57
58
  try {
58
- for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
59
- var _proposal = _step3.value;
59
+ for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
60
+ var _proposal = _step4.value;
60
61
  stats.openspecProposals.add(_proposal);
62
+
63
+ // Aggregate by proposal
64
+ var proposalStats = proposalStatsMap.get(_proposal);
65
+ if (!proposalStats) {
66
+ proposalStats = {
67
+ proposal: _proposal,
68
+ commits: 0,
69
+ contributors: new Set(),
70
+ codeFilesChanged: 0,
71
+ additions: 0,
72
+ deletions: 0,
73
+ netChanges: 0,
74
+ commitHashes: new Set()
75
+ };
76
+ proposalStatsMap.set(_proposal, proposalStats);
77
+ }
78
+
79
+ // Only count each commit once per proposal
80
+ if (!proposalStats.commitHashes.has(analysis.commit.hash)) {
81
+ proposalStats.commitHashes.add(analysis.commit.hash);
82
+ proposalStats.commits++;
83
+ proposalStats.contributors.add(normalizedAuthor);
84
+ proposalStats.codeFilesChanged += analysis.codeFiles.length;
85
+ proposalStats.additions += analysis.totalAdditions;
86
+ proposalStats.deletions += analysis.totalDeletions;
87
+ proposalStats.netChanges += analysis.netChanges;
88
+ }
61
89
  }
62
90
  } catch (err) {
63
- _iterator3.e(err);
91
+ _iterator4.e(err);
64
92
  } finally {
65
- _iterator3.f();
93
+ _iterator4.f();
66
94
  }
67
95
  if (!stats.lastCommitDate || analysis.commit.date > stats.lastCommitDate) {
68
96
  stats.lastCommitDate = analysis.commit.date;
@@ -71,11 +99,11 @@ export var StatsAggregator = /*#__PURE__*/function () {
71
99
  stats.firstCommitDate = analysis.commit.date;
72
100
  }
73
101
  if (analysis.commit.branches && stats.branchStats) {
74
- var _iterator4 = _createForOfIteratorHelper(analysis.commit.branches),
75
- _step4;
102
+ var _iterator5 = _createForOfIteratorHelper(analysis.commit.branches),
103
+ _step5;
76
104
  try {
77
- for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
78
- var branch = _step4.value;
105
+ for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
106
+ var branch = _step5.value;
79
107
  var branchStat = stats.branchStats.get(branch);
80
108
  if (!branchStat) {
81
109
  branchStat = {
@@ -94,23 +122,23 @@ export var StatsAggregator = /*#__PURE__*/function () {
94
122
  branchStat.deletions += analysis.totalDeletions;
95
123
  branchStat.netChanges += analysis.netChanges;
96
124
  branchStat.codeFilesChanged += analysis.codeFiles.length;
97
- var _iterator5 = _createForOfIteratorHelper(analysis.openspecProposals),
98
- _step5;
125
+ var _iterator6 = _createForOfIteratorHelper(analysis.openspecProposals),
126
+ _step6;
99
127
  try {
100
- for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
101
- var proposal = _step5.value;
128
+ for (_iterator6.s(); !(_step6 = _iterator6.n()).done;) {
129
+ var proposal = _step6.value;
102
130
  branchStat.openspecProposals.add(proposal);
103
131
  }
104
132
  } catch (err) {
105
- _iterator5.e(err);
133
+ _iterator6.e(err);
106
134
  } finally {
107
- _iterator5.f();
135
+ _iterator6.f();
108
136
  }
109
137
  }
110
138
  } catch (err) {
111
- _iterator4.e(err);
139
+ _iterator5.e(err);
112
140
  } finally {
113
- _iterator4.f();
141
+ _iterator5.f();
114
142
  }
115
143
  }
116
144
  }
@@ -134,13 +162,40 @@ export var StatsAggregator = /*#__PURE__*/function () {
134
162
  } finally {
135
163
  _iterator2.f();
136
164
  }
165
+ var actualBranches = new Set();
166
+ var _iterator3 = _createForOfIteratorHelper(authorStatsMap.values()),
167
+ _step3;
168
+ try {
169
+ for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
170
+ var _stats2 = _step3.value;
171
+ if (_stats2.branchStats) {
172
+ var _iterator7 = _createForOfIteratorHelper(_stats2.branchStats.keys()),
173
+ _step7;
174
+ try {
175
+ for (_iterator7.s(); !(_step7 = _iterator7.n()).done;) {
176
+ var _branch = _step7.value;
177
+ actualBranches.add(_branch);
178
+ }
179
+ } catch (err) {
180
+ _iterator7.e(err);
181
+ } finally {
182
+ _iterator7.f();
183
+ }
184
+ }
185
+ }
186
+ } catch (err) {
187
+ _iterator3.e(err);
188
+ } finally {
189
+ _iterator3.f();
190
+ }
137
191
  return {
138
192
  timeRange: {
139
193
  since: since,
140
194
  until: until
141
195
  },
142
- branches: branches,
196
+ branches: actualBranches.size > 0 ? Array.from(actualBranches) : branches,
143
197
  authors: authorStatsMap,
198
+ proposals: proposalStatsMap,
144
199
  totalCommits: analyses.length
145
200
  };
146
201
  }
@@ -66,6 +66,16 @@ export interface BranchStats {
66
66
  deletions: number;
67
67
  netChanges: number;
68
68
  }
69
+ export interface ProposalStats {
70
+ proposal: string;
71
+ commits: number;
72
+ contributors: Set<string>;
73
+ codeFilesChanged: number;
74
+ additions: number;
75
+ deletions: number;
76
+ netChanges: number;
77
+ commitHashes: Set<string>;
78
+ }
69
79
  export interface StatsResult {
70
80
  timeRange: {
71
81
  since: Date;
@@ -73,5 +83,6 @@ export interface StatsResult {
73
83
  };
74
84
  branches: string[];
75
85
  authors: Map<string, AuthorStats>;
86
+ proposals: Map<string, ProposalStats>;
76
87
  totalCommits: number;
77
88
  }
package/package.json CHANGED
@@ -1,10 +1,11 @@
1
1
  {
2
2
  "name": "openspec-stat",
3
- "version": "1.0.0",
3
+ "version": "1.2.0",
4
4
  "description": "Track team members' OpenSpec proposals and code changes in Git repositories",
5
5
  "main": "dist/cjs/index.js",
6
6
  "types": "dist/cjs/index.d.ts",
7
7
  "type": "module",
8
+ "packageManager": "pnpm@10.12.1",
8
9
  "bin": {
9
10
  "openspec-stat": "dist/esm/cli.js"
10
11
  },
@@ -14,7 +15,20 @@
14
15
  "build:deps": "father prebundle",
15
16
  "prepublishOnly": "father doctor && npm run build",
16
17
  "test:cli": "node dist/esm/cli.js --help",
17
- "link:global": "npm link"
18
+ "link:global": "npm link",
19
+ "link:local": "pnpm run build && chmod +x dist/esm/cli.js && npm link .",
20
+ "unlink": "npm unlink -g openspec-stat",
21
+ "lint": "eslint src --ext .ts,.tsx",
22
+ "lint:fix": "eslint src --ext .ts,.tsx --fix",
23
+ "format": "prettier --write \"src/**/*.{ts,tsx,js,jsx,json,md}\"",
24
+ "format:check": "prettier --check \"src/**/*.{ts,tsx,js,jsx,json,md}\"",
25
+ "prepare": "husky",
26
+ "changeset": "changeset",
27
+ "changeset:add": "changeset add",
28
+ "version": "changeset version && git add . && git commit -m 'chore: version packages'",
29
+ "release": "pnpm run release:version && pnpm run release:tag",
30
+ "release:version": "pnpm changeset version && git add . && git commit -m 'chore: version packages' && git push origin main",
31
+ "release:tag": "git tag v$(node -p \"require('./package.json').version\") && git push origin v$(node -p \"require('./package.json').version\")"
18
32
  },
19
33
  "keywords": [
20
34
  "openspec",
@@ -43,8 +57,26 @@
43
57
  "access": "public"
44
58
  },
45
59
  "devDependencies": {
60
+ "@changesets/cli": "^2.27.1",
46
61
  "@types/node": "^25.0.3",
47
- "father": "^4.6.13"
62
+ "@typescript-eslint/eslint-plugin": "^6.21.0",
63
+ "@typescript-eslint/parser": "^6.21.0",
64
+ "eslint": "^8.56.0",
65
+ "eslint-config-prettier": "^9.1.0",
66
+ "eslint-plugin-prettier": "^5.1.3",
67
+ "father": "^4.6.13",
68
+ "husky": "^9.0.11",
69
+ "lint-staged": "^15.2.2",
70
+ "prettier": "^3.2.5"
71
+ },
72
+ "lint-staged": {
73
+ "*.{ts,tsx}": [
74
+ "eslint --fix",
75
+ "prettier --write"
76
+ ],
77
+ "*.{js,jsx,json,md}": [
78
+ "prettier --write"
79
+ ]
48
80
  },
49
81
  "dependencies": {
50
82
  "@inquirer/prompts": "^8.1.0",