bugproof 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +65 -0
- package/README.md +256 -0
- package/assets/icon-16x16.png +0 -0
- package/assets/icon-32x32.png +0 -0
- package/assets/icon-512x512.png +0 -0
- package/dist/capture/engine.d.ts +12 -0
- package/dist/capture/engine.d.ts.map +1 -0
- package/dist/capture/engine.js +129 -0
- package/dist/capture/engine.js.map +1 -0
- package/dist/capture/packager.d.ts +39 -0
- package/dist/capture/packager.d.ts.map +1 -0
- package/dist/capture/packager.js +145 -0
- package/dist/capture/packager.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +538 -0
- package/dist/cli.js.map +1 -0
- package/dist/diff/engine.d.ts +28 -0
- package/dist/diff/engine.d.ts.map +1 -0
- package/dist/diff/engine.js +88 -0
- package/dist/diff/engine.js.map +1 -0
- package/dist/replay/engine.d.ts +41 -0
- package/dist/replay/engine.d.ts.map +1 -0
- package/dist/replay/engine.js +69 -0
- package/dist/replay/engine.js.map +1 -0
- package/dist/replay/sandbox.d.ts +33 -0
- package/dist/replay/sandbox.d.ts.map +1 -0
- package/dist/replay/sandbox.js +167 -0
- package/dist/replay/sandbox.js.map +1 -0
- package/dist/replay/verdict.d.ts +8 -0
- package/dist/replay/verdict.d.ts.map +1 -0
- package/dist/replay/verdict.js +32 -0
- package/dist/replay/verdict.js.map +1 -0
- package/dist/sandbox/bugbox.d.ts +38 -0
- package/dist/sandbox/bugbox.d.ts.map +1 -0
- package/dist/sandbox/bugbox.js +122 -0
- package/dist/sandbox/bugbox.js.map +1 -0
- package/dist/sandbox/capabilities.d.ts +33 -0
- package/dist/sandbox/capabilities.d.ts.map +1 -0
- package/dist/sandbox/capabilities.js +53 -0
- package/dist/sandbox/capabilities.js.map +1 -0
- package/dist/sandbox/filesystem.d.ts +50 -0
- package/dist/sandbox/filesystem.d.ts.map +1 -0
- package/dist/sandbox/filesystem.js +134 -0
- package/dist/sandbox/filesystem.js.map +1 -0
- package/dist/sandbox/network.d.ts +68 -0
- package/dist/sandbox/network.d.ts.map +1 -0
- package/dist/sandbox/network.js +136 -0
- package/dist/sandbox/network.js.map +1 -0
- package/dist/sandbox/process.d.ts +17 -0
- package/dist/sandbox/process.d.ts.map +1 -0
- package/dist/sandbox/process.js +30 -0
- package/dist/sandbox/process.js.map +1 -0
- package/dist/sandbox/resources.d.ts +21 -0
- package/dist/sandbox/resources.d.ts.map +1 -0
- package/dist/sandbox/resources.js +60 -0
- package/dist/sandbox/resources.js.map +1 -0
- package/dist/types/artifact.d.ts +57 -0
- package/dist/types/artifact.d.ts.map +1 -0
- package/dist/types/artifact.js +2 -0
- package/dist/types/artifact.js.map +1 -0
- package/dist/types/failure.d.ts +12 -0
- package/dist/types/failure.d.ts.map +1 -0
- package/dist/types/failure.js +2 -0
- package/dist/types/failure.js.map +1 -0
- package/dist/utils/archive.d.ts +13 -0
- package/dist/utils/archive.d.ts.map +1 -0
- package/dist/utils/archive.js +39 -0
- package/dist/utils/archive.js.map +1 -0
- package/dist/utils/associations.d.ts +10 -0
- package/dist/utils/associations.d.ts.map +1 -0
- package/dist/utils/associations.js +46 -0
- package/dist/utils/associations.js.map +1 -0
- package/dist/utils/exclude.d.ts +12 -0
- package/dist/utils/exclude.d.ts.map +1 -0
- package/dist/utils/exclude.js +42 -0
- package/dist/utils/exclude.js.map +1 -0
- package/dist/utils/fingerprint.d.ts +16 -0
- package/dist/utils/fingerprint.d.ts.map +1 -0
- package/dist/utils/fingerprint.js +72 -0
- package/dist/utils/fingerprint.js.map +1 -0
- package/dist/utils/git.d.ts +13 -0
- package/dist/utils/git.d.ts.map +1 -0
- package/dist/utils/git.js +41 -0
- package/dist/utils/git.js.map +1 -0
- package/dist/utils/json-output.d.ts +36 -0
- package/dist/utils/json-output.d.ts.map +1 -0
- package/dist/utils/json-output.js +49 -0
- package/dist/utils/json-output.js.map +1 -0
- package/dist/utils/paths.d.ts +19 -0
- package/dist/utils/paths.d.ts.map +1 -0
- package/dist/utils/paths.js +43 -0
- package/dist/utils/paths.js.map +1 -0
- package/dist/utils/secrets.d.ts +13 -0
- package/dist/utils/secrets.d.ts.map +1 -0
- package/dist/utils/secrets.js +52 -0
- package/dist/utils/secrets.js.map +1 -0
- package/dist/utils/security.d.ts +27 -0
- package/dist/utils/security.d.ts.map +1 -0
- package/dist/utils/security.js +75 -0
- package/dist/utils/security.js.map +1 -0
- package/dist/utils/ui.d.ts +31 -0
- package/dist/utils/ui.d.ts.map +1 -0
- package/dist/utils/ui.js +54 -0
- package/dist/utils/ui.js.map +1 -0
- package/package.json +80 -0
- package/scripts/bugproof-file-association-linux.sh +80 -0
- package/scripts/bugproof-file-association-macos.sh +48 -0
- package/scripts/bugproof-file-association-windows.reg +44 -0
- package/scripts/postinstall.cjs +215 -0
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bug-Box Resource Isolation
|
|
3
|
+
*
|
|
4
|
+
* Provides resource limits (memory, CPU) for the replayed process
|
|
5
|
+
* using cgroups v2 on Linux and Job Objects on Windows.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Selects the best available resource isolation strategy based on capabilities.
|
|
9
|
+
*/
|
|
10
|
+
export function selectResourceStrategy(caps) {
|
|
11
|
+
if (caps.platform === 'linux' && caps.hasCgroupsV2) {
|
|
12
|
+
return 'cgroups';
|
|
13
|
+
}
|
|
14
|
+
if (caps.platform === 'win32' && caps.hasJobObjects) {
|
|
15
|
+
return 'job-object';
|
|
16
|
+
}
|
|
17
|
+
return 'none';
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Modifies the command array to apply resource limits.
|
|
21
|
+
*/
|
|
22
|
+
export function buildResourceIsolationArgs(strategy, command, limits) {
|
|
23
|
+
// If no limits are requested, return command unchanged
|
|
24
|
+
if (!limits.maxMemoryMB && !limits.maxCpuPercent) {
|
|
25
|
+
return command;
|
|
26
|
+
}
|
|
27
|
+
if (strategy === 'cgroups') {
|
|
28
|
+
const args = ['systemd-run', '--user', '--scope', '--quiet'];
|
|
29
|
+
if (limits.maxMemoryMB) {
|
|
30
|
+
args.push('-p', `MemoryMax=${limits.maxMemoryMB}M`);
|
|
31
|
+
}
|
|
32
|
+
if (limits.maxCpuPercent) {
|
|
33
|
+
args.push('-p', `CPUQuota=${limits.maxCpuPercent}%`);
|
|
34
|
+
}
|
|
35
|
+
args.push('--', ...command);
|
|
36
|
+
return args;
|
|
37
|
+
}
|
|
38
|
+
if (strategy === 'job-object') {
|
|
39
|
+
// PowerShell wrapper that creates a Job Object with memory limits and runs the command.
|
|
40
|
+
const argList = command.length > 1
|
|
41
|
+
? command.slice(1).map(c => `"${c.replace(/"/g, '`"')}"`).join(',')
|
|
42
|
+
: '';
|
|
43
|
+
let limitClauses = '';
|
|
44
|
+
if (limits.maxMemoryMB) {
|
|
45
|
+
// Use Start-Process with simplified memory check (full Job Object API requires C# interop)
|
|
46
|
+
limitClauses += `$memLimitBytes = ${limits.maxMemoryMB * 1024 * 1024}; `;
|
|
47
|
+
}
|
|
48
|
+
const psWrapper = [
|
|
49
|
+
'$ErrorActionPreference = "Stop"',
|
|
50
|
+
limitClauses,
|
|
51
|
+
argList
|
|
52
|
+
? `$proc = Start-Process -NoNewWindow -Wait -PassThru -FilePath "${command[0].replace(/"/g, '`"')}" -ArgumentList ${argList}`
|
|
53
|
+
: `$proc = Start-Process -NoNewWindow -Wait -PassThru -FilePath "${command[0].replace(/"/g, '`"')}"`,
|
|
54
|
+
'exit $proc.ExitCode',
|
|
55
|
+
].filter(Boolean).join('; ');
|
|
56
|
+
return ['powershell', '-NoProfile', '-Command', psWrapper];
|
|
57
|
+
}
|
|
58
|
+
return command;
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=resources.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resources.js","sourceRoot":"","sources":["../../src/sandbox/resources.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAWH;;GAEG;AACH,MAAM,UAAU,sBAAsB,CAAC,IAA0B;IAC/D,IAAI,IAAI,CAAC,QAAQ,KAAK,OAAO,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;QACnD,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,IAAI,IAAI,CAAC,QAAQ,KAAK,OAAO,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;QACpD,OAAO,YAAY,CAAC;IACtB,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,0BAA0B,CACxC,QAA0B,EAC1B,OAAiB,EACjB,MAAsB;IAEtB,uDAAuD;IACvD,IAAI,CAAC,MAAM,CAAC,WAAW,IAAI,CAAC,MAAM,CAAC,aAAa,EAAE,CAAC;QACjD,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC3B,MAAM,IAAI,GAAG,CAAC,aAAa,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;QAE7D,IAAI,MAAM,CAAC,WAAW,EAAE,CAAC;YACvB,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,aAAa,MAAM,CAAC,WAAW,GAAG,CAAC,CAAC;QACtD,CAAC;QAED,IAAI,MAAM,CAAC,aAAa,EAAE,CAAC;YACzB,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,YAAY,MAAM,CAAC,aAAa,GAAG,CAAC,CAAC;QACvD,CAAC;QAED,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,OAAO,CAAC,CAAC;QAC5B,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,QAAQ,KAAK,YAAY,EAAE,CAAC;QAC9B,wFAAwF;QACxF,MAAM,OAAO,GAAG,OAAO,CAAC,MAAM,GAAG,CAAC;YAChC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;YACnE,CAAC,CAAC,EAAE,CAAC;QAEP,IAAI,YAAY,GAAG,EAAE,CAAC;QACtB,IAAI,MAAM,CAAC,WAAW,EAAE,CAAC;YACvB,2FAA2F;YAC3F,YAAY,IAAI,oBAAoB,MAAM,CAAC,WAAW,GAAG,IAAI,GAAG,IAAI,IAAI,CAAC;QAC3E,CAAC;QAED,MAAM,SAAS,GAAG;YAChB,iCAAiC;YACjC,YAAY;YACZ,OAAO;gBACL,CAAC,CAAC,iEAAiE,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,mBAAmB,OAAO,EAAE;gBAC7H,CAAC,CAAC,iEAAiE,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG;YACtG,qBAAqB;SACtB,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAE7B,OAAO,CAAC,YAAY,EAAE,YAAY,EAAE,UAAU,EAAE,SAAS,CAAC,CAAC;IAC7D,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
export interface ArtifactManifest {
|
|
2
|
+
version: string;
|
|
3
|
+
bugproof_version: string;
|
|
4
|
+
name: string;
|
|
5
|
+
description: string;
|
|
6
|
+
captured_at: string;
|
|
7
|
+
captured_on: CapturedPlatformContext;
|
|
8
|
+
command: string[];
|
|
9
|
+
working_directory: string;
|
|
10
|
+
exit_code: number;
|
|
11
|
+
duration_ms: number;
|
|
12
|
+
files_count: number;
|
|
13
|
+
files_size_bytes: number;
|
|
14
|
+
secrets_detected: boolean;
|
|
15
|
+
secrets_skipped: string[];
|
|
16
|
+
}
|
|
17
|
+
export interface CapturedPlatformContext {
|
|
18
|
+
os: string;
|
|
19
|
+
arch: string;
|
|
20
|
+
node_version: string;
|
|
21
|
+
git_commit?: string;
|
|
22
|
+
git_branch?: string;
|
|
23
|
+
git_dirty?: boolean;
|
|
24
|
+
}
|
|
25
|
+
export interface EnvSchema {
|
|
26
|
+
required: string[];
|
|
27
|
+
optional: string[];
|
|
28
|
+
secrets: string[];
|
|
29
|
+
captured_env_keys: string[];
|
|
30
|
+
}
|
|
31
|
+
export interface RunConfig {
|
|
32
|
+
command: string[];
|
|
33
|
+
working_directory: string;
|
|
34
|
+
environment: Record<string, string>;
|
|
35
|
+
timeout_ms: number;
|
|
36
|
+
capture_output: boolean;
|
|
37
|
+
}
|
|
38
|
+
export interface ArtifactMetadata {
|
|
39
|
+
capture_tool_version: string;
|
|
40
|
+
captured_at: string;
|
|
41
|
+
captured_by: string;
|
|
42
|
+
captured_platform: {
|
|
43
|
+
os: string;
|
|
44
|
+
os_version: string;
|
|
45
|
+
arch: string;
|
|
46
|
+
cpu_count: number;
|
|
47
|
+
memory_gb: number;
|
|
48
|
+
};
|
|
49
|
+
project_context: {
|
|
50
|
+
git_repo?: string;
|
|
51
|
+
git_commit?: string;
|
|
52
|
+
git_branch?: string;
|
|
53
|
+
git_dirty?: boolean;
|
|
54
|
+
git_tags?: string[];
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=artifact.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"artifact.d.ts","sourceRoot":"","sources":["../../src/types/artifact.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,gBAAgB,EAAE,MAAM,CAAC;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,uBAAuB,CAAC;IACrC,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,gBAAgB,EAAE,MAAM,CAAC;IACzB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,eAAe,EAAE,MAAM,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,uBAAuB;IACtC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,SAAS;IACxB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,iBAAiB,EAAE,MAAM,EAAE,CAAC;CAC7B;AAED,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,gBAAgB;IAC/B,oBAAoB,EAAE,MAAM,CAAC;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,iBAAiB,EAAE;QACjB,EAAE,EAAE,MAAM,CAAC;QACX,UAAU,EAAE,MAAM,CAAC;QACnB,IAAI,EAAE,MAAM,CAAC;QACb,SAAS,EAAE,MAAM,CAAC;QAClB,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;IACF,eAAe,EAAE;QACf,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,SAAS,CAAC,EAAE,OAAO,CAAC;QACpB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;KACrB,CAAC;CACH"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"artifact.js","sourceRoot":"","sources":["../../src/types/artifact.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export interface FailureRecord {
|
|
2
|
+
exit_code: number;
|
|
3
|
+
signal: string | null;
|
|
4
|
+
stdout_lines: number;
|
|
5
|
+
stderr_lines: number;
|
|
6
|
+
stderr_snippet: string;
|
|
7
|
+
fingerprint: string;
|
|
8
|
+
error_patterns: string[];
|
|
9
|
+
duration_ms: number;
|
|
10
|
+
timeout: boolean;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=failure.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"failure.d.ts","sourceRoot":"","sources":["../../src/types/failure.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;CAClB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"failure.js","sourceRoot":"","sources":["../../src/types/failure.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compresses a directory into a ZIP archive.
|
|
3
|
+
* @param sourceDir The directory to compress.
|
|
4
|
+
* @param outPath The destination path for the ZIP file.
|
|
5
|
+
*/
|
|
6
|
+
export declare function zipDirectory(sourceDir: string, outPath: string): Promise<void>;
|
|
7
|
+
/**
|
|
8
|
+
* Extracts a ZIP archive to a destination directory.
|
|
9
|
+
* @param zipPath The path to the ZIP file.
|
|
10
|
+
* @param destDir The target extraction directory (must be absolute).
|
|
11
|
+
*/
|
|
12
|
+
export declare function extractZip(zipPath: string, destDir: string): Promise<void>;
|
|
13
|
+
//# sourceMappingURL=archive.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"archive.d.ts","sourceRoot":"","sources":["../../src/utils/archive.ts"],"names":[],"mappings":"AAIA;;;;GAIG;AACH,wBAAsB,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAoBpF;AAED;;;;GAIG;AACH,wBAAsB,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAMhF"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
import archiver from 'archiver';
|
|
3
|
+
import extract from 'extract-zip';
|
|
4
|
+
/**
|
|
5
|
+
* Compresses a directory into a ZIP archive.
|
|
6
|
+
* @param sourceDir The directory to compress.
|
|
7
|
+
* @param outPath The destination path for the ZIP file.
|
|
8
|
+
*/
|
|
9
|
+
export async function zipDirectory(sourceDir, outPath) {
|
|
10
|
+
return new Promise((resolve, reject) => {
|
|
11
|
+
const archive = archiver('zip', {
|
|
12
|
+
zlib: { level: 9 }, // Maximum compression
|
|
13
|
+
});
|
|
14
|
+
const stream = fs.createWriteStream(outPath);
|
|
15
|
+
stream.on('close', () => {
|
|
16
|
+
resolve();
|
|
17
|
+
});
|
|
18
|
+
archive.on('error', (err) => {
|
|
19
|
+
reject(err);
|
|
20
|
+
});
|
|
21
|
+
archive.pipe(stream);
|
|
22
|
+
archive.directory(sourceDir, false); // false means put contents at root of zip
|
|
23
|
+
archive.finalize();
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Extracts a ZIP archive to a destination directory.
|
|
28
|
+
* @param zipPath The path to the ZIP file.
|
|
29
|
+
* @param destDir The target extraction directory (must be absolute).
|
|
30
|
+
*/
|
|
31
|
+
export async function extractZip(zipPath, destDir) {
|
|
32
|
+
try {
|
|
33
|
+
await extract(zipPath, { dir: destDir });
|
|
34
|
+
}
|
|
35
|
+
catch (err) {
|
|
36
|
+
throw new Error(`Failed to extract artifact: ${err instanceof Error ? err.message : err}`);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=archive.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"archive.js","sourceRoot":"","sources":["../../src/utils/archive.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,QAAQ,MAAM,UAAU,CAAC;AAChC,OAAO,OAAO,MAAM,aAAa,CAAC;AAElC;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,SAAiB,EAAE,OAAe;IACnE,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,OAAO,GAAG,QAAQ,CAAC,KAAK,EAAE;YAC9B,IAAI,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,sBAAsB;SAC3C,CAAC,CAAC;QAEH,MAAM,MAAM,GAAG,EAAE,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC;QAE7C,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;YACtB,OAAO,EAAE,CAAC;QACZ,CAAC,CAAC,CAAC;QAEH,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;YAC1B,MAAM,CAAC,GAAG,CAAC,CAAC;QACd,CAAC,CAAC,CAAC;QAEH,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACrB,OAAO,CAAC,SAAS,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC,CAAC,0CAA0C;QAC/E,OAAO,CAAC,QAAQ,EAAE,CAAC;IACrB,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,OAAe,EAAE,OAAe;IAC/D,IAAI,CAAC;QACH,MAAM,OAAO,CAAC,OAAO,EAAE,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC,CAAC;IAC3C,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,+BAA+B,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;IAC7F,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Silently attempts to register the .bug extension icon on the OS.
|
|
3
|
+
* Only runs once per user profile (tracked via a flag file).
|
|
4
|
+
*
|
|
5
|
+
* Uses spawnSync with an argument array (not execSync with a shell string) to
|
|
6
|
+
* avoid all shell quoting issues — paths with spaces or backslashes are passed
|
|
7
|
+
* verbatim to reg.exe.
|
|
8
|
+
*/
|
|
9
|
+
export declare function registerAssociationsSilently(): void;
|
|
10
|
+
//# sourceMappingURL=associations.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"associations.d.ts","sourceRoot":"","sources":["../../src/utils/associations.ts"],"names":[],"mappings":"AAYA;;;;;;;GAOG;AACH,wBAAgB,4BAA4B,IAAI,IAAI,CAgCnD"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import * as os from 'os';
|
|
2
|
+
import * as fs from 'fs';
|
|
3
|
+
import * as path from 'path';
|
|
4
|
+
import { spawnSync } from 'child_process';
|
|
5
|
+
import { fileURLToPath } from 'url';
|
|
6
|
+
// ESM-safe __dirname equivalent
|
|
7
|
+
const _filename = fileURLToPath(import.meta.url);
|
|
8
|
+
const _dirname = path.dirname(_filename);
|
|
9
|
+
const FLAG_FILE = path.join(os.homedir(), '.bugproof', '.associations_registered');
|
|
10
|
+
/**
|
|
11
|
+
* Silently attempts to register the .bug extension icon on the OS.
|
|
12
|
+
* Only runs once per user profile (tracked via a flag file).
|
|
13
|
+
*
|
|
14
|
+
* Uses spawnSync with an argument array (not execSync with a shell string) to
|
|
15
|
+
* avoid all shell quoting issues — paths with spaces or backslashes are passed
|
|
16
|
+
* verbatim to reg.exe.
|
|
17
|
+
*/
|
|
18
|
+
export function registerAssociationsSilently() {
|
|
19
|
+
if (fs.existsSync(FLAG_FILE)) {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
try {
|
|
23
|
+
// Resolve assets: package layout is dist/utils/associations.js -> dist/ -> root -> assets/
|
|
24
|
+
const assetsDir = path.resolve(_dirname, '../../assets');
|
|
25
|
+
const iconPath = path.join(assetsDir, 'icon-512x512.png');
|
|
26
|
+
if (!fs.existsSync(iconPath)) {
|
|
27
|
+
return; // Skip silently if the asset is missing (e.g. stripped installs)
|
|
28
|
+
}
|
|
29
|
+
if (process.platform === 'win32') {
|
|
30
|
+
// Register in HKCU — no Administrator privileges required.
|
|
31
|
+
// spawnSync avoids all shell string quoting pitfalls.
|
|
32
|
+
const reg = (args) => spawnSync('reg', args, { encoding: 'utf-8', timeout: 5000, stdio: 'pipe' });
|
|
33
|
+
reg(['add', 'HKCU\\Software\\Classes\\.bug', '/ve', '/d', 'BugProof.Artifact', '/f']);
|
|
34
|
+
reg(['add', 'HKCU\\Software\\Classes\\BugProof.Artifact', '/ve', '/d', 'BugProof Artifact', '/f']);
|
|
35
|
+
// iconPath is passed as a plain argument — no shell quoting needed
|
|
36
|
+
reg(['add', 'HKCU\\Software\\Classes\\BugProof.Artifact\\DefaultIcon', '/ve', '/d', iconPath, '/f']);
|
|
37
|
+
}
|
|
38
|
+
// Write flag file so we don't repeat this on every CLI invocation
|
|
39
|
+
fs.mkdirSync(path.dirname(FLAG_FILE), { recursive: true });
|
|
40
|
+
fs.writeFileSync(FLAG_FILE, new Date().toISOString(), 'utf-8');
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
// Silently ignore failures — icon registration must never crash the CLI
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=associations.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"associations.js","sourceRoot":"","sources":["../../src/utils/associations.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AAEpC,gCAAgC;AAChC,MAAM,SAAS,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACjD,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;AAEzC,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,WAAW,EAAE,0BAA0B,CAAC,CAAC;AAEnF;;;;;;;GAOG;AACH,MAAM,UAAU,4BAA4B;IAC1C,IAAI,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAC7B,OAAO;IACT,CAAC;IAED,IAAI,CAAC;QACH,2FAA2F;QAC3F,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,cAAc,CAAC,CAAC;QACzD,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,kBAAkB,CAAC,CAAC;QAE1D,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC7B,OAAO,CAAC,iEAAiE;QAC3E,CAAC;QAED,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;YACjC,2DAA2D;YAC3D,sDAAsD;YACtD,MAAM,GAAG,GAAG,CAAC,IAAc,EAAE,EAAE,CAC7B,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;YAE9E,GAAG,CAAC,CAAC,KAAK,EAAE,+BAA+B,EAAE,KAAK,EAAE,IAAI,EAAE,mBAAmB,EAAE,IAAI,CAAC,CAAC,CAAC;YACtF,GAAG,CAAC,CAAC,KAAK,EAAE,4CAA4C,EAAE,KAAK,EAAE,IAAI,EAAE,mBAAmB,EAAE,IAAI,CAAC,CAAC,CAAC;YACnG,mEAAmE;YACnE,GAAG,CAAC,CAAC,KAAK,EAAE,yDAAyD,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAC;QACvG,CAAC;QAED,kEAAkE;QAClE,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC3D,EAAE,CAAC,aAAa,CAAC,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,OAAO,CAAC,CAAC;IACjE,CAAC;IAAC,MAAM,CAAC;QACP,wEAAwE;IAC1E,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Filters a list of file paths by removing any that match the given exclude
|
|
3
|
+
* glob patterns. Uses a simple glob matcher (no external dependency).
|
|
4
|
+
*
|
|
5
|
+
* Supported patterns:
|
|
6
|
+
* - `**` matches everything
|
|
7
|
+
* - `dir/**` matches any file under `dir/`
|
|
8
|
+
* - `*.ext` matches files ending in `.ext` (at any depth)
|
|
9
|
+
* - `exact.file` matches the literal filename
|
|
10
|
+
*/
|
|
11
|
+
export declare function filterByExcludePatterns(files: string[], excludePatterns: string[]): string[];
|
|
12
|
+
//# sourceMappingURL=exclude.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exclude.d.ts","sourceRoot":"","sources":["../../src/utils/exclude.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,eAAe,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAQ5F"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Filters a list of file paths by removing any that match the given exclude
|
|
3
|
+
* glob patterns. Uses a simple glob matcher (no external dependency).
|
|
4
|
+
*
|
|
5
|
+
* Supported patterns:
|
|
6
|
+
* - `**` matches everything
|
|
7
|
+
* - `dir/**` matches any file under `dir/`
|
|
8
|
+
* - `*.ext` matches files ending in `.ext` (at any depth)
|
|
9
|
+
* - `exact.file` matches the literal filename
|
|
10
|
+
*/
|
|
11
|
+
export function filterByExcludePatterns(files, excludePatterns) {
|
|
12
|
+
if (excludePatterns.length === 0)
|
|
13
|
+
return files;
|
|
14
|
+
const matchers = excludePatterns.map(p => patternToMatcher(p));
|
|
15
|
+
return files.filter(filePath => {
|
|
16
|
+
return !matchers.some(match => match(filePath));
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Converts a glob-like pattern string to a predicate function.
|
|
21
|
+
*/
|
|
22
|
+
function patternToMatcher(pattern) {
|
|
23
|
+
// Normalize separators
|
|
24
|
+
const normalized = pattern.replace(/\\/g, '/');
|
|
25
|
+
// "**" matches everything
|
|
26
|
+
if (normalized === '**') {
|
|
27
|
+
return () => true;
|
|
28
|
+
}
|
|
29
|
+
// "dir/**" matches anything under dir/
|
|
30
|
+
if (normalized.endsWith('/**')) {
|
|
31
|
+
const prefix = normalized.slice(0, -3); // strip "/**"
|
|
32
|
+
return (filePath) => filePath.startsWith(prefix + '/') || filePath === prefix;
|
|
33
|
+
}
|
|
34
|
+
// "*.ext" matches any file with that extension (at any depth)
|
|
35
|
+
if (normalized.startsWith('*.')) {
|
|
36
|
+
const ext = normalized.slice(1); // e.g. ".json"
|
|
37
|
+
return (filePath) => filePath.endsWith(ext);
|
|
38
|
+
}
|
|
39
|
+
// Exact match (e.g. ".env", ".env.local")
|
|
40
|
+
return (filePath) => filePath === normalized;
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=exclude.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exclude.js","sourceRoot":"","sources":["../../src/utils/exclude.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,MAAM,UAAU,uBAAuB,CAAC,KAAe,EAAE,eAAyB;IAChF,IAAI,eAAe,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAE/C,MAAM,QAAQ,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC;IAE/D,OAAO,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE;QAC7B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;GAEG;AACH,SAAS,gBAAgB,CAAC,OAAe;IACvC,uBAAuB;IACvB,MAAM,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IAE/C,0BAA0B;IAC1B,IAAI,UAAU,KAAK,IAAI,EAAE,CAAC;QACxB,OAAO,GAAG,EAAE,CAAC,IAAI,CAAC;IACpB,CAAC;IAED,uCAAuC;IACvC,IAAI,UAAU,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QAC/B,MAAM,MAAM,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,cAAc;QACtD,OAAO,CAAC,QAAgB,EAAE,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,MAAM,GAAG,GAAG,CAAC,IAAI,QAAQ,KAAK,MAAM,CAAC;IACxF,CAAC;IAED,8DAA8D;IAC9D,IAAI,UAAU,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QAChC,MAAM,GAAG,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe;QAChD,OAAO,CAAC,QAAgB,EAAE,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;IACtD,CAAC;IAED,0CAA0C;IAC1C,OAAO,CAAC,QAAgB,EAAE,EAAE,CAAC,QAAQ,KAAK,UAAU,CAAC;AACvD,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generates a SHA-256 fingerprint from stderr/stdout output.
|
|
3
|
+
* This provides the exact match hash for deterministic failures.
|
|
4
|
+
*
|
|
5
|
+
* Normalizes:
|
|
6
|
+
* - Line endings (\r\n → \n)
|
|
7
|
+
* - Absolute file paths (stripped to basename)
|
|
8
|
+
* - Trailing whitespace
|
|
9
|
+
*/
|
|
10
|
+
export declare function generateExactFingerprint(stderr: string): string;
|
|
11
|
+
/**
|
|
12
|
+
* Extracts common error patterns from stderr (e.g., Exception names)
|
|
13
|
+
* This provides the fuzzy fallback for non-deterministic failures (like memory addresses).
|
|
14
|
+
*/
|
|
15
|
+
export declare function extractErrorPatterns(stderr: string): string[];
|
|
16
|
+
//# sourceMappingURL=fingerprint.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fingerprint.d.ts","sourceRoot":"","sources":["../../src/utils/fingerprint.ts"],"names":[],"mappings":"AAuBA;;;;;;;;GAQG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAO/D;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAiC7D"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import * as crypto from 'crypto';
|
|
2
|
+
/**
|
|
3
|
+
* Strips OS-specific absolute file paths from text so that the same error
|
|
4
|
+
* produces the same fingerprint regardless of where it was captured.
|
|
5
|
+
*
|
|
6
|
+
* Targets:
|
|
7
|
+
* - Windows: C:\Users\foo\project\file.js → <PATH>/file.js
|
|
8
|
+
* - Linux: /home/foo/project/file.js → <PATH>/file.js
|
|
9
|
+
* - Node internal: node:internal/... → left as-is (already portable)
|
|
10
|
+
*/
|
|
11
|
+
function stripAbsolutePaths(text) {
|
|
12
|
+
// Windows absolute paths: drive letter + backslash paths
|
|
13
|
+
// e.g. D:\BugProof\bugproof\tests\e2e\fixtures\syntax-error.js → <PATH>/syntax-error.js
|
|
14
|
+
let result = text.replace(/[A-Z]:\\(?:[^\s:()]+\\)*([^\s:()\\]+)/gi, '<PATH>/$1');
|
|
15
|
+
// Unix absolute paths: /home/user/.../file.ext or /tmp/...
|
|
16
|
+
// Capture the last path segment (the filename)
|
|
17
|
+
result = result.replace(/(?:home|tmp|usr|var|opt|root|private)(?:[^\s:()]+)*([^\s:()]+)/g, '<PATH>/$1');
|
|
18
|
+
return result;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Generates a SHA-256 fingerprint from stderr/stdout output.
|
|
22
|
+
* This provides the exact match hash for deterministic failures.
|
|
23
|
+
*
|
|
24
|
+
* Normalizes:
|
|
25
|
+
* - Line endings (\r\n → \n)
|
|
26
|
+
* - Absolute file paths (stripped to basename)
|
|
27
|
+
* - Trailing whitespace
|
|
28
|
+
*/
|
|
29
|
+
export function generateExactFingerprint(stderr) {
|
|
30
|
+
const hash = crypto.createHash('sha256');
|
|
31
|
+
let normalized = stderr.replace(/\r\n/g, '\n').trim();
|
|
32
|
+
// Strip OS-specific paths so cross-platform fingerprints match
|
|
33
|
+
normalized = stripAbsolutePaths(normalized);
|
|
34
|
+
hash.update(normalized);
|
|
35
|
+
return `sha256:${hash.digest('hex')}`;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Extracts common error patterns from stderr (e.g., Exception names)
|
|
39
|
+
* This provides the fuzzy fallback for non-deterministic failures (like memory addresses).
|
|
40
|
+
*/
|
|
41
|
+
export function extractErrorPatterns(stderr) {
|
|
42
|
+
const patterns = [];
|
|
43
|
+
// Look for common exception formats (e.g. "NameError: ...", "Exception in thread ...")
|
|
44
|
+
const exceptionRegex = /([A-Z][a-zA-Z0-9]+Error|Exception):/g;
|
|
45
|
+
let match;
|
|
46
|
+
while ((match = exceptionRegex.exec(stderr)) !== null) {
|
|
47
|
+
if (!patterns.includes(match[1])) {
|
|
48
|
+
patterns.push(match[1]);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
// Look for "fatal:" or "error:" standard CLI outputs
|
|
52
|
+
const standardErrorRegex = /(?:fatal|error):\s*(.+)$/im;
|
|
53
|
+
const stdMatch = standardErrorRegex.exec(stderr);
|
|
54
|
+
if (stdMatch && stdMatch[1]) {
|
|
55
|
+
patterns.push(stdMatch[1].trim());
|
|
56
|
+
}
|
|
57
|
+
// Look for Node.js-specific error codes: ERR_MODULE_NOT_FOUND, MODULE_NOT_FOUND, EACCES, EPERM, etc.
|
|
58
|
+
const errCodeRegex = /\b((?:ERR_)?[A-Z][A-Z0-9_]{3,})\b/g;
|
|
59
|
+
while ((match = errCodeRegex.exec(stderr)) !== null) {
|
|
60
|
+
const code = match[1];
|
|
61
|
+
// Skip common noise words that match the pattern but aren't error codes
|
|
62
|
+
if (['REQUIRED', 'NODE', 'PATH', 'FILE', 'HOME', 'USER', 'CRASH', 'REPORT',
|
|
63
|
+
'END', 'APPLICATION', 'VERSION', 'PROCESS', 'PLATFORM',
|
|
64
|
+
'PID', 'STACK', 'TRACE', 'UNHANDLED'].includes(code))
|
|
65
|
+
continue;
|
|
66
|
+
if (!patterns.includes(code)) {
|
|
67
|
+
patterns.push(code);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return patterns;
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=fingerprint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fingerprint.js","sourceRoot":"","sources":["../../src/utils/fingerprint.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,QAAQ,CAAC;AAEjC;;;;;;;;GAQG;AACH,SAAS,kBAAkB,CAAC,IAAY;IACtC,yDAAyD;IACzD,wFAAwF;IACxF,IAAI,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,yCAAyC,EAAE,WAAW,CAAC,CAAC;IAElF,2DAA2D;IAC3D,+CAA+C;IAC/C,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,iEAAiE,EAAE,WAAW,CAAC,CAAC;IAExG,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,wBAAwB,CAAC,MAAc;IACrD,MAAM,IAAI,GAAG,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;IACzC,IAAI,UAAU,GAAG,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;IACtD,+DAA+D;IAC/D,UAAU,GAAG,kBAAkB,CAAC,UAAU,CAAC,CAAC;IAC5C,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;IACxB,OAAO,UAAU,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;AACxC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,oBAAoB,CAAC,MAAc;IACjD,MAAM,QAAQ,GAAa,EAAE,CAAC;IAE9B,uFAAuF;IACvF,MAAM,cAAc,GAAG,sCAAsC,CAAC;IAC9D,IAAI,KAAK,CAAC;IACV,OAAO,CAAC,KAAK,GAAG,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QACtD,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YACjC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QAC1B,CAAC;IACH,CAAC;IAED,qDAAqD;IACrD,MAAM,kBAAkB,GAAG,4BAA4B,CAAC;IACxD,MAAM,QAAQ,GAAG,kBAAkB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACjD,IAAI,QAAQ,IAAI,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;QAC5B,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IACpC,CAAC;IAED,qGAAqG;IACrG,MAAM,YAAY,GAAG,oCAAoC,CAAC;IAC1D,OAAO,CAAC,KAAK,GAAG,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QACpD,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QACtB,wEAAwE;QACxE,IAAI,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ;YACrE,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,SAAS,EAAE,UAAU;YACtD,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,WAAW,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC;YAAE,SAAS;QACpE,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;YAC7B,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACtB,CAAC;IACH,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export interface GitContext {
|
|
2
|
+
commit: string | undefined;
|
|
3
|
+
branch: string | undefined;
|
|
4
|
+
dirty: boolean;
|
|
5
|
+
repo: string | undefined;
|
|
6
|
+
tags: string[];
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Reads git metadata from the working directory.
|
|
10
|
+
* Returns undefined fields when git is unavailable or the directory is not a repo.
|
|
11
|
+
*/
|
|
12
|
+
export declare function getGitContext(cwd: string): GitContext;
|
|
13
|
+
//# sourceMappingURL=git.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git.d.ts","sourceRoot":"","sources":["../../src/utils/git.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,KAAK,EAAE,OAAO,CAAC;IACf,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;IACzB,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,CAuCrD"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { spawnSync } from 'child_process';
|
|
2
|
+
/**
|
|
3
|
+
* Reads git metadata from the working directory.
|
|
4
|
+
* Returns undefined fields when git is unavailable or the directory is not a repo.
|
|
5
|
+
*/
|
|
6
|
+
export function getGitContext(cwd) {
|
|
7
|
+
const ctx = {
|
|
8
|
+
commit: undefined,
|
|
9
|
+
branch: undefined,
|
|
10
|
+
dirty: false,
|
|
11
|
+
repo: undefined,
|
|
12
|
+
tags: [],
|
|
13
|
+
};
|
|
14
|
+
try {
|
|
15
|
+
const head = spawnSync('git', ['rev-parse', 'HEAD'], { cwd, encoding: 'utf-8', timeout: 5000 });
|
|
16
|
+
if (head.status === 0) {
|
|
17
|
+
ctx.commit = head.stdout.trim();
|
|
18
|
+
}
|
|
19
|
+
const branch = spawnSync('git', ['branch', '--show-current'], { cwd, encoding: 'utf-8', timeout: 5000 });
|
|
20
|
+
if (branch.status === 0) {
|
|
21
|
+
ctx.branch = branch.stdout.trim() || undefined;
|
|
22
|
+
}
|
|
23
|
+
const status = spawnSync('git', ['status', '--porcelain'], { cwd, encoding: 'utf-8', timeout: 5000 });
|
|
24
|
+
if (status.status === 0) {
|
|
25
|
+
ctx.dirty = status.stdout.trim().length > 0;
|
|
26
|
+
}
|
|
27
|
+
const remote = spawnSync('git', ['config', '--get', 'remote.origin.url'], { cwd, encoding: 'utf-8', timeout: 5000 });
|
|
28
|
+
if (remote.status === 0) {
|
|
29
|
+
ctx.repo = remote.stdout.trim() || undefined;
|
|
30
|
+
}
|
|
31
|
+
const tags = spawnSync('git', ['tag', '--points-at', 'HEAD'], { cwd, encoding: 'utf-8', timeout: 5000 });
|
|
32
|
+
if (tags.status === 0 && tags.stdout.trim()) {
|
|
33
|
+
ctx.tags = tags.stdout.trim().split('\n').filter(Boolean);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
// git not available or not a repo, return defaults
|
|
38
|
+
}
|
|
39
|
+
return ctx;
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=git.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git.js","sourceRoot":"","sources":["../../src/utils/git.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAU1C;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,GAAW;IACvC,MAAM,GAAG,GAAe;QACtB,MAAM,EAAE,SAAS;QACjB,MAAM,EAAE,SAAS;QACjB,KAAK,EAAE,KAAK;QACZ,IAAI,EAAE,SAAS;QACf,IAAI,EAAE,EAAE;KACT,CAAC;IAEF,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,SAAS,CAAC,KAAK,EAAE,CAAC,WAAW,EAAE,MAAM,CAAC,EAAE,EAAE,GAAG,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;QAChG,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACtB,GAAG,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;QAClC,CAAC;QAED,MAAM,MAAM,GAAG,SAAS,CAAC,KAAK,EAAE,CAAC,QAAQ,EAAE,gBAAgB,CAAC,EAAE,EAAE,GAAG,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;QACzG,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACxB,GAAG,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,SAAS,CAAC;QACjD,CAAC;QAED,MAAM,MAAM,GAAG,SAAS,CAAC,KAAK,EAAE,CAAC,QAAQ,EAAE,aAAa,CAAC,EAAE,EAAE,GAAG,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;QACtG,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACxB,GAAG,CAAC,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC;QAC9C,CAAC;QAED,MAAM,MAAM,GAAG,SAAS,CAAC,KAAK,EAAE,CAAC,QAAQ,EAAE,OAAO,EAAE,mBAAmB,CAAC,EAAE,EAAE,GAAG,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;QACrH,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACxB,GAAG,CAAC,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,SAAS,CAAC;QAC/C,CAAC;QAED,MAAM,IAAI,GAAG,SAAS,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE,aAAa,EAAE,MAAM,CAAC,EAAE,EAAE,GAAG,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;QACzG,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC;YAC5C,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAC5D,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,mDAAmD;IACrD,CAAC;IAED,OAAO,GAAG,CAAC;AACb,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structured JSON output formatters for CI integration.
|
|
3
|
+
* When --json is passed, the CLI prints these instead of human-readable output.
|
|
4
|
+
*/
|
|
5
|
+
import { ArtifactManifest } from '../types/artifact.js';
|
|
6
|
+
import { FailureRecord } from '../types/failure.js';
|
|
7
|
+
import { Verdict } from '../replay/verdict.js';
|
|
8
|
+
import { FileEntry } from '../capture/packager.js';
|
|
9
|
+
export interface CaptureJsonInput {
|
|
10
|
+
manifest: ArtifactManifest;
|
|
11
|
+
failure: FailureRecord;
|
|
12
|
+
artifactPath: string;
|
|
13
|
+
filesCount: number;
|
|
14
|
+
totalSize: number;
|
|
15
|
+
}
|
|
16
|
+
export declare function formatCaptureJson(input: CaptureJsonInput): string;
|
|
17
|
+
export interface ReplayJsonInput {
|
|
18
|
+
verdict: Verdict;
|
|
19
|
+
expectedExitCode: number;
|
|
20
|
+
actualExitCode: number;
|
|
21
|
+
artifactName: string;
|
|
22
|
+
bugBox?: {
|
|
23
|
+
level: string;
|
|
24
|
+
appliedLayers: string[];
|
|
25
|
+
skippedLayers: string[];
|
|
26
|
+
platform: string;
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
export declare function formatReplayJson(input: ReplayJsonInput): string;
|
|
30
|
+
export interface InspectJsonInput {
|
|
31
|
+
manifest: ArtifactManifest;
|
|
32
|
+
failure: FailureRecord;
|
|
33
|
+
files: FileEntry[];
|
|
34
|
+
}
|
|
35
|
+
export declare function formatInspectJson(input: InspectJsonInput): string;
|
|
36
|
+
//# sourceMappingURL=json-output.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"json-output.d.ts","sourceRoot":"","sources":["../../src/utils/json-output.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAC/C,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAInD,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,OAAO,EAAE,aAAa,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,gBAAgB,GAAG,MAAM,CAuBjE;AAID,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,gBAAgB,EAAE,MAAM,CAAC;IACzB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE;QACP,KAAK,EAAE,MAAM,CAAC;QACd,aAAa,EAAE,MAAM,EAAE,CAAC;QACxB,aAAa,EAAE,MAAM,EAAE,CAAC;QACxB,QAAQ,EAAE,MAAM,CAAC;KAClB,CAAC;CACH;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,eAAe,GAAG,MAAM,CAY/D;AAID,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,OAAO,EAAE,aAAa,CAAC;IACvB,KAAK,EAAE,SAAS,EAAE,CAAC;CACpB;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,gBAAgB,GAAG,MAAM,CAMjE"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structured JSON output formatters for CI integration.
|
|
3
|
+
* When --json is passed, the CLI prints these instead of human-readable output.
|
|
4
|
+
*/
|
|
5
|
+
export function formatCaptureJson(input) {
|
|
6
|
+
return JSON.stringify({
|
|
7
|
+
success: true,
|
|
8
|
+
artifact: {
|
|
9
|
+
name: input.manifest.name,
|
|
10
|
+
path: input.artifactPath,
|
|
11
|
+
version: input.manifest.bugproof_version,
|
|
12
|
+
captured_at: input.manifest.captured_at,
|
|
13
|
+
},
|
|
14
|
+
failure: {
|
|
15
|
+
exit_code: input.failure.exit_code,
|
|
16
|
+
fingerprint: input.failure.fingerprint,
|
|
17
|
+
error_patterns: input.failure.error_patterns,
|
|
18
|
+
duration_ms: input.failure.duration_ms,
|
|
19
|
+
timeout: input.failure.timeout,
|
|
20
|
+
},
|
|
21
|
+
files: {
|
|
22
|
+
count: input.filesCount,
|
|
23
|
+
total_size_bytes: input.totalSize,
|
|
24
|
+
},
|
|
25
|
+
command: input.manifest.command,
|
|
26
|
+
platform: input.manifest.captured_on,
|
|
27
|
+
}, null, 2);
|
|
28
|
+
}
|
|
29
|
+
export function formatReplayJson(input) {
|
|
30
|
+
return JSON.stringify({
|
|
31
|
+
reproduced: input.verdict.status === 'confirmed',
|
|
32
|
+
verdict: {
|
|
33
|
+
status: input.verdict.status,
|
|
34
|
+
message: input.verdict.message,
|
|
35
|
+
},
|
|
36
|
+
expected_exit_code: input.expectedExitCode,
|
|
37
|
+
actual_exit_code: input.actualExitCode,
|
|
38
|
+
artifact: input.artifactName,
|
|
39
|
+
bugBox: input.bugBox,
|
|
40
|
+
}, null, 2);
|
|
41
|
+
}
|
|
42
|
+
export function formatInspectJson(input) {
|
|
43
|
+
return JSON.stringify({
|
|
44
|
+
manifest: input.manifest,
|
|
45
|
+
failure: input.failure,
|
|
46
|
+
files: input.files,
|
|
47
|
+
}, null, 2);
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=json-output.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"json-output.js","sourceRoot":"","sources":["../../src/utils/json-output.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAiBH,MAAM,UAAU,iBAAiB,CAAC,KAAuB;IACvD,OAAO,IAAI,CAAC,SAAS,CAAC;QACpB,OAAO,EAAE,IAAI;QACb,QAAQ,EAAE;YACR,IAAI,EAAE,KAAK,CAAC,QAAQ,CAAC,IAAI;YACzB,IAAI,EAAE,KAAK,CAAC,YAAY;YACxB,OAAO,EAAE,KAAK,CAAC,QAAQ,CAAC,gBAAgB;YACxC,WAAW,EAAE,KAAK,CAAC,QAAQ,CAAC,WAAW;SACxC;QACD,OAAO,EAAE;YACP,SAAS,EAAE,KAAK,CAAC,OAAO,CAAC,SAAS;YAClC,WAAW,EAAE,KAAK,CAAC,OAAO,CAAC,WAAW;YACtC,cAAc,EAAE,KAAK,CAAC,OAAO,CAAC,cAAc;YAC5C,WAAW,EAAE,KAAK,CAAC,OAAO,CAAC,WAAW;YACtC,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,OAAO;SAC/B;QACD,KAAK,EAAE;YACL,KAAK,EAAE,KAAK,CAAC,UAAU;YACvB,gBAAgB,EAAE,KAAK,CAAC,SAAS;SAClC;QACD,OAAO,EAAE,KAAK,CAAC,QAAQ,CAAC,OAAO;QAC/B,QAAQ,EAAE,KAAK,CAAC,QAAQ,CAAC,WAAW;KACrC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;AACd,CAAC;AAiBD,MAAM,UAAU,gBAAgB,CAAC,KAAsB;IACrD,OAAO,IAAI,CAAC,SAAS,CAAC;QACpB,UAAU,EAAE,KAAK,CAAC,OAAO,CAAC,MAAM,KAAK,WAAW;QAChD,OAAO,EAAE;YACP,MAAM,EAAE,KAAK,CAAC,OAAO,CAAC,MAAM;YAC5B,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,OAAO;SAC/B;QACD,kBAAkB,EAAE,KAAK,CAAC,gBAAgB;QAC1C,gBAAgB,EAAE,KAAK,CAAC,cAAc;QACtC,QAAQ,EAAE,KAAK,CAAC,YAAY;QAC5B,MAAM,EAAE,KAAK,CAAC,MAAM;KACrB,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;AACd,CAAC;AAUD,MAAM,UAAU,iBAAiB,CAAC,KAAuB;IACvD,OAAO,IAAI,CAAC,SAAS,CAAC;QACpB,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,KAAK,EAAE,KAAK,CAAC,KAAK;KACnB,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;AACd,CAAC"}
|