@nathapp/nax 0.64.0-canary.2 → 0.64.0-canary.4
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 +234 -146
- package/package.json +1 -1
package/dist/nax.js
CHANGED
|
@@ -3660,7 +3660,8 @@ class SpawnAcpSession {
|
|
|
3660
3660
|
return {
|
|
3661
3661
|
messages: [{ role: "assistant", content: errorContent }],
|
|
3662
3662
|
stopReason: "error",
|
|
3663
|
-
retryable: parsedOnError.retryable
|
|
3663
|
+
retryable: parsedOnError.retryable,
|
|
3664
|
+
exitCode
|
|
3664
3665
|
};
|
|
3665
3666
|
}
|
|
3666
3667
|
try {
|
|
@@ -18937,6 +18938,7 @@ class AcpSessionHandleImpl {
|
|
|
18937
18938
|
_resumed;
|
|
18938
18939
|
_timeoutSeconds;
|
|
18939
18940
|
_modelDef;
|
|
18941
|
+
_permissionMode;
|
|
18940
18942
|
constructor(opts) {
|
|
18941
18943
|
this.id = opts.id;
|
|
18942
18944
|
this.agentName = opts.agentName;
|
|
@@ -18947,6 +18949,7 @@ class AcpSessionHandleImpl {
|
|
|
18947
18949
|
this._resumed = opts.resumed;
|
|
18948
18950
|
this._timeoutSeconds = opts.timeoutSeconds;
|
|
18949
18951
|
this._modelDef = opts.modelDef;
|
|
18952
|
+
this._permissionMode = opts.permissionMode;
|
|
18950
18953
|
}
|
|
18951
18954
|
}
|
|
18952
18955
|
function extractOutput(response) {
|
|
@@ -19288,7 +19291,8 @@ class AcpAgentAdapter {
|
|
|
19288
19291
|
sessionName: name,
|
|
19289
19292
|
resumed: ensured.resumed,
|
|
19290
19293
|
timeoutSeconds,
|
|
19291
|
-
modelDef
|
|
19294
|
+
modelDef,
|
|
19295
|
+
permissionMode: resolvedPermissions.mode
|
|
19292
19296
|
});
|
|
19293
19297
|
} catch (error48) {
|
|
19294
19298
|
if (session) {
|
|
@@ -19300,7 +19304,8 @@ class AcpAgentAdapter {
|
|
|
19300
19304
|
}
|
|
19301
19305
|
async sendTurn(handle, prompt, opts) {
|
|
19302
19306
|
const impl = handle;
|
|
19303
|
-
const {
|
|
19307
|
+
const { _sessionName: sessionName, _timeoutSeconds: timeoutSeconds, _modelDef: modelDef } = impl;
|
|
19308
|
+
let sessionRecreated = false;
|
|
19304
19309
|
const { interactionHandler, signal } = opts;
|
|
19305
19310
|
const MAX_TURNS = opts.maxTurns ?? 10;
|
|
19306
19311
|
let totalTokenUsage = { inputTokens: 0, outputTokens: 0 };
|
|
@@ -19321,7 +19326,7 @@ class AcpAgentAdapter {
|
|
|
19321
19326
|
while (turnCount < MAX_TURNS) {
|
|
19322
19327
|
turnCount++;
|
|
19323
19328
|
getSafeLogger()?.debug("acp-adapter", `Session turn ${turnCount}/${MAX_TURNS}`, { sessionName });
|
|
19324
|
-
const turnResult = await runSessionPrompt(
|
|
19329
|
+
const turnResult = await runSessionPrompt(impl._session, currentPrompt, timeoutSeconds * 1000, signal);
|
|
19325
19330
|
if (turnResult.timedOut) {
|
|
19326
19331
|
timedOut = true;
|
|
19327
19332
|
break;
|
|
@@ -19333,6 +19338,21 @@ class AcpAgentAdapter {
|
|
|
19333
19338
|
lastResponse = turnResult.response;
|
|
19334
19339
|
if (!lastResponse)
|
|
19335
19340
|
break;
|
|
19341
|
+
if (lastResponse.exitCode === 4 && !sessionRecreated) {
|
|
19342
|
+
sessionRecreated = true;
|
|
19343
|
+
getSafeLogger()?.info("acp-adapter", "NO_SESSION detected \u2014 re-establishing session", { sessionName });
|
|
19344
|
+
try {
|
|
19345
|
+
const ensured = await ensureAcpSession(impl._client, impl._sessionName, impl.agentName, impl._permissionMode);
|
|
19346
|
+
impl._session = ensured.session;
|
|
19347
|
+
turnCount--;
|
|
19348
|
+
continue;
|
|
19349
|
+
} catch (err) {
|
|
19350
|
+
getSafeLogger()?.warn("acp-adapter", "Session re-establishment failed after NO_SESSION", {
|
|
19351
|
+
sessionName,
|
|
19352
|
+
error: err instanceof Error ? err.message : String(err)
|
|
19353
|
+
});
|
|
19354
|
+
}
|
|
19355
|
+
}
|
|
19336
19356
|
if (lastResponse.cumulative_token_usage) {
|
|
19337
19357
|
totalTokenUsage = addTokenUsage(totalTokenUsage, this._mapper.toInternal(lastResponse.cumulative_token_usage));
|
|
19338
19358
|
}
|
|
@@ -19973,6 +19993,7 @@ class AgentManager {
|
|
|
19973
19993
|
agentName,
|
|
19974
19994
|
kind: "complete",
|
|
19975
19995
|
request: null,
|
|
19996
|
+
completeOptions: augmented,
|
|
19976
19997
|
prompt,
|
|
19977
19998
|
config: this._config,
|
|
19978
19999
|
signal: options.signal,
|
|
@@ -30190,6 +30211,7 @@ function turnResultToAgentResult(r) {
|
|
|
30190
30211
|
rateLimited: false,
|
|
30191
30212
|
durationMs: 0,
|
|
30192
30213
|
estimatedCostUsd: r.estimatedCostUsd ?? 0,
|
|
30214
|
+
exactCostUsd: r.exactCostUsd,
|
|
30193
30215
|
tokenUsage: r.tokenUsage
|
|
30194
30216
|
};
|
|
30195
30217
|
}
|
|
@@ -30362,7 +30384,8 @@ async function callOp(ctx, op, input) {
|
|
|
30362
30384
|
jsonMode: completeOp.jsonMode ?? false,
|
|
30363
30385
|
pipelineStage: op.stage,
|
|
30364
30386
|
storyId: ctx.storyId,
|
|
30365
|
-
workdir: ctx.packageDir
|
|
30387
|
+
workdir: ctx.packageDir,
|
|
30388
|
+
featureName: ctx.featureName
|
|
30366
30389
|
});
|
|
30367
30390
|
return op.parse(raw.output, input, buildCtx);
|
|
30368
30391
|
}
|
|
@@ -34509,8 +34532,8 @@ var init_truncation = __esm(() => {
|
|
|
34509
34532
|
init_adapter();
|
|
34510
34533
|
});
|
|
34511
34534
|
|
|
34512
|
-
// src/operations/
|
|
34513
|
-
function
|
|
34535
|
+
// src/operations/types.ts
|
|
34536
|
+
function parseLlmReviewShape(raw) {
|
|
34514
34537
|
if (typeof raw !== "object" || raw === null)
|
|
34515
34538
|
return null;
|
|
34516
34539
|
const obj = raw;
|
|
@@ -34520,11 +34543,13 @@ function parseLLMShape(raw) {
|
|
|
34520
34543
|
return null;
|
|
34521
34544
|
return { passed: obj.passed, findings: obj.findings };
|
|
34522
34545
|
}
|
|
34546
|
+
|
|
34547
|
+
// src/operations/semantic-review.ts
|
|
34523
34548
|
var FAIL_OPEN, semanticReviewHopBody = async (initialPrompt, ctx) => {
|
|
34524
34549
|
const first = await ctx.send(initialPrompt);
|
|
34525
34550
|
const isTruncated = looksLikeTruncatedJson(first.output);
|
|
34526
34551
|
const parsed = tryParseLLMJson(first.output);
|
|
34527
|
-
if (!isTruncated && parsed &&
|
|
34552
|
+
if (!isTruncated && parsed && parseLlmReviewShape(parsed))
|
|
34528
34553
|
return first;
|
|
34529
34554
|
const retryPrompt = isTruncated ? ReviewPromptBuilder.jsonRetryCondensed() : ReviewPromptBuilder.jsonRetry();
|
|
34530
34555
|
const retry = await ctx.send(retryPrompt);
|
|
@@ -34562,7 +34587,7 @@ var init_semantic_review = __esm(() => {
|
|
|
34562
34587
|
},
|
|
34563
34588
|
parse(output, _input, _ctx) {
|
|
34564
34589
|
const raw = tryParseLLMJson(output);
|
|
34565
|
-
const parsed =
|
|
34590
|
+
const parsed = parseLlmReviewShape(raw);
|
|
34566
34591
|
if (parsed)
|
|
34567
34592
|
return parsed;
|
|
34568
34593
|
if (/"passed"\s*:\s*false/.test(output))
|
|
@@ -34573,21 +34598,11 @@ var init_semantic_review = __esm(() => {
|
|
|
34573
34598
|
});
|
|
34574
34599
|
|
|
34575
34600
|
// src/operations/adversarial-review.ts
|
|
34576
|
-
function parseLLMShape2(raw) {
|
|
34577
|
-
if (typeof raw !== "object" || raw === null)
|
|
34578
|
-
return null;
|
|
34579
|
-
const obj = raw;
|
|
34580
|
-
if (typeof obj.passed !== "boolean")
|
|
34581
|
-
return null;
|
|
34582
|
-
if (!Array.isArray(obj.findings))
|
|
34583
|
-
return null;
|
|
34584
|
-
return { passed: obj.passed, findings: obj.findings };
|
|
34585
|
-
}
|
|
34586
34601
|
var FAIL_OPEN2, adversarialReviewHopBody = async (initialPrompt, ctx) => {
|
|
34587
34602
|
const first = await ctx.send(initialPrompt);
|
|
34588
34603
|
const isTruncated = looksLikeTruncatedJson(first.output);
|
|
34589
34604
|
const parsed = tryParseLLMJson(first.output);
|
|
34590
|
-
if (!isTruncated && parsed &&
|
|
34605
|
+
if (!isTruncated && parsed && parseLlmReviewShape(parsed))
|
|
34591
34606
|
return first;
|
|
34592
34607
|
const retryPrompt = isTruncated ? ReviewPromptBuilder.jsonRetryCondensed() : ReviewPromptBuilder.jsonRetry();
|
|
34593
34608
|
const retry = await ctx.send(retryPrompt);
|
|
@@ -34627,7 +34642,7 @@ var init_adversarial_review = __esm(() => {
|
|
|
34627
34642
|
},
|
|
34628
34643
|
parse(output, _input, _ctx) {
|
|
34629
34644
|
const raw = tryParseLLMJson(output);
|
|
34630
|
-
const parsed =
|
|
34645
|
+
const parsed = parseLlmReviewShape(raw);
|
|
34631
34646
|
if (parsed)
|
|
34632
34647
|
return parsed;
|
|
34633
34648
|
if (/"passed"\s*:\s*false/.test(output))
|
|
@@ -35189,7 +35204,7 @@ var init_cost_aggregator = __esm(() => {
|
|
|
35189
35204
|
});
|
|
35190
35205
|
|
|
35191
35206
|
// src/runtime/prompt-auditor.ts
|
|
35192
|
-
import {
|
|
35207
|
+
import { appendFile as appendFile3, mkdir as mkdir3 } from "fs/promises";
|
|
35193
35208
|
import { join as join21 } from "path";
|
|
35194
35209
|
function createNoOpPromptAuditor() {
|
|
35195
35210
|
return {
|
|
@@ -35198,6 +35213,25 @@ function createNoOpPromptAuditor() {
|
|
|
35198
35213
|
async flush() {}
|
|
35199
35214
|
};
|
|
35200
35215
|
}
|
|
35216
|
+
function deriveTxtFilename(entry) {
|
|
35217
|
+
if (entry.sessionName) {
|
|
35218
|
+
const suffix = deriveAuditSuffix(entry);
|
|
35219
|
+
return `${entry.ts}-${entry.sessionName}${suffix ? `-${suffix}` : ""}.txt`;
|
|
35220
|
+
}
|
|
35221
|
+
const parts = [String(entry.ts), entry.callType ?? "call", entry.stage ?? "unknown"];
|
|
35222
|
+
if (entry.storyId)
|
|
35223
|
+
parts.push(entry.storyId);
|
|
35224
|
+
return `${parts.join("-")}.txt`;
|
|
35225
|
+
}
|
|
35226
|
+
function deriveAuditSuffix(entry) {
|
|
35227
|
+
if (entry.callType === "run" && entry.turn !== undefined) {
|
|
35228
|
+
const stage = entry.stage ?? "run";
|
|
35229
|
+
return `${stage}-t${String(entry.turn).padStart(2, "0")}`;
|
|
35230
|
+
}
|
|
35231
|
+
if (entry.callType === "complete")
|
|
35232
|
+
return "complete";
|
|
35233
|
+
return entry.stage ?? entry.callType;
|
|
35234
|
+
}
|
|
35201
35235
|
function buildTxtContent(entry) {
|
|
35202
35236
|
const ts = new Date(entry.ts).toISOString();
|
|
35203
35237
|
const lines = [
|
|
@@ -35226,77 +35260,51 @@ function buildTxtContent(entry) {
|
|
|
35226
35260
|
}
|
|
35227
35261
|
|
|
35228
35262
|
class PromptAuditor {
|
|
35229
|
-
|
|
35230
|
-
|
|
35231
|
-
|
|
35232
|
-
|
|
35233
|
-
|
|
35234
|
-
|
|
35235
|
-
|
|
35236
|
-
this._runId = _runId;
|
|
35237
|
-
this._flushDir = _flushDir;
|
|
35238
|
-
this._featureName = _featureName;
|
|
35263
|
+
_queue = Promise.resolve();
|
|
35264
|
+
_dirCreated = false;
|
|
35265
|
+
_jsonlPath;
|
|
35266
|
+
_featureDir;
|
|
35267
|
+
constructor(runId, flushDir, featureName) {
|
|
35268
|
+
this._featureDir = join21(flushDir, featureName);
|
|
35269
|
+
this._jsonlPath = join21(this._featureDir, `${runId}.jsonl`);
|
|
35239
35270
|
}
|
|
35240
35271
|
record(entry) {
|
|
35241
|
-
|
|
35242
|
-
this._inFlightEntries.push(entry);
|
|
35243
|
-
return;
|
|
35244
|
-
}
|
|
35245
|
-
this._entries.push(entry);
|
|
35272
|
+
this._enqueue(entry);
|
|
35246
35273
|
}
|
|
35247
35274
|
recordError(entry) {
|
|
35248
|
-
|
|
35249
|
-
|
|
35250
|
-
|
|
35275
|
+
this._enqueue(entry);
|
|
35276
|
+
}
|
|
35277
|
+
_enqueue(entry) {
|
|
35278
|
+
this._queue = this._queue.then(() => this._writeEntry(entry)).catch((err) => {
|
|
35279
|
+
getSafeLogger()?.warn("audit", "prompt-audit write failed", {
|
|
35280
|
+
path: this._jsonlPath,
|
|
35281
|
+
error: errorMessage(err)
|
|
35282
|
+
});
|
|
35283
|
+
});
|
|
35284
|
+
}
|
|
35285
|
+
async _writeEntry(entry) {
|
|
35286
|
+
if (!this._dirCreated) {
|
|
35287
|
+
await mkdir3(this._featureDir, { recursive: true });
|
|
35288
|
+
this._dirCreated = true;
|
|
35251
35289
|
}
|
|
35252
|
-
this.
|
|
35290
|
+
await _promptAuditorDeps.appendLine(this._jsonlPath, `${JSON.stringify(entry)}
|
|
35291
|
+
`);
|
|
35292
|
+
if (!("prompt" in entry) || !("response" in entry))
|
|
35293
|
+
return;
|
|
35294
|
+
const auditEntry = entry;
|
|
35295
|
+
const filename = deriveTxtFilename(auditEntry);
|
|
35296
|
+
await _promptAuditorDeps.write(join21(this._featureDir, filename), buildTxtContent(auditEntry));
|
|
35253
35297
|
}
|
|
35254
35298
|
async flush() {
|
|
35255
|
-
this.
|
|
35256
|
-
try {
|
|
35257
|
-
const entries = this._entries.splice(0);
|
|
35258
|
-
if (entries.length === 0)
|
|
35259
|
-
return;
|
|
35260
|
-
const featureDir = join21(this._flushDir, this._featureName);
|
|
35261
|
-
mkdirSync3(featureDir, { recursive: true });
|
|
35262
|
-
const jsonlPath = join21(featureDir, `${this._runId}.jsonl`);
|
|
35263
|
-
await _promptAuditorDeps.write(jsonlPath, `${entries.map((e) => JSON.stringify(e)).join(`
|
|
35264
|
-
`)}
|
|
35265
|
-
`);
|
|
35266
|
-
for (const entry of entries) {
|
|
35267
|
-
if (!("prompt" in entry) || !("response" in entry))
|
|
35268
|
-
continue;
|
|
35269
|
-
const auditEntry = entry;
|
|
35270
|
-
if (!auditEntry.sessionName)
|
|
35271
|
-
continue;
|
|
35272
|
-
const filename = `${auditEntry.ts}-${auditEntry.sessionName}.txt`;
|
|
35273
|
-
await _promptAuditorDeps.write(join21(featureDir, filename), buildTxtContent(auditEntry));
|
|
35274
|
-
}
|
|
35275
|
-
const lateEntries = this._inFlightEntries.splice(0);
|
|
35276
|
-
if (lateEntries.length > 0) {
|
|
35277
|
-
const allEntries = [...entries, ...lateEntries];
|
|
35278
|
-
await _promptAuditorDeps.write(jsonlPath, `${allEntries.map((e) => JSON.stringify(e)).join(`
|
|
35279
|
-
`)}
|
|
35280
|
-
`);
|
|
35281
|
-
for (const entry of lateEntries) {
|
|
35282
|
-
if (!("prompt" in entry) || !("response" in entry))
|
|
35283
|
-
continue;
|
|
35284
|
-
const auditEntry = entry;
|
|
35285
|
-
if (!auditEntry.sessionName)
|
|
35286
|
-
continue;
|
|
35287
|
-
const filename = `${auditEntry.ts}-${auditEntry.sessionName}.txt`;
|
|
35288
|
-
await _promptAuditorDeps.write(join21(featureDir, filename), buildTxtContent(auditEntry));
|
|
35289
|
-
}
|
|
35290
|
-
}
|
|
35291
|
-
} finally {
|
|
35292
|
-
this._draining = false;
|
|
35293
|
-
}
|
|
35299
|
+
await this._queue;
|
|
35294
35300
|
}
|
|
35295
35301
|
}
|
|
35296
35302
|
var _promptAuditorDeps;
|
|
35297
35303
|
var init_prompt_auditor = __esm(() => {
|
|
35304
|
+
init_logger2();
|
|
35298
35305
|
_promptAuditorDeps = {
|
|
35299
|
-
write: (path4, data) => Bun.write(path4, data)
|
|
35306
|
+
write: (path4, data) => Bun.write(path4, data),
|
|
35307
|
+
appendLine: (path4, data) => appendFile3(path4, data, "utf8")
|
|
35300
35308
|
};
|
|
35301
35309
|
});
|
|
35302
35310
|
|
|
@@ -35358,7 +35366,7 @@ var init_types5 = __esm(() => {
|
|
|
35358
35366
|
|
|
35359
35367
|
// src/session/manager.ts
|
|
35360
35368
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
35361
|
-
import { mkdir as
|
|
35369
|
+
import { mkdir as mkdir4 } from "fs/promises";
|
|
35362
35370
|
import { isAbsolute as isAbsolute8, join as join22, relative as relative8, sep } from "path";
|
|
35363
35371
|
function resolveProjectDirFromScratchDir(scratchDir) {
|
|
35364
35372
|
const marker = `${sep}.nax${sep}features${sep}`;
|
|
@@ -35678,6 +35686,10 @@ class SessionManager {
|
|
|
35678
35686
|
if (this._busySessions.has(handle.id)) {
|
|
35679
35687
|
throw new NaxError(`Session "${handle.id}" is already processing a prompt (single-flight invariant)`, "SESSION_BUSY", { stage: "session", sessionName: handle.id });
|
|
35680
35688
|
}
|
|
35689
|
+
const terminalDesc = this._findByName(handle.id);
|
|
35690
|
+
if (terminalDesc && (terminalDesc.state === "COMPLETED" || terminalDesc.state === "FAILED")) {
|
|
35691
|
+
throw new NaxError(`Session "${handle.id}" is in terminal state ${terminalDesc.state} \u2014 call openSession first to resume`, "SESSION_TERMINAL_STATE", { stage: "session", sessionName: handle.id, state: terminalDesc.state });
|
|
35692
|
+
}
|
|
35681
35693
|
const adapter = this._getAdapter(handle.agentName);
|
|
35682
35694
|
if (!adapter) {
|
|
35683
35695
|
throw new NaxError(`SessionManager.sendPrompt: no adapter found for agent "${handle.agentName}"`, "ADAPTER_NOT_FOUND", { stage: "session", agentName: handle.agentName });
|
|
@@ -35842,7 +35854,7 @@ var init_manager2 = __esm(() => {
|
|
|
35842
35854
|
uuid: () => randomUUID2(),
|
|
35843
35855
|
sessionScratchDir: (projectDir, featureName, sessionId) => join22(projectDir, ".nax", "features", featureName, "sessions", sessionId),
|
|
35844
35856
|
writeDescriptor: async (scratchDir, descriptor, projectDir) => {
|
|
35845
|
-
await
|
|
35857
|
+
await mkdir4(scratchDir, { recursive: true });
|
|
35846
35858
|
const { handle: _handle, ...persistable } = descriptor;
|
|
35847
35859
|
const derivedProjectDir = projectDir ?? resolveProjectDirFromScratchDir(scratchDir);
|
|
35848
35860
|
if (derivedProjectDir) {
|
|
@@ -35955,9 +35967,11 @@ function extractCosts(result) {
|
|
|
35955
35967
|
if (!result || typeof result !== "object")
|
|
35956
35968
|
return null;
|
|
35957
35969
|
const r = result;
|
|
35970
|
+
const hasEstimatedCost = "estimatedCostUsd" in r;
|
|
35971
|
+
const hasCost = "costUsd" in r;
|
|
35958
35972
|
const estimatedCostUsd = r.estimatedCostUsd ?? r.costUsd ?? 0;
|
|
35959
35973
|
const exactCostUsd = r.exactCostUsd;
|
|
35960
|
-
if (
|
|
35974
|
+
if (!hasEstimatedCost && !hasCost && exactCostUsd == null)
|
|
35961
35975
|
return null;
|
|
35962
35976
|
return { estimatedCostUsd, exactCostUsd };
|
|
35963
35977
|
}
|
|
@@ -35965,6 +35979,8 @@ function costMiddleware(aggregator, runId) {
|
|
|
35965
35979
|
return {
|
|
35966
35980
|
name: "cost",
|
|
35967
35981
|
async after(ctx, result, durationMs) {
|
|
35982
|
+
if (ctx.kind === "run" && ctx.sessionHandle === undefined && ctx.request?.executeHop)
|
|
35983
|
+
return;
|
|
35968
35984
|
const tokens = extractTokens(result);
|
|
35969
35985
|
const costs = extractCosts(result);
|
|
35970
35986
|
if (!tokens && !costs)
|
|
@@ -36013,17 +36029,35 @@ function extractOutput2(result) {
|
|
|
36013
36029
|
return "";
|
|
36014
36030
|
return result.output ?? "";
|
|
36015
36031
|
}
|
|
36032
|
+
function sessionNameFromCompleteOptions(ctx) {
|
|
36033
|
+
const opts = ctx.completeOptions;
|
|
36034
|
+
if (!opts)
|
|
36035
|
+
return;
|
|
36036
|
+
if (opts.sessionName)
|
|
36037
|
+
return opts.sessionName;
|
|
36038
|
+
if (!opts.workdir || !opts.featureName)
|
|
36039
|
+
return;
|
|
36040
|
+
return formatSessionName({
|
|
36041
|
+
workdir: opts.workdir,
|
|
36042
|
+
featureName: opts.featureName,
|
|
36043
|
+
storyId: opts.storyId,
|
|
36044
|
+
role: opts.sessionRole,
|
|
36045
|
+
pipelineStage: opts.pipelineStage
|
|
36046
|
+
});
|
|
36047
|
+
}
|
|
36016
36048
|
function auditMiddleware(auditor, runId) {
|
|
36017
36049
|
return {
|
|
36018
36050
|
name: "audit",
|
|
36019
36051
|
async after(ctx, result, durationMs) {
|
|
36052
|
+
if (ctx.kind === "run" && ctx.sessionHandle === undefined && ctx.request?.executeHop)
|
|
36053
|
+
return;
|
|
36020
36054
|
const runOpts = ctx.request?.runOptions;
|
|
36021
36055
|
const prompt = ctx.prompt ?? runOpts?.prompt;
|
|
36022
36056
|
if (!prompt)
|
|
36023
36057
|
return;
|
|
36024
36058
|
const agentResult = result ?? {};
|
|
36025
36059
|
const { protocolIds } = agentResult;
|
|
36026
|
-
const sessionName = ctx.sessionHandle?.id;
|
|
36060
|
+
const sessionName = ctx.sessionHandle?.id ?? sessionNameFromCompleteOptions(ctx);
|
|
36027
36061
|
const internalRoundTrips = result && typeof result === "object" && "internalRoundTrips" in result ? result.internalRoundTrips : undefined;
|
|
36028
36062
|
const entry = {
|
|
36029
36063
|
ts: Date.now(),
|
|
@@ -36036,9 +36070,9 @@ function auditMiddleware(auditor, runId) {
|
|
|
36036
36070
|
response: extractOutput2(result),
|
|
36037
36071
|
durationMs,
|
|
36038
36072
|
callType: ctx.kind,
|
|
36039
|
-
workdir: runOpts?.workdir,
|
|
36073
|
+
workdir: runOpts?.workdir ?? ctx.completeOptions?.workdir,
|
|
36040
36074
|
projectDir: runOpts?.projectDir,
|
|
36041
|
-
featureName: runOpts?.featureName,
|
|
36075
|
+
featureName: runOpts?.featureName ?? ctx.completeOptions?.featureName,
|
|
36042
36076
|
...sessionName !== undefined && { sessionName },
|
|
36043
36077
|
...protocolIds?.recordId !== undefined && { recordId: protocolIds.recordId },
|
|
36044
36078
|
...protocolIds?.sessionId !== undefined && { sessionId: protocolIds.sessionId },
|
|
@@ -36072,6 +36106,7 @@ function auditMiddleware(auditor, runId) {
|
|
|
36072
36106
|
}
|
|
36073
36107
|
var init_audit = __esm(() => {
|
|
36074
36108
|
init_errors();
|
|
36109
|
+
init_session_name();
|
|
36075
36110
|
});
|
|
36076
36111
|
|
|
36077
36112
|
// src/runtime/middleware/index.ts
|
|
@@ -38274,6 +38309,9 @@ __export(exports_acceptance_setup, {
|
|
|
38274
38309
|
_acceptanceSetupDeps: () => _acceptanceSetupDeps
|
|
38275
38310
|
});
|
|
38276
38311
|
import path7 from "path";
|
|
38312
|
+
function hasLikelyTestContent2(content) {
|
|
38313
|
+
return /\b(?:describe|test|it|expect)\s*\(/.test(content) || /func\s+Test\w+\s*\(/.test(content) || /def\s+test_\w+/.test(content) || /#\[test\]/.test(content);
|
|
38314
|
+
}
|
|
38277
38315
|
function computeACFingerprint(criteria) {
|
|
38278
38316
|
const sorted = [...criteria].sort().join(`
|
|
38279
38317
|
`);
|
|
@@ -38344,6 +38382,9 @@ var init_acceptance_setup = __esm(() => {
|
|
|
38344
38382
|
writeMeta: async (metaPath, meta3) => {
|
|
38345
38383
|
await Bun.write(metaPath, JSON.stringify(meta3, null, 2));
|
|
38346
38384
|
},
|
|
38385
|
+
readFile: async (filePath) => {
|
|
38386
|
+
return Bun.file(filePath).text();
|
|
38387
|
+
},
|
|
38347
38388
|
autoCommitIfDirty,
|
|
38348
38389
|
loadGroupConfig: async (projectDir, relativeWorkdir) => {
|
|
38349
38390
|
return loadConfigForWorkdir(path7.join(projectDir, ".nax", "config.json"), relativeWorkdir || undefined);
|
|
@@ -38464,6 +38505,7 @@ ${stderr}` };
|
|
|
38464
38505
|
`);
|
|
38465
38506
|
const frameworkOverrideLine = ctx.config.acceptance.testFramework ? `
|
|
38466
38507
|
[FRAMEWORK OVERRIDE: Use ${ctx.config.acceptance.testFramework} as the test framework regardless of what you detect.]` : "";
|
|
38508
|
+
const groupStoryId = group.stories[0]?.id;
|
|
38467
38509
|
const genResult = await _acceptanceSetupDeps.callOp(ctx, packageDir, acceptanceGenerateOp, {
|
|
38468
38510
|
featureName: featureName ?? "",
|
|
38469
38511
|
criteriaList,
|
|
@@ -38471,17 +38513,53 @@ ${stderr}` };
|
|
|
38471
38513
|
targetTestFilePath: testPath,
|
|
38472
38514
|
..."implementationContext" in ctx && ctx.implementationContext ? { implementationContext: ctx.implementationContext } : {},
|
|
38473
38515
|
..."previousFailure" in ctx && ctx.previousFailure ? { previousFailure: ctx.previousFailure } : {}
|
|
38474
|
-
});
|
|
38516
|
+
}, groupStoryId);
|
|
38475
38517
|
let testCode = genResult.testCode;
|
|
38476
38518
|
if (!testCode) {
|
|
38477
|
-
const
|
|
38478
|
-
|
|
38479
|
-
|
|
38480
|
-
|
|
38481
|
-
|
|
38482
|
-
|
|
38519
|
+
const backupPath = `${testPath}.llm-recovery.bak`;
|
|
38520
|
+
if (await _acceptanceSetupDeps.fileExists(testPath)) {
|
|
38521
|
+
try {
|
|
38522
|
+
const existing = await _acceptanceSetupDeps.readFile(testPath);
|
|
38523
|
+
const extracted = extractTestCode(existing);
|
|
38524
|
+
if (extracted) {
|
|
38525
|
+
testCode = extracted;
|
|
38526
|
+
getSafeLogger()?.info("acceptance-setup", "Agent wrote fenced code block to disk \u2014 using extracted code", { storyId: groupStoryId, testPath });
|
|
38527
|
+
} else if (existing.trim().length > 0 && hasLikelyTestContent2(existing)) {
|
|
38528
|
+
let backupCreated = false;
|
|
38529
|
+
try {
|
|
38530
|
+
await _acceptanceSetupDeps.writeFile(backupPath, existing);
|
|
38531
|
+
backupCreated = true;
|
|
38532
|
+
} catch (backupErr) {
|
|
38533
|
+
getSafeLogger()?.warn("acceptance-setup", "Failed to create .llm-recovery.bak \u2014 preserving agent file anyway", { storyId: groupStoryId, testPath, backupPath, error: errorMessage(backupErr) });
|
|
38534
|
+
}
|
|
38535
|
+
testCode = existing;
|
|
38536
|
+
getSafeLogger()?.info("acceptance-setup", "Agent wrote acceptance test directly \u2014 preserving file with backup", { storyId: groupStoryId, testPath, backupPath, backupCreated });
|
|
38537
|
+
} else {
|
|
38538
|
+
if (existing.trim().length > 0) {
|
|
38539
|
+
try {
|
|
38540
|
+
await _acceptanceSetupDeps.writeFile(backupPath, existing);
|
|
38541
|
+
} catch (backupErr) {
|
|
38542
|
+
getSafeLogger()?.warn("acceptance-setup", "Failed to create .llm-recovery.bak for unrecognised file", { storyId: groupStoryId, testPath, backupPath, error: errorMessage(backupErr) });
|
|
38543
|
+
}
|
|
38544
|
+
}
|
|
38545
|
+
getSafeLogger()?.error("acceptance-setup", "Agent-written file not recognised as test code \u2014 falling back to skeleton", { storyId: groupStoryId, testPath, backupPath, fileSize: existing.length });
|
|
38546
|
+
}
|
|
38547
|
+
} catch (err) {
|
|
38548
|
+
getSafeLogger()?.warn("acceptance-setup", "Failed to read agent-written file \u2014 falling back to skeleton", { storyId: groupStoryId, testPath, error: errorMessage(err) });
|
|
38549
|
+
}
|
|
38550
|
+
}
|
|
38551
|
+
if (!testCode) {
|
|
38552
|
+
const skeletonCriteria = groupRefined.map((c, i) => ({
|
|
38553
|
+
id: `AC-${i + 1}`,
|
|
38554
|
+
text: c.refined,
|
|
38555
|
+
lineNumber: i + 1
|
|
38556
|
+
}));
|
|
38557
|
+
testCode = generateSkeletonTests(featureName, skeletonCriteria, ctx.config.acceptance.testFramework, language);
|
|
38558
|
+
}
|
|
38559
|
+
}
|
|
38560
|
+
if (testCode) {
|
|
38561
|
+
await _acceptanceSetupDeps.writeFile(testPath, testCode);
|
|
38483
38562
|
}
|
|
38484
|
-
await _acceptanceSetupDeps.writeFile(testPath, testCode);
|
|
38485
38563
|
}
|
|
38486
38564
|
if (allRefinedCriteria.length > 0) {
|
|
38487
38565
|
const refinedJsonContent = JSON.stringify(allRefinedCriteria.map((c, i) => ({
|
|
@@ -39982,7 +40060,7 @@ var init_nax_project_root = __esm(() => {
|
|
|
39982
40060
|
});
|
|
39983
40061
|
|
|
39984
40062
|
// src/review/review-audit.ts
|
|
39985
|
-
import { mkdir as
|
|
40063
|
+
import { mkdir as mkdir5 } from "fs/promises";
|
|
39986
40064
|
import { join as join33 } from "path";
|
|
39987
40065
|
async function writeReviewAudit(entry) {
|
|
39988
40066
|
try {
|
|
@@ -40015,7 +40093,7 @@ var init_review_audit = __esm(() => {
|
|
|
40015
40093
|
init_nax_project_root();
|
|
40016
40094
|
_reviewAuditDeps = {
|
|
40017
40095
|
async mkdir(path8) {
|
|
40018
|
-
await
|
|
40096
|
+
await mkdir5(path8, { recursive: true });
|
|
40019
40097
|
},
|
|
40020
40098
|
async writeFile(path8, content) {
|
|
40021
40099
|
await Bun.write(path8, content);
|
|
@@ -41466,7 +41544,7 @@ var init_runner4 = __esm(() => {
|
|
|
41466
41544
|
});
|
|
41467
41545
|
|
|
41468
41546
|
// src/review/verdict-writer.ts
|
|
41469
|
-
import { mkdir as
|
|
41547
|
+
import { mkdir as mkdir6 } from "fs/promises";
|
|
41470
41548
|
import { join as join34 } from "path";
|
|
41471
41549
|
async function writeReviewVerdict(entry) {
|
|
41472
41550
|
const logger = getSafeLogger();
|
|
@@ -41495,7 +41573,7 @@ var init_verdict_writer = __esm(() => {
|
|
|
41495
41573
|
init_nax_project_root();
|
|
41496
41574
|
_verdictWriterDeps = {
|
|
41497
41575
|
findNaxProjectRoot,
|
|
41498
|
-
mkdir:
|
|
41576
|
+
mkdir: mkdir6,
|
|
41499
41577
|
writeFile: Bun.write
|
|
41500
41578
|
};
|
|
41501
41579
|
});
|
|
@@ -42555,8 +42633,8 @@ var init_semantic_verdict = __esm(() => {
|
|
|
42555
42633
|
init_logger2();
|
|
42556
42634
|
_semanticVerdictDeps = {
|
|
42557
42635
|
mkdirp: async (dir) => {
|
|
42558
|
-
const { mkdir:
|
|
42559
|
-
await
|
|
42636
|
+
const { mkdir: mkdir7 } = await import("fs/promises");
|
|
42637
|
+
await mkdir7(dir, { recursive: true });
|
|
42560
42638
|
},
|
|
42561
42639
|
writeFile: async (filePath, content) => {
|
|
42562
42640
|
await Bun.write(filePath, content);
|
|
@@ -42703,15 +42781,15 @@ var init_effectiveness = __esm(() => {
|
|
|
42703
42781
|
});
|
|
42704
42782
|
|
|
42705
42783
|
// src/execution/progress.ts
|
|
42706
|
-
import { appendFile as
|
|
42784
|
+
import { appendFile as appendFile4, mkdir as mkdir7 } from "fs/promises";
|
|
42707
42785
|
import { join as join36 } from "path";
|
|
42708
42786
|
async function appendProgress(featureDir, storyId, status, message) {
|
|
42709
|
-
await
|
|
42787
|
+
await mkdir7(featureDir, { recursive: true });
|
|
42710
42788
|
const progressPath = join36(featureDir, "progress.txt");
|
|
42711
42789
|
const timestamp = new Date().toISOString();
|
|
42712
42790
|
const entry = `[${timestamp}] ${storyId} \u2014 ${status.toUpperCase()} \u2014 ${message}
|
|
42713
42791
|
`;
|
|
42714
|
-
await
|
|
42792
|
+
await appendFile4(progressPath, entry);
|
|
42715
42793
|
}
|
|
42716
42794
|
var init_progress = () => {};
|
|
42717
42795
|
|
|
@@ -43550,7 +43628,7 @@ async function getStoryChangedFiles(workdir, fromRef) {
|
|
|
43550
43628
|
async function runFullSuiteGate(story, config2, workdir, agentManager, implementerTier, lite, logger, featureName, projectDir, storyFromRef, sessionManager, sessionId, runtime) {
|
|
43551
43629
|
const rectificationEnabled = config2.execution.rectification?.enabled ?? false;
|
|
43552
43630
|
if (!rectificationEnabled)
|
|
43553
|
-
return { passed: false, cost: 0 };
|
|
43631
|
+
return { passed: false, cost: 0, fullSuiteGatePassed: false };
|
|
43554
43632
|
const rectificationConfig = config2.execution.rectification;
|
|
43555
43633
|
const fullSuiteTimeout = rectificationConfig.fullSuiteTimeoutSeconds;
|
|
43556
43634
|
const { testCommand: resolvedTestCmd } = await _rectificationGateDeps.resolveTestCommands(config2, workdir, story.workdir);
|
|
@@ -43564,8 +43642,18 @@ async function runFullSuiteGate(story, config2, workdir, agentManager, implement
|
|
|
43564
43642
|
if (!fullSuitePassed && fullSuiteResult.output) {
|
|
43565
43643
|
const testSummary = _rectificationGateDeps.parseTestOutput(fullSuiteResult.output);
|
|
43566
43644
|
if (testSummary.failed > 0) {
|
|
43645
|
+
if (testSummary.failures.length === 0) {
|
|
43646
|
+
logger.warn("tdd", "Full suite gate found unattributable failures \u2014 deferring to run-level regression", {
|
|
43647
|
+
storyId: story.id,
|
|
43648
|
+
failedTests: testSummary.failed,
|
|
43649
|
+
passedTests: testSummary.passed,
|
|
43650
|
+
outputLength: fullSuiteResult.output.length,
|
|
43651
|
+
outputTail: fullSuiteResult.output.slice(-200)
|
|
43652
|
+
});
|
|
43653
|
+
return { passed: true, cost: 0, fullSuiteGatePassed: false };
|
|
43654
|
+
}
|
|
43567
43655
|
let filteredFailures = testSummary.failures;
|
|
43568
|
-
if (storyFromRef
|
|
43656
|
+
if (storyFromRef) {
|
|
43569
43657
|
const storyFiles = await getStoryChangedFiles(workdir, storyFromRef);
|
|
43570
43658
|
if (storyFiles.size > 0) {
|
|
43571
43659
|
filteredFailures = testSummary.failures.filter((f) => storyFiles.has(f.file));
|
|
@@ -43580,7 +43668,7 @@ async function runFullSuiteGate(story, config2, workdir, agentManager, implement
|
|
|
43580
43668
|
suppressedTestCount: testSummary.failures.length,
|
|
43581
43669
|
suppressedFiles: uniqueSuppressedFiles
|
|
43582
43670
|
});
|
|
43583
|
-
return { passed: true, cost: 0 };
|
|
43671
|
+
return { passed: true, cost: 0, fullSuiteGatePassed: true };
|
|
43584
43672
|
}
|
|
43585
43673
|
if (wasFiltered) {
|
|
43586
43674
|
logger.info("tdd", "Full suite gate: suppressed pre-existing failures", {
|
|
@@ -43603,7 +43691,7 @@ async function runFullSuiteGate(story, config2, workdir, agentManager, implement
|
|
|
43603
43691
|
exitCode: fullSuiteResult.exitCode,
|
|
43604
43692
|
passedTests: testSummary.passed
|
|
43605
43693
|
});
|
|
43606
|
-
return { passed: true, cost: 0 };
|
|
43694
|
+
return { passed: true, cost: 0, fullSuiteGatePassed: true };
|
|
43607
43695
|
}
|
|
43608
43696
|
logger.warn("tdd", "Full suite gate inconclusive \u2014 no test results parsed from output (possible crash/OOM)", {
|
|
43609
43697
|
storyId: story.id,
|
|
@@ -43611,17 +43699,17 @@ async function runFullSuiteGate(story, config2, workdir, agentManager, implement
|
|
|
43611
43699
|
outputLength: fullSuiteResult.output.length,
|
|
43612
43700
|
outputTail: fullSuiteResult.output.slice(-200)
|
|
43613
43701
|
});
|
|
43614
|
-
return { passed: false, cost: 0 };
|
|
43702
|
+
return { passed: false, cost: 0, fullSuiteGatePassed: false };
|
|
43615
43703
|
}
|
|
43616
43704
|
if (fullSuitePassed) {
|
|
43617
43705
|
logger.info("tdd", "Full suite gate passed", { storyId: story.id });
|
|
43618
|
-
return { passed: true, cost: 0 };
|
|
43706
|
+
return { passed: true, cost: 0, fullSuiteGatePassed: true };
|
|
43619
43707
|
}
|
|
43620
43708
|
logger.warn("tdd", "Full suite gate execution failed (no output)", {
|
|
43621
43709
|
storyId: story.id,
|
|
43622
43710
|
exitCode: fullSuiteResult.exitCode
|
|
43623
43711
|
});
|
|
43624
|
-
return { passed: false, cost: 0 };
|
|
43712
|
+
return { passed: false, cost: 0, fullSuiteGatePassed: false };
|
|
43625
43713
|
}
|
|
43626
43714
|
async function runRectificationLoop(story, config2, workdir, agentManager, implementerTier, lite, logger, testSummary, rectificationConfig, testCmd, fullSuiteTimeout, testOutput, featureName, projectDir, sessionManager, sessionId, runtime) {
|
|
43627
43715
|
logger.warn("tdd", "Full suite gate detected regressions", {
|
|
@@ -43761,13 +43849,13 @@ async function runRectificationLoop(story, config2, workdir, agentManager, imple
|
|
|
43761
43849
|
});
|
|
43762
43850
|
const fixed = outcome.outcome === "fixed";
|
|
43763
43851
|
if (fixed) {
|
|
43764
|
-
return { passed: true, cost: gateCostAccum };
|
|
43852
|
+
return { passed: true, cost: gateCostAccum, fullSuiteGatePassed: true };
|
|
43765
43853
|
}
|
|
43766
43854
|
logger.warn("tdd", "[WARN] Full suite gate failed after rectification exhausted", {
|
|
43767
43855
|
storyId: story.id,
|
|
43768
43856
|
attempts: outcome.attempts
|
|
43769
43857
|
});
|
|
43770
|
-
return { passed: false, cost: gateCostAccum };
|
|
43858
|
+
return { passed: false, cost: gateCostAccum, fullSuiteGatePassed: false };
|
|
43771
43859
|
}
|
|
43772
43860
|
var _rectificationGateDeps;
|
|
43773
43861
|
var init_rectification_gate = __esm(() => {
|
|
@@ -44236,7 +44324,7 @@ async function runThreeSessionTdd(options) {
|
|
|
44236
44324
|
};
|
|
44237
44325
|
}
|
|
44238
44326
|
const implementerBinding = getTddSessionBinding?.("implementer");
|
|
44239
|
-
const {
|
|
44327
|
+
const { cost: fullSuiteGateCost, fullSuiteGatePassed } = await runFullSuiteGate(story, config2, workdir, wrapAdapterAsManager(agent), implementerTier, lite, logger, featureName, projectDir, initialRef, implementerBinding?.sessionManager, implementerBinding?.sessionId);
|
|
44240
44328
|
const session3Ref = await captureGitRef(workdir) ?? "HEAD";
|
|
44241
44329
|
const verifierBundle = await getTddContextBundle?.("verifier") ?? tddContextBundles?.verifier;
|
|
44242
44330
|
const session3 = await runTddSessionOp(verifyTddOp, options, session3Ref, verifierBundle, getTddSessionBinding?.("verifier"));
|
|
@@ -46400,7 +46488,7 @@ __export(exports_init_context, {
|
|
|
46400
46488
|
_initContextDeps: () => _initContextDeps
|
|
46401
46489
|
});
|
|
46402
46490
|
import { existsSync as existsSync21 } from "fs";
|
|
46403
|
-
import { mkdir as
|
|
46491
|
+
import { mkdir as mkdir8 } from "fs/promises";
|
|
46404
46492
|
import { basename as basename5, join as join42 } from "path";
|
|
46405
46493
|
async function findFiles(dir, maxFiles = 200) {
|
|
46406
46494
|
try {
|
|
@@ -46644,7 +46732,7 @@ async function initPackage(repoRoot, packagePath, force = false) {
|
|
|
46644
46732
|
return;
|
|
46645
46733
|
}
|
|
46646
46734
|
if (!existsSync21(naxDir)) {
|
|
46647
|
-
await
|
|
46735
|
+
await mkdir8(naxDir, { recursive: true });
|
|
46648
46736
|
}
|
|
46649
46737
|
const content = generatePackageContextTemplate(packagePath);
|
|
46650
46738
|
await Bun.write(contextPath, content);
|
|
@@ -46659,7 +46747,7 @@ async function initContext(projectRoot, options = {}) {
|
|
|
46659
46747
|
return;
|
|
46660
46748
|
}
|
|
46661
46749
|
if (!existsSync21(naxDir)) {
|
|
46662
|
-
await
|
|
46750
|
+
await mkdir8(naxDir, { recursive: true });
|
|
46663
46751
|
}
|
|
46664
46752
|
const scan = await scanProject(projectRoot);
|
|
46665
46753
|
let content;
|
|
@@ -47427,7 +47515,7 @@ var package_default;
|
|
|
47427
47515
|
var init_package = __esm(() => {
|
|
47428
47516
|
package_default = {
|
|
47429
47517
|
name: "@nathapp/nax",
|
|
47430
|
-
version: "0.64.0-canary.
|
|
47518
|
+
version: "0.64.0-canary.4",
|
|
47431
47519
|
description: "AI Coding Agent Orchestrator \u2014 loops until done",
|
|
47432
47520
|
type: "module",
|
|
47433
47521
|
bin: {
|
|
@@ -47509,8 +47597,8 @@ var init_version = __esm(() => {
|
|
|
47509
47597
|
NAX_VERSION = package_default.version;
|
|
47510
47598
|
NAX_COMMIT = (() => {
|
|
47511
47599
|
try {
|
|
47512
|
-
if (/^[0-9a-f]{6,10}$/.test("
|
|
47513
|
-
return "
|
|
47600
|
+
if (/^[0-9a-f]{6,10}$/.test("c0ad2048"))
|
|
47601
|
+
return "c0ad2048";
|
|
47514
47602
|
} catch {}
|
|
47515
47603
|
try {
|
|
47516
47604
|
const result = Bun.spawnSync(["git", "rev-parse", "--short", "HEAD"], {
|
|
@@ -48331,7 +48419,7 @@ var init_acceptance_loop = __esm(() => {
|
|
|
48331
48419
|
});
|
|
48332
48420
|
|
|
48333
48421
|
// src/session/scratch-purge.ts
|
|
48334
|
-
import { mkdir as
|
|
48422
|
+
import { mkdir as mkdir10, rename, rm } from "fs/promises";
|
|
48335
48423
|
import { dirname as dirname9, join as join60 } from "path";
|
|
48336
48424
|
async function purgeStaleScratch(projectDir, featureName, retentionDays, archiveInsteadOfDelete = false) {
|
|
48337
48425
|
const sessionsDir = join60(projectDir, ".nax", "features", featureName, "sessions");
|
|
@@ -48383,7 +48471,7 @@ var init_scratch_purge = __esm(() => {
|
|
|
48383
48471
|
readFile: (path16) => Bun.file(path16).text(),
|
|
48384
48472
|
remove: (path16) => rm(path16, { recursive: true, force: true }),
|
|
48385
48473
|
move: async (src, dest) => {
|
|
48386
|
-
await
|
|
48474
|
+
await mkdir10(dirname9(dest), { recursive: true });
|
|
48387
48475
|
await rename(src, dest);
|
|
48388
48476
|
},
|
|
48389
48477
|
now: () => Date.now()
|
|
@@ -49017,7 +49105,7 @@ function precomputeBatchPlan(stories, maxBatchSize = DEFAULT_MAX_BATCH_SIZE) {
|
|
|
49017
49105
|
var DEFAULT_MAX_BATCH_SIZE = 4;
|
|
49018
49106
|
|
|
49019
49107
|
// src/pipeline/subscribers/events-writer.ts
|
|
49020
|
-
import { appendFile as
|
|
49108
|
+
import { appendFile as appendFile5, mkdir as mkdir11 } from "fs/promises";
|
|
49021
49109
|
import { homedir as homedir5 } from "os";
|
|
49022
49110
|
import { basename as basename9, join as join61 } from "path";
|
|
49023
49111
|
function wireEventsWriter(bus, feature, runId, workdir) {
|
|
@@ -49030,10 +49118,10 @@ function wireEventsWriter(bus, feature, runId, workdir) {
|
|
|
49030
49118
|
return (async () => {
|
|
49031
49119
|
try {
|
|
49032
49120
|
if (!dirReady) {
|
|
49033
|
-
await
|
|
49121
|
+
await mkdir11(eventsDir, { recursive: true });
|
|
49034
49122
|
dirReady = true;
|
|
49035
49123
|
}
|
|
49036
|
-
await
|
|
49124
|
+
await appendFile5(eventsFile, `${JSON.stringify(line)}
|
|
49037
49125
|
`);
|
|
49038
49126
|
} catch (err) {
|
|
49039
49127
|
logger?.warn("events-writer", "Failed to write event line (non-fatal)", {
|
|
@@ -49203,7 +49291,7 @@ var init_interaction2 = __esm(() => {
|
|
|
49203
49291
|
});
|
|
49204
49292
|
|
|
49205
49293
|
// src/pipeline/subscribers/registry.ts
|
|
49206
|
-
import { mkdir as
|
|
49294
|
+
import { mkdir as mkdir12, writeFile } from "fs/promises";
|
|
49207
49295
|
import { homedir as homedir6 } from "os";
|
|
49208
49296
|
import { basename as basename10, join as join62 } from "path";
|
|
49209
49297
|
function wireRegistry(bus, feature, runId, workdir) {
|
|
@@ -49214,7 +49302,7 @@ function wireRegistry(bus, feature, runId, workdir) {
|
|
|
49214
49302
|
const unsub = bus.on("run:started", (_ev) => {
|
|
49215
49303
|
return (async () => {
|
|
49216
49304
|
try {
|
|
49217
|
-
await
|
|
49305
|
+
await mkdir12(runDir, { recursive: true });
|
|
49218
49306
|
const meta3 = {
|
|
49219
49307
|
runId,
|
|
49220
49308
|
project,
|
|
@@ -49556,7 +49644,7 @@ __export(exports_manager, {
|
|
|
49556
49644
|
WorktreeManager: () => WorktreeManager
|
|
49557
49645
|
});
|
|
49558
49646
|
import { existsSync as existsSync30, symlinkSync } from "fs";
|
|
49559
|
-
import { mkdir as
|
|
49647
|
+
import { mkdir as mkdir13 } from "fs/promises";
|
|
49560
49648
|
import { join as join64 } from "path";
|
|
49561
49649
|
|
|
49562
49650
|
class WorktreeManager {
|
|
@@ -49565,7 +49653,7 @@ class WorktreeManager {
|
|
|
49565
49653
|
const infoDir = join64(projectRoot, ".git", "info");
|
|
49566
49654
|
const excludePath = join64(infoDir, "exclude");
|
|
49567
49655
|
try {
|
|
49568
|
-
await
|
|
49656
|
+
await mkdir13(infoDir, { recursive: true });
|
|
49569
49657
|
let existing = "";
|
|
49570
49658
|
if (existsSync30(excludePath)) {
|
|
49571
49659
|
existing = await Bun.file(excludePath).text();
|
|
@@ -52006,7 +52094,7 @@ var exports_precheck_runner = {};
|
|
|
52006
52094
|
__export(exports_precheck_runner, {
|
|
52007
52095
|
runPrecheckValidation: () => runPrecheckValidation
|
|
52008
52096
|
});
|
|
52009
|
-
import { mkdirSync as
|
|
52097
|
+
import { mkdirSync as mkdirSync6 } from "fs";
|
|
52010
52098
|
import path18 from "path";
|
|
52011
52099
|
async function runPrecheckValidation(ctx) {
|
|
52012
52100
|
const logger = getSafeLogger();
|
|
@@ -52022,7 +52110,7 @@ async function runPrecheckValidation(ctx) {
|
|
|
52022
52110
|
silent: true
|
|
52023
52111
|
});
|
|
52024
52112
|
if (ctx.logFilePath) {
|
|
52025
|
-
|
|
52113
|
+
mkdirSync6(path18.dirname(ctx.logFilePath), { recursive: true });
|
|
52026
52114
|
const precheckLog = {
|
|
52027
52115
|
type: "precheck",
|
|
52028
52116
|
timestamp: new Date().toISOString(),
|
|
@@ -83483,7 +83571,7 @@ var require_jsx_dev_runtime = __commonJS((exports, module) => {
|
|
|
83483
83571
|
|
|
83484
83572
|
// bin/nax.ts
|
|
83485
83573
|
init_source();
|
|
83486
|
-
import { existsSync as existsSync33, mkdirSync as
|
|
83574
|
+
import { existsSync as existsSync33, mkdirSync as mkdirSync7 } from "fs";
|
|
83487
83575
|
import { homedir as homedir8 } from "os";
|
|
83488
83576
|
import { join as join72 } from "path";
|
|
83489
83577
|
|
|
@@ -85347,7 +85435,7 @@ async function runsShowCommand(options) {
|
|
|
85347
85435
|
}
|
|
85348
85436
|
// src/cli/prompts-main.ts
|
|
85349
85437
|
init_logger2();
|
|
85350
|
-
import { existsSync as existsSync19, mkdirSync as
|
|
85438
|
+
import { existsSync as existsSync19, mkdirSync as mkdirSync3 } from "fs";
|
|
85351
85439
|
import { join as join40 } from "path";
|
|
85352
85440
|
|
|
85353
85441
|
// src/pipeline/index.ts
|
|
@@ -85487,7 +85575,7 @@ async function promptsCommand(options) {
|
|
|
85487
85575
|
throw new Error(storyId ? `Story "${storyId}" not found in feature "${feature}"` : `No stories found in feature "${feature}"`);
|
|
85488
85576
|
}
|
|
85489
85577
|
if (outputDir) {
|
|
85490
|
-
|
|
85578
|
+
mkdirSync3(outputDir, { recursive: true });
|
|
85491
85579
|
}
|
|
85492
85580
|
logger.info("cli", "Assembling prompts", {
|
|
85493
85581
|
feature,
|
|
@@ -85569,7 +85657,7 @@ ${"=".repeat(80)}`);
|
|
|
85569
85657
|
}
|
|
85570
85658
|
// src/cli/prompts-init.ts
|
|
85571
85659
|
init_role_task();
|
|
85572
|
-
import { existsSync as existsSync20, mkdirSync as
|
|
85660
|
+
import { existsSync as existsSync20, mkdirSync as mkdirSync4 } from "fs";
|
|
85573
85661
|
import { join as join41 } from "path";
|
|
85574
85662
|
var TEMPLATE_ROLES = [
|
|
85575
85663
|
{ file: "test-writer.md", role: "test-writer" },
|
|
@@ -85595,7 +85683,7 @@ var TEMPLATE_HEADER = `<!--
|
|
|
85595
85683
|
async function promptsInitCommand(options) {
|
|
85596
85684
|
const { workdir, force = false, autoWireConfig = true } = options;
|
|
85597
85685
|
const templatesDir = join41(workdir, ".nax", "templates");
|
|
85598
|
-
|
|
85686
|
+
mkdirSync4(templatesDir, { recursive: true });
|
|
85599
85687
|
const existingFiles = TEMPLATE_ROLES.map((t) => t.file).filter((f) => existsSync20(join41(templatesDir, f)));
|
|
85600
85688
|
if (existingFiles.length > 0 && !force) {
|
|
85601
85689
|
console.warn(`[WARN] nax/templates/ already contains files: ${existingFiles.join(", ")}. No files overwritten.
|
|
@@ -86736,7 +86824,7 @@ function formatValueForTable(value) {
|
|
|
86736
86824
|
// src/cli/config-profile.ts
|
|
86737
86825
|
init_paths();
|
|
86738
86826
|
init_profile();
|
|
86739
|
-
import { mkdirSync as
|
|
86827
|
+
import { mkdirSync as mkdirSync5 } from "fs";
|
|
86740
86828
|
import { readdirSync as readdirSync7 } from "fs";
|
|
86741
86829
|
import { join as join49 } from "path";
|
|
86742
86830
|
var _profileCLIDeps = {
|
|
@@ -86830,7 +86918,7 @@ async function profileCreateCommand(profileName, startDir) {
|
|
|
86830
86918
|
if (await profileFile.exists()) {
|
|
86831
86919
|
throw new Error(`Profile "${profileName}" already exists at ${profilePath}`);
|
|
86832
86920
|
}
|
|
86833
|
-
|
|
86921
|
+
mkdirSync5(profilesDir, { recursive: true });
|
|
86834
86922
|
await Bun.write(profilePath, "{}");
|
|
86835
86923
|
return profilePath;
|
|
86836
86924
|
}
|
|
@@ -86946,7 +87034,7 @@ async function contextInspectCommand(options) {
|
|
|
86946
87034
|
// src/cli/rules.ts
|
|
86947
87035
|
init_canonical_loader();
|
|
86948
87036
|
init_errors();
|
|
86949
|
-
import { mkdir as
|
|
87037
|
+
import { mkdir as mkdir9 } from "fs/promises";
|
|
86950
87038
|
import { basename as basename8, join as join50 } from "path";
|
|
86951
87039
|
var _rulesCLIDeps = {
|
|
86952
87040
|
readFile: async (path15) => Bun.file(path15).text(),
|
|
@@ -86962,7 +87050,7 @@ var _rulesCLIDeps = {
|
|
|
86962
87050
|
}
|
|
86963
87051
|
},
|
|
86964
87052
|
mkdir: async (path15) => {
|
|
86965
|
-
await
|
|
87053
|
+
await mkdir9(path15, { recursive: true });
|
|
86966
87054
|
},
|
|
86967
87055
|
globCanonicalRuleFiles: (workdir) => {
|
|
86968
87056
|
try {
|
|
@@ -95647,8 +95735,8 @@ Next: nax generate --package ${options.package}`));
|
|
|
95647
95735
|
console.log(source_default.yellow("nax already initialized. Use --force to overwrite."));
|
|
95648
95736
|
return;
|
|
95649
95737
|
}
|
|
95650
|
-
|
|
95651
|
-
|
|
95738
|
+
mkdirSync7(join72(naxDir, "features"), { recursive: true });
|
|
95739
|
+
mkdirSync7(join72(naxDir, "hooks"), { recursive: true });
|
|
95652
95740
|
await Bun.write(join72(naxDir, "config.json"), JSON.stringify(DEFAULT_CONFIG, null, 2));
|
|
95653
95741
|
await Bun.write(join72(naxDir, "hooks.json"), JSON.stringify({
|
|
95654
95742
|
hooks: {
|
|
@@ -95817,7 +95905,7 @@ program2.command("run").description("Run the orchestration loop for a feature").
|
|
|
95817
95905
|
}
|
|
95818
95906
|
try {
|
|
95819
95907
|
const planLogDir = join72(featureDir, "plan");
|
|
95820
|
-
|
|
95908
|
+
mkdirSync7(planLogDir, { recursive: true });
|
|
95821
95909
|
const planLogId = new Date().toISOString().replace(/:/g, "-").replace(/\..+/, "");
|
|
95822
95910
|
const planLogPath = join72(planLogDir, `${planLogId}.jsonl`);
|
|
95823
95911
|
initLogger({ level: "info", filePath: planLogPath, useChalk: false, headless: true });
|
|
@@ -95864,7 +95952,7 @@ program2.command("run").description("Run the orchestration loop for a feature").
|
|
|
95864
95952
|
}
|
|
95865
95953
|
resetLogger();
|
|
95866
95954
|
const runsDir = join72(featureDir, "runs");
|
|
95867
|
-
|
|
95955
|
+
mkdirSync7(runsDir, { recursive: true });
|
|
95868
95956
|
const runId = new Date().toISOString().replace(/:/g, "-").replace(/\..+/, "");
|
|
95869
95957
|
const logFilePath = join72(runsDir, `${runId}.jsonl`);
|
|
95870
95958
|
const isTTY = process.stdout.isTTY ?? false;
|
|
@@ -95971,7 +96059,7 @@ features.command("create <name>").description("Create a new feature").option("-d
|
|
|
95971
96059
|
process.exit(1);
|
|
95972
96060
|
}
|
|
95973
96061
|
const featureDir = join72(naxDir, "features", name);
|
|
95974
|
-
|
|
96062
|
+
mkdirSync7(featureDir, { recursive: true });
|
|
95975
96063
|
await Bun.write(join72(featureDir, "spec.md"), `# Feature: ${name}
|
|
95976
96064
|
|
|
95977
96065
|
## Overview
|
|
@@ -96082,7 +96170,7 @@ Use: nax plan -f <feature> --from <spec>`));
|
|
|
96082
96170
|
}
|
|
96083
96171
|
const config2 = await loadConfig(workdir, cliOverrides);
|
|
96084
96172
|
const featureLogDir = join72(naxDir, "features", options.feature, "plan");
|
|
96085
|
-
|
|
96173
|
+
mkdirSync7(featureLogDir, { recursive: true });
|
|
96086
96174
|
const planLogId = new Date().toISOString().replace(/:/g, "-").replace(/\..+/, "");
|
|
96087
96175
|
const planLogPath = join72(featureLogDir, `${planLogId}.jsonl`);
|
|
96088
96176
|
initLogger({ level: "info", filePath: planLogPath, useChalk: false, headless: true });
|