tend-cli 0.6.1 → 0.7.0
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/bin.js +595 -90
- package/dist/{config-Dz4byqjU.js → config-DPlVYfKX.js} +90 -19
- package/dist/index.d.ts +121 -39
- package/dist/index.js +1 -1
- package/package.json +1 -1
|
@@ -743,6 +743,10 @@ const FAILURE_CLASSES = [
|
|
|
743
743
|
"tool-timeout",
|
|
744
744
|
"rate-limit",
|
|
745
745
|
"model-tool-failure",
|
|
746
|
+
"sandbox-setup-failed",
|
|
747
|
+
"patch-conflict",
|
|
748
|
+
"unowned-patch",
|
|
749
|
+
"final-integration-failed",
|
|
746
750
|
"no-edit",
|
|
747
751
|
"no-op",
|
|
748
752
|
"regression",
|
|
@@ -809,7 +813,11 @@ const FindingSchema = z.object({
|
|
|
809
813
|
"regression",
|
|
810
814
|
"typecheck",
|
|
811
815
|
"session-error",
|
|
812
|
-
"needs-lockfile-update"
|
|
816
|
+
"needs-lockfile-update",
|
|
817
|
+
"sandbox-setup-failed",
|
|
818
|
+
"patch-conflict",
|
|
819
|
+
"unowned-patch",
|
|
820
|
+
"final-integration-failed"
|
|
813
821
|
]).optional(),
|
|
814
822
|
revertDetail: z.string().optional(),
|
|
815
823
|
finalFailureClass: z.enum(FAILURE_CLASSES).optional(),
|
|
@@ -1389,6 +1397,12 @@ var Snapshot = class Snapshot {
|
|
|
1389
1397
|
sha: this.sha
|
|
1390
1398
|
};
|
|
1391
1399
|
}
|
|
1400
|
+
commitSha() {
|
|
1401
|
+
return this.sha;
|
|
1402
|
+
}
|
|
1403
|
+
repoRoot() {
|
|
1404
|
+
return this.root;
|
|
1405
|
+
}
|
|
1392
1406
|
static fromJSON(data) {
|
|
1393
1407
|
return new Snapshot(data.cwd, data.root, data.sha);
|
|
1394
1408
|
}
|
|
@@ -1652,6 +1666,8 @@ function allowsDeleteOnly(unit) {
|
|
|
1652
1666
|
async function gateUnitChanges(unit, before, deps, opts = {}) {
|
|
1653
1667
|
const usage = opts.usage ?? zeroUsage();
|
|
1654
1668
|
const after = snapshotUnitNow(deps.cwd, unit.files);
|
|
1669
|
+
const scannerTools = [...new Set(unit.findings.map((finding) => finding.tool))];
|
|
1670
|
+
opts.onProgress?.("anti-suppression");
|
|
1655
1671
|
const supp = antiSuppression(buildDiff(before, after), { allowDeleteOnly: allowsDeleteOnly(unit) });
|
|
1656
1672
|
if (!supp.ok) return {
|
|
1657
1673
|
kept: false,
|
|
@@ -1659,6 +1675,7 @@ async function gateUnitChanges(unit, before, deps, opts = {}) {
|
|
|
1659
1675
|
detail: supp.detail,
|
|
1660
1676
|
usage
|
|
1661
1677
|
};
|
|
1678
|
+
opts.onProgress?.("typecheck");
|
|
1662
1679
|
const tc = await typecheck({
|
|
1663
1680
|
hasTsconfig: () => deps.typescript,
|
|
1664
1681
|
runTsc: deps.runTsc
|
|
@@ -1670,6 +1687,7 @@ async function gateUnitChanges(unit, before, deps, opts = {}) {
|
|
|
1670
1687
|
usage
|
|
1671
1688
|
};
|
|
1672
1689
|
if (unit.strategy === "generated-source-repair" && deps.runBuild) {
|
|
1690
|
+
opts.onProgress?.("build");
|
|
1673
1691
|
const build = await deps.runBuild();
|
|
1674
1692
|
if (build.exitCode !== 0) return {
|
|
1675
1693
|
kept: false,
|
|
@@ -1680,8 +1698,14 @@ async function gateUnitChanges(unit, before, deps, opts = {}) {
|
|
|
1680
1698
|
}
|
|
1681
1699
|
const phase = await runTestPhase({
|
|
1682
1700
|
baseline: deps.baseline,
|
|
1683
|
-
runRelated: () =>
|
|
1684
|
-
|
|
1701
|
+
runRelated: () => {
|
|
1702
|
+
opts.onProgress?.("related-tests");
|
|
1703
|
+
return deps.runRelated(unit.files);
|
|
1704
|
+
},
|
|
1705
|
+
repair: async (attempt, regressed) => {
|
|
1706
|
+
opts.onProgress?.("test-repair", `${attempt}/${opts.maxRepairs ?? 0}`);
|
|
1707
|
+
await (opts.repair ?? (async () => {}))(attempt, regressed);
|
|
1708
|
+
},
|
|
1685
1709
|
maxRepairs: opts.maxRepairs ?? 0,
|
|
1686
1710
|
hasTestRunner: deps.hasTestRunner
|
|
1687
1711
|
});
|
|
@@ -1692,7 +1716,9 @@ async function gateUnitChanges(unit, before, deps, opts = {}) {
|
|
|
1692
1716
|
usage
|
|
1693
1717
|
};
|
|
1694
1718
|
const verificationTargets = unit.verificationTargets ?? unit.files;
|
|
1695
|
-
|
|
1719
|
+
opts.onProgress?.("rescan");
|
|
1720
|
+
const afterFindings = await deps.scanFindings(verificationTargets, scannerTools);
|
|
1721
|
+
opts.onProgress?.("regression-check");
|
|
1696
1722
|
const regression = antiRegression(unit.findings, afterFindings, { requireResolved: opts.requireResolved || unit.strategy === "multi-file-duplicate-refactor" });
|
|
1697
1723
|
if (!regression.ok) return {
|
|
1698
1724
|
kept: false,
|
|
@@ -2251,7 +2277,16 @@ const FailureSummarySchema = z.object({
|
|
|
2251
2277
|
sessionErrors: z.number().int().nonnegative(),
|
|
2252
2278
|
regressions: z.number().int().nonnegative(),
|
|
2253
2279
|
typecheckFailures: z.number().int().nonnegative(),
|
|
2254
|
-
testFailures: z.number().int().nonnegative()
|
|
2280
|
+
testFailures: z.number().int().nonnegative(),
|
|
2281
|
+
sandboxSetupFailures: z.number().int().nonnegative().default(0),
|
|
2282
|
+
patchConflicts: z.number().int().nonnegative().default(0),
|
|
2283
|
+
unownedPatches: z.number().int().nonnegative().default(0),
|
|
2284
|
+
finalIntegrationFailures: z.number().int().nonnegative().default(0)
|
|
2285
|
+
});
|
|
2286
|
+
const FinalIntegrationSchema = z.object({
|
|
2287
|
+
ok: z.boolean(),
|
|
2288
|
+
files: z.array(z.string()).default([]),
|
|
2289
|
+
detail: z.string().optional()
|
|
2255
2290
|
});
|
|
2256
2291
|
const ZERO_AI_USAGE$1 = {
|
|
2257
2292
|
estimatedCostUsd: 0,
|
|
@@ -2269,7 +2304,11 @@ const ZERO_FAILURE_SUMMARY = {
|
|
|
2269
2304
|
sessionErrors: 0,
|
|
2270
2305
|
regressions: 0,
|
|
2271
2306
|
typecheckFailures: 0,
|
|
2272
|
-
testFailures: 0
|
|
2307
|
+
testFailures: 0,
|
|
2308
|
+
sandboxSetupFailures: 0,
|
|
2309
|
+
patchConflicts: 0,
|
|
2310
|
+
unownedPatches: 0,
|
|
2311
|
+
finalIntegrationFailures: 0
|
|
2273
2312
|
};
|
|
2274
2313
|
const ReportSchema = z.object({
|
|
2275
2314
|
findings: z.array(FindingSchema),
|
|
@@ -2282,6 +2321,7 @@ const ReportSchema = z.object({
|
|
|
2282
2321
|
fixPolicy: FixPolicySchema,
|
|
2283
2322
|
aiUsage: AiUsageSchema.default(ZERO_AI_USAGE$1),
|
|
2284
2323
|
failureSummary: FailureSummarySchema.default(ZERO_FAILURE_SUMMARY),
|
|
2324
|
+
finalIntegration: FinalIntegrationSchema.optional(),
|
|
2285
2325
|
unresolvedEligibleCount: z.number().int().nonnegative().default(0),
|
|
2286
2326
|
loops: z.number().int().nonnegative(),
|
|
2287
2327
|
durationMs: z.number().nonnegative(),
|
|
@@ -2320,7 +2360,11 @@ function deriveReportFields(findings, scannerStatuses, fixPolicy = DEFAULT_FIX_P
|
|
|
2320
2360
|
sessionErrors: blockingUnresolved.filter((f) => f.revertReason === "session-error").length,
|
|
2321
2361
|
regressions: blockingUnresolved.filter((f) => f.revertReason === "regression").length,
|
|
2322
2362
|
typecheckFailures: blockingUnresolved.filter((f) => f.revertReason === "typecheck").length,
|
|
2323
|
-
testFailures: blockingUnresolved.filter((f) => f.revertReason === "broke-test").length
|
|
2363
|
+
testFailures: blockingUnresolved.filter((f) => f.revertReason === "broke-test").length,
|
|
2364
|
+
sandboxSetupFailures: blockingUnresolved.filter((f) => f.finalFailureClass === "sandbox-setup-failed").length,
|
|
2365
|
+
patchConflicts: blockingUnresolved.filter((f) => f.finalFailureClass === "patch-conflict").length,
|
|
2366
|
+
unownedPatches: blockingUnresolved.filter((f) => f.finalFailureClass === "unowned-patch").length,
|
|
2367
|
+
finalIntegrationFailures: blockingUnresolved.filter((f) => f.finalFailureClass === "final-integration-failed").length
|
|
2324
2368
|
};
|
|
2325
2369
|
return {
|
|
2326
2370
|
secrets: findings.filter((f) => f.category === "secret"),
|
|
@@ -2375,6 +2419,7 @@ var ReportBuilder = class {
|
|
|
2375
2419
|
fixPolicy,
|
|
2376
2420
|
aiUsage: meta.aiUsage ?? ZERO_AI_USAGE,
|
|
2377
2421
|
failureSummary: derived.failureSummary,
|
|
2422
|
+
finalIntegration: meta.finalIntegration,
|
|
2378
2423
|
unresolvedEligibleCount: derived.unresolvedEligibleCount,
|
|
2379
2424
|
loops: meta.loops,
|
|
2380
2425
|
durationMs: meta.durationMs,
|
|
@@ -2445,6 +2490,10 @@ function classFromOutcome(outcome) {
|
|
|
2445
2490
|
case "broke-test": return "broke-test";
|
|
2446
2491
|
case "suppression": return "suppression";
|
|
2447
2492
|
case "needs-lockfile-update": return "needs-lockfile-update";
|
|
2493
|
+
case "sandbox-setup-failed": return "sandbox-setup-failed";
|
|
2494
|
+
case "patch-conflict": return "patch-conflict";
|
|
2495
|
+
case "unowned-patch": return "unowned-patch";
|
|
2496
|
+
case "final-integration-failed": return "final-integration-failed";
|
|
2448
2497
|
case "session-error": return "model-tool-failure";
|
|
2449
2498
|
default: return void 0;
|
|
2450
2499
|
}
|
|
@@ -2754,6 +2803,10 @@ function reasonLabel(reason) {
|
|
|
2754
2803
|
case "suppression": return "added a suppression";
|
|
2755
2804
|
case "regression": return "introduced a new issue";
|
|
2756
2805
|
case "session-error": return "the fix session failed";
|
|
2806
|
+
case "sandbox-setup-failed": return "sandbox setup failed";
|
|
2807
|
+
case "patch-conflict": return "patch conflict";
|
|
2808
|
+
case "unowned-patch": return "unowned patch";
|
|
2809
|
+
case "final-integration-failed": return "final integration failed";
|
|
2757
2810
|
case "needs-lockfile-update": return "needs lockfile update";
|
|
2758
2811
|
default: return "couldn't fix";
|
|
2759
2812
|
}
|
|
@@ -2985,17 +3038,24 @@ function renderPlainSummary(report, b, theme, verbose) {
|
|
|
2985
3038
|
];
|
|
2986
3039
|
const strategyCounts = repairStrategyCounts(report);
|
|
2987
3040
|
if (strategyCounts.size > 0) lines$1.push(["repairStrategies", ...[...strategyCounts.entries()].map(([strategy, count]) => `${strategy}=${count}`)].join(" "));
|
|
2988
|
-
if (report.exitStatus !== 0 || hasFailureSummary(report))
|
|
2989
|
-
|
|
2990
|
-
|
|
2991
|
-
|
|
2992
|
-
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
|
-
|
|
2996
|
-
|
|
2997
|
-
|
|
2998
|
-
|
|
3041
|
+
if (report.exitStatus !== 0 || hasFailureSummary(report)) {
|
|
3042
|
+
lines$1.push([
|
|
3043
|
+
"failureSummary",
|
|
3044
|
+
`blockingSecrets=${report.failureSummary.blockingSecrets}`,
|
|
3045
|
+
`unresolvedEligible=${report.failureSummary.unresolvedEligible}`,
|
|
3046
|
+
`toolFailures=${report.failureSummary.toolFailures}`,
|
|
3047
|
+
`failedDeterministic=${report.failureSummary.failedDeterministic}`,
|
|
3048
|
+
`sessionErrors=${report.failureSummary.sessionErrors}`,
|
|
3049
|
+
`regressions=${report.failureSummary.regressions}`,
|
|
3050
|
+
`typecheckFailures=${report.failureSummary.typecheckFailures}`,
|
|
3051
|
+
`testFailures=${report.failureSummary.testFailures}`,
|
|
3052
|
+
`sandboxSetupFailures=${report.failureSummary.sandboxSetupFailures}`,
|
|
3053
|
+
`patchConflicts=${report.failureSummary.patchConflicts}`,
|
|
3054
|
+
`unownedPatches=${report.failureSummary.unownedPatches}`,
|
|
3055
|
+
`finalIntegrationFailures=${report.failureSummary.finalIntegrationFailures}`
|
|
3056
|
+
].join(" "));
|
|
3057
|
+
if (report.finalIntegration && !report.finalIntegration.ok) lines$1.push(`final-integration status=failed files=${report.finalIntegration.files.length} detail=${JSON.stringify(firstLine(report.finalIntegration.detail ?? ""))}`);
|
|
3058
|
+
}
|
|
2999
3059
|
const counts = inScopeByTool(report);
|
|
3000
3060
|
const statusByTool = new Map(report.scannerStatuses.map((s) => [s.tool, s]));
|
|
3001
3061
|
const tools = TOOLS.filter((t) => statusByTool.has(t) || counts.has(t));
|
|
@@ -3056,6 +3116,7 @@ function renderOverallTable(report, b, theme) {
|
|
|
3056
3116
|
const rows = [
|
|
3057
3117
|
["status", status],
|
|
3058
3118
|
["fix passes", String(report.loops)],
|
|
3119
|
+
...report.finalIntegration && !report.finalIntegration.ok ? [["final integration", theme.error(firstLine(report.finalIntegration.detail ?? "failed"))]] : [],
|
|
3059
3120
|
["elapsed", formatDuration(report.durationMs)],
|
|
3060
3121
|
["fixed", `${theme.fixed(theme.glyph.fixed)} ${b.fixed.length}`],
|
|
3061
3122
|
["timed out/session error", `${theme.reverted(theme.glyph.reverted)} ${b.timedOutSessionError.length}`],
|
|
@@ -3081,7 +3142,7 @@ function renderOverallTable(report, b, theme) {
|
|
|
3081
3142
|
}
|
|
3082
3143
|
function hasFailureSummary(report) {
|
|
3083
3144
|
const summary = report.failureSummary;
|
|
3084
|
-
return summary.blockingSecrets > 0 || summary.unresolvedEligible > 0 || summary.toolFailures > 0 || summary.failedDeterministic > 0 || summary.sessionErrors > 0 || summary.regressions > 0 || summary.typecheckFailures > 0 || summary.testFailures > 0;
|
|
3145
|
+
return summary.blockingSecrets > 0 || summary.unresolvedEligible > 0 || summary.toolFailures > 0 || summary.failedDeterministic > 0 || summary.sessionErrors > 0 || summary.regressions > 0 || summary.typecheckFailures > 0 || summary.testFailures > 0 || summary.sandboxSetupFailures > 0 || summary.patchConflicts > 0 || summary.unownedPatches > 0 || summary.finalIntegrationFailures > 0;
|
|
3085
3146
|
}
|
|
3086
3147
|
/** Estimated AI cost as `$X.XX` — always two decimals, never called a "bill". */
|
|
3087
3148
|
function formatCost(usd) {
|
|
@@ -3210,6 +3271,10 @@ function findingReason(f) {
|
|
|
3210
3271
|
if (f.finalFailureClass === "tool-timeout") return "timeout/session error";
|
|
3211
3272
|
if (f.finalFailureClass === "rate-limit") return "rate limited";
|
|
3212
3273
|
if (f.finalFailureClass === "no-op") return "no-op";
|
|
3274
|
+
if (f.finalFailureClass === "sandbox-setup-failed") return "sandbox setup failed";
|
|
3275
|
+
if (f.finalFailureClass === "patch-conflict") return "patch conflict";
|
|
3276
|
+
if (f.finalFailureClass === "unowned-patch") return "unowned patch";
|
|
3277
|
+
if (f.finalFailureClass === "final-integration-failed") return "final integration failed";
|
|
3213
3278
|
switch (f.revertReason) {
|
|
3214
3279
|
case "session-error": return "timeout/session error";
|
|
3215
3280
|
case "regression": return "regression introduced";
|
|
@@ -3223,6 +3288,9 @@ function retryTarget(f) {
|
|
|
3223
3288
|
return f.retryId ?? f.id;
|
|
3224
3289
|
}
|
|
3225
3290
|
const COULDNT_FIX_REASON_ORDER = [
|
|
3291
|
+
"sandbox setup failed",
|
|
3292
|
+
"patch conflict",
|
|
3293
|
+
"unowned patch",
|
|
3226
3294
|
"session error",
|
|
3227
3295
|
"regression",
|
|
3228
3296
|
"typecheck failed",
|
|
@@ -3232,6 +3300,9 @@ const COULDNT_FIX_REASON_ORDER = [
|
|
|
3232
3300
|
];
|
|
3233
3301
|
function couldntFixReason(f) {
|
|
3234
3302
|
if (f.track === "report-only") return "unsupported / report-only";
|
|
3303
|
+
if (f.finalFailureClass === "sandbox-setup-failed") return "sandbox setup failed";
|
|
3304
|
+
if (f.finalFailureClass === "patch-conflict") return "patch conflict";
|
|
3305
|
+
if (f.finalFailureClass === "unowned-patch") return "unowned patch";
|
|
3235
3306
|
if (f.revertReason === "session-error" || f.finalFailureClass === "tool-timeout" || f.finalFailureClass === "rate-limit" || f.finalFailureClass === "model-tool-failure" || f.finalFailureClass === "no-edit") return "session error";
|
|
3236
3307
|
if (f.revertReason === "regression" || f.finalFailureClass === "regression") return "regression";
|
|
3237
3308
|
if (f.revertReason === "typecheck" || f.finalFailureClass === "typecheck") return "typecheck failed";
|