@azizbekdevuz/gitguard-cli 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +88 -0
- package/dist/collectors/conflict-extractor.d.ts +7 -0
- package/dist/collectors/conflict-extractor.d.ts.map +1 -0
- package/dist/collectors/conflict-extractor.js +94 -0
- package/dist/collectors/conflict-extractor.js.map +1 -0
- package/dist/collectors/git-info.d.ts +18 -0
- package/dist/collectors/git-info.d.ts.map +1 -0
- package/dist/collectors/git-info.js +59 -0
- package/dist/collectors/git-info.js.map +1 -0
- package/dist/collectors/rebase-detector.d.ts +7 -0
- package/dist/collectors/rebase-detector.d.ts.map +1 -0
- package/dist/collectors/rebase-detector.js +57 -0
- package/dist/collectors/rebase-detector.js.map +1 -0
- package/dist/commands/send.d.ts +7 -0
- package/dist/commands/send.d.ts.map +1 -0
- package/dist/commands/send.js +169 -0
- package/dist/commands/send.js.map +1 -0
- package/dist/commands/snapshot.d.ts +7 -0
- package/dist/commands/snapshot.d.ts.map +1 -0
- package/dist/commands/snapshot.js +92 -0
- package/dist/commands/snapshot.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +22 -0
- package/dist/index.js.map +1 -0
- package/dist/parsers/branch-parser.d.ts +7 -0
- package/dist/parsers/branch-parser.d.ts.map +1 -0
- package/dist/parsers/branch-parser.js +20 -0
- package/dist/parsers/branch-parser.js.map +1 -0
- package/dist/parsers/diffstat-parser.d.ts +8 -0
- package/dist/parsers/diffstat-parser.d.ts.map +1 -0
- package/dist/parsers/diffstat-parser.js +42 -0
- package/dist/parsers/diffstat-parser.js.map +1 -0
- package/dist/parsers/log-parser.d.ts +8 -0
- package/dist/parsers/log-parser.d.ts.map +1 -0
- package/dist/parsers/log-parser.js +46 -0
- package/dist/parsers/log-parser.js.map +1 -0
- package/dist/parsers/reflog-parser.d.ts +8 -0
- package/dist/parsers/reflog-parser.d.ts.map +1 -0
- package/dist/parsers/reflog-parser.js +65 -0
- package/dist/parsers/reflog-parser.js.map +1 -0
- package/dist/parsers/status-parser.d.ts +27 -0
- package/dist/parsers/status-parser.d.ts.map +1 -0
- package/dist/parsers/status-parser.js +110 -0
- package/dist/parsers/status-parser.js.map +1 -0
- package/dist/utils/exec.d.ts +14 -0
- package/dist/utils/exec.d.ts.map +1 -0
- package/dist/utils/exec.js +54 -0
- package/dist/utils/exec.js.map +1 -0
- package/package.json +46 -0
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { writeFileSync } from 'node:fs';
|
|
2
|
+
import { SnapshotV1Schema } from '@gitguard/schema';
|
|
3
|
+
import { collectGitInfo } from '../collectors/git-info.js';
|
|
4
|
+
import { parseStatus } from '../parsers/status-parser.js';
|
|
5
|
+
import { parseBranches } from '../parsers/branch-parser.js';
|
|
6
|
+
import { parseLog } from '../parsers/log-parser.js';
|
|
7
|
+
import { parseReflog } from '../parsers/reflog-parser.js';
|
|
8
|
+
import { parseDiffStat } from '../parsers/diffstat-parser.js';
|
|
9
|
+
import { detectRebaseState } from '../collectors/rebase-detector.js';
|
|
10
|
+
import { extractConflicts } from '../collectors/conflict-extractor.js';
|
|
11
|
+
export async function snapshotCommand(options) {
|
|
12
|
+
const requestId = `snapshot-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
|
|
13
|
+
console.error(`[CLI:SNAPSHOT:${requestId}] ========================================`);
|
|
14
|
+
console.error(`[CLI:SNAPSHOT:${requestId}] 📸 Starting snapshot generation`);
|
|
15
|
+
console.error(`[CLI:SNAPSHOT:${requestId}] Output: ${options.output || 'stdout'}`);
|
|
16
|
+
console.error(`[CLI:SNAPSHOT:${requestId}] Pretty: ${options.pretty || false}`);
|
|
17
|
+
try {
|
|
18
|
+
console.error(`[CLI:SNAPSHOT:${requestId}] 📥 Collecting Git repository information...`);
|
|
19
|
+
// Collect git information
|
|
20
|
+
const gitInfo = await collectGitInfo();
|
|
21
|
+
console.error(`[CLI:SNAPSHOT:${requestId}] ✅ Git info collected`);
|
|
22
|
+
// Parse status
|
|
23
|
+
const statusInfo = parseStatus(gitInfo.status);
|
|
24
|
+
// Parse branches
|
|
25
|
+
const branchInfo = parseBranches(gitInfo.branches, statusInfo.branch);
|
|
26
|
+
// Parse logs
|
|
27
|
+
const logEntries = parseLog(gitInfo.log);
|
|
28
|
+
const reflogEntries = parseReflog(gitInfo.reflog);
|
|
29
|
+
// Parse diff stats
|
|
30
|
+
const diffStats = parseDiffStat(gitInfo.diffStat);
|
|
31
|
+
// Detect rebase state
|
|
32
|
+
const rebaseState = await detectRebaseState(gitInfo.gitDir);
|
|
33
|
+
// Extract conflict details for up to 5 unmerged files (increased for better conflict exploration)
|
|
34
|
+
const unmergedFiles = await extractConflicts(gitInfo.repoRoot, statusInfo.unmergedPaths.slice(0, 5));
|
|
35
|
+
// Build snapshot
|
|
36
|
+
const snapshot = {
|
|
37
|
+
version: 1,
|
|
38
|
+
timestamp: new Date().toISOString(),
|
|
39
|
+
platform: process.platform,
|
|
40
|
+
repoRoot: gitInfo.repoRoot,
|
|
41
|
+
gitDir: gitInfo.gitDir,
|
|
42
|
+
branch: branchInfo,
|
|
43
|
+
isDetachedHead: statusInfo.isDetachedHead,
|
|
44
|
+
rebaseState,
|
|
45
|
+
unmergedFiles,
|
|
46
|
+
stagedFiles: statusInfo.stagedFiles,
|
|
47
|
+
modifiedFiles: statusInfo.modifiedFiles,
|
|
48
|
+
untrackedFiles: statusInfo.untrackedFiles,
|
|
49
|
+
recentLog: logEntries,
|
|
50
|
+
recentReflog: reflogEntries,
|
|
51
|
+
// NEW: Commit graph for history visualization
|
|
52
|
+
commitGraph: gitInfo.commitGraph || undefined,
|
|
53
|
+
// NEW: Diff stats for file summary
|
|
54
|
+
diffStats: diffStats.length > 0 ? diffStats : undefined,
|
|
55
|
+
// NEW: Merge metadata
|
|
56
|
+
mergeHead: gitInfo.mergeHead || undefined,
|
|
57
|
+
mergeMessage: gitInfo.mergeMessage || undefined,
|
|
58
|
+
rawStatus: gitInfo.status,
|
|
59
|
+
rawBranches: gitInfo.branches,
|
|
60
|
+
};
|
|
61
|
+
console.error(`[CLI:SNAPSHOT:${requestId}] ✅ Validating snapshot with schema...`);
|
|
62
|
+
// Validate with Zod
|
|
63
|
+
const validated = SnapshotV1Schema.parse(snapshot);
|
|
64
|
+
console.error(`[CLI:SNAPSHOT:${requestId}] ✅ Snapshot validated`);
|
|
65
|
+
console.error(`[CLI:SNAPSHOT:${requestId}] Snapshot size: ${JSON.stringify(validated).length} bytes`);
|
|
66
|
+
// Output
|
|
67
|
+
const jsonOutput = options.pretty
|
|
68
|
+
? JSON.stringify(validated, null, 2)
|
|
69
|
+
: JSON.stringify(validated);
|
|
70
|
+
if (options.output) {
|
|
71
|
+
writeFileSync(options.output, jsonOutput, 'utf-8');
|
|
72
|
+
console.error(`[CLI:SNAPSHOT:${requestId}] ✅ Snapshot written to: ${options.output}`);
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
console.log(jsonOutput);
|
|
76
|
+
console.error(`[CLI:SNAPSHOT:${requestId}] ✅ Snapshot output to stdout`);
|
|
77
|
+
}
|
|
78
|
+
console.error(`[CLI:SNAPSHOT:${requestId}] ========================================`);
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
81
|
+
console.error(`[CLI:SNAPSHOT:${requestId}] ❌ Snapshot generation failed`);
|
|
82
|
+
if (error instanceof Error) {
|
|
83
|
+
console.error(`[CLI:SNAPSHOT:${requestId}] Error: ${error.message}`);
|
|
84
|
+
if (error.message.includes('not a git repository')) {
|
|
85
|
+
console.error('Please run this command from within a git repository.');
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
console.error(`[CLI:SNAPSHOT:${requestId}] ========================================`);
|
|
89
|
+
process.exit(1);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=snapshot.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"snapshot.js","sourceRoot":"","sources":["../../src/commands/snapshot.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { program } from 'commander';
|
|
3
|
+
import { snapshotCommand } from './commands/snapshot.js';
|
|
4
|
+
import { sendCommand } from './commands/send.js';
|
|
5
|
+
program
|
|
6
|
+
.name('gitguard')
|
|
7
|
+
.description('GitGuard Agent - Safe git recovery helper')
|
|
8
|
+
.version('1.0.0');
|
|
9
|
+
program
|
|
10
|
+
.command('snapshot')
|
|
11
|
+
.description('Generate a read-only snapshot of the current git repository state')
|
|
12
|
+
.option('-o, --output <file>', 'Write snapshot to file instead of stdout')
|
|
13
|
+
.option('--pretty', 'Pretty-print JSON output')
|
|
14
|
+
.action(snapshotCommand);
|
|
15
|
+
program
|
|
16
|
+
.command('send')
|
|
17
|
+
.description('Capture and send repository state to GitGuard for analysis')
|
|
18
|
+
.option('-u, --api-url <url>', 'GitGuard API URL (default: http://localhost:3000)')
|
|
19
|
+
.option('-o, --open', 'Open the incident room in browser after upload')
|
|
20
|
+
.action(sendCommand);
|
|
21
|
+
program.parse();
|
|
22
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEjD,OAAO;KACJ,IAAI,CAAC,UAAU,CAAC;KAChB,WAAW,CAAC,2CAA2C,CAAC;KACxD,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,OAAO;KACJ,OAAO,CAAC,UAAU,CAAC;KACnB,WAAW,CAAC,mEAAmE,CAAC;KAChF,MAAM,CAAC,qBAAqB,EAAE,0CAA0C,CAAC;KACzE,MAAM,CAAC,UAAU,EAAE,0BAA0B,CAAC;KAC9C,MAAM,CAAC,eAAe,CAAC,CAAC;AAE3B,OAAO;KACJ,OAAO,CAAC,MAAM,CAAC;KACf,WAAW,CAAC,4DAA4D,CAAC;KACzE,MAAM,CAAC,qBAAqB,EAAE,mDAAmD,CAAC;KAClF,MAAM,CAAC,YAAY,EAAE,gDAAgD,CAAC;KACtE,MAAM,CAAC,WAAW,CAAC,CAAC;AAEvB,OAAO,CAAC,KAAK,EAAE,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { BranchInfo } from '@gitguard/schema';
|
|
2
|
+
import type { StatusInfo } from './status-parser.js';
|
|
3
|
+
/**
|
|
4
|
+
* Parse branch information from git branch -vv and status info.
|
|
5
|
+
*/
|
|
6
|
+
export declare function parseBranches(branchOutput: string, statusBranch: StatusInfo['branch']): BranchInfo;
|
|
7
|
+
//# sourceMappingURL=branch-parser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"branch-parser.d.ts","sourceRoot":"","sources":["../../src/parsers/branch-parser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAErD;;GAEG;AACH,wBAAgB,aAAa,CAC3B,YAAY,EAAE,MAAM,EACpB,YAAY,EAAE,UAAU,CAAC,QAAQ,CAAC,GACjC,UAAU,CAkBZ"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse branch information from git branch -vv and status info.
|
|
3
|
+
*/
|
|
4
|
+
export function parseBranches(branchOutput, statusBranch) {
|
|
5
|
+
const result = {
|
|
6
|
+
head: statusBranch.head,
|
|
7
|
+
oid: statusBranch.oid,
|
|
8
|
+
};
|
|
9
|
+
if (statusBranch.upstream) {
|
|
10
|
+
result.upstream = statusBranch.upstream;
|
|
11
|
+
}
|
|
12
|
+
if (statusBranch.ahead !== undefined && statusBranch.behind !== undefined) {
|
|
13
|
+
result.aheadBehind = {
|
|
14
|
+
ahead: statusBranch.ahead,
|
|
15
|
+
behind: statusBranch.behind,
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
return result;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=branch-parser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"branch-parser.js","sourceRoot":"","sources":["../../src/parsers/branch-parser.ts"],"names":[],"mappings":"AAGA;;GAEG;AACH,MAAM,UAAU,aAAa,CAC3B,YAAoB,EACpB,YAAkC;IAElC,MAAM,MAAM,GAAe;QACzB,IAAI,EAAE,YAAY,CAAC,IAAI;QACvB,GAAG,EAAE,YAAY,CAAC,GAAG;KACtB,CAAC;IAEF,IAAI,YAAY,CAAC,QAAQ,EAAE,CAAC;QAC1B,MAAM,CAAC,QAAQ,GAAG,YAAY,CAAC,QAAQ,CAAC;IAC1C,CAAC;IAED,IAAI,YAAY,CAAC,KAAK,KAAK,SAAS,IAAI,YAAY,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;QAC1E,MAAM,CAAC,WAAW,GAAG;YACnB,KAAK,EAAE,YAAY,CAAC,KAAK;YACzB,MAAM,EAAE,YAAY,CAAC,MAAM;SAC5B,CAAC;IACJ,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { DiffStat } from '@gitguard/schema';
|
|
2
|
+
/**
|
|
3
|
+
* Parse git diff --numstat output into structured diff stats.
|
|
4
|
+
* Format: additions<TAB>deletions<TAB>path
|
|
5
|
+
* For binary files: -<TAB>-<TAB>path
|
|
6
|
+
*/
|
|
7
|
+
export declare function parseDiffStat(rawOutput: string): DiffStat[];
|
|
8
|
+
//# sourceMappingURL=diffstat-parser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diffstat-parser.d.ts","sourceRoot":"","sources":["../../src/parsers/diffstat-parser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEjD;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,QAAQ,EAAE,CAuC3D"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse git diff --numstat output into structured diff stats.
|
|
3
|
+
* Format: additions<TAB>deletions<TAB>path
|
|
4
|
+
* For binary files: -<TAB>-<TAB>path
|
|
5
|
+
*/
|
|
6
|
+
export function parseDiffStat(rawOutput) {
|
|
7
|
+
if (!rawOutput.trim()) {
|
|
8
|
+
return [];
|
|
9
|
+
}
|
|
10
|
+
const stats = [];
|
|
11
|
+
const lines = rawOutput.split('\n').filter(Boolean);
|
|
12
|
+
for (const line of lines) {
|
|
13
|
+
// Skip the summary line (e.g., "3 files changed, 10 insertions(+)")
|
|
14
|
+
if (line.includes('files changed') || line.includes('file changed')) {
|
|
15
|
+
continue;
|
|
16
|
+
}
|
|
17
|
+
// Parse numstat format: additions<TAB>deletions<TAB>path
|
|
18
|
+
const parts = line.split('\t');
|
|
19
|
+
if (parts.length >= 3) {
|
|
20
|
+
const [addStr, delStr, ...pathParts] = parts;
|
|
21
|
+
const path = pathParts.join('\t'); // Handle paths with tabs
|
|
22
|
+
if (addStr === '-' && delStr === '-') {
|
|
23
|
+
// Binary file
|
|
24
|
+
stats.push({
|
|
25
|
+
path,
|
|
26
|
+
additions: 0,
|
|
27
|
+
deletions: 0,
|
|
28
|
+
binary: true,
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
stats.push({
|
|
33
|
+
path,
|
|
34
|
+
additions: parseInt(addStr, 10) || 0,
|
|
35
|
+
deletions: parseInt(delStr, 10) || 0,
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return stats;
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=diffstat-parser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diffstat-parser.js","sourceRoot":"","sources":["../../src/parsers/diffstat-parser.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAC,SAAiB;IAC7C,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,EAAE,CAAC;QACtB,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,MAAM,KAAK,GAAe,EAAE,CAAC;IAC7B,MAAM,KAAK,GAAG,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAEpD,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,oEAAoE;QACpE,IAAI,IAAI,CAAC,QAAQ,CAAC,eAAe,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC;YACpE,SAAS;QACX,CAAC;QAED,yDAAyD;QACzD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC/B,IAAI,KAAK,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;YACtB,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC,GAAG,KAAK,CAAC;YAC7C,MAAM,IAAI,GAAG,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,yBAAyB;YAE5D,IAAI,MAAM,KAAK,GAAG,IAAI,MAAM,KAAK,GAAG,EAAE,CAAC;gBACrC,cAAc;gBACd,KAAK,CAAC,IAAI,CAAC;oBACT,IAAI;oBACJ,SAAS,EAAE,CAAC;oBACZ,SAAS,EAAE,CAAC;oBACZ,MAAM,EAAE,IAAI;iBACb,CAAC,CAAC;YACL,CAAC;iBAAM,CAAC;gBACN,KAAK,CAAC,IAAI,CAAC;oBACT,IAAI;oBACJ,SAAS,EAAE,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,CAAC;oBACpC,SAAS,EAAE,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,CAAC;iBACrC,CAAC,CAAC;YACL,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { LogEntry } from '@gitguard/schema';
|
|
2
|
+
/**
|
|
3
|
+
* Parse git log --oneline --decorate output.
|
|
4
|
+
* Format: <hash> (<decorations>) <message>
|
|
5
|
+
* Or: <hash> <message> (if no decorations)
|
|
6
|
+
*/
|
|
7
|
+
export declare function parseLog(logOutput: string): LogEntry[];
|
|
8
|
+
//# sourceMappingURL=log-parser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log-parser.d.ts","sourceRoot":"","sources":["../../src/parsers/log-parser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEjD;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,QAAQ,EAAE,CAYtD"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse git log --oneline --decorate output.
|
|
3
|
+
* Format: <hash> (<decorations>) <message>
|
|
4
|
+
* Or: <hash> <message> (if no decorations)
|
|
5
|
+
*/
|
|
6
|
+
export function parseLog(logOutput) {
|
|
7
|
+
const lines = logOutput.split('\n').filter(line => line.length > 0);
|
|
8
|
+
const entries = [];
|
|
9
|
+
for (const line of lines) {
|
|
10
|
+
const entry = parseLogLine(line);
|
|
11
|
+
if (entry) {
|
|
12
|
+
entries.push(entry);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
return entries;
|
|
16
|
+
}
|
|
17
|
+
function parseLogLine(line) {
|
|
18
|
+
// Match: <hash> (optional decorations) <message>
|
|
19
|
+
const match = line.match(/^([a-f0-9]+)\s+(?:\(([^)]+)\)\s+)?(.*)$/);
|
|
20
|
+
if (!match) {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
const [, hash, decorations, message] = match;
|
|
24
|
+
const refs = [];
|
|
25
|
+
if (decorations) {
|
|
26
|
+
// Parse decorations like "HEAD -> main, origin/main, tag: v1.0"
|
|
27
|
+
const parts = decorations.split(',').map(p => p.trim());
|
|
28
|
+
for (const part of parts) {
|
|
29
|
+
// Handle "HEAD -> branch"
|
|
30
|
+
if (part.includes('->')) {
|
|
31
|
+
const [head, branch] = part.split('->').map(s => s.trim());
|
|
32
|
+
refs.push(head);
|
|
33
|
+
refs.push(branch);
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
refs.push(part);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return {
|
|
41
|
+
hash,
|
|
42
|
+
refs,
|
|
43
|
+
message: message.trim(),
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=log-parser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log-parser.js","sourceRoot":"","sources":["../../src/parsers/log-parser.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,MAAM,UAAU,QAAQ,CAAC,SAAiB;IACxC,MAAM,KAAK,GAAG,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACpE,MAAM,OAAO,GAAe,EAAE,CAAC;IAE/B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,KAAK,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;QACjC,IAAI,KAAK,EAAE,CAAC;YACV,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACtB,CAAC;IACH,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,SAAS,YAAY,CAAC,IAAY;IAChC,iDAAiD;IACjD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,yCAAyC,CAAC,CAAC;IAEpE,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,CAAC,GAAG,KAAK,CAAC;IAE7C,MAAM,IAAI,GAAa,EAAE,CAAC;IAC1B,IAAI,WAAW,EAAE,CAAC;QAChB,gEAAgE;QAChE,MAAM,KAAK,GAAG,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;QACxD,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,0BAA0B;YAC1B,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;gBACxB,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;gBAC3D,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBAChB,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACpB,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAClB,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO;QACL,IAAI;QACJ,IAAI;QACJ,OAAO,EAAE,OAAO,CAAC,IAAI,EAAE;KACxB,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ReflogEntry } from '@gitguard/schema';
|
|
2
|
+
/**
|
|
3
|
+
* Parse git reflog output.
|
|
4
|
+
* Format: <hash> <selector> <action>: <message>
|
|
5
|
+
* Example: abc1234 HEAD@{0} commit: Fix bug
|
|
6
|
+
*/
|
|
7
|
+
export declare function parseReflog(reflogOutput: string): ReflogEntry[];
|
|
8
|
+
//# sourceMappingURL=reflog-parser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reflog-parser.d.ts","sourceRoot":"","sources":["../../src/parsers/reflog-parser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAEpD;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,YAAY,EAAE,MAAM,GAAG,WAAW,EAAE,CAY/D"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse git reflog output.
|
|
3
|
+
* Format: <hash> <selector> <action>: <message>
|
|
4
|
+
* Example: abc1234 HEAD@{0} commit: Fix bug
|
|
5
|
+
*/
|
|
6
|
+
export function parseReflog(reflogOutput) {
|
|
7
|
+
const lines = reflogOutput.split('\n').filter(line => line.length > 0);
|
|
8
|
+
const entries = [];
|
|
9
|
+
for (const line of lines) {
|
|
10
|
+
const entry = parseReflogLine(line);
|
|
11
|
+
if (entry) {
|
|
12
|
+
entries.push(entry);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
return entries;
|
|
16
|
+
}
|
|
17
|
+
function parseReflogLine(line) {
|
|
18
|
+
// Match: <hash> <selector> <action>: <message>
|
|
19
|
+
// Example: 57c3040 HEAD@{0}: commit: Add validation to functions
|
|
20
|
+
// Note: action can contain sub-parts like "commit (initial)"
|
|
21
|
+
const match = line.match(/^([a-f0-9]+)\s+(HEAD@\{\d+\}):\s+([^:]+):\s*(.*)$/);
|
|
22
|
+
if (match) {
|
|
23
|
+
const [, hash, selector, action, message] = match;
|
|
24
|
+
return {
|
|
25
|
+
hash,
|
|
26
|
+
selector,
|
|
27
|
+
action: action.trim(),
|
|
28
|
+
message: message.trim(),
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
// Try format with parentheses in action: "commit (initial): message"
|
|
32
|
+
const parenMatch = line.match(/^([a-f0-9]+)\s+(HEAD@\{\d+\}):\s+([^:]+\([^)]+\)):\s*(.*)$/);
|
|
33
|
+
if (parenMatch) {
|
|
34
|
+
const [, hash, selector, action, message] = parenMatch;
|
|
35
|
+
return {
|
|
36
|
+
hash,
|
|
37
|
+
selector,
|
|
38
|
+
action: action.trim(),
|
|
39
|
+
message: message.trim(),
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
// Fallback: simpler format
|
|
43
|
+
const simpleMatch = line.match(/^([a-f0-9]+)\s+(HEAD@\{\d+\}):\s+(.*)$/);
|
|
44
|
+
if (simpleMatch) {
|
|
45
|
+
const [, hash, selector, rest] = simpleMatch;
|
|
46
|
+
// Try to split on first colon for action
|
|
47
|
+
const colonIdx = rest.indexOf(':');
|
|
48
|
+
if (colonIdx > 0) {
|
|
49
|
+
return {
|
|
50
|
+
hash,
|
|
51
|
+
selector,
|
|
52
|
+
action: rest.slice(0, colonIdx).trim(),
|
|
53
|
+
message: rest.slice(colonIdx + 1).trim(),
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
return {
|
|
57
|
+
hash,
|
|
58
|
+
selector,
|
|
59
|
+
action: 'unknown',
|
|
60
|
+
message: rest.trim(),
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=reflog-parser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reflog-parser.js","sourceRoot":"","sources":["../../src/parsers/reflog-parser.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,MAAM,UAAU,WAAW,CAAC,YAAoB;IAC9C,MAAM,KAAK,GAAG,YAAY,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACvE,MAAM,OAAO,GAAkB,EAAE,CAAC;IAElC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,KAAK,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC;QACpC,IAAI,KAAK,EAAE,CAAC;YACV,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACtB,CAAC;IACH,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,SAAS,eAAe,CAAC,IAAY;IACnC,+CAA+C;IAC/C,iEAAiE;IACjE,6DAA6D;IAC7D,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,mDAAmD,CAAC,CAAC;IAE9E,IAAI,KAAK,EAAE,CAAC;QACV,MAAM,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,GAAG,KAAK,CAAC;QAClD,OAAO;YACL,IAAI;YACJ,QAAQ;YACR,MAAM,EAAE,MAAM,CAAC,IAAI,EAAE;YACrB,OAAO,EAAE,OAAO,CAAC,IAAI,EAAE;SACxB,CAAC;IACJ,CAAC;IAED,qEAAqE;IACrE,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,4DAA4D,CAAC,CAAC;IAC5F,IAAI,UAAU,EAAE,CAAC;QACf,MAAM,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,GAAG,UAAU,CAAC;QACvD,OAAO;YACL,IAAI;YACJ,QAAQ;YACR,MAAM,EAAE,MAAM,CAAC,IAAI,EAAE;YACrB,OAAO,EAAE,OAAO,CAAC,IAAI,EAAE;SACxB,CAAC;IACJ,CAAC;IAED,2BAA2B;IAC3B,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,wCAAwC,CAAC,CAAC;IACzE,IAAI,WAAW,EAAE,CAAC;QAChB,MAAM,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,CAAC,GAAG,WAAW,CAAC;QAC7C,yCAAyC;QACzC,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACnC,IAAI,QAAQ,GAAG,CAAC,EAAE,CAAC;YACjB,OAAO;gBACL,IAAI;gBACJ,QAAQ;gBACR,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,IAAI,EAAE;gBACtC,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE;aACzC,CAAC;QACJ,CAAC;QACD,OAAO;YACL,IAAI;YACJ,QAAQ;YACR,MAAM,EAAE,SAAS;YACjB,OAAO,EAAE,IAAI,CAAC,IAAI,EAAE;SACrB,CAAC;IACJ,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse git status --porcelain=v2 --branch output.
|
|
3
|
+
*
|
|
4
|
+
* Format reference:
|
|
5
|
+
* - Branch headers: # branch.oid, # branch.head, # branch.upstream, # branch.ab
|
|
6
|
+
* - Ordinary changed entries: 1 <XY> <sub> <mH> <mI> <mW> <hH> <hI> <path>
|
|
7
|
+
* - Renamed/copied entries: 2 <XY> <sub> <mH> <mI> <mW> <hH> <hI> <X><score> <path><tab><origPath>
|
|
8
|
+
* - Unmerged entries: u <XY> <sub> <m1> <m2> <m3> <mW> <h1> <h2> <h3> <path>
|
|
9
|
+
* - Untracked entries: ? <path>
|
|
10
|
+
* - Ignored entries: ! <path>
|
|
11
|
+
*/
|
|
12
|
+
export interface StatusInfo {
|
|
13
|
+
branch: {
|
|
14
|
+
oid: string;
|
|
15
|
+
head: string;
|
|
16
|
+
upstream?: string;
|
|
17
|
+
ahead?: number;
|
|
18
|
+
behind?: number;
|
|
19
|
+
};
|
|
20
|
+
isDetachedHead: boolean;
|
|
21
|
+
unmergedPaths: string[];
|
|
22
|
+
stagedFiles: string[];
|
|
23
|
+
modifiedFiles: string[];
|
|
24
|
+
untrackedFiles: string[];
|
|
25
|
+
}
|
|
26
|
+
export declare function parseStatus(status: string): StatusInfo;
|
|
27
|
+
//# sourceMappingURL=status-parser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status-parser.d.ts","sourceRoot":"","sources":["../../src/parsers/status-parser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE;QACN,GAAG,EAAE,MAAM,CAAC;QACZ,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,CAAC;IACF,cAAc,EAAE,OAAO,CAAC;IACxB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,cAAc,EAAE,MAAM,EAAE,CAAC;CAC1B;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,CAgEtD"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse git status --porcelain=v2 --branch output.
|
|
3
|
+
*
|
|
4
|
+
* Format reference:
|
|
5
|
+
* - Branch headers: # branch.oid, # branch.head, # branch.upstream, # branch.ab
|
|
6
|
+
* - Ordinary changed entries: 1 <XY> <sub> <mH> <mI> <mW> <hH> <hI> <path>
|
|
7
|
+
* - Renamed/copied entries: 2 <XY> <sub> <mH> <mI> <mW> <hH> <hI> <X><score> <path><tab><origPath>
|
|
8
|
+
* - Unmerged entries: u <XY> <sub> <m1> <m2> <m3> <mW> <h1> <h2> <h3> <path>
|
|
9
|
+
* - Untracked entries: ? <path>
|
|
10
|
+
* - Ignored entries: ! <path>
|
|
11
|
+
*/
|
|
12
|
+
export function parseStatus(status) {
|
|
13
|
+
const lines = status.split('\n').filter(line => line.length > 0);
|
|
14
|
+
const result = {
|
|
15
|
+
branch: {
|
|
16
|
+
oid: '',
|
|
17
|
+
head: '',
|
|
18
|
+
},
|
|
19
|
+
isDetachedHead: false,
|
|
20
|
+
unmergedPaths: [],
|
|
21
|
+
stagedFiles: [],
|
|
22
|
+
modifiedFiles: [],
|
|
23
|
+
untrackedFiles: [],
|
|
24
|
+
};
|
|
25
|
+
for (const line of lines) {
|
|
26
|
+
// Branch headers
|
|
27
|
+
if (line.startsWith('# branch.oid ')) {
|
|
28
|
+
result.branch.oid = line.slice('# branch.oid '.length);
|
|
29
|
+
}
|
|
30
|
+
else if (line.startsWith('# branch.head ')) {
|
|
31
|
+
result.branch.head = line.slice('# branch.head '.length);
|
|
32
|
+
result.isDetachedHead = result.branch.head === '(detached)';
|
|
33
|
+
}
|
|
34
|
+
else if (line.startsWith('# branch.upstream ')) {
|
|
35
|
+
result.branch.upstream = line.slice('# branch.upstream '.length);
|
|
36
|
+
}
|
|
37
|
+
else if (line.startsWith('# branch.ab ')) {
|
|
38
|
+
const match = line.match(/# branch\.ab \+(\d+) -(\d+)/);
|
|
39
|
+
if (match) {
|
|
40
|
+
result.branch.ahead = parseInt(match[1], 10);
|
|
41
|
+
result.branch.behind = parseInt(match[2], 10);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
// Unmerged entries (conflicts)
|
|
45
|
+
else if (line.startsWith('u ')) {
|
|
46
|
+
const path = parseUnmergedLine(line);
|
|
47
|
+
if (path) {
|
|
48
|
+
result.unmergedPaths.push(path);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
// Ordinary changed entries
|
|
52
|
+
else if (line.startsWith('1 ')) {
|
|
53
|
+
const parsed = parseOrdinaryLine(line);
|
|
54
|
+
if (parsed) {
|
|
55
|
+
if (parsed.staged) {
|
|
56
|
+
result.stagedFiles.push(parsed.path);
|
|
57
|
+
}
|
|
58
|
+
if (parsed.modified) {
|
|
59
|
+
result.modifiedFiles.push(parsed.path);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
// Renamed/copied entries
|
|
64
|
+
else if (line.startsWith('2 ')) {
|
|
65
|
+
const parsed = parseRenamedLine(line);
|
|
66
|
+
if (parsed) {
|
|
67
|
+
result.stagedFiles.push(parsed.path);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
// Untracked entries
|
|
71
|
+
else if (line.startsWith('? ')) {
|
|
72
|
+
result.untrackedFiles.push(line.slice(2));
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return result;
|
|
76
|
+
}
|
|
77
|
+
function parseUnmergedLine(line) {
|
|
78
|
+
// u <XY> <sub> <m1> <m2> <m3> <mW> <h1> <h2> <h3> <path>
|
|
79
|
+
const parts = line.split(' ');
|
|
80
|
+
if (parts.length >= 11) {
|
|
81
|
+
// Path is everything after the 10th space-separated element
|
|
82
|
+
return parts.slice(10).join(' ');
|
|
83
|
+
}
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
function parseOrdinaryLine(line) {
|
|
87
|
+
// 1 <XY> <sub> <mH> <mI> <mW> <hH> <hI> <path>
|
|
88
|
+
const parts = line.split(' ');
|
|
89
|
+
if (parts.length >= 9) {
|
|
90
|
+
const xy = parts[1];
|
|
91
|
+
const path = parts.slice(8).join(' ');
|
|
92
|
+
// X is index status (staged), Y is worktree status (modified)
|
|
93
|
+
const staged = xy[0] !== '.';
|
|
94
|
+
const modified = xy[1] !== '.';
|
|
95
|
+
return { path, staged, modified };
|
|
96
|
+
}
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
function parseRenamedLine(line) {
|
|
100
|
+
// 2 <XY> <sub> <mH> <mI> <mW> <hH> <hI> <X><score> <path><tab><origPath>
|
|
101
|
+
const tabIndex = line.indexOf('\t');
|
|
102
|
+
if (tabIndex !== -1) {
|
|
103
|
+
const beforeTab = line.slice(0, tabIndex).split(' ');
|
|
104
|
+
const origPath = line.slice(tabIndex + 1);
|
|
105
|
+
const path = beforeTab[beforeTab.length - 1];
|
|
106
|
+
return { path, origPath };
|
|
107
|
+
}
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=status-parser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status-parser.js","sourceRoot":"","sources":["../../src/parsers/status-parser.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface ExecResult {
|
|
2
|
+
stdout: string;
|
|
3
|
+
success: boolean;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Execute a git command and return the output.
|
|
7
|
+
* Normalizes line endings to LF for cross-platform compatibility.
|
|
8
|
+
*/
|
|
9
|
+
export declare function execGit(args: string[], cwd?: string): ExecResult;
|
|
10
|
+
/**
|
|
11
|
+
* Check if a path exists using git rev-parse --git-path
|
|
12
|
+
*/
|
|
13
|
+
export declare function gitPathExists(gitDir: string, subpath: string): Promise<boolean>;
|
|
14
|
+
//# sourceMappingURL=exec.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exec.d.ts","sourceRoot":"","sources":["../../src/utils/exec.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;CAClB;AAED;;;GAGG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,UAAU,CA0BhE;AAED;;GAEG;AACH,wBAAsB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAmBrF"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { execSync } from 'node:child_process';
|
|
2
|
+
/**
|
|
3
|
+
* Execute a git command and return the output.
|
|
4
|
+
* Normalizes line endings to LF for cross-platform compatibility.
|
|
5
|
+
*/
|
|
6
|
+
export function execGit(args, cwd) {
|
|
7
|
+
try {
|
|
8
|
+
const result = execSync(`git ${args.join(' ')}`, {
|
|
9
|
+
cwd,
|
|
10
|
+
encoding: 'utf-8',
|
|
11
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
12
|
+
maxBuffer: 10 * 1024 * 1024, // 10MB
|
|
13
|
+
});
|
|
14
|
+
// Normalize CRLF to LF
|
|
15
|
+
const normalized = result.replace(/\r\n/g, '\n');
|
|
16
|
+
return {
|
|
17
|
+
stdout: normalized,
|
|
18
|
+
success: true,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
catch (error) {
|
|
22
|
+
if (error instanceof Error && 'stdout' in error) {
|
|
23
|
+
const stdout = error.stdout || '';
|
|
24
|
+
return {
|
|
25
|
+
stdout: stdout.replace(/\r\n/g, '\n'),
|
|
26
|
+
success: false,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
throw error;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Check if a path exists using git rev-parse --git-path
|
|
34
|
+
*/
|
|
35
|
+
export async function gitPathExists(gitDir, subpath) {
|
|
36
|
+
try {
|
|
37
|
+
const result = execGit(['rev-parse', '--git-path', subpath]);
|
|
38
|
+
if (!result.success)
|
|
39
|
+
return false;
|
|
40
|
+
const fullPath = result.stdout.trim();
|
|
41
|
+
// Use git to check if the path exists by trying to list it
|
|
42
|
+
const { existsSync } = await import('node:fs');
|
|
43
|
+
const { resolve } = await import('node:path');
|
|
44
|
+
// If the path is relative, resolve it against gitDir's parent
|
|
45
|
+
const resolvedPath = fullPath.startsWith('/') || /^[A-Za-z]:/.test(fullPath)
|
|
46
|
+
? fullPath
|
|
47
|
+
: resolve(process.cwd(), fullPath);
|
|
48
|
+
return existsSync(resolvedPath);
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=exec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exec.js","sourceRoot":"","sources":["../../src/utils/exec.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAO9C;;;GAGG;AACH,MAAM,UAAU,OAAO,CAAC,IAAc,EAAE,GAAY;IAClD,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,QAAQ,CAAC,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE;YAC/C,GAAG;YACH,QAAQ,EAAE,OAAO;YACjB,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;YAC/B,SAAS,EAAE,EAAE,GAAG,IAAI,GAAG,IAAI,EAAE,OAAO;SACrC,CAAC,CAAC;QAEH,uBAAuB;QACvB,MAAM,UAAU,GAAG,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;QAEjD,OAAO;YACL,MAAM,EAAE,UAAU;YAClB,OAAO,EAAE,IAAI;SACd,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,KAAK,IAAI,QAAQ,IAAI,KAAK,EAAE,CAAC;YAChD,MAAM,MAAM,GAAI,KAA4B,CAAC,MAAM,IAAI,EAAE,CAAC;YAC1D,OAAO;gBACL,MAAM,EAAE,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC;gBACrC,OAAO,EAAE,KAAK;aACf,CAAC;QACJ,CAAC;QACD,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,MAAc,EAAE,OAAe;IACjE,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,OAAO,CAAC,CAAC,WAAW,EAAE,YAAY,EAAE,OAAO,CAAC,CAAC,CAAC;QAC7D,IAAI,CAAC,MAAM,CAAC,OAAO;YAAE,OAAO,KAAK,CAAC;QAElC,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;QACtC,2DAA2D;QAC3D,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,CAAC;QAC/C,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,CAAC;QAE9C,8DAA8D;QAC9D,MAAM,YAAY,GAAG,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,YAAY,CAAC,IAAI,CAAC,QAAQ,CAAC;YAC1E,CAAC,CAAC,QAAQ;YACV,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,QAAQ,CAAC,CAAC;QAErC,OAAO,UAAU,CAAC,YAAY,CAAC,CAAC;IAClC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC"}
|