Skip to content

fix: bash redirection allowEdit gate, timeout prompt improvements (#536, #538) #1831

fix: bash redirection allowEdit gate, timeout prompt improvements (#536, #538)

fix: bash redirection allowEdit gate, timeout prompt improvements (#536, #538) #1831

name: Integration Tests
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
actionlint:
name: Lint GitHub Actions workflows
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Download actionlint
id: get_actionlint
run: |
bash <(curl https://raw.githubusercontent.com/rhysd/actionlint/main/scripts/download-actionlint.bash)
echo "executable=./actionlint" >> "$GITHUB_OUTPUT"
shell: bash
- name: Check workflow files
run: ${{ steps.get_actionlint.outputs.executable }} -color
shell: bash
integration-test:
name: Test npm installation on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
node-version: [20]
fail-fast: false
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@1.92.0
with:
components: rustfmt, clippy
- name: Setup Rust cache
uses: actions/cache@v4
timeout-minutes: 5
with:
path: |
~/.cargo/bin/
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
target/
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}-${{ hashFiles('rust-toolchain', 'rust-toolchain.toml') || 'stable' }}
restore-keys: |
${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}-
${{ runner.os }}-cargo-
- name: Build Rust binary (debug mode for CI speed)
run: cargo build
- name: Prepare npm package with local binary
shell: bash
run: |
# Create bin directory in npm package
mkdir -p npm/bin
# Copy the built binary to npm package bin directory with correct naming
# On Unix, we need to preserve the Node.js wrapper script (probe) and put the binary as probe-binary
if [[ "${{ runner.os }}" == "Windows" ]]; then
cp target/debug/probe.exe npm/bin/probe.exe
else
cp target/debug/probe npm/bin/probe-binary
chmod +x npm/bin/probe-binary
fi
# Debug: Check what files are actually in npm/bin before npm link
echo "Debug: Files in npm/bin before npm link:"
ls -la npm/bin/
# Install npm package dependencies and build all packages
# Skip postinstall script since we're providing the binary manually
cd npm && npm install --ignore-scripts && npm run build
# Debug: Check what files are in npm/bin after npm install/build
echo "Debug: Files in npm/bin after build:"
ls -la bin/
- name: Link Probe package locally
run: |
cd npm && npm link --ignore-scripts
- name: Verify Probe installation
run: probe --version
- name: Test search functionality
shell: bash
run: |
echo "Current directory: $(pwd)"
echo "Probe version:"
echo "Debugging npm link setup:"
which probe || echo "probe command not found in PATH"
ls -la "$(which probe)" || echo "probe symlink not found"
if [[ "${{ runner.os }}" == "Windows" ]]; then
echo "Windows-specific checks:"
npm list -g @probelabs/probe || echo "Package listing failed"
else
echo "Unix-specific checks:"
readlink -f "$(which probe)" || echo "Cannot resolve probe symlink"
fi
echo "Checking package structure:"
if [[ "${{ runner.os }}" == "Windows" ]]; then
ls -la "$(npm root -g)/@probelabs/probe/bin/" || echo "npm package bin directory not found"
else
# For npm link, the package might be in a different location
npm list -g @probelabs/probe --depth=0 || echo "Linked package not found"
fi
echo "Testing probe command (using npm link):"
npm --version
probe --version
echo "Running search command..."
# Use the probe command from npm global installation (this uses our shim)
probe search "context engine" README.md --format json > search_results.json
echo "Search command completed, checking file size:"
if [[ "${{ runner.os }}" == "Windows" ]]; then
powershell -Command "Get-ChildItem search_results.json | Select-Object Name,Length"
echo "File contents (first 10 lines):"
powershell -Command "Get-Content search_results.json | Select-Object -First 10"
else
ls -la search_results.json
echo "File contents (first 10 lines):"
head -10 search_results.json
fi
- name: Verify search results (Unix)
if: runner.os != 'Windows'
run: |
# Check that the JSON output contains expected fields
if ! grep -q '"file"' search_results.json; then
echo "Error: JSON output missing 'file' field"
cat search_results.json
exit 1
fi
if ! grep -q '"code"' search_results.json; then
echo "Error: JSON output missing 'code' field"
cat search_results.json
exit 1
fi
if ! grep -q 'README.md' search_results.json; then
echo "Error: Search results don't contain README.md"
cat search_results.json
exit 1
fi
if ! grep -q 'context engine' search_results.json; then
echo "Error: Search results don't contain the search term"
cat search_results.json
exit 1
fi
echo "✅ Search results validation passed"
- name: Verify search results (Windows)
if: runner.os == 'Windows'
shell: pwsh
run: |
# shellcheck disable=SC1009,SC1073,SC1065,SC1064,SC1072
# Check that the JSON output contains expected fields
if (-not (Test-Path search_results.json)) {
Write-Host "Error: search_results.json file not found"
exit 1
}
$content = Get-Content search_results.json -Raw
if (-not $content) {
Write-Host "Error: search_results.json file is empty"
exit 1
}
# Extract JSON part by finding the first '{' character (skip debug output)
$jsonStart = $content.IndexOf('{')
if ($jsonStart -eq -1) {
Write-Host "Error: No JSON found in output"
Get-Content search_results.json
exit 1
}
$jsonContent = $content.Substring($jsonStart)
if (-not ($jsonContent -match '"file"')) {
Write-Host "Error: JSON output missing 'file' field"
Get-Content search_results.json
exit 1
}
if (-not ($jsonContent -match '"code"')) {
Write-Host "Error: JSON output missing 'code' field"
Get-Content search_results.json
exit 1
}
if (-not ($jsonContent -match 'README.md')) {
Write-Host "Error: Search results don't contain README.md"
Get-Content search_results.json
exit 1
}
if (-not ($jsonContent -match 'context engine')) {
Write-Host "Error: Search results don't contain the search term"
Get-Content search_results.json
exit 1
}
Write-Host "✅ Search results validation passed"
- name: Test extract functionality
shell: bash
run: |
echo "Running extract command..."
# Use the probe command from npm global installation (this uses our shim)
probe extract README.md:1 --format json > extract_results.json
- name: Verify extract results (Unix)
if: runner.os != 'Windows'
run: |
# Check that the extract output contains expected fields
if ! grep -q '"file"' extract_results.json; then
echo "Error: Extract JSON output missing 'file' field"
cat extract_results.json
exit 1
fi
if ! grep -q 'README.md' extract_results.json; then
echo "Error: Extract results don't contain README.md"
cat extract_results.json
exit 1
fi
echo "✅ Extract results validation passed"
- name: Verify extract results (Windows)
if: runner.os == 'Windows'
shell: pwsh
run: |
# shellcheck disable=SC1009,SC1073,SC1065,SC1064,SC1072
# Check that the extract output contains expected fields
if (-not (Test-Path extract_results.json)) {
Write-Host "Error: extract_results.json file not found"
exit 1
}
$content = Get-Content extract_results.json -Raw
if (-not $content) {
Write-Host "Error: extract_results.json file is empty"
exit 1
}
# Extract JSON part by finding the first '{' character (skip debug output)
$jsonStart = $content.IndexOf('{')
if ($jsonStart -eq -1) {
Write-Host "Error: No JSON found in output"
Get-Content extract_results.json
exit 1
}
$jsonContent = $content.Substring($jsonStart)
if (-not ($jsonContent -match '"file"')) {
Write-Host "Error: Extract JSON output missing 'file' field"
Get-Content extract_results.json
exit 1
}
if (-not ($jsonContent -match 'README.md')) {
Write-Host "Error: Extract results don't contain README.md"
Get-Content extract_results.json
exit 1
}
Write-Host "✅ Extract results validation passed"
- name: Test MCP server functionality
shell: bash
run: |
echo "Testing MCP server functionality using npm link..."
# Debug: Check what probe command is actually being executed
echo "Debugging probe command resolution:"
which probe
ls -la "$(which probe)" || echo "Cannot stat probe command"
# Check if it's our Node.js shim
echo "Checking if probe command is our Node.js shim:"
head -3 "$(readlink -f "$(which probe)" 2>/dev/null || which probe)" || echo "Cannot read probe file content"
# Test that probe mcp --help works (this tests our shim routing)
echo "Testing MCP help command:"
probe mcp --help > mcp_help.txt 2>&1
mcp_exit_code=$?
if [ $mcp_exit_code -ne 0 ]; then
echo "MCP help command completed with exit code: $mcp_exit_code"
fi
echo "Debug - Command that was actually executed for 'probe mcp --help':"
echo "Exit code: $mcp_exit_code"
# Verify the help output contains MCP-specific content
if grep -q "Probe MCP Server" mcp_help.txt; then
echo "✅ MCP server help shows correct content - shim routing works!"
echo "MCP help output preview:"
head -5 mcp_help.txt
else
echo "❌ MCP help output doesn't contain expected content"
echo "Expected: 'Probe MCP Server'"
echo "Full output:"
cat mcp_help.txt
echo "--- End of output ---"
# Debug: Let's check if the MCP build files exist
echo "Checking MCP build files:"
ls -la npm/build/mcp/ || echo "MCP build directory not found"
# Check if we can run the MCP server directly
echo "Testing direct MCP server execution:"
node npm/build/mcp/index.js --help 2>&1 | head -5 || echo "Direct MCP execution failed"
exit 1
fi
# Test basic MCP functionality with timeout handling
if [[ "${{ runner.os }}" == "Windows" ]]; then
echo "Testing basic MCP server startup on Windows..."
# On Windows, just verify the command starts (we already tested help above)
echo "✅ MCP server routing verified on Windows"
else
echo "Testing MCP server JSON-RPC on Unix..."
# Test MCP server with tools/list request via echo and timeout
echo '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' | timeout 3s probe mcp > mcp_tools.json 2>/dev/null || echo "MCP tools test completed"
# Check if MCP server produced any output (means it started successfully)
if [ -f mcp_tools.json ] && [ -s mcp_tools.json ]; then
echo "✅ MCP server responded to JSON-RPC successfully"
echo "MCP response preview:"
head -3 mcp_tools.json
else
echo "✅ MCP server started successfully (no JSON response expected for basic test)"
fi
fi
# Note: npm agent tests are handled by the dedicated rust-tests.yml workflow
# This integration test focuses on npm package installation and functionality verification
- name: Upload test artifacts on failure
if: failure()
uses: actions/upload-artifact@v4
with:
name: test-results-${{ matrix.os }}-node${{ matrix.node-version }}
path: |
search_results.json
extract_results.json
npm/coverage/
retention-days: 7
chat-integration-test:
name: Test chat example on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
timeout-minutes: 15
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
node-version: [20]
fail-fast: false
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@1.92.0
with:
components: rustfmt, clippy
- name: Setup Rust cache
uses: actions/cache@v4
timeout-minutes: 5
with:
path: |
~/.cargo/bin/
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
target/
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}-${{ hashFiles('rust-toolchain', 'rust-toolchain.toml') || 'stable' }}
restore-keys: |
${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}-
${{ runner.os }}-cargo-
- name: Build Rust binary (debug mode for CI speed)
run: cargo build
- name: Build npm package
run: |
cd npm
npm install
npm run build
- name: Install chat example dependencies
run: |
cd examples/chat
npm install
- name: Register mock backend
run: |
cd examples/chat
# The mock backend is automatically available in the implement/backends directory
echo "Mock backend is available at: implement/backends/MockBackend.js"
- name: Run chat flow integration tests
run: |
cd examples/chat
npm run test:chat
- name: Run tool calling integration tests
run: |
cd examples/chat
npm run test:tools
- name: Run all chat tests
run: |
cd examples/chat
npm test
- name: Upload test artifacts on failure
if: failure()
uses: actions/upload-artifact@v4
with:
name: chat-test-results-${{ matrix.os }}-node${{ matrix.node-version }}
path: |
examples/chat/test-results/
examples/chat/npm-debug.log
retention-days: 7