@nathapp/nax 0.65.1 → 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 +424 -65
- 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();
|
|
@@ -43417,7 +43528,7 @@ function collectAdversarialSourceChecks(ctx) {
|
|
|
43417
43528
|
function buildAutofixStrategies(ctx, maxAttempts) {
|
|
43418
43529
|
const implementer = {
|
|
43419
43530
|
name: "autofix-implementer",
|
|
43420
|
-
appliesTo: (f) => (f.fixTarget ?? "source") === "source",
|
|
43531
|
+
appliesTo: (f) => (f.fixTarget ?? "source") === "source" && f.category !== "prd_quote_mismatch",
|
|
43421
43532
|
fixOp: implementerRectifyOp,
|
|
43422
43533
|
maxAttempts,
|
|
43423
43534
|
coRun: "co-run-sequential",
|
|
@@ -43425,16 +43536,22 @@ function buildAutofixStrategies(ctx, maxAttempts) {
|
|
|
43425
43536
|
failedChecks: collectFailedChecks(ctx),
|
|
43426
43537
|
story: ctx.story
|
|
43427
43538
|
}),
|
|
43428
|
-
extractApplied: (output) =>
|
|
43429
|
-
|
|
43430
|
-
|
|
43431
|
-
|
|
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
|
+
}
|
|
43432
43549
|
};
|
|
43433
43550
|
const testWriter = {
|
|
43434
43551
|
name: "autofix-test-writer",
|
|
43435
43552
|
appliesTo: (f) => f.fixTarget === "test" || (f.fixTarget ?? "source") === "source" && f.severity === "error" && f.source === "adversarial-review",
|
|
43436
43553
|
fixOp: testWriterRectifyOp,
|
|
43437
|
-
maxAttempts:
|
|
43554
|
+
maxAttempts: 2,
|
|
43438
43555
|
coRun: "co-run-sequential",
|
|
43439
43556
|
buildInput: (findings, _prior, _cycleCtx) => {
|
|
43440
43557
|
const hasSourceBug = findings.some((f) => (f.fixTarget ?? "source") === "source" && f.source === "adversarial-review");
|
|
@@ -43455,6 +43572,25 @@ function buildAutofixStrategies(ctx, maxAttempts) {
|
|
|
43455
43572
|
};
|
|
43456
43573
|
return [testWriter, implementer];
|
|
43457
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
|
+
}
|
|
43458
43594
|
function buildEscalationDigest(findings) {
|
|
43459
43595
|
const byFile = new Map;
|
|
43460
43596
|
for (const f of findings) {
|
|
@@ -43494,6 +43630,50 @@ async function writeShadowReport(ctx, result, initialFindingsCount) {
|
|
|
43494
43630
|
});
|
|
43495
43631
|
}
|
|
43496
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
|
+
}
|
|
43497
43677
|
async function runAgentRectificationV2(ctx, _lintFixCmd, _formatFixCmd, _effectiveWorkdir) {
|
|
43498
43678
|
const logger = getLogger();
|
|
43499
43679
|
const storyId = ctx.story.id;
|
|
@@ -43517,7 +43697,18 @@ async function runAgentRectificationV2(ctx, _lintFixCmd, _formatFixCmd, _effecti
|
|
|
43517
43697
|
},
|
|
43518
43698
|
async validate(_cycleCtx) {
|
|
43519
43699
|
await _autofixDeps.recheckReview(ctx);
|
|
43520
|
-
|
|
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;
|
|
43521
43712
|
}
|
|
43522
43713
|
};
|
|
43523
43714
|
const result = await runFixCycle(cycle, cycleCtx, "autofix-v2");
|
|
@@ -45170,6 +45361,42 @@ ${formatFindings2(blockingFindings)}`,
|
|
|
45170
45361
|
};
|
|
45171
45362
|
}
|
|
45172
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
|
+
}
|
|
45173
45400
|
const durationMs2 = Date.now() - startTime;
|
|
45174
45401
|
logger?.info("review", "Adversarial review passed (all findings below blocking threshold)", {
|
|
45175
45402
|
storyId: story.id,
|
|
@@ -46228,6 +46455,42 @@ ${formatFindings(blockingFindings)}`;
|
|
|
46228
46455
|
};
|
|
46229
46456
|
}
|
|
46230
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
|
+
}
|
|
46231
46494
|
const durationMs2 = Date.now() - startTime;
|
|
46232
46495
|
logger?.info("review", "Semantic review passed (all findings below blocking threshold)", {
|
|
46233
46496
|
storyId: story.id,
|
|
@@ -47315,12 +47578,115 @@ async function recheckReview(ctx) {
|
|
|
47315
47578
|
return false;
|
|
47316
47579
|
return ctx.reviewResult?.success === true;
|
|
47317
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
|
+
}
|
|
47318
47683
|
var NON_FIXABLE_BY_RECTIFICATION, autofixStage, _autofixDeps;
|
|
47319
47684
|
var init_autofix = __esm(() => {
|
|
47320
47685
|
init_logger2();
|
|
47321
47686
|
init_quality();
|
|
47322
47687
|
init_event_bus();
|
|
47323
47688
|
init_autofix_agent();
|
|
47689
|
+
init_autofix_cycle();
|
|
47324
47690
|
init_autofix_scope_split();
|
|
47325
47691
|
init_autofix_test_writer2();
|
|
47326
47692
|
NON_FIXABLE_BY_RECTIFICATION = new Set(["git-clean"]);
|
|
@@ -47345,8 +47711,7 @@ var init_autofix = __esm(() => {
|
|
|
47345
47711
|
if (!reviewResult || reviewResult.success) {
|
|
47346
47712
|
return { action: "continue" };
|
|
47347
47713
|
}
|
|
47348
|
-
|
|
47349
|
-
const formatFixCmd = ctx.config.quality.commands.formatFix ?? ctx.config.review.commands.formatFix;
|
|
47714
|
+
ctx.autofixAttempt = (ctx.autofixAttempt ?? 0) + 1;
|
|
47350
47715
|
const failedCheckNames = new Set((reviewResult.checks ?? []).filter((c) => !c.success).map((c) => c.check));
|
|
47351
47716
|
const hasLintFailure = failedCheckNames.has("lint");
|
|
47352
47717
|
const totalFindingCount = (reviewResult.checks ?? []).reduce((n, c) => n + (c.findings?.length ?? 0), 0);
|
|
@@ -47367,42 +47732,8 @@ var init_autofix = __esm(() => {
|
|
|
47367
47732
|
failedChecks: [...failedCheckNames],
|
|
47368
47733
|
workdir: ctx.workdir
|
|
47369
47734
|
});
|
|
47370
|
-
if (hasLintFailure && (
|
|
47371
|
-
|
|
47372
|
-
pipelineEventBus.emit({ type: "autofix:started", storyId: ctx.story.id, command: lintFixCmd });
|
|
47373
|
-
const lintResult = await _autofixDeps.runQualityCommand({
|
|
47374
|
-
commandName: "lintFix",
|
|
47375
|
-
command: lintFixCmd,
|
|
47376
|
-
workdir: ctx.workdir,
|
|
47377
|
-
storyId: ctx.story.id
|
|
47378
|
-
});
|
|
47379
|
-
logger.debug("autofix", `lintFix exit=${lintResult.exitCode}`, { storyId: ctx.story.id, command: lintFixCmd });
|
|
47380
|
-
if (lintResult.exitCode !== 0) {
|
|
47381
|
-
logger.warn("autofix", "lintFix command failed \u2014 may not have fixed all issues", {
|
|
47382
|
-
storyId: ctx.story.id,
|
|
47383
|
-
exitCode: lintResult.exitCode
|
|
47384
|
-
});
|
|
47385
|
-
}
|
|
47386
|
-
}
|
|
47387
|
-
if (formatFixCmd) {
|
|
47388
|
-
pipelineEventBus.emit({ type: "autofix:started", storyId: ctx.story.id, command: formatFixCmd });
|
|
47389
|
-
const fmtResult = await _autofixDeps.runQualityCommand({
|
|
47390
|
-
commandName: "formatFix",
|
|
47391
|
-
command: formatFixCmd,
|
|
47392
|
-
workdir: ctx.workdir,
|
|
47393
|
-
storyId: ctx.story.id
|
|
47394
|
-
});
|
|
47395
|
-
logger.debug("autofix", `formatFix exit=${fmtResult.exitCode}`, {
|
|
47396
|
-
storyId: ctx.story.id,
|
|
47397
|
-
command: formatFixCmd
|
|
47398
|
-
});
|
|
47399
|
-
if (fmtResult.exitCode !== 0) {
|
|
47400
|
-
logger.warn("autofix", "formatFix command failed \u2014 may not have fixed all issues", {
|
|
47401
|
-
storyId: ctx.story.id,
|
|
47402
|
-
exitCode: fmtResult.exitCode
|
|
47403
|
-
});
|
|
47404
|
-
}
|
|
47405
|
-
}
|
|
47735
|
+
if (hasLintFailure && hasMechanicalFixCommand(ctx)) {
|
|
47736
|
+
await runMechanicalFixes(ctx, failedCheckNames);
|
|
47406
47737
|
const recheckPassed = await _autofixDeps.recheckReview(ctx);
|
|
47407
47738
|
pipelineEventBus.emit({ type: "autofix:completed", storyId: ctx.story.id, fixed: recheckPassed });
|
|
47408
47739
|
if (recheckPassed) {
|
|
@@ -47445,7 +47776,7 @@ var init_autofix = __esm(() => {
|
|
|
47445
47776
|
cost: agentCost,
|
|
47446
47777
|
unresolvedReason,
|
|
47447
47778
|
escalationDigest
|
|
47448
|
-
} = await _autofixDeps.runAgentRectification(ctx,
|
|
47779
|
+
} = await _autofixDeps.runAgentRectification(ctx, resolveBroadFixCommand(ctx, "lintFix"), resolveBroadFixCommand(ctx, "formatFix"), ctx.workdir);
|
|
47449
47780
|
if (!agentFixed && unresolvedReason) {
|
|
47450
47781
|
if (ctx.mechanicalFailedOnly) {
|
|
47451
47782
|
logger.warn("autofix", "Mechanical-only failure unfixable \u2014 proceeding (LLM review passed)", {
|
|
@@ -47480,7 +47811,8 @@ var init_autofix = __esm(() => {
|
|
|
47480
47811
|
const totalUsed = ctx.autofixAttempt ?? 0;
|
|
47481
47812
|
const currentlyFailing = new Set((ctx.reviewResult?.checks ?? []).filter((c) => !c.success || c.failOpen).map((c) => c.check));
|
|
47482
47813
|
const nowPassing = [...failedCheckNames].filter((c) => !currentlyFailing.has(c));
|
|
47483
|
-
|
|
47814
|
+
const capacityExhausted = autofixCapacityExhausted(ctx);
|
|
47815
|
+
if (nowPassing.length > 0 && totalUsed < maxTotal && !capacityExhausted) {
|
|
47484
47816
|
ctx.retrySkipChecks = new Set([...ctx.retrySkipChecks ?? [], ...nowPassing]);
|
|
47485
47817
|
logger.info("autofix", "Partial progress \u2014 retrying review with updated skip list", {
|
|
47486
47818
|
storyId: ctx.story.id,
|
|
@@ -47490,6 +47822,13 @@ var init_autofix = __esm(() => {
|
|
|
47490
47822
|
});
|
|
47491
47823
|
return { action: "retry", fromStage: "review", cost: agentCost };
|
|
47492
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
|
+
}
|
|
47493
47832
|
logger.warn("autofix", "Autofix exhausted \u2014 escalating", { storyId: ctx.story.id });
|
|
47494
47833
|
return {
|
|
47495
47834
|
action: "escalate",
|
|
@@ -54286,7 +54625,7 @@ var package_default;
|
|
|
54286
54625
|
var init_package = __esm(() => {
|
|
54287
54626
|
package_default = {
|
|
54288
54627
|
name: "@nathapp/nax",
|
|
54289
|
-
version: "0.65.
|
|
54628
|
+
version: "0.65.2",
|
|
54290
54629
|
description: "AI Coding Agent Orchestrator \u2014 loops until done",
|
|
54291
54630
|
type: "module",
|
|
54292
54631
|
bin: {
|
|
@@ -54372,8 +54711,8 @@ var init_version = __esm(() => {
|
|
|
54372
54711
|
NAX_VERSION = package_default.version;
|
|
54373
54712
|
NAX_COMMIT = (() => {
|
|
54374
54713
|
try {
|
|
54375
|
-
if (/^[0-9a-f]{6,10}$/.test("
|
|
54376
|
-
return "
|
|
54714
|
+
if (/^[0-9a-f]{6,10}$/.test("99828ef9"))
|
|
54715
|
+
return "99828ef9";
|
|
54377
54716
|
} catch {}
|
|
54378
54717
|
try {
|
|
54379
54718
|
const result = Bun.spawnSync(["git", "rev-parse", "--short", "HEAD"], {
|
|
@@ -90724,6 +91063,7 @@ __export(exports_curator, {
|
|
|
90724
91063
|
_curatorCmdDeps: () => _curatorCmdDeps
|
|
90725
91064
|
});
|
|
90726
91065
|
import { readdirSync as readdirSync10 } from "fs";
|
|
91066
|
+
import { unlink as unlink4 } from "fs/promises";
|
|
90727
91067
|
import { basename as basename16, join as join79 } from "path";
|
|
90728
91068
|
function getProjectKey(config2, projectDir) {
|
|
90729
91069
|
return config2.name?.trim() || basename16(projectDir);
|
|
@@ -90994,6 +91334,16 @@ async function curatorGc(options) {
|
|
|
90994
91334
|
`)}
|
|
90995
91335
|
`;
|
|
90996
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
|
+
}
|
|
90997
91347
|
console.log(`[gc] Pruned rollup to ${keep} most recent runs (was ${uniqueRunIds.length}).`);
|
|
90998
91348
|
}
|
|
90999
91349
|
var _curatorCmdDeps, DEFAULT_KEEP = 50;
|
|
@@ -91017,6 +91367,11 @@ var init_curator2 = __esm(() => {
|
|
|
91017
91367
|
const prev = await existing.exists() ? await existing.text() : "";
|
|
91018
91368
|
await Bun.write(p, prev + content);
|
|
91019
91369
|
},
|
|
91370
|
+
removeFile: async (p) => {
|
|
91371
|
+
try {
|
|
91372
|
+
await unlink4(p);
|
|
91373
|
+
} catch {}
|
|
91374
|
+
},
|
|
91020
91375
|
openInEditor: async (filePath) => {
|
|
91021
91376
|
const editor = process.env.EDITOR ?? process.env.VISUAL ?? "vi";
|
|
91022
91377
|
const proc = Bun.spawnSync([editor, filePath], { stdio: ["inherit", "inherit", "inherit"] });
|
|
@@ -92516,6 +92871,8 @@ var FIELD_DESCRIPTIONS = {
|
|
|
92516
92871
|
"quality.commands.typecheck": "Custom typecheck command",
|
|
92517
92872
|
"quality.commands.lint": "Custom lint command",
|
|
92518
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}})",
|
|
92519
92876
|
"quality.commands.test": "Custom test command",
|
|
92520
92877
|
"quality.commands.build": "Custom build command",
|
|
92521
92878
|
"quality.forceExit": "Append --forceExit to test command (prevents hangs)",
|
|
@@ -92549,6 +92906,8 @@ var FIELD_DESCRIPTIONS = {
|
|
|
92549
92906
|
"review.commands.typecheck": "Custom typecheck command for review",
|
|
92550
92907
|
"review.commands.lint": "Custom lint command for review",
|
|
92551
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}})",
|
|
92552
92911
|
"review.commands.test": "Custom test command for review",
|
|
92553
92912
|
"review.commands.build": "Custom build command for review",
|
|
92554
92913
|
"review.semantic": "Semantic review configuration (code quality analysis)",
|