mirror of
https://github.com/hanzoai/dev.git
synced 2026-10-25 03:32:32 +00:00
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:
@@ -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
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
@@ -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) };
|
||||
@@ -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."
|
||||
@@ -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"
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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;
|
||||
})()
|
||||
@@ -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
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
Test the following JavaScript code in a browser at https://example.com:
|
||||
|
||||
(() => { return { test: 'iife-works' }; })()
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
Reference in New Issue
Block a user