Skip to content

Commit 9e23bce

Browse files
authored
chore: add biome.json + apply formatter flag-day (#25)
Caught during the eval.ts retirement PR: this repo has no formatter config, so running biome with defaults reformats files spaces→tabs. The eval-retire PR had to revert biome's default reformat to avoid shipping a 700-line stylistic blast. Adding a biome.json that matches the existing 2-space / double-quote / semicolon / trailing-comma convention, plus a one-shot `biome format --write` of the codebase so future biome runs are no-ops. Linter is disabled in the config (recommended ruleset finds ~63 errors in existing code — that's a separate cleanup decision). After this PR: - `npx @biomejs/biome format .` returns "No fixes applied" - `npm run build` clean, all 115 tests still pass - Any contributor running biome will get the same style without reformat conflicts Style choices locked in: - indent: 2 spaces (matches all existing files) - line width: 80 - quotes: double, semicolons: always - trailing commas: all - arrow parens: always
1 parent e86cd34 commit 9e23bce

32 files changed

Lines changed: 1056 additions & 788 deletions

biome.json

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
{
2+
"$schema": "https://biomejs.dev/schemas/2.4.15/schema.json",
3+
"formatter": {
4+
"enabled": true,
5+
"indentStyle": "space",
6+
"indentWidth": 2,
7+
"lineWidth": 80
8+
},
9+
"javascript": {
10+
"formatter": {
11+
"quoteStyle": "double",
12+
"semicolons": "always",
13+
"trailingCommas": "all",
14+
"arrowParentheses": "always"
15+
}
16+
},
17+
"linter": {
18+
"enabled": false
19+
},
20+
"files": {
21+
"includes": [
22+
"src/**/*.ts",
23+
"tests/**/*.ts",
24+
"*.json",
25+
"!node_modules/**",
26+
"!resources/**",
27+
"!.vapi-state.*.json",
28+
"!.vapi-state.*.snapshots/**",
29+
"!package-lock.json"
30+
]
31+
}
32+
}

src/api.ts

Lines changed: 37 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,11 @@ import type { VapiResponse } from "./types.ts";
1414

1515
const DRY_RUN_COUNTS = { POST: 0, PATCH: 0, DELETE: 0 };
1616

17-
export function getDryRunCounts(): { POST: number; PATCH: number; DELETE: number } {
17+
export function getDryRunCounts(): {
18+
POST: number;
19+
PATCH: number;
20+
DELETE: number;
21+
} {
1822
return { ...DRY_RUN_COUNTS };
1923
}
2024

@@ -54,7 +58,9 @@ function parseApiMessage(body: string): string {
5458
const parsed = JSON.parse(body);
5559
if (typeof parsed.message === "string") return parsed.message;
5660
if (Array.isArray(parsed.message)) return parsed.message.join("; ");
57-
} catch { /* not JSON, use raw body */ }
61+
} catch {
62+
/* not JSON, use raw body */
63+
}
5864
return body;
5965
}
6066

@@ -87,7 +93,7 @@ function shouldRetry(status: number): boolean {
8793
export async function vapiRequest<T = VapiResponse>(
8894
method: "POST" | "PATCH",
8995
endpoint: string,
90-
body: Record<string, unknown>
96+
body: Record<string, unknown>,
9197
): Promise<T> {
9298
const url = `${VAPI_BASE_URL}${endpoint}`;
9399

@@ -122,14 +128,25 @@ export async function vapiRequest<T = VapiResponse>(
122128

123129
if (shouldRetry(response.status) && attempt < MAX_RETRIES) {
124130
const delay = INITIAL_DELAY_MS * Math.pow(2, attempt);
125-
const reason = response.status === 429 ? "Rate limited" : `Server error ${response.status}`;
126-
console.log(` ⏳ ${reason}, retrying in ${delay / 1000}s (attempt ${attempt + 1}/${MAX_RETRIES})...`);
131+
const reason =
132+
response.status === 429
133+
? "Rate limited"
134+
: `Server error ${response.status}`;
135+
console.log(
136+
` ⏳ ${reason}, retrying in ${delay / 1000}s (attempt ${attempt + 1}/${MAX_RETRIES})...`,
137+
);
127138
await sleep(delay);
128139
continue;
129140
}
130141

131142
const errorText = await response.text();
132-
throw new VapiApiError(method, endpoint, response.status, parseApiMessage(errorText), errorText);
143+
throw new VapiApiError(
144+
method,
145+
endpoint,
146+
response.status,
147+
parseApiMessage(errorText),
148+
errorText,
149+
);
133150
}
134151

135152
throw new VapiApiError(method, endpoint, 429, "max retries exceeded", "");
@@ -159,16 +176,26 @@ export async function vapiDelete(endpoint: string): Promise<void> {
159176

160177
if (shouldRetry(response.status) && attempt < MAX_RETRIES) {
161178
const delay = INITIAL_DELAY_MS * Math.pow(2, attempt);
162-
const reason = response.status === 429 ? "Rate limited" : `Server error ${response.status}`;
163-
console.log(` ⏳ ${reason}, retrying in ${delay / 1000}s (attempt ${attempt + 1}/${MAX_RETRIES})...`);
179+
const reason =
180+
response.status === 429
181+
? "Rate limited"
182+
: `Server error ${response.status}`;
183+
console.log(
184+
` ⏳ ${reason}, retrying in ${delay / 1000}s (attempt ${attempt + 1}/${MAX_RETRIES})...`,
185+
);
164186
await sleep(delay);
165187
continue;
166188
}
167189

168190
const errorText = await response.text();
169-
throw new VapiApiError("DELETE", endpoint, response.status, parseApiMessage(errorText), errorText);
191+
throw new VapiApiError(
192+
"DELETE",
193+
endpoint,
194+
response.status,
195+
parseApiMessage(errorText),
196+
errorText,
197+
);
170198
}
171199

172200
throw new VapiApiError("DELETE", endpoint, 429, "max retries exceeded", "");
173201
}
174-

src/apply.ts

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ export async function runApply(): Promise<void> {
2929
const allArgs = process.argv.slice(3);
3030
const hasForce = allArgs.includes("--force");
3131

32-
const pullArgs = allArgs.filter(a => a !== "--force").join(" ");
32+
const pullArgs = allArgs.filter((a) => a !== "--force").join(" ");
3333
const pushArgs = allArgs.join(" ");
3434

3535
if (!env || !SLUG_RE.test(env)) {
@@ -40,18 +40,24 @@ export async function runApply(): Promise<void> {
4040
console.error(" Pulls latest platform state (preserving local changes),");
4141
console.error(" then pushes the result back to the platform.");
4242
console.error("");
43-
console.error(" --force Enable deletions: resources you deleted locally");
43+
console.error(
44+
" --force Enable deletions: resources you deleted locally",
45+
);
4446
console.error(" will also be deleted from the platform.");
4547
process.exit(1);
4648
}
4749

48-
console.log("═══════════════════════════════════════════════════════════════");
50+
console.log(
51+
"═══════════════════════════════════════════════════════════════",
52+
);
4953
console.log(`🔄 Vapi GitOps Apply - Environment: ${env}`);
5054
console.log(" Pull → Merge → Push");
5155
if (hasForce) {
5256
console.log(" ⚠️ Deletions enabled (--force)");
5357
}
54-
console.log("═══════════════════════════════════════════════════════════════\n");
58+
console.log(
59+
"═══════════════════════════════════════════════════════════════\n",
60+
);
5561

5662
const pullCmd = `npx tsx src/pull.ts ${env} ${pullArgs}`.trim();
5763
const pullExit = runPassthrough(pullCmd);
@@ -68,9 +74,13 @@ export async function runApply(): Promise<void> {
6874
process.exit(1);
6975
}
7076

71-
console.log("\n═══════════════════════════════════════════════════════════════");
77+
console.log(
78+
"\n═══════════════════════════════════════════════════════════════",
79+
);
7280
console.log("✅ Apply complete! (Pull → Merge → Push)");
73-
console.log("═══════════════════════════════════════════════════════════════\n");
81+
console.log(
82+
"═══════════════════════════════════════════════════════════════\n",
83+
);
7484
}
7585

7686
// Run when executed directly

src/call.ts

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -207,9 +207,7 @@ async function checkMicrophonePermission(): Promise<boolean> {
207207
console.log(
208208
" If prompted, please grant microphone permission in System Settings.",
209209
);
210-
console.log(
211-
" System Settings > Privacy & Security > Microphone\n",
212-
);
210+
console.log(" System Settings > Privacy & Security > Microphone\n");
213211

214212
// Ask user to continue anyway
215213
const shouldContinue = await askUserConfirmation(
@@ -832,7 +830,9 @@ function handleControlMessage(
832830
"assistant-request-returned-error": "Assistant request error",
833831
"assistant-not-found": "Assistant not found",
834832
};
835-
const label = cm.reason ? (reasonLabels[cm.reason] ?? cm.reason) : "unknown reason";
833+
const label = cm.reason
834+
? (reasonLabels[cm.reason] ?? cm.reason)
835+
: "unknown reason";
836836
clearWrittenLine(process.stdout, state.lastTranscript);
837837
state.lastTranscript = "";
838838
console.log(`📞 Call ended: ${label}`);
@@ -908,7 +908,10 @@ function handleControlMessage(
908908
}
909909
case "transfer-update": {
910910
const tm = message as TransferUpdateMessage;
911-
printEvent(state, `🔀 Transfer${formatTransferDestination(tm.destination)}`);
911+
printEvent(
912+
state,
913+
`🔀 Transfer${formatTransferDestination(tm.destination)}`,
914+
);
912915
break;
913916
}
914917
default:
@@ -980,10 +983,17 @@ function createAudioContext(): {
980983
} catch (error) {
981984
const msg = error instanceof Error ? error.message : String(error);
982985
if (msg.includes("Cannot find module")) {
983-
console.warn("⚠️ 'speaker' module not installed. Audio playback disabled.");
986+
console.warn(
987+
"⚠️ 'speaker' module not installed. Audio playback disabled.",
988+
);
984989
console.warn(" Install with: npm install speaker");
985-
} else if (msg.includes("Could not locate the bindings file") || msg.includes("NODE_MODULE_VERSION")) {
986-
console.warn("⚠️ 'speaker' native bindings not built for this Node version.");
990+
} else if (
991+
msg.includes("Could not locate the bindings file") ||
992+
msg.includes("NODE_MODULE_VERSION")
993+
) {
994+
console.warn(
995+
"⚠️ 'speaker' native bindings not built for this Node version.",
996+
);
987997
console.warn(" Rebuild with: npm rebuild speaker");
988998
} else {
989999
console.warn(`⚠️ Could not initialize speaker: ${msg}`);
@@ -1040,7 +1050,9 @@ function createMicrophoneStream(onData: (data: Buffer) => void): {
10401050
console.warn(" Install with: npm install mic");
10411051
} else if (msg.includes("sox") || msg.includes("rec")) {
10421052
console.warn("⚠️ sox/rec not found. Required for microphone input.");
1043-
console.warn(" Install with: brew install sox (macOS) or apt install sox (Linux)");
1053+
console.warn(
1054+
" Install with: brew install sox (macOS) or apt install sox (Linux)",
1055+
);
10441056
} else {
10451057
console.warn(`⚠️ Could not initialize microphone: ${msg}`);
10461058
}

src/config.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -346,7 +346,10 @@ export function loadIgnorePatterns(): string[] {
346346
cachedIgnorePatterns = raw
347347
.split("\n")
348348
.map((line) => line.trim())
349-
.filter((line) => line.length > 0 && !line.startsWith("#") && !line.startsWith("!"));
349+
.filter(
350+
(line) =>
351+
line.length > 0 && !line.startsWith("#") && !line.startsWith("!"),
352+
);
350353

351354
return cachedIgnorePatterns;
352355
}

0 commit comments

Comments
 (0)