feat(cli): image pasting support via Ctrl+V and /paste command#2823
feat(cli): image pasting support via Ctrl+V and /paste command#2823Stranmor wants to merge 12 commits intoantinomyhq:mainfrom
Conversation
| let line = if (line.starts_with('"') && line.ends_with('"')) | ||
| || (line.starts_with('\'') && line.ends_with('\'')) | ||
| { | ||
| &line[1..line.len() - 1] | ||
| } else { | ||
| line | ||
| }; |
There was a problem hiding this comment.
Slice indexing panic when line is a single quote character
If the clipboard contains a single " or ' character, this code will panic at runtime with an index out of bounds error.
When line = "\"" (length 1):
line.starts_with('"')returnstrueline.ends_with('"')returnstrue&line[1..line.len() - 1]becomes&line[1..0], which is an invalid slice range
Fix:
let line = if line.len() >= 2 && ((line.starts_with('"') && line.ends_with('"'))
|| (line.starts_with('\'') && line.ends_with('\'')))
{
&line[1..line.len() - 1]
} else {
line
};| let line = if (line.starts_with('"') && line.ends_with('"')) | |
| || (line.starts_with('\'') && line.ends_with('\'')) | |
| { | |
| &line[1..line.len() - 1] | |
| } else { | |
| line | |
| }; | |
| let line = if line.len() >= 2 && ((line.starts_with('"') && line.ends_with('"')) | |
| || (line.starts_with('\'') && line.ends_with('\''))) | |
| { | |
| &line[1..line.len() - 1] | |
| } else { | |
| line | |
| }; | |
Spotted by Graphite
Is this helpful? React 👍 or 👎 to let us know.
| if let Ok(mut f) = std::fs::OpenOptions::new() | ||
| .create(true) | ||
| .append(true) | ||
| .open("/tmp/forge_paste.log") | ||
| { | ||
| let _ = writeln!(&mut f, "Received !forge_internal_paste_image"); | ||
| use std::io::Write; | ||
| } |
There was a problem hiding this comment.
Debug logging code was left in production. This will create and append to /tmp/forge_paste.log on every Ctrl+V press, causing unnecessary disk I/O and potential disk space issues over time.
// Remove this debug code block entirely:
if let Ok(mut f) = std::fs::OpenOptions::new()
.create(true)
.append(true)
.open("/tmp/forge_paste.log")
{
let _ = writeln!(&mut f, "Received !forge_internal_paste_image");
use std::io::Write;
}Spotted by Graphite
Is this helpful? React 👍 or 👎 to let us know.
| use url::Url; | ||
|
|
||
| fn get_images_dir() -> Option<PathBuf> { | ||
| let home_dir = std::env::var("HOME").unwrap_or_else(|_| "/tmp".to_string()); |
There was a problem hiding this comment.
Cross-platform compatibility issue. Using HOME environment variable with /tmp fallback will fail on Windows where neither exists. The path /tmp doesn't exist on Windows and would cause directory creation to fail, breaking the paste functionality.
// Use platform-appropriate directories:
let home_dir = if cfg!(windows) {
std::env::var("USERPROFILE").unwrap_or_else(|_| std::env::var("TEMP").unwrap_or_else(|_| "C:\\Temp".to_string()))
} else {
std::env::var("HOME").unwrap_or_else(|_| "/tmp".to_string())
};| let home_dir = std::env::var("HOME").unwrap_or_else(|_| "/tmp".to_string()); | |
| let home_dir = if cfg!(windows) { | |
| std::env::var("USERPROFILE").unwrap_or_else(|_| { | |
| std::env::var("TEMP").unwrap_or_else(|_| "C:\\Temp".to_string()) | |
| }) | |
| } else { | |
| std::env::var("HOME").unwrap_or_else(|_| "/tmp".to_string()) | |
| }; |
Spotted by Graphite
Is this helpful? React 👍 or 👎 to let us know.
| async fn get_custom_instructions(&self) -> Vec<String> { | ||
| let paths = self.cache.get_or_init(|| self.discover_agents_files()).await; | ||
|
|
||
| let mut custom_instructions = Vec::new(); | ||
|
|
||
| for path in paths { | ||
| if let Ok(content) = self.infra.read_utf8(&path).await { | ||
| if let Ok(content) = self.infra.read_utf8(path).await { | ||
| custom_instructions.push(content); | ||
| } | ||
| } |
There was a problem hiding this comment.
The cache behavior has changed from caching file contents to only caching file paths. This means files are re-read from disk on every get_custom_instructions() call instead of being cached in memory. While this may be intentional to pick up file changes, it significantly reduces cache effectiveness and introduces repeated file I/O.
If the old caching behavior is desired, the cache type should remain Vec<String> and cache the actual content:
cache: tokio::sync::OnceCell<Vec<String>>,
async fn init(&self) -> Vec<String> {
let paths = self.discover_agents_files().await;
let mut custom_instructions = Vec::new();
for path in paths {
if let Ok(content) = self.infra.read_utf8(&path).await {
custom_instructions.push(content);
}
}
custom_instructions
}
async fn get_custom_instructions(&self) -> Vec<String> {
self.cache.get_or_init(|| self.init()).await.clone()
}| async fn get_custom_instructions(&self) -> Vec<String> { | |
| let paths = self.cache.get_or_init(|| self.discover_agents_files()).await; | |
| let mut custom_instructions = Vec::new(); | |
| for path in paths { | |
| if let Ok(content) = self.infra.read_utf8(&path).await { | |
| if let Ok(content) = self.infra.read_utf8(path).await { | |
| custom_instructions.push(content); | |
| } | |
| } | |
| async fn get_custom_instructions(&self) -> Vec<String> { | |
| self.cache.get_or_init(|| async { | |
| let paths = self.discover_agents_files().await; | |
| let mut custom_instructions = Vec::new(); | |
| for path in paths { | |
| if let Ok(content) = self.infra.read_utf8(&path).await { | |
| custom_instructions.push(content); | |
| } | |
| } | |
| custom_instructions | |
| }).await.clone() | |
| } | |
Spotted by Graphite
Is this helpful? React 👍 or 👎 to let us know.
…ssion in Renderer
… instead of dropping it
e6a47dd to
1a5ffa5
Compare
…g, cross-platform paths Co-Authored-By: ForgeCode <noreply@forgecode.dev>
1a5ffa5 to
67d9323
Compare
Closes #2811
This PR adds support for inserting images directly into the chat prompt from the clipboard.
Features
Ctrl+Vin the prompt to read an image from the clipboard./pasteslash command as an alternative way to paste images.~/.local/share/forge/imagesand inserted as@[/path/to/image.png].wl-paste,xclip) for accurate pixel extraction.arboardif native tools aren't present.file://...) or absolute paths if the user copied image files directly from a file manager.