@nathapp/nax 0.46.0 → 0.46.2
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/CHANGELOG.md +22 -0
- package/dist/nax.js +343 -188
- package/package.json +1 -1
- package/src/acceptance/generator.ts +1 -1
- package/src/acceptance/types.ts +2 -0
- package/src/agents/acp/cost.ts +5 -75
- package/src/agents/acp/spawn-client.ts +11 -1
- package/src/agents/claude/cost.ts +12 -264
- package/src/agents/claude/execution.ts +12 -1
- package/src/agents/cost/calculate.ts +154 -0
- package/src/agents/cost/index.ts +10 -0
- package/src/agents/cost/parse.ts +97 -0
- package/src/agents/cost/pricing.ts +59 -0
- package/src/agents/cost/types.ts +45 -0
- package/src/agents/index.ts +4 -2
- package/src/agents/types.ts +3 -0
- package/src/cli/init.ts +15 -1
- package/src/pipeline/stages/acceptance-setup.ts +1 -0
- package/src/pipeline/stages/autofix.ts +112 -25
- package/src/precheck/checks-git.ts +28 -2
- package/src/precheck/checks-warnings.ts +30 -2
- package/src/precheck/checks.ts +1 -0
- package/src/precheck/index.ts +2 -0
package/dist/nax.js
CHANGED
|
@@ -3458,7 +3458,46 @@ var init_complete = __esm(() => {
|
|
|
3458
3458
|
};
|
|
3459
3459
|
});
|
|
3460
3460
|
|
|
3461
|
-
// src/agents/
|
|
3461
|
+
// src/agents/cost/pricing.ts
|
|
3462
|
+
var COST_RATES, MODEL_PRICING;
|
|
3463
|
+
var init_pricing = __esm(() => {
|
|
3464
|
+
COST_RATES = {
|
|
3465
|
+
fast: {
|
|
3466
|
+
inputPer1M: 0.8,
|
|
3467
|
+
outputPer1M: 4
|
|
3468
|
+
},
|
|
3469
|
+
balanced: {
|
|
3470
|
+
inputPer1M: 3,
|
|
3471
|
+
outputPer1M: 15
|
|
3472
|
+
},
|
|
3473
|
+
powerful: {
|
|
3474
|
+
inputPer1M: 15,
|
|
3475
|
+
outputPer1M: 75
|
|
3476
|
+
}
|
|
3477
|
+
};
|
|
3478
|
+
MODEL_PRICING = {
|
|
3479
|
+
sonnet: { input: 3, output: 15 },
|
|
3480
|
+
haiku: { input: 0.8, output: 4, cacheRead: 0.1, cacheCreation: 1 },
|
|
3481
|
+
opus: { input: 15, output: 75 },
|
|
3482
|
+
"claude-sonnet-4": { input: 3, output: 15 },
|
|
3483
|
+
"claude-sonnet-4-5": { input: 3, output: 15 },
|
|
3484
|
+
"claude-sonnet-4-6": { input: 3, output: 15 },
|
|
3485
|
+
"claude-haiku": { input: 0.8, output: 4, cacheRead: 0.1, cacheCreation: 1 },
|
|
3486
|
+
"claude-haiku-4-5": { input: 0.8, output: 4, cacheRead: 0.1, cacheCreation: 1 },
|
|
3487
|
+
"claude-opus": { input: 15, output: 75 },
|
|
3488
|
+
"claude-opus-4": { input: 15, output: 75 },
|
|
3489
|
+
"claude-opus-4-6": { input: 15, output: 75 },
|
|
3490
|
+
"gpt-4.1": { input: 10, output: 30 },
|
|
3491
|
+
"gpt-4": { input: 30, output: 60 },
|
|
3492
|
+
"gpt-3.5-turbo": { input: 0.5, output: 1.5 },
|
|
3493
|
+
"gemini-2.5-pro": { input: 0.075, output: 0.3 },
|
|
3494
|
+
"gemini-2-pro": { input: 0.075, output: 0.3 },
|
|
3495
|
+
codex: { input: 0.02, output: 0.06 },
|
|
3496
|
+
"code-davinci-002": { input: 0.02, output: 0.06 }
|
|
3497
|
+
};
|
|
3498
|
+
});
|
|
3499
|
+
|
|
3500
|
+
// src/agents/cost/parse.ts
|
|
3462
3501
|
function parseTokenUsage(output) {
|
|
3463
3502
|
try {
|
|
3464
3503
|
const jsonMatch = output.match(/\{[^}]*"usage"\s*:\s*\{[^}]*"input_tokens"\s*:\s*(\d+)[^}]*"output_tokens"\s*:\s*(\d+)[^}]*\}[^}]*\}/);
|
|
@@ -3502,6 +3541,8 @@ function parseTokenUsage(output) {
|
|
|
3502
3541
|
}
|
|
3503
3542
|
return null;
|
|
3504
3543
|
}
|
|
3544
|
+
|
|
3545
|
+
// src/agents/cost/calculate.ts
|
|
3505
3546
|
function estimateCost(modelTier, inputTokens, outputTokens, customRates) {
|
|
3506
3547
|
const rates = customRates ?? COST_RATES[modelTier];
|
|
3507
3548
|
const inputCost = inputTokens / 1e6 * rates.inputPer1M;
|
|
@@ -3543,25 +3584,45 @@ function formatCostWithConfidence(estimate) {
|
|
|
3543
3584
|
return `~${formattedCost} (duration-based)`;
|
|
3544
3585
|
}
|
|
3545
3586
|
}
|
|
3546
|
-
|
|
3587
|
+
function estimateCostFromTokenUsage(usage, model) {
|
|
3588
|
+
const pricing = MODEL_PRICING[model];
|
|
3589
|
+
if (!pricing) {
|
|
3590
|
+
const fallbackInputRate = 3 / 1e6;
|
|
3591
|
+
const fallbackOutputRate = 15 / 1e6;
|
|
3592
|
+
const inputCost2 = (usage.input_tokens ?? 0) * fallbackInputRate;
|
|
3593
|
+
const outputCost2 = (usage.output_tokens ?? 0) * fallbackOutputRate;
|
|
3594
|
+
const cacheReadCost2 = (usage.cache_read_input_tokens ?? 0) * (0.5 / 1e6);
|
|
3595
|
+
const cacheCreationCost2 = (usage.cache_creation_input_tokens ?? 0) * (2 / 1e6);
|
|
3596
|
+
return inputCost2 + outputCost2 + cacheReadCost2 + cacheCreationCost2;
|
|
3597
|
+
}
|
|
3598
|
+
const inputRate = pricing.input / 1e6;
|
|
3599
|
+
const outputRate = pricing.output / 1e6;
|
|
3600
|
+
const cacheReadRate = (pricing.cacheRead ?? pricing.input * 0.1) / 1e6;
|
|
3601
|
+
const cacheCreationRate = (pricing.cacheCreation ?? pricing.input * 0.33) / 1e6;
|
|
3602
|
+
const inputCost = (usage.input_tokens ?? 0) * inputRate;
|
|
3603
|
+
const outputCost = (usage.output_tokens ?? 0) * outputRate;
|
|
3604
|
+
const cacheReadCost = (usage.cache_read_input_tokens ?? 0) * cacheReadRate;
|
|
3605
|
+
const cacheCreationCost = (usage.cache_creation_input_tokens ?? 0) * cacheCreationRate;
|
|
3606
|
+
return inputCost + outputCost + cacheReadCost + cacheCreationCost;
|
|
3607
|
+
}
|
|
3608
|
+
var init_calculate = __esm(() => {
|
|
3609
|
+
init_pricing();
|
|
3610
|
+
});
|
|
3611
|
+
|
|
3612
|
+
// src/agents/cost/index.ts
|
|
3547
3613
|
var init_cost = __esm(() => {
|
|
3548
|
-
|
|
3549
|
-
|
|
3550
|
-
|
|
3551
|
-
|
|
3552
|
-
|
|
3553
|
-
|
|
3554
|
-
|
|
3555
|
-
outputPer1M: 15
|
|
3556
|
-
},
|
|
3557
|
-
powerful: {
|
|
3558
|
-
inputPer1M: 15,
|
|
3559
|
-
outputPer1M: 75
|
|
3560
|
-
}
|
|
3561
|
-
};
|
|
3614
|
+
init_pricing();
|
|
3615
|
+
init_calculate();
|
|
3616
|
+
});
|
|
3617
|
+
|
|
3618
|
+
// src/agents/claude/cost.ts
|
|
3619
|
+
var init_cost2 = __esm(() => {
|
|
3620
|
+
init_cost();
|
|
3562
3621
|
});
|
|
3563
3622
|
|
|
3564
3623
|
// src/agents/claude/execution.ts
|
|
3624
|
+
import { homedir } from "os";
|
|
3625
|
+
import { isAbsolute } from "path";
|
|
3565
3626
|
function buildCommand(binary, options) {
|
|
3566
3627
|
const model = options.modelDef.model;
|
|
3567
3628
|
const { skipPermissions } = resolvePermissions(options.config, options.pipelineStage ?? "run");
|
|
@@ -3570,12 +3631,19 @@ function buildCommand(binary, options) {
|
|
|
3570
3631
|
}
|
|
3571
3632
|
function buildAllowedEnv(options) {
|
|
3572
3633
|
const allowed = {};
|
|
3573
|
-
const essentialVars = ["PATH", "
|
|
3634
|
+
const essentialVars = ["PATH", "TMPDIR", "NODE_ENV", "USER", "LOGNAME"];
|
|
3574
3635
|
for (const varName of essentialVars) {
|
|
3575
3636
|
if (process.env[varName]) {
|
|
3576
3637
|
allowed[varName] = process.env[varName];
|
|
3577
3638
|
}
|
|
3578
3639
|
}
|
|
3640
|
+
const rawHome = process.env.HOME ?? "";
|
|
3641
|
+
const safeHome = rawHome && isAbsolute(rawHome) ? rawHome : homedir();
|
|
3642
|
+
if (rawHome !== safeHome) {
|
|
3643
|
+
const logger = getLogger();
|
|
3644
|
+
logger.warn("env", `HOME env is not absolute ("${rawHome}"), falling back to os.homedir(): ${safeHome}`);
|
|
3645
|
+
}
|
|
3646
|
+
allowed.HOME = safeHome;
|
|
3579
3647
|
const apiKeyVars = ["ANTHROPIC_API_KEY", "OPENAI_API_KEY"];
|
|
3580
3648
|
for (const varName of apiKeyVars) {
|
|
3581
3649
|
if (process.env[varName]) {
|
|
@@ -3665,7 +3733,7 @@ async function executeOnce(binary, options, pidRegistry) {
|
|
|
3665
3733
|
var MAX_AGENT_OUTPUT_CHARS = 5000, MAX_AGENT_STDERR_CHARS = 1000, SIGKILL_GRACE_PERIOD_MS = 5000, _runOnceDeps;
|
|
3666
3734
|
var init_execution = __esm(() => {
|
|
3667
3735
|
init_logger2();
|
|
3668
|
-
|
|
3736
|
+
init_cost2();
|
|
3669
3737
|
_runOnceDeps = {
|
|
3670
3738
|
killProc(proc, signal) {
|
|
3671
3739
|
proc.kill(signal);
|
|
@@ -18671,7 +18739,7 @@ Respond with ONLY the TypeScript test code (no markdown code fences, no explanat
|
|
|
18671
18739
|
testable: c.testable,
|
|
18672
18740
|
storyId: c.storyId
|
|
18673
18741
|
})), null, 2);
|
|
18674
|
-
await _generatorPRDDeps.writeFile(join2(options.
|
|
18742
|
+
await _generatorPRDDeps.writeFile(join2(options.featureDir, "acceptance-refined.json"), refinedJsonContent);
|
|
18675
18743
|
return { testCode, criteria };
|
|
18676
18744
|
}
|
|
18677
18745
|
function buildStrategyInstructions(strategy, framework) {
|
|
@@ -19047,13 +19115,21 @@ function parseAcpxJsonOutput(rawOutput) {
|
|
|
19047
19115
|
}
|
|
19048
19116
|
|
|
19049
19117
|
// src/agents/acp/spawn-client.ts
|
|
19118
|
+
import { homedir as homedir2 } from "os";
|
|
19119
|
+
import { isAbsolute as isAbsolute2 } from "path";
|
|
19050
19120
|
function buildAllowedEnv2(extraEnv) {
|
|
19051
19121
|
const allowed = {};
|
|
19052
|
-
const essentialVars = ["PATH", "
|
|
19122
|
+
const essentialVars = ["PATH", "TMPDIR", "NODE_ENV", "USER", "LOGNAME"];
|
|
19053
19123
|
for (const varName of essentialVars) {
|
|
19054
19124
|
if (process.env[varName])
|
|
19055
19125
|
allowed[varName] = process.env[varName];
|
|
19056
19126
|
}
|
|
19127
|
+
const rawHome = process.env.HOME ?? "";
|
|
19128
|
+
const safeHome = rawHome && isAbsolute2(rawHome) ? rawHome : homedir2();
|
|
19129
|
+
if (rawHome !== safeHome) {
|
|
19130
|
+
getSafeLogger()?.warn("env", `HOME env is not absolute ("${rawHome}"), falling back to os.homedir(): ${safeHome}`);
|
|
19131
|
+
}
|
|
19132
|
+
allowed.HOME = safeHome;
|
|
19057
19133
|
const apiKeyVars = ["ANTHROPIC_API_KEY", "OPENAI_API_KEY", "GEMINI_API_KEY", "GOOGLE_API_KEY", "CLAUDE_API_KEY"];
|
|
19058
19134
|
for (const varName of apiKeyVars) {
|
|
19059
19135
|
if (process.env[varName])
|
|
@@ -19270,44 +19346,8 @@ var init_spawn_client = __esm(() => {
|
|
|
19270
19346
|
});
|
|
19271
19347
|
|
|
19272
19348
|
// src/agents/acp/cost.ts
|
|
19273
|
-
|
|
19274
|
-
|
|
19275
|
-
if (!pricing) {
|
|
19276
|
-
const fallbackInputRate = 3 / 1e6;
|
|
19277
|
-
const fallbackOutputRate = 15 / 1e6;
|
|
19278
|
-
const inputCost2 = (usage.input_tokens ?? 0) * fallbackInputRate;
|
|
19279
|
-
const outputCost2 = (usage.output_tokens ?? 0) * fallbackOutputRate;
|
|
19280
|
-
const cacheReadCost2 = (usage.cache_read_input_tokens ?? 0) * (0.5 / 1e6);
|
|
19281
|
-
const cacheCreationCost2 = (usage.cache_creation_input_tokens ?? 0) * (2 / 1e6);
|
|
19282
|
-
return inputCost2 + outputCost2 + cacheReadCost2 + cacheCreationCost2;
|
|
19283
|
-
}
|
|
19284
|
-
const inputRate = pricing.input / 1e6;
|
|
19285
|
-
const outputRate = pricing.output / 1e6;
|
|
19286
|
-
const cacheReadRate = (pricing.cacheRead ?? pricing.input * 0.1) / 1e6;
|
|
19287
|
-
const cacheCreationRate = (pricing.cacheCreation ?? pricing.input * 0.33) / 1e6;
|
|
19288
|
-
const inputCost = (usage.input_tokens ?? 0) * inputRate;
|
|
19289
|
-
const outputCost = (usage.output_tokens ?? 0) * outputRate;
|
|
19290
|
-
const cacheReadCost = (usage.cache_read_input_tokens ?? 0) * cacheReadRate;
|
|
19291
|
-
const cacheCreationCost = (usage.cache_creation_input_tokens ?? 0) * cacheCreationRate;
|
|
19292
|
-
return inputCost + outputCost + cacheReadCost + cacheCreationCost;
|
|
19293
|
-
}
|
|
19294
|
-
var MODEL_PRICING;
|
|
19295
|
-
var init_cost2 = __esm(() => {
|
|
19296
|
-
MODEL_PRICING = {
|
|
19297
|
-
"claude-sonnet-4": { input: 3, output: 15 },
|
|
19298
|
-
"claude-sonnet-4-5": { input: 3, output: 15 },
|
|
19299
|
-
"claude-haiku": { input: 0.8, output: 4, cacheRead: 0.1, cacheCreation: 1 },
|
|
19300
|
-
"claude-haiku-4-5": { input: 0.8, output: 4, cacheRead: 0.1, cacheCreation: 1 },
|
|
19301
|
-
"claude-opus": { input: 15, output: 75 },
|
|
19302
|
-
"claude-opus-4": { input: 15, output: 75 },
|
|
19303
|
-
"gpt-4.1": { input: 10, output: 30 },
|
|
19304
|
-
"gpt-4": { input: 30, output: 60 },
|
|
19305
|
-
"gpt-3.5-turbo": { input: 0.5, output: 1.5 },
|
|
19306
|
-
"gemini-2.5-pro": { input: 0.075, output: 0.3 },
|
|
19307
|
-
"gemini-2-pro": { input: 0.075, output: 0.3 },
|
|
19308
|
-
codex: { input: 0.02, output: 0.06 },
|
|
19309
|
-
"code-davinci-002": { input: 0.02, output: 0.06 }
|
|
19310
|
-
};
|
|
19349
|
+
var init_cost3 = __esm(() => {
|
|
19350
|
+
init_cost();
|
|
19311
19351
|
});
|
|
19312
19352
|
|
|
19313
19353
|
// src/agents/acp/adapter.ts
|
|
@@ -19828,7 +19868,7 @@ var init_adapter2 = __esm(() => {
|
|
|
19828
19868
|
init_decompose();
|
|
19829
19869
|
init_spawn_client();
|
|
19830
19870
|
init_types2();
|
|
19831
|
-
|
|
19871
|
+
init_cost3();
|
|
19832
19872
|
INTERACTION_TIMEOUT_MS = 5 * 60 * 1000;
|
|
19833
19873
|
AGENT_REGISTRY = {
|
|
19834
19874
|
claude: {
|
|
@@ -20427,7 +20467,7 @@ var init_chain = __esm(() => {
|
|
|
20427
20467
|
|
|
20428
20468
|
// src/utils/path-security.ts
|
|
20429
20469
|
import { realpathSync } from "fs";
|
|
20430
|
-
import { dirname, isAbsolute, join as join5, normalize, resolve } from "path";
|
|
20470
|
+
import { dirname, isAbsolute as isAbsolute3, join as join5, normalize, resolve } from "path";
|
|
20431
20471
|
function safeRealpath(p) {
|
|
20432
20472
|
try {
|
|
20433
20473
|
return realpathSync(p);
|
|
@@ -20445,7 +20485,7 @@ function validateModulePath(modulePath, allowedRoots) {
|
|
|
20445
20485
|
return { valid: false, error: "Module path is empty" };
|
|
20446
20486
|
}
|
|
20447
20487
|
const normalizedRoots = allowedRoots.map((r) => safeRealpath(resolve(r)));
|
|
20448
|
-
if (
|
|
20488
|
+
if (isAbsolute3(modulePath)) {
|
|
20449
20489
|
const absoluteTarget = safeRealpath(normalize(modulePath));
|
|
20450
20490
|
const isWithin = normalizedRoots.some((root) => {
|
|
20451
20491
|
return absoluteTarget.startsWith(`${root}/`) || absoluteTarget === root;
|
|
@@ -20736,7 +20776,7 @@ function isPlainObject2(value) {
|
|
|
20736
20776
|
|
|
20737
20777
|
// src/config/path-security.ts
|
|
20738
20778
|
import { existsSync as existsSync4, lstatSync, realpathSync as realpathSync2 } from "fs";
|
|
20739
|
-
import { isAbsolute as
|
|
20779
|
+
import { isAbsolute as isAbsolute4, normalize as normalize2, resolve as resolve3 } from "path";
|
|
20740
20780
|
function validateDirectory(dirPath, baseDir) {
|
|
20741
20781
|
const resolved = resolve3(dirPath);
|
|
20742
20782
|
if (!existsSync4(resolved)) {
|
|
@@ -20768,7 +20808,7 @@ function validateDirectory(dirPath, baseDir) {
|
|
|
20768
20808
|
function isWithinDirectory(targetPath, basePath) {
|
|
20769
20809
|
const normalizedTarget = normalize2(targetPath);
|
|
20770
20810
|
const normalizedBase = normalize2(basePath);
|
|
20771
|
-
if (!
|
|
20811
|
+
if (!isAbsolute4(normalizedTarget) || !isAbsolute4(normalizedBase)) {
|
|
20772
20812
|
return false;
|
|
20773
20813
|
}
|
|
20774
20814
|
const baseWithSlash = normalizedBase.endsWith("/") ? normalizedBase : `${normalizedBase}/`;
|
|
@@ -20804,10 +20844,10 @@ var MAX_DIRECTORY_DEPTH = 10;
|
|
|
20804
20844
|
var init_path_security2 = () => {};
|
|
20805
20845
|
|
|
20806
20846
|
// src/config/paths.ts
|
|
20807
|
-
import { homedir } from "os";
|
|
20847
|
+
import { homedir as homedir3 } from "os";
|
|
20808
20848
|
import { join as join6, resolve as resolve4 } from "path";
|
|
20809
20849
|
function globalConfigDir() {
|
|
20810
|
-
return join6(
|
|
20850
|
+
return join6(homedir3(), ".nax");
|
|
20811
20851
|
}
|
|
20812
20852
|
var init_paths = () => {};
|
|
20813
20853
|
|
|
@@ -22138,7 +22178,7 @@ var package_default;
|
|
|
22138
22178
|
var init_package = __esm(() => {
|
|
22139
22179
|
package_default = {
|
|
22140
22180
|
name: "@nathapp/nax",
|
|
22141
|
-
version: "0.46.
|
|
22181
|
+
version: "0.46.2",
|
|
22142
22182
|
description: "AI Coding Agent Orchestrator \u2014 loops until done",
|
|
22143
22183
|
type: "module",
|
|
22144
22184
|
bin: {
|
|
@@ -22211,8 +22251,8 @@ var init_version = __esm(() => {
|
|
|
22211
22251
|
NAX_VERSION = package_default.version;
|
|
22212
22252
|
NAX_COMMIT = (() => {
|
|
22213
22253
|
try {
|
|
22214
|
-
if (/^[0-9a-f]{6,10}$/.test("
|
|
22215
|
-
return "
|
|
22254
|
+
if (/^[0-9a-f]{6,10}$/.test("506ad27"))
|
|
22255
|
+
return "506ad27";
|
|
22216
22256
|
} catch {}
|
|
22217
22257
|
try {
|
|
22218
22258
|
const result = Bun.spawnSync(["git", "rev-parse", "--short", "HEAD"], {
|
|
@@ -24018,6 +24058,7 @@ ${stderr}` };
|
|
|
24018
24058
|
const result = await _acceptanceSetupDeps.generate(ctx.prd.userStories, refinedCriteria, {
|
|
24019
24059
|
featureName: ctx.prd.feature,
|
|
24020
24060
|
workdir: ctx.workdir,
|
|
24061
|
+
featureDir: ctx.featureDir,
|
|
24021
24062
|
codebaseContext: "",
|
|
24022
24063
|
modelTier: ctx.config.acceptance.model ?? "fast",
|
|
24023
24064
|
modelDef: resolveModel(ctx.config.models[ctx.config.acceptance.model ?? "fast"]),
|
|
@@ -24045,6 +24086,99 @@ ${stderr}` };
|
|
|
24045
24086
|
};
|
|
24046
24087
|
});
|
|
24047
24088
|
|
|
24089
|
+
// src/agents/shared/validation.ts
|
|
24090
|
+
function validateAgentForTier(agent, tier) {
|
|
24091
|
+
return agent.capabilities.supportedTiers.includes(tier);
|
|
24092
|
+
}
|
|
24093
|
+
function validateAgentFeature(agent, feature) {
|
|
24094
|
+
return agent.capabilities.features.has(feature);
|
|
24095
|
+
}
|
|
24096
|
+
function describeAgentCapabilities(agent) {
|
|
24097
|
+
const tiers = agent.capabilities.supportedTiers.join(",");
|
|
24098
|
+
const features = Array.from(agent.capabilities.features).join(",");
|
|
24099
|
+
const maxTokens = agent.capabilities.maxContextTokens;
|
|
24100
|
+
return `${agent.name}: tiers=[${tiers}], maxTokens=${maxTokens}, features=[${features}]`;
|
|
24101
|
+
}
|
|
24102
|
+
|
|
24103
|
+
// src/agents/shared/version-detection.ts
|
|
24104
|
+
async function getAgentVersion(binaryName) {
|
|
24105
|
+
try {
|
|
24106
|
+
const proc = _versionDetectionDeps.spawn([binaryName, "--version"], {
|
|
24107
|
+
stdout: "pipe",
|
|
24108
|
+
stderr: "pipe"
|
|
24109
|
+
});
|
|
24110
|
+
const exitCode = await proc.exited;
|
|
24111
|
+
if (exitCode !== 0) {
|
|
24112
|
+
return null;
|
|
24113
|
+
}
|
|
24114
|
+
const stdout = await new Response(proc.stdout).text();
|
|
24115
|
+
const versionLine = stdout.trim().split(`
|
|
24116
|
+
`)[0];
|
|
24117
|
+
const versionMatch = versionLine.match(/v?(\d+\.\d+(?:\.\d+)?(?:[-+][\w.]+)?)/);
|
|
24118
|
+
if (versionMatch) {
|
|
24119
|
+
return versionMatch[0];
|
|
24120
|
+
}
|
|
24121
|
+
return versionLine || null;
|
|
24122
|
+
} catch {
|
|
24123
|
+
return null;
|
|
24124
|
+
}
|
|
24125
|
+
}
|
|
24126
|
+
async function getAgentVersions() {
|
|
24127
|
+
const agents = await getInstalledAgents();
|
|
24128
|
+
const agentsByName = new Map(agents.map((a) => [a.name, a]));
|
|
24129
|
+
const { ALL_AGENTS: ALL_AGENTS2 } = await Promise.resolve().then(() => (init_registry(), exports_registry));
|
|
24130
|
+
const versions2 = await Promise.all(ALL_AGENTS2.map(async (agent) => {
|
|
24131
|
+
const version2 = agentsByName.has(agent.name) ? await getAgentVersion(agent.binary) : null;
|
|
24132
|
+
return {
|
|
24133
|
+
name: agent.name,
|
|
24134
|
+
displayName: agent.displayName,
|
|
24135
|
+
version: version2,
|
|
24136
|
+
installed: agentsByName.has(agent.name)
|
|
24137
|
+
};
|
|
24138
|
+
}));
|
|
24139
|
+
return versions2;
|
|
24140
|
+
}
|
|
24141
|
+
var _versionDetectionDeps;
|
|
24142
|
+
var init_version_detection = __esm(() => {
|
|
24143
|
+
init_registry();
|
|
24144
|
+
_versionDetectionDeps = {
|
|
24145
|
+
spawn(cmd, opts) {
|
|
24146
|
+
return Bun.spawn(cmd, opts);
|
|
24147
|
+
}
|
|
24148
|
+
};
|
|
24149
|
+
});
|
|
24150
|
+
|
|
24151
|
+
// src/agents/index.ts
|
|
24152
|
+
var exports_agents = {};
|
|
24153
|
+
__export(exports_agents, {
|
|
24154
|
+
validateAgentForTier: () => validateAgentForTier,
|
|
24155
|
+
validateAgentFeature: () => validateAgentFeature,
|
|
24156
|
+
parseTokenUsage: () => parseTokenUsage,
|
|
24157
|
+
getInstalledAgents: () => getInstalledAgents,
|
|
24158
|
+
getAllAgentNames: () => getAllAgentNames,
|
|
24159
|
+
getAgentVersions: () => getAgentVersions,
|
|
24160
|
+
getAgentVersion: () => getAgentVersion,
|
|
24161
|
+
getAgent: () => getAgent,
|
|
24162
|
+
formatCostWithConfidence: () => formatCostWithConfidence,
|
|
24163
|
+
estimateCostFromTokenUsage: () => estimateCostFromTokenUsage,
|
|
24164
|
+
estimateCostFromOutput: () => estimateCostFromOutput,
|
|
24165
|
+
estimateCostByDuration: () => estimateCostByDuration,
|
|
24166
|
+
estimateCost: () => estimateCost,
|
|
24167
|
+
describeAgentCapabilities: () => describeAgentCapabilities,
|
|
24168
|
+
checkAgentHealth: () => checkAgentHealth,
|
|
24169
|
+
MODEL_PRICING: () => MODEL_PRICING,
|
|
24170
|
+
CompleteError: () => CompleteError,
|
|
24171
|
+
ClaudeCodeAdapter: () => ClaudeCodeAdapter,
|
|
24172
|
+
COST_RATES: () => COST_RATES
|
|
24173
|
+
});
|
|
24174
|
+
var init_agents = __esm(() => {
|
|
24175
|
+
init_types2();
|
|
24176
|
+
init_claude();
|
|
24177
|
+
init_registry();
|
|
24178
|
+
init_cost();
|
|
24179
|
+
init_version_detection();
|
|
24180
|
+
});
|
|
24181
|
+
|
|
24048
24182
|
// src/pipeline/event-bus.ts
|
|
24049
24183
|
class PipelineEventBus {
|
|
24050
24184
|
subscribers = new Map;
|
|
@@ -24455,8 +24589,87 @@ async function recheckReview(ctx) {
|
|
|
24455
24589
|
const result = await reviewStage2.execute(ctx);
|
|
24456
24590
|
return result.action === "continue";
|
|
24457
24591
|
}
|
|
24592
|
+
function collectFailedChecks(ctx) {
|
|
24593
|
+
return (ctx.reviewResult?.checks ?? []).filter((c) => !c.success);
|
|
24594
|
+
}
|
|
24595
|
+
function buildReviewRectificationPrompt(failedChecks, story) {
|
|
24596
|
+
const errors3 = failedChecks.map((c) => `## ${c.check} errors (exit code ${c.exitCode})
|
|
24597
|
+
\`\`\`
|
|
24598
|
+
${c.output}
|
|
24599
|
+
\`\`\``).join(`
|
|
24600
|
+
|
|
24601
|
+
`);
|
|
24602
|
+
return `You are fixing lint/typecheck errors from a code review.
|
|
24603
|
+
|
|
24604
|
+
Story: ${story.title} (${story.id})
|
|
24605
|
+
|
|
24606
|
+
The following quality checks failed after implementation:
|
|
24607
|
+
|
|
24608
|
+
${errors3}
|
|
24609
|
+
|
|
24610
|
+
Fix ALL errors listed above. Do NOT change test files or test behavior.
|
|
24611
|
+
Do NOT add new features \u2014 only fix the quality check errors.
|
|
24612
|
+
Commit your fixes when done.`;
|
|
24613
|
+
}
|
|
24614
|
+
async function runAgentRectification(ctx) {
|
|
24615
|
+
const logger = getLogger();
|
|
24616
|
+
const maxAttempts = ctx.config.quality.autofix?.maxAttempts ?? 2;
|
|
24617
|
+
const failedChecks = collectFailedChecks(ctx);
|
|
24618
|
+
if (failedChecks.length === 0) {
|
|
24619
|
+
logger.debug("autofix", "No failed checks found \u2014 skipping agent rectification", { storyId: ctx.story.id });
|
|
24620
|
+
return false;
|
|
24621
|
+
}
|
|
24622
|
+
logger.info("autofix", "Starting agent rectification for review failures", {
|
|
24623
|
+
storyId: ctx.story.id,
|
|
24624
|
+
failedChecks: failedChecks.map((c) => c.check),
|
|
24625
|
+
maxAttempts
|
|
24626
|
+
});
|
|
24627
|
+
const agentGetFn = ctx.agentGetFn ?? getAgent;
|
|
24628
|
+
for (let attempt = 1;attempt <= maxAttempts; attempt++) {
|
|
24629
|
+
logger.info("autofix", `Agent rectification attempt ${attempt}/${maxAttempts}`, { storyId: ctx.story.id });
|
|
24630
|
+
const agent = agentGetFn(ctx.config.autoMode.defaultAgent);
|
|
24631
|
+
if (!agent) {
|
|
24632
|
+
logger.error("autofix", "Agent not found \u2014 cannot run agent rectification", { storyId: ctx.story.id });
|
|
24633
|
+
return false;
|
|
24634
|
+
}
|
|
24635
|
+
const prompt = buildReviewRectificationPrompt(failedChecks, ctx.story);
|
|
24636
|
+
const modelTier = ctx.story.routing?.modelTier ?? ctx.config.autoMode.escalation.tierOrder[0]?.tier ?? "balanced";
|
|
24637
|
+
const modelDef = resolveModel(ctx.config.models[modelTier]);
|
|
24638
|
+
await agent.run({
|
|
24639
|
+
prompt,
|
|
24640
|
+
workdir: ctx.workdir,
|
|
24641
|
+
modelTier,
|
|
24642
|
+
modelDef,
|
|
24643
|
+
timeoutSeconds: ctx.config.execution.sessionTimeoutSeconds,
|
|
24644
|
+
dangerouslySkipPermissions: resolvePermissions(ctx.config, "rectification").skipPermissions,
|
|
24645
|
+
pipelineStage: "rectification",
|
|
24646
|
+
config: ctx.config,
|
|
24647
|
+
maxInteractionTurns: ctx.config.agent?.maxInteractionTurns,
|
|
24648
|
+
storyId: ctx.story.id,
|
|
24649
|
+
sessionRole: "implementer"
|
|
24650
|
+
});
|
|
24651
|
+
const passed = await _autofixDeps.recheckReview(ctx);
|
|
24652
|
+
if (passed) {
|
|
24653
|
+
logger.info("autofix", `[OK] Agent rectification succeeded on attempt ${attempt}`, {
|
|
24654
|
+
storyId: ctx.story.id
|
|
24655
|
+
});
|
|
24656
|
+
return true;
|
|
24657
|
+
}
|
|
24658
|
+
const updatedFailed = collectFailedChecks(ctx);
|
|
24659
|
+
if (updatedFailed.length > 0) {
|
|
24660
|
+
failedChecks.splice(0, failedChecks.length, ...updatedFailed);
|
|
24661
|
+
}
|
|
24662
|
+
logger.warn("autofix", `Agent rectification still failing after attempt ${attempt}`, {
|
|
24663
|
+
storyId: ctx.story.id
|
|
24664
|
+
});
|
|
24665
|
+
}
|
|
24666
|
+
logger.warn("autofix", "Agent rectification exhausted", { storyId: ctx.story.id });
|
|
24667
|
+
return false;
|
|
24668
|
+
}
|
|
24458
24669
|
var autofixStage, _autofixDeps;
|
|
24459
24670
|
var init_autofix = __esm(() => {
|
|
24671
|
+
init_agents();
|
|
24672
|
+
init_config();
|
|
24460
24673
|
init_logger2();
|
|
24461
24674
|
init_event_bus();
|
|
24462
24675
|
autofixStage = {
|
|
@@ -24482,14 +24695,7 @@ var init_autofix = __esm(() => {
|
|
|
24482
24695
|
}
|
|
24483
24696
|
const lintFixCmd = ctx.config.quality.commands.lintFix;
|
|
24484
24697
|
const formatFixCmd = ctx.config.quality.commands.formatFix;
|
|
24485
|
-
if (
|
|
24486
|
-
logger.debug("autofix", "No fix commands configured \u2014 skipping autofix", { storyId: ctx.story.id });
|
|
24487
|
-
return { action: "escalate", reason: "Review failed and no autofix commands configured" };
|
|
24488
|
-
}
|
|
24489
|
-
const maxAttempts = ctx.config.quality.autofix?.maxAttempts ?? 2;
|
|
24490
|
-
let fixed = false;
|
|
24491
|
-
for (let attempt = 1;attempt <= maxAttempts; attempt++) {
|
|
24492
|
-
logger.info("autofix", `Autofix attempt ${attempt}/${maxAttempts}`, { storyId: ctx.story.id });
|
|
24698
|
+
if (lintFixCmd || formatFixCmd) {
|
|
24493
24699
|
if (lintFixCmd) {
|
|
24494
24700
|
pipelineEventBus.emit({ type: "autofix:started", storyId: ctx.story.id, command: lintFixCmd });
|
|
24495
24701
|
const lintResult = await _autofixDeps.runCommand(lintFixCmd, ctx.workdir);
|
|
@@ -24515,22 +24721,24 @@ var init_autofix = __esm(() => {
|
|
|
24515
24721
|
const recheckPassed = await _autofixDeps.recheckReview(ctx);
|
|
24516
24722
|
pipelineEventBus.emit({ type: "autofix:completed", storyId: ctx.story.id, fixed: recheckPassed });
|
|
24517
24723
|
if (recheckPassed) {
|
|
24518
|
-
if (ctx.reviewResult)
|
|
24724
|
+
if (ctx.reviewResult)
|
|
24519
24725
|
ctx.reviewResult = { ...ctx.reviewResult, success: true };
|
|
24520
|
-
}
|
|
24521
|
-
|
|
24522
|
-
break;
|
|
24726
|
+
logger.info("autofix", "Mechanical autofix succeeded \u2014 retrying review", { storyId: ctx.story.id });
|
|
24727
|
+
return { action: "retry", fromStage: "review" };
|
|
24523
24728
|
}
|
|
24524
24729
|
}
|
|
24525
|
-
|
|
24526
|
-
|
|
24730
|
+
const agentFixed = await _autofixDeps.runAgentRectification(ctx);
|
|
24731
|
+
if (agentFixed) {
|
|
24732
|
+
if (ctx.reviewResult)
|
|
24733
|
+
ctx.reviewResult = { ...ctx.reviewResult, success: true };
|
|
24734
|
+
logger.info("autofix", "Agent rectification succeeded \u2014 retrying review", { storyId: ctx.story.id });
|
|
24527
24735
|
return { action: "retry", fromStage: "review" };
|
|
24528
24736
|
}
|
|
24529
24737
|
logger.warn("autofix", "Autofix exhausted \u2014 escalating", { storyId: ctx.story.id });
|
|
24530
24738
|
return { action: "escalate", reason: "Autofix exhausted: review still failing after fix attempts" };
|
|
24531
24739
|
}
|
|
24532
24740
|
};
|
|
24533
|
-
_autofixDeps = { runCommand, recheckReview };
|
|
24741
|
+
_autofixDeps = { runCommand, recheckReview, runAgentRectification };
|
|
24534
24742
|
});
|
|
24535
24743
|
|
|
24536
24744
|
// src/execution/progress.ts
|
|
@@ -25678,97 +25886,6 @@ ${pluginMarkdown}` : pluginMarkdown;
|
|
|
25678
25886
|
};
|
|
25679
25887
|
});
|
|
25680
25888
|
|
|
25681
|
-
// src/agents/shared/validation.ts
|
|
25682
|
-
function validateAgentForTier(agent, tier) {
|
|
25683
|
-
return agent.capabilities.supportedTiers.includes(tier);
|
|
25684
|
-
}
|
|
25685
|
-
function validateAgentFeature(agent, feature) {
|
|
25686
|
-
return agent.capabilities.features.has(feature);
|
|
25687
|
-
}
|
|
25688
|
-
function describeAgentCapabilities(agent) {
|
|
25689
|
-
const tiers = agent.capabilities.supportedTiers.join(",");
|
|
25690
|
-
const features = Array.from(agent.capabilities.features).join(",");
|
|
25691
|
-
const maxTokens = agent.capabilities.maxContextTokens;
|
|
25692
|
-
return `${agent.name}: tiers=[${tiers}], maxTokens=${maxTokens}, features=[${features}]`;
|
|
25693
|
-
}
|
|
25694
|
-
|
|
25695
|
-
// src/agents/shared/version-detection.ts
|
|
25696
|
-
async function getAgentVersion(binaryName) {
|
|
25697
|
-
try {
|
|
25698
|
-
const proc = _versionDetectionDeps.spawn([binaryName, "--version"], {
|
|
25699
|
-
stdout: "pipe",
|
|
25700
|
-
stderr: "pipe"
|
|
25701
|
-
});
|
|
25702
|
-
const exitCode = await proc.exited;
|
|
25703
|
-
if (exitCode !== 0) {
|
|
25704
|
-
return null;
|
|
25705
|
-
}
|
|
25706
|
-
const stdout = await new Response(proc.stdout).text();
|
|
25707
|
-
const versionLine = stdout.trim().split(`
|
|
25708
|
-
`)[0];
|
|
25709
|
-
const versionMatch = versionLine.match(/v?(\d+\.\d+(?:\.\d+)?(?:[-+][\w.]+)?)/);
|
|
25710
|
-
if (versionMatch) {
|
|
25711
|
-
return versionMatch[0];
|
|
25712
|
-
}
|
|
25713
|
-
return versionLine || null;
|
|
25714
|
-
} catch {
|
|
25715
|
-
return null;
|
|
25716
|
-
}
|
|
25717
|
-
}
|
|
25718
|
-
async function getAgentVersions() {
|
|
25719
|
-
const agents = await getInstalledAgents();
|
|
25720
|
-
const agentsByName = new Map(agents.map((a) => [a.name, a]));
|
|
25721
|
-
const { ALL_AGENTS: ALL_AGENTS2 } = await Promise.resolve().then(() => (init_registry(), exports_registry));
|
|
25722
|
-
const versions2 = await Promise.all(ALL_AGENTS2.map(async (agent) => {
|
|
25723
|
-
const version2 = agentsByName.has(agent.name) ? await getAgentVersion(agent.binary) : null;
|
|
25724
|
-
return {
|
|
25725
|
-
name: agent.name,
|
|
25726
|
-
displayName: agent.displayName,
|
|
25727
|
-
version: version2,
|
|
25728
|
-
installed: agentsByName.has(agent.name)
|
|
25729
|
-
};
|
|
25730
|
-
}));
|
|
25731
|
-
return versions2;
|
|
25732
|
-
}
|
|
25733
|
-
var _versionDetectionDeps;
|
|
25734
|
-
var init_version_detection = __esm(() => {
|
|
25735
|
-
init_registry();
|
|
25736
|
-
_versionDetectionDeps = {
|
|
25737
|
-
spawn(cmd, opts) {
|
|
25738
|
-
return Bun.spawn(cmd, opts);
|
|
25739
|
-
}
|
|
25740
|
-
};
|
|
25741
|
-
});
|
|
25742
|
-
|
|
25743
|
-
// src/agents/index.ts
|
|
25744
|
-
var exports_agents = {};
|
|
25745
|
-
__export(exports_agents, {
|
|
25746
|
-
validateAgentForTier: () => validateAgentForTier,
|
|
25747
|
-
validateAgentFeature: () => validateAgentFeature,
|
|
25748
|
-
parseTokenUsage: () => parseTokenUsage,
|
|
25749
|
-
getInstalledAgents: () => getInstalledAgents,
|
|
25750
|
-
getAllAgentNames: () => getAllAgentNames,
|
|
25751
|
-
getAgentVersions: () => getAgentVersions,
|
|
25752
|
-
getAgentVersion: () => getAgentVersion,
|
|
25753
|
-
getAgent: () => getAgent,
|
|
25754
|
-
formatCostWithConfidence: () => formatCostWithConfidence,
|
|
25755
|
-
estimateCostFromOutput: () => estimateCostFromOutput,
|
|
25756
|
-
estimateCostByDuration: () => estimateCostByDuration,
|
|
25757
|
-
estimateCost: () => estimateCost,
|
|
25758
|
-
describeAgentCapabilities: () => describeAgentCapabilities,
|
|
25759
|
-
checkAgentHealth: () => checkAgentHealth,
|
|
25760
|
-
CompleteError: () => CompleteError,
|
|
25761
|
-
ClaudeCodeAdapter: () => ClaudeCodeAdapter,
|
|
25762
|
-
COST_RATES: () => COST_RATES
|
|
25763
|
-
});
|
|
25764
|
-
var init_agents = __esm(() => {
|
|
25765
|
-
init_types2();
|
|
25766
|
-
init_claude();
|
|
25767
|
-
init_registry();
|
|
25768
|
-
init_cost();
|
|
25769
|
-
init_version_detection();
|
|
25770
|
-
});
|
|
25771
|
-
|
|
25772
25889
|
// src/tdd/isolation.ts
|
|
25773
25890
|
function isTestFile(filePath) {
|
|
25774
25891
|
return TEST_PATTERNS.some((pattern) => pattern.test(filePath));
|
|
@@ -30069,12 +30186,15 @@ async function checkWorkingTreeClean(workdir) {
|
|
|
30069
30186
|
});
|
|
30070
30187
|
const output = await new Response(proc.stdout).text();
|
|
30071
30188
|
const exitCode = await proc.exited;
|
|
30072
|
-
const
|
|
30189
|
+
const lines = output.trim() === "" ? [] : output.split(`
|
|
30190
|
+
`).filter(Boolean);
|
|
30191
|
+
const nonNaxDirtyFiles = lines.filter((line) => !NAX_RUNTIME_PATTERNS.some((pattern) => pattern.test(line)));
|
|
30192
|
+
const passed = exitCode === 0 && nonNaxDirtyFiles.length === 0;
|
|
30073
30193
|
return {
|
|
30074
30194
|
name: "working-tree-clean",
|
|
30075
30195
|
tier: "blocker",
|
|
30076
30196
|
passed,
|
|
30077
|
-
message: passed ? "Working tree is clean" :
|
|
30197
|
+
message: passed ? "Working tree is clean" : `Uncommitted changes detected: ${nonNaxDirtyFiles.map((l) => l.slice(3)).join(", ")}`
|
|
30078
30198
|
};
|
|
30079
30199
|
}
|
|
30080
30200
|
async function checkGitUserConfigured(workdir) {
|
|
@@ -30099,7 +30219,23 @@ async function checkGitUserConfigured(workdir) {
|
|
|
30099
30219
|
message: passed ? "Git user is configured" : !hasName && !hasEmail ? "Git user.name and user.email not configured" : !hasName ? "Git user.name not configured" : "Git user.email not configured"
|
|
30100
30220
|
};
|
|
30101
30221
|
}
|
|
30102
|
-
var
|
|
30222
|
+
var NAX_RUNTIME_PATTERNS;
|
|
30223
|
+
var init_checks_git = __esm(() => {
|
|
30224
|
+
NAX_RUNTIME_PATTERNS = [
|
|
30225
|
+
/^.{2} nax\.lock$/,
|
|
30226
|
+
/^.{2} nax\/metrics\.json$/,
|
|
30227
|
+
/^.{2} nax\/features\/[^/]+\/status\.json$/,
|
|
30228
|
+
/^.{2} nax\/features\/[^/]+\/runs\//,
|
|
30229
|
+
/^.{2} nax\/features\/[^/]+\/plan\//,
|
|
30230
|
+
/^.{2} nax\/features\/[^/]+\/acp-sessions\.json$/,
|
|
30231
|
+
/^.{2} nax\/features\/[^/]+\/interactions\//,
|
|
30232
|
+
/^.{2} nax\/features\/[^/]+\/progress\.txt$/,
|
|
30233
|
+
/^.{2} nax\/features\/[^/]+\/acceptance-refined\.json$/,
|
|
30234
|
+
/^.{2} \.nax-verifier-verdict\.json$/,
|
|
30235
|
+
/^.{2} \.nax-pids$/,
|
|
30236
|
+
/^.{2} \.nax-wt\//
|
|
30237
|
+
];
|
|
30238
|
+
});
|
|
30103
30239
|
|
|
30104
30240
|
// src/precheck/checks-config.ts
|
|
30105
30241
|
import { existsSync as existsSync26, statSync as statSync3 } from "fs";
|
|
@@ -30360,6 +30496,7 @@ var init_checks_blockers = __esm(() => {
|
|
|
30360
30496
|
|
|
30361
30497
|
// src/precheck/checks-warnings.ts
|
|
30362
30498
|
import { existsSync as existsSync28 } from "fs";
|
|
30499
|
+
import { isAbsolute as isAbsolute6 } from "path";
|
|
30363
30500
|
async function checkClaudeMdExists(workdir) {
|
|
30364
30501
|
const claudeMdPath = `${workdir}/CLAUDE.md`;
|
|
30365
30502
|
const passed = existsSync28(claudeMdPath);
|
|
@@ -30453,7 +30590,14 @@ async function checkGitignoreCoversNax(workdir) {
|
|
|
30453
30590
|
}
|
|
30454
30591
|
const file2 = Bun.file(gitignorePath);
|
|
30455
30592
|
const content = await file2.text();
|
|
30456
|
-
const patterns = [
|
|
30593
|
+
const patterns = [
|
|
30594
|
+
"nax.lock",
|
|
30595
|
+
"nax/**/runs/",
|
|
30596
|
+
"nax/metrics.json",
|
|
30597
|
+
"nax/features/*/status.json",
|
|
30598
|
+
".nax-pids",
|
|
30599
|
+
".nax-wt/"
|
|
30600
|
+
];
|
|
30457
30601
|
const missing = patterns.filter((pattern) => !content.includes(pattern));
|
|
30458
30602
|
const passed = missing.length === 0;
|
|
30459
30603
|
return {
|
|
@@ -30482,6 +30626,16 @@ async function checkPromptOverrideFiles(config2, workdir) {
|
|
|
30482
30626
|
}
|
|
30483
30627
|
return checks3;
|
|
30484
30628
|
}
|
|
30629
|
+
async function checkHomeEnvValid() {
|
|
30630
|
+
const home = process.env.HOME ?? "";
|
|
30631
|
+
const passed = home !== "" && isAbsolute6(home);
|
|
30632
|
+
return {
|
|
30633
|
+
name: "home-env-valid",
|
|
30634
|
+
tier: "warning",
|
|
30635
|
+
passed,
|
|
30636
|
+
message: passed ? `HOME env is valid: ${home}` : home === "" ? "HOME env is not set \u2014 agent may write files to unexpected locations" : `HOME env is not an absolute path ("${home}") \u2014 may cause literal "~" directories in repo`
|
|
30637
|
+
};
|
|
30638
|
+
}
|
|
30485
30639
|
var init_checks_warnings = () => {};
|
|
30486
30640
|
|
|
30487
30641
|
// src/precheck/checks-agents.ts
|
|
@@ -30662,6 +30816,7 @@ function getEnvironmentWarnings(config2, workdir) {
|
|
|
30662
30816
|
() => checkDiskSpace(),
|
|
30663
30817
|
() => checkOptionalCommands(config2, workdir),
|
|
30664
30818
|
() => checkGitignoreCoversNax(workdir),
|
|
30819
|
+
() => checkHomeEnvValid(),
|
|
30665
30820
|
() => checkPromptOverrideFiles(config2, workdir),
|
|
30666
30821
|
() => checkMultiAgentHealth()
|
|
30667
30822
|
];
|
|
@@ -32902,12 +33057,12 @@ var init_parallel_executor = __esm(() => {
|
|
|
32902
33057
|
|
|
32903
33058
|
// src/pipeline/subscribers/events-writer.ts
|
|
32904
33059
|
import { appendFile as appendFile2, mkdir } from "fs/promises";
|
|
32905
|
-
import { homedir as
|
|
33060
|
+
import { homedir as homedir7 } from "os";
|
|
32906
33061
|
import { basename as basename3, join as join40 } from "path";
|
|
32907
33062
|
function wireEventsWriter(bus, feature, runId, workdir) {
|
|
32908
33063
|
const logger = getSafeLogger();
|
|
32909
33064
|
const project = basename3(workdir);
|
|
32910
|
-
const eventsDir = join40(
|
|
33065
|
+
const eventsDir = join40(homedir7(), ".nax", "events", project);
|
|
32911
33066
|
const eventsFile = join40(eventsDir, "events.jsonl");
|
|
32912
33067
|
let dirReady = false;
|
|
32913
33068
|
const write = (line) => {
|
|
@@ -33067,12 +33222,12 @@ var init_interaction2 = __esm(() => {
|
|
|
33067
33222
|
|
|
33068
33223
|
// src/pipeline/subscribers/registry.ts
|
|
33069
33224
|
import { mkdir as mkdir2, writeFile } from "fs/promises";
|
|
33070
|
-
import { homedir as
|
|
33225
|
+
import { homedir as homedir8 } from "os";
|
|
33071
33226
|
import { basename as basename4, join as join41 } from "path";
|
|
33072
33227
|
function wireRegistry(bus, feature, runId, workdir) {
|
|
33073
33228
|
const logger = getSafeLogger();
|
|
33074
33229
|
const project = basename4(workdir);
|
|
33075
|
-
const runDir = join41(
|
|
33230
|
+
const runDir = join41(homedir8(), ".nax", "runs", `${project}-${feature}-${runId}`);
|
|
33076
33231
|
const metaFile = join41(runDir, "meta.json");
|
|
33077
33232
|
const unsub = bus.on("run:started", (_ev) => {
|
|
33078
33233
|
(async () => {
|
|
@@ -65472,7 +65627,7 @@ var require_jsx_dev_runtime = __commonJS((exports, module) => {
|
|
|
65472
65627
|
// bin/nax.ts
|
|
65473
65628
|
init_source();
|
|
65474
65629
|
import { existsSync as existsSync32, mkdirSync as mkdirSync6 } from "fs";
|
|
65475
|
-
import { homedir as
|
|
65630
|
+
import { homedir as homedir10 } from "os";
|
|
65476
65631
|
import { join as join43 } from "path";
|
|
65477
65632
|
|
|
65478
65633
|
// node_modules/commander/esm.mjs
|
|
@@ -68628,10 +68783,10 @@ import { join as join32 } from "path";
|
|
|
68628
68783
|
// src/commands/logs-reader.ts
|
|
68629
68784
|
import { existsSync as existsSync23, readdirSync as readdirSync6 } from "fs";
|
|
68630
68785
|
import { readdir as readdir3 } from "fs/promises";
|
|
68631
|
-
import { homedir as
|
|
68786
|
+
import { homedir as homedir5 } from "os";
|
|
68632
68787
|
import { join as join31 } from "path";
|
|
68633
68788
|
var _deps6 = {
|
|
68634
|
-
getRunsDir: () => process.env.NAX_RUNS_DIR ?? join31(
|
|
68789
|
+
getRunsDir: () => process.env.NAX_RUNS_DIR ?? join31(homedir5(), ".nax", "runs")
|
|
68635
68790
|
};
|
|
68636
68791
|
async function resolveRunFileFromRegistry(runId) {
|
|
68637
68792
|
const runsDir = _deps6.getRunsDir();
|
|
@@ -68957,11 +69112,11 @@ async function precheckCommand(options) {
|
|
|
68957
69112
|
// src/commands/runs.ts
|
|
68958
69113
|
init_source();
|
|
68959
69114
|
import { readdir as readdir4 } from "fs/promises";
|
|
68960
|
-
import { homedir as
|
|
69115
|
+
import { homedir as homedir6 } from "os";
|
|
68961
69116
|
import { join as join35 } from "path";
|
|
68962
69117
|
var DEFAULT_LIMIT = 20;
|
|
68963
69118
|
var _deps8 = {
|
|
68964
|
-
getRunsDir: () => join35(
|
|
69119
|
+
getRunsDir: () => join35(homedir6(), ".nax", "runs")
|
|
68965
69120
|
};
|
|
68966
69121
|
function formatDuration3(ms) {
|
|
68967
69122
|
if (ms <= 0)
|
|
@@ -77155,7 +77310,7 @@ program2.command("run").description("Run the orchestration loop for a feature").
|
|
|
77155
77310
|
config2.autoMode.defaultAgent = options.agent;
|
|
77156
77311
|
}
|
|
77157
77312
|
config2.execution.maxIterations = Number.parseInt(options.maxIterations, 10);
|
|
77158
|
-
const globalNaxDir = join43(
|
|
77313
|
+
const globalNaxDir = join43(homedir10(), ".nax");
|
|
77159
77314
|
const hooks = await loadHooksConfig(naxDir, globalNaxDir);
|
|
77160
77315
|
const eventEmitter = new PipelineEventEmitter;
|
|
77161
77316
|
let tuiInstance;
|