@nathapp/nax 0.65.0 → 0.65.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/dist/nax.js +659 -94
- package/package.json +1 -1
package/dist/nax.js
CHANGED
|
@@ -19957,7 +19957,9 @@ var init_schemas_execution = __esm(() => {
|
|
|
19957
19957
|
test: exports_external.string().optional(),
|
|
19958
19958
|
testScoped: exports_external.string().optional(),
|
|
19959
19959
|
lintFix: exports_external.string().optional(),
|
|
19960
|
+
lintFixScoped: exports_external.string().optional(),
|
|
19960
19961
|
formatFix: exports_external.string().optional(),
|
|
19962
|
+
formatFixScoped: exports_external.string().optional(),
|
|
19961
19963
|
build: exports_external.string().optional()
|
|
19962
19964
|
}).default({}),
|
|
19963
19965
|
lintOutput: exports_external.object({
|
|
@@ -20045,7 +20047,7 @@ var init_schemas_execution = __esm(() => {
|
|
|
20045
20047
|
});
|
|
20046
20048
|
|
|
20047
20049
|
// src/config/schemas-infra.ts
|
|
20048
|
-
var PlanConfigSchema, AcceptanceFixConfigSchema, AcceptanceConfigSchema, LlmRoutingConfigSchema, RoutingConfigSchema, OptimizerConfigSchema, PluginConfigEntrySchema, HooksConfigSchema, InteractionConfigSchema, StorySizeGateConfigSchema, PromptAuditConfigSchema, AgentFallbackConfigSchema, AgentIdleWatchdogConfigSchema, AgentAcpConfigSchema, AgentConfigSchema, PrecheckConfigSchema, PromptsConfigSchema, ProjectProfileSchema, VALID_AGENT_TYPES, GenerateConfigSchema, CuratorThresholdsSchema, CuratorConfigSchema;
|
|
20050
|
+
var PlanConfigSchema, AcceptanceFixConfigSchema, AcceptanceConfigSchema, LlmRoutingConfigSchema, RoutingConfigSchema, OptimizerConfigSchema, PluginConfigEntrySchema, HooksConfigSchema, InteractionConfigSchema, StorySizeGateConfigSchema, PromptAuditConfigSchema, AgentFallbackConfigSchema, DEFAULT_AGENT_IDLE_WATCHDOG_CONFIG, AgentIdleWatchdogConfigSchema, AgentAcpConfigSchema, AgentConfigSchema, PrecheckConfigSchema, PromptsConfigSchema, ProjectProfileSchema, VALID_AGENT_TYPES, GenerateConfigSchema, CuratorThresholdsSchema, CuratorConfigSchema;
|
|
20049
20051
|
var init_schemas_infra = __esm(() => {
|
|
20050
20052
|
init_zod();
|
|
20051
20053
|
init_schemas_model();
|
|
@@ -20147,6 +20149,14 @@ var init_schemas_infra = __esm(() => {
|
|
|
20147
20149
|
onQualityFailure: exports_external.boolean().default(false),
|
|
20148
20150
|
rebuildContext: exports_external.boolean().default(true)
|
|
20149
20151
|
});
|
|
20152
|
+
DEFAULT_AGENT_IDLE_WATCHDOG_CONFIG = {
|
|
20153
|
+
enabled: true,
|
|
20154
|
+
mode: "warn-then-cancel",
|
|
20155
|
+
idleTimeoutSeconds: 900,
|
|
20156
|
+
activityKinds: ["message_update", "thinking_update", "usage_update"],
|
|
20157
|
+
cancelGraceSeconds: 10,
|
|
20158
|
+
maxRetryAttempts: 3
|
|
20159
|
+
};
|
|
20150
20160
|
AgentIdleWatchdogConfigSchema = exports_external.object({
|
|
20151
20161
|
enabled: exports_external.boolean().default(true),
|
|
20152
20162
|
mode: exports_external.enum(["off", "observe", "warn-then-cancel", "cancel"]).default("warn-then-cancel"),
|
|
@@ -20173,7 +20183,7 @@ var init_schemas_infra = __esm(() => {
|
|
|
20173
20183
|
rebuildContext: true
|
|
20174
20184
|
}),
|
|
20175
20185
|
acp: AgentAcpConfigSchema.default({ promptRetries: 0 }),
|
|
20176
|
-
idleWatchdog: AgentIdleWatchdogConfigSchema.
|
|
20186
|
+
idleWatchdog: AgentIdleWatchdogConfigSchema.default(DEFAULT_AGENT_IDLE_WATCHDOG_CONFIG)
|
|
20177
20187
|
});
|
|
20178
20188
|
PrecheckConfigSchema = exports_external.object({
|
|
20179
20189
|
storySizeGate: StorySizeGateConfigSchema
|
|
@@ -20255,7 +20265,9 @@ var init_schemas_review = __esm(() => {
|
|
|
20255
20265
|
test: exports_external.string().optional(),
|
|
20256
20266
|
build: exports_external.string().optional(),
|
|
20257
20267
|
lintFix: exports_external.string().optional(),
|
|
20258
|
-
|
|
20268
|
+
lintFixScoped: exports_external.string().optional(),
|
|
20269
|
+
formatFix: exports_external.string().optional(),
|
|
20270
|
+
formatFixScoped: exports_external.string().optional()
|
|
20259
20271
|
}),
|
|
20260
20272
|
pluginMode: exports_external.enum(["per-story", "deferred"]).default("per-story"),
|
|
20261
20273
|
audit: exports_external.object({ enabled: exports_external.boolean().default(false) }).default({ enabled: false }),
|
|
@@ -20546,7 +20558,8 @@ var init_schemas3 = __esm(() => {
|
|
|
20546
20558
|
maxInteractionTurns: 20,
|
|
20547
20559
|
promptAudit: { enabled: false },
|
|
20548
20560
|
fallback: { enabled: false, map: {}, maxHopsPerStory: 2, onQualityFailure: false, rebuildContext: true },
|
|
20549
|
-
acp: { promptRetries: 0 }
|
|
20561
|
+
acp: { promptRetries: 0 },
|
|
20562
|
+
idleWatchdog: DEFAULT_AGENT_IDLE_WATCHDOG_CONFIG
|
|
20550
20563
|
}),
|
|
20551
20564
|
precheck: PrecheckConfigSchema.optional().default({
|
|
20552
20565
|
storySizeGate: {
|
|
@@ -20716,6 +20729,15 @@ function mergePackageConfig(root, packageOverride) {
|
|
|
20716
20729
|
...packageOverride.quality?.commands?.lintFix !== undefined && {
|
|
20717
20730
|
lintFix: packageOverride.quality.commands.lintFix
|
|
20718
20731
|
},
|
|
20732
|
+
...packageOverride.quality?.commands?.lintFixScoped !== undefined && {
|
|
20733
|
+
lintFixScoped: packageOverride.quality.commands.lintFixScoped
|
|
20734
|
+
},
|
|
20735
|
+
...packageOverride.quality?.commands?.formatFix !== undefined && {
|
|
20736
|
+
formatFix: packageOverride.quality.commands.formatFix
|
|
20737
|
+
},
|
|
20738
|
+
...packageOverride.quality?.commands?.formatFixScoped !== undefined && {
|
|
20739
|
+
formatFixScoped: packageOverride.quality.commands.formatFixScoped
|
|
20740
|
+
},
|
|
20719
20741
|
...packageOverride.quality?.commands?.typecheck !== undefined && {
|
|
20720
20742
|
typecheck: packageOverride.quality.commands.typecheck
|
|
20721
20743
|
},
|
|
@@ -29412,10 +29434,14 @@ For each acceptance criterion, verify the current codebase implements it correct
|
|
|
29412
29434
|
- The \`verifiedBy.observed\` field MUST be a **verbatim** 1-3 line code excerpt copy-pasted from the file \u2014 not a description. Paste the actual source lines (or a substring of them) that prove your claim. A description like "function X does not check Y" is not a verifiable observation; quote the lines that demonstrate the omission instead. If you cannot quote an exact excerpt that proves your point, downgrade the finding to "unverifiable".
|
|
29413
29435
|
|
|
29414
29436
|
**AC-grounding rule \u2014 required for every "error" finding:**
|
|
29415
|
-
- Every "error" finding MUST include \`acQuote\`: a verbatim substring of one AC bullet that names or constrains the exact
|
|
29437
|
+
- Every "error" finding MUST include \`acQuote\`: a verbatim substring of one AC bullet that names or constrains the exact **symbol** you are flagging \u2014 not merely the file the symbol lives in.
|
|
29416
29438
|
- Include \`acIndex\` (1-based) indicating which AC bullet you are quoting.
|
|
29417
|
-
-
|
|
29418
|
-
|
|
29439
|
+
- Copy \`acQuote\` directly from the Acceptance Criteria \u2014 including any backticks, asterisks, or punctuation. Do not paraphrase, strip formatting, or rewrite.
|
|
29440
|
+
|
|
29441
|
+
**The "AC names the file but not the symbol" trap (most common failure mode):**
|
|
29442
|
+
If the AC bullet mentions a file or component but the **specific symbol you are flagging** (the function, class, interface, type, or convention) is not named in that bullet, the AC does **not** constrain your finding. Emit it as \`severity: "info"\` \u2014 not \`"error"\`. **Convention / coding-standard violations almost always belong as \`"info"\`** unless an AC specifically names the convention or the symbol it concerns.
|
|
29443
|
+
|
|
29444
|
+
If you cannot find an AC that names the **specific symbol** in your finding, downgrade to \`"info"\`. A finding dropped by the validator as ungrounded is worse than one correctly classified as advisory.
|
|
29419
29445
|
|
|
29420
29446
|
Flag issues only when you have confirmed:
|
|
29421
29447
|
1. An AC is not implemented or partially implemented (verified by reading the actual files)
|
|
@@ -29663,10 +29689,22 @@ Severity guide:
|
|
|
29663
29689
|
\`passed\` may be \`true\` with findings if all findings are \`"info"\` or \`"unverifiable"\`.
|
|
29664
29690
|
|
|
29665
29691
|
**AC-grounding rule \u2014 required for every "error" finding:**
|
|
29666
|
-
- \`acQuote\` must be a verbatim substring of one AC bullet (from the Acceptance Criteria above) that names or constrains the exact
|
|
29692
|
+
- \`acQuote\` must be a verbatim substring of one AC bullet (from the Acceptance Criteria above) that names or constrains the exact **symbol** you are flagging \u2014 not merely the file the symbol lives in.
|
|
29667
29693
|
- \`acIndex\` is the 1-based position of that AC bullet in the list.
|
|
29668
|
-
-
|
|
29669
|
-
|
|
29694
|
+
- Copy \`acQuote\` **exactly** from the AC text, including any backticks, asterisks, or punctuation. Do not paraphrase, strip formatting, or rewrite.
|
|
29695
|
+
|
|
29696
|
+
**The "AC names the file but not the symbol" trap (most common failure mode):**
|
|
29697
|
+
If the AC bullet mentions a file or component but the **specific symbol you are flagging** (the function, class, interface, type, or convention) is not named in that bullet, the AC does **not** constrain your finding. Emit it as \`"info"\` \u2014 not \`"error"\`.
|
|
29698
|
+
|
|
29699
|
+
Worked example:
|
|
29700
|
+
- AC#1 reads: \`\`\`\`AstIndexService.indexCommit() is called by the code_commit outbox handler\`\`\`\`
|
|
29701
|
+
- You found that \`code-commit-outbox-handler.ts\` defines a custom \`ExtendedPrismaClient\` interface, violating a project convention rule.
|
|
29702
|
+
- WRONG: severity \`"error"\`, \`acQuote: "AstIndexService.indexCommit() is called by the code_commit outbox handler"\`, \`acIndex: 1\`. \u2014 AC#1 is about *who calls indexCommit*; it says nothing about Prisma typing. Picking it because the file is named is mis-grounding.
|
|
29703
|
+
- RIGHT: severity \`"info"\`, no \`acQuote\`. The convention violation is real, but no AC constrains \`ExtendedPrismaClient\`, so it cannot block the story.
|
|
29704
|
+
|
|
29705
|
+
**Convention / coding-standard violations almost always belong as \`"info"\`** unless an AC specifically names the convention or the symbol it concerns.
|
|
29706
|
+
|
|
29707
|
+
If you cannot find an AC that names the **specific symbol** in your finding, downgrade to \`"info"\`. A finding dropped by the validator is worse than one correctly classified as advisory.`;
|
|
29670
29708
|
var init_adversarial_review_builder = () => {};
|
|
29671
29709
|
|
|
29672
29710
|
// src/prompts/builders/acceptance-builder-helpers.ts
|
|
@@ -33670,12 +33708,79 @@ var init_rectify = __esm(() => {
|
|
|
33670
33708
|
init_prompts();
|
|
33671
33709
|
});
|
|
33672
33710
|
|
|
33711
|
+
// src/operations/test-edit-declaration.ts
|
|
33712
|
+
function readBlockField(block, key) {
|
|
33713
|
+
const re = new RegExp(`^${key}:\\s*(.+)$`, "m");
|
|
33714
|
+
const m = block.match(re);
|
|
33715
|
+
if (!m?.[1])
|
|
33716
|
+
return null;
|
|
33717
|
+
return m[1].trim();
|
|
33718
|
+
}
|
|
33719
|
+
function unwrapQuotes(s) {
|
|
33720
|
+
if (s.length >= 2 && s.startsWith('"') && s.endsWith('"'))
|
|
33721
|
+
return s.slice(1, -1);
|
|
33722
|
+
return s;
|
|
33723
|
+
}
|
|
33724
|
+
function parseTestEditDeclarations(output) {
|
|
33725
|
+
const result = [];
|
|
33726
|
+
const blocks = output.split(/\n\s*\n/);
|
|
33727
|
+
for (const block of blocks) {
|
|
33728
|
+
const reasonMatch = block.match(REASON_RE);
|
|
33729
|
+
if (!reasonMatch?.[1])
|
|
33730
|
+
continue;
|
|
33731
|
+
const reason = reasonMatch[1];
|
|
33732
|
+
if (reason === "prd_contract") {
|
|
33733
|
+
const file3 = readBlockField(block, "FILE");
|
|
33734
|
+
const prdQuote = readBlockField(block, "PRD_QUOTE");
|
|
33735
|
+
const testBefore = readBlockField(block, "TEST_BEFORE");
|
|
33736
|
+
const testAfter = readBlockField(block, "TEST_AFTER");
|
|
33737
|
+
if (!file3 || !prdQuote || !testBefore || !testAfter)
|
|
33738
|
+
continue;
|
|
33739
|
+
result.push({
|
|
33740
|
+
reason,
|
|
33741
|
+
file: file3,
|
|
33742
|
+
prdQuote: unwrapQuotes(prdQuote),
|
|
33743
|
+
testBefore,
|
|
33744
|
+
testAfter
|
|
33745
|
+
});
|
|
33746
|
+
} else if (reason === "lint_only") {
|
|
33747
|
+
const file3 = readBlockField(block, "FILE");
|
|
33748
|
+
const finding = readBlockField(block, "FINDING");
|
|
33749
|
+
if (!file3 || !finding)
|
|
33750
|
+
continue;
|
|
33751
|
+
result.push({ reason, file: file3, finding });
|
|
33752
|
+
} else if (reason === "sibling_scope") {
|
|
33753
|
+
const file3 = readBlockField(block, "SIBLING_FILE");
|
|
33754
|
+
const finding = readBlockField(block, "FINDING");
|
|
33755
|
+
if (!file3 || !finding)
|
|
33756
|
+
continue;
|
|
33757
|
+
result.push({ reason, file: file3, finding });
|
|
33758
|
+
}
|
|
33759
|
+
}
|
|
33760
|
+
return result;
|
|
33761
|
+
}
|
|
33762
|
+
function normaliseWs(s) {
|
|
33763
|
+
return s.replace(/\s+/g, " ").replace(/\s*([(),<>])\s*/g, "$1").replace(/\s*:\s*/g, ": ").trim();
|
|
33764
|
+
}
|
|
33765
|
+
function validatePrdQuote(prdQuote, story) {
|
|
33766
|
+
if (!prdQuote.trim())
|
|
33767
|
+
return false;
|
|
33768
|
+
const needle = normaliseWs(prdQuote);
|
|
33769
|
+
const haystack = normaliseWs([story.description, ...story.acceptanceCriteria].join(" "));
|
|
33770
|
+
return haystack.includes(needle);
|
|
33771
|
+
}
|
|
33772
|
+
var REASON_RE;
|
|
33773
|
+
var init_test_edit_declaration = __esm(() => {
|
|
33774
|
+
REASON_RE = /^TEST_EDIT_REASON:\s*(prd_contract|lint_only|sibling_scope)\s*$/m;
|
|
33775
|
+
});
|
|
33776
|
+
|
|
33673
33777
|
// src/operations/autofix-implementer.ts
|
|
33674
33778
|
var implementerRectifyOp;
|
|
33675
33779
|
var init_autofix_implementer = __esm(() => {
|
|
33676
33780
|
init_config();
|
|
33677
33781
|
init_logger2();
|
|
33678
33782
|
init_prompts();
|
|
33783
|
+
init_test_edit_declaration();
|
|
33679
33784
|
implementerRectifyOp = {
|
|
33680
33785
|
kind: "run",
|
|
33681
33786
|
name: "autofix-implementer",
|
|
@@ -33690,15 +33795,20 @@ var init_autofix_implementer = __esm(() => {
|
|
|
33690
33795
|
};
|
|
33691
33796
|
},
|
|
33692
33797
|
parse(output, input, _ctx) {
|
|
33693
|
-
const
|
|
33694
|
-
const
|
|
33695
|
-
|
|
33798
|
+
const unresolvedMatch = output.match(/^UNRESOLVED:\s*(.+)$/m);
|
|
33799
|
+
const declarations = parseTestEditDeclarations(output);
|
|
33800
|
+
for (const d of declarations) {
|
|
33696
33801
|
getSafeLogger()?.info("autofix", "test_edit_declared", {
|
|
33697
33802
|
storyId: input.story.id,
|
|
33698
|
-
reason:
|
|
33803
|
+
reason: d.reason,
|
|
33804
|
+
file: d.file
|
|
33699
33805
|
});
|
|
33700
33806
|
}
|
|
33701
|
-
return {
|
|
33807
|
+
return {
|
|
33808
|
+
applied: true,
|
|
33809
|
+
testEditDeclarations: declarations,
|
|
33810
|
+
...unresolvedMatch ? { unresolvedReason: unresolvedMatch[1]?.trim() } : {}
|
|
33811
|
+
};
|
|
33702
33812
|
}
|
|
33703
33813
|
};
|
|
33704
33814
|
});
|
|
@@ -35142,6 +35252,7 @@ var init_operations = __esm(() => {
|
|
|
35142
35252
|
init_adversarial_review();
|
|
35143
35253
|
init_rectify();
|
|
35144
35254
|
init_autofix_implementer();
|
|
35255
|
+
init_test_edit_declaration();
|
|
35145
35256
|
init_autofix_test_writer();
|
|
35146
35257
|
init_debate_propose();
|
|
35147
35258
|
init_debate_rebut();
|
|
@@ -40710,6 +40821,9 @@ var init_checks_cli = __esm(() => {
|
|
|
40710
40821
|
|
|
40711
40822
|
// src/precheck/checks-system.ts
|
|
40712
40823
|
import { existsSync as existsSync12, statSync as statSync4 } from "fs";
|
|
40824
|
+
function discoverCanonicalRuleRoots(workdir) {
|
|
40825
|
+
return [workdir];
|
|
40826
|
+
}
|
|
40713
40827
|
async function checkDependenciesInstalled(workdir) {
|
|
40714
40828
|
const depPaths = [
|
|
40715
40829
|
{ path: "node_modules" },
|
|
@@ -40787,7 +40901,47 @@ async function checkTypecheckCommand(config2) {
|
|
|
40787
40901
|
message: `Typecheck command configured: ${typecheckCommand}`
|
|
40788
40902
|
};
|
|
40789
40903
|
}
|
|
40790
|
-
|
|
40904
|
+
async function checkCanonicalRulesLint(workdir) {
|
|
40905
|
+
const roots = _checkCanonicalRulesDeps.discoverRoots(workdir);
|
|
40906
|
+
let ruleCount = 0;
|
|
40907
|
+
try {
|
|
40908
|
+
for (const root of roots) {
|
|
40909
|
+
const rules = await _checkCanonicalRulesDeps.loadCanonicalRules(root);
|
|
40910
|
+
ruleCount += rules.length;
|
|
40911
|
+
}
|
|
40912
|
+
} catch (err) {
|
|
40913
|
+
if (err instanceof NeutralityLintError) {
|
|
40914
|
+
const first = err.violations[0];
|
|
40915
|
+
const detail = first ? `${first.file}:${first.lineNumber} (${first.ruleId})` : "unknown location";
|
|
40916
|
+
return {
|
|
40917
|
+
name: "canonical-rules-lint",
|
|
40918
|
+
tier: "blocker",
|
|
40919
|
+
passed: false,
|
|
40920
|
+
message: `Canonical rules lint failed (${err.violations.length} violation(s)): ${detail}`
|
|
40921
|
+
};
|
|
40922
|
+
}
|
|
40923
|
+
return {
|
|
40924
|
+
name: "canonical-rules-lint",
|
|
40925
|
+
tier: "blocker",
|
|
40926
|
+
passed: false,
|
|
40927
|
+
message: `Canonical rules lint failed: ${errorMessage(err)}`
|
|
40928
|
+
};
|
|
40929
|
+
}
|
|
40930
|
+
return {
|
|
40931
|
+
name: "canonical-rules-lint",
|
|
40932
|
+
tier: "blocker",
|
|
40933
|
+
passed: true,
|
|
40934
|
+
message: `Canonical rules lint passed (${ruleCount} file(s) across ${roots.length} root(s))`
|
|
40935
|
+
};
|
|
40936
|
+
}
|
|
40937
|
+
var _checkCanonicalRulesDeps;
|
|
40938
|
+
var init_checks_system = __esm(() => {
|
|
40939
|
+
init_canonical_loader();
|
|
40940
|
+
_checkCanonicalRulesDeps = {
|
|
40941
|
+
discoverRoots: discoverCanonicalRuleRoots,
|
|
40942
|
+
loadCanonicalRules
|
|
40943
|
+
};
|
|
40944
|
+
});
|
|
40791
40945
|
|
|
40792
40946
|
// src/precheck/checks-blockers.ts
|
|
40793
40947
|
var init_checks_blockers = __esm(() => {
|
|
@@ -41255,6 +41409,7 @@ function getLateEnvironmentBlockers(config2, workdir) {
|
|
|
41255
41409
|
() => checkTestCommand(config2),
|
|
41256
41410
|
() => checkLintCommand(config2),
|
|
41257
41411
|
() => checkTypecheckCommand(config2),
|
|
41412
|
+
() => checkCanonicalRulesLint(workdir),
|
|
41258
41413
|
() => checkGitUserConfigured(workdir)
|
|
41259
41414
|
];
|
|
41260
41415
|
}
|
|
@@ -43373,7 +43528,7 @@ function collectAdversarialSourceChecks(ctx) {
|
|
|
43373
43528
|
function buildAutofixStrategies(ctx, maxAttempts) {
|
|
43374
43529
|
const implementer = {
|
|
43375
43530
|
name: "autofix-implementer",
|
|
43376
|
-
appliesTo: (f) => (f.fixTarget ?? "source") === "source",
|
|
43531
|
+
appliesTo: (f) => (f.fixTarget ?? "source") === "source" && f.category !== "prd_quote_mismatch",
|
|
43377
43532
|
fixOp: implementerRectifyOp,
|
|
43378
43533
|
maxAttempts,
|
|
43379
43534
|
coRun: "co-run-sequential",
|
|
@@ -43381,16 +43536,22 @@ function buildAutofixStrategies(ctx, maxAttempts) {
|
|
|
43381
43536
|
failedChecks: collectFailedChecks(ctx),
|
|
43382
43537
|
story: ctx.story
|
|
43383
43538
|
}),
|
|
43384
|
-
extractApplied: (output) =>
|
|
43385
|
-
|
|
43386
|
-
|
|
43387
|
-
|
|
43539
|
+
extractApplied: (output) => {
|
|
43540
|
+
const decls = output.testEditDeclarations ?? [];
|
|
43541
|
+
if (decls.length > 0) {
|
|
43542
|
+
ctx.testEditDeclarations = [...ctx.testEditDeclarations ?? [], ...decls];
|
|
43543
|
+
}
|
|
43544
|
+
return {
|
|
43545
|
+
summary: output.unresolvedReason ?? "",
|
|
43546
|
+
unresolved: output.unresolvedReason
|
|
43547
|
+
};
|
|
43548
|
+
}
|
|
43388
43549
|
};
|
|
43389
43550
|
const testWriter = {
|
|
43390
43551
|
name: "autofix-test-writer",
|
|
43391
43552
|
appliesTo: (f) => f.fixTarget === "test" || (f.fixTarget ?? "source") === "source" && f.severity === "error" && f.source === "adversarial-review",
|
|
43392
43553
|
fixOp: testWriterRectifyOp,
|
|
43393
|
-
maxAttempts:
|
|
43554
|
+
maxAttempts: 2,
|
|
43394
43555
|
coRun: "co-run-sequential",
|
|
43395
43556
|
buildInput: (findings, _prior, _cycleCtx) => {
|
|
43396
43557
|
const hasSourceBug = findings.some((f) => (f.fixTarget ?? "source") === "source" && f.source === "adversarial-review");
|
|
@@ -43411,6 +43572,25 @@ function buildAutofixStrategies(ctx, maxAttempts) {
|
|
|
43411
43572
|
};
|
|
43412
43573
|
return [testWriter, implementer];
|
|
43413
43574
|
}
|
|
43575
|
+
function autofixCapacityExhausted(ctx) {
|
|
43576
|
+
const findings = collectCurrentFindings(ctx);
|
|
43577
|
+
if (findings.length === 0)
|
|
43578
|
+
return false;
|
|
43579
|
+
const maxAttempts = ctx.config.quality.autofix?.maxAttempts ?? 3;
|
|
43580
|
+
const maxTotal = ctx.config.quality.autofix?.maxTotalAttempts ?? 12;
|
|
43581
|
+
const prior = ctx.autofixPriorIterations ?? [];
|
|
43582
|
+
const totalUsed = prior.reduce((sum, iter) => sum + iter.fixesApplied.length, 0);
|
|
43583
|
+
if (totalUsed >= maxTotal)
|
|
43584
|
+
return true;
|
|
43585
|
+
const strategies = buildAutofixStrategies(ctx, maxAttempts);
|
|
43586
|
+
const active = strategies.filter((s) => findings.some((f) => s.appliesTo(f)));
|
|
43587
|
+
if (active.length === 0)
|
|
43588
|
+
return true;
|
|
43589
|
+
return active.some((s) => {
|
|
43590
|
+
const used = prior.reduce((sum, iter) => sum + iter.fixesApplied.filter((fa) => fa.strategyName === s.name).length, 0);
|
|
43591
|
+
return used >= s.maxAttempts;
|
|
43592
|
+
});
|
|
43593
|
+
}
|
|
43414
43594
|
function buildEscalationDigest(findings) {
|
|
43415
43595
|
const byFile = new Map;
|
|
43416
43596
|
for (const f of findings) {
|
|
@@ -43450,6 +43630,50 @@ async function writeShadowReport(ctx, result, initialFindingsCount) {
|
|
|
43450
43630
|
});
|
|
43451
43631
|
}
|
|
43452
43632
|
}
|
|
43633
|
+
function applyTestEditDeclarations(findings, declarations, story) {
|
|
43634
|
+
if (declarations.length === 0)
|
|
43635
|
+
return findings;
|
|
43636
|
+
const out = [...findings];
|
|
43637
|
+
const originalLength = findings.length;
|
|
43638
|
+
const reTaggedKeys = new Set;
|
|
43639
|
+
for (const decl of declarations) {
|
|
43640
|
+
if (decl.reason !== "prd_contract")
|
|
43641
|
+
continue;
|
|
43642
|
+
if (!validatePrdQuote(decl.prdQuote ?? "", story)) {
|
|
43643
|
+
out.push({
|
|
43644
|
+
source: "adversarial-review",
|
|
43645
|
+
severity: "warning",
|
|
43646
|
+
category: "prd_quote_mismatch",
|
|
43647
|
+
message: `Implementer declared TEST_EDIT_REASON: prd_contract with PRD_QUOTE not found in story description or AC text: ${decl.prdQuote}`,
|
|
43648
|
+
file: decl.file,
|
|
43649
|
+
fixTarget: "source"
|
|
43650
|
+
});
|
|
43651
|
+
continue;
|
|
43652
|
+
}
|
|
43653
|
+
for (let i = 0;i < originalLength; i++) {
|
|
43654
|
+
if (reTaggedKeys.has(i))
|
|
43655
|
+
continue;
|
|
43656
|
+
if (out[i].file !== decl.file)
|
|
43657
|
+
continue;
|
|
43658
|
+
if ((out[i].fixTarget ?? "source") === "test")
|
|
43659
|
+
continue;
|
|
43660
|
+
out[i] = {
|
|
43661
|
+
...out[i],
|
|
43662
|
+
fixTarget: "test",
|
|
43663
|
+
meta: {
|
|
43664
|
+
...out[i].meta ?? {},
|
|
43665
|
+
prdContractDeclaration: {
|
|
43666
|
+
prdQuote: decl.prdQuote,
|
|
43667
|
+
testBefore: decl.testBefore,
|
|
43668
|
+
testAfter: decl.testAfter
|
|
43669
|
+
}
|
|
43670
|
+
}
|
|
43671
|
+
};
|
|
43672
|
+
reTaggedKeys.add(i);
|
|
43673
|
+
}
|
|
43674
|
+
}
|
|
43675
|
+
return out;
|
|
43676
|
+
}
|
|
43453
43677
|
async function runAgentRectificationV2(ctx, _lintFixCmd, _formatFixCmd, _effectiveWorkdir) {
|
|
43454
43678
|
const logger = getLogger();
|
|
43455
43679
|
const storyId = ctx.story.id;
|
|
@@ -43473,7 +43697,18 @@ async function runAgentRectificationV2(ctx, _lintFixCmd, _formatFixCmd, _effecti
|
|
|
43473
43697
|
},
|
|
43474
43698
|
async validate(_cycleCtx) {
|
|
43475
43699
|
await _autofixDeps.recheckReview(ctx);
|
|
43476
|
-
|
|
43700
|
+
const fresh = collectCurrentFindings(ctx);
|
|
43701
|
+
const pending = ctx.testEditDeclarations ?? [];
|
|
43702
|
+
if (pending.length === 0)
|
|
43703
|
+
return fresh;
|
|
43704
|
+
const retagged = applyTestEditDeclarations(fresh, pending, ctx.story);
|
|
43705
|
+
ctx.testEditDeclarations = [];
|
|
43706
|
+
logger.info("autofix-cycle", "applied test-edit declarations", {
|
|
43707
|
+
storyId: ctx.story.id,
|
|
43708
|
+
declarationCount: pending.length,
|
|
43709
|
+
reTaggedCount: retagged.filter((f) => f.fixTarget === "test").length - fresh.filter((f) => f.fixTarget === "test").length
|
|
43710
|
+
});
|
|
43711
|
+
return retagged;
|
|
43477
43712
|
}
|
|
43478
43713
|
};
|
|
43479
43714
|
const result = await runFixCycle(cycle, cycleCtx, "autofix-v2");
|
|
@@ -44712,6 +44947,109 @@ var init_diff_utils = __esm(() => {
|
|
|
44712
44947
|
DEFAULT_SUFFIX_STRIPPERS = [/\.(test|spec)\.(ts|js|tsx|jsx)$/, /_test\.go$/];
|
|
44713
44948
|
});
|
|
44714
44949
|
|
|
44950
|
+
// src/review/finding-projection.ts
|
|
44951
|
+
function narrowSeverity(raw) {
|
|
44952
|
+
return SEVERITY_MAP[raw] ?? "info";
|
|
44953
|
+
}
|
|
44954
|
+
function slugLeadingTokens(text, tokenCount = RULE_ID_SLUG_TOKENS) {
|
|
44955
|
+
return text.toLowerCase().replace(/[^a-z0-9\s-]/g, " ").split(/\s+/).filter(Boolean).slice(0, tokenCount).join("-");
|
|
44956
|
+
}
|
|
44957
|
+
function deriveRuleId(category, issue2) {
|
|
44958
|
+
const prefix = category?.trim() ? category.trim() : "review";
|
|
44959
|
+
const slug = slugLeadingTokens(issue2) || "unspecified";
|
|
44960
|
+
return `${prefix}:${slug}`;
|
|
44961
|
+
}
|
|
44962
|
+
function joinMessage(issue2, suggestion) {
|
|
44963
|
+
const trimmedIssue = issue2.trim();
|
|
44964
|
+
const trimmedSuggestion = (suggestion ?? "").trim();
|
|
44965
|
+
if (trimmedIssue && trimmedSuggestion) {
|
|
44966
|
+
return `${trimmedIssue}
|
|
44967
|
+
\u2192 ${trimmedSuggestion}`;
|
|
44968
|
+
}
|
|
44969
|
+
return trimmedIssue;
|
|
44970
|
+
}
|
|
44971
|
+
function buildMeta(f, originalSeverity) {
|
|
44972
|
+
const meta3 = {};
|
|
44973
|
+
if (f.issue)
|
|
44974
|
+
meta3.issue = f.issue;
|
|
44975
|
+
if (f.suggestion)
|
|
44976
|
+
meta3.suggestion = f.suggestion;
|
|
44977
|
+
if (f.acQuote)
|
|
44978
|
+
meta3.acQuote = f.acQuote;
|
|
44979
|
+
if (typeof f.acIndex === "number" && f.acIndex >= 1)
|
|
44980
|
+
meta3.acIndex = f.acIndex;
|
|
44981
|
+
if ("acId" in f && f.acId)
|
|
44982
|
+
meta3.acId = f.acId;
|
|
44983
|
+
if ("verifiedBy" in f && f.verifiedBy)
|
|
44984
|
+
meta3.verifiedBy = f.verifiedBy;
|
|
44985
|
+
if (originalSeverity !== undefined)
|
|
44986
|
+
meta3.originalSeverity = originalSeverity;
|
|
44987
|
+
return Object.keys(meta3).length > 0 ? meta3 : undefined;
|
|
44988
|
+
}
|
|
44989
|
+
function findingCategory(f) {
|
|
44990
|
+
return "category" in f && f.category ? f.category : undefined;
|
|
44991
|
+
}
|
|
44992
|
+
function llmFindingToReviewFinding(f, opts = {}) {
|
|
44993
|
+
const category = findingCategory(f);
|
|
44994
|
+
const narrowed = narrowSeverity(f.severity);
|
|
44995
|
+
const result = {
|
|
44996
|
+
ruleId: deriveRuleId(category, f.issue),
|
|
44997
|
+
severity: narrowed,
|
|
44998
|
+
file: f.file,
|
|
44999
|
+
line: f.line,
|
|
45000
|
+
message: joinMessage(f.issue, f.suggestion)
|
|
45001
|
+
};
|
|
45002
|
+
if (category)
|
|
45003
|
+
result.category = category;
|
|
45004
|
+
if (opts.source)
|
|
45005
|
+
result.source = opts.source;
|
|
45006
|
+
const meta3 = buildMeta(f, f.severity !== narrowed ? f.severity : undefined);
|
|
45007
|
+
if (meta3)
|
|
45008
|
+
result.meta = meta3;
|
|
45009
|
+
return result;
|
|
45010
|
+
}
|
|
45011
|
+
function llmFindingsToReviewFindings(findings, opts = {}) {
|
|
45012
|
+
return findings.map((f) => llmFindingToReviewFinding(f, opts));
|
|
45013
|
+
}
|
|
45014
|
+
function findingToReviewFinding(f, opts = {}) {
|
|
45015
|
+
const narrowed = narrowSeverity(f.severity);
|
|
45016
|
+
const ruleId = f.rule?.trim() ? f.rule.trim() : deriveRuleId(f.category, f.message);
|
|
45017
|
+
const result = {
|
|
45018
|
+
ruleId,
|
|
45019
|
+
severity: narrowed,
|
|
45020
|
+
file: f.file ?? "",
|
|
45021
|
+
line: f.line ?? 0,
|
|
45022
|
+
message: f.message
|
|
45023
|
+
};
|
|
45024
|
+
if (f.category)
|
|
45025
|
+
result.category = f.category;
|
|
45026
|
+
const effectiveSource = opts.source ?? f.source;
|
|
45027
|
+
if (effectiveSource)
|
|
45028
|
+
result.source = effectiveSource;
|
|
45029
|
+
const meta3 = { ...f.meta ?? {} };
|
|
45030
|
+
if (f.suggestion)
|
|
45031
|
+
meta3.suggestion = f.suggestion;
|
|
45032
|
+
if (f.severity !== narrowed)
|
|
45033
|
+
meta3.originalSeverity = f.severity;
|
|
45034
|
+
if (Object.keys(meta3).length > 0)
|
|
45035
|
+
result.meta = meta3;
|
|
45036
|
+
return result;
|
|
45037
|
+
}
|
|
45038
|
+
function findingsToReviewFindings(findings, opts = {}) {
|
|
45039
|
+
return findings.map((f) => findingToReviewFinding(f, opts));
|
|
45040
|
+
}
|
|
45041
|
+
var SEVERITY_MAP, RULE_ID_SLUG_TOKENS = 6;
|
|
45042
|
+
var init_finding_projection = __esm(() => {
|
|
45043
|
+
SEVERITY_MAP = {
|
|
45044
|
+
critical: "critical",
|
|
45045
|
+
error: "error",
|
|
45046
|
+
warning: "warning",
|
|
45047
|
+
warn: "warning",
|
|
45048
|
+
info: "info",
|
|
45049
|
+
low: "low"
|
|
45050
|
+
};
|
|
45051
|
+
});
|
|
45052
|
+
|
|
44715
45053
|
// src/review/adversarial.ts
|
|
44716
45054
|
import { relative as relative11, sep as sep3 } from "path";
|
|
44717
45055
|
function recordAdversarialAudit(opts) {
|
|
@@ -45002,8 +45340,11 @@ async function runAdversarialReview(opts) {
|
|
|
45002
45340
|
failOpen: false,
|
|
45003
45341
|
passed: false,
|
|
45004
45342
|
blockingThreshold: threshold,
|
|
45005
|
-
result: {
|
|
45006
|
-
|
|
45343
|
+
result: {
|
|
45344
|
+
passed: false,
|
|
45345
|
+
findings: llmFindingsToReviewFindings(parsed.findings, { source: "adversarial-review" })
|
|
45346
|
+
},
|
|
45347
|
+
advisoryFindings: advisoryFindings.length > 0 ? llmFindingsToReviewFindings(advisoryFindings, { source: "adversarial-review" }) : undefined
|
|
45007
45348
|
});
|
|
45008
45349
|
return {
|
|
45009
45350
|
check: "adversarial",
|
|
@@ -45020,6 +45361,42 @@ ${formatFindings2(blockingFindings)}`,
|
|
|
45020
45361
|
};
|
|
45021
45362
|
}
|
|
45022
45363
|
if (!parsed.passed && blockingFindings.length === 0) {
|
|
45364
|
+
if (acDropped.length > 0) {
|
|
45365
|
+
const durationMs3 = Date.now() - startTime;
|
|
45366
|
+
logger?.warn("review", "Adversarial review fail-closed: blocking findings dropped as ungrounded", {
|
|
45367
|
+
storyId: story.id,
|
|
45368
|
+
durationMs: durationMs3,
|
|
45369
|
+
droppedCount: acDropped.length,
|
|
45370
|
+
dropCodes: acDropped.map((d) => d.code)
|
|
45371
|
+
});
|
|
45372
|
+
const dropSummary = acDropped.map((d, i) => `${i + 1}. [${d.code}] ${d.finding.file ?? "<unknown>"}: ${d.finding.issue}`).join(`
|
|
45373
|
+
`);
|
|
45374
|
+
recordAdversarialAudit({
|
|
45375
|
+
runtime,
|
|
45376
|
+
workdir,
|
|
45377
|
+
projectDir,
|
|
45378
|
+
storyId: story.id,
|
|
45379
|
+
featureName,
|
|
45380
|
+
parsed: true,
|
|
45381
|
+
failOpen: false,
|
|
45382
|
+
passed: false,
|
|
45383
|
+
blockingThreshold: threshold,
|
|
45384
|
+
result: { passed: false, findings: [] },
|
|
45385
|
+
advisoryFindings: advisoryFindings.length > 0 ? llmFindingsToReviewFindings(advisoryFindings, { source: "adversarial-review" }) : undefined
|
|
45386
|
+
});
|
|
45387
|
+
return {
|
|
45388
|
+
check: "adversarial",
|
|
45389
|
+
success: false,
|
|
45390
|
+
command: "",
|
|
45391
|
+
exitCode: 1,
|
|
45392
|
+
output: `Adversarial review failed: ${acDropped.length} blocking finding(s) dropped as ungrounded \u2014 the model emitted "passed: false" with concerns it could not ground in any acceptance criterion. Either re-classify these as "info" upstream or extend the ACs. Drops:
|
|
45393
|
+
|
|
45394
|
+
${dropSummary}`,
|
|
45395
|
+
durationMs: durationMs3,
|
|
45396
|
+
advisoryFindings: advisoryFindings.length > 0 ? toAdversarialReviewFindings(advisoryFindings) : undefined,
|
|
45397
|
+
cost: llmCost
|
|
45398
|
+
};
|
|
45399
|
+
}
|
|
45023
45400
|
const durationMs2 = Date.now() - startTime;
|
|
45024
45401
|
logger?.info("review", "Adversarial review passed (all findings below blocking threshold)", {
|
|
45025
45402
|
storyId: story.id,
|
|
@@ -45035,8 +45412,11 @@ ${formatFindings2(blockingFindings)}`,
|
|
|
45035
45412
|
failOpen: false,
|
|
45036
45413
|
passed: true,
|
|
45037
45414
|
blockingThreshold: threshold,
|
|
45038
|
-
result: {
|
|
45039
|
-
|
|
45415
|
+
result: {
|
|
45416
|
+
passed: true,
|
|
45417
|
+
findings: llmFindingsToReviewFindings(parsed.findings, { source: "adversarial-review" })
|
|
45418
|
+
},
|
|
45419
|
+
advisoryFindings: advisoryFindings.length > 0 ? llmFindingsToReviewFindings(advisoryFindings, { source: "adversarial-review" }) : undefined
|
|
45040
45420
|
});
|
|
45041
45421
|
return {
|
|
45042
45422
|
check: "adversarial",
|
|
@@ -45063,8 +45443,11 @@ ${formatFindings2(blockingFindings)}`,
|
|
|
45063
45443
|
failOpen: false,
|
|
45064
45444
|
passed: parsed.passed,
|
|
45065
45445
|
blockingThreshold: threshold,
|
|
45066
|
-
result: {
|
|
45067
|
-
|
|
45446
|
+
result: {
|
|
45447
|
+
passed: parsed.passed,
|
|
45448
|
+
findings: llmFindingsToReviewFindings(parsed.findings, { source: "adversarial-review" })
|
|
45449
|
+
},
|
|
45450
|
+
advisoryFindings: advisoryFindings.length > 0 ? llmFindingsToReviewFindings(advisoryFindings, { source: "adversarial-review" }) : undefined
|
|
45068
45451
|
});
|
|
45069
45452
|
return {
|
|
45070
45453
|
check: "adversarial",
|
|
@@ -45089,6 +45472,7 @@ var init_adversarial = __esm(() => {
|
|
|
45089
45472
|
init_ac_quote_validator();
|
|
45090
45473
|
init_adversarial_helpers();
|
|
45091
45474
|
init_diff_utils();
|
|
45475
|
+
init_finding_projection();
|
|
45092
45476
|
init_review_audit();
|
|
45093
45477
|
_adversarialDeps = {
|
|
45094
45478
|
writeReviewAudit,
|
|
@@ -45481,7 +45865,10 @@ async function runSemanticDebate(opts) {
|
|
|
45481
45865
|
parsed: true,
|
|
45482
45866
|
passed: false,
|
|
45483
45867
|
blockingThreshold,
|
|
45484
|
-
result: {
|
|
45868
|
+
result: {
|
|
45869
|
+
passed: false,
|
|
45870
|
+
findings: findingsToReviewFindings(findings, { source: "semantic-debate-review" })
|
|
45871
|
+
}
|
|
45485
45872
|
});
|
|
45486
45873
|
return {
|
|
45487
45874
|
check: "semantic",
|
|
@@ -45507,7 +45894,10 @@ ${findings.map((f) => `${f.rule ?? "semantic"}: ${f.message}`).join(`
|
|
|
45507
45894
|
parsed: true,
|
|
45508
45895
|
passed: true,
|
|
45509
45896
|
blockingThreshold,
|
|
45510
|
-
result: {
|
|
45897
|
+
result: {
|
|
45898
|
+
passed: true,
|
|
45899
|
+
findings: findingsToReviewFindings(findings, { source: "semantic-debate-review" })
|
|
45900
|
+
}
|
|
45511
45901
|
});
|
|
45512
45902
|
return {
|
|
45513
45903
|
check: "semantic",
|
|
@@ -45567,8 +45957,11 @@ ${findings.map((f) => `${f.rule ?? "semantic"}: ${f.message}`).join(`
|
|
|
45567
45957
|
parsed: true,
|
|
45568
45958
|
passed: false,
|
|
45569
45959
|
blockingThreshold: debateThreshold,
|
|
45570
|
-
result: {
|
|
45571
|
-
|
|
45960
|
+
result: {
|
|
45961
|
+
passed: false,
|
|
45962
|
+
findings: llmFindingsToReviewFindings(debateFindings, { source: "semantic-debate-review" })
|
|
45963
|
+
},
|
|
45964
|
+
advisoryFindings: debateAdvisory.length > 0 ? llmFindingsToReviewFindings(debateAdvisory, { source: "semantic-debate-review" }) : undefined
|
|
45572
45965
|
});
|
|
45573
45966
|
return {
|
|
45574
45967
|
check: "semantic",
|
|
@@ -45596,8 +45989,11 @@ ${formatFindings(debateBlocking)}`,
|
|
|
45596
45989
|
parsed: true,
|
|
45597
45990
|
passed: true,
|
|
45598
45991
|
blockingThreshold: debateThreshold,
|
|
45599
|
-
result: {
|
|
45600
|
-
|
|
45992
|
+
result: {
|
|
45993
|
+
passed: true,
|
|
45994
|
+
findings: llmFindingsToReviewFindings(debateFindings, { source: "semantic-debate-review" })
|
|
45995
|
+
},
|
|
45996
|
+
advisoryFindings: debateAdvisory.length > 0 ? llmFindingsToReviewFindings(debateAdvisory, { source: "semantic-debate-review" }) : undefined
|
|
45601
45997
|
});
|
|
45602
45998
|
return {
|
|
45603
45999
|
check: "semantic",
|
|
@@ -45619,8 +46015,11 @@ ${formatFindings(debateBlocking)}`,
|
|
|
45619
46015
|
parsed: true,
|
|
45620
46016
|
passed: true,
|
|
45621
46017
|
blockingThreshold: debateThreshold,
|
|
45622
|
-
result: {
|
|
45623
|
-
|
|
46018
|
+
result: {
|
|
46019
|
+
passed: true,
|
|
46020
|
+
findings: llmFindingsToReviewFindings(debateFindings, { source: "semantic-debate-review" })
|
|
46021
|
+
},
|
|
46022
|
+
advisoryFindings: debateAdvisory.length > 0 ? llmFindingsToReviewFindings(debateAdvisory, { source: "semantic-debate-review" }) : undefined
|
|
45624
46023
|
});
|
|
45625
46024
|
return {
|
|
45626
46025
|
check: "semantic",
|
|
@@ -45636,6 +46035,7 @@ ${formatFindings(debateBlocking)}`,
|
|
|
45636
46035
|
var init_semantic_debate = __esm(() => {
|
|
45637
46036
|
init_logger2();
|
|
45638
46037
|
init_ac_quote_validator();
|
|
46038
|
+
init_finding_projection();
|
|
45639
46039
|
init_semantic_helpers();
|
|
45640
46040
|
});
|
|
45641
46041
|
|
|
@@ -46036,8 +46436,11 @@ ${formatFindings(blockingFindings)}`;
|
|
|
46036
46436
|
failOpen: false,
|
|
46037
46437
|
passed: false,
|
|
46038
46438
|
blockingThreshold: threshold,
|
|
46039
|
-
result: {
|
|
46040
|
-
|
|
46439
|
+
result: {
|
|
46440
|
+
passed: false,
|
|
46441
|
+
findings: llmFindingsToReviewFindings(sanitizedParsed.findings, { source: "semantic-review" })
|
|
46442
|
+
},
|
|
46443
|
+
advisoryFindings: advisoryFindings.length > 0 ? llmFindingsToReviewFindings(advisoryFindings, { source: "semantic-review" }) : undefined
|
|
46041
46444
|
});
|
|
46042
46445
|
return {
|
|
46043
46446
|
check: "semantic",
|
|
@@ -46052,6 +46455,42 @@ ${formatFindings(blockingFindings)}`;
|
|
|
46052
46455
|
};
|
|
46053
46456
|
}
|
|
46054
46457
|
if (!sanitizedParsed.passed && blockingFindings.length === 0) {
|
|
46458
|
+
if (acDropped.length > 0) {
|
|
46459
|
+
const durationMs3 = Date.now() - startTime;
|
|
46460
|
+
logger?.warn("review", "Semantic review fail-closed: blocking findings dropped as ungrounded", {
|
|
46461
|
+
storyId: story.id,
|
|
46462
|
+
durationMs: durationMs3,
|
|
46463
|
+
droppedCount: acDropped.length,
|
|
46464
|
+
dropCodes: acDropped.map((d) => d.code)
|
|
46465
|
+
});
|
|
46466
|
+
const dropSummary = acDropped.map((d, i) => `${i + 1}. [${d.code}] ${d.finding.file ?? "<unknown>"}: ${d.finding.issue}`).join(`
|
|
46467
|
+
`);
|
|
46468
|
+
recordSemanticAudit({
|
|
46469
|
+
runtime,
|
|
46470
|
+
workdir,
|
|
46471
|
+
projectDir,
|
|
46472
|
+
storyId: story.id,
|
|
46473
|
+
featureName,
|
|
46474
|
+
parsed: true,
|
|
46475
|
+
failOpen: false,
|
|
46476
|
+
passed: false,
|
|
46477
|
+
blockingThreshold: threshold,
|
|
46478
|
+
result: { passed: false, findings: [] },
|
|
46479
|
+
advisoryFindings: advisoryFindings.length > 0 ? llmFindingsToReviewFindings(advisoryFindings, { source: "semantic-review" }) : undefined
|
|
46480
|
+
});
|
|
46481
|
+
return {
|
|
46482
|
+
check: "semantic",
|
|
46483
|
+
success: false,
|
|
46484
|
+
command: "",
|
|
46485
|
+
exitCode: 1,
|
|
46486
|
+
output: `Semantic review failed: ${acDropped.length} blocking finding(s) dropped as ungrounded \u2014 the model emitted "passed: false" with concerns it could not ground in any acceptance criterion. Either re-classify these as "info" upstream or extend the ACs. Drops:
|
|
46487
|
+
|
|
46488
|
+
${dropSummary}`,
|
|
46489
|
+
durationMs: durationMs3,
|
|
46490
|
+
advisoryFindings: advisoryFindings.length > 0 ? toReviewFindings(advisoryFindings) : undefined,
|
|
46491
|
+
cost: llmCost
|
|
46492
|
+
};
|
|
46493
|
+
}
|
|
46055
46494
|
const durationMs2 = Date.now() - startTime;
|
|
46056
46495
|
logger?.info("review", "Semantic review passed (all findings below blocking threshold)", {
|
|
46057
46496
|
storyId: story.id,
|
|
@@ -46067,8 +46506,11 @@ ${formatFindings(blockingFindings)}`;
|
|
|
46067
46506
|
failOpen: false,
|
|
46068
46507
|
passed: true,
|
|
46069
46508
|
blockingThreshold: threshold,
|
|
46070
|
-
result: {
|
|
46071
|
-
|
|
46509
|
+
result: {
|
|
46510
|
+
passed: true,
|
|
46511
|
+
findings: llmFindingsToReviewFindings(sanitizedParsed.findings, { source: "semantic-review" })
|
|
46512
|
+
},
|
|
46513
|
+
advisoryFindings: advisoryFindings.length > 0 ? llmFindingsToReviewFindings(advisoryFindings, { source: "semantic-review" }) : undefined
|
|
46072
46514
|
});
|
|
46073
46515
|
return {
|
|
46074
46516
|
check: "semantic",
|
|
@@ -46095,8 +46537,11 @@ ${formatFindings(blockingFindings)}`;
|
|
|
46095
46537
|
failOpen: false,
|
|
46096
46538
|
passed: sanitizedParsed.passed,
|
|
46097
46539
|
blockingThreshold: threshold,
|
|
46098
|
-
result: {
|
|
46099
|
-
|
|
46540
|
+
result: {
|
|
46541
|
+
passed: sanitizedParsed.passed,
|
|
46542
|
+
findings: llmFindingsToReviewFindings(sanitizedParsed.findings, { source: "semantic-review" })
|
|
46543
|
+
},
|
|
46544
|
+
advisoryFindings: advisoryFindings.length > 0 ? llmFindingsToReviewFindings(advisoryFindings, { source: "semantic-review" }) : undefined
|
|
46100
46545
|
});
|
|
46101
46546
|
return {
|
|
46102
46547
|
check: "semantic",
|
|
@@ -46122,6 +46567,7 @@ var init_semantic = __esm(() => {
|
|
|
46122
46567
|
init_test_runners();
|
|
46123
46568
|
init_ac_quote_validator();
|
|
46124
46569
|
init_diff_utils();
|
|
46570
|
+
init_finding_projection();
|
|
46125
46571
|
init_review_audit();
|
|
46126
46572
|
init_semantic_debate();
|
|
46127
46573
|
init_semantic_evidence();
|
|
@@ -47132,12 +47578,115 @@ async function recheckReview(ctx) {
|
|
|
47132
47578
|
return false;
|
|
47133
47579
|
return ctx.reviewResult?.success === true;
|
|
47134
47580
|
}
|
|
47581
|
+
async function runMechanicalFixes(ctx, failedCheckNames) {
|
|
47582
|
+
const commands = resolveMechanicalFixCommands(ctx, failedCheckNames);
|
|
47583
|
+
for (const resolved of commands) {
|
|
47584
|
+
if (resolved.skipped)
|
|
47585
|
+
continue;
|
|
47586
|
+
pipelineEventBus.emit({ type: "autofix:started", storyId: ctx.story.id, command: resolved.command });
|
|
47587
|
+
const result = await _autofixDeps.runQualityCommand({
|
|
47588
|
+
commandName: resolved.commandName,
|
|
47589
|
+
command: resolved.command,
|
|
47590
|
+
workdir: ctx.workdir,
|
|
47591
|
+
storyId: ctx.story.id
|
|
47592
|
+
});
|
|
47593
|
+
logMechanicalFixResult(ctx, resolved, result.exitCode);
|
|
47594
|
+
}
|
|
47595
|
+
}
|
|
47596
|
+
function resolveMechanicalFixCommands(ctx, failedCheckNames) {
|
|
47597
|
+
if (!failedCheckNames.has("lint"))
|
|
47598
|
+
return [];
|
|
47599
|
+
const scopeFiles = collectLintScopeFiles(ctx.reviewResult?.checks ?? []);
|
|
47600
|
+
return [resolveFixCommand(ctx, "lintFix", scopeFiles), resolveFixCommand(ctx, "formatFix", scopeFiles)].filter((cmd) => cmd !== undefined);
|
|
47601
|
+
}
|
|
47602
|
+
function resolveFixCommand(ctx, commandName, scopeFiles) {
|
|
47603
|
+
const broad = resolveBroadFixCommand(ctx, commandName);
|
|
47604
|
+
const template = resolveScopedFixTemplate(ctx, commandName);
|
|
47605
|
+
if (!broad && !template)
|
|
47606
|
+
return;
|
|
47607
|
+
if (!scopeFiles)
|
|
47608
|
+
return warnAndUseFullFix(ctx, commandName, broad, "missing_lint_scope");
|
|
47609
|
+
if (scopeFiles.length === 0)
|
|
47610
|
+
return logEmptyFixScope(ctx, commandName, broad ?? template ?? "");
|
|
47611
|
+
if (template) {
|
|
47612
|
+
return {
|
|
47613
|
+
commandName,
|
|
47614
|
+
command: template.replaceAll("{{files}}", scopeFiles.map(shellQuotePath2).join(" ")),
|
|
47615
|
+
scoped: true
|
|
47616
|
+
};
|
|
47617
|
+
}
|
|
47618
|
+
if (!broad)
|
|
47619
|
+
return;
|
|
47620
|
+
const derived = deriveScopedFixCommand(broad, scopeFiles);
|
|
47621
|
+
if (derived)
|
|
47622
|
+
return { commandName, command: derived, scoped: true };
|
|
47623
|
+
return warnAndUseFullFix(ctx, commandName, broad, "unsupported_scoped_command_shape");
|
|
47624
|
+
}
|
|
47625
|
+
function collectLintScopeFiles(checks3) {
|
|
47626
|
+
const lintChecks = checks3.filter((check2) => check2.check === "lint" && !check2.success);
|
|
47627
|
+
if (lintChecks.length === 0)
|
|
47628
|
+
return;
|
|
47629
|
+
if (lintChecks.some((check2) => !check2.lintScope))
|
|
47630
|
+
return;
|
|
47631
|
+
if (lintChecks.some((check2) => check2.lintScope?.status === "degraded"))
|
|
47632
|
+
return;
|
|
47633
|
+
const files = lintChecks.flatMap((check2) => check2.lintScope?.packageGroups.flatMap((group) => group.files) ?? []);
|
|
47634
|
+
return [...new Set(files)];
|
|
47635
|
+
}
|
|
47636
|
+
function resolveBroadFixCommand(ctx, commandName) {
|
|
47637
|
+
return commandName === "lintFix" ? ctx.config.quality.commands.lintFix ?? ctx.config.review.commands.lintFix : ctx.config.quality.commands.formatFix ?? ctx.config.review.commands.formatFix;
|
|
47638
|
+
}
|
|
47639
|
+
function hasMechanicalFixCommand(ctx) {
|
|
47640
|
+
return ["lintFix", "formatFix"].some((name) => resolveBroadFixCommand(ctx, name) ?? resolveScopedFixTemplate(ctx, name));
|
|
47641
|
+
}
|
|
47642
|
+
function resolveScopedFixTemplate(ctx, commandName) {
|
|
47643
|
+
return commandName === "lintFix" ? ctx.config.review.commands.lintFixScoped ?? ctx.config.quality.commands.lintFixScoped : ctx.config.review.commands.formatFixScoped ?? ctx.config.quality.commands.formatFixScoped;
|
|
47644
|
+
}
|
|
47645
|
+
function deriveScopedFixCommand(command, files) {
|
|
47646
|
+
const trimmed = command.trim();
|
|
47647
|
+
const supportedTools = ["eslint", "biome", "ruff", "flake8", "prettier"];
|
|
47648
|
+
const isSupported = supportedTools.some((tool) => trimmed === tool || trimmed.startsWith(`${tool} `)) || supportedTools.some((tool) => trimmed.startsWith(`bunx ${tool}`));
|
|
47649
|
+
if (!isSupported)
|
|
47650
|
+
return;
|
|
47651
|
+
return `${command} ${files.map(shellQuotePath2).join(" ")}`;
|
|
47652
|
+
}
|
|
47653
|
+
function shellQuotePath2(path9) {
|
|
47654
|
+
return `'${path9.replaceAll("'", "'\\''")}'`;
|
|
47655
|
+
}
|
|
47656
|
+
function logEmptyFixScope(ctx, commandName, command) {
|
|
47657
|
+
getLogger().info("autofix", `${toScopeLogPrefix(commandName)}_scope_empty`, { storyId: ctx.story.id });
|
|
47658
|
+
return { commandName, command, scoped: true, skipped: true };
|
|
47659
|
+
}
|
|
47660
|
+
function warnAndUseFullFix(ctx, commandName, command, reason) {
|
|
47661
|
+
getLogger().warn("autofix", `${toScopeLogPrefix(commandName)}_scope_degraded`, { storyId: ctx.story.id, reason });
|
|
47662
|
+
if (!command)
|
|
47663
|
+
return { commandName, command: "", scoped: false, skipped: true };
|
|
47664
|
+
return { commandName, command, scoped: false };
|
|
47665
|
+
}
|
|
47666
|
+
function toScopeLogPrefix(commandName) {
|
|
47667
|
+
return commandName === "lintFix" ? "lint_fix" : "format_fix";
|
|
47668
|
+
}
|
|
47669
|
+
function logMechanicalFixResult(ctx, resolved, exitCode) {
|
|
47670
|
+
const logger = getLogger();
|
|
47671
|
+
logger.debug("autofix", `${resolved.commandName} exit=${exitCode}`, {
|
|
47672
|
+
storyId: ctx.story.id,
|
|
47673
|
+
command: resolved.command,
|
|
47674
|
+
scoped: resolved.scoped
|
|
47675
|
+
});
|
|
47676
|
+
if (exitCode !== 0) {
|
|
47677
|
+
logger.warn("autofix", `${resolved.commandName} command failed \u2014 may not have fixed all issues`, {
|
|
47678
|
+
storyId: ctx.story.id,
|
|
47679
|
+
exitCode
|
|
47680
|
+
});
|
|
47681
|
+
}
|
|
47682
|
+
}
|
|
47135
47683
|
var NON_FIXABLE_BY_RECTIFICATION, autofixStage, _autofixDeps;
|
|
47136
47684
|
var init_autofix = __esm(() => {
|
|
47137
47685
|
init_logger2();
|
|
47138
47686
|
init_quality();
|
|
47139
47687
|
init_event_bus();
|
|
47140
47688
|
init_autofix_agent();
|
|
47689
|
+
init_autofix_cycle();
|
|
47141
47690
|
init_autofix_scope_split();
|
|
47142
47691
|
init_autofix_test_writer2();
|
|
47143
47692
|
NON_FIXABLE_BY_RECTIFICATION = new Set(["git-clean"]);
|
|
@@ -47162,8 +47711,7 @@ var init_autofix = __esm(() => {
|
|
|
47162
47711
|
if (!reviewResult || reviewResult.success) {
|
|
47163
47712
|
return { action: "continue" };
|
|
47164
47713
|
}
|
|
47165
|
-
|
|
47166
|
-
const formatFixCmd = ctx.config.quality.commands.formatFix ?? ctx.config.review.commands.formatFix;
|
|
47714
|
+
ctx.autofixAttempt = (ctx.autofixAttempt ?? 0) + 1;
|
|
47167
47715
|
const failedCheckNames = new Set((reviewResult.checks ?? []).filter((c) => !c.success).map((c) => c.check));
|
|
47168
47716
|
const hasLintFailure = failedCheckNames.has("lint");
|
|
47169
47717
|
const totalFindingCount = (reviewResult.checks ?? []).reduce((n, c) => n + (c.findings?.length ?? 0), 0);
|
|
@@ -47184,42 +47732,8 @@ var init_autofix = __esm(() => {
|
|
|
47184
47732
|
failedChecks: [...failedCheckNames],
|
|
47185
47733
|
workdir: ctx.workdir
|
|
47186
47734
|
});
|
|
47187
|
-
if (hasLintFailure && (
|
|
47188
|
-
|
|
47189
|
-
pipelineEventBus.emit({ type: "autofix:started", storyId: ctx.story.id, command: lintFixCmd });
|
|
47190
|
-
const lintResult = await _autofixDeps.runQualityCommand({
|
|
47191
|
-
commandName: "lintFix",
|
|
47192
|
-
command: lintFixCmd,
|
|
47193
|
-
workdir: ctx.workdir,
|
|
47194
|
-
storyId: ctx.story.id
|
|
47195
|
-
});
|
|
47196
|
-
logger.debug("autofix", `lintFix exit=${lintResult.exitCode}`, { storyId: ctx.story.id, command: lintFixCmd });
|
|
47197
|
-
if (lintResult.exitCode !== 0) {
|
|
47198
|
-
logger.warn("autofix", "lintFix command failed \u2014 may not have fixed all issues", {
|
|
47199
|
-
storyId: ctx.story.id,
|
|
47200
|
-
exitCode: lintResult.exitCode
|
|
47201
|
-
});
|
|
47202
|
-
}
|
|
47203
|
-
}
|
|
47204
|
-
if (formatFixCmd) {
|
|
47205
|
-
pipelineEventBus.emit({ type: "autofix:started", storyId: ctx.story.id, command: formatFixCmd });
|
|
47206
|
-
const fmtResult = await _autofixDeps.runQualityCommand({
|
|
47207
|
-
commandName: "formatFix",
|
|
47208
|
-
command: formatFixCmd,
|
|
47209
|
-
workdir: ctx.workdir,
|
|
47210
|
-
storyId: ctx.story.id
|
|
47211
|
-
});
|
|
47212
|
-
logger.debug("autofix", `formatFix exit=${fmtResult.exitCode}`, {
|
|
47213
|
-
storyId: ctx.story.id,
|
|
47214
|
-
command: formatFixCmd
|
|
47215
|
-
});
|
|
47216
|
-
if (fmtResult.exitCode !== 0) {
|
|
47217
|
-
logger.warn("autofix", "formatFix command failed \u2014 may not have fixed all issues", {
|
|
47218
|
-
storyId: ctx.story.id,
|
|
47219
|
-
exitCode: fmtResult.exitCode
|
|
47220
|
-
});
|
|
47221
|
-
}
|
|
47222
|
-
}
|
|
47735
|
+
if (hasLintFailure && hasMechanicalFixCommand(ctx)) {
|
|
47736
|
+
await runMechanicalFixes(ctx, failedCheckNames);
|
|
47223
47737
|
const recheckPassed = await _autofixDeps.recheckReview(ctx);
|
|
47224
47738
|
pipelineEventBus.emit({ type: "autofix:completed", storyId: ctx.story.id, fixed: recheckPassed });
|
|
47225
47739
|
if (recheckPassed) {
|
|
@@ -47262,7 +47776,7 @@ var init_autofix = __esm(() => {
|
|
|
47262
47776
|
cost: agentCost,
|
|
47263
47777
|
unresolvedReason,
|
|
47264
47778
|
escalationDigest
|
|
47265
|
-
} = await _autofixDeps.runAgentRectification(ctx,
|
|
47779
|
+
} = await _autofixDeps.runAgentRectification(ctx, resolveBroadFixCommand(ctx, "lintFix"), resolveBroadFixCommand(ctx, "formatFix"), ctx.workdir);
|
|
47266
47780
|
if (!agentFixed && unresolvedReason) {
|
|
47267
47781
|
if (ctx.mechanicalFailedOnly) {
|
|
47268
47782
|
logger.warn("autofix", "Mechanical-only failure unfixable \u2014 proceeding (LLM review passed)", {
|
|
@@ -47297,7 +47811,8 @@ var init_autofix = __esm(() => {
|
|
|
47297
47811
|
const totalUsed = ctx.autofixAttempt ?? 0;
|
|
47298
47812
|
const currentlyFailing = new Set((ctx.reviewResult?.checks ?? []).filter((c) => !c.success || c.failOpen).map((c) => c.check));
|
|
47299
47813
|
const nowPassing = [...failedCheckNames].filter((c) => !currentlyFailing.has(c));
|
|
47300
|
-
|
|
47814
|
+
const capacityExhausted = autofixCapacityExhausted(ctx);
|
|
47815
|
+
if (nowPassing.length > 0 && totalUsed < maxTotal && !capacityExhausted) {
|
|
47301
47816
|
ctx.retrySkipChecks = new Set([...ctx.retrySkipChecks ?? [], ...nowPassing]);
|
|
47302
47817
|
logger.info("autofix", "Partial progress \u2014 retrying review with updated skip list", {
|
|
47303
47818
|
storyId: ctx.story.id,
|
|
@@ -47307,6 +47822,13 @@ var init_autofix = __esm(() => {
|
|
|
47307
47822
|
});
|
|
47308
47823
|
return { action: "retry", fromStage: "review", cost: agentCost };
|
|
47309
47824
|
}
|
|
47825
|
+
if (nowPassing.length > 0 && capacityExhausted) {
|
|
47826
|
+
logger.info("autofix", "Partial progress \u2014 but autofix capacity exhausted; escalating instead of retrying review", {
|
|
47827
|
+
storyId: ctx.story.id,
|
|
47828
|
+
nowPassing,
|
|
47829
|
+
remaining: [...currentlyFailing]
|
|
47830
|
+
});
|
|
47831
|
+
}
|
|
47310
47832
|
logger.warn("autofix", "Autofix exhausted \u2014 escalating", { storyId: ctx.story.id });
|
|
47311
47833
|
return {
|
|
47312
47834
|
action: "escalate",
|
|
@@ -52583,7 +53105,18 @@ async function collectFromMetrics(context) {
|
|
|
52583
53105
|
return observations;
|
|
52584
53106
|
}
|
|
52585
53107
|
function findingRuleId(finding) {
|
|
52586
|
-
return stringValue(finding.
|
|
53108
|
+
return stringValue(finding.ruleId ?? finding.rule ?? finding.checkId ?? finding.category, "unknown");
|
|
53109
|
+
}
|
|
53110
|
+
function findingMessage(finding) {
|
|
53111
|
+
const message = stringValue(finding.message);
|
|
53112
|
+
if (message)
|
|
53113
|
+
return message;
|
|
53114
|
+
const issue2 = stringValue(finding.issue);
|
|
53115
|
+
const suggestion = stringValue(finding.suggestion);
|
|
53116
|
+
if (issue2 && suggestion)
|
|
53117
|
+
return `${issue2}
|
|
53118
|
+
\u2192 ${suggestion}`;
|
|
53119
|
+
return issue2;
|
|
52587
53120
|
}
|
|
52588
53121
|
async function collectFromReviewAudit(context) {
|
|
52589
53122
|
const observations = [];
|
|
@@ -52619,7 +53152,7 @@ async function collectFromReviewAudit(context) {
|
|
|
52619
53152
|
severity: stringValue(finding.severity, "info"),
|
|
52620
53153
|
file: stringValue(finding.file),
|
|
52621
53154
|
line: numberValue(finding.line, 0),
|
|
52622
|
-
message:
|
|
53155
|
+
message: findingMessage(finding)
|
|
52623
53156
|
}
|
|
52624
53157
|
};
|
|
52625
53158
|
observations.push(obs);
|
|
@@ -52893,31 +53426,43 @@ function mergeThresholds(thresholds) {
|
|
|
52893
53426
|
function uniqueStoryIds(storyIds) {
|
|
52894
53427
|
return [...new Set(storyIds)];
|
|
52895
53428
|
}
|
|
53429
|
+
function firstLine2(message) {
|
|
53430
|
+
return message.split(`
|
|
53431
|
+
`)[0] ?? message;
|
|
53432
|
+
}
|
|
52896
53433
|
function h1RepeatedReviewFinding(observations, threshold) {
|
|
52897
53434
|
const findings = observations.filter((o) => o.kind === "review-finding");
|
|
52898
|
-
const
|
|
53435
|
+
const groups = new Map;
|
|
52899
53436
|
for (const obs of findings) {
|
|
52900
53437
|
const ruleId = obs.payload.ruleId;
|
|
52901
|
-
const
|
|
53438
|
+
const message = obs.payload.message;
|
|
53439
|
+
const existing = groups.get(ruleId);
|
|
52902
53440
|
if (existing) {
|
|
52903
|
-
existing.push(obs.storyId);
|
|
53441
|
+
existing.storyIds.push(obs.storyId);
|
|
53442
|
+
const sampleKey = firstLine2(message);
|
|
53443
|
+
if (existing.samples.length < 2 && sampleKey && !existing.samples.includes(sampleKey)) {
|
|
53444
|
+
existing.samples.push(sampleKey);
|
|
53445
|
+
}
|
|
52904
53446
|
} else {
|
|
52905
|
-
|
|
53447
|
+
const sampleKey = firstLine2(message);
|
|
53448
|
+
groups.set(ruleId, { storyIds: [obs.storyId], samples: sampleKey ? [sampleKey] : [] });
|
|
52906
53449
|
}
|
|
52907
53450
|
}
|
|
52908
53451
|
const proposals = [];
|
|
52909
|
-
for (const [ruleId, storyIds] of
|
|
53452
|
+
for (const [ruleId, { storyIds, samples }] of groups.entries()) {
|
|
52910
53453
|
if (storyIds.length < threshold)
|
|
52911
53454
|
continue;
|
|
52912
53455
|
const count = storyIds.length;
|
|
52913
53456
|
const severity = count >= 4 ? "HIGH" : "MED";
|
|
52914
53457
|
const unique = uniqueStoryIds(storyIds);
|
|
53458
|
+
const sampleSection = samples.length > 0 ? `
|
|
53459
|
+
Examples: ${samples.join(" | ")}` : "";
|
|
52915
53460
|
proposals.push({
|
|
52916
53461
|
id: "H1",
|
|
52917
53462
|
severity,
|
|
52918
53463
|
target: { canonicalFile: ".nax/rules/curator-suggestions.md", action: "add" },
|
|
52919
53464
|
description: `Repeated review finding: ${ruleId} appeared ${count}x across stories`,
|
|
52920
|
-
evidence: `Rule ${ruleId} fired ${count}\xD7 in stories: ${unique.join(", ")}`,
|
|
53465
|
+
evidence: `Rule ${ruleId} fired ${count}\xD7 in stories: ${unique.join(", ")}${sampleSection}`,
|
|
52921
53466
|
sourceKinds: ["review-finding"],
|
|
52922
53467
|
storyIds: unique
|
|
52923
53468
|
});
|
|
@@ -54080,7 +54625,7 @@ var package_default;
|
|
|
54080
54625
|
var init_package = __esm(() => {
|
|
54081
54626
|
package_default = {
|
|
54082
54627
|
name: "@nathapp/nax",
|
|
54083
|
-
version: "0.65.
|
|
54628
|
+
version: "0.65.2",
|
|
54084
54629
|
description: "AI Coding Agent Orchestrator \u2014 loops until done",
|
|
54085
54630
|
type: "module",
|
|
54086
54631
|
bin: {
|
|
@@ -54166,8 +54711,8 @@ var init_version = __esm(() => {
|
|
|
54166
54711
|
NAX_VERSION = package_default.version;
|
|
54167
54712
|
NAX_COMMIT = (() => {
|
|
54168
54713
|
try {
|
|
54169
|
-
if (/^[0-9a-f]{6,10}$/.test("
|
|
54170
|
-
return "
|
|
54714
|
+
if (/^[0-9a-f]{6,10}$/.test("99828ef9"))
|
|
54715
|
+
return "99828ef9";
|
|
54171
54716
|
} catch {}
|
|
54172
54717
|
try {
|
|
54173
54718
|
const result = Bun.spawnSync(["git", "rev-parse", "--short", "HEAD"], {
|
|
@@ -90518,6 +91063,7 @@ __export(exports_curator, {
|
|
|
90518
91063
|
_curatorCmdDeps: () => _curatorCmdDeps
|
|
90519
91064
|
});
|
|
90520
91065
|
import { readdirSync as readdirSync10 } from "fs";
|
|
91066
|
+
import { unlink as unlink4 } from "fs/promises";
|
|
90521
91067
|
import { basename as basename16, join as join79 } from "path";
|
|
90522
91068
|
function getProjectKey(config2, projectDir) {
|
|
90523
91069
|
return config2.name?.trim() || basename16(projectDir);
|
|
@@ -90788,6 +91334,16 @@ async function curatorGc(options) {
|
|
|
90788
91334
|
`)}
|
|
90789
91335
|
`;
|
|
90790
91336
|
await _curatorCmdDeps.writeFile(rollupPath, newContent);
|
|
91337
|
+
const projectKey = getProjectKey(config2, resolved.projectDir);
|
|
91338
|
+
const outputDir = _curatorCmdDeps.projectOutputDir(projectKey, config2.outputDir);
|
|
91339
|
+
const perRunsDir = join79(outputDir, "runs");
|
|
91340
|
+
for (const runId of uniqueRunIds) {
|
|
91341
|
+
if (!keepSet.has(runId)) {
|
|
91342
|
+
const runDir = join79(perRunsDir, runId);
|
|
91343
|
+
await _curatorCmdDeps.removeFile(join79(runDir, "observations.jsonl"));
|
|
91344
|
+
await _curatorCmdDeps.removeFile(join79(runDir, "curator-proposals.md"));
|
|
91345
|
+
}
|
|
91346
|
+
}
|
|
90791
91347
|
console.log(`[gc] Pruned rollup to ${keep} most recent runs (was ${uniqueRunIds.length}).`);
|
|
90792
91348
|
}
|
|
90793
91349
|
var _curatorCmdDeps, DEFAULT_KEEP = 50;
|
|
@@ -90811,6 +91367,11 @@ var init_curator2 = __esm(() => {
|
|
|
90811
91367
|
const prev = await existing.exists() ? await existing.text() : "";
|
|
90812
91368
|
await Bun.write(p, prev + content);
|
|
90813
91369
|
},
|
|
91370
|
+
removeFile: async (p) => {
|
|
91371
|
+
try {
|
|
91372
|
+
await unlink4(p);
|
|
91373
|
+
} catch {}
|
|
91374
|
+
},
|
|
90814
91375
|
openInEditor: async (filePath) => {
|
|
90815
91376
|
const editor = process.env.EDITOR ?? process.env.VISUAL ?? "vi";
|
|
90816
91377
|
const proc = Bun.spawnSync([editor, filePath], { stdio: ["inherit", "inherit", "inherit"] });
|
|
@@ -92310,6 +92871,8 @@ var FIELD_DESCRIPTIONS = {
|
|
|
92310
92871
|
"quality.commands.typecheck": "Custom typecheck command",
|
|
92311
92872
|
"quality.commands.lint": "Custom lint command",
|
|
92312
92873
|
"quality.commands.lintScoped": "Scoped lint command template for story-owned files (supports {{files}})",
|
|
92874
|
+
"quality.commands.lintFixScoped": "Scoped lint fix command template for story-owned files (supports {{files}})",
|
|
92875
|
+
"quality.commands.formatFixScoped": "Scoped format fix command template for story-owned files (supports {{files}})",
|
|
92313
92876
|
"quality.commands.test": "Custom test command",
|
|
92314
92877
|
"quality.commands.build": "Custom build command",
|
|
92315
92878
|
"quality.forceExit": "Append --forceExit to test command (prevents hangs)",
|
|
@@ -92343,6 +92906,8 @@ var FIELD_DESCRIPTIONS = {
|
|
|
92343
92906
|
"review.commands.typecheck": "Custom typecheck command for review",
|
|
92344
92907
|
"review.commands.lint": "Custom lint command for review",
|
|
92345
92908
|
"review.commands.lintScoped": "Scoped lint command template for review (supports {{files}})",
|
|
92909
|
+
"review.commands.lintFixScoped": "Scoped lint fix command template for review (supports {{files}})",
|
|
92910
|
+
"review.commands.formatFixScoped": "Scoped format fix command template for review (supports {{files}})",
|
|
92346
92911
|
"review.commands.test": "Custom test command for review",
|
|
92347
92912
|
"review.commands.build": "Custom build command for review",
|
|
92348
92913
|
"review.semantic": "Semantic review configuration (code quality analysis)",
|