@litmers/cursorflow-orchestrator 0.1.28 → 0.1.30

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/src/utils/git.ts CHANGED
@@ -132,6 +132,10 @@ function filterGitStderr(stderr: string): string {
132
132
  export function runGit(args: string[], options: GitRunOptions = {}): string {
133
133
  const { cwd, silent = false } = options;
134
134
 
135
+ if (process.env['DEBUG_GIT']) {
136
+ console.log(`[DEBUG_GIT] Running: git ${args.join(' ')} (cwd: ${cwd || process.cwd()})`);
137
+ }
138
+
135
139
  try {
136
140
  const stdioMode = silent ? 'pipe' : ['inherit', 'inherit', 'pipe'];
137
141
 
@@ -141,6 +145,13 @@ export function runGit(args: string[], options: GitRunOptions = {}): string {
141
145
  stdio: stdioMode as any,
142
146
  });
143
147
 
148
+ if (result.error) {
149
+ if (!silent) {
150
+ console.error(`[ERROR_GIT] Failed to execute git command: ${result.error.message}`);
151
+ }
152
+ throw result.error;
153
+ }
154
+
144
155
  if (!silent && result.stderr) {
145
156
  const filteredStderr = filterGitStderr(result.stderr);
146
157
  if (filteredStderr) {
@@ -149,12 +160,16 @@ export function runGit(args: string[], options: GitRunOptions = {}): string {
149
160
  }
150
161
 
151
162
  if (result.status !== 0 && !silent) {
152
- throw new Error(`Git command failed: git ${args.join(' ')}\n${result.stderr || ''}`);
163
+ const errorMsg = `Git command failed (exit code ${result.status}): git ${args.join(' ')}\n${result.stderr || ''}`;
164
+ throw new Error(errorMsg);
153
165
  }
154
166
 
155
167
  return result.stdout ? result.stdout.trim() : '';
156
168
  } catch (error) {
157
169
  if (silent) {
170
+ if (process.env['DEBUG_GIT']) {
171
+ console.error(`[DEBUG_GIT] Command failed (silent mode): ${error instanceof Error ? error.message : String(error)}`);
172
+ }
158
173
  return '';
159
174
  }
160
175
  throw error;
@@ -167,18 +182,28 @@ export function runGit(args: string[], options: GitRunOptions = {}): string {
167
182
  export function runGitResult(args: string[], options: GitRunOptions = {}): GitResult {
168
183
  const { cwd } = options;
169
184
 
185
+ if (process.env['DEBUG_GIT']) {
186
+ console.log(`[DEBUG_GIT] Running: git ${args.join(' ')} (result mode, cwd: ${cwd || process.cwd()})`);
187
+ }
188
+
170
189
  const result = spawnSync('git', args, {
171
190
  cwd: cwd || process.cwd(),
172
191
  encoding: 'utf8',
173
192
  stdio: 'pipe',
174
193
  });
175
194
 
176
- return {
195
+ const gitResult = {
177
196
  exitCode: result.status ?? 1,
178
197
  stdout: (result.stdout || '').toString().trim(),
179
198
  stderr: (result.stderr || '').toString().trim(),
180
199
  success: result.status === 0,
181
200
  };
201
+
202
+ if (process.env['DEBUG_GIT'] && !gitResult.success) {
203
+ console.error(`[DEBUG_GIT] Command failed: git ${args.join(' ')}\nstderr: ${gitResult.stderr}`);
204
+ }
205
+
206
+ return gitResult;
182
207
  }
183
208
 
184
209
  /**
@@ -829,6 +854,94 @@ export function getWorktreeForPath(targetPath: string, cwd?: string): WorktreeIn
829
854
  /**
830
855
  * Sync branch with remote (fetch + merge or rebase)
831
856
  */
857
+ /**
858
+ * Push branch to remote, creating it if it doesn't exist
859
+ * Returns success status and any error message
860
+ */
861
+ export function pushBranchSafe(branchName: string, options: { cwd?: string; force?: boolean } = {}): { success: boolean; error?: string } {
862
+ const { cwd, force = false } = options;
863
+
864
+ // Check if origin exists
865
+ if (!remoteExists('origin', { cwd })) {
866
+ return { success: false, error: 'No remote "origin" configured' };
867
+ }
868
+
869
+ const args = ['push'];
870
+ if (force) {
871
+ args.push('--force');
872
+ }
873
+ args.push('-u', 'origin', branchName);
874
+
875
+ const result = runGitResult(args, { cwd });
876
+
877
+ if (result.success) {
878
+ return { success: true };
879
+ }
880
+
881
+ return { success: false, error: result.stderr };
882
+ }
883
+
884
+ /**
885
+ * Auto-commit any uncommitted changes and push to remote
886
+ * Used for checkpoint before destructive operations
887
+ */
888
+ export function checkpointAndPush(options: {
889
+ cwd?: string;
890
+ message?: string;
891
+ branchName?: string;
892
+ } = {}): { success: boolean; committed: boolean; pushed: boolean; error?: string } {
893
+ const { cwd, message = '[cursorflow] checkpoint before clean' } = options;
894
+
895
+ let committed = false;
896
+ let pushed = false;
897
+
898
+ // Get current branch if not specified
899
+ let branchName = options.branchName;
900
+ if (!branchName) {
901
+ try {
902
+ branchName = getCurrentBranch(cwd);
903
+ } catch {
904
+ return { success: false, committed: false, pushed: false, error: 'Failed to get current branch' };
905
+ }
906
+ }
907
+
908
+ // Check for uncommitted changes
909
+ if (hasUncommittedChanges(cwd)) {
910
+ // Stage all changes
911
+ const addResult = runGitResult(['add', '-A'], { cwd });
912
+ if (!addResult.success) {
913
+ return { success: false, committed: false, pushed: false, error: `Failed to stage changes: ${addResult.stderr}` };
914
+ }
915
+
916
+ // Commit
917
+ const commitResult = runGitResult(['commit', '-m', message], { cwd });
918
+ if (!commitResult.success) {
919
+ return { success: false, committed: false, pushed: false, error: `Failed to commit: ${commitResult.stderr}` };
920
+ }
921
+ committed = true;
922
+ }
923
+
924
+ // Push to remote
925
+ const pushResult = pushBranchSafe(branchName, { cwd });
926
+ if (pushResult.success) {
927
+ pushed = true;
928
+ } else {
929
+ // Push failed but commit succeeded - partial success
930
+ if (committed) {
931
+ return { success: true, committed: true, pushed: false, error: `Commit succeeded but push failed: ${pushResult.error}` };
932
+ }
933
+ // Nothing to commit and push failed - check if there's anything to push
934
+ const localCommits = runGitResult(['rev-list', `origin/${branchName}..HEAD`], { cwd });
935
+ if (localCommits.success && localCommits.stdout.trim()) {
936
+ return { success: false, committed: false, pushed: false, error: `Push failed: ${pushResult.error}` };
937
+ }
938
+ // Nothing to push
939
+ pushed = true;
940
+ }
941
+
942
+ return { success: true, committed, pushed };
943
+ }
944
+
832
945
  export function syncWithRemote(branch: string, options: {
833
946
  cwd?: string;
834
947
  strategy?: 'merge' | 'rebase';