@nathapp/nax 0.31.0 → 0.31.1

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/nax.js CHANGED
@@ -19505,7 +19505,7 @@ var package_default;
19505
19505
  var init_package = __esm(() => {
19506
19506
  package_default = {
19507
19507
  name: "@nathapp/nax",
19508
- version: "0.31.0",
19508
+ version: "0.31.1",
19509
19509
  description: "AI Coding Agent Orchestrator \u2014 loops until done",
19510
19510
  type: "module",
19511
19511
  bin: {
@@ -19567,8 +19567,8 @@ var init_version = __esm(() => {
19567
19567
  NAX_VERSION = package_default.version;
19568
19568
  NAX_COMMIT = (() => {
19569
19569
  try {
19570
- if (/^[0-9a-f]{6,10}$/.test("6b2cc85"))
19571
- return "6b2cc85";
19570
+ if (/^[0-9a-f]{6,10}$/.test("ab045bf"))
19571
+ return "ab045bf";
19572
19572
  } catch {}
19573
19573
  try {
19574
19574
  const result = Bun.spawnSync(["git", "rev-parse", "--short", "HEAD"], {
@@ -24001,6 +24001,7 @@ async function runTddSession(role, agent, story, config2, workdir, modelTier, be
24001
24001
  if (!result.success && result.pid) {
24002
24002
  await cleanupProcessTree(result.pid);
24003
24003
  }
24004
+ await autoCommitIfDirty(workdir, role, story.id);
24004
24005
  let isolation;
24005
24006
  if (!skipIsolation) {
24006
24007
  if (role === "test-writer") {
@@ -24047,6 +24048,38 @@ async function runTddSession(role, agent, story, config2, workdir, modelTier, be
24047
24048
  estimatedCost: result.estimatedCost
24048
24049
  };
24049
24050
  }
24051
+ async function autoCommitIfDirty(workdir, role, storyId) {
24052
+ const logger = getLogger();
24053
+ try {
24054
+ const statusProc = Bun.spawn(["git", "status", "--porcelain"], {
24055
+ cwd: workdir,
24056
+ stdout: "pipe",
24057
+ stderr: "pipe"
24058
+ });
24059
+ const statusOutput = await new Response(statusProc.stdout).text();
24060
+ await statusProc.exited;
24061
+ if (!statusOutput.trim())
24062
+ return;
24063
+ logger.warn("tdd", `Agent did not commit after ${role} session \u2014 auto-committing`, {
24064
+ role,
24065
+ storyId,
24066
+ dirtyFiles: statusOutput.trim().split(`
24067
+ `).length
24068
+ });
24069
+ const addProc = Bun.spawn(["git", "add", "-A"], {
24070
+ cwd: workdir,
24071
+ stdout: "pipe",
24072
+ stderr: "pipe"
24073
+ });
24074
+ await addProc.exited;
24075
+ const commitProc = Bun.spawn(["git", "commit", "-m", `chore(${storyId}): auto-commit after ${role} session`], {
24076
+ cwd: workdir,
24077
+ stdout: "pipe",
24078
+ stderr: "pipe"
24079
+ });
24080
+ await commitProc.exited;
24081
+ } catch {}
24082
+ }
24050
24083
  var init_session_runner = __esm(() => {
24051
24084
  init_config();
24052
24085
  init_logger2();
@@ -24497,6 +24530,34 @@ function routeTddFailure(failureCategory, isLiteMode, ctx, reviewReason) {
24497
24530
  reason: reviewReason || "Three-session TDD requires review"
24498
24531
  };
24499
24532
  }
24533
+ async function autoCommitIfDirty2(workdir, role, storyId) {
24534
+ try {
24535
+ const statusProc = Bun.spawn(["git", "status", "--porcelain"], {
24536
+ cwd: workdir,
24537
+ stdout: "pipe",
24538
+ stderr: "pipe"
24539
+ });
24540
+ const statusOutput = await new Response(statusProc.stdout).text();
24541
+ await statusProc.exited;
24542
+ if (!statusOutput.trim())
24543
+ return;
24544
+ const logger = getLogger();
24545
+ logger.warn("execution", `Agent did not commit after ${role} session \u2014 auto-committing`, {
24546
+ role,
24547
+ storyId,
24548
+ dirtyFiles: statusOutput.trim().split(`
24549
+ `).length
24550
+ });
24551
+ const addProc = Bun.spawn(["git", "add", "-A"], { cwd: workdir, stdout: "pipe", stderr: "pipe" });
24552
+ await addProc.exited;
24553
+ const commitProc = Bun.spawn(["git", "commit", "-m", `chore(${storyId}): auto-commit after ${role} session`], {
24554
+ cwd: workdir,
24555
+ stdout: "pipe",
24556
+ stderr: "pipe"
24557
+ });
24558
+ await commitProc.exited;
24559
+ } catch {}
24560
+ }
24500
24561
  var executionStage, _executionDeps;
24501
24562
  var init_execution = __esm(() => {
24502
24563
  init_agents();
@@ -24578,6 +24639,7 @@ var init_execution = __esm(() => {
24578
24639
  dangerouslySkipPermissions: ctx.config.execution.dangerouslySkipPermissions
24579
24640
  });
24580
24641
  ctx.agentResult = result;
24642
+ await autoCommitIfDirty2(ctx.workdir, "single-session", ctx.story.id);
24581
24643
  const combinedOutput = (result.output ?? "") + (result.stderr ?? "");
24582
24644
  if (_executionDeps.detectMergeConflict(combinedOutput) && ctx.interaction && isTriggerEnabled("merge-conflict", ctx.config)) {
24583
24645
  const shouldProceed = await _executionDeps.checkMergeConflict({ featureName: ctx.prd.feature, storyId: ctx.story.id }, ctx.config, ctx.interaction);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nathapp/nax",
3
- "version": "0.31.0",
3
+ "version": "0.31.1",
4
4
  "description": "AI Coding Agent Orchestrator \u2014 loops until done",
5
5
  "type": "module",
6
6
  "bin": {
@@ -199,6 +199,9 @@ export const executionStage: PipelineStage = {
199
199
 
200
200
  ctx.agentResult = result;
201
201
 
202
+ // BUG-058: Auto-commit if agent left uncommitted changes (single-session/test-after)
203
+ await autoCommitIfDirty(ctx.workdir, "single-session", ctx.story.id);
204
+
202
205
  // merge-conflict trigger: detect CONFLICT markers in agent output
203
206
  const combinedOutput = (result.output ?? "") + (result.stderr ?? "");
204
207
  if (
@@ -267,3 +270,40 @@ export const _executionDeps = {
267
270
  isAmbiguousOutput,
268
271
  checkStoryAmbiguity,
269
272
  };
273
+
274
+ /**
275
+ * BUG-058: Auto-commit safety net for single-session/test-after.
276
+ * Mirrors the same function in tdd/session-runner.ts for three-session TDD.
277
+ */
278
+ async function autoCommitIfDirty(workdir: string, role: string, storyId: string): Promise<void> {
279
+ try {
280
+ const statusProc = Bun.spawn(["git", "status", "--porcelain"], {
281
+ cwd: workdir,
282
+ stdout: "pipe",
283
+ stderr: "pipe",
284
+ });
285
+ const statusOutput = await new Response(statusProc.stdout).text();
286
+ await statusProc.exited;
287
+
288
+ if (!statusOutput.trim()) return;
289
+
290
+ const logger = getLogger();
291
+ logger.warn("execution", `Agent did not commit after ${role} session — auto-committing`, {
292
+ role,
293
+ storyId,
294
+ dirtyFiles: statusOutput.trim().split("\n").length,
295
+ });
296
+
297
+ const addProc = Bun.spawn(["git", "add", "-A"], { cwd: workdir, stdout: "pipe", stderr: "pipe" });
298
+ await addProc.exited;
299
+
300
+ const commitProc = Bun.spawn(["git", "commit", "-m", `chore(${storyId}): auto-commit after ${role} session`], {
301
+ cwd: workdir,
302
+ stdout: "pipe",
303
+ stderr: "pipe",
304
+ });
305
+ await commitProc.exited;
306
+ } catch {
307
+ // Silently ignore — auto-commit is best-effort
308
+ }
309
+ }
@@ -129,6 +129,9 @@ export async function runTddSession(
129
129
  await cleanupProcessTree(result.pid);
130
130
  }
131
131
 
132
+ // BUG-058: Auto-commit if agent left uncommitted changes
133
+ await autoCommitIfDirty(workdir, role, story.id);
134
+
132
135
  // Check isolation based on role and skipIsolation flag.
133
136
  let isolation: IsolationCheck | undefined;
134
137
  if (!skipIsolation) {
@@ -181,3 +184,51 @@ export async function runTddSession(
181
184
  estimatedCost: result.estimatedCost,
182
185
  };
183
186
  }
187
+
188
+ /**
189
+ * BUG-058: Auto-commit safety net.
190
+ *
191
+ * If the agent left uncommitted changes, stage and commit them automatically.
192
+ * This prevents the review stage from failing with "uncommitted changes" errors.
193
+ * Only triggers when the agent forgot — if tree is clean, this is a no-op.
194
+ */
195
+ async function autoCommitIfDirty(workdir: string, role: string, storyId: string): Promise<void> {
196
+ const logger = getLogger();
197
+
198
+ // Check if working tree is dirty
199
+ try {
200
+ const statusProc = Bun.spawn(["git", "status", "--porcelain"], {
201
+ cwd: workdir,
202
+ stdout: "pipe",
203
+ stderr: "pipe",
204
+ });
205
+ const statusOutput = await new Response(statusProc.stdout).text();
206
+ await statusProc.exited;
207
+
208
+ if (!statusOutput.trim()) return; // Clean tree, nothing to do
209
+
210
+ logger.warn("tdd", `Agent did not commit after ${role} session — auto-committing`, {
211
+ role,
212
+ storyId,
213
+ dirtyFiles: statusOutput.trim().split("\n").length,
214
+ });
215
+
216
+ // Stage all changes
217
+ const addProc = Bun.spawn(["git", "add", "-A"], {
218
+ cwd: workdir,
219
+ stdout: "pipe",
220
+ stderr: "pipe",
221
+ });
222
+ await addProc.exited;
223
+
224
+ // Commit with descriptive message
225
+ const commitProc = Bun.spawn(["git", "commit", "-m", `chore(${storyId}): auto-commit after ${role} session`], {
226
+ cwd: workdir,
227
+ stdout: "pipe",
228
+ stderr: "pipe",
229
+ });
230
+ await commitProc.exited;
231
+ } catch {
232
+ // Silently ignore — auto-commit is best-effort
233
+ }
234
+ }