@vibe-validate/history 0.12.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/README.md ADDED
@@ -0,0 +1,239 @@
1
+ # @vibe-validate/history
2
+
3
+ Validation history tracking via git notes for vibe-validate.
4
+
5
+ ## Features
6
+
7
+ - **Git Notes Storage**: Store validation results keyed by git tree hash
8
+ - **Distributed Cache**: Remember validation for EVERY tree hash
9
+ - **Worktree Stability Check**: Verify tree unchanged during validation
10
+ - **Multi-Run Support**: Handle flaky tests, multiple branches at same tree
11
+ - **Output Truncation**: Efficient storage (10KB max per step)
12
+ - **Proactive Health**: Warn when pruning recommended
13
+ - **Privacy-First**: Local by default, no auto-sharing
14
+
15
+ ## Installation
16
+
17
+ ```bash
18
+ npm install @vibe-validate/history
19
+ ```
20
+
21
+ ## Usage
22
+
23
+ ### Record Validation History
24
+
25
+ ```typescript
26
+ import { recordValidationHistory, checkWorktreeStability } from '@vibe-validate/history';
27
+ import { getGitTreeHash } from '@vibe-validate/git';
28
+
29
+ // Get tree hash before validation
30
+ const treeHashBefore = await getGitTreeHash();
31
+
32
+ // Run validation
33
+ const result = await runValidation(config);
34
+
35
+ // Check stability (did tree change during validation?)
36
+ const stability = await checkWorktreeStability(treeHashBefore);
37
+
38
+ if (!stability.stable) {
39
+ console.warn('⚠️ Worktree changed during validation - not caching');
40
+ } else {
41
+ // Record to git notes
42
+ const recordResult = await recordValidationHistory(treeHashBefore, result);
43
+
44
+ if (recordResult.recorded) {
45
+ console.log('📝 History recorded');
46
+ }
47
+ }
48
+ ```
49
+
50
+ ### Read Validation History
51
+
52
+ ```typescript
53
+ import { readHistoryNote, listHistoryTreeHashes } from '@vibe-validate/history';
54
+
55
+ // Read specific tree hash
56
+ const note = await readHistoryNote('abc123def456...');
57
+
58
+ if (note) {
59
+ console.log(`Found ${note.runs.length} validation runs for this tree`);
60
+
61
+ for (const run of note.runs) {
62
+ console.log(`- ${run.timestamp}: ${run.passed ? 'PASSED' : 'FAILED'}`);
63
+ }
64
+ }
65
+
66
+ // List all tree hashes with history
67
+ const treeHashes = await listHistoryTreeHashes();
68
+ console.log(`Total history: ${treeHashes.length} tree hashes`);
69
+ ```
70
+
71
+ ### Health Check
72
+
73
+ ```typescript
74
+ import { checkHistoryHealth } from '@vibe-validate/history';
75
+
76
+ const health = await checkHistoryHealth();
77
+
78
+ if (health.shouldWarn) {
79
+ console.log(health.warningMessage);
80
+ // Example output:
81
+ // ℹ️ Validation history has grown large (127 tree hashes)
82
+ // Found 15 notes older than 90 days
83
+ // Consider pruning: vibe-validate history prune --older-than "90 days"
84
+ }
85
+ ```
86
+
87
+ ### Prune Old History
88
+
89
+ ```typescript
90
+ import { pruneHistoryByAge } from '@vibe-validate/history';
91
+
92
+ // Prune notes older than 90 days (dry run)
93
+ const dryRunResult = await pruneHistoryByAge(90, {}, true);
94
+ console.log(`Would prune ${dryRunResult.notesPruned} notes`);
95
+
96
+ // Actually prune
97
+ const pruneResult = await pruneHistoryByAge(90);
98
+ console.log(`Pruned ${pruneResult.notesPruned} notes`);
99
+ console.log(`${pruneResult.notesRemaining} notes remaining`);
100
+ ```
101
+
102
+ ## Configuration
103
+
104
+ ```typescript
105
+ import type { HistoryConfig } from '@vibe-validate/history';
106
+
107
+ const config: HistoryConfig = {
108
+ enabled: true,
109
+
110
+ gitNotes: {
111
+ ref: 'vibe-validate/runs', // Git notes ref namespace
112
+ maxRunsPerTree: 10, // Keep last 10 runs per tree
113
+ maxOutputBytes: 10000, // 10KB max per step output
114
+ },
115
+
116
+ retention: {
117
+ warnAfterDays: 90, // Warn about notes >90 days old
118
+ warnAfterCount: 100, // Warn when >100 tree hashes
119
+ },
120
+ };
121
+ ```
122
+
123
+ ## API Reference
124
+
125
+ ### Types
126
+
127
+ - **ValidationRun**: Single validation run entry
128
+ - **HistoryNote**: Git note structure (array of runs per tree)
129
+ - **RecordResult**: Result of recording validation
130
+ - **StabilityCheck**: Worktree stability check result
131
+ - **HealthCheckResult**: History health check result
132
+ - **PruneResult**: Result of pruning operation
133
+
134
+ ### Functions
135
+
136
+ #### Recording
137
+ - `recordValidationHistory(treeHash, result, config?)`: Record validation to git notes
138
+ - `checkWorktreeStability(treeHashBefore)`: Check if tree changed during validation
139
+
140
+ #### Reading
141
+ - `readHistoryNote(treeHash, notesRef?)`: Read note for specific tree hash
142
+ - `listHistoryTreeHashes(notesRef?)`: List all tree hashes with notes
143
+ - `getAllHistoryNotes(notesRef?)`: Get all history notes
144
+ - `hasHistoryForTree(treeHash, notesRef?)`: Check if history exists
145
+
146
+ #### Pruning
147
+ - `pruneHistoryByAge(olderThanDays, config?, dryRun?)`: Prune by age
148
+ - `pruneAllHistory(config?, dryRun?)`: Prune all history
149
+
150
+ #### Health
151
+ - `checkHistoryHealth(config?)`: Check history health
152
+
153
+ #### Utilities
154
+ - `truncateValidationOutput(result, maxBytes?)`: Truncate validation output
155
+
156
+ ## Design
157
+
158
+ ### Git Tree Hash Caching
159
+
160
+ Traditional validation caching (single state file):
161
+ - Only remembers ONE tree hash
162
+ - Switch branches → cache miss
163
+ - Revert changes → cache miss
164
+
165
+ Git notes caching (this package):
166
+ - Remembers EVERY tree hash
167
+ - Switch branches → cache hit (if tree unchanged)
168
+ - Revert changes → cache hit
169
+ - **Result**: Improved cache effectiveness
170
+
171
+ ### Note Structure
172
+
173
+ ```yaml
174
+ # Git note: refs/notes/vibe-validate/runs → tree hash abc123
175
+ treeHash: "abc123def456..."
176
+ runs:
177
+ - id: "run-1729522215123"
178
+ timestamp: "2025-10-21T14:30:15.123Z"
179
+ duration: 2300
180
+ passed: true
181
+ branch: "feature/foo"
182
+ headCommit: "9abc3c4"
183
+ uncommittedChanges: false
184
+ result:
185
+ # Full validation result (output truncated to 10KB/step)
186
+ ```
187
+
188
+ ### Worktree Stability
189
+
190
+ Critical safety feature: Verify tree unchanged during validation.
191
+
192
+ ```typescript
193
+ // Before validation
194
+ const treeHashBefore = await getGitTreeHash();
195
+
196
+ // Run validation (potentially long-running)
197
+ const result = await runValidation();
198
+
199
+ // After validation - check stability
200
+ const stability = await checkWorktreeStability(treeHashBefore);
201
+
202
+ if (!stability.stable) {
203
+ // Tree changed during validation - don't cache
204
+ console.warn('⚠️ Worktree changed during validation');
205
+ return result; // Skip recording
206
+ }
207
+
208
+ // Safe to cache
209
+ await recordValidationHistory(treeHashBefore, result);
210
+ ```
211
+
212
+ ## Privacy & Scope
213
+
214
+ **Current Scope**: Local user validation caching only
215
+
216
+ **What's recorded**:
217
+ - ✅ Tree hash (content-based, no PII)
218
+ - ✅ Timestamp
219
+ - ✅ Branch name
220
+ - ✅ HEAD commit
221
+ - ✅ Validation results (truncated output)
222
+
223
+ **What's NOT recorded** (privacy-first):
224
+ - ❌ Author name/email (already in git history)
225
+ - ❌ Machine hostname
226
+ - ❌ Environment variables
227
+ - ❌ File paths with usernames
228
+
229
+ **Sharing**: Local by default (no auto-push to remote)
230
+
231
+ ## Future Extensions
232
+
233
+ - Team sharing (opt-in)
234
+ - Environment tracking (OS, Node version, CI matrix)
235
+ - Analytics export (JSONL for SQLite/DuckDB analysis)
236
+
237
+ ## License
238
+
239
+ MIT
@@ -0,0 +1,12 @@
1
+ /**
2
+ * History health check utilities
3
+ */
4
+ import type { HealthCheckResult, HistoryConfig } from './types.js';
5
+ /**
6
+ * Check validation history health
7
+ *
8
+ * @param config - History configuration
9
+ * @returns Health check result
10
+ */
11
+ export declare function checkHistoryHealth(config?: HistoryConfig): Promise<HealthCheckResult>;
12
+ //# sourceMappingURL=health-check.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"health-check.d.ts","sourceRoot":"","sources":["../src/health-check.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAInE;;;;;GAKG;AACH,wBAAsB,kBAAkB,CACtC,MAAM,GAAE,aAAkB,GACzB,OAAO,CAAC,iBAAiB,CAAC,CAkE5B"}
@@ -0,0 +1,68 @@
1
+ /**
2
+ * History health check utilities
3
+ */
4
+ import { DEFAULT_HISTORY_CONFIG } from './types.js';
5
+ import { getAllHistoryNotes } from './reader.js';
6
+ /**
7
+ * Check validation history health
8
+ *
9
+ * @param config - History configuration
10
+ * @returns Health check result
11
+ */
12
+ export async function checkHistoryHealth(config = {}) {
13
+ const mergedConfig = {
14
+ ...DEFAULT_HISTORY_CONFIG,
15
+ ...config,
16
+ retention: {
17
+ ...DEFAULT_HISTORY_CONFIG.retention,
18
+ ...config.retention,
19
+ },
20
+ };
21
+ // Type assertion safe: DEFAULT_HISTORY_CONFIG is Required<HistoryConfig>
22
+ const warnAfterDays = (mergedConfig.retention.warnAfterDays ?? DEFAULT_HISTORY_CONFIG.retention.warnAfterDays);
23
+ const warnAfterCount = (mergedConfig.retention.warnAfterCount ?? DEFAULT_HISTORY_CONFIG.retention.warnAfterCount);
24
+ const allNotes = await getAllHistoryNotes(mergedConfig.gitNotes?.ref || DEFAULT_HISTORY_CONFIG.gitNotes.ref);
25
+ const totalNotes = allNotes.length;
26
+ const cutoffTime = Date.now() - warnAfterDays * 24 * 60 * 60 * 1000;
27
+ let oldNotesCount = 0;
28
+ for (const note of allNotes) {
29
+ if (!note.runs || note.runs.length === 0) {
30
+ continue;
31
+ }
32
+ // Check oldest run
33
+ const oldestRun = note.runs[0];
34
+ const oldestTimestamp = new Date(oldestRun.timestamp).getTime();
35
+ if (oldestTimestamp < cutoffTime) {
36
+ oldNotesCount++;
37
+ }
38
+ }
39
+ // Determine if we should warn
40
+ const shouldWarnCount = totalNotes > warnAfterCount;
41
+ const shouldWarnAge = oldNotesCount > 0;
42
+ const shouldWarn = shouldWarnCount || shouldWarnAge;
43
+ let warningMessage;
44
+ if (shouldWarnCount && shouldWarnAge) {
45
+ warningMessage =
46
+ `ℹ️ Validation history has grown large (${totalNotes} tree hashes)\n` +
47
+ ` Found ${oldNotesCount} notes older than ${warnAfterDays} days\n` +
48
+ ` Consider pruning: vibe-validate history prune --older-than "${warnAfterDays} days"`;
49
+ }
50
+ else if (shouldWarnCount) {
51
+ warningMessage =
52
+ `ℹ️ Validation history has grown large (${totalNotes} tree hashes)\n` +
53
+ ` Consider pruning: vibe-validate history prune --older-than "${warnAfterDays} days"`;
54
+ }
55
+ else if (shouldWarnAge) {
56
+ warningMessage =
57
+ `ℹ️ Found validation history older than ${warnAfterDays} days\n` +
58
+ ` ${oldNotesCount} tree hashes can be pruned\n` +
59
+ ` Run: vibe-validate history prune --older-than "${warnAfterDays} days"`;
60
+ }
61
+ return {
62
+ totalNotes,
63
+ oldNotesCount,
64
+ shouldWarn,
65
+ warningMessage,
66
+ };
67
+ }
68
+ //# sourceMappingURL=health-check.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"health-check.js","sourceRoot":"","sources":["../src/health-check.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAEjD;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,SAAwB,EAAE;IAE1B,MAAM,YAAY,GAAG;QACnB,GAAG,sBAAsB;QACzB,GAAG,MAAM;QACT,SAAS,EAAE;YACT,GAAG,sBAAsB,CAAC,SAAS;YACnC,GAAG,MAAM,CAAC,SAAS;SACpB;KACF,CAAC;IAEF,yEAAyE;IACzE,MAAM,aAAa,GAAG,CAAC,YAAY,CAAC,SAAS,CAAC,aAAa,IAAI,sBAAsB,CAAC,SAAS,CAAC,aAAa,CAAW,CAAC;IACzH,MAAM,cAAc,GAAG,CAAC,YAAY,CAAC,SAAS,CAAC,cAAc,IAAI,sBAAsB,CAAC,SAAS,CAAC,cAAc,CAAW,CAAC;IAE5H,MAAM,QAAQ,GAAG,MAAM,kBAAkB,CACvC,YAAY,CAAC,QAAQ,EAAE,GAAG,IAAI,sBAAsB,CAAC,QAAQ,CAAC,GAAG,CAClE,CAAC;IAEF,MAAM,UAAU,GAAG,QAAQ,CAAC,MAAM,CAAC;IACnC,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,aAAa,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;IAEpE,IAAI,aAAa,GAAG,CAAC,CAAC;IAEtB,KAAK,MAAM,IAAI,IAAI,QAAQ,EAAE,CAAC;QAC5B,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACzC,SAAS;QACX,CAAC;QAED,mBAAmB;QACnB,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC/B,MAAM,eAAe,GAAG,IAAI,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,CAAC;QAEhE,IAAI,eAAe,GAAG,UAAU,EAAE,CAAC;YACjC,aAAa,EAAE,CAAC;QAClB,CAAC;IACH,CAAC;IAED,8BAA8B;IAC9B,MAAM,eAAe,GAAG,UAAU,GAAG,cAAc,CAAC;IACpD,MAAM,aAAa,GAAG,aAAa,GAAG,CAAC,CAAC;IACxC,MAAM,UAAU,GAAG,eAAe,IAAI,aAAa,CAAC;IAEpD,IAAI,cAAkC,CAAC;IAEvC,IAAI,eAAe,IAAI,aAAa,EAAE,CAAC;QACrC,cAAc;YACZ,2CAA2C,UAAU,iBAAiB;gBACtE,YAAY,aAAa,qBAAqB,aAAa,SAAS;gBACpE,kEAAkE,aAAa,QAAQ,CAAC;IAC5F,CAAC;SAAM,IAAI,eAAe,EAAE,CAAC;QAC3B,cAAc;YACZ,2CAA2C,UAAU,iBAAiB;gBACtE,kEAAkE,aAAa,QAAQ,CAAC;IAC5F,CAAC;SAAM,IAAI,aAAa,EAAE,CAAC;QACzB,cAAc;YACZ,2CAA2C,aAAa,SAAS;gBACjE,MAAM,aAAa,8BAA8B;gBACjD,qDAAqD,aAAa,QAAQ,CAAC;IAC/E,CAAC;IAED,OAAO;QACL,UAAU;QACV,aAAa;QACb,UAAU;QACV,cAAc;KACf,CAAC;AACJ,CAAC"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Validation history tracking via git notes
3
+ *
4
+ * @packageDocumentation
5
+ */
6
+ export type { ValidationRun, HistoryNote, RecordResult, StabilityCheck, HistoryConfig, HealthCheckResult, PruneResult, } from './types.js';
7
+ export { DEFAULT_HISTORY_CONFIG } from './types.js';
8
+ export { recordValidationHistory, checkWorktreeStability, } from './recorder.js';
9
+ export { readHistoryNote, listHistoryTreeHashes, getAllHistoryNotes, hasHistoryForTree, } from './reader.js';
10
+ export { pruneHistoryByAge, pruneAllHistory } from './pruner.js';
11
+ export { checkHistoryHealth } from './health-check.js';
12
+ export { truncateValidationOutput } from './truncate.js';
13
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,YAAY,EACV,aAAa,EACb,WAAW,EACX,YAAY,EACZ,cAAc,EACd,aAAa,EACb,iBAAiB,EACjB,WAAW,GACZ,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAGpD,OAAO,EACL,uBAAuB,EACvB,sBAAsB,GACvB,MAAM,eAAe,CAAC;AAGvB,OAAO,EACL,eAAe,EACf,qBAAqB,EACrB,kBAAkB,EAClB,iBAAiB,GAClB,MAAM,aAAa,CAAC;AAGrB,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAGjE,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAGvD,OAAO,EAAE,wBAAwB,EAAE,MAAM,eAAe,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Validation history tracking via git notes
3
+ *
4
+ * @packageDocumentation
5
+ */
6
+ export { DEFAULT_HISTORY_CONFIG } from './types.js';
7
+ // Recorder
8
+ export { recordValidationHistory, checkWorktreeStability, } from './recorder.js';
9
+ // Reader
10
+ export { readHistoryNote, listHistoryTreeHashes, getAllHistoryNotes, hasHistoryForTree, } from './reader.js';
11
+ // Pruner
12
+ export { pruneHistoryByAge, pruneAllHistory } from './pruner.js';
13
+ // Health check
14
+ export { checkHistoryHealth } from './health-check.js';
15
+ // Truncate
16
+ export { truncateValidationOutput } from './truncate.js';
17
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAaH,OAAO,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAEpD,WAAW;AACX,OAAO,EACL,uBAAuB,EACvB,sBAAsB,GACvB,MAAM,eAAe,CAAC;AAEvB,SAAS;AACT,OAAO,EACL,eAAe,EACf,qBAAqB,EACrB,kBAAkB,EAClB,iBAAiB,GAClB,MAAM,aAAa,CAAC;AAErB,SAAS;AACT,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEjE,eAAe;AACf,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAEvD,WAAW;AACX,OAAO,EAAE,wBAAwB,EAAE,MAAM,eAAe,CAAC"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * History pruning utilities
3
+ */
4
+ import type { PruneResult, HistoryConfig } from './types.js';
5
+ /**
6
+ * Prune validation history older than specified days
7
+ *
8
+ * @param olderThanDays - Remove notes older than this many days
9
+ * @param config - History configuration
10
+ * @param dryRun - If true, don't actually delete (default: false)
11
+ * @returns Prune result
12
+ */
13
+ export declare function pruneHistoryByAge(olderThanDays: number, config?: HistoryConfig, dryRun?: boolean): Promise<PruneResult>;
14
+ /**
15
+ * Prune all validation history
16
+ *
17
+ * @param config - History configuration
18
+ * @param dryRun - If true, don't actually delete (default: false)
19
+ * @returns Prune result
20
+ */
21
+ export declare function pruneAllHistory(config?: HistoryConfig, dryRun?: boolean): Promise<PruneResult>;
22
+ //# sourceMappingURL=pruner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pruner.d.ts","sourceRoot":"","sources":["../src/pruner.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAW7D;;;;;;;GAOG;AACH,wBAAsB,iBAAiB,CACrC,aAAa,EAAE,MAAM,EACrB,MAAM,GAAE,aAAkB,EAC1B,MAAM,GAAE,OAAe,GACtB,OAAO,CAAC,WAAW,CAAC,CAsDtB;AAED;;;;;;GAMG;AACH,wBAAsB,eAAe,CACnC,MAAM,GAAE,aAAkB,EAC1B,MAAM,GAAE,OAAe,GACtB,OAAO,CAAC,WAAW,CAAC,CAwCtB"}
package/dist/pruner.js ADDED
@@ -0,0 +1,107 @@
1
+ /**
2
+ * History pruning utilities
3
+ */
4
+ import { execSync } from 'child_process';
5
+ import { DEFAULT_HISTORY_CONFIG } from './types.js';
6
+ import { getAllHistoryNotes } from './reader.js';
7
+ const GIT_TIMEOUT = 30000;
8
+ const GIT_OPTIONS = {
9
+ encoding: 'utf8',
10
+ timeout: GIT_TIMEOUT,
11
+ stdio: ['pipe', 'pipe', 'ignore'],
12
+ };
13
+ /**
14
+ * Prune validation history older than specified days
15
+ *
16
+ * @param olderThanDays - Remove notes older than this many days
17
+ * @param config - History configuration
18
+ * @param dryRun - If true, don't actually delete (default: false)
19
+ * @returns Prune result
20
+ */
21
+ export async function pruneHistoryByAge(olderThanDays, config = {}, dryRun = false) {
22
+ const mergedConfig = {
23
+ ...DEFAULT_HISTORY_CONFIG,
24
+ ...config,
25
+ gitNotes: {
26
+ ...DEFAULT_HISTORY_CONFIG.gitNotes,
27
+ ...config.gitNotes,
28
+ },
29
+ };
30
+ const notesRef = mergedConfig.gitNotes.ref;
31
+ const cutoffTime = Date.now() - olderThanDays * 24 * 60 * 60 * 1000;
32
+ let notesPruned = 0;
33
+ let runsPruned = 0;
34
+ const prunedTreeHashes = [];
35
+ const allNotes = await getAllHistoryNotes(notesRef);
36
+ const notesRemaining = allNotes.length;
37
+ for (const note of allNotes) {
38
+ if (!note.runs || note.runs.length === 0) {
39
+ continue;
40
+ }
41
+ // Get oldest run timestamp
42
+ const oldestRun = note.runs[0];
43
+ const oldestTimestamp = new Date(oldestRun.timestamp).getTime();
44
+ if (oldestTimestamp < cutoffTime) {
45
+ // All runs in this note are old - delete entire note
46
+ if (!dryRun) {
47
+ try {
48
+ execSync(`git notes --ref=${notesRef} remove ${note.treeHash}`, { ...GIT_OPTIONS, stdio: 'ignore' });
49
+ }
50
+ catch {
51
+ // Ignore errors (note might not exist)
52
+ }
53
+ }
54
+ notesPruned++;
55
+ runsPruned += note.runs.length;
56
+ prunedTreeHashes.push(note.treeHash);
57
+ }
58
+ }
59
+ return {
60
+ notesPruned,
61
+ runsPruned,
62
+ notesRemaining: notesRemaining - notesPruned,
63
+ prunedTreeHashes,
64
+ };
65
+ }
66
+ /**
67
+ * Prune all validation history
68
+ *
69
+ * @param config - History configuration
70
+ * @param dryRun - If true, don't actually delete (default: false)
71
+ * @returns Prune result
72
+ */
73
+ export async function pruneAllHistory(config = {}, dryRun = false) {
74
+ const mergedConfig = {
75
+ ...DEFAULT_HISTORY_CONFIG,
76
+ ...config,
77
+ gitNotes: {
78
+ ...DEFAULT_HISTORY_CONFIG.gitNotes,
79
+ ...config.gitNotes,
80
+ },
81
+ };
82
+ const notesRef = mergedConfig.gitNotes.ref;
83
+ const allNotes = await getAllHistoryNotes(notesRef);
84
+ let notesPruned = 0;
85
+ let runsPruned = 0;
86
+ const prunedTreeHashes = [];
87
+ for (const note of allNotes) {
88
+ if (!dryRun) {
89
+ try {
90
+ execSync(`git notes --ref=${notesRef} remove ${note.treeHash}`, { ...GIT_OPTIONS, stdio: 'ignore' });
91
+ }
92
+ catch {
93
+ // Ignore errors
94
+ }
95
+ }
96
+ notesPruned++;
97
+ runsPruned += note.runs?.length || 0;
98
+ prunedTreeHashes.push(note.treeHash);
99
+ }
100
+ return {
101
+ notesPruned,
102
+ runsPruned,
103
+ notesRemaining: 0,
104
+ prunedTreeHashes,
105
+ };
106
+ }
107
+ //# sourceMappingURL=pruner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pruner.js","sourceRoot":"","sources":["../src/pruner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Git notes reader
3
+ */
4
+ import type { HistoryNote } from './types.js';
5
+ /**
6
+ * Read validation history note for a tree hash
7
+ *
8
+ * @param treeHash - Git tree hash
9
+ * @param notesRef - Git notes ref (default: vibe-validate/runs)
10
+ * @returns History note or null if not found
11
+ */
12
+ export declare function readHistoryNote(treeHash: string, notesRef?: string): Promise<HistoryNote | null>;
13
+ /**
14
+ * List all tree hashes with validation history
15
+ *
16
+ * @param notesRef - Git notes ref (default: vibe-validate/runs)
17
+ * @returns Array of tree hashes with notes
18
+ */
19
+ export declare function listHistoryTreeHashes(notesRef?: string): Promise<string[]>;
20
+ /**
21
+ * Get all validation history notes
22
+ *
23
+ * @param notesRef - Git notes ref (default: vibe-validate/runs)
24
+ * @returns Array of all history notes
25
+ */
26
+ export declare function getAllHistoryNotes(notesRef?: string): Promise<HistoryNote[]>;
27
+ /**
28
+ * Check if validation history exists for a tree hash
29
+ *
30
+ * @param treeHash - Git tree hash
31
+ * @param notesRef - Git notes ref (default: vibe-validate/runs)
32
+ * @returns True if history exists
33
+ */
34
+ export declare function hasHistoryForTree(treeHash: string, notesRef?: string): Promise<boolean>;
35
+ //# sourceMappingURL=reader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reader.d.ts","sourceRoot":"","sources":["../src/reader.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAS9C;;;;;;GAMG;AACH,wBAAsB,eAAe,CACnC,QAAQ,EAAE,MAAM,EAChB,QAAQ,GAAE,MAA6B,GACtC,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAa7B;AAED;;;;;GAKG;AACH,wBAAsB,qBAAqB,CACzC,QAAQ,GAAE,MAA6B,GACtC,OAAO,CAAC,MAAM,EAAE,CAAC,CAuBnB;AAED;;;;;GAKG;AACH,wBAAsB,kBAAkB,CACtC,QAAQ,GAAE,MAA6B,GACtC,OAAO,CAAC,WAAW,EAAE,CAAC,CAYxB;AAED;;;;;;GAMG;AACH,wBAAsB,iBAAiB,CACrC,QAAQ,EAAE,MAAM,EAChB,QAAQ,GAAE,MAA6B,GACtC,OAAO,CAAC,OAAO,CAAC,CAGlB"}
package/dist/reader.js ADDED
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Git notes reader
3
+ */
4
+ import { execSync } from 'child_process';
5
+ import { parse as parseYaml } from 'yaml';
6
+ const GIT_TIMEOUT = 30000;
7
+ const GIT_OPTIONS = {
8
+ encoding: 'utf8',
9
+ timeout: GIT_TIMEOUT,
10
+ stdio: ['pipe', 'pipe', 'ignore'],
11
+ };
12
+ /**
13
+ * Read validation history note for a tree hash
14
+ *
15
+ * @param treeHash - Git tree hash
16
+ * @param notesRef - Git notes ref (default: vibe-validate/runs)
17
+ * @returns History note or null if not found
18
+ */
19
+ export async function readHistoryNote(treeHash, notesRef = 'vibe-validate/runs') {
20
+ try {
21
+ const yaml = execSync(`git notes --ref=${notesRef} show ${treeHash}`, GIT_OPTIONS);
22
+ const note = parseYaml(yaml);
23
+ return note;
24
+ }
25
+ catch (_error) {
26
+ // Note doesn't exist - this is fine
27
+ return null;
28
+ }
29
+ }
30
+ /**
31
+ * List all tree hashes with validation history
32
+ *
33
+ * @param notesRef - Git notes ref (default: vibe-validate/runs)
34
+ * @returns Array of tree hashes with notes
35
+ */
36
+ export async function listHistoryTreeHashes(notesRef = 'vibe-validate/runs') {
37
+ try {
38
+ const output = execSync(`git notes --ref=${notesRef} list`, GIT_OPTIONS);
39
+ if (!output.trim()) {
40
+ return [];
41
+ }
42
+ // Output format: "<note-sha> <tree-hash>"
43
+ const treeHashes = output
44
+ .trim()
45
+ .split('\n')
46
+ .map((line) => {
47
+ const parts = line.split(' ');
48
+ return parts[1]; // tree hash
49
+ })
50
+ .filter(Boolean);
51
+ return treeHashes;
52
+ }
53
+ catch (_error) {
54
+ // No notes exist yet
55
+ return [];
56
+ }
57
+ }
58
+ /**
59
+ * Get all validation history notes
60
+ *
61
+ * @param notesRef - Git notes ref (default: vibe-validate/runs)
62
+ * @returns Array of all history notes
63
+ */
64
+ export async function getAllHistoryNotes(notesRef = 'vibe-validate/runs') {
65
+ const treeHashes = await listHistoryTreeHashes(notesRef);
66
+ const notes = [];
67
+ for (const treeHash of treeHashes) {
68
+ const note = await readHistoryNote(treeHash, notesRef);
69
+ if (note) {
70
+ notes.push(note);
71
+ }
72
+ }
73
+ return notes;
74
+ }
75
+ /**
76
+ * Check if validation history exists for a tree hash
77
+ *
78
+ * @param treeHash - Git tree hash
79
+ * @param notesRef - Git notes ref (default: vibe-validate/runs)
80
+ * @returns True if history exists
81
+ */
82
+ export async function hasHistoryForTree(treeHash, notesRef = 'vibe-validate/runs') {
83
+ const note = await readHistoryNote(treeHash, notesRef);
84
+ return note !== null;
85
+ }
86
+ //# sourceMappingURL=reader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reader.js","sourceRoot":"","sources":["../src/reader.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,KAAK,IAAI,SAAS,EAAE,MAAM,MAAM,CAAC;AAG1C,MAAM,WAAW,GAAG,KAAK,CAAC;AAC1B,MAAM,WAAW,GAAG;IAClB,QAAQ,EAAE,MAAe;IACzB,OAAO,EAAE,WAAW;IACpB,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,CAA+B;CAChE,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,QAAgB,EAChB,WAAmB,oBAAoB;IAEvC,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,QAAQ,CACnB,mBAAmB,QAAQ,SAAS,QAAQ,EAAE,EAC9C,WAAW,CACZ,CAAC;QAEF,MAAM,IAAI,GAAG,SAAS,CAAC,IAAI,CAAgB,CAAC;QAC5C,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,OAAO,MAAM,EAAE,CAAC;QAChB,oCAAoC;QACpC,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,WAAmB,oBAAoB;IAEvC,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,QAAQ,CAAC,mBAAmB,QAAQ,OAAO,EAAE,WAAW,CAAC,CAAC;QAEzE,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC;YACnB,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,0CAA0C;QAC1C,MAAM,UAAU,GAAG,MAAM;aACtB,IAAI,EAAE;aACN,KAAK,CAAC,IAAI,CAAC;aACX,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;YACZ,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YAC9B,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,YAAY;QAC/B,CAAC,CAAC;aACD,MAAM,CAAC,OAAO,CAAC,CAAC;QAEnB,OAAO,UAAU,CAAC;IACpB,CAAC;IAAC,OAAO,MAAM,EAAE,CAAC;QAChB,qBAAqB;QACrB,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,WAAmB,oBAAoB;IAEvC,MAAM,UAAU,GAAG,MAAM,qBAAqB,CAAC,QAAQ,CAAC,CAAC;IACzD,MAAM,KAAK,GAAkB,EAAE,CAAC;IAEhC,KAAK,MAAM,QAAQ,IAAI,UAAU,EAAE,CAAC;QAClC,MAAM,IAAI,GAAG,MAAM,eAAe,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;QACvD,IAAI,IAAI,EAAE,CAAC;YACT,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACnB,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,QAAgB,EAChB,WAAmB,oBAAoB;IAEvC,MAAM,IAAI,GAAG,MAAM,eAAe,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IACvD,OAAO,IAAI,KAAK,IAAI,CAAC;AACvB,CAAC"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Git notes recorder
3
+ */
4
+ import type { ValidationResult } from '@vibe-validate/core';
5
+ import type { RecordResult, StabilityCheck, HistoryConfig } from './types.js';
6
+ /**
7
+ * Record validation result to git notes
8
+ *
9
+ * @param treeHash - Git tree hash
10
+ * @param result - Validation result
11
+ * @param config - History configuration
12
+ * @returns Record result
13
+ */
14
+ export declare function recordValidationHistory(treeHash: string, result: ValidationResult, config?: HistoryConfig): Promise<RecordResult>;
15
+ /**
16
+ * Check worktree stability (compare tree hash before and after)
17
+ *
18
+ * @param treeHashBefore - Tree hash before validation
19
+ * @returns Stability check result
20
+ */
21
+ export declare function checkWorktreeStability(treeHashBefore: string): Promise<StabilityCheck>;
22
+ //# sourceMappingURL=recorder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recorder.d.ts","sourceRoot":"","sources":["../src/recorder.ts"],"names":[],"mappings":"AAAA;;GAEG;AAQH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,KAAK,EAGV,YAAY,EACZ,cAAc,EACd,aAAa,EACd,MAAM,YAAY,CAAC;AAuCpB;;;;;;;GAOG;AACH,wBAAsB,uBAAuB,CAC3C,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,gBAAgB,EACxB,MAAM,GAAE,aAAkB,GACzB,OAAO,CAAC,YAAY,CAAC,CA8FvB;AAED;;;;;GAKG;AACH,wBAAsB,sBAAsB,CAC1C,cAAc,EAAE,MAAM,GACrB,OAAO,CAAC,cAAc,CAAC,CAQzB"}
@@ -0,0 +1,151 @@
1
+ /**
2
+ * Git notes recorder
3
+ */
4
+ import { execSync } from 'child_process';
5
+ import { writeFileSync, unlinkSync } from 'fs';
6
+ import { tmpdir } from 'os';
7
+ import { join } from 'path';
8
+ import { stringify as stringifyYaml } from 'yaml';
9
+ import { getGitTreeHash, hasWorkingTreeChanges } from '@vibe-validate/git';
10
+ import { DEFAULT_HISTORY_CONFIG } from './types.js';
11
+ import { truncateValidationOutput } from './truncate.js';
12
+ import { readHistoryNote } from './reader.js';
13
+ const GIT_TIMEOUT = 30000;
14
+ const GIT_OPTIONS = {
15
+ encoding: 'utf8',
16
+ timeout: GIT_TIMEOUT,
17
+ stdio: ['pipe', 'pipe', 'ignore'],
18
+ };
19
+ /**
20
+ * Get current branch name
21
+ *
22
+ * @returns Branch name or 'detached' if in detached HEAD state
23
+ */
24
+ async function getCurrentBranch() {
25
+ try {
26
+ const branch = execSync('git rev-parse --abbrev-ref HEAD', GIT_OPTIONS).trim();
27
+ return branch === 'HEAD' ? 'detached' : branch;
28
+ }
29
+ catch {
30
+ return 'unknown';
31
+ }
32
+ }
33
+ /**
34
+ * Get HEAD commit SHA
35
+ *
36
+ * @returns Commit SHA or 'none' if no commits
37
+ */
38
+ async function getHeadCommit() {
39
+ try {
40
+ return execSync('git rev-parse HEAD', GIT_OPTIONS).trim();
41
+ }
42
+ catch {
43
+ return 'none';
44
+ }
45
+ }
46
+ /**
47
+ * Record validation result to git notes
48
+ *
49
+ * @param treeHash - Git tree hash
50
+ * @param result - Validation result
51
+ * @param config - History configuration
52
+ * @returns Record result
53
+ */
54
+ export async function recordValidationHistory(treeHash, result, config = {}) {
55
+ const mergedConfig = {
56
+ ...DEFAULT_HISTORY_CONFIG,
57
+ ...config,
58
+ gitNotes: {
59
+ ...DEFAULT_HISTORY_CONFIG.gitNotes,
60
+ ...config.gitNotes,
61
+ },
62
+ retention: {
63
+ ...DEFAULT_HISTORY_CONFIG.retention,
64
+ ...config.retention,
65
+ },
66
+ };
67
+ // Type assertions safe: DEFAULT_HISTORY_CONFIG is Required<HistoryConfig>
68
+ const notesRef = (mergedConfig.gitNotes.ref ?? DEFAULT_HISTORY_CONFIG.gitNotes.ref);
69
+ const maxRunsPerTree = (mergedConfig.gitNotes.maxRunsPerTree ?? DEFAULT_HISTORY_CONFIG.gitNotes.maxRunsPerTree);
70
+ const maxOutputBytes = (mergedConfig.gitNotes.maxOutputBytes ?? DEFAULT_HISTORY_CONFIG.gitNotes.maxOutputBytes);
71
+ try {
72
+ // 1. Read existing note (if any)
73
+ const existingNote = await readHistoryNote(treeHash, notesRef);
74
+ // 2. Create new run entry
75
+ const newRun = {
76
+ id: `run-${Date.now()}`,
77
+ timestamp: new Date().toISOString(),
78
+ duration: result.passed ? 0 : 0, // Will be calculated from result if available
79
+ passed: result.passed,
80
+ branch: await getCurrentBranch(),
81
+ headCommit: await getHeadCommit(),
82
+ uncommittedChanges: await hasWorkingTreeChanges(),
83
+ result: truncateValidationOutput(result, maxOutputBytes),
84
+ };
85
+ // Calculate duration from result phases if available (convert to milliseconds)
86
+ if (result.phases && result.phases.length > 0) {
87
+ newRun.duration = result.phases.reduce((total, phase) => total + (phase.durationSecs || 0) * 1000, 0);
88
+ }
89
+ // 3. Append or create
90
+ let note;
91
+ if (existingNote) {
92
+ note = {
93
+ ...existingNote,
94
+ runs: [...existingNote.runs, newRun],
95
+ };
96
+ // Prune: keep last N runs
97
+ if (note.runs.length > maxRunsPerTree) {
98
+ note.runs = note.runs.slice(-maxRunsPerTree);
99
+ }
100
+ }
101
+ else {
102
+ note = {
103
+ treeHash,
104
+ runs: [newRun],
105
+ };
106
+ }
107
+ // 4. Write note to temp file (use cross-platform temp directory)
108
+ const tempFile = join(tmpdir(), `note.vibe-validate.${treeHash.slice(0, 12)}.${process.pid}.yaml`);
109
+ try {
110
+ writeFileSync(tempFile, stringifyYaml(note), 'utf8');
111
+ // 5. Add note to git (force overwrite)
112
+ execSync(`git notes --ref=${notesRef} add -f -F "${tempFile}" ${treeHash}`, { ...GIT_OPTIONS, stdio: 'ignore' });
113
+ return {
114
+ recorded: true,
115
+ treeHash,
116
+ };
117
+ }
118
+ finally {
119
+ // Cleanup temp file
120
+ try {
121
+ unlinkSync(tempFile);
122
+ }
123
+ catch {
124
+ // Ignore cleanup errors
125
+ }
126
+ }
127
+ }
128
+ catch (error) {
129
+ const errorMessage = error instanceof Error ? error.message : String(error);
130
+ return {
131
+ recorded: false,
132
+ reason: errorMessage,
133
+ treeHash,
134
+ };
135
+ }
136
+ }
137
+ /**
138
+ * Check worktree stability (compare tree hash before and after)
139
+ *
140
+ * @param treeHashBefore - Tree hash before validation
141
+ * @returns Stability check result
142
+ */
143
+ export async function checkWorktreeStability(treeHashBefore) {
144
+ const treeHashAfter = await getGitTreeHash();
145
+ return {
146
+ stable: treeHashBefore === treeHashAfter,
147
+ treeHashBefore,
148
+ treeHashAfter,
149
+ };
150
+ }
151
+ //# sourceMappingURL=recorder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recorder.js","sourceRoot":"","sources":["../src/recorder.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Output truncation utilities
3
+ */
4
+ import type { ValidationResult } from '@vibe-validate/core';
5
+ /**
6
+ * Truncate validation result output to max bytes
7
+ *
8
+ * @param result - Validation result to truncate
9
+ * @param maxBytes - Maximum bytes per step output (default: 10000)
10
+ * @returns Truncated validation result
11
+ */
12
+ export declare function truncateValidationOutput(result: ValidationResult, maxBytes?: number): ValidationResult;
13
+ //# sourceMappingURL=truncate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"truncate.d.ts","sourceRoot":"","sources":["../src/truncate.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAE5D;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,gBAAgB,EACxB,QAAQ,GAAE,MAAc,GACvB,gBAAgB,CAgClB"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Output truncation utilities
3
+ */
4
+ /**
5
+ * Truncate validation result output to max bytes
6
+ *
7
+ * @param result - Validation result to truncate
8
+ * @param maxBytes - Maximum bytes per step output (default: 10000)
9
+ * @returns Truncated validation result
10
+ */
11
+ export function truncateValidationOutput(result, maxBytes = 10000) {
12
+ // Deep clone to avoid mutating original
13
+ const truncated = JSON.parse(JSON.stringify(result));
14
+ // Truncate phase outputs
15
+ if (truncated.phases) {
16
+ for (const phase of truncated.phases) {
17
+ if (phase.steps) {
18
+ for (const step of phase.steps) {
19
+ if (step.output && step.output.length > maxBytes) {
20
+ const originalLength = step.output.length;
21
+ step.output =
22
+ step.output.slice(0, maxBytes) +
23
+ `\n\n[... truncated ${originalLength - maxBytes} bytes]`;
24
+ }
25
+ }
26
+ }
27
+ }
28
+ }
29
+ // Truncate failed step output
30
+ if (truncated.failedStepOutput &&
31
+ truncated.failedStepOutput.length > maxBytes) {
32
+ const originalLength = truncated.failedStepOutput.length;
33
+ truncated.failedStepOutput =
34
+ truncated.failedStepOutput.slice(0, maxBytes) +
35
+ `\n\n[... truncated ${originalLength - maxBytes} bytes]`;
36
+ }
37
+ return truncated;
38
+ }
39
+ //# sourceMappingURL=truncate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"truncate.js","sourceRoot":"","sources":["../src/truncate.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH;;;;;;GAMG;AACH,MAAM,UAAU,wBAAwB,CACtC,MAAwB,EACxB,WAAmB,KAAK;IAExB,wCAAwC;IACxC,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAqB,CAAC;IAEzE,yBAAyB;IACzB,IAAI,SAAS,CAAC,MAAM,EAAE,CAAC;QACrB,KAAK,MAAM,KAAK,IAAI,SAAS,CAAC,MAAM,EAAE,CAAC;YACrC,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;gBAChB,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;oBAC/B,IAAI,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,QAAQ,EAAE,CAAC;wBACjD,MAAM,cAAc,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC;wBAC1C,IAAI,CAAC,MAAM;4BACT,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC;gCAC9B,sBAAsB,cAAc,GAAG,QAAQ,SAAS,CAAC;oBAC7D,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,8BAA8B;IAC9B,IACE,SAAS,CAAC,gBAAgB;QAC1B,SAAS,CAAC,gBAAgB,CAAC,MAAM,GAAG,QAAQ,EAC5C,CAAC;QACD,MAAM,cAAc,GAAG,SAAS,CAAC,gBAAgB,CAAC,MAAM,CAAC;QACzD,SAAS,CAAC,gBAAgB;YACxB,SAAS,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC;gBAC7C,sBAAsB,cAAc,GAAG,QAAQ,SAAS,CAAC;IAC7D,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC"}
@@ -0,0 +1,110 @@
1
+ /**
2
+ * Validation history types
3
+ */
4
+ import type { ValidationResult } from '@vibe-validate/core';
5
+ /**
6
+ * Single validation run entry
7
+ */
8
+ export interface ValidationRun {
9
+ /** Unique run ID (run-{timestamp}) */
10
+ id: string;
11
+ /** ISO 8601 timestamp */
12
+ timestamp: string;
13
+ /** Duration in milliseconds */
14
+ duration: number;
15
+ /** Did validation pass? */
16
+ passed: boolean;
17
+ /** Branch name at time of validation */
18
+ branch: string;
19
+ /** HEAD commit SHA at time of validation */
20
+ headCommit: string;
21
+ /** Were there uncommitted changes? */
22
+ uncommittedChanges: boolean;
23
+ /** Full validation result (with truncated output) */
24
+ result: ValidationResult;
25
+ }
26
+ /**
27
+ * Git note structure (stored as YAML)
28
+ */
29
+ export interface HistoryNote {
30
+ /** Tree hash this note is attached to */
31
+ treeHash: string;
32
+ /** Array of validation runs for this tree */
33
+ runs: ValidationRun[];
34
+ }
35
+ /**
36
+ * Result of recording validation history
37
+ */
38
+ export interface RecordResult {
39
+ /** Was history successfully recorded? */
40
+ recorded: boolean;
41
+ /** Reason if not recorded */
42
+ reason?: string;
43
+ /** Tree hash that was recorded (or attempted) */
44
+ treeHash: string;
45
+ }
46
+ /**
47
+ * Worktree stability check result
48
+ */
49
+ export interface StabilityCheck {
50
+ /** Is worktree stable? */
51
+ stable: boolean;
52
+ /** Tree hash before validation */
53
+ treeHashBefore: string;
54
+ /** Tree hash after validation */
55
+ treeHashAfter: string;
56
+ }
57
+ /**
58
+ * History configuration
59
+ */
60
+ export interface HistoryConfig {
61
+ /** Enable history recording */
62
+ enabled?: boolean;
63
+ /** Git notes configuration */
64
+ gitNotes?: {
65
+ /** Git ref namespace */
66
+ ref?: string;
67
+ /** Max runs to keep per tree */
68
+ maxRunsPerTree?: number;
69
+ /** Truncate output to max bytes */
70
+ maxOutputBytes?: number;
71
+ };
72
+ /** Retention policy */
73
+ retention?: {
74
+ /** Warn after this many days */
75
+ warnAfterDays?: number;
76
+ /** Warn after this many total notes */
77
+ warnAfterCount?: number;
78
+ };
79
+ }
80
+ /**
81
+ * Default history configuration
82
+ */
83
+ export declare const DEFAULT_HISTORY_CONFIG: Required<HistoryConfig>;
84
+ /**
85
+ * Health check result
86
+ */
87
+ export interface HealthCheckResult {
88
+ /** Total number of tree hashes with notes */
89
+ totalNotes: number;
90
+ /** Number of notes older than retention policy */
91
+ oldNotesCount: number;
92
+ /** Should warn user about cleanup? */
93
+ shouldWarn: boolean;
94
+ /** Warning message (if any) */
95
+ warningMessage?: string;
96
+ }
97
+ /**
98
+ * Prune result
99
+ */
100
+ export interface PruneResult {
101
+ /** Number of notes pruned */
102
+ notesPruned: number;
103
+ /** Number of runs pruned (across all notes) */
104
+ runsPruned: number;
105
+ /** Number of notes remaining */
106
+ notesRemaining: number;
107
+ /** Tree hashes that were pruned */
108
+ prunedTreeHashes: string[];
109
+ }
110
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAE5D;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,sCAAsC;IACtC,EAAE,EAAE,MAAM,CAAC;IAEX,yBAAyB;IACzB,SAAS,EAAE,MAAM,CAAC;IAElB,+BAA+B;IAC/B,QAAQ,EAAE,MAAM,CAAC;IAEjB,2BAA2B;IAC3B,MAAM,EAAE,OAAO,CAAC;IAEhB,wCAAwC;IACxC,MAAM,EAAE,MAAM,CAAC;IAEf,4CAA4C;IAC5C,UAAU,EAAE,MAAM,CAAC;IAEnB,sCAAsC;IACtC,kBAAkB,EAAE,OAAO,CAAC;IAE5B,qDAAqD;IACrD,MAAM,EAAE,gBAAgB,CAAC;CAC1B;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,yCAAyC;IACzC,QAAQ,EAAE,MAAM,CAAC;IAEjB,6CAA6C;IAC7C,IAAI,EAAE,aAAa,EAAE,CAAC;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,yCAAyC;IACzC,QAAQ,EAAE,OAAO,CAAC;IAElB,6BAA6B;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,iDAAiD;IACjD,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,0BAA0B;IAC1B,MAAM,EAAE,OAAO,CAAC;IAEhB,kCAAkC;IAClC,cAAc,EAAE,MAAM,CAAC;IAEvB,iCAAiC;IACjC,aAAa,EAAE,MAAM,CAAC;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,+BAA+B;IAC/B,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB,8BAA8B;IAC9B,QAAQ,CAAC,EAAE;QACT,wBAAwB;QACxB,GAAG,CAAC,EAAE,MAAM,CAAC;QAEb,gCAAgC;QAChC,cAAc,CAAC,EAAE,MAAM,CAAC;QAExB,mCAAmC;QACnC,cAAc,CAAC,EAAE,MAAM,CAAC;KACzB,CAAC;IAEF,uBAAuB;IACvB,SAAS,CAAC,EAAE;QACV,gCAAgC;QAChC,aAAa,CAAC,EAAE,MAAM,CAAC;QAEvB,uCAAuC;QACvC,cAAc,CAAC,EAAE,MAAM,CAAC;KACzB,CAAC;CACH;AAED;;GAEG;AACH,eAAO,MAAM,sBAAsB,EAAE,QAAQ,CAAC,aAAa,CAW1D,CAAC;AAEF;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,6CAA6C;IAC7C,UAAU,EAAE,MAAM,CAAC;IAEnB,kDAAkD;IAClD,aAAa,EAAE,MAAM,CAAC;IAEtB,sCAAsC;IACtC,UAAU,EAAE,OAAO,CAAC;IAEpB,+BAA+B;IAC/B,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,6BAA6B;IAC7B,WAAW,EAAE,MAAM,CAAC;IAEpB,+CAA+C;IAC/C,UAAU,EAAE,MAAM,CAAC;IAEnB,gCAAgC;IAChC,cAAc,EAAE,MAAM,CAAC;IAEvB,mCAAmC;IACnC,gBAAgB,EAAE,MAAM,EAAE,CAAC;CAC5B"}
package/dist/types.js ADDED
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Validation history types
3
+ */
4
+ /**
5
+ * Default history configuration
6
+ */
7
+ export const DEFAULT_HISTORY_CONFIG = {
8
+ enabled: true,
9
+ gitNotes: {
10
+ ref: 'vibe-validate/runs',
11
+ maxRunsPerTree: 10,
12
+ maxOutputBytes: 10000,
13
+ },
14
+ retention: {
15
+ warnAfterDays: 90,
16
+ warnAfterCount: 100,
17
+ },
18
+ };
19
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAqGH;;GAEG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAA4B;IAC7D,OAAO,EAAE,IAAI;IACb,QAAQ,EAAE;QACR,GAAG,EAAE,oBAAoB;QACzB,cAAc,EAAE,EAAE;QAClB,cAAc,EAAE,KAAK;KACtB;IACD,SAAS,EAAE;QACT,aAAa,EAAE,EAAE;QACjB,cAAc,EAAE,GAAG;KACpB;CACF,CAAC"}
package/package.json ADDED
@@ -0,0 +1,55 @@
1
+ {
2
+ "name": "@vibe-validate/history",
3
+ "version": "0.12.0",
4
+ "description": "Validation history tracking via git notes for vibe-validate",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ }
13
+ },
14
+ "files": [
15
+ "dist",
16
+ "README.md",
17
+ "LICENSE"
18
+ ],
19
+ "scripts": {
20
+ "build": "tsc",
21
+ "clean": "rm -rf dist",
22
+ "test": "vitest run",
23
+ "test:watch": "vitest"
24
+ },
25
+ "keywords": [
26
+ "validation",
27
+ "history",
28
+ "git-notes",
29
+ "caching",
30
+ "sdlc"
31
+ ],
32
+ "author": "Jeff Dutton",
33
+ "license": "MIT",
34
+ "repository": {
35
+ "type": "git",
36
+ "url": "git+https://github.com/jdutton/vibe-validate.git",
37
+ "directory": "packages/history"
38
+ },
39
+ "engines": {
40
+ "node": ">=20.0.0"
41
+ },
42
+ "publishConfig": {
43
+ "access": "public"
44
+ },
45
+ "dependencies": {
46
+ "@vibe-validate/git": "workspace:*",
47
+ "@vibe-validate/core": "workspace:*",
48
+ "yaml": "^2.3.4"
49
+ },
50
+ "devDependencies": {
51
+ "@types/node": "^22.0.0",
52
+ "typescript": "^5.6.0",
53
+ "vitest": "^2.0.0"
54
+ }
55
+ }