@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 +65 -3
- package/package.json +1 -1
- package/src/pipeline/stages/execution.ts +40 -0
- package/src/tdd/session-runner.ts +51 -0
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.
|
|
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("
|
|
19571
|
-
return "
|
|
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
|
@@ -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
|
+
}
|