-
Notifications
You must be signed in to change notification settings - Fork 3.5k
Add bun feedback command for user feedback submission
#22684
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,173 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Output banner immediately before any requires | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.error("\nbun feedback - Send feedback to the Bun team\n"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const { readFileSync, existsSync, writeFileSync, fstatSync } = require("fs"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const { join } = require("path"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const VERSION = process.versions.bun || "unknown"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const OS = process.platform; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const ARCH = process.arch; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Check if stdin is readable (not /dev/null or closed) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| function isStdinReadable() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Get file descriptor 0 (stdin) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const stats = fstatSync(0); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Check if it's a regular file and has size 0 (like /dev/null) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // or if it's not a character device/pipe/socket | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (stats.isFile() && stats.size === 0) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return false; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return true; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return false; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| async function getEmail() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const bunInstall = process.env.BUN_INSTALL; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Check for saved email | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (bunInstall) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const feedbackPath = join(bunInstall, "feedback"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (existsSync(feedbackPath)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const savedEmail = readFileSync(feedbackPath, "utf8").trim(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (savedEmail) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return savedEmail; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Try to get email from git config | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let defaultEmail = ""; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const result = Bun.spawnSync(["git", "config", "user.email"], { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| stdout: "pipe", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| stderr: "ignore", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (result.exitCode === 0 && result.stdout) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| defaultEmail = result.stdout.toString().trim(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch {} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // If stdin is not readable (e.g., /dev/null), return default or empty | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!isStdinReadable()) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return defaultEmail || ""; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Prompt for email | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| process.stderr.write(`? Email address${defaultEmail ? ` (${defaultEmail})` : ""}: `); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const decoder = new TextDecoder(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for await (const chunk of Bun.stdin.stream()) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const line = decoder.decode(chunk).trim(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const email = line || defaultEmail; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Save email if BUN_INSTALL is set | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (bunInstall && email) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const feedbackPath = join(bunInstall, "feedback"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| writeFileSync(feedbackPath, email); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch {} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return email; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return defaultEmail; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| async function getBody() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Get args from process.argv | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // process.argv[0] = bun executable, process.argv[1+] = actual args | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const args = process.argv.slice(1); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+83
to
+84
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💡 Verification agent 🧩 Analysis chainIncorrect argv slicing for embedded eval scripts When running as an embedded eval script, Apply this diff to correctly handle arguments: // Get args from process.argv
- // process.argv[0] = bun executable, process.argv[1+] = actual args
- const args = process.argv.slice(1);
+ // When running as eval: process.argv[0] = bun executable, process.argv[1] = "feedback", process.argv[2+] = user args
+ const args = process.argv.slice(2);Let me verify how process.argv works for eval scripts in Bun: 🏁 Script executed: #!/bin/bash
# Search for how other eval scripts handle process.argv
rg -n "process\.argv.*slice" src/js/eval/ --type=tsLength of output: 64 🏁 Script executed: #!/bin/bash
# Look for documentation or tests about eval script argv handling
rg -n "eval.*process\.argv|argv.*eval" test/ --type=ts --type=jsLength of output: 683 Incorrect argv slicing for embedded eval scripts — use slice(2) When running as an embedded eval, process.argv[0]=bun and process.argv[1]="feedback", so user arguments start at process.argv[2]; slice(1) wrongly includes "feedback". Change to slice(2). File: src/js/eval/feedback.ts (around lines 83–84) // Get args from process.argv
- // process.argv[0] = bun executable, process.argv[1+] = actual args
- const args = process.argv.slice(1);
+ // When running as eval: process.argv[0] = bun executable, process.argv[1] = "feedback", process.argv[2+] = user args
+ const args = process.argv.slice(2);📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // If we have positional arguments, use them | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (args.length > 0) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return args.join(" "); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Check if stdin is readable | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!isStdinReadable()) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return ""; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // If stdin is not a TTY, read from pipe | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!process.stdin.isTTY) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const chunks = []; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for await (const chunk of Bun.stdin.stream()) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| chunks.push(chunk); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const buffer = Buffer.concat(chunks); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return buffer.toString("utf8").trim(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Otherwise prompt for message | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| process.stderr.write("? Feedback message (Press Enter to submit): "); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const decoder = new TextDecoder(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for await (const chunk of Bun.stdin.stream()) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return decoder.decode(chunk).trim(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return ""; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| async function sendFeedback(email, body) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const url = process.env.BUN_FEEDBACK_URL || "https://bun.com/api/v1/feedback"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const payload = JSON.stringify({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| os: OS, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| cpu: ARCH, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| version: VERSION, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| body, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| email, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Show progress | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| process.stderr.write("Sending feedback..."); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const response = await fetch(url, { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| method: "POST", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| headers: { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "Content-Type": "application/json", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| body: payload, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| process.stderr.write("\r\x1b[K"); // Clear the line | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+128
to
+139
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Add timeout and better error handling for network requests The fetch request lacks a timeout, which could cause the command to hang indefinitely on network issues. Also, the error clearing could leave artifacts on some terminals. Apply this diff to add timeout and improve error handling: // Show progress
process.stderr.write("Sending feedback...");
try {
+ const controller = new AbortController();
+ const timeoutId = setTimeout(() => controller.abort(), 30000); // 30 second timeout
+
const response = await fetch(url, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: payload,
+ signal: controller.signal,
});
+
+ clearTimeout(timeoutId);
process.stderr.write("\r\x1b[K"); // Clear the lineAlso, consider handling specific error cases: } catch (error) {
process.stderr.write("\r\x1b[K"); // Clear the line
- console.error(`\nerror: Failed to send feedback: ${error?.message || error}\n`);
+ const errorMessage = error?.name === 'AbortError'
+ ? 'Request timed out'
+ : error?.message || String(error);
+ console.error(`\nerror: Failed to send feedback: ${errorMessage}\n`);
process.exit(1);
}📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (response.ok) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.error("\n✓ Thank you for your feedback!\n"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.error(`\nerror: Failed to send feedback (status code: ${response.status})\n`); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| process.exit(1); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (error) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| process.stderr.write("\r\x1b[K"); // Clear the line | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.error(`\nerror: Failed to send feedback: ${error?.message || error}\n`); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| process.exit(1); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| (async () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Get email | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const email = await getEmail(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Get feedback body | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const body = await getBody(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!body) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.error("error: No feedback message provided"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| process.exit(1); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Send feedback | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await sendFeedback(email, body); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (err) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.error("error: Unexpected error in feedback command:", err); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| process.exit(1); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| })(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Fix: Incorrect file descriptor stats check on Windows
The logic for checking if stdin is
/dev/nullwon't work correctly on Windows. Whenstats.isFile()returns true withsize === 0, this could match legitimate empty files, not just/dev/null. Additionally, on Windows,/dev/nulldoesn't exist - it'sNULinstead.Apply this diff to handle both Unix and Windows correctly:
function isStdinReadable() { try { // Get file descriptor 0 (stdin) const stats = fstatSync(0); - // Check if it's a regular file and has size 0 (like /dev/null) - // or if it's not a character device/pipe/socket - if (stats.isFile() && stats.size === 0) { + // On Unix: /dev/null is a character device with specific properties + // On Windows: NUL doesn't have a file descriptor, so this will throw + if (process.platform === "win32") { + // Windows doesn't have /dev/null, it has NUL + // This check will be handled by the catch block + return true; + } + // Check if it's a regular file with size 0 or if it's the null device + if (stats.isCharacterDevice() && stats.rdev === 259) { // Unix /dev/null return false; } + if (stats.isFile() && stats.size === 0 && stats.dev === 0) { + return false; + } return true; } catch { return false; } }Let me verify if this is the correct approach for detecting
/dev/nullacross platforms:🏁 Script executed:
Length of output: 421
🏁 Script executed:
Length of output: 6831
Fix: robust cross‑platform stdin (/dev/null) detection
Do not use
stats.isFile() && stats.size === 0or an unconditionalprocess.platform === "win32"early-return — that misidentifies empty files as/dev/nulland the proposed Windows shortcut is incorrect. Replace with platform‑agnostic checks:stats.isFIFO()orstats.isSocket()→ stdin is piped/readable (return true).stats.isCharacterDevice()→ return!!process.stdin?.isTTY(tty = interactive/readable; non‑tty char device is likely/dev/null).stats.isFile()→ handle empty‑file semantics explicitly (empty file != automatically treat as/dev/null; usestats.size > 0only if you require non‑empty input).Location: src/js/eval/feedback.ts (around the
fstatSync(0)check). Note: the repo already maps devNull for Windows in src/js/os.ts — don’t short‑circuitwin32totrue.🤖 Prompt for AI Agents