mirror of
https://github.com/jlengrand/Maestro.git
synced 2026-03-10 08:31:19 +00:00
## CHANGES
- Hardened Linux releases with architecture-safe npm caching to prevent cross-contamination 🛡️ - Added Linux-only prebuild cache purges to avoid wrong-arch native binaries 🧹 - Force rebuild native modules per platform, with explicit x64/arm64 env targeting 🧬 - Cleaned node-pty and better-sqlite3 prebuild directories before Linux packaging 🧱 - Added x64 better-sqlite3 binary architecture verification step in CI 🔍 - Improved Auto Run error handling with rich history entries and recovery guidance 🧾 - Added toast notifications for Auto Run errors with friendly titles and details 🔔 - Extended history entry API to track success/failure for better visibility ✅ - Enhanced Auto Run pause logging with recoverability flags and raw error context 🧰 - Bumped version to 0.13.1 for this release rollout 🚀
This commit is contained in:
117
.github/workflows/release.yml
vendored
117
.github/workflows/release.yml
vendored
@@ -39,12 +39,42 @@ jobs:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Node.js
|
||||
# CRITICAL: Do NOT use setup-node's built-in npm cache for Linux builds.
|
||||
# The cache key doesn't include architecture, so x64 and arm64 share the same cache.
|
||||
# This causes ARM64 prebuilds to contaminate x64 builds (GitHub issue #116).
|
||||
- name: Setup Node.js (Linux - no cache)
|
||||
if: matrix.platform == 'linux' || matrix.platform == 'linux-arm64'
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20'
|
||||
# Explicitly no cache to prevent cross-architecture contamination
|
||||
|
||||
- name: Setup Node.js (non-Linux - with cache)
|
||||
if: matrix.platform != 'linux' && matrix.platform != 'linux-arm64'
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20'
|
||||
cache: 'npm'
|
||||
|
||||
# Use architecture-specific cache for Linux builds
|
||||
- name: Cache npm dependencies (Linux)
|
||||
if: matrix.platform == 'linux' || matrix.platform == 'linux-arm64'
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/.npm
|
||||
key: npm-linux-${{ matrix.arch }}-${{ hashFiles('**/package-lock.json') }}
|
||||
restore-keys: |
|
||||
npm-linux-${{ matrix.arch }}-
|
||||
|
||||
# Extra safety: Clear any prebuild cache that might have wrong-arch binaries
|
||||
- name: Clear prebuild cache (Linux)
|
||||
if: matrix.platform == 'linux' || matrix.platform == 'linux-arm64'
|
||||
run: |
|
||||
echo "Clearing any cached prebuilds to prevent architecture contamination..."
|
||||
rm -rf ~/.npm/_prebuilds 2>/dev/null || true
|
||||
rm -rf ~/.cache/prebuild-install 2>/dev/null || true
|
||||
echo "Prebuild caches cleared"
|
||||
|
||||
# Linux x64: Install build dependencies for native modules and electron-builder
|
||||
# Requires build-essential for compiling node-pty native module
|
||||
- name: Install Linux x64 build dependencies
|
||||
@@ -123,8 +153,48 @@ jobs:
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
# Clean any prebuilt binaries that may have been downloaded for wrong architecture
|
||||
# This is critical: prebuild-install downloads binaries during npm ci, which may be wrong
|
||||
- name: Clean prebuilt binaries (Linux x64)
|
||||
if: matrix.platform == 'linux'
|
||||
run: |
|
||||
echo "Cleaning prebuilt binaries to force rebuild from source..."
|
||||
rm -rf node_modules/node-pty/prebuilds
|
||||
rm -rf node_modules/node-pty/build
|
||||
rm -rf node_modules/better-sqlite3/prebuilds
|
||||
rm -rf node_modules/better-sqlite3/build
|
||||
echo "Prebuilt directories cleaned"
|
||||
|
||||
# Clean any prebuilt binaries that may have been downloaded for wrong architecture
|
||||
- name: Clean prebuilt binaries (Linux ARM64)
|
||||
if: matrix.platform == 'linux-arm64'
|
||||
run: |
|
||||
echo "Cleaning prebuilt binaries to force rebuild from source..."
|
||||
rm -rf node_modules/node-pty/prebuilds
|
||||
rm -rf node_modules/node-pty/build
|
||||
rm -rf node_modules/better-sqlite3/prebuilds
|
||||
rm -rf node_modules/better-sqlite3/build
|
||||
echo "Prebuilt directories cleaned"
|
||||
|
||||
# Rebuild native modules for the target platform
|
||||
- name: Rebuild native modules
|
||||
- name: Rebuild native modules (Linux x64)
|
||||
if: matrix.platform == 'linux'
|
||||
run: npm run postinstall
|
||||
env:
|
||||
npm_config_build_from_source: true
|
||||
npm_config_arch: x64
|
||||
npm_config_target_arch: x64
|
||||
|
||||
- name: Rebuild native modules (Linux ARM64)
|
||||
if: matrix.platform == 'linux-arm64'
|
||||
run: npm run postinstall
|
||||
env:
|
||||
npm_config_build_from_source: true
|
||||
npm_config_arch: arm64
|
||||
npm_config_target_arch: arm64
|
||||
|
||||
- name: Rebuild native modules (non-Linux)
|
||||
if: matrix.platform != 'linux' && matrix.platform != 'linux-arm64'
|
||||
run: npm run postinstall
|
||||
env:
|
||||
npm_config_build_from_source: true
|
||||
@@ -171,8 +241,29 @@ jobs:
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Verify better-sqlite3 architecture (Linux ARM64 only)
|
||||
- name: Verify better-sqlite3 architecture
|
||||
# Verify better-sqlite3 architecture (Linux x64)
|
||||
- name: Verify better-sqlite3 architecture (Linux x64)
|
||||
if: matrix.platform == 'linux'
|
||||
run: |
|
||||
echo "Checking better-sqlite3 binary architecture..."
|
||||
SQLITE_PATH=$(find node_modules/better-sqlite3 -name "better_sqlite3.node" -type f 2>/dev/null | head -1)
|
||||
if [ -n "$SQLITE_PATH" ]; then
|
||||
file "$SQLITE_PATH"
|
||||
# Verify it's x64, not ARM64
|
||||
if file "$SQLITE_PATH" | grep -q "x86-64\|x86_64\|AMD64"; then
|
||||
echo "✓ better-sqlite3 is correctly built for x64"
|
||||
else
|
||||
echo "✗ ERROR: better-sqlite3 is NOT built for x64!"
|
||||
file "$SQLITE_PATH"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
echo "✗ ERROR: better-sqlite3 binary not found!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Verify better-sqlite3 architecture (Linux ARM64)
|
||||
- name: Verify better-sqlite3 architecture (Linux ARM64)
|
||||
if: matrix.platform == 'linux-arm64'
|
||||
run: |
|
||||
echo "Checking better-sqlite3 binary architecture..."
|
||||
@@ -251,8 +342,17 @@ jobs:
|
||||
DEBUG: electron-builder
|
||||
npm_config_arch: x64
|
||||
npm_config_target_arch: x64
|
||||
npm_config_build_from_source: true
|
||||
BUILD_VERSION: ${{ steps.version.outputs.VERSION }}
|
||||
run: |
|
||||
# Critical: Clean build directories to force fresh compilation
|
||||
# This prevents any cached/prebuilt ARM binaries from being used
|
||||
echo "Cleaning native module build directories..."
|
||||
rm -rf node_modules/node-pty/build
|
||||
rm -rf node_modules/node-pty/prebuilds
|
||||
rm -rf node_modules/better-sqlite3/build
|
||||
rm -rf node_modules/better-sqlite3/prebuilds
|
||||
|
||||
# Explicitly rebuild native modules for x64 architecture
|
||||
echo "Rebuilding native modules for x64..."
|
||||
npx electron-rebuild --arch=x64 --force
|
||||
@@ -304,9 +404,18 @@ jobs:
|
||||
DEBUG: electron-builder
|
||||
npm_config_arch: arm64
|
||||
npm_config_target_arch: arm64
|
||||
npm_config_build_from_source: true
|
||||
USE_SYSTEM_FPM: "true"
|
||||
BUILD_VERSION: ${{ steps.version.outputs.VERSION }}
|
||||
run: |
|
||||
# Critical: Clean build directories to force fresh compilation
|
||||
# This prevents any cached/prebuilt x64 binaries from being used
|
||||
echo "Cleaning native module build directories..."
|
||||
rm -rf node_modules/node-pty/build
|
||||
rm -rf node_modules/node-pty/prebuilds
|
||||
rm -rf node_modules/better-sqlite3/build
|
||||
rm -rf node_modules/better-sqlite3/prebuilds
|
||||
|
||||
# Explicitly rebuild native modules for ARM64 architecture
|
||||
# This ensures node-pty is correctly compiled before packaging
|
||||
echo "Rebuilding native modules for ARM64..."
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "maestro",
|
||||
"version": "0.13.0",
|
||||
"version": "0.13.1",
|
||||
"description": "Maestro hones fractured attention into focused intent.",
|
||||
"main": "dist/main/index.js",
|
||||
"author": {
|
||||
|
||||
@@ -120,6 +120,31 @@ import { isLikelyConcatenatedToolNames, getSlashCommandDescription } from './con
|
||||
|
||||
// Note: DEFAULT_IMAGE_ONLY_PROMPT is now imported from useInputProcessing hook
|
||||
|
||||
/**
|
||||
* Get a human-readable title for an agent error type.
|
||||
* Used for toast notifications and history entries.
|
||||
*/
|
||||
function getErrorTitleForType(type: AgentError['type']): string {
|
||||
switch (type) {
|
||||
case 'auth_expired':
|
||||
return 'Authentication Required';
|
||||
case 'token_exhaustion':
|
||||
return 'Context Limit Reached';
|
||||
case 'rate_limited':
|
||||
return 'Rate Limit Exceeded';
|
||||
case 'network_error':
|
||||
return 'Connection Error';
|
||||
case 'agent_crashed':
|
||||
return 'Agent Error';
|
||||
case 'permission_denied':
|
||||
return 'Permission Denied';
|
||||
case 'session_not_found':
|
||||
return 'Session Not Found';
|
||||
default:
|
||||
return 'Error';
|
||||
}
|
||||
}
|
||||
|
||||
function MaestroConsoleInner() {
|
||||
// --- LAYER STACK (for blocking shortcuts when modals are open) ---
|
||||
const { hasOpenLayers, hasOpenModal } = useLayerStack();
|
||||
@@ -2103,6 +2128,7 @@ function MaestroConsoleInner() {
|
||||
}));
|
||||
|
||||
// Phase 5.10: Check if there's an active batch run for this session and pause it
|
||||
// Also add history entry and toast for Auto Run errors
|
||||
if (getBatchStateRef.current && pauseBatchOnErrorRef.current) {
|
||||
const batchState = getBatchStateRef.current(actualSessionId);
|
||||
if (batchState.isRunning && !batchState.errorPaused) {
|
||||
@@ -2114,6 +2140,54 @@ function MaestroConsoleInner() {
|
||||
batchState.currentDocumentIndex,
|
||||
currentDoc ? `Processing ${currentDoc}` : undefined
|
||||
);
|
||||
|
||||
// Get session for history entry
|
||||
const session = sessionsRef.current.find(s => s.id === actualSessionId);
|
||||
|
||||
// Add history entry for Auto Run error (similar to stalled document entries)
|
||||
if (addHistoryEntryRef.current && session) {
|
||||
const errorTitle = getErrorTitleForType(agentError.type);
|
||||
const errorExplanation = [
|
||||
`**Auto Run Error: ${errorTitle}**`,
|
||||
'',
|
||||
`Auto Run encountered an error while processing:`,
|
||||
currentDoc ? `- Document: ${currentDoc}` : '',
|
||||
`- Error: ${agentError.message}`,
|
||||
'',
|
||||
'**What to do:**',
|
||||
agentError.type === 'auth_expired'
|
||||
? '- Re-authenticate with the provider (e.g., run `claude login` in terminal)'
|
||||
: agentError.type === 'token_exhaustion'
|
||||
? '- Start a new session to reset the context window'
|
||||
: agentError.type === 'rate_limited'
|
||||
? '- Wait a few minutes before retrying'
|
||||
: agentError.type === 'network_error'
|
||||
? '- Check your internet connection and try again'
|
||||
: '- Review the error message and take appropriate action',
|
||||
'',
|
||||
'After resolving the issue, you can resume, skip, or abort the Auto Run.',
|
||||
].filter(Boolean).join('\n');
|
||||
|
||||
addHistoryEntryRef.current({
|
||||
type: 'AUTO',
|
||||
summary: `Auto Run error: ${errorTitle}${currentDoc ? ` (${currentDoc})` : ''}`,
|
||||
fullResponse: errorExplanation,
|
||||
projectPath: session.cwd,
|
||||
sessionId: actualSessionId,
|
||||
success: false,
|
||||
});
|
||||
}
|
||||
|
||||
// Show toast notification for Auto Run error
|
||||
if (addToastRef.current) {
|
||||
const errorTitle = getErrorTitleForType(agentError.type);
|
||||
addToastRef.current({
|
||||
type: 'error',
|
||||
title: `Auto Run: ${errorTitle}`,
|
||||
message: agentError.message,
|
||||
sessionId: actualSessionId,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,8 @@ export interface HistoryEntryInput {
|
||||
projectPath?: string;
|
||||
/** Optional override for background operations (prevents cross-agent bleed) */
|
||||
sessionName?: string;
|
||||
/** Whether the operation succeeded (false for errors/failures) */
|
||||
success?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -121,7 +123,9 @@ export function useAgentSessionManagement(
|
||||
...(shouldIncludeContextUsage ? { contextUsage: activeSession?.contextUsage } : {}),
|
||||
// Only include usageStats if explicitly provided (per-task tracking)
|
||||
// Never use cumulative session stats - they're lifetime totals
|
||||
usageStats: entry.usageStats
|
||||
usageStats: entry.usageStats,
|
||||
// Pass through success field for error/failure tracking
|
||||
success: entry.success,
|
||||
});
|
||||
|
||||
// Refresh history panel to show the new entry
|
||||
|
||||
@@ -1358,14 +1358,17 @@ export function useBatchProcessor({
|
||||
const pauseBatchOnError = useCallback((sessionId: string, error: AgentError, documentIndex: number, taskDescription?: string) => {
|
||||
if (!isMountedRef.current) return;
|
||||
|
||||
// Log detailed error to system logs with full context
|
||||
window.maestro.logger.autorun(
|
||||
`Auto Run paused due to error: ${error.type}`,
|
||||
`Auto Run paused due to ${error.type}: ${error.message}`,
|
||||
sessionId,
|
||||
{
|
||||
errorType: error.type,
|
||||
errorMessage: error.message,
|
||||
recoverable: error.recoverable,
|
||||
documentIndex,
|
||||
taskDescription
|
||||
taskDescription,
|
||||
rawError: error.raw
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user