@stackbilt/cli 0.1.6 → 0.1.9

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
@@ -10,7 +10,8 @@ CLI entry point for Charter Kit -- a local-first governance toolkit for software
10
10
  npm install -g @stackbilt/cli
11
11
  ```
12
12
 
13
- This pulls in all Charter Kit packages automatically. You get the `charter` command globally.
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.
14
15
 
15
16
  For CI pipelines, install as a dev dependency instead:
16
17
 
@@ -18,24 +19,76 @@ For CI pipelines, install as a dev dependency instead:
18
19
  npm install --save-dev @stackbilt/cli
19
20
  ```
20
21
 
21
- Requires Node >= 18.
22
-
23
- ## Quick Start
24
-
25
- ```bash
26
- charter setup # bootstrap .charter/ directory
27
- charter doctor # check CLI + config health
28
- charter validate # validate commit governance trailers
29
- charter drift # scan for blessed-stack drift
30
- charter audit # generate governance audit report
31
- charter classify "migrate auth provider"
32
- ```
22
+ Requires Node >= 18.
23
+
24
+ ## Quick Start
25
+
26
+ ```bash
27
+ charter # quick value/risk snapshot + next action
28
+ charter why # why teams adopt Charter and expected payoff
29
+ charter setup # bootstrap .charter/ directory + policy baseline
30
+ charter doctor # check CLI + config health
31
+ charter validate # validate commit governance trailers
32
+ charter drift # scan for blessed-stack drift
33
+ charter audit # generate governance audit report
34
+ charter classify "migrate auth provider"
35
+ ```
36
+
37
+ ## Human Onboarding (Copy/Paste)
38
+
39
+ Run this in the target repository:
40
+
41
+ ```bash
42
+ npm install -g @stackbilt/cli
43
+ charter
44
+ charter setup --ci github
45
+ charter doctor --format json
46
+ charter validate --format text
47
+ charter drift --format text
48
+ charter audit --format text
49
+ ```
50
+
51
+ This ensures people immediately see:
52
+ - what Charter is doing in their repo
53
+ - where baseline files were created (`.charter/*`)
54
+ - how policy checks behave before merge
55
+
56
+ ## LM Agent Onboarding (Deterministic)
57
+
58
+ Use JSON output and explicit CI semantics:
59
+
60
+ ```bash
61
+ charter --format json
62
+ charter setup --ci github --yes --format json
63
+ charter doctor --format json
64
+ charter validate --format json --ci
65
+ charter drift --format json --ci
66
+ charter audit --format json
67
+ ```
68
+
69
+ Agent handling contract:
70
+ - `exit 0`: pass
71
+ - `exit 1`: policy violation (action required)
72
+ - `exit 2`: runtime/usage failure
33
73
 
34
74
  ## Commands
35
75
 
36
- ### `charter setup`
37
-
38
- Bootstrap `.charter/` with config, patterns, and policies. Optionally generates a GitHub Actions workflow.
76
+ ### `charter` (no args)
77
+
78
+ Default first-run experience. Shows:
79
+ - repository governance baseline status
80
+ - commit governance coverage snapshot
81
+ - high-risk unlinked commit count
82
+ - one recommended next action
83
+
84
+ ### `charter why`
85
+
86
+ Explains the adoption case in plain terms (problem, what Charter enforces, expected operational payoff).
87
+
88
+ ### `charter setup`
89
+
90
+ Bootstrap `.charter/` with config, patterns, and policies. Optionally generates a GitHub Actions workflow.
91
+ This is the command that applies Charter governance into a repository.
39
92
 
40
93
  ```bash
41
94
  charter setup --ci github --yes
@@ -69,13 +122,13 @@ charter drift --path ./src --ci
69
122
 
70
123
  Generate a governance audit report covering trailers, risk, and drift.
71
124
 
72
- ### `charter classify`
125
+ ### `charter classify`
73
126
 
74
127
  Classify a change as `SURFACE`, `LOCAL`, or `CROSS_CUTTING`.
75
128
 
76
129
  ```bash
77
- charter classify "update button color"
78
- ```
130
+ charter classify "update button color"
131
+ ```
79
132
 
80
133
  ## Global Options
81
134
 
@@ -107,17 +107,22 @@ async function setupCommand(options, args) {
107
107
  console.log(JSON.stringify(result, null, 2));
108
108
  return index_2.EXIT_CODE.SUCCESS;
109
109
  }
110
- console.log(' Charter setup complete.');
111
- console.log(` Config path: ${result.configPath}`);
112
- console.log(` .charter initialized: ${result.initialized ? 'yes' : 'already present'}`);
110
+ console.log(' Governance guardrails are now active for this repo.');
111
+ console.log(` Baseline path: ${result.configPath}`);
112
+ console.log(` Baseline created: ${result.initialized ? 'yes' : 'already present'}`);
113
113
  if (result.workflow.mode === 'github') {
114
- console.log(` GitHub workflow: ${result.workflow.created ? 'created' : 'already present'} (${result.workflow.path})`);
114
+ console.log(` CI policy gate: ${result.workflow.created ? 'enabled' : 'already present'} (${result.workflow.path})`);
115
115
  }
116
116
  console.log('');
117
- console.log(' Next steps:');
118
- console.log(' 1. Run: charter validate --format text');
119
- console.log(' 2. Run: charter drift --format text');
120
- console.log(' 3. Tune .charter/config.json and patterns/*.json');
117
+ console.log(' What this gives you immediately:');
118
+ console.log(' - Merge-time checks for risky changes without governance links');
119
+ console.log(' - Drift detection against your blessed stack');
120
+ console.log(' - Audit-ready governance evidence from repo history');
121
+ console.log('');
122
+ console.log(' Run now:');
123
+ console.log(' 1. charter validate --format text');
124
+ console.log(' 2. charter drift --format text');
125
+ console.log(' 3. charter audit --format text');
121
126
  return index_2.EXIT_CODE.SUCCESS;
122
127
  }
123
128
  function writeFileIfMissing(targetPath, content, force) {
@@ -137,4 +142,4 @@ function getFlag(args, flag) {
137
142
  }
138
143
  return undefined;
139
144
  }
140
- //# sourceMappingURL=setup.js.map
145
+ //# sourceMappingURL=setup.js.map
@@ -0,0 +1,3 @@
1
+ import type { CLIOptions } from '../index';
2
+ export declare function quickstartCommand(options: CLIOptions): Promise<number>;
3
+ export declare function whyCommand(options: CLIOptions): Promise<number>;
@@ -0,0 +1,168 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.quickstartCommand = quickstartCommand;
4
+ exports.whyCommand = whyCommand;
5
+ const node_child_process_1 = require("node:child_process");
6
+ const fs = require("node:fs");
7
+ const path = require("node:path");
8
+ const index_1 = require("../index");
9
+ const git_1 = require("@stackbilt/git");
10
+ async function quickstartCommand(options) {
11
+ const snapshot = getSnapshot(options.configPath);
12
+ if (options.format === 'json') {
13
+ console.log(JSON.stringify(snapshot, null, 2));
14
+ return index_1.EXIT_CODE.SUCCESS;
15
+ }
16
+ console.log('');
17
+ console.log(' Charter Quickstart');
18
+ console.log(' Turns governance from abstract policy into merge-time guardrails.');
19
+ console.log('');
20
+ console.log(' Repo snapshot:');
21
+ console.log(` - Git repo: ${snapshot.inGitRepo ? 'yes' : 'no'}`);
22
+ console.log(` - Governance baseline (.charter): ${snapshot.hasBaseline ? 'installed' : 'missing'}`);
23
+ console.log(` - Recent commits scanned: ${snapshot.commitsScanned}`);
24
+ console.log(` - Governance-linked commit coverage: ${snapshot.coveragePercent}%`);
25
+ console.log(` - High-risk commits without governance links: ${snapshot.highRiskUnlinked}`);
26
+ console.log('');
27
+ console.log(' Why teams use Charter:');
28
+ console.log(' - Catch risky, unreviewed changes before merge');
29
+ console.log(' - Create an auditable trail from code changes to governance decisions');
30
+ console.log(' - Keep policy checks consistent across local dev and CI');
31
+ console.log('');
32
+ console.log(` Next action: ${snapshot.nextAction}`);
33
+ console.log('');
34
+ return index_1.EXIT_CODE.SUCCESS;
35
+ }
36
+ async function whyCommand(options) {
37
+ if (options.format === 'json') {
38
+ console.log(JSON.stringify({
39
+ problem: 'Teams lose context on risky changes and approvals become inconsistent.',
40
+ charterSolves: [
41
+ 'Enforces governance trailers for significant changes',
42
+ 'Scans for stack drift against blessed patterns',
43
+ 'Produces repeatable audit evidence for PRs and reviews',
44
+ ],
45
+ value: [
46
+ 'Lower probability of breaking changes landing without architectural context',
47
+ 'Faster reviews because reviewers see linked decisions in commit metadata',
48
+ 'Clear governance posture for leadership and compliance reporting',
49
+ ],
50
+ start: 'charter setup --ci github',
51
+ }, null, 2));
52
+ return index_1.EXIT_CODE.SUCCESS;
53
+ }
54
+ console.log('');
55
+ console.log(' Why Charter');
56
+ console.log('');
57
+ console.log(' Problem it solves:');
58
+ console.log(' Governance intent lives in docs, but risky changes merge without clear decision links.');
59
+ console.log('');
60
+ console.log(' What Charter does:');
61
+ console.log(' - Enforces commit-level governance links for significant changes');
62
+ console.log(' - Detects drift from your blessed architecture patterns');
63
+ console.log(' - Generates audit output leadership and reviewers can actually use');
64
+ console.log('');
65
+ console.log(' Expected payoff:');
66
+ console.log(' - Fewer high-impact surprises in production');
67
+ console.log(' - Faster review cycles with clearer architectural accountability');
68
+ console.log(' - Consistent governance behavior across repos');
69
+ console.log('');
70
+ console.log(' Start here: charter setup --ci github');
71
+ console.log('');
72
+ return index_1.EXIT_CODE.SUCCESS;
73
+ }
74
+ function getSnapshot(configPath) {
75
+ const inGitRepo = isGitRepo();
76
+ const hasBaseline = fs.existsSync(path.join(configPath, 'config.json'));
77
+ if (!inGitRepo) {
78
+ return {
79
+ inGitRepo,
80
+ hasBaseline,
81
+ commitsScanned: 0,
82
+ coveragePercent: 0,
83
+ highRiskUnlinked: 0,
84
+ nextAction: 'Run this inside a git repository, then run: charter setup --ci github',
85
+ };
86
+ }
87
+ const commits = hasCommits() ? getRecentCommits(20) : [];
88
+ const parsed = (0, git_1.parseAllTrailers)(commits);
89
+ const linked = new Set();
90
+ for (const t of parsed.governedBy)
91
+ linked.add(t.commitSha);
92
+ for (const t of parsed.resolvesRequest)
93
+ linked.add(t.commitSha);
94
+ let highRiskUnlinked = 0;
95
+ for (const commit of commits) {
96
+ if (!linked.has(commit.sha) && (0, git_1.assessCommitRisk)(commit.files_changed, commit.message) === 'HIGH') {
97
+ highRiskUnlinked++;
98
+ }
99
+ }
100
+ const coveragePercent = commits.length > 0 ? Math.round((linked.size / commits.length) * 100) : 0;
101
+ const nextAction = !hasBaseline
102
+ ? 'Run: charter setup --ci github'
103
+ : highRiskUnlinked > 0
104
+ ? 'Run: charter validate --format text and add Governed-By trailers to high-risk commits'
105
+ : 'Run: charter audit --format text for a shareable governance posture report';
106
+ return {
107
+ inGitRepo,
108
+ hasBaseline,
109
+ commitsScanned: commits.length,
110
+ coveragePercent,
111
+ highRiskUnlinked,
112
+ nextAction,
113
+ };
114
+ }
115
+ function isGitRepo() {
116
+ try {
117
+ (0, node_child_process_1.execFileSync)('git', ['rev-parse', '--is-inside-work-tree'], { stdio: 'ignore' });
118
+ return true;
119
+ }
120
+ catch {
121
+ return false;
122
+ }
123
+ }
124
+ function getRecentCommits(count) {
125
+ try {
126
+ const log = (0, node_child_process_1.execFileSync)('git', ['log', `-${count}`, '--format=%H|%s', '--name-only'], {
127
+ encoding: 'utf-8',
128
+ maxBuffer: 10 * 1024 * 1024,
129
+ stdio: ['ignore', 'pipe', 'ignore'],
130
+ });
131
+ const commits = [];
132
+ let current = null;
133
+ for (const line of log.split('\n')) {
134
+ if (line.includes('|') && line.length > 40) {
135
+ if (current)
136
+ commits.push(current);
137
+ const [sha, ...message] = line.split('|');
138
+ current = {
139
+ sha,
140
+ author: '',
141
+ timestamp: '',
142
+ message: message.join('|'),
143
+ files_changed: [],
144
+ };
145
+ }
146
+ else if (line.trim() && current) {
147
+ current.files_changed.push(line.trim());
148
+ }
149
+ }
150
+ if (current)
151
+ commits.push(current);
152
+ return commits;
153
+ }
154
+ catch {
155
+ return [];
156
+ }
157
+ }
158
+ function hasCommits() {
159
+ try {
160
+ (0, node_child_process_1.execFileSync)('git', ['rev-parse', '--verify', 'HEAD'], {
161
+ stdio: 'ignore',
162
+ });
163
+ return true;
164
+ }
165
+ catch {
166
+ return false;
167
+ }
168
+ }
package/dist/index.js CHANGED
@@ -15,18 +15,21 @@ const validate_1 = require("./commands/validate");
15
15
  const audit_1 = require("./commands/audit");
16
16
  const drift_1 = require("./commands/drift");
17
17
  const classify_1 = require("./commands/classify");
18
+ const why_1 = require("./commands/why");
18
19
  const package_json_1 = require("../package.json");
19
20
  const CLI_VERSION = package_json_1.version;
20
21
  const HELP = `
21
22
  charter - repo-level governance toolkit
22
23
 
23
24
  Usage:
25
+ charter Show immediate governance value + risk snapshot
24
26
  charter setup [--ci github] Bootstrap .charter/ and optional CI workflow
25
27
  charter init Scaffold .charter/ config directory
26
28
  charter validate Validate git commits for governance trailers
27
29
  charter audit Generate governance audit report
28
30
  charter drift [--path <dir>] Scan files for pattern drift
29
31
  charter classify <subject> Classify a change (SURFACE/LOCAL/CROSS_CUTTING)
32
+ charter why Explain why teams adopt Charter and expected ROI
30
33
  charter doctor Check CLI + config health
31
34
  charter --help Show this help
32
35
  charter --version Show version
@@ -52,7 +55,7 @@ class CLIError extends Error {
52
55
  }
53
56
  exports.CLIError = CLIError;
54
57
  async function run(args) {
55
- if (args.length === 0 || args.includes('--help') || args.includes('-h')) {
58
+ if (args.includes('--help') || args.includes('-h')) {
56
59
  console.log(HELP);
57
60
  return exports.EXIT_CODE.SUCCESS;
58
61
  }
@@ -60,18 +63,21 @@ async function run(args) {
60
63
  console.log(`charter v${CLI_VERSION}`);
61
64
  return exports.EXIT_CODE.SUCCESS;
62
65
  }
63
- const command = args[0];
64
- const restArgs = args.slice(1);
65
- const format = getFlag(restArgs, '--format') || 'text';
66
+ const format = getFlag(args, '--format') || 'text';
66
67
  if (format !== 'text' && format !== 'json') {
67
68
  throw new CLIError(`Invalid --format value: ${format}. Use text or json.`);
68
69
  }
69
70
  const options = {
70
- configPath: getFlag(restArgs, '--config') || '.charter',
71
+ configPath: getFlag(args, '--config') || '.charter',
71
72
  format,
72
- ciMode: restArgs.includes('--ci'),
73
- yes: restArgs.includes('--yes'),
73
+ ciMode: args.includes('--ci'),
74
+ yes: args.includes('--yes'),
74
75
  };
76
+ if (args.length === 0 || args[0].startsWith('-')) {
77
+ return (0, why_1.quickstartCommand)(options);
78
+ }
79
+ const command = args[0];
80
+ const restArgs = args.slice(1);
75
81
  switch (command) {
76
82
  case 'setup':
77
83
  return (0, setup_1.setupCommand)(options, restArgs);
@@ -85,6 +91,8 @@ async function run(args) {
85
91
  return (0, drift_1.driftCommand)(options, restArgs);
86
92
  case 'classify':
87
93
  return (0, classify_1.classifyCommand)(options, restArgs);
94
+ case 'why':
95
+ return (0, why_1.whyCommand)(options);
88
96
  case 'doctor':
89
97
  return (0, doctor_1.doctorCommand)(options);
90
98
  default:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stackbilt/cli",
3
- "version": "0.1.6",
3
+ "version": "0.1.9",
4
4
  "description": "Charter CLI — repo-level governance checks",
5
5
  "bin": {
6
6
  "charter": "./dist/bin.js"
@@ -37,12 +37,12 @@
37
37
  "build": "pnpm exec tsc -p tsconfig.json"
38
38
  },
39
39
  "dependencies": {
40
- "@stackbilt/types": "^0.1.3",
41
- "@stackbilt/core": "^0.1.3",
42
- "@stackbilt/git": "^0.1.4",
43
- "@stackbilt/classify": "^0.1.4",
44
- "@stackbilt/validate": "^0.1.4",
45
- "@stackbilt/drift": "^0.1.4"
40
+ "@stackbilt/types": "^0.1.9",
41
+ "@stackbilt/core": "^0.1.9",
42
+ "@stackbilt/git": "^0.1.9",
43
+ "@stackbilt/classify": "^0.1.9",
44
+ "@stackbilt/validate": "^0.1.9",
45
+ "@stackbilt/drift": "^0.1.9"
46
46
  },
47
47
  "license": "Apache-2.0"
48
48
  }