@nathapp/nax 0.35.0 → 0.36.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/src/utils/git.ts CHANGED
@@ -3,6 +3,7 @@
3
3
  */
4
4
 
5
5
  import { spawn } from "bun";
6
+ import { getSafeLogger } from "../logger";
6
7
 
7
8
  /**
8
9
  * Default timeout for git subprocess calls.
@@ -126,3 +127,51 @@ export async function hasCommitsForStory(workdir: string, storyId: string, maxCo
126
127
  export function detectMergeConflict(output: string): boolean {
127
128
  return output.includes("CONFLICT") || output.includes("conflict");
128
129
  }
130
+
131
+ /**
132
+ * Auto-commit safety net.
133
+ *
134
+ * If the agent left uncommitted changes after a session, stage and commit them
135
+ * automatically. Prevents the review stage from failing with "uncommitted
136
+ * changes" errors. No-op when the working tree is clean.
137
+ *
138
+ * Used by session-runner.ts (TDD sessions), rectification-gate.ts, and
139
+ * execution.ts (single-session / test-after).
140
+ *
141
+ * @param workdir - Working directory (git repo root)
142
+ * @param stage - Log stage prefix (e.g. "tdd", "execution")
143
+ * @param role - Session role for the commit message (e.g. "implementer")
144
+ * @param storyId - Story ID for the commit message
145
+ */
146
+ export async function autoCommitIfDirty(workdir: string, stage: string, role: string, storyId: string): Promise<void> {
147
+ const logger = getSafeLogger();
148
+ try {
149
+ const statusProc = Bun.spawn(["git", "status", "--porcelain"], {
150
+ cwd: workdir,
151
+ stdout: "pipe",
152
+ stderr: "pipe",
153
+ });
154
+ const statusOutput = await new Response(statusProc.stdout).text();
155
+ await statusProc.exited;
156
+
157
+ if (!statusOutput.trim()) return;
158
+
159
+ logger?.warn(stage, `Agent did not commit after ${role} session — auto-committing`, {
160
+ role,
161
+ storyId,
162
+ dirtyFiles: statusOutput.trim().split("\n").length,
163
+ });
164
+
165
+ const addProc = Bun.spawn(["git", "add", "-A"], { cwd: workdir, stdout: "pipe", stderr: "pipe" });
166
+ await addProc.exited;
167
+
168
+ const commitProc = Bun.spawn(["git", "commit", "-m", `chore(${storyId}): auto-commit after ${role} session`], {
169
+ cwd: workdir,
170
+ stdout: "pipe",
171
+ stderr: "pipe",
172
+ });
173
+ await commitProc.exited;
174
+ } catch {
175
+ // Silently ignore — auto-commit is best-effort
176
+ }
177
+ }