Skip to content

Commit c713cef

Browse files
authored
Merge pull request #360 from AutoMaker-Org/feat/mass-edit-backlog-features
feat: add mass edit feature for backlog kanban cards
2 parents fe7bc95 + 5f7cbd3 commit c713cef

27 files changed

Lines changed: 1707 additions & 377 deletions

Dockerfile

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@ RUN npm run build:packages && npm run build --workspace=apps/server
5555
# =============================================================================
5656
FROM node:22-slim AS server
5757

58+
# Build argument for tracking which commit this image was built from
59+
ARG GIT_COMMIT_SHA=unknown
60+
LABEL automaker.git.commit.sha="${GIT_COMMIT_SHA}"
61+
5862
# Install git, curl, bash (for terminal), gosu (for user switching), and GitHub CLI (pinned version, multi-arch)
5963
RUN apt-get update && apt-get install -y --no-install-recommends \
6064
git curl bash gosu ca-certificates openssh-client \
@@ -184,6 +188,10 @@ RUN npm run build:packages && npm run build --workspace=apps/ui
184188
# =============================================================================
185189
FROM nginx:alpine AS ui
186190

191+
# Build argument for tracking which commit this image was built from
192+
ARG GIT_COMMIT_SHA=unknown
193+
LABEL automaker.git.commit.sha="${GIT_COMMIT_SHA}"
194+
187195
# Copy built files
188196
COPY --from=ui-builder /app/apps/ui/dist /usr/share/nginx/html
189197

Dockerfile.dev

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
# Automaker Development Dockerfile
2+
# For development with live reload via volume mounting
3+
# Source code is NOT copied - it's mounted as a volume
4+
#
5+
# Usage:
6+
# docker compose -f docker-compose.dev.yml up
7+
8+
FROM node:22-slim
9+
10+
# Install build dependencies for native modules (node-pty) and runtime tools
11+
RUN apt-get update && apt-get install -y --no-install-recommends \
12+
python3 make g++ \
13+
git curl bash gosu ca-certificates openssh-client \
14+
&& GH_VERSION="2.63.2" \
15+
&& ARCH=$(uname -m) \
16+
&& case "$ARCH" in \
17+
x86_64) GH_ARCH="amd64" ;; \
18+
aarch64|arm64) GH_ARCH="arm64" ;; \
19+
*) echo "Unsupported architecture: $ARCH" && exit 1 ;; \
20+
esac \
21+
&& curl -L "https://github.com/cli/cli/releases/download/v${GH_VERSION}/gh_${GH_VERSION}_linux_${GH_ARCH}.tar.gz" -o gh.tar.gz \
22+
&& tar -xzf gh.tar.gz \
23+
&& mv gh_${GH_VERSION}_linux_${GH_ARCH}/bin/gh /usr/local/bin/gh \
24+
&& rm -rf gh.tar.gz gh_${GH_VERSION}_linux_${GH_ARCH} \
25+
&& rm -rf /var/lib/apt/lists/*
26+
27+
# Install Claude CLI globally
28+
RUN npm install -g @anthropic-ai/claude-code
29+
30+
# Create non-root user
31+
RUN groupadd -g 1001 automaker && \
32+
useradd -u 1001 -g automaker -m -d /home/automaker -s /bin/bash automaker && \
33+
mkdir -p /home/automaker/.local/bin && \
34+
mkdir -p /home/automaker/.cursor && \
35+
chown -R automaker:automaker /home/automaker && \
36+
chmod 700 /home/automaker/.cursor
37+
38+
# Install Cursor CLI as automaker user
39+
USER automaker
40+
ENV HOME=/home/automaker
41+
RUN curl https://cursor.com/install -fsS | bash || true
42+
USER root
43+
44+
# Add PATH to profile for Cursor CLI
45+
RUN mkdir -p /etc/profile.d && \
46+
echo 'export PATH="/home/automaker/.local/bin:$PATH"' > /etc/profile.d/cursor-cli.sh && \
47+
chmod +x /etc/profile.d/cursor-cli.sh
48+
49+
# Add to user bashrc files
50+
RUN echo 'export PATH="/home/automaker/.local/bin:$PATH"' >> /home/automaker/.bashrc && \
51+
chown automaker:automaker /home/automaker/.bashrc
52+
RUN echo 'export PATH="/home/automaker/.local/bin:$PATH"' >> /root/.bashrc
53+
54+
WORKDIR /app
55+
56+
# Create directories with proper permissions
57+
RUN mkdir -p /data /projects && chown automaker:automaker /data /projects
58+
59+
# Configure git for mounted volumes
60+
RUN git config --system --add safe.directory '*' && \
61+
git config --system credential.helper '!gh auth git-credential'
62+
63+
# Copy entrypoint script
64+
COPY docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh
65+
RUN chmod +x /usr/local/bin/docker-entrypoint.sh
66+
67+
# Environment variables
68+
ENV PORT=3008
69+
ENV DATA_DIR=/data
70+
ENV HOME=/home/automaker
71+
ENV PATH="/home/automaker/.local/bin:${PATH}"
72+
73+
# Expose both dev ports
74+
EXPOSE 3007 3008
75+
76+
# Use entrypoint for permission handling
77+
ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"]
78+
79+
# Default command - will be overridden by docker-compose
80+
CMD ["npm", "run", "dev:web"]

README.md

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -117,24 +117,16 @@ cd automaker
117117
# 2. Install dependencies
118118
npm install
119119

120-
# 3. Build shared packages (Now can be skipped npm install / run dev does it automaticly)
120+
# 3. Build shared packages (can be skipped - npm run dev does it automatically)
121121
npm run build:packages
122122

123-
# 4. Start Automaker (production mode)
124-
npm run start
123+
# 4. Start Automaker
124+
npm run dev
125125
# Choose between:
126126
# 1. Web Application (browser at localhost:3007)
127127
# 2. Desktop Application (Electron - recommended)
128128
```
129129

130-
**Note:** The `npm run start` command will:
131-
132-
- Check for dependencies and install if needed
133-
- Build the application if needed
134-
- Kill any processes on ports 3007/3008
135-
- Present an interactive menu to choose your run mode
136-
- Run in production mode (no hot reload)
137-
138130
**Authentication Setup:** On first run, Automaker will automatically show a setup wizard where you can configure authentication. You can choose to:
139131

140132
- Use **Claude Code CLI** (recommended) - Automaker will detect your CLI credentials automatically
@@ -150,7 +142,7 @@ export ANTHROPIC_API_KEY="sk-ant-..."
150142
echo "ANTHROPIC_API_KEY=sk-ant-..." > .env
151143
```
152144

153-
**For Development:** If you want to develop on Automaker with Vite live reload and hot module replacement, use `npm run dev` instead. This will start the development server with fast refresh and instant updates as you make changes.
145+
**For Development:** `npm run dev` starts the development server with Vite live reload and hot module replacement for fast refresh and instant updates as you make changes.
154146

155147
## How to Run
156148

@@ -194,9 +186,6 @@ npm run dev:web
194186
```bash
195187
# Build for web deployment (uses Vite)
196188
npm run build
197-
198-
# Run production build
199-
npm run start
200189
```
201190

202191
#### Desktop Application

apps/server/src/routes/features/index.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { createListHandler } from './routes/list.js';
99
import { createGetHandler } from './routes/get.js';
1010
import { createCreateHandler } from './routes/create.js';
1111
import { createUpdateHandler } from './routes/update.js';
12+
import { createBulkUpdateHandler } from './routes/bulk-update.js';
1213
import { createDeleteHandler } from './routes/delete.js';
1314
import { createAgentOutputHandler, createRawOutputHandler } from './routes/agent-output.js';
1415
import { createGenerateTitleHandler } from './routes/generate-title.js';
@@ -20,6 +21,11 @@ export function createFeaturesRoutes(featureLoader: FeatureLoader): Router {
2021
router.post('/get', validatePathParams('projectPath'), createGetHandler(featureLoader));
2122
router.post('/create', validatePathParams('projectPath'), createCreateHandler(featureLoader));
2223
router.post('/update', validatePathParams('projectPath'), createUpdateHandler(featureLoader));
24+
router.post(
25+
'/bulk-update',
26+
validatePathParams('projectPath'),
27+
createBulkUpdateHandler(featureLoader)
28+
);
2329
router.post('/delete', validatePathParams('projectPath'), createDeleteHandler(featureLoader));
2430
router.post('/agent-output', createAgentOutputHandler(featureLoader));
2531
router.post('/raw-output', createRawOutputHandler(featureLoader));
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/**
2+
* POST /bulk-update endpoint - Update multiple features at once
3+
*/
4+
5+
import type { Request, Response } from 'express';
6+
import { FeatureLoader } from '../../../services/feature-loader.js';
7+
import type { Feature } from '@automaker/types';
8+
import { getErrorMessage, logError } from '../common.js';
9+
10+
interface BulkUpdateRequest {
11+
projectPath: string;
12+
featureIds: string[];
13+
updates: Partial<Feature>;
14+
}
15+
16+
interface BulkUpdateResult {
17+
featureId: string;
18+
success: boolean;
19+
error?: string;
20+
}
21+
22+
export function createBulkUpdateHandler(featureLoader: FeatureLoader) {
23+
return async (req: Request, res: Response): Promise<void> => {
24+
try {
25+
const { projectPath, featureIds, updates } = req.body as BulkUpdateRequest;
26+
27+
if (!projectPath || !featureIds || !Array.isArray(featureIds) || featureIds.length === 0) {
28+
res.status(400).json({
29+
success: false,
30+
error: 'projectPath and featureIds (non-empty array) are required',
31+
});
32+
return;
33+
}
34+
35+
if (!updates || Object.keys(updates).length === 0) {
36+
res.status(400).json({
37+
success: false,
38+
error: 'updates object with at least one field is required',
39+
});
40+
return;
41+
}
42+
43+
const results: BulkUpdateResult[] = [];
44+
const updatedFeatures: Feature[] = [];
45+
46+
for (const featureId of featureIds) {
47+
try {
48+
const updated = await featureLoader.update(projectPath, featureId, updates);
49+
results.push({ featureId, success: true });
50+
updatedFeatures.push(updated);
51+
} catch (error) {
52+
results.push({
53+
featureId,
54+
success: false,
55+
error: getErrorMessage(error),
56+
});
57+
}
58+
}
59+
60+
const successCount = results.filter((r) => r.success).length;
61+
const failureCount = results.filter((r) => !r.success).length;
62+
63+
res.json({
64+
success: failureCount === 0,
65+
updatedCount: successCount,
66+
failedCount: failureCount,
67+
results,
68+
features: updatedFeatures,
69+
});
70+
} catch (error) {
71+
logError(error, 'Bulk update features failed');
72+
res.status(500).json({ success: false, error: getErrorMessage(error) });
73+
}
74+
};
75+
}

0 commit comments

Comments
 (0)