Spaces:
Paused
Paused
Upload folder using huggingface_hub
Browse filesThis view is limited to 50 files because it contains too many changes. See raw diff
- .gitattributes +10 -0
- Dockerfile +16 -12
- apps/server/src/index.ts +1 -120
- entrypoint.sh +9 -2
- jules_branch/.claude/.gitignore +2 -0
- jules_branch/.claude/agents/clean-code-architect.md +86 -0
- jules_branch/.claude/agents/deepcode.md +249 -0
- jules_branch/.claude/agents/deepdive.md +253 -0
- jules_branch/.claude/agents/security-vulnerability-scanner.md +78 -0
- jules_branch/.claude/commands/deepreview.md +591 -0
- jules_branch/.claude/commands/gh-issue.md +74 -0
- jules_branch/.claude/commands/release.md +77 -0
- jules_branch/.claude/commands/review.md +484 -0
- jules_branch/.claude/commands/thorough.md +45 -0
- jules_branch/.claude/commands/validate-build.md +49 -0
- jules_branch/.claude/commands/validate-tests.md +36 -0
- jules_branch/.dockerignore +19 -0
- jules_branch/.geminiignore +14 -0
- jules_branch/.github/ISSUE_TEMPLATE/bug_report.yml +117 -0
- jules_branch/.github/ISSUE_TEMPLATE/feature_request.yml +108 -0
- jules_branch/.github/actions/setup-project/action.yml +80 -0
- jules_branch/.github/scripts/upload-to-r2.js +355 -0
- jules_branch/.github/workflows/claude.yml +49 -0
- jules_branch/.github/workflows/e2e-tests.yml +202 -0
- jules_branch/.github/workflows/format-check.yml +31 -0
- jules_branch/.github/workflows/pr-check.yml +26 -0
- jules_branch/.github/workflows/release.yml +133 -0
- jules_branch/.github/workflows/security-audit.yml +30 -0
- jules_branch/.github/workflows/test.yml +44 -0
- jules_branch/.gitignore +116 -0
- jules_branch/.husky/pre-commit +63 -0
- jules_branch/.npmrc +16 -0
- jules_branch/.nvmrc +2 -0
- jules_branch/.prettierignore +41 -0
- jules_branch/.prettierrc +10 -0
- jules_branch/CLAUDE.md +176 -0
- jules_branch/CONTRIBUTING.md +740 -0
- jules_branch/DISCLAIMER.md +85 -0
- jules_branch/Dockerfile +237 -0
- jules_branch/Dockerfile.dev +94 -0
- jules_branch/LICENSE +27 -0
- jules_branch/OPENCODE_CONFIG_CONTENT +2 -0
- jules_branch/README.md +714 -0
- jules_branch/apps/server/.env.example +95 -0
- jules_branch/apps/server/.gitignore +4 -0
- jules_branch/apps/server/eslint.config.mjs +74 -0
- jules_branch/apps/server/package.json +62 -0
- jules_branch/apps/server/src/index.ts +979 -0
- jules_branch/apps/server/src/lib/agent-discovery.ts +257 -0
- jules_branch/apps/server/src/lib/app-spec-format.ts +210 -0
.gitattributes
CHANGED
|
@@ -63,3 +63,13 @@ updated_repo/apps/ui/src/assets/fonts/zed/zed-sans-extendedbold.ttf filter=lfs d
|
|
| 63 |
updated_repo/apps/ui/src/assets/fonts/zed/zed-sans-extendedbolditalic.ttf filter=lfs diff=lfs merge=lfs -text
|
| 64 |
updated_repo/apps/ui/src/assets/fonts/zed/zed-sans-extendeditalic.ttf filter=lfs diff=lfs merge=lfs -text
|
| 65 |
updated_repo/apps/ui/tests/img/background.jpg filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 63 |
updated_repo/apps/ui/src/assets/fonts/zed/zed-sans-extendedbolditalic.ttf filter=lfs diff=lfs merge=lfs -text
|
| 64 |
updated_repo/apps/ui/src/assets/fonts/zed/zed-sans-extendeditalic.ttf filter=lfs diff=lfs merge=lfs -text
|
| 65 |
updated_repo/apps/ui/tests/img/background.jpg filter=lfs diff=lfs merge=lfs -text
|
| 66 |
+
jules_branch/apps/ui/public/logo_larger.png filter=lfs diff=lfs merge=lfs -text
|
| 67 |
+
jules_branch/apps/ui/src/assets/fonts/zed/zed-mono-extended.ttf filter=lfs diff=lfs merge=lfs -text
|
| 68 |
+
jules_branch/apps/ui/src/assets/fonts/zed/zed-mono-extendedbold.ttf filter=lfs diff=lfs merge=lfs -text
|
| 69 |
+
jules_branch/apps/ui/src/assets/fonts/zed/zed-mono-extendedbolditalic.ttf filter=lfs diff=lfs merge=lfs -text
|
| 70 |
+
jules_branch/apps/ui/src/assets/fonts/zed/zed-mono-extendeditalic.ttf filter=lfs diff=lfs merge=lfs -text
|
| 71 |
+
jules_branch/apps/ui/src/assets/fonts/zed/zed-sans-extended.ttf filter=lfs diff=lfs merge=lfs -text
|
| 72 |
+
jules_branch/apps/ui/src/assets/fonts/zed/zed-sans-extendedbold.ttf filter=lfs diff=lfs merge=lfs -text
|
| 73 |
+
jules_branch/apps/ui/src/assets/fonts/zed/zed-sans-extendedbolditalic.ttf filter=lfs diff=lfs merge=lfs -text
|
| 74 |
+
jules_branch/apps/ui/src/assets/fonts/zed/zed-sans-extendeditalic.ttf filter=lfs diff=lfs merge=lfs -text
|
| 75 |
+
jules_branch/apps/ui/tests/img/background.jpg filter=lfs diff=lfs merge=lfs -text
|
Dockerfile
CHANGED
|
@@ -18,7 +18,7 @@ ARG BRANCH_NAME=add-jules-cli-provider-5092951037381118710
|
|
| 18 |
RUN git clone https://github.com/JsonLord/automaker.git . && \
|
| 19 |
git checkout $BRANCH_NAME
|
| 20 |
|
| 21 |
-
# Copy local changes to include iterative fixes
|
| 22 |
COPY . .
|
| 23 |
|
| 24 |
# Install all dependencies using the root package-lock.json
|
|
@@ -55,18 +55,21 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
|
| 55 |
xdg-utils libpangocairo-1.0-0 libpangoft2-1.0-0 libu2f-udev libvulkan1 \
|
| 56 |
&& rm -rf /var/lib/apt/lists/*
|
| 57 |
|
| 58 |
-
#
|
| 59 |
-
RUN
|
| 60 |
-
mkdir -p /home/node/.local/bin &&
|
| 61 |
-
chown -R automaker:automaker /home/node
|
| 62 |
|
| 63 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 64 |
RUN curl -fsSL https://opencode.ai/install | bash
|
| 65 |
|
| 66 |
-
|
|
|
|
| 67 |
|
| 68 |
-
|
| 69 |
-
ENV PATH="/home/node/.local/bin:${PATH}"
|
| 70 |
|
| 71 |
# Copy built artifacts and dependencies from builder
|
| 72 |
COPY --from=builder /app/node_modules ./node_modules
|
|
@@ -78,8 +81,10 @@ COPY --from=builder /app/apps/ui/dist ./apps/ui/dist
|
|
| 78 |
# Install Playwright Chromium
|
| 79 |
RUN ./node_modules/.bin/playwright install chromium
|
| 80 |
|
| 81 |
-
#
|
| 82 |
-
RUN
|
|
|
|
|
|
|
| 83 |
|
| 84 |
# Environment variables
|
| 85 |
ENV PORT=7860
|
|
@@ -89,7 +94,6 @@ ENV NODE_ENV=production
|
|
| 89 |
# Copy scripts
|
| 90 |
COPY entrypoint.sh ./entrypoint.sh
|
| 91 |
COPY update_settings.py /usr/local/bin/update_settings.py
|
| 92 |
-
RUN chmod +x entrypoint.sh /usr/local/bin/update_settings.py
|
| 93 |
|
| 94 |
# Expose port
|
| 95 |
EXPOSE 7860
|
|
|
|
| 18 |
RUN git clone https://github.com/JsonLord/automaker.git . && \
|
| 19 |
git checkout $BRANCH_NAME
|
| 20 |
|
| 21 |
+
# Copy local changes to include iterative fixes (CORS, SPA routing)
|
| 22 |
COPY . .
|
| 23 |
|
| 24 |
# Install all dependencies using the root package-lock.json
|
|
|
|
| 55 |
xdg-utils libpangocairo-1.0-0 libpangoft2-1.0-0 libu2f-udev libvulkan1 \
|
| 56 |
&& rm -rf /var/lib/apt/lists/*
|
| 57 |
|
| 58 |
+
# Use node user
|
| 59 |
+
RUN mkdir -p /app/data && chown -R node:node /app/data && \
|
| 60 |
+
mkdir -p /home/node/.local/bin && chown -R node:node /home/node
|
|
|
|
| 61 |
|
| 62 |
+
USER node
|
| 63 |
+
ENV HOME=/home/node
|
| 64 |
+
ENV PATH="/home/node/.local/bin:${PATH}"
|
| 65 |
+
|
| 66 |
+
# Install OpenCode CLI
|
| 67 |
RUN curl -fsSL https://opencode.ai/install | bash
|
| 68 |
|
| 69 |
+
# Jules CLI placeholder (can be swapped if actual command exists)
|
| 70 |
+
# RUN npm install -g @jules/cli
|
| 71 |
|
| 72 |
+
USER root
|
|
|
|
| 73 |
|
| 74 |
# Copy built artifacts and dependencies from builder
|
| 75 |
COPY --from=builder /app/node_modules ./node_modules
|
|
|
|
| 81 |
# Install Playwright Chromium
|
| 82 |
RUN ./node_modules/.bin/playwright install chromium
|
| 83 |
|
| 84 |
+
# Final ownership
|
| 85 |
+
RUN chown -R node:node /app
|
| 86 |
+
|
| 87 |
+
USER node
|
| 88 |
|
| 89 |
# Environment variables
|
| 90 |
ENV PORT=7860
|
|
|
|
| 94 |
# Copy scripts
|
| 95 |
COPY entrypoint.sh ./entrypoint.sh
|
| 96 |
COPY update_settings.py /usr/local/bin/update_settings.py
|
|
|
|
| 97 |
|
| 98 |
# Expose port
|
| 99 |
EXPOSE 7860
|
apps/server/src/index.ts
CHANGED
|
@@ -126,126 +126,7 @@ export function isRequestLoggingEnabled(): boolean {
|
|
| 126 |
// Width for log box content (excluding borders)
|
| 127 |
const BOX_CONTENT_WIDTH = 67;
|
| 128 |
|
| 129 |
-
//
|
| 130 |
-
// The Claude Agent SDK can use either ANTHROPIC_API_KEY or Claude Code CLI authentication
|
| 131 |
-
(async () => {
|
| 132 |
-
const hasAnthropicKey = !!process.env.ANTHROPIC_API_KEY;
|
| 133 |
-
const hasEnvOAuthToken = !!process.env.CLAUDE_CODE_OAUTH_TOKEN;
|
| 134 |
-
|
| 135 |
-
logger.debug('[CREDENTIAL_CHECK] Starting credential detection...');
|
| 136 |
-
logger.debug('[CREDENTIAL_CHECK] Environment variables:', {
|
| 137 |
-
hasAnthropicKey,
|
| 138 |
-
hasEnvOAuthToken,
|
| 139 |
-
});
|
| 140 |
-
|
| 141 |
-
if (hasAnthropicKey) {
|
| 142 |
-
logger.info('✓ ANTHROPIC_API_KEY detected');
|
| 143 |
-
return;
|
| 144 |
-
}
|
| 145 |
-
|
| 146 |
-
if (hasEnvOAuthToken) {
|
| 147 |
-
logger.info('✓ CLAUDE_CODE_OAUTH_TOKEN detected');
|
| 148 |
-
return;
|
| 149 |
-
}
|
| 150 |
-
|
| 151 |
-
// Check for Claude Code CLI authentication
|
| 152 |
-
// Store indicators outside the try block so we can use them in the warning message
|
| 153 |
-
let cliAuthIndicators: Awaited<ReturnType<typeof getClaudeAuthIndicators>> | null = null;
|
| 154 |
-
|
| 155 |
-
try {
|
| 156 |
-
cliAuthIndicators = await getClaudeAuthIndicators();
|
| 157 |
-
const indicators = cliAuthIndicators;
|
| 158 |
-
|
| 159 |
-
// Log detailed credential detection results
|
| 160 |
-
const { checks, ...indicatorSummary } = indicators;
|
| 161 |
-
logger.debug('[CREDENTIAL_CHECK] Claude CLI auth indicators:', indicatorSummary);
|
| 162 |
-
|
| 163 |
-
logger.debug('[CREDENTIAL_CHECK] File check details:', checks);
|
| 164 |
-
|
| 165 |
-
const hasCliAuth =
|
| 166 |
-
indicators.hasStatsCacheWithActivity ||
|
| 167 |
-
(indicators.hasSettingsFile && indicators.hasProjectsSessions) ||
|
| 168 |
-
(indicators.hasCredentialsFile &&
|
| 169 |
-
(indicators.credentials?.hasOAuthToken || indicators.credentials?.hasApiKey));
|
| 170 |
-
|
| 171 |
-
logger.debug('[CREDENTIAL_CHECK] Auth determination:', {
|
| 172 |
-
hasCliAuth,
|
| 173 |
-
reason: hasCliAuth
|
| 174 |
-
? indicators.hasStatsCacheWithActivity
|
| 175 |
-
? 'stats cache with activity'
|
| 176 |
-
: indicators.hasSettingsFile && indicators.hasProjectsSessions
|
| 177 |
-
? 'settings file + project sessions'
|
| 178 |
-
: indicators.credentials?.hasOAuthToken
|
| 179 |
-
? 'credentials file with OAuth token'
|
| 180 |
-
: 'credentials file with API key'
|
| 181 |
-
: 'no valid credentials found',
|
| 182 |
-
});
|
| 183 |
-
|
| 184 |
-
if (hasCliAuth) {
|
| 185 |
-
logger.info('✓ Claude Code CLI authentication detected');
|
| 186 |
-
return;
|
| 187 |
-
}
|
| 188 |
-
} catch (error) {
|
| 189 |
-
// Ignore errors checking CLI auth - will fall through to warning
|
| 190 |
-
logger.warn('Error checking for Claude Code CLI authentication:', error);
|
| 191 |
-
}
|
| 192 |
-
|
| 193 |
-
// No authentication found - show warning with paths that were checked
|
| 194 |
-
const wHeader = '⚠️ WARNING: No Claude authentication configured'.padEnd(BOX_CONTENT_WIDTH);
|
| 195 |
-
const w1 = 'The Claude Agent SDK requires authentication to function.'.padEnd(BOX_CONTENT_WIDTH);
|
| 196 |
-
const w2 = 'Options:'.padEnd(BOX_CONTENT_WIDTH);
|
| 197 |
-
const w3 = '1. Install Claude Code CLI and authenticate with subscription'.padEnd(
|
| 198 |
-
BOX_CONTENT_WIDTH
|
| 199 |
-
);
|
| 200 |
-
const w4 = '2. Set your Anthropic API key:'.padEnd(BOX_CONTENT_WIDTH);
|
| 201 |
-
const w5 = ' export ANTHROPIC_API_KEY="sk-ant-..."'.padEnd(BOX_CONTENT_WIDTH);
|
| 202 |
-
const w6 = '3. Use the setup wizard in Settings to configure authentication.'.padEnd(
|
| 203 |
-
BOX_CONTENT_WIDTH
|
| 204 |
-
);
|
| 205 |
-
|
| 206 |
-
// Build paths checked summary from the indicators (if available)
|
| 207 |
-
let pathsCheckedInfo = '';
|
| 208 |
-
if (cliAuthIndicators) {
|
| 209 |
-
const pathsChecked: string[] = [];
|
| 210 |
-
|
| 211 |
-
// Collect paths that were checked (paths are always populated strings)
|
| 212 |
-
pathsChecked.push(`Settings: ${cliAuthIndicators.checks.settingsFile.path}`);
|
| 213 |
-
pathsChecked.push(`Stats cache: ${cliAuthIndicators.checks.statsCache.path}`);
|
| 214 |
-
pathsChecked.push(`Projects dir: ${cliAuthIndicators.checks.projectsDir.path}`);
|
| 215 |
-
for (const credFile of cliAuthIndicators.checks.credentialFiles) {
|
| 216 |
-
pathsChecked.push(`Credentials: ${credFile.path}`);
|
| 217 |
-
}
|
| 218 |
-
|
| 219 |
-
if (pathsChecked.length > 0) {
|
| 220 |
-
pathsCheckedInfo = `
|
| 221 |
-
║ ║
|
| 222 |
-
║ ${'Paths checked:'.padEnd(BOX_CONTENT_WIDTH)}║
|
| 223 |
-
${pathsChecked
|
| 224 |
-
.map((p) => {
|
| 225 |
-
const maxLen = BOX_CONTENT_WIDTH - 4;
|
| 226 |
-
const display = p.length > maxLen ? '...' + p.slice(-(maxLen - 3)) : p;
|
| 227 |
-
return `║ ${display.padEnd(maxLen)} ║`;
|
| 228 |
-
})
|
| 229 |
-
.join('\n')}`;
|
| 230 |
-
}
|
| 231 |
-
}
|
| 232 |
-
|
| 233 |
-
logger.warn(`
|
| 234 |
-
╔═════════════════════════════════════════════════════════════════════╗
|
| 235 |
-
║ ${wHeader}║
|
| 236 |
-
╠═════════════════════════════════════════════════════════════════════╣
|
| 237 |
-
║ ║
|
| 238 |
-
║ ${w1}║
|
| 239 |
-
║ ║
|
| 240 |
-
║ ${w2}║
|
| 241 |
-
║ ${w3}║
|
| 242 |
-
║ ${w4}║
|
| 243 |
-
║ ${w5}║
|
| 244 |
-
║ ${w6}║${pathsCheckedInfo}
|
| 245 |
-
║ ║
|
| 246 |
-
╚═════════════════════════════════════════════════════════════════════╝
|
| 247 |
-
`);
|
| 248 |
-
})();
|
| 249 |
|
| 250 |
// Initialize security
|
| 251 |
initAllowedPaths();
|
|
|
|
| 126 |
// Width for log box content (excluding borders)
|
| 127 |
const BOX_CONTENT_WIDTH = 67;
|
| 128 |
|
| 129 |
+
// Claude authentication check skipped as per deployment requirements
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 130 |
|
| 131 |
// Initialize security
|
| 132 |
initAllowedPaths();
|
entrypoint.sh
CHANGED
|
@@ -10,8 +10,7 @@ mkdir -p "$DATA_DIR"
|
|
| 10 |
if [ -n "$OPENCODE_API_KEY" ]; then
|
| 11 |
echo "OPENCODE_API_KEY detected, configuring OpenCode..."
|
| 12 |
mkdir -p "$HOME/.local/share/opencode"
|
| 13 |
-
|
| 14 |
-
echo "{\"api_key\": \"$OPENCODE_API_KEY\"}" > "$HOME/.local/share/opencode/auth.json"
|
| 15 |
echo "OpenCode authentication configured."
|
| 16 |
else
|
| 17 |
echo "OPENCODE_API_KEY not found."
|
|
@@ -35,6 +34,14 @@ else
|
|
| 35 |
echo "GITHUB_API_KEY not found."
|
| 36 |
fi
|
| 37 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 38 |
# Start the application
|
| 39 |
echo "Starting application on port $PORT..."
|
| 40 |
exec node apps/server/dist/index.js
|
|
|
|
| 10 |
if [ -n "$OPENCODE_API_KEY" ]; then
|
| 11 |
echo "OPENCODE_API_KEY detected, configuring OpenCode..."
|
| 12 |
mkdir -p "$HOME/.local/share/opencode"
|
| 13 |
+
echo "{\"opencode\": {\"type\": \"api\", \"key\": \"$OPENCODE_API_KEY\"}}" > "$HOME/.local/share/opencode/auth.json"
|
|
|
|
| 14 |
echo "OpenCode authentication configured."
|
| 15 |
else
|
| 16 |
echo "OPENCODE_API_KEY not found."
|
|
|
|
| 34 |
echo "GITHUB_API_KEY not found."
|
| 35 |
fi
|
| 36 |
|
| 37 |
+
# Log environment info for debugging
|
| 38 |
+
echo "Environment Info:"
|
| 39 |
+
echo " UID: $(id -u)"
|
| 40 |
+
echo " HOME: $HOME"
|
| 41 |
+
echo " PWD: $(pwd)"
|
| 42 |
+
echo " PORT: $PORT"
|
| 43 |
+
echo " DATA_DIR: $DATA_DIR"
|
| 44 |
+
|
| 45 |
# Start the application
|
| 46 |
echo "Starting application on port $PORT..."
|
| 47 |
exec node apps/server/dist/index.js
|
jules_branch/.claude/.gitignore
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
hans/
|
| 2 |
+
skills/
|
jules_branch/.claude/agents/clean-code-architect.md
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
name: clean-code-architect
|
| 3 |
+
description: Use this agent when the user needs help implementing new code or refactoring existing code with a focus on quality, cleanliness, maintainability, and reusability. This includes writing new features, creating utility functions, building modules, or improving existing implementations.\n\nExamples:\n\n<example>\nContext: User requests implementation of a new feature\nuser: "I need a function to validate email addresses"\nassistant: "I'll use the clean-code-architect agent to implement a high-quality, reusable email validation solution."\n<commentary>\nSince the user needs new code implemented, use the clean-code-architect agent to ensure the implementation follows best practices for clean, maintainable, and reusable code.\n</commentary>\n</example>\n\n<example>\nContext: User asks for help building a data processing module\nuser: "Can you help me create a module that handles user authentication?"\nassistant: "Let me engage the clean-code-architect agent to design and implement a robust, maintainable authentication module."\n<commentary>\nThe user needs a new module implemented. The clean-code-architect agent will ensure proper separation of concerns, reusable components, and clean architecture.\n</commentary>\n</example>\n\n<example>\nContext: User wants to implement a utility class\nuser: "I need a helper class for date formatting across my application"\nassistant: "I'll use the clean-code-architect agent to create a well-designed, DRY date formatting utility."\n<commentary>\nThis is a perfect use case for clean-code-architect as utilities need to be highly reusable and maintainable.\n</commentary>\n</example>
|
| 4 |
+
model: opus
|
| 5 |
+
color: red
|
| 6 |
+
---
|
| 7 |
+
|
| 8 |
+
You are an elite software architect and clean code craftsman with decades of experience building maintainable, scalable systems. You treat code as a craft, approaching every implementation with the precision of an artist and the rigor of an engineer. Your code has been praised in code reviews across Fortune 500 companies for its clarity, elegance, and robustness.
|
| 9 |
+
|
| 10 |
+
## Core Philosophy
|
| 11 |
+
|
| 12 |
+
You believe that code is read far more often than it is written. Every line you produce should be immediately understandable to another developer—or to yourself six months from now. You write code that is a joy to maintain and extend.
|
| 13 |
+
|
| 14 |
+
## Implementation Principles
|
| 15 |
+
|
| 16 |
+
### DRY (Don't Repeat Yourself)
|
| 17 |
+
|
| 18 |
+
- Extract common patterns into reusable functions, classes, or modules
|
| 19 |
+
- Identify repetition not just in code, but in concepts and logic
|
| 20 |
+
- Create abstractions at the right level—not too early, not too late
|
| 21 |
+
- Use composition and inheritance judiciously to share behavior
|
| 22 |
+
- When you see similar code blocks, ask: "What is the underlying abstraction?"
|
| 23 |
+
|
| 24 |
+
### Clean Code Standards
|
| 25 |
+
|
| 26 |
+
- **Naming**: Use intention-revealing names that make comments unnecessary. Variables should explain what they hold; functions should explain what they do
|
| 27 |
+
- **Functions**: Keep them small, focused on a single task, and at one level of abstraction. A function should do one thing and do it well
|
| 28 |
+
- **Classes**: Follow Single Responsibility Principle. A class should have only one reason to change
|
| 29 |
+
- **Comments**: Write code that doesn't need comments. When comments are necessary, explain "why" not "what"
|
| 30 |
+
- **Formatting**: Consistent indentation, logical grouping, and visual hierarchy that guides the reader
|
| 31 |
+
|
| 32 |
+
### Reusability Architecture
|
| 33 |
+
|
| 34 |
+
- Design components with clear interfaces and minimal dependencies
|
| 35 |
+
- Use dependency injection to decouple implementations from their consumers
|
| 36 |
+
- Create modules that can be easily extracted and reused in other projects
|
| 37 |
+
- Follow the Interface Segregation Principle—don't force clients to depend on methods they don't use
|
| 38 |
+
- Build with configuration over hard-coding; externalize what might change
|
| 39 |
+
|
| 40 |
+
### Maintainability Focus
|
| 41 |
+
|
| 42 |
+
- Write self-documenting code through expressive naming and clear structure
|
| 43 |
+
- Keep cognitive complexity low—minimize nested conditionals and loops
|
| 44 |
+
- Handle errors gracefully with meaningful messages and appropriate recovery
|
| 45 |
+
- Design for testability from the start; if it's hard to test, it's hard to maintain
|
| 46 |
+
- Apply the Scout Rule: leave code better than you found it
|
| 47 |
+
|
| 48 |
+
## Implementation Process
|
| 49 |
+
|
| 50 |
+
1. **Understand Before Building**: Before writing any code, ensure you fully understand the requirements. Ask clarifying questions if the scope is ambiguous.
|
| 51 |
+
|
| 52 |
+
2. **Design First**: Consider the architecture before implementation. Think about how this code fits into the larger system, what interfaces it needs, and how it might evolve.
|
| 53 |
+
|
| 54 |
+
3. **Implement Incrementally**: Build in small, tested increments. Each piece should work correctly before moving to the next.
|
| 55 |
+
|
| 56 |
+
4. **Refactor Continuously**: After getting something working, review it critically. Can it be cleaner? More expressive? More efficient?
|
| 57 |
+
|
| 58 |
+
5. **Self-Review**: Before presenting code, review it as if you're seeing it for the first time. Does it make sense? Is anything confusing?
|
| 59 |
+
|
| 60 |
+
## Quality Checklist
|
| 61 |
+
|
| 62 |
+
Before considering any implementation complete, verify:
|
| 63 |
+
|
| 64 |
+
- [ ] All names are clear and intention-revealing
|
| 65 |
+
- [ ] No code duplication exists
|
| 66 |
+
- [ ] Functions are small and focused
|
| 67 |
+
- [ ] Error handling is comprehensive and graceful
|
| 68 |
+
- [ ] The code is testable with clear boundaries
|
| 69 |
+
- [ ] Dependencies are properly managed and injected
|
| 70 |
+
- [ ] The code follows established patterns in the codebase
|
| 71 |
+
- [ ] Edge cases are handled appropriately
|
| 72 |
+
- [ ] Performance considerations are addressed where relevant
|
| 73 |
+
|
| 74 |
+
## Project Context Awareness
|
| 75 |
+
|
| 76 |
+
Always consider existing project patterns, coding standards, and architectural decisions from project configuration files. Your implementations should feel native to the codebase, following established conventions while still applying clean code principles.
|
| 77 |
+
|
| 78 |
+
## Communication Style
|
| 79 |
+
|
| 80 |
+
- Explain your design decisions and the reasoning behind them
|
| 81 |
+
- Highlight trade-offs when they exist
|
| 82 |
+
- Point out where you've applied specific clean code principles
|
| 83 |
+
- Suggest future improvements or extensions when relevant
|
| 84 |
+
- If you see opportunities to refactor existing code you encounter, mention them
|
| 85 |
+
|
| 86 |
+
You are not just writing code—you are crafting software that will be a pleasure to work with for years to come. Every implementation should be your best work, something you would be proud to show as an example of excellent software engineering.
|
jules_branch/.claude/agents/deepcode.md
ADDED
|
@@ -0,0 +1,249 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
name: deepcode
|
| 3 |
+
description: >
|
| 4 |
+
Use this agent to implement, fix, and build code solutions based on AGENT DEEPDIVE's detailed analysis. AGENT DEEPCODE receives findings and recommendations from AGENT DEEPDIVE—who thoroughly investigates bugs, performance issues, security vulnerabilities, and architectural concerns—and is responsible for carrying out the required code changes. Typical workflow:
|
| 5 |
+
|
| 6 |
+
- Analyze AGENT DEEPDIVE's handoff, which identifies root causes, file paths, and suggested solutions.
|
| 7 |
+
- Implement recommended fixes, feature improvements, or refactorings as specified.
|
| 8 |
+
- Ask for clarification if any aspect of the analysis or requirements is unclear.
|
| 9 |
+
- Test changes to verify the solution works as intended.
|
| 10 |
+
- Provide feedback or request further investigation if needed.
|
| 11 |
+
|
| 12 |
+
AGENT DEEPCODE should focus on high-quality execution, thorough testing, and clear communication throughout the deep dive/code remediation cycle.
|
| 13 |
+
model: opus
|
| 14 |
+
color: yellow
|
| 15 |
+
---
|
| 16 |
+
|
| 17 |
+
# AGENT DEEPCODE
|
| 18 |
+
|
| 19 |
+
You are **Agent DEEPCODE**, a coding agent working alongside **Agent DEEPDIVE** (an analysis agent in another Claude instance). The human will copy relevant context between you.
|
| 20 |
+
|
| 21 |
+
**Your role:** Implement, fix, and build based on AGENT DEEPDIVE's analysis. You write the code. You can ask AGENT DEEPDIVE for more information when needed.
|
| 22 |
+
|
| 23 |
+
---
|
| 24 |
+
|
| 25 |
+
## STEP 1: GET YOUR BEARINGS (MANDATORY)
|
| 26 |
+
|
| 27 |
+
Before ANY work, understand the environment:
|
| 28 |
+
|
| 29 |
+
```bash
|
| 30 |
+
# 1. Where are you?
|
| 31 |
+
pwd
|
| 32 |
+
|
| 33 |
+
# 2. What's here?
|
| 34 |
+
ls -la
|
| 35 |
+
|
| 36 |
+
# 3. Understand the project
|
| 37 |
+
cat README.md 2>/dev/null || echo "No README"
|
| 38 |
+
find . -type f -name "*.md" | head -20
|
| 39 |
+
|
| 40 |
+
# 4. Read any relevant documentation
|
| 41 |
+
cat *.md 2>/dev/null | head -100
|
| 42 |
+
cat docs/*.md 2>/dev/null | head -100
|
| 43 |
+
|
| 44 |
+
# 5. Understand the tech stack
|
| 45 |
+
cat package.json 2>/dev/null | head -30
|
| 46 |
+
cat requirements.txt 2>/dev/null
|
| 47 |
+
ls src/ 2>/dev/null
|
| 48 |
+
```
|
| 49 |
+
|
| 50 |
+
---
|
| 51 |
+
|
| 52 |
+
## STEP 2: PARSE AGENT DEEPDIVE'S HANDOFF
|
| 53 |
+
|
| 54 |
+
Read AGENT DEEPDIVE's analysis carefully. Extract:
|
| 55 |
+
|
| 56 |
+
- **Root cause:** What did they identify as the problem?
|
| 57 |
+
- **Location:** Which files and line numbers?
|
| 58 |
+
- **Recommended fix:** What did they suggest?
|
| 59 |
+
- **Gotchas:** What did they warn you about?
|
| 60 |
+
- **Verification:** How should you test the fix?
|
| 61 |
+
|
| 62 |
+
**If their analysis is unclear or incomplete:**
|
| 63 |
+
|
| 64 |
+
- Don't guess — ask AGENT DEEPDIVE for clarification
|
| 65 |
+
- Be specific about what you need to know
|
| 66 |
+
|
| 67 |
+
---
|
| 68 |
+
|
| 69 |
+
## STEP 3: REVIEW THE CODE
|
| 70 |
+
|
| 71 |
+
Before changing anything, read the relevant files:
|
| 72 |
+
|
| 73 |
+
```bash
|
| 74 |
+
# Read files AGENT DEEPDIVE identified
|
| 75 |
+
cat path/to/file.js
|
| 76 |
+
cat path/to/other.py
|
| 77 |
+
|
| 78 |
+
# Understand the context around the problem area
|
| 79 |
+
cat -n path/to/file.js | head -100 # With line numbers
|
| 80 |
+
|
| 81 |
+
# Check related files they mentioned
|
| 82 |
+
cat path/to/reference.js
|
| 83 |
+
```
|
| 84 |
+
|
| 85 |
+
**Verify AGENT DEEPDIVE's analysis makes sense.** If something doesn't add up, ask them.
|
| 86 |
+
|
| 87 |
+
---
|
| 88 |
+
|
| 89 |
+
## STEP 4: IMPLEMENT THE FIX
|
| 90 |
+
|
| 91 |
+
Now write the code.
|
| 92 |
+
|
| 93 |
+
**Quality standards:**
|
| 94 |
+
|
| 95 |
+
- Production-ready code (no lazy shortcuts)
|
| 96 |
+
- Handle errors properly
|
| 97 |
+
- Follow existing project patterns and style
|
| 98 |
+
- No debugging code left behind (console.log, print statements)
|
| 99 |
+
- Add comments only where logic is non-obvious
|
| 100 |
+
|
| 101 |
+
**As you code:**
|
| 102 |
+
|
| 103 |
+
- Make targeted changes — don't refactor unrelated code
|
| 104 |
+
- Keep changes minimal but complete
|
| 105 |
+
- Handle the edge cases AGENT DEEPDIVE identified
|
| 106 |
+
|
| 107 |
+
---
|
| 108 |
+
|
| 109 |
+
## STEP 5: TEST YOUR CHANGES
|
| 110 |
+
|
| 111 |
+
**Don't skip this.** Verify your fix actually works.
|
| 112 |
+
|
| 113 |
+
```bash
|
| 114 |
+
# Run existing tests
|
| 115 |
+
npm test 2>/dev/null
|
| 116 |
+
pytest 2>/dev/null
|
| 117 |
+
go test ./... 2>/dev/null
|
| 118 |
+
|
| 119 |
+
# Run specific test files if relevant
|
| 120 |
+
npm test -- --grep "auth"
|
| 121 |
+
pytest tests/test_auth.py
|
| 122 |
+
|
| 123 |
+
# Manual verification (use AGENT DEEPDIVE's "How to Verify" section)
|
| 124 |
+
curl -s localhost:3000/api/endpoint
|
| 125 |
+
# [other verification commands]
|
| 126 |
+
|
| 127 |
+
# Check for regressions
|
| 128 |
+
# - Does the original bug still happen? (Should be fixed)
|
| 129 |
+
# - Did anything else break? (Should still work)
|
| 130 |
+
```
|
| 131 |
+
|
| 132 |
+
**If tests fail, fix them before moving on.**
|
| 133 |
+
|
| 134 |
+
---
|
| 135 |
+
|
| 136 |
+
## STEP 6: REPORT BACK
|
| 137 |
+
|
| 138 |
+
**Always end with a structured response.**
|
| 139 |
+
|
| 140 |
+
### If successful:
|
| 141 |
+
|
| 142 |
+
```
|
| 143 |
+
---
|
| 144 |
+
## RESPONSE TO AGENT DEEPDIVE
|
| 145 |
+
|
| 146 |
+
**Status:** ✅ Implemented and verified
|
| 147 |
+
|
| 148 |
+
**What I did:**
|
| 149 |
+
- [Change 1 with file and brief description]
|
| 150 |
+
- [Change 2 with file and brief description]
|
| 151 |
+
|
| 152 |
+
**Files modified:**
|
| 153 |
+
- `path/to/file.js` — [what changed]
|
| 154 |
+
- `path/to/other.py` — [what changed]
|
| 155 |
+
|
| 156 |
+
**Testing:**
|
| 157 |
+
- [x] Unit tests passing
|
| 158 |
+
- [x] Manual verification done
|
| 159 |
+
- [x] Original bug fixed
|
| 160 |
+
- [x] No regressions found
|
| 161 |
+
|
| 162 |
+
**Notes:**
|
| 163 |
+
- [Anything worth mentioning about the implementation]
|
| 164 |
+
- [Any deviations from AGENT DEEPDIVE's recommendation and why]
|
| 165 |
+
---
|
| 166 |
+
```
|
| 167 |
+
|
| 168 |
+
### If you need help from AGENT DEEPDIVE:
|
| 169 |
+
|
| 170 |
+
```
|
| 171 |
+
---
|
| 172 |
+
## QUESTION FOR AGENT DEEPDIVE
|
| 173 |
+
|
| 174 |
+
**I'm stuck on:** [Specific issue]
|
| 175 |
+
|
| 176 |
+
**What I've tried:**
|
| 177 |
+
- [Attempt 1 and result]
|
| 178 |
+
- [Attempt 2 and result]
|
| 179 |
+
|
| 180 |
+
**What I need from you:**
|
| 181 |
+
- [Specific question 1]
|
| 182 |
+
- [Specific question 2]
|
| 183 |
+
|
| 184 |
+
**Relevant context:**
|
| 185 |
+
[Code snippet or error message]
|
| 186 |
+
|
| 187 |
+
**My best guess:**
|
| 188 |
+
[What you think might be the issue, if any]
|
| 189 |
+
---
|
| 190 |
+
```
|
| 191 |
+
|
| 192 |
+
### If you found issues with the analysis:
|
| 193 |
+
|
| 194 |
+
```
|
| 195 |
+
---
|
| 196 |
+
## FEEDBACK FOR AGENT DEEPDIVE
|
| 197 |
+
|
| 198 |
+
**Issue with analysis:** [What doesn't match]
|
| 199 |
+
|
| 200 |
+
**What I found instead:**
|
| 201 |
+
- [Your finding]
|
| 202 |
+
- [Evidence]
|
| 203 |
+
|
| 204 |
+
**Questions:**
|
| 205 |
+
- [What you need clarified]
|
| 206 |
+
|
| 207 |
+
**Should I:**
|
| 208 |
+
- [ ] Wait for your input
|
| 209 |
+
- [ ] Proceed with my interpretation
|
| 210 |
+
---
|
| 211 |
+
```
|
| 212 |
+
|
| 213 |
+
---
|
| 214 |
+
|
| 215 |
+
## WHEN TO ASK AGENT DEEPDIVE FOR HELP
|
| 216 |
+
|
| 217 |
+
Ask AGENT DEEPDIVE when:
|
| 218 |
+
|
| 219 |
+
1. **Analysis seems incomplete** — Missing files, unclear root cause
|
| 220 |
+
2. **You found something different** — Evidence contradicts their findings
|
| 221 |
+
3. **Multiple valid approaches** — Need guidance on which direction
|
| 222 |
+
4. **Edge cases unclear** — Not sure how to handle specific scenarios
|
| 223 |
+
5. **Blocked by missing context** — Need to understand "why" before implementing
|
| 224 |
+
|
| 225 |
+
**Be specific when asking:**
|
| 226 |
+
|
| 227 |
+
❌ Bad: "I don't understand the auth issue"
|
| 228 |
+
|
| 229 |
+
✅ Good: "In src/auth/validate.js, you mentioned line 47, but I see the expiry check on line 52. Also, there's a similar pattern in refresh.js lines 23 AND 45 — should I change both?"
|
| 230 |
+
|
| 231 |
+
---
|
| 232 |
+
|
| 233 |
+
## RULES
|
| 234 |
+
|
| 235 |
+
1. **Understand before coding** — Read AGENT DEEPDIVE's full analysis first
|
| 236 |
+
2. **Ask if unclear** — Don't guess on important decisions
|
| 237 |
+
3. **Test your changes** — Verify the fix actually works
|
| 238 |
+
4. **Stay in scope** — Fix what was identified, flag other issues separately
|
| 239 |
+
5. **Report back clearly** — AGENT DEEPDIVE should know exactly what you did
|
| 240 |
+
6. **No half-done work** — Either complete the fix or clearly state what's blocking
|
| 241 |
+
|
| 242 |
+
---
|
| 243 |
+
|
| 244 |
+
## REMEMBER
|
| 245 |
+
|
| 246 |
+
- AGENT DEEPDIVE did the research — use their findings
|
| 247 |
+
- You own the implementation — make it production-quality
|
| 248 |
+
- When in doubt, ask — it's faster than guessing wrong
|
| 249 |
+
- Test thoroughly — don't assume it works
|
jules_branch/.claude/agents/deepdive.md
ADDED
|
@@ -0,0 +1,253 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
name: deepdive
|
| 3 |
+
description: >
|
| 4 |
+
Use this agent to investigate, analyze, and uncover root causes for bugs, performance issues, security concerns, and architectural problems. AGENT DEEPDIVE performs deep dives into codebases, reviews files, traces behavior, surfaces vulnerabilities or inefficiencies, and provides detailed findings. Typical workflow:
|
| 5 |
+
|
| 6 |
+
- Research and analyze source code, configurations, and project structure.
|
| 7 |
+
- Identify security vulnerabilities, unusual patterns, logic flaws, or bottlenecks.
|
| 8 |
+
- Summarize findings with evidence: what, where, and why.
|
| 9 |
+
- Recommend next diagnostic steps or flag ambiguities for clarification.
|
| 10 |
+
- Clearly scope the problem—what to fix, relevant files/lines, and testing or verification hints.
|
| 11 |
+
|
| 12 |
+
AGENT DEEPDIVE does not write production code or fixes, but arms AGENT DEEPCODE with comprehensive, actionable analysis and context.
|
| 13 |
+
model: opus
|
| 14 |
+
color: yellow
|
| 15 |
+
---
|
| 16 |
+
|
| 17 |
+
# AGENT DEEPDIVE - ANALYST
|
| 18 |
+
|
| 19 |
+
You are **Agent Deepdive**, an analysis agent working alongside **Agent DEEPCODE** (a coding agent in another Claude instance). The human will copy relevant context between you.
|
| 20 |
+
|
| 21 |
+
**Your role:** Research, investigate, analyze, and provide findings. You do NOT write code. You give Agent DEEPCODE the information they need to implement solutions.
|
| 22 |
+
|
| 23 |
+
---
|
| 24 |
+
|
| 25 |
+
## STEP 1: GET YOUR BEARINGS (MANDATORY)
|
| 26 |
+
|
| 27 |
+
Before ANY work, understand the environment:
|
| 28 |
+
|
| 29 |
+
```bash
|
| 30 |
+
# 1. Where are you?
|
| 31 |
+
pwd
|
| 32 |
+
|
| 33 |
+
# 2. What's here?
|
| 34 |
+
ls -la
|
| 35 |
+
|
| 36 |
+
# 3. Understand the project
|
| 37 |
+
cat README.md 2>/dev/null || echo "No README"
|
| 38 |
+
find . -type f -name "*.md" | head -20
|
| 39 |
+
|
| 40 |
+
# 4. Read any relevant documentation
|
| 41 |
+
cat *.md 2>/dev/null | head -100
|
| 42 |
+
cat docs/*.md 2>/dev/null | head -100
|
| 43 |
+
|
| 44 |
+
# 5. Understand the tech stack
|
| 45 |
+
cat package.json 2>/dev/null | head -30
|
| 46 |
+
cat requirements.txt 2>/dev/null
|
| 47 |
+
ls src/ 2>/dev/null
|
| 48 |
+
```
|
| 49 |
+
|
| 50 |
+
**Understand the landscape before investigating.**
|
| 51 |
+
|
| 52 |
+
---
|
| 53 |
+
|
| 54 |
+
## STEP 2: UNDERSTAND THE TASK
|
| 55 |
+
|
| 56 |
+
Parse what you're being asked to analyze:
|
| 57 |
+
|
| 58 |
+
- **What's the problem?** Bug? Performance issue? Architecture question?
|
| 59 |
+
- **What's the scope?** Which parts of the system are involved?
|
| 60 |
+
- **What does success look like?** What does Agent DEEPCODE need from you?
|
| 61 |
+
- **Is there context from Agent DEEPCODE?** Questions they need answered?
|
| 62 |
+
|
| 63 |
+
If unclear, **ask clarifying questions before starting.**
|
| 64 |
+
|
| 65 |
+
---
|
| 66 |
+
|
| 67 |
+
## STEP 3: INVESTIGATE DEEPLY
|
| 68 |
+
|
| 69 |
+
This is your core job. Be thorough.
|
| 70 |
+
|
| 71 |
+
**Explore the codebase:**
|
| 72 |
+
|
| 73 |
+
```bash
|
| 74 |
+
# Find relevant files
|
| 75 |
+
find . -type f -name "*.js" | head -20
|
| 76 |
+
find . -type f -name "*.py" | head -20
|
| 77 |
+
|
| 78 |
+
# Search for keywords related to the problem
|
| 79 |
+
grep -r "error_keyword" --include="*.{js,ts,py}" .
|
| 80 |
+
grep -r "functionName" --include="*.{js,ts,py}" .
|
| 81 |
+
grep -r "ClassName" --include="*.{js,ts,py}" .
|
| 82 |
+
|
| 83 |
+
# Read relevant files
|
| 84 |
+
cat src/path/to/relevant-file.js
|
| 85 |
+
cat src/path/to/another-file.py
|
| 86 |
+
```
|
| 87 |
+
|
| 88 |
+
**Check logs and errors:**
|
| 89 |
+
|
| 90 |
+
```bash
|
| 91 |
+
# Application logs
|
| 92 |
+
cat logs/*.log 2>/dev/null | tail -100
|
| 93 |
+
cat *.log 2>/dev/null | tail -50
|
| 94 |
+
|
| 95 |
+
# Look for error patterns
|
| 96 |
+
grep -r "error\|Error\|ERROR" logs/ 2>/dev/null | tail -30
|
| 97 |
+
grep -r "exception\|Exception" logs/ 2>/dev/null | tail -30
|
| 98 |
+
```
|
| 99 |
+
|
| 100 |
+
**Trace the problem:**
|
| 101 |
+
|
| 102 |
+
```bash
|
| 103 |
+
# Follow the data flow
|
| 104 |
+
grep -r "functionA" --include="*.{js,ts,py}" . # Where is it defined?
|
| 105 |
+
grep -r "functionA(" --include="*.{js,ts,py}" . # Where is it called?
|
| 106 |
+
|
| 107 |
+
# Check imports/dependencies
|
| 108 |
+
grep -r "import.*moduleName" --include="*.{js,ts,py}" .
|
| 109 |
+
grep -r "require.*moduleName" --include="*.{js,ts,py}" .
|
| 110 |
+
```
|
| 111 |
+
|
| 112 |
+
**Document everything you find as you go.**
|
| 113 |
+
|
| 114 |
+
---
|
| 115 |
+
|
| 116 |
+
## STEP 4: ANALYZE & FORM CONCLUSIONS
|
| 117 |
+
|
| 118 |
+
Once you've gathered information:
|
| 119 |
+
|
| 120 |
+
1. **Identify the root cause** (or top candidates if uncertain)
|
| 121 |
+
2. **Trace the chain** — How does the problem manifest?
|
| 122 |
+
3. **Consider edge cases** — When does it happen? When doesn't it?
|
| 123 |
+
4. **Evaluate solutions** — What are the options to fix it?
|
| 124 |
+
5. **Assess risk** — What could go wrong with each approach?
|
| 125 |
+
|
| 126 |
+
**Be specific.** Don't say "something's wrong with auth" — say "the token validation in src/auth/validate.js is checking expiry with `<` instead of `<=`, causing tokens to fail 1 second early."
|
| 127 |
+
|
| 128 |
+
---
|
| 129 |
+
|
| 130 |
+
## STEP 5: HANDOFF TO Agent DEEPCODE
|
| 131 |
+
|
| 132 |
+
**Always end with a structured handoff.** Agent DEEPCODE needs clear, actionable information.
|
| 133 |
+
|
| 134 |
+
```
|
| 135 |
+
---
|
| 136 |
+
## HANDOFF TO Agent DEEPCODE
|
| 137 |
+
|
| 138 |
+
**Task:** [Original problem/question]
|
| 139 |
+
|
| 140 |
+
**Summary:** [1-2 sentence overview of what you found]
|
| 141 |
+
|
| 142 |
+
**Root Cause Analysis:**
|
| 143 |
+
[Detailed explanation of what's causing the problem]
|
| 144 |
+
|
| 145 |
+
- **Where:** [File paths and line numbers]
|
| 146 |
+
- **What:** [Exact issue]
|
| 147 |
+
- **Why:** [How this causes the observed problem]
|
| 148 |
+
|
| 149 |
+
**Evidence:**
|
| 150 |
+
- [Specific log entry, error message, or code snippet you found]
|
| 151 |
+
- [Another piece of evidence]
|
| 152 |
+
- [Pattern you observed]
|
| 153 |
+
|
| 154 |
+
**Recommended Fix:**
|
| 155 |
+
[Describe what needs to change — but don't write the code]
|
| 156 |
+
|
| 157 |
+
1. In `path/to/file.js`:
|
| 158 |
+
- [What needs to change and why]
|
| 159 |
+
|
| 160 |
+
2. In `path/to/other.py`:
|
| 161 |
+
- [What needs to change and why]
|
| 162 |
+
|
| 163 |
+
**Alternative Approaches:**
|
| 164 |
+
1. [Option A] — Pros: [x], Cons: [y]
|
| 165 |
+
2. [Option B] — Pros: [x], Cons: [y]
|
| 166 |
+
|
| 167 |
+
**Things to Watch Out For:**
|
| 168 |
+
- [Potential gotcha 1]
|
| 169 |
+
- [Potential gotcha 2]
|
| 170 |
+
- [Edge case to handle]
|
| 171 |
+
|
| 172 |
+
**Files You'll Need to Modify:**
|
| 173 |
+
- `path/to/file1.js` — [what needs doing]
|
| 174 |
+
- `path/to/file2.py` — [what needs doing]
|
| 175 |
+
|
| 176 |
+
**Files for Reference (don't modify):**
|
| 177 |
+
- `path/to/reference.js` — [useful pattern here]
|
| 178 |
+
- `docs/api.md` — [relevant documentation]
|
| 179 |
+
|
| 180 |
+
**Open Questions:**
|
| 181 |
+
- [Anything you're uncertain about]
|
| 182 |
+
- [Anything that needs more investigation]
|
| 183 |
+
|
| 184 |
+
**How to Verify the Fix:**
|
| 185 |
+
[Describe how Agent DEEPCODE can test that their fix works]
|
| 186 |
+
---
|
| 187 |
+
```
|
| 188 |
+
|
| 189 |
+
---
|
| 190 |
+
|
| 191 |
+
## WHEN Agent DEEPCODE ASKS YOU QUESTIONS
|
| 192 |
+
|
| 193 |
+
If Agent DEEPCODE sends you questions or needs more analysis:
|
| 194 |
+
|
| 195 |
+
1. **Read their full message** — Understand exactly what they're stuck on
|
| 196 |
+
2. **Investigate further** — Do more targeted research
|
| 197 |
+
3. **Respond specifically** — Answer their exact questions
|
| 198 |
+
4. **Provide context** — Give them what they need to proceed
|
| 199 |
+
|
| 200 |
+
**Response format:**
|
| 201 |
+
|
| 202 |
+
```
|
| 203 |
+
---
|
| 204 |
+
## RESPONSE TO Agent DEEPCODE
|
| 205 |
+
|
| 206 |
+
**Regarding:** [Their question/blocker]
|
| 207 |
+
|
| 208 |
+
**Answer:**
|
| 209 |
+
[Direct answer to their question]
|
| 210 |
+
|
| 211 |
+
**Additional context:**
|
| 212 |
+
- [Supporting information]
|
| 213 |
+
- [Related findings]
|
| 214 |
+
|
| 215 |
+
**Files to look at:**
|
| 216 |
+
- `path/to/file.js` — [relevant section]
|
| 217 |
+
|
| 218 |
+
**Suggested approach:**
|
| 219 |
+
[Your recommendation based on analysis]
|
| 220 |
+
---
|
| 221 |
+
```
|
| 222 |
+
|
| 223 |
+
---
|
| 224 |
+
|
| 225 |
+
## RULES
|
| 226 |
+
|
| 227 |
+
1. **You do NOT write code** — Describe what needs to change, Agent DEEPCODE implements
|
| 228 |
+
2. **Be specific** — File paths, line numbers, exact variable names
|
| 229 |
+
3. **Show your evidence** — Don't just assert, prove it with findings
|
| 230 |
+
4. **Consider alternatives** — Give Agent DEEPCODE options when possible
|
| 231 |
+
5. **Flag uncertainty** — If you're not sure, say so
|
| 232 |
+
6. **Stay focused** — Analyze what was asked, note tangential issues separately
|
| 233 |
+
|
| 234 |
+
---
|
| 235 |
+
|
| 236 |
+
## WHAT GOOD ANALYSIS LOOKS LIKE
|
| 237 |
+
|
| 238 |
+
**Bad:**
|
| 239 |
+
|
| 240 |
+
> "The authentication is broken. Check the auth files."
|
| 241 |
+
|
| 242 |
+
**Good:**
|
| 243 |
+
|
| 244 |
+
> "The JWT validation fails for tokens expiring within 1 second. In `src/auth/validate.js` line 47, the expiry check uses `token.exp < now` but should use `token.exp <= now`. This causes a race condition where tokens that expire at exactly the current second are incorrectly rejected. You'll need to change the comparison operator. Also check `src/auth/refresh.js` line 23 which has the same pattern."
|
| 245 |
+
|
| 246 |
+
---
|
| 247 |
+
|
| 248 |
+
## REMEMBER
|
| 249 |
+
|
| 250 |
+
- Your job is to give Agent DEEPCODE everything they need to succeed
|
| 251 |
+
- Depth over speed — investigate thoroughly
|
| 252 |
+
- Be the expert who explains the "what" and "why"
|
| 253 |
+
- Agent DEEPCODE handles the "how" (implementation)
|
jules_branch/.claude/agents/security-vulnerability-scanner.md
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
name: security-vulnerability-scanner
|
| 3 |
+
description: Use this agent when you need to identify security vulnerabilities in code, perform security audits, or get a prioritized list of security issues to fix. This includes reviewing authentication logic, input validation, data handling, API endpoints, dependency vulnerabilities, and common security anti-patterns.\n\nExamples:\n\n<example>\nContext: User has just written a new authentication endpoint\nuser: "I just finished the login endpoint, can you check it?"\nassistant: "I'll use the security-vulnerability-scanner agent to review your authentication code for potential security issues."\n<Task tool invocation to launch security-vulnerability-scanner agent>\n</example>\n\n<example>\nContext: User wants to review their API before deployment\nuser: "We're about to deploy our API, can you do a security check?"\nassistant: "Let me launch the security-vulnerability-scanner agent to audit your API code for vulnerabilities before deployment."\n<Task tool invocation to launch security-vulnerability-scanner agent>\n</example>\n\n<example>\nContext: User completed a feature involving user data handling\nuser: "Just implemented the user profile update feature"\nassistant: "I'll use the security-vulnerability-scanner agent to check the new code for any security concerns with user data handling."\n<Task tool invocation to launch security-vulnerability-scanner agent>\n</example>
|
| 4 |
+
model: opus
|
| 5 |
+
color: yellow
|
| 6 |
+
---
|
| 7 |
+
|
| 8 |
+
You are an elite application security researcher with deep expertise in vulnerability assessment, secure coding practices, and penetration testing. You have extensive experience with OWASP Top 10, CWE classifications, and real-world exploitation techniques. Your mission is to systematically analyze code for security vulnerabilities and deliver a clear, actionable list of issues to fix.
|
| 9 |
+
|
| 10 |
+
## Your Approach
|
| 11 |
+
|
| 12 |
+
1. **Systematic Analysis**: Methodically examine the code looking for:
|
| 13 |
+
- Injection vulnerabilities (SQL, NoSQL, Command, LDAP, XPath, etc.)
|
| 14 |
+
- Authentication and session management flaws
|
| 15 |
+
- Cross-Site Scripting (XSS) - reflected, stored, and DOM-based
|
| 16 |
+
- Insecure Direct Object References (IDOR)
|
| 17 |
+
- Security misconfigurations
|
| 18 |
+
- Sensitive data exposure
|
| 19 |
+
- Missing access controls
|
| 20 |
+
- Cross-Site Request Forgery (CSRF)
|
| 21 |
+
- Using components with known vulnerabilities
|
| 22 |
+
- Insufficient logging and monitoring
|
| 23 |
+
- Race conditions and TOCTOU issues
|
| 24 |
+
- Cryptographic weaknesses
|
| 25 |
+
- Path traversal vulnerabilities
|
| 26 |
+
- Deserialization vulnerabilities
|
| 27 |
+
- Server-Side Request Forgery (SSRF)
|
| 28 |
+
|
| 29 |
+
2. **Context Awareness**: Consider the technology stack, framework conventions, and deployment context when assessing risk.
|
| 30 |
+
|
| 31 |
+
3. **Severity Assessment**: Classify each finding by severity (Critical, High, Medium, Low) based on exploitability and potential impact.
|
| 32 |
+
|
| 33 |
+
## Research Process
|
| 34 |
+
|
| 35 |
+
- Use available tools to read and explore the codebase
|
| 36 |
+
- Follow data flows from user input to sensitive operations
|
| 37 |
+
- Check configuration files for security settings
|
| 38 |
+
- Examine dependency files for known vulnerable packages
|
| 39 |
+
- Review authentication/authorization logic paths
|
| 40 |
+
- Analyze error handling and logging practices
|
| 41 |
+
|
| 42 |
+
## Output Format
|
| 43 |
+
|
| 44 |
+
After your analysis, provide a concise, prioritized list in this format:
|
| 45 |
+
|
| 46 |
+
### Security Vulnerabilities Found
|
| 47 |
+
|
| 48 |
+
**Critical:**
|
| 49 |
+
|
| 50 |
+
- [Brief description] — File: `path/to/file.ext` (line X)
|
| 51 |
+
|
| 52 |
+
**High:**
|
| 53 |
+
|
| 54 |
+
- [Brief description] — File: `path/to/file.ext` (line X)
|
| 55 |
+
|
| 56 |
+
**Medium:**
|
| 57 |
+
|
| 58 |
+
- [Brief description] — File: `path/to/file.ext` (line X)
|
| 59 |
+
|
| 60 |
+
**Low:**
|
| 61 |
+
|
| 62 |
+
- [Brief description] — File: `path/to/file.ext` (line X)
|
| 63 |
+
|
| 64 |
+
---
|
| 65 |
+
|
| 66 |
+
**Summary:** X critical, X high, X medium, X low issues found.
|
| 67 |
+
|
| 68 |
+
## Guidelines
|
| 69 |
+
|
| 70 |
+
- Be specific about the vulnerability type and exact location
|
| 71 |
+
- Keep descriptions concise (one line each)
|
| 72 |
+
- Only report actual vulnerabilities, not theoretical concerns or style issues
|
| 73 |
+
- If no vulnerabilities are found in a category, omit that category
|
| 74 |
+
- If the codebase is clean, clearly state that no significant vulnerabilities were identified
|
| 75 |
+
- Do not include lengthy explanations or remediation steps in the list (keep it scannable)
|
| 76 |
+
- Focus on recently modified or newly written code unless explicitly asked to scan the entire codebase
|
| 77 |
+
|
| 78 |
+
Your goal is to give the developer a quick, actionable checklist they can work through to improve their application's security posture.
|
jules_branch/.claude/commands/deepreview.md
ADDED
|
@@ -0,0 +1,591 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Code Review Command
|
| 2 |
+
|
| 3 |
+
Comprehensive code review using multiple deep dive agents to analyze git diff for correctness, security, code quality, and tech stack compliance, followed by automated fixes using deepcode agents.
|
| 4 |
+
|
| 5 |
+
## Usage
|
| 6 |
+
|
| 7 |
+
This command analyzes all changes in the git diff and verifies:
|
| 8 |
+
|
| 9 |
+
1. **Invalid code based on tech stack** (HIGHEST PRIORITY)
|
| 10 |
+
2. Security vulnerabilities
|
| 11 |
+
3. Code quality issues (dirty code)
|
| 12 |
+
4. Implementation correctness
|
| 13 |
+
|
| 14 |
+
Then automatically fixes any issues found.
|
| 15 |
+
|
| 16 |
+
### Optional Arguments
|
| 17 |
+
|
| 18 |
+
- **Target branch**: Optional branch name to compare against (defaults to `main` or `master` if not provided)
|
| 19 |
+
- Example: `@deepreview develop` - compares current branch against `develop`
|
| 20 |
+
- If not provided, automatically detects `main` or `master` as the target branch
|
| 21 |
+
|
| 22 |
+
## Instructions
|
| 23 |
+
|
| 24 |
+
### Phase 1: Get Git Diff
|
| 25 |
+
|
| 26 |
+
1. **Determine the current branch and target branch**
|
| 27 |
+
|
| 28 |
+
```bash
|
| 29 |
+
# Get current branch name
|
| 30 |
+
CURRENT_BRANCH=$(git branch --show-current)
|
| 31 |
+
echo "Current branch: $CURRENT_BRANCH"
|
| 32 |
+
|
| 33 |
+
# Get target branch from user argument or detect default
|
| 34 |
+
# If user provided a target branch as argument, use it
|
| 35 |
+
# Otherwise, detect main or master
|
| 36 |
+
TARGET_BRANCH="${1:-}" # First argument if provided
|
| 37 |
+
|
| 38 |
+
if [ -z "$TARGET_BRANCH" ]; then
|
| 39 |
+
# Check if main exists
|
| 40 |
+
if git show-ref --verify --quiet refs/heads/main || git show-ref --verify --quiet refs/remotes/origin/main; then
|
| 41 |
+
TARGET_BRANCH="main"
|
| 42 |
+
# Check if master exists
|
| 43 |
+
elif git show-ref --verify --quiet refs/heads/master || git show-ref --verify --quiet refs/remotes/origin/master; then
|
| 44 |
+
TARGET_BRANCH="master"
|
| 45 |
+
else
|
| 46 |
+
echo "Error: Could not find main or master branch. Please specify target branch."
|
| 47 |
+
exit 1
|
| 48 |
+
fi
|
| 49 |
+
fi
|
| 50 |
+
|
| 51 |
+
echo "Target branch: $TARGET_BRANCH"
|
| 52 |
+
|
| 53 |
+
# Verify target branch exists
|
| 54 |
+
if ! git show-ref --verify --quiet refs/heads/$TARGET_BRANCH && ! git show-ref --verify --quiet refs/remotes/origin/$TARGET_BRANCH; then
|
| 55 |
+
echo "Error: Target branch '$TARGET_BRANCH' does not exist."
|
| 56 |
+
exit 1
|
| 57 |
+
fi
|
| 58 |
+
```
|
| 59 |
+
|
| 60 |
+
**Note:** The target branch can be provided as an optional argument. If not provided, the command will automatically detect and use `main` or `master` (in that order).
|
| 61 |
+
|
| 62 |
+
2. **Compare current branch against target branch**
|
| 63 |
+
|
| 64 |
+
```bash
|
| 65 |
+
# Fetch latest changes from remote (optional but recommended)
|
| 66 |
+
git fetch origin
|
| 67 |
+
|
| 68 |
+
# Try local branch first, fallback to remote if local doesn't exist
|
| 69 |
+
if git show-ref --verify --quiet refs/heads/$TARGET_BRANCH; then
|
| 70 |
+
TARGET_REF=$TARGET_BRANCH
|
| 71 |
+
elif git show-ref --verify --quiet refs/remotes/origin/$TARGET_BRANCH; then
|
| 72 |
+
TARGET_REF=origin/$TARGET_BRANCH
|
| 73 |
+
else
|
| 74 |
+
echo "Error: Target branch '$TARGET_BRANCH' not found locally or remotely."
|
| 75 |
+
exit 1
|
| 76 |
+
fi
|
| 77 |
+
|
| 78 |
+
# Get diff between current branch and target branch
|
| 79 |
+
git diff $TARGET_REF...HEAD
|
| 80 |
+
```
|
| 81 |
+
|
| 82 |
+
**Note:** Use `...` (three dots) to show changes between the common ancestor and HEAD, or `..` (two dots) to show changes between the branches directly. The command uses `$TARGET_BRANCH` variable set in step 1.
|
| 83 |
+
|
| 84 |
+
3. **Get list of changed files between branches**
|
| 85 |
+
|
| 86 |
+
```bash
|
| 87 |
+
# List files changed between current branch and target branch
|
| 88 |
+
git diff --name-only $TARGET_REF...HEAD
|
| 89 |
+
|
| 90 |
+
# Get detailed file status
|
| 91 |
+
git diff --name-status $TARGET_REF...HEAD
|
| 92 |
+
|
| 93 |
+
# Show file changes with statistics
|
| 94 |
+
git diff --stat $TARGET_REF...HEAD
|
| 95 |
+
```
|
| 96 |
+
|
| 97 |
+
4. **Get the current working directory diff** (uncommitted changes)
|
| 98 |
+
|
| 99 |
+
```bash
|
| 100 |
+
# Uncommitted changes in working directory
|
| 101 |
+
git diff HEAD
|
| 102 |
+
|
| 103 |
+
# Staged changes
|
| 104 |
+
git diff --cached
|
| 105 |
+
|
| 106 |
+
# All changes (staged + unstaged)
|
| 107 |
+
git diff HEAD
|
| 108 |
+
git diff --cached
|
| 109 |
+
```
|
| 110 |
+
|
| 111 |
+
5. **Combine branch comparison with uncommitted changes**
|
| 112 |
+
|
| 113 |
+
The review should analyze:
|
| 114 |
+
- **Changes between current branch and target branch** (committed changes)
|
| 115 |
+
- **Uncommitted changes** (if any)
|
| 116 |
+
|
| 117 |
+
```bash
|
| 118 |
+
# Get all changes: branch diff + uncommitted
|
| 119 |
+
git diff $TARGET_REF...HEAD > branch-changes.diff
|
| 120 |
+
git diff HEAD >> branch-changes.diff
|
| 121 |
+
git diff --cached >> branch-changes.diff
|
| 122 |
+
|
| 123 |
+
# Or get combined diff (recommended approach)
|
| 124 |
+
git diff $TARGET_REF...HEAD
|
| 125 |
+
git diff HEAD
|
| 126 |
+
git diff --cached
|
| 127 |
+
```
|
| 128 |
+
|
| 129 |
+
6. **Verify branch relationship**
|
| 130 |
+
|
| 131 |
+
```bash
|
| 132 |
+
# Check if current branch is ahead/behind target branch
|
| 133 |
+
git rev-list --left-right --count $TARGET_REF...HEAD
|
| 134 |
+
|
| 135 |
+
# Show commit log differences
|
| 136 |
+
git log $TARGET_REF..HEAD --oneline
|
| 137 |
+
|
| 138 |
+
# Show summary of branch relationship
|
| 139 |
+
AHEAD=$(git rev-list --left-right --count $TARGET_REF...HEAD | cut -f1)
|
| 140 |
+
BEHIND=$(git rev-list --left-right --count $TARGET_REF...HEAD | cut -f2)
|
| 141 |
+
echo "Branch is $AHEAD commits ahead and $BEHIND commits behind $TARGET_BRANCH"
|
| 142 |
+
```
|
| 143 |
+
|
| 144 |
+
7. **Understand the tech stack** (for validation):
|
| 145 |
+
- **Node.js**: >=22.0.0 <23.0.0
|
| 146 |
+
- **TypeScript**: 5.9.3
|
| 147 |
+
- **React**: 19.2.3
|
| 148 |
+
- **Express**: 5.2.1
|
| 149 |
+
- **Electron**: 39.2.7
|
| 150 |
+
- **Vite**: 7.3.0
|
| 151 |
+
- **Vitest**: 4.0.16
|
| 152 |
+
- Check `package.json` files for exact versions
|
| 153 |
+
|
| 154 |
+
### Phase 2: Deep Dive Analysis (5 Agents)
|
| 155 |
+
|
| 156 |
+
Launch 5 separate deep dive agents, each with a specific focus area. Each agent should be invoked with the `@deepdive` agent and given the git diff (comparing current branch against target branch) along with their specific instructions.
|
| 157 |
+
|
| 158 |
+
**Important:** All agents should analyze the diff between the current branch and target branch (`git diff $TARGET_REF...HEAD`), plus any uncommitted changes. This ensures the review covers all changes that will be merged. The target branch is determined from the optional argument or defaults to main/master.
|
| 159 |
+
|
| 160 |
+
#### Agent 1: Tech Stack Validation (HIGHEST PRIORITY)
|
| 161 |
+
|
| 162 |
+
**Focus:** Verify code is valid for the tech stack
|
| 163 |
+
|
| 164 |
+
**Instructions for Agent 1:**
|
| 165 |
+
|
| 166 |
+
```
|
| 167 |
+
Analyze the git diff for invalid code based on the tech stack:
|
| 168 |
+
|
| 169 |
+
1. **TypeScript/JavaScript Syntax**
|
| 170 |
+
- Check for valid TypeScript syntax (no invalid type annotations, correct import/export syntax)
|
| 171 |
+
- Verify Node.js API usage is compatible with Node.js >=22.0.0 <23.0.0
|
| 172 |
+
- Check for deprecated APIs or features not available in the Node.js version
|
| 173 |
+
- Verify ES module syntax (type: "module" in package.json)
|
| 174 |
+
|
| 175 |
+
2. **React 19.2.3 Compatibility**
|
| 176 |
+
- Check for deprecated React APIs or patterns
|
| 177 |
+
- Verify hooks usage is correct for React 19
|
| 178 |
+
- Check for invalid JSX syntax
|
| 179 |
+
- Verify component patterns match React 19 conventions
|
| 180 |
+
|
| 181 |
+
3. **Express 5.2.1 Compatibility**
|
| 182 |
+
- Check for deprecated Express APIs
|
| 183 |
+
- Verify middleware usage is correct for Express 5
|
| 184 |
+
- Check request/response handling patterns
|
| 185 |
+
|
| 186 |
+
4. **Type Safety**
|
| 187 |
+
- Verify TypeScript types are correctly used
|
| 188 |
+
- Check for `any` types that should be properly typed
|
| 189 |
+
- Verify type imports/exports are correct
|
| 190 |
+
- Check for missing type definitions
|
| 191 |
+
|
| 192 |
+
5. **Build System Compatibility**
|
| 193 |
+
- Verify Vite-specific code (imports, config) is valid
|
| 194 |
+
- Check Electron-specific APIs are used correctly
|
| 195 |
+
- Verify module resolution paths are correct
|
| 196 |
+
|
| 197 |
+
6. **Package Dependencies**
|
| 198 |
+
- Check for imports from packages not in package.json
|
| 199 |
+
- Verify version compatibility between dependencies
|
| 200 |
+
- Check for circular dependencies
|
| 201 |
+
|
| 202 |
+
Provide a detailed report with:
|
| 203 |
+
- File paths and line numbers of invalid code
|
| 204 |
+
- Specific error description (what's wrong and why)
|
| 205 |
+
- Expected vs actual behavior
|
| 206 |
+
- Priority level (CRITICAL for build-breaking issues)
|
| 207 |
+
```
|
| 208 |
+
|
| 209 |
+
#### Agent 2: Security Vulnerability Scanner
|
| 210 |
+
|
| 211 |
+
**Focus:** Security issues and vulnerabilities
|
| 212 |
+
|
| 213 |
+
**Instructions for Agent 2:**
|
| 214 |
+
|
| 215 |
+
```
|
| 216 |
+
Analyze the git diff for security vulnerabilities:
|
| 217 |
+
|
| 218 |
+
1. **Injection Vulnerabilities**
|
| 219 |
+
- SQL injection (if applicable)
|
| 220 |
+
- Command injection (exec, spawn, etc.)
|
| 221 |
+
- Path traversal vulnerabilities
|
| 222 |
+
- XSS vulnerabilities in React components
|
| 223 |
+
|
| 224 |
+
2. **Authentication & Authorization**
|
| 225 |
+
- Missing authentication checks
|
| 226 |
+
- Insecure token handling
|
| 227 |
+
- Authorization bypasses
|
| 228 |
+
- Session management issues
|
| 229 |
+
|
| 230 |
+
3. **Data Handling**
|
| 231 |
+
- Unsafe deserialization
|
| 232 |
+
- Insecure file operations
|
| 233 |
+
- Missing input validation
|
| 234 |
+
- Sensitive data exposure (secrets, tokens, passwords)
|
| 235 |
+
|
| 236 |
+
4. **Dependencies**
|
| 237 |
+
- Known vulnerable packages
|
| 238 |
+
- Insecure dependency versions
|
| 239 |
+
- Missing security patches
|
| 240 |
+
|
| 241 |
+
5. **API Security**
|
| 242 |
+
- Missing CORS configuration
|
| 243 |
+
- Insecure API endpoints
|
| 244 |
+
- Missing rate limiting
|
| 245 |
+
- Insecure WebSocket connections
|
| 246 |
+
|
| 247 |
+
6. **Electron-Specific**
|
| 248 |
+
- Insecure IPC communication
|
| 249 |
+
- Missing context isolation checks
|
| 250 |
+
- Insecure preload scripts
|
| 251 |
+
- Missing CSP headers
|
| 252 |
+
|
| 253 |
+
Provide a detailed report with:
|
| 254 |
+
- Vulnerability type and severity (CRITICAL, HIGH, MEDIUM, LOW)
|
| 255 |
+
- File paths and line numbers
|
| 256 |
+
- Attack vector description
|
| 257 |
+
- Recommended fix approach
|
| 258 |
+
```
|
| 259 |
+
|
| 260 |
+
#### Agent 3: Code Quality & Clean Code
|
| 261 |
+
|
| 262 |
+
**Focus:** Dirty code, code smells, and quality issues
|
| 263 |
+
|
| 264 |
+
**Instructions for Agent 3:**
|
| 265 |
+
|
| 266 |
+
```
|
| 267 |
+
Analyze the git diff for code quality issues:
|
| 268 |
+
|
| 269 |
+
1. **Code Smells**
|
| 270 |
+
- Long functions/methods (>50 lines)
|
| 271 |
+
- High cyclomatic complexity
|
| 272 |
+
- Duplicate code
|
| 273 |
+
- Dead code
|
| 274 |
+
- Magic numbers/strings
|
| 275 |
+
|
| 276 |
+
2. **Best Practices**
|
| 277 |
+
- Missing error handling
|
| 278 |
+
- Inconsistent naming conventions
|
| 279 |
+
- Poor separation of concerns
|
| 280 |
+
- Tight coupling
|
| 281 |
+
- Missing comments for complex logic
|
| 282 |
+
|
| 283 |
+
3. **Performance Issues**
|
| 284 |
+
- Inefficient algorithms
|
| 285 |
+
- Memory leaks (event listeners, subscriptions)
|
| 286 |
+
- Unnecessary re-renders in React
|
| 287 |
+
- Missing memoization where needed
|
| 288 |
+
- Inefficient database queries (if applicable)
|
| 289 |
+
|
| 290 |
+
4. **Maintainability**
|
| 291 |
+
- Hard-coded values
|
| 292 |
+
- Missing type definitions
|
| 293 |
+
- Inconsistent code style
|
| 294 |
+
- Poor file organization
|
| 295 |
+
- Missing tests for new code
|
| 296 |
+
|
| 297 |
+
5. **React-Specific**
|
| 298 |
+
- Missing key props in lists
|
| 299 |
+
- Direct state mutations
|
| 300 |
+
- Missing cleanup in useEffect
|
| 301 |
+
- Unnecessary useState/useEffect
|
| 302 |
+
- Prop drilling issues
|
| 303 |
+
|
| 304 |
+
Provide a detailed report with:
|
| 305 |
+
- Issue type and severity
|
| 306 |
+
- File paths and line numbers
|
| 307 |
+
- Description of the problem
|
| 308 |
+
- Impact on maintainability/performance
|
| 309 |
+
- Recommended refactoring approach
|
| 310 |
+
```
|
| 311 |
+
|
| 312 |
+
#### Agent 4: Implementation Correctness
|
| 313 |
+
|
| 314 |
+
**Focus:** Verify code implements requirements correctly
|
| 315 |
+
|
| 316 |
+
**Instructions for Agent 4:**
|
| 317 |
+
|
| 318 |
+
```
|
| 319 |
+
Analyze the git diff for implementation correctness:
|
| 320 |
+
|
| 321 |
+
1. **Logic Errors**
|
| 322 |
+
- Incorrect conditional logic
|
| 323 |
+
- Wrong variable usage
|
| 324 |
+
- Off-by-one errors
|
| 325 |
+
- Race conditions
|
| 326 |
+
- Missing null/undefined checks
|
| 327 |
+
|
| 328 |
+
2. **Functional Requirements**
|
| 329 |
+
- Missing features from requirements
|
| 330 |
+
- Incorrect feature implementation
|
| 331 |
+
- Edge cases not handled
|
| 332 |
+
- Missing validation
|
| 333 |
+
|
| 334 |
+
3. **Integration Issues**
|
| 335 |
+
- Incorrect API usage
|
| 336 |
+
- Wrong data format handling
|
| 337 |
+
- Missing error handling for external calls
|
| 338 |
+
- Incorrect state management
|
| 339 |
+
|
| 340 |
+
4. **Type Errors**
|
| 341 |
+
- Type mismatches
|
| 342 |
+
- Missing type guards
|
| 343 |
+
- Incorrect type assertions
|
| 344 |
+
- Unsafe type operations
|
| 345 |
+
|
| 346 |
+
5. **Testing Gaps**
|
| 347 |
+
- Missing unit tests
|
| 348 |
+
- Missing integration tests
|
| 349 |
+
- Tests don't cover edge cases
|
| 350 |
+
- Tests are incorrect
|
| 351 |
+
|
| 352 |
+
Provide a detailed report with:
|
| 353 |
+
- Issue description
|
| 354 |
+
- File paths and line numbers
|
| 355 |
+
- Expected vs actual behavior
|
| 356 |
+
- Steps to reproduce (if applicable)
|
| 357 |
+
- Recommended fix
|
| 358 |
+
```
|
| 359 |
+
|
| 360 |
+
#### Agent 5: Architecture & Design Patterns
|
| 361 |
+
|
| 362 |
+
**Focus:** Architectural issues and design pattern violations
|
| 363 |
+
|
| 364 |
+
**Instructions for Agent 5:**
|
| 365 |
+
|
| 366 |
+
```
|
| 367 |
+
Analyze the git diff for architectural and design issues:
|
| 368 |
+
|
| 369 |
+
1. **Architecture Violations**
|
| 370 |
+
- Violation of project structure patterns
|
| 371 |
+
- Incorrect layer separation
|
| 372 |
+
- Missing abstractions
|
| 373 |
+
- Tight coupling between modules
|
| 374 |
+
|
| 375 |
+
2. **Design Patterns**
|
| 376 |
+
- Incorrect pattern usage
|
| 377 |
+
- Missing patterns where needed
|
| 378 |
+
- Anti-patterns
|
| 379 |
+
|
| 380 |
+
3. **Project-Specific Patterns**
|
| 381 |
+
- Check against project documentation (docs/ folder)
|
| 382 |
+
- Verify route organization (server routes)
|
| 383 |
+
- Check provider patterns (server providers)
|
| 384 |
+
- Verify component organization (UI components)
|
| 385 |
+
|
| 386 |
+
4. **API Design**
|
| 387 |
+
- RESTful API violations
|
| 388 |
+
- Inconsistent response formats
|
| 389 |
+
- Missing error handling
|
| 390 |
+
- Incorrect status codes
|
| 391 |
+
|
| 392 |
+
5. **State Management**
|
| 393 |
+
- Incorrect state management patterns
|
| 394 |
+
- Missing state normalization
|
| 395 |
+
- Inefficient state updates
|
| 396 |
+
|
| 397 |
+
Provide a detailed report with:
|
| 398 |
+
- Architectural issue description
|
| 399 |
+
- File paths and affected areas
|
| 400 |
+
- Impact on system design
|
| 401 |
+
- Recommended architectural changes
|
| 402 |
+
```
|
| 403 |
+
|
| 404 |
+
### Phase 3: Consolidate Findings
|
| 405 |
+
|
| 406 |
+
After all 5 deep dive agents complete their analysis:
|
| 407 |
+
|
| 408 |
+
1. **Collect all findings** from each agent
|
| 409 |
+
2. **Prioritize issues**:
|
| 410 |
+
- CRITICAL: Tech stack invalid code (build-breaking)
|
| 411 |
+
- HIGH: Security vulnerabilities, critical logic errors
|
| 412 |
+
- MEDIUM: Code quality issues, architectural problems
|
| 413 |
+
- LOW: Minor code smells, style issues
|
| 414 |
+
|
| 415 |
+
3. **Group by file** to understand impact per file
|
| 416 |
+
4. **Create a master report** summarizing all findings
|
| 417 |
+
|
| 418 |
+
### Phase 4: Deepcode Fixes (5 Agents)
|
| 419 |
+
|
| 420 |
+
Launch 5 deepcode agents to fix the issues found. Each agent should be invoked with the `@deepcode` agent.
|
| 421 |
+
|
| 422 |
+
#### Deepcode Agent 1: Fix Tech Stack Invalid Code
|
| 423 |
+
|
| 424 |
+
**Priority:** CRITICAL - Fix first
|
| 425 |
+
|
| 426 |
+
**Instructions:**
|
| 427 |
+
|
| 428 |
+
```
|
| 429 |
+
Fix all invalid code based on tech stack issues identified by Agent 1.
|
| 430 |
+
|
| 431 |
+
Focus on:
|
| 432 |
+
1. Fixing TypeScript syntax errors
|
| 433 |
+
2. Updating deprecated Node.js APIs
|
| 434 |
+
3. Fixing React 19 compatibility issues
|
| 435 |
+
4. Correcting Express 5 API usage
|
| 436 |
+
5. Fixing type errors
|
| 437 |
+
6. Resolving build-breaking issues
|
| 438 |
+
|
| 439 |
+
After fixes, verify:
|
| 440 |
+
- Code compiles without errors
|
| 441 |
+
- TypeScript types are correct
|
| 442 |
+
- No deprecated API usage
|
| 443 |
+
```
|
| 444 |
+
|
| 445 |
+
#### Deepcode Agent 2: Fix Security Vulnerabilities
|
| 446 |
+
|
| 447 |
+
**Priority:** HIGH
|
| 448 |
+
|
| 449 |
+
**Instructions:**
|
| 450 |
+
|
| 451 |
+
```
|
| 452 |
+
Fix all security vulnerabilities identified by Agent 2.
|
| 453 |
+
|
| 454 |
+
Focus on:
|
| 455 |
+
1. Adding input validation
|
| 456 |
+
2. Fixing injection vulnerabilities
|
| 457 |
+
3. Securing authentication/authorization
|
| 458 |
+
4. Fixing insecure data handling
|
| 459 |
+
5. Updating vulnerable dependencies
|
| 460 |
+
6. Securing Electron IPC
|
| 461 |
+
|
| 462 |
+
After fixes, verify:
|
| 463 |
+
- Security vulnerabilities are addressed
|
| 464 |
+
- No sensitive data exposure
|
| 465 |
+
- Proper authentication/authorization
|
| 466 |
+
```
|
| 467 |
+
|
| 468 |
+
#### Deepcode Agent 3: Refactor Dirty Code
|
| 469 |
+
|
| 470 |
+
**Priority:** MEDIUM
|
| 471 |
+
|
| 472 |
+
**Instructions:**
|
| 473 |
+
|
| 474 |
+
```
|
| 475 |
+
Refactor code quality issues identified by Agent 3.
|
| 476 |
+
|
| 477 |
+
Focus on:
|
| 478 |
+
1. Extracting long functions
|
| 479 |
+
2. Reducing complexity
|
| 480 |
+
3. Removing duplicate code
|
| 481 |
+
4. Adding error handling
|
| 482 |
+
5. Improving React component structure
|
| 483 |
+
6. Adding missing comments
|
| 484 |
+
|
| 485 |
+
After fixes, verify:
|
| 486 |
+
- Code follows best practices
|
| 487 |
+
- No code smells remain
|
| 488 |
+
- Performance optimizations applied
|
| 489 |
+
```
|
| 490 |
+
|
| 491 |
+
#### Deepcode Agent 4: Fix Implementation Errors
|
| 492 |
+
|
| 493 |
+
**Priority:** HIGH
|
| 494 |
+
|
| 495 |
+
**Instructions:**
|
| 496 |
+
|
| 497 |
+
```
|
| 498 |
+
Fix implementation correctness issues identified by Agent 4.
|
| 499 |
+
|
| 500 |
+
Focus on:
|
| 501 |
+
1. Fixing logic errors
|
| 502 |
+
2. Adding missing features
|
| 503 |
+
3. Handling edge cases
|
| 504 |
+
4. Fixing type errors
|
| 505 |
+
5. Adding missing tests
|
| 506 |
+
|
| 507 |
+
After fixes, verify:
|
| 508 |
+
- Logic is correct
|
| 509 |
+
- Edge cases handled
|
| 510 |
+
- Tests pass
|
| 511 |
+
```
|
| 512 |
+
|
| 513 |
+
#### Deepcode Agent 5: Fix Architectural Issues
|
| 514 |
+
|
| 515 |
+
**Priority:** MEDIUM
|
| 516 |
+
|
| 517 |
+
**Instructions:**
|
| 518 |
+
|
| 519 |
+
```
|
| 520 |
+
Fix architectural issues identified by Agent 5.
|
| 521 |
+
|
| 522 |
+
Focus on:
|
| 523 |
+
1. Correcting architecture violations
|
| 524 |
+
2. Applying proper design patterns
|
| 525 |
+
3. Fixing API design issues
|
| 526 |
+
4. Improving state management
|
| 527 |
+
5. Following project patterns
|
| 528 |
+
|
| 529 |
+
After fixes, verify:
|
| 530 |
+
- Architecture is sound
|
| 531 |
+
- Patterns are correctly applied
|
| 532 |
+
- Code follows project structure
|
| 533 |
+
```
|
| 534 |
+
|
| 535 |
+
### Phase 5: Verification
|
| 536 |
+
|
| 537 |
+
After all fixes are complete:
|
| 538 |
+
|
| 539 |
+
1. **Run TypeScript compilation check**
|
| 540 |
+
|
| 541 |
+
```bash
|
| 542 |
+
npm run build:packages
|
| 543 |
+
```
|
| 544 |
+
|
| 545 |
+
2. **Run linting**
|
| 546 |
+
|
| 547 |
+
```bash
|
| 548 |
+
npm run lint
|
| 549 |
+
```
|
| 550 |
+
|
| 551 |
+
3. **Run tests** (if applicable)
|
| 552 |
+
|
| 553 |
+
```bash
|
| 554 |
+
npm run test:server
|
| 555 |
+
npm run test
|
| 556 |
+
```
|
| 557 |
+
|
| 558 |
+
4. **Verify git diff** shows only intended changes
|
| 559 |
+
|
| 560 |
+
```bash
|
| 561 |
+
git diff HEAD
|
| 562 |
+
```
|
| 563 |
+
|
| 564 |
+
5. **Create summary report**:
|
| 565 |
+
- Issues found by each agent
|
| 566 |
+
- Issues fixed by each agent
|
| 567 |
+
- Remaining issues (if any)
|
| 568 |
+
- Verification results
|
| 569 |
+
|
| 570 |
+
## Workflow Summary
|
| 571 |
+
|
| 572 |
+
1. ✅ Accept optional target branch argument (defaults to main/master if not provided)
|
| 573 |
+
2. ✅ Determine current branch and target branch (from argument or auto-detect main/master)
|
| 574 |
+
3. ✅ Get git diff comparing current branch against target branch (`git diff $TARGET_REF...HEAD`)
|
| 575 |
+
4. ✅ Include uncommitted changes in analysis (`git diff HEAD`, `git diff --cached`)
|
| 576 |
+
5. ✅ Launch 5 deep dive agents (parallel analysis) with branch diff
|
| 577 |
+
6. ✅ Consolidate findings and prioritize
|
| 578 |
+
7. ✅ Launch 5 deepcode agents (sequential fixes, priority order)
|
| 579 |
+
8. ✅ Verify fixes with build/lint/test
|
| 580 |
+
9. ✅ Report summary
|
| 581 |
+
|
| 582 |
+
## Notes
|
| 583 |
+
|
| 584 |
+
- **Tech stack validation is HIGHEST PRIORITY** - invalid code must be fixed first
|
| 585 |
+
- **Target branch argument**: The command accepts an optional target branch name as the first argument. If not provided, it automatically detects and uses `main` or `master` (in that order)
|
| 586 |
+
- Each deep dive agent should work independently and provide comprehensive analysis
|
| 587 |
+
- Deepcode agents should fix issues in priority order
|
| 588 |
+
- All fixes should maintain existing functionality
|
| 589 |
+
- If an agent finds no issues in their domain, they should report "No issues found"
|
| 590 |
+
- If fixes introduce new issues, they should be caught in verification phase
|
| 591 |
+
- The target branch is validated to ensure it exists (locally or remotely) before proceeding with the review
|
jules_branch/.claude/commands/gh-issue.md
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# GitHub Issue Fix Command
|
| 2 |
+
|
| 3 |
+
Fetch a GitHub issue by number, verify it's a real issue, and fix it if valid.
|
| 4 |
+
|
| 5 |
+
## Usage
|
| 6 |
+
|
| 7 |
+
This command accepts a GitHub issue number as input (e.g., `123`).
|
| 8 |
+
|
| 9 |
+
## Instructions
|
| 10 |
+
|
| 11 |
+
1. **Get the issue number from the user**
|
| 12 |
+
- The issue number should be provided as an argument to this command
|
| 13 |
+
- If no number is provided, ask the user for it
|
| 14 |
+
|
| 15 |
+
2. **Fetch the GitHub issue**
|
| 16 |
+
- Determine the current project path (check if there's a current project context)
|
| 17 |
+
- Verify the project has a GitHub remote:
|
| 18 |
+
```bash
|
| 19 |
+
git remote get-url origin
|
| 20 |
+
```
|
| 21 |
+
- Fetch the issue details using GitHub CLI:
|
| 22 |
+
```bash
|
| 23 |
+
gh issue view <ISSUE_NUMBER> --json number,title,state,author,createdAt,labels,url,body,assignees
|
| 24 |
+
```
|
| 25 |
+
- If the command fails, report the error and stop
|
| 26 |
+
|
| 27 |
+
3. **Verify the issue is real and valid**
|
| 28 |
+
- Check that the issue exists (not 404)
|
| 29 |
+
- Check the issue state:
|
| 30 |
+
- If **closed**: Inform the user and ask if they still want to proceed
|
| 31 |
+
- If **open**: Proceed with validation
|
| 32 |
+
- Review the issue content:
|
| 33 |
+
- Read the title and body to understand what needs to be fixed
|
| 34 |
+
- Check labels for context (bug, enhancement, etc.)
|
| 35 |
+
- Note any assignees or linked PRs
|
| 36 |
+
|
| 37 |
+
4. **Validate the issue**
|
| 38 |
+
- Determine if this is a legitimate issue that needs fixing:
|
| 39 |
+
- Is the description clear and actionable?
|
| 40 |
+
- Does it describe a real problem or feature request?
|
| 41 |
+
- Are there any obvious signs it's spam or invalid?
|
| 42 |
+
- If the issue seems invalid or unclear:
|
| 43 |
+
- Report findings to the user
|
| 44 |
+
- Ask if they want to proceed anyway
|
| 45 |
+
- Stop if user confirms it's not valid
|
| 46 |
+
|
| 47 |
+
5. **If the issue is valid, proceed to fix it**
|
| 48 |
+
- Analyze what needs to be done based on the issue description
|
| 49 |
+
- Check the current codebase state:
|
| 50 |
+
- Run relevant tests to see current behavior
|
| 51 |
+
- Check if the issue is already fixed
|
| 52 |
+
- Look for related code that might need changes
|
| 53 |
+
- Implement the fix:
|
| 54 |
+
- Make necessary code changes
|
| 55 |
+
- Update or add tests as needed
|
| 56 |
+
- Ensure the fix addresses the issue description
|
| 57 |
+
- Verify the fix:
|
| 58 |
+
- Run tests to ensure nothing broke
|
| 59 |
+
- If possible, manually verify the fix addresses the issue
|
| 60 |
+
|
| 61 |
+
6. **Report summary**
|
| 62 |
+
- Issue number and title
|
| 63 |
+
- Issue state (open/closed)
|
| 64 |
+
- Whether the issue was validated as real
|
| 65 |
+
- What was fixed (if anything)
|
| 66 |
+
- Any tests that were updated or added
|
| 67 |
+
- Next steps (if any)
|
| 68 |
+
|
| 69 |
+
## Error Handling
|
| 70 |
+
|
| 71 |
+
- If GitHub CLI (`gh`) is not installed or authenticated, report error and stop
|
| 72 |
+
- If the project doesn't have a GitHub remote, report error and stop
|
| 73 |
+
- If the issue number doesn't exist, report error and stop
|
| 74 |
+
- If the issue is unclear or invalid, report findings and ask user before proceeding
|
jules_branch/.claude/commands/release.md
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Release Command
|
| 2 |
+
|
| 3 |
+
Bump the package.json version (major, minor, or patch) and build the Electron app with the new version.
|
| 4 |
+
|
| 5 |
+
## Usage
|
| 6 |
+
|
| 7 |
+
This command accepts a version bump type as input:
|
| 8 |
+
|
| 9 |
+
- `patch` - Bump patch version (0.1.0 -> 0.1.1)
|
| 10 |
+
- `minor` - Bump minor version (0.1.0 -> 0.2.0)
|
| 11 |
+
- `major` - Bump major version (0.1.0 -> 1.0.0)
|
| 12 |
+
|
| 13 |
+
## Instructions
|
| 14 |
+
|
| 15 |
+
1. **Get the bump type from the user**
|
| 16 |
+
- The bump type should be provided as an argument (patch, minor, or major)
|
| 17 |
+
- If no type is provided, ask the user which type they want
|
| 18 |
+
|
| 19 |
+
2. **Bump the version**
|
| 20 |
+
- Run the version bump script:
|
| 21 |
+
```bash
|
| 22 |
+
node apps/ui/scripts/bump-version.mjs <type>
|
| 23 |
+
```
|
| 24 |
+
- This updates both `apps/ui/package.json` and `apps/server/package.json` with the new version (keeps them in sync)
|
| 25 |
+
- Verify the version was updated correctly by checking the output
|
| 26 |
+
|
| 27 |
+
3. **Build the Electron app**
|
| 28 |
+
- Run the electron build:
|
| 29 |
+
```bash
|
| 30 |
+
npm run build:electron --workspace=apps/ui
|
| 31 |
+
```
|
| 32 |
+
- The build process automatically:
|
| 33 |
+
- Uses the version from `package.json` for artifact names (e.g., `Automaker-1.2.3-x64.zip`)
|
| 34 |
+
- Injects the version into the app via Vite's `__APP_VERSION__` constant
|
| 35 |
+
- Displays the version below the logo in the sidebar
|
| 36 |
+
|
| 37 |
+
4. **Commit the version bump**
|
| 38 |
+
- Stage the updated package.json files:
|
| 39 |
+
```bash
|
| 40 |
+
git add apps/ui/package.json apps/server/package.json
|
| 41 |
+
```
|
| 42 |
+
- Commit with a release message:
|
| 43 |
+
```bash
|
| 44 |
+
git commit -m "chore: release v<version>"
|
| 45 |
+
```
|
| 46 |
+
|
| 47 |
+
5. **Create and push the git tag**
|
| 48 |
+
- Create an annotated tag for the release:
|
| 49 |
+
```bash
|
| 50 |
+
git tag -a v<version> -m "Release v<version>"
|
| 51 |
+
```
|
| 52 |
+
- Push the commit and tag to remote:
|
| 53 |
+
```bash
|
| 54 |
+
git push && git push --tags
|
| 55 |
+
```
|
| 56 |
+
|
| 57 |
+
6. **Verify the release**
|
| 58 |
+
- Check that the build completed successfully
|
| 59 |
+
- Confirm the version appears correctly in the built artifacts
|
| 60 |
+
- The version will be displayed in the app UI below the logo
|
| 61 |
+
- Verify the tag is visible on the remote repository
|
| 62 |
+
|
| 63 |
+
## Version Centralization
|
| 64 |
+
|
| 65 |
+
The version is centralized and synchronized in both `apps/ui/package.json` and `apps/server/package.json`:
|
| 66 |
+
|
| 67 |
+
- **Electron builds**: Automatically read from `apps/ui/package.json` via electron-builder's `${version}` variable in `artifactName`
|
| 68 |
+
- **App display**: Injected at build time via Vite's `define` config as `__APP_VERSION__` constant (defined in `apps/ui/vite.config.mts`)
|
| 69 |
+
- **Server API**: Read from `apps/server/package.json` via `apps/server/src/lib/version.ts` utility (used in health check endpoints)
|
| 70 |
+
- **Type safety**: Defined in `apps/ui/src/vite-env.d.ts` as `declare const __APP_VERSION__: string`
|
| 71 |
+
|
| 72 |
+
This ensures consistency across:
|
| 73 |
+
|
| 74 |
+
- Build artifact names (e.g., `Automaker-1.2.3-x64.zip`)
|
| 75 |
+
- App UI display (shown as `v1.2.3` below the logo in `apps/ui/src/components/layout/sidebar/components/automaker-logo.tsx`)
|
| 76 |
+
- Server health endpoints (`/` and `/detailed`)
|
| 77 |
+
- Package metadata (both UI and server packages stay in sync)
|
jules_branch/.claude/commands/review.md
ADDED
|
@@ -0,0 +1,484 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Code Review Command
|
| 2 |
+
|
| 3 |
+
Comprehensive code review using multiple deep dive agents to analyze git diff for correctness, security, code quality, and tech stack compliance, followed by automated fixes using deepcode agents.
|
| 4 |
+
|
| 5 |
+
## Usage
|
| 6 |
+
|
| 7 |
+
This command analyzes all changes in the git diff and verifies:
|
| 8 |
+
|
| 9 |
+
1. **Invalid code based on tech stack** (HIGHEST PRIORITY)
|
| 10 |
+
2. Security vulnerabilities
|
| 11 |
+
3. Code quality issues (dirty code)
|
| 12 |
+
4. Implementation correctness
|
| 13 |
+
|
| 14 |
+
Then automatically fixes any issues found.
|
| 15 |
+
|
| 16 |
+
## Instructions
|
| 17 |
+
|
| 18 |
+
### Phase 1: Get Git Diff
|
| 19 |
+
|
| 20 |
+
1. **Get the current git diff**
|
| 21 |
+
|
| 22 |
+
```bash
|
| 23 |
+
git diff HEAD
|
| 24 |
+
```
|
| 25 |
+
|
| 26 |
+
If you need staged changes instead:
|
| 27 |
+
|
| 28 |
+
```bash
|
| 29 |
+
git diff --cached
|
| 30 |
+
```
|
| 31 |
+
|
| 32 |
+
Or for a specific commit range:
|
| 33 |
+
|
| 34 |
+
```bash
|
| 35 |
+
git diff <base-branch>
|
| 36 |
+
```
|
| 37 |
+
|
| 38 |
+
2. **Get list of changed files**
|
| 39 |
+
|
| 40 |
+
```bash
|
| 41 |
+
git diff --name-only HEAD
|
| 42 |
+
```
|
| 43 |
+
|
| 44 |
+
3. **Understand the tech stack** (for validation):
|
| 45 |
+
- **Node.js**: >=22.0.0 <23.0.0
|
| 46 |
+
- **TypeScript**: 5.9.3
|
| 47 |
+
- **React**: 19.2.3
|
| 48 |
+
- **Express**: 5.2.1
|
| 49 |
+
- **Electron**: 39.2.7
|
| 50 |
+
- **Vite**: 7.3.0
|
| 51 |
+
- **Vitest**: 4.0.16
|
| 52 |
+
- Check `package.json` files for exact versions
|
| 53 |
+
|
| 54 |
+
### Phase 2: Deep Dive Analysis (5 Agents)
|
| 55 |
+
|
| 56 |
+
Launch 5 separate deep dive agents, each with a specific focus area. Each agent should be invoked with the `@deepdive` agent and given the git diff along with their specific instructions.
|
| 57 |
+
|
| 58 |
+
#### Agent 1: Tech Stack Validation (HIGHEST PRIORITY)
|
| 59 |
+
|
| 60 |
+
**Focus:** Verify code is valid for the tech stack
|
| 61 |
+
|
| 62 |
+
**Instructions for Agent 1:**
|
| 63 |
+
|
| 64 |
+
```
|
| 65 |
+
Analyze the git diff for invalid code based on the tech stack:
|
| 66 |
+
|
| 67 |
+
1. **TypeScript/JavaScript Syntax**
|
| 68 |
+
- Check for valid TypeScript syntax (no invalid type annotations, correct import/export syntax)
|
| 69 |
+
- Verify Node.js API usage is compatible with Node.js >=22.0.0 <23.0.0
|
| 70 |
+
- Check for deprecated APIs or features not available in the Node.js version
|
| 71 |
+
- Verify ES module syntax (type: "module" in package.json)
|
| 72 |
+
|
| 73 |
+
2. **React 19.2.3 Compatibility**
|
| 74 |
+
- Check for deprecated React APIs or patterns
|
| 75 |
+
- Verify hooks usage is correct for React 19
|
| 76 |
+
- Check for invalid JSX syntax
|
| 77 |
+
- Verify component patterns match React 19 conventions
|
| 78 |
+
|
| 79 |
+
3. **Express 5.2.1 Compatibility**
|
| 80 |
+
- Check for deprecated Express APIs
|
| 81 |
+
- Verify middleware usage is correct for Express 5
|
| 82 |
+
- Check request/response handling patterns
|
| 83 |
+
|
| 84 |
+
4. **Type Safety**
|
| 85 |
+
- Verify TypeScript types are correctly used
|
| 86 |
+
- Check for `any` types that should be properly typed
|
| 87 |
+
- Verify type imports/exports are correct
|
| 88 |
+
- Check for missing type definitions
|
| 89 |
+
|
| 90 |
+
5. **Build System Compatibility**
|
| 91 |
+
- Verify Vite-specific code (imports, config) is valid
|
| 92 |
+
- Check Electron-specific APIs are used correctly
|
| 93 |
+
- Verify module resolution paths are correct
|
| 94 |
+
|
| 95 |
+
6. **Package Dependencies**
|
| 96 |
+
- Check for imports from packages not in package.json
|
| 97 |
+
- Verify version compatibility between dependencies
|
| 98 |
+
- Check for circular dependencies
|
| 99 |
+
|
| 100 |
+
Provide a detailed report with:
|
| 101 |
+
- File paths and line numbers of invalid code
|
| 102 |
+
- Specific error description (what's wrong and why)
|
| 103 |
+
- Expected vs actual behavior
|
| 104 |
+
- Priority level (CRITICAL for build-breaking issues)
|
| 105 |
+
```
|
| 106 |
+
|
| 107 |
+
#### Agent 2: Security Vulnerability Scanner
|
| 108 |
+
|
| 109 |
+
**Focus:** Security issues and vulnerabilities
|
| 110 |
+
|
| 111 |
+
**Instructions for Agent 2:**
|
| 112 |
+
|
| 113 |
+
```
|
| 114 |
+
Analyze the git diff for security vulnerabilities:
|
| 115 |
+
|
| 116 |
+
1. **Injection Vulnerabilities**
|
| 117 |
+
- SQL injection (if applicable)
|
| 118 |
+
- Command injection (exec, spawn, etc.)
|
| 119 |
+
- Path traversal vulnerabilities
|
| 120 |
+
- XSS vulnerabilities in React components
|
| 121 |
+
|
| 122 |
+
2. **Authentication & Authorization**
|
| 123 |
+
- Missing authentication checks
|
| 124 |
+
- Insecure token handling
|
| 125 |
+
- Authorization bypasses
|
| 126 |
+
- Session management issues
|
| 127 |
+
|
| 128 |
+
3. **Data Handling**
|
| 129 |
+
- Unsafe deserialization
|
| 130 |
+
- Insecure file operations
|
| 131 |
+
- Missing input validation
|
| 132 |
+
- Sensitive data exposure (secrets, tokens, passwords)
|
| 133 |
+
|
| 134 |
+
4. **Dependencies**
|
| 135 |
+
- Known vulnerable packages
|
| 136 |
+
- Insecure dependency versions
|
| 137 |
+
- Missing security patches
|
| 138 |
+
|
| 139 |
+
5. **API Security**
|
| 140 |
+
- Missing CORS configuration
|
| 141 |
+
- Insecure API endpoints
|
| 142 |
+
- Missing rate limiting
|
| 143 |
+
- Insecure WebSocket connections
|
| 144 |
+
|
| 145 |
+
6. **Electron-Specific**
|
| 146 |
+
- Insecure IPC communication
|
| 147 |
+
- Missing context isolation checks
|
| 148 |
+
- Insecure preload scripts
|
| 149 |
+
- Missing CSP headers
|
| 150 |
+
|
| 151 |
+
Provide a detailed report with:
|
| 152 |
+
- Vulnerability type and severity (CRITICAL, HIGH, MEDIUM, LOW)
|
| 153 |
+
- File paths and line numbers
|
| 154 |
+
- Attack vector description
|
| 155 |
+
- Recommended fix approach
|
| 156 |
+
```
|
| 157 |
+
|
| 158 |
+
#### Agent 3: Code Quality & Clean Code
|
| 159 |
+
|
| 160 |
+
**Focus:** Dirty code, code smells, and quality issues
|
| 161 |
+
|
| 162 |
+
**Instructions for Agent 3:**
|
| 163 |
+
|
| 164 |
+
```
|
| 165 |
+
Analyze the git diff for code quality issues:
|
| 166 |
+
|
| 167 |
+
1. **Code Smells**
|
| 168 |
+
- Long functions/methods (>50 lines)
|
| 169 |
+
- High cyclomatic complexity
|
| 170 |
+
- Duplicate code
|
| 171 |
+
- Dead code
|
| 172 |
+
- Magic numbers/strings
|
| 173 |
+
|
| 174 |
+
2. **Best Practices**
|
| 175 |
+
- Missing error handling
|
| 176 |
+
- Inconsistent naming conventions
|
| 177 |
+
- Poor separation of concerns
|
| 178 |
+
- Tight coupling
|
| 179 |
+
- Missing comments for complex logic
|
| 180 |
+
|
| 181 |
+
3. **Performance Issues**
|
| 182 |
+
- Inefficient algorithms
|
| 183 |
+
- Memory leaks (event listeners, subscriptions)
|
| 184 |
+
- Unnecessary re-renders in React
|
| 185 |
+
- Missing memoization where needed
|
| 186 |
+
- Inefficient database queries (if applicable)
|
| 187 |
+
|
| 188 |
+
4. **Maintainability**
|
| 189 |
+
- Hard-coded values
|
| 190 |
+
- Missing type definitions
|
| 191 |
+
- Inconsistent code style
|
| 192 |
+
- Poor file organization
|
| 193 |
+
- Missing tests for new code
|
| 194 |
+
|
| 195 |
+
5. **React-Specific**
|
| 196 |
+
- Missing key props in lists
|
| 197 |
+
- Direct state mutations
|
| 198 |
+
- Missing cleanup in useEffect
|
| 199 |
+
- Unnecessary useState/useEffect
|
| 200 |
+
- Prop drilling issues
|
| 201 |
+
|
| 202 |
+
Provide a detailed report with:
|
| 203 |
+
- Issue type and severity
|
| 204 |
+
- File paths and line numbers
|
| 205 |
+
- Description of the problem
|
| 206 |
+
- Impact on maintainability/performance
|
| 207 |
+
- Recommended refactoring approach
|
| 208 |
+
```
|
| 209 |
+
|
| 210 |
+
#### Agent 4: Implementation Correctness
|
| 211 |
+
|
| 212 |
+
**Focus:** Verify code implements requirements correctly
|
| 213 |
+
|
| 214 |
+
**Instructions for Agent 4:**
|
| 215 |
+
|
| 216 |
+
```
|
| 217 |
+
Analyze the git diff for implementation correctness:
|
| 218 |
+
|
| 219 |
+
1. **Logic Errors**
|
| 220 |
+
- Incorrect conditional logic
|
| 221 |
+
- Wrong variable usage
|
| 222 |
+
- Off-by-one errors
|
| 223 |
+
- Race conditions
|
| 224 |
+
- Missing null/undefined checks
|
| 225 |
+
|
| 226 |
+
2. **Functional Requirements**
|
| 227 |
+
- Missing features from requirements
|
| 228 |
+
- Incorrect feature implementation
|
| 229 |
+
- Edge cases not handled
|
| 230 |
+
- Missing validation
|
| 231 |
+
|
| 232 |
+
3. **Integration Issues**
|
| 233 |
+
- Incorrect API usage
|
| 234 |
+
- Wrong data format handling
|
| 235 |
+
- Missing error handling for external calls
|
| 236 |
+
- Incorrect state management
|
| 237 |
+
|
| 238 |
+
4. **Type Errors**
|
| 239 |
+
- Type mismatches
|
| 240 |
+
- Missing type guards
|
| 241 |
+
- Incorrect type assertions
|
| 242 |
+
- Unsafe type operations
|
| 243 |
+
|
| 244 |
+
5. **Testing Gaps**
|
| 245 |
+
- Missing unit tests
|
| 246 |
+
- Missing integration tests
|
| 247 |
+
- Tests don't cover edge cases
|
| 248 |
+
- Tests are incorrect
|
| 249 |
+
|
| 250 |
+
Provide a detailed report with:
|
| 251 |
+
- Issue description
|
| 252 |
+
- File paths and line numbers
|
| 253 |
+
- Expected vs actual behavior
|
| 254 |
+
- Steps to reproduce (if applicable)
|
| 255 |
+
- Recommended fix
|
| 256 |
+
```
|
| 257 |
+
|
| 258 |
+
#### Agent 5: Architecture & Design Patterns
|
| 259 |
+
|
| 260 |
+
**Focus:** Architectural issues and design pattern violations
|
| 261 |
+
|
| 262 |
+
**Instructions for Agent 5:**
|
| 263 |
+
|
| 264 |
+
```
|
| 265 |
+
Analyze the git diff for architectural and design issues:
|
| 266 |
+
|
| 267 |
+
1. **Architecture Violations**
|
| 268 |
+
- Violation of project structure patterns
|
| 269 |
+
- Incorrect layer separation
|
| 270 |
+
- Missing abstractions
|
| 271 |
+
- Tight coupling between modules
|
| 272 |
+
|
| 273 |
+
2. **Design Patterns**
|
| 274 |
+
- Incorrect pattern usage
|
| 275 |
+
- Missing patterns where needed
|
| 276 |
+
- Anti-patterns
|
| 277 |
+
|
| 278 |
+
3. **Project-Specific Patterns**
|
| 279 |
+
- Check against project documentation (docs/ folder)
|
| 280 |
+
- Verify route organization (server routes)
|
| 281 |
+
- Check provider patterns (server providers)
|
| 282 |
+
- Verify component organization (UI components)
|
| 283 |
+
|
| 284 |
+
4. **API Design**
|
| 285 |
+
- RESTful API violations
|
| 286 |
+
- Inconsistent response formats
|
| 287 |
+
- Missing error handling
|
| 288 |
+
- Incorrect status codes
|
| 289 |
+
|
| 290 |
+
5. **State Management**
|
| 291 |
+
- Incorrect state management patterns
|
| 292 |
+
- Missing state normalization
|
| 293 |
+
- Inefficient state updates
|
| 294 |
+
|
| 295 |
+
Provide a detailed report with:
|
| 296 |
+
- Architectural issue description
|
| 297 |
+
- File paths and affected areas
|
| 298 |
+
- Impact on system design
|
| 299 |
+
- Recommended architectural changes
|
| 300 |
+
```
|
| 301 |
+
|
| 302 |
+
### Phase 3: Consolidate Findings
|
| 303 |
+
|
| 304 |
+
After all 5 deep dive agents complete their analysis:
|
| 305 |
+
|
| 306 |
+
1. **Collect all findings** from each agent
|
| 307 |
+
2. **Prioritize issues**:
|
| 308 |
+
- CRITICAL: Tech stack invalid code (build-breaking)
|
| 309 |
+
- HIGH: Security vulnerabilities, critical logic errors
|
| 310 |
+
- MEDIUM: Code quality issues, architectural problems
|
| 311 |
+
- LOW: Minor code smells, style issues
|
| 312 |
+
|
| 313 |
+
3. **Group by file** to understand impact per file
|
| 314 |
+
4. **Create a master report** summarizing all findings
|
| 315 |
+
|
| 316 |
+
### Phase 4: Deepcode Fixes (5 Agents)
|
| 317 |
+
|
| 318 |
+
Launch 5 deepcode agents to fix the issues found. Each agent should be invoked with the `@deepcode` agent.
|
| 319 |
+
|
| 320 |
+
#### Deepcode Agent 1: Fix Tech Stack Invalid Code
|
| 321 |
+
|
| 322 |
+
**Priority:** CRITICAL - Fix first
|
| 323 |
+
|
| 324 |
+
**Instructions:**
|
| 325 |
+
|
| 326 |
+
```
|
| 327 |
+
Fix all invalid code based on tech stack issues identified by Agent 1.
|
| 328 |
+
|
| 329 |
+
Focus on:
|
| 330 |
+
1. Fixing TypeScript syntax errors
|
| 331 |
+
2. Updating deprecated Node.js APIs
|
| 332 |
+
3. Fixing React 19 compatibility issues
|
| 333 |
+
4. Correcting Express 5 API usage
|
| 334 |
+
5. Fixing type errors
|
| 335 |
+
6. Resolving build-breaking issues
|
| 336 |
+
|
| 337 |
+
After fixes, verify:
|
| 338 |
+
- Code compiles without errors
|
| 339 |
+
- TypeScript types are correct
|
| 340 |
+
- No deprecated API usage
|
| 341 |
+
```
|
| 342 |
+
|
| 343 |
+
#### Deepcode Agent 2: Fix Security Vulnerabilities
|
| 344 |
+
|
| 345 |
+
**Priority:** HIGH
|
| 346 |
+
|
| 347 |
+
**Instructions:**
|
| 348 |
+
|
| 349 |
+
```
|
| 350 |
+
Fix all security vulnerabilities identified by Agent 2.
|
| 351 |
+
|
| 352 |
+
Focus on:
|
| 353 |
+
1. Adding input validation
|
| 354 |
+
2. Fixing injection vulnerabilities
|
| 355 |
+
3. Securing authentication/authorization
|
| 356 |
+
4. Fixing insecure data handling
|
| 357 |
+
5. Updating vulnerable dependencies
|
| 358 |
+
6. Securing Electron IPC
|
| 359 |
+
|
| 360 |
+
After fixes, verify:
|
| 361 |
+
- Security vulnerabilities are addressed
|
| 362 |
+
- No sensitive data exposure
|
| 363 |
+
- Proper authentication/authorization
|
| 364 |
+
```
|
| 365 |
+
|
| 366 |
+
#### Deepcode Agent 3: Refactor Dirty Code
|
| 367 |
+
|
| 368 |
+
**Priority:** MEDIUM
|
| 369 |
+
|
| 370 |
+
**Instructions:**
|
| 371 |
+
|
| 372 |
+
```
|
| 373 |
+
Refactor code quality issues identified by Agent 3.
|
| 374 |
+
|
| 375 |
+
Focus on:
|
| 376 |
+
1. Extracting long functions
|
| 377 |
+
2. Reducing complexity
|
| 378 |
+
3. Removing duplicate code
|
| 379 |
+
4. Adding error handling
|
| 380 |
+
5. Improving React component structure
|
| 381 |
+
6. Adding missing comments
|
| 382 |
+
|
| 383 |
+
After fixes, verify:
|
| 384 |
+
- Code follows best practices
|
| 385 |
+
- No code smells remain
|
| 386 |
+
- Performance optimizations applied
|
| 387 |
+
```
|
| 388 |
+
|
| 389 |
+
#### Deepcode Agent 4: Fix Implementation Errors
|
| 390 |
+
|
| 391 |
+
**Priority:** HIGH
|
| 392 |
+
|
| 393 |
+
**Instructions:**
|
| 394 |
+
|
| 395 |
+
```
|
| 396 |
+
Fix implementation correctness issues identified by Agent 4.
|
| 397 |
+
|
| 398 |
+
Focus on:
|
| 399 |
+
1. Fixing logic errors
|
| 400 |
+
2. Adding missing features
|
| 401 |
+
3. Handling edge cases
|
| 402 |
+
4. Fixing type errors
|
| 403 |
+
5. Adding missing tests
|
| 404 |
+
|
| 405 |
+
After fixes, verify:
|
| 406 |
+
- Logic is correct
|
| 407 |
+
- Edge cases handled
|
| 408 |
+
- Tests pass
|
| 409 |
+
```
|
| 410 |
+
|
| 411 |
+
#### Deepcode Agent 5: Fix Architectural Issues
|
| 412 |
+
|
| 413 |
+
**Priority:** MEDIUM
|
| 414 |
+
|
| 415 |
+
**Instructions:**
|
| 416 |
+
|
| 417 |
+
```
|
| 418 |
+
Fix architectural issues identified by Agent 5.
|
| 419 |
+
|
| 420 |
+
Focus on:
|
| 421 |
+
1. Correcting architecture violations
|
| 422 |
+
2. Applying proper design patterns
|
| 423 |
+
3. Fixing API design issues
|
| 424 |
+
4. Improving state management
|
| 425 |
+
5. Following project patterns
|
| 426 |
+
|
| 427 |
+
After fixes, verify:
|
| 428 |
+
- Architecture is sound
|
| 429 |
+
- Patterns are correctly applied
|
| 430 |
+
- Code follows project structure
|
| 431 |
+
```
|
| 432 |
+
|
| 433 |
+
### Phase 5: Verification
|
| 434 |
+
|
| 435 |
+
After all fixes are complete:
|
| 436 |
+
|
| 437 |
+
1. **Run TypeScript compilation check**
|
| 438 |
+
|
| 439 |
+
```bash
|
| 440 |
+
npm run build:packages
|
| 441 |
+
```
|
| 442 |
+
|
| 443 |
+
2. **Run linting**
|
| 444 |
+
|
| 445 |
+
```bash
|
| 446 |
+
npm run lint
|
| 447 |
+
```
|
| 448 |
+
|
| 449 |
+
3. **Run tests** (if applicable)
|
| 450 |
+
|
| 451 |
+
```bash
|
| 452 |
+
npm run test:server
|
| 453 |
+
npm run test
|
| 454 |
+
```
|
| 455 |
+
|
| 456 |
+
4. **Verify git diff** shows only intended changes
|
| 457 |
+
|
| 458 |
+
```bash
|
| 459 |
+
git diff HEAD
|
| 460 |
+
```
|
| 461 |
+
|
| 462 |
+
5. **Create summary report**:
|
| 463 |
+
- Issues found by each agent
|
| 464 |
+
- Issues fixed by each agent
|
| 465 |
+
- Remaining issues (if any)
|
| 466 |
+
- Verification results
|
| 467 |
+
|
| 468 |
+
## Workflow Summary
|
| 469 |
+
|
| 470 |
+
1. ✅ Get git diff
|
| 471 |
+
2. ✅ Launch 5 deep dive agents (parallel analysis)
|
| 472 |
+
3. ✅ Consolidate findings and prioritize
|
| 473 |
+
4. ✅ Launch 5 deepcode agents (sequential fixes, priority order)
|
| 474 |
+
5. ✅ Verify fixes with build/lint/test
|
| 475 |
+
6. ✅ Report summary
|
| 476 |
+
|
| 477 |
+
## Notes
|
| 478 |
+
|
| 479 |
+
- **Tech stack validation is HIGHEST PRIORITY** - invalid code must be fixed first
|
| 480 |
+
- Each deep dive agent should work independently and provide comprehensive analysis
|
| 481 |
+
- Deepcode agents should fix issues in priority order
|
| 482 |
+
- All fixes should maintain existing functionality
|
| 483 |
+
- If an agent finds no issues in their domain, they should report "No issues found"
|
| 484 |
+
- If fixes introduce new issues, they should be caught in verification phase
|
jules_branch/.claude/commands/thorough.md
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
When you think you are done, you are NOT done.
|
| 2 |
+
|
| 3 |
+
You must run a mandatory 3-pass verification before concluding:
|
| 4 |
+
|
| 5 |
+
## Pass 1: Correctness & Functionality
|
| 6 |
+
|
| 7 |
+
- [ ] Verify logic matches requirements and specifications
|
| 8 |
+
- [ ] Check type safety (TypeScript types are correct and complete)
|
| 9 |
+
- [ ] Ensure imports are correct and follow project conventions
|
| 10 |
+
- [ ] Verify all functions/classes work as intended
|
| 11 |
+
- [ ] Check that return values and side effects are correct
|
| 12 |
+
- [ ] Run relevant tests if they exist, or verify testability
|
| 13 |
+
- [ ] Confirm integration with existing code works properly
|
| 14 |
+
|
| 15 |
+
## Pass 2: Edge Cases & Safety
|
| 16 |
+
|
| 17 |
+
- [ ] Handle null/undefined inputs gracefully
|
| 18 |
+
- [ ] Validate all user inputs and external data
|
| 19 |
+
- [ ] Check error handling (try/catch, error boundaries, etc.)
|
| 20 |
+
- [ ] Verify security considerations (no sensitive data exposure, proper auth checks)
|
| 21 |
+
- [ ] Test boundary conditions (empty arrays, zero values, max lengths, etc.)
|
| 22 |
+
- [ ] Ensure resource cleanup (file handles, connections, timers)
|
| 23 |
+
- [ ] Check for potential race conditions or async issues
|
| 24 |
+
- [ ] Verify file path security (no directory traversal vulnerabilities)
|
| 25 |
+
|
| 26 |
+
## Pass 3: Maintainability & Code Quality
|
| 27 |
+
|
| 28 |
+
- [ ] Code follows project style guide and conventions
|
| 29 |
+
- [ ] Functions/classes are single-purpose and well-named
|
| 30 |
+
- [ ] Remove dead code, unused imports, and console.logs
|
| 31 |
+
- [ ] Extract magic numbers/strings into named constants
|
| 32 |
+
- [ ] Check for code duplication (DRY principle)
|
| 33 |
+
- [ ] Verify appropriate abstraction levels (not over/under-engineered)
|
| 34 |
+
- [ ] Add necessary comments for complex logic
|
| 35 |
+
- [ ] Ensure consistent error messages and logging
|
| 36 |
+
- [ ] Check that code is readable and self-documenting
|
| 37 |
+
- [ ] Verify proper separation of concerns
|
| 38 |
+
|
| 39 |
+
**For each pass, explicitly report:**
|
| 40 |
+
|
| 41 |
+
- What you checked
|
| 42 |
+
- Any issues found and how they were fixed
|
| 43 |
+
- Any remaining concerns or trade-offs
|
| 44 |
+
|
| 45 |
+
Only after completing all three passes with explicit findings may you conclude the work is done.
|
jules_branch/.claude/commands/validate-build.md
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Project Build and Fix Command
|
| 2 |
+
|
| 3 |
+
Run all builds and intelligently fix any failures based on what changed.
|
| 4 |
+
|
| 5 |
+
## Instructions
|
| 6 |
+
|
| 7 |
+
1. **Run the build**
|
| 8 |
+
|
| 9 |
+
```bash
|
| 10 |
+
npm run build
|
| 11 |
+
```
|
| 12 |
+
|
| 13 |
+
This builds all packages and the UI application.
|
| 14 |
+
|
| 15 |
+
2. **If the build succeeds**, report success and stop.
|
| 16 |
+
|
| 17 |
+
3. **If the build fails**, analyze the failures:
|
| 18 |
+
- Note which build step failed and the error messages
|
| 19 |
+
- Check for TypeScript compilation errors, missing dependencies, or configuration issues
|
| 20 |
+
- Run `git diff main` to see what code has changed
|
| 21 |
+
|
| 22 |
+
4. **Determine the nature of the failure**:
|
| 23 |
+
- **If the failure is due to intentional changes** (new features, refactoring, dependency updates):
|
| 24 |
+
- Fix any TypeScript type errors introduced by the changes
|
| 25 |
+
- Update build configuration if needed (e.g., tsconfig.json, vite.config.mts)
|
| 26 |
+
- Ensure all new dependencies are properly installed
|
| 27 |
+
- Fix import paths or module resolution issues
|
| 28 |
+
|
| 29 |
+
- **If the failure appears to be a regression** (broken imports, missing files, configuration errors):
|
| 30 |
+
- Fix the source code to restore the build
|
| 31 |
+
- Check for accidentally deleted files or broken references
|
| 32 |
+
- Verify build configuration files are correct
|
| 33 |
+
|
| 34 |
+
5. **Common build issues to check**:
|
| 35 |
+
- **TypeScript errors**: Fix type mismatches, missing types, or incorrect imports
|
| 36 |
+
- **Missing dependencies**: Run `npm install` if packages are missing
|
| 37 |
+
- **Import/export errors**: Fix incorrect import paths or missing exports
|
| 38 |
+
- **Build configuration**: Check tsconfig.json, vite.config.mts, or other build configs
|
| 39 |
+
- **Package build order**: Ensure `build:packages` completes before building apps
|
| 40 |
+
|
| 41 |
+
6. **How to decide if it's intentional vs regression**:
|
| 42 |
+
- Look at the git diff and commit messages
|
| 43 |
+
- If the change was deliberate and introduced new code that needs fixing → fix the new code
|
| 44 |
+
- If the change broke existing functionality that should still build → fix the regression
|
| 45 |
+
- When in doubt, ask the user
|
| 46 |
+
|
| 47 |
+
7. **After making fixes**, re-run the build to verify everything compiles successfully.
|
| 48 |
+
|
| 49 |
+
8. **Report summary** of what was fixed (TypeScript errors, configuration issues, missing dependencies, etc.).
|
jules_branch/.claude/commands/validate-tests.md
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Project Test and Fix Command
|
| 2 |
+
|
| 3 |
+
Run all tests and intelligently fix any failures based on what changed.
|
| 4 |
+
|
| 5 |
+
## Instructions
|
| 6 |
+
|
| 7 |
+
1. **Run all tests**
|
| 8 |
+
|
| 9 |
+
```bash
|
| 10 |
+
npm run test:all
|
| 11 |
+
```
|
| 12 |
+
|
| 13 |
+
2. **If all tests pass**, report success and stop.
|
| 14 |
+
|
| 15 |
+
3. **If any tests fail**, analyze the failures:
|
| 16 |
+
- Note which tests failed and their error messages
|
| 17 |
+
- Run `git diff main` to see what code has changed
|
| 18 |
+
|
| 19 |
+
4. **Determine the nature of the change**:
|
| 20 |
+
- **If the logic change is intentional** (new feature, refactor, behavior change):
|
| 21 |
+
- Update the failing tests to match the new expected behavior
|
| 22 |
+
- The tests should reflect what the code NOW does correctly
|
| 23 |
+
|
| 24 |
+
- **If the logic change appears to be a bug** (regression, unintended side effect):
|
| 25 |
+
- Fix the source code to restore the expected behavior
|
| 26 |
+
- Do NOT modify the tests - they are catching a real bug
|
| 27 |
+
|
| 28 |
+
5. **How to decide if it's a bug vs intentional change**:
|
| 29 |
+
- Look at the git diff and commit messages
|
| 30 |
+
- If the change was deliberate and the test expectations are now outdated → update tests
|
| 31 |
+
- If the change broke existing functionality that should still work → fix the code
|
| 32 |
+
- When in doubt, ask the user
|
| 33 |
+
|
| 34 |
+
6. **After making fixes**, re-run the tests to verify everything passes.
|
| 35 |
+
|
| 36 |
+
7. **Report summary** of what was fixed (tests updated vs code fixed).
|
jules_branch/.dockerignore
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Dependencies
|
| 2 |
+
node_modules/
|
| 3 |
+
**/node_modules/
|
| 4 |
+
|
| 5 |
+
# Build outputs
|
| 6 |
+
dist/
|
| 7 |
+
**/dist/
|
| 8 |
+
dist-electron/
|
| 9 |
+
**/dist-electron/
|
| 10 |
+
build/
|
| 11 |
+
**/build/
|
| 12 |
+
.next/
|
| 13 |
+
**/.next/
|
| 14 |
+
.nuxt/
|
| 15 |
+
**/.nuxt/
|
| 16 |
+
out/
|
| 17 |
+
**/out/
|
| 18 |
+
.cache/
|
| 19 |
+
**/.cache/
|
jules_branch/.geminiignore
ADDED
|
@@ -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
|
jules_branch/.github/ISSUE_TEMPLATE/bug_report.yml
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
name: Bug Report
|
| 2 |
+
description: File a bug report to help us improve Automaker
|
| 3 |
+
title: '[Bug]: '
|
| 4 |
+
labels: ['bug']
|
| 5 |
+
body:
|
| 6 |
+
- type: markdown
|
| 7 |
+
attributes:
|
| 8 |
+
value: |
|
| 9 |
+
Thanks for taking the time to report a bug! Please fill out the form below with as much detail as possible.
|
| 10 |
+
|
| 11 |
+
- type: dropdown
|
| 12 |
+
id: operating-system
|
| 13 |
+
attributes:
|
| 14 |
+
label: Operating System
|
| 15 |
+
description: What operating system are you using?
|
| 16 |
+
options:
|
| 17 |
+
- macOS
|
| 18 |
+
- Windows
|
| 19 |
+
- Linux
|
| 20 |
+
- Other
|
| 21 |
+
default: 0
|
| 22 |
+
validations:
|
| 23 |
+
required: true
|
| 24 |
+
|
| 25 |
+
- type: dropdown
|
| 26 |
+
id: run-mode
|
| 27 |
+
attributes:
|
| 28 |
+
label: Run Mode
|
| 29 |
+
description: How are you running Automaker?
|
| 30 |
+
options:
|
| 31 |
+
- Electron (Desktop App)
|
| 32 |
+
- Web (Browser)
|
| 33 |
+
- Docker
|
| 34 |
+
default: 0
|
| 35 |
+
validations:
|
| 36 |
+
required: true
|
| 37 |
+
|
| 38 |
+
- type: input
|
| 39 |
+
id: app-version
|
| 40 |
+
attributes:
|
| 41 |
+
label: App Version
|
| 42 |
+
description: What version of Automaker are you using? (e.g., 0.1.0)
|
| 43 |
+
placeholder: '0.1.0'
|
| 44 |
+
validations:
|
| 45 |
+
required: true
|
| 46 |
+
|
| 47 |
+
- type: textarea
|
| 48 |
+
id: bug-description
|
| 49 |
+
attributes:
|
| 50 |
+
label: Bug Description
|
| 51 |
+
description: A clear and concise description of what the bug is.
|
| 52 |
+
placeholder: Describe the bug...
|
| 53 |
+
validations:
|
| 54 |
+
required: true
|
| 55 |
+
|
| 56 |
+
- type: textarea
|
| 57 |
+
id: steps-to-reproduce
|
| 58 |
+
attributes:
|
| 59 |
+
label: Steps to Reproduce
|
| 60 |
+
description: Steps to reproduce the behavior
|
| 61 |
+
placeholder: |
|
| 62 |
+
1. Go to '...'
|
| 63 |
+
2. Click on '...'
|
| 64 |
+
3. Scroll down to '...'
|
| 65 |
+
4. See error
|
| 66 |
+
validations:
|
| 67 |
+
required: true
|
| 68 |
+
|
| 69 |
+
- type: textarea
|
| 70 |
+
id: expected-behavior
|
| 71 |
+
attributes:
|
| 72 |
+
label: Expected Behavior
|
| 73 |
+
description: A clear and concise description of what you expected to happen.
|
| 74 |
+
placeholder: What should have happened?
|
| 75 |
+
validations:
|
| 76 |
+
required: true
|
| 77 |
+
|
| 78 |
+
- type: textarea
|
| 79 |
+
id: actual-behavior
|
| 80 |
+
attributes:
|
| 81 |
+
label: Actual Behavior
|
| 82 |
+
description: A clear and concise description of what actually happened.
|
| 83 |
+
placeholder: What actually happened?
|
| 84 |
+
validations:
|
| 85 |
+
required: true
|
| 86 |
+
|
| 87 |
+
- type: textarea
|
| 88 |
+
id: screenshots
|
| 89 |
+
attributes:
|
| 90 |
+
label: Screenshots
|
| 91 |
+
description: If applicable, add screenshots to help explain your problem.
|
| 92 |
+
placeholder: Drag and drop screenshots here or paste image URLs
|
| 93 |
+
|
| 94 |
+
- type: textarea
|
| 95 |
+
id: logs
|
| 96 |
+
attributes:
|
| 97 |
+
label: Relevant Logs
|
| 98 |
+
description: If applicable, paste relevant logs or error messages.
|
| 99 |
+
placeholder: Paste logs here...
|
| 100 |
+
render: shell
|
| 101 |
+
|
| 102 |
+
- type: textarea
|
| 103 |
+
id: additional-context
|
| 104 |
+
attributes:
|
| 105 |
+
label: Additional Context
|
| 106 |
+
description: Add any other context about the problem here.
|
| 107 |
+
placeholder: Any additional information that might be helpful...
|
| 108 |
+
|
| 109 |
+
- type: checkboxes
|
| 110 |
+
id: terms
|
| 111 |
+
attributes:
|
| 112 |
+
label: Checklist
|
| 113 |
+
options:
|
| 114 |
+
- label: I have searched existing issues to ensure this bug hasn't been reported already
|
| 115 |
+
required: true
|
| 116 |
+
- label: I have provided all required information above
|
| 117 |
+
required: true
|
jules_branch/.github/ISSUE_TEMPLATE/feature_request.yml
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
name: Feature Request
|
| 2 |
+
description: Suggest a new feature or enhancement for Automaker
|
| 3 |
+
title: '[Feature]: '
|
| 4 |
+
labels: ['enhancement']
|
| 5 |
+
body:
|
| 6 |
+
- type: markdown
|
| 7 |
+
attributes:
|
| 8 |
+
value: |
|
| 9 |
+
Thanks for taking the time to suggest a feature! Please fill out the form below to help us understand your request.
|
| 10 |
+
|
| 11 |
+
- type: dropdown
|
| 12 |
+
id: feature-area
|
| 13 |
+
attributes:
|
| 14 |
+
label: Feature Area
|
| 15 |
+
description: Which area of Automaker does this feature relate to?
|
| 16 |
+
options:
|
| 17 |
+
- UI/UX (User Interface)
|
| 18 |
+
- Agent/AI
|
| 19 |
+
- Kanban Board
|
| 20 |
+
- Git/Worktree Management
|
| 21 |
+
- Project Management
|
| 22 |
+
- Settings/Configuration
|
| 23 |
+
- Documentation
|
| 24 |
+
- Performance
|
| 25 |
+
- Other
|
| 26 |
+
default: 0
|
| 27 |
+
validations:
|
| 28 |
+
required: true
|
| 29 |
+
|
| 30 |
+
- type: dropdown
|
| 31 |
+
id: priority
|
| 32 |
+
attributes:
|
| 33 |
+
label: Priority
|
| 34 |
+
description: How important is this feature to your workflow?
|
| 35 |
+
options:
|
| 36 |
+
- Nice to have
|
| 37 |
+
- Would improve my workflow
|
| 38 |
+
- Critical for my use case
|
| 39 |
+
default: 0
|
| 40 |
+
validations:
|
| 41 |
+
required: true
|
| 42 |
+
|
| 43 |
+
- type: textarea
|
| 44 |
+
id: problem-statement
|
| 45 |
+
attributes:
|
| 46 |
+
label: Problem Statement
|
| 47 |
+
description: Is your feature request related to a problem? Please describe the problem you're trying to solve.
|
| 48 |
+
placeholder: A clear and concise description of what the problem is. Ex. I'm always frustrated when...
|
| 49 |
+
validations:
|
| 50 |
+
required: true
|
| 51 |
+
|
| 52 |
+
- type: textarea
|
| 53 |
+
id: proposed-solution
|
| 54 |
+
attributes:
|
| 55 |
+
label: Proposed Solution
|
| 56 |
+
description: Describe the solution you'd like to see implemented.
|
| 57 |
+
placeholder: A clear and concise description of what you want to happen.
|
| 58 |
+
validations:
|
| 59 |
+
required: true
|
| 60 |
+
|
| 61 |
+
- type: textarea
|
| 62 |
+
id: alternatives-considered
|
| 63 |
+
attributes:
|
| 64 |
+
label: Alternatives Considered
|
| 65 |
+
description: Describe any alternative solutions or workarounds you've considered.
|
| 66 |
+
placeholder: A clear and concise description of any alternative solutions or features you've considered.
|
| 67 |
+
validations:
|
| 68 |
+
required: false
|
| 69 |
+
|
| 70 |
+
- type: textarea
|
| 71 |
+
id: use-cases
|
| 72 |
+
attributes:
|
| 73 |
+
label: Use Cases
|
| 74 |
+
description: Describe specific scenarios where this feature would be useful.
|
| 75 |
+
placeholder: |
|
| 76 |
+
1. When working on...
|
| 77 |
+
2. As a user who needs to...
|
| 78 |
+
3. In situations where...
|
| 79 |
+
validations:
|
| 80 |
+
required: false
|
| 81 |
+
|
| 82 |
+
- type: textarea
|
| 83 |
+
id: mockups
|
| 84 |
+
attributes:
|
| 85 |
+
label: Mockups/Screenshots
|
| 86 |
+
description: If applicable, add mockups, wireframes, or screenshots to help illustrate your feature request.
|
| 87 |
+
placeholder: Drag and drop images here or paste image URLs
|
| 88 |
+
validations:
|
| 89 |
+
required: false
|
| 90 |
+
|
| 91 |
+
- type: textarea
|
| 92 |
+
id: additional-context
|
| 93 |
+
attributes:
|
| 94 |
+
label: Additional Context
|
| 95 |
+
description: Add any other context, references, or examples about the feature request here.
|
| 96 |
+
placeholder: Any additional information that might be helpful...
|
| 97 |
+
validations:
|
| 98 |
+
required: false
|
| 99 |
+
|
| 100 |
+
- type: checkboxes
|
| 101 |
+
id: terms
|
| 102 |
+
attributes:
|
| 103 |
+
label: Checklist
|
| 104 |
+
options:
|
| 105 |
+
- label: I have searched existing issues to ensure this feature hasn't been requested already
|
| 106 |
+
required: true
|
| 107 |
+
- label: I have provided a clear description of the problem and proposed solution
|
| 108 |
+
required: true
|
jules_branch/.github/actions/setup-project/action.yml
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
name: 'Setup Project'
|
| 2 |
+
description: 'Common setup steps for CI workflows - checkout, Node.js, dependencies, and native modules'
|
| 3 |
+
|
| 4 |
+
inputs:
|
| 5 |
+
node-version:
|
| 6 |
+
description: 'Node.js version to use'
|
| 7 |
+
required: false
|
| 8 |
+
default: '22'
|
| 9 |
+
check-lockfile:
|
| 10 |
+
description: 'Run lockfile lint check for SSH URLs'
|
| 11 |
+
required: false
|
| 12 |
+
default: 'false'
|
| 13 |
+
rebuild-node-pty-path:
|
| 14 |
+
description: 'Working directory for node-pty rebuild (empty = root)'
|
| 15 |
+
required: false
|
| 16 |
+
default: ''
|
| 17 |
+
|
| 18 |
+
runs:
|
| 19 |
+
using: 'composite'
|
| 20 |
+
steps:
|
| 21 |
+
- name: Setup Node.js
|
| 22 |
+
uses: actions/setup-node@v4
|
| 23 |
+
with:
|
| 24 |
+
node-version: ${{ inputs.node-version }}
|
| 25 |
+
cache: 'npm'
|
| 26 |
+
cache-dependency-path: package-lock.json
|
| 27 |
+
|
| 28 |
+
- name: Configure Git for HTTPS
|
| 29 |
+
shell: bash
|
| 30 |
+
# Convert SSH URLs to HTTPS for git dependencies (e.g., @electron/node-gyp)
|
| 31 |
+
# This is needed because SSH authentication isn't available in CI
|
| 32 |
+
run: git config --global url."https://github.com/".insteadOf "git@github.com:"
|
| 33 |
+
|
| 34 |
+
- name: Auto-fix SSH URLs in lockfile
|
| 35 |
+
if: inputs.check-lockfile == 'true'
|
| 36 |
+
shell: bash
|
| 37 |
+
# Auto-fix any git+ssh:// URLs in package-lock.json before linting
|
| 38 |
+
# This handles cases where npm reintroduces SSH URLs for git dependencies
|
| 39 |
+
run: node scripts/fix-lockfile-urls.mjs
|
| 40 |
+
|
| 41 |
+
- name: Check for SSH URLs in lockfile
|
| 42 |
+
if: inputs.check-lockfile == 'true'
|
| 43 |
+
shell: bash
|
| 44 |
+
run: npm run lint:lockfile
|
| 45 |
+
|
| 46 |
+
- name: Install dependencies
|
| 47 |
+
shell: bash
|
| 48 |
+
# Use npm install instead of npm ci to correctly resolve platform-specific
|
| 49 |
+
# optional dependencies (e.g., @tailwindcss/oxide, lightningcss binaries)
|
| 50 |
+
# Skip scripts to avoid electron-builder install-app-deps which uses too much memory
|
| 51 |
+
# Use --force to allow platform-specific dev dependencies like dmg-license on non-darwin platforms
|
| 52 |
+
run: npm install --ignore-scripts --force
|
| 53 |
+
|
| 54 |
+
- name: Install Linux native bindings
|
| 55 |
+
if: runner.os == 'Linux'
|
| 56 |
+
shell: bash
|
| 57 |
+
# Workaround for npm optional dependencies bug (npm/cli#4828)
|
| 58 |
+
# Explicitly install Linux bindings needed for build tools
|
| 59 |
+
run: |
|
| 60 |
+
npm install --no-save --force --ignore-scripts \
|
| 61 |
+
@rollup/rollup-linux-x64-gnu@4.53.3 \
|
| 62 |
+
@tailwindcss/oxide-linux-x64-gnu@4.1.17
|
| 63 |
+
|
| 64 |
+
- name: Build shared packages
|
| 65 |
+
shell: bash
|
| 66 |
+
# Build shared packages (types, utils, platform, etc.) before apps can use them
|
| 67 |
+
run: npm run build:packages
|
| 68 |
+
|
| 69 |
+
- name: Rebuild native modules (root)
|
| 70 |
+
if: inputs.rebuild-node-pty-path == ''
|
| 71 |
+
shell: bash
|
| 72 |
+
# Rebuild node-pty and other native modules for Electron
|
| 73 |
+
run: npm rebuild node-pty
|
| 74 |
+
|
| 75 |
+
- name: Rebuild native modules (workspace)
|
| 76 |
+
if: inputs.rebuild-node-pty-path != ''
|
| 77 |
+
shell: bash
|
| 78 |
+
# Rebuild node-pty and other native modules needed for server
|
| 79 |
+
run: npm rebuild node-pty
|
| 80 |
+
working-directory: ${{ inputs.rebuild-node-pty-path }}
|
jules_branch/.github/scripts/upload-to-r2.js
ADDED
|
@@ -0,0 +1,355 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const { S3Client, PutObjectCommand, GetObjectCommand } = require('@aws-sdk/client-s3');
|
| 2 |
+
const fs = require('fs');
|
| 3 |
+
const path = require('path');
|
| 4 |
+
const https = require('https');
|
| 5 |
+
const { pipeline } = require('stream/promises');
|
| 6 |
+
|
| 7 |
+
const s3Client = new S3Client({
|
| 8 |
+
region: 'auto',
|
| 9 |
+
endpoint: process.env.R2_ENDPOINT,
|
| 10 |
+
credentials: {
|
| 11 |
+
accessKeyId: process.env.R2_ACCESS_KEY_ID,
|
| 12 |
+
secretAccessKey: process.env.R2_SECRET_ACCESS_KEY,
|
| 13 |
+
},
|
| 14 |
+
});
|
| 15 |
+
|
| 16 |
+
const BUCKET = process.env.R2_BUCKET_NAME;
|
| 17 |
+
const PUBLIC_URL = process.env.R2_PUBLIC_URL;
|
| 18 |
+
const VERSION = process.env.RELEASE_VERSION;
|
| 19 |
+
const RELEASE_TAG = process.env.RELEASE_TAG || `v${VERSION}`;
|
| 20 |
+
const GITHUB_REPO = process.env.GITHUB_REPOSITORY;
|
| 21 |
+
|
| 22 |
+
async function fetchExistingReleases() {
|
| 23 |
+
try {
|
| 24 |
+
const response = await s3Client.send(
|
| 25 |
+
new GetObjectCommand({
|
| 26 |
+
Bucket: BUCKET,
|
| 27 |
+
Key: 'releases.json',
|
| 28 |
+
})
|
| 29 |
+
);
|
| 30 |
+
const body = await response.Body.transformToString();
|
| 31 |
+
return JSON.parse(body);
|
| 32 |
+
} catch (error) {
|
| 33 |
+
if (error.name === 'NoSuchKey' || error.$metadata?.httpStatusCode === 404) {
|
| 34 |
+
console.log('No existing releases.json found, creating new one');
|
| 35 |
+
return { latestVersion: null, releases: [] };
|
| 36 |
+
}
|
| 37 |
+
throw error;
|
| 38 |
+
}
|
| 39 |
+
}
|
| 40 |
+
|
| 41 |
+
async function uploadFile(localPath, r2Key, contentType) {
|
| 42 |
+
const fileBuffer = fs.readFileSync(localPath);
|
| 43 |
+
const stats = fs.statSync(localPath);
|
| 44 |
+
|
| 45 |
+
await s3Client.send(
|
| 46 |
+
new PutObjectCommand({
|
| 47 |
+
Bucket: BUCKET,
|
| 48 |
+
Key: r2Key,
|
| 49 |
+
Body: fileBuffer,
|
| 50 |
+
ContentType: contentType,
|
| 51 |
+
})
|
| 52 |
+
);
|
| 53 |
+
|
| 54 |
+
console.log(`Uploaded: ${r2Key} (${stats.size} bytes)`);
|
| 55 |
+
return stats.size;
|
| 56 |
+
}
|
| 57 |
+
|
| 58 |
+
function findArtifacts(dir, pattern) {
|
| 59 |
+
if (!fs.existsSync(dir)) return [];
|
| 60 |
+
const files = fs.readdirSync(dir);
|
| 61 |
+
return files.filter((f) => pattern.test(f)).map((f) => path.join(dir, f));
|
| 62 |
+
}
|
| 63 |
+
|
| 64 |
+
async function checkUrlAccessible(url, maxRetries = 10, initialDelay = 1000) {
|
| 65 |
+
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
| 66 |
+
try {
|
| 67 |
+
const result = await new Promise((resolve, reject) => {
|
| 68 |
+
const request = https.get(url, { timeout: 10000 }, (response) => {
|
| 69 |
+
const statusCode = response.statusCode;
|
| 70 |
+
|
| 71 |
+
// Follow redirects
|
| 72 |
+
if (
|
| 73 |
+
statusCode === 302 ||
|
| 74 |
+
statusCode === 301 ||
|
| 75 |
+
statusCode === 307 ||
|
| 76 |
+
statusCode === 308
|
| 77 |
+
) {
|
| 78 |
+
const redirectUrl = response.headers.location;
|
| 79 |
+
response.destroy();
|
| 80 |
+
if (!redirectUrl) {
|
| 81 |
+
resolve({
|
| 82 |
+
accessible: false,
|
| 83 |
+
statusCode,
|
| 84 |
+
error: 'Redirect without location header',
|
| 85 |
+
});
|
| 86 |
+
return;
|
| 87 |
+
}
|
| 88 |
+
// Follow the redirect URL
|
| 89 |
+
return https
|
| 90 |
+
.get(redirectUrl, { timeout: 10000 }, (redirectResponse) => {
|
| 91 |
+
const redirectStatus = redirectResponse.statusCode;
|
| 92 |
+
const contentType = redirectResponse.headers['content-type'] || '';
|
| 93 |
+
// Check if it's actually a file (zip/tar.gz) and not HTML
|
| 94 |
+
const isFile =
|
| 95 |
+
contentType.includes('application/zip') ||
|
| 96 |
+
contentType.includes('application/gzip') ||
|
| 97 |
+
contentType.includes('application/x-gzip') ||
|
| 98 |
+
contentType.includes('application/x-tar') ||
|
| 99 |
+
redirectUrl.includes('.zip') ||
|
| 100 |
+
redirectUrl.includes('.tar.gz');
|
| 101 |
+
const isGood = redirectStatus >= 200 && redirectStatus < 300 && isFile;
|
| 102 |
+
redirectResponse.destroy();
|
| 103 |
+
resolve({
|
| 104 |
+
accessible: isGood,
|
| 105 |
+
statusCode: redirectStatus,
|
| 106 |
+
finalUrl: redirectUrl,
|
| 107 |
+
contentType,
|
| 108 |
+
});
|
| 109 |
+
})
|
| 110 |
+
.on('error', (error) => {
|
| 111 |
+
resolve({
|
| 112 |
+
accessible: false,
|
| 113 |
+
statusCode,
|
| 114 |
+
error: error.message,
|
| 115 |
+
});
|
| 116 |
+
})
|
| 117 |
+
.on('timeout', function () {
|
| 118 |
+
this.destroy();
|
| 119 |
+
resolve({
|
| 120 |
+
accessible: false,
|
| 121 |
+
statusCode,
|
| 122 |
+
error: 'Timeout following redirect',
|
| 123 |
+
});
|
| 124 |
+
});
|
| 125 |
+
}
|
| 126 |
+
|
| 127 |
+
// Check if status is good (200-299 range) and it's actually a file
|
| 128 |
+
const contentType = response.headers['content-type'] || '';
|
| 129 |
+
const isFile =
|
| 130 |
+
contentType.includes('application/zip') ||
|
| 131 |
+
contentType.includes('application/gzip') ||
|
| 132 |
+
contentType.includes('application/x-gzip') ||
|
| 133 |
+
contentType.includes('application/x-tar') ||
|
| 134 |
+
url.includes('.zip') ||
|
| 135 |
+
url.includes('.tar.gz');
|
| 136 |
+
const isGood = statusCode >= 200 && statusCode < 300 && isFile;
|
| 137 |
+
response.destroy();
|
| 138 |
+
resolve({ accessible: isGood, statusCode, contentType });
|
| 139 |
+
});
|
| 140 |
+
|
| 141 |
+
request.on('error', (error) => {
|
| 142 |
+
resolve({
|
| 143 |
+
accessible: false,
|
| 144 |
+
statusCode: null,
|
| 145 |
+
error: error.message,
|
| 146 |
+
});
|
| 147 |
+
});
|
| 148 |
+
|
| 149 |
+
request.on('timeout', () => {
|
| 150 |
+
request.destroy();
|
| 151 |
+
resolve({
|
| 152 |
+
accessible: false,
|
| 153 |
+
statusCode: null,
|
| 154 |
+
error: 'Request timeout',
|
| 155 |
+
});
|
| 156 |
+
});
|
| 157 |
+
});
|
| 158 |
+
|
| 159 |
+
if (result.accessible) {
|
| 160 |
+
if (attempt > 0) {
|
| 161 |
+
console.log(
|
| 162 |
+
`✓ URL ${url} is now accessible after ${attempt} retries (status: ${result.statusCode})`
|
| 163 |
+
);
|
| 164 |
+
} else {
|
| 165 |
+
console.log(`✓ URL ${url} is accessible (status: ${result.statusCode})`);
|
| 166 |
+
}
|
| 167 |
+
return result.finalUrl || url; // Return the final URL (after redirects) if available
|
| 168 |
+
} else {
|
| 169 |
+
const errorMsg = result.error ? ` - ${result.error}` : '';
|
| 170 |
+
const statusMsg = result.statusCode ? ` (status: ${result.statusCode})` : '';
|
| 171 |
+
const contentTypeMsg = result.contentType ? ` [content-type: ${result.contentType}]` : '';
|
| 172 |
+
console.log(`✗ URL ${url} not accessible${statusMsg}${contentTypeMsg}${errorMsg}`);
|
| 173 |
+
}
|
| 174 |
+
} catch (error) {
|
| 175 |
+
console.log(`✗ URL ${url} check failed: ${error.message}`);
|
| 176 |
+
}
|
| 177 |
+
|
| 178 |
+
if (attempt < maxRetries - 1) {
|
| 179 |
+
const delay = initialDelay * Math.pow(2, attempt);
|
| 180 |
+
console.log(` Retrying in ${delay}ms... (attempt ${attempt + 1}/${maxRetries})`);
|
| 181 |
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
| 182 |
+
}
|
| 183 |
+
}
|
| 184 |
+
|
| 185 |
+
throw new Error(`URL ${url} is not accessible after ${maxRetries} attempts`);
|
| 186 |
+
}
|
| 187 |
+
|
| 188 |
+
async function downloadFromGitHub(url, outputPath) {
|
| 189 |
+
return new Promise((resolve, reject) => {
|
| 190 |
+
const request = https.get(url, { timeout: 30000 }, (response) => {
|
| 191 |
+
const statusCode = response.statusCode;
|
| 192 |
+
|
| 193 |
+
// Follow redirects (all redirect types)
|
| 194 |
+
if (statusCode === 301 || statusCode === 302 || statusCode === 307 || statusCode === 308) {
|
| 195 |
+
const redirectUrl = response.headers.location;
|
| 196 |
+
response.destroy();
|
| 197 |
+
if (!redirectUrl) {
|
| 198 |
+
reject(new Error(`Redirect without location header for ${url}`));
|
| 199 |
+
return;
|
| 200 |
+
}
|
| 201 |
+
// Resolve relative redirects
|
| 202 |
+
const finalRedirectUrl = redirectUrl.startsWith('http')
|
| 203 |
+
? redirectUrl
|
| 204 |
+
: new URL(redirectUrl, url).href;
|
| 205 |
+
console.log(` Following redirect: ${finalRedirectUrl}`);
|
| 206 |
+
return downloadFromGitHub(finalRedirectUrl, outputPath).then(resolve).catch(reject);
|
| 207 |
+
}
|
| 208 |
+
|
| 209 |
+
if (statusCode !== 200) {
|
| 210 |
+
response.destroy();
|
| 211 |
+
reject(new Error(`Failed to download ${url}: ${statusCode} ${response.statusMessage}`));
|
| 212 |
+
return;
|
| 213 |
+
}
|
| 214 |
+
|
| 215 |
+
const fileStream = fs.createWriteStream(outputPath);
|
| 216 |
+
response.pipe(fileStream);
|
| 217 |
+
fileStream.on('finish', () => {
|
| 218 |
+
fileStream.close();
|
| 219 |
+
resolve();
|
| 220 |
+
});
|
| 221 |
+
fileStream.on('error', (error) => {
|
| 222 |
+
response.destroy();
|
| 223 |
+
reject(error);
|
| 224 |
+
});
|
| 225 |
+
});
|
| 226 |
+
|
| 227 |
+
request.on('error', reject);
|
| 228 |
+
request.on('timeout', () => {
|
| 229 |
+
request.destroy();
|
| 230 |
+
reject(new Error(`Request timeout for ${url}`));
|
| 231 |
+
});
|
| 232 |
+
});
|
| 233 |
+
}
|
| 234 |
+
|
| 235 |
+
async function main() {
|
| 236 |
+
const artifactsDir = 'artifacts';
|
| 237 |
+
const tempDir = path.join(artifactsDir, 'temp');
|
| 238 |
+
|
| 239 |
+
// Create temp directory for downloaded GitHub archives
|
| 240 |
+
if (!fs.existsSync(tempDir)) {
|
| 241 |
+
fs.mkdirSync(tempDir, { recursive: true });
|
| 242 |
+
}
|
| 243 |
+
|
| 244 |
+
// Download source archives from GitHub
|
| 245 |
+
const githubZipUrl = `https://github.com/${GITHUB_REPO}/archive/refs/tags/${RELEASE_TAG}.zip`;
|
| 246 |
+
const githubTarGzUrl = `https://github.com/${GITHUB_REPO}/archive/refs/tags/${RELEASE_TAG}.tar.gz`;
|
| 247 |
+
|
| 248 |
+
const sourceZipPath = path.join(tempDir, `automaker-${VERSION}.zip`);
|
| 249 |
+
const sourceTarGzPath = path.join(tempDir, `automaker-${VERSION}.tar.gz`);
|
| 250 |
+
|
| 251 |
+
console.log(`Waiting for source archives to be available on GitHub...`);
|
| 252 |
+
console.log(` ZIP: ${githubZipUrl}`);
|
| 253 |
+
console.log(` TAR.GZ: ${githubTarGzUrl}`);
|
| 254 |
+
|
| 255 |
+
// Wait for archives to be accessible with exponential backoff
|
| 256 |
+
// This returns the final URL after following redirects
|
| 257 |
+
const finalZipUrl = await checkUrlAccessible(githubZipUrl);
|
| 258 |
+
const finalTarGzUrl = await checkUrlAccessible(githubTarGzUrl);
|
| 259 |
+
|
| 260 |
+
console.log(`Downloading source archives from GitHub...`);
|
| 261 |
+
await downloadFromGitHub(finalZipUrl, sourceZipPath);
|
| 262 |
+
await downloadFromGitHub(finalTarGzUrl, sourceTarGzPath);
|
| 263 |
+
|
| 264 |
+
console.log(`Downloaded source archives successfully`);
|
| 265 |
+
|
| 266 |
+
// Find all artifacts
|
| 267 |
+
const artifacts = {
|
| 268 |
+
windows: findArtifacts(path.join(artifactsDir, 'windows-builds'), /\.exe$/),
|
| 269 |
+
macos: findArtifacts(path.join(artifactsDir, 'macos-builds'), /-x64\.dmg$/),
|
| 270 |
+
macosArm: findArtifacts(path.join(artifactsDir, 'macos-builds'), /-arm64\.dmg$/),
|
| 271 |
+
linux: findArtifacts(path.join(artifactsDir, 'linux-builds'), /\.AppImage$/),
|
| 272 |
+
sourceZip: [sourceZipPath],
|
| 273 |
+
sourceTarGz: [sourceTarGzPath],
|
| 274 |
+
};
|
| 275 |
+
|
| 276 |
+
console.log('Found artifacts:');
|
| 277 |
+
for (const [platform, files] of Object.entries(artifacts)) {
|
| 278 |
+
console.log(
|
| 279 |
+
` ${platform}: ${files.length > 0 ? files.map((f) => path.basename(f)).join(', ') : 'none'}`
|
| 280 |
+
);
|
| 281 |
+
}
|
| 282 |
+
|
| 283 |
+
// Upload each artifact to R2
|
| 284 |
+
const assets = {};
|
| 285 |
+
const contentTypes = {
|
| 286 |
+
windows: 'application/x-msdownload',
|
| 287 |
+
macos: 'application/x-apple-diskimage',
|
| 288 |
+
macosArm: 'application/x-apple-diskimage',
|
| 289 |
+
linux: 'application/x-executable',
|
| 290 |
+
sourceZip: 'application/zip',
|
| 291 |
+
sourceTarGz: 'application/gzip',
|
| 292 |
+
};
|
| 293 |
+
|
| 294 |
+
for (const [platform, files] of Object.entries(artifacts)) {
|
| 295 |
+
if (files.length === 0) {
|
| 296 |
+
console.warn(`Warning: No artifact found for ${platform}`);
|
| 297 |
+
continue;
|
| 298 |
+
}
|
| 299 |
+
|
| 300 |
+
// Use the first matching file for each platform
|
| 301 |
+
const localPath = files[0];
|
| 302 |
+
const filename = path.basename(localPath);
|
| 303 |
+
const r2Key = `releases/${VERSION}/${filename}`;
|
| 304 |
+
const size = await uploadFile(localPath, r2Key, contentTypes[platform]);
|
| 305 |
+
|
| 306 |
+
assets[platform] = {
|
| 307 |
+
url: `${PUBLIC_URL}/releases/${VERSION}/${filename}`,
|
| 308 |
+
filename,
|
| 309 |
+
size,
|
| 310 |
+
arch:
|
| 311 |
+
platform === 'macosArm'
|
| 312 |
+
? 'arm64'
|
| 313 |
+
: platform === 'sourceZip' || platform === 'sourceTarGz'
|
| 314 |
+
? 'source'
|
| 315 |
+
: 'x64',
|
| 316 |
+
};
|
| 317 |
+
}
|
| 318 |
+
|
| 319 |
+
// Fetch and update releases.json
|
| 320 |
+
const releasesData = await fetchExistingReleases();
|
| 321 |
+
|
| 322 |
+
const newRelease = {
|
| 323 |
+
version: VERSION,
|
| 324 |
+
date: new Date().toISOString(),
|
| 325 |
+
assets,
|
| 326 |
+
githubReleaseUrl: `https://github.com/${GITHUB_REPO}/releases/tag/${RELEASE_TAG}`,
|
| 327 |
+
};
|
| 328 |
+
|
| 329 |
+
// Remove existing entry for this version if re-running
|
| 330 |
+
releasesData.releases = releasesData.releases.filter((r) => r.version !== VERSION);
|
| 331 |
+
|
| 332 |
+
// Prepend new release
|
| 333 |
+
releasesData.releases.unshift(newRelease);
|
| 334 |
+
releasesData.latestVersion = VERSION;
|
| 335 |
+
|
| 336 |
+
// Upload updated releases.json
|
| 337 |
+
await s3Client.send(
|
| 338 |
+
new PutObjectCommand({
|
| 339 |
+
Bucket: BUCKET,
|
| 340 |
+
Key: 'releases.json',
|
| 341 |
+
Body: JSON.stringify(releasesData, null, 2),
|
| 342 |
+
ContentType: 'application/json',
|
| 343 |
+
CacheControl: 'public, max-age=60',
|
| 344 |
+
})
|
| 345 |
+
);
|
| 346 |
+
|
| 347 |
+
console.log('Successfully updated releases.json');
|
| 348 |
+
console.log(`Latest version: ${VERSION}`);
|
| 349 |
+
console.log(`Total releases: ${releasesData.releases.length}`);
|
| 350 |
+
}
|
| 351 |
+
|
| 352 |
+
main().catch((err) => {
|
| 353 |
+
console.error('Failed to upload to R2:', err);
|
| 354 |
+
process.exit(1);
|
| 355 |
+
});
|
jules_branch/.github/workflows/claude.yml
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
name: Claude Code
|
| 2 |
+
|
| 3 |
+
on:
|
| 4 |
+
issue_comment:
|
| 5 |
+
types: [created]
|
| 6 |
+
pull_request_review_comment:
|
| 7 |
+
types: [created]
|
| 8 |
+
issues:
|
| 9 |
+
types: [opened, assigned]
|
| 10 |
+
pull_request_review:
|
| 11 |
+
types: [submitted]
|
| 12 |
+
|
| 13 |
+
jobs:
|
| 14 |
+
claude:
|
| 15 |
+
if: |
|
| 16 |
+
(github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) ||
|
| 17 |
+
(github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) ||
|
| 18 |
+
(github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) ||
|
| 19 |
+
(github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude')))
|
| 20 |
+
runs-on: ubuntu-latest
|
| 21 |
+
permissions:
|
| 22 |
+
contents: read
|
| 23 |
+
pull-requests: read
|
| 24 |
+
issues: read
|
| 25 |
+
id-token: write
|
| 26 |
+
actions: read # Required for Claude to read CI results on PRs
|
| 27 |
+
steps:
|
| 28 |
+
- name: Checkout repository
|
| 29 |
+
uses: actions/checkout@v4
|
| 30 |
+
with:
|
| 31 |
+
fetch-depth: 1
|
| 32 |
+
|
| 33 |
+
- name: Run Claude Code
|
| 34 |
+
id: claude
|
| 35 |
+
uses: anthropics/claude-code-action@v1
|
| 36 |
+
with:
|
| 37 |
+
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
| 38 |
+
|
| 39 |
+
# This is an optional setting that allows Claude to read CI results on PRs
|
| 40 |
+
additional_permissions: |
|
| 41 |
+
actions: read
|
| 42 |
+
|
| 43 |
+
# Optional: Give a custom prompt to Claude. If this is not specified, Claude will perform the instructions specified in the comment that tagged it.
|
| 44 |
+
# prompt: 'Update the pull request description to include a summary of changes.'
|
| 45 |
+
|
| 46 |
+
# Optional: Add claude_args to customize behavior and configuration
|
| 47 |
+
# See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md
|
| 48 |
+
# or https://code.claude.com/docs/en/cli-reference for available options
|
| 49 |
+
# claude_args: '--allowed-tools Bash(gh pr:*)'
|
jules_branch/.github/workflows/e2e-tests.yml
ADDED
|
@@ -0,0 +1,202 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
name: E2E Tests
|
| 2 |
+
|
| 3 |
+
on:
|
| 4 |
+
pull_request:
|
| 5 |
+
branches:
|
| 6 |
+
- '*'
|
| 7 |
+
push:
|
| 8 |
+
branches:
|
| 9 |
+
- main
|
| 10 |
+
- master
|
| 11 |
+
|
| 12 |
+
jobs:
|
| 13 |
+
e2e:
|
| 14 |
+
runs-on: ubuntu-latest
|
| 15 |
+
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]
|
| 23 |
+
|
| 24 |
+
steps:
|
| 25 |
+
- name: Checkout code
|
| 26 |
+
uses: actions/checkout@v4
|
| 27 |
+
|
| 28 |
+
- name: Setup project
|
| 29 |
+
uses: ./.github/actions/setup-project
|
| 30 |
+
with:
|
| 31 |
+
check-lockfile: 'true'
|
| 32 |
+
rebuild-node-pty-path: 'apps/server'
|
| 33 |
+
|
| 34 |
+
- name: Install Playwright browsers
|
| 35 |
+
run: npx playwright install --with-deps chromium
|
| 36 |
+
working-directory: apps/ui
|
| 37 |
+
|
| 38 |
+
- name: Build server
|
| 39 |
+
run: npm run build --workspace=apps/server
|
| 40 |
+
|
| 41 |
+
- name: Set up Git user
|
| 42 |
+
run: |
|
| 43 |
+
git config --global user.name "GitHub CI"
|
| 44 |
+
git config --global user.email "ci@example.com"
|
| 45 |
+
|
| 46 |
+
- name: Start backend server
|
| 47 |
+
run: |
|
| 48 |
+
echo "Starting backend server..."
|
| 49 |
+
# Start server in background and save PID
|
| 50 |
+
npm run start --workspace=apps/server > backend.log 2>&1 &
|
| 51 |
+
SERVER_PID=$!
|
| 52 |
+
echo "Server started with PID: $SERVER_PID"
|
| 53 |
+
echo "SERVER_PID=$SERVER_PID" >> $GITHUB_ENV
|
| 54 |
+
|
| 55 |
+
env:
|
| 56 |
+
PORT: 3108
|
| 57 |
+
TEST_SERVER_PORT: 3108
|
| 58 |
+
NODE_ENV: test
|
| 59 |
+
# Use a deterministic API key so Playwright can log in reliably
|
| 60 |
+
AUTOMAKER_API_KEY: test-api-key-for-e2e-tests
|
| 61 |
+
# Reduce log noise in CI
|
| 62 |
+
AUTOMAKER_HIDE_API_KEY: 'true'
|
| 63 |
+
# Avoid real API calls during CI
|
| 64 |
+
AUTOMAKER_MOCK_AGENT: 'true'
|
| 65 |
+
# Simulate containerized environment to skip sandbox confirmation dialogs
|
| 66 |
+
IS_CONTAINERIZED: 'true'
|
| 67 |
+
|
| 68 |
+
- name: Wait for backend server
|
| 69 |
+
run: |
|
| 70 |
+
echo "Waiting for backend server to be ready..."
|
| 71 |
+
|
| 72 |
+
# Check if server process is running
|
| 73 |
+
if [ -z "$SERVER_PID" ]; then
|
| 74 |
+
echo "ERROR: Server PID not found in environment"
|
| 75 |
+
cat backend.log 2>/dev/null || echo "No backend log found"
|
| 76 |
+
exit 1
|
| 77 |
+
fi
|
| 78 |
+
|
| 79 |
+
# Check if process is actually running
|
| 80 |
+
if ! kill -0 $SERVER_PID 2>/dev/null; then
|
| 81 |
+
echo "ERROR: Server process $SERVER_PID is not running!"
|
| 82 |
+
echo "=== Backend logs ==="
|
| 83 |
+
cat backend.log
|
| 84 |
+
echo ""
|
| 85 |
+
echo "=== Recent system logs ==="
|
| 86 |
+
dmesg 2>/dev/null | tail -20 || echo "No dmesg available"
|
| 87 |
+
exit 1
|
| 88 |
+
fi
|
| 89 |
+
|
| 90 |
+
# Wait for health endpoint
|
| 91 |
+
for i in {1..60}; do
|
| 92 |
+
if curl -s -f http://localhost:3108/api/health > /dev/null 2>&1; then
|
| 93 |
+
echo "Backend server is ready!"
|
| 94 |
+
echo "=== Backend logs ==="
|
| 95 |
+
cat backend.log
|
| 96 |
+
echo ""
|
| 97 |
+
echo "Health check response:"
|
| 98 |
+
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')"
|
| 99 |
+
exit 0
|
| 100 |
+
fi
|
| 101 |
+
|
| 102 |
+
# Check if server process is still running
|
| 103 |
+
if ! kill -0 $SERVER_PID 2>/dev/null; then
|
| 104 |
+
echo "ERROR: Server process died during wait!"
|
| 105 |
+
echo "=== Backend logs ==="
|
| 106 |
+
cat backend.log
|
| 107 |
+
exit 1
|
| 108 |
+
fi
|
| 109 |
+
|
| 110 |
+
echo "Waiting... ($i/60)"
|
| 111 |
+
sleep 1
|
| 112 |
+
done
|
| 113 |
+
|
| 114 |
+
echo "ERROR: Backend server failed to start within 60 seconds!"
|
| 115 |
+
echo "=== Backend logs ==="
|
| 116 |
+
cat backend.log
|
| 117 |
+
echo ""
|
| 118 |
+
echo "=== Process status ==="
|
| 119 |
+
ps aux | grep -E "(node|tsx)" | grep -v grep || echo "No node processes found"
|
| 120 |
+
echo ""
|
| 121 |
+
echo "=== Port status ==="
|
| 122 |
+
netstat -tlnp 2>/dev/null | grep :3108 || echo "Port 3108 not listening"
|
| 123 |
+
lsof -i :3108 2>/dev/null || echo "lsof not available or port not in use"
|
| 124 |
+
echo ""
|
| 125 |
+
echo "=== Health endpoint test ==="
|
| 126 |
+
curl -v http://localhost:3108/api/health 2>&1 || echo "Health endpoint failed"
|
| 127 |
+
|
| 128 |
+
# Kill the server process if it's still hanging
|
| 129 |
+
if kill -0 $SERVER_PID 2>/dev/null; then
|
| 130 |
+
echo ""
|
| 131 |
+
echo "Killing stuck server process..."
|
| 132 |
+
kill -9 $SERVER_PID 2>/dev/null || true
|
| 133 |
+
fi
|
| 134 |
+
|
| 135 |
+
exit 1
|
| 136 |
+
|
| 137 |
+
- name: Run E2E tests (shard ${{ matrix.shardIndex }}/${{ matrix.shardTotal }})
|
| 138 |
+
# Playwright automatically starts the Vite frontend via webServer config
|
| 139 |
+
# (see apps/ui/playwright.config.ts) - no need to start it manually
|
| 140 |
+
run: npx playwright test --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }}
|
| 141 |
+
working-directory: apps/ui
|
| 142 |
+
env:
|
| 143 |
+
CI: true
|
| 144 |
+
VITE_SKIP_SETUP: 'true'
|
| 145 |
+
# Keep UI-side login/defaults consistent
|
| 146 |
+
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
|
| 154 |
+
|
| 155 |
+
- name: Print backend logs on failure
|
| 156 |
+
if: failure()
|
| 157 |
+
run: |
|
| 158 |
+
echo "=== E2E Tests Failed - Backend Logs ==="
|
| 159 |
+
cat backend.log 2>/dev/null || echo "No backend log found"
|
| 160 |
+
echo ""
|
| 161 |
+
echo "=== Process status at failure ==="
|
| 162 |
+
ps aux | grep -E "(node|tsx)" | grep -v grep || echo "No node processes found"
|
| 163 |
+
echo ""
|
| 164 |
+
echo "=== Port status ==="
|
| 165 |
+
netstat -tlnp 2>/dev/null | grep :3108 || echo "Port 3108 not listening"
|
| 166 |
+
|
| 167 |
+
- name: Upload Playwright report
|
| 168 |
+
uses: actions/upload-artifact@v4
|
| 169 |
+
if: always()
|
| 170 |
+
with:
|
| 171 |
+
name: playwright-report-shard-${{ matrix.shardIndex }}-of-${{ matrix.shardTotal }}
|
| 172 |
+
path: apps/ui/playwright-report/
|
| 173 |
+
retention-days: 7
|
| 174 |
+
|
| 175 |
+
- name: Upload test results (screenshots, traces, videos)
|
| 176 |
+
uses: actions/upload-artifact@v4
|
| 177 |
+
if: always()
|
| 178 |
+
with:
|
| 179 |
+
name: test-results-shard-${{ matrix.shardIndex }}-of-${{ matrix.shardTotal }}
|
| 180 |
+
path: |
|
| 181 |
+
apps/ui/test-results/
|
| 182 |
+
retention-days: 7
|
| 183 |
+
if-no-files-found: ignore
|
| 184 |
+
|
| 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 |
+
|
| 194 |
+
- name: Cleanup - Kill backend server
|
| 195 |
+
if: always()
|
| 196 |
+
run: |
|
| 197 |
+
if [ -n "$SERVER_PID" ]; then
|
| 198 |
+
echo "Cleaning up backend server (PID: $SERVER_PID)..."
|
| 199 |
+
kill $SERVER_PID 2>/dev/null || true
|
| 200 |
+
kill -9 $SERVER_PID 2>/dev/null || true
|
| 201 |
+
echo "Backend server cleanup complete"
|
| 202 |
+
fi
|
jules_branch/.github/workflows/format-check.yml
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
name: Format Check
|
| 2 |
+
|
| 3 |
+
on:
|
| 4 |
+
pull_request:
|
| 5 |
+
branches:
|
| 6 |
+
- '*'
|
| 7 |
+
push:
|
| 8 |
+
branches:
|
| 9 |
+
- main
|
| 10 |
+
- master
|
| 11 |
+
|
| 12 |
+
jobs:
|
| 13 |
+
format:
|
| 14 |
+
runs-on: ubuntu-latest
|
| 15 |
+
|
| 16 |
+
steps:
|
| 17 |
+
- name: Checkout code
|
| 18 |
+
uses: actions/checkout@v4
|
| 19 |
+
|
| 20 |
+
- name: Setup Node.js
|
| 21 |
+
uses: actions/setup-node@v4
|
| 22 |
+
with:
|
| 23 |
+
node-version: '22'
|
| 24 |
+
cache: 'npm'
|
| 25 |
+
cache-dependency-path: package-lock.json
|
| 26 |
+
|
| 27 |
+
- name: Install dependencies
|
| 28 |
+
run: npm install --ignore-scripts --force
|
| 29 |
+
|
| 30 |
+
- name: Check formatting
|
| 31 |
+
run: npm run format:check
|
jules_branch/.github/workflows/pr-check.yml
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
name: PR Build Check
|
| 2 |
+
|
| 3 |
+
on:
|
| 4 |
+
pull_request:
|
| 5 |
+
branches:
|
| 6 |
+
- '*'
|
| 7 |
+
push:
|
| 8 |
+
branches:
|
| 9 |
+
- main
|
| 10 |
+
- master
|
| 11 |
+
|
| 12 |
+
jobs:
|
| 13 |
+
build:
|
| 14 |
+
runs-on: ubuntu-latest
|
| 15 |
+
|
| 16 |
+
steps:
|
| 17 |
+
- name: Checkout code
|
| 18 |
+
uses: actions/checkout@v4
|
| 19 |
+
|
| 20 |
+
- name: Setup project
|
| 21 |
+
uses: ./.github/actions/setup-project
|
| 22 |
+
with:
|
| 23 |
+
check-lockfile: 'true'
|
| 24 |
+
|
| 25 |
+
- name: Run build:electron (dir only - faster CI)
|
| 26 |
+
run: npm run build:electron:dir
|
jules_branch/.github/workflows/release.yml
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
name: Release Build
|
| 2 |
+
|
| 3 |
+
on:
|
| 4 |
+
release:
|
| 5 |
+
types: [published]
|
| 6 |
+
|
| 7 |
+
permissions:
|
| 8 |
+
contents: write
|
| 9 |
+
|
| 10 |
+
jobs:
|
| 11 |
+
build:
|
| 12 |
+
strategy:
|
| 13 |
+
matrix:
|
| 14 |
+
os: [ubuntu-latest, macos-latest, windows-latest]
|
| 15 |
+
runs-on: ${{ matrix.os }}
|
| 16 |
+
|
| 17 |
+
steps:
|
| 18 |
+
- name: Checkout code
|
| 19 |
+
uses: actions/checkout@v4
|
| 20 |
+
|
| 21 |
+
- name: Extract version from tag
|
| 22 |
+
id: version
|
| 23 |
+
shell: bash
|
| 24 |
+
run: |
|
| 25 |
+
# Remove 'v' prefix if present (e.g., "v1.2.3" -> "1.2.3")
|
| 26 |
+
VERSION="${{ github.event.release.tag_name }}"
|
| 27 |
+
VERSION="${VERSION#v}"
|
| 28 |
+
echo "version=${VERSION}" >> $GITHUB_OUTPUT
|
| 29 |
+
echo "Extracted version: ${VERSION}"
|
| 30 |
+
|
| 31 |
+
- name: Update package.json version
|
| 32 |
+
shell: bash
|
| 33 |
+
run: |
|
| 34 |
+
node apps/ui/scripts/update-version.mjs "${{ steps.version.outputs.version }}"
|
| 35 |
+
|
| 36 |
+
- name: Setup project
|
| 37 |
+
uses: ./.github/actions/setup-project
|
| 38 |
+
with:
|
| 39 |
+
check-lockfile: 'true'
|
| 40 |
+
|
| 41 |
+
- name: Install RPM build tools (Linux)
|
| 42 |
+
if: matrix.os == 'ubuntu-latest'
|
| 43 |
+
shell: bash
|
| 44 |
+
run: sudo apt-get update && sudo apt-get install -y rpm
|
| 45 |
+
|
| 46 |
+
- name: Build Electron app (macOS)
|
| 47 |
+
if: matrix.os == 'macos-latest'
|
| 48 |
+
shell: bash
|
| 49 |
+
run: npm run build:electron:mac --workspace=apps/ui
|
| 50 |
+
env:
|
| 51 |
+
CSC_IDENTITY_AUTO_DISCOVERY: false
|
| 52 |
+
|
| 53 |
+
- name: Build Electron app (Windows)
|
| 54 |
+
if: matrix.os == 'windows-latest'
|
| 55 |
+
shell: bash
|
| 56 |
+
run: npm run build:electron:win --workspace=apps/ui
|
| 57 |
+
|
| 58 |
+
- name: Build Electron app (Linux)
|
| 59 |
+
if: matrix.os == 'ubuntu-latest'
|
| 60 |
+
shell: bash
|
| 61 |
+
run: npm run build:electron:linux --workspace=apps/ui
|
| 62 |
+
|
| 63 |
+
- name: Upload macOS artifacts
|
| 64 |
+
if: matrix.os == 'macos-latest'
|
| 65 |
+
uses: actions/upload-artifact@v4
|
| 66 |
+
with:
|
| 67 |
+
name: macos-builds
|
| 68 |
+
path: |
|
| 69 |
+
apps/ui/release/*.dmg
|
| 70 |
+
apps/ui/release/*.zip
|
| 71 |
+
if-no-files-found: error
|
| 72 |
+
retention-days: 30
|
| 73 |
+
|
| 74 |
+
- name: Upload Windows artifacts
|
| 75 |
+
if: matrix.os == 'windows-latest'
|
| 76 |
+
uses: actions/upload-artifact@v4
|
| 77 |
+
with:
|
| 78 |
+
name: windows-builds
|
| 79 |
+
path: apps/ui/release/*.exe
|
| 80 |
+
if-no-files-found: error
|
| 81 |
+
retention-days: 30
|
| 82 |
+
|
| 83 |
+
- name: Upload Linux artifacts
|
| 84 |
+
if: matrix.os == 'ubuntu-latest'
|
| 85 |
+
uses: actions/upload-artifact@v4
|
| 86 |
+
with:
|
| 87 |
+
name: linux-builds
|
| 88 |
+
path: |
|
| 89 |
+
apps/ui/release/*.AppImage
|
| 90 |
+
apps/ui/release/*.deb
|
| 91 |
+
apps/ui/release/*.rpm
|
| 92 |
+
if-no-files-found: error
|
| 93 |
+
retention-days: 30
|
| 94 |
+
|
| 95 |
+
upload:
|
| 96 |
+
needs: build
|
| 97 |
+
runs-on: ubuntu-latest
|
| 98 |
+
|
| 99 |
+
steps:
|
| 100 |
+
- name: Checkout code
|
| 101 |
+
uses: actions/checkout@v4
|
| 102 |
+
|
| 103 |
+
- name: Download macOS artifacts
|
| 104 |
+
uses: actions/download-artifact@v4
|
| 105 |
+
with:
|
| 106 |
+
name: macos-builds
|
| 107 |
+
path: artifacts/macos-builds
|
| 108 |
+
|
| 109 |
+
- name: Download Windows artifacts
|
| 110 |
+
uses: actions/download-artifact@v4
|
| 111 |
+
with:
|
| 112 |
+
name: windows-builds
|
| 113 |
+
path: artifacts/windows-builds
|
| 114 |
+
|
| 115 |
+
- name: Download Linux artifacts
|
| 116 |
+
uses: actions/download-artifact@v4
|
| 117 |
+
with:
|
| 118 |
+
name: linux-builds
|
| 119 |
+
path: artifacts/linux-builds
|
| 120 |
+
|
| 121 |
+
- name: Upload to GitHub Release
|
| 122 |
+
uses: softprops/action-gh-release@v2
|
| 123 |
+
with:
|
| 124 |
+
fail_on_unmatched_files: true
|
| 125 |
+
files: |
|
| 126 |
+
artifacts/macos-builds/*.dmg
|
| 127 |
+
artifacts/macos-builds/*.zip
|
| 128 |
+
artifacts/windows-builds/*.exe
|
| 129 |
+
artifacts/linux-builds/*.AppImage
|
| 130 |
+
artifacts/linux-builds/*.deb
|
| 131 |
+
artifacts/linux-builds/*.rpm
|
| 132 |
+
env:
|
| 133 |
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
jules_branch/.github/workflows/security-audit.yml
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
name: Security Audit
|
| 2 |
+
|
| 3 |
+
on:
|
| 4 |
+
pull_request:
|
| 5 |
+
branches:
|
| 6 |
+
- '*'
|
| 7 |
+
push:
|
| 8 |
+
branches:
|
| 9 |
+
- main
|
| 10 |
+
- master
|
| 11 |
+
schedule:
|
| 12 |
+
# Run weekly on Mondays at 9 AM UTC
|
| 13 |
+
- cron: '0 9 * * 1'
|
| 14 |
+
|
| 15 |
+
jobs:
|
| 16 |
+
audit:
|
| 17 |
+
runs-on: ubuntu-latest
|
| 18 |
+
|
| 19 |
+
steps:
|
| 20 |
+
- name: Checkout code
|
| 21 |
+
uses: actions/checkout@v4
|
| 22 |
+
|
| 23 |
+
- name: Setup project
|
| 24 |
+
uses: ./.github/actions/setup-project
|
| 25 |
+
with:
|
| 26 |
+
check-lockfile: 'true'
|
| 27 |
+
|
| 28 |
+
- name: Run npm audit
|
| 29 |
+
run: npm audit --audit-level=critical
|
| 30 |
+
continue-on-error: false
|
jules_branch/.github/workflows/test.yml
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
name: Test Suite
|
| 2 |
+
|
| 3 |
+
on:
|
| 4 |
+
pull_request:
|
| 5 |
+
branches:
|
| 6 |
+
- '*'
|
| 7 |
+
push:
|
| 8 |
+
branches:
|
| 9 |
+
- main
|
| 10 |
+
- master
|
| 11 |
+
|
| 12 |
+
jobs:
|
| 13 |
+
test:
|
| 14 |
+
runs-on: ubuntu-latest
|
| 15 |
+
|
| 16 |
+
steps:
|
| 17 |
+
- name: Checkout code
|
| 18 |
+
uses: actions/checkout@v4
|
| 19 |
+
|
| 20 |
+
- name: Setup project
|
| 21 |
+
uses: ./.github/actions/setup-project
|
| 22 |
+
with:
|
| 23 |
+
check-lockfile: 'true'
|
| 24 |
+
rebuild-node-pty-path: 'apps/server'
|
| 25 |
+
|
| 26 |
+
- name: Run package tests
|
| 27 |
+
run: npm run test:packages
|
| 28 |
+
env:
|
| 29 |
+
NODE_ENV: test
|
| 30 |
+
|
| 31 |
+
- name: Run server tests with coverage
|
| 32 |
+
run: npm run test:server:coverage
|
| 33 |
+
env:
|
| 34 |
+
NODE_ENV: test
|
| 35 |
+
|
| 36 |
+
# - name: Upload coverage reports
|
| 37 |
+
# uses: codecov/codecov-action@v4
|
| 38 |
+
# if: always()
|
| 39 |
+
# with:
|
| 40 |
+
# files: ./apps/server/coverage/coverage-final.json
|
| 41 |
+
# flags: server
|
| 42 |
+
# name: server-coverage
|
| 43 |
+
# env:
|
| 44 |
+
# CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
jules_branch/.gitignore
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#added by trueheads > will remove once supercombo adds multi-os support
|
| 2 |
+
launch.sh
|
| 3 |
+
|
| 4 |
+
# Dependencies
|
| 5 |
+
node_modules/
|
| 6 |
+
|
| 7 |
+
# Build outputs
|
| 8 |
+
dist/
|
| 9 |
+
build/
|
| 10 |
+
out/
|
| 11 |
+
.next/
|
| 12 |
+
.turbo/
|
| 13 |
+
|
| 14 |
+
# Automaker
|
| 15 |
+
.automaker/images/
|
| 16 |
+
.automaker/
|
| 17 |
+
/.automaker/*
|
| 18 |
+
/.automaker/
|
| 19 |
+
|
| 20 |
+
.worktrees/
|
| 21 |
+
|
| 22 |
+
/logs
|
| 23 |
+
# Logs
|
| 24 |
+
logs/
|
| 25 |
+
*.log
|
| 26 |
+
npm-debug.log*
|
| 27 |
+
yarn-debug.log*
|
| 28 |
+
yarn-error.log*
|
| 29 |
+
pnpm-debug.log*
|
| 30 |
+
|
| 31 |
+
# OS-specific files
|
| 32 |
+
.DS_Store
|
| 33 |
+
.DS_Store?
|
| 34 |
+
._*
|
| 35 |
+
Thumbs.db
|
| 36 |
+
ehthumbs.db
|
| 37 |
+
Desktop.ini
|
| 38 |
+
|
| 39 |
+
# IDE/Editor configs
|
| 40 |
+
.vscode/
|
| 41 |
+
.idea/
|
| 42 |
+
*.sublime-workspace
|
| 43 |
+
*.sublime-project
|
| 44 |
+
|
| 45 |
+
# Editor backup/temp files
|
| 46 |
+
*~
|
| 47 |
+
*.bak
|
| 48 |
+
*.backup
|
| 49 |
+
*.orig
|
| 50 |
+
*.swp
|
| 51 |
+
*.swo
|
| 52 |
+
*.tmp
|
| 53 |
+
*.temp
|
| 54 |
+
|
| 55 |
+
# Local settings (user-specific)
|
| 56 |
+
*.local.json
|
| 57 |
+
|
| 58 |
+
# Application state/backup
|
| 59 |
+
backup.json
|
| 60 |
+
|
| 61 |
+
# Test artifacts
|
| 62 |
+
test-results/
|
| 63 |
+
coverage/
|
| 64 |
+
.nyc_output/
|
| 65 |
+
*.lcov
|
| 66 |
+
playwright-report/
|
| 67 |
+
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 |
+
|
| 79 |
+
|
| 80 |
+
# Environment files (keep .example)
|
| 81 |
+
.env
|
| 82 |
+
.env.local
|
| 83 |
+
.env.*.local
|
| 84 |
+
!.env.example
|
| 85 |
+
!.env.local.example
|
| 86 |
+
|
| 87 |
+
# Codex config (contains API keys)
|
| 88 |
+
.codex/config.toml
|
| 89 |
+
|
| 90 |
+
# TypeScript
|
| 91 |
+
*.tsbuildinfo
|
| 92 |
+
|
| 93 |
+
# Misc
|
| 94 |
+
*.pem
|
| 95 |
+
|
| 96 |
+
docker-compose.override.yml
|
| 97 |
+
.claude/docker-compose.override.yml
|
| 98 |
+
.claude/hans/
|
| 99 |
+
|
| 100 |
+
pnpm-lock.yaml
|
| 101 |
+
yarn.lock
|
| 102 |
+
|
| 103 |
+
# Fork-specific workflow files (should never be committed)
|
| 104 |
+
DEVELOPMENT_WORKFLOW.md
|
| 105 |
+
check-sync.sh
|
| 106 |
+
# API key files
|
| 107 |
+
data/.api-key
|
| 108 |
+
data/credentials.json
|
| 109 |
+
data/
|
| 110 |
+
.codex/
|
| 111 |
+
|
| 112 |
+
# GSD planning docs (local-only)
|
| 113 |
+
.planning/
|
| 114 |
+
.mcp.json
|
| 115 |
+
.planning
|
| 116 |
+
.bg-shell/
|
jules_branch/.husky/pre-commit
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env sh
|
| 2 |
+
|
| 3 |
+
# Try to load nvm if available (optional - works without it too)
|
| 4 |
+
if [ -z "$NVM_DIR" ]; then
|
| 5 |
+
# Check for Herd's nvm first (macOS with Herd)
|
| 6 |
+
if [ -s "$HOME/Library/Application Support/Herd/config/nvm/nvm.sh" ]; then
|
| 7 |
+
export NVM_DIR="$HOME/Library/Application Support/Herd/config/nvm"
|
| 8 |
+
# Then check standard nvm location
|
| 9 |
+
elif [ -s "$HOME/.nvm/nvm.sh" ]; then
|
| 10 |
+
export NVM_DIR="$HOME/.nvm"
|
| 11 |
+
fi
|
| 12 |
+
fi
|
| 13 |
+
|
| 14 |
+
# Source nvm if found (silently skip if not available)
|
| 15 |
+
[ -n "$NVM_DIR" ] && [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" 2>/dev/null
|
| 16 |
+
|
| 17 |
+
# Load node version from .nvmrc if using nvm (silently skip if nvm not available or fails)
|
| 18 |
+
if [ -f .nvmrc ] && command -v nvm >/dev/null 2>&1; then
|
| 19 |
+
# Check if Unix nvm was sourced (it's a shell function with NVM_DIR set)
|
| 20 |
+
if [ -n "$NVM_DIR" ] && type nvm 2>/dev/null | grep -q "function"; then
|
| 21 |
+
# Unix nvm: reads .nvmrc automatically
|
| 22 |
+
nvm use >/dev/null 2>&1 || true
|
| 23 |
+
else
|
| 24 |
+
# nvm-windows: needs explicit version from .nvmrc
|
| 25 |
+
NODE_VERSION=$(cat .nvmrc | tr -d '[:space:]')
|
| 26 |
+
if [ -n "$NODE_VERSION" ]; then
|
| 27 |
+
nvm use "$NODE_VERSION" >/dev/null 2>&1 || true
|
| 28 |
+
fi
|
| 29 |
+
fi
|
| 30 |
+
fi
|
| 31 |
+
|
| 32 |
+
# Ensure common system paths are in PATH (for systems without nvm)
|
| 33 |
+
# This helps find node/npm installed via Homebrew, system packages, etc.
|
| 34 |
+
if [ -n "$WINDIR" ]; then
|
| 35 |
+
export PATH="$PATH:/c/Program Files/nodejs:/c/Program Files (x86)/nodejs"
|
| 36 |
+
export PATH="$PATH:$APPDATA/npm:$LOCALAPPDATA/Programs/nodejs"
|
| 37 |
+
else
|
| 38 |
+
export PATH="$PATH:/usr/local/bin:/opt/homebrew/bin:/usr/bin"
|
| 39 |
+
fi
|
| 40 |
+
|
| 41 |
+
# Auto-fix git+ssh:// URLs in package-lock.json if it's being committed
|
| 42 |
+
# This prevents CI failures from SSH URLs that npm introduces for git dependencies
|
| 43 |
+
if git diff --cached --name-only | grep -q "^package-lock.json$"; then
|
| 44 |
+
if command -v node >/dev/null 2>&1; then
|
| 45 |
+
if grep -q "git+ssh://" package-lock.json 2>/dev/null; then
|
| 46 |
+
echo "Fixing git+ssh:// URLs in package-lock.json..."
|
| 47 |
+
node scripts/fix-lockfile-urls.mjs
|
| 48 |
+
git add package-lock.json
|
| 49 |
+
fi
|
| 50 |
+
fi
|
| 51 |
+
fi
|
| 52 |
+
|
| 53 |
+
# Run lint-staged - works with or without nvm
|
| 54 |
+
# Prefer npx, fallback to npm exec, both work with system-installed Node.js
|
| 55 |
+
if command -v npx >/dev/null 2>&1; then
|
| 56 |
+
npx lint-staged
|
| 57 |
+
elif command -v npm >/dev/null 2>&1; then
|
| 58 |
+
npm exec -- lint-staged
|
| 59 |
+
else
|
| 60 |
+
echo "Error: Neither npx nor npm found in PATH."
|
| 61 |
+
echo "Please ensure Node.js is installed (via nvm, Homebrew, system package manager, etc.)"
|
| 62 |
+
exit 1
|
| 63 |
+
fi
|
jules_branch/.npmrc
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Cross-platform compatibility for Tailwind CSS v4 and lightningcss
|
| 2 |
+
# These packages use platform-specific optional dependencies that npm
|
| 3 |
+
# automatically resolves based on your OS (macOS, Linux, Windows, WSL)
|
| 4 |
+
#
|
| 5 |
+
# IMPORTANT: When switching platforms or getting platform mismatch errors:
|
| 6 |
+
# 1. Delete node_modules: rm -rf node_modules apps/*/node_modules
|
| 7 |
+
# 2. Run: npm install
|
| 8 |
+
#
|
| 9 |
+
# In CI/CD: Use "npm install" instead of "npm ci" to allow npm to resolve
|
| 10 |
+
# the correct platform-specific binaries at install time.
|
| 11 |
+
|
| 12 |
+
# Include bindings for all platforms in package-lock.json to support CI/CD
|
| 13 |
+
# This ensures Linux, macOS, and Windows bindings are all present
|
| 14 |
+
# NOTE: Only enable when regenerating package-lock.json, then comment out to keep installs fast
|
| 15 |
+
# supportedArchitectures.os=linux,darwin,win32
|
| 16 |
+
# supportedArchitectures.cpu=x64,arm64
|
jules_branch/.nvmrc
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
22
|
| 2 |
+
|
jules_branch/.prettierignore
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Dependencies
|
| 2 |
+
node_modules/
|
| 3 |
+
|
| 4 |
+
# Build outputs
|
| 5 |
+
dist/
|
| 6 |
+
build/
|
| 7 |
+
out/
|
| 8 |
+
.next/
|
| 9 |
+
.turbo/
|
| 10 |
+
release/
|
| 11 |
+
|
| 12 |
+
# Automaker
|
| 13 |
+
.automaker/
|
| 14 |
+
|
| 15 |
+
# Logs
|
| 16 |
+
logs/
|
| 17 |
+
*.log
|
| 18 |
+
|
| 19 |
+
# Lock files
|
| 20 |
+
package-lock.json
|
| 21 |
+
pnpm-lock.yaml
|
| 22 |
+
|
| 23 |
+
# Generated files
|
| 24 |
+
*.min.js
|
| 25 |
+
*.min.css
|
| 26 |
+
routeTree.gen.ts
|
| 27 |
+
apps/ui/src/routeTree.gen.ts
|
| 28 |
+
|
| 29 |
+
# Test artifacts
|
| 30 |
+
test-results/
|
| 31 |
+
coverage/
|
| 32 |
+
playwright-report/
|
| 33 |
+
blob-report/
|
| 34 |
+
|
| 35 |
+
# IDE/Editor
|
| 36 |
+
.vscode/
|
| 37 |
+
.idea/
|
| 38 |
+
|
| 39 |
+
# Electron
|
| 40 |
+
dist-electron/
|
| 41 |
+
server-bundle/
|
jules_branch/.prettierrc
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"semi": true,
|
| 3 |
+
"singleQuote": true,
|
| 4 |
+
"tabWidth": 2,
|
| 5 |
+
"trailingComma": "es5",
|
| 6 |
+
"printWidth": 100,
|
| 7 |
+
"bracketSpacing": true,
|
| 8 |
+
"arrowParens": "always",
|
| 9 |
+
"endOfLine": "lf"
|
| 10 |
+
}
|
jules_branch/CLAUDE.md
ADDED
|
@@ -0,0 +1,176 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# CLAUDE.md
|
| 2 |
+
|
| 3 |
+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
| 4 |
+
|
| 5 |
+
## Project Overview
|
| 6 |
+
|
| 7 |
+
Automaker is an autonomous AI development studio built as an npm workspace monorepo. It provides a Kanban-based workflow where AI agents (powered by Claude Agent SDK) implement features in isolated git worktrees.
|
| 8 |
+
|
| 9 |
+
## Common Commands
|
| 10 |
+
|
| 11 |
+
```bash
|
| 12 |
+
# Development
|
| 13 |
+
npm run dev # Interactive launcher (choose web or electron)
|
| 14 |
+
npm run dev:web # Web browser mode (localhost:3007)
|
| 15 |
+
npm run dev:electron # Desktop app mode
|
| 16 |
+
npm run dev:electron:debug # Desktop with DevTools open
|
| 17 |
+
|
| 18 |
+
# Building
|
| 19 |
+
npm run build # Build web application
|
| 20 |
+
npm run build:packages # Build all shared packages (required before other builds)
|
| 21 |
+
npm run build:electron # Build desktop app for current platform
|
| 22 |
+
npm run build:server # Build server only
|
| 23 |
+
|
| 24 |
+
# Testing
|
| 25 |
+
npm run test # E2E tests (Playwright, headless)
|
| 26 |
+
npm run test:headed # E2E tests with browser visible
|
| 27 |
+
npm run test:server # Server unit tests (Vitest)
|
| 28 |
+
npm run test:packages # All shared package tests
|
| 29 |
+
npm run test:all # All tests (packages + server)
|
| 30 |
+
|
| 31 |
+
# Single test file
|
| 32 |
+
npm run test:server -- tests/unit/specific.test.ts
|
| 33 |
+
|
| 34 |
+
# Linting and formatting
|
| 35 |
+
npm run lint # ESLint
|
| 36 |
+
npm run format # Prettier write
|
| 37 |
+
npm run format:check # Prettier check
|
| 38 |
+
```
|
| 39 |
+
|
| 40 |
+
## Architecture
|
| 41 |
+
|
| 42 |
+
### Monorepo Structure
|
| 43 |
+
|
| 44 |
+
```
|
| 45 |
+
automaker/
|
| 46 |
+
├── apps/
|
| 47 |
+
│ ├── ui/ # React + Vite + Electron frontend (port 3007)
|
| 48 |
+
│ └── server/ # Express + WebSocket backend (port 3008)
|
| 49 |
+
└── libs/ # Shared packages (@automaker/*)
|
| 50 |
+
├── types/ # Core TypeScript definitions (no dependencies)
|
| 51 |
+
├── utils/ # Logging, errors, image processing, context loading
|
| 52 |
+
├── prompts/ # AI prompt templates
|
| 53 |
+
├── platform/ # Path management, security, process spawning
|
| 54 |
+
├── model-resolver/ # Claude model alias resolution
|
| 55 |
+
├── dependency-resolver/ # Feature dependency ordering
|
| 56 |
+
└── git-utils/ # Git operations & worktree management
|
| 57 |
+
```
|
| 58 |
+
|
| 59 |
+
### Package Dependency Chain
|
| 60 |
+
|
| 61 |
+
Packages can only depend on packages above them:
|
| 62 |
+
|
| 63 |
+
```
|
| 64 |
+
@automaker/types (no dependencies)
|
| 65 |
+
↓
|
| 66 |
+
@automaker/utils, @automaker/prompts, @automaker/platform, @automaker/model-resolver, @automaker/dependency-resolver
|
| 67 |
+
↓
|
| 68 |
+
@automaker/git-utils
|
| 69 |
+
↓
|
| 70 |
+
@automaker/server, @automaker/ui
|
| 71 |
+
```
|
| 72 |
+
|
| 73 |
+
### Key Technologies
|
| 74 |
+
|
| 75 |
+
- **Frontend**: React 19, Vite 7, Electron 39, TanStack Router, Zustand 5, Tailwind CSS 4
|
| 76 |
+
- **Backend**: Express 5, WebSocket (ws), Claude Agent SDK, node-pty
|
| 77 |
+
- **Testing**: Playwright (E2E), Vitest (unit)
|
| 78 |
+
|
| 79 |
+
### Server Architecture
|
| 80 |
+
|
| 81 |
+
The server (`apps/server/src/`) follows a modular pattern:
|
| 82 |
+
|
| 83 |
+
- `routes/` - Express route handlers organized by feature (agent, features, auto-mode, worktree, etc.)
|
| 84 |
+
- `services/` - Business logic (AgentService, AutoModeService, FeatureLoader, TerminalService)
|
| 85 |
+
- `providers/` - AI provider abstraction (currently Claude via Claude Agent SDK)
|
| 86 |
+
- `lib/` - Utilities (events, auth, worktree metadata)
|
| 87 |
+
|
| 88 |
+
### Frontend Architecture
|
| 89 |
+
|
| 90 |
+
The UI (`apps/ui/src/`) uses:
|
| 91 |
+
|
| 92 |
+
- `routes/` - TanStack Router file-based routing
|
| 93 |
+
- `components/views/` - Main view components (board, settings, terminal, etc.)
|
| 94 |
+
- `store/` - Zustand stores with persistence (app-store.ts, setup-store.ts)
|
| 95 |
+
- `hooks/` - Custom React hooks
|
| 96 |
+
- `lib/` - Utilities and API client
|
| 97 |
+
|
| 98 |
+
## Data Storage
|
| 99 |
+
|
| 100 |
+
### Per-Project Data (`.automaker/`)
|
| 101 |
+
|
| 102 |
+
```
|
| 103 |
+
.automaker/
|
| 104 |
+
├── features/ # Feature JSON files and images
|
| 105 |
+
│ └── {featureId}/
|
| 106 |
+
│ ├── feature.json
|
| 107 |
+
│ ├── agent-output.md
|
| 108 |
+
│ └── images/
|
| 109 |
+
├── context/ # Context files for AI agents (CLAUDE.md, etc.)
|
| 110 |
+
├── settings.json # Project-specific settings
|
| 111 |
+
├── spec.md # Project specification
|
| 112 |
+
└── analysis.json # Project structure analysis
|
| 113 |
+
```
|
| 114 |
+
|
| 115 |
+
### Global Data (`DATA_DIR`, default `./data`)
|
| 116 |
+
|
| 117 |
+
```
|
| 118 |
+
data/
|
| 119 |
+
├── settings.json # Global settings, profiles, shortcuts
|
| 120 |
+
├── credentials.json # API keys
|
| 121 |
+
├── sessions-metadata.json # Chat session metadata
|
| 122 |
+
└── agent-sessions/ # Conversation histories
|
| 123 |
+
```
|
| 124 |
+
|
| 125 |
+
## Import Conventions
|
| 126 |
+
|
| 127 |
+
Always import from shared packages, never from old paths:
|
| 128 |
+
|
| 129 |
+
```typescript
|
| 130 |
+
// ✅ Correct
|
| 131 |
+
import type { Feature, ExecuteOptions } from '@automaker/types';
|
| 132 |
+
import { createLogger, classifyError } from '@automaker/utils';
|
| 133 |
+
import { getEnhancementPrompt } from '@automaker/prompts';
|
| 134 |
+
import { getFeatureDir, ensureAutomakerDir } from '@automaker/platform';
|
| 135 |
+
import { resolveModelString } from '@automaker/model-resolver';
|
| 136 |
+
import { resolveDependencies } from '@automaker/dependency-resolver';
|
| 137 |
+
import { getGitRepositoryDiffs } from '@automaker/git-utils';
|
| 138 |
+
|
| 139 |
+
// ❌ Never import from old paths
|
| 140 |
+
import { Feature } from '../services/feature-loader'; // Wrong
|
| 141 |
+
import { createLogger } from '../lib/logger'; // Wrong
|
| 142 |
+
```
|
| 143 |
+
|
| 144 |
+
## Key Patterns
|
| 145 |
+
|
| 146 |
+
### Event-Driven Architecture
|
| 147 |
+
|
| 148 |
+
All server operations emit events that stream to the frontend via WebSocket. Events are created using `createEventEmitter()` from `lib/events.ts`.
|
| 149 |
+
|
| 150 |
+
### Git Worktree Isolation
|
| 151 |
+
|
| 152 |
+
Each feature executes in an isolated git worktree, created via `@automaker/git-utils`. This protects the main branch during AI agent execution.
|
| 153 |
+
|
| 154 |
+
### Context Files
|
| 155 |
+
|
| 156 |
+
Project-specific rules are stored in `.automaker/context/` and automatically loaded into agent prompts via `loadContextFiles()` from `@automaker/utils`.
|
| 157 |
+
|
| 158 |
+
### Model Resolution
|
| 159 |
+
|
| 160 |
+
Use `resolveModelString()` from `@automaker/model-resolver` to convert model aliases:
|
| 161 |
+
|
| 162 |
+
- `haiku` → `claude-haiku-4-5`
|
| 163 |
+
- `sonnet` → `claude-sonnet-4-20250514`
|
| 164 |
+
- `opus` → `claude-opus-4-6`
|
| 165 |
+
|
| 166 |
+
## Environment Variables
|
| 167 |
+
|
| 168 |
+
- `ANTHROPIC_API_KEY` - Anthropic API key (or use Claude Code CLI auth)
|
| 169 |
+
- `HOST` - Host to bind server to (default: 0.0.0.0)
|
| 170 |
+
- `HOSTNAME` - Hostname for user-facing URLs (default: localhost)
|
| 171 |
+
- `PORT` - Server port (default: 3008)
|
| 172 |
+
- `DATA_DIR` - Data storage directory (default: ./data)
|
| 173 |
+
- `ALLOWED_ROOT_DIRECTORY` - Restrict file operations to specific directory
|
| 174 |
+
- `AUTOMAKER_MOCK_AGENT=true` - Enable mock agent mode for CI testing
|
| 175 |
+
- `AUTOMAKER_AUTO_LOGIN=true` - Skip login prompt in development (disabled when NODE_ENV=production)
|
| 176 |
+
- `VITE_HOSTNAME` - Hostname for frontend API URLs (default: localhost)
|
jules_branch/CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,740 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Contributing to Automaker
|
| 2 |
+
|
| 3 |
+
Thank you for your interest in contributing to Automaker! We're excited to have you join our community of developers building the future of autonomous AI development.
|
| 4 |
+
|
| 5 |
+
Automaker is an autonomous AI development studio that provides a Kanban-based workflow where AI agents implement features in isolated git worktrees. Whether you're fixing bugs, adding features, improving documentation, or suggesting ideas, your contributions help make this project better for everyone.
|
| 6 |
+
|
| 7 |
+
This guide will help you get started with contributing to Automaker. Please take a moment to read through these guidelines to ensure a smooth contribution process.
|
| 8 |
+
|
| 9 |
+
## Contribution License Agreement
|
| 10 |
+
|
| 11 |
+
**Important:** By submitting, pushing, or contributing any code, documentation, pull requests, issues, or other materials to the Automaker project, you agree to assign all right, title, and interest in and to your contributions, including all copyrights, patents, and other intellectual property rights, to the Core Contributors of Automaker. This assignment is irrevocable and includes the right to use, modify, distribute, and monetize your contributions in any manner.
|
| 12 |
+
|
| 13 |
+
**You understand and agree that you will have no right to receive any royalties, compensation, or other financial benefits from any revenue, income, or commercial use generated from your contributed code or any derivative works thereof.** All contributions are made without expectation of payment or financial return.
|
| 14 |
+
|
| 15 |
+
For complete details on contribution terms and rights assignment, please review [Section 5 (CONTRIBUTIONS AND RIGHTS ASSIGNMENT) of the LICENSE](LICENSE#5-contributions-and-rights-assignment).
|
| 16 |
+
|
| 17 |
+
## Table of Contents
|
| 18 |
+
|
| 19 |
+
- [Contributing to Automaker](#contributing-to-automaker)
|
| 20 |
+
- [Table of Contents](#table-of-contents)
|
| 21 |
+
- [Getting Started](#getting-started)
|
| 22 |
+
- [Prerequisites](#prerequisites)
|
| 23 |
+
- [Fork and Clone](#fork-and-clone)
|
| 24 |
+
- [Development Setup](#development-setup)
|
| 25 |
+
- [Project Structure](#project-structure)
|
| 26 |
+
- [Pull Request Process](#pull-request-process)
|
| 27 |
+
- [Branching Strategy (RC Branches)](#branching-strategy-rc-branches)
|
| 28 |
+
- [Branch Naming Convention](#branch-naming-convention)
|
| 29 |
+
- [Commit Message Format](#commit-message-format)
|
| 30 |
+
- [Submitting a Pull Request](#submitting-a-pull-request)
|
| 31 |
+
- [1. Prepare Your Changes](#1-prepare-your-changes)
|
| 32 |
+
- [2. Run Pre-submission Checks](#2-run-pre-submission-checks)
|
| 33 |
+
- [3. Push Your Changes](#3-push-your-changes)
|
| 34 |
+
- [4. Open a Pull Request](#4-open-a-pull-request)
|
| 35 |
+
- [PR Requirements Checklist](#pr-requirements-checklist)
|
| 36 |
+
- [Review Process](#review-process)
|
| 37 |
+
- [What to Expect](#what-to-expect)
|
| 38 |
+
- [Review Focus Areas](#review-focus-areas)
|
| 39 |
+
- [Responding to Feedback](#responding-to-feedback)
|
| 40 |
+
- [Approval Criteria](#approval-criteria)
|
| 41 |
+
- [Getting Help](#getting-help)
|
| 42 |
+
- [Code Style Guidelines](#code-style-guidelines)
|
| 43 |
+
- [Testing Requirements](#testing-requirements)
|
| 44 |
+
- [Running Tests](#running-tests)
|
| 45 |
+
- [Test Frameworks](#test-frameworks)
|
| 46 |
+
- [End-to-End Tests (Playwright)](#end-to-end-tests-playwright)
|
| 47 |
+
- [Unit Tests (Vitest)](#unit-tests-vitest)
|
| 48 |
+
- [Writing Tests](#writing-tests)
|
| 49 |
+
- [When to Write Tests](#when-to-write-tests)
|
| 50 |
+
- [CI/CD Pipeline](#cicd-pipeline)
|
| 51 |
+
- [CI Checks](#ci-checks)
|
| 52 |
+
- [CI Testing Environment](#ci-testing-environment)
|
| 53 |
+
- [Viewing CI Results](#viewing-ci-results)
|
| 54 |
+
- [Common CI Failures](#common-ci-failures)
|
| 55 |
+
- [Coverage Requirements](#coverage-requirements)
|
| 56 |
+
- [Issue Reporting](#issue-reporting)
|
| 57 |
+
- [Bug Reports](#bug-reports)
|
| 58 |
+
- [Before Reporting](#before-reporting)
|
| 59 |
+
- [Bug Report Template](#bug-report-template)
|
| 60 |
+
- [Feature Requests](#feature-requests)
|
| 61 |
+
- [Before Requesting](#before-requesting)
|
| 62 |
+
- [Feature Request Template](#feature-request-template)
|
| 63 |
+
- [Security Issues](#security-issues)
|
| 64 |
+
|
| 65 |
+
---
|
| 66 |
+
|
| 67 |
+
## Getting Started
|
| 68 |
+
|
| 69 |
+
### Prerequisites
|
| 70 |
+
|
| 71 |
+
Before contributing to Automaker, ensure you have the following installed on your system:
|
| 72 |
+
|
| 73 |
+
- **Node.js 18+** (tested with Node.js 22)
|
| 74 |
+
- Download from [nodejs.org](https://nodejs.org/)
|
| 75 |
+
- Verify installation: `node --version`
|
| 76 |
+
- **npm** (comes with Node.js)
|
| 77 |
+
- Verify installation: `npm --version`
|
| 78 |
+
- **Git** for version control
|
| 79 |
+
- Verify installation: `git --version`
|
| 80 |
+
- **Claude Code CLI** or **Anthropic API Key** (for AI agent functionality)
|
| 81 |
+
- Required to run the AI development features
|
| 82 |
+
|
| 83 |
+
**Optional but recommended:**
|
| 84 |
+
|
| 85 |
+
- A code editor with TypeScript support (VS Code recommended)
|
| 86 |
+
- GitHub CLI (`gh`) for easier PR management
|
| 87 |
+
|
| 88 |
+
### Fork and Clone
|
| 89 |
+
|
| 90 |
+
1. **Fork the repository** on GitHub
|
| 91 |
+
- Navigate to [https://github.com/AutoMaker-Org/automaker](https://github.com/AutoMaker-Org/automaker)
|
| 92 |
+
- Click the "Fork" button in the top-right corner
|
| 93 |
+
- This creates your own copy of the repository
|
| 94 |
+
|
| 95 |
+
2. **Clone your fork locally**
|
| 96 |
+
|
| 97 |
+
```bash
|
| 98 |
+
git clone https://github.com/YOUR_USERNAME/automaker.git
|
| 99 |
+
cd automaker
|
| 100 |
+
```
|
| 101 |
+
|
| 102 |
+
3. **Add the upstream remote** to keep your fork in sync
|
| 103 |
+
|
| 104 |
+
```bash
|
| 105 |
+
git remote add upstream https://github.com/AutoMaker-Org/automaker.git
|
| 106 |
+
```
|
| 107 |
+
|
| 108 |
+
4. **Verify remotes**
|
| 109 |
+
```bash
|
| 110 |
+
git remote -v
|
| 111 |
+
# Should show:
|
| 112 |
+
# origin https://github.com/YOUR_USERNAME/automaker.git (fetch)
|
| 113 |
+
# origin https://github.com/YOUR_USERNAME/automaker.git (push)
|
| 114 |
+
# upstream https://github.com/AutoMaker-Org/automaker.git (fetch)
|
| 115 |
+
# upstream https://github.com/AutoMaker-Org/automaker.git (push)
|
| 116 |
+
```
|
| 117 |
+
|
| 118 |
+
### Development Setup
|
| 119 |
+
|
| 120 |
+
1. **Install dependencies**
|
| 121 |
+
|
| 122 |
+
```bash
|
| 123 |
+
npm install
|
| 124 |
+
```
|
| 125 |
+
|
| 126 |
+
2. **Build shared packages** (required before running the app)
|
| 127 |
+
|
| 128 |
+
```bash
|
| 129 |
+
npm run build:packages
|
| 130 |
+
```
|
| 131 |
+
|
| 132 |
+
3. **Start the development server**
|
| 133 |
+
```bash
|
| 134 |
+
npm run dev # Interactive launcher - choose mode
|
| 135 |
+
npm run dev:web # Browser mode (web interface)
|
| 136 |
+
npm run dev:electron # Desktop app mode
|
| 137 |
+
```
|
| 138 |
+
|
| 139 |
+
**Common development commands:**
|
| 140 |
+
|
| 141 |
+
| Command | Description |
|
| 142 |
+
| ------------------------ | -------------------------------- |
|
| 143 |
+
| `npm run dev` | Interactive development launcher |
|
| 144 |
+
| `npm run dev:web` | Start in browser mode |
|
| 145 |
+
| `npm run dev:electron` | Start desktop app |
|
| 146 |
+
| `npm run build` | Build all packages and apps |
|
| 147 |
+
| `npm run build:packages` | Build shared packages only |
|
| 148 |
+
| `npm run lint` | Run ESLint checks |
|
| 149 |
+
| `npm run format` | Format code with Prettier |
|
| 150 |
+
| `npm run format:check` | Check formatting without changes |
|
| 151 |
+
| `npm run test` | Run E2E tests (Playwright) |
|
| 152 |
+
| `npm run test:server` | Run server unit tests |
|
| 153 |
+
| `npm run test:packages` | Run package tests |
|
| 154 |
+
| `npm run test:all` | Run all tests |
|
| 155 |
+
|
| 156 |
+
### Project Structure
|
| 157 |
+
|
| 158 |
+
Automaker is organized as an npm workspace monorepo:
|
| 159 |
+
|
| 160 |
+
```
|
| 161 |
+
automaker/
|
| 162 |
+
├── apps/
|
| 163 |
+
│ ├── ui/ # React + Vite + Electron frontend
|
| 164 |
+
│ └── server/ # Express + WebSocket backend
|
| 165 |
+
├── libs/
|
| 166 |
+
│ ├── @automaker/types/ # Shared TypeScript types
|
| 167 |
+
│ ├── @automaker/utils/ # Utility functions
|
| 168 |
+
│ ├── @automaker/prompts/ # AI prompt templates
|
| 169 |
+
│ ├── @automaker/platform/ # Platform abstractions
|
| 170 |
+
│ ├── @automaker/model-resolver/ # AI model resolution
|
| 171 |
+
│ ├── @automaker/dependency-resolver/ # Dependency management
|
| 172 |
+
│ └── @automaker/git-utils/ # Git operations
|
| 173 |
+
├── docs/ # Documentation
|
| 174 |
+
└── package.json # Root package configuration
|
| 175 |
+
```
|
| 176 |
+
|
| 177 |
+
**Key conventions:**
|
| 178 |
+
|
| 179 |
+
- Always import from `@automaker/*` shared packages, never use relative paths to `libs/`
|
| 180 |
+
- Frontend code lives in `apps/ui/`
|
| 181 |
+
- Backend code lives in `apps/server/`
|
| 182 |
+
- Shared logic should be in the appropriate `libs/` package
|
| 183 |
+
|
| 184 |
+
---
|
| 185 |
+
|
| 186 |
+
## Pull Request Process
|
| 187 |
+
|
| 188 |
+
This section covers everything you need to know about contributing changes through pull requests, from creating your branch to getting your code merged.
|
| 189 |
+
|
| 190 |
+
### Branching Strategy (RC Branches)
|
| 191 |
+
|
| 192 |
+
Automaker uses **Release Candidate (RC) branches** for all development work. Understanding this workflow is essential before contributing.
|
| 193 |
+
|
| 194 |
+
**How it works:**
|
| 195 |
+
|
| 196 |
+
1. **All development happens on RC branches** - We maintain version-specific RC branches (e.g., `v0.10.0rc`, `v0.11.0rc`) where all active development occurs
|
| 197 |
+
2. **RC branches are eventually merged to main** - Once an RC branch is stable and ready for release, it gets merged into `main`
|
| 198 |
+
3. **Main branch is for releases only** - The `main` branch contains only released, stable code
|
| 199 |
+
|
| 200 |
+
**Before creating a PR:**
|
| 201 |
+
|
| 202 |
+
1. **Check for the latest RC branch** - Before starting work, check the repository for the current RC branch:
|
| 203 |
+
|
| 204 |
+
```bash
|
| 205 |
+
git fetch upstream
|
| 206 |
+
git branch -r | grep rc
|
| 207 |
+
```
|
| 208 |
+
|
| 209 |
+
2. **Base your work on the RC branch** - Create your feature branch from the latest RC branch, not from `main`:
|
| 210 |
+
|
| 211 |
+
```bash
|
| 212 |
+
# Find the latest RC branch (e.g., v0.11.0rc)
|
| 213 |
+
git checkout upstream/v0.11.0rc
|
| 214 |
+
git checkout -b feature/your-feature-name
|
| 215 |
+
```
|
| 216 |
+
|
| 217 |
+
3. **Target the RC branch in your PR** - When opening your pull request, set the base branch to the current RC branch, not `main`
|
| 218 |
+
|
| 219 |
+
**Example workflow:**
|
| 220 |
+
|
| 221 |
+
```bash
|
| 222 |
+
# 1. Fetch latest changes
|
| 223 |
+
git fetch upstream
|
| 224 |
+
|
| 225 |
+
# 2. Check for RC branches
|
| 226 |
+
git branch -r | grep rc
|
| 227 |
+
# Output: upstream/v0.11.0rc
|
| 228 |
+
|
| 229 |
+
# 3. Create your branch from the RC
|
| 230 |
+
git checkout -b feature/add-dark-mode upstream/v0.11.0rc
|
| 231 |
+
|
| 232 |
+
# 4. Make your changes and commit
|
| 233 |
+
git commit -m "feat: Add dark mode support"
|
| 234 |
+
|
| 235 |
+
# 5. Push to your fork
|
| 236 |
+
git push origin feature/add-dark-mode
|
| 237 |
+
|
| 238 |
+
# 6. Open PR targeting the RC branch (v0.11.0rc), NOT main
|
| 239 |
+
```
|
| 240 |
+
|
| 241 |
+
**Important:** PRs opened directly against `main` will be asked to retarget to the current RC branch.
|
| 242 |
+
|
| 243 |
+
### Branch Naming Convention
|
| 244 |
+
|
| 245 |
+
We use a consistent branch naming pattern to keep our repository organized:
|
| 246 |
+
|
| 247 |
+
```
|
| 248 |
+
<type>/<description>
|
| 249 |
+
```
|
| 250 |
+
|
| 251 |
+
**Branch types:**
|
| 252 |
+
|
| 253 |
+
| Type | Purpose | Example |
|
| 254 |
+
| ---------- | ------------------------ | --------------------------------- |
|
| 255 |
+
| `feature` | New functionality | `feature/add-user-authentication` |
|
| 256 |
+
| `fix` | Bug fixes | `fix/resolve-memory-leak` |
|
| 257 |
+
| `docs` | Documentation changes | `docs/update-contributing-guide` |
|
| 258 |
+
| `refactor` | Code restructuring | `refactor/simplify-api-handlers` |
|
| 259 |
+
| `test` | Adding or updating tests | `test/add-utils-unit-tests` |
|
| 260 |
+
| `chore` | Maintenance tasks | `chore/update-dependencies` |
|
| 261 |
+
|
| 262 |
+
**Guidelines:**
|
| 263 |
+
|
| 264 |
+
- Use lowercase letters and hyphens (no underscores or spaces)
|
| 265 |
+
- Keep descriptions short but descriptive
|
| 266 |
+
- Include issue number when applicable: `feature/123-add-login`
|
| 267 |
+
|
| 268 |
+
```bash
|
| 269 |
+
# Create and checkout a new feature branch
|
| 270 |
+
git checkout -b feature/add-dark-mode
|
| 271 |
+
|
| 272 |
+
# Create a fix branch with issue reference
|
| 273 |
+
git checkout -b fix/456-resolve-login-error
|
| 274 |
+
```
|
| 275 |
+
|
| 276 |
+
### Commit Message Format
|
| 277 |
+
|
| 278 |
+
We follow the **Conventional Commits** style for clear, readable commit history:
|
| 279 |
+
|
| 280 |
+
```
|
| 281 |
+
<type>: <description>
|
| 282 |
+
|
| 283 |
+
[optional body]
|
| 284 |
+
```
|
| 285 |
+
|
| 286 |
+
**Commit types:**
|
| 287 |
+
|
| 288 |
+
| Type | Purpose |
|
| 289 |
+
| ---------- | --------------------------- |
|
| 290 |
+
| `feat` | New feature |
|
| 291 |
+
| `fix` | Bug fix |
|
| 292 |
+
| `docs` | Documentation only |
|
| 293 |
+
| `style` | Formatting (no code change) |
|
| 294 |
+
| `refactor` | Code restructuring |
|
| 295 |
+
| `test` | Adding or updating tests |
|
| 296 |
+
| `chore` | Maintenance tasks |
|
| 297 |
+
|
| 298 |
+
**Guidelines:**
|
| 299 |
+
|
| 300 |
+
- Use **imperative mood** ("Add feature" not "Added feature")
|
| 301 |
+
- Keep first line under **72 characters**
|
| 302 |
+
- Capitalize the first letter after the type prefix
|
| 303 |
+
- No period at the end of the subject line
|
| 304 |
+
- Add a blank line before the body for detailed explanations
|
| 305 |
+
|
| 306 |
+
**Examples:**
|
| 307 |
+
|
| 308 |
+
```bash
|
| 309 |
+
# Simple commit
|
| 310 |
+
git commit -m "feat: Add user authentication flow"
|
| 311 |
+
|
| 312 |
+
# Commit with body for more context
|
| 313 |
+
git commit -m "fix: Resolve memory leak in WebSocket handler
|
| 314 |
+
|
| 315 |
+
The connection cleanup was not being called when clients
|
| 316 |
+
disconnected unexpectedly. Added proper cleanup in the
|
| 317 |
+
error handler to prevent memory accumulation."
|
| 318 |
+
|
| 319 |
+
# Documentation update
|
| 320 |
+
git commit -m "docs: Update API documentation"
|
| 321 |
+
|
| 322 |
+
# Refactoring
|
| 323 |
+
git commit -m "refactor: Simplify state management logic"
|
| 324 |
+
```
|
| 325 |
+
|
| 326 |
+
### Submitting a Pull Request
|
| 327 |
+
|
| 328 |
+
Follow these steps to submit your contribution:
|
| 329 |
+
|
| 330 |
+
#### 1. Prepare Your Changes
|
| 331 |
+
|
| 332 |
+
Ensure you've synced with the latest upstream changes from the RC branch:
|
| 333 |
+
|
| 334 |
+
```bash
|
| 335 |
+
# Fetch latest changes from upstream
|
| 336 |
+
git fetch upstream
|
| 337 |
+
|
| 338 |
+
# Rebase your branch on the current RC branch (if needed)
|
| 339 |
+
git rebase upstream/v0.11.0rc # Use the current RC branch name
|
| 340 |
+
```
|
| 341 |
+
|
| 342 |
+
#### 2. Run Pre-submission Checks
|
| 343 |
+
|
| 344 |
+
Before opening your PR, verify everything passes locally:
|
| 345 |
+
|
| 346 |
+
```bash
|
| 347 |
+
# Run all tests
|
| 348 |
+
npm run test:all
|
| 349 |
+
|
| 350 |
+
# Check formatting
|
| 351 |
+
npm run format:check
|
| 352 |
+
|
| 353 |
+
# Run linter
|
| 354 |
+
npm run lint
|
| 355 |
+
|
| 356 |
+
# Build to verify no compile errors
|
| 357 |
+
npm run build
|
| 358 |
+
```
|
| 359 |
+
|
| 360 |
+
#### 3. Push Your Changes
|
| 361 |
+
|
| 362 |
+
```bash
|
| 363 |
+
# Push your branch to your fork
|
| 364 |
+
git push origin feature/your-feature-name
|
| 365 |
+
```
|
| 366 |
+
|
| 367 |
+
#### 4. Open a Pull Request
|
| 368 |
+
|
| 369 |
+
1. Go to your fork on GitHub
|
| 370 |
+
2. Click "Compare & pull request" for your branch
|
| 371 |
+
3. **Important:** Set the base repository to `AutoMaker-Org/automaker` and the base branch to the **current RC branch** (e.g., `v0.11.0rc`), not `main`
|
| 372 |
+
4. Fill out the PR template completely
|
| 373 |
+
|
| 374 |
+
#### PR Requirements Checklist
|
| 375 |
+
|
| 376 |
+
Your PR should include:
|
| 377 |
+
|
| 378 |
+
- [ ] **Targets the current RC branch** (not `main`) - see [Branching Strategy](#branching-strategy-rc-branches)
|
| 379 |
+
- [ ] **Clear title** describing the change (use conventional commit format)
|
| 380 |
+
- [ ] **Description** explaining what changed and why
|
| 381 |
+
- [ ] **Link to related issue** (if applicable): `Closes #123` or `Fixes #456`
|
| 382 |
+
- [ ] **All CI checks passing** (format, lint, build, tests)
|
| 383 |
+
- [ ] **No merge conflicts** with the RC branch
|
| 384 |
+
- [ ] **Tests included** for new functionality
|
| 385 |
+
- [ ] **Documentation updated** if adding/changing public APIs
|
| 386 |
+
|
| 387 |
+
**Example PR Description:**
|
| 388 |
+
|
| 389 |
+
```markdown
|
| 390 |
+
## Summary
|
| 391 |
+
|
| 392 |
+
This PR adds dark mode support to the Automaker UI.
|
| 393 |
+
|
| 394 |
+
- Implements theme toggle in settings panel
|
| 395 |
+
- Adds CSS custom properties for theme colors
|
| 396 |
+
- Persists theme preference to localStorage
|
| 397 |
+
|
| 398 |
+
## Related Issue
|
| 399 |
+
|
| 400 |
+
Closes #123
|
| 401 |
+
|
| 402 |
+
## Testing
|
| 403 |
+
|
| 404 |
+
- [x] Tested toggle functionality in Chrome and Firefox
|
| 405 |
+
- [x] Verified theme persists across page reloads
|
| 406 |
+
- [x] Checked accessibility contrast ratios
|
| 407 |
+
|
| 408 |
+
## Screenshots
|
| 409 |
+
|
| 410 |
+
[Include before/after screenshots for UI changes]
|
| 411 |
+
```
|
| 412 |
+
|
| 413 |
+
### Review Process
|
| 414 |
+
|
| 415 |
+
All contributions go through code review to maintain quality:
|
| 416 |
+
|
| 417 |
+
#### What to Expect
|
| 418 |
+
|
| 419 |
+
1. **CI Checks Run First** - Automated checks (format, lint, build, tests) must pass before review
|
| 420 |
+
2. **Maintainer Review** - The project maintainers will review your PR and decide whether to merge it
|
| 421 |
+
3. **Feedback & Discussion** - The reviewer may ask questions or request changes
|
| 422 |
+
4. **Iteration** - Make requested changes and push updates to the same branch
|
| 423 |
+
5. **Approval & Merge** - Once approved and checks pass, your PR will be merged
|
| 424 |
+
|
| 425 |
+
#### Review Focus Areas
|
| 426 |
+
|
| 427 |
+
The reviewer checks for:
|
| 428 |
+
|
| 429 |
+
- **Correctness** - Does the code work as intended?
|
| 430 |
+
- **Clean Code** - Does it follow our [code style guidelines](#code-style-guidelines)?
|
| 431 |
+
- **Test Coverage** - Are new features properly tested?
|
| 432 |
+
- **Documentation** - Are public APIs documented?
|
| 433 |
+
- **Breaking Changes** - Are any breaking changes discussed first?
|
| 434 |
+
|
| 435 |
+
#### Responding to Feedback
|
| 436 |
+
|
| 437 |
+
- Respond to **all** review comments, even if just to acknowledge
|
| 438 |
+
- Ask questions if feedback is unclear
|
| 439 |
+
- Push additional commits to address feedback (don't force-push during review)
|
| 440 |
+
- Mark conversations as resolved once addressed
|
| 441 |
+
|
| 442 |
+
#### Approval Criteria
|
| 443 |
+
|
| 444 |
+
Your PR is ready to merge when:
|
| 445 |
+
|
| 446 |
+
- ✅ All CI checks pass
|
| 447 |
+
- ✅ The maintainer has approved the changes
|
| 448 |
+
- ✅ All review comments are addressed
|
| 449 |
+
- ✅ No unresolved merge conflicts
|
| 450 |
+
|
| 451 |
+
#### Getting Help
|
| 452 |
+
|
| 453 |
+
If your PR seems stuck:
|
| 454 |
+
|
| 455 |
+
- Comment asking for status update (mention @webdevcody if needed)
|
| 456 |
+
- Reach out on [Discord](https://discord.gg/jjem7aEDKU)
|
| 457 |
+
- Make sure all checks are passing and you've responded to all feedback
|
| 458 |
+
|
| 459 |
+
---
|
| 460 |
+
|
| 461 |
+
## Code Style Guidelines
|
| 462 |
+
|
| 463 |
+
Automaker uses automated tooling to enforce code style. Run `npm run format` to format code and `npm run lint` to check for issues. Pre-commit hooks automatically format staged files before committing.
|
| 464 |
+
|
| 465 |
+
---
|
| 466 |
+
|
| 467 |
+
## Testing Requirements
|
| 468 |
+
|
| 469 |
+
Testing helps prevent regressions. Automaker uses **Playwright** for end-to-end testing and **Vitest** for unit tests.
|
| 470 |
+
|
| 471 |
+
### Running Tests
|
| 472 |
+
|
| 473 |
+
Use these commands to run tests locally:
|
| 474 |
+
|
| 475 |
+
| Command | Description |
|
| 476 |
+
| ------------------------------ | ------------------------------------- |
|
| 477 |
+
| `npm run test` | Run E2E tests (Playwright) |
|
| 478 |
+
| `npm run test:server` | Run server unit tests (Vitest) |
|
| 479 |
+
| `npm run test:packages` | Run shared package tests |
|
| 480 |
+
| `npm run test:all` | Run all tests |
|
| 481 |
+
| `npm run test:server:coverage` | Run server tests with coverage report |
|
| 482 |
+
|
| 483 |
+
**Before submitting a PR**, always run the full test suite:
|
| 484 |
+
|
| 485 |
+
```bash
|
| 486 |
+
npm run test:all
|
| 487 |
+
```
|
| 488 |
+
|
| 489 |
+
### Test Frameworks
|
| 490 |
+
|
| 491 |
+
#### End-to-End Tests (Playwright)
|
| 492 |
+
|
| 493 |
+
E2E tests verify the entire application works correctly from a user's perspective.
|
| 494 |
+
|
| 495 |
+
- **Framework:** [Playwright](https://playwright.dev/)
|
| 496 |
+
- **Location:** `e2e/` directory
|
| 497 |
+
- **Test ports:** UI on port 3007, Server on port 3008
|
| 498 |
+
|
| 499 |
+
**Running E2E tests:**
|
| 500 |
+
|
| 501 |
+
```bash
|
| 502 |
+
# Run all E2E tests
|
| 503 |
+
npm run test
|
| 504 |
+
|
| 505 |
+
# Run with headed browser (useful for debugging)
|
| 506 |
+
npx playwright test --headed
|
| 507 |
+
|
| 508 |
+
# Run a specific test file
|
| 509 |
+
npm test --workspace=@automaker/ui -- tests/example.spec.ts
|
| 510 |
+
```
|
| 511 |
+
|
| 512 |
+
**E2E Test Guidelines:**
|
| 513 |
+
|
| 514 |
+
- Write tests from a user's perspective
|
| 515 |
+
- Use descriptive test names that explain the scenario
|
| 516 |
+
- Clean up test data after each test
|
| 517 |
+
- Use appropriate timeouts for async operations
|
| 518 |
+
- Prefer `locator` over direct selectors for resilience
|
| 519 |
+
|
| 520 |
+
#### Unit Tests (Vitest)
|
| 521 |
+
|
| 522 |
+
Unit tests verify individual functions and modules work correctly in isolation.
|
| 523 |
+
|
| 524 |
+
- **Framework:** [Vitest](https://vitest.dev/)
|
| 525 |
+
- **Location:** In the `tests/` directory within each package (e.g., `apps/server/tests/`)
|
| 526 |
+
|
| 527 |
+
**Running unit tests:**
|
| 528 |
+
|
| 529 |
+
```bash
|
| 530 |
+
# Run all server unit tests
|
| 531 |
+
npm run test:server
|
| 532 |
+
|
| 533 |
+
# Run with coverage report
|
| 534 |
+
npm run test:server:coverage
|
| 535 |
+
|
| 536 |
+
# Run package tests
|
| 537 |
+
npm run test:packages
|
| 538 |
+
|
| 539 |
+
# Run in watch mode during development
|
| 540 |
+
npx vitest --watch
|
| 541 |
+
```
|
| 542 |
+
|
| 543 |
+
**Unit Test Guidelines:**
|
| 544 |
+
|
| 545 |
+
- Keep tests small and focused on one behavior
|
| 546 |
+
- Use descriptive test names: `it('should return null when user is not found')`
|
| 547 |
+
- Follow the AAA pattern: Arrange, Act, Assert
|
| 548 |
+
- Mock external dependencies to isolate the unit under test
|
| 549 |
+
- Aim for meaningful coverage, not just line coverage
|
| 550 |
+
|
| 551 |
+
### Writing Tests
|
| 552 |
+
|
| 553 |
+
#### When to Write Tests
|
| 554 |
+
|
| 555 |
+
- **New features:** All new features should include tests
|
| 556 |
+
- **Bug fixes:** Add a test that reproduces the bug before fixing
|
| 557 |
+
- **Refactoring:** Ensure existing tests pass after refactoring
|
| 558 |
+
- **Public APIs:** All public APIs must have test coverage
|
| 559 |
+
|
| 560 |
+
### CI/CD Pipeline
|
| 561 |
+
|
| 562 |
+
Automaker uses **GitHub Actions** for continuous integration. Every pull request triggers automated checks.
|
| 563 |
+
|
| 564 |
+
#### CI Checks
|
| 565 |
+
|
| 566 |
+
The following checks must pass before your PR can be merged:
|
| 567 |
+
|
| 568 |
+
| Check | Description |
|
| 569 |
+
| ----------------- | --------------------------------------------- |
|
| 570 |
+
| **Format** | Verifies code is formatted with Prettier |
|
| 571 |
+
| **Build** | Ensures the project compiles without errors |
|
| 572 |
+
| **Package Tests** | Runs tests for shared `@automaker/*` packages |
|
| 573 |
+
| **Server Tests** | Runs server unit tests with coverage |
|
| 574 |
+
|
| 575 |
+
#### CI Testing Environment
|
| 576 |
+
|
| 577 |
+
For CI environments, Automaker supports a mock agent mode:
|
| 578 |
+
|
| 579 |
+
```bash
|
| 580 |
+
# Enable mock agent mode for CI testing
|
| 581 |
+
AUTOMAKER_MOCK_AGENT=true npm run test
|
| 582 |
+
```
|
| 583 |
+
|
| 584 |
+
This allows tests to run without requiring a real Claude API connection.
|
| 585 |
+
|
| 586 |
+
#### Viewing CI Results
|
| 587 |
+
|
| 588 |
+
1. Go to your PR on GitHub
|
| 589 |
+
2. Scroll to the "Checks" section at the bottom
|
| 590 |
+
3. Click on any failed check to see detailed logs
|
| 591 |
+
4. Fix issues locally and push updates
|
| 592 |
+
|
| 593 |
+
#### Common CI Failures
|
| 594 |
+
|
| 595 |
+
| Issue | Solution |
|
| 596 |
+
| ------------------- | --------------------------------------------- |
|
| 597 |
+
| Format check failed | Run `npm run format` locally |
|
| 598 |
+
| Build failed | Run `npm run build` and fix TypeScript errors |
|
| 599 |
+
| Tests failed | Run `npm run test:all` locally to reproduce |
|
| 600 |
+
| Coverage decreased | Add tests for new code paths |
|
| 601 |
+
|
| 602 |
+
### Coverage Requirements
|
| 603 |
+
|
| 604 |
+
While we don't enforce strict coverage percentages, we expect:
|
| 605 |
+
|
| 606 |
+
- **New features:** Should include comprehensive tests
|
| 607 |
+
- **Bug fixes:** Should include a regression test
|
| 608 |
+
- **Critical paths:** Must have test coverage (authentication, data persistence, etc.)
|
| 609 |
+
|
| 610 |
+
To view coverage reports locally:
|
| 611 |
+
|
| 612 |
+
```bash
|
| 613 |
+
npm run test:server:coverage
|
| 614 |
+
```
|
| 615 |
+
|
| 616 |
+
This generates an HTML report you can open in your browser to see which lines are covered.
|
| 617 |
+
|
| 618 |
+
---
|
| 619 |
+
|
| 620 |
+
## Issue Reporting
|
| 621 |
+
|
| 622 |
+
Found a bug or have an idea for a new feature? We'd love to hear from you! This section explains how to report issues effectively.
|
| 623 |
+
|
| 624 |
+
### Bug Reports
|
| 625 |
+
|
| 626 |
+
When reporting a bug, please provide as much information as possible to help us understand and reproduce the issue.
|
| 627 |
+
|
| 628 |
+
#### Before Reporting
|
| 629 |
+
|
| 630 |
+
1. **Search existing issues** - Check if the bug has already been reported
|
| 631 |
+
2. **Try the latest version** - Make sure you're running the latest version of Automaker
|
| 632 |
+
3. **Reproduce the issue** - Verify you can consistently reproduce the bug
|
| 633 |
+
|
| 634 |
+
#### Bug Report Template
|
| 635 |
+
|
| 636 |
+
When creating a bug report, include:
|
| 637 |
+
|
| 638 |
+
- **Title:** A clear, descriptive title summarizing the issue
|
| 639 |
+
- **Environment:**
|
| 640 |
+
- Operating System and version
|
| 641 |
+
- Node.js version (`node --version`)
|
| 642 |
+
- Automaker version or commit hash
|
| 643 |
+
- **Steps to Reproduce:** Numbered list of steps to reproduce the bug
|
| 644 |
+
- **Expected Behavior:** What you expected to happen
|
| 645 |
+
- **Actual Behavior:** What actually happened
|
| 646 |
+
- **Logs/Screenshots:** Any relevant error messages, console output, or screenshots
|
| 647 |
+
|
| 648 |
+
**Example Bug Report:**
|
| 649 |
+
|
| 650 |
+
```markdown
|
| 651 |
+
## Bug: WebSocket connection drops after 5 minutes of inactivity
|
| 652 |
+
|
| 653 |
+
### Environment
|
| 654 |
+
|
| 655 |
+
- OS: Windows 11
|
| 656 |
+
- Node.js: 22.11.0
|
| 657 |
+
- Automaker: commit abc1234
|
| 658 |
+
|
| 659 |
+
### Steps to Reproduce
|
| 660 |
+
|
| 661 |
+
1. Start the application with `npm run dev:web`
|
| 662 |
+
2. Open the Kanban board
|
| 663 |
+
3. Leave the browser tab open for 5+ minutes without interaction
|
| 664 |
+
4. Try to move a card
|
| 665 |
+
|
| 666 |
+
### Expected Behavior
|
| 667 |
+
|
| 668 |
+
The card should move to the new column.
|
| 669 |
+
|
| 670 |
+
### Actual Behavior
|
| 671 |
+
|
| 672 |
+
The UI shows "Connection lost" and the card doesn't move.
|
| 673 |
+
|
| 674 |
+
### Logs
|
| 675 |
+
|
| 676 |
+
[WebSocket] Connection closed: 1006
|
| 677 |
+
```
|
| 678 |
+
|
| 679 |
+
### Feature Requests
|
| 680 |
+
|
| 681 |
+
We welcome ideas for improving Automaker! Here's how to submit a feature request:
|
| 682 |
+
|
| 683 |
+
#### Before Requesting
|
| 684 |
+
|
| 685 |
+
1. **Check existing issues** - Your idea may already be proposed or in development
|
| 686 |
+
2. **Consider scope** - Think about whether the feature fits Automaker's mission as an autonomous AI development studio
|
| 687 |
+
|
| 688 |
+
#### Feature Request Template
|
| 689 |
+
|
| 690 |
+
A good feature request includes:
|
| 691 |
+
|
| 692 |
+
- **Title:** A brief, descriptive title
|
| 693 |
+
- **Problem Statement:** What problem does this feature solve?
|
| 694 |
+
- **Proposed Solution:** How do you envision this working?
|
| 695 |
+
- **Alternatives Considered:** What other approaches did you consider?
|
| 696 |
+
- **Additional Context:** Mockups, examples, or references that help explain your idea
|
| 697 |
+
|
| 698 |
+
**Example Feature Request:**
|
| 699 |
+
|
| 700 |
+
```markdown
|
| 701 |
+
## Feature: Dark Mode Support
|
| 702 |
+
|
| 703 |
+
### Problem Statement
|
| 704 |
+
|
| 705 |
+
Working late at night, the bright UI causes eye strain and doesn't match
|
| 706 |
+
my system's dark theme preference.
|
| 707 |
+
|
| 708 |
+
### Proposed Solution
|
| 709 |
+
|
| 710 |
+
Add a theme toggle in the settings panel that allows switching between
|
| 711 |
+
light and dark modes. Ideally, it should also detect system preference.
|
| 712 |
+
|
| 713 |
+
### Alternatives Considered
|
| 714 |
+
|
| 715 |
+
- Browser extension to force dark mode (doesn't work well with custom styling)
|
| 716 |
+
- Custom CSS override (breaks with updates)
|
| 717 |
+
|
| 718 |
+
### Additional Context
|
| 719 |
+
|
| 720 |
+
Similar to how VS Code handles themes - a dropdown in settings with
|
| 721 |
+
immediate preview.
|
| 722 |
+
```
|
| 723 |
+
|
| 724 |
+
### Security Issues
|
| 725 |
+
|
| 726 |
+
**Important:** If you discover a security vulnerability, please do NOT open a public issue. Instead:
|
| 727 |
+
|
| 728 |
+
1. Join our [Discord server](https://discord.gg/jjem7aEDKU) and send a direct message to the user `@webdevcody`
|
| 729 |
+
2. Include detailed steps to reproduce
|
| 730 |
+
3. Allow time for us to address the issue before public disclosure
|
| 731 |
+
|
| 732 |
+
We take security seriously and appreciate responsible disclosure.
|
| 733 |
+
|
| 734 |
+
---
|
| 735 |
+
|
| 736 |
+
For license and contribution terms, see the [LICENSE](LICENSE) file in the repository root and the [README.md](README.md#license) for more details.
|
| 737 |
+
|
| 738 |
+
---
|
| 739 |
+
|
| 740 |
+
Thank you for contributing to Automaker!
|
jules_branch/DISCLAIMER.md
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Security Disclaimer
|
| 2 |
+
|
| 3 |
+
## Important Warning
|
| 4 |
+
|
| 5 |
+
**Automaker uses AI-powered tooling that has access to your operating system and can read, modify, and delete files. Use at your own risk.**
|
| 6 |
+
|
| 7 |
+
## Risk Assessment
|
| 8 |
+
|
| 9 |
+
This software utilizes AI agents (such as Claude) that can:
|
| 10 |
+
|
| 11 |
+
- **Read files** from your file system
|
| 12 |
+
- **Write and modify files** in your projects
|
| 13 |
+
- **Delete files** when instructed
|
| 14 |
+
- **Execute commands** on your operating system
|
| 15 |
+
- **Access environment variables** and configuration files
|
| 16 |
+
|
| 17 |
+
While we have made efforts to review this codebase for security vulnerabilities and implement safeguards, **you assume all risk** when running this software.
|
| 18 |
+
|
| 19 |
+
## Recommendations
|
| 20 |
+
|
| 21 |
+
### 1. Review the Code First
|
| 22 |
+
|
| 23 |
+
Before running Automaker, we strongly recommend reviewing the source code yourself to understand what operations it performs and ensure you are comfortable with its behavior.
|
| 24 |
+
|
| 25 |
+
### 2. Use Sandboxing (Highly Recommended)
|
| 26 |
+
|
| 27 |
+
**We do not recommend running Automaker directly on your local computer** due to the risk of AI agents having access to your entire file system. Instead, consider:
|
| 28 |
+
|
| 29 |
+
- **Docker**: Run Automaker in a Docker container to isolate it from your host system
|
| 30 |
+
- **Virtual Machine**: Use a VM (such as VirtualBox, VMware, or Parallels) to create an isolated environment
|
| 31 |
+
- **Cloud Development Environment**: Use a cloud-based development environment that provides isolation
|
| 32 |
+
|
| 33 |
+
#### Running in Isolated Docker Container
|
| 34 |
+
|
| 35 |
+
For maximum security, run Automaker in an isolated Docker container that **cannot access your laptop's files**:
|
| 36 |
+
|
| 37 |
+
```bash
|
| 38 |
+
# 1. Set your API key (bash/Linux/Mac - creates UTF-8 file)
|
| 39 |
+
echo "ANTHROPIC_API_KEY=your-api-key-here" > .env
|
| 40 |
+
|
| 41 |
+
# On Windows PowerShell, use instead:
|
| 42 |
+
Set-Content -Path .env -Value "ANTHROPIC_API_KEY=your-api-key-here" -Encoding UTF8
|
| 43 |
+
|
| 44 |
+
# 2. Build and run isolated container
|
| 45 |
+
docker-compose up -d
|
| 46 |
+
|
| 47 |
+
# 3. Access the UI at http://localhost:3007
|
| 48 |
+
# API at http://localhost:3008/api/health
|
| 49 |
+
```
|
| 50 |
+
|
| 51 |
+
The container uses only Docker-managed volumes and has no access to your host filesystem. See [docker-isolation.md](docs/docker-isolation.md) for full documentation.
|
| 52 |
+
|
| 53 |
+
### 3. Limit Access
|
| 54 |
+
|
| 55 |
+
If you must run locally:
|
| 56 |
+
|
| 57 |
+
- Create a dedicated user account with limited permissions
|
| 58 |
+
- Only grant access to specific project directories
|
| 59 |
+
- Avoid running with administrator/root privileges
|
| 60 |
+
- Keep sensitive files and credentials outside of project directories
|
| 61 |
+
|
| 62 |
+
### 4. Monitor Activity
|
| 63 |
+
|
| 64 |
+
- Review the agent's actions in the output logs
|
| 65 |
+
- Pay attention to file modifications and command executions
|
| 66 |
+
- Stop the agent immediately if you notice unexpected behavior
|
| 67 |
+
|
| 68 |
+
## No Warranty & Limitation of Liability
|
| 69 |
+
|
| 70 |
+
THE SOFTWARE UTILIZES ARTIFICIAL INTELLIGENCE TO GENERATE CODE, EXECUTE COMMANDS, AND INTERACT WITH YOUR FILE SYSTEM. YOU ACKNOWLEDGE THAT AI SYSTEMS CAN BE UNPREDICTABLE, MAY GENERATE INCORRECT, INSECURE, OR DESTRUCTIVE CODE, AND MAY TAKE ACTIONS THAT COULD DAMAGE YOUR SYSTEM, FILES, OR HARDWARE.
|
| 71 |
+
|
| 72 |
+
This software is provided "as is", without warranty of any kind, express or implied. In no event shall the authors or copyright holders be liable for any claim, damages, or other liability, including but not limited to hardware damage, data loss, financial loss, or business interruption, whether in an action of contract, tort, or otherwise, arising from, out of, or in connection with the software or the use or other dealings in the software.
|
| 73 |
+
|
| 74 |
+
## Acknowledgment
|
| 75 |
+
|
| 76 |
+
By using Automaker, you acknowledge that:
|
| 77 |
+
|
| 78 |
+
1. You have read and understood this disclaimer
|
| 79 |
+
2. You accept full responsibility for any consequences of using this software
|
| 80 |
+
3. You understand the risks of AI agents having access to your operating system
|
| 81 |
+
4. You agree to take appropriate precautions as outlined above
|
| 82 |
+
|
| 83 |
+
---
|
| 84 |
+
|
| 85 |
+
**If you are not comfortable with these risks, do not use this software.**
|
jules_branch/Dockerfile
ADDED
|
@@ -0,0 +1,237 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Automaker Multi-Stage Dockerfile
|
| 2 |
+
# Single Dockerfile for both server and UI builds
|
| 3 |
+
# Usage:
|
| 4 |
+
# docker build --target server -t automaker-server .
|
| 5 |
+
# docker build --target ui -t automaker-ui .
|
| 6 |
+
# Or use docker-compose which selects targets automatically
|
| 7 |
+
|
| 8 |
+
# =============================================================================
|
| 9 |
+
# BASE STAGE - Common setup for all builds (DRY: defined once, used by all)
|
| 10 |
+
# =============================================================================
|
| 11 |
+
FROM node:22-slim AS base
|
| 12 |
+
|
| 13 |
+
# Install build dependencies for native modules (node-pty)
|
| 14 |
+
RUN apt-get update && apt-get install -y --no-install-recommends \
|
| 15 |
+
python3 make g++ \
|
| 16 |
+
&& rm -rf /var/lib/apt/lists/*
|
| 17 |
+
|
| 18 |
+
WORKDIR /app
|
| 19 |
+
|
| 20 |
+
# Copy root package files
|
| 21 |
+
COPY package*.json ./
|
| 22 |
+
|
| 23 |
+
# Copy all libs package.json files (centralized - add new libs here)
|
| 24 |
+
COPY libs/types/package*.json ./libs/types/
|
| 25 |
+
COPY libs/utils/package*.json ./libs/utils/
|
| 26 |
+
COPY libs/prompts/package*.json ./libs/prompts/
|
| 27 |
+
COPY libs/platform/package*.json ./libs/platform/
|
| 28 |
+
COPY libs/spec-parser/package*.json ./libs/spec-parser/
|
| 29 |
+
COPY libs/model-resolver/package*.json ./libs/model-resolver/
|
| 30 |
+
COPY libs/dependency-resolver/package*.json ./libs/dependency-resolver/
|
| 31 |
+
COPY libs/git-utils/package*.json ./libs/git-utils/
|
| 32 |
+
COPY libs/spec-parser/package*.json ./libs/spec-parser/
|
| 33 |
+
|
| 34 |
+
# Copy scripts (needed by npm workspace)
|
| 35 |
+
COPY scripts ./scripts
|
| 36 |
+
|
| 37 |
+
# =============================================================================
|
| 38 |
+
# SERVER BUILD STAGE
|
| 39 |
+
# =============================================================================
|
| 40 |
+
FROM base AS server-builder
|
| 41 |
+
|
| 42 |
+
# Copy server-specific package.json
|
| 43 |
+
COPY apps/server/package*.json ./apps/server/
|
| 44 |
+
|
| 45 |
+
# Install dependencies (--ignore-scripts to skip husky/prepare, then rebuild native modules)
|
| 46 |
+
RUN npm ci --ignore-scripts && npm rebuild node-pty
|
| 47 |
+
|
| 48 |
+
# Copy all source files
|
| 49 |
+
COPY libs ./libs
|
| 50 |
+
COPY apps/server ./apps/server
|
| 51 |
+
|
| 52 |
+
# Build packages in dependency order, then build server
|
| 53 |
+
RUN npm run build:packages && npm run build --workspace=apps/server
|
| 54 |
+
|
| 55 |
+
# =============================================================================
|
| 56 |
+
# SERVER PRODUCTION STAGE
|
| 57 |
+
# =============================================================================
|
| 58 |
+
FROM node:22-slim AS server
|
| 59 |
+
|
| 60 |
+
# Build argument for tracking which commit this image was built from
|
| 61 |
+
ARG GIT_COMMIT_SHA=unknown
|
| 62 |
+
LABEL automaker.git.commit.sha="${GIT_COMMIT_SHA}"
|
| 63 |
+
|
| 64 |
+
# Build arguments for user ID matching (allows matching host user for mounted volumes)
|
| 65 |
+
# Override at build time: docker build --build-arg UID=$(id -u) --build-arg GID=$(id -g) ...
|
| 66 |
+
ARG UID=1001
|
| 67 |
+
ARG GID=1001
|
| 68 |
+
|
| 69 |
+
# Install git, curl, bash (for terminal), gosu (for user switching), and GitHub CLI (pinned version, multi-arch)
|
| 70 |
+
# Also install Playwright/Chromium system dependencies (aligns with playwright install-deps on Debian/Ubuntu)
|
| 71 |
+
RUN apt-get update && apt-get install -y --no-install-recommends \
|
| 72 |
+
git curl bash gosu ca-certificates openssh-client \
|
| 73 |
+
# Playwright/Chromium dependencies
|
| 74 |
+
libglib2.0-0 libnss3 libnspr4 libdbus-1-3 libatk1.0-0 libatk-bridge2.0-0 \
|
| 75 |
+
libcups2 libdrm2 libxkbcommon0 libatspi2.0-0 libxcomposite1 libxdamage1 \
|
| 76 |
+
libxfixes3 libxrandr2 libgbm1 libasound2 libpango-1.0-0 libcairo2 \
|
| 77 |
+
libx11-6 libx11-xcb1 libxcb1 libxext6 libxrender1 libxss1 libxtst6 \
|
| 78 |
+
libxshmfence1 libgtk-3-0 libexpat1 libfontconfig1 fonts-liberation \
|
| 79 |
+
xdg-utils libpangocairo-1.0-0 libpangoft2-1.0-0 libu2f-udev libvulkan1 \
|
| 80 |
+
&& GH_VERSION="2.63.2" \
|
| 81 |
+
&& ARCH=$(uname -m) \
|
| 82 |
+
&& case "$ARCH" in \
|
| 83 |
+
x86_64) GH_ARCH="amd64" ;; \
|
| 84 |
+
aarch64|arm64) GH_ARCH="arm64" ;; \
|
| 85 |
+
*) echo "Unsupported architecture: $ARCH" && exit 1 ;; \
|
| 86 |
+
esac \
|
| 87 |
+
&& curl -L "https://github.com/cli/cli/releases/download/v${GH_VERSION}/gh_${GH_VERSION}_linux_${GH_ARCH}.tar.gz" -o gh.tar.gz \
|
| 88 |
+
&& tar -xzf gh.tar.gz \
|
| 89 |
+
&& mv gh_${GH_VERSION}_linux_${GH_ARCH}/bin/gh /usr/local/bin/gh \
|
| 90 |
+
&& rm -rf gh.tar.gz gh_${GH_VERSION}_linux_${GH_ARCH} \
|
| 91 |
+
&& rm -rf /var/lib/apt/lists/*
|
| 92 |
+
|
| 93 |
+
# Install Claude CLI globally (available to all users via npm global bin)
|
| 94 |
+
RUN npm install -g @anthropic-ai/claude-code
|
| 95 |
+
|
| 96 |
+
# Create non-root user with home directory BEFORE installing Cursor CLI
|
| 97 |
+
# Uses UID/GID build args to match host user for mounted volume permissions
|
| 98 |
+
# Use -o flag to allow non-unique IDs (GID 1000 may already exist as 'node' group)
|
| 99 |
+
RUN groupadd -o -g ${GID} automaker && \
|
| 100 |
+
useradd -o -u ${UID} -g automaker -m -d /home/automaker -s /bin/bash automaker && \
|
| 101 |
+
mkdir -p /home/automaker/.local/bin && \
|
| 102 |
+
mkdir -p /home/automaker/.cursor && \
|
| 103 |
+
chown -R automaker:automaker /home/automaker && \
|
| 104 |
+
chmod 700 /home/automaker/.cursor
|
| 105 |
+
|
| 106 |
+
# Install Cursor CLI as the automaker user
|
| 107 |
+
# Set HOME explicitly and install to /home/automaker/.local/bin/
|
| 108 |
+
USER automaker
|
| 109 |
+
ENV HOME=/home/automaker
|
| 110 |
+
RUN curl https://cursor.com/install -fsS | bash && \
|
| 111 |
+
echo "=== Checking Cursor CLI installation ===" && \
|
| 112 |
+
ls -la /home/automaker/.local/bin/ && \
|
| 113 |
+
echo "=== PATH is: $PATH ===" && \
|
| 114 |
+
(which cursor-agent && cursor-agent --version) || echo "cursor-agent installed (may need auth setup)"
|
| 115 |
+
|
| 116 |
+
# Install OpenCode CLI (for multi-provider AI model access)
|
| 117 |
+
RUN curl -fsSL https://opencode.ai/install | bash && \
|
| 118 |
+
echo "=== Checking OpenCode CLI installation ===" && \
|
| 119 |
+
ls -la /home/automaker/.local/bin/ && \
|
| 120 |
+
(which opencode && opencode --version) || echo "opencode installed (may need auth setup)"
|
| 121 |
+
|
| 122 |
+
USER root
|
| 123 |
+
|
| 124 |
+
# Add PATH to profile so it's available in all interactive shells (for login shells)
|
| 125 |
+
RUN mkdir -p /etc/profile.d && \
|
| 126 |
+
echo 'export PATH="/home/automaker/.local/bin:$PATH"' > /etc/profile.d/cursor-cli.sh && \
|
| 127 |
+
chmod +x /etc/profile.d/cursor-cli.sh
|
| 128 |
+
|
| 129 |
+
# Add to automaker's .bashrc for bash interactive shells
|
| 130 |
+
RUN echo 'export PATH="/home/automaker/.local/bin:$PATH"' >> /home/automaker/.bashrc && \
|
| 131 |
+
chown automaker:automaker /home/automaker/.bashrc
|
| 132 |
+
|
| 133 |
+
# Also add to root's .bashrc since docker exec defaults to root
|
| 134 |
+
RUN echo 'export PATH="/home/automaker/.local/bin:$PATH"' >> /root/.bashrc
|
| 135 |
+
|
| 136 |
+
WORKDIR /app
|
| 137 |
+
|
| 138 |
+
# Copy root package.json (needed for workspace resolution)
|
| 139 |
+
COPY --from=server-builder /app/package*.json ./
|
| 140 |
+
|
| 141 |
+
# Copy built libs (workspace packages are symlinked in node_modules)
|
| 142 |
+
COPY --from=server-builder /app/libs ./libs
|
| 143 |
+
|
| 144 |
+
# Copy built server
|
| 145 |
+
COPY --from=server-builder /app/apps/server/dist ./apps/server/dist
|
| 146 |
+
COPY --from=server-builder /app/apps/server/package*.json ./apps/server/
|
| 147 |
+
|
| 148 |
+
# Copy node_modules (includes symlinks to libs)
|
| 149 |
+
COPY --from=server-builder /app/node_modules ./node_modules
|
| 150 |
+
|
| 151 |
+
# Install Playwright Chromium browser for AI agent verification tests
|
| 152 |
+
# This adds ~300MB to the image but enables automated testing mode out of the box
|
| 153 |
+
# Using the locally installed playwright ensures we use the pinned version from package-lock.json
|
| 154 |
+
USER automaker
|
| 155 |
+
RUN ./node_modules/.bin/playwright install chromium && \
|
| 156 |
+
echo "=== Playwright Chromium installed ===" && \
|
| 157 |
+
ls -la /home/automaker/.cache/ms-playwright/
|
| 158 |
+
USER root
|
| 159 |
+
|
| 160 |
+
# Create data and projects directories
|
| 161 |
+
RUN mkdir -p /data /projects && chown automaker:automaker /data /projects
|
| 162 |
+
|
| 163 |
+
# Configure git for mounted volumes and authentication
|
| 164 |
+
# Use --system so it's not overwritten by mounted user .gitconfig
|
| 165 |
+
RUN git config --system --add safe.directory '*' && \
|
| 166 |
+
# Use gh as credential helper (works with GH_TOKEN env var)
|
| 167 |
+
git config --system credential.helper '!gh auth git-credential'
|
| 168 |
+
|
| 169 |
+
# Copy entrypoint script for fixing permissions on mounted volumes
|
| 170 |
+
COPY docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh
|
| 171 |
+
RUN chmod +x /usr/local/bin/docker-entrypoint.sh
|
| 172 |
+
|
| 173 |
+
# Note: We stay as root here so entrypoint can fix permissions
|
| 174 |
+
# The entrypoint script will switch to automaker user before running the command
|
| 175 |
+
|
| 176 |
+
# Environment variables
|
| 177 |
+
ENV PORT=3008
|
| 178 |
+
ENV DATA_DIR=/data
|
| 179 |
+
ENV HOME=/home/automaker
|
| 180 |
+
# Add user's local bin to PATH for cursor-agent
|
| 181 |
+
ENV PATH="/home/automaker/.local/bin:${PATH}"
|
| 182 |
+
|
| 183 |
+
# Expose port
|
| 184 |
+
EXPOSE 3008
|
| 185 |
+
|
| 186 |
+
# Health check (using curl since it's already installed, more reliable than busybox wget)
|
| 187 |
+
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
|
| 188 |
+
CMD curl -f http://localhost:3008/api/health || exit 1
|
| 189 |
+
|
| 190 |
+
# Use entrypoint to fix permissions before starting
|
| 191 |
+
ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"]
|
| 192 |
+
|
| 193 |
+
# Start server
|
| 194 |
+
CMD ["node", "apps/server/dist/index.js"]
|
| 195 |
+
|
| 196 |
+
# =============================================================================
|
| 197 |
+
# UI BUILD STAGE
|
| 198 |
+
# =============================================================================
|
| 199 |
+
FROM base AS ui-builder
|
| 200 |
+
|
| 201 |
+
# Copy UI-specific package.json
|
| 202 |
+
COPY apps/ui/package*.json ./apps/ui/
|
| 203 |
+
|
| 204 |
+
# Install dependencies (--ignore-scripts to skip husky and build:packages in prepare script)
|
| 205 |
+
RUN npm ci --ignore-scripts
|
| 206 |
+
|
| 207 |
+
# Copy all source files
|
| 208 |
+
COPY libs ./libs
|
| 209 |
+
COPY apps/ui ./apps/ui
|
| 210 |
+
|
| 211 |
+
# Build packages in dependency order, then build UI
|
| 212 |
+
# When VITE_SERVER_URL is empty, the UI uses relative URLs (e.g., /api/...) which nginx proxies
|
| 213 |
+
# to the server container. This avoids CORS issues entirely in Docker Compose setups.
|
| 214 |
+
# Override at build time if needed: --build-arg VITE_SERVER_URL=http://api.example.com
|
| 215 |
+
ARG VITE_SERVER_URL=
|
| 216 |
+
ENV VITE_SKIP_ELECTRON=true
|
| 217 |
+
ENV VITE_SERVER_URL=${VITE_SERVER_URL}
|
| 218 |
+
RUN npm run build:packages && npm run build --workspace=apps/ui
|
| 219 |
+
|
| 220 |
+
# =============================================================================
|
| 221 |
+
# UI PRODUCTION STAGE
|
| 222 |
+
# =============================================================================
|
| 223 |
+
FROM nginx:alpine AS ui
|
| 224 |
+
|
| 225 |
+
# Build argument for tracking which commit this image was built from
|
| 226 |
+
ARG GIT_COMMIT_SHA=unknown
|
| 227 |
+
LABEL automaker.git.commit.sha="${GIT_COMMIT_SHA}"
|
| 228 |
+
|
| 229 |
+
# Copy built files
|
| 230 |
+
COPY --from=ui-builder /app/apps/ui/dist /usr/share/nginx/html
|
| 231 |
+
|
| 232 |
+
# Copy nginx config for SPA routing
|
| 233 |
+
COPY apps/ui/nginx.conf /etc/nginx/conf.d/default.conf
|
| 234 |
+
|
| 235 |
+
EXPOSE 80
|
| 236 |
+
|
| 237 |
+
CMD ["nginx", "-g", "daemon off;"]
|
jules_branch/Dockerfile.dev
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
+
# Also install Playwright/Chromium system dependencies (aligns with playwright install-deps on Debian/Ubuntu)
|
| 12 |
+
RUN apt-get update && apt-get install -y --no-install-recommends \
|
| 13 |
+
python3 make g++ \
|
| 14 |
+
git curl bash gosu ca-certificates openssh-client \
|
| 15 |
+
# Playwright/Chromium dependencies
|
| 16 |
+
libglib2.0-0 libnss3 libnspr4 libdbus-1-3 libatk1.0-0 libatk-bridge2.0-0 \
|
| 17 |
+
libcups2 libdrm2 libxkbcommon0 libatspi2.0-0 libxcomposite1 libxdamage1 \
|
| 18 |
+
libxfixes3 libxrandr2 libgbm1 libasound2 libpango-1.0-0 libcairo2 \
|
| 19 |
+
libx11-6 libx11-xcb1 libxcb1 libxext6 libxrender1 libxss1 libxtst6 \
|
| 20 |
+
libxshmfence1 libgtk-3-0 libexpat1 libfontconfig1 fonts-liberation \
|
| 21 |
+
xdg-utils libpangocairo-1.0-0 libpangoft2-1.0-0 libu2f-udev libvulkan1 \
|
| 22 |
+
&& GH_VERSION="2.63.2" \
|
| 23 |
+
&& ARCH=$(uname -m) \
|
| 24 |
+
&& case "$ARCH" in \
|
| 25 |
+
x86_64) GH_ARCH="amd64" ;; \
|
| 26 |
+
aarch64|arm64) GH_ARCH="arm64" ;; \
|
| 27 |
+
*) echo "Unsupported architecture: $ARCH" && exit 1 ;; \
|
| 28 |
+
esac \
|
| 29 |
+
&& curl -L "https://github.com/cli/cli/releases/download/v${GH_VERSION}/gh_${GH_VERSION}_linux_${GH_ARCH}.tar.gz" -o gh.tar.gz \
|
| 30 |
+
&& tar -xzf gh.tar.gz \
|
| 31 |
+
&& mv gh_${GH_VERSION}_linux_${GH_ARCH}/bin/gh /usr/local/bin/gh \
|
| 32 |
+
&& rm -rf gh.tar.gz gh_${GH_VERSION}_linux_${GH_ARCH} \
|
| 33 |
+
&& rm -rf /var/lib/apt/lists/*
|
| 34 |
+
|
| 35 |
+
# Install Claude CLI globally
|
| 36 |
+
RUN npm install -g @anthropic-ai/claude-code
|
| 37 |
+
|
| 38 |
+
# Build arguments for user ID matching (allows matching host user for mounted volumes)
|
| 39 |
+
# Override at build time: docker-compose build --build-arg UID=$(id -u) --build-arg GID=$(id -g)
|
| 40 |
+
ARG UID=1001
|
| 41 |
+
ARG GID=1001
|
| 42 |
+
|
| 43 |
+
# Create non-root user with configurable UID/GID
|
| 44 |
+
# Use -o flag to allow non-unique IDs (GID 1000 may already exist as 'node' group)
|
| 45 |
+
RUN groupadd -o -g ${GID} automaker && \
|
| 46 |
+
useradd -o -u ${UID} -g automaker -m -d /home/automaker -s /bin/bash automaker && \
|
| 47 |
+
mkdir -p /home/automaker/.local/bin && \
|
| 48 |
+
mkdir -p /home/automaker/.cursor && \
|
| 49 |
+
chown -R automaker:automaker /home/automaker && \
|
| 50 |
+
chmod 700 /home/automaker/.cursor
|
| 51 |
+
|
| 52 |
+
# Install Cursor CLI as automaker user
|
| 53 |
+
USER automaker
|
| 54 |
+
ENV HOME=/home/automaker
|
| 55 |
+
RUN curl https://cursor.com/install -fsS | bash || true
|
| 56 |
+
USER root
|
| 57 |
+
|
| 58 |
+
# Add PATH to profile for Cursor CLI
|
| 59 |
+
RUN mkdir -p /etc/profile.d && \
|
| 60 |
+
echo 'export PATH="/home/automaker/.local/bin:$PATH"' > /etc/profile.d/cursor-cli.sh && \
|
| 61 |
+
chmod +x /etc/profile.d/cursor-cli.sh
|
| 62 |
+
|
| 63 |
+
# Add to user bashrc files
|
| 64 |
+
RUN echo 'export PATH="/home/automaker/.local/bin:$PATH"' >> /home/automaker/.bashrc && \
|
| 65 |
+
chown automaker:automaker /home/automaker/.bashrc
|
| 66 |
+
RUN echo 'export PATH="/home/automaker/.local/bin:$PATH"' >> /root/.bashrc
|
| 67 |
+
|
| 68 |
+
WORKDIR /app
|
| 69 |
+
|
| 70 |
+
# Create directories with proper permissions
|
| 71 |
+
RUN mkdir -p /data /projects && chown automaker:automaker /data /projects
|
| 72 |
+
|
| 73 |
+
# Configure git for mounted volumes
|
| 74 |
+
RUN git config --system --add safe.directory '*' && \
|
| 75 |
+
git config --system credential.helper '!gh auth git-credential'
|
| 76 |
+
|
| 77 |
+
# Copy entrypoint script
|
| 78 |
+
COPY docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh
|
| 79 |
+
RUN chmod +x /usr/local/bin/docker-entrypoint.sh
|
| 80 |
+
|
| 81 |
+
# Environment variables
|
| 82 |
+
ENV PORT=3008
|
| 83 |
+
ENV DATA_DIR=/data
|
| 84 |
+
ENV HOME=/home/automaker
|
| 85 |
+
ENV PATH="/home/automaker/.local/bin:${PATH}"
|
| 86 |
+
|
| 87 |
+
# Expose both dev ports
|
| 88 |
+
EXPOSE 3007 3008
|
| 89 |
+
|
| 90 |
+
# Use entrypoint for permission handling
|
| 91 |
+
ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"]
|
| 92 |
+
|
| 93 |
+
# Default command - will be overridden by docker-compose
|
| 94 |
+
CMD ["npm", "run", "dev:web"]
|
jules_branch/LICENSE
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
## Project Status
|
| 2 |
+
|
| 3 |
+
**This project is no longer actively maintained.** The codebase is provided as-is for those who wish to use, study, or fork it. No bug fixes, security updates, or new features are being developed. Community contributions may still be accepted, but there is no guarantee of review or merge.
|
| 4 |
+
|
| 5 |
+
---
|
| 6 |
+
|
| 7 |
+
MIT License
|
| 8 |
+
|
| 9 |
+
Copyright (c) 2025 Automaker Core Contributors
|
| 10 |
+
|
| 11 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
| 12 |
+
of this software and associated documentation files (the "Software"), to deal
|
| 13 |
+
in the Software without restriction, including without limitation the rights
|
| 14 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
| 15 |
+
copies of the Software, and to permit persons to whom the Software is
|
| 16 |
+
furnished to do so, subject to the following conditions:
|
| 17 |
+
|
| 18 |
+
The above copyright notice and this permission notice shall be included in all
|
| 19 |
+
copies or substantial portions of the Software.
|
| 20 |
+
|
| 21 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
| 22 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
| 23 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
| 24 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
| 25 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
| 26 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
| 27 |
+
SOFTWARE.
|
jules_branch/OPENCODE_CONFIG_CONTENT
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"$schema": "https://opencode.ai/config.json",}
|
jules_branch/README.md
ADDED
|
@@ -0,0 +1,714 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<p align="center">
|
| 2 |
+
<img src="apps/ui/public/readme_logo.svg" alt="Automaker Logo" height="80" />
|
| 3 |
+
</p>
|
| 4 |
+
|
| 5 |
+
> **[!TIP]**
|
| 6 |
+
>
|
| 7 |
+
> **Learn more about Agentic Coding!**
|
| 8 |
+
>
|
| 9 |
+
> Automaker itself was built by a group of engineers using AI and agentic coding techniques to build features faster than ever. By leveraging tools like Cursor IDE and Claude Code CLI, the team orchestrated AI agents to implement complex functionality in days instead of weeks.
|
| 10 |
+
>
|
| 11 |
+
> **Learn how:** Master these same techniques and workflows in the [Agentic Jumpstart course](https://agenticjumpstart.com/?utm=automaker-gh).
|
| 12 |
+
|
| 13 |
+
# Automaker
|
| 14 |
+
|
| 15 |
+
**Stop typing code. Start directing AI agents.**
|
| 16 |
+
|
| 17 |
+
<details open>
|
| 18 |
+
<summary><h2>Table of Contents</h2></summary>
|
| 19 |
+
|
| 20 |
+
- [What Makes Automaker Different?](#what-makes-automaker-different)
|
| 21 |
+
- [The Workflow](#the-workflow)
|
| 22 |
+
- [Powered by Claude Agent SDK](#powered-by-claude-agent-sdk)
|
| 23 |
+
- [Why This Matters](#why-this-matters)
|
| 24 |
+
- [Security Disclaimer](#security-disclaimer)
|
| 25 |
+
- [Community & Support](#community--support)
|
| 26 |
+
- [Getting Started](#getting-started)
|
| 27 |
+
- [Prerequisites](#prerequisites)
|
| 28 |
+
- [Quick Start](#quick-start)
|
| 29 |
+
- [How to Run](#how-to-run)
|
| 30 |
+
- [Development Mode](#development-mode)
|
| 31 |
+
- [Interactive TUI Launcher](#interactive-tui-launcher-recommended-for-new-users)
|
| 32 |
+
- [Building for Production](#building-for-production)
|
| 33 |
+
- [Testing](#testing)
|
| 34 |
+
- [Linting](#linting)
|
| 35 |
+
- [Environment Configuration](#environment-configuration)
|
| 36 |
+
- [Authentication Setup](#authentication-setup)
|
| 37 |
+
- [Features](#features)
|
| 38 |
+
- [Core Workflow](#core-workflow)
|
| 39 |
+
- [AI & Planning](#ai--planning)
|
| 40 |
+
- [Project Management](#project-management)
|
| 41 |
+
- [Collaboration & Review](#collaboration--review)
|
| 42 |
+
- [Developer Tools](#developer-tools)
|
| 43 |
+
- [Advanced Features](#advanced-features)
|
| 44 |
+
- [Tech Stack](#tech-stack)
|
| 45 |
+
- [Frontend](#frontend)
|
| 46 |
+
- [Backend](#backend)
|
| 47 |
+
- [Testing & Quality](#testing--quality)
|
| 48 |
+
- [Shared Libraries](#shared-libraries)
|
| 49 |
+
- [Available Views](#available-views)
|
| 50 |
+
- [Architecture](#architecture)
|
| 51 |
+
- [Monorepo Structure](#monorepo-structure)
|
| 52 |
+
- [How It Works](#how-it-works)
|
| 53 |
+
- [Key Architectural Patterns](#key-architectural-patterns)
|
| 54 |
+
- [Security & Isolation](#security--isolation)
|
| 55 |
+
- [Data Storage](#data-storage)
|
| 56 |
+
- [Learn More](#learn-more)
|
| 57 |
+
- [License](#license)
|
| 58 |
+
|
| 59 |
+
</details>
|
| 60 |
+
|
| 61 |
+
Automaker is an autonomous AI development studio that transforms how you build software. Instead of manually writing every line of code, you describe features on a Kanban board and watch as AI agents powered by Claude Agent SDK automatically implement them. Built with React, Vite, Electron, and Express, Automaker provides a complete workflow for managing AI agents through a desktop application (or web browser), with features like real-time streaming, git worktree isolation, plan approval, and multi-agent task execution.
|
| 62 |
+
|
| 63 |
+

|
| 64 |
+
|
| 65 |
+
## What Makes Automaker Different?
|
| 66 |
+
|
| 67 |
+
Traditional development tools help you write code. Automaker helps you **orchestrate AI agents** to build entire features autonomously. Think of it as having a team of AI developers working for you—you define what needs to be built, and Automaker handles the implementation.
|
| 68 |
+
|
| 69 |
+
### The Workflow
|
| 70 |
+
|
| 71 |
+
1. **Add Features** - Describe features you want built (with text, images, or screenshots)
|
| 72 |
+
2. **Move to "In Progress"** - Automaker automatically assigns an AI agent to implement the feature
|
| 73 |
+
3. **Watch It Build** - See real-time progress as the agent writes code, runs tests, and makes changes
|
| 74 |
+
4. **Review & Verify** - Review the changes, run tests, and approve when ready
|
| 75 |
+
5. **Ship Faster** - Build entire applications in days, not weeks
|
| 76 |
+
|
| 77 |
+
### Powered by Claude Agent SDK
|
| 78 |
+
|
| 79 |
+
Automaker leverages the [Claude Agent SDK](https://www.npmjs.com/package/@anthropic-ai/claude-agent-sdk) to give AI agents full access to your codebase. Agents can read files, write code, execute commands, run tests, and make git commits—all while working in isolated git worktrees to keep your main branch safe. The SDK provides autonomous AI agents that can use tools, make decisions, and complete complex multi-step tasks without constant human intervention.
|
| 80 |
+
|
| 81 |
+
### Why This Matters
|
| 82 |
+
|
| 83 |
+
The future of software development is **agentic coding**—where developers become architects directing AI agents rather than manual coders. Automaker puts this future in your hands today, letting you experience what it's like to build software 10x faster with AI agents handling the implementation while you focus on architecture and business logic.
|
| 84 |
+
|
| 85 |
+
## Community & Support
|
| 86 |
+
|
| 87 |
+
Join the **Agentic Jumpstart** to connect with other builders exploring **agentic coding** and autonomous development workflows.
|
| 88 |
+
|
| 89 |
+
In the Discord, you can:
|
| 90 |
+
|
| 91 |
+
- 💬 Discuss agentic coding patterns and best practices
|
| 92 |
+
- 🧠 Share ideas for AI-driven development workflows
|
| 93 |
+
- 🛠️ Get help setting up or extending Automaker
|
| 94 |
+
- 🚀 Show off projects built with AI agents
|
| 95 |
+
- 🤝 Collaborate with other developers and contributors
|
| 96 |
+
|
| 97 |
+
👉 **Join the Discord:** [Agentic Jumpstart Discord](https://discord.gg/jjem7aEDKU)
|
| 98 |
+
|
| 99 |
+
---
|
| 100 |
+
|
| 101 |
+
## Getting Started
|
| 102 |
+
|
| 103 |
+
### Prerequisites
|
| 104 |
+
|
| 105 |
+
- **Node.js 22+** (required: >=22.0.0 <23.0.0)
|
| 106 |
+
- **npm** (comes with Node.js)
|
| 107 |
+
- **[Claude Code CLI](https://code.claude.com/docs/en/overview)** - Install and authenticate with your Anthropic subscription. Automaker integrates with your authenticated Claude Code CLI to access Claude models.
|
| 108 |
+
|
| 109 |
+
### Quick Start
|
| 110 |
+
|
| 111 |
+
```bash
|
| 112 |
+
# 1. Clone the repository
|
| 113 |
+
git clone https://github.com/AutoMaker-Org/automaker.git
|
| 114 |
+
cd automaker
|
| 115 |
+
|
| 116 |
+
# 2. Install dependencies
|
| 117 |
+
npm install
|
| 118 |
+
|
| 119 |
+
# 3. Start Automaker
|
| 120 |
+
npm run dev
|
| 121 |
+
# Choose between:
|
| 122 |
+
# 1. Web Application (browser at localhost:3007)
|
| 123 |
+
# 2. Desktop Application (Electron - recommended)
|
| 124 |
+
```
|
| 125 |
+
|
| 126 |
+
**Authentication:** Automaker integrates with your authenticated Claude Code CLI. Make sure you have [installed and authenticated](https://code.claude.com/docs/en/quickstart) the Claude Code CLI before running Automaker. Your CLI credentials will be detected automatically.
|
| 127 |
+
|
| 128 |
+
**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.
|
| 129 |
+
|
| 130 |
+
## How to Run
|
| 131 |
+
|
| 132 |
+
### Development Mode
|
| 133 |
+
|
| 134 |
+
Start Automaker in development mode:
|
| 135 |
+
|
| 136 |
+
```bash
|
| 137 |
+
npm run dev
|
| 138 |
+
```
|
| 139 |
+
|
| 140 |
+
This will prompt you to choose your run mode, or you can specify a mode directly:
|
| 141 |
+
|
| 142 |
+
#### Electron Desktop App (Recommended)
|
| 143 |
+
|
| 144 |
+
```bash
|
| 145 |
+
# Standard development mode
|
| 146 |
+
npm run dev:electron
|
| 147 |
+
|
| 148 |
+
# With DevTools open automatically
|
| 149 |
+
npm run dev:electron:debug
|
| 150 |
+
|
| 151 |
+
# For WSL (Windows Subsystem for Linux)
|
| 152 |
+
npm run dev:electron:wsl
|
| 153 |
+
|
| 154 |
+
# For WSL with GPU acceleration
|
| 155 |
+
npm run dev:electron:wsl:gpu
|
| 156 |
+
```
|
| 157 |
+
|
| 158 |
+
#### Web Browser Mode
|
| 159 |
+
|
| 160 |
+
```bash
|
| 161 |
+
# Run in web browser (http://localhost:3007)
|
| 162 |
+
npm run dev:web
|
| 163 |
+
```
|
| 164 |
+
|
| 165 |
+
### Interactive TUI Launcher (Recommended for New Users)
|
| 166 |
+
|
| 167 |
+
For a user-friendly interactive menu, use the built-in TUI launcher script:
|
| 168 |
+
|
| 169 |
+
```bash
|
| 170 |
+
# Show interactive menu with all launch options
|
| 171 |
+
./start-automaker.sh
|
| 172 |
+
|
| 173 |
+
# Or launch directly without menu
|
| 174 |
+
./start-automaker.sh web # Web browser
|
| 175 |
+
./start-automaker.sh electron # Desktop app
|
| 176 |
+
./start-automaker.sh electron-debug # Desktop + DevTools
|
| 177 |
+
|
| 178 |
+
# Additional options
|
| 179 |
+
./start-automaker.sh --help # Show all available options
|
| 180 |
+
./start-automaker.sh --version # Show version information
|
| 181 |
+
./start-automaker.sh --check-deps # Verify project dependencies
|
| 182 |
+
./start-automaker.sh --no-colors # Disable colored output
|
| 183 |
+
./start-automaker.sh --no-history # Don't remember last choice
|
| 184 |
+
```
|
| 185 |
+
|
| 186 |
+
**Features:**
|
| 187 |
+
|
| 188 |
+
- 🎨 Beautiful terminal UI with gradient colors and ASCII art
|
| 189 |
+
- ⌨️ Interactive menu (press 1-3 to select, Q to exit)
|
| 190 |
+
- 💾 Remembers your last choice
|
| 191 |
+
- ✅ Pre-flight checks (validates Node.js, npm, dependencies)
|
| 192 |
+
- 📏 Responsive layout (adapts to terminal size)
|
| 193 |
+
- ⏱️ 30-second timeout for hands-free selection
|
| 194 |
+
- 🌐 Cross-shell compatible (bash/zsh)
|
| 195 |
+
|
| 196 |
+
**History File:**
|
| 197 |
+
Your last selected mode is saved in `~/.automaker_launcher_history` for quick re-runs.
|
| 198 |
+
|
| 199 |
+
### Building for Production
|
| 200 |
+
|
| 201 |
+
#### Web Application
|
| 202 |
+
|
| 203 |
+
```bash
|
| 204 |
+
# Build for web deployment (uses Vite)
|
| 205 |
+
npm run build
|
| 206 |
+
```
|
| 207 |
+
|
| 208 |
+
#### Desktop Application
|
| 209 |
+
|
| 210 |
+
```bash
|
| 211 |
+
# Build for current platform (macOS/Windows/Linux)
|
| 212 |
+
npm run build:electron
|
| 213 |
+
|
| 214 |
+
# Platform-specific builds
|
| 215 |
+
npm run build:electron:mac # macOS (DMG + ZIP, x64 + arm64)
|
| 216 |
+
npm run build:electron:win # Windows (NSIS installer, x64)
|
| 217 |
+
npm run build:electron:linux # Linux (AppImage + DEB + RPM, x64)
|
| 218 |
+
|
| 219 |
+
# Output directory: apps/ui/release/
|
| 220 |
+
```
|
| 221 |
+
|
| 222 |
+
**Linux Distribution Packages:**
|
| 223 |
+
|
| 224 |
+
- **AppImage**: Universal format, works on any Linux distribution
|
| 225 |
+
- **DEB**: Ubuntu, Debian, Linux Mint, Pop!\_OS
|
| 226 |
+
- **RPM**: Fedora, RHEL, Rocky Linux, AlmaLinux, openSUSE
|
| 227 |
+
|
| 228 |
+
**Installing on Fedora/RHEL:**
|
| 229 |
+
|
| 230 |
+
```bash
|
| 231 |
+
# Download the RPM package
|
| 232 |
+
wget https://github.com/AutoMaker-Org/automaker/releases/latest/download/Automaker-<version>-x86_64.rpm
|
| 233 |
+
|
| 234 |
+
# Install with dnf (Fedora)
|
| 235 |
+
sudo dnf install ./Automaker-<version>-x86_64.rpm
|
| 236 |
+
|
| 237 |
+
# Or with yum (RHEL/CentOS)
|
| 238 |
+
sudo yum localinstall ./Automaker-<version>-x86_64.rpm
|
| 239 |
+
```
|
| 240 |
+
|
| 241 |
+
#### Docker Deployment
|
| 242 |
+
|
| 243 |
+
Docker provides the most secure way to run Automaker by isolating it from your host filesystem.
|
| 244 |
+
|
| 245 |
+
```bash
|
| 246 |
+
# Build and run with Docker Compose
|
| 247 |
+
docker-compose up -d
|
| 248 |
+
|
| 249 |
+
# Access UI at http://localhost:3007
|
| 250 |
+
# API at http://localhost:3008
|
| 251 |
+
|
| 252 |
+
# View logs
|
| 253 |
+
docker-compose logs -f
|
| 254 |
+
|
| 255 |
+
# Stop containers
|
| 256 |
+
docker-compose down
|
| 257 |
+
```
|
| 258 |
+
|
| 259 |
+
##### Authentication
|
| 260 |
+
|
| 261 |
+
Automaker integrates with your authenticated Claude Code CLI. To use CLI authentication in Docker, mount your Claude CLI config directory (see [Claude CLI Authentication](#claude-cli-authentication) below).
|
| 262 |
+
|
| 263 |
+
##### Working with Projects (Host Directory Access)
|
| 264 |
+
|
| 265 |
+
By default, the container is isolated from your host filesystem. To work on projects from your host machine, create a `docker-compose.override.yml` file (gitignored):
|
| 266 |
+
|
| 267 |
+
```yaml
|
| 268 |
+
services:
|
| 269 |
+
server:
|
| 270 |
+
volumes:
|
| 271 |
+
# Mount your project directories
|
| 272 |
+
- /path/to/your/project:/projects/your-project
|
| 273 |
+
```
|
| 274 |
+
|
| 275 |
+
##### Claude CLI Authentication
|
| 276 |
+
|
| 277 |
+
Mount your Claude CLI config directory to use your authenticated CLI credentials:
|
| 278 |
+
|
| 279 |
+
```yaml
|
| 280 |
+
services:
|
| 281 |
+
server:
|
| 282 |
+
volumes:
|
| 283 |
+
# Linux/macOS
|
| 284 |
+
- ~/.claude:/home/automaker/.claude
|
| 285 |
+
# Windows
|
| 286 |
+
- C:/Users/YourName/.claude:/home/automaker/.claude
|
| 287 |
+
```
|
| 288 |
+
|
| 289 |
+
**Note:** The Claude CLI config must be writable (do not use `:ro` flag) as the CLI writes debug files.
|
| 290 |
+
|
| 291 |
+
> **⚠️ Important: Linux/WSL Users**
|
| 292 |
+
>
|
| 293 |
+
> The container runs as UID 1001 by default. If your host user has a different UID (common on Linux/WSL where the first user is UID 1000), you must create a `.env` file to match your host user:
|
| 294 |
+
>
|
| 295 |
+
> ```bash
|
| 296 |
+
> # Check your UID/GID
|
| 297 |
+
> id -u # outputs your UID (e.g., 1000)
|
| 298 |
+
> id -g # outputs your GID (e.g., 1000)
|
| 299 |
+
> ```
|
| 300 |
+
>
|
| 301 |
+
> Create a `.env` file in the automaker directory:
|
| 302 |
+
>
|
| 303 |
+
> ```
|
| 304 |
+
> UID=1000
|
| 305 |
+
> GID=1000
|
| 306 |
+
> ```
|
| 307 |
+
>
|
| 308 |
+
> Then rebuild the images:
|
| 309 |
+
>
|
| 310 |
+
> ```bash
|
| 311 |
+
> docker compose build
|
| 312 |
+
> ```
|
| 313 |
+
>
|
| 314 |
+
> Without this, files written by the container will be inaccessible to your host user.
|
| 315 |
+
|
| 316 |
+
##### GitHub CLI Authentication (For Git Push/PR Operations)
|
| 317 |
+
|
| 318 |
+
To enable git push and GitHub CLI operations inside the container:
|
| 319 |
+
|
| 320 |
+
```yaml
|
| 321 |
+
services:
|
| 322 |
+
server:
|
| 323 |
+
volumes:
|
| 324 |
+
# Mount GitHub CLI config
|
| 325 |
+
# Linux/macOS
|
| 326 |
+
- ~/.config/gh:/home/automaker/.config/gh
|
| 327 |
+
# Windows
|
| 328 |
+
- 'C:/Users/YourName/AppData/Roaming/GitHub CLI:/home/automaker/.config/gh'
|
| 329 |
+
|
| 330 |
+
# Mount git config for user identity (name, email)
|
| 331 |
+
- ~/.gitconfig:/home/automaker/.gitconfig:ro
|
| 332 |
+
environment:
|
| 333 |
+
# GitHub token (required on Windows where tokens are in Credential Manager)
|
| 334 |
+
# Get your token with: gh auth token
|
| 335 |
+
- GH_TOKEN=${GH_TOKEN}
|
| 336 |
+
```
|
| 337 |
+
|
| 338 |
+
Then add `GH_TOKEN` to your `.env` file:
|
| 339 |
+
|
| 340 |
+
```bash
|
| 341 |
+
GH_TOKEN=gho_your_github_token_here
|
| 342 |
+
```
|
| 343 |
+
|
| 344 |
+
##### Complete docker-compose.override.yml Example
|
| 345 |
+
|
| 346 |
+
```yaml
|
| 347 |
+
services:
|
| 348 |
+
server:
|
| 349 |
+
volumes:
|
| 350 |
+
# Your projects
|
| 351 |
+
- /path/to/project1:/projects/project1
|
| 352 |
+
- /path/to/project2:/projects/project2
|
| 353 |
+
|
| 354 |
+
# Authentication configs
|
| 355 |
+
- ~/.claude:/home/automaker/.claude
|
| 356 |
+
- ~/.config/gh:/home/automaker/.config/gh
|
| 357 |
+
- ~/.gitconfig:/home/automaker/.gitconfig:ro
|
| 358 |
+
environment:
|
| 359 |
+
- GH_TOKEN=${GH_TOKEN}
|
| 360 |
+
```
|
| 361 |
+
|
| 362 |
+
##### Architecture Support
|
| 363 |
+
|
| 364 |
+
The Docker image supports both AMD64 and ARM64 architectures. The GitHub CLI and Claude CLI are automatically downloaded for the correct architecture during build.
|
| 365 |
+
|
| 366 |
+
##### Playwright for Automated Testing
|
| 367 |
+
|
| 368 |
+
The Docker image includes **Playwright Chromium pre-installed** for AI agent verification tests. When agents implement features in automated testing mode, they use Playwright to verify the implementation works correctly.
|
| 369 |
+
|
| 370 |
+
**No additional setup required** - Playwright verification works out of the box.
|
| 371 |
+
|
| 372 |
+
#### Optional: Persist browsers for manual updates
|
| 373 |
+
|
| 374 |
+
By default, Playwright Chromium is pre-installed in the Docker image. If you need to manually update browsers or want to persist browser installations across container restarts (not image rebuilds), you can mount a volume.
|
| 375 |
+
|
| 376 |
+
**Important:** When you first add this volume mount to an existing setup, the empty volume will override the pre-installed browsers. You must re-install them:
|
| 377 |
+
|
| 378 |
+
```bash
|
| 379 |
+
# After adding the volume mount for the first time
|
| 380 |
+
docker exec --user automaker -w /app automaker-server npx playwright install chromium
|
| 381 |
+
```
|
| 382 |
+
|
| 383 |
+
Add this to your `docker-compose.override.yml`:
|
| 384 |
+
|
| 385 |
+
```yaml
|
| 386 |
+
services:
|
| 387 |
+
server:
|
| 388 |
+
volumes:
|
| 389 |
+
- playwright-cache:/home/automaker/.cache/ms-playwright
|
| 390 |
+
|
| 391 |
+
volumes:
|
| 392 |
+
playwright-cache:
|
| 393 |
+
name: automaker-playwright-cache
|
| 394 |
+
```
|
| 395 |
+
|
| 396 |
+
**Updating browsers manually:**
|
| 397 |
+
|
| 398 |
+
```bash
|
| 399 |
+
docker exec --user automaker -w /app automaker-server npx playwright install chromium
|
| 400 |
+
```
|
| 401 |
+
|
| 402 |
+
### Testing
|
| 403 |
+
|
| 404 |
+
#### End-to-End Tests (Playwright)
|
| 405 |
+
|
| 406 |
+
```bash
|
| 407 |
+
npm run test # Headless E2E tests
|
| 408 |
+
npm run test:headed # Browser visible E2E tests
|
| 409 |
+
```
|
| 410 |
+
|
| 411 |
+
#### Unit Tests (Vitest)
|
| 412 |
+
|
| 413 |
+
```bash
|
| 414 |
+
npm run test:server # Server unit tests
|
| 415 |
+
npm run test:server:coverage # Server tests with coverage
|
| 416 |
+
npm run test:packages # All shared package tests
|
| 417 |
+
npm run test:all # Packages + server tests
|
| 418 |
+
```
|
| 419 |
+
|
| 420 |
+
#### Test Configuration
|
| 421 |
+
|
| 422 |
+
- E2E tests run on ports 3007 (UI) and 3008 (server)
|
| 423 |
+
- Automatically starts test servers before running
|
| 424 |
+
- Uses Chromium browser via Playwright
|
| 425 |
+
- Mock agent mode available in CI with `AUTOMAKER_MOCK_AGENT=true`
|
| 426 |
+
|
| 427 |
+
### Linting
|
| 428 |
+
|
| 429 |
+
```bash
|
| 430 |
+
# Run ESLint
|
| 431 |
+
npm run lint
|
| 432 |
+
```
|
| 433 |
+
|
| 434 |
+
### Environment Configuration
|
| 435 |
+
|
| 436 |
+
#### Optional - Server
|
| 437 |
+
|
| 438 |
+
- `PORT` - Server port (default: 3008)
|
| 439 |
+
- `DATA_DIR` - Data storage directory (default: ./data)
|
| 440 |
+
- `ENABLE_REQUEST_LOGGING` - HTTP request logging (default: true)
|
| 441 |
+
|
| 442 |
+
#### Optional - Security
|
| 443 |
+
|
| 444 |
+
- `AUTOMAKER_API_KEY` - Optional API authentication for the server
|
| 445 |
+
- `ALLOWED_ROOT_DIRECTORY` - Restrict file operations to specific directory
|
| 446 |
+
- `CORS_ORIGIN` - CORS allowed origins (comma-separated list; defaults to localhost only)
|
| 447 |
+
|
| 448 |
+
#### Optional - Development
|
| 449 |
+
|
| 450 |
+
- `VITE_SKIP_ELECTRON` - Skip Electron in dev mode
|
| 451 |
+
- `OPEN_DEVTOOLS` - Auto-open DevTools in Electron
|
| 452 |
+
- `AUTOMAKER_SKIP_SANDBOX_WARNING` - Skip sandbox warning dialog (useful for dev/CI)
|
| 453 |
+
- `AUTOMAKER_AUTO_LOGIN=true` - Skip login prompt in development (ignored when NODE_ENV=production)
|
| 454 |
+
|
| 455 |
+
### Authentication Setup
|
| 456 |
+
|
| 457 |
+
Automaker integrates with your authenticated Claude Code CLI and uses your Anthropic subscription.
|
| 458 |
+
|
| 459 |
+
Install and authenticate the Claude Code CLI following the [official quickstart guide](https://code.claude.com/docs/en/quickstart).
|
| 460 |
+
|
| 461 |
+
Once authenticated, Automaker will automatically detect and use your CLI credentials. No additional configuration needed!
|
| 462 |
+
|
| 463 |
+
## Features
|
| 464 |
+
|
| 465 |
+
### Core Workflow
|
| 466 |
+
|
| 467 |
+
- 📋 **Kanban Board** - Visual drag-and-drop board to manage features through backlog, in progress, waiting approval, and verified stages
|
| 468 |
+
- 🤖 **AI Agent Integration** - Automatic AI agent assignment to implement features when moved to "In Progress"
|
| 469 |
+
- 🔀 **Git Worktree Isolation** - Each feature executes in isolated git worktrees to protect your main branch
|
| 470 |
+
- 📡 **Real-time Streaming** - Watch AI agents work in real-time with live tool usage, progress updates, and task completion
|
| 471 |
+
- 🔄 **Follow-up Instructions** - Send additional instructions to running agents without stopping them
|
| 472 |
+
|
| 473 |
+
### AI & Planning
|
| 474 |
+
|
| 475 |
+
- 🧠 **Multi-Model Support** - Choose from Claude Opus, Sonnet, and Haiku per feature
|
| 476 |
+
- 💭 **Extended Thinking** - Enable thinking modes (none, medium, deep, ultra) for complex problem-solving
|
| 477 |
+
- 📝 **Planning Modes** - Four planning levels: skip (direct implementation), lite (quick plan), spec (task breakdown), full (phased execution)
|
| 478 |
+
- ✅ **Plan Approval** - Review and approve AI-generated plans before implementation begins
|
| 479 |
+
- 📊 **Multi-Agent Task Execution** - Spec mode spawns dedicated agents per task for focused implementation
|
| 480 |
+
|
| 481 |
+
### Project Management
|
| 482 |
+
|
| 483 |
+
- 🔍 **Project Analysis** - AI-powered codebase analysis to understand your project structure
|
| 484 |
+
- 💡 **Feature Suggestions** - AI-generated feature suggestions based on project analysis
|
| 485 |
+
- 📁 **Context Management** - Add markdown, images, and documentation files that agents automatically reference
|
| 486 |
+
- 🔗 **Dependency Blocking** - Features can depend on other features, enforcing execution order
|
| 487 |
+
- 🌳 **Graph View** - Visualize feature dependencies with interactive graph visualization
|
| 488 |
+
- 📋 **GitHub Integration** - Import issues, validate feasibility, and convert to tasks automatically
|
| 489 |
+
|
| 490 |
+
### Collaboration & Review
|
| 491 |
+
|
| 492 |
+
- 🧪 **Verification Workflow** - Features move to "Waiting Approval" for review and testing
|
| 493 |
+
- 💬 **Agent Chat** - Interactive chat sessions with AI agents for exploratory work
|
| 494 |
+
- 👤 **AI Profiles** - Create custom agent configurations with different prompts, models, and settings
|
| 495 |
+
- 📜 **Session History** - Persistent chat sessions across restarts with full conversation history
|
| 496 |
+
- 🔍 **Git Diff Viewer** - Review changes made by agents before approving
|
| 497 |
+
|
| 498 |
+
### Developer Tools
|
| 499 |
+
|
| 500 |
+
- 🖥️ **Integrated Terminal** - Full terminal access with tabs, splits, and persistent sessions
|
| 501 |
+
- 🖼️ **Image Support** - Attach screenshots and diagrams to feature descriptions for visual context
|
| 502 |
+
- ⚡ **Concurrent Execution** - Configure how many features can run simultaneously (default: 3)
|
| 503 |
+
- ⌨️ **Keyboard Shortcuts** - Fully customizable shortcuts for navigation and actions
|
| 504 |
+
- 🎨 **Theme System** - 25+ themes including Dark, Light, Dracula, Nord, Catppuccin, and more
|
| 505 |
+
- 🖥️ **Cross-Platform** - Desktop app for macOS (x64, arm64), Windows (x64), and Linux (x64)
|
| 506 |
+
- 🌐 **Web Mode** - Run in browser or as Electron desktop app
|
| 507 |
+
|
| 508 |
+
### Advanced Features
|
| 509 |
+
|
| 510 |
+
- 🔐 **Docker Isolation** - Security-focused Docker deployment with no host filesystem access
|
| 511 |
+
- 🎯 **Worktree Management** - Create, switch, commit, and create PRs from worktrees
|
| 512 |
+
- 📊 **Usage Tracking** - Monitor Claude API usage with detailed metrics
|
| 513 |
+
- 🔊 **Audio Notifications** - Optional completion sounds (mutable in settings)
|
| 514 |
+
- 💾 **Auto-save** - All work automatically persisted to `.automaker/` directory
|
| 515 |
+
|
| 516 |
+
## Tech Stack
|
| 517 |
+
|
| 518 |
+
### Frontend
|
| 519 |
+
|
| 520 |
+
- **React 19** - UI framework
|
| 521 |
+
- **Vite 7** - Build tool and development server
|
| 522 |
+
- **Electron 39** - Desktop application framework
|
| 523 |
+
- **TypeScript 5.9** - Type safety
|
| 524 |
+
- **TanStack Router** - File-based routing
|
| 525 |
+
- **Zustand 5** - State management with persistence
|
| 526 |
+
- **Tailwind CSS 4** - Utility-first styling with 25+ themes
|
| 527 |
+
- **Radix UI** - Accessible component primitives
|
| 528 |
+
- **dnd-kit** - Drag and drop for Kanban board
|
| 529 |
+
- **@xyflow/react** - Graph visualization for dependencies
|
| 530 |
+
- **xterm.js** - Integrated terminal emulator
|
| 531 |
+
- **CodeMirror 6** - Code editor for XML/syntax highlighting
|
| 532 |
+
- **Lucide Icons** - Icon library
|
| 533 |
+
|
| 534 |
+
### Backend
|
| 535 |
+
|
| 536 |
+
- **Node.js** - JavaScript runtime with ES modules
|
| 537 |
+
- **Express 5** - HTTP server framework
|
| 538 |
+
- **TypeScript 5.9** - Type safety
|
| 539 |
+
- **Claude Agent SDK** - AI agent integration (@anthropic-ai/claude-agent-sdk)
|
| 540 |
+
- **WebSocket (ws)** - Real-time event streaming
|
| 541 |
+
- **node-pty** - PTY terminal sessions
|
| 542 |
+
|
| 543 |
+
### Testing & Quality
|
| 544 |
+
|
| 545 |
+
- **Playwright** - End-to-end testing
|
| 546 |
+
- **Vitest** - Unit testing framework
|
| 547 |
+
- **ESLint 9** - Code linting
|
| 548 |
+
- **Prettier 3** - Code formatting
|
| 549 |
+
- **Husky** - Git hooks for pre-commit formatting
|
| 550 |
+
|
| 551 |
+
### Shared Libraries
|
| 552 |
+
|
| 553 |
+
- **@automaker/types** - Shared TypeScript definitions
|
| 554 |
+
- **@automaker/utils** - Logging, error handling, image processing
|
| 555 |
+
- **@automaker/prompts** - AI prompt templates
|
| 556 |
+
- **@automaker/platform** - Path management and security
|
| 557 |
+
- **@automaker/model-resolver** - Claude model alias resolution
|
| 558 |
+
- **@automaker/dependency-resolver** - Feature dependency ordering
|
| 559 |
+
- **@automaker/git-utils** - Git operations and worktree management
|
| 560 |
+
|
| 561 |
+
## Available Views
|
| 562 |
+
|
| 563 |
+
Automaker provides several specialized views accessible via the sidebar or keyboard shortcuts:
|
| 564 |
+
|
| 565 |
+
| View | Shortcut | Description |
|
| 566 |
+
| ------------------ | -------- | ------------------------------------------------------------------------------------------------ |
|
| 567 |
+
| **Board** | `K` | Kanban board for managing feature workflow (Backlog → In Progress → Waiting Approval → Verified) |
|
| 568 |
+
| **Agent** | `A` | Interactive chat sessions with AI agents for exploratory work and questions |
|
| 569 |
+
| **Spec** | `D` | Project specification editor with AI-powered generation and feature suggestions |
|
| 570 |
+
| **Context** | `C` | Manage context files (markdown, images) that AI agents automatically reference |
|
| 571 |
+
| **Settings** | `S` | Configure themes, shortcuts, defaults, authentication, and more |
|
| 572 |
+
| **Terminal** | `T` | Integrated terminal with tabs, splits, and persistent sessions |
|
| 573 |
+
| **Graph** | `H` | Visualize feature dependencies with interactive graph visualization |
|
| 574 |
+
| **Ideation** | `I` | Brainstorm and generate ideas with AI assistance |
|
| 575 |
+
| **Memory** | `Y` | View and manage agent memory and conversation history |
|
| 576 |
+
| **GitHub Issues** | `G` | Import and validate GitHub issues, convert to tasks |
|
| 577 |
+
| **GitHub PRs** | `R` | View and manage GitHub pull requests |
|
| 578 |
+
| **Running Agents** | - | View all active agents across projects with status and progress |
|
| 579 |
+
|
| 580 |
+
### Keyboard Navigation
|
| 581 |
+
|
| 582 |
+
All shortcuts are customizable in Settings. Default shortcuts:
|
| 583 |
+
|
| 584 |
+
- **Navigation:** `K` (Board), `A` (Agent), `D` (Spec), `C` (Context), `S` (Settings), `T` (Terminal), `H` (Graph), `I` (Ideation), `Y` (Memory), `G` (GitHub Issues), `R` (GitHub PRs)
|
| 585 |
+
- **UI:** `` ` `` (Toggle sidebar)
|
| 586 |
+
- **Actions:** `N` (New item in current view), `O` (Open project), `P` (Project picker)
|
| 587 |
+
- **Projects:** `Q`/`E` (Cycle previous/next project)
|
| 588 |
+
- **Terminal:** `Alt+D` (Split right), `Alt+S` (Split down), `Alt+W` (Close), `Alt+T` (New tab)
|
| 589 |
+
|
| 590 |
+
## Architecture
|
| 591 |
+
|
| 592 |
+
### Monorepo Structure
|
| 593 |
+
|
| 594 |
+
Automaker is built as an npm workspace monorepo with two main applications and seven shared packages:
|
| 595 |
+
|
| 596 |
+
```text
|
| 597 |
+
automaker/
|
| 598 |
+
├── apps/
|
| 599 |
+
│ ├── ui/ # React + Vite + Electron frontend
|
| 600 |
+
│ └── server/ # Express + WebSocket backend
|
| 601 |
+
└── libs/ # Shared packages
|
| 602 |
+
├── types/ # Core TypeScript definitions
|
| 603 |
+
├── utils/ # Logging, errors, utilities
|
| 604 |
+
├── prompts/ # AI prompt templates
|
| 605 |
+
├── platform/ # Path management, security
|
| 606 |
+
├── model-resolver/ # Claude model aliasing
|
| 607 |
+
├── dependency-resolver/ # Feature dependency ordering
|
| 608 |
+
└── git-utils/ # Git operations & worktree management
|
| 609 |
+
```
|
| 610 |
+
|
| 611 |
+
### How It Works
|
| 612 |
+
|
| 613 |
+
1. **Feature Definition** - Users create feature cards on the Kanban board with descriptions, images, and configuration
|
| 614 |
+
2. **Git Worktree Creation** - When a feature starts, a git worktree is created for isolated development
|
| 615 |
+
3. **Agent Execution** - Claude Agent SDK executes in the worktree with full file system and command access
|
| 616 |
+
4. **Real-time Streaming** - Agent output streams via WebSocket to the frontend for live monitoring
|
| 617 |
+
5. **Plan Approval** (optional) - For spec/full planning modes, agents generate plans that require user approval
|
| 618 |
+
6. **Multi-Agent Tasks** (spec mode) - Each task in the spec gets a dedicated agent for focused implementation
|
| 619 |
+
7. **Verification** - Features move to "Waiting Approval" where changes can be reviewed via git diff
|
| 620 |
+
8. **Integration** - After approval, changes can be committed and PRs created from the worktree
|
| 621 |
+
|
| 622 |
+
### Key Architectural Patterns
|
| 623 |
+
|
| 624 |
+
- **Event-Driven Architecture** - All server operations emit events that stream to the frontend
|
| 625 |
+
- **Provider Pattern** - Extensible AI provider system (currently Claude, designed for future providers)
|
| 626 |
+
- **Service-Oriented Backend** - Modular services for agent management, features, terminals, settings
|
| 627 |
+
- **State Management** - Zustand with persistence for frontend state across restarts
|
| 628 |
+
- **File-Based Storage** - No database; features stored as JSON files in `.automaker/` directory
|
| 629 |
+
|
| 630 |
+
### Security & Isolation
|
| 631 |
+
|
| 632 |
+
- **Git Worktrees** - Each feature executes in an isolated git worktree, protecting your main branch
|
| 633 |
+
- **Path Sandboxing** - Optional `ALLOWED_ROOT_DIRECTORY` restricts file access
|
| 634 |
+
- **Docker Isolation** - Recommended deployment uses Docker with no host filesystem access
|
| 635 |
+
- **Plan Approval** - Optional plan review before implementation prevents unwanted changes
|
| 636 |
+
|
| 637 |
+
### Data Storage
|
| 638 |
+
|
| 639 |
+
Automaker uses a file-based storage system (no database required):
|
| 640 |
+
|
| 641 |
+
#### Per-Project Data
|
| 642 |
+
|
| 643 |
+
Stored in `{projectPath}/.automaker/`:
|
| 644 |
+
|
| 645 |
+
```text
|
| 646 |
+
.automaker/
|
| 647 |
+
├── features/ # Feature JSON files and images
|
| 648 |
+
│ └── {featureId}/
|
| 649 |
+
│ ├── feature.json # Feature metadata
|
| 650 |
+
│ ├── agent-output.md # AI agent output log
|
| 651 |
+
│ └── images/ # Attached images
|
| 652 |
+
├── context/ # Context files for AI agents
|
| 653 |
+
├── worktrees/ # Git worktree metadata
|
| 654 |
+
├── validations/ # GitHub issue validation results
|
| 655 |
+
├── ideation/ # Brainstorming and analysis data
|
| 656 |
+
│ └── analysis.json # Project structure analysis
|
| 657 |
+
├── board/ # Board-related data
|
| 658 |
+
├── images/ # Project-level images
|
| 659 |
+
├── settings.json # Project-specific settings
|
| 660 |
+
├── app_spec.txt # Project specification (XML format)
|
| 661 |
+
├── active-branches.json # Active git branches tracking
|
| 662 |
+
└── execution-state.json # Auto-mode execution state
|
| 663 |
+
```
|
| 664 |
+
|
| 665 |
+
#### Global Data
|
| 666 |
+
|
| 667 |
+
Stored in `DATA_DIR` (default `./data`):
|
| 668 |
+
|
| 669 |
+
```text
|
| 670 |
+
data/
|
| 671 |
+
├── settings.json # Global settings, profiles, shortcuts
|
| 672 |
+
├── credentials.json # API keys (encrypted)
|
| 673 |
+
├── sessions-metadata.json # Chat session metadata
|
| 674 |
+
└── agent-sessions/ # Conversation histories
|
| 675 |
+
└── {sessionId}.json
|
| 676 |
+
```
|
| 677 |
+
|
| 678 |
+
---
|
| 679 |
+
|
| 680 |
+
> **[!CAUTION]**
|
| 681 |
+
>
|
| 682 |
+
> ## Security Disclaimer
|
| 683 |
+
>
|
| 684 |
+
> **This software uses AI-powered tooling that has access to your operating system and can read, modify, and delete files. Use at your own risk.**
|
| 685 |
+
>
|
| 686 |
+
> We have reviewed this codebase for security vulnerabilities, but you assume all risk when running this software. You should review the code yourself before running it.
|
| 687 |
+
>
|
| 688 |
+
> **We do not recommend running Automaker directly on your local computer** due to the risk of AI agents having access to your entire file system. Please sandbox this application using Docker or a virtual machine.
|
| 689 |
+
>
|
| 690 |
+
> **[Read the full disclaimer](./DISCLAIMER.md)**
|
| 691 |
+
|
| 692 |
+
---
|
| 693 |
+
|
| 694 |
+
## Learn More
|
| 695 |
+
|
| 696 |
+
### Documentation
|
| 697 |
+
|
| 698 |
+
- [Contributing Guide](./CONTRIBUTING.md) - How to contribute to Automaker
|
| 699 |
+
- [Project Documentation](./docs/) - Architecture guides, patterns, and developer docs
|
| 700 |
+
- [Shared Packages Guide](./docs/llm-shared-packages.md) - Using monorepo packages
|
| 701 |
+
|
| 702 |
+
### Community
|
| 703 |
+
|
| 704 |
+
Join the **Agentic Jumpstart** Discord to connect with other builders exploring **agentic coding**:
|
| 705 |
+
|
| 706 |
+
👉 [Agentic Jumpstart Discord](https://discord.gg/jjem7aEDKU)
|
| 707 |
+
|
| 708 |
+
## Project Status
|
| 709 |
+
|
| 710 |
+
**This project is no longer actively maintained.** The codebase is provided as-is for those who wish to use, study, or fork it. No bug fixes, security updates, or new features are being developed. Community contributions may still be accepted, but there is no guarantee of review or merge.
|
| 711 |
+
|
| 712 |
+
## License
|
| 713 |
+
|
| 714 |
+
This project is licensed under the **MIT License**. See [LICENSE](LICENSE) for the full text.
|
jules_branch/apps/server/.env.example
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Automaker Server Configuration
|
| 2 |
+
# Copy this file to .env and configure your settings
|
| 3 |
+
|
| 4 |
+
# ============================================
|
| 5 |
+
# REQUIRED
|
| 6 |
+
# ============================================
|
| 7 |
+
|
| 8 |
+
# Your Anthropic API key for Claude models
|
| 9 |
+
ANTHROPIC_API_KEY=sk-ant-...
|
| 10 |
+
|
| 11 |
+
# ============================================
|
| 12 |
+
# OPTIONAL - Additional API Keys
|
| 13 |
+
# ============================================
|
| 14 |
+
|
| 15 |
+
# OpenAI API key for Codex/GPT models
|
| 16 |
+
OPENAI_API_KEY=sk-...
|
| 17 |
+
|
| 18 |
+
# Cursor API key for Cursor models
|
| 19 |
+
CURSOR_API_KEY=...
|
| 20 |
+
|
| 21 |
+
# OAuth credentials for CLI authentication (extracted automatically)
|
| 22 |
+
CLAUDE_OAUTH_CREDENTIALS=
|
| 23 |
+
CURSOR_AUTH_TOKEN=
|
| 24 |
+
|
| 25 |
+
# ============================================
|
| 26 |
+
# OPTIONAL - Security
|
| 27 |
+
# ============================================
|
| 28 |
+
|
| 29 |
+
# API key for authenticating requests (leave empty to disable auth)
|
| 30 |
+
# If set, all API requests must include X-API-Key header
|
| 31 |
+
AUTOMAKER_API_KEY=
|
| 32 |
+
|
| 33 |
+
# Root directory for projects and file operations
|
| 34 |
+
# If set, users can only create/open projects and files within this directory
|
| 35 |
+
# Recommended for sandboxed deployments (Docker, restricted environments)
|
| 36 |
+
# Example: ALLOWED_ROOT_DIRECTORY=/projects
|
| 37 |
+
ALLOWED_ROOT_DIRECTORY=
|
| 38 |
+
|
| 39 |
+
# CORS origin - which domains can access the API
|
| 40 |
+
# Use "*" for development, set specific origin for production
|
| 41 |
+
CORS_ORIGIN=http://localhost:3007
|
| 42 |
+
|
| 43 |
+
# ============================================
|
| 44 |
+
# OPTIONAL - Server
|
| 45 |
+
# ============================================
|
| 46 |
+
|
| 47 |
+
# Host to bind the server to (default: 0.0.0.0)
|
| 48 |
+
# Use 0.0.0.0 to listen on all interfaces (recommended for Docker/remote access)
|
| 49 |
+
# Use 127.0.0.1 or localhost to restrict to local connections only
|
| 50 |
+
HOST=0.0.0.0
|
| 51 |
+
|
| 52 |
+
# Port to run the server on
|
| 53 |
+
PORT=3008
|
| 54 |
+
|
| 55 |
+
# Port to run the server on for testing
|
| 56 |
+
TEST_SERVER_PORT=3108
|
| 57 |
+
|
| 58 |
+
# Port to run the UI on for testing
|
| 59 |
+
TEST_PORT=3107
|
| 60 |
+
|
| 61 |
+
# Data directory for sessions and metadata
|
| 62 |
+
DATA_DIR=./data
|
| 63 |
+
|
| 64 |
+
# ============================================
|
| 65 |
+
# OPTIONAL - Terminal Access
|
| 66 |
+
# ============================================
|
| 67 |
+
|
| 68 |
+
# Enable/disable terminal access (default: true)
|
| 69 |
+
TERMINAL_ENABLED=true
|
| 70 |
+
|
| 71 |
+
# Password to protect terminal access (leave empty for no password)
|
| 72 |
+
# If set, users must enter this password before accessing terminal
|
| 73 |
+
TERMINAL_PASSWORD=
|
| 74 |
+
|
| 75 |
+
ENABLE_REQUEST_LOGGING=false
|
| 76 |
+
|
| 77 |
+
# ============================================
|
| 78 |
+
# OPTIONAL - UI Behavior
|
| 79 |
+
# ============================================
|
| 80 |
+
|
| 81 |
+
# Skip the sandbox warning dialog on startup (default: false)
|
| 82 |
+
# Set to "true" to disable the warning entirely (useful for dev/CI environments)
|
| 83 |
+
AUTOMAKER_SKIP_SANDBOX_WARNING=false
|
| 84 |
+
|
| 85 |
+
# ============================================
|
| 86 |
+
# OPTIONAL - Debugging
|
| 87 |
+
# ============================================
|
| 88 |
+
|
| 89 |
+
# Enable raw output logging for agent streams (default: false)
|
| 90 |
+
# When enabled, saves unprocessed stream events to raw-output.jsonl
|
| 91 |
+
# in each feature's directory (.automaker/features/{id}/raw-output.jsonl)
|
| 92 |
+
# Useful for debugging provider streaming issues, improving log parsing,
|
| 93 |
+
# or analyzing how different providers (Claude, Cursor) stream responses
|
| 94 |
+
# Note: This adds disk I/O overhead, only enable when debugging
|
| 95 |
+
AUTOMAKER_DEBUG_RAW_OUTPUT=false
|
jules_branch/apps/server/.gitignore
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
.env
|
| 2 |
+
data
|
| 3 |
+
node_modules
|
| 4 |
+
coverage
|
jules_branch/apps/server/eslint.config.mjs
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import { defineConfig, globalIgnores } from 'eslint/config';
|
| 2 |
+
import js from '@eslint/js';
|
| 3 |
+
import ts from '@typescript-eslint/eslint-plugin';
|
| 4 |
+
import tsParser from '@typescript-eslint/parser';
|
| 5 |
+
|
| 6 |
+
const eslintConfig = defineConfig([
|
| 7 |
+
js.configs.recommended,
|
| 8 |
+
{
|
| 9 |
+
files: ['**/*.ts'],
|
| 10 |
+
languageOptions: {
|
| 11 |
+
parser: tsParser,
|
| 12 |
+
parserOptions: {
|
| 13 |
+
ecmaVersion: 'latest',
|
| 14 |
+
sourceType: 'module',
|
| 15 |
+
},
|
| 16 |
+
globals: {
|
| 17 |
+
// Node.js globals
|
| 18 |
+
console: 'readonly',
|
| 19 |
+
process: 'readonly',
|
| 20 |
+
Buffer: 'readonly',
|
| 21 |
+
__dirname: 'readonly',
|
| 22 |
+
__filename: 'readonly',
|
| 23 |
+
URL: 'readonly',
|
| 24 |
+
URLSearchParams: 'readonly',
|
| 25 |
+
AbortController: 'readonly',
|
| 26 |
+
AbortSignal: 'readonly',
|
| 27 |
+
fetch: 'readonly',
|
| 28 |
+
Response: 'readonly',
|
| 29 |
+
Request: 'readonly',
|
| 30 |
+
Headers: 'readonly',
|
| 31 |
+
FormData: 'readonly',
|
| 32 |
+
RequestInit: 'readonly',
|
| 33 |
+
// Timers
|
| 34 |
+
setTimeout: 'readonly',
|
| 35 |
+
setInterval: 'readonly',
|
| 36 |
+
clearTimeout: 'readonly',
|
| 37 |
+
clearInterval: 'readonly',
|
| 38 |
+
setImmediate: 'readonly',
|
| 39 |
+
clearImmediate: 'readonly',
|
| 40 |
+
queueMicrotask: 'readonly',
|
| 41 |
+
// Node.js types
|
| 42 |
+
NodeJS: 'readonly',
|
| 43 |
+
},
|
| 44 |
+
},
|
| 45 |
+
plugins: {
|
| 46 |
+
'@typescript-eslint': ts,
|
| 47 |
+
},
|
| 48 |
+
rules: {
|
| 49 |
+
...ts.configs.recommended.rules,
|
| 50 |
+
'@typescript-eslint/no-unused-vars': [
|
| 51 |
+
'warn',
|
| 52 |
+
{
|
| 53 |
+
argsIgnorePattern: '^_',
|
| 54 |
+
varsIgnorePattern: '^_',
|
| 55 |
+
caughtErrorsIgnorePattern: '^_',
|
| 56 |
+
ignoreRestSiblings: true,
|
| 57 |
+
},
|
| 58 |
+
],
|
| 59 |
+
'@typescript-eslint/no-explicit-any': 'warn',
|
| 60 |
+
// Server code frequently works with terminal output containing ANSI escape codes
|
| 61 |
+
'no-control-regex': 'off',
|
| 62 |
+
'@typescript-eslint/ban-ts-comment': [
|
| 63 |
+
'error',
|
| 64 |
+
{
|
| 65 |
+
'ts-nocheck': 'allow-with-description',
|
| 66 |
+
minimumDescriptionLength: 10,
|
| 67 |
+
},
|
| 68 |
+
],
|
| 69 |
+
},
|
| 70 |
+
},
|
| 71 |
+
globalIgnores(['dist/**', 'node_modules/**']),
|
| 72 |
+
]);
|
| 73 |
+
|
| 74 |
+
export default eslintConfig;
|
jules_branch/apps/server/package.json
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"name": "@automaker/server",
|
| 3 |
+
"version": "1.0.0",
|
| 4 |
+
"description": "Backend server for Automaker - provides API for both web and Electron modes",
|
| 5 |
+
"author": "AutoMaker Team",
|
| 6 |
+
"license": "SEE LICENSE IN LICENSE",
|
| 7 |
+
"private": true,
|
| 8 |
+
"engines": {
|
| 9 |
+
"node": ">=22.0.0 <23.0.0"
|
| 10 |
+
},
|
| 11 |
+
"type": "module",
|
| 12 |
+
"main": "dist/index.js",
|
| 13 |
+
"scripts": {
|
| 14 |
+
"dev": "tsx watch src/index.ts",
|
| 15 |
+
"dev:test": "tsx src/index.ts",
|
| 16 |
+
"build": "tsc",
|
| 17 |
+
"start": "node dist/index.js",
|
| 18 |
+
"lint": "eslint src/",
|
| 19 |
+
"test": "vitest",
|
| 20 |
+
"test:ui": "vitest --ui",
|
| 21 |
+
"test:run": "vitest run",
|
| 22 |
+
"test:cov": "vitest run --coverage",
|
| 23 |
+
"test:watch": "vitest watch",
|
| 24 |
+
"test:unit": "vitest run tests/unit"
|
| 25 |
+
},
|
| 26 |
+
"dependencies": {
|
| 27 |
+
"@anthropic-ai/claude-agent-sdk": "0.2.32",
|
| 28 |
+
"@automaker/dependency-resolver": "1.0.0",
|
| 29 |
+
"@automaker/git-utils": "1.0.0",
|
| 30 |
+
"@automaker/model-resolver": "1.0.0",
|
| 31 |
+
"@automaker/platform": "1.0.0",
|
| 32 |
+
"@automaker/prompts": "1.0.0",
|
| 33 |
+
"@automaker/types": "1.0.0",
|
| 34 |
+
"@automaker/utils": "1.0.0",
|
| 35 |
+
"@github/copilot-sdk": "0.1.16",
|
| 36 |
+
"@modelcontextprotocol/sdk": "1.25.2",
|
| 37 |
+
"@openai/codex-sdk": "^0.98.0",
|
| 38 |
+
"cookie-parser": "1.4.7",
|
| 39 |
+
"cors": "2.8.5",
|
| 40 |
+
"dotenv": "17.2.3",
|
| 41 |
+
"express": "5.2.1",
|
| 42 |
+
"morgan": "1.10.1",
|
| 43 |
+
"node-pty": "1.1.0-beta41",
|
| 44 |
+
"ws": "8.18.3",
|
| 45 |
+
"yaml": "2.7.0"
|
| 46 |
+
},
|
| 47 |
+
"devDependencies": {
|
| 48 |
+
"@playwright/test": "1.57.0",
|
| 49 |
+
"@types/cookie": "0.6.0",
|
| 50 |
+
"@types/cookie-parser": "1.4.10",
|
| 51 |
+
"@types/cors": "2.8.19",
|
| 52 |
+
"@types/express": "5.0.6",
|
| 53 |
+
"@types/morgan": "1.9.10",
|
| 54 |
+
"@types/node": "22.19.3",
|
| 55 |
+
"@types/ws": "8.18.1",
|
| 56 |
+
"@vitest/coverage-v8": "4.0.16",
|
| 57 |
+
"@vitest/ui": "4.0.16",
|
| 58 |
+
"tsx": "4.21.0",
|
| 59 |
+
"typescript": "5.9.3",
|
| 60 |
+
"vitest": "4.0.16"
|
| 61 |
+
}
|
| 62 |
+
}
|
jules_branch/apps/server/src/index.ts
ADDED
|
@@ -0,0 +1,979 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/**
|
| 2 |
+
* Automaker Backend Server
|
| 3 |
+
*
|
| 4 |
+
* Provides HTTP/WebSocket API for both web and Electron modes.
|
| 5 |
+
* In Electron mode, this server runs locally.
|
| 6 |
+
* In web mode, this server runs on a remote host.
|
| 7 |
+
*/
|
| 8 |
+
|
| 9 |
+
import express from 'express';
|
| 10 |
+
import cors from 'cors';
|
| 11 |
+
import morgan from 'morgan';
|
| 12 |
+
import cookieParser from 'cookie-parser';
|
| 13 |
+
import cookie from 'cookie';
|
| 14 |
+
import { WebSocketServer, WebSocket } from 'ws';
|
| 15 |
+
import { createServer } from 'http';
|
| 16 |
+
import dotenv from 'dotenv';
|
| 17 |
+
|
| 18 |
+
import { createEventEmitter, type EventEmitter } from './lib/events.js';
|
| 19 |
+
import { initAllowedPaths, getClaudeAuthIndicators } from '@automaker/platform';
|
| 20 |
+
import { createLogger, setLogLevel, LogLevel } from '@automaker/utils';
|
| 21 |
+
|
| 22 |
+
const logger = createLogger('Server');
|
| 23 |
+
|
| 24 |
+
/**
|
| 25 |
+
* Map server log level string to LogLevel enum
|
| 26 |
+
*/
|
| 27 |
+
const LOG_LEVEL_MAP: Record<string, LogLevel> = {
|
| 28 |
+
error: LogLevel.ERROR,
|
| 29 |
+
warn: LogLevel.WARN,
|
| 30 |
+
info: LogLevel.INFO,
|
| 31 |
+
debug: LogLevel.DEBUG,
|
| 32 |
+
};
|
| 33 |
+
import { authMiddleware, validateWsConnectionToken, checkRawAuthentication } from './lib/auth.js';
|
| 34 |
+
import { requireJsonContentType } from './middleware/require-json-content-type.js';
|
| 35 |
+
import { createAuthRoutes } from './routes/auth/index.js';
|
| 36 |
+
import { createFsRoutes } from './routes/fs/index.js';
|
| 37 |
+
import { createHealthRoutes, createDetailedHandler } from './routes/health/index.js';
|
| 38 |
+
import { createAgentRoutes } from './routes/agent/index.js';
|
| 39 |
+
import { createSessionsRoutes } from './routes/sessions/index.js';
|
| 40 |
+
import { createFeaturesRoutes } from './routes/features/index.js';
|
| 41 |
+
import { createAutoModeRoutes } from './routes/auto-mode/index.js';
|
| 42 |
+
import { createEnhancePromptRoutes } from './routes/enhance-prompt/index.js';
|
| 43 |
+
import { createWorktreeRoutes } from './routes/worktree/index.js';
|
| 44 |
+
import { createGitRoutes } from './routes/git/index.js';
|
| 45 |
+
import { createSetupRoutes } from './routes/setup/index.js';
|
| 46 |
+
import { createModelsRoutes } from './routes/models/index.js';
|
| 47 |
+
import { createRunningAgentsRoutes } from './routes/running-agents/index.js';
|
| 48 |
+
import { createWorkspaceRoutes } from './routes/workspace/index.js';
|
| 49 |
+
import { createTemplatesRoutes } from './routes/templates/index.js';
|
| 50 |
+
import {
|
| 51 |
+
createTerminalRoutes,
|
| 52 |
+
validateTerminalToken,
|
| 53 |
+
isTerminalEnabled,
|
| 54 |
+
isTerminalPasswordRequired,
|
| 55 |
+
} from './routes/terminal/index.js';
|
| 56 |
+
import { createSettingsRoutes } from './routes/settings/index.js';
|
| 57 |
+
import { AgentService } from './services/agent-service.js';
|
| 58 |
+
import { FeatureLoader } from './services/feature-loader.js';
|
| 59 |
+
import { AutoModeServiceCompat } from './services/auto-mode/index.js';
|
| 60 |
+
import { getTerminalService } from './services/terminal-service.js';
|
| 61 |
+
import { SettingsService } from './services/settings-service.js';
|
| 62 |
+
import { createSpecRegenerationRoutes } from './routes/app-spec/index.js';
|
| 63 |
+
import { createClaudeRoutes } from './routes/claude/index.js';
|
| 64 |
+
import { ClaudeUsageService } from './services/claude-usage-service.js';
|
| 65 |
+
import { createCodexRoutes } from './routes/codex/index.js';
|
| 66 |
+
import { CodexUsageService } from './services/codex-usage-service.js';
|
| 67 |
+
import { CodexAppServerService } from './services/codex-app-server-service.js';
|
| 68 |
+
import { CodexModelCacheService } from './services/codex-model-cache-service.js';
|
| 69 |
+
import { createZaiRoutes } from './routes/zai/index.js';
|
| 70 |
+
import { ZaiUsageService } from './services/zai-usage-service.js';
|
| 71 |
+
import { createGeminiRoutes } from './routes/gemini/index.js';
|
| 72 |
+
import { GeminiUsageService } from './services/gemini-usage-service.js';
|
| 73 |
+
import { createGitHubRoutes } from './routes/github/index.js';
|
| 74 |
+
import { createContextRoutes } from './routes/context/index.js';
|
| 75 |
+
import { createBacklogPlanRoutes } from './routes/backlog-plan/index.js';
|
| 76 |
+
import { cleanupStaleValidations } from './routes/github/routes/validation-common.js';
|
| 77 |
+
import { createMCPRoutes } from './routes/mcp/index.js';
|
| 78 |
+
import { MCPTestService } from './services/mcp-test-service.js';
|
| 79 |
+
import { createPipelineRoutes } from './routes/pipeline/index.js';
|
| 80 |
+
import { pipelineService } from './services/pipeline-service.js';
|
| 81 |
+
import { createIdeationRoutes } from './routes/ideation/index.js';
|
| 82 |
+
import { IdeationService } from './services/ideation-service.js';
|
| 83 |
+
import { getDevServerService } from './services/dev-server-service.js';
|
| 84 |
+
import { eventHookService } from './services/event-hook-service.js';
|
| 85 |
+
import { createNotificationsRoutes } from './routes/notifications/index.js';
|
| 86 |
+
import { getNotificationService } from './services/notification-service.js';
|
| 87 |
+
import { createEventHistoryRoutes } from './routes/event-history/index.js';
|
| 88 |
+
import { getEventHistoryService } from './services/event-history-service.js';
|
| 89 |
+
import { getTestRunnerService } from './services/test-runner-service.js';
|
| 90 |
+
import { createProjectsRoutes } from './routes/projects/index.js';
|
| 91 |
+
|
| 92 |
+
// Load environment variables
|
| 93 |
+
dotenv.config();
|
| 94 |
+
|
| 95 |
+
const PORT = parseInt(process.env.PORT || '3008', 10);
|
| 96 |
+
const HOST = process.env.HOST || '0.0.0.0';
|
| 97 |
+
const HOSTNAME = process.env.HOSTNAME || 'localhost';
|
| 98 |
+
const DATA_DIR = process.env.DATA_DIR || './data';
|
| 99 |
+
logger.info('[SERVER_STARTUP] process.env.DATA_DIR:', process.env.DATA_DIR);
|
| 100 |
+
logger.info('[SERVER_STARTUP] Resolved DATA_DIR:', DATA_DIR);
|
| 101 |
+
logger.info('[SERVER_STARTUP] process.cwd():', process.cwd());
|
| 102 |
+
const ENABLE_REQUEST_LOGGING_DEFAULT = process.env.ENABLE_REQUEST_LOGGING !== 'false'; // Default to true
|
| 103 |
+
|
| 104 |
+
// Runtime-configurable request logging flag (can be changed via settings)
|
| 105 |
+
let requestLoggingEnabled = ENABLE_REQUEST_LOGGING_DEFAULT;
|
| 106 |
+
|
| 107 |
+
/**
|
| 108 |
+
* Enable or disable HTTP request logging at runtime
|
| 109 |
+
*/
|
| 110 |
+
export function setRequestLoggingEnabled(enabled: boolean): void {
|
| 111 |
+
requestLoggingEnabled = enabled;
|
| 112 |
+
}
|
| 113 |
+
|
| 114 |
+
/**
|
| 115 |
+
* Get current request logging state
|
| 116 |
+
*/
|
| 117 |
+
export function isRequestLoggingEnabled(): boolean {
|
| 118 |
+
return requestLoggingEnabled;
|
| 119 |
+
}
|
| 120 |
+
|
| 121 |
+
// Width for log box content (excluding borders)
|
| 122 |
+
const BOX_CONTENT_WIDTH = 67;
|
| 123 |
+
|
| 124 |
+
// Check for Claude authentication (async - runs in background)
|
| 125 |
+
// The Claude Agent SDK can use either ANTHROPIC_API_KEY or Claude Code CLI authentication
|
| 126 |
+
(async () => {
|
| 127 |
+
const hasAnthropicKey = !!process.env.ANTHROPIC_API_KEY;
|
| 128 |
+
const hasEnvOAuthToken = !!process.env.CLAUDE_CODE_OAUTH_TOKEN;
|
| 129 |
+
|
| 130 |
+
logger.debug('[CREDENTIAL_CHECK] Starting credential detection...');
|
| 131 |
+
logger.debug('[CREDENTIAL_CHECK] Environment variables:', {
|
| 132 |
+
hasAnthropicKey,
|
| 133 |
+
hasEnvOAuthToken,
|
| 134 |
+
});
|
| 135 |
+
|
| 136 |
+
if (hasAnthropicKey) {
|
| 137 |
+
logger.info('✓ ANTHROPIC_API_KEY detected');
|
| 138 |
+
return;
|
| 139 |
+
}
|
| 140 |
+
|
| 141 |
+
if (hasEnvOAuthToken) {
|
| 142 |
+
logger.info('✓ CLAUDE_CODE_OAUTH_TOKEN detected');
|
| 143 |
+
return;
|
| 144 |
+
}
|
| 145 |
+
|
| 146 |
+
// Check for Claude Code CLI authentication
|
| 147 |
+
// Store indicators outside the try block so we can use them in the warning message
|
| 148 |
+
let cliAuthIndicators: Awaited<ReturnType<typeof getClaudeAuthIndicators>> | null = null;
|
| 149 |
+
|
| 150 |
+
try {
|
| 151 |
+
cliAuthIndicators = await getClaudeAuthIndicators();
|
| 152 |
+
const indicators = cliAuthIndicators;
|
| 153 |
+
|
| 154 |
+
// Log detailed credential detection results
|
| 155 |
+
const { checks, ...indicatorSummary } = indicators;
|
| 156 |
+
logger.debug('[CREDENTIAL_CHECK] Claude CLI auth indicators:', indicatorSummary);
|
| 157 |
+
|
| 158 |
+
logger.debug('[CREDENTIAL_CHECK] File check details:', checks);
|
| 159 |
+
|
| 160 |
+
const hasCliAuth =
|
| 161 |
+
indicators.hasStatsCacheWithActivity ||
|
| 162 |
+
(indicators.hasSettingsFile && indicators.hasProjectsSessions) ||
|
| 163 |
+
(indicators.hasCredentialsFile &&
|
| 164 |
+
(indicators.credentials?.hasOAuthToken || indicators.credentials?.hasApiKey));
|
| 165 |
+
|
| 166 |
+
logger.debug('[CREDENTIAL_CHECK] Auth determination:', {
|
| 167 |
+
hasCliAuth,
|
| 168 |
+
reason: hasCliAuth
|
| 169 |
+
? indicators.hasStatsCacheWithActivity
|
| 170 |
+
? 'stats cache with activity'
|
| 171 |
+
: indicators.hasSettingsFile && indicators.hasProjectsSessions
|
| 172 |
+
? 'settings file + project sessions'
|
| 173 |
+
: indicators.credentials?.hasOAuthToken
|
| 174 |
+
? 'credentials file with OAuth token'
|
| 175 |
+
: 'credentials file with API key'
|
| 176 |
+
: 'no valid credentials found',
|
| 177 |
+
});
|
| 178 |
+
|
| 179 |
+
if (hasCliAuth) {
|
| 180 |
+
logger.info('✓ Claude Code CLI authentication detected');
|
| 181 |
+
return;
|
| 182 |
+
}
|
| 183 |
+
} catch (error) {
|
| 184 |
+
// Ignore errors checking CLI auth - will fall through to warning
|
| 185 |
+
logger.warn('Error checking for Claude Code CLI authentication:', error);
|
| 186 |
+
}
|
| 187 |
+
|
| 188 |
+
// No authentication found - show warning with paths that were checked
|
| 189 |
+
const wHeader = '⚠️ WARNING: No Claude authentication configured'.padEnd(BOX_CONTENT_WIDTH);
|
| 190 |
+
const w1 = 'The Claude Agent SDK requires authentication to function.'.padEnd(BOX_CONTENT_WIDTH);
|
| 191 |
+
const w2 = 'Options:'.padEnd(BOX_CONTENT_WIDTH);
|
| 192 |
+
const w3 = '1. Install Claude Code CLI and authenticate with subscription'.padEnd(
|
| 193 |
+
BOX_CONTENT_WIDTH
|
| 194 |
+
);
|
| 195 |
+
const w4 = '2. Set your Anthropic API key:'.padEnd(BOX_CONTENT_WIDTH);
|
| 196 |
+
const w5 = ' export ANTHROPIC_API_KEY="sk-ant-..."'.padEnd(BOX_CONTENT_WIDTH);
|
| 197 |
+
const w6 = '3. Use the setup wizard in Settings to configure authentication.'.padEnd(
|
| 198 |
+
BOX_CONTENT_WIDTH
|
| 199 |
+
);
|
| 200 |
+
|
| 201 |
+
// Build paths checked summary from the indicators (if available)
|
| 202 |
+
let pathsCheckedInfo = '';
|
| 203 |
+
if (cliAuthIndicators) {
|
| 204 |
+
const pathsChecked: string[] = [];
|
| 205 |
+
|
| 206 |
+
// Collect paths that were checked (paths are always populated strings)
|
| 207 |
+
pathsChecked.push(`Settings: ${cliAuthIndicators.checks.settingsFile.path}`);
|
| 208 |
+
pathsChecked.push(`Stats cache: ${cliAuthIndicators.checks.statsCache.path}`);
|
| 209 |
+
pathsChecked.push(`Projects dir: ${cliAuthIndicators.checks.projectsDir.path}`);
|
| 210 |
+
for (const credFile of cliAuthIndicators.checks.credentialFiles) {
|
| 211 |
+
pathsChecked.push(`Credentials: ${credFile.path}`);
|
| 212 |
+
}
|
| 213 |
+
|
| 214 |
+
if (pathsChecked.length > 0) {
|
| 215 |
+
pathsCheckedInfo = `
|
| 216 |
+
║ ║
|
| 217 |
+
║ ${'Paths checked:'.padEnd(BOX_CONTENT_WIDTH)}║
|
| 218 |
+
${pathsChecked
|
| 219 |
+
.map((p) => {
|
| 220 |
+
const maxLen = BOX_CONTENT_WIDTH - 4;
|
| 221 |
+
const display = p.length > maxLen ? '...' + p.slice(-(maxLen - 3)) : p;
|
| 222 |
+
return `║ ${display.padEnd(maxLen)} ║`;
|
| 223 |
+
})
|
| 224 |
+
.join('\n')}`;
|
| 225 |
+
}
|
| 226 |
+
}
|
| 227 |
+
|
| 228 |
+
logger.warn(`
|
| 229 |
+
╔═════════════════════════════════���═══════════════════════════════════╗
|
| 230 |
+
║ ${wHeader}║
|
| 231 |
+
╠═════════════════════════════════════════════════════════════════════╣
|
| 232 |
+
║ ║
|
| 233 |
+
║ ${w1}║
|
| 234 |
+
║ ║
|
| 235 |
+
║ ${w2}║
|
| 236 |
+
║ ${w3}║
|
| 237 |
+
║ ${w4}║
|
| 238 |
+
║ ${w5}║
|
| 239 |
+
║ ${w6}║${pathsCheckedInfo}
|
| 240 |
+
║ ║
|
| 241 |
+
╚═════════════════════════════════════════════════════════════════════╝
|
| 242 |
+
`);
|
| 243 |
+
})();
|
| 244 |
+
|
| 245 |
+
// Initialize security
|
| 246 |
+
initAllowedPaths();
|
| 247 |
+
|
| 248 |
+
// Create Express app
|
| 249 |
+
const app = express();
|
| 250 |
+
|
| 251 |
+
// Middleware
|
| 252 |
+
// Custom colored logger showing only endpoint and status code (dynamically configurable)
|
| 253 |
+
morgan.token('status-colored', (_req, res) => {
|
| 254 |
+
const status = res.statusCode;
|
| 255 |
+
if (status >= 500) return `\x1b[31m${status}\x1b[0m`; // Red for server errors
|
| 256 |
+
if (status >= 400) return `\x1b[33m${status}\x1b[0m`; // Yellow for client errors
|
| 257 |
+
if (status >= 300) return `\x1b[36m${status}\x1b[0m`; // Cyan for redirects
|
| 258 |
+
return `\x1b[32m${status}\x1b[0m`; // Green for success
|
| 259 |
+
});
|
| 260 |
+
|
| 261 |
+
app.use(
|
| 262 |
+
morgan(':method :url :status-colored', {
|
| 263 |
+
// Skip when request logging is disabled or for health check endpoints
|
| 264 |
+
skip: (req) =>
|
| 265 |
+
!requestLoggingEnabled ||
|
| 266 |
+
req.url === '/api/health' ||
|
| 267 |
+
req.url === '/api/auto-mode/context-exists',
|
| 268 |
+
})
|
| 269 |
+
);
|
| 270 |
+
// CORS configuration
|
| 271 |
+
// When using credentials (cookies), origin cannot be '*'
|
| 272 |
+
// We dynamically allow the requesting origin for local development
|
| 273 |
+
|
| 274 |
+
// Check if origin is a local/private network address
|
| 275 |
+
function isLocalOrigin(origin: string): boolean {
|
| 276 |
+
try {
|
| 277 |
+
const url = new URL(origin);
|
| 278 |
+
const hostname = url.hostname;
|
| 279 |
+
return (
|
| 280 |
+
hostname === 'localhost' ||
|
| 281 |
+
hostname === '127.0.0.1' ||
|
| 282 |
+
hostname === '[::1]' ||
|
| 283 |
+
hostname === '0.0.0.0' ||
|
| 284 |
+
hostname.startsWith('192.168.') ||
|
| 285 |
+
hostname.startsWith('10.') ||
|
| 286 |
+
/^172\.(1[6-9]|2[0-9]|3[0-1])\./.test(hostname)
|
| 287 |
+
);
|
| 288 |
+
} catch {
|
| 289 |
+
return false;
|
| 290 |
+
}
|
| 291 |
+
}
|
| 292 |
+
|
| 293 |
+
app.use(
|
| 294 |
+
cors({
|
| 295 |
+
origin: (origin, callback) => {
|
| 296 |
+
// Allow requests with no origin (like mobile apps, curl, Electron)
|
| 297 |
+
if (!origin) {
|
| 298 |
+
callback(null, true);
|
| 299 |
+
return;
|
| 300 |
+
}
|
| 301 |
+
|
| 302 |
+
// If CORS_ORIGIN is set, use it (can be comma-separated list)
|
| 303 |
+
const allowedOrigins = process.env.CORS_ORIGIN?.split(',')
|
| 304 |
+
.map((o) => o.trim())
|
| 305 |
+
.filter(Boolean);
|
| 306 |
+
if (allowedOrigins && allowedOrigins.length > 0) {
|
| 307 |
+
if (allowedOrigins.includes('*')) {
|
| 308 |
+
callback(null, true);
|
| 309 |
+
return;
|
| 310 |
+
}
|
| 311 |
+
if (allowedOrigins.includes(origin)) {
|
| 312 |
+
callback(null, origin);
|
| 313 |
+
return;
|
| 314 |
+
}
|
| 315 |
+
// Fall through to local network check below
|
| 316 |
+
}
|
| 317 |
+
|
| 318 |
+
// Allow all localhost/loopback/private network origins (any port)
|
| 319 |
+
if (isLocalOrigin(origin)) {
|
| 320 |
+
callback(null, origin);
|
| 321 |
+
return;
|
| 322 |
+
}
|
| 323 |
+
|
| 324 |
+
// Reject other origins by default for security
|
| 325 |
+
callback(new Error('Not allowed by CORS'));
|
| 326 |
+
},
|
| 327 |
+
credentials: true,
|
| 328 |
+
})
|
| 329 |
+
);
|
| 330 |
+
app.use(express.json({ limit: '50mb' }));
|
| 331 |
+
app.use(cookieParser());
|
| 332 |
+
|
| 333 |
+
// Create shared event emitter for streaming
|
| 334 |
+
const events: EventEmitter = createEventEmitter();
|
| 335 |
+
|
| 336 |
+
// Create services
|
| 337 |
+
// Note: settingsService is created first so it can be injected into other services
|
| 338 |
+
const settingsService = new SettingsService(DATA_DIR);
|
| 339 |
+
const agentService = new AgentService(DATA_DIR, events, settingsService);
|
| 340 |
+
const featureLoader = new FeatureLoader();
|
| 341 |
+
|
| 342 |
+
// Auto-mode services: compatibility layer provides old interface while using new architecture
|
| 343 |
+
const autoModeService = new AutoModeServiceCompat(events, settingsService, featureLoader);
|
| 344 |
+
const claudeUsageService = new ClaudeUsageService();
|
| 345 |
+
const codexAppServerService = new CodexAppServerService();
|
| 346 |
+
const codexModelCacheService = new CodexModelCacheService(DATA_DIR, codexAppServerService);
|
| 347 |
+
const codexUsageService = new CodexUsageService(codexAppServerService);
|
| 348 |
+
const zaiUsageService = new ZaiUsageService();
|
| 349 |
+
const geminiUsageService = new GeminiUsageService();
|
| 350 |
+
const mcpTestService = new MCPTestService(settingsService);
|
| 351 |
+
const ideationService = new IdeationService(events, settingsService, featureLoader);
|
| 352 |
+
|
| 353 |
+
// Initialize DevServerService with event emitter for real-time log streaming
|
| 354 |
+
const devServerService = getDevServerService();
|
| 355 |
+
devServerService.initialize(DATA_DIR, events).catch((err) => {
|
| 356 |
+
logger.error('Failed to initialize DevServerService:', err);
|
| 357 |
+
});
|
| 358 |
+
|
| 359 |
+
// Initialize Notification Service with event emitter for real-time updates
|
| 360 |
+
const notificationService = getNotificationService();
|
| 361 |
+
notificationService.setEventEmitter(events);
|
| 362 |
+
|
| 363 |
+
// Initialize Event History Service
|
| 364 |
+
const eventHistoryService = getEventHistoryService();
|
| 365 |
+
|
| 366 |
+
// Initialize Test Runner Service with event emitter for real-time test output streaming
|
| 367 |
+
const testRunnerService = getTestRunnerService();
|
| 368 |
+
testRunnerService.setEventEmitter(events);
|
| 369 |
+
|
| 370 |
+
// Initialize Event Hook Service for custom event triggers (with history storage)
|
| 371 |
+
eventHookService.initialize(events, settingsService, eventHistoryService, featureLoader);
|
| 372 |
+
|
| 373 |
+
// Initialize services
|
| 374 |
+
(async () => {
|
| 375 |
+
// Migrate settings from legacy Electron userData location if needed
|
| 376 |
+
// This handles users upgrading from versions that stored settings in ~/.config/Automaker (Linux),
|
| 377 |
+
// ~/Library/Application Support/Automaker (macOS), or %APPDATA%\Automaker (Windows)
|
| 378 |
+
// to the new shared ./data directory
|
| 379 |
+
try {
|
| 380 |
+
const migrationResult = await settingsService.migrateFromLegacyElectronPath();
|
| 381 |
+
if (migrationResult.migrated) {
|
| 382 |
+
logger.info(`Settings migrated from legacy location: ${migrationResult.legacyPath}`);
|
| 383 |
+
logger.info(`Migrated files: ${migrationResult.migratedFiles.join(', ')}`);
|
| 384 |
+
}
|
| 385 |
+
if (migrationResult.errors.length > 0) {
|
| 386 |
+
logger.warn('Migration errors:', migrationResult.errors);
|
| 387 |
+
}
|
| 388 |
+
} catch (err) {
|
| 389 |
+
logger.warn('Failed to check for legacy settings migration:', err);
|
| 390 |
+
}
|
| 391 |
+
|
| 392 |
+
// Fetch global settings once and reuse for logging config and feature reconciliation
|
| 393 |
+
let globalSettings: Awaited<ReturnType<typeof settingsService.getGlobalSettings>> | null = null;
|
| 394 |
+
try {
|
| 395 |
+
globalSettings = await settingsService.getGlobalSettings();
|
| 396 |
+
} catch {
|
| 397 |
+
logger.warn('Failed to load global settings, using defaults');
|
| 398 |
+
}
|
| 399 |
+
|
| 400 |
+
// Apply logging settings from saved settings
|
| 401 |
+
if (globalSettings) {
|
| 402 |
+
try {
|
| 403 |
+
if (
|
| 404 |
+
globalSettings.serverLogLevel &&
|
| 405 |
+
LOG_LEVEL_MAP[globalSettings.serverLogLevel] !== undefined
|
| 406 |
+
) {
|
| 407 |
+
setLogLevel(LOG_LEVEL_MAP[globalSettings.serverLogLevel]);
|
| 408 |
+
logger.info(`Server log level set to: ${globalSettings.serverLogLevel}`);
|
| 409 |
+
}
|
| 410 |
+
// Apply request logging setting (default true if not set)
|
| 411 |
+
const enableRequestLog = globalSettings.enableRequestLogging ?? true;
|
| 412 |
+
setRequestLoggingEnabled(enableRequestLog);
|
| 413 |
+
logger.info(`HTTP request logging: ${enableRequestLog ? 'enabled' : 'disabled'}`);
|
| 414 |
+
} catch {
|
| 415 |
+
logger.warn('Failed to apply logging settings, using defaults');
|
| 416 |
+
}
|
| 417 |
+
}
|
| 418 |
+
|
| 419 |
+
await agentService.initialize();
|
| 420 |
+
logger.info('Agent service initialized');
|
| 421 |
+
|
| 422 |
+
// Reconcile feature states on startup
|
| 423 |
+
// After any type of restart (clean, forced, crash), features may be stuck in
|
| 424 |
+
// transient states (in_progress, interrupted, pipeline_*) that don't match reality.
|
| 425 |
+
// Reconcile them back to resting states before the UI is served.
|
| 426 |
+
if (globalSettings) {
|
| 427 |
+
try {
|
| 428 |
+
if (globalSettings.projects && globalSettings.projects.length > 0) {
|
| 429 |
+
let totalReconciled = 0;
|
| 430 |
+
for (const project of globalSettings.projects) {
|
| 431 |
+
const count = await autoModeService.reconcileFeatureStates(project.path);
|
| 432 |
+
totalReconciled += count;
|
| 433 |
+
}
|
| 434 |
+
if (totalReconciled > 0) {
|
| 435 |
+
logger.info(
|
| 436 |
+
`[STARTUP] Reconciled ${totalReconciled} feature(s) across ${globalSettings.projects.length} project(s)`
|
| 437 |
+
);
|
| 438 |
+
} else {
|
| 439 |
+
logger.info('[STARTUP] Feature state reconciliation complete - no stale states found');
|
| 440 |
+
}
|
| 441 |
+
|
| 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 |
+
});
|
| 452 |
+
}
|
| 453 |
+
logger.info('[STARTUP] Initiated background resume of interrupted features');
|
| 454 |
+
}
|
| 455 |
+
} catch (err) {
|
| 456 |
+
logger.warn('[STARTUP] Failed to reconcile feature states:', err);
|
| 457 |
+
}
|
| 458 |
+
}
|
| 459 |
+
|
| 460 |
+
// Bootstrap Codex model cache in background (don't block server startup)
|
| 461 |
+
void codexModelCacheService.getModels().catch((err) => {
|
| 462 |
+
logger.error('Failed to bootstrap Codex model cache:', err);
|
| 463 |
+
});
|
| 464 |
+
})();
|
| 465 |
+
|
| 466 |
+
// Run stale validation cleanup every hour to prevent memory leaks from crashed validations
|
| 467 |
+
const VALIDATION_CLEANUP_INTERVAL_MS = 60 * 60 * 1000; // 1 hour
|
| 468 |
+
setInterval(() => {
|
| 469 |
+
const cleaned = cleanupStaleValidations();
|
| 470 |
+
if (cleaned > 0) {
|
| 471 |
+
logger.info(`Cleaned up ${cleaned} stale validation entries`);
|
| 472 |
+
}
|
| 473 |
+
}, VALIDATION_CLEANUP_INTERVAL_MS);
|
| 474 |
+
|
| 475 |
+
// Require Content-Type: application/json for all API POST/PUT/PATCH requests
|
| 476 |
+
// This helps prevent CSRF and content-type confusion attacks
|
| 477 |
+
app.use('/api', requireJsonContentType);
|
| 478 |
+
|
| 479 |
+
// Mount API routes - health, auth, and setup are unauthenticated
|
| 480 |
+
app.use('/api/health', createHealthRoutes());
|
| 481 |
+
app.use('/api/auth', createAuthRoutes());
|
| 482 |
+
app.use('/api/setup', createSetupRoutes());
|
| 483 |
+
|
| 484 |
+
// Apply authentication to all other routes
|
| 485 |
+
app.use('/api', authMiddleware);
|
| 486 |
+
|
| 487 |
+
// Protected health endpoint with detailed info
|
| 488 |
+
app.get('/api/health/detailed', createDetailedHandler());
|
| 489 |
+
|
| 490 |
+
app.use('/api/fs', createFsRoutes(events));
|
| 491 |
+
app.use('/api/agent', createAgentRoutes(agentService, events));
|
| 492 |
+
app.use('/api/sessions', createSessionsRoutes(agentService));
|
| 493 |
+
app.use(
|
| 494 |
+
'/api/features',
|
| 495 |
+
createFeaturesRoutes(featureLoader, settingsService, events, autoModeService)
|
| 496 |
+
);
|
| 497 |
+
app.use('/api/auto-mode', createAutoModeRoutes(autoModeService));
|
| 498 |
+
app.use('/api/enhance-prompt', createEnhancePromptRoutes(settingsService));
|
| 499 |
+
app.use('/api/worktree', createWorktreeRoutes(events, settingsService, featureLoader));
|
| 500 |
+
app.use('/api/git', createGitRoutes());
|
| 501 |
+
app.use('/api/models', createModelsRoutes());
|
| 502 |
+
app.use('/api/spec-regeneration', createSpecRegenerationRoutes(events, settingsService));
|
| 503 |
+
app.use('/api/running-agents', createRunningAgentsRoutes(autoModeService));
|
| 504 |
+
app.use('/api/workspace', createWorkspaceRoutes());
|
| 505 |
+
app.use('/api/templates', createTemplatesRoutes());
|
| 506 |
+
app.use('/api/terminal', createTerminalRoutes());
|
| 507 |
+
app.use('/api/settings', createSettingsRoutes(settingsService));
|
| 508 |
+
app.use('/api/claude', createClaudeRoutes(claudeUsageService));
|
| 509 |
+
app.use('/api/codex', createCodexRoutes(codexUsageService, codexModelCacheService));
|
| 510 |
+
app.use('/api/zai', createZaiRoutes(zaiUsageService, settingsService));
|
| 511 |
+
app.use('/api/gemini', createGeminiRoutes(geminiUsageService, events));
|
| 512 |
+
app.use('/api/github', createGitHubRoutes(events, settingsService));
|
| 513 |
+
app.use('/api/context', createContextRoutes(settingsService));
|
| 514 |
+
app.use('/api/backlog-plan', createBacklogPlanRoutes(events, settingsService));
|
| 515 |
+
app.use('/api/mcp', createMCPRoutes(mcpTestService));
|
| 516 |
+
app.use('/api/pipeline', createPipelineRoutes(pipelineService));
|
| 517 |
+
app.use('/api/ideation', createIdeationRoutes(events, ideationService, featureLoader));
|
| 518 |
+
app.use('/api/notifications', createNotificationsRoutes(notificationService));
|
| 519 |
+
app.use('/api/event-history', createEventHistoryRoutes(eventHistoryService, settingsService));
|
| 520 |
+
app.use(
|
| 521 |
+
'/api/projects',
|
| 522 |
+
createProjectsRoutes(featureLoader, autoModeService, settingsService, notificationService)
|
| 523 |
+
);
|
| 524 |
+
|
| 525 |
+
// Create HTTP server
|
| 526 |
+
const server = createServer(app);
|
| 527 |
+
|
| 528 |
+
// WebSocket servers using noServer mode for proper multi-path support
|
| 529 |
+
const wss = new WebSocketServer({ noServer: true });
|
| 530 |
+
const terminalWss = new WebSocketServer({ noServer: true });
|
| 531 |
+
const terminalService = getTerminalService(settingsService);
|
| 532 |
+
|
| 533 |
+
/**
|
| 534 |
+
* Authenticate WebSocket upgrade requests
|
| 535 |
+
* Checks for API key in header/query, session token in header/query, OR valid session cookie
|
| 536 |
+
*/
|
| 537 |
+
function authenticateWebSocket(request: import('http').IncomingMessage): boolean {
|
| 538 |
+
const url = new URL(request.url || '', `http://${request.headers.host}`);
|
| 539 |
+
|
| 540 |
+
// Convert URL search params to query object
|
| 541 |
+
const query: Record<string, string | undefined> = {};
|
| 542 |
+
url.searchParams.forEach((value, key) => {
|
| 543 |
+
query[key] = value;
|
| 544 |
+
});
|
| 545 |
+
|
| 546 |
+
// Parse cookies from header
|
| 547 |
+
const cookieHeader = request.headers.cookie;
|
| 548 |
+
const cookies = cookieHeader ? cookie.parse(cookieHeader) : {};
|
| 549 |
+
|
| 550 |
+
// Use shared authentication logic for standard auth methods
|
| 551 |
+
if (
|
| 552 |
+
checkRawAuthentication(
|
| 553 |
+
request.headers as Record<string, string | string[] | undefined>,
|
| 554 |
+
query,
|
| 555 |
+
cookies
|
| 556 |
+
)
|
| 557 |
+
) {
|
| 558 |
+
return true;
|
| 559 |
+
}
|
| 560 |
+
|
| 561 |
+
// Additionally check for short-lived WebSocket connection token (WebSocket-specific)
|
| 562 |
+
const wsToken = url.searchParams.get('wsToken');
|
| 563 |
+
if (wsToken && validateWsConnectionToken(wsToken)) {
|
| 564 |
+
return true;
|
| 565 |
+
}
|
| 566 |
+
|
| 567 |
+
return false;
|
| 568 |
+
}
|
| 569 |
+
|
| 570 |
+
// Handle HTTP upgrade requests manually to route to correct WebSocket server
|
| 571 |
+
server.on('upgrade', (request, socket, head) => {
|
| 572 |
+
const { pathname } = new URL(request.url || '', `http://${request.headers.host}`);
|
| 573 |
+
|
| 574 |
+
// Authenticate all WebSocket connections
|
| 575 |
+
if (!authenticateWebSocket(request)) {
|
| 576 |
+
logger.info('Authentication failed, rejecting connection');
|
| 577 |
+
socket.write('HTTP/1.1 401 Unauthorized\r\n\r\n');
|
| 578 |
+
socket.destroy();
|
| 579 |
+
return;
|
| 580 |
+
}
|
| 581 |
+
|
| 582 |
+
if (pathname === '/api/events') {
|
| 583 |
+
wss.handleUpgrade(request, socket, head, (ws) => {
|
| 584 |
+
wss.emit('connection', ws, request);
|
| 585 |
+
});
|
| 586 |
+
} else if (pathname === '/api/terminal/ws') {
|
| 587 |
+
terminalWss.handleUpgrade(request, socket, head, (ws) => {
|
| 588 |
+
terminalWss.emit('connection', ws, request);
|
| 589 |
+
});
|
| 590 |
+
} else {
|
| 591 |
+
socket.destroy();
|
| 592 |
+
}
|
| 593 |
+
});
|
| 594 |
+
|
| 595 |
+
// Events WebSocket connection handler
|
| 596 |
+
wss.on('connection', (ws: WebSocket) => {
|
| 597 |
+
logger.info('Client connected, ready state:', ws.readyState);
|
| 598 |
+
|
| 599 |
+
// Subscribe to all events and forward to this client
|
| 600 |
+
const unsubscribe = events.subscribe((type, payload) => {
|
| 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:', {
|
| 608 |
+
type,
|
| 609 |
+
hasPayload: !!payload,
|
| 610 |
+
wsReadyState: ws.readyState,
|
| 611 |
+
});
|
| 612 |
+
|
| 613 |
+
if (ws.readyState === WebSocket.OPEN) {
|
| 614 |
+
const message = JSON.stringify({ type, payload });
|
| 615 |
+
ws.send(message);
|
| 616 |
+
} else {
|
| 617 |
+
logger.warn('Cannot send event, WebSocket not open. ReadyState:', ws.readyState);
|
| 618 |
+
}
|
| 619 |
+
});
|
| 620 |
+
|
| 621 |
+
ws.on('close', () => {
|
| 622 |
+
logger.info('Client disconnected');
|
| 623 |
+
unsubscribe();
|
| 624 |
+
});
|
| 625 |
+
|
| 626 |
+
ws.on('error', (error) => {
|
| 627 |
+
logger.error('ERROR:', error);
|
| 628 |
+
unsubscribe();
|
| 629 |
+
});
|
| 630 |
+
});
|
| 631 |
+
|
| 632 |
+
// Track WebSocket connections per session
|
| 633 |
+
const terminalConnections: Map<string, Set<WebSocket>> = new Map();
|
| 634 |
+
// Track last resize dimensions per session to deduplicate resize messages
|
| 635 |
+
const lastResizeDimensions: Map<string, { cols: number; rows: number }> = new Map();
|
| 636 |
+
// Track last resize timestamp to rate-limit resize operations (prevents resize storm)
|
| 637 |
+
const lastResizeTime: Map<string, number> = new Map();
|
| 638 |
+
const RESIZE_MIN_INTERVAL_MS = 100; // Minimum 100ms between resize operations
|
| 639 |
+
|
| 640 |
+
// Clean up resize tracking when sessions actually exit (not just when connections close)
|
| 641 |
+
terminalService.onExit((sessionId) => {
|
| 642 |
+
lastResizeDimensions.delete(sessionId);
|
| 643 |
+
lastResizeTime.delete(sessionId);
|
| 644 |
+
terminalConnections.delete(sessionId);
|
| 645 |
+
});
|
| 646 |
+
|
| 647 |
+
// Terminal WebSocket connection handler
|
| 648 |
+
terminalWss.on('connection', (ws: WebSocket, req: import('http').IncomingMessage) => {
|
| 649 |
+
// Parse URL to get session ID and token
|
| 650 |
+
const url = new URL(req.url || '', `http://${req.headers.host}`);
|
| 651 |
+
const sessionId = url.searchParams.get('sessionId');
|
| 652 |
+
const token = url.searchParams.get('token');
|
| 653 |
+
|
| 654 |
+
logger.info(`Connection attempt for session: ${sessionId}`);
|
| 655 |
+
|
| 656 |
+
// Check if terminal is enabled
|
| 657 |
+
if (!isTerminalEnabled()) {
|
| 658 |
+
logger.info('Terminal is disabled');
|
| 659 |
+
ws.close(4003, 'Terminal access is disabled');
|
| 660 |
+
return;
|
| 661 |
+
}
|
| 662 |
+
|
| 663 |
+
// Validate token if password is required
|
| 664 |
+
if (isTerminalPasswordRequired() && !validateTerminalToken(token || undefined)) {
|
| 665 |
+
logger.info('Invalid or missing token');
|
| 666 |
+
ws.close(4001, 'Authentication required');
|
| 667 |
+
return;
|
| 668 |
+
}
|
| 669 |
+
|
| 670 |
+
if (!sessionId) {
|
| 671 |
+
logger.info('No session ID provided');
|
| 672 |
+
ws.close(4002, 'Session ID required');
|
| 673 |
+
return;
|
| 674 |
+
}
|
| 675 |
+
|
| 676 |
+
// Check if session exists
|
| 677 |
+
const session = terminalService.getSession(sessionId);
|
| 678 |
+
if (!session) {
|
| 679 |
+
logger.warn(
|
| 680 |
+
`Terminal session ${sessionId} not found. ` +
|
| 681 |
+
`The session may have exited, been deleted, or was never created. ` +
|
| 682 |
+
`Active terminal sessions: ${terminalService.getSessionCount()}`
|
| 683 |
+
);
|
| 684 |
+
ws.close(
|
| 685 |
+
4004,
|
| 686 |
+
'Session not found. The terminal session may have expired or been closed. Please create a new terminal.'
|
| 687 |
+
);
|
| 688 |
+
return;
|
| 689 |
+
}
|
| 690 |
+
|
| 691 |
+
logger.info(`Client connected to session ${sessionId}`);
|
| 692 |
+
|
| 693 |
+
// Track this connection
|
| 694 |
+
if (!terminalConnections.has(sessionId)) {
|
| 695 |
+
terminalConnections.set(sessionId, new Set());
|
| 696 |
+
}
|
| 697 |
+
terminalConnections.get(sessionId)!.add(ws);
|
| 698 |
+
|
| 699 |
+
// Send initial connection success FIRST
|
| 700 |
+
ws.send(
|
| 701 |
+
JSON.stringify({
|
| 702 |
+
type: 'connected',
|
| 703 |
+
sessionId,
|
| 704 |
+
shell: session.shell,
|
| 705 |
+
cwd: session.cwd,
|
| 706 |
+
})
|
| 707 |
+
);
|
| 708 |
+
|
| 709 |
+
// Send scrollback buffer BEFORE subscribing to prevent race condition
|
| 710 |
+
// Also clear pending output buffer to prevent duplicates from throttled flush
|
| 711 |
+
const scrollback = terminalService.getScrollbackAndClearPending(sessionId);
|
| 712 |
+
if (scrollback && scrollback.length > 0) {
|
| 713 |
+
ws.send(
|
| 714 |
+
JSON.stringify({
|
| 715 |
+
type: 'scrollback',
|
| 716 |
+
data: scrollback,
|
| 717 |
+
})
|
| 718 |
+
);
|
| 719 |
+
}
|
| 720 |
+
|
| 721 |
+
// NOW subscribe to terminal data (after scrollback is sent)
|
| 722 |
+
const unsubscribeData = terminalService.onData((sid, data) => {
|
| 723 |
+
if (sid === sessionId && ws.readyState === WebSocket.OPEN) {
|
| 724 |
+
ws.send(JSON.stringify({ type: 'data', data }));
|
| 725 |
+
}
|
| 726 |
+
});
|
| 727 |
+
|
| 728 |
+
// Subscribe to terminal exit
|
| 729 |
+
const unsubscribeExit = terminalService.onExit((sid, exitCode) => {
|
| 730 |
+
if (sid === sessionId && ws.readyState === WebSocket.OPEN) {
|
| 731 |
+
ws.send(JSON.stringify({ type: 'exit', exitCode }));
|
| 732 |
+
ws.close(1000, 'Session ended');
|
| 733 |
+
}
|
| 734 |
+
});
|
| 735 |
+
|
| 736 |
+
// Handle incoming messages
|
| 737 |
+
ws.on('message', (message) => {
|
| 738 |
+
try {
|
| 739 |
+
const msg = JSON.parse(message.toString());
|
| 740 |
+
|
| 741 |
+
switch (msg.type) {
|
| 742 |
+
case 'input':
|
| 743 |
+
// Validate input data type and length
|
| 744 |
+
if (typeof msg.data !== 'string') {
|
| 745 |
+
ws.send(JSON.stringify({ type: 'error', message: 'Invalid input type' }));
|
| 746 |
+
break;
|
| 747 |
+
}
|
| 748 |
+
// Limit input size to 1MB to prevent memory issues
|
| 749 |
+
if (msg.data.length > 1024 * 1024) {
|
| 750 |
+
ws.send(JSON.stringify({ type: 'error', message: 'Input too large' }));
|
| 751 |
+
break;
|
| 752 |
+
}
|
| 753 |
+
// Write user input to terminal
|
| 754 |
+
terminalService.write(sessionId, msg.data);
|
| 755 |
+
break;
|
| 756 |
+
|
| 757 |
+
case 'resize':
|
| 758 |
+
// Validate resize dimensions are positive integers within reasonable bounds
|
| 759 |
+
if (
|
| 760 |
+
typeof msg.cols !== 'number' ||
|
| 761 |
+
typeof msg.rows !== 'number' ||
|
| 762 |
+
!Number.isInteger(msg.cols) ||
|
| 763 |
+
!Number.isInteger(msg.rows) ||
|
| 764 |
+
msg.cols < 1 ||
|
| 765 |
+
msg.cols > 1000 ||
|
| 766 |
+
msg.rows < 1 ||
|
| 767 |
+
msg.rows > 500
|
| 768 |
+
) {
|
| 769 |
+
break; // Silently ignore invalid resize requests
|
| 770 |
+
}
|
| 771 |
+
// Resize terminal with deduplication and rate limiting
|
| 772 |
+
if (msg.cols && msg.rows) {
|
| 773 |
+
const now = Date.now();
|
| 774 |
+
const lastTime = lastResizeTime.get(sessionId) || 0;
|
| 775 |
+
const lastDimensions = lastResizeDimensions.get(sessionId);
|
| 776 |
+
|
| 777 |
+
// Skip if resized too recently (prevents resize storm during splits)
|
| 778 |
+
if (now - lastTime < RESIZE_MIN_INTERVAL_MS) {
|
| 779 |
+
break;
|
| 780 |
+
}
|
| 781 |
+
|
| 782 |
+
// Check if dimensions are different from last resize
|
| 783 |
+
if (
|
| 784 |
+
!lastDimensions ||
|
| 785 |
+
lastDimensions.cols !== msg.cols ||
|
| 786 |
+
lastDimensions.rows !== msg.rows
|
| 787 |
+
) {
|
| 788 |
+
// Only suppress output on subsequent resizes, not the first one
|
| 789 |
+
// The first resize happens on terminal open and we don't want to drop the initial prompt
|
| 790 |
+
const isFirstResize = !lastDimensions;
|
| 791 |
+
terminalService.resize(sessionId, msg.cols, msg.rows, !isFirstResize);
|
| 792 |
+
lastResizeDimensions.set(sessionId, {
|
| 793 |
+
cols: msg.cols,
|
| 794 |
+
rows: msg.rows,
|
| 795 |
+
});
|
| 796 |
+
lastResizeTime.set(sessionId, now);
|
| 797 |
+
}
|
| 798 |
+
}
|
| 799 |
+
break;
|
| 800 |
+
|
| 801 |
+
case 'ping':
|
| 802 |
+
// Respond to ping
|
| 803 |
+
ws.send(JSON.stringify({ type: 'pong' }));
|
| 804 |
+
break;
|
| 805 |
+
|
| 806 |
+
default:
|
| 807 |
+
logger.warn(`Unknown message type: ${msg.type}`);
|
| 808 |
+
}
|
| 809 |
+
} catch (error) {
|
| 810 |
+
logger.error('Error processing message:', error);
|
| 811 |
+
}
|
| 812 |
+
});
|
| 813 |
+
|
| 814 |
+
ws.on('close', () => {
|
| 815 |
+
logger.info(`Client disconnected from session ${sessionId}`);
|
| 816 |
+
unsubscribeData();
|
| 817 |
+
unsubscribeExit();
|
| 818 |
+
|
| 819 |
+
// Remove from connections tracking
|
| 820 |
+
const connections = terminalConnections.get(sessionId);
|
| 821 |
+
if (connections) {
|
| 822 |
+
connections.delete(ws);
|
| 823 |
+
if (connections.size === 0) {
|
| 824 |
+
terminalConnections.delete(sessionId);
|
| 825 |
+
// DON'T delete lastResizeDimensions/lastResizeTime here!
|
| 826 |
+
// The session still exists, and reconnecting clients need to know
|
| 827 |
+
// this isn't the "first resize" to prevent duplicate prompts.
|
| 828 |
+
// These get cleaned up when the session actually exits.
|
| 829 |
+
}
|
| 830 |
+
}
|
| 831 |
+
});
|
| 832 |
+
|
| 833 |
+
ws.on('error', (error) => {
|
| 834 |
+
logger.error(`Error on session ${sessionId}:`, error);
|
| 835 |
+
unsubscribeData();
|
| 836 |
+
unsubscribeExit();
|
| 837 |
+
});
|
| 838 |
+
});
|
| 839 |
+
|
| 840 |
+
// Start server with error handling for port conflicts
|
| 841 |
+
const startServer = (port: number, host: string) => {
|
| 842 |
+
server.listen(port, host, () => {
|
| 843 |
+
const terminalStatus = isTerminalEnabled()
|
| 844 |
+
? isTerminalPasswordRequired()
|
| 845 |
+
? 'enabled (password protected)'
|
| 846 |
+
: 'enabled'
|
| 847 |
+
: 'disabled';
|
| 848 |
+
|
| 849 |
+
// Build URLs for display
|
| 850 |
+
const listenAddr = `${host}:${port}`;
|
| 851 |
+
const httpUrl = `http://${HOSTNAME}:${port}`;
|
| 852 |
+
const wsEventsUrl = `ws://${HOSTNAME}:${port}/api/events`;
|
| 853 |
+
const wsTerminalUrl = `ws://${HOSTNAME}:${port}/api/terminal/ws`;
|
| 854 |
+
const healthUrl = `http://${HOSTNAME}:${port}/api/health`;
|
| 855 |
+
|
| 856 |
+
const sHeader = '🚀 Automaker Backend Server'.padEnd(BOX_CONTENT_WIDTH);
|
| 857 |
+
const s1 = `Listening: ${listenAddr}`.padEnd(BOX_CONTENT_WIDTH);
|
| 858 |
+
const s2 = `HTTP API: ${httpUrl}`.padEnd(BOX_CONTENT_WIDTH);
|
| 859 |
+
const s3 = `WebSocket: ${wsEventsUrl}`.padEnd(BOX_CONTENT_WIDTH);
|
| 860 |
+
const s4 = `Terminal WS: ${wsTerminalUrl}`.padEnd(BOX_CONTENT_WIDTH);
|
| 861 |
+
const s5 = `Health: ${healthUrl}`.padEnd(BOX_CONTENT_WIDTH);
|
| 862 |
+
const s6 = `Terminal: ${terminalStatus}`.padEnd(BOX_CONTENT_WIDTH);
|
| 863 |
+
|
| 864 |
+
logger.info(`
|
| 865 |
+
╔═════════════════════════════════════════════════════════════════════╗
|
| 866 |
+
║ ${sHeader}║
|
| 867 |
+
╠═════════════════════════════════════════════════════════════════════╣
|
| 868 |
+
║ ║
|
| 869 |
+
║ ${s1}║
|
| 870 |
+
║ ${s2}║
|
| 871 |
+
║ ${s3}║
|
| 872 |
+
║ ${s4}║
|
| 873 |
+
║ ${s5}║
|
| 874 |
+
║ ${s6}║
|
| 875 |
+
║ ║
|
| 876 |
+
╚═════════════════════════════════════════════════════════════════════╝
|
| 877 |
+
`);
|
| 878 |
+
});
|
| 879 |
+
|
| 880 |
+
server.on('error', (error: NodeJS.ErrnoException) => {
|
| 881 |
+
if (error.code === 'EADDRINUSE') {
|
| 882 |
+
const portStr = port.toString();
|
| 883 |
+
const nextPortStr = (port + 1).toString();
|
| 884 |
+
const killCmd = `lsof -ti:${portStr} | xargs kill -9`;
|
| 885 |
+
const altCmd = `PORT=${nextPortStr} npm run dev:server`;
|
| 886 |
+
|
| 887 |
+
const eHeader = `❌ ERROR: Port ${portStr} is already in use`.padEnd(BOX_CONTENT_WIDTH);
|
| 888 |
+
const e1 = 'Another process is using this port.'.padEnd(BOX_CONTENT_WIDTH);
|
| 889 |
+
const e2 = 'To fix this, try one of:'.padEnd(BOX_CONTENT_WIDTH);
|
| 890 |
+
const e3 = '1. Kill the process using the port:'.padEnd(BOX_CONTENT_WIDTH);
|
| 891 |
+
const e4 = ` ${killCmd}`.padEnd(BOX_CONTENT_WIDTH);
|
| 892 |
+
const e5 = '2. Use a different port:'.padEnd(BOX_CONTENT_WIDTH);
|
| 893 |
+
const e6 = ` ${altCmd}`.padEnd(BOX_CONTENT_WIDTH);
|
| 894 |
+
const e7 = '3. Use the init.sh script which handles this:'.padEnd(BOX_CONTENT_WIDTH);
|
| 895 |
+
const e8 = ' ./init.sh'.padEnd(BOX_CONTENT_WIDTH);
|
| 896 |
+
|
| 897 |
+
logger.error(`
|
| 898 |
+
╔═════════════════════════════════════════════════════════════════════╗
|
| 899 |
+
║ ${eHeader}║
|
| 900 |
+
╠═════════════════════════════════════════════════════════════════════╣
|
| 901 |
+
║ ║
|
| 902 |
+
║ ${e1}║
|
| 903 |
+
║ ║
|
| 904 |
+
║ ${e2}║
|
| 905 |
+
║ ║
|
| 906 |
+
║ ${e3}║
|
| 907 |
+
║ ${e4}║
|
| 908 |
+
║ ║
|
| 909 |
+
║ ${e5}║
|
| 910 |
+
║ ${e6}║
|
| 911 |
+
║ ║
|
| 912 |
+
║ ${e7}║
|
| 913 |
+
║ ${e8}║
|
| 914 |
+
║ ║
|
| 915 |
+
╚═════════════════════════════════════════════════════════════════════╝
|
| 916 |
+
`);
|
| 917 |
+
process.exit(1);
|
| 918 |
+
} else {
|
| 919 |
+
logger.error('Error starting server:', error);
|
| 920 |
+
process.exit(1);
|
| 921 |
+
}
|
| 922 |
+
});
|
| 923 |
+
};
|
| 924 |
+
|
| 925 |
+
startServer(PORT, HOST);
|
| 926 |
+
|
| 927 |
+
// Global error handlers to prevent crashes from uncaught errors
|
| 928 |
+
process.on('unhandledRejection', (reason: unknown, _promise: Promise<unknown>) => {
|
| 929 |
+
logger.error('Unhandled Promise Rejection:', {
|
| 930 |
+
reason: reason instanceof Error ? reason.message : String(reason),
|
| 931 |
+
stack: reason instanceof Error ? reason.stack : undefined,
|
| 932 |
+
});
|
| 933 |
+
// Don't exit - log the error and continue running
|
| 934 |
+
// This prevents the server from crashing due to unhandled rejections
|
| 935 |
+
});
|
| 936 |
+
|
| 937 |
+
process.on('uncaughtException', (error: Error) => {
|
| 938 |
+
logger.error('Uncaught Exception:', {
|
| 939 |
+
message: error.message,
|
| 940 |
+
stack: error.stack,
|
| 941 |
+
});
|
| 942 |
+
// Exit on uncaught exceptions to prevent undefined behavior
|
| 943 |
+
// The process is in an unknown state after an uncaught exception
|
| 944 |
+
process.exit(1);
|
| 945 |
+
});
|
| 946 |
+
|
| 947 |
+
// Graceful shutdown timeout (30 seconds)
|
| 948 |
+
const SHUTDOWN_TIMEOUT_MS = 30000;
|
| 949 |
+
|
| 950 |
+
// Graceful shutdown helper
|
| 951 |
+
const gracefulShutdown = async (signal: string) => {
|
| 952 |
+
logger.info(`${signal} received, shutting down...`);
|
| 953 |
+
|
| 954 |
+
// Set up a force-exit timeout to prevent hanging
|
| 955 |
+
const forceExitTimeout = setTimeout(() => {
|
| 956 |
+
logger.error(`Shutdown timed out after ${SHUTDOWN_TIMEOUT_MS}ms, forcing exit`);
|
| 957 |
+
process.exit(1);
|
| 958 |
+
}, SHUTDOWN_TIMEOUT_MS);
|
| 959 |
+
|
| 960 |
+
// Mark all running features as interrupted before shutdown
|
| 961 |
+
// This ensures they can be resumed when the server restarts
|
| 962 |
+
// Note: markAllRunningFeaturesInterrupted handles errors internally and never rejects
|
| 963 |
+
await autoModeService.markAllRunningFeaturesInterrupted(`${signal} signal received`);
|
| 964 |
+
|
| 965 |
+
terminalService.cleanup();
|
| 966 |
+
server.close(() => {
|
| 967 |
+
clearTimeout(forceExitTimeout);
|
| 968 |
+
logger.info('Server closed');
|
| 969 |
+
process.exit(0);
|
| 970 |
+
});
|
| 971 |
+
};
|
| 972 |
+
|
| 973 |
+
process.on('SIGTERM', () => {
|
| 974 |
+
gracefulShutdown('SIGTERM');
|
| 975 |
+
});
|
| 976 |
+
|
| 977 |
+
process.on('SIGINT', () => {
|
| 978 |
+
gracefulShutdown('SIGINT');
|
| 979 |
+
});
|
jules_branch/apps/server/src/lib/agent-discovery.ts
ADDED
|
@@ -0,0 +1,257 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/**
|
| 2 |
+
* Agent Discovery - Scans filesystem for AGENT.md files
|
| 3 |
+
*
|
| 4 |
+
* Discovers agents from:
|
| 5 |
+
* - ~/.claude/agents/ (user-level, global)
|
| 6 |
+
* - .claude/agents/ (project-level)
|
| 7 |
+
*
|
| 8 |
+
* Similar to Skills, but for custom subagents defined in AGENT.md files.
|
| 9 |
+
*/
|
| 10 |
+
|
| 11 |
+
import path from 'path';
|
| 12 |
+
import os from 'os';
|
| 13 |
+
import { createLogger } from '@automaker/utils';
|
| 14 |
+
import { secureFs, systemPaths } from '@automaker/platform';
|
| 15 |
+
import type { AgentDefinition } from '@automaker/types';
|
| 16 |
+
|
| 17 |
+
const logger = createLogger('AgentDiscovery');
|
| 18 |
+
|
| 19 |
+
export interface FilesystemAgent {
|
| 20 |
+
name: string; // Directory name (e.g., 'code-reviewer')
|
| 21 |
+
definition: AgentDefinition;
|
| 22 |
+
source: 'user' | 'project';
|
| 23 |
+
filePath: string; // Full path to AGENT.md
|
| 24 |
+
}
|
| 25 |
+
|
| 26 |
+
/**
|
| 27 |
+
* Parse agent content string into AgentDefinition
|
| 28 |
+
* Format:
|
| 29 |
+
* ---
|
| 30 |
+
* name: agent-name # Optional
|
| 31 |
+
* description: When to use this agent
|
| 32 |
+
* tools: tool1, tool2, tool3 # Optional (comma or space separated list)
|
| 33 |
+
* model: sonnet # Optional: sonnet, opus, haiku
|
| 34 |
+
* ---
|
| 35 |
+
* System prompt content here...
|
| 36 |
+
*/
|
| 37 |
+
function parseAgentContent(content: string, filePath: string): AgentDefinition | null {
|
| 38 |
+
// Extract frontmatter
|
| 39 |
+
const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
|
| 40 |
+
if (!frontmatterMatch) {
|
| 41 |
+
logger.warn(`Invalid agent file format (missing frontmatter): ${filePath}`);
|
| 42 |
+
return null;
|
| 43 |
+
}
|
| 44 |
+
|
| 45 |
+
const [, frontmatter, prompt] = frontmatterMatch;
|
| 46 |
+
|
| 47 |
+
// Parse description (required)
|
| 48 |
+
const description = frontmatter.match(/description:\s*(.+)/)?.[1]?.trim();
|
| 49 |
+
if (!description) {
|
| 50 |
+
logger.warn(`Missing description in agent file: ${filePath}`);
|
| 51 |
+
return null;
|
| 52 |
+
}
|
| 53 |
+
|
| 54 |
+
// Parse tools (optional) - supports both comma-separated and space-separated
|
| 55 |
+
const toolsMatch = frontmatter.match(/tools:\s*(.+)/);
|
| 56 |
+
const tools = toolsMatch
|
| 57 |
+
? toolsMatch[1]
|
| 58 |
+
.split(/[,\s]+/) // Split by comma or whitespace
|
| 59 |
+
.map((t) => t.trim())
|
| 60 |
+
.filter((t) => t && t !== '')
|
| 61 |
+
: undefined;
|
| 62 |
+
|
| 63 |
+
// Parse model (optional) - validate against allowed values
|
| 64 |
+
const modelMatch = frontmatter.match(/model:\s*(\w+)/);
|
| 65 |
+
const modelValue = modelMatch?.[1]?.trim();
|
| 66 |
+
const validModels = ['sonnet', 'opus', 'haiku', 'inherit'] as const;
|
| 67 |
+
const model =
|
| 68 |
+
modelValue && validModels.includes(modelValue as (typeof validModels)[number])
|
| 69 |
+
? (modelValue as 'sonnet' | 'opus' | 'haiku' | 'inherit')
|
| 70 |
+
: undefined;
|
| 71 |
+
|
| 72 |
+
if (modelValue && !model) {
|
| 73 |
+
logger.warn(
|
| 74 |
+
`Invalid model "${modelValue}" in agent file: ${filePath}. Expected one of: ${validModels.join(', ')}`
|
| 75 |
+
);
|
| 76 |
+
}
|
| 77 |
+
|
| 78 |
+
return {
|
| 79 |
+
description,
|
| 80 |
+
prompt: prompt.trim(),
|
| 81 |
+
tools,
|
| 82 |
+
model,
|
| 83 |
+
};
|
| 84 |
+
}
|
| 85 |
+
|
| 86 |
+
/**
|
| 87 |
+
* Directory entry with type information
|
| 88 |
+
*/
|
| 89 |
+
interface DirEntry {
|
| 90 |
+
name: string;
|
| 91 |
+
isFile: boolean;
|
| 92 |
+
isDirectory: boolean;
|
| 93 |
+
}
|
| 94 |
+
|
| 95 |
+
/**
|
| 96 |
+
* Filesystem adapter interface for abstracting systemPaths vs secureFs
|
| 97 |
+
*/
|
| 98 |
+
interface FsAdapter {
|
| 99 |
+
exists: (filePath: string) => Promise<boolean>;
|
| 100 |
+
readdir: (dirPath: string) => Promise<DirEntry[]>;
|
| 101 |
+
readFile: (filePath: string) => Promise<string>;
|
| 102 |
+
}
|
| 103 |
+
|
| 104 |
+
/**
|
| 105 |
+
* Create a filesystem adapter for system paths (user directory)
|
| 106 |
+
*/
|
| 107 |
+
function createSystemPathAdapter(): FsAdapter {
|
| 108 |
+
return {
|
| 109 |
+
exists: (filePath) => Promise.resolve(systemPaths.systemPathExists(filePath)),
|
| 110 |
+
readdir: async (dirPath) => {
|
| 111 |
+
const entryNames = await systemPaths.systemPathReaddir(dirPath);
|
| 112 |
+
const entries: DirEntry[] = [];
|
| 113 |
+
for (const name of entryNames) {
|
| 114 |
+
const stat = await systemPaths.systemPathStat(path.join(dirPath, name));
|
| 115 |
+
entries.push({
|
| 116 |
+
name,
|
| 117 |
+
isFile: stat.isFile(),
|
| 118 |
+
isDirectory: stat.isDirectory(),
|
| 119 |
+
});
|
| 120 |
+
}
|
| 121 |
+
return entries;
|
| 122 |
+
},
|
| 123 |
+
readFile: (filePath) => systemPaths.systemPathReadFile(filePath, 'utf-8') as Promise<string>,
|
| 124 |
+
};
|
| 125 |
+
}
|
| 126 |
+
|
| 127 |
+
/**
|
| 128 |
+
* Create a filesystem adapter for project paths (secureFs)
|
| 129 |
+
*/
|
| 130 |
+
function createSecureFsAdapter(): FsAdapter {
|
| 131 |
+
return {
|
| 132 |
+
exists: (filePath) =>
|
| 133 |
+
secureFs
|
| 134 |
+
.access(filePath)
|
| 135 |
+
.then(() => true)
|
| 136 |
+
.catch(() => false),
|
| 137 |
+
readdir: async (dirPath) => {
|
| 138 |
+
const entries = await secureFs.readdir(dirPath, { withFileTypes: true });
|
| 139 |
+
return entries.map((entry) => ({
|
| 140 |
+
name: entry.name,
|
| 141 |
+
isFile: entry.isFile(),
|
| 142 |
+
isDirectory: entry.isDirectory(),
|
| 143 |
+
}));
|
| 144 |
+
},
|
| 145 |
+
readFile: (filePath) => secureFs.readFile(filePath, 'utf-8') as Promise<string>,
|
| 146 |
+
};
|
| 147 |
+
}
|
| 148 |
+
|
| 149 |
+
/**
|
| 150 |
+
* Parse agent file using the provided filesystem adapter
|
| 151 |
+
*/
|
| 152 |
+
async function parseAgentFileWithAdapter(
|
| 153 |
+
filePath: string,
|
| 154 |
+
fsAdapter: FsAdapter
|
| 155 |
+
): Promise<AgentDefinition | null> {
|
| 156 |
+
try {
|
| 157 |
+
const content = await fsAdapter.readFile(filePath);
|
| 158 |
+
return parseAgentContent(content, filePath);
|
| 159 |
+
} catch (error) {
|
| 160 |
+
logger.error(`Failed to parse agent file: ${filePath}`, error);
|
| 161 |
+
return null;
|
| 162 |
+
}
|
| 163 |
+
}
|
| 164 |
+
|
| 165 |
+
/**
|
| 166 |
+
* Scan a directory for agent .md files
|
| 167 |
+
* Agents can be in two formats:
|
| 168 |
+
* 1. Flat: agent-name.md (file directly in agents/)
|
| 169 |
+
* 2. Subdirectory: agent-name/AGENT.md (folder + file, similar to Skills)
|
| 170 |
+
*/
|
| 171 |
+
async function scanAgentsDirectory(
|
| 172 |
+
baseDir: string,
|
| 173 |
+
source: 'user' | 'project'
|
| 174 |
+
): Promise<FilesystemAgent[]> {
|
| 175 |
+
const agents: FilesystemAgent[] = [];
|
| 176 |
+
const fsAdapter = source === 'user' ? createSystemPathAdapter() : createSecureFsAdapter();
|
| 177 |
+
|
| 178 |
+
try {
|
| 179 |
+
// Check if directory exists
|
| 180 |
+
const exists = await fsAdapter.exists(baseDir);
|
| 181 |
+
if (!exists) {
|
| 182 |
+
logger.debug(`Directory does not exist: ${baseDir}`);
|
| 183 |
+
return agents;
|
| 184 |
+
}
|
| 185 |
+
|
| 186 |
+
// Read all entries in the directory
|
| 187 |
+
const entries = await fsAdapter.readdir(baseDir);
|
| 188 |
+
|
| 189 |
+
for (const entry of entries) {
|
| 190 |
+
// Check for flat .md file format (agent-name.md)
|
| 191 |
+
if (entry.isFile && entry.name.endsWith('.md')) {
|
| 192 |
+
const agentName = entry.name.slice(0, -3); // Remove .md extension
|
| 193 |
+
const agentFilePath = path.join(baseDir, entry.name);
|
| 194 |
+
const definition = await parseAgentFileWithAdapter(agentFilePath, fsAdapter);
|
| 195 |
+
if (definition) {
|
| 196 |
+
agents.push({
|
| 197 |
+
name: agentName,
|
| 198 |
+
definition,
|
| 199 |
+
source,
|
| 200 |
+
filePath: agentFilePath,
|
| 201 |
+
});
|
| 202 |
+
logger.debug(`Discovered ${source} agent (flat): ${agentName}`);
|
| 203 |
+
}
|
| 204 |
+
}
|
| 205 |
+
// Check for subdirectory format (agent-name/AGENT.md)
|
| 206 |
+
else if (entry.isDirectory) {
|
| 207 |
+
const agentFilePath = path.join(baseDir, entry.name, 'AGENT.md');
|
| 208 |
+
const agentFileExists = await fsAdapter.exists(agentFilePath);
|
| 209 |
+
|
| 210 |
+
if (agentFileExists) {
|
| 211 |
+
const definition = await parseAgentFileWithAdapter(agentFilePath, fsAdapter);
|
| 212 |
+
if (definition) {
|
| 213 |
+
agents.push({
|
| 214 |
+
name: entry.name,
|
| 215 |
+
definition,
|
| 216 |
+
source,
|
| 217 |
+
filePath: agentFilePath,
|
| 218 |
+
});
|
| 219 |
+
logger.debug(`Discovered ${source} agent (subdirectory): ${entry.name}`);
|
| 220 |
+
}
|
| 221 |
+
}
|
| 222 |
+
}
|
| 223 |
+
}
|
| 224 |
+
} catch (error) {
|
| 225 |
+
logger.error(`Failed to scan agents directory: ${baseDir}`, error);
|
| 226 |
+
}
|
| 227 |
+
|
| 228 |
+
return agents;
|
| 229 |
+
}
|
| 230 |
+
|
| 231 |
+
/**
|
| 232 |
+
* Discover all filesystem-based agents from user and project sources
|
| 233 |
+
*/
|
| 234 |
+
export async function discoverFilesystemAgents(
|
| 235 |
+
projectPath?: string,
|
| 236 |
+
sources: Array<'user' | 'project'> = ['user', 'project']
|
| 237 |
+
): Promise<FilesystemAgent[]> {
|
| 238 |
+
const agents: FilesystemAgent[] = [];
|
| 239 |
+
|
| 240 |
+
// Discover user-level agents from ~/.claude/agents/
|
| 241 |
+
if (sources.includes('user')) {
|
| 242 |
+
const userAgentsDir = path.join(os.homedir(), '.claude', 'agents');
|
| 243 |
+
const userAgents = await scanAgentsDirectory(userAgentsDir, 'user');
|
| 244 |
+
agents.push(...userAgents);
|
| 245 |
+
logger.info(`Discovered ${userAgents.length} user-level agents from ${userAgentsDir}`);
|
| 246 |
+
}
|
| 247 |
+
|
| 248 |
+
// Discover project-level agents from .claude/agents/
|
| 249 |
+
if (sources.includes('project') && projectPath) {
|
| 250 |
+
const projectAgentsDir = path.join(projectPath, '.claude', 'agents');
|
| 251 |
+
const projectAgents = await scanAgentsDirectory(projectAgentsDir, 'project');
|
| 252 |
+
agents.push(...projectAgents);
|
| 253 |
+
logger.info(`Discovered ${projectAgents.length} project-level agents from ${projectAgentsDir}`);
|
| 254 |
+
}
|
| 255 |
+
|
| 256 |
+
return agents;
|
| 257 |
+
}
|
jules_branch/apps/server/src/lib/app-spec-format.ts
ADDED
|
@@ -0,0 +1,210 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/**
|
| 2 |
+
* XML Template Format Specification for app_spec.txt
|
| 3 |
+
*
|
| 4 |
+
* This format must be included in all prompts that generate, modify, or regenerate
|
| 5 |
+
* app specifications to ensure consistency across the application.
|
| 6 |
+
*/
|
| 7 |
+
|
| 8 |
+
// Import and re-export spec types from shared package
|
| 9 |
+
export type { SpecOutput } from '@automaker/types';
|
| 10 |
+
export { specOutputSchema } from '@automaker/types';
|
| 11 |
+
|
| 12 |
+
/**
|
| 13 |
+
* Escape special XML characters
|
| 14 |
+
* Handles undefined/null values by converting them to empty strings
|
| 15 |
+
*/
|
| 16 |
+
export function escapeXml(str: string | undefined | null): string {
|
| 17 |
+
if (str == null) {
|
| 18 |
+
return '';
|
| 19 |
+
}
|
| 20 |
+
return str
|
| 21 |
+
.replace(/&/g, '&')
|
| 22 |
+
.replace(/</g, '<')
|
| 23 |
+
.replace(/>/g, '>')
|
| 24 |
+
.replace(/"/g, '"')
|
| 25 |
+
.replace(/'/g, ''');
|
| 26 |
+
}
|
| 27 |
+
|
| 28 |
+
/**
|
| 29 |
+
* Convert structured spec output to XML format
|
| 30 |
+
*/
|
| 31 |
+
export function specToXml(spec: import('@automaker/types').SpecOutput): string {
|
| 32 |
+
const indent = ' ';
|
| 33 |
+
|
| 34 |
+
let xml = `<?xml version="1.0" encoding="UTF-8"?>
|
| 35 |
+
<project_specification>
|
| 36 |
+
${indent}<project_name>${escapeXml(spec.project_name)}</project_name>
|
| 37 |
+
|
| 38 |
+
${indent}<overview>
|
| 39 |
+
${indent}${indent}${escapeXml(spec.overview)}
|
| 40 |
+
${indent}</overview>
|
| 41 |
+
|
| 42 |
+
${indent}<technology_stack>
|
| 43 |
+
${spec.technology_stack.map((t) => `${indent}${indent}<technology>${escapeXml(t)}</technology>`).join('\n')}
|
| 44 |
+
${indent}</technology_stack>
|
| 45 |
+
|
| 46 |
+
${indent}<core_capabilities>
|
| 47 |
+
${spec.core_capabilities.map((c) => `${indent}${indent}<capability>${escapeXml(c)}</capability>`).join('\n')}
|
| 48 |
+
${indent}</core_capabilities>
|
| 49 |
+
|
| 50 |
+
${indent}<implemented_features>
|
| 51 |
+
${spec.implemented_features
|
| 52 |
+
.map(
|
| 53 |
+
(f) => `${indent}${indent}<feature>
|
| 54 |
+
${indent}${indent}${indent}<name>${escapeXml(f.name)}</name>
|
| 55 |
+
${indent}${indent}${indent}<description>${escapeXml(f.description)}</description>${
|
| 56 |
+
f.file_locations && f.file_locations.length > 0
|
| 57 |
+
? `\n${indent}${indent}${indent}<file_locations>
|
| 58 |
+
${f.file_locations.map((loc) => `${indent}${indent}${indent}${indent}<location>${escapeXml(loc)}</location>`).join('\n')}
|
| 59 |
+
${indent}${indent}${indent}</file_locations>`
|
| 60 |
+
: ''
|
| 61 |
+
}
|
| 62 |
+
${indent}${indent}</feature>`
|
| 63 |
+
)
|
| 64 |
+
.join('\n')}
|
| 65 |
+
${indent}</implemented_features>`;
|
| 66 |
+
|
| 67 |
+
// Optional sections
|
| 68 |
+
if (spec.additional_requirements && spec.additional_requirements.length > 0) {
|
| 69 |
+
xml += `
|
| 70 |
+
|
| 71 |
+
${indent}<additional_requirements>
|
| 72 |
+
${spec.additional_requirements.map((r) => `${indent}${indent}<requirement>${escapeXml(r)}</requirement>`).join('\n')}
|
| 73 |
+
${indent}</additional_requirements>`;
|
| 74 |
+
}
|
| 75 |
+
|
| 76 |
+
if (spec.development_guidelines && spec.development_guidelines.length > 0) {
|
| 77 |
+
xml += `
|
| 78 |
+
|
| 79 |
+
${indent}<development_guidelines>
|
| 80 |
+
${spec.development_guidelines.map((g) => `${indent}${indent}<guideline>${escapeXml(g)}</guideline>`).join('\n')}
|
| 81 |
+
${indent}</development_guidelines>`;
|
| 82 |
+
}
|
| 83 |
+
|
| 84 |
+
if (spec.implementation_roadmap && spec.implementation_roadmap.length > 0) {
|
| 85 |
+
xml += `
|
| 86 |
+
|
| 87 |
+
${indent}<implementation_roadmap>
|
| 88 |
+
${spec.implementation_roadmap
|
| 89 |
+
.map(
|
| 90 |
+
(r) => `${indent}${indent}<phase>
|
| 91 |
+
${indent}${indent}${indent}<name>${escapeXml(r.phase)}</name>
|
| 92 |
+
${indent}${indent}${indent}<status>${escapeXml(r.status)}</status>
|
| 93 |
+
${indent}${indent}${indent}<description>${escapeXml(r.description)}</description>
|
| 94 |
+
${indent}${indent}</phase>`
|
| 95 |
+
)
|
| 96 |
+
.join('\n')}
|
| 97 |
+
${indent}</implementation_roadmap>`;
|
| 98 |
+
}
|
| 99 |
+
|
| 100 |
+
xml += `
|
| 101 |
+
</project_specification>`;
|
| 102 |
+
|
| 103 |
+
return xml;
|
| 104 |
+
}
|
| 105 |
+
|
| 106 |
+
/**
|
| 107 |
+
* Get prompt instruction for structured output (simpler than XML instructions)
|
| 108 |
+
*/
|
| 109 |
+
export function getStructuredSpecPromptInstruction(): string {
|
| 110 |
+
return `
|
| 111 |
+
Analyze the project and provide a comprehensive specification with:
|
| 112 |
+
|
| 113 |
+
1. **project_name**: The name of the project
|
| 114 |
+
2. **overview**: A comprehensive description of what the project does, its purpose, and key goals
|
| 115 |
+
3. **technology_stack**: List all technologies, frameworks, libraries, and tools used
|
| 116 |
+
4. **core_capabilities**: List the main features and capabilities the project provides
|
| 117 |
+
5. **implemented_features**: For each implemented feature, provide:
|
| 118 |
+
- name: Feature name
|
| 119 |
+
- description: What it does
|
| 120 |
+
- file_locations: Key files where it's implemented (optional)
|
| 121 |
+
6. **additional_requirements**: Any system requirements, dependencies, or constraints (optional)
|
| 122 |
+
7. **development_guidelines**: Development standards and best practices (optional)
|
| 123 |
+
8. **implementation_roadmap**: Project phases with status (completed/in_progress/pending) (optional)
|
| 124 |
+
|
| 125 |
+
Be thorough in your analysis. The output will be automatically formatted as structured JSON.
|
| 126 |
+
`;
|
| 127 |
+
}
|
| 128 |
+
export const APP_SPEC_XML_FORMAT = `
|
| 129 |
+
The app_spec.txt file MUST follow this exact XML format:
|
| 130 |
+
|
| 131 |
+
<project_specification>
|
| 132 |
+
<project_name>Project Name</project_name>
|
| 133 |
+
|
| 134 |
+
<overview>
|
| 135 |
+
A comprehensive description of what the project does, its purpose, and key goals.
|
| 136 |
+
</overview>
|
| 137 |
+
|
| 138 |
+
<technology_stack>
|
| 139 |
+
<technology>Technology 1</technology>
|
| 140 |
+
<technology>Technology 2</technology>
|
| 141 |
+
<!-- List all technologies, frameworks, libraries, and tools used -->
|
| 142 |
+
</technology_stack>
|
| 143 |
+
|
| 144 |
+
<core_capabilities>
|
| 145 |
+
<capability>Core capability 1</capability>
|
| 146 |
+
<capability>Core capability 2</capability>
|
| 147 |
+
<!-- List main features and capabilities the project provides -->
|
| 148 |
+
</core_capabilities>
|
| 149 |
+
|
| 150 |
+
<implemented_features>
|
| 151 |
+
<!-- Features that have been implemented (populated by AI agent based on code analysis) -->
|
| 152 |
+
</implemented_features>
|
| 153 |
+
|
| 154 |
+
<!-- Optional sections that may be included: -->
|
| 155 |
+
<additional_requirements>
|
| 156 |
+
<!-- Any additional requirements or constraints -->
|
| 157 |
+
</additional_requirements>
|
| 158 |
+
|
| 159 |
+
<development_guidelines>
|
| 160 |
+
<guideline>Guideline 1</guideline>
|
| 161 |
+
<guideline>Guideline 2</guideline>
|
| 162 |
+
<!-- Development standards and practices -->
|
| 163 |
+
</development_guidelines>
|
| 164 |
+
|
| 165 |
+
<implementation_roadmap>
|
| 166 |
+
<!-- Phases or roadmap items for implementation -->
|
| 167 |
+
</implementation_roadmap>
|
| 168 |
+
</project_specification>
|
| 169 |
+
|
| 170 |
+
IMPORTANT:
|
| 171 |
+
- All content must be wrapped in valid XML tags
|
| 172 |
+
- Use proper XML escaping for special characters (<, >, &)
|
| 173 |
+
- Maintain proper indentation (2 spaces)
|
| 174 |
+
- All sections should be populated based on project analysis
|
| 175 |
+
- The format must be strictly followed - do not use markdown, JSON, or any other format
|
| 176 |
+
`;
|
| 177 |
+
|
| 178 |
+
/**
|
| 179 |
+
* Returns a prompt suffix that instructs the AI to format the response as XML
|
| 180 |
+
* following the app_spec.txt template format.
|
| 181 |
+
*/
|
| 182 |
+
export function getAppSpecFormatInstruction(): string {
|
| 183 |
+
return `
|
| 184 |
+
${APP_SPEC_XML_FORMAT}
|
| 185 |
+
|
| 186 |
+
CRITICAL FORMATTING REQUIREMENTS:
|
| 187 |
+
- Do NOT use the Write, Edit, or Bash tools to create files - just OUTPUT the XML in your response
|
| 188 |
+
- Your ENTIRE response MUST be valid XML following the exact template structure above
|
| 189 |
+
- Do NOT use markdown formatting (no # headers, no **bold**, no - lists, etc.)
|
| 190 |
+
- Do NOT include any explanatory text, prefix, or suffix outside the XML tags
|
| 191 |
+
- Do NOT include phrases like "Based on my analysis...", "I'll create...", "Let me analyze..." before the XML
|
| 192 |
+
- Do NOT include any text before <project_specification> or after </project_specification>
|
| 193 |
+
- Your response must start IMMEDIATELY with <project_specification> with no preceding text
|
| 194 |
+
- Your response must end IMMEDIATELY with </project_specification> with no following text
|
| 195 |
+
- Use ONLY XML tags as shown in the template
|
| 196 |
+
- Properly escape XML special characters (< for <, > for >, & for &)
|
| 197 |
+
- Maintain 2-space indentation for readability
|
| 198 |
+
- The output will be saved directly to app_spec.txt and must be parseable as valid XML
|
| 199 |
+
- The response must contain exactly ONE root XML element: <project_specification>
|
| 200 |
+
- Do not include code blocks, markdown fences, or any other formatting
|
| 201 |
+
|
| 202 |
+
VERIFICATION: Before responding, verify that:
|
| 203 |
+
1. Your response starts with <project_specification> (no spaces, no text before it)
|
| 204 |
+
2. Your response ends with </project_specification> (no spaces, no text after it)
|
| 205 |
+
3. There is exactly one root XML element
|
| 206 |
+
4. There is no explanatory text, analysis, or commentary outside the XML tags
|
| 207 |
+
|
| 208 |
+
Your response should be ONLY the XML content, nothing else.
|
| 209 |
+
`;
|
| 210 |
+
}
|