@ankurhalder/codebase-snapshot 3.0.0 → 4.0.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/README.md +161 -310
- package/dist/bin.js +2247 -709
- package/dist/{chunk-5B4UVQLR.js → chunk-RGIMMEAW.js} +1763 -425
- package/dist/cli.cjs +2212 -673
- package/dist/cli.d.cts +3 -1
- package/dist/cli.d.ts +3 -1
- package/dist/cli.js +268 -68
- package/dist/index.cjs +1762 -422
- package/dist/index.d.cts +28 -29
- package/dist/index.d.ts +28 -29
- package/dist/index.js +1 -1
- package/dist/{types-CJqkePM4.d.cts → types-LSfwsKE-.d.cts} +38 -4
- package/dist/{types-CJqkePM4.d.ts → types-LSfwsKE-.d.ts} +38 -4
- package/docs/agent.md +77 -37
- package/docs/cli.md +317 -0
- package/docs/configuration.md +254 -226
- package/docs/install.md +114 -86
- package/docs/output.md +213 -0
- package/docs/troubleshooting.md +277 -0
- package/package.json +7 -4
package/dist/index.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { J as JsonSummary, M as MarkdownSummary, S as SourceSummary, R as ResolvedSnapshotConfig, a as SnapshotConfig, B as ByteSize, C as CliOptions, F as FileEntry, P as PartMetadata, L as LayerRule, K as KindRule, b as SecretRule, c as SecretFinding, V as ValidationResult, d as Manifest, A as ArtifactSelection, e as SkipRecord } from './types-
|
|
2
|
-
export { f as BudgetConfig, H as HooksConfig, I as InclusionMode, g as ManifestArtifact, h as ManifestConfigSnapshot, i as ManifestIndexes, j as ManifestTotals, k as Mode, O as OutputFormat, l as PartFileEntry, m as ResolvedArtifacts, n as ResolvedBudgets, o as SecretRuleInput, p as SkipReason, q as SummaryQuality, r as ValidationDrift } from './types-
|
|
1
|
+
import { J as JsonSummary, M as MarkdownSummary, S as SourceSummary, R as ResolvedSnapshotConfig, a as SnapshotConfig, B as ByteSize, C as CliOptions, F as FileEntry, P as PartMetadata, L as LayerRule, K as KindRule, b as SecretRule, c as SecretFinding, V as ValidationResult, d as Manifest, A as ArtifactSelection, e as SkipRecord } from './types-LSfwsKE-.cjs';
|
|
2
|
+
export { f as BudgetConfig, H as HooksConfig, I as InclusionMode, g as ManifestArtifact, h as ManifestConfigSnapshot, i as ManifestIndexes, j as ManifestTotals, k as Mode, O as OutputFormat, l as PartFileEntry, m as ResolvedArtifacts, n as ResolvedBudgets, o as SecretRuleInput, p as SkipReason, q as SummaryQuality, r as ValidationDrift } from './types-LSfwsKE-.cjs';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Strips `//` and block comments the way JSONC does, without touching anything
|
|
@@ -142,6 +142,16 @@ declare function renumberParts(parts: PartitionedPart[], contentFingerprint?: st
|
|
|
142
142
|
* contains a fenced block cannot break out of its own code block.
|
|
143
143
|
*/
|
|
144
144
|
declare function fenceForContent(content: string): string;
|
|
145
|
+
/**
|
|
146
|
+
* A fence longer than any backtick run in `content`, never shorter than
|
|
147
|
+
* `minimum`.
|
|
148
|
+
*
|
|
149
|
+
* Every fenced block the generator writes goes through this, not just file
|
|
150
|
+
* bodies: a *filename* may contain a backtick run (it is a legal name), and a
|
|
151
|
+
* fixed three-backtick fence around the `## Files` list let such a name close
|
|
152
|
+
* the block and turn the following filenames into live document text.
|
|
153
|
+
*/
|
|
154
|
+
declare function fenceForText(content: string, minimum: number): string;
|
|
145
155
|
/**
|
|
146
156
|
* Stable, injective anchor for a file path.
|
|
147
157
|
*
|
|
@@ -238,6 +248,8 @@ declare function detectLanguage(filePath: string): string;
|
|
|
238
248
|
*
|
|
239
249
|
* - Replaces only the matched span, so unrelated code sharing the line survives
|
|
240
250
|
* (the previous implementation discarded the whole line).
|
|
251
|
+
* - When a rule declares `valueGroup`, only that capture group is masked, so
|
|
252
|
+
* `dbPassword: "…"` keeps its key and stays parseable.
|
|
241
253
|
* - Masks PEM private-key blocks as a unit; per-line rules can only see the
|
|
242
254
|
* `BEGIN` header, which left every body line of a real key in the output.
|
|
243
255
|
* - Records `{ rule, line, path }` only. No excerpt of the source is retained,
|
|
@@ -262,20 +274,6 @@ declare function scanAndRedactSecrets(content: string, rules: SecretRule[], file
|
|
|
262
274
|
*/
|
|
263
275
|
declare function validateSnapshot(configInput: ResolvedSnapshotConfig | SnapshotConfig): ValidationResult;
|
|
264
276
|
|
|
265
|
-
/**
|
|
266
|
-
* Default secret rules.
|
|
267
|
-
*
|
|
268
|
-
* Design notes:
|
|
269
|
-
* - Every quantifier is bounded. An unbounded `[A-Za-z0-9_-]{10,}` followed by
|
|
270
|
-
* `\.` backtracks to the end of the line at every start position, which made
|
|
271
|
-
* `jwt-token` quadratic (measured: 1.22 s for a 200 KB line). JWT segments are
|
|
272
|
-
* never longer than a few KB, so bounding at 1024 keeps the match linear in
|
|
273
|
-
* practice while still matching every realistic token.
|
|
274
|
-
* - Rules are line-oriented; the whole-block private-key scan lives in
|
|
275
|
-
* `redact.ts` because it spans lines.
|
|
276
|
-
* - Names are matched case-insensitively only where a value is anchored by
|
|
277
|
-
* quotes or a length, to keep false positives at zero on ordinary source.
|
|
278
|
-
*/
|
|
279
277
|
declare const DEFAULT_SECRET_PATTERNS: SecretRule[];
|
|
280
278
|
|
|
281
279
|
interface ExplainResult {
|
|
@@ -329,12 +327,7 @@ interface DiffSide {
|
|
|
329
327
|
fileCount: number;
|
|
330
328
|
partsCount: number;
|
|
331
329
|
}
|
|
332
|
-
/**
|
|
333
|
-
* Compares two manifests file by file.
|
|
334
|
-
*
|
|
335
|
-
* The per-file hashes and the content fingerprint already make this exact, so
|
|
336
|
-
* nothing is inferred: a path is added, removed or changed, never "maybe".
|
|
337
|
-
*/
|
|
330
|
+
/** Compares two manifests file by file. */
|
|
338
331
|
declare function compareManifests(before: Manifest, after: Manifest): ManifestDiff;
|
|
339
332
|
/** Loads a manifest from a snapshot directory or a `manifest.json` path. */
|
|
340
333
|
declare function loadManifest(target: string): Manifest;
|
|
@@ -464,6 +457,11 @@ interface CollectOptions {
|
|
|
464
457
|
* Default `false`: they are skipped with `reason: "sensitive-file"`.
|
|
465
458
|
*/
|
|
466
459
|
includeSensitiveFiles?: boolean;
|
|
460
|
+
/**
|
|
461
|
+
* Secret rules used to scan *paths* (defaults are always applied). Pass
|
|
462
|
+
* `config.secretRules` so `customPatterns` also protect file names.
|
|
463
|
+
*/
|
|
464
|
+
secretRules?: readonly SecretRule[];
|
|
467
465
|
}
|
|
468
466
|
interface CollectResult {
|
|
469
467
|
files: string[];
|
|
@@ -497,7 +495,7 @@ declare function matchesExclude(relativePath: string, pattern: string): boolean;
|
|
|
497
495
|
declare function collectFiles(cwd: string, options?: CollectOptions): CollectResult;
|
|
498
496
|
|
|
499
497
|
declare const GENERATOR_NAME = "@ankurhalder/codebase-snapshot";
|
|
500
|
-
declare const GENERATOR_VERSION = "
|
|
498
|
+
declare const GENERATOR_VERSION = "4.0.1";
|
|
501
499
|
declare const SCHEMA_VERSION = "3.0.0";
|
|
502
500
|
interface GenerateOptions {
|
|
503
501
|
/** Compute the full manifest but write nothing to disk. */
|
|
@@ -521,12 +519,13 @@ declare function resolveSafeOutputDirs(config: {
|
|
|
521
519
|
/**
|
|
522
520
|
* Refuses to replace a directory that this generator did not write.
|
|
523
521
|
*
|
|
524
|
-
*
|
|
525
|
-
*
|
|
526
|
-
*
|
|
527
|
-
*
|
|
522
|
+
* Path checks alone cannot make the swap safe: `outDir: "src"` is a plausible
|
|
523
|
+
* typo, and a user directory that happens to contain a `.codebase-snapshot` file
|
|
524
|
+
* or a manifest-shaped JSON document is not a snapshot. The staging root is
|
|
525
|
+
* checked separately by {@link assertStagingRootUsable}, because it holds one
|
|
526
|
+
* directory per run rather than a single snapshot.
|
|
528
527
|
*/
|
|
529
|
-
declare function assertReplaceable(target: string, label: "outDir" | "tmpDir"): void;
|
|
528
|
+
declare function assertReplaceable(target: string, label: "outDir" | "tmpDir", secretRules?: readonly SecretRule[]): void;
|
|
530
529
|
/**
|
|
531
530
|
* Generates the snapshot.
|
|
532
531
|
*
|
|
@@ -538,4 +537,4 @@ declare function generateSnapshot(configInput?: SnapshotConfig | ResolvedSnapsho
|
|
|
538
537
|
/** Promise-returning wrapper for consumers that prefer an async call site. */
|
|
539
538
|
declare function generateSnapshotAsync(configInput?: SnapshotConfig | ResolvedSnapshotConfig | null, options?: GenerateOptions): Promise<Manifest>;
|
|
540
539
|
|
|
541
|
-
export { ARTIFACT_NAMES, ArtifactSelection, ByteSize, CliOptions, DEFAULT_ANSWERS, DEFAULT_SECRET_PATTERNS, type ExplainResult, FileEntry, GENERATOR_NAME, GENERATOR_VERSION, type GenerateOptions, type HeuristicResult, type InitOptions, type InitResult, JsonSummary, KindRule, LANGUAGE_PROFILES, type LanguageProfile, LayerRule, MIN_MAX_PART_BYTES, Manifest, type ManifestDiff, MarkdownSummary, PRESETS, PartMetadata, PromptCancelled, ResolvedSnapshotConfig, SCHEMA_VERSION, SecretFinding, SecretRule, SkipRecord, SnapshotConfig, SourceSummary, ValidationResult, type WizardAnswers, anchorForPath, assertReplaceable, assertUsableConfigInput, collectFiles, compareManifests, countLines, defineConfig, detectLanguage, detectPreset, explainPath, fenceForContent, generateProjectTree, generateSnapshot, generateSnapshotAsync, getPreset, globToRegExp, isBinaryBuffer, isBinaryExtension, isBinaryFile, isInteractive, isResolvedConfig, isSensitivePath, listPresetNames, loadConfigFile, loadConfigFileDetailed, loadManifest, markResolvedConfig, matchRule, matchesExclude, normalizeResolvedConfig, parseByteSize, partitionFiles, profileForPath, renderConfig, renderDiffText, renderExplainText, renderMinimalConfig, renumberParts, resolveConfig, resolveSafeOutputDirs, runInit, scanAndRedactSecrets, stripJsonComments, summarizeJson, summarizeMarkdown, summarizeTypeScriptSource, summarizeWithProfile, supportsTypeScriptImports, truncatePreview, truncateToBytes, validateSnapshot };
|
|
540
|
+
export { ARTIFACT_NAMES, ArtifactSelection, ByteSize, CliOptions, DEFAULT_ANSWERS, DEFAULT_SECRET_PATTERNS, type ExplainResult, FileEntry, GENERATOR_NAME, GENERATOR_VERSION, type GenerateOptions, type HeuristicResult, type InitOptions, type InitResult, JsonSummary, KindRule, LANGUAGE_PROFILES, type LanguageProfile, LayerRule, MIN_MAX_PART_BYTES, Manifest, type ManifestDiff, MarkdownSummary, PRESETS, PartMetadata, PromptCancelled, ResolvedSnapshotConfig, SCHEMA_VERSION, SecretFinding, SecretRule, SkipRecord, SnapshotConfig, SourceSummary, ValidationResult, type WizardAnswers, anchorForPath, assertReplaceable, assertUsableConfigInput, collectFiles, compareManifests, countLines, defineConfig, detectLanguage, detectPreset, explainPath, fenceForContent, fenceForText, generateProjectTree, generateSnapshot, generateSnapshotAsync, getPreset, globToRegExp, isBinaryBuffer, isBinaryExtension, isBinaryFile, isInteractive, isResolvedConfig, isSensitivePath, listPresetNames, loadConfigFile, loadConfigFileDetailed, loadManifest, markResolvedConfig, matchRule, matchesExclude, normalizeResolvedConfig, parseByteSize, partitionFiles, profileForPath, renderConfig, renderDiffText, renderExplainText, renderMinimalConfig, renumberParts, resolveConfig, resolveSafeOutputDirs, runInit, scanAndRedactSecrets, stripJsonComments, summarizeJson, summarizeMarkdown, summarizeTypeScriptSource, summarizeWithProfile, supportsTypeScriptImports, truncatePreview, truncateToBytes, validateSnapshot };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { J as JsonSummary, M as MarkdownSummary, S as SourceSummary, R as ResolvedSnapshotConfig, a as SnapshotConfig, B as ByteSize, C as CliOptions, F as FileEntry, P as PartMetadata, L as LayerRule, K as KindRule, b as SecretRule, c as SecretFinding, V as ValidationResult, d as Manifest, A as ArtifactSelection, e as SkipRecord } from './types-
|
|
2
|
-
export { f as BudgetConfig, H as HooksConfig, I as InclusionMode, g as ManifestArtifact, h as ManifestConfigSnapshot, i as ManifestIndexes, j as ManifestTotals, k as Mode, O as OutputFormat, l as PartFileEntry, m as ResolvedArtifacts, n as ResolvedBudgets, o as SecretRuleInput, p as SkipReason, q as SummaryQuality, r as ValidationDrift } from './types-
|
|
1
|
+
import { J as JsonSummary, M as MarkdownSummary, S as SourceSummary, R as ResolvedSnapshotConfig, a as SnapshotConfig, B as ByteSize, C as CliOptions, F as FileEntry, P as PartMetadata, L as LayerRule, K as KindRule, b as SecretRule, c as SecretFinding, V as ValidationResult, d as Manifest, A as ArtifactSelection, e as SkipRecord } from './types-LSfwsKE-.js';
|
|
2
|
+
export { f as BudgetConfig, H as HooksConfig, I as InclusionMode, g as ManifestArtifact, h as ManifestConfigSnapshot, i as ManifestIndexes, j as ManifestTotals, k as Mode, O as OutputFormat, l as PartFileEntry, m as ResolvedArtifacts, n as ResolvedBudgets, o as SecretRuleInput, p as SkipReason, q as SummaryQuality, r as ValidationDrift } from './types-LSfwsKE-.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Strips `//` and block comments the way JSONC does, without touching anything
|
|
@@ -142,6 +142,16 @@ declare function renumberParts(parts: PartitionedPart[], contentFingerprint?: st
|
|
|
142
142
|
* contains a fenced block cannot break out of its own code block.
|
|
143
143
|
*/
|
|
144
144
|
declare function fenceForContent(content: string): string;
|
|
145
|
+
/**
|
|
146
|
+
* A fence longer than any backtick run in `content`, never shorter than
|
|
147
|
+
* `minimum`.
|
|
148
|
+
*
|
|
149
|
+
* Every fenced block the generator writes goes through this, not just file
|
|
150
|
+
* bodies: a *filename* may contain a backtick run (it is a legal name), and a
|
|
151
|
+
* fixed three-backtick fence around the `## Files` list let such a name close
|
|
152
|
+
* the block and turn the following filenames into live document text.
|
|
153
|
+
*/
|
|
154
|
+
declare function fenceForText(content: string, minimum: number): string;
|
|
145
155
|
/**
|
|
146
156
|
* Stable, injective anchor for a file path.
|
|
147
157
|
*
|
|
@@ -238,6 +248,8 @@ declare function detectLanguage(filePath: string): string;
|
|
|
238
248
|
*
|
|
239
249
|
* - Replaces only the matched span, so unrelated code sharing the line survives
|
|
240
250
|
* (the previous implementation discarded the whole line).
|
|
251
|
+
* - When a rule declares `valueGroup`, only that capture group is masked, so
|
|
252
|
+
* `dbPassword: "…"` keeps its key and stays parseable.
|
|
241
253
|
* - Masks PEM private-key blocks as a unit; per-line rules can only see the
|
|
242
254
|
* `BEGIN` header, which left every body line of a real key in the output.
|
|
243
255
|
* - Records `{ rule, line, path }` only. No excerpt of the source is retained,
|
|
@@ -262,20 +274,6 @@ declare function scanAndRedactSecrets(content: string, rules: SecretRule[], file
|
|
|
262
274
|
*/
|
|
263
275
|
declare function validateSnapshot(configInput: ResolvedSnapshotConfig | SnapshotConfig): ValidationResult;
|
|
264
276
|
|
|
265
|
-
/**
|
|
266
|
-
* Default secret rules.
|
|
267
|
-
*
|
|
268
|
-
* Design notes:
|
|
269
|
-
* - Every quantifier is bounded. An unbounded `[A-Za-z0-9_-]{10,}` followed by
|
|
270
|
-
* `\.` backtracks to the end of the line at every start position, which made
|
|
271
|
-
* `jwt-token` quadratic (measured: 1.22 s for a 200 KB line). JWT segments are
|
|
272
|
-
* never longer than a few KB, so bounding at 1024 keeps the match linear in
|
|
273
|
-
* practice while still matching every realistic token.
|
|
274
|
-
* - Rules are line-oriented; the whole-block private-key scan lives in
|
|
275
|
-
* `redact.ts` because it spans lines.
|
|
276
|
-
* - Names are matched case-insensitively only where a value is anchored by
|
|
277
|
-
* quotes or a length, to keep false positives at zero on ordinary source.
|
|
278
|
-
*/
|
|
279
277
|
declare const DEFAULT_SECRET_PATTERNS: SecretRule[];
|
|
280
278
|
|
|
281
279
|
interface ExplainResult {
|
|
@@ -329,12 +327,7 @@ interface DiffSide {
|
|
|
329
327
|
fileCount: number;
|
|
330
328
|
partsCount: number;
|
|
331
329
|
}
|
|
332
|
-
/**
|
|
333
|
-
* Compares two manifests file by file.
|
|
334
|
-
*
|
|
335
|
-
* The per-file hashes and the content fingerprint already make this exact, so
|
|
336
|
-
* nothing is inferred: a path is added, removed or changed, never "maybe".
|
|
337
|
-
*/
|
|
330
|
+
/** Compares two manifests file by file. */
|
|
338
331
|
declare function compareManifests(before: Manifest, after: Manifest): ManifestDiff;
|
|
339
332
|
/** Loads a manifest from a snapshot directory or a `manifest.json` path. */
|
|
340
333
|
declare function loadManifest(target: string): Manifest;
|
|
@@ -464,6 +457,11 @@ interface CollectOptions {
|
|
|
464
457
|
* Default `false`: they are skipped with `reason: "sensitive-file"`.
|
|
465
458
|
*/
|
|
466
459
|
includeSensitiveFiles?: boolean;
|
|
460
|
+
/**
|
|
461
|
+
* Secret rules used to scan *paths* (defaults are always applied). Pass
|
|
462
|
+
* `config.secretRules` so `customPatterns` also protect file names.
|
|
463
|
+
*/
|
|
464
|
+
secretRules?: readonly SecretRule[];
|
|
467
465
|
}
|
|
468
466
|
interface CollectResult {
|
|
469
467
|
files: string[];
|
|
@@ -497,7 +495,7 @@ declare function matchesExclude(relativePath: string, pattern: string): boolean;
|
|
|
497
495
|
declare function collectFiles(cwd: string, options?: CollectOptions): CollectResult;
|
|
498
496
|
|
|
499
497
|
declare const GENERATOR_NAME = "@ankurhalder/codebase-snapshot";
|
|
500
|
-
declare const GENERATOR_VERSION = "
|
|
498
|
+
declare const GENERATOR_VERSION = "4.0.1";
|
|
501
499
|
declare const SCHEMA_VERSION = "3.0.0";
|
|
502
500
|
interface GenerateOptions {
|
|
503
501
|
/** Compute the full manifest but write nothing to disk. */
|
|
@@ -521,12 +519,13 @@ declare function resolveSafeOutputDirs(config: {
|
|
|
521
519
|
/**
|
|
522
520
|
* Refuses to replace a directory that this generator did not write.
|
|
523
521
|
*
|
|
524
|
-
*
|
|
525
|
-
*
|
|
526
|
-
*
|
|
527
|
-
*
|
|
522
|
+
* Path checks alone cannot make the swap safe: `outDir: "src"` is a plausible
|
|
523
|
+
* typo, and a user directory that happens to contain a `.codebase-snapshot` file
|
|
524
|
+
* or a manifest-shaped JSON document is not a snapshot. The staging root is
|
|
525
|
+
* checked separately by {@link assertStagingRootUsable}, because it holds one
|
|
526
|
+
* directory per run rather than a single snapshot.
|
|
528
527
|
*/
|
|
529
|
-
declare function assertReplaceable(target: string, label: "outDir" | "tmpDir"): void;
|
|
528
|
+
declare function assertReplaceable(target: string, label: "outDir" | "tmpDir", secretRules?: readonly SecretRule[]): void;
|
|
530
529
|
/**
|
|
531
530
|
* Generates the snapshot.
|
|
532
531
|
*
|
|
@@ -538,4 +537,4 @@ declare function generateSnapshot(configInput?: SnapshotConfig | ResolvedSnapsho
|
|
|
538
537
|
/** Promise-returning wrapper for consumers that prefer an async call site. */
|
|
539
538
|
declare function generateSnapshotAsync(configInput?: SnapshotConfig | ResolvedSnapshotConfig | null, options?: GenerateOptions): Promise<Manifest>;
|
|
540
539
|
|
|
541
|
-
export { ARTIFACT_NAMES, ArtifactSelection, ByteSize, CliOptions, DEFAULT_ANSWERS, DEFAULT_SECRET_PATTERNS, type ExplainResult, FileEntry, GENERATOR_NAME, GENERATOR_VERSION, type GenerateOptions, type HeuristicResult, type InitOptions, type InitResult, JsonSummary, KindRule, LANGUAGE_PROFILES, type LanguageProfile, LayerRule, MIN_MAX_PART_BYTES, Manifest, type ManifestDiff, MarkdownSummary, PRESETS, PartMetadata, PromptCancelled, ResolvedSnapshotConfig, SCHEMA_VERSION, SecretFinding, SecretRule, SkipRecord, SnapshotConfig, SourceSummary, ValidationResult, type WizardAnswers, anchorForPath, assertReplaceable, assertUsableConfigInput, collectFiles, compareManifests, countLines, defineConfig, detectLanguage, detectPreset, explainPath, fenceForContent, generateProjectTree, generateSnapshot, generateSnapshotAsync, getPreset, globToRegExp, isBinaryBuffer, isBinaryExtension, isBinaryFile, isInteractive, isResolvedConfig, isSensitivePath, listPresetNames, loadConfigFile, loadConfigFileDetailed, loadManifest, markResolvedConfig, matchRule, matchesExclude, normalizeResolvedConfig, parseByteSize, partitionFiles, profileForPath, renderConfig, renderDiffText, renderExplainText, renderMinimalConfig, renumberParts, resolveConfig, resolveSafeOutputDirs, runInit, scanAndRedactSecrets, stripJsonComments, summarizeJson, summarizeMarkdown, summarizeTypeScriptSource, summarizeWithProfile, supportsTypeScriptImports, truncatePreview, truncateToBytes, validateSnapshot };
|
|
540
|
+
export { ARTIFACT_NAMES, ArtifactSelection, ByteSize, CliOptions, DEFAULT_ANSWERS, DEFAULT_SECRET_PATTERNS, type ExplainResult, FileEntry, GENERATOR_NAME, GENERATOR_VERSION, type GenerateOptions, type HeuristicResult, type InitOptions, type InitResult, JsonSummary, KindRule, LANGUAGE_PROFILES, type LanguageProfile, LayerRule, MIN_MAX_PART_BYTES, Manifest, type ManifestDiff, MarkdownSummary, PRESETS, PartMetadata, PromptCancelled, ResolvedSnapshotConfig, SCHEMA_VERSION, SecretFinding, SecretRule, SkipRecord, SnapshotConfig, SourceSummary, ValidationResult, type WizardAnswers, anchorForPath, assertReplaceable, assertUsableConfigInput, collectFiles, compareManifests, countLines, defineConfig, detectLanguage, detectPreset, explainPath, fenceForContent, fenceForText, generateProjectTree, generateSnapshot, generateSnapshotAsync, getPreset, globToRegExp, isBinaryBuffer, isBinaryExtension, isBinaryFile, isInteractive, isResolvedConfig, isSensitivePath, listPresetNames, loadConfigFile, loadConfigFileDetailed, loadManifest, markResolvedConfig, matchRule, matchesExclude, normalizeResolvedConfig, parseByteSize, partitionFiles, profileForPath, renderConfig, renderDiffText, renderExplainText, renderMinimalConfig, renumberParts, resolveConfig, resolveSafeOutputDirs, runInit, scanAndRedactSecrets, stripJsonComments, summarizeJson, summarizeMarkdown, summarizeTypeScriptSource, summarizeWithProfile, supportsTypeScriptImports, truncatePreview, truncateToBytes, validateSnapshot };
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { ARTIFACT_NAMES, DEFAULT_ANSWERS, DEFAULT_SECRET_PATTERNS, GENERATOR_NAME, GENERATOR_VERSION, LANGUAGE_PROFILES, MIN_MAX_PART_BYTES, PRESETS, PromptCancelled, SCHEMA_VERSION, anchorForPath, assertReplaceable, assertUsableConfigInput, collectFiles, compareManifests, countLines, defineConfig, detectLanguage, detectPreset, explainPath, fenceForContent, generateProjectTree, generateSnapshot, generateSnapshotAsync, getPreset, globToRegExp, isBinaryBuffer, isBinaryExtension, isBinaryFile, isInteractive, isResolvedConfig, isSensitivePath, listPresetNames, loadConfigFile, loadConfigFileDetailed, loadManifest, markResolvedConfig, matchRule, matchesExclude, normalizeResolvedConfig, parseByteSize, partitionFiles, profileForPath, renderConfig, renderDiffText, renderExplainText, renderMinimalConfig, renumberParts, resolveConfig, resolveSafeOutputDirs, runInit, scanAndRedactSecrets, stripJsonComments, summarizeJson, summarizeMarkdown, summarizeTypeScriptSource, summarizeWithProfile, supportsTypeScriptImports, truncatePreview, truncateToBytes, validateSnapshot } from './chunk-
|
|
1
|
+
export { ARTIFACT_NAMES, DEFAULT_ANSWERS, DEFAULT_SECRET_PATTERNS, GENERATOR_NAME, GENERATOR_VERSION, LANGUAGE_PROFILES, MIN_MAX_PART_BYTES, PRESETS, PromptCancelled, SCHEMA_VERSION, anchorForPath, assertReplaceable, assertUsableConfigInput, collectFiles, compareManifests, countLines, defineConfig, detectLanguage, detectPreset, explainPath, fenceForContent, fenceForText, generateProjectTree, generateSnapshot, generateSnapshotAsync, getPreset, globToRegExp, isBinaryBuffer, isBinaryExtension, isBinaryFile, isInteractive, isResolvedConfig, isSensitivePath, listPresetNames, loadConfigFile, loadConfigFileDetailed, loadManifest, markResolvedConfig, matchRule, matchesExclude, normalizeResolvedConfig, parseByteSize, partitionFiles, profileForPath, renderConfig, renderDiffText, renderExplainText, renderMinimalConfig, renumberParts, resolveConfig, resolveSafeOutputDirs, runInit, scanAndRedactSecrets, stripJsonComments, summarizeJson, summarizeMarkdown, summarizeTypeScriptSource, summarizeWithProfile, supportsTypeScriptImports, truncatePreview, truncateToBytes, validateSnapshot } from './chunk-RGIMMEAW.js';
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
|
3
3
|
//# sourceMappingURL=index.js.map
|
|
@@ -44,8 +44,29 @@ interface MarkdownSummary {
|
|
|
44
44
|
* as one.
|
|
45
45
|
*/
|
|
46
46
|
type SummaryQuality = "ast" | "structural" | "heuristic";
|
|
47
|
-
|
|
47
|
+
/**
|
|
48
|
+
* Why a discovered path was not emitted.
|
|
49
|
+
*
|
|
50
|
+
* Every reason below is produced by the scanner; nothing in the type is
|
|
51
|
+
* aspirational. `asset` was removed because no code path ever emitted it.
|
|
52
|
+
*/
|
|
53
|
+
type SkipReason = "binary" | "read-error" | "not-file"
|
|
54
|
+
/** A credential-bearing name (`.env`, `*.pem`, `.npmrc`, …). */
|
|
55
|
+
| "sensitive-file"
|
|
56
|
+
/** The path itself matched a secret rule; the emitted path is span-masked. */
|
|
57
|
+
| "sensitive-path"
|
|
58
|
+
/** A directory link (never followed), or a link to neither file nor directory. */
|
|
59
|
+
| "symlink"
|
|
60
|
+
/** A file link whose target resolves outside the scanned root. */
|
|
61
|
+
| "outside-root"
|
|
62
|
+
/** Excluded by a `.gitignore` in a scan without git. */
|
|
63
|
+
| "gitignore"
|
|
64
|
+
/** Excluded by a built-in rule: the ignore list, a preset, or an output dir. */
|
|
65
|
+
| "default-ignore"
|
|
66
|
+
/** Excluded by the user's own `excludePatterns` or `include` allow-list. */
|
|
67
|
+
| "excluded";
|
|
48
68
|
interface SkipRecord {
|
|
69
|
+
/** Path as it may be shown in an artifact: secret spans are masked. */
|
|
49
70
|
path: string;
|
|
50
71
|
reason: SkipReason;
|
|
51
72
|
detail?: string;
|
|
@@ -103,12 +124,25 @@ interface PartMetadata {
|
|
|
103
124
|
interface SecretRule {
|
|
104
125
|
rule: string;
|
|
105
126
|
pattern: RegExp;
|
|
127
|
+
/**
|
|
128
|
+
* Index of the capture group that holds the secret, when the rule has to match
|
|
129
|
+
* its surrounding context to identify one (`password: "…"`). Redaction then
|
|
130
|
+
* masks only that group, so the key and the rest of the line survive.
|
|
131
|
+
*/
|
|
132
|
+
valueGroup?: number;
|
|
106
133
|
}
|
|
107
|
-
/**
|
|
108
|
-
|
|
134
|
+
/**
|
|
135
|
+
* Shape accepted for `secrets.customPatterns`.
|
|
136
|
+
*
|
|
137
|
+
* A bare `RegExp` or string is accepted because it is the documented form; the
|
|
138
|
+
* object form exists to name a rule. `valueGroup` is only useful with the object
|
|
139
|
+
* form, since a bare pattern has no group to name.
|
|
140
|
+
*/
|
|
141
|
+
type SecretRuleInput = {
|
|
109
142
|
rule: string;
|
|
110
143
|
pattern: RegExp | string;
|
|
111
|
-
|
|
144
|
+
valueGroup?: number;
|
|
145
|
+
} | RegExp | string;
|
|
112
146
|
/**
|
|
113
147
|
* A detected secret. Deliberately carries no excerpt of the matched source:
|
|
114
148
|
* the previous `snippet` field was the vector by which raw credentials were
|
|
@@ -44,8 +44,29 @@ interface MarkdownSummary {
|
|
|
44
44
|
* as one.
|
|
45
45
|
*/
|
|
46
46
|
type SummaryQuality = "ast" | "structural" | "heuristic";
|
|
47
|
-
|
|
47
|
+
/**
|
|
48
|
+
* Why a discovered path was not emitted.
|
|
49
|
+
*
|
|
50
|
+
* Every reason below is produced by the scanner; nothing in the type is
|
|
51
|
+
* aspirational. `asset` was removed because no code path ever emitted it.
|
|
52
|
+
*/
|
|
53
|
+
type SkipReason = "binary" | "read-error" | "not-file"
|
|
54
|
+
/** A credential-bearing name (`.env`, `*.pem`, `.npmrc`, …). */
|
|
55
|
+
| "sensitive-file"
|
|
56
|
+
/** The path itself matched a secret rule; the emitted path is span-masked. */
|
|
57
|
+
| "sensitive-path"
|
|
58
|
+
/** A directory link (never followed), or a link to neither file nor directory. */
|
|
59
|
+
| "symlink"
|
|
60
|
+
/** A file link whose target resolves outside the scanned root. */
|
|
61
|
+
| "outside-root"
|
|
62
|
+
/** Excluded by a `.gitignore` in a scan without git. */
|
|
63
|
+
| "gitignore"
|
|
64
|
+
/** Excluded by a built-in rule: the ignore list, a preset, or an output dir. */
|
|
65
|
+
| "default-ignore"
|
|
66
|
+
/** Excluded by the user's own `excludePatterns` or `include` allow-list. */
|
|
67
|
+
| "excluded";
|
|
48
68
|
interface SkipRecord {
|
|
69
|
+
/** Path as it may be shown in an artifact: secret spans are masked. */
|
|
49
70
|
path: string;
|
|
50
71
|
reason: SkipReason;
|
|
51
72
|
detail?: string;
|
|
@@ -103,12 +124,25 @@ interface PartMetadata {
|
|
|
103
124
|
interface SecretRule {
|
|
104
125
|
rule: string;
|
|
105
126
|
pattern: RegExp;
|
|
127
|
+
/**
|
|
128
|
+
* Index of the capture group that holds the secret, when the rule has to match
|
|
129
|
+
* its surrounding context to identify one (`password: "…"`). Redaction then
|
|
130
|
+
* masks only that group, so the key and the rest of the line survive.
|
|
131
|
+
*/
|
|
132
|
+
valueGroup?: number;
|
|
106
133
|
}
|
|
107
|
-
/**
|
|
108
|
-
|
|
134
|
+
/**
|
|
135
|
+
* Shape accepted for `secrets.customPatterns`.
|
|
136
|
+
*
|
|
137
|
+
* A bare `RegExp` or string is accepted because it is the documented form; the
|
|
138
|
+
* object form exists to name a rule. `valueGroup` is only useful with the object
|
|
139
|
+
* form, since a bare pattern has no group to name.
|
|
140
|
+
*/
|
|
141
|
+
type SecretRuleInput = {
|
|
109
142
|
rule: string;
|
|
110
143
|
pattern: RegExp | string;
|
|
111
|
-
|
|
144
|
+
valueGroup?: number;
|
|
145
|
+
} | RegExp | string;
|
|
112
146
|
/**
|
|
113
147
|
* A detected secret. Deliberately carries no excerpt of the matched source:
|
|
114
148
|
* the previous `snippet` field was the vector by which raw credentials were
|
package/docs/agent.md
CHANGED
|
@@ -1,45 +1,63 @@
|
|
|
1
1
|
# Using this with an AI agent
|
|
2
2
|
|
|
3
|
-
The package ships two things that make it usable by an agent that has never heard of it:
|
|
4
|
-
|
|
3
|
+
The package ships two things that make it usable by an agent that has never heard of it: a
|
|
4
|
+
**machine-readable contract** and a **bundled skill**.
|
|
5
5
|
|
|
6
|
-
Nothing
|
|
7
|
-
required.
|
|
6
|
+
Nothing needs to be installed globally and no prior knowledge of the tool is required.
|
|
8
7
|
|
|
9
8
|
## The three commands an agent needs
|
|
10
9
|
|
|
11
10
|
```bash
|
|
12
11
|
# 1. Read the contract. This is the machine-readable replacement for --help.
|
|
13
|
-
npx @ankurhalder/codebase-snapshot
|
|
12
|
+
npx @ankurhalder/codebase-snapshot describe --format json
|
|
14
13
|
|
|
15
14
|
# 2. Write a commented config that lists every setting (non-interactive).
|
|
16
|
-
npx @ankurhalder/codebase-snapshot
|
|
15
|
+
npx @ankurhalder/codebase-snapshot init --yes
|
|
17
16
|
|
|
18
17
|
# 3. Generate and verify.
|
|
19
|
-
npx @ankurhalder/codebase-snapshot
|
|
20
|
-
npx @ankurhalder/codebase-snapshot
|
|
18
|
+
npx @ankurhalder/codebase-snapshot generate
|
|
19
|
+
npx @ankurhalder/codebase-snapshot validate
|
|
21
20
|
```
|
|
22
21
|
|
|
23
|
-
`
|
|
24
|
-
|
|
25
|
-
the config file names, the output layout, safety rules and a troubleshooting table — all
|
|
26
|
-
as JSON on stdout.
|
|
22
|
+
The bare package name works; pin `@latest` or `@4` when the same version must run on every
|
|
23
|
+
machine.
|
|
27
24
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
25
|
+
## The contract
|
|
26
|
+
|
|
27
|
+
`describe --format json` returns the whole tool as data on stdout:
|
|
28
|
+
|
|
29
|
+
| Field | Contents |
|
|
30
|
+
| :--- | :--- |
|
|
31
|
+
| `invocation` | The supported one-shot and installed commands, and the bin names. |
|
|
32
|
+
| `workflow` | An ordered six-step procedure: verify → understand → configure → generate → verify output → consume. |
|
|
33
|
+
| `commands` | Every command with what it does, its positionals and its exit codes. |
|
|
34
|
+
| `options` | Every option with its type, default, which commands it applies to, and a summary. |
|
|
35
|
+
| `exitCodes` | `0` success, `1` drift or refused generation, `2` usage error. |
|
|
36
|
+
| `presets` | All 25, with priority, recommended budget and ecosystem ignores. |
|
|
37
|
+
| `artifacts` | Each artifact with its on/off default and what it contains. |
|
|
38
|
+
| `config` | Every config filename and every setting with its default. |
|
|
39
|
+
| `output` | The directory layout and how to read `manifest.json`. |
|
|
40
|
+
| `safety` | What is excluded or redacted, and which directories are refused. |
|
|
41
|
+
| `troubleshooting` | Symptom → cause → fix. |
|
|
42
|
+
|
|
43
|
+
It is generated from the same code the CLI runs — presets, artifact names and versions are
|
|
44
|
+
read directly — and a test compares its documented defaults against a real
|
|
45
|
+
`generate --dry-run` manifest. If a default changes, the test fails rather than the contract
|
|
46
|
+
silently misleading an agent.
|
|
47
|
+
|
|
48
|
+
`describe` with no `--format` renders the same content for a human.
|
|
31
49
|
|
|
32
50
|
## The skill
|
|
33
51
|
|
|
34
52
|
```bash
|
|
35
|
-
npx @ankurhalder/codebase-snapshot
|
|
36
|
-
npx @ankurhalder/codebase-snapshot
|
|
53
|
+
npx @ankurhalder/codebase-snapshot skill # print it (stdout)
|
|
54
|
+
npx @ankurhalder/codebase-snapshot skill --install # write it into the repository
|
|
37
55
|
```
|
|
38
56
|
|
|
39
57
|
Printing goes to stdout deliberately, so it can be redirected:
|
|
40
58
|
|
|
41
59
|
```bash
|
|
42
|
-
npx @ankurhalder/codebase-snapshot
|
|
60
|
+
npx @ankurhalder/codebase-snapshot skill > SKILL.md
|
|
43
61
|
```
|
|
44
62
|
|
|
45
63
|
`--install` writes the same skill to every location agents look at by default:
|
|
@@ -51,30 +69,52 @@ npx @ankurhalder/codebase-snapshot@latest skill > SKILL.md
|
|
|
51
69
|
| `cursor` | `.cursor/rules/codebase-snapshot.mdc` | Cursor rules |
|
|
52
70
|
|
|
53
71
|
```bash
|
|
54
|
-
skill --install --target claude
|
|
55
|
-
skill --install
|
|
72
|
+
npx @ankurhalder/codebase-snapshot skill --install --target claude # one location
|
|
73
|
+
npx @ankurhalder/codebase-snapshot skill --install # all three (default)
|
|
56
74
|
```
|
|
57
75
|
|
|
58
|
-
The install is **idempotent and non-destructive**: re-running replaces only the block
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
76
|
+
The install is **idempotent and non-destructive**: re-running replaces only the block between
|
|
77
|
+
`<!-- codebase-snapshot:skill:start -->` and `<!-- codebase-snapshot:skill:end -->`, so an
|
|
78
|
+
`AGENTS.md` that already documents your conventions keeps them. `--format json` reports what
|
|
79
|
+
was created, updated or unchanged.
|
|
62
80
|
|
|
63
81
|
`codebase-snapshot init` prints a reminder about this; it never installs the skill on its own.
|
|
64
82
|
|
|
65
83
|
## Why both a contract and a skill
|
|
66
84
|
|
|
67
|
-
The contract is for **doing** —
|
|
68
|
-
options, and it is asserted against the real defaults in the test suite so it cannot drift
|
|
69
|
-
into lying.
|
|
70
|
-
|
|
85
|
+
The contract is for **doing** — the data an agent needs to pick correct commands and options.
|
|
71
86
|
The skill is for **knowing when to act** — it carries the trigger conditions, the ordered
|
|
72
|
-
workflow, and the surprises
|
|
73
|
-
output directory being tool-owned
|
|
74
|
-
|
|
75
|
-
##
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
87
|
+
workflow, and the surprises an agent cannot infer from a schema: sensitive files excluded by
|
|
88
|
+
default, secrets redacted, the output directory being tool-owned.
|
|
89
|
+
|
|
90
|
+
## What an agent should avoid
|
|
91
|
+
|
|
92
|
+
- **Do not point `--out-dir` at source code.** It is refused, and the refusal is deliberate.
|
|
93
|
+
- **Do not add `--include-sensitive-files`** unless the user explicitly asked for credential
|
|
94
|
+
files; by default they are excluded and recorded as `sensitive-file` in `manifest.skipped[]`.
|
|
95
|
+
- **Do not work around redaction.** If a value is masked, ask the user rather than reading the
|
|
96
|
+
original file.
|
|
97
|
+
- **Do not assume exit 2 means the repository is broken.** It means the command was wrong.
|
|
98
|
+
Re-read the contract.
|
|
99
|
+
- **Do not treat a bare `npx` that prints nothing as a repository problem.** A stale global
|
|
100
|
+
install shadows `npx`; see [Troubleshooting](troubleshooting.md#the-command-does-nothing).
|
|
101
|
+
|
|
102
|
+
## Verifying an agent can drive it
|
|
103
|
+
|
|
104
|
+
`tests/agent-simulation.test.js` runs the published instructions as an agent would: read
|
|
105
|
+
`--help`, discover `describe`, then execute the six workflow steps in order against an 8-file
|
|
106
|
+
Django fixture.
|
|
107
|
+
|
|
108
|
+
It asserts what the contract promises at each step: `--version` prints a version, every
|
|
109
|
+
published option states where it applies, `init --yes` writes a config naming **every**
|
|
110
|
+
setting the contract lists, `generate --format json` exits `0` with
|
|
111
|
+
`validation.status: "passed"` and the preset `python-django`, every fixture file is either in
|
|
112
|
+
`manifest.files[]` or explained in `manifest.skipped[]`, each `files[]` entry carries its
|
|
113
|
+
classification and hash, and `validate` then exits `0`. If an agent following the published
|
|
114
|
+
words would fail, that test fails.
|
|
115
|
+
|
|
116
|
+
When you parse the manifest, remember what is conditional: `manifest.files[]` carries
|
|
117
|
+
`relativePath`, `layer`, `kind`, `language`, `part`, `inclusionMode` and `hashSha256` for
|
|
118
|
+
every included file, but `summary` and `summaryQuality` only for a language the tool can
|
|
119
|
+
analyse. A `.gitignore` or plain-text entry has neither key, and a file whose summary was too
|
|
120
|
+
large for its part carries `summaryOmitted: true` instead of a `summary`.
|