@nathapp/nax 0.56.1 → 0.56.3
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 +222 -110
- package/package.json +1 -1
package/dist/nax.js
CHANGED
|
@@ -3663,7 +3663,18 @@ var init_env = __esm(() => {
|
|
|
3663
3663
|
init_logger2();
|
|
3664
3664
|
ESSENTIAL_VARS = ["PATH", "TMPDIR", "NODE_ENV", "USER", "LOGNAME"];
|
|
3665
3665
|
API_KEY_VARS = ["ANTHROPIC_API_KEY", "OPENAI_API_KEY", "GEMINI_API_KEY", "GOOGLE_API_KEY", "CLAUDE_API_KEY"];
|
|
3666
|
-
ALLOWED_PREFIXES = [
|
|
3666
|
+
ALLOWED_PREFIXES = [
|
|
3667
|
+
"CLAUDE_",
|
|
3668
|
+
"NAX_",
|
|
3669
|
+
"CLAW_",
|
|
3670
|
+
"TURBO_",
|
|
3671
|
+
"ACPX_",
|
|
3672
|
+
"CODEX_",
|
|
3673
|
+
"GEMINI_",
|
|
3674
|
+
"ANTHROPIC_",
|
|
3675
|
+
"OPENCODE_",
|
|
3676
|
+
"MINIMAX_"
|
|
3677
|
+
];
|
|
3667
3678
|
});
|
|
3668
3679
|
|
|
3669
3680
|
// src/agents/cost/pricing.ts
|
|
@@ -22056,7 +22067,7 @@ var package_default;
|
|
|
22056
22067
|
var init_package = __esm(() => {
|
|
22057
22068
|
package_default = {
|
|
22058
22069
|
name: "@nathapp/nax",
|
|
22059
|
-
version: "0.56.
|
|
22070
|
+
version: "0.56.3",
|
|
22060
22071
|
description: "AI Coding Agent Orchestrator \u2014 loops until done",
|
|
22061
22072
|
type: "module",
|
|
22062
22073
|
bin: {
|
|
@@ -22135,8 +22146,8 @@ var init_version = __esm(() => {
|
|
|
22135
22146
|
NAX_VERSION = package_default.version;
|
|
22136
22147
|
NAX_COMMIT = (() => {
|
|
22137
22148
|
try {
|
|
22138
|
-
if (/^[0-9a-f]{6,10}$/.test("
|
|
22139
|
-
return "
|
|
22149
|
+
if (/^[0-9a-f]{6,10}$/.test("52dcc35f"))
|
|
22150
|
+
return "52dcc35f";
|
|
22140
22151
|
} catch {}
|
|
22141
22152
|
try {
|
|
22142
22153
|
const result = Bun.spawnSync(["git", "rev-parse", "--short", "HEAD"], {
|
|
@@ -22389,6 +22400,18 @@ var DEFAULT_FALLBACK_AGENT = "claude";
|
|
|
22389
22400
|
var init_resolvers = () => {};
|
|
22390
22401
|
|
|
22391
22402
|
// src/debate/session.ts
|
|
22403
|
+
function resolveDebaterModel(debater, config2) {
|
|
22404
|
+
const tier = debater.model ?? "fast";
|
|
22405
|
+
if (!config2?.models)
|
|
22406
|
+
return debater.model;
|
|
22407
|
+
try {
|
|
22408
|
+
const defaultAgent = config2.autoMode?.defaultAgent ?? debater.agent;
|
|
22409
|
+
const modelDef = resolveModelForAgent(config2.models, debater.agent, tier, defaultAgent);
|
|
22410
|
+
return modelDef.model;
|
|
22411
|
+
} catch {
|
|
22412
|
+
return debater.model;
|
|
22413
|
+
}
|
|
22414
|
+
}
|
|
22392
22415
|
function buildFailedResult(storyId, stage, stageConfig, totalCostUsd = 0) {
|
|
22393
22416
|
return {
|
|
22394
22417
|
storyId,
|
|
@@ -22411,10 +22434,12 @@ class DebateSession {
|
|
|
22411
22434
|
storyId;
|
|
22412
22435
|
stage;
|
|
22413
22436
|
stageConfig;
|
|
22437
|
+
config;
|
|
22414
22438
|
constructor(opts) {
|
|
22415
22439
|
this.storyId = opts.storyId;
|
|
22416
22440
|
this.stage = opts.stage;
|
|
22417
22441
|
this.stageConfig = opts.stageConfig;
|
|
22442
|
+
this.config = opts.config;
|
|
22418
22443
|
}
|
|
22419
22444
|
async run(prompt) {
|
|
22420
22445
|
const sessionMode = this.stageConfig.sessionMode ?? "one-shot";
|
|
@@ -22437,11 +22462,17 @@ class DebateSession {
|
|
|
22437
22462
|
}
|
|
22438
22463
|
resolved.push({ debater, adapter });
|
|
22439
22464
|
}
|
|
22465
|
+
logger?.info("debate", "debate:start", {
|
|
22466
|
+
storyId: this.storyId,
|
|
22467
|
+
stage: this.stage,
|
|
22468
|
+
debaters: resolved.map((r) => r.debater.agent)
|
|
22469
|
+
});
|
|
22440
22470
|
const sessions = [];
|
|
22441
22471
|
try {
|
|
22442
22472
|
for (let i = 0;i < resolved.length; i++) {
|
|
22443
22473
|
const { debater, adapter } = resolved[i];
|
|
22444
|
-
const
|
|
22474
|
+
const resolvedModel = resolveDebaterModel(debater, this.config);
|
|
22475
|
+
const cmdStr = resolvedModel ? `acpx --model ${resolvedModel} ${debater.agent}` : `acpx ${debater.agent}`;
|
|
22445
22476
|
const client = _debateSessionDeps.createSpawnAcpClient(cmdStr);
|
|
22446
22477
|
const sessionName = `nax-debate-${this.storyId}-${i}`;
|
|
22447
22478
|
try {
|
|
@@ -22457,9 +22488,19 @@ class DebateSession {
|
|
|
22457
22488
|
}
|
|
22458
22489
|
if (sessions.length < 2) {
|
|
22459
22490
|
if (sessions.length === 1) {
|
|
22491
|
+
logger?.warn("debate", "debate:fallback", {
|
|
22492
|
+
storyId: this.storyId,
|
|
22493
|
+
stage: this.stage,
|
|
22494
|
+
reason: "only 1 session created"
|
|
22495
|
+
});
|
|
22460
22496
|
const solo = sessions[0];
|
|
22461
22497
|
const response = await solo.session.prompt(prompt);
|
|
22462
22498
|
const output = extractSessionOutput(response);
|
|
22499
|
+
logger?.info("debate", "debate:result", {
|
|
22500
|
+
storyId: this.storyId,
|
|
22501
|
+
stage: this.stage,
|
|
22502
|
+
outcome: "passed"
|
|
22503
|
+
});
|
|
22463
22504
|
return {
|
|
22464
22505
|
storyId: this.storyId,
|
|
22465
22506
|
stage: this.stage,
|
|
@@ -22471,6 +22512,11 @@ class DebateSession {
|
|
|
22471
22512
|
totalCostUsd
|
|
22472
22513
|
};
|
|
22473
22514
|
}
|
|
22515
|
+
logger?.warn("debate", "debate:fallback", {
|
|
22516
|
+
storyId: this.storyId,
|
|
22517
|
+
stage: this.stage,
|
|
22518
|
+
reason: "no sessions created"
|
|
22519
|
+
});
|
|
22474
22520
|
return buildFailedResult(this.storyId, this.stage, config2, totalCostUsd);
|
|
22475
22521
|
}
|
|
22476
22522
|
const proposalSettled = await Promise.allSettled(sessions.map(({ session }) => session.prompt(prompt)));
|
|
@@ -22486,8 +22532,22 @@ class DebateSession {
|
|
|
22486
22532
|
}
|
|
22487
22533
|
}
|
|
22488
22534
|
if (successfulSessions.length < 2) {
|
|
22535
|
+
logger?.warn("debate", "debate:fallback", {
|
|
22536
|
+
storyId: this.storyId,
|
|
22537
|
+
stage: this.stage,
|
|
22538
|
+
reason: "fewer than 2 proposal rounds succeeded"
|
|
22539
|
+
});
|
|
22489
22540
|
return buildFailedResult(this.storyId, this.stage, config2, totalCostUsd);
|
|
22490
22541
|
}
|
|
22542
|
+
for (let i = 0;i < successfulSessions.length; i++) {
|
|
22543
|
+
const s = successfulSessions[i];
|
|
22544
|
+
logger?.info("debate", "debate:proposal", {
|
|
22545
|
+
storyId: this.storyId,
|
|
22546
|
+
stage: this.stage,
|
|
22547
|
+
debaterIndex: i,
|
|
22548
|
+
agent: s.entry.debater.agent
|
|
22549
|
+
});
|
|
22550
|
+
}
|
|
22491
22551
|
let critiqueOutputs = [];
|
|
22492
22552
|
if (config2.rounds > 1) {
|
|
22493
22553
|
const proposalOutputs2 = successfulSessions.map((s) => s.output);
|
|
@@ -22506,6 +22566,11 @@ class DebateSession {
|
|
|
22506
22566
|
debater: s.entry.debater,
|
|
22507
22567
|
output: s.output
|
|
22508
22568
|
}));
|
|
22569
|
+
logger?.info("debate", "debate:result", {
|
|
22570
|
+
storyId: this.storyId,
|
|
22571
|
+
stage: this.stage,
|
|
22572
|
+
outcome
|
|
22573
|
+
});
|
|
22509
22574
|
return {
|
|
22510
22575
|
storyId: this.storyId,
|
|
22511
22576
|
stage: this.stage,
|
|
@@ -22534,16 +22599,40 @@ class DebateSession {
|
|
|
22534
22599
|
}
|
|
22535
22600
|
resolved.push({ debater, adapter });
|
|
22536
22601
|
}
|
|
22537
|
-
|
|
22602
|
+
logger?.info("debate", "debate:start", {
|
|
22603
|
+
storyId: this.storyId,
|
|
22604
|
+
stage: this.stage,
|
|
22605
|
+
debaters: resolved.map((r) => r.debater.agent)
|
|
22606
|
+
});
|
|
22607
|
+
const proposalSettled = await Promise.allSettled(resolved.map(({ debater, adapter }) => adapter.complete(prompt, { model: resolveDebaterModel(debater, this.config) }).then((output) => ({ debater, adapter, output, cost: 0 }))));
|
|
22538
22608
|
const successful = proposalSettled.filter((r) => r.status === "fulfilled").map((r) => r.value);
|
|
22539
22609
|
for (const r of proposalSettled) {
|
|
22540
22610
|
if (r.status === "fulfilled") {
|
|
22541
22611
|
totalCostUsd += r.value.cost;
|
|
22542
22612
|
}
|
|
22543
22613
|
}
|
|
22614
|
+
for (let i = 0;i < successful.length; i++) {
|
|
22615
|
+
logger?.info("debate", "debate:proposal", {
|
|
22616
|
+
storyId: this.storyId,
|
|
22617
|
+
stage: this.stage,
|
|
22618
|
+
debaterIndex: i,
|
|
22619
|
+
agent: successful[i].debater.agent,
|
|
22620
|
+
model: resolveDebaterModel(successful[i].debater, this.config)
|
|
22621
|
+
});
|
|
22622
|
+
}
|
|
22544
22623
|
if (successful.length < 2) {
|
|
22545
22624
|
if (successful.length === 1) {
|
|
22625
|
+
logger?.warn("debate", "debate:fallback", {
|
|
22626
|
+
storyId: this.storyId,
|
|
22627
|
+
stage: this.stage,
|
|
22628
|
+
reason: "only 1 debater succeeded"
|
|
22629
|
+
});
|
|
22546
22630
|
const solo = successful[0];
|
|
22631
|
+
logger?.info("debate", "debate:result", {
|
|
22632
|
+
storyId: this.storyId,
|
|
22633
|
+
stage: this.stage,
|
|
22634
|
+
outcome: "passed"
|
|
22635
|
+
});
|
|
22547
22636
|
return {
|
|
22548
22637
|
storyId: this.storyId,
|
|
22549
22638
|
stage: this.stage,
|
|
@@ -22557,8 +22646,20 @@ class DebateSession {
|
|
|
22557
22646
|
}
|
|
22558
22647
|
if (resolved.length > 0) {
|
|
22559
22648
|
const { adapter: fallbackAdapter, debater: fallbackDebater } = resolved[0];
|
|
22649
|
+
logger?.warn("debate", "debate:fallback", {
|
|
22650
|
+
storyId: this.storyId,
|
|
22651
|
+
stage: this.stage,
|
|
22652
|
+
reason: "all debaters failed \u2014 retrying with first adapter"
|
|
22653
|
+
});
|
|
22560
22654
|
try {
|
|
22561
|
-
const fallbackOutput = await fallbackAdapter.complete(prompt, {
|
|
22655
|
+
const fallbackOutput = await fallbackAdapter.complete(prompt, {
|
|
22656
|
+
model: resolveDebaterModel(fallbackDebater, this.config)
|
|
22657
|
+
});
|
|
22658
|
+
logger?.info("debate", "debate:result", {
|
|
22659
|
+
storyId: this.storyId,
|
|
22660
|
+
stage: this.stage,
|
|
22661
|
+
outcome: "passed"
|
|
22662
|
+
});
|
|
22562
22663
|
return {
|
|
22563
22664
|
storyId: this.storyId,
|
|
22564
22665
|
stage: this.stage,
|
|
@@ -22577,7 +22678,7 @@ class DebateSession {
|
|
|
22577
22678
|
if (config2.rounds > 1) {
|
|
22578
22679
|
const proposalOutputs2 = successful.map((p) => p.output);
|
|
22579
22680
|
const critiqueSettled = await Promise.allSettled(successful.map(({ debater, adapter }, i) => adapter.complete(buildCritiquePrompt(prompt, proposalOutputs2, i), {
|
|
22580
|
-
model: debater.
|
|
22681
|
+
model: resolveDebaterModel(debater, this.config)
|
|
22581
22682
|
})));
|
|
22582
22683
|
for (const r of critiqueSettled) {
|
|
22583
22684
|
if (r.status === "fulfilled") {
|
|
@@ -22593,6 +22694,11 @@ class DebateSession {
|
|
|
22593
22694
|
debater: p.debater,
|
|
22594
22695
|
output: p.output
|
|
22595
22696
|
}));
|
|
22697
|
+
logger?.info("debate", "debate:result", {
|
|
22698
|
+
storyId: this.storyId,
|
|
22699
|
+
stage: this.stage,
|
|
22700
|
+
outcome
|
|
22701
|
+
});
|
|
22596
22702
|
return {
|
|
22597
22703
|
storyId: this.storyId,
|
|
22598
22704
|
stage: this.stage,
|
|
@@ -22604,7 +22710,7 @@ class DebateSession {
|
|
|
22604
22710
|
totalCostUsd
|
|
22605
22711
|
};
|
|
22606
22712
|
}
|
|
22607
|
-
async resolve(proposalOutputs, critiqueOutputs,
|
|
22713
|
+
async resolve(proposalOutputs, critiqueOutputs, _successful) {
|
|
22608
22714
|
const resolverConfig = this.stageConfig.resolver;
|
|
22609
22715
|
if (resolverConfig.type === "majority-fail-closed" || resolverConfig.type === "majority-fail-open") {
|
|
22610
22716
|
return majorityResolver(proposalOutputs, resolverConfig.type === "majority-fail-open");
|
|
@@ -22631,6 +22737,7 @@ var RESOLVER_FALLBACK_AGENT = "synthesis", _debateSessionDeps;
|
|
|
22631
22737
|
var init_session = __esm(() => {
|
|
22632
22738
|
init_spawn_client();
|
|
22633
22739
|
init_registry();
|
|
22740
|
+
init_config();
|
|
22634
22741
|
init_logger2();
|
|
22635
22742
|
init_resolvers();
|
|
22636
22743
|
_debateSessionDeps = {
|
|
@@ -26276,7 +26383,8 @@ async function runSemanticReview(workdir, storyGitRef, story, semanticConfig, mo
|
|
|
26276
26383
|
const debateSession = _semanticDeps.createDebateSession({
|
|
26277
26384
|
storyId: story.id,
|
|
26278
26385
|
stage: "review",
|
|
26279
|
-
stageConfig: reviewStageConfig
|
|
26386
|
+
stageConfig: reviewStageConfig,
|
|
26387
|
+
config: naxConfig
|
|
26280
26388
|
});
|
|
26281
26389
|
const debateResult = await debateSession.run(prompt);
|
|
26282
26390
|
let passCount = 0;
|
|
@@ -27030,17 +27138,15 @@ var init_autofix = __esm(() => {
|
|
|
27030
27138
|
});
|
|
27031
27139
|
|
|
27032
27140
|
// src/execution/progress.ts
|
|
27033
|
-
import {
|
|
27141
|
+
import { appendFile as appendFile2, mkdir } from "fs/promises";
|
|
27034
27142
|
import { join as join18 } from "path";
|
|
27035
27143
|
async function appendProgress(featureDir, storyId, status, message) {
|
|
27036
|
-
|
|
27144
|
+
await mkdir(featureDir, { recursive: true });
|
|
27037
27145
|
const progressPath = join18(featureDir, "progress.txt");
|
|
27038
27146
|
const timestamp = new Date().toISOString();
|
|
27039
27147
|
const entry = `[${timestamp}] ${storyId} \u2014 ${status.toUpperCase()} \u2014 ${message}
|
|
27040
27148
|
`;
|
|
27041
|
-
|
|
27042
|
-
const existing = await file3.exists() ? await file3.text() : "";
|
|
27043
|
-
await Bun.write(progressPath, existing + entry);
|
|
27149
|
+
await appendFile2(progressPath, entry);
|
|
27044
27150
|
}
|
|
27045
27151
|
var init_progress = () => {};
|
|
27046
27152
|
|
|
@@ -32384,7 +32490,7 @@ __export(exports_init_context, {
|
|
|
32384
32490
|
_initContextDeps: () => _initContextDeps
|
|
32385
32491
|
});
|
|
32386
32492
|
import { existsSync as existsSync24 } from "fs";
|
|
32387
|
-
import { mkdir } from "fs/promises";
|
|
32493
|
+
import { mkdir as mkdir2 } from "fs/promises";
|
|
32388
32494
|
import { basename as basename3, join as join30 } from "path";
|
|
32389
32495
|
async function findFiles(dir, maxFiles = 200) {
|
|
32390
32496
|
try {
|
|
@@ -32628,7 +32734,7 @@ async function initPackage(repoRoot, packagePath, force = false) {
|
|
|
32628
32734
|
return;
|
|
32629
32735
|
}
|
|
32630
32736
|
if (!existsSync24(naxDir)) {
|
|
32631
|
-
await
|
|
32737
|
+
await mkdir2(naxDir, { recursive: true });
|
|
32632
32738
|
}
|
|
32633
32739
|
const content = generatePackageContextTemplate(packagePath);
|
|
32634
32740
|
await Bun.write(contextPath, content);
|
|
@@ -32643,7 +32749,7 @@ async function initContext(projectRoot, options = {}) {
|
|
|
32643
32749
|
return;
|
|
32644
32750
|
}
|
|
32645
32751
|
if (!existsSync24(naxDir)) {
|
|
32646
|
-
await
|
|
32752
|
+
await mkdir2(naxDir, { recursive: true });
|
|
32647
32753
|
}
|
|
32648
32754
|
const scan = await scanProject(projectRoot);
|
|
32649
32755
|
let content;
|
|
@@ -34346,7 +34452,7 @@ var init_headless_formatter = __esm(() => {
|
|
|
34346
34452
|
});
|
|
34347
34453
|
|
|
34348
34454
|
// src/pipeline/subscribers/events-writer.ts
|
|
34349
|
-
import { appendFile as
|
|
34455
|
+
import { appendFile as appendFile3, mkdir as mkdir3 } from "fs/promises";
|
|
34350
34456
|
import { homedir as homedir5 } from "os";
|
|
34351
34457
|
import { basename as basename6, join as join47 } from "path";
|
|
34352
34458
|
function wireEventsWriter(bus, feature, runId, workdir) {
|
|
@@ -34359,10 +34465,10 @@ function wireEventsWriter(bus, feature, runId, workdir) {
|
|
|
34359
34465
|
return (async () => {
|
|
34360
34466
|
try {
|
|
34361
34467
|
if (!dirReady) {
|
|
34362
|
-
await
|
|
34468
|
+
await mkdir3(eventsDir, { recursive: true });
|
|
34363
34469
|
dirReady = true;
|
|
34364
34470
|
}
|
|
34365
|
-
await
|
|
34471
|
+
await appendFile3(eventsFile, `${JSON.stringify(line)}
|
|
34366
34472
|
`);
|
|
34367
34473
|
} catch (err) {
|
|
34368
34474
|
logger?.warn("events-writer", "Failed to write event line (non-fatal)", {
|
|
@@ -34532,7 +34638,7 @@ var init_interaction2 = __esm(() => {
|
|
|
34532
34638
|
});
|
|
34533
34639
|
|
|
34534
34640
|
// src/pipeline/subscribers/registry.ts
|
|
34535
|
-
import { mkdir as
|
|
34641
|
+
import { mkdir as mkdir4, writeFile } from "fs/promises";
|
|
34536
34642
|
import { homedir as homedir6 } from "os";
|
|
34537
34643
|
import { basename as basename7, join as join48 } from "path";
|
|
34538
34644
|
function wireRegistry(bus, feature, runId, workdir) {
|
|
@@ -34543,7 +34649,7 @@ function wireRegistry(bus, feature, runId, workdir) {
|
|
|
34543
34649
|
const unsub = bus.on("run:started", (_ev) => {
|
|
34544
34650
|
return (async () => {
|
|
34545
34651
|
try {
|
|
34546
|
-
await
|
|
34652
|
+
await mkdir4(runDir, { recursive: true });
|
|
34547
34653
|
const meta3 = {
|
|
34548
34654
|
runId,
|
|
34549
34655
|
project,
|
|
@@ -35495,7 +35601,7 @@ __export(exports_manager, {
|
|
|
35495
35601
|
WorktreeManager: () => WorktreeManager
|
|
35496
35602
|
});
|
|
35497
35603
|
import { existsSync as existsSync32, symlinkSync } from "fs";
|
|
35498
|
-
import { mkdir as
|
|
35604
|
+
import { mkdir as mkdir5 } from "fs/promises";
|
|
35499
35605
|
import { join as join50 } from "path";
|
|
35500
35606
|
|
|
35501
35607
|
class WorktreeManager {
|
|
@@ -35504,7 +35610,7 @@ class WorktreeManager {
|
|
|
35504
35610
|
const infoDir = join50(projectRoot, ".git", "info");
|
|
35505
35611
|
const excludePath = join50(infoDir, "exclude");
|
|
35506
35612
|
try {
|
|
35507
|
-
await
|
|
35613
|
+
await mkdir5(infoDir, { recursive: true });
|
|
35508
35614
|
let existing = "";
|
|
35509
35615
|
if (existsSync32(excludePath)) {
|
|
35510
35616
|
existing = await Bun.file(excludePath).text();
|
|
@@ -36685,6 +36791,7 @@ class StatusWriter {
|
|
|
36685
36791
|
_prd = null;
|
|
36686
36792
|
_currentStory = null;
|
|
36687
36793
|
_consecutiveWriteFailures = 0;
|
|
36794
|
+
_mutex = Promise.resolve();
|
|
36688
36795
|
constructor(statusFile, config2, ctx) {
|
|
36689
36796
|
this.statusFile = statusFile;
|
|
36690
36797
|
this.costLimit = config2.execution.costLimit === Number.POSITIVE_INFINITY ? null : config2.execution.costLimit;
|
|
@@ -36720,6 +36827,11 @@ class StatusWriter {
|
|
|
36720
36827
|
async update(totalCost, iterations, overrides = {}) {
|
|
36721
36828
|
if (!this._prd)
|
|
36722
36829
|
return;
|
|
36830
|
+
const write = this._doUpdate(totalCost, iterations, overrides);
|
|
36831
|
+
this._mutex = this._mutex.then(() => write).catch(() => write);
|
|
36832
|
+
return this._mutex;
|
|
36833
|
+
}
|
|
36834
|
+
async _doUpdate(totalCost, iterations, overrides) {
|
|
36723
36835
|
const safeLogger = getSafeLogger();
|
|
36724
36836
|
try {
|
|
36725
36837
|
const base = this.getSnapshot(totalCost, iterations);
|
|
@@ -36744,20 +36856,23 @@ class StatusWriter {
|
|
|
36744
36856
|
return;
|
|
36745
36857
|
const safeLogger = getSafeLogger();
|
|
36746
36858
|
const featureStatusPath = join52(featureDir, "status.json");
|
|
36747
|
-
|
|
36748
|
-
|
|
36749
|
-
|
|
36750
|
-
|
|
36859
|
+
const write = async () => {
|
|
36860
|
+
try {
|
|
36861
|
+
const base = this.getSnapshot(totalCost, iterations);
|
|
36862
|
+
if (!base)
|
|
36863
|
+
throw new Error("Failed to get snapshot");
|
|
36864
|
+
const state = { ...base, ...overrides };
|
|
36865
|
+
await writeStatusFile(featureStatusPath, buildStatusSnapshot(state));
|
|
36866
|
+
safeLogger?.debug("status-file", "Feature status written", { path: featureStatusPath });
|
|
36867
|
+
} catch (err) {
|
|
36868
|
+
safeLogger?.warn("status-file", "Failed to write feature status file (non-fatal)", {
|
|
36869
|
+
path: featureStatusPath,
|
|
36870
|
+
error: err.message
|
|
36871
|
+
});
|
|
36751
36872
|
}
|
|
36752
|
-
|
|
36753
|
-
|
|
36754
|
-
|
|
36755
|
-
} catch (err) {
|
|
36756
|
-
safeLogger?.warn("status-file", "Failed to write feature status file (non-fatal)", {
|
|
36757
|
-
path: featureStatusPath,
|
|
36758
|
-
error: err.message
|
|
36759
|
-
});
|
|
36760
|
-
}
|
|
36873
|
+
};
|
|
36874
|
+
this._mutex = this._mutex.then(write).catch(() => write());
|
|
36875
|
+
return this._mutex;
|
|
36761
36876
|
}
|
|
36762
36877
|
}
|
|
36763
36878
|
var init_status_writer = __esm(() => {
|
|
@@ -36856,7 +36971,7 @@ var exports_precheck_runner = {};
|
|
|
36856
36971
|
__export(exports_precheck_runner, {
|
|
36857
36972
|
runPrecheckValidation: () => runPrecheckValidation
|
|
36858
36973
|
});
|
|
36859
|
-
import { mkdirSync as
|
|
36974
|
+
import { mkdirSync as mkdirSync4 } from "fs";
|
|
36860
36975
|
import path17 from "path";
|
|
36861
36976
|
async function runPrecheckValidation(ctx) {
|
|
36862
36977
|
const logger = getSafeLogger();
|
|
@@ -36871,7 +36986,7 @@ async function runPrecheckValidation(ctx) {
|
|
|
36871
36986
|
format: "human"
|
|
36872
36987
|
});
|
|
36873
36988
|
if (ctx.logFilePath) {
|
|
36874
|
-
|
|
36989
|
+
mkdirSync4(path17.dirname(ctx.logFilePath), { recursive: true });
|
|
36875
36990
|
const precheckLog = {
|
|
36876
36991
|
type: "precheck",
|
|
36877
36992
|
timestamp: new Date().toISOString(),
|
|
@@ -68177,7 +68292,7 @@ var require_jsx_dev_runtime = __commonJS((exports, module) => {
|
|
|
68177
68292
|
|
|
68178
68293
|
// bin/nax.ts
|
|
68179
68294
|
init_source();
|
|
68180
|
-
import { existsSync as existsSync34, mkdirSync as
|
|
68295
|
+
import { existsSync as existsSync34, mkdirSync as mkdirSync5 } from "fs";
|
|
68181
68296
|
import { homedir as homedir8 } from "os";
|
|
68182
68297
|
import { join as join55 } from "path";
|
|
68183
68298
|
|
|
@@ -69453,78 +69568,75 @@ async function planCommand(workdir, config2, options) {
|
|
|
69453
69568
|
autoModel = resolveModelForAgent2(config2.models, defaultAgent, planTier, defaultAgent).model;
|
|
69454
69569
|
}
|
|
69455
69570
|
} catch {}
|
|
69456
|
-
|
|
69457
|
-
|
|
69458
|
-
|
|
69459
|
-
|
|
69460
|
-
|
|
69461
|
-
feature: options.feature,
|
|
69462
|
-
timeoutSeconds
|
|
69463
|
-
});
|
|
69464
|
-
const pidRegistry = new PidRegistry(workdir);
|
|
69465
|
-
try {
|
|
69466
|
-
await adapter.plan({
|
|
69467
|
-
prompt,
|
|
69571
|
+
const runSingleAgentPlan = async () => {
|
|
69572
|
+
if (isAcp) {
|
|
69573
|
+
logger?.info("plan", "Starting ACP auto planning session", {
|
|
69574
|
+
agent: agentName,
|
|
69575
|
+
model: autoModel ?? config2?.plan?.model ?? "balanced",
|
|
69468
69576
|
workdir,
|
|
69469
|
-
|
|
69470
|
-
timeoutSeconds
|
|
69471
|
-
config: config2,
|
|
69472
|
-
modelTier: config2?.plan?.model ?? "balanced",
|
|
69473
|
-
dangerouslySkipPermissions: resolvePermissions(config2, "plan").skipPermissions,
|
|
69474
|
-
maxInteractionTurns: config2?.agent?.maxInteractionTurns,
|
|
69475
|
-
featureName: options.feature,
|
|
69476
|
-
pidRegistry,
|
|
69477
|
-
sessionRole: "plan"
|
|
69478
|
-
});
|
|
69479
|
-
} finally {
|
|
69480
|
-
await pidRegistry.killAll().catch(() => {});
|
|
69481
|
-
}
|
|
69482
|
-
if (!_planDeps.existsSync(outputPath)) {
|
|
69483
|
-
throw new Error(`[plan] ACP agent did not write PRD to ${outputPath}. Check agent logs for errors.`);
|
|
69484
|
-
}
|
|
69485
|
-
rawResponse = await _planDeps.readFile(outputPath);
|
|
69486
|
-
} else {
|
|
69487
|
-
const debateEnabled = config2?.debate?.enabled && config2?.debate?.stages?.plan?.enabled;
|
|
69488
|
-
if (debateEnabled) {
|
|
69489
|
-
const planStageConfig = config2.debate?.stages.plan;
|
|
69490
|
-
const debateSession = _planDeps.createDebateSession({
|
|
69491
|
-
storyId: options.feature,
|
|
69492
|
-
stage: "plan",
|
|
69493
|
-
stageConfig: planStageConfig
|
|
69577
|
+
feature: options.feature,
|
|
69578
|
+
timeoutSeconds
|
|
69494
69579
|
});
|
|
69495
|
-
const
|
|
69496
|
-
|
|
69497
|
-
|
|
69498
|
-
|
|
69499
|
-
logger?.warn("debate", "All debaters failed \u2014 falling back to single agent", {
|
|
69500
|
-
stage: "debate",
|
|
69501
|
-
event: "fallback"
|
|
69502
|
-
});
|
|
69503
|
-
rawResponse = await adapter.complete(prompt, {
|
|
69504
|
-
model: autoModel,
|
|
69505
|
-
jsonMode: true,
|
|
69580
|
+
const pidRegistry = new PidRegistry(workdir);
|
|
69581
|
+
try {
|
|
69582
|
+
await adapter.plan({
|
|
69583
|
+
prompt,
|
|
69506
69584
|
workdir,
|
|
69585
|
+
interactive: false,
|
|
69586
|
+
timeoutSeconds,
|
|
69507
69587
|
config: config2,
|
|
69588
|
+
modelTier: config2?.plan?.model ?? "balanced",
|
|
69589
|
+
dangerouslySkipPermissions: resolvePermissions(config2, "plan").skipPermissions,
|
|
69590
|
+
maxInteractionTurns: config2?.agent?.maxInteractionTurns,
|
|
69508
69591
|
featureName: options.feature,
|
|
69592
|
+
pidRegistry,
|
|
69509
69593
|
sessionRole: "plan"
|
|
69510
69594
|
});
|
|
69595
|
+
} finally {
|
|
69596
|
+
await pidRegistry.killAll().catch(() => {});
|
|
69511
69597
|
}
|
|
69512
|
-
|
|
69513
|
-
|
|
69514
|
-
|
|
69515
|
-
|
|
69516
|
-
workdir,
|
|
69517
|
-
config: config2,
|
|
69518
|
-
featureName: options.feature,
|
|
69519
|
-
sessionRole: "plan"
|
|
69520
|
-
});
|
|
69598
|
+
if (!_planDeps.existsSync(outputPath)) {
|
|
69599
|
+
throw new Error(`[plan] ACP agent did not write PRD to ${outputPath}. Check agent logs for errors.`);
|
|
69600
|
+
}
|
|
69601
|
+
return await _planDeps.readFile(outputPath);
|
|
69521
69602
|
}
|
|
69603
|
+
let result = await adapter.complete(prompt, {
|
|
69604
|
+
model: autoModel,
|
|
69605
|
+
jsonMode: true,
|
|
69606
|
+
workdir,
|
|
69607
|
+
config: config2,
|
|
69608
|
+
featureName: options.feature,
|
|
69609
|
+
sessionRole: "plan"
|
|
69610
|
+
});
|
|
69522
69611
|
try {
|
|
69523
|
-
const envelope = JSON.parse(
|
|
69612
|
+
const envelope = JSON.parse(result);
|
|
69524
69613
|
if (envelope?.type === "result" && typeof envelope?.result === "string") {
|
|
69525
|
-
|
|
69614
|
+
result = envelope.result;
|
|
69526
69615
|
}
|
|
69527
69616
|
} catch {}
|
|
69617
|
+
return result;
|
|
69618
|
+
};
|
|
69619
|
+
const debateEnabled = config2?.debate?.enabled && config2?.debate?.stages?.plan?.enabled;
|
|
69620
|
+
if (debateEnabled) {
|
|
69621
|
+
const planStageConfig = config2?.debate?.stages.plan;
|
|
69622
|
+
const debateSession = _planDeps.createDebateSession({
|
|
69623
|
+
storyId: options.feature,
|
|
69624
|
+
stage: "plan",
|
|
69625
|
+
stageConfig: planStageConfig,
|
|
69626
|
+
config: config2
|
|
69627
|
+
});
|
|
69628
|
+
const debateResult = await debateSession.run(prompt);
|
|
69629
|
+
if (debateResult.outcome !== "failed" && debateResult.output) {
|
|
69630
|
+
rawResponse = debateResult.output;
|
|
69631
|
+
} else {
|
|
69632
|
+
logger?.warn("debate", "All debaters failed \u2014 falling back to single agent", {
|
|
69633
|
+
stage: "debate",
|
|
69634
|
+
event: "fallback"
|
|
69635
|
+
});
|
|
69636
|
+
rawResponse = await runSingleAgentPlan();
|
|
69637
|
+
}
|
|
69638
|
+
} else {
|
|
69639
|
+
rawResponse = await runSingleAgentPlan();
|
|
69528
69640
|
}
|
|
69529
69641
|
} else {
|
|
69530
69642
|
const prompt = buildPlanningPrompt(specContent, codebaseContext, outputPath, relativePackages, packageDetails, config2?.project);
|
|
@@ -70589,7 +70701,7 @@ async function runsShowCommand(options) {
|
|
|
70589
70701
|
}
|
|
70590
70702
|
// src/cli/prompts-main.ts
|
|
70591
70703
|
init_logger2();
|
|
70592
|
-
import { existsSync as existsSync22, mkdirSync as
|
|
70704
|
+
import { existsSync as existsSync22, mkdirSync as mkdirSync2 } from "fs";
|
|
70593
70705
|
import { join as join28 } from "path";
|
|
70594
70706
|
|
|
70595
70707
|
// src/pipeline/index.ts
|
|
@@ -70729,7 +70841,7 @@ async function promptsCommand(options) {
|
|
|
70729
70841
|
throw new Error(storyId ? `Story "${storyId}" not found in feature "${feature}"` : `No stories found in feature "${feature}"`);
|
|
70730
70842
|
}
|
|
70731
70843
|
if (outputDir) {
|
|
70732
|
-
|
|
70844
|
+
mkdirSync2(outputDir, { recursive: true });
|
|
70733
70845
|
}
|
|
70734
70846
|
logger.info("cli", "Assembling prompts", {
|
|
70735
70847
|
feature,
|
|
@@ -70809,7 +70921,7 @@ ${"=".repeat(80)}`);
|
|
|
70809
70921
|
return processedStories;
|
|
70810
70922
|
}
|
|
70811
70923
|
// src/cli/prompts-init.ts
|
|
70812
|
-
import { existsSync as existsSync23, mkdirSync as
|
|
70924
|
+
import { existsSync as existsSync23, mkdirSync as mkdirSync3 } from "fs";
|
|
70813
70925
|
import { join as join29 } from "path";
|
|
70814
70926
|
var TEMPLATE_ROLES = [
|
|
70815
70927
|
{ file: "test-writer.md", role: "test-writer" },
|
|
@@ -70835,7 +70947,7 @@ var TEMPLATE_HEADER = `<!--
|
|
|
70835
70947
|
async function promptsInitCommand(options) {
|
|
70836
70948
|
const { workdir, force = false, autoWireConfig = true } = options;
|
|
70837
70949
|
const templatesDir = join29(workdir, ".nax", "templates");
|
|
70838
|
-
|
|
70950
|
+
mkdirSync3(templatesDir, { recursive: true });
|
|
70839
70951
|
const existingFiles = TEMPLATE_ROLES.map((t) => t.file).filter((f) => existsSync23(join29(templatesDir, f)));
|
|
70840
70952
|
if (existingFiles.length > 0 && !force) {
|
|
70841
70953
|
console.warn(`[WARN] nax/templates/ already contains files: ${existingFiles.join(", ")}. No files overwritten.
|
|
@@ -80304,8 +80416,8 @@ Next: nax generate --package ${options.package}`));
|
|
|
80304
80416
|
console.log(source_default.yellow("nax already initialized. Use --force to overwrite."));
|
|
80305
80417
|
return;
|
|
80306
80418
|
}
|
|
80307
|
-
|
|
80308
|
-
|
|
80419
|
+
mkdirSync5(join55(naxDir, "features"), { recursive: true });
|
|
80420
|
+
mkdirSync5(join55(naxDir, "hooks"), { recursive: true });
|
|
80309
80421
|
await Bun.write(join55(naxDir, "config.json"), JSON.stringify(DEFAULT_CONFIG, null, 2));
|
|
80310
80422
|
await Bun.write(join55(naxDir, "hooks.json"), JSON.stringify({
|
|
80311
80423
|
hooks: {
|
|
@@ -80470,7 +80582,7 @@ program2.command("run").description("Run the orchestration loop for a feature").
|
|
|
80470
80582
|
}
|
|
80471
80583
|
try {
|
|
80472
80584
|
const planLogDir = join55(featureDir, "plan");
|
|
80473
|
-
|
|
80585
|
+
mkdirSync5(planLogDir, { recursive: true });
|
|
80474
80586
|
const planLogId = new Date().toISOString().replace(/:/g, "-").replace(/\..+/, "");
|
|
80475
80587
|
const planLogPath = join55(planLogDir, `${planLogId}.jsonl`);
|
|
80476
80588
|
initLogger({ level: "info", filePath: planLogPath, useChalk: false, headless: true });
|
|
@@ -80517,7 +80629,7 @@ program2.command("run").description("Run the orchestration loop for a feature").
|
|
|
80517
80629
|
}
|
|
80518
80630
|
resetLogger();
|
|
80519
80631
|
const runsDir = join55(featureDir, "runs");
|
|
80520
|
-
|
|
80632
|
+
mkdirSync5(runsDir, { recursive: true });
|
|
80521
80633
|
const runId = new Date().toISOString().replace(/:/g, "-").replace(/\..+/, "");
|
|
80522
80634
|
const logFilePath = join55(runsDir, `${runId}.jsonl`);
|
|
80523
80635
|
const isTTY = process.stdout.isTTY ?? false;
|
|
@@ -80623,7 +80735,7 @@ features.command("create <name>").description("Create a new feature").option("-d
|
|
|
80623
80735
|
process.exit(1);
|
|
80624
80736
|
}
|
|
80625
80737
|
const featureDir = join55(naxDir, "features", name);
|
|
80626
|
-
|
|
80738
|
+
mkdirSync5(featureDir, { recursive: true });
|
|
80627
80739
|
await Bun.write(join55(featureDir, "spec.md"), `# Feature: ${name}
|
|
80628
80740
|
|
|
80629
80741
|
## Overview
|
|
@@ -80730,7 +80842,7 @@ Use: nax plan -f <feature> --from <spec>`));
|
|
|
80730
80842
|
}
|
|
80731
80843
|
const config2 = await loadConfig(workdir);
|
|
80732
80844
|
const featureLogDir = join55(naxDir, "features", options.feature, "plan");
|
|
80733
|
-
|
|
80845
|
+
mkdirSync5(featureLogDir, { recursive: true });
|
|
80734
80846
|
const planLogId = new Date().toISOString().replace(/:/g, "-").replace(/\..+/, "");
|
|
80735
80847
|
const planLogPath = join55(featureLogDir, `${planLogId}.jsonl`);
|
|
80736
80848
|
initLogger({ level: "info", filePath: planLogPath, useChalk: false, headless: true });
|