@vibe-validate/git 0.16.1 → 0.17.0-rc.11
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/dist/git-commands.d.ts +61 -0
- package/dist/git-commands.d.ts.map +1 -0
- package/dist/git-commands.js +80 -0
- package/dist/git-commands.js.map +1 -0
- package/dist/git-executor.d.ts +144 -0
- package/dist/git-executor.d.ts.map +1 -0
- package/dist/git-executor.js +192 -0
- package/dist/git-executor.js.map +1 -0
- package/dist/git-notes.d.ts +142 -0
- package/dist/git-notes.d.ts.map +1 -0
- package/dist/git-notes.js +251 -0
- package/dist/git-notes.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/dist/yaml-detection.d.ts.map +1 -1
- package/dist/yaml-detection.js +1 -0
- package/dist/yaml-detection.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Git Command Utilities
|
|
3
|
+
*
|
|
4
|
+
* High-level git operations built on top of the secure git-executor.
|
|
5
|
+
* These functions provide convenient access to common git commands.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Check if the current directory is inside a git repository
|
|
9
|
+
* @returns true if inside a git repository, false otherwise
|
|
10
|
+
*/
|
|
11
|
+
export declare function isGitRepository(): boolean;
|
|
12
|
+
/**
|
|
13
|
+
* Get the path to the .git directory
|
|
14
|
+
* @returns The absolute path to the .git directory
|
|
15
|
+
* @throws Error if not in a git repository
|
|
16
|
+
*/
|
|
17
|
+
export declare function getGitDir(): string;
|
|
18
|
+
/**
|
|
19
|
+
* Get the root directory of the git repository
|
|
20
|
+
* @returns The absolute path to the repository root
|
|
21
|
+
* @throws Error if not in a git repository
|
|
22
|
+
*/
|
|
23
|
+
export declare function getRepositoryRoot(): string;
|
|
24
|
+
/**
|
|
25
|
+
* Get the current branch name
|
|
26
|
+
* @returns The name of the current branch
|
|
27
|
+
* @throws Error if not on a branch (detached HEAD)
|
|
28
|
+
*/
|
|
29
|
+
export declare function getCurrentBranch(): string;
|
|
30
|
+
/**
|
|
31
|
+
* Get the commit SHA of HEAD
|
|
32
|
+
* @returns The full SHA of the current commit
|
|
33
|
+
* @throws Error if not in a git repository or HEAD is invalid
|
|
34
|
+
*/
|
|
35
|
+
export declare function getHeadCommitSha(): string;
|
|
36
|
+
/**
|
|
37
|
+
* Get the tree hash of the current HEAD commit
|
|
38
|
+
* @returns The tree hash of HEAD
|
|
39
|
+
* @throws Error if not in a git repository or HEAD is invalid
|
|
40
|
+
*/
|
|
41
|
+
export declare function getHeadTreeSha(): string;
|
|
42
|
+
/**
|
|
43
|
+
* Verify that a git reference exists
|
|
44
|
+
* @param ref - The reference to verify (branch, tag, commit SHA, etc.)
|
|
45
|
+
* @returns true if the reference exists, false otherwise
|
|
46
|
+
*/
|
|
47
|
+
export declare function verifyRef(ref: string): boolean;
|
|
48
|
+
/**
|
|
49
|
+
* Verify that a git reference exists (alternate form for backwards compatibility)
|
|
50
|
+
* @param ref - The reference to verify
|
|
51
|
+
* @returns The SHA of the reference if it exists
|
|
52
|
+
* @throws Error if the reference doesn't exist
|
|
53
|
+
*/
|
|
54
|
+
export declare function verifyRefOrThrow(ref: string): string;
|
|
55
|
+
/**
|
|
56
|
+
* Check if git notes exist for a specific ref
|
|
57
|
+
* @param notesRef - The notes reference to check (e.g., 'refs/notes/vibe-validate/validate')
|
|
58
|
+
* @returns true if the notes ref exists, false otherwise
|
|
59
|
+
*/
|
|
60
|
+
export declare function hasNotesRef(notesRef: string): boolean;
|
|
61
|
+
//# sourceMappingURL=git-commands.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git-commands.d.ts","sourceRoot":"","sources":["../src/git-commands.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH;;;GAGG;AACH,wBAAgB,eAAe,IAAI,OAAO,CAEzC;AAED;;;;GAIG;AACH,wBAAgB,SAAS,IAAI,MAAM,CAElC;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC;AAED;;;;GAIG;AACH,wBAAgB,cAAc,IAAI,MAAM,CAEvC;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAE9C;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAErD"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Git Command Utilities
|
|
3
|
+
*
|
|
4
|
+
* High-level git operations built on top of the secure git-executor.
|
|
5
|
+
* These functions provide convenient access to common git commands.
|
|
6
|
+
*/
|
|
7
|
+
import { execGitCommand, tryGitCommand } from './git-executor.js';
|
|
8
|
+
/**
|
|
9
|
+
* Check if the current directory is inside a git repository
|
|
10
|
+
* @returns true if inside a git repository, false otherwise
|
|
11
|
+
*/
|
|
12
|
+
export function isGitRepository() {
|
|
13
|
+
return tryGitCommand(['rev-parse', '--is-inside-work-tree']);
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Get the path to the .git directory
|
|
17
|
+
* @returns The absolute path to the .git directory
|
|
18
|
+
* @throws Error if not in a git repository
|
|
19
|
+
*/
|
|
20
|
+
export function getGitDir() {
|
|
21
|
+
return execGitCommand(['rev-parse', '--git-dir']);
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Get the root directory of the git repository
|
|
25
|
+
* @returns The absolute path to the repository root
|
|
26
|
+
* @throws Error if not in a git repository
|
|
27
|
+
*/
|
|
28
|
+
export function getRepositoryRoot() {
|
|
29
|
+
return execGitCommand(['rev-parse', '--show-toplevel']);
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Get the current branch name
|
|
33
|
+
* @returns The name of the current branch
|
|
34
|
+
* @throws Error if not on a branch (detached HEAD)
|
|
35
|
+
*/
|
|
36
|
+
export function getCurrentBranch() {
|
|
37
|
+
return execGitCommand(['rev-parse', '--abbrev-ref', 'HEAD']);
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Get the commit SHA of HEAD
|
|
41
|
+
* @returns The full SHA of the current commit
|
|
42
|
+
* @throws Error if not in a git repository or HEAD is invalid
|
|
43
|
+
*/
|
|
44
|
+
export function getHeadCommitSha() {
|
|
45
|
+
return execGitCommand(['rev-parse', 'HEAD']);
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Get the tree hash of the current HEAD commit
|
|
49
|
+
* @returns The tree hash of HEAD
|
|
50
|
+
* @throws Error if not in a git repository or HEAD is invalid
|
|
51
|
+
*/
|
|
52
|
+
export function getHeadTreeSha() {
|
|
53
|
+
return execGitCommand(['rev-parse', 'HEAD^{tree}']);
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Verify that a git reference exists
|
|
57
|
+
* @param ref - The reference to verify (branch, tag, commit SHA, etc.)
|
|
58
|
+
* @returns true if the reference exists, false otherwise
|
|
59
|
+
*/
|
|
60
|
+
export function verifyRef(ref) {
|
|
61
|
+
return tryGitCommand(['rev-parse', '--verify', ref]);
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Verify that a git reference exists (alternate form for backwards compatibility)
|
|
65
|
+
* @param ref - The reference to verify
|
|
66
|
+
* @returns The SHA of the reference if it exists
|
|
67
|
+
* @throws Error if the reference doesn't exist
|
|
68
|
+
*/
|
|
69
|
+
export function verifyRefOrThrow(ref) {
|
|
70
|
+
return execGitCommand(['rev-parse', '--verify', ref]);
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Check if git notes exist for a specific ref
|
|
74
|
+
* @param notesRef - The notes reference to check (e.g., 'refs/notes/vibe-validate/validate')
|
|
75
|
+
* @returns true if the notes ref exists, false otherwise
|
|
76
|
+
*/
|
|
77
|
+
export function hasNotesRef(notesRef) {
|
|
78
|
+
return tryGitCommand(['rev-parse', '--verify', notesRef]);
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=git-commands.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git-commands.js","sourceRoot":"","sources":["../src/git-commands.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAElE;;;GAGG;AACH,MAAM,UAAU,eAAe;IAC7B,OAAO,aAAa,CAAC,CAAC,WAAW,EAAE,uBAAuB,CAAC,CAAC,CAAC;AAC/D,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,SAAS;IACvB,OAAO,cAAc,CAAC,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC,CAAC;AACpD,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,iBAAiB;IAC/B,OAAO,cAAc,CAAC,CAAC,WAAW,EAAE,iBAAiB,CAAC,CAAC,CAAC;AAC1D,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,gBAAgB;IAC9B,OAAO,cAAc,CAAC,CAAC,WAAW,EAAE,cAAc,EAAE,MAAM,CAAC,CAAC,CAAC;AAC/D,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,gBAAgB;IAC9B,OAAO,cAAc,CAAC,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC,CAAC;AAC/C,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,cAAc;IAC5B,OAAO,cAAc,CAAC,CAAC,WAAW,EAAE,aAAa,CAAC,CAAC,CAAC;AACtD,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,SAAS,CAAC,GAAW;IACnC,OAAO,aAAa,CAAC,CAAC,WAAW,EAAE,UAAU,EAAE,GAAG,CAAC,CAAC,CAAC;AACvD,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAAC,GAAW;IAC1C,OAAO,cAAc,CAAC,CAAC,WAAW,EAAE,UAAU,EAAE,GAAG,CAAC,CAAC,CAAC;AACxD,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,WAAW,CAAC,QAAgB;IAC1C,OAAO,aAAa,CAAC,CAAC,WAAW,EAAE,UAAU,EAAE,QAAQ,CAAC,CAAC,CAAC;AAC5D,CAAC"}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Secure Git Command Execution
|
|
3
|
+
*
|
|
4
|
+
* This module provides a centralized, secure way to execute git commands.
|
|
5
|
+
* ALL git command execution in vibe-validate MUST go through this module.
|
|
6
|
+
*
|
|
7
|
+
* Security principles:
|
|
8
|
+
* 1. Use spawnSync with array arguments (never string interpolation)
|
|
9
|
+
* 2. Validate all user-controlled inputs
|
|
10
|
+
* 3. No shell piping or heredocs
|
|
11
|
+
* 4. Explicit argument construction
|
|
12
|
+
*
|
|
13
|
+
* @packageDocumentation
|
|
14
|
+
*/
|
|
15
|
+
export interface GitExecutionOptions {
|
|
16
|
+
/**
|
|
17
|
+
* Maximum time to wait for git command (ms)
|
|
18
|
+
* @default 30000
|
|
19
|
+
*/
|
|
20
|
+
timeout?: number;
|
|
21
|
+
/**
|
|
22
|
+
* Encoding for stdout/stderr
|
|
23
|
+
* @default 'utf8'
|
|
24
|
+
*/
|
|
25
|
+
encoding?: BufferEncoding;
|
|
26
|
+
/**
|
|
27
|
+
* Standard input to pass to command
|
|
28
|
+
*/
|
|
29
|
+
stdin?: string;
|
|
30
|
+
/**
|
|
31
|
+
* Whether to ignore errors (return empty string instead of throwing)
|
|
32
|
+
* @default false
|
|
33
|
+
*/
|
|
34
|
+
ignoreErrors?: boolean;
|
|
35
|
+
/**
|
|
36
|
+
* Whether to suppress stderr
|
|
37
|
+
* @default false
|
|
38
|
+
*/
|
|
39
|
+
suppressStderr?: boolean;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Result of a git command execution
|
|
43
|
+
*/
|
|
44
|
+
export interface GitExecutionResult {
|
|
45
|
+
/** Standard output from the command */
|
|
46
|
+
stdout: string;
|
|
47
|
+
/** Standard error from the command */
|
|
48
|
+
stderr: string;
|
|
49
|
+
/** Exit code (0 for success) */
|
|
50
|
+
exitCode: number;
|
|
51
|
+
/** Whether the command succeeded */
|
|
52
|
+
success: boolean;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Error thrown when a git command fails
|
|
56
|
+
*/
|
|
57
|
+
export interface GitCommandError extends Error {
|
|
58
|
+
/** Exit code from the git command */
|
|
59
|
+
exitCode: number;
|
|
60
|
+
/** Standard error output */
|
|
61
|
+
stderr: string;
|
|
62
|
+
/** Standard output */
|
|
63
|
+
stdout: string;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Execute a git command securely using spawnSync with array arguments
|
|
67
|
+
*
|
|
68
|
+
* This is the ONLY function that should execute git commands. All other
|
|
69
|
+
* git operations must go through this function or higher-level abstractions.
|
|
70
|
+
*
|
|
71
|
+
* @param args - Git command arguments (e.g., ['rev-parse', '--git-dir'])
|
|
72
|
+
* @param options - Execution options
|
|
73
|
+
* @returns Execution result
|
|
74
|
+
* @throws Error if command fails and ignoreErrors is false
|
|
75
|
+
*
|
|
76
|
+
* @example
|
|
77
|
+
* ```typescript
|
|
78
|
+
* // Get git directory
|
|
79
|
+
* const result = executeGitCommand(['rev-parse', '--git-dir']);
|
|
80
|
+
* console.log(result.stdout); // ".git"
|
|
81
|
+
*
|
|
82
|
+
* // Add note with stdin
|
|
83
|
+
* executeGitCommand(
|
|
84
|
+
* ['notes', '--ref=vibe-validate/validate', 'add', '-f', '-F', '-', treeHash],
|
|
85
|
+
* { stdin: noteContent }
|
|
86
|
+
* );
|
|
87
|
+
* ```
|
|
88
|
+
*/
|
|
89
|
+
export declare function executeGitCommand(args: string[], options?: GitExecutionOptions): GitExecutionResult;
|
|
90
|
+
/**
|
|
91
|
+
* Execute a git command and return stdout, throwing on error
|
|
92
|
+
*
|
|
93
|
+
* Convenience wrapper for the common case of executing a git command
|
|
94
|
+
* and only caring about the stdout result.
|
|
95
|
+
*
|
|
96
|
+
* @param args - Git command arguments
|
|
97
|
+
* @param options - Execution options
|
|
98
|
+
* @returns Command stdout, trimmed
|
|
99
|
+
* @throws Error if command fails
|
|
100
|
+
*/
|
|
101
|
+
export declare function execGitCommand(args: string[], options?: GitExecutionOptions): string;
|
|
102
|
+
/**
|
|
103
|
+
* Execute a git command and return success status (no throw)
|
|
104
|
+
*
|
|
105
|
+
* Useful for checking if a git operation would succeed without
|
|
106
|
+
* handling exceptions.
|
|
107
|
+
*
|
|
108
|
+
* @param args - Git command arguments
|
|
109
|
+
* @param options - Execution options
|
|
110
|
+
* @returns true if command succeeded, false otherwise
|
|
111
|
+
*/
|
|
112
|
+
export declare function tryGitCommand(args: string[], options?: GitExecutionOptions): boolean;
|
|
113
|
+
/**
|
|
114
|
+
* Validate that a string is safe to use as a git ref
|
|
115
|
+
*
|
|
116
|
+
* Git refs must:
|
|
117
|
+
* - Not contain special shell characters
|
|
118
|
+
* - Not start with a dash (looks like an option)
|
|
119
|
+
* - Not contain path traversal sequences
|
|
120
|
+
* - Match git's ref format rules
|
|
121
|
+
*
|
|
122
|
+
* @param ref - The ref to validate
|
|
123
|
+
* @throws Error if ref is invalid
|
|
124
|
+
*/
|
|
125
|
+
export declare function validateGitRef(ref: string): void;
|
|
126
|
+
/**
|
|
127
|
+
* Validate that a string is safe to use as a git notes ref
|
|
128
|
+
*
|
|
129
|
+
* Notes refs have additional restrictions beyond normal refs.
|
|
130
|
+
*
|
|
131
|
+
* @param notesRef - The notes ref to validate
|
|
132
|
+
* @throws Error if notes ref is invalid
|
|
133
|
+
*/
|
|
134
|
+
export declare function validateNotesRef(notesRef: string): void;
|
|
135
|
+
/**
|
|
136
|
+
* Validate that a string is safe to use as a tree hash
|
|
137
|
+
*
|
|
138
|
+
* Tree hashes must be valid git object IDs (40-char hex or abbreviated).
|
|
139
|
+
*
|
|
140
|
+
* @param treeHash - The tree hash to validate
|
|
141
|
+
* @throws Error if tree hash is invalid
|
|
142
|
+
*/
|
|
143
|
+
export declare function validateTreeHash(treeHash: string): void;
|
|
144
|
+
//# sourceMappingURL=git-executor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git-executor.d.ts","sourceRoot":"","sources":["../src/git-executor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AASH,MAAM,WAAW,mBAAmB;IAClC;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;;OAGG;IACH,QAAQ,CAAC,EAAE,cAAc,CAAC;IAE1B;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;;OAGG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IAEvB;;;OAGG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,uCAAuC;IACvC,MAAM,EAAE,MAAM,CAAC;IACf,sCAAsC;IACtC,MAAM,EAAE,MAAM,CAAC;IACf,gCAAgC;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,oCAAoC;IACpC,OAAO,EAAE,OAAO,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,eAAgB,SAAQ,KAAK;IAC5C,qCAAqC;IACrC,QAAQ,EAAE,MAAM,CAAC;IACjB,4BAA4B;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,sBAAsB;IACtB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,GAAE,mBAAwB,GAChC,kBAAkB,CAqDpB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,GAAE,mBAAwB,GAAG,MAAM,CAGxF;AAED;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,GAAE,mBAAwB,GAAG,OAAO,CAGxF;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CA6BhD;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAWvD;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAcvD"}
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Secure Git Command Execution
|
|
3
|
+
*
|
|
4
|
+
* This module provides a centralized, secure way to execute git commands.
|
|
5
|
+
* ALL git command execution in vibe-validate MUST go through this module.
|
|
6
|
+
*
|
|
7
|
+
* Security principles:
|
|
8
|
+
* 1. Use spawnSync with array arguments (never string interpolation)
|
|
9
|
+
* 2. Validate all user-controlled inputs
|
|
10
|
+
* 3. No shell piping or heredocs
|
|
11
|
+
* 4. Explicit argument construction
|
|
12
|
+
*
|
|
13
|
+
* @packageDocumentation
|
|
14
|
+
*/
|
|
15
|
+
import { spawnSync } from 'node:child_process';
|
|
16
|
+
/**
|
|
17
|
+
* Standard options for git command execution
|
|
18
|
+
*/
|
|
19
|
+
const GIT_TIMEOUT = 30000; // 30 seconds
|
|
20
|
+
/**
|
|
21
|
+
* Execute a git command securely using spawnSync with array arguments
|
|
22
|
+
*
|
|
23
|
+
* This is the ONLY function that should execute git commands. All other
|
|
24
|
+
* git operations must go through this function or higher-level abstractions.
|
|
25
|
+
*
|
|
26
|
+
* @param args - Git command arguments (e.g., ['rev-parse', '--git-dir'])
|
|
27
|
+
* @param options - Execution options
|
|
28
|
+
* @returns Execution result
|
|
29
|
+
* @throws Error if command fails and ignoreErrors is false
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```typescript
|
|
33
|
+
* // Get git directory
|
|
34
|
+
* const result = executeGitCommand(['rev-parse', '--git-dir']);
|
|
35
|
+
* console.log(result.stdout); // ".git"
|
|
36
|
+
*
|
|
37
|
+
* // Add note with stdin
|
|
38
|
+
* executeGitCommand(
|
|
39
|
+
* ['notes', '--ref=vibe-validate/validate', 'add', '-f', '-F', '-', treeHash],
|
|
40
|
+
* { stdin: noteContent }
|
|
41
|
+
* );
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
export function executeGitCommand(args, options = {}) {
|
|
45
|
+
const { timeout = GIT_TIMEOUT, encoding = 'utf8', stdin, ignoreErrors = false, suppressStderr = false, } = options;
|
|
46
|
+
// Validate arguments
|
|
47
|
+
if (!Array.isArray(args) || args.length === 0) {
|
|
48
|
+
throw new Error('Git command arguments must be a non-empty array');
|
|
49
|
+
}
|
|
50
|
+
// Build spawn options
|
|
51
|
+
const spawnOptions = {
|
|
52
|
+
encoding,
|
|
53
|
+
timeout,
|
|
54
|
+
maxBuffer: 10 * 1024 * 1024, // 10MB buffer
|
|
55
|
+
};
|
|
56
|
+
// Configure stdio
|
|
57
|
+
if (stdin !== undefined) {
|
|
58
|
+
spawnOptions.input = stdin;
|
|
59
|
+
spawnOptions.stdio = ['pipe', 'pipe', suppressStderr ? 'ignore' : 'pipe'];
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
spawnOptions.stdio = ['ignore', 'pipe', suppressStderr ? 'ignore' : 'pipe'];
|
|
63
|
+
}
|
|
64
|
+
// Execute command
|
|
65
|
+
const result = spawnSync('git', args, spawnOptions);
|
|
66
|
+
const stdout = (result.stdout?.toString() || '').trim();
|
|
67
|
+
const stderr = (result.stderr?.toString() || '').trim();
|
|
68
|
+
const exitCode = result.status ?? 1;
|
|
69
|
+
const success = exitCode === 0;
|
|
70
|
+
// Handle errors
|
|
71
|
+
if (success || ignoreErrors) {
|
|
72
|
+
return {
|
|
73
|
+
stdout,
|
|
74
|
+
stderr,
|
|
75
|
+
exitCode,
|
|
76
|
+
success,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
const errorMessage = stderr || stdout || 'Git command failed';
|
|
80
|
+
const error = new Error(`Git command failed: git ${args.join(' ')}\n${errorMessage}`);
|
|
81
|
+
error.exitCode = exitCode;
|
|
82
|
+
error.stderr = stderr;
|
|
83
|
+
error.stdout = stdout;
|
|
84
|
+
throw error;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Execute a git command and return stdout, throwing on error
|
|
88
|
+
*
|
|
89
|
+
* Convenience wrapper for the common case of executing a git command
|
|
90
|
+
* and only caring about the stdout result.
|
|
91
|
+
*
|
|
92
|
+
* @param args - Git command arguments
|
|
93
|
+
* @param options - Execution options
|
|
94
|
+
* @returns Command stdout, trimmed
|
|
95
|
+
* @throws Error if command fails
|
|
96
|
+
*/
|
|
97
|
+
export function execGitCommand(args, options = {}) {
|
|
98
|
+
const result = executeGitCommand(args, options);
|
|
99
|
+
return result.stdout;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Execute a git command and return success status (no throw)
|
|
103
|
+
*
|
|
104
|
+
* Useful for checking if a git operation would succeed without
|
|
105
|
+
* handling exceptions.
|
|
106
|
+
*
|
|
107
|
+
* @param args - Git command arguments
|
|
108
|
+
* @param options - Execution options
|
|
109
|
+
* @returns true if command succeeded, false otherwise
|
|
110
|
+
*/
|
|
111
|
+
export function tryGitCommand(args, options = {}) {
|
|
112
|
+
const result = executeGitCommand(args, { ...options, ignoreErrors: true });
|
|
113
|
+
return result.success;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Validate that a string is safe to use as a git ref
|
|
117
|
+
*
|
|
118
|
+
* Git refs must:
|
|
119
|
+
* - Not contain special shell characters
|
|
120
|
+
* - Not start with a dash (looks like an option)
|
|
121
|
+
* - Not contain path traversal sequences
|
|
122
|
+
* - Match git's ref format rules
|
|
123
|
+
*
|
|
124
|
+
* @param ref - The ref to validate
|
|
125
|
+
* @throws Error if ref is invalid
|
|
126
|
+
*/
|
|
127
|
+
export function validateGitRef(ref) {
|
|
128
|
+
if (typeof ref !== 'string' || ref.length === 0) {
|
|
129
|
+
throw new Error('Git ref must be a non-empty string');
|
|
130
|
+
}
|
|
131
|
+
// Check for shell special characters
|
|
132
|
+
if (/[;&|`$(){}[\]<>!\\"]/.test(ref)) {
|
|
133
|
+
throw new Error(`Invalid git ref: contains shell special characters: ${ref}`);
|
|
134
|
+
}
|
|
135
|
+
// Check for leading dash (looks like an option)
|
|
136
|
+
if (ref.startsWith('-')) {
|
|
137
|
+
throw new Error(`Invalid git ref: starts with dash: ${ref}`);
|
|
138
|
+
}
|
|
139
|
+
// Check for path traversal
|
|
140
|
+
if (ref.includes('..') || ref.includes('//')) {
|
|
141
|
+
throw new Error(`Invalid git ref: contains path traversal: ${ref}`);
|
|
142
|
+
}
|
|
143
|
+
// Check for null bytes
|
|
144
|
+
if (ref.includes('\0')) {
|
|
145
|
+
throw new Error('Invalid git ref: contains null byte');
|
|
146
|
+
}
|
|
147
|
+
// Check for newlines (could break command)
|
|
148
|
+
if (ref.includes('\n') || ref.includes('\r')) {
|
|
149
|
+
throw new Error('Invalid git ref: contains newline');
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Validate that a string is safe to use as a git notes ref
|
|
154
|
+
*
|
|
155
|
+
* Notes refs have additional restrictions beyond normal refs.
|
|
156
|
+
*
|
|
157
|
+
* @param notesRef - The notes ref to validate
|
|
158
|
+
* @throws Error if notes ref is invalid
|
|
159
|
+
*/
|
|
160
|
+
export function validateNotesRef(notesRef) {
|
|
161
|
+
validateGitRef(notesRef);
|
|
162
|
+
// Notes refs should follow refs/notes/* pattern or short form
|
|
163
|
+
// Short form: 'vibe-validate/validate' → 'refs/notes/vibe-validate/validate'
|
|
164
|
+
if (!notesRef.startsWith('refs/notes/') && notesRef.includes('/')) {
|
|
165
|
+
// Short form is valid, but must not contain spaces
|
|
166
|
+
if (/\s/.test(notesRef)) {
|
|
167
|
+
throw new Error(`Invalid notes ref: contains whitespace: ${notesRef}`);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Validate that a string is safe to use as a tree hash
|
|
173
|
+
*
|
|
174
|
+
* Tree hashes must be valid git object IDs (40-char hex or abbreviated).
|
|
175
|
+
*
|
|
176
|
+
* @param treeHash - The tree hash to validate
|
|
177
|
+
* @throws Error if tree hash is invalid
|
|
178
|
+
*/
|
|
179
|
+
export function validateTreeHash(treeHash) {
|
|
180
|
+
if (typeof treeHash !== 'string' || treeHash.length === 0) {
|
|
181
|
+
throw new Error('Tree hash must be a non-empty string');
|
|
182
|
+
}
|
|
183
|
+
// Must be hex characters only
|
|
184
|
+
if (!/^[0-9a-f]+$/.test(treeHash)) {
|
|
185
|
+
throw new Error(`Invalid tree hash: must be hexadecimal: ${treeHash}`);
|
|
186
|
+
}
|
|
187
|
+
// Must be reasonable length (4-40 chars for abbreviated or full hash)
|
|
188
|
+
if (treeHash.length < 4 || treeHash.length > 40) {
|
|
189
|
+
throw new Error(`Invalid tree hash: invalid length: ${treeHash}`);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
//# sourceMappingURL=git-executor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git-executor.js","sourceRoot":"","sources":["../src/git-executor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Git Notes Operations
|
|
3
|
+
*
|
|
4
|
+
* High-level abstraction for git notes operations. All notes-related
|
|
5
|
+
* commands in vibe-validate must use these functions.
|
|
6
|
+
*
|
|
7
|
+
* @packageDocumentation
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Add or update a git note
|
|
11
|
+
*
|
|
12
|
+
* @param notesRef - The notes reference (e.g., 'vibe-validate/validate')
|
|
13
|
+
* @param object - The git object to attach the note to (tree hash, commit SHA, etc.)
|
|
14
|
+
* @param content - The note content
|
|
15
|
+
* @param force - Whether to overwrite existing note
|
|
16
|
+
* @returns true if note was added successfully
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```typescript
|
|
20
|
+
* addNote('vibe-validate/validate', treeHash, noteContent, true);
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export declare function addNote(notesRef: string, object: string, content: string, force?: boolean): boolean;
|
|
24
|
+
/**
|
|
25
|
+
* Read a git note
|
|
26
|
+
*
|
|
27
|
+
* @param notesRef - The notes reference
|
|
28
|
+
* @param object - The git object to read the note from
|
|
29
|
+
* @returns The note content, or null if no note exists
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```typescript
|
|
33
|
+
* const note = readNote('vibe-validate/validate', treeHash);
|
|
34
|
+
* if (note) {
|
|
35
|
+
* console.log('Note content:', note);
|
|
36
|
+
* }
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
export declare function readNote(notesRef: string, object: string): string | null;
|
|
40
|
+
/**
|
|
41
|
+
* Remove a git note
|
|
42
|
+
*
|
|
43
|
+
* @param notesRef - The notes reference
|
|
44
|
+
* @param object - The git object to remove the note from
|
|
45
|
+
* @returns true if note was removed, false if it didn't exist
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* ```typescript
|
|
49
|
+
* const removed = removeNote('vibe-validate/validate', treeHash);
|
|
50
|
+
* console.log(removed ? 'Removed' : 'Did not exist');
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
export declare function removeNote(notesRef: string, object: string): boolean;
|
|
54
|
+
/**
|
|
55
|
+
* List all notes in a notes reference
|
|
56
|
+
*
|
|
57
|
+
* @param notesRef - The notes reference
|
|
58
|
+
* @returns Array of [object, content] pairs, or empty array if no notes
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* ```typescript
|
|
62
|
+
* const notes = listNotes('vibe-validate/validate');
|
|
63
|
+
* for (const [treeHash, content] of notes) {
|
|
64
|
+
* console.log(`${treeHash}: ${content}`);
|
|
65
|
+
* }
|
|
66
|
+
* ```
|
|
67
|
+
*/
|
|
68
|
+
export declare function listNotes(notesRef: string): Array<[string, string]>;
|
|
69
|
+
/**
|
|
70
|
+
* Check if a note exists
|
|
71
|
+
*
|
|
72
|
+
* @param notesRef - The notes reference
|
|
73
|
+
* @param object - The git object to check
|
|
74
|
+
* @returns true if note exists, false otherwise
|
|
75
|
+
*
|
|
76
|
+
* @example
|
|
77
|
+
* ```typescript
|
|
78
|
+
* if (hasNote('vibe-validate/validate', treeHash)) {
|
|
79
|
+
* console.log('Note exists');
|
|
80
|
+
* }
|
|
81
|
+
* ```
|
|
82
|
+
*/
|
|
83
|
+
export declare function hasNote(notesRef: string, object: string): boolean;
|
|
84
|
+
/**
|
|
85
|
+
* List all refs under a notes namespace
|
|
86
|
+
*
|
|
87
|
+
* This is useful for finding all notes under a particular path,
|
|
88
|
+
* such as all run cache entries under refs/notes/vibe-validate/run/
|
|
89
|
+
*
|
|
90
|
+
* @param notesPath - The notes path (e.g., 'refs/notes/vibe-validate/run')
|
|
91
|
+
* @returns Array of full ref names
|
|
92
|
+
*
|
|
93
|
+
* @example
|
|
94
|
+
* ```typescript
|
|
95
|
+
* const refs = listNotesRefs('refs/notes/vibe-validate/run');
|
|
96
|
+
* for (const ref of refs) {
|
|
97
|
+
* console.log('Found note ref:', ref);
|
|
98
|
+
* }
|
|
99
|
+
* ```
|
|
100
|
+
*/
|
|
101
|
+
export declare function listNotesRefs(notesPath: string): string[];
|
|
102
|
+
/**
|
|
103
|
+
* Remove all notes refs under a namespace
|
|
104
|
+
*
|
|
105
|
+
* This is used for bulk cleanup operations, such as pruning all
|
|
106
|
+
* run cache entries under a tree hash.
|
|
107
|
+
*
|
|
108
|
+
* SECURITY: This function validates each ref before deletion to prevent
|
|
109
|
+
* accidental deletion of non-notes refs.
|
|
110
|
+
*
|
|
111
|
+
* @param notesPath - The notes path (e.g., 'refs/notes/vibe-validate/run/abc123')
|
|
112
|
+
* @returns Number of refs deleted
|
|
113
|
+
*
|
|
114
|
+
* @example
|
|
115
|
+
* ```typescript
|
|
116
|
+
* const deleted = removeNotesRefs('refs/notes/vibe-validate/run/abc123');
|
|
117
|
+
* console.log(`Deleted ${deleted} refs`);
|
|
118
|
+
* ```
|
|
119
|
+
*/
|
|
120
|
+
export declare function removeNotesRefs(notesPath: string): number;
|
|
121
|
+
/**
|
|
122
|
+
* Check if a notes ref exists
|
|
123
|
+
*
|
|
124
|
+
* @param notesRef - The notes reference
|
|
125
|
+
* @returns true if the notes ref exists, false otherwise
|
|
126
|
+
*
|
|
127
|
+
* @example
|
|
128
|
+
* ```typescript
|
|
129
|
+
* if (hasNotesRef('vibe-validate/validate')) {
|
|
130
|
+
* console.log('Notes ref exists');
|
|
131
|
+
* }
|
|
132
|
+
* ```
|
|
133
|
+
*/
|
|
134
|
+
export declare function hasNotesRef(notesRef: string): boolean;
|
|
135
|
+
/**
|
|
136
|
+
* Get the commit SHA that a notes ref points to
|
|
137
|
+
*
|
|
138
|
+
* @param notesRef - The notes reference
|
|
139
|
+
* @returns The commit SHA, or null if ref doesn't exist
|
|
140
|
+
*/
|
|
141
|
+
export declare function getNotesRefSha(notesRef: string): string | null;
|
|
142
|
+
//# sourceMappingURL=git-notes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git-notes.d.ts","sourceRoot":"","sources":["../src/git-notes.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AASH;;;;;;;;;;;;;GAaG;AACH,wBAAgB,OAAO,CACrB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EACf,KAAK,GAAE,OAAe,GACrB,OAAO,CAiBT;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAUxE;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAOpE;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CA4BnE;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAOjE;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,CAczD;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAgCzD;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAWrD;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAa9D"}
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Git Notes Operations
|
|
3
|
+
*
|
|
4
|
+
* High-level abstraction for git notes operations. All notes-related
|
|
5
|
+
* commands in vibe-validate must use these functions.
|
|
6
|
+
*
|
|
7
|
+
* @packageDocumentation
|
|
8
|
+
*/
|
|
9
|
+
import { executeGitCommand, tryGitCommand, validateNotesRef, validateTreeHash, } from './git-executor.js';
|
|
10
|
+
/**
|
|
11
|
+
* Add or update a git note
|
|
12
|
+
*
|
|
13
|
+
* @param notesRef - The notes reference (e.g., 'vibe-validate/validate')
|
|
14
|
+
* @param object - The git object to attach the note to (tree hash, commit SHA, etc.)
|
|
15
|
+
* @param content - The note content
|
|
16
|
+
* @param force - Whether to overwrite existing note
|
|
17
|
+
* @returns true if note was added successfully
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```typescript
|
|
21
|
+
* addNote('vibe-validate/validate', treeHash, noteContent, true);
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
export function addNote(notesRef, object, content, force = false) {
|
|
25
|
+
validateNotesRef(notesRef);
|
|
26
|
+
validateTreeHash(object);
|
|
27
|
+
const args = ['notes', `--ref=${notesRef}`, 'add'];
|
|
28
|
+
if (force) {
|
|
29
|
+
args.push('-f');
|
|
30
|
+
}
|
|
31
|
+
args.push('-F', '-', object);
|
|
32
|
+
const result = executeGitCommand(args, {
|
|
33
|
+
stdin: content,
|
|
34
|
+
ignoreErrors: true,
|
|
35
|
+
suppressStderr: true,
|
|
36
|
+
});
|
|
37
|
+
return result.success;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Read a git note
|
|
41
|
+
*
|
|
42
|
+
* @param notesRef - The notes reference
|
|
43
|
+
* @param object - The git object to read the note from
|
|
44
|
+
* @returns The note content, or null if no note exists
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```typescript
|
|
48
|
+
* const note = readNote('vibe-validate/validate', treeHash);
|
|
49
|
+
* if (note) {
|
|
50
|
+
* console.log('Note content:', note);
|
|
51
|
+
* }
|
|
52
|
+
* ```
|
|
53
|
+
*/
|
|
54
|
+
export function readNote(notesRef, object) {
|
|
55
|
+
validateNotesRef(notesRef);
|
|
56
|
+
validateTreeHash(object);
|
|
57
|
+
const result = executeGitCommand(['notes', `--ref=${notesRef}`, 'show', object], {
|
|
58
|
+
ignoreErrors: true,
|
|
59
|
+
suppressStderr: true,
|
|
60
|
+
});
|
|
61
|
+
return result.success ? result.stdout : null;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Remove a git note
|
|
65
|
+
*
|
|
66
|
+
* @param notesRef - The notes reference
|
|
67
|
+
* @param object - The git object to remove the note from
|
|
68
|
+
* @returns true if note was removed, false if it didn't exist
|
|
69
|
+
*
|
|
70
|
+
* @example
|
|
71
|
+
* ```typescript
|
|
72
|
+
* const removed = removeNote('vibe-validate/validate', treeHash);
|
|
73
|
+
* console.log(removed ? 'Removed' : 'Did not exist');
|
|
74
|
+
* ```
|
|
75
|
+
*/
|
|
76
|
+
export function removeNote(notesRef, object) {
|
|
77
|
+
validateNotesRef(notesRef);
|
|
78
|
+
validateTreeHash(object);
|
|
79
|
+
return tryGitCommand(['notes', `--ref=${notesRef}`, 'remove', object], {
|
|
80
|
+
suppressStderr: true,
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* List all notes in a notes reference
|
|
85
|
+
*
|
|
86
|
+
* @param notesRef - The notes reference
|
|
87
|
+
* @returns Array of [object, content] pairs, or empty array if no notes
|
|
88
|
+
*
|
|
89
|
+
* @example
|
|
90
|
+
* ```typescript
|
|
91
|
+
* const notes = listNotes('vibe-validate/validate');
|
|
92
|
+
* for (const [treeHash, content] of notes) {
|
|
93
|
+
* console.log(`${treeHash}: ${content}`);
|
|
94
|
+
* }
|
|
95
|
+
* ```
|
|
96
|
+
*/
|
|
97
|
+
export function listNotes(notesRef) {
|
|
98
|
+
validateNotesRef(notesRef);
|
|
99
|
+
// Get list of objects that have notes
|
|
100
|
+
const objectsResult = executeGitCommand(['notes', `--ref=${notesRef}`, 'list'], {
|
|
101
|
+
ignoreErrors: true,
|
|
102
|
+
suppressStderr: true,
|
|
103
|
+
});
|
|
104
|
+
if (!objectsResult.success || !objectsResult.stdout) {
|
|
105
|
+
return [];
|
|
106
|
+
}
|
|
107
|
+
const notes = [];
|
|
108
|
+
// Parse "note_sha object_sha" pairs
|
|
109
|
+
for (const line of objectsResult.stdout.split('\n')) {
|
|
110
|
+
const [, objectSha] = line.split(/\s+/);
|
|
111
|
+
if (!objectSha)
|
|
112
|
+
continue;
|
|
113
|
+
// Read the note content
|
|
114
|
+
const content = readNote(notesRef, objectSha);
|
|
115
|
+
if (content !== null) {
|
|
116
|
+
notes.push([objectSha, content]);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return notes;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Check if a note exists
|
|
123
|
+
*
|
|
124
|
+
* @param notesRef - The notes reference
|
|
125
|
+
* @param object - The git object to check
|
|
126
|
+
* @returns true if note exists, false otherwise
|
|
127
|
+
*
|
|
128
|
+
* @example
|
|
129
|
+
* ```typescript
|
|
130
|
+
* if (hasNote('vibe-validate/validate', treeHash)) {
|
|
131
|
+
* console.log('Note exists');
|
|
132
|
+
* }
|
|
133
|
+
* ```
|
|
134
|
+
*/
|
|
135
|
+
export function hasNote(notesRef, object) {
|
|
136
|
+
validateNotesRef(notesRef);
|
|
137
|
+
validateTreeHash(object);
|
|
138
|
+
return tryGitCommand(['notes', `--ref=${notesRef}`, 'show', object], {
|
|
139
|
+
suppressStderr: true,
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* List all refs under a notes namespace
|
|
144
|
+
*
|
|
145
|
+
* This is useful for finding all notes under a particular path,
|
|
146
|
+
* such as all run cache entries under refs/notes/vibe-validate/run/
|
|
147
|
+
*
|
|
148
|
+
* @param notesPath - The notes path (e.g., 'refs/notes/vibe-validate/run')
|
|
149
|
+
* @returns Array of full ref names
|
|
150
|
+
*
|
|
151
|
+
* @example
|
|
152
|
+
* ```typescript
|
|
153
|
+
* const refs = listNotesRefs('refs/notes/vibe-validate/run');
|
|
154
|
+
* for (const ref of refs) {
|
|
155
|
+
* console.log('Found note ref:', ref);
|
|
156
|
+
* }
|
|
157
|
+
* ```
|
|
158
|
+
*/
|
|
159
|
+
export function listNotesRefs(notesPath) {
|
|
160
|
+
// Normalize path
|
|
161
|
+
const fullPath = notesPath.startsWith('refs/') ? notesPath : `refs/notes/${notesPath}`;
|
|
162
|
+
const result = executeGitCommand(['for-each-ref', '--format=%(refname)', fullPath], { ignoreErrors: true, suppressStderr: true });
|
|
163
|
+
if (!result.success || !result.stdout) {
|
|
164
|
+
return [];
|
|
165
|
+
}
|
|
166
|
+
return result.stdout.split('\n').filter(Boolean);
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Remove all notes refs under a namespace
|
|
170
|
+
*
|
|
171
|
+
* This is used for bulk cleanup operations, such as pruning all
|
|
172
|
+
* run cache entries under a tree hash.
|
|
173
|
+
*
|
|
174
|
+
* SECURITY: This function validates each ref before deletion to prevent
|
|
175
|
+
* accidental deletion of non-notes refs.
|
|
176
|
+
*
|
|
177
|
+
* @param notesPath - The notes path (e.g., 'refs/notes/vibe-validate/run/abc123')
|
|
178
|
+
* @returns Number of refs deleted
|
|
179
|
+
*
|
|
180
|
+
* @example
|
|
181
|
+
* ```typescript
|
|
182
|
+
* const deleted = removeNotesRefs('refs/notes/vibe-validate/run/abc123');
|
|
183
|
+
* console.log(`Deleted ${deleted} refs`);
|
|
184
|
+
* ```
|
|
185
|
+
*/
|
|
186
|
+
export function removeNotesRefs(notesPath) {
|
|
187
|
+
// Normalize path
|
|
188
|
+
const fullPath = notesPath.startsWith('refs/') ? notesPath : `refs/notes/${notesPath}`;
|
|
189
|
+
// Security: Only allow deletion under refs/notes/vibe-validate/
|
|
190
|
+
if (!fullPath.startsWith('refs/notes/vibe-validate/')) {
|
|
191
|
+
throw new Error(`Refusing to delete refs outside vibe-validate namespace: ${fullPath}`);
|
|
192
|
+
}
|
|
193
|
+
// Get list of refs
|
|
194
|
+
const refs = listNotesRefs(fullPath);
|
|
195
|
+
let deleted = 0;
|
|
196
|
+
for (const ref of refs) {
|
|
197
|
+
// Double-check each ref is under the expected namespace
|
|
198
|
+
if (!ref.startsWith('refs/notes/vibe-validate/')) {
|
|
199
|
+
console.warn(`Skipping ref outside vibe-validate namespace: ${ref}`);
|
|
200
|
+
continue;
|
|
201
|
+
}
|
|
202
|
+
const success = tryGitCommand(['update-ref', '-d', ref], {
|
|
203
|
+
suppressStderr: true,
|
|
204
|
+
});
|
|
205
|
+
if (success) {
|
|
206
|
+
deleted++;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
return deleted;
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Check if a notes ref exists
|
|
213
|
+
*
|
|
214
|
+
* @param notesRef - The notes reference
|
|
215
|
+
* @returns true if the notes ref exists, false otherwise
|
|
216
|
+
*
|
|
217
|
+
* @example
|
|
218
|
+
* ```typescript
|
|
219
|
+
* if (hasNotesRef('vibe-validate/validate')) {
|
|
220
|
+
* console.log('Notes ref exists');
|
|
221
|
+
* }
|
|
222
|
+
* ```
|
|
223
|
+
*/
|
|
224
|
+
export function hasNotesRef(notesRef) {
|
|
225
|
+
validateNotesRef(notesRef);
|
|
226
|
+
// Convert short form to full form if needed
|
|
227
|
+
const fullRef = notesRef.startsWith('refs/')
|
|
228
|
+
? notesRef
|
|
229
|
+
: `refs/notes/${notesRef}`;
|
|
230
|
+
return tryGitCommand(['rev-parse', '--verify', fullRef], {
|
|
231
|
+
suppressStderr: true,
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Get the commit SHA that a notes ref points to
|
|
236
|
+
*
|
|
237
|
+
* @param notesRef - The notes reference
|
|
238
|
+
* @returns The commit SHA, or null if ref doesn't exist
|
|
239
|
+
*/
|
|
240
|
+
export function getNotesRefSha(notesRef) {
|
|
241
|
+
validateNotesRef(notesRef);
|
|
242
|
+
const fullRef = notesRef.startsWith('refs/')
|
|
243
|
+
? notesRef
|
|
244
|
+
: `refs/notes/${notesRef}`;
|
|
245
|
+
const result = executeGitCommand(['rev-parse', '--verify', fullRef], {
|
|
246
|
+
ignoreErrors: true,
|
|
247
|
+
suppressStderr: true,
|
|
248
|
+
});
|
|
249
|
+
return result.success ? result.stdout : null;
|
|
250
|
+
}
|
|
251
|
+
//# sourceMappingURL=git-notes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git-notes.js","sourceRoot":"","sources":["../src/git-notes.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -11,4 +11,7 @@ export { BranchSyncChecker, checkBranchSync, type SyncCheckResult, type SyncChec
|
|
|
11
11
|
export { PostPRMergeCleanup, cleanupMergedBranches, type CleanupResult, type CleanupOptions } from './post-merge-cleanup.js';
|
|
12
12
|
export { encodeRunCacheKey } from './cache-key.js';
|
|
13
13
|
export { extractYamlContent, extractYamlWithPreamble } from './yaml-detection.js';
|
|
14
|
+
export { isGitRepository, getGitDir, getRepositoryRoot, getCurrentBranch, getHeadCommitSha, getHeadTreeSha, verifyRef, verifyRefOrThrow, hasNotesRef } from './git-commands.js';
|
|
15
|
+
export { executeGitCommand, execGitCommand, tryGitCommand, validateGitRef, validateNotesRef, validateTreeHash, type GitExecutionOptions, type GitExecutionResult } from './git-executor.js';
|
|
16
|
+
export { addNote, readNote, removeNote, listNotes, hasNote, listNotesRefs, removeNotesRefs, getNotesRefSha } from './git-notes.js';
|
|
14
17
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EACL,cAAc,EACd,eAAe,EACf,qBAAqB,EACtB,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EACL,iBAAiB,EACjB,eAAe,EACf,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACtB,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EACL,kBAAkB,EAClB,qBAAqB,EACrB,KAAK,aAAa,EAClB,KAAK,cAAc,EACpB,MAAM,yBAAyB,CAAC;AAGjC,OAAO,EACL,iBAAiB,EAClB,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EACL,kBAAkB,EAClB,uBAAuB,EACxB,MAAM,qBAAqB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EACL,cAAc,EACd,eAAe,EACf,qBAAqB,EACtB,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EACL,iBAAiB,EACjB,eAAe,EACf,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACtB,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EACL,kBAAkB,EAClB,qBAAqB,EACrB,KAAK,aAAa,EAClB,KAAK,cAAc,EACpB,MAAM,yBAAyB,CAAC;AAGjC,OAAO,EACL,iBAAiB,EAClB,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EACL,kBAAkB,EAClB,uBAAuB,EACxB,MAAM,qBAAqB,CAAC;AAG7B,OAAO,EACL,eAAe,EACf,SAAS,EACT,iBAAiB,EACjB,gBAAgB,EAChB,gBAAgB,EAChB,cAAc,EACd,SAAS,EACT,gBAAgB,EAChB,WAAW,EACZ,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EACL,iBAAiB,EACjB,cAAc,EACd,aAAa,EACb,cAAc,EACd,gBAAgB,EAChB,gBAAgB,EAChB,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EACxB,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EACL,OAAO,EACP,QAAQ,EACR,UAAU,EACV,SAAS,EACT,OAAO,EACP,aAAa,EACb,eAAe,EACf,cAAc,EACf,MAAM,gBAAgB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -16,4 +16,10 @@ export { PostPRMergeCleanup, cleanupMergedBranches } from './post-merge-cleanup.
|
|
|
16
16
|
export { encodeRunCacheKey } from './cache-key.js';
|
|
17
17
|
// YAML output detection
|
|
18
18
|
export { extractYamlContent, extractYamlWithPreamble } from './yaml-detection.js';
|
|
19
|
+
// Git command utilities (standardized rev-parse operations)
|
|
20
|
+
export { isGitRepository, getGitDir, getRepositoryRoot, getCurrentBranch, getHeadCommitSha, getHeadTreeSha, verifyRef, verifyRefOrThrow, hasNotesRef } from './git-commands.js';
|
|
21
|
+
// Secure git command execution (low-level - use high-level APIs when possible)
|
|
22
|
+
export { executeGitCommand, execGitCommand, tryGitCommand, validateGitRef, validateNotesRef, validateTreeHash } from './git-executor.js';
|
|
23
|
+
// Git notes operations (high-level abstraction)
|
|
24
|
+
export { addNote, readNote, removeNote, listNotes, hasNote, listNotesRefs, removeNotesRefs, getNotesRefSha } from './git-notes.js';
|
|
19
25
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,uDAAuD;AACvD,OAAO,EACL,cAAc,EACd,eAAe,EACf,qBAAqB,EACtB,MAAM,gBAAgB,CAAC;AAExB,6CAA6C;AAC7C,OAAO,EACL,iBAAiB,EACjB,eAAe,EAGhB,MAAM,kBAAkB,CAAC;AAE1B,8CAA8C;AAC9C,OAAO,EACL,kBAAkB,EAClB,qBAAqB,EAGtB,MAAM,yBAAyB,CAAC;AAEjC,qCAAqC;AACrC,OAAO,EACL,iBAAiB,EAClB,MAAM,gBAAgB,CAAC;AAExB,wBAAwB;AACxB,OAAO,EACL,kBAAkB,EAClB,uBAAuB,EACxB,MAAM,qBAAqB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,uDAAuD;AACvD,OAAO,EACL,cAAc,EACd,eAAe,EACf,qBAAqB,EACtB,MAAM,gBAAgB,CAAC;AAExB,6CAA6C;AAC7C,OAAO,EACL,iBAAiB,EACjB,eAAe,EAGhB,MAAM,kBAAkB,CAAC;AAE1B,8CAA8C;AAC9C,OAAO,EACL,kBAAkB,EAClB,qBAAqB,EAGtB,MAAM,yBAAyB,CAAC;AAEjC,qCAAqC;AACrC,OAAO,EACL,iBAAiB,EAClB,MAAM,gBAAgB,CAAC;AAExB,wBAAwB;AACxB,OAAO,EACL,kBAAkB,EAClB,uBAAuB,EACxB,MAAM,qBAAqB,CAAC;AAE7B,4DAA4D;AAC5D,OAAO,EACL,eAAe,EACf,SAAS,EACT,iBAAiB,EACjB,gBAAgB,EAChB,gBAAgB,EAChB,cAAc,EACd,SAAS,EACT,gBAAgB,EAChB,WAAW,EACZ,MAAM,mBAAmB,CAAC;AAE3B,+EAA+E;AAC/E,OAAO,EACL,iBAAiB,EACjB,cAAc,EACd,aAAa,EACb,cAAc,EACd,gBAAgB,EAChB,gBAAgB,EAGjB,MAAM,mBAAmB,CAAC;AAE3B,gDAAgD;AAChD,OAAO,EACL,OAAO,EACP,QAAQ,EACR,UAAU,EACV,SAAS,EACT,OAAO,EACP,aAAa,EACb,eAAe,EACf,cAAc,EACf,MAAM,gBAAgB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"yaml-detection.d.ts","sourceRoot":"","sources":["../src/yaml-detection.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;
|
|
1
|
+
{"version":3,"file":"yaml-detection.d.ts","sourceRoot":"","sources":["../src/yaml-detection.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAgCH;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAGhE;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAWjG"}
|
package/dist/yaml-detection.js
CHANGED
|
@@ -43,6 +43,7 @@
|
|
|
43
43
|
* - `"---\ntitle: Post\n---\nContent"` → matches, captures `"---\ntitle: Post\n"` (stops at trailing `---`)
|
|
44
44
|
* - `"no yaml"` → no match
|
|
45
45
|
*/
|
|
46
|
+
// eslint-disable-next-line security/detect-unsafe-regex -- Safe: Parses controlled YAML frontmatter from command output (not user input), no ReDoS risk
|
|
46
47
|
const YAML_OUTPUT_PATTERN = /(?:^|\r?\n)(---\r?\n(?:(?!---(?:\r?\n|$))[\s\S])*)/;
|
|
47
48
|
/**
|
|
48
49
|
* Extract YAML output content from command output
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"yaml-detection.js","sourceRoot":"","sources":["../src/yaml-detection.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,MAAM,mBAAmB,GAAG,oDAAoD,CAAC;AAEjF;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,UAAU,kBAAkB,CAAC,MAAc;IAC/C,MAAM,KAAK,GAAG,mBAAmB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC/C,OAAO,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AACjC,CAAC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,UAAU,uBAAuB,CAAC,MAAc;IACpD,MAAM,KAAK,GAAG,mBAAmB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC/C,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,WAAW,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;IAC7B,MAAM,cAAc,GAAG,KAAK,CAAC,KAAK,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC;IAC5E,MAAM,QAAQ,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,cAAc,CAAC,CAAC,IAAI,EAAE,CAAC;IAE5D,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,CAAC;AACzC,CAAC"}
|
|
1
|
+
{"version":3,"file":"yaml-detection.js","sourceRoot":"","sources":["../src/yaml-detection.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wJAAwJ;AACxJ,MAAM,mBAAmB,GAAG,oDAAoD,CAAC;AAEjF;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,UAAU,kBAAkB,CAAC,MAAc;IAC/C,MAAM,KAAK,GAAG,mBAAmB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC/C,OAAO,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AACjC,CAAC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,UAAU,uBAAuB,CAAC,MAAc;IACpD,MAAM,KAAK,GAAG,mBAAmB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC/C,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,WAAW,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;IAC7B,MAAM,cAAc,GAAG,KAAK,CAAC,KAAK,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC;IAC5E,MAAM,QAAQ,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,cAAc,CAAC,CAAC,IAAI,EAAE,CAAC;IAE5D,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,CAAC;AACzC,CAAC"}
|
package/package.json
CHANGED