@ankurhalder/codebase-snapshot 0.0.0-stage → 2.1.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.
@@ -0,0 +1,391 @@
1
+ type Mode = "generate" | "validate" | "report";
2
+ type OutputFormat = "text" | "json";
3
+ /**
4
+ * How much of a file made it into the snapshot.
5
+ * `full` – the complete file body was emitted.
6
+ * `preview` – the body was truncated (by lines and/or bytes) before emission.
7
+ */
8
+ type InclusionMode = "full" | "preview";
9
+ interface SourceSummary {
10
+ directives: string[];
11
+ imports: string[];
12
+ exports: string[];
13
+ /** Module specifiers re-exported wholesale via `export * from "..."`. */
14
+ reExports: string[];
15
+ functions: string[];
16
+ classes: string[];
17
+ interfaces: string[];
18
+ types: string[];
19
+ enums: string[];
20
+ variables: string[];
21
+ reactComponents: string[];
22
+ hooks: string[];
23
+ routeHandlers: string[];
24
+ /** Number of parser diagnostics, present only when the file has syntax errors. */
25
+ parseErrors?: number;
26
+ }
27
+ interface JsonSummary {
28
+ shape: string;
29
+ itemCount: number | null;
30
+ keys: string[];
31
+ sampleKeys: string[];
32
+ }
33
+ interface MarkdownSummary {
34
+ headings: string[];
35
+ frontmatterKeys: string[];
36
+ }
37
+ /**
38
+ * How a summary was produced.
39
+ *
40
+ * `ast` — a real parser (TypeScript compiler; the script block of a
41
+ * Vue/Svelte/Astro component).
42
+ * `structural` — a real grammar for a data format (JSON, Markdown).
43
+ * `heuristic` — line patterns. Useful, but not a parse, and never presented
44
+ * as one.
45
+ */
46
+ type SummaryQuality = "ast" | "structural" | "heuristic";
47
+ type SkipReason = "asset" | "binary" | "read-error" | "not-file" | "sensitive-file" | "symlink" | "default-ignore" | "excluded";
48
+ interface SkipRecord {
49
+ path: string;
50
+ reason: SkipReason;
51
+ detail?: string;
52
+ }
53
+ /**
54
+ * One scanned file. Field names are canonical and unique by design:
55
+ * earlier releases carried `path`/`relativePath`, `sizeBytes`/`bytes` and
56
+ * `hashSha256`/`sha256` aliases that could only ever agree.
57
+ */
58
+ interface FileEntry {
59
+ relativePath: string;
60
+ sizeBytes: number;
61
+ lines: number;
62
+ hashSha256: string;
63
+ part: string;
64
+ layer: string;
65
+ kind: string;
66
+ language: string;
67
+ inclusionMode: InclusionMode;
68
+ isLarge: boolean;
69
+ isPreviewTruncated: boolean;
70
+ /** Line count of the file on disk. */
71
+ originalLines: number;
72
+ /** Lines actually emitted into the snapshot. */
73
+ includedLines: number;
74
+ /** UTF-8 bytes of file content actually emitted into the snapshot. */
75
+ includedBytes: number;
76
+ summary?: SourceSummary | JsonSummary | MarkdownSummary;
77
+ /** How the summary was produced. Absent when there is no summary. */
78
+ summaryQuality?: SummaryQuality;
79
+ /** True when the summary alone was too large for the part budget and was dropped. */
80
+ summaryOmitted?: boolean;
81
+ /** Emitted body after redaction/truncation. Never serialized into the manifest. */
82
+ content?: string;
83
+ }
84
+ interface PartFileEntry {
85
+ relativePath: string;
86
+ sourceBytes: number;
87
+ includedBytes: number;
88
+ lines: number;
89
+ layer: string;
90
+ kind: string;
91
+ }
92
+ interface PartMetadata {
93
+ index: number;
94
+ filename: string;
95
+ /** Exact UTF-8 byte length of the emitted part file. */
96
+ byteSize: number;
97
+ sha256: string;
98
+ lines: number;
99
+ fileCount: number;
100
+ layersCovered: string[];
101
+ includedFiles: PartFileEntry[];
102
+ }
103
+ interface SecretRule {
104
+ rule: string;
105
+ pattern: RegExp;
106
+ }
107
+ /** Shape accepted from JSON config files, where `pattern` can only be a string. */
108
+ interface SecretRuleInput {
109
+ rule: string;
110
+ pattern: RegExp | string;
111
+ }
112
+ /**
113
+ * A detected secret. Deliberately carries no excerpt of the matched source:
114
+ * the previous `snippet` field was the vector by which raw credentials were
115
+ * written into `reports/audit.md`.
116
+ */
117
+ interface SecretFinding {
118
+ rule: string;
119
+ line: number;
120
+ path?: string;
121
+ }
122
+ interface ManifestTotals {
123
+ candidateFiles: number;
124
+ includedFiles: number;
125
+ fullFiles: number;
126
+ previewFiles: number;
127
+ skippedFiles: number;
128
+ totalSourceBytes: number;
129
+ totalContentBytes: number;
130
+ partCount: number;
131
+ warningCount: number;
132
+ }
133
+ interface ManifestArtifact {
134
+ byteSize: number;
135
+ sha256: string;
136
+ }
137
+ interface ManifestIndexes {
138
+ routes: Array<{
139
+ path: string;
140
+ methods: string[];
141
+ part: string;
142
+ }>;
143
+ components: Array<{
144
+ path: string;
145
+ symbols: string[];
146
+ part: string;
147
+ layer: string;
148
+ }>;
149
+ handlers: Array<{
150
+ path: string;
151
+ exports: string[];
152
+ part: string;
153
+ }>;
154
+ features: Array<{
155
+ name: string;
156
+ files: number;
157
+ }>;
158
+ imports: {
159
+ byFile: Array<{
160
+ path: string;
161
+ imports: string[];
162
+ exports: string[];
163
+ }>;
164
+ centralFiles: Array<{
165
+ path: string;
166
+ importedByCount: number;
167
+ }>;
168
+ };
169
+ directives: Array<{
170
+ path: string;
171
+ directives: string[];
172
+ }>;
173
+ }
174
+ /** Effective configuration recorded so `validate` can detect config drift. */
175
+ interface ManifestConfigSnapshot {
176
+ maxPartBytes: number;
177
+ largeFileBytes: number;
178
+ previewHeadLines: number;
179
+ previewTailLines: number;
180
+ includeMonolith: boolean;
181
+ includeSensitiveFiles: boolean;
182
+ artifacts: ResolvedArtifacts;
183
+ include: string[];
184
+ preset: string;
185
+ layersMode: "merge" | "replace";
186
+ budgets: ResolvedBudgets;
187
+ excludePatterns: string[];
188
+ layers: string[];
189
+ kinds: string[];
190
+ }
191
+ interface Manifest {
192
+ schemaVersion: string;
193
+ generatedAt: string;
194
+ generator: {
195
+ name: string;
196
+ version: string;
197
+ };
198
+ git: {
199
+ branch: string;
200
+ commit: string;
201
+ isDirty: boolean;
202
+ };
203
+ budgets: {
204
+ maxPartBytes: number;
205
+ largeFileBytes: number;
206
+ };
207
+ config: ManifestConfigSnapshot;
208
+ counts: {
209
+ totalFiles: number;
210
+ totalSizeBytes: number;
211
+ totalLines: number;
212
+ partsCount: number;
213
+ skippedCount: number;
214
+ largeFileCount: number;
215
+ truncatedPreviewCount: number;
216
+ };
217
+ totals: ManifestTotals;
218
+ fingerprint: string;
219
+ validation: {
220
+ status: "passed" | "failed";
221
+ errors: string[];
222
+ };
223
+ artifacts: {
224
+ fullJson: ManifestArtifact | null;
225
+ fullMarkdown: ManifestArtifact | null;
226
+ };
227
+ layers: Record<string, number>;
228
+ kinds: Record<string, number>;
229
+ indexes: ManifestIndexes;
230
+ parts: PartMetadata[];
231
+ files: FileEntry[];
232
+ skipped: SkipRecord[];
233
+ warnings: string[];
234
+ }
235
+ interface LayerRule {
236
+ name: string;
237
+ match: string | RegExp | ((filePath: string) => boolean);
238
+ }
239
+ /**
240
+ * Which snapshot artifacts get written.
241
+ *
242
+ * Everything a developer opens is produced by default; each entry exists only so
243
+ * a single artifact can be switched off without disabling the rest. `monolith`
244
+ * is the one exception, because it duplicates the entire payload: it follows
245
+ * `includeMonolith` (off by default) unless set here explicitly.
246
+ */
247
+ interface ArtifactSelection {
248
+ /** `README.md` — the orientation page for humans and models. */
249
+ readme?: boolean;
250
+ /** `manifest.json` — the registry `validate` and `report` read. */
251
+ manifest?: boolean;
252
+ /** `parts/part-XXX.md` — the partitioned code payload. */
253
+ parts?: boolean;
254
+ /** `reports/navigation.md` — file-to-part lookup index. */
255
+ navigation?: boolean;
256
+ /** `reports/project-tree.md` — ASCII repository tree. */
257
+ projectTree?: boolean;
258
+ /** `reports/audit.md` — security, layer, kind and skip findings. */
259
+ audit?: boolean;
260
+ /** `full-codebase.{json,md}` — one file per format, the whole payload again. */
261
+ monolith?: boolean;
262
+ }
263
+ /** Every artifact decision made concrete. */
264
+ type ResolvedArtifacts = Required<ArtifactSelection>;
265
+ interface KindRule {
266
+ kind: string;
267
+ match: string | RegExp | ((filePath: string) => boolean);
268
+ }
269
+ /** A byte budget: either raw bytes or a human-readable size such as `"120k"`. */
270
+ type ByteSize = number | string;
271
+ /** Per-layer part budgets. Unlisted layers fall back to `default`. */
272
+ interface BudgetConfig {
273
+ default?: ByteSize;
274
+ byLayer?: Record<string, ByteSize>;
275
+ }
276
+ /** Every budget resolved to concrete byte counts. */
277
+ interface ResolvedBudgets {
278
+ default: number;
279
+ byLayer: Record<string, number>;
280
+ }
281
+ /** Lifecycle hooks. Not serialized into the manifest (functions are not data). */
282
+ interface HooksConfig {
283
+ /** Runs once after a successful generate, with the manifest that was written. */
284
+ afterGenerate?: (manifest: Manifest) => void;
285
+ }
286
+ interface SnapshotConfig {
287
+ cwd?: string;
288
+ branch?: string;
289
+ outDir?: string;
290
+ tmpDir?: string;
291
+ /** Raw bytes, or a human-readable size (`"120k"`, `"1.5mb"`). */
292
+ maxPartBytes?: ByteSize;
293
+ largeFileBytes?: ByteSize;
294
+ previewHeadLines?: number;
295
+ previewTailLines?: number;
296
+ includeMonolith?: boolean;
297
+ maxMonolithBytes?: ByteSize | null;
298
+ /** Opt in to emitting `.env`/`*.pem`/`.npmrc`/credential files. Default false. */
299
+ includeSensitiveFiles?: boolean;
300
+ /** Allow-list of globs. When non-empty, only matching files are included. */
301
+ include?: string[];
302
+ /** Force a preset by name instead of auto-detecting one. */
303
+ preset?: string;
304
+ /** Switch individual snapshot artifacts off. Everything is on by default. */
305
+ artifacts?: ArtifactSelection;
306
+ /**
307
+ * How user `layers`/`kinds` interact with the detected preset (default
308
+ * `"merge"`): user rules are evaluated first, then the preset fills the gaps.
309
+ * `"replace"` discards the preset entirely.
310
+ */
311
+ layersMode?: "merge" | "replace";
312
+ /** Per-layer part budgets. */
313
+ budgets?: BudgetConfig;
314
+ hooks?: HooksConfig;
315
+ layers?: LayerRule[];
316
+ kinds?: KindRule[];
317
+ excludePatterns?: string[];
318
+ secrets?: {
319
+ customPatterns?: SecretRuleInput[];
320
+ disableDefaultPatterns?: boolean;
321
+ };
322
+ }
323
+ interface ResolvedSnapshotConfig {
324
+ cwd: string;
325
+ branch: string;
326
+ outDir: string;
327
+ tmpDir: string;
328
+ maxPartBytes: number;
329
+ largeFileBytes: number;
330
+ previewHeadLines: number;
331
+ previewTailLines: number;
332
+ includeMonolith: boolean;
333
+ maxMonolithBytes: number | null;
334
+ includeSensitiveFiles: boolean;
335
+ /** Empty means "no allow-list"; every discovered file is a candidate. */
336
+ include: string[];
337
+ /** The preset that was resolved (detected or forced). */
338
+ preset: string;
339
+ /** Ecosystem ignores contributed by the preset, merged with `excludePatterns`. */
340
+ presetExclude: string[];
341
+ artifacts: ResolvedArtifacts;
342
+ layersMode: "merge" | "replace";
343
+ budgets: ResolvedBudgets;
344
+ hooks: HooksConfig;
345
+ layers: LayerRule[];
346
+ kinds: KindRule[];
347
+ excludePatterns: string[];
348
+ secretRules: SecretRule[];
349
+ }
350
+ interface CliOptions {
351
+ mode: Mode;
352
+ format: OutputFormat;
353
+ dryRun: boolean;
354
+ cwd?: string;
355
+ outDir?: string;
356
+ includeMonolith?: boolean;
357
+ includeSensitiveFiles?: boolean;
358
+ maxMonolithBytes?: number | null;
359
+ maxPartBytes?: number;
360
+ largeFileBytes?: number;
361
+ /** Artifact names to suppress for this invocation (`--skip-artifacts`). */
362
+ skipArtifacts?: string[];
363
+ }
364
+ interface ValidationDrift {
365
+ missingInSnapshot: string[];
366
+ missingOnDisk: string[];
367
+ hashMismatches: Array<{
368
+ path: string;
369
+ diskHash: string;
370
+ snapshotHash: string;
371
+ }>;
372
+ /** Emitted `parts/*.md` that are missing or no longer match their recorded hash. */
373
+ partIssues: Array<{
374
+ part: string;
375
+ issue: string;
376
+ }>;
377
+ /** `counts`/`totals`/`budgets` that disagree with the rest of the manifest. */
378
+ totalsMismatches: string[];
379
+ /** Effective-configuration differences between the manifest and the current run. */
380
+ configMismatches: string[];
381
+ }
382
+ interface ValidationResult {
383
+ valid: boolean;
384
+ manifestPresent: boolean;
385
+ drift: ValidationDrift;
386
+ errors: string[];
387
+ /** Non-fatal observations (e.g. branch moved on). */
388
+ warnings: string[];
389
+ }
390
+
391
+ export type { ArtifactSelection as A, ByteSize as B, CliOptions as C, FileEntry as F, HooksConfig as H, InclusionMode as I, JsonSummary as J, KindRule as K, LayerRule as L, MarkdownSummary as M, OutputFormat as O, PartMetadata as P, ResolvedSnapshotConfig as R, SourceSummary as S, ValidationResult as V, SnapshotConfig as a, SecretRule as b, SecretFinding as c, Manifest as d, SkipRecord as e, BudgetConfig as f, ManifestArtifact as g, ManifestConfigSnapshot as h, ManifestIndexes as i, ManifestTotals as j, Mode as k, PartFileEntry as l, ResolvedArtifacts as m, ResolvedBudgets as n, SecretRuleInput as o, SkipReason as p, SummaryQuality as q, ValidationDrift as r };