Skip to content

Commit 9885fd2

Browse files
committed
fix: resolve biome formatting issues for CI
Made-with: Cursor
1 parent 8a2f93f commit 9885fd2

File tree

8 files changed

+120
-63
lines changed

8 files changed

+120
-63
lines changed

src/ai/planner.ts

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -138,8 +138,12 @@ async function validateAndRepairPlan(
138138

139139
// Phase 1: AI-driven revision (same conversation context)
140140
for (let round = 1; round <= MAX_AI_REVISION_ROUNDS; round++) {
141-
const progress = new ProgressSpinner(`Verifying boundaries (round ${round}/${MAX_AI_REVISION_ROUNDS})`);
142-
const results = await applyAndCheckBoundaries(plan, repoDir, language, checkOptions, (step) => progress.update(step));
141+
const progress = new ProgressSpinner(
142+
`Verifying boundaries (round ${round}/${MAX_AI_REVISION_ROUNDS})`,
143+
);
144+
const results = await applyAndCheckBoundaries(plan, repoDir, language, checkOptions, (step) =>
145+
progress.update(step),
146+
);
143147
if (results.failures.length === 0) {
144148
progress.succeed();
145149
logger.success("All boundaries passed verification");
@@ -151,11 +155,13 @@ async function validateAndRepairPlan(
151155
if (!firstFailure) break;
152156

153157
try {
154-
plan = await withSpinner("AI revising plan", () => adapter.revisePlan(plan, {
155-
sliceOrder: firstFailure.sliceOrder,
156-
errorOutput: firstFailure.errorOutput,
157-
failedCheck: firstFailure.check,
158-
}));
158+
plan = await withSpinner("AI revising plan", () =>
159+
adapter.revisePlan(plan, {
160+
sliceOrder: firstFailure.sliceOrder,
161+
errorOutput: firstFailure.errorOutput,
162+
failedCheck: firstFailure.check,
163+
}),
164+
);
159165
} catch (error) {
160166
const msg = error instanceof Error ? error.message : String(error);
161167
logger.warn(`AI revision failed: ${msg} — falling back to mechanical collapse`);
@@ -165,8 +171,12 @@ async function validateAndRepairPlan(
165171

166172
// Phase 2: Mechanical collapse as fallback
167173
for (let round = 1; round <= MAX_COLLAPSE_ROUNDS; round++) {
168-
const progress = new ProgressSpinner(`Verifying after collapse (round ${round}/${MAX_COLLAPSE_ROUNDS})`);
169-
const results = await applyAndCheckBoundaries(plan, repoDir, language, checkOptions, (step) => progress.update(step));
174+
const progress = new ProgressSpinner(
175+
`Verifying after collapse (round ${round}/${MAX_COLLAPSE_ROUNDS})`,
176+
);
177+
const results = await applyAndCheckBoundaries(plan, repoDir, language, checkOptions, (step) =>
178+
progress.update(step),
179+
);
170180
if (results.failures.length === 0) {
171181
progress.succeed();
172182
logger.success("All boundaries passed verification after collapse");

src/cli/apply.ts

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1+
import { colorize } from "consola/utils";
12
import type { SimpleGit } from "simple-git";
23
import { simpleGit } from "simple-git";
3-
import { colorize } from "consola/utils";
44
import { readPlan } from "../core/plan.js";
55
import { applyPlan } from "../git/plan-applier.js";
66
import type { StackPlan } from "../types/index.js";
@@ -28,7 +28,9 @@ export async function applyCommand(): Promise<void> {
2828

2929
console.log(formatStackTree(plan));
3030
console.log(formatBranchStats(plan, diffStats));
31-
console.log(formatBeforeAfter(plan.metadata.totalFiles, plan.metadata.totalLoc, plan.slices.length));
31+
console.log(
32+
formatBeforeAfter(plan.metadata.totalFiles, plan.metadata.totalLoc, plan.slices.length),
33+
);
3234

3335
await verifyStackEquivalence(git, plan);
3436
}
@@ -41,7 +43,7 @@ async function getDiffStatsBySlice(git: SimpleGit, plan: StackPlan): Promise<Bra
4143
const slice = sortedSlices[i];
4244
if (!slice) continue;
4345

44-
const prevBranch = i === 0 ? plan.baseBranch : sortedSlices[i - 1]?.branch ?? plan.baseBranch;
46+
const prevBranch = i === 0 ? plan.baseBranch : (sortedSlices[i - 1]?.branch ?? plan.baseBranch);
4547
try {
4648
const diffOutput = await git.diff(["--shortstat", `${prevBranch}..${slice.branch}`]);
4749
stats.push({ sliceOrder: slice.order, ...parseShortStat(diffOutput) });
@@ -61,13 +63,19 @@ async function verifyStackEquivalence(git: SimpleGit, plan: StackPlan): Promise<
6163
const diff = await git.diff([`${lastBranch}..${plan.sourceBranch}`]);
6264

6365
if (diff.trim().length === 0) {
64-
console.log(`\n ${colorize("green", "✓ Stack verified:")} final branch ${lastBranch} is identical to ${plan.sourceBranch}`);
66+
console.log(
67+
`\n ${colorize("green", "✓ Stack verified:")} final branch ${lastBranch} is identical to ${plan.sourceBranch}`,
68+
);
6569
} else {
6670
const lines = diff.split("\n").length;
6771
logger.warn(
6872
`Stack divergence: ${lastBranch} differs from ${plan.sourceBranch} by ${lines} lines`,
6973
);
70-
console.log(`\n ${colorize("yellow", "⚠ Stack divergence:")} ${lastBranch} differs from ${plan.sourceBranch}`);
71-
console.log(` ${lines} diff lines — some changes may have been lost or modified during splitting`);
74+
console.log(
75+
`\n ${colorize("yellow", "⚠ Stack divergence:")} ${lastBranch} differs from ${plan.sourceBranch}`,
76+
);
77+
console.log(
78+
` ${lines} diff lines — some changes may have been lost or modified during splitting`,
79+
);
7280
}
7381
}

src/utils/display.ts

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,8 @@ export function formatPlanSummary(plan: StackPlan): string {
7575
);
7676

7777
const loc = computeSliceLoc(plan, slice.order);
78-
const locDisplay = loc > 0 ? `~${loc}` : `~${Math.round(plan.metadata.totalLoc / sortedSlices.length)}`;
78+
const locDisplay =
79+
loc > 0 ? `~${loc}` : `~${Math.round(plan.metadata.totalLoc / sortedSlices.length)}`;
7980

8081
const row: Array<string | number> = [slice.order, slice.title, sliceFiles.length, locDisplay];
8182

@@ -117,8 +118,11 @@ export function formatPlanSummary(plan: StackPlan): string {
117118
if (hasTests) {
118119
const totalTests = verification.reduce((sum, v) => sum + (v.testsRun ?? 0), 0);
119120
const totalPassed = verification.reduce((sum, v) => sum + (v.testsPassed ?? 0), 0);
120-
const testIcon = totalPassed === totalTests ? colorize("green", "✓") : colorize("yellow", "⚠");
121-
parts.push(`${testIcon} Tests: ${totalPassed}/${totalTests} passed across ${lintTotal} slices`);
121+
const testIcon =
122+
totalPassed === totalTests ? colorize("green", "✓") : colorize("yellow", "⚠");
123+
parts.push(
124+
`${testIcon} Tests: ${totalPassed}/${totalTests} passed across ${lintTotal} slices`,
125+
);
122126
}
123127

124128
summary += `\n\n ${parts.join("\n ")}`;
@@ -133,15 +137,16 @@ export function formatStackTree(plan: StackPlan): string {
133137
function buildTreeItems(
134138
slices: typeof sortedSlices,
135139
index: number,
136-
): Array<{ text: string; children?: Array<{ text: string; children?: ReturnType<typeof buildTreeItems> }> }> {
140+
): Array<{
141+
text: string;
142+
children?: Array<{ text: string; children?: ReturnType<typeof buildTreeItems> }>;
143+
}> {
137144
if (index >= slices.length) return [];
138145
const slice = slices[index];
139146
if (!slice) return [];
140147

141148
const isFirst = index === 0;
142-
const status = isFirst
143-
? colorize("green", "Ready for Review")
144-
: colorize("yellow", "Draft");
149+
const status = isFirst ? colorize("green", "Ready for Review") : colorize("yellow", "Draft");
145150
const label = `${colors.bold(slice.branch)} ${colors.gray(`PR #${slice.order}`)} · ${status}`;
146151

147152
return [
@@ -225,7 +230,7 @@ export function formatPrCards(plan: StackPlan, prs: PrResult[]): string {
225230
if (!pr) continue;
226231

227232
const isFirst = i === 0;
228-
const baseBranch = isFirst ? plan.baseBranch : sortedSlices[i - 1]?.branch ?? plan.baseBranch;
233+
const baseBranch = isFirst ? plan.baseBranch : (sortedSlices[i - 1]?.branch ?? plan.baseBranch);
229234
const statusBadge = pr.draft
230235
? colorize("yellow", "Draft")
231236
: colorize("green", "Ready for Review");
@@ -262,7 +267,11 @@ export function formatPrCards(plan: StackPlan, prs: PrResult[]): string {
262267
return cards.join("\n");
263268
}
264269

265-
export function parseShortStat(output: string): { filesChanged: number; insertions: number; deletions: number } {
270+
export function parseShortStat(output: string): {
271+
filesChanged: number;
272+
insertions: number;
273+
deletions: number;
274+
} {
266275
const filesMatch = output.match(/(\d+) files? changed/);
267276
const insertionsMatch = output.match(/(\d+) insertions?\(\+\)/);
268277
const deletionsMatch = output.match(/(\d+) deletions?\(-\)/);

tests/e2e/demo-e2e.test.ts

Lines changed: 32 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ import { execFile } from "node:child_process";
22
import { readFile } from "node:fs/promises";
33
import { join, resolve } from "node:path";
44
import { promisify } from "node:util";
5-
import { afterEach, beforeEach, describe, expect, it } from "vitest";
6-
import { simpleGit } from "simple-git";
75
import type { SimpleGit } from "simple-git";
6+
import { simpleGit } from "simple-git";
7+
import { afterEach, beforeEach, describe, expect, it } from "vitest";
88
import { validatePlan, writePlan } from "../../src/core/plan.js";
99
import { applyPlan } from "../../src/git/plan-applier.js";
1010
import type { StackPlan } from "../../src/types/index.js";
@@ -87,31 +87,37 @@ describe("demo E2E with cached AI response", () => {
8787
expect(app5).toContain("postRouter");
8888
});
8989

90-
it("tests are colocated with their code (not in separate slice)", { timeout: 30_000 }, async () => {
91-
await git.checkout("feat/full-rest-api");
92-
await writePlan(plan, demoDir);
93-
await applyPlan(git, plan, demoDir);
90+
it(
91+
"tests are colocated with their code (not in separate slice)",
92+
{ timeout: 30_000 },
93+
async () => {
94+
await git.checkout("feat/full-rest-api");
95+
await writePlan(plan, demoDir);
96+
await applyPlan(git, plan, demoDir);
9497

95-
const testAssignments = plan.fileAssignments.filter(
96-
(fa) => fa.path.includes("test") || fa.path.includes("spec"),
97-
);
98-
99-
for (const testFile of testAssignments) {
100-
const targetSlice = testFile.targetSlice
101-
?? testFile.sliceContents?.[0]?.slice;
102-
expect(targetSlice, `${testFile.path} should have a slice assignment`).toBeDefined();
103-
104-
// The test file's slice should also contain non-test code
105-
const sliceFiles = plan.fileAssignments.filter((fa) => {
106-
if (fa.targetSlice === targetSlice) return true;
107-
return fa.sliceContents?.some((sc) => sc.slice === targetSlice) ?? false;
108-
});
109-
const hasSourceCode = sliceFiles.some(
110-
(fa) => !fa.path.includes("test") && !fa.path.includes("spec"),
98+
const testAssignments = plan.fileAssignments.filter(
99+
(fa) => fa.path.includes("test") || fa.path.includes("spec"),
111100
);
112-
expect(hasSourceCode, `slice ${targetSlice} (with ${testFile.path}) should also have source code`).toBe(true);
113-
}
114-
});
101+
102+
for (const testFile of testAssignments) {
103+
const targetSlice = testFile.targetSlice ?? testFile.sliceContents?.[0]?.slice;
104+
expect(targetSlice, `${testFile.path} should have a slice assignment`).toBeDefined();
105+
106+
// The test file's slice should also contain non-test code
107+
const sliceFiles = plan.fileAssignments.filter((fa) => {
108+
if (fa.targetSlice === targetSlice) return true;
109+
return fa.sliceContents?.some((sc) => sc.slice === targetSlice) ?? false;
110+
});
111+
const hasSourceCode = sliceFiles.some(
112+
(fa) => !fa.path.includes("test") && !fa.path.includes("spec"),
113+
);
114+
expect(
115+
hasSourceCode,
116+
`slice ${targetSlice} (with ${testFile.path}) should also have source code`,
117+
).toBe(true);
118+
}
119+
},
120+
);
115121

116122
it("verification data shows progressive test counts", () => {
117123
const verification = plan.metadata.verification;
@@ -139,9 +145,7 @@ describe("demo E2E with cached AI response", () => {
139145
await writePlan(plan, demoDir);
140146
await applyPlan(git, plan, demoDir);
141147

142-
const lastBranch = plan.slices
143-
.sort((a, b) => a.order - b.order)
144-
.at(-1)?.branch;
148+
const lastBranch = plan.slices.sort((a, b) => a.order - b.order).at(-1)?.branch;
145149
expect(lastBranch).toBeDefined();
146150

147151
const diff = await git.diff([`${lastBranch}..feat/full-rest-api`]);

tests/e2e/demo-fixture.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ import { execFile } from "node:child_process";
22
import { access } from "node:fs/promises";
33
import { join, resolve } from "node:path";
44
import { promisify } from "node:util";
5-
import { afterEach, describe, expect, it } from "vitest";
65
import { simpleGit } from "simple-git";
6+
import { afterEach, describe, expect, it } from "vitest";
77

88
const execFileAsync = promisify(execFile);
99
const SETUP_SCRIPT = resolve(import.meta.dirname, "../../demo/setup-fixture.sh");

tests/e2e/split-apply.test.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -98,9 +98,7 @@ describe("E2E: split → apply pipeline", () => {
9898

9999
await applyPlan(repo.git, modifiedPlan, repo.dir);
100100

101-
const lastBranch = modifiedPlan.slices
102-
.sort((a, b) => a.order - b.order)
103-
.at(-1)?.branch;
101+
const lastBranch = modifiedPlan.slices.sort((a, b) => a.order - b.order).at(-1)?.branch;
104102
expect(lastBranch).toBeDefined();
105103

106104
const diff = await repo.git.diff([`${lastBranch}..${plan.sourceBranch}`]);

tests/fixtures/plans/demo-golden-plan.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,4 +166,4 @@
166166
}
167167
]
168168
}
169-
}
169+
}

tests/unit/display.test.ts

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { describe, expect, it } from "vitest";
2-
import type { StackPlan } from "../../src/types/index.js";
32
import type { PrResult } from "../../src/github/pr-manager.js";
3+
import type { StackPlan } from "../../src/types/index.js";
44
import {
55
type BranchDiffStat,
66
formatBeforeAfter,
@@ -17,9 +17,27 @@ function makePlan(): StackPlan {
1717
baseBranch: "main",
1818
sourceBranch: "feat/user-api",
1919
slices: [
20-
{ order: 1, title: "Add types", rationale: "Foundation", branch: "stack/01-types", confidence: 0.95 },
21-
{ order: 2, title: "Add service", rationale: "Core logic", branch: "stack/02-service", confidence: 0.9 },
22-
{ order: 3, title: "Add routes", rationale: "HTTP layer", branch: "stack/03-routes", confidence: 0.85 },
20+
{
21+
order: 1,
22+
title: "Add types",
23+
rationale: "Foundation",
24+
branch: "stack/01-types",
25+
confidence: 0.95,
26+
},
27+
{
28+
order: 2,
29+
title: "Add service",
30+
rationale: "Core logic",
31+
branch: "stack/02-service",
32+
confidence: 0.9,
33+
},
34+
{
35+
order: 3,
36+
title: "Add routes",
37+
rationale: "HTTP layer",
38+
branch: "stack/03-routes",
39+
confidence: 0.85,
40+
},
2341
],
2442
fileAssignments: [
2543
{ path: "src/types/user.ts", splitStrategy: "whole", targetSlice: 1 },
@@ -67,8 +85,18 @@ function makePlanWithDissect(): StackPlan {
6785
path: "src/app.ts",
6886
splitStrategy: "dissect",
6987
sliceContents: [
70-
{ slice: 1, content: "import express from 'express';\nconst app = express();\nexport default app;\n", description: "Base app" },
71-
{ slice: 2, content: "import express from 'express';\nimport { userRouter } from './routes/users.js';\nconst app = express();\napp.use('/users', userRouter);\nexport default app;\n", description: "Wire routes" },
88+
{
89+
slice: 1,
90+
content:
91+
"import express from 'express';\nconst app = express();\nexport default app;\n",
92+
description: "Base app",
93+
},
94+
{
95+
slice: 2,
96+
content:
97+
"import express from 'express';\nimport { userRouter } from './routes/users.js';\nconst app = express();\napp.use('/users', userRouter);\nexport default app;\n",
98+
description: "Wire routes",
99+
},
72100
],
73101
},
74102
],

0 commit comments

Comments
 (0)