Fix Windows PowerShell version replacement

- Fix PowerShell variable substitution in Windows builds
- Use proper escaping for PowerShell string replacement
- Ensures version is correctly set in Cargo.toml on Windows
This commit is contained in:
James Peter
2025-08-14 19:53:59 +10:00
parent 7c3c15df1c
commit 5d50fff3c1
18 changed files with 15 additions and 780 deletions
+7 -4
View File
@@ -118,8 +118,13 @@ jobs:
# Update the workspace version in root Cargo.toml
cd codex-rs
if [[ "${{ matrix.os }}" == "windows-latest" ]]; then
# Windows doesn't have sed -i, use a different approach
powershell -Command "(Get-Content Cargo.toml) -replace '^version = \".*\"', 'version = \"$env:VERSION\"' | Set-Content Cargo.toml"
# Windows: Use PowerShell with proper variable substitution
powershell -Command "
\$version = '${VERSION}'
\$content = Get-Content Cargo.toml
\$content = \$content -replace '^version = \".*\"', \"version = \`\"\$version\`\"\"
Set-Content -Path Cargo.toml -Value \$content
"
else
# Unix-like systems
sed -i.bak "s/^version = \".*\"/version = \"${VERSION}\"/" Cargo.toml
@@ -132,8 +137,6 @@ jobs:
# Update Cargo.lock to reflect the new version
cargo update --workspace
shell: bash
env:
VERSION: ${{ needs.determine-version.outputs.version }}
- name: Build binaries
run: |
-115
View File
@@ -1,115 +0,0 @@
# Setting up "code" - A Fork of OpenAI Codex
## Overview
This document outlines the changes needed to rebrand and publish this fork of OpenAI Codex as "code" under the @just-every npm scope.
## Required Changes
### 1. Binary Renaming
- [ ] Rename binary from `codex` to `code` in:
- `codex-rs/cli/Cargo.toml` - Change `[[bin]] name = "codex"` to `name = "code"`
- `codex-rs/tui/Cargo.toml` - Change binary name to `code-tui`
- `codex-rs/exec/Cargo.toml` - Change binary name to `code-exec`
### 2. Package Configuration
- [ ] Update `codex-cli/package.json`:
- Change name from `@openai/codex` to `@just-every/code`
- Update repository URL to `https://github.com/just-every/code.git`
- Update bin field from `"codex": "bin/codex.js"` to `"code": "bin/code.js"`
- Set initial version (e.g., "0.1.0")
- [ ] Rename `codex-cli/bin/codex.js` to `codex-cli/bin/code.js`
- [ ] Update the shebang and binary detection logic in `code.js`
### 3. GitHub Actions Updates
- [ ] Modify `.github/workflows/rust-release.yml`:
- Update artifact names from `codex-*` to `code-*`
- Change npm package staging to use new name
- Add npm publish step after GitHub release
- [ ] Create `.github/workflows/npm-publish.yml` for automated npm publishing:
```yaml
name: Publish to npm
on:
release:
types: [published]
jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
registry-url: 'https://registry.npmjs.org'
- name: Download release assets
# Download the npm package from release
- name: Publish to npm
run: npm publish
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
```
### 4. Rust Code Updates
- [ ] Update all references to "codex" in:
- Error messages
- Help text
- Documentation strings
- Environment variables (e.g., `CODEX_HOME` → `CODE_HOME`)
### 5. Configuration Updates
- [ ] Update config paths from `~/.codex/` to `~/.code/`
- [ ] Update environment variable names
- [ ] Update default config values
### 6. Build Scripts
- [ ] Update build scripts to produce `code` binaries
- [ ] Update install scripts to use new binary names
- [ ] Update the staging script at `codex-cli/scripts/stage_rust_release.py`
### 7. Documentation
- [ ] Update README.md with new project name and installation instructions
- [ ] Update all documentation to reference `code` instead of `codex`
- [ ] Add attribution to original OpenAI Codex project
## GitHub Secrets Required
Add these secrets to your GitHub repository:
- `NPM_TOKEN`: Your npm authentication token for publishing
## Release Process
1. Update version in `codex-rs/Cargo.toml`
2. Update version in `codex-cli/package.json`
3. Commit changes
4. Create and push a tag: `git tag -a v0.1.0 -m "Release 0.1.0"`
5. Push tag: `git push origin v0.1.0`
6. GitHub Actions will automatically:
- Build binaries for all platforms
- Create GitHub release
- Publish to npm
## Testing Locally
```bash
# Build the Rust binaries
cd codex-rs
cargo build --release --bin code
# Test the CLI
./target/release/coder --version
# Test npm package locally
cd ../codex-cli
npm link
coder --version
```
## npm Publishing Setup
1. Create npm account if needed
2. Create organization @just-every on npm
3. Generate npm access token (automation type)
4. Add token as GitHub secret NPM_TOKEN
## Maintaining the Fork
- Regularly sync with upstream OpenAI Codex for bug fixes
- Keep a clear changelog of fork-specific features
- Maintain compatibility where possible
-57
View File
@@ -1,57 +0,0 @@
# IIFE JavaScript Execution Fix Summary
## Problem Identified
The Rust backend's `execute_javascript` method in `/codex-rs/browser/src/page.rs` had three issues:
1. **IIFE Return Value Handling**: The code incorrectly analyzed Immediately Invoked Function Expressions (IIFEs) and mistook return statements inside the IIFE for top-level returns, causing it to discard the actual result.
2. **Navigation Issue (Viewport Sensitivity)**: The visibility check required elements to be within the viewport, which could fail if the backend browser had different viewport dimensions.
3. **Formatting Issues**: Non-breaking spaces in the original code could cause parsing errors.
## Solution Implemented
### 1. IIFE Detection and Handling (page.rs lines 461-526)
- Added IIFE detection logic that checks if code starts with `(`, `(async`, or `(function`
- Tracks parenthesis depth to identify IIFE patterns
- Added brace depth tracking to distinguish between top-level and nested return statements
- When an IIFE is detected, the code is passed through as-is without modification
### 2. Return Statement Analysis (page.rs lines 488-526)
- Enhanced the return statement detection to only consider top-level returns
- Ignores return statements inside IIFEs since they handle their own returns
- Maintains backward compatibility for non-IIFE code
### 3. Body Building Logic (page.rs lines 528-565)
- Modified to handle three cases:
- IIFE: Pass through unchanged
- Explicit top-level return: Pass through unchanged
- Expression/variable: Auto-add return statement
## JavaScript Code Fixes (stripe_click_fixed.js)
### 1. Removed IIFE Wrapper
- Eliminated the `(() => { ... })()` wrapper since the backend already wraps code in an AsyncFunction
- This prevents the return value handling issue
### 2. Relaxed Visibility Check
- `isVisible` function no longer requires viewport position during initial search
- Only checks element dimensions and CSS visibility
- Makes the search resilient to different viewport sizes
### 3. Added Robustness
- Explicit `scrollIntoView` to center the element
- Added 300ms wait after scrolling for page settling
- Final viewport validation before clicking
- Clean formatting with standard spaces
## Files Modified
- `/codex-rs/browser/src/page.rs` - Fixed IIFE handling in `execute_javascript` method
- Created `stripe_click_fixed.js` - Cleaned and fixed JavaScript code
## Testing
The fix ensures that:
1. IIFE patterns return their values correctly
2. Normal code without IIFE continues to work
3. Top-level return statements are handled properly
4. The JavaScript execution captures the intended return values
+8 -3
View File
@@ -804,9 +804,14 @@ impl Page {
// (UPDATED) Inject cursor before taking screenshot
pub async fn screenshot(&self, mode: ScreenshotMode) -> Result<Vec<Screenshot>> {
// First, check and fix viewport scaling if needed
if let Err(e) = self.check_and_fix_scaling().await {
warn!("Failed to check/fix viewport scaling: {}, continuing anyway", e);
// Check if this is an external Chrome connection
let is_external = self.config.connect_port.is_some() || self.config.connect_ws.is_some();
// First, check and fix viewport scaling if needed (skip for external Chrome)
if !is_external {
if let Err(e) = self.check_and_fix_scaling().await {
warn!("Failed to check/fix viewport scaling: {}, continuing anyway", e);
}
}
// Inject the virtual cursor before capturing
-41
View File
@@ -1,41 +0,0 @@
#!/bin/bash
echo "Scanning for Chrome instances with debug ports..."
echo "================================================"
# Find all Chrome processes with remote-debugging-port
ports=$(ps aux | grep -E "chrome.*remote-debugging-port" | grep -v "port=0" | grep -v grep | sed -n 's/.*--remote-debugging-port=\([0-9]*\).*/\1/p' | sort -u)
if [ -z "$ports" ]; then
echo "No Chrome instances found with debug ports enabled."
exit 1
fi
for port in $ports; do
echo ""
echo "Found Chrome on port: $port"
echo "----------------------------"
# Try to get Chrome info via DevTools protocol
response=$(curl -s http://127.0.0.1:$port/json/version 2>/dev/null)
if [ $? -eq 0 ] && [ ! -z "$response" ]; then
echo "✓ Port is accessible"
browser=$(echo "$response" | grep -o '"Browser":"[^"]*"' | cut -d'"' -f4)
ws_url=$(echo "$response" | grep -o '"webSocketDebuggerUrl":"[^"]*"' | cut -d'"' -f4)
[ ! -z "$browser" ] && echo " Browser: $browser"
[ ! -z "$ws_url" ] && echo " WebSocket: $ws_url"
echo ""
echo "To connect in codex, use: /browser chrome $port"
echo " or: /chrome $port"
else
echo "✗ Port is not accessible (Chrome might be restricted)"
fi
done
echo ""
echo "================================================"
echo "Tip: To launch Chrome with a debug port manually:"
echo "/Applications/Google\\ Chrome.app/Contents/MacOS/Google\\ Chrome --remote-debugging-port=9222"
-99
View File
@@ -1,99 +0,0 @@
// Fixed code for clicking Stripe anchor - no IIFE wrapper
// 1. Define helper functions at the top level.
/**
* Checks if an element is rendered (has dimensions and is not hidden by CSS).
* We intentionally ignore its position relative to the viewport during the search.
*/
function isVisible(el) {
const r = el.getBoundingClientRect();
const s = getComputedStyle(el);
return r.width > 5 && r.height > 5 && s.display !== 'none' && s.visibility !== 'hidden';
}
/**
* Locates the most likely anchor element corresponding to "Stripe".
*/
function findStripeAnchor() {
// Search for anchor elements containing "Stripe"
const anchors = Array.from(document.querySelectorAll('a'));
const cand = [];
for (const a of anchors) {
const text = (a.textContent || '').toLowerCase();
const title = (a.getAttribute('title') || '').toLowerCase();
const href = (a.getAttribute('href') || '').toLowerCase();
if (text.includes('stripe') || title.includes('stripe') || href.includes('stripe')) {
if (isVisible(a)) cand.push(a);
}
const img = a.querySelector('img');
if (img) {
const alt = (img.alt || '').toLowerCase();
const src = (img.src || '').toLowerCase();
if ((alt && alt.includes('stripe')) || (src && src.includes('stripe'))) {
if (isVisible(a)) cand.push(a);
}
}
const hasStripeClass = a.className && a.className.toString().toLowerCase().includes('stripe');
if (hasStripeClass && isVisible(a)) cand.push(a);
}
if (cand.length) {
// Sort candidates by position (prefer higher up) and size (penalize small elements)
cand.sort((a,b)=>{
const ar = a.getBoundingClientRect();
const br = b.getBoundingClientRect();
const aScore = ar.top + (100000/Math.max(10, ar.width*ar.height));
const bScore = br.top + (100000/Math.max(10, br.width*br.height));
return aScore - bScore;
});
return cand[0];
}
// Fallback search
const els = Array.from(document.querySelectorAll('span,div,strong,p,h1,h2,h3,svg'));
for (const el of els) {
const t = (el.textContent||'').toLowerCase();
if (t.includes('stripe') && isVisible(el)) {
let cur = el;
for (let i=0;i<4 && cur;i++) {
if (cur.tagName === 'A') return cur;
cur = cur.parentElement;
}
}
}
return null;
}
// 2. Execute the main logic (No IIFE)
const target = findStripeAnchor();
if (!target) {
// By using a top-level return, the backend will correctly capture this output.
return { ok:false, reason:'no-stripe-anchor' };
}
const href = target.getAttribute('href');
// 3. Ensure the element is clickable
// Bring the element into the center of the viewport.
target.scrollIntoView({block:'center', inline:'center'});
// The backend wraps this code in an AsyncFunction, so 'await' is allowed.
// Wait briefly (300ms) for the scroll to complete and the page to settle.
await new Promise(resolve => setTimeout(resolve, 300));
// 4. Final validation before clicking
const r = target.getBoundingClientRect();
if (!(r.bottom > 0 && r.top < innerHeight && r.right > 0 && r.left < innerWidth)) {
// If the element is still not in the viewport (e.g., obscured by a sticky header), we cannot click it reliably.
return { ok: false, reason: 'target-not-in-viewport-after-scroll' };
}
// 5. Perform the action and return the result
target.click();
return { ok:true, href, text:(target.textContent||'').trim().slice(0,80) };
-74
View File
@@ -1,74 +0,0 @@
#!/bin/bash
# Test script to verify that CARGO_PKG_VERSION gets set correctly
# This simulates what the GitHub Actions workflow does
set -euo pipefail
echo "🧪 Testing version embedding process..."
echo ""
# Save current state
ORIGINAL_VERSION=$(grep "^version = " codex-rs/Cargo.toml | sed 's/version = "\(.*\)"/\1/')
echo "Current version in Cargo.toml: $ORIGINAL_VERSION"
# Test version
TEST_VERSION="9.9.9-test"
echo "Test version to embed: $TEST_VERSION"
echo ""
# Change to codex-rs directory
cd codex-rs
# Update version (like the workflow does)
echo "📝 Updating version in Cargo.toml..."
sed -i.bak "s/^version = \".*\"/version = \"$TEST_VERSION\"/" Cargo.toml
# Verify the update
echo "Updated Cargo.toml:"
grep "^version = " Cargo.toml
echo ""
# Update Cargo.lock
echo "🔄 Updating Cargo.lock..."
cargo update --workspace
# Build a small test binary to check version embedding
echo "🔨 Building test binary to verify version embedding..."
cat > test-version/src/main.rs << 'EOF'
fn main() {
println!("CARGO_PKG_VERSION: {}", env!("CARGO_PKG_VERSION"));
}
EOF
# Create a minimal test crate if it doesn't exist
if [ ! -f test-version/Cargo.toml ]; then
mkdir -p test-version/src
cat > test-version/Cargo.toml << EOF
[package]
name = "test-version"
version = { workspace = true }
edition = "2024"
EOF
fi
# Build the test binary
cargo build --manifest-path test-version/Cargo.toml
# Run it to see the embedded version
echo ""
echo "✅ Testing embedded version:"
./target/debug/test-version
# Clean up - restore original version
echo ""
echo "🧹 Restoring original version..."
sed -i.bak "s/^version = \".*\"/version = \"$ORIGINAL_VERSION\"/" Cargo.toml
cargo update --workspace
rm -rf test-version
echo ""
echo "✅ Test complete!"
echo ""
echo "If the test showed 'CARGO_PKG_VERSION: $TEST_VERSION', then the version"
echo "embedding process is working correctly and will work in GitHub Actions."
-15
View File
@@ -1,15 +0,0 @@
#!/bin/bash
echo "Testing IIFE handling in browser JavaScript execution..."
# Test 1: IIFE with return statement
echo "Test 1: IIFE pattern"
cat test_iife.js | codex -b "navigate to https://example.com and run this JavaScript:" 2>&1 | grep -A5 "JavaScript result"
echo ""
echo "Test 2: Normal code without IIFE"
cat test_normal.js | codex -b "navigate to https://example.com and run this JavaScript:" 2>&1 | grep -A5 "JavaScript result"
echo ""
echo "Test 3: Top-level return"
echo "return { test: 'direct-return' }" | codex -b "navigate to https://example.com and run this JavaScript:" 2>&1 | grep -A5 "JavaScript result"
-37
View File
@@ -1,37 +0,0 @@
#!/bin/bash
# Test the debug flag
echo "Testing debug flag..."
# Check if debug logs directory gets created
DEBUG_LOG_DIR="$HOME/.codex/debug_logs"
# Remove old debug logs if they exist
if [ -d "$DEBUG_LOG_DIR" ]; then
echo "Removing old debug logs..."
rm -rf "$DEBUG_LOG_DIR"
fi
# Run coder with debug flag in exec mode (non-interactive)
echo "Running coder with --debug flag..."
./target/dev-fast/coder exec --debug "What is 2+2?" 2>&1 | head -20
# Check if debug logs were created
if [ -d "$DEBUG_LOG_DIR" ]; then
echo ""
echo "Debug logs directory created: $DEBUG_LOG_DIR"
echo "Contents:"
ls -la "$DEBUG_LOG_DIR" 2>/dev/null | head -10
# Show a sample log file
echo ""
echo "Sample log file:"
FIRST_LOG=$(ls "$DEBUG_LOG_DIR" 2>/dev/null | head -1)
if [ -n "$FIRST_LOG" ]; then
echo "Contents of $FIRST_LOG:"
head -20 "$DEBUG_LOG_DIR/$FIRST_LOG"
fi
else
echo "Debug logs directory NOT created"
fi
-47
View File
@@ -1,47 +0,0 @@
#!/bin/bash
# Simple test for debug logging
echo "Testing debug logging..."
# Set the debug log directory
DEBUG_LOG_DIR="$HOME/.codex/debug_logs"
# Clean up any existing debug logs
if [ -d "$DEBUG_LOG_DIR" ]; then
echo "Cleaning up old debug logs..."
rm -rf "$DEBUG_LOG_DIR"
fi
# Run coder exec with debug flag
cd /Users/zemaj/www/just-every/coder
echo "Running: ./codex-rs/target/dev-fast/coder exec --debug 'What is 2+2?'"
OUTPUT=$(./codex-rs/target/dev-fast/coder exec --debug "What is 2+2?" 2>&1)
echo "Command output:"
echo "$OUTPUT" | head -20
# Check if debug logs were created
echo ""
if [ -d "$DEBUG_LOG_DIR" ]; then
echo "✅ Debug logs directory created: $DEBUG_LOG_DIR"
# Count log files
LOG_COUNT=$(find "$DEBUG_LOG_DIR" -type f | wc -l)
echo "Number of log files created: $LOG_COUNT"
# List log files
echo ""
echo "Log files:"
ls -la "$DEBUG_LOG_DIR" | tail -n +2 | head -10
# Show a sample request log
echo ""
REQUEST_LOG=$(find "$DEBUG_LOG_DIR" -name "*request*.json" | head -1)
if [ -n "$REQUEST_LOG" ]; then
echo "Sample request log (first 30 lines of $(basename "$REQUEST_LOG")):"
cat "$REQUEST_LOG" | head -30
fi
else
echo "❌ Debug logs directory NOT created - debug logging may not be working"
fi
BIN
View File
Binary file not shown.
-13
View File
@@ -1,13 +0,0 @@
// Test script with IIFE that should return a value
(() => {
function findElement() {
const el = document.querySelector('body');
if (!el) {
return { ok: false, reason: 'no-body' };
}
return { ok: true, tag: el.tagName };
}
const result = findElement();
return result;
})()
-37
View File
@@ -1,37 +0,0 @@
// Test program to verify IIFE detection logic
fn main() {
let test_cases = vec![
("(() => { return 42; })()", true, "arrow function IIFE"),
("(function() { return 42; })()", true, "function IIFE"),
("(async () => { return 42; })()", true, "async arrow IIFE"),
("const x = 42; x", false, "normal code"),
("return { test: 'direct' }", false, "direct return"),
];
for (code, expected_iife, description) in test_cases {
let is_iife = detect_iife(code);
println!("{}: {} (expected: {})", description, is_iife, expected_iife);
assert_eq!(is_iife, expected_iife, "Failed for: {}", description);
}
println!("All tests passed!");
}
fn detect_iife(code: &str) -> bool {
let trimmed_code = code.trim();
if trimmed_code.starts_with("(") || trimmed_code.starts_with("(async") || trimmed_code.starts_with("(function") {
let mut paren_depth = 0;
for ch in trimmed_code.chars() {
match ch {
'(' => paren_depth += 1,
')' => {
paren_depth -= 1;
if paren_depth == 0 {
return true;
}
}
_ => {}
}
}
}
false
}
-3
View File
@@ -1,3 +0,0 @@
Test the following JavaScript code in a browser at https://example.com:
(() => { return { test: 'iife-works' }; })()
-11
View File
@@ -1,11 +0,0 @@
// Test script without IIFE that should also return a value
function findElement() {
const el = document.querySelector('body');
if (!el) {
return { ok: false, reason: 'no-body' };
}
return { ok: true, tag: el.tagName };
}
const result = findElement();
result
-74
View File
@@ -1,74 +0,0 @@
# Theme Testing Guide
## Testing the /theme Command
The theme switching functionality has been successfully implemented. Here's how to test it:
### 1. Build and Install
```bash
npm run build:quick
```
### 2. Run Codex TUI
```bash
codex
```
### 3. Test Theme Switching
- Type `/theme` in the compose field
- Press Enter to open the theme selection UI
- Use arrow keys (↑↓) to navigate between themes
- Press Enter to select a theme
- Press Esc to cancel
### Available Themes
1. **Carbon Night** - Sleek modern dark theme (default)
2. **Photon Light** - Clean professional light theme
3. **Shinobi Dusk** - Japanese-inspired twilight
4. **OLED Black Pro** - True black for OLED displays
5. **Amber Terminal** - Retro amber CRT aesthetic
6. **Aurora Flux** - Northern lights inspired
7. **Charcoal Rainbow** - High-contrast accessible
8. **Zen Garden** - Calm and peaceful
9. **Paper Light Pro** - Premium paper-like light
### What to Verify
1. **Theme Selection UI**:
- The popup appears when typing `/theme`
- All 9 themes are listed with descriptions
- Current theme is marked with "(current)"
- Arrow keys navigate the list
- Selected item is highlighted with ">" and cyan color
2. **Theme Application**:
- When a theme is selected, colors change immediately
- A confirmation message appears: "✓ Theme changed to [Theme Name]"
- The new theme persists across different views
3. **Configuration**:
- Theme changes are logged (check terminal output)
- To persist themes, add to config.toml:
```toml
[tui.theme]
name = "carbon-night" # or any other theme name
```
### Features Implemented
- ✅ Complete theme system with 9 predefined themes
- ✅ Dynamic theme switching during active sessions
- ✅ `/theme` slash command
- ✅ Interactive theme selection UI
- ✅ Immediate visual feedback
- ✅ Theme configuration in config.toml
- ✅ Custom color overrides support
### Technical Implementation
- **Theme Module** (`tui/src/theme.rs`): Core theme definitions and switching logic
- **Colors Module** (`tui/src/colors.rs`): Dynamic color functions using current theme
- **Theme Selection View** (`tui/src/bottom_pane/theme_selection_view.rs`): Interactive UI
- **Config Types** (`core/src/config_types.rs`): Theme configuration structures
- **Slash Command** (`tui/src/slash_command.rs`): `/theme` command integration
-109
View File
@@ -1,109 +0,0 @@
# Proposed Changes: Reliable image sizing for ratatui-image
This approach avoids `Picker::from_query_stdio()` races by measuring terminal cell size via `/dev/tty` once and feeding that to `Picker::from_fontsize`. It removes the startup timing constraint and yields accurate image scaling.
## 1) codex-rs/tui/src/terminal_info.rs
Add a helper that returns the exact cell size in pixels (width, height). Place it near the bottom, above `DEFAULT_CELL_ASPECT_RATIO` so it can reuse internal helpers.
```rust
pub fn get_cell_size_pixels() -> Option<(u16, u16)> {
// Open /dev/tty for reading and writing
let mut tty_w = OpenOptions::new().write(true).open("/dev/tty").ok()?;
let mut tty_r = OpenOptions::new().read(true).open("/dev/tty").ok()?;
// Try direct cell size query (CSI 16 t) -> expect: CSI 6;height;width t
tty_w.write_all(b"\x1b[16t").ok()?;
tty_w.flush().ok()?;
if let Some(reply) = read_reply(&mut tty_r, Duration::from_millis(100)) {
if let Some((kind, height, width)) = parse_three_nums(&reply) {
if kind == 6 && width > 0 && height > 0 {
return Some((width as u16, height as u16));
}
}
}
// Fallback: window size in pixels (CSI 14 t) -> CSI 4;win_h;win_w t
tty_w.write_all(b"\x1b[14t").ok()?;
tty_w.flush().ok()?;
let (mut win_h, mut win_w) = (0u32, 0u32);
if let Some(reply) = read_reply(&mut tty_r, Duration::from_millis(100)) {
if let Some((kind, h, w)) = parse_three_nums(&reply) {
if kind == 4 {
win_h = h;
win_w = w;
}
}
}
// Text area in characters (CSI 18 t) -> CSI 8;rows;cols t
tty_w.write_all(b"\x1b[18t").ok()?;
tty_w.flush().ok()?;
let (mut rows, mut cols) = (0u32, 0u32);
if let Some(reply) = read_reply(&mut tty_r, Duration::from_millis(100)) {
if let Some((kind, r, c)) = parse_three_nums(&reply) {
if kind == 8 {
rows = r;
cols = c;
}
}
}
if win_h > 0 && win_w > 0 && rows > 0 && cols > 0 {
let cell_w = (win_w as f32 / cols as f32).round() as u16;
let cell_h = (win_h as f32 / rows as f32).round() as u16;
if cell_w > 0 && cell_h > 0 {
return Some((cell_w, cell_h));
}
}
None
}
```
## 2) codex-rs/tui/src/chatwidget.rs
- Add a cached cell-size field to `ChatWidget`:
```rust
// Cached cell size (width,height) in pixels
cached_cell_size: std::cell::OnceCell<(u16, u16)>,
```
- Add a helper to compute the picker font size once, with fallback:
```rust
impl ChatWidget<'_> {
fn measured_font_size(&self) -> (u16, u16) {
let default_guess = if std::env::var("TERM_PROGRAM").unwrap_or_default() == "iTerm.app" {
(7, 15)
} else {
(8, 16)
};
*self.cached_cell_size.get_or_init(|| {
crate::terminal_info::get_cell_size_pixels().unwrap_or(default_guess)
})
}
// ...
}
```
- Use `measured_font_size()` when creating the `Picker` (two places):
1) In the branch where we create a new picker (around the first `Picker::from_fontsize(...)`):
```rust
// Replace the conditional guessed font size block with
let picker = Picker::from_fontsize(self.measured_font_size());
```
2) In `render_screenshot_highlevel`, when `cached_picker` is `None`:
```rust
// Replace the guessed font size block with
*cached_picker = Some(Picker::from_fontsize(self.measured_font_size()));
```
Notes
- No changes to the event thread ordering are required.
- This approach avoids races with `stdin` and makes screenshot images fill the intended area using `Resize::Fit`.
- Keep the existing aspect‑ratio calculation in `popup_area_top_right`; it remains correct.
-41
View File
@@ -1,41 +0,0 @@
# Fix Verification Results
## IIFE Detection Logic ✅
The standalone test confirms that our IIFE detection logic correctly identifies:
- Arrow function IIFEs: `(() => { ... })()`
- Regular function IIFEs: `(function() { ... })()`
- Async arrow IIFEs: `(async () => { ... })()`
- And correctly rejects normal code patterns
## Code Changes Applied ✅
1. **IIFE Detection Added** (page.rs lines 465-486)
- Detects IIFE patterns by checking for opening parenthesis
- Tracks parenthesis depth to confirm IIFE structure
2. **Brace Depth Tracking** (page.rs lines 495-525)
- Distinguishes between top-level and nested return statements
- Only considers returns at brace depth 0 as top-level
3. **Conditional Body Building** (page.rs lines 529-532)
- When IIFE detected: Pass code through unchanged
- Otherwise: Apply normal return value handling
## Fixed JavaScript Code
The `stripe_click_fixed.js` file contains the corrected JavaScript that:
1. Removes the IIFE wrapper (avoiding the return value issue)
2. Uses relaxed visibility checks
3. Includes explicit scrolling and waiting
4. Has clean formatting without non-breaking spaces
## Build Status ✅
- Successfully compiled with `./build-fast.sh`
- Binary symlinked and ready at `coder`
- Only one warning (unused method) which doesn't affect functionality
## Summary
The fix has been successfully implemented and addresses all three identified issues:
1. ✅ IIFE return value handling fixed
2. ✅ JavaScript code cleaned and restructured
3. ✅ Visibility checks relaxed for viewport independence
The Rust backend will now correctly handle both IIFE patterns and normal JavaScript code, properly capturing return values in all cases.