@nathapp/nax 0.54.7 → 0.54.8
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 +67 -50
- package/package.json +1 -1
package/dist/nax.js
CHANGED
|
@@ -17982,7 +17982,8 @@ var init_schemas3 = __esm(() => {
|
|
|
17982
17982
|
SemanticReviewConfigSchema = exports_external.object({
|
|
17983
17983
|
modelTier: ModelTierSchema.default("balanced"),
|
|
17984
17984
|
rules: exports_external.array(exports_external.string()).default([]),
|
|
17985
|
-
timeoutMs: exports_external.number().int().positive().default(600000)
|
|
17985
|
+
timeoutMs: exports_external.number().int().positive().default(600000),
|
|
17986
|
+
excludePatterns: exports_external.array(exports_external.string()).default([":!test/", ":!tests/", ":!*_test.go", ":!*.test.ts", ":!*.spec.ts", ":!**/__tests__/"])
|
|
17986
17987
|
});
|
|
17987
17988
|
ReviewConfigSchema = exports_external.object({
|
|
17988
17989
|
enabled: exports_external.boolean(),
|
|
@@ -18278,7 +18279,8 @@ var init_defaults = __esm(() => {
|
|
|
18278
18279
|
semantic: {
|
|
18279
18280
|
modelTier: "balanced",
|
|
18280
18281
|
rules: [],
|
|
18281
|
-
timeoutMs: 600000
|
|
18282
|
+
timeoutMs: 600000,
|
|
18283
|
+
excludePatterns: [":!test/", ":!tests/", ":!*_test.go", ":!*.test.ts", ":!*.spec.ts", ":!**/__tests__/"]
|
|
18282
18284
|
}
|
|
18283
18285
|
},
|
|
18284
18286
|
plan: {
|
|
@@ -19927,14 +19929,13 @@ function extractQuestion(output) {
|
|
|
19927
19929
|
const text = output.trim();
|
|
19928
19930
|
if (!text)
|
|
19929
19931
|
return null;
|
|
19930
|
-
const
|
|
19931
|
-
|
|
19932
|
-
|
|
19933
|
-
|
|
19934
|
-
|
|
19935
|
-
|
|
19936
|
-
|
|
19937
|
-
const lower = text.toLowerCase();
|
|
19932
|
+
const lines = text.split(`
|
|
19933
|
+
`).filter((l) => l.trim().length > 0);
|
|
19934
|
+
const lastLine = lines.at(-1)?.trim() ?? "";
|
|
19935
|
+
if (lastLine.endsWith("?") && lastLine.length > 10) {
|
|
19936
|
+
return lastLine;
|
|
19937
|
+
}
|
|
19938
|
+
const lower = lastLine.toLowerCase();
|
|
19938
19939
|
const markers = [
|
|
19939
19940
|
"please confirm",
|
|
19940
19941
|
"please specify",
|
|
@@ -19946,7 +19947,7 @@ function extractQuestion(output) {
|
|
|
19946
19947
|
];
|
|
19947
19948
|
for (const marker of markers) {
|
|
19948
19949
|
if (lower.includes(marker)) {
|
|
19949
|
-
return
|
|
19950
|
+
return lastLine;
|
|
19950
19951
|
}
|
|
19951
19952
|
}
|
|
19952
19953
|
return null;
|
|
@@ -20133,7 +20134,19 @@ class AcpAgentAdapter {
|
|
|
20133
20134
|
};
|
|
20134
20135
|
}
|
|
20135
20136
|
async complete(prompt, _options) {
|
|
20136
|
-
|
|
20137
|
+
let model = _options?.model;
|
|
20138
|
+
if (!model && _options?.modelTier && _options?.config?.models) {
|
|
20139
|
+
const tier = _options.modelTier;
|
|
20140
|
+
const { resolveModel: resolveModel2 } = await Promise.resolve().then(() => (init_schema(), exports_schema));
|
|
20141
|
+
const models = _options.config.models;
|
|
20142
|
+
const entry = models[tier] ?? models.balanced;
|
|
20143
|
+
if (entry) {
|
|
20144
|
+
try {
|
|
20145
|
+
model = resolveModel2(entry).model;
|
|
20146
|
+
} catch {}
|
|
20147
|
+
}
|
|
20148
|
+
}
|
|
20149
|
+
model ??= "default";
|
|
20137
20150
|
const timeoutMs = _options?.timeoutMs ?? 120000;
|
|
20138
20151
|
const permissionMode = resolvePermissions(_options?.config, "complete").mode;
|
|
20139
20152
|
const workdir = _options?.workdir;
|
|
@@ -22352,7 +22365,7 @@ var package_default;
|
|
|
22352
22365
|
var init_package = __esm(() => {
|
|
22353
22366
|
package_default = {
|
|
22354
22367
|
name: "@nathapp/nax",
|
|
22355
|
-
version: "0.54.
|
|
22368
|
+
version: "0.54.8",
|
|
22356
22369
|
description: "AI Coding Agent Orchestrator \u2014 loops until done",
|
|
22357
22370
|
type: "module",
|
|
22358
22371
|
bin: {
|
|
@@ -22429,8 +22442,8 @@ var init_version = __esm(() => {
|
|
|
22429
22442
|
NAX_VERSION = package_default.version;
|
|
22430
22443
|
NAX_COMMIT = (() => {
|
|
22431
22444
|
try {
|
|
22432
|
-
if (/^[0-9a-f]{6,10}$/.test("
|
|
22433
|
-
return "
|
|
22445
|
+
if (/^[0-9a-f]{6,10}$/.test("6f97ec3"))
|
|
22446
|
+
return "6f97ec3";
|
|
22434
22447
|
} catch {}
|
|
22435
22448
|
try {
|
|
22436
22449
|
const result = Bun.spawnSync(["git", "rev-parse", "--short", "HEAD"], {
|
|
@@ -22478,7 +22491,7 @@ function buildInteractionBridge(chain, context, timeoutMs = DEFAULT_INTERACTION_
|
|
|
22478
22491
|
}
|
|
22479
22492
|
var QUESTION_PATTERNS, DEFAULT_INTERACTION_TIMEOUT_MS = 120000;
|
|
22480
22493
|
var init_bridge_builder = __esm(() => {
|
|
22481
|
-
QUESTION_PATTERNS = [
|
|
22494
|
+
QUESTION_PATTERNS = [/\?\s*$/, /\bwhich\b/i, /\bshould i\b/i, /\bunclear\b/i, /\bplease clarify\b/i];
|
|
22482
22495
|
});
|
|
22483
22496
|
|
|
22484
22497
|
// src/interaction/chain.ts
|
|
@@ -24853,9 +24866,13 @@ var init_language_commands = __esm(() => {
|
|
|
24853
24866
|
|
|
24854
24867
|
// src/review/semantic.ts
|
|
24855
24868
|
var {spawn: spawn2 } = globalThis.Bun;
|
|
24856
|
-
async function collectDiff(workdir, storyGitRef) {
|
|
24869
|
+
async function collectDiff(workdir, storyGitRef, excludePatterns) {
|
|
24870
|
+
const cmd = ["git", "diff", "--unified=3", `${storyGitRef}..HEAD`];
|
|
24871
|
+
if (excludePatterns.length > 0) {
|
|
24872
|
+
cmd.push("--", ".", ...excludePatterns);
|
|
24873
|
+
}
|
|
24857
24874
|
const proc = _semanticDeps.spawn({
|
|
24858
|
-
cmd
|
|
24875
|
+
cmd,
|
|
24859
24876
|
cwd: workdir,
|
|
24860
24877
|
stdout: "pipe",
|
|
24861
24878
|
stderr: "pipe"
|
|
@@ -24901,15 +24918,13 @@ ${stat}
|
|
|
24901
24918
|
}
|
|
24902
24919
|
function buildPrompt(story, semanticConfig, diff) {
|
|
24903
24920
|
const acList = story.acceptanceCriteria.map((ac, i) => `${i + 1}. ${ac}`).join(`
|
|
24904
|
-
`);
|
|
24905
|
-
const defaultRulesText = DEFAULT_RULES.map((r, i) => `${i + 1}. ${r}`).join(`
|
|
24906
24921
|
`);
|
|
24907
24922
|
const customRulesSection = semanticConfig.rules.length > 0 ? `
|
|
24908
|
-
##
|
|
24923
|
+
## Additional Review Rules
|
|
24909
24924
|
${semanticConfig.rules.map((r, i) => `${i + 1}. ${r}`).join(`
|
|
24910
24925
|
`)}
|
|
24911
24926
|
` : "";
|
|
24912
|
-
return `You are a code reviewer.
|
|
24927
|
+
return `You are a semantic code reviewer. Your job is to verify that the implementation satisfies the story's acceptance criteria (ACs). You are NOT a linter or style checker \u2014 lint, typecheck, and convention checks are handled separately.
|
|
24913
24928
|
|
|
24914
24929
|
## Story: ${story.title}
|
|
24915
24930
|
|
|
@@ -24918,27 +24933,29 @@ ${story.description}
|
|
|
24918
24933
|
|
|
24919
24934
|
### Acceptance Criteria
|
|
24920
24935
|
${acList}
|
|
24921
|
-
|
|
24922
|
-
## Review Rules
|
|
24923
|
-
|
|
24924
|
-
### Default Rules
|
|
24925
|
-
${defaultRulesText}
|
|
24926
24936
|
${customRulesSection}
|
|
24927
|
-
## Git Diff
|
|
24937
|
+
## Git Diff (production code only \u2014 test files excluded)
|
|
24928
24938
|
|
|
24929
24939
|
\`\`\`diff
|
|
24930
24940
|
${diff}\`\`\`
|
|
24931
24941
|
|
|
24932
24942
|
## Instructions
|
|
24933
24943
|
|
|
24934
|
-
|
|
24935
|
-
|
|
24944
|
+
For each acceptance criterion, verify the diff implements it correctly. Flag issues only when:
|
|
24945
|
+
1. An AC is not implemented or partially implemented
|
|
24946
|
+
2. The implementation contradicts what the AC specifies
|
|
24947
|
+
3. New code has dead paths that will never execute (stubs, noops, unreachable branches)
|
|
24948
|
+
4. New code is not wired into callers/exports (written but never used)
|
|
24949
|
+
|
|
24950
|
+
Do NOT flag: style issues, naming conventions, import ordering, file length, or anything lint handles.
|
|
24951
|
+
|
|
24952
|
+
Respond in JSON format:
|
|
24936
24953
|
{
|
|
24937
24954
|
"passed": boolean,
|
|
24938
24955
|
"findings": [
|
|
24939
24956
|
{
|
|
24940
24957
|
"severity": "error" | "warn" | "info",
|
|
24941
|
-
"file": "path/to/file
|
|
24958
|
+
"file": "path/to/file",
|
|
24942
24959
|
"line": 42,
|
|
24943
24960
|
"issue": "description of the issue",
|
|
24944
24961
|
"suggestion": "how to fix it"
|
|
@@ -24946,7 +24963,7 @@ Format:
|
|
|
24946
24963
|
]
|
|
24947
24964
|
}
|
|
24948
24965
|
|
|
24949
|
-
If
|
|
24966
|
+
If all ACs are correctly implemented, respond with { "passed": true, "findings": [] }.`;
|
|
24950
24967
|
}
|
|
24951
24968
|
function parseLLMResponse(raw) {
|
|
24952
24969
|
try {
|
|
@@ -24989,7 +25006,7 @@ function toReviewFindings(findings) {
|
|
|
24989
25006
|
source: "semantic-review"
|
|
24990
25007
|
}));
|
|
24991
25008
|
}
|
|
24992
|
-
async function runSemanticReview(workdir, storyGitRef, story, semanticConfig, modelResolver) {
|
|
25009
|
+
async function runSemanticReview(workdir, storyGitRef, story, semanticConfig, modelResolver, naxConfig) {
|
|
24993
25010
|
const startTime = Date.now();
|
|
24994
25011
|
const logger = getSafeLogger();
|
|
24995
25012
|
if (!storyGitRef) {
|
|
@@ -25002,8 +25019,12 @@ async function runSemanticReview(workdir, storyGitRef, story, semanticConfig, mo
|
|
|
25002
25019
|
durationMs: Date.now() - startTime
|
|
25003
25020
|
};
|
|
25004
25021
|
}
|
|
25005
|
-
logger?.info("review", "Running semantic check", {
|
|
25006
|
-
|
|
25022
|
+
logger?.info("review", "Running semantic check", {
|
|
25023
|
+
storyId: story.id,
|
|
25024
|
+
modelTier: semanticConfig.modelTier,
|
|
25025
|
+
configProvided: !!naxConfig
|
|
25026
|
+
});
|
|
25027
|
+
const rawDiff = await collectDiff(workdir, storyGitRef, semanticConfig.excludePatterns);
|
|
25007
25028
|
const needsTruncation = rawDiff.length > DIFF_CAP_BYTES;
|
|
25008
25029
|
const stat = needsTruncation ? await collectDiffStat(workdir, storyGitRef) : undefined;
|
|
25009
25030
|
const diff = truncateDiff(rawDiff, stat);
|
|
@@ -25027,7 +25048,9 @@ async function runSemanticReview(workdir, storyGitRef, story, semanticConfig, mo
|
|
|
25027
25048
|
rawResponse = await agent.complete(prompt, {
|
|
25028
25049
|
sessionName: `nax-semantic-${story.id}`,
|
|
25029
25050
|
workdir,
|
|
25030
|
-
timeoutMs: semanticConfig.timeoutMs
|
|
25051
|
+
timeoutMs: semanticConfig.timeoutMs,
|
|
25052
|
+
modelTier: semanticConfig.modelTier,
|
|
25053
|
+
config: naxConfig
|
|
25031
25054
|
});
|
|
25032
25055
|
} catch (err) {
|
|
25033
25056
|
logger?.warn("semantic", "LLM call failed \u2014 fail-open", { cause: String(err) });
|
|
@@ -25108,19 +25131,12 @@ ${formatFindings(parsed.findings)}`;
|
|
|
25108
25131
|
durationMs
|
|
25109
25132
|
};
|
|
25110
25133
|
}
|
|
25111
|
-
var _semanticDeps, DIFF_CAP_BYTES =
|
|
25134
|
+
var _semanticDeps, DIFF_CAP_BYTES = 51200;
|
|
25112
25135
|
var init_semantic = __esm(() => {
|
|
25113
25136
|
init_logger2();
|
|
25114
25137
|
_semanticDeps = {
|
|
25115
25138
|
spawn: spawn2
|
|
25116
25139
|
};
|
|
25117
|
-
DEFAULT_RULES = [
|
|
25118
|
-
"No stubs or noops left in production code paths",
|
|
25119
|
-
"No placeholder values (TODO, FIXME, hardcoded dummy data)",
|
|
25120
|
-
"No unrelated changes outside the story scope",
|
|
25121
|
-
"All new code is properly wired into callers and exports",
|
|
25122
|
-
"No silent error swallowing (catch blocks that discard errors without logging)"
|
|
25123
|
-
];
|
|
25124
25140
|
});
|
|
25125
25141
|
|
|
25126
25142
|
// src/review/runner.ts
|
|
@@ -25267,7 +25283,7 @@ async function getUncommittedFilesImpl(workdir) {
|
|
|
25267
25283
|
return [];
|
|
25268
25284
|
}
|
|
25269
25285
|
}
|
|
25270
|
-
async function runReview(config2, workdir, executionConfig, qualityCommands, storyId, storyGitRef, story, modelResolver) {
|
|
25286
|
+
async function runReview(config2, workdir, executionConfig, qualityCommands, storyId, storyGitRef, story, modelResolver, naxConfig) {
|
|
25271
25287
|
const startTime = Date.now();
|
|
25272
25288
|
const logger = getSafeLogger();
|
|
25273
25289
|
const checks3 = [];
|
|
@@ -25317,9 +25333,10 @@ Stage and commit these files before running review.`
|
|
|
25317
25333
|
const semanticCfg = config2.semantic ?? {
|
|
25318
25334
|
modelTier: "balanced",
|
|
25319
25335
|
rules: [],
|
|
25320
|
-
timeoutMs: 600000
|
|
25336
|
+
timeoutMs: 600000,
|
|
25337
|
+
excludePatterns: [":!test/", ":!tests/", ":!*_test.go", ":!*.test.ts", ":!*.spec.ts", ":!**/__tests__/"]
|
|
25321
25338
|
};
|
|
25322
|
-
const result2 = await _reviewSemanticDeps.runSemanticReview(workdir, storyGitRef, semanticStory, semanticCfg, modelResolver ?? (() => null));
|
|
25339
|
+
const result2 = await _reviewSemanticDeps.runSemanticReview(workdir, storyGitRef, semanticStory, semanticCfg, modelResolver ?? (() => null), naxConfig);
|
|
25323
25340
|
checks3.push(result2);
|
|
25324
25341
|
if (!result2.success && !firstFailure) {
|
|
25325
25342
|
firstFailure = `${checkName} failed`;
|
|
@@ -25401,9 +25418,9 @@ async function getChangedFiles(workdir, baseRef) {
|
|
|
25401
25418
|
}
|
|
25402
25419
|
|
|
25403
25420
|
class ReviewOrchestrator {
|
|
25404
|
-
async review(reviewConfig, workdir, executionConfig, plugins, storyGitRef, scopePrefix, qualityCommands, storyId, story, modelResolver) {
|
|
25421
|
+
async review(reviewConfig, workdir, executionConfig, plugins, storyGitRef, scopePrefix, qualityCommands, storyId, story, modelResolver, naxConfig) {
|
|
25405
25422
|
const logger = getSafeLogger();
|
|
25406
|
-
const builtIn = await runReview(reviewConfig, workdir, executionConfig, qualityCommands, storyId, storyGitRef, story, modelResolver);
|
|
25423
|
+
const builtIn = await runReview(reviewConfig, workdir, executionConfig, qualityCommands, storyId, storyGitRef, story, modelResolver, naxConfig);
|
|
25407
25424
|
if (!builtIn.success) {
|
|
25408
25425
|
return { builtIn, success: false, failureReason: builtIn.failureReason, pluginFailed: false };
|
|
25409
25426
|
}
|
|
@@ -25502,7 +25519,7 @@ var init_review = __esm(() => {
|
|
|
25502
25519
|
title: ctx.story.title,
|
|
25503
25520
|
description: ctx.story.description,
|
|
25504
25521
|
acceptanceCriteria: ctx.story.acceptanceCriteria
|
|
25505
|
-
}, modelResolver);
|
|
25522
|
+
}, modelResolver, ctx.config);
|
|
25506
25523
|
ctx.reviewResult = result.builtIn;
|
|
25507
25524
|
if (!result.success) {
|
|
25508
25525
|
const pluginFindings = result.builtIn.pluginReviewers?.flatMap((pr) => pr.findings ?? []) ?? [];
|