@stackbilt/cli 0.1.9 → 0.1.10

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/README.md CHANGED
@@ -4,16 +4,28 @@ CLI entry point for Charter Kit -- a local-first governance toolkit for software
4
4
 
5
5
  > **This is the only package most users need.** One install gives you the full Charter Kit toolkit.
6
6
 
7
- ## Install
8
-
9
- ```bash
10
- npm install -g @stackbilt/cli
11
- ```
12
-
13
- This pulls in all Charter Kit packages automatically. You get the `charter` command globally.
14
- Use `charter setup` inside each repo to scaffold governance baseline files.
15
-
16
- For CI pipelines, install as a dev dependency instead:
7
+ ## Install (Recommended)
8
+
9
+ ```bash
10
+ npm install --save-dev @stackbilt/cli
11
+ ```
12
+
13
+ Use with `npx` in each repository:
14
+
15
+ ```bash
16
+ npx charter
17
+ npx charter setup --ci github
18
+ ```
19
+
20
+ Global install is optional if you want `charter` available system-wide:
21
+
22
+ ```bash
23
+ npm install -g @stackbilt/cli
24
+ ```
25
+
26
+ This pulls in all Charter Kit packages automatically. Use `charter setup` inside each repo to scaffold governance baseline files.
27
+
28
+ For CI pipelines, install as a dev dependency:
17
29
 
18
30
  ```bash
19
31
  npm install --save-dev @stackbilt/cli
@@ -91,6 +91,11 @@ function generateAuditReport(projectName, configPath, patterns) {
91
91
  const patternScore = Math.min(100, activePatterns.length * 20);
92
92
  const policyScore = Math.min(100, policyFiles.length * 33);
93
93
  const overall = Math.round((trailerScore * 0.5) + (patternScore * 0.3) + (policyScore * 0.2));
94
+ const scoreInputs = {
95
+ coveragePercent,
96
+ activePatterns: activePatterns.length,
97
+ policyFiles: policyFiles.length,
98
+ };
94
99
  return {
95
100
  project: projectName,
96
101
  generatedAt: new Date().toISOString(),
@@ -118,6 +123,12 @@ function generateAuditReport(projectName, configPath, patterns) {
118
123
  patternDefinitions: Math.round(patternScore),
119
124
  policyDocumentation: Math.round(policyScore),
120
125
  },
126
+ criteria: {
127
+ trailerCoverage: 'coverage_percent * 1.5 (max 100). 67%+ coverage earns full points.',
128
+ patternDefinitions: 'active_pattern_count * 20 (max 100). 5+ active patterns earns full points.',
129
+ policyDocumentation: 'policy_markdown_files * 33 (max 100). 3+ policy files earns full points.',
130
+ },
131
+ recommendations: getRecommendations(scoreInputs),
121
132
  },
122
133
  };
123
134
  }
@@ -151,6 +162,16 @@ function printReport(report) {
151
162
  console.log(` Pattern definitions: ${report.score.breakdown.patternDefinitions}/100 (30% weight)`);
152
163
  console.log(` Policy documentation: ${report.score.breakdown.policyDocumentation}/100 (20% weight)`);
153
164
  console.log('');
165
+ console.log(' Scoring Criteria');
166
+ console.log(` - Trailer coverage: ${report.score.criteria.trailerCoverage}`);
167
+ console.log(` - Pattern definitions: ${report.score.criteria.patternDefinitions}`);
168
+ console.log(` - Policy documentation: ${report.score.criteria.policyDocumentation}`);
169
+ console.log('');
170
+ console.log(' Actionable Next Steps');
171
+ for (const rec of report.score.recommendations) {
172
+ console.log(` - ${rec}`);
173
+ }
174
+ console.log('');
154
175
  }
155
176
  function getRecentCommits(count) {
156
177
  try {
@@ -193,6 +214,32 @@ function runGit(args) {
193
214
  return (0, node_child_process_1.execFileSync)('git', args, {
194
215
  encoding: 'utf-8',
195
216
  maxBuffer: 10 * 1024 * 1024,
217
+ stdio: ['ignore', 'pipe', 'pipe'],
196
218
  });
197
219
  }
220
+ function getRecommendations(inputs) {
221
+ const recommendations = [];
222
+ const missingCoverage = Math.max(0, 67 - inputs.coveragePercent);
223
+ if (missingCoverage > 0) {
224
+ recommendations.push(`Increase governance trailer coverage by ${missingCoverage}% to reach full trailer score (add Governed-By/Resolves-Request trailers).`);
225
+ }
226
+ else {
227
+ recommendations.push('Trailer coverage is at full-score threshold.');
228
+ }
229
+ const missingPatterns = Math.max(0, 5 - inputs.activePatterns);
230
+ if (missingPatterns > 0) {
231
+ recommendations.push(`Add ${missingPatterns} active pattern(s) in .charter/patterns/*.json to reach full pattern score (target: 5 active patterns).`);
232
+ }
233
+ else {
234
+ recommendations.push('Pattern definitions are at full-score threshold.');
235
+ }
236
+ const missingPolicies = Math.max(0, 3 - inputs.policyFiles);
237
+ if (missingPolicies > 0) {
238
+ recommendations.push(`Add ${missingPolicies} policy markdown file(s) in .charter/policies/ to reach full policy score (target: 3 policy files).`);
239
+ }
240
+ else {
241
+ recommendations.push('Policy documentation is at full-score threshold.');
242
+ }
243
+ return recommendations;
244
+ }
198
245
  //# sourceMappingURL=audit.js.map
@@ -14,8 +14,32 @@ const git_1 = require("@stackbilt/git");
14
14
  const git_2 = require("@stackbilt/git");
15
15
  async function validateCommand(options, args) {
16
16
  const config = (0, config_1.loadConfig)(options.configPath);
17
+ if (!hasCommits()) {
18
+ if (options.format === 'json') {
19
+ console.log(JSON.stringify({ status: 'PASS', summary: 'No commits to validate.' }, null, 2));
20
+ }
21
+ else {
22
+ console.log(' No commits to validate.');
23
+ }
24
+ return index_1.EXIT_CODE.SUCCESS;
25
+ }
17
26
  const range = getCommitRange(args);
18
- const commits = getGitCommits(range);
27
+ const commitLoad = getGitCommits(range);
28
+ if (commitLoad.error) {
29
+ if (options.format === 'json') {
30
+ console.log(JSON.stringify({
31
+ status: 'ERROR',
32
+ summary: 'Failed to read git commits for validation.',
33
+ details: commitLoad.error,
34
+ }, null, 2));
35
+ }
36
+ else {
37
+ console.log(' [fail] Failed to read git commits for validation.');
38
+ console.log(` ${commitLoad.error}`);
39
+ }
40
+ return index_1.EXIT_CODE.RUNTIME_ERROR;
41
+ }
42
+ const commits = commitLoad.commits;
19
43
  if (commits.length === 0) {
20
44
  if (options.format === 'json') {
21
45
  console.log(JSON.stringify({ status: 'PASS', summary: 'No commits to validate.' }, null, 2));
@@ -123,6 +147,7 @@ function getCommitRange(args) {
123
147
  if (rangeIdx !== -1 && rangeIdx + 1 < args.length) {
124
148
  return args[rangeIdx + 1];
125
149
  }
150
+ const recentRange = getRecentCommitRange();
126
151
  try {
127
152
  const currentBranch = runGit(['rev-parse', 'HEAD']).trim();
128
153
  let baseBranch = '';
@@ -133,12 +158,12 @@ function getCommitRange(args) {
133
158
  baseBranch = runGit(['rev-parse', '--verify', 'master']).trim();
134
159
  }
135
160
  if (!baseBranch || baseBranch === currentBranch) {
136
- return 'HEAD~5..HEAD';
161
+ return recentRange;
137
162
  }
138
163
  return `${baseBranch}..HEAD`;
139
164
  }
140
165
  catch {
141
- return 'HEAD~5..HEAD';
166
+ return recentRange;
142
167
  }
143
168
  }
144
169
  function getGitCommits(range) {
@@ -165,16 +190,58 @@ function getGitCommits(range) {
165
190
  }
166
191
  if (current)
167
192
  commits.push(current);
168
- return commits;
193
+ return { commits };
194
+ }
195
+ catch (error) {
196
+ return {
197
+ commits: [],
198
+ error: getGitErrorMessage(error),
199
+ };
200
+ }
201
+ }
202
+ function hasCommits() {
203
+ try {
204
+ runGit(['rev-parse', '--verify', 'HEAD']);
205
+ return true;
169
206
  }
170
207
  catch {
171
- return [];
208
+ return false;
209
+ }
210
+ }
211
+ function getRecentCommitRange() {
212
+ try {
213
+ const count = Number.parseInt(runGit(['rev-list', '--count', 'HEAD']).trim(), 10);
214
+ if (!Number.isFinite(count) || count <= 1) {
215
+ return 'HEAD';
216
+ }
217
+ const span = Math.min(5, count - 1);
218
+ return `HEAD~${span}..HEAD`;
219
+ }
220
+ catch {
221
+ return 'HEAD';
222
+ }
223
+ }
224
+ function getGitErrorMessage(error) {
225
+ const fallback = 'Unknown git error.';
226
+ if (!(error instanceof Error))
227
+ return fallback;
228
+ const execError = error;
229
+ if (execError.stderr) {
230
+ const stderr = execError.stderr.toString().trim();
231
+ if (stderr.length > 0) {
232
+ return stderr;
233
+ }
234
+ }
235
+ if (execError.message) {
236
+ return execError.message.trim();
172
237
  }
238
+ return fallback;
173
239
  }
174
240
  function runGit(args) {
175
241
  return (0, node_child_process_1.execFileSync)('git', args, {
176
242
  encoding: 'utf-8',
177
243
  maxBuffer: 10 * 1024 * 1024,
244
+ stdio: ['ignore', 'pipe', 'pipe'],
178
245
  });
179
246
  }
180
247
  //# sourceMappingURL=validate.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stackbilt/cli",
3
- "version": "0.1.9",
3
+ "version": "0.1.10",
4
4
  "description": "Charter CLI — repo-level governance checks",
5
5
  "bin": {
6
6
  "charter": "./dist/bin.js"