Skip to content

Commit d37ced1

Browse files
authored
Merge pull request #841 from AutoMaker-Org/v1.0.0rc
V1.0.0rc
2 parents 6408f51 + 0311130 commit d37ced1

323 files changed

Lines changed: 33590 additions & 2156 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.geminiignore

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Auto-generated by Automaker to speed up Gemini CLI startup
2+
# Prevents Gemini CLI from scanning large directories during context discovery
3+
.git
4+
node_modules
5+
dist
6+
build
7+
.next
8+
.nuxt
9+
coverage
10+
.automaker
11+
.worktrees
12+
.vscode
13+
.idea
14+
*.lock

.github/workflows/e2e-tests.yml

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,13 @@ jobs:
1313
e2e:
1414
runs-on: ubuntu-latest
1515
timeout-minutes: 15
16+
strategy:
17+
fail-fast: false
18+
matrix:
19+
# shardIndex: [1, 2, 3]
20+
# shardTotal: [3]
21+
shardIndex: [1]
22+
shardTotal: [1]
1623

1724
steps:
1825
- name: Checkout code
@@ -91,15 +98,15 @@ jobs:
9198
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')"
9299
exit 0
93100
fi
94-
101+
95102
# Check if server process is still running
96103
if ! kill -0 $SERVER_PID 2>/dev/null; then
97104
echo "ERROR: Server process died during wait!"
98105
echo "=== Backend logs ==="
99106
cat backend.log
100107
exit 1
101108
fi
102-
109+
103110
echo "Waiting... ($i/60)"
104111
sleep 1
105112
done
@@ -127,17 +134,23 @@ jobs:
127134
128135
exit 1
129136
130-
- name: Run E2E tests
137+
- name: Run E2E tests (shard ${{ matrix.shardIndex }}/${{ matrix.shardTotal }})
131138
# Playwright automatically starts the Vite frontend via webServer config
132139
# (see apps/ui/playwright.config.ts) - no need to start it manually
133-
run: npm run test --workspace=apps/ui
140+
run: npx playwright test --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }}
141+
working-directory: apps/ui
134142
env:
135143
CI: true
136-
VITE_SERVER_URL: http://localhost:3108
137-
SERVER_URL: http://localhost:3108
138144
VITE_SKIP_SETUP: 'true'
139145
# Keep UI-side login/defaults consistent
140146
AUTOMAKER_API_KEY: test-api-key-for-e2e-tests
147+
# Backend is already started above - Playwright config sets
148+
# AUTOMAKER_SERVER_PORT so the Vite proxy forwards /api/* to the backend.
149+
# Do NOT set VITE_SERVER_URL here: it bypasses the Vite proxy and causes
150+
# a cookie domain mismatch (cookies are bound to 127.0.0.1, but
151+
# VITE_SERVER_URL=http://localhost:3108 makes the frontend call localhost).
152+
TEST_USE_EXTERNAL_BACKEND: 'true'
153+
TEST_SERVER_PORT: 3108
141154

142155
- name: Print backend logs on failure
143156
if: failure()
@@ -155,20 +168,29 @@ jobs:
155168
uses: actions/upload-artifact@v4
156169
if: always()
157170
with:
158-
name: playwright-report
171+
name: playwright-report-shard-${{ matrix.shardIndex }}-of-${{ matrix.shardTotal }}
159172
path: apps/ui/playwright-report/
160173
retention-days: 7
161174

162175
- name: Upload test results (screenshots, traces, videos)
163176
uses: actions/upload-artifact@v4
164177
if: always()
165178
with:
166-
name: test-results
179+
name: test-results-shard-${{ matrix.shardIndex }}-of-${{ matrix.shardTotal }}
167180
path: |
168181
apps/ui/test-results/
169182
retention-days: 7
170183
if-no-files-found: ignore
171184

185+
- name: Upload blob report for merging
186+
uses: actions/upload-artifact@v4
187+
if: always()
188+
with:
189+
name: blob-report-shard-${{ matrix.shardIndex }}-of-${{ matrix.shardTotal }}
190+
path: apps/ui/blob-report/
191+
retention-days: 1
192+
if-no-files-found: ignore
193+
172194
- name: Cleanup - Kill backend server
173195
if: always()
174196
run: |

.gitignore

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,17 @@ coverage/
6565
*.lcov
6666
playwright-report/
6767
blob-report/
68+
test/**/test-project-[0-9]*/
69+
test/opus-thinking-*/
70+
test/agent-session-test-*/
71+
test/feature-backlog-test-*/
72+
test/running-task-display-test-*/
73+
test/agent-output-modal-responsive-*/
74+
test/fixtures/
75+
test/board-bg-test-*/
76+
test/edit-feature-test-*/
77+
test/open-project-test-*/
78+
6879

6980
# Environment files (keep .example)
7081
.env
@@ -102,3 +113,4 @@ data/
102113
.planning/
103114
.mcp.json
104115
.planning
116+
.bg-shell/

apps/server/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@automaker/server",
3-
"version": "0.15.0",
3+
"version": "1.0.0",
44
"description": "Backend server for Automaker - provides API for both web and Electron modes",
55
"author": "AutoMaker Team",
66
"license": "SEE LICENSE IN LICENSE",
@@ -32,7 +32,7 @@
3232
"@automaker/prompts": "1.0.0",
3333
"@automaker/types": "1.0.0",
3434
"@automaker/utils": "1.0.0",
35-
"@github/copilot-sdk": "^0.1.16",
35+
"@github/copilot-sdk": "0.1.16",
3636
"@modelcontextprotocol/sdk": "1.25.2",
3737
"@openai/codex-sdk": "^0.98.0",
3838
"cookie-parser": "1.4.7",

apps/server/src/index.ts

Lines changed: 27 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,10 @@ morgan.token('status-colored', (_req, res) => {
261261
app.use(
262262
morgan(':method :url :status-colored', {
263263
// Skip when request logging is disabled or for health check endpoints
264-
skip: (req) => !requestLoggingEnabled || req.url === '/api/health',
264+
skip: (req) =>
265+
!requestLoggingEnabled ||
266+
req.url === '/api/health' ||
267+
req.url === '/api/auto-mode/context-exists',
265268
})
266269
);
267270
// CORS configuration
@@ -349,7 +352,9 @@ const ideationService = new IdeationService(events, settingsService, featureLoad
349352

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

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

437-
// Resume interrupted features in the background after reconciliation.
438-
// This uses the saved execution state to identify features that were running
439-
// before the restart (their statuses have been reset to ready/backlog by
440-
// reconciliation above). Running in background so it doesn't block startup.
441-
if (totalReconciled > 0) {
442-
for (const project of globalSettings.projects) {
443-
autoModeService.resumeInterruptedFeatures(project.path).catch((err) => {
444-
logger.warn(
445-
`[STARTUP] Failed to resume interrupted features for ${project.path}:`,
446-
err
447-
);
448-
});
449-
}
450-
logger.info('[STARTUP] Initiated background resume of interrupted features');
442+
// Resume interrupted features in the background for all projects.
443+
// This handles features stuck in transient states (in_progress, pipeline_*)
444+
// or explicitly marked as interrupted. Running in background so it doesn't block startup.
445+
for (const project of globalSettings.projects) {
446+
autoModeService.resumeInterruptedFeatures(project.path).catch((err) => {
447+
logger.warn(
448+
`[STARTUP] Failed to resume interrupted features for ${project.path}:`,
449+
err
450+
);
451+
});
451452
}
453+
logger.info('[STARTUP] Initiated background resume of interrupted features');
452454
}
453455
} catch (err) {
454456
logger.warn('[STARTUP] Failed to reconcile feature states:', err);
@@ -494,7 +496,7 @@ app.use(
494496
);
495497
app.use('/api/auto-mode', createAutoModeRoutes(autoModeService));
496498
app.use('/api/enhance-prompt', createEnhancePromptRoutes(settingsService));
497-
app.use('/api/worktree', createWorktreeRoutes(events, settingsService));
499+
app.use('/api/worktree', createWorktreeRoutes(events, settingsService, featureLoader));
498500
app.use('/api/git', createGitRoutes());
499501
app.use('/api/models', createModelsRoutes());
500502
app.use('/api/spec-regeneration', createSpecRegenerationRoutes(events, settingsService));
@@ -596,24 +598,23 @@ wss.on('connection', (ws: WebSocket) => {
596598

597599
// Subscribe to all events and forward to this client
598600
const unsubscribe = events.subscribe((type, payload) => {
599-
logger.info('Event received:', {
601+
// Use debug level for high-frequency events to avoid log spam
602+
// that causes progressive memory growth and server slowdown
603+
const isHighFrequency =
604+
type === 'dev-server:output' || type === 'test-runner:output' || type === 'feature:progress';
605+
const log = isHighFrequency ? logger.debug.bind(logger) : logger.info.bind(logger);
606+
607+
log('Event received:', {
600608
type,
601609
hasPayload: !!payload,
602-
payloadKeys: payload ? Object.keys(payload) : [],
603610
wsReadyState: ws.readyState,
604-
wsOpen: ws.readyState === WebSocket.OPEN,
605611
});
606612

607613
if (ws.readyState === WebSocket.OPEN) {
608614
const message = JSON.stringify({ type, payload });
609-
logger.info('Sending event to client:', {
610-
type,
611-
messageLength: message.length,
612-
sessionId: (payload as Record<string, unknown>)?.sessionId,
613-
});
614615
ws.send(message);
615616
} else {
616-
logger.info('WARNING: Cannot send event, WebSocket not open. ReadyState:', ws.readyState);
617+
logger.warn('Cannot send event, WebSocket not open. ReadyState:', ws.readyState);
617618
}
618619
});
619620

apps/server/src/lib/git.ts

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,27 @@ import { createLogger } from '@automaker/utils';
1313

1414
const logger = createLogger('GitLib');
1515

16+
// Extended PATH so git is found when the process does not inherit a full shell PATH
17+
// (e.g. Electron, some CI, or IDE-launched processes).
18+
const pathSeparator = process.platform === 'win32' ? ';' : ':';
19+
const extraPaths: string[] =
20+
process.platform === 'win32'
21+
? ([
22+
process.env.LOCALAPPDATA && `${process.env.LOCALAPPDATA}\\Programs\\Git\\cmd`,
23+
process.env.PROGRAMFILES && `${process.env.PROGRAMFILES}\\Git\\cmd`,
24+
process.env['ProgramFiles(x86)'] && `${process.env['ProgramFiles(x86)']}\\Git\\cmd`,
25+
].filter(Boolean) as string[])
26+
: [
27+
'/opt/homebrew/bin',
28+
'/usr/local/bin',
29+
'/usr/bin',
30+
'/home/linuxbrew/.linuxbrew/bin',
31+
process.env.HOME ? `${process.env.HOME}/.local/bin` : '',
32+
].filter(Boolean);
33+
34+
const extendedPath = [process.env.PATH, ...extraPaths].filter(Boolean).join(pathSeparator);
35+
const gitEnv = { ...process.env, PATH: extendedPath };
36+
1637
// ============================================================================
1738
// Secure Command Execution
1839
// ============================================================================
@@ -65,7 +86,14 @@ export async function execGitCommand(
6586
command: 'git',
6687
args,
6788
cwd,
68-
...(env !== undefined ? { env } : {}),
89+
env:
90+
env !== undefined
91+
? {
92+
...gitEnv,
93+
...env,
94+
PATH: [gitEnv.PATH, env.PATH].filter(Boolean).join(pathSeparator),
95+
}
96+
: gitEnv,
6997
...(abortController !== undefined ? { abortController } : {}),
7098
});
7199

0 commit comments

Comments
 (0)