@gitgov/core 1.13.0 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,798 @@
1
+ /**
2
+ * RecordStore<T> - Generic interface for record persistence
3
+ *
4
+ * Abstracts CRUD operations without assuming storage backend.
5
+ * Each implementation decides how to persist (fs, memory, db, remote).
6
+ */
7
+ interface RecordStore<T> {
8
+ /**
9
+ * Gets a record by ID
10
+ * @returns The record or null if it doesn't exist
11
+ */
12
+ get(id: string): Promise<T | null>;
13
+ /**
14
+ * Persists a record
15
+ * @param id - Unique identifier
16
+ * @param value - The record to persist
17
+ */
18
+ put(id: string, value: T): Promise<void>;
19
+ /**
20
+ * Deletes a record
21
+ * @param id - Identifier of the record to delete
22
+ */
23
+ delete(id: string): Promise<void>;
24
+ /**
25
+ * Lists all record IDs
26
+ * @returns Array of IDs
27
+ */
28
+ list(): Promise<string[]>;
29
+ /**
30
+ * Checks if a record exists
31
+ * @param id - Identifier to check
32
+ */
33
+ exists(id: string): Promise<boolean>;
34
+ }
35
+
36
+ /**
37
+ * ConfigManager Types
38
+ */
39
+ /**
40
+ * GitGovernance Configuration
41
+ * Based on config_file.md blueprint
42
+ */
43
+ type GitGovConfig = {
44
+ protocolVersion: string;
45
+ projectId: string;
46
+ projectName: string;
47
+ rootCycle: string;
48
+ state?: {
49
+ branch?: string;
50
+ sync?: {
51
+ strategy?: "manual" | "immediate" | "batched";
52
+ maxRetries?: number;
53
+ pushIntervalSeconds?: number;
54
+ batchIntervalSeconds?: number;
55
+ };
56
+ defaults?: {
57
+ pullScheduler?: {
58
+ defaultIntervalSeconds?: number;
59
+ defaultEnabled?: boolean;
60
+ defaultContinueOnNetworkError?: boolean;
61
+ defaultStopOnConflict?: boolean;
62
+ };
63
+ fileWatcher?: {
64
+ defaultDebounceMs?: number;
65
+ defaultIgnoredPatterns?: string[];
66
+ };
67
+ };
68
+ audit?: {
69
+ lastFullAuditCommit?: string;
70
+ lastFullAuditTimestamp?: string;
71
+ lastFullAuditFindingsCount?: number;
72
+ };
73
+ };
74
+ };
75
+ /**
76
+ * Audit state stored in config.json for incremental mode
77
+ */
78
+ type AuditState = {
79
+ lastFullAuditCommit: string | null;
80
+ lastFullAuditTimestamp: string | null;
81
+ lastFullAuditFindingsCount: number | null;
82
+ };
83
+ /**
84
+ * Sync configuration from config.json
85
+ */
86
+ type SyncConfig = {
87
+ strategy: "manual" | "immediate" | "batched";
88
+ maxRetries: number;
89
+ pushIntervalSeconds: number;
90
+ batchIntervalSeconds: number;
91
+ };
92
+ /**
93
+ * Sync defaults from config.json
94
+ */
95
+ type SyncDefaults = {
96
+ pullScheduler: {
97
+ defaultIntervalSeconds: number;
98
+ defaultEnabled: boolean;
99
+ defaultContinueOnNetworkError: boolean;
100
+ defaultStopOnConflict: boolean;
101
+ };
102
+ fileWatcher: {
103
+ defaultDebounceMs: number;
104
+ defaultIgnoredPatterns: string[];
105
+ };
106
+ };
107
+ /**
108
+ * Audit state update payload
109
+ */
110
+ type AuditStateUpdate = {
111
+ lastFullAuditCommit: string;
112
+ lastFullAuditTimestamp: string;
113
+ lastFullAuditFindingsCount: number;
114
+ };
115
+ /**
116
+ * IConfigManager interface
117
+ *
118
+ * Provides typed access to GitGovernance project configuration.
119
+ * Configuration is versioned in Git and shared between collaborators.
120
+ */
121
+ interface IConfigManager {
122
+ /**
123
+ * Load GitGovernance configuration
124
+ */
125
+ loadConfig(): Promise<GitGovConfig | null>;
126
+ /**
127
+ * Get root cycle from configuration
128
+ */
129
+ getRootCycle(): Promise<string | null>;
130
+ /**
131
+ * Get project information from configuration
132
+ */
133
+ getProjectInfo(): Promise<{
134
+ id: string;
135
+ name: string;
136
+ } | null>;
137
+ /**
138
+ * Get sync configuration from config.json
139
+ * Returns sync strategy and related settings with defaults
140
+ */
141
+ getSyncConfig(): Promise<SyncConfig | null>;
142
+ /**
143
+ * Get sync defaults from config.json
144
+ * Returns recommended defaults for pullScheduler and fileWatcher
145
+ */
146
+ getSyncDefaults(): Promise<SyncDefaults>;
147
+ /**
148
+ * Get audit state from config.json
149
+ * Returns last full audit commit and timestamp for incremental mode
150
+ */
151
+ getAuditState(): Promise<AuditState>;
152
+ /**
153
+ * Update audit state in config.json after a full audit
154
+ * This is used to enable incremental audits
155
+ */
156
+ updateAuditState(auditState: AuditStateUpdate): Promise<void>;
157
+ /**
158
+ * Get state branch name from configuration
159
+ */
160
+ getStateBranch(): Promise<string>;
161
+ }
162
+
163
+ /**
164
+ * SessionManager Types
165
+ */
166
+ /**
167
+ * Sync status for an actor's synchronization state.
168
+ */
169
+ type SyncStatus = {
170
+ lastSyncPush?: string;
171
+ lastSyncPull?: string;
172
+ status?: 'synced' | 'pending' | 'pulling' | 'pushing' | 'conflict';
173
+ lastError?: string;
174
+ };
175
+ /**
176
+ * State for a specific actor on this machine.
177
+ */
178
+ type ActorState = {
179
+ activeTaskId?: string | undefined;
180
+ activeCycleId?: string | undefined;
181
+ lastSync?: string;
182
+ syncStatus?: SyncStatus;
183
+ [key: string]: unknown;
184
+ };
185
+ /**
186
+ * GitGovernance Session State
187
+ * Based on session_state.md blueprint
188
+ */
189
+ type GitGovSession = {
190
+ cloud?: {
191
+ sessionToken?: string;
192
+ };
193
+ lastSession?: {
194
+ actorId: string;
195
+ timestamp: string;
196
+ };
197
+ actorState?: Record<string, ActorState>;
198
+ syncPreferences?: {
199
+ pullScheduler?: {
200
+ enabled?: boolean;
201
+ pullIntervalSeconds?: number;
202
+ continueOnNetworkError?: boolean;
203
+ stopOnConflict?: boolean;
204
+ };
205
+ fileWatcher?: {
206
+ enabled?: boolean;
207
+ debounceMs?: number;
208
+ ignoredPatterns?: string[];
209
+ };
210
+ };
211
+ };
212
+ /**
213
+ * Sync preferences update payload
214
+ */
215
+ type SyncPreferencesUpdate = {
216
+ pullScheduler?: Partial<{
217
+ enabled: boolean;
218
+ pullIntervalSeconds: number;
219
+ continueOnNetworkError: boolean;
220
+ stopOnConflict: boolean;
221
+ }>;
222
+ fileWatcher?: Partial<{
223
+ enabled: boolean;
224
+ debounceMs: number;
225
+ ignoredPatterns: string[];
226
+ }>;
227
+ };
228
+ /**
229
+ * ISessionManager interface
230
+ *
231
+ * Provides typed access to GitGovernance session state.
232
+ * Session state is ephemeral, machine-local, and NOT versioned in Git.
233
+ */
234
+ interface ISessionManager {
235
+ /**
236
+ * Load GitGovernance session state
237
+ * [EARS-B9] Auto-detects actor from .key files if no session or no actorId exists
238
+ */
239
+ loadSession(): Promise<GitGovSession | null>;
240
+ /**
241
+ * [EARS-B9] Detect actor from .key files in .gitgov/actors/
242
+ */
243
+ detectActorFromKeyFiles(): Promise<string | null>;
244
+ /**
245
+ * Get actor state for a specific actor
246
+ */
247
+ getActorState(actorId: string): Promise<ActorState | null>;
248
+ /**
249
+ * Update actor state for a specific actor
250
+ */
251
+ updateActorState(actorId: string, state: Partial<ActorState>): Promise<void>;
252
+ /**
253
+ * Get cloud session token
254
+ */
255
+ getCloudSessionToken(): Promise<string | null>;
256
+ /**
257
+ * Get sync preferences from session
258
+ */
259
+ getSyncPreferences(): Promise<GitGovSession['syncPreferences'] | null>;
260
+ /**
261
+ * Update sync preferences in .session.json
262
+ * These are local machine preferences that override project defaults
263
+ */
264
+ updateSyncPreferences(preferences: SyncPreferencesUpdate): Promise<void>;
265
+ /**
266
+ * Get last session info (last human who interacted)
267
+ */
268
+ getLastSession(): Promise<{
269
+ actorId: string;
270
+ timestamp: string;
271
+ } | null>;
272
+ }
273
+
274
+ /**
275
+ * SessionStore - Session persistence abstraction
276
+ *
277
+ * Interface for storing and retrieving local session state (.session.json).
278
+ * Session state is ephemeral, machine-local, and NOT versioned in Git.
279
+ *
280
+ * Implementations:
281
+ * - FsSessionStore: Filesystem-based (production)
282
+ * - MemorySessionStore: In-memory (tests, serverless)
283
+ */
284
+
285
+ /**
286
+ * Interface for session state persistence.
287
+ *
288
+ * Session state includes:
289
+ * - Actor state (activeTaskId, activeCycleId, syncStatus)
290
+ * - Sync preferences (pullScheduler, fileWatcher settings)
291
+ * - Cloud session tokens
292
+ * - Last session information
293
+ *
294
+ * Unlike ConfigStore, SessionStore handles ephemeral, machine-local state
295
+ * that is NOT shared between collaborators.
296
+ */
297
+ interface SessionStore {
298
+ /**
299
+ * Load session state from storage.
300
+ *
301
+ * @returns GitGovSession object or null if not found
302
+ */
303
+ loadSession(): Promise<GitGovSession | null>;
304
+ /**
305
+ * Save session state to storage.
306
+ *
307
+ * @param session - The session state to persist
308
+ */
309
+ saveSession(session: GitGovSession): Promise<void>;
310
+ /**
311
+ * Detect actor from private key files.
312
+ *
313
+ * Optional method for implementations that support actor auto-detection
314
+ * from .key files in the actors directory.
315
+ *
316
+ * @returns Actor ID (e.g., "human:camilo-v2") or null if not detectable
317
+ */
318
+ detectActorFromKeyFiles?(): Promise<string | null>;
319
+ }
320
+
321
+ /**
322
+ * ConfigStore Interface
323
+ *
324
+ * Abstraction for config.json persistence.
325
+ * Enables backend-agnostic access to GitGovernance project configuration
326
+ * (filesystem, memory for tests, or future cloud backends).
327
+ *
328
+ * NOTE: Session state (.session.json) is handled by SessionStore, not ConfigStore.
329
+ * This separation allows different backends for config (immutable, versioned)
330
+ * vs session (ephemeral, local).
331
+ */
332
+
333
+ /**
334
+ * Interface for project configuration persistence.
335
+ *
336
+ * ConfigStore manages the project config.json file which is:
337
+ * - Versioned in Git (shared between collaborators)
338
+ * - Contains project-level settings (protocolVersion, projectId, rootCycle, etc.)
339
+ * - Rarely changes after initial setup
340
+ *
341
+ * Implementations:
342
+ * - FsConfigStore: Filesystem-based (.gitgov/config.json)
343
+ * - MemoryConfigStore: In-memory for tests
344
+ *
345
+ * @example
346
+ * ```typescript
347
+ * // Production with filesystem
348
+ * const store = new FsConfigStore('/path/to/project');
349
+ * const config = await store.loadConfig();
350
+ *
351
+ * // Tests with memory
352
+ * const store = new MemoryConfigStore();
353
+ * store.setConfig({ protocolVersion: '1.0', ... });
354
+ * ```
355
+ */
356
+ interface ConfigStore {
357
+ /**
358
+ * Load project configuration from config.json
359
+ *
360
+ * @returns GitGovConfig or null if not found/invalid
361
+ */
362
+ loadConfig(): Promise<GitGovConfig | null>;
363
+ /**
364
+ * Save project configuration to config.json
365
+ *
366
+ * @param config - Configuration to persist
367
+ */
368
+ saveConfig(config: GitGovConfig): Promise<void>;
369
+ }
370
+
371
+ /**
372
+ * KeyProvider Interface
373
+ *
374
+ * Abstracts private key storage for Actor signing operations.
375
+ * Enables different backends: filesystem (development), environment variables (serverless),
376
+ * or cloud KMS (enterprise).
377
+ *
378
+ * @module key_provider
379
+ */
380
+ /**
381
+ * Error codes for KeyProvider operations.
382
+ */
383
+ type KeyProviderErrorCode = 'KEY_NOT_FOUND' | 'KEY_READ_ERROR' | 'KEY_WRITE_ERROR' | 'KEY_DELETE_ERROR' | 'INVALID_KEY_FORMAT' | 'INVALID_ACTOR_ID';
384
+ /**
385
+ * Error thrown when key operations fail.
386
+ */
387
+ declare class KeyProviderError extends Error {
388
+ readonly code: KeyProviderErrorCode;
389
+ readonly actorId?: string | undefined;
390
+ constructor(message: string, code: KeyProviderErrorCode, actorId?: string | undefined);
391
+ }
392
+ /**
393
+ * Interface for managing private key storage.
394
+ * Implementations handle the actual persistence mechanism.
395
+ *
396
+ * @example
397
+ * ```typescript
398
+ * // Filesystem backend (development)
399
+ * const provider = new FsKeyProvider({ actorsDir: '.gitgov/actors' });
400
+ *
401
+ * // Environment backend (serverless)
402
+ * const provider = new EnvKeyProvider({ prefix: 'GITGOV_KEY_' });
403
+ *
404
+ * // Usage
405
+ * const privateKey = await provider.getPrivateKey('actor:human:alice');
406
+ * if (privateKey) {
407
+ * const signature = signPayload(payload, privateKey, actorId, role);
408
+ * }
409
+ * ```
410
+ */
411
+ interface KeyProvider {
412
+ /**
413
+ * Retrieves the private key for an actor.
414
+ * @param actorId - The actor's ID (e.g., 'actor:human:alice')
415
+ * @returns The base64-encoded private key, or null if not found
416
+ */
417
+ getPrivateKey(actorId: string): Promise<string | null>;
418
+ /**
419
+ * Stores a private key for an actor.
420
+ * @param actorId - The actor's ID
421
+ * @param privateKey - The base64-encoded private key
422
+ * @throws KeyProviderError if write fails
423
+ */
424
+ setPrivateKey(actorId: string, privateKey: string): Promise<void>;
425
+ /**
426
+ * Checks if a private key exists for an actor.
427
+ * @param actorId - The actor's ID
428
+ * @returns true if key exists, false otherwise
429
+ */
430
+ hasPrivateKey(actorId: string): Promise<boolean>;
431
+ /**
432
+ * Deletes the private key for an actor.
433
+ * @param actorId - The actor's ID
434
+ * @returns true if key was deleted, false if it didn't exist
435
+ */
436
+ deletePrivateKey(actorId: string): Promise<boolean>;
437
+ }
438
+
439
+ /**
440
+ * Options for file listing.
441
+ */
442
+ type FileListOptions = {
443
+ /** Glob patterns to ignore (e.g., ['node_modules/**']) */
444
+ ignore?: string[];
445
+ /** Only return files (not directories). Default: true */
446
+ onlyFiles?: boolean;
447
+ /** Return absolute paths instead of relative. Default: false */
448
+ absolute?: boolean;
449
+ /** Maximum depth to traverse. Default: unlimited */
450
+ maxDepth?: number;
451
+ };
452
+ /**
453
+ * File statistics returned by stat().
454
+ */
455
+ type FileStats = {
456
+ /** File size in bytes */
457
+ size: number;
458
+ /** Last modification time as timestamp (ms since epoch) */
459
+ mtime: number;
460
+ /** Whether it's a file (not directory) */
461
+ isFile: boolean;
462
+ };
463
+ /**
464
+ * Options for FsFileLister.
465
+ */
466
+ type FsFileListerOptions = {
467
+ /** Base directory for all operations */
468
+ cwd: string;
469
+ };
470
+ /**
471
+ * Options for MemoryFileLister.
472
+ */
473
+ type MemoryFileListerOptions = {
474
+ /** Map of filePath -> content */
475
+ files?: Map<string, string> | Record<string, string>;
476
+ /** Map of filePath -> stats (optional, generated if not provided) */
477
+ stats?: Map<string, FileStats>;
478
+ };
479
+
480
+ /**
481
+ * FileLister Interface
482
+ *
483
+ * Abstracts file listing and reading operations for serverless compatibility.
484
+ * Enables modules like ScopeSelector and IndexerAdapter to work without
485
+ * direct filesystem dependencies.
486
+ *
487
+ * @module file_lister
488
+ */
489
+
490
+ /**
491
+ * Interface for listing and reading files.
492
+ * Abstracts filesystem operations for serverless compatibility.
493
+ *
494
+ * @example
495
+ * ```typescript
496
+ * // Filesystem backend (development/CLI)
497
+ * import { FsFileLister } from '@gitgov/core/fs';
498
+ * const lister = new FsFileLister({ cwd: '/path/to/project' });
499
+ *
500
+ * // Memory backend (testing)
501
+ * import { MemoryFileLister } from '@gitgov/core/memory';
502
+ * const lister = new MemoryFileLister({ files: { 'src/index.ts': 'code...' } });
503
+ *
504
+ * // Usage
505
+ * const files = await lister.list(['**\/*.ts']);
506
+ * const content = await lister.read('src/index.ts');
507
+ * ```
508
+ */
509
+ interface FileLister {
510
+ /**
511
+ * [EARS-FL01] Lists files matching glob patterns.
512
+ * @param patterns - Glob patterns to match (e.g., ['**\/*.ts', 'src/**'])
513
+ * @param options - Optional configuration for listing
514
+ * @returns Array of file paths relative to cwd
515
+ */
516
+ list(patterns: string[], options?: FileListOptions): Promise<string[]>;
517
+ /**
518
+ * [EARS-FL02] Checks if a file exists.
519
+ * @param filePath - Path relative to cwd
520
+ * @returns true if file exists, false otherwise
521
+ */
522
+ exists(filePath: string): Promise<boolean>;
523
+ /**
524
+ * [EARS-FL03] Reads file content as string.
525
+ * @param filePath - Path relative to cwd
526
+ * @returns File content as UTF-8 string
527
+ * @throws FileListerError if file doesn't exist or can't be read
528
+ */
529
+ read(filePath: string): Promise<string>;
530
+ /**
531
+ * [EARS-FL04] Gets file statistics.
532
+ * @param filePath - Path relative to cwd
533
+ * @returns File stats (size, mtime)
534
+ * @throws FileListerError if file doesn't exist
535
+ */
536
+ stat(filePath: string): Promise<FileStats>;
537
+ }
538
+
539
+ /**
540
+ * Type Definitions for GitModule
541
+ *
542
+ * These types define the contracts for Git operations,
543
+ * dependencies, and data structures used throughout the module.
544
+ */
545
+ /**
546
+ * Options for executing shell commands
547
+ */
548
+ type ExecOptions = {
549
+ /** Working directory for the command */
550
+ cwd?: string;
551
+ /** Additional environment variables */
552
+ env?: Record<string, string>;
553
+ /** Timeout in milliseconds */
554
+ timeout?: number;
555
+ };
556
+ /**
557
+ * Result of executing a shell command
558
+ */
559
+ type ExecResult = {
560
+ /** Exit code (0 = success) */
561
+ exitCode: number;
562
+ /** Standard output */
563
+ stdout: string;
564
+ /** Standard error output */
565
+ stderr: string;
566
+ };
567
+ /**
568
+ * Dependencies required by LocalGitModule
569
+ *
570
+ * This module uses dependency injection to allow testing with mocks
571
+ * and support different execution environments.
572
+ */
573
+ type GitModuleDependencies = {
574
+ /** Path to the Git repository root (optional, auto-detected if not provided) */
575
+ repoRoot?: string;
576
+ /** Function to execute shell commands (required) */
577
+ execCommand: (command: string, args: string[], options?: ExecOptions) => Promise<ExecResult>;
578
+ };
579
+ /**
580
+ * Options for retrieving commit history
581
+ */
582
+ type GetCommitHistoryOptions = {
583
+ /** Maximum number of commits to return */
584
+ maxCount?: number;
585
+ /** Path filter (e.g., ".gitgov/") */
586
+ pathFilter?: string;
587
+ /** Output format (default: "json") */
588
+ format?: 'json' | 'text';
589
+ };
590
+ /**
591
+ * Information about a commit in the history
592
+ */
593
+ type CommitInfo = {
594
+ /** Commit hash */
595
+ hash: string;
596
+ /** Commit message */
597
+ message: string;
598
+ /** Commit author (name <email>) */
599
+ author: string;
600
+ /** Commit date (ISO 8601) */
601
+ date: string;
602
+ /** List of modified files (optional) */
603
+ files?: string[];
604
+ };
605
+ /**
606
+ * Information about a changed file
607
+ */
608
+ type ChangedFile = {
609
+ /** Change status: A (Added), M (Modified), D (Deleted) */
610
+ status: 'A' | 'M' | 'D';
611
+ /** File path relative to repository root */
612
+ file: string;
613
+ };
614
+ /**
615
+ * Author information for commits
616
+ */
617
+ type CommitAuthor = {
618
+ /** Author name */
619
+ name: string;
620
+ /** Author email */
621
+ email: string;
622
+ };
623
+
624
+ /**
625
+ * Custom Error Classes for GitModule
626
+ *
627
+ * These errors provide typed exceptions for better error handling
628
+ * and diagnostics in the Git module operations.
629
+ */
630
+ /**
631
+ * Base error class for all Git-related errors
632
+ */
633
+ declare class GitError extends Error {
634
+ constructor(message: string);
635
+ }
636
+ /**
637
+ * Error thrown when a Git command fails
638
+ */
639
+ declare class GitCommandError extends GitError {
640
+ readonly stderr: string;
641
+ readonly stdout?: string | undefined;
642
+ readonly command?: string | undefined;
643
+ constructor(message: string, stderr?: string, command?: string | undefined, stdout?: string);
644
+ }
645
+ /**
646
+ * Error thrown when a branch does not exist
647
+ */
648
+ declare class BranchNotFoundError extends GitError {
649
+ readonly branchName: string;
650
+ constructor(branchName: string);
651
+ }
652
+ /**
653
+ * Error thrown when a file does not exist in a commit
654
+ */
655
+ declare class FileNotFoundError extends GitError {
656
+ readonly filePath: string;
657
+ readonly commitHash: string;
658
+ constructor(filePath: string, commitHash: string);
659
+ }
660
+ /**
661
+ * Error thrown when a merge conflict occurs
662
+ */
663
+ declare class MergeConflictError extends GitError {
664
+ readonly conflictedFiles: string[];
665
+ constructor(conflictedFiles: string[]);
666
+ }
667
+ /**
668
+ * Error thrown when a rebase conflict occurs
669
+ */
670
+ declare class RebaseConflictError extends GitError {
671
+ readonly conflictedFiles: string[];
672
+ constructor(conflictedFiles: string[]);
673
+ }
674
+ /**
675
+ * Error thrown when trying to continue/abort a rebase that is not in progress
676
+ */
677
+ declare class RebaseNotInProgressError extends GitError {
678
+ constructor();
679
+ }
680
+ /**
681
+ * Error thrown when trying to create a branch that already exists
682
+ */
683
+ declare class BranchAlreadyExistsError extends GitError {
684
+ readonly branchName: string;
685
+ constructor(branchName: string);
686
+ }
687
+
688
+ /**
689
+ * GitModule - Low-level Git Operations
690
+ *
691
+ * This module provides backend-agnostic access to Git operations.
692
+ *
693
+ * IMPORTANT: This module only exports the interface and types.
694
+ * For implementations, use:
695
+ * - @gitgov/core/fs for LocalGitModule (CLI-based)
696
+ * - @gitgov/core/memory for MemoryGitModule (testing)
697
+ *
698
+ * @example
699
+ * ```typescript
700
+ * // Import interface and types
701
+ * import type { IGitModule } from '@gitgov/core';
702
+ *
703
+ * // Import CLI implementation from fs entry point
704
+ * import { LocalGitModule } from '@gitgov/core/fs';
705
+ *
706
+ * // Import memory implementation from memory entry point
707
+ * import { MemoryGitModule } from '@gitgov/core/memory';
708
+ * ```
709
+ *
710
+ * @module git
711
+ */
712
+
713
+ /**
714
+ * IGitModule - Interface for Git operations
715
+ *
716
+ * Implementations:
717
+ * - LocalGitModule: Uses execCommand to run git CLI (production)
718
+ * - MemoryGitModule: In-memory mock for unit tests
719
+ * - Future: GitHubGitModule for SaaS API-based operations
720
+ *
721
+ * All methods are async to support both local CLI execution
722
+ * and future API-based implementations (GitHub REST/GraphQL).
723
+ */
724
+ interface IGitModule {
725
+ exec(command: string, args: string[], options?: ExecOptions): Promise<ExecResult>;
726
+ init(): Promise<void>;
727
+ getRepoRoot(): Promise<string>;
728
+ getCurrentBranch(): Promise<string>;
729
+ getCommitHash(ref?: string): Promise<string>;
730
+ setConfig(key: string, value: string, scope?: 'local' | 'global' | 'system'): Promise<void>;
731
+ getMergeBase(branchA: string, branchB: string): Promise<string>;
732
+ getChangedFiles(fromCommit: string, toCommit: string, pathFilter: string): Promise<ChangedFile[]>;
733
+ getStagedFiles(): Promise<string[]>;
734
+ getFileContent(commitHash: string, filePath: string): Promise<string>;
735
+ getCommitHistory(branch: string, options?: GetCommitHistoryOptions): Promise<CommitInfo[]>;
736
+ getCommitHistoryRange(fromHash: string, toHash: string, options?: GetCommitHistoryOptions): Promise<CommitInfo[]>;
737
+ getCommitMessage(commitHash: string): Promise<string>;
738
+ hasUncommittedChanges(pathFilter?: string): Promise<boolean>;
739
+ isRebaseInProgress(): Promise<boolean>;
740
+ branchExists(branchName: string): Promise<boolean>;
741
+ listRemoteBranches(remoteName: string): Promise<string[]>;
742
+ isRemoteConfigured(remoteName: string): Promise<boolean>;
743
+ getBranchRemote(branchName: string): Promise<string | null>;
744
+ getConflictedFiles(): Promise<string[]>;
745
+ checkoutBranch(branchName: string): Promise<void>;
746
+ stash(message?: string): Promise<string | null>;
747
+ stashPop(): Promise<boolean>;
748
+ stashDrop(stashHash?: string): Promise<void>;
749
+ checkoutOrphanBranch(branchName: string): Promise<void>;
750
+ fetch(remote: string): Promise<void>;
751
+ pull(remote: string, branchName: string): Promise<void>;
752
+ pullRebase(remote: string, branchName: string): Promise<void>;
753
+ resetHard(target: string): Promise<void>;
754
+ checkoutFilesFromBranch(sourceBranch: string, filePaths: string[]): Promise<void>;
755
+ add(filePaths: string[], options?: {
756
+ force?: boolean;
757
+ }): Promise<void>;
758
+ rm(filePaths: string[]): Promise<void>;
759
+ commit(message: string, author?: CommitAuthor): Promise<string>;
760
+ commitAllowEmpty(message: string, author?: CommitAuthor): Promise<string>;
761
+ push(remote: string, branchName: string): Promise<void>;
762
+ pushWithUpstream(remote: string, branchName: string): Promise<void>;
763
+ setUpstream(branchName: string, remote: string, remoteBranch: string): Promise<void>;
764
+ rebaseContinue(): Promise<string>;
765
+ rebaseAbort(): Promise<void>;
766
+ createBranch(branchName: string, startPoint?: string): Promise<void>;
767
+ rebase(targetBranch: string): Promise<void>;
768
+ }
769
+
770
+ type index_BranchAlreadyExistsError = BranchAlreadyExistsError;
771
+ declare const index_BranchAlreadyExistsError: typeof BranchAlreadyExistsError;
772
+ type index_BranchNotFoundError = BranchNotFoundError;
773
+ declare const index_BranchNotFoundError: typeof BranchNotFoundError;
774
+ type index_ChangedFile = ChangedFile;
775
+ type index_CommitAuthor = CommitAuthor;
776
+ type index_CommitInfo = CommitInfo;
777
+ type index_ExecOptions = ExecOptions;
778
+ type index_ExecResult = ExecResult;
779
+ type index_FileNotFoundError = FileNotFoundError;
780
+ declare const index_FileNotFoundError: typeof FileNotFoundError;
781
+ type index_GetCommitHistoryOptions = GetCommitHistoryOptions;
782
+ type index_GitCommandError = GitCommandError;
783
+ declare const index_GitCommandError: typeof GitCommandError;
784
+ type index_GitError = GitError;
785
+ declare const index_GitError: typeof GitError;
786
+ type index_GitModuleDependencies = GitModuleDependencies;
787
+ type index_IGitModule = IGitModule;
788
+ type index_MergeConflictError = MergeConflictError;
789
+ declare const index_MergeConflictError: typeof MergeConflictError;
790
+ type index_RebaseConflictError = RebaseConflictError;
791
+ declare const index_RebaseConflictError: typeof RebaseConflictError;
792
+ type index_RebaseNotInProgressError = RebaseNotInProgressError;
793
+ declare const index_RebaseNotInProgressError: typeof RebaseNotInProgressError;
794
+ declare namespace index {
795
+ export { index_BranchAlreadyExistsError as BranchAlreadyExistsError, index_BranchNotFoundError as BranchNotFoundError, type index_ChangedFile as ChangedFile, type index_CommitAuthor as CommitAuthor, type index_CommitInfo as CommitInfo, type index_ExecOptions as ExecOptions, type index_ExecResult as ExecResult, index_FileNotFoundError as FileNotFoundError, type index_GetCommitHistoryOptions as GetCommitHistoryOptions, index_GitCommandError as GitCommandError, index_GitError as GitError, type index_GitModuleDependencies as GitModuleDependencies, type index_IGitModule as IGitModule, index_MergeConflictError as MergeConflictError, index_RebaseConflictError as RebaseConflictError, index_RebaseNotInProgressError as RebaseNotInProgressError };
796
+ }
797
+
798
+ export { type ActorState as A, type ConfigStore as C, type ExecOptions as E, type FsFileListerOptions as F, type GitGovConfig as G, type IGitModule as I, type KeyProvider as K, type MemoryFileListerOptions as M, type RecordStore as R, type SessionStore as S, type GitGovSession as a, type GitModuleDependencies as b, type ExecResult as c, type ChangedFile as d, type GetCommitHistoryOptions as e, type CommitInfo as f, type CommitAuthor as g, type ISessionManager as h, type SyncPreferencesUpdate as i, type SyncStatus as j, type AuditState as k, type AuditStateUpdate as l, type IConfigManager as m, type SyncConfig as n, type SyncDefaults as o, KeyProviderError as p, type KeyProviderErrorCode as q, type FileListOptions as r, type FileLister as s, type FileStats as t, index as u };