@stackbilt/cli 0.1.1
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/dist/__tests__/classify.test.d.ts +2 -0
- package/dist/__tests__/classify.test.d.ts.map +1 -0
- package/dist/__tests__/classify.test.js +41 -0
- package/dist/__tests__/classify.test.js.map +1 -0
- package/dist/bin.d.ts +6 -0
- package/dist/bin.d.ts.map +1 -0
- package/dist/bin.js +22 -0
- package/dist/bin.js.map +1 -0
- package/dist/commands/audit.d.ts +9 -0
- package/dist/commands/audit.d.ts.map +1 -0
- package/dist/commands/audit.js +192 -0
- package/dist/commands/audit.js.map +1 -0
- package/dist/commands/classify.d.ts +9 -0
- package/dist/commands/classify.d.ts.map +1 -0
- package/dist/commands/classify.js +45 -0
- package/dist/commands/classify.js.map +1 -0
- package/dist/commands/doctor.d.ts +8 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +130 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/drift.d.ts +9 -0
- package/dist/commands/drift.d.ts.map +1 -0
- package/dist/commands/drift.js +178 -0
- package/dist/commands/drift.js.map +1 -0
- package/dist/commands/init.d.ts +15 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +141 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/setup.d.ts +8 -0
- package/dist/commands/setup.d.ts.map +1 -0
- package/dist/commands/setup.js +140 -0
- package/dist/commands/setup.js.map +1 -0
- package/dist/commands/validate.d.ts +9 -0
- package/dist/commands/validate.d.ts.map +1 -0
- package/dist/commands/validate.js +170 -0
- package/dist/commands/validate.js.map +1 -0
- package/dist/config.d.ts +60 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +145 -0
- package/dist/config.js.map +1 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +99 -0
- package/dist/index.js.map +1 -0
- package/package.json +48 -0
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* charter validate
|
|
4
|
+
*
|
|
5
|
+
* Validates recent git commits for governance trailers.
|
|
6
|
+
* Checks that high-risk commits reference ADRs or governance requests.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.validateCommand = validateCommand;
|
|
10
|
+
const node_child_process_1 = require("node:child_process");
|
|
11
|
+
const index_1 = require("../index");
|
|
12
|
+
const config_1 = require("../config");
|
|
13
|
+
const git_1 = require("@stackbilt/git");
|
|
14
|
+
const git_2 = require("@stackbilt/git");
|
|
15
|
+
async function validateCommand(options, args) {
|
|
16
|
+
const config = (0, config_1.loadConfig)(options.configPath);
|
|
17
|
+
const range = getCommitRange(args);
|
|
18
|
+
const commits = getGitCommits(range);
|
|
19
|
+
if (commits.length === 0) {
|
|
20
|
+
if (options.format === 'json') {
|
|
21
|
+
console.log(JSON.stringify({ status: 'PASS', summary: 'No commits to validate.' }, null, 2));
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
console.log(' No commits to validate.');
|
|
25
|
+
}
|
|
26
|
+
return index_1.EXIT_CODE.SUCCESS;
|
|
27
|
+
}
|
|
28
|
+
const result = validateCommits(commits, config.git.trailerThreshold);
|
|
29
|
+
if (options.format === 'json') {
|
|
30
|
+
console.log(JSON.stringify(result, null, 2));
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
printResult(result);
|
|
34
|
+
}
|
|
35
|
+
if (options.ciMode && (result.status === 'FAIL' || (config.ci.failOnWarn && result.status === 'WARN'))) {
|
|
36
|
+
return index_1.EXIT_CODE.POLICY_VIOLATION;
|
|
37
|
+
}
|
|
38
|
+
return index_1.EXIT_CODE.SUCCESS;
|
|
39
|
+
}
|
|
40
|
+
function validateCommits(commits, threshold) {
|
|
41
|
+
const parsed = (0, git_1.parseAllTrailers)(commits);
|
|
42
|
+
const linkedCommits = new Set();
|
|
43
|
+
parsed.governedBy.forEach((t) => linkedCommits.add(t.commitSha));
|
|
44
|
+
parsed.resolvesRequest.forEach((t) => linkedCommits.add(t.commitSha));
|
|
45
|
+
const unlinked = [];
|
|
46
|
+
let highRiskUnlinked = 0;
|
|
47
|
+
const thresholdRanks = { LOW: 0, MEDIUM: 1, HIGH: 2 };
|
|
48
|
+
const thresholdRank = thresholdRanks[threshold];
|
|
49
|
+
for (const commit of commits) {
|
|
50
|
+
if (!linkedCommits.has(commit.sha)) {
|
|
51
|
+
const risk = (0, git_2.assessCommitRisk)(commit.files_changed, commit.message);
|
|
52
|
+
const riskRank = thresholdRanks[risk];
|
|
53
|
+
if (riskRank >= thresholdRank) {
|
|
54
|
+
unlinked.push({ sha: commit.sha, message: commit.message.split('\n')[0], risk });
|
|
55
|
+
if (risk === 'HIGH')
|
|
56
|
+
highRiskUnlinked++;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
const trailers = {
|
|
61
|
+
governed_by: parsed.governedBy.map((t) => ({
|
|
62
|
+
commit_sha: t.commitSha,
|
|
63
|
+
reference: t.reference,
|
|
64
|
+
valid: true,
|
|
65
|
+
resolved_id: null,
|
|
66
|
+
ledger_entry_id: null,
|
|
67
|
+
})),
|
|
68
|
+
resolves_request: parsed.resolvesRequest.map((t) => ({
|
|
69
|
+
commit_sha: t.commitSha,
|
|
70
|
+
reference: t.reference,
|
|
71
|
+
valid: true,
|
|
72
|
+
resolved_id: null,
|
|
73
|
+
request_id: null,
|
|
74
|
+
})),
|
|
75
|
+
};
|
|
76
|
+
const unlinkedForSuggestions = unlinked.map((u) => ({
|
|
77
|
+
sha: u.sha,
|
|
78
|
+
short_sha: u.sha.slice(0, 7),
|
|
79
|
+
message_first_line: u.message.slice(0, 72),
|
|
80
|
+
risk_level: u.risk,
|
|
81
|
+
suggestion: u.risk === 'HIGH'
|
|
82
|
+
? 'HIGH-risk changes should reference governance. Add: Governed-By: <adr-id>'
|
|
83
|
+
: 'Consider adding governance reference for traceability.',
|
|
84
|
+
}));
|
|
85
|
+
const suggestions = (0, git_2.generateSuggestions)(trailers, unlinkedForSuggestions, commits.length);
|
|
86
|
+
let status;
|
|
87
|
+
if (highRiskUnlinked > 0) {
|
|
88
|
+
status = 'FAIL';
|
|
89
|
+
}
|
|
90
|
+
else if (unlinked.length > 0) {
|
|
91
|
+
status = 'WARN';
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
status = 'PASS';
|
|
95
|
+
}
|
|
96
|
+
const totalTrailers = parsed.governedBy.length + parsed.resolvesRequest.length;
|
|
97
|
+
return {
|
|
98
|
+
status,
|
|
99
|
+
summary: status === 'PASS'
|
|
100
|
+
? `All ${commits.length} commit(s) pass governance checks.`
|
|
101
|
+
: `${unlinked.length} commit(s) above ${threshold} risk threshold without governance trailers.`,
|
|
102
|
+
commits: commits.length,
|
|
103
|
+
trailersFound: totalTrailers,
|
|
104
|
+
highRiskUnlinked,
|
|
105
|
+
suggestions,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
function printResult(result) {
|
|
109
|
+
const icon = result.status === 'PASS' ? '[ok]' : result.status === 'WARN' ? '[warn]' : '[fail]';
|
|
110
|
+
console.log(`\n ${icon} ${result.status}: ${result.summary}`);
|
|
111
|
+
console.log(` Commits: ${result.commits} | Trailers found: ${result.trailersFound}`);
|
|
112
|
+
if (result.suggestions.length > 0) {
|
|
113
|
+
console.log('');
|
|
114
|
+
console.log(' Suggestions:');
|
|
115
|
+
for (const s of result.suggestions) {
|
|
116
|
+
console.log(` - ${s}`);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
console.log('');
|
|
120
|
+
}
|
|
121
|
+
function getCommitRange(args) {
|
|
122
|
+
const rangeIdx = args.indexOf('--range');
|
|
123
|
+
if (rangeIdx !== -1 && rangeIdx + 1 < args.length) {
|
|
124
|
+
return args[rangeIdx + 1];
|
|
125
|
+
}
|
|
126
|
+
try {
|
|
127
|
+
const mainBranch = (0, node_child_process_1.execSync)('git rev-parse --verify main 2>/dev/null || git rev-parse --verify master 2>/dev/null', {
|
|
128
|
+
encoding: 'utf-8',
|
|
129
|
+
}).trim();
|
|
130
|
+
const currentBranch = (0, node_child_process_1.execSync)('git rev-parse HEAD', { encoding: 'utf-8' }).trim();
|
|
131
|
+
if (mainBranch === currentBranch) {
|
|
132
|
+
return 'HEAD~5..HEAD';
|
|
133
|
+
}
|
|
134
|
+
return `${mainBranch}..HEAD`;
|
|
135
|
+
}
|
|
136
|
+
catch {
|
|
137
|
+
return 'HEAD~5..HEAD';
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
function getGitCommits(range) {
|
|
141
|
+
try {
|
|
142
|
+
const log = (0, node_child_process_1.execSync)(`git log ${range} --format='%H|%an|%aI|%s' --name-only`, { encoding: 'utf-8', maxBuffer: 10 * 1024 * 1024 });
|
|
143
|
+
const commits = [];
|
|
144
|
+
let current = null;
|
|
145
|
+
for (const line of log.split('\n')) {
|
|
146
|
+
if (line.includes('|') && line.length > 40) {
|
|
147
|
+
if (current)
|
|
148
|
+
commits.push(current);
|
|
149
|
+
const [sha, author, timestamp, ...msgParts] = line.split('|');
|
|
150
|
+
current = {
|
|
151
|
+
sha: sha.replace(/'/g, ''),
|
|
152
|
+
author,
|
|
153
|
+
timestamp,
|
|
154
|
+
message: msgParts.join('|'),
|
|
155
|
+
files_changed: [],
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
else if (line.trim() && current) {
|
|
159
|
+
current.files_changed.push(line.trim());
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
if (current)
|
|
163
|
+
commits.push(current);
|
|
164
|
+
return commits;
|
|
165
|
+
}
|
|
166
|
+
catch {
|
|
167
|
+
return [];
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
//# sourceMappingURL=validate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate.js","sourceRoot":"","sources":["../../src/commands/validate.ts"],"names":[],"mappings":"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"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* .charter/ Config Loader
|
|
3
|
+
*
|
|
4
|
+
* Loads governance configuration from the .charter/ directory.
|
|
5
|
+
* Config format is kept simple for v0.1 — YAML support comes later.
|
|
6
|
+
* For now, we use JSON config files.
|
|
7
|
+
*/
|
|
8
|
+
import type { Pattern } from '@stackbilt/types';
|
|
9
|
+
export interface CharterConfig {
|
|
10
|
+
/** Project name */
|
|
11
|
+
project: string;
|
|
12
|
+
/** Version of config schema */
|
|
13
|
+
version: string;
|
|
14
|
+
/** Git validation settings */
|
|
15
|
+
git: {
|
|
16
|
+
/** Require Governed-By trailers on high-risk commits */
|
|
17
|
+
requireTrailers: boolean;
|
|
18
|
+
/** Risk level threshold for requiring trailers: LOW, MEDIUM, HIGH */
|
|
19
|
+
trailerThreshold: 'LOW' | 'MEDIUM' | 'HIGH';
|
|
20
|
+
};
|
|
21
|
+
/** Drift scanning settings */
|
|
22
|
+
drift: {
|
|
23
|
+
/** Enable drift scanning */
|
|
24
|
+
enabled: boolean;
|
|
25
|
+
/** Minimum drift score to pass (0.0-1.0) */
|
|
26
|
+
minScore: number;
|
|
27
|
+
/** File glob patterns to include */
|
|
28
|
+
include: string[];
|
|
29
|
+
/** File glob patterns to exclude */
|
|
30
|
+
exclude: string[];
|
|
31
|
+
};
|
|
32
|
+
/** Validation settings */
|
|
33
|
+
validation: {
|
|
34
|
+
/** Citation strictness: STRICT, WARN, PERMISSIVE */
|
|
35
|
+
citationStrictness: 'STRICT' | 'WARN' | 'PERMISSIVE';
|
|
36
|
+
};
|
|
37
|
+
/** CI behavior */
|
|
38
|
+
ci: {
|
|
39
|
+
/** Fail CI on WARN (default: only fail on FAIL) */
|
|
40
|
+
failOnWarn: boolean;
|
|
41
|
+
/** Post PR comments (requires GitHub token) */
|
|
42
|
+
postComments: boolean;
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
declare const DEFAULT_CONFIG: CharterConfig;
|
|
46
|
+
/**
|
|
47
|
+
* Load config from .charter/config.json
|
|
48
|
+
* Falls back to defaults if not found.
|
|
49
|
+
*/
|
|
50
|
+
export declare function loadConfig(configPath: string): CharterConfig;
|
|
51
|
+
/**
|
|
52
|
+
* Load blessed patterns from .charter/patterns/*.json
|
|
53
|
+
*/
|
|
54
|
+
export declare function loadPatterns(configPath: string): Pattern[];
|
|
55
|
+
/**
|
|
56
|
+
* Get the default config as JSON string (for init command).
|
|
57
|
+
*/
|
|
58
|
+
export declare function getDefaultConfigJSON(): string;
|
|
59
|
+
export { DEFAULT_CONFIG };
|
|
60
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAMhD,MAAM,WAAW,aAAa;IAC5B,mBAAmB;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,+BAA+B;IAC/B,OAAO,EAAE,MAAM,CAAC;IAEhB,8BAA8B;IAC9B,GAAG,EAAE;QACH,wDAAwD;QACxD,eAAe,EAAE,OAAO,CAAC;QACzB,qEAAqE;QACrE,gBAAgB,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;KAC7C,CAAC;IAEF,8BAA8B;IAC9B,KAAK,EAAE;QACL,4BAA4B;QAC5B,OAAO,EAAE,OAAO,CAAC;QACjB,4CAA4C;QAC5C,QAAQ,EAAE,MAAM,CAAC;QACjB,oCAAoC;QACpC,OAAO,EAAE,MAAM,EAAE,CAAC;QAClB,oCAAoC;QACpC,OAAO,EAAE,MAAM,EAAE,CAAC;KACnB,CAAC;IAEF,0BAA0B;IAC1B,UAAU,EAAE;QACV,oDAAoD;QACpD,kBAAkB,EAAE,QAAQ,GAAG,MAAM,GAAG,YAAY,CAAC;KACtD,CAAC;IAEF,kBAAkB;IAClB,EAAE,EAAE;QACF,mDAAmD;QACnD,UAAU,EAAE,OAAO,CAAC;QACpB,+CAA+C;QAC/C,YAAY,EAAE,OAAO,CAAC;KACvB,CAAC;CACH;AAED,QAAA,MAAM,cAAc,EAAE,aAoBrB,CAAC;AAMF;;;GAGG;AACH,wBAAgB,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,aAAa,CAuB5D;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,EAAE,CAsC1D;AAED;;GAEG;AACH,wBAAgB,oBAAoB,IAAI,MAAM,CAE7C;AAED,OAAO,EAAE,cAAc,EAAE,CAAC"}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* .charter/ Config Loader
|
|
4
|
+
*
|
|
5
|
+
* Loads governance configuration from the .charter/ directory.
|
|
6
|
+
* Config format is kept simple for v0.1 — YAML support comes later.
|
|
7
|
+
* For now, we use JSON config files.
|
|
8
|
+
*/
|
|
9
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
12
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
13
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
14
|
+
}
|
|
15
|
+
Object.defineProperty(o, k2, desc);
|
|
16
|
+
}) : (function(o, m, k, k2) {
|
|
17
|
+
if (k2 === undefined) k2 = k;
|
|
18
|
+
o[k2] = m[k];
|
|
19
|
+
}));
|
|
20
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
21
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
22
|
+
}) : function(o, v) {
|
|
23
|
+
o["default"] = v;
|
|
24
|
+
});
|
|
25
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
26
|
+
var ownKeys = function(o) {
|
|
27
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
28
|
+
var ar = [];
|
|
29
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
30
|
+
return ar;
|
|
31
|
+
};
|
|
32
|
+
return ownKeys(o);
|
|
33
|
+
};
|
|
34
|
+
return function (mod) {
|
|
35
|
+
if (mod && mod.__esModule) return mod;
|
|
36
|
+
var result = {};
|
|
37
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
38
|
+
__setModuleDefault(result, mod);
|
|
39
|
+
return result;
|
|
40
|
+
};
|
|
41
|
+
})();
|
|
42
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
43
|
+
exports.DEFAULT_CONFIG = void 0;
|
|
44
|
+
exports.loadConfig = loadConfig;
|
|
45
|
+
exports.loadPatterns = loadPatterns;
|
|
46
|
+
exports.getDefaultConfigJSON = getDefaultConfigJSON;
|
|
47
|
+
const fs = __importStar(require("node:fs"));
|
|
48
|
+
const path = __importStar(require("node:path"));
|
|
49
|
+
const DEFAULT_CONFIG = {
|
|
50
|
+
project: 'my-project',
|
|
51
|
+
version: '0.1',
|
|
52
|
+
git: {
|
|
53
|
+
requireTrailers: true,
|
|
54
|
+
trailerThreshold: 'HIGH',
|
|
55
|
+
},
|
|
56
|
+
drift: {
|
|
57
|
+
enabled: true,
|
|
58
|
+
minScore: 0.7,
|
|
59
|
+
include: ['**/*.ts', '**/*.js', '**/*.tsx', '**/*.jsx'],
|
|
60
|
+
exclude: ['node_modules/**', 'dist/**', '.git/**', 'coverage/**'],
|
|
61
|
+
},
|
|
62
|
+
validation: {
|
|
63
|
+
citationStrictness: 'WARN',
|
|
64
|
+
},
|
|
65
|
+
ci: {
|
|
66
|
+
failOnWarn: false,
|
|
67
|
+
postComments: false,
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
exports.DEFAULT_CONFIG = DEFAULT_CONFIG;
|
|
71
|
+
// ============================================================================
|
|
72
|
+
// Config Loading
|
|
73
|
+
// ============================================================================
|
|
74
|
+
/**
|
|
75
|
+
* Load config from .charter/config.json
|
|
76
|
+
* Falls back to defaults if not found.
|
|
77
|
+
*/
|
|
78
|
+
function loadConfig(configPath) {
|
|
79
|
+
const configFile = path.join(configPath, 'config.json');
|
|
80
|
+
if (!fs.existsSync(configFile)) {
|
|
81
|
+
return DEFAULT_CONFIG;
|
|
82
|
+
}
|
|
83
|
+
try {
|
|
84
|
+
const raw = fs.readFileSync(configFile, 'utf-8');
|
|
85
|
+
const parsed = JSON.parse(raw);
|
|
86
|
+
// Merge with defaults (shallow merge per section)
|
|
87
|
+
return {
|
|
88
|
+
project: parsed.project || DEFAULT_CONFIG.project,
|
|
89
|
+
version: parsed.version || DEFAULT_CONFIG.version,
|
|
90
|
+
git: { ...DEFAULT_CONFIG.git, ...parsed.git },
|
|
91
|
+
drift: { ...DEFAULT_CONFIG.drift, ...parsed.drift },
|
|
92
|
+
validation: { ...DEFAULT_CONFIG.validation, ...parsed.validation },
|
|
93
|
+
ci: { ...DEFAULT_CONFIG.ci, ...parsed.ci },
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
catch (err) {
|
|
97
|
+
console.warn(`Warning: Failed to parse ${configFile}, using defaults`);
|
|
98
|
+
return DEFAULT_CONFIG;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Load blessed patterns from .charter/patterns/*.json
|
|
103
|
+
*/
|
|
104
|
+
function loadPatterns(configPath) {
|
|
105
|
+
const patternsDir = path.join(configPath, 'patterns');
|
|
106
|
+
if (!fs.existsSync(patternsDir)) {
|
|
107
|
+
return [];
|
|
108
|
+
}
|
|
109
|
+
const patterns = [];
|
|
110
|
+
const files = fs.readdirSync(patternsDir).filter(f => f.endsWith('.json'));
|
|
111
|
+
for (const file of files) {
|
|
112
|
+
try {
|
|
113
|
+
const raw = fs.readFileSync(path.join(patternsDir, file), 'utf-8');
|
|
114
|
+
const parsed = JSON.parse(raw);
|
|
115
|
+
// Support both single pattern and array of patterns
|
|
116
|
+
const items = Array.isArray(parsed) ? parsed : [parsed];
|
|
117
|
+
for (const item of items) {
|
|
118
|
+
patterns.push({
|
|
119
|
+
id: item.id || `local-${file}-${patterns.length}`,
|
|
120
|
+
name: item.name,
|
|
121
|
+
category: item.category || 'COMPUTE',
|
|
122
|
+
blessedSolution: item.blessed_solution || item.blessedSolution || '',
|
|
123
|
+
rationale: item.rationale || null,
|
|
124
|
+
antiPatterns: item.anti_patterns || item.antiPatterns || null,
|
|
125
|
+
documentationUrl: item.documentation_url || item.documentationUrl || null,
|
|
126
|
+
relatedLedgerId: null,
|
|
127
|
+
status: item.status || 'ACTIVE',
|
|
128
|
+
createdAt: item.created_at || new Date().toISOString(),
|
|
129
|
+
projectId: null,
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
catch {
|
|
134
|
+
console.warn(`Warning: Failed to parse pattern file: ${file}`);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return patterns;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Get the default config as JSON string (for init command).
|
|
141
|
+
*/
|
|
142
|
+
function getDefaultConfigJSON() {
|
|
143
|
+
return JSON.stringify(DEFAULT_CONFIG, null, 2);
|
|
144
|
+
}
|
|
145
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Charter CLI
|
|
3
|
+
*
|
|
4
|
+
* Config-driven governance checks that run locally and in CI.
|
|
5
|
+
* Zero cloud dependency - works fully offline.
|
|
6
|
+
*/
|
|
7
|
+
export declare const EXIT_CODE: {
|
|
8
|
+
readonly SUCCESS: 0;
|
|
9
|
+
readonly POLICY_VIOLATION: 1;
|
|
10
|
+
readonly RUNTIME_ERROR: 2;
|
|
11
|
+
};
|
|
12
|
+
export declare class CLIError extends Error {
|
|
13
|
+
readonly exitCode: number;
|
|
14
|
+
constructor(message: string, exitCode?: number);
|
|
15
|
+
}
|
|
16
|
+
export interface CLIOptions {
|
|
17
|
+
configPath: string;
|
|
18
|
+
format: 'text' | 'json';
|
|
19
|
+
ciMode: boolean;
|
|
20
|
+
yes: boolean;
|
|
21
|
+
}
|
|
22
|
+
export declare function run(args: string[]): Promise<number>;
|
|
23
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AA+BH,eAAO,MAAM,SAAS;;;;CAIZ,CAAC;AAEX,qBAAa,QAAS,SAAQ,KAAK;aAGf,QAAQ,EAAE,MAAM;gBADhC,OAAO,EAAE,MAAM,EACC,QAAQ,GAAE,MAAgC;CAK7D;AAED,MAAM,WAAW,UAAU;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,MAAM,EAAE,OAAO,CAAC;IAChB,GAAG,EAAE,OAAO,CAAC;CACd;AAED,wBAAsB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CA2CzD"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Charter CLI
|
|
4
|
+
*
|
|
5
|
+
* Config-driven governance checks that run locally and in CI.
|
|
6
|
+
* Zero cloud dependency - works fully offline.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.CLIError = exports.EXIT_CODE = void 0;
|
|
10
|
+
exports.run = run;
|
|
11
|
+
const init_1 = require("./commands/init");
|
|
12
|
+
const setup_1 = require("./commands/setup");
|
|
13
|
+
const doctor_1 = require("./commands/doctor");
|
|
14
|
+
const validate_1 = require("./commands/validate");
|
|
15
|
+
const audit_1 = require("./commands/audit");
|
|
16
|
+
const drift_1 = require("./commands/drift");
|
|
17
|
+
const classify_1 = require("./commands/classify");
|
|
18
|
+
const HELP = `
|
|
19
|
+
charter - repo-level governance toolkit
|
|
20
|
+
|
|
21
|
+
Usage:
|
|
22
|
+
charter setup [--ci github] Bootstrap .charter/ and optional CI workflow
|
|
23
|
+
charter init Scaffold .charter/ config directory
|
|
24
|
+
charter validate Validate git commits for governance trailers
|
|
25
|
+
charter audit Generate governance audit report
|
|
26
|
+
charter drift [--path <dir>] Scan files for pattern drift
|
|
27
|
+
charter classify <subject> Classify a change (SURFACE/LOCAL/CROSS_CUTTING)
|
|
28
|
+
charter doctor Check CLI + config health
|
|
29
|
+
charter --help Show this help
|
|
30
|
+
charter --version Show version
|
|
31
|
+
|
|
32
|
+
Options:
|
|
33
|
+
--config <path> Path to .charter/ directory (default: .charter/)
|
|
34
|
+
--format <type> Output format: text, json (default: text)
|
|
35
|
+
--ci CI mode: exit non-zero on WARN or FAIL
|
|
36
|
+
--yes Auto-accept safe setup overwrites
|
|
37
|
+
`;
|
|
38
|
+
exports.EXIT_CODE = {
|
|
39
|
+
SUCCESS: 0,
|
|
40
|
+
POLICY_VIOLATION: 1,
|
|
41
|
+
RUNTIME_ERROR: 2,
|
|
42
|
+
};
|
|
43
|
+
class CLIError extends Error {
|
|
44
|
+
exitCode;
|
|
45
|
+
constructor(message, exitCode = exports.EXIT_CODE.RUNTIME_ERROR) {
|
|
46
|
+
super(message);
|
|
47
|
+
this.exitCode = exitCode;
|
|
48
|
+
this.name = 'CLIError';
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
exports.CLIError = CLIError;
|
|
52
|
+
async function run(args) {
|
|
53
|
+
if (args.length === 0 || args.includes('--help') || args.includes('-h')) {
|
|
54
|
+
console.log(HELP);
|
|
55
|
+
return exports.EXIT_CODE.SUCCESS;
|
|
56
|
+
}
|
|
57
|
+
if (args.includes('--version') || args.includes('-v')) {
|
|
58
|
+
console.log('charter v0.1.0');
|
|
59
|
+
return exports.EXIT_CODE.SUCCESS;
|
|
60
|
+
}
|
|
61
|
+
const command = args[0];
|
|
62
|
+
const restArgs = args.slice(1);
|
|
63
|
+
const format = getFlag(restArgs, '--format') || 'text';
|
|
64
|
+
if (format !== 'text' && format !== 'json') {
|
|
65
|
+
throw new CLIError(`Invalid --format value: ${format}. Use text or json.`);
|
|
66
|
+
}
|
|
67
|
+
const options = {
|
|
68
|
+
configPath: getFlag(restArgs, '--config') || '.charter',
|
|
69
|
+
format,
|
|
70
|
+
ciMode: restArgs.includes('--ci'),
|
|
71
|
+
yes: restArgs.includes('--yes'),
|
|
72
|
+
};
|
|
73
|
+
switch (command) {
|
|
74
|
+
case 'setup':
|
|
75
|
+
return (0, setup_1.setupCommand)(options, restArgs);
|
|
76
|
+
case 'init':
|
|
77
|
+
return (0, init_1.initCommand)(options, restArgs);
|
|
78
|
+
case 'validate':
|
|
79
|
+
return (0, validate_1.validateCommand)(options, restArgs);
|
|
80
|
+
case 'audit':
|
|
81
|
+
return (0, audit_1.auditCommand)(options);
|
|
82
|
+
case 'drift':
|
|
83
|
+
return (0, drift_1.driftCommand)(options, restArgs);
|
|
84
|
+
case 'classify':
|
|
85
|
+
return (0, classify_1.classifyCommand)(options, restArgs);
|
|
86
|
+
case 'doctor':
|
|
87
|
+
return (0, doctor_1.doctorCommand)(options);
|
|
88
|
+
default:
|
|
89
|
+
throw new CLIError(`Unknown command: ${command}\n${HELP}`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
function getFlag(args, flag) {
|
|
93
|
+
const idx = args.indexOf(flag);
|
|
94
|
+
if (idx !== -1 && idx + 1 < args.length) {
|
|
95
|
+
return args[idx + 1];
|
|
96
|
+
}
|
|
97
|
+
return undefined;
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@stackbilt/cli",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "Charter CLI — repo-level governance checks",
|
|
5
|
+
"bin": {
|
|
6
|
+
"charter": "./dist/bin.js"
|
|
7
|
+
},
|
|
8
|
+
"main": "./dist/index.js",
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"default": "./dist/index.js"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist",
|
|
18
|
+
"README.md",
|
|
19
|
+
"LICENSE"
|
|
20
|
+
],
|
|
21
|
+
"engines": {
|
|
22
|
+
"node": ">=18.0.0"
|
|
23
|
+
},
|
|
24
|
+
"repository": {
|
|
25
|
+
"type": "git",
|
|
26
|
+
"url": "https://github.com/Stackbilt-dev/charter.git",
|
|
27
|
+
"directory": "packages/cli"
|
|
28
|
+
},
|
|
29
|
+
"bugs": {
|
|
30
|
+
"url": "https://github.com/Stackbilt-dev/charter/issues"
|
|
31
|
+
},
|
|
32
|
+
"homepage": "https://github.com/Stackbilt-dev/charter#readme",
|
|
33
|
+
"publishConfig": {
|
|
34
|
+
"access": "public"
|
|
35
|
+
},
|
|
36
|
+
"scripts": {
|
|
37
|
+
"build": "pnpm exec tsc -p tsconfig.json"
|
|
38
|
+
},
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"@stackbilt/types": "workspace:*",
|
|
41
|
+
"@stackbilt/core": "workspace:*",
|
|
42
|
+
"@stackbilt/git": "workspace:*",
|
|
43
|
+
"@stackbilt/classify": "workspace:*",
|
|
44
|
+
"@stackbilt/validate": "workspace:*",
|
|
45
|
+
"@stackbilt/drift": "workspace:*"
|
|
46
|
+
},
|
|
47
|
+
"license": "Apache-2.0"
|
|
48
|
+
}
|