Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
46ee34d
fix: resolve desktop entry launch failure and hide Electron menu bar …
DhanushSantosh Feb 26, 2026
70c9fd7
fix: correct production icon path and refresh icon cache on RPM install
DhanushSantosh Feb 26, 2026
9747faf
Fix agent output summary for pipeline steps (#812)
gsxdsm Feb 26, 2026
82e9396
fix: use absolute icon path and place icon outside asar on Linux
DhanushSantosh Feb 26, 2026
5e15f41
Merge remote-tracking branch 'upstream/v1.0.0rc' into patchcraft
DhanushSantosh Feb 26, 2026
6a824a9
fix: use linux.desktop.entry for custom desktop Icon field
DhanushSantosh Feb 26, 2026
dd7654c
fix: set desktop name on Linux so taskbar uses the correct app icon
DhanushSantosh Feb 26, 2026
70d4007
Fix: memory and context views mobile friendly (#818)
gsxdsm Feb 26, 2026
0196911
Bug fixes and stability improvements (#815)
gsxdsm Feb 28, 2026
1c0e460
Add orphaned features management routes and UI integration (#819)
gsxdsm Feb 28, 2026
63b0a4f
Fix orphaned features when deleting worktrees (#820)
gsxdsm Feb 28, 2026
57bcb28
Improve auto-loop event emission and add ntfy notifications (#821)
gsxdsm Mar 1, 2026
34161cc
Changes from fix/bug-fixes-1rc
gsxdsm Mar 2, 2026
33a2e04
feat: Add settingsService integration for feature defaults and improv…
gsxdsm Mar 2, 2026
c11f390
feat: Add conflict source branch detection and fix re-render cascade …
gsxdsm Mar 2, 2026
59b100b
feat: Add conflict source branch tracking and fix auto-mode subscript…
gsxdsm Mar 2, 2026
8218c48
fix: use object destructuring in Playwright beforeEach callback
gsxdsm Mar 2, 2026
1c3d643
fix: reduce excessive POST /api/auto-mode/context-exists requests
gsxdsm Mar 2, 2026
54d69e9
fix: E2E test stability and UI performance improvements (#823)
gsxdsm Mar 3, 2026
4a128ef
Changes from fix/board-crash-new-feat
gsxdsm Mar 3, 2026
341a653
refactor: extract shared isBacklogLikeStatus helper and improve comments
gsxdsm Mar 3, 2026
cf3d312
fix: Remove overly restrictive pattern from summary extraction regex
gsxdsm Mar 3, 2026
b2915f4
refactor: Simplify click URL resolution logic
gsxdsm Mar 3, 2026
ae48065
Fix dev server hang by reducing log spam and event frequency (#828)
gsxdsm Mar 3, 2026
dd7108a
Fixes critical React crash on the Kanban board view (#830)
gsxdsm Mar 4, 2026
20e7c74
Fix event endpoint persistence (#831)
gsxdsm Mar 4, 2026
26b73df
Fix feature deep link with project path handling (#834)
gsxdsm Mar 4, 2026
7be8163
Preserve pipeline work by using waiting_approval on post-completion e…
gsxdsm Mar 5, 2026
0311130
fix: Update @github/copilot-sdk version and enhance version utility t…
gsxdsm Mar 13, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
14 changes: 14 additions & 0 deletions .geminiignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Auto-generated by Automaker to speed up Gemini CLI startup
# Prevents Gemini CLI from scanning large directories during context discovery
.git
node_modules
dist
build
.next
.nuxt
coverage
.automaker
.worktrees
.vscode
.idea
*.lock
38 changes: 30 additions & 8 deletions .github/workflows/e2e-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,13 @@ jobs:
e2e:
runs-on: ubuntu-latest
timeout-minutes: 15
strategy:
fail-fast: false
matrix:
# shardIndex: [1, 2, 3]
# shardTotal: [3]
shardIndex: [1]
shardTotal: [1]

steps:
- name: Checkout code
Expand Down Expand Up @@ -91,15 +98,15 @@ jobs:
curl -s http://localhost:3108/api/health | jq . 2>/dev/null || echo "Health check: $(curl -s http://localhost:3108/api/health 2>/dev/null || echo 'No response')"
exit 0
fi

# Check if server process is still running
if ! kill -0 $SERVER_PID 2>/dev/null; then
echo "ERROR: Server process died during wait!"
echo "=== Backend logs ==="
cat backend.log
exit 1
fi

echo "Waiting... ($i/60)"
sleep 1
done
Expand Down Expand Up @@ -127,17 +134,23 @@ jobs:

exit 1

- name: Run E2E tests
- name: Run E2E tests (shard ${{ matrix.shardIndex }}/${{ matrix.shardTotal }})
# Playwright automatically starts the Vite frontend via webServer config
# (see apps/ui/playwright.config.ts) - no need to start it manually
run: npm run test --workspace=apps/ui
run: npx playwright test --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }}
working-directory: apps/ui
env:
CI: true
VITE_SERVER_URL: http://localhost:3108
SERVER_URL: http://localhost:3108
VITE_SKIP_SETUP: 'true'
# Keep UI-side login/defaults consistent
AUTOMAKER_API_KEY: test-api-key-for-e2e-tests
# Backend is already started above - Playwright config sets
# AUTOMAKER_SERVER_PORT so the Vite proxy forwards /api/* to the backend.
# Do NOT set VITE_SERVER_URL here: it bypasses the Vite proxy and causes
# a cookie domain mismatch (cookies are bound to 127.0.0.1, but
# VITE_SERVER_URL=http://localhost:3108 makes the frontend call localhost).
TEST_USE_EXTERNAL_BACKEND: 'true'
TEST_SERVER_PORT: 3108

- name: Print backend logs on failure
if: failure()
Expand All @@ -155,20 +168,29 @@ jobs:
uses: actions/upload-artifact@v4
if: always()
with:
name: playwright-report
name: playwright-report-shard-${{ matrix.shardIndex }}-of-${{ matrix.shardTotal }}
path: apps/ui/playwright-report/
retention-days: 7

- name: Upload test results (screenshots, traces, videos)
uses: actions/upload-artifact@v4
if: always()
with:
name: test-results
name: test-results-shard-${{ matrix.shardIndex }}-of-${{ matrix.shardTotal }}
path: |
apps/ui/test-results/
retention-days: 7
if-no-files-found: ignore

- name: Upload blob report for merging
uses: actions/upload-artifact@v4
if: always()
with:
name: blob-report-shard-${{ matrix.shardIndex }}-of-${{ matrix.shardTotal }}
path: apps/ui/blob-report/
retention-days: 1
if-no-files-found: ignore

- name: Cleanup - Kill backend server
if: always()
run: |
Expand Down
12 changes: 12 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,17 @@ coverage/
*.lcov
playwright-report/
blob-report/
test/**/test-project-[0-9]*/
test/opus-thinking-*/
test/agent-session-test-*/
test/feature-backlog-test-*/
test/running-task-display-test-*/
test/agent-output-modal-responsive-*/
test/fixtures/
test/board-bg-test-*/
test/edit-feature-test-*/
test/open-project-test-*/


# Environment files (keep .example)
.env
Expand Down Expand Up @@ -102,3 +113,4 @@ data/
.planning/
.mcp.json
.planning
.bg-shell/
4 changes: 2 additions & 2 deletions apps/server/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@automaker/server",
"version": "0.15.0",
"version": "1.0.0",
"description": "Backend server for Automaker - provides API for both web and Electron modes",
"author": "AutoMaker Team",
"license": "SEE LICENSE IN LICENSE",
Expand Down Expand Up @@ -32,7 +32,7 @@
"@automaker/prompts": "1.0.0",
"@automaker/types": "1.0.0",
"@automaker/utils": "1.0.0",
"@github/copilot-sdk": "^0.1.16",
"@github/copilot-sdk": "0.1.16",
"@modelcontextprotocol/sdk": "1.25.2",
"@openai/codex-sdk": "^0.98.0",
"cookie-parser": "1.4.7",
Expand Down
53 changes: 27 additions & 26 deletions apps/server/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,10 @@ morgan.token('status-colored', (_req, res) => {
app.use(
morgan(':method :url :status-colored', {
// Skip when request logging is disabled or for health check endpoints
skip: (req) => !requestLoggingEnabled || req.url === '/api/health',
skip: (req) =>
!requestLoggingEnabled ||
req.url === '/api/health' ||
req.url === '/api/auto-mode/context-exists',
})
);
// CORS configuration
Expand Down Expand Up @@ -349,7 +352,9 @@ const ideationService = new IdeationService(events, settingsService, featureLoad

// Initialize DevServerService with event emitter for real-time log streaming
const devServerService = getDevServerService();
devServerService.setEventEmitter(events);
devServerService.initialize(DATA_DIR, events).catch((err) => {
logger.error('Failed to initialize DevServerService:', err);
});

// Initialize Notification Service with event emitter for real-time updates
const notificationService = getNotificationService();
Expand Down Expand Up @@ -434,21 +439,18 @@ eventHookService.initialize(events, settingsService, eventHistoryService, featur
logger.info('[STARTUP] Feature state reconciliation complete - no stale states found');
}

// Resume interrupted features in the background after reconciliation.
// This uses the saved execution state to identify features that were running
// before the restart (their statuses have been reset to ready/backlog by
// reconciliation above). Running in background so it doesn't block startup.
if (totalReconciled > 0) {
for (const project of globalSettings.projects) {
autoModeService.resumeInterruptedFeatures(project.path).catch((err) => {
logger.warn(
`[STARTUP] Failed to resume interrupted features for ${project.path}:`,
err
);
});
}
logger.info('[STARTUP] Initiated background resume of interrupted features');
// Resume interrupted features in the background for all projects.
// This handles features stuck in transient states (in_progress, pipeline_*)
// or explicitly marked as interrupted. Running in background so it doesn't block startup.
for (const project of globalSettings.projects) {
autoModeService.resumeInterruptedFeatures(project.path).catch((err) => {
logger.warn(
`[STARTUP] Failed to resume interrupted features for ${project.path}:`,
err
);
});
}
logger.info('[STARTUP] Initiated background resume of interrupted features');
}
} catch (err) {
logger.warn('[STARTUP] Failed to reconcile feature states:', err);
Expand Down Expand Up @@ -494,7 +496,7 @@ app.use(
);
app.use('/api/auto-mode', createAutoModeRoutes(autoModeService));
app.use('/api/enhance-prompt', createEnhancePromptRoutes(settingsService));
app.use('/api/worktree', createWorktreeRoutes(events, settingsService));
app.use('/api/worktree', createWorktreeRoutes(events, settingsService, featureLoader));
app.use('/api/git', createGitRoutes());
app.use('/api/models', createModelsRoutes());
app.use('/api/spec-regeneration', createSpecRegenerationRoutes(events, settingsService));
Expand Down Expand Up @@ -596,24 +598,23 @@ wss.on('connection', (ws: WebSocket) => {

// Subscribe to all events and forward to this client
const unsubscribe = events.subscribe((type, payload) => {
logger.info('Event received:', {
// Use debug level for high-frequency events to avoid log spam
// that causes progressive memory growth and server slowdown
const isHighFrequency =
type === 'dev-server:output' || type === 'test-runner:output' || type === 'feature:progress';
const log = isHighFrequency ? logger.debug.bind(logger) : logger.info.bind(logger);

log('Event received:', {
type,
hasPayload: !!payload,
payloadKeys: payload ? Object.keys(payload) : [],
wsReadyState: ws.readyState,
wsOpen: ws.readyState === WebSocket.OPEN,
});

if (ws.readyState === WebSocket.OPEN) {
const message = JSON.stringify({ type, payload });
logger.info('Sending event to client:', {
type,
messageLength: message.length,
sessionId: (payload as Record<string, unknown>)?.sessionId,
});
ws.send(message);
} else {
logger.info('WARNING: Cannot send event, WebSocket not open. ReadyState:', ws.readyState);
logger.warn('Cannot send event, WebSocket not open. ReadyState:', ws.readyState);
}
});

Expand Down
30 changes: 29 additions & 1 deletion apps/server/src/lib/git.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,27 @@ import { createLogger } from '@automaker/utils';

const logger = createLogger('GitLib');

// Extended PATH so git is found when the process does not inherit a full shell PATH
// (e.g. Electron, some CI, or IDE-launched processes).
const pathSeparator = process.platform === 'win32' ? ';' : ':';
const extraPaths: string[] =
process.platform === 'win32'
? ([
process.env.LOCALAPPDATA && `${process.env.LOCALAPPDATA}\\Programs\\Git\\cmd`,
process.env.PROGRAMFILES && `${process.env.PROGRAMFILES}\\Git\\cmd`,
process.env['ProgramFiles(x86)'] && `${process.env['ProgramFiles(x86)']}\\Git\\cmd`,
].filter(Boolean) as string[])
: [
'/opt/homebrew/bin',
'/usr/local/bin',
'/usr/bin',
'/home/linuxbrew/.linuxbrew/bin',
process.env.HOME ? `${process.env.HOME}/.local/bin` : '',
].filter(Boolean);

const extendedPath = [process.env.PATH, ...extraPaths].filter(Boolean).join(pathSeparator);
const gitEnv = { ...process.env, PATH: extendedPath };

// ============================================================================
// Secure Command Execution
// ============================================================================
Expand Down Expand Up @@ -65,7 +86,14 @@ export async function execGitCommand(
command: 'git',
args,
cwd,
...(env !== undefined ? { env } : {}),
env:
env !== undefined
? {
...gitEnv,
...env,
PATH: [gitEnv.PATH, env.PATH].filter(Boolean).join(pathSeparator),
}
: gitEnv,
...(abortController !== undefined ? { abortController } : {}),
});

Expand Down
Loading
Loading