@stackbilt/cli 0.6.0 → 0.7.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.
- package/dist/__tests__/integration/evidence-contracts.test.d.ts +9 -0
- package/dist/__tests__/integration/evidence-contracts.test.d.ts.map +1 -0
- package/dist/__tests__/integration/evidence-contracts.test.js +203 -0
- package/dist/__tests__/integration/evidence-contracts.test.js.map +1 -0
- package/dist/__tests__/integration/precommit-hook.test.d.ts +12 -0
- package/dist/__tests__/integration/precommit-hook.test.d.ts.map +1 -0
- package/dist/__tests__/integration/precommit-hook.test.js +270 -0
- package/dist/__tests__/integration/precommit-hook.test.js.map +1 -0
- package/dist/__tests__/integration/sync-bundle.test.d.ts +10 -0
- package/dist/__tests__/integration/sync-bundle.test.d.ts.map +1 -0
- package/dist/__tests__/integration/sync-bundle.test.js +241 -0
- package/dist/__tests__/integration/sync-bundle.test.js.map +1 -0
- package/dist/__tests__/integration/vendor-bloat.test.d.ts +12 -0
- package/dist/__tests__/integration/vendor-bloat.test.d.ts.map +1 -0
- package/dist/__tests__/integration/vendor-bloat.test.js +300 -0
- package/dist/__tests__/integration/vendor-bloat.test.js.map +1 -0
- package/dist/commands/adf-migrate.d.ts.map +1 -1
- package/dist/commands/adf-migrate.js +4 -1
- package/dist/commands/adf-migrate.js.map +1 -1
- package/dist/commands/adf-tidy.d.ts +10 -0
- package/dist/commands/adf-tidy.d.ts.map +1 -0
- package/dist/commands/adf-tidy.js +547 -0
- package/dist/commands/adf-tidy.js.map +1 -0
- package/dist/commands/adf.d.ts +7 -4
- package/dist/commands/adf.d.ts.map +1 -1
- package/dist/commands/adf.js +53 -24
- package/dist/commands/adf.js.map +1 -1
- package/dist/commands/bootstrap.d.ts.map +1 -1
- package/dist/commands/bootstrap.js +4 -1
- package/dist/commands/bootstrap.js.map +1 -1
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +98 -1
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/hook.d.ts.map +1 -1
- package/dist/commands/hook.js +38 -4
- package/dist/commands/hook.js.map +1 -1
- package/dist/commands/serve.d.ts +14 -0
- package/dist/commands/serve.d.ts.map +1 -0
- package/dist/commands/serve.js +253 -0
- package/dist/commands/serve.js.map +1 -0
- package/dist/commands/setup.d.ts.map +1 -1
- package/dist/commands/setup.js +38 -0
- package/dist/commands/setup.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/package.json +9 -8
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Integration tests: adf evidence --ci exit code contracts
|
|
3
|
+
*
|
|
4
|
+
* Validates the constraint evaluation pipeline that gates pre-commit
|
|
5
|
+
* and CI pipelines: ceiling breach (exit 1), boundary warn (exit 0),
|
|
6
|
+
* stale baseline field assertions.
|
|
7
|
+
*/
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=evidence-contracts.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"evidence-contracts.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/integration/evidence-contracts.test.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG"}
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Integration tests: adf evidence --ci exit code contracts
|
|
4
|
+
*
|
|
5
|
+
* Validates the constraint evaluation pipeline that gates pre-commit
|
|
6
|
+
* and CI pipelines: ceiling breach (exit 1), boundary warn (exit 0),
|
|
7
|
+
* stale baseline field assertions.
|
|
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
|
+
const fs = __importStar(require("node:fs"));
|
|
44
|
+
const os = __importStar(require("node:os"));
|
|
45
|
+
const path = __importStar(require("node:path"));
|
|
46
|
+
const vitest_1 = require("vitest");
|
|
47
|
+
const index_1 = require("../../index");
|
|
48
|
+
const adf_evidence_1 = require("../../commands/adf-evidence");
|
|
49
|
+
// ============================================================================
|
|
50
|
+
// Fixture Helpers
|
|
51
|
+
// ============================================================================
|
|
52
|
+
const originalCwd = process.cwd();
|
|
53
|
+
const tempDirs = [];
|
|
54
|
+
function makeTempDir(label) {
|
|
55
|
+
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), `charter-integ-ev-${label}-`));
|
|
56
|
+
tempDirs.push(tmp);
|
|
57
|
+
return tmp;
|
|
58
|
+
}
|
|
59
|
+
const jsonOptions = {
|
|
60
|
+
configPath: '.charter',
|
|
61
|
+
format: 'json',
|
|
62
|
+
ciMode: false,
|
|
63
|
+
yes: false,
|
|
64
|
+
};
|
|
65
|
+
const ciOptions = {
|
|
66
|
+
...jsonOptions,
|
|
67
|
+
ciMode: true,
|
|
68
|
+
};
|
|
69
|
+
/**
|
|
70
|
+
* Build a fixture with a metric at a specific value/ceiling relationship.
|
|
71
|
+
*
|
|
72
|
+
* @param tmp - temp directory
|
|
73
|
+
* @param actualLines - number of lines in the measured file
|
|
74
|
+
* @param baseline - baseline value stored in core.adf metric
|
|
75
|
+
* @param ceiling - ceiling value stored in core.adf metric
|
|
76
|
+
*/
|
|
77
|
+
function writeEvidenceFixture(tmp, actualLines, baseline, ceiling) {
|
|
78
|
+
fs.mkdirSync(path.join(tmp, '.ai'), { recursive: true });
|
|
79
|
+
fs.mkdirSync(path.join(tmp, 'src'), { recursive: true });
|
|
80
|
+
fs.writeFileSync(path.join(tmp, '.ai', 'manifest.adf'), `ADF: 0.1
|
|
81
|
+
|
|
82
|
+
📦 DEFAULT_LOAD:
|
|
83
|
+
- core.adf
|
|
84
|
+
- state.adf
|
|
85
|
+
|
|
86
|
+
💰 BUDGET:
|
|
87
|
+
MAX_TOKENS: 4000
|
|
88
|
+
|
|
89
|
+
📊 METRICS:
|
|
90
|
+
APP_LOC: src/app.ts
|
|
91
|
+
`);
|
|
92
|
+
fs.writeFileSync(path.join(tmp, '.ai', 'core.adf'), `ADF: 0.1
|
|
93
|
+
|
|
94
|
+
📊 METRICS:
|
|
95
|
+
app_loc: ${baseline} / ${ceiling} [lines]
|
|
96
|
+
`);
|
|
97
|
+
fs.writeFileSync(path.join(tmp, '.ai', 'state.adf'), 'ADF: 0.1\n\n📋 STATE:\n - CURRENT: testing\n');
|
|
98
|
+
// Write a source file with exactly `actualLines` lines
|
|
99
|
+
const content = Array.from({ length: actualLines }, (_, i) => `// line ${i + 1}`).join('\n') + '\n';
|
|
100
|
+
fs.writeFileSync(path.join(tmp, 'src', 'app.ts'), content);
|
|
101
|
+
}
|
|
102
|
+
/** Capture console.log output during a command invocation */
|
|
103
|
+
function captureJson(fn, options, args) {
|
|
104
|
+
const logs = [];
|
|
105
|
+
const spy = vitest_1.vi.spyOn(console, 'log').mockImplementation((...msgs) => {
|
|
106
|
+
logs.push(msgs.map(String).join(' '));
|
|
107
|
+
});
|
|
108
|
+
let exitCode;
|
|
109
|
+
try {
|
|
110
|
+
exitCode = fn(options, args);
|
|
111
|
+
}
|
|
112
|
+
finally {
|
|
113
|
+
spy.mockRestore();
|
|
114
|
+
}
|
|
115
|
+
const raw = logs.join('\n').trim();
|
|
116
|
+
return { exitCode, output: JSON.parse(raw) };
|
|
117
|
+
}
|
|
118
|
+
// ============================================================================
|
|
119
|
+
// Lifecycle
|
|
120
|
+
// ============================================================================
|
|
121
|
+
(0, vitest_1.afterEach)(() => {
|
|
122
|
+
process.chdir(originalCwd);
|
|
123
|
+
while (tempDirs.length > 0) {
|
|
124
|
+
const dir = tempDirs.pop();
|
|
125
|
+
if (dir)
|
|
126
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
127
|
+
}
|
|
128
|
+
vitest_1.vi.restoreAllMocks();
|
|
129
|
+
});
|
|
130
|
+
// ============================================================================
|
|
131
|
+
// v1.1 Evidence Contract Tests
|
|
132
|
+
// ============================================================================
|
|
133
|
+
(0, vitest_1.describe)('adf evidence CI contracts (integration)', () => {
|
|
134
|
+
// ── Ceiling breach: measured > ceiling → fail, CI exit 1 ────────────────
|
|
135
|
+
// Note: split('\n').length on a file ending with \n counts lines+1,
|
|
136
|
+
// so writing N lines produces a measured value of N+1.
|
|
137
|
+
(0, vitest_1.it)('exits 1 in CI mode when measured value exceeds ceiling', () => {
|
|
138
|
+
const tmp = makeTempDir('breach');
|
|
139
|
+
process.chdir(tmp);
|
|
140
|
+
// 160 lines → measured 161 > ceiling 150
|
|
141
|
+
writeEvidenceFixture(tmp, /* actual */ 160, /* baseline */ 100, /* ceiling */ 150);
|
|
142
|
+
const { exitCode, output } = captureJson(adf_evidence_1.adfEvidence, ciOptions, ['--auto-measure']);
|
|
143
|
+
(0, vitest_1.expect)(exitCode).toBe(index_1.EXIT_CODE.POLICY_VIOLATION);
|
|
144
|
+
(0, vitest_1.expect)(output.allPassing).toBe(false);
|
|
145
|
+
(0, vitest_1.expect)(output.failCount).toBe(1);
|
|
146
|
+
(0, vitest_1.expect)(output.nextActions).toBeDefined();
|
|
147
|
+
(0, vitest_1.expect)(output.nextActions).toContain('Fix failing constraints before merging');
|
|
148
|
+
});
|
|
149
|
+
// ── Boundary warn: measured === ceiling → warn, CI exit 0 ──────────────
|
|
150
|
+
(0, vitest_1.it)('exits 0 in CI mode when measured value equals ceiling (warn boundary)', () => {
|
|
151
|
+
const tmp = makeTempDir('boundary');
|
|
152
|
+
process.chdir(tmp);
|
|
153
|
+
// 149 lines → measured 150 === ceiling 150 → warn
|
|
154
|
+
writeEvidenceFixture(tmp, /* actual */ 149, /* baseline */ 100, /* ceiling */ 150);
|
|
155
|
+
const { exitCode, output } = captureJson(adf_evidence_1.adfEvidence, ciOptions, ['--auto-measure']);
|
|
156
|
+
(0, vitest_1.expect)(exitCode).toBe(index_1.EXIT_CODE.SUCCESS);
|
|
157
|
+
(0, vitest_1.expect)(output.allPassing).toBe(true);
|
|
158
|
+
(0, vitest_1.expect)(output.warnCount).toBe(1);
|
|
159
|
+
(0, vitest_1.expect)(output.nextActions).toBeDefined();
|
|
160
|
+
(0, vitest_1.expect)(output.nextActions).toContain('Review metrics at ceiling boundary');
|
|
161
|
+
});
|
|
162
|
+
// ── Comfortable pass: measured < ceiling → pass, no warnings ───────────
|
|
163
|
+
(0, vitest_1.it)('exits 0 with no warnings when measured value is well under ceiling', () => {
|
|
164
|
+
const tmp = makeTempDir('pass');
|
|
165
|
+
process.chdir(tmp);
|
|
166
|
+
// 79 lines → measured 80 < ceiling 150
|
|
167
|
+
writeEvidenceFixture(tmp, /* actual */ 79, /* baseline */ 80, /* ceiling */ 150);
|
|
168
|
+
const { exitCode, output } = captureJson(adf_evidence_1.adfEvidence, ciOptions, ['--auto-measure']);
|
|
169
|
+
(0, vitest_1.expect)(exitCode).toBe(index_1.EXIT_CODE.SUCCESS);
|
|
170
|
+
(0, vitest_1.expect)(output.allPassing).toBe(true);
|
|
171
|
+
(0, vitest_1.expect)(output.failCount).toBe(0);
|
|
172
|
+
(0, vitest_1.expect)(output.warnCount).toBe(0);
|
|
173
|
+
});
|
|
174
|
+
// ── Stale baseline: current/baseline ratio ≥ 1.2 → staleBaselines ─────
|
|
175
|
+
(0, vitest_1.it)('reports stale baselines when measured value drifts far from baseline', () => {
|
|
176
|
+
const tmp = makeTempDir('stale');
|
|
177
|
+
process.chdir(tmp);
|
|
178
|
+
// baseline=50, ceiling=200, actual=79 → measured=80, ratio 80/50=1.6 ≥ 1.2
|
|
179
|
+
writeEvidenceFixture(tmp, /* actual */ 79, /* baseline */ 50, /* ceiling */ 200);
|
|
180
|
+
const { exitCode, output } = captureJson(adf_evidence_1.adfEvidence, jsonOptions, ['--auto-measure']);
|
|
181
|
+
(0, vitest_1.expect)(exitCode).toBe(index_1.EXIT_CODE.SUCCESS);
|
|
182
|
+
(0, vitest_1.expect)(output.staleBaselineCount).toBeGreaterThan(0);
|
|
183
|
+
(0, vitest_1.expect)(output.staleBaselines).toBeDefined();
|
|
184
|
+
const stale = output.staleBaselines;
|
|
185
|
+
(0, vitest_1.expect)(stale[0].metric).toBe('app_loc');
|
|
186
|
+
(0, vitest_1.expect)(stale[0].baseline).toBe(50);
|
|
187
|
+
(0, vitest_1.expect)(stale[0].current).toBe(80);
|
|
188
|
+
(0, vitest_1.expect)(stale[0].recommendedCeiling).toBeGreaterThan(80);
|
|
189
|
+
(0, vitest_1.expect)(output.nextActions).toContain('charter adf metrics recalibrate --headroom 15 --reason "<rationale>" --dry-run');
|
|
190
|
+
});
|
|
191
|
+
// ── No stale baseline when ratio is under threshold ────────────────────
|
|
192
|
+
(0, vitest_1.it)('does not report stale baselines when ratio is under threshold', () => {
|
|
193
|
+
const tmp = makeTempDir('fresh');
|
|
194
|
+
process.chdir(tmp);
|
|
195
|
+
// baseline=100, ceiling=150, actual=109 → measured=110, ratio 110/100=1.1 < 1.2
|
|
196
|
+
writeEvidenceFixture(tmp, /* actual */ 109, /* baseline */ 100, /* ceiling */ 150);
|
|
197
|
+
const { exitCode, output } = captureJson(adf_evidence_1.adfEvidence, jsonOptions, ['--auto-measure']);
|
|
198
|
+
(0, vitest_1.expect)(exitCode).toBe(index_1.EXIT_CODE.SUCCESS);
|
|
199
|
+
(0, vitest_1.expect)(output.staleBaselineCount).toBe(0);
|
|
200
|
+
(0, vitest_1.expect)(output.staleBaselines).toBeUndefined(); // field omitted when empty
|
|
201
|
+
});
|
|
202
|
+
});
|
|
203
|
+
//# sourceMappingURL=evidence-contracts.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"evidence-contracts.test.js","sourceRoot":"","sources":["../../../src/__tests__/integration/evidence-contracts.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Integration tests: real pre-commit hook simulation
|
|
3
|
+
*
|
|
4
|
+
* v3 scenario — sets up actual git repos with hooks, stages bloated
|
|
5
|
+
* vendor files, runs git commit, and verifies the hook auto-tidies
|
|
6
|
+
* and re-stages corrected files.
|
|
7
|
+
*
|
|
8
|
+
* These tests are slower (real git operations) but validate the full
|
|
9
|
+
* end-to-end contract that the pre-commit hook provides.
|
|
10
|
+
*/
|
|
11
|
+
export {};
|
|
12
|
+
//# sourceMappingURL=precommit-hook.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"precommit-hook.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/integration/precommit-hook.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG"}
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Integration tests: real pre-commit hook simulation
|
|
4
|
+
*
|
|
5
|
+
* v3 scenario — sets up actual git repos with hooks, stages bloated
|
|
6
|
+
* vendor files, runs git commit, and verifies the hook auto-tidies
|
|
7
|
+
* and re-stages corrected files.
|
|
8
|
+
*
|
|
9
|
+
* These tests are slower (real git operations) but validate the full
|
|
10
|
+
* end-to-end contract that the pre-commit hook provides.
|
|
11
|
+
*/
|
|
12
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
13
|
+
if (k2 === undefined) k2 = k;
|
|
14
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
15
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
16
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
17
|
+
}
|
|
18
|
+
Object.defineProperty(o, k2, desc);
|
|
19
|
+
}) : (function(o, m, k, k2) {
|
|
20
|
+
if (k2 === undefined) k2 = k;
|
|
21
|
+
o[k2] = m[k];
|
|
22
|
+
}));
|
|
23
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
24
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
25
|
+
}) : function(o, v) {
|
|
26
|
+
o["default"] = v;
|
|
27
|
+
});
|
|
28
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
29
|
+
var ownKeys = function(o) {
|
|
30
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
31
|
+
var ar = [];
|
|
32
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
33
|
+
return ar;
|
|
34
|
+
};
|
|
35
|
+
return ownKeys(o);
|
|
36
|
+
};
|
|
37
|
+
return function (mod) {
|
|
38
|
+
if (mod && mod.__esModule) return mod;
|
|
39
|
+
var result = {};
|
|
40
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
41
|
+
__setModuleDefault(result, mod);
|
|
42
|
+
return result;
|
|
43
|
+
};
|
|
44
|
+
})();
|
|
45
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
46
|
+
const fs = __importStar(require("node:fs"));
|
|
47
|
+
const os = __importStar(require("node:os"));
|
|
48
|
+
const path = __importStar(require("node:path"));
|
|
49
|
+
const node_child_process_1 = require("node:child_process");
|
|
50
|
+
const vitest_1 = require("vitest");
|
|
51
|
+
// ============================================================================
|
|
52
|
+
// Fixture Helpers
|
|
53
|
+
// ============================================================================
|
|
54
|
+
const tempDirs = [];
|
|
55
|
+
const CLI_BIN = path.resolve(__dirname, '../../../dist/bin.js');
|
|
56
|
+
function makeTempDir(label) {
|
|
57
|
+
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), `charter-integ-hook-${label}-`));
|
|
58
|
+
tempDirs.push(tmp);
|
|
59
|
+
return tmp;
|
|
60
|
+
}
|
|
61
|
+
function git(tmp, ...args) {
|
|
62
|
+
return (0, node_child_process_1.execFileSync)('git', args, {
|
|
63
|
+
cwd: tmp,
|
|
64
|
+
encoding: 'utf-8',
|
|
65
|
+
env: { ...process.env, GIT_AUTHOR_NAME: 'Test', GIT_AUTHOR_EMAIL: 'test@test.com', GIT_COMMITTER_NAME: 'Test', GIT_COMMITTER_EMAIL: 'test@test.com' },
|
|
66
|
+
}).trim();
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Scaffold a full git repo with ADF, a pre-commit hook that uses
|
|
70
|
+
* the built CLI, and an initial clean commit.
|
|
71
|
+
*/
|
|
72
|
+
function writeHookFixtureRepo(tmp) {
|
|
73
|
+
// Init git
|
|
74
|
+
git(tmp, 'init');
|
|
75
|
+
git(tmp, 'config', 'user.email', 'test@test.com');
|
|
76
|
+
git(tmp, 'config', 'user.name', 'Test');
|
|
77
|
+
// ADF structure
|
|
78
|
+
fs.mkdirSync(path.join(tmp, '.ai'), { recursive: true });
|
|
79
|
+
fs.mkdirSync(path.join(tmp, '.charter'), { recursive: true });
|
|
80
|
+
fs.writeFileSync(path.join(tmp, '.ai', 'manifest.adf'), `ADF: 0.1
|
|
81
|
+
|
|
82
|
+
📦 DEFAULT_LOAD:
|
|
83
|
+
- core.adf
|
|
84
|
+
- state.adf
|
|
85
|
+
|
|
86
|
+
📂 ON_DEMAND:
|
|
87
|
+
- backend.adf (Triggers on: database, API, migration)
|
|
88
|
+
|
|
89
|
+
💰 BUDGET:
|
|
90
|
+
MAX_TOKENS: 4000
|
|
91
|
+
`);
|
|
92
|
+
fs.writeFileSync(path.join(tmp, '.ai', 'core.adf'), `ADF: 0.1
|
|
93
|
+
|
|
94
|
+
📐 RULES:
|
|
95
|
+
- All changes require tests
|
|
96
|
+
`);
|
|
97
|
+
fs.writeFileSync(path.join(tmp, '.ai', 'state.adf'), 'ADF: 0.1\n\n📋 STATE:\n - CURRENT: testing\n');
|
|
98
|
+
fs.writeFileSync(path.join(tmp, '.ai', 'backend.adf'), `ADF: 0.1
|
|
99
|
+
|
|
100
|
+
📐 RULES:
|
|
101
|
+
- Database access through repository pattern
|
|
102
|
+
`);
|
|
103
|
+
// Clean thin pointer
|
|
104
|
+
fs.writeFileSync(path.join(tmp, 'CLAUDE.md'), `# CLAUDE.md
|
|
105
|
+
|
|
106
|
+
> **DO NOT add rules, constraints, or context to this file.**
|
|
107
|
+
> This file is auto-managed by Charter. All project rules live in \`.ai/\`.
|
|
108
|
+
> New rules should be added to the appropriate \`.ai/*.adf\` module.
|
|
109
|
+
> See \`.ai/manifest.adf\` for the module routing manifest.
|
|
110
|
+
|
|
111
|
+
## Environment
|
|
112
|
+
- Node 20
|
|
113
|
+
`);
|
|
114
|
+
// Pre-commit hook — simplified version that just runs tidy
|
|
115
|
+
const hookDir = path.join(tmp, '.githooks');
|
|
116
|
+
fs.mkdirSync(hookDir, { recursive: true });
|
|
117
|
+
// Build hook script avoiding JS template ${} expansion issues
|
|
118
|
+
// by using string concatenation for the CLI_BIN path
|
|
119
|
+
const hookScript = [
|
|
120
|
+
'#!/usr/bin/env bash',
|
|
121
|
+
'set -euo pipefail',
|
|
122
|
+
'',
|
|
123
|
+
'# Vendor file auto-tidy',
|
|
124
|
+
'if [ "${CHARTER_SKIP_TIDY:-0}" != "1" ] && [ -f ".ai/manifest.adf" ]; then',
|
|
125
|
+
' VENDOR_FILES="CLAUDE.md .cursorrules agents.md AGENTS.md GEMINI.md copilot-instructions.md"',
|
|
126
|
+
' STAGED_VENDORS=""',
|
|
127
|
+
' for vf in $VENDOR_FILES; do',
|
|
128
|
+
' if git diff --cached --name-only | grep -qx "$vf"; then',
|
|
129
|
+
' STAGED_VENDORS="$STAGED_VENDORS $vf"',
|
|
130
|
+
' fi',
|
|
131
|
+
' done',
|
|
132
|
+
'',
|
|
133
|
+
' if [ -n "$STAGED_VENDORS" ]; then',
|
|
134
|
+
` TIDY_OUTPUT=$(node ${CLI_BIN} adf tidy --dry-run --format json 2>/dev/null || echo '{}')`,
|
|
135
|
+
' EXTRACTED=$(echo "$TIDY_OUTPUT" | grep -o \'"totalExtracted": *[0-9][0-9]*\' | grep -o \'[0-9][0-9]*\' || echo "0")',
|
|
136
|
+
'',
|
|
137
|
+
' if [ "$EXTRACTED" -gt 0 ] 2>/dev/null; then',
|
|
138
|
+
` node ${CLI_BIN} adf tidy 2>/dev/null`,
|
|
139
|
+
'',
|
|
140
|
+
' for vf in $STAGED_VENDORS; do',
|
|
141
|
+
' if [ -f "$vf" ]; then',
|
|
142
|
+
' git add "$vf"',
|
|
143
|
+
' fi',
|
|
144
|
+
' done',
|
|
145
|
+
' git add .ai/*.adf 2>/dev/null || true',
|
|
146
|
+
' fi',
|
|
147
|
+
' fi',
|
|
148
|
+
'fi',
|
|
149
|
+
'',
|
|
150
|
+
].join('\n');
|
|
151
|
+
fs.writeFileSync(path.join(hookDir, 'pre-commit'), hookScript);
|
|
152
|
+
fs.chmodSync(path.join(hookDir, 'pre-commit'), 0o755);
|
|
153
|
+
// Point git to custom hooks dir
|
|
154
|
+
git(tmp, 'config', 'core.hooksPath', '.githooks');
|
|
155
|
+
// Initial commit with clean state
|
|
156
|
+
git(tmp, 'add', '-A');
|
|
157
|
+
git(tmp, 'commit', '-m', 'initial');
|
|
158
|
+
}
|
|
159
|
+
// ============================================================================
|
|
160
|
+
// Lifecycle
|
|
161
|
+
// ============================================================================
|
|
162
|
+
(0, vitest_1.afterEach)(() => {
|
|
163
|
+
while (tempDirs.length > 0) {
|
|
164
|
+
const dir = tempDirs.pop();
|
|
165
|
+
if (dir)
|
|
166
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
// ============================================================================
|
|
170
|
+
// v3 Pre-commit Hook Simulation
|
|
171
|
+
// ============================================================================
|
|
172
|
+
(0, vitest_1.describe)('pre-commit hook auto-tidy (integration)', () => {
|
|
173
|
+
(0, vitest_1.it)('auto-tidies bloated CLAUDE.md during git commit', { timeout: 30000 }, () => {
|
|
174
|
+
const tmp = makeTempDir('hook-tidy');
|
|
175
|
+
writeHookFixtureRepo(tmp);
|
|
176
|
+
// Inject bloat into CLAUDE.md
|
|
177
|
+
const bloatedContent = fs.readFileSync(path.join(tmp, 'CLAUDE.md'), 'utf-8') + `
|
|
178
|
+
## Architecture
|
|
179
|
+
- Layered architecture with repository pattern
|
|
180
|
+
- All database queries go through the repository layer
|
|
181
|
+
- API endpoints validate input before processing
|
|
182
|
+
|
|
183
|
+
## Database Rules
|
|
184
|
+
- All database migrations must be reversible
|
|
185
|
+
- Schema changes require migration scripts
|
|
186
|
+
`;
|
|
187
|
+
fs.writeFileSync(path.join(tmp, 'CLAUDE.md'), bloatedContent);
|
|
188
|
+
// Stage and commit — hook should auto-tidy
|
|
189
|
+
git(tmp, 'add', 'CLAUDE.md');
|
|
190
|
+
const commitOutput = git(tmp, 'commit', '-m', 'add bloated content');
|
|
191
|
+
// Verify commit succeeded
|
|
192
|
+
(0, vitest_1.expect)(commitOutput).toContain('add bloated content');
|
|
193
|
+
// Verify CLAUDE.md was tidied (restored to thin pointer)
|
|
194
|
+
const finalContent = fs.readFileSync(path.join(tmp, 'CLAUDE.md'), 'utf-8');
|
|
195
|
+
(0, vitest_1.expect)(finalContent).toContain('DO NOT add rules');
|
|
196
|
+
(0, vitest_1.expect)(finalContent).not.toContain('## Architecture');
|
|
197
|
+
(0, vitest_1.expect)(finalContent).not.toContain('## Database Rules');
|
|
198
|
+
(0, vitest_1.expect)(finalContent).toContain('## Environment');
|
|
199
|
+
});
|
|
200
|
+
(0, vitest_1.it)('passes through cleanly when CLAUDE.md has no bloat', { timeout: 30000 }, () => {
|
|
201
|
+
const tmp = makeTempDir('hook-clean');
|
|
202
|
+
writeHookFixtureRepo(tmp);
|
|
203
|
+
// Make a trivial change to CLAUDE.md (add env item, not bloat)
|
|
204
|
+
const content = fs.readFileSync(path.join(tmp, 'CLAUDE.md'), 'utf-8');
|
|
205
|
+
fs.writeFileSync(path.join(tmp, 'CLAUDE.md'), content.trimEnd() + '\n- pnpm 9\n');
|
|
206
|
+
git(tmp, 'add', 'CLAUDE.md');
|
|
207
|
+
const commitOutput = git(tmp, 'commit', '-m', 'add env item');
|
|
208
|
+
(0, vitest_1.expect)(commitOutput).toContain('add env item');
|
|
209
|
+
// CLAUDE.md should be unchanged (env addition preserved)
|
|
210
|
+
const finalContent = fs.readFileSync(path.join(tmp, 'CLAUDE.md'), 'utf-8');
|
|
211
|
+
(0, vitest_1.expect)(finalContent).toContain('DO NOT add rules');
|
|
212
|
+
});
|
|
213
|
+
(0, vitest_1.it)('skips tidy when CHARTER_SKIP_TIDY=1 is set', { timeout: 30000 }, () => {
|
|
214
|
+
const tmp = makeTempDir('hook-skip');
|
|
215
|
+
writeHookFixtureRepo(tmp);
|
|
216
|
+
// Inject bloat
|
|
217
|
+
const bloatedContent = fs.readFileSync(path.join(tmp, 'CLAUDE.md'), 'utf-8') + `
|
|
218
|
+
## Architecture
|
|
219
|
+
- Layered architecture pattern
|
|
220
|
+
`;
|
|
221
|
+
fs.writeFileSync(path.join(tmp, 'CLAUDE.md'), bloatedContent);
|
|
222
|
+
// Stage and commit with skip flag
|
|
223
|
+
git(tmp, 'add', 'CLAUDE.md');
|
|
224
|
+
(0, node_child_process_1.execFileSync)('git', ['commit', '-m', 'bloat preserved'], {
|
|
225
|
+
cwd: tmp,
|
|
226
|
+
encoding: 'utf-8',
|
|
227
|
+
env: {
|
|
228
|
+
...process.env,
|
|
229
|
+
CHARTER_SKIP_TIDY: '1',
|
|
230
|
+
GIT_AUTHOR_NAME: 'Test',
|
|
231
|
+
GIT_AUTHOR_EMAIL: 'test@test.com',
|
|
232
|
+
GIT_COMMITTER_NAME: 'Test',
|
|
233
|
+
GIT_COMMITTER_EMAIL: 'test@test.com',
|
|
234
|
+
},
|
|
235
|
+
});
|
|
236
|
+
// Bloat should still be there (tidy was skipped)
|
|
237
|
+
const finalContent = fs.readFileSync(path.join(tmp, 'CLAUDE.md'), 'utf-8');
|
|
238
|
+
(0, vitest_1.expect)(finalContent).toContain('## Architecture');
|
|
239
|
+
});
|
|
240
|
+
(0, vitest_1.it)('re-stages modified .adf modules after tidy', { timeout: 30000 }, () => {
|
|
241
|
+
const tmp = makeTempDir('hook-restage');
|
|
242
|
+
writeHookFixtureRepo(tmp);
|
|
243
|
+
// Inject bloat with trigger keywords that route to backend.adf
|
|
244
|
+
const bloatedContent = fs.readFileSync(path.join(tmp, 'CLAUDE.md'), 'utf-8') + `
|
|
245
|
+
## Database Rules
|
|
246
|
+
- All database migrations must be reversible
|
|
247
|
+
- Schema changes require migration scripts
|
|
248
|
+
- API rate limiting applies to all database endpoints
|
|
249
|
+
`;
|
|
250
|
+
fs.writeFileSync(path.join(tmp, 'CLAUDE.md'), bloatedContent);
|
|
251
|
+
// Record pre-commit state of backend.adf
|
|
252
|
+
const beforeBackend = fs.readFileSync(path.join(tmp, '.ai', 'backend.adf'), 'utf-8');
|
|
253
|
+
git(tmp, 'add', 'CLAUDE.md');
|
|
254
|
+
git(tmp, 'commit', '-m', 'auto-routed content');
|
|
255
|
+
// Verify the committed CLAUDE.md is clean
|
|
256
|
+
const committedClaude = (0, node_child_process_1.execSync)('git show HEAD:CLAUDE.md', { cwd: tmp, encoding: 'utf-8' });
|
|
257
|
+
(0, vitest_1.expect)(committedClaude).toContain('DO NOT add rules');
|
|
258
|
+
(0, vitest_1.expect)(committedClaude).not.toContain('## Database Rules');
|
|
259
|
+
// Verify .adf modules were modified and committed
|
|
260
|
+
// (the tidy should have routed content somewhere)
|
|
261
|
+
const afterBackend = fs.readFileSync(path.join(tmp, '.ai', 'backend.adf'), 'utf-8');
|
|
262
|
+
const coreAfter = fs.readFileSync(path.join(tmp, '.ai', 'core.adf'), 'utf-8');
|
|
263
|
+
// At least one module should have grown
|
|
264
|
+
const anyModuleGrew = afterBackend.length > beforeBackend.length ||
|
|
265
|
+
coreAfter.includes('migration') || coreAfter.includes('database') ||
|
|
266
|
+
afterBackend.includes('migration') || afterBackend.includes('database');
|
|
267
|
+
(0, vitest_1.expect)(anyModuleGrew).toBe(true);
|
|
268
|
+
});
|
|
269
|
+
});
|
|
270
|
+
//# sourceMappingURL=precommit-hook.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"precommit-hook.test.js","sourceRoot":"","sources":["../../../src/__tests__/integration/precommit-hook.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Integration tests: sync drift + bundle missing-module + stability rerun
|
|
3
|
+
*
|
|
4
|
+
* v2 scenarios covering:
|
|
5
|
+
* - adf sync --check exit contract (drift detection)
|
|
6
|
+
* - bundle missing default module (hard fail) vs on-demand (soft warning)
|
|
7
|
+
* - stability rerun (same scenario twice, normalized JSON must match)
|
|
8
|
+
*/
|
|
9
|
+
export {};
|
|
10
|
+
//# sourceMappingURL=sync-bundle.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sync-bundle.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/integration/sync-bundle.test.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG"}
|