Merge pull request #37 from AutoMaker-Org/refactor/monorepo-restructure
Refactor/monorepo restructure
8
.github/workflows/pr-check.yml
vendored
@@ -22,12 +22,12 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
node-version: "20"
|
node-version: "20"
|
||||||
cache: "npm"
|
cache: "npm"
|
||||||
cache-dependency-path: app/package-lock.json
|
cache-dependency-path: package-lock.json
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
working-directory: ./app
|
# Use npm install instead of npm ci to correctly resolve platform-specific
|
||||||
run: npm ci
|
# optional dependencies (e.g., @tailwindcss/oxide, lightningcss binaries)
|
||||||
|
run: npm install
|
||||||
|
|
||||||
- name: Run build:electron
|
- name: Run build:electron
|
||||||
working-directory: ./app
|
|
||||||
run: npm run build:electron
|
run: npm run build:electron
|
||||||
|
|||||||
34
.github/workflows/release.yml
vendored
@@ -3,13 +3,13 @@ name: Build and Release Electron App
|
|||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
tags:
|
tags:
|
||||||
- 'v*.*.*' # Triggers on version tags like v1.0.0
|
- "v*.*.*" # Triggers on version tags like v1.0.0
|
||||||
workflow_dispatch: # Allows manual triggering
|
workflow_dispatch: # Allows manual triggering
|
||||||
inputs:
|
inputs:
|
||||||
version:
|
version:
|
||||||
description: 'Version to release (e.g., v1.0.0)'
|
description: "Version to release (e.g., v1.0.0)"
|
||||||
required: true
|
required: true
|
||||||
default: 'v0.1.0'
|
default: "v0.1.0"
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build-and-release:
|
build-and-release:
|
||||||
@@ -36,31 +36,29 @@ jobs:
|
|||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: '20'
|
node-version: "20"
|
||||||
cache: 'npm'
|
cache: "npm"
|
||||||
cache-dependency-path: app/package-lock.json
|
cache-dependency-path: package-lock.json
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
working-directory: ./app
|
# Use npm install instead of npm ci to correctly resolve platform-specific
|
||||||
run: npm ci
|
# optional dependencies (e.g., @tailwindcss/oxide, lightningcss binaries)
|
||||||
|
run: npm install
|
||||||
|
|
||||||
- name: Build Electron App (macOS)
|
- name: Build Electron App (macOS)
|
||||||
if: matrix.os == 'macos-latest'
|
if: matrix.os == 'macos-latest'
|
||||||
working-directory: ./app
|
|
||||||
env:
|
env:
|
||||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
run: npm run build:electron -- --mac --x64 --arm64
|
run: npm run build:electron -- --mac --x64 --arm64
|
||||||
|
|
||||||
- name: Build Electron App (Windows)
|
- name: Build Electron App (Windows)
|
||||||
if: matrix.os == 'windows-latest'
|
if: matrix.os == 'windows-latest'
|
||||||
working-directory: ./app
|
|
||||||
env:
|
env:
|
||||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
run: npm run build:electron -- --win --x64
|
run: npm run build:electron -- --win --x64
|
||||||
|
|
||||||
- name: Build Electron App (Linux)
|
- name: Build Electron App (Linux)
|
||||||
if: matrix.os == 'ubuntu-latest'
|
if: matrix.os == 'ubuntu-latest'
|
||||||
working-directory: ./app
|
|
||||||
env:
|
env:
|
||||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
run: npm run build:electron -- --linux --x64
|
run: npm run build:electron -- --linux --x64
|
||||||
@@ -70,12 +68,12 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
tag_name: ${{ github.event.inputs.version || github.ref_name }}
|
tag_name: ${{ github.event.inputs.version || github.ref_name }}
|
||||||
files: |
|
files: |
|
||||||
app/dist/*.exe
|
apps/app/dist/*.exe
|
||||||
app/dist/*.dmg
|
apps/app/dist/*.dmg
|
||||||
app/dist/*.AppImage
|
apps/app/dist/*.AppImage
|
||||||
app/dist/*.zip
|
apps/app/dist/*.zip
|
||||||
app/dist/*.deb
|
apps/app/dist/*.deb
|
||||||
app/dist/*.rpm
|
apps/app/dist/*.rpm
|
||||||
draft: false
|
draft: false
|
||||||
prerelease: false
|
prerelease: false
|
||||||
env:
|
env:
|
||||||
|
|||||||
9
.gitignore
vendored
@@ -1,2 +1,9 @@
|
|||||||
#added by trueheads > will remove once supercombo adds multi-os support
|
#added by trueheads > will remove once supercombo adds multi-os support
|
||||||
launch.sh
|
launch.sh
|
||||||
|
|
||||||
|
# Dependencies
|
||||||
|
node_modules/
|
||||||
|
|
||||||
|
# Build outputs
|
||||||
|
dist/
|
||||||
|
.next/
|
||||||
|
|||||||
10
.npmrc
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
# Cross-platform compatibility for Tailwind CSS v4 and lightningcss
|
||||||
|
# These packages use platform-specific optional dependencies that npm
|
||||||
|
# automatically resolves based on your OS (macOS, Linux, Windows, WSL)
|
||||||
|
#
|
||||||
|
# IMPORTANT: When switching platforms or getting platform mismatch errors:
|
||||||
|
# 1. Delete node_modules: rm -rf node_modules apps/*/node_modules
|
||||||
|
# 2. Run: npm install
|
||||||
|
#
|
||||||
|
# In CI/CD: Use "npm install" instead of "npm ci" to allow npm to resolve
|
||||||
|
# the correct platform-specific binaries at install time.
|
||||||
14605
app/package-lock.json
generated
0
app/.gitignore → apps/app/.gitignore
vendored
@@ -42,7 +42,10 @@ function createWindow() {
|
|||||||
const isDev = !app.isPackaged;
|
const isDev = !app.isPackaged;
|
||||||
if (isDev) {
|
if (isDev) {
|
||||||
mainWindow.loadURL("http://localhost:3007");
|
mainWindow.loadURL("http://localhost:3007");
|
||||||
// mainWindow.webContents.openDevTools();
|
// Open DevTools if OPEN_DEVTOOLS environment variable is set
|
||||||
|
if (process.env.OPEN_DEVTOOLS === "true") {
|
||||||
|
mainWindow.webContents.openDevTools();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
mainWindow.loadFile(path.join(__dirname, "../.next/server/app/index.html"));
|
mainWindow.loadFile(path.join(__dirname, "../.next/server/app/index.html"));
|
||||||
}
|
}
|
||||||
@@ -894,12 +897,9 @@ ipcMain.handle(
|
|||||||
async (_, { featureId, status, projectPath, summary }) => {
|
async (_, { featureId, status, projectPath, summary }) => {
|
||||||
try {
|
try {
|
||||||
const featureLoader = require("./services/feature-loader");
|
const featureLoader = require("./services/feature-loader");
|
||||||
await featureLoader.updateFeatureStatus(
|
await featureLoader.updateFeatureStatus(featureId, status, projectPath, {
|
||||||
featureId,
|
summary,
|
||||||
status,
|
});
|
||||||
projectPath,
|
|
||||||
{ summary }
|
|
||||||
);
|
|
||||||
|
|
||||||
// Notify renderer if window is available
|
// Notify renderer if window is available
|
||||||
if (mainWindow && !mainWindow.isDestroyed()) {
|
if (mainWindow && !mainWindow.isDestroyed()) {
|
||||||
@@ -931,51 +931,59 @@ let suggestionsExecution = null;
|
|||||||
* @param {string} projectPath - The path to the project
|
* @param {string} projectPath - The path to the project
|
||||||
* @param {string} suggestionType - Type of suggestions: "features", "refactoring", "security", "performance"
|
* @param {string} suggestionType - Type of suggestions: "features", "refactoring", "security", "performance"
|
||||||
*/
|
*/
|
||||||
ipcMain.handle("suggestions:generate", async (_, { projectPath, suggestionType = "features" }) => {
|
ipcMain.handle(
|
||||||
try {
|
"suggestions:generate",
|
||||||
// Check if already running
|
async (_, { projectPath, suggestionType = "features" }) => {
|
||||||
if (suggestionsExecution && suggestionsExecution.isActive()) {
|
try {
|
||||||
return {
|
// Check if already running
|
||||||
success: false,
|
if (suggestionsExecution && suggestionsExecution.isActive()) {
|
||||||
error: "Suggestions generation is already running",
|
return {
|
||||||
};
|
success: false,
|
||||||
}
|
error: "Suggestions generation is already running",
|
||||||
|
};
|
||||||
// Create execution context
|
|
||||||
suggestionsExecution = {
|
|
||||||
abortController: null,
|
|
||||||
query: null,
|
|
||||||
isActive: () => suggestionsExecution !== null,
|
|
||||||
};
|
|
||||||
|
|
||||||
const sendToRenderer = (data) => {
|
|
||||||
if (mainWindow && !mainWindow.isDestroyed()) {
|
|
||||||
mainWindow.webContents.send("suggestions:event", data);
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
// Start generating suggestions (runs in background)
|
// Create execution context
|
||||||
featureSuggestionsService
|
suggestionsExecution = {
|
||||||
.generateSuggestions(projectPath, sendToRenderer, suggestionsExecution, suggestionType)
|
abortController: null,
|
||||||
.catch((error) => {
|
query: null,
|
||||||
console.error("[IPC] suggestions:generate background error:", error);
|
isActive: () => suggestionsExecution !== null,
|
||||||
sendToRenderer({
|
};
|
||||||
type: "suggestions_error",
|
|
||||||
error: error.message,
|
const sendToRenderer = (data) => {
|
||||||
|
if (mainWindow && !mainWindow.isDestroyed()) {
|
||||||
|
mainWindow.webContents.send("suggestions:event", data);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Start generating suggestions (runs in background)
|
||||||
|
featureSuggestionsService
|
||||||
|
.generateSuggestions(
|
||||||
|
projectPath,
|
||||||
|
sendToRenderer,
|
||||||
|
suggestionsExecution,
|
||||||
|
suggestionType
|
||||||
|
)
|
||||||
|
.catch((error) => {
|
||||||
|
console.error("[IPC] suggestions:generate background error:", error);
|
||||||
|
sendToRenderer({
|
||||||
|
type: "suggestions_error",
|
||||||
|
error: error.message,
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
suggestionsExecution = null;
|
||||||
});
|
});
|
||||||
})
|
|
||||||
.finally(() => {
|
|
||||||
suggestionsExecution = null;
|
|
||||||
});
|
|
||||||
|
|
||||||
// Return immediately
|
// Return immediately
|
||||||
return { success: true };
|
return { success: true };
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("[IPC] suggestions:generate error:", error);
|
console.error("[IPC] suggestions:generate error:", error);
|
||||||
suggestionsExecution = null;
|
suggestionsExecution = null;
|
||||||
return { success: false, error: error.message };
|
return { success: false, error: error.message };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stop the current suggestions generation
|
* Stop the current suggestions generation
|
||||||
@@ -1248,7 +1256,10 @@ ipcMain.handle(
|
|||||||
|
|
||||||
// Check if already running
|
// Check if already running
|
||||||
if (specRegenerationExecution && specRegenerationExecution.isActive()) {
|
if (specRegenerationExecution && specRegenerationExecution.isActive()) {
|
||||||
return { success: false, error: "Spec regeneration is already running" };
|
return {
|
||||||
|
success: false,
|
||||||
|
error: "Spec regeneration is already running",
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create execution context
|
// Create execution context
|
||||||
@@ -1266,7 +1277,11 @@ ipcMain.handle(
|
|||||||
|
|
||||||
// Start generating features (runs in background)
|
// Start generating features (runs in background)
|
||||||
specRegenerationService
|
specRegenerationService
|
||||||
.generateFeaturesOnly(projectPath, sendToRenderer, specRegenerationExecution)
|
.generateFeaturesOnly(
|
||||||
|
projectPath,
|
||||||
|
sendToRenderer,
|
||||||
|
specRegenerationExecution
|
||||||
|
)
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
console.error(
|
console.error(
|
||||||
"[IPC] spec-regeneration:generate-features background error:",
|
"[IPC] spec-regeneration:generate-features background error:",
|
||||||
@@ -1788,7 +1803,10 @@ ipcMain.handle(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const featureLoader = require("./services/feature-loader");
|
const featureLoader = require("./services/feature-loader");
|
||||||
const content = await featureLoader.getAgentOutput(projectPath, featureId);
|
const content = await featureLoader.getAgentOutput(
|
||||||
|
projectPath,
|
||||||
|
featureId
|
||||||
|
);
|
||||||
return { success: true, content };
|
return { success: true, content };
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("[IPC] features:getAgentOutput error:", error);
|
console.error("[IPC] features:getAgentOutput error:", error);
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "automaker",
|
"name": "@automaker/app",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"description": "An autonomous AI development studio that helps you build software faster using AI-powered agents",
|
"description": "An autonomous AI development studio that helps you build software faster using AI-powered agents",
|
||||||
"homepage": "https://github.com/AutoMaker-Org/automaker",
|
"homepage": "https://github.com/AutoMaker-Org/automaker",
|
||||||
@@ -18,6 +18,7 @@
|
|||||||
"dev": "next dev -p 3007",
|
"dev": "next dev -p 3007",
|
||||||
"dev:web": "next dev -p 3007",
|
"dev:web": "next dev -p 3007",
|
||||||
"dev:electron": "concurrently \"next dev -p 3007\" \"wait-on http://localhost:3007 && electron .\"",
|
"dev:electron": "concurrently \"next dev -p 3007\" \"wait-on http://localhost:3007 && electron .\"",
|
||||||
|
"dev:electron:debug": "concurrently \"next dev -p 3007\" \"wait-on http://localhost:3007 && OPEN_DEVTOOLS=true electron .\"",
|
||||||
"build": "next build",
|
"build": "next build",
|
||||||
"build:electron": "next build && electron-builder",
|
"build:electron": "next build && electron-builder",
|
||||||
"start": "next start",
|
"start": "next start",
|
||||||
@@ -47,6 +48,7 @@
|
|||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"cmdk": "^1.1.1",
|
"cmdk": "^1.1.1",
|
||||||
"dotenv": "^17.2.3",
|
"dotenv": "^17.2.3",
|
||||||
|
"geist": "^1.5.1",
|
||||||
"lucide-react": "^0.556.0",
|
"lucide-react": "^0.556.0",
|
||||||
"next": "16.0.7",
|
"next": "16.0.7",
|
||||||
"react": "19.2.0",
|
"react": "19.2.0",
|
||||||
@@ -76,6 +78,7 @@
|
|||||||
"build": {
|
"build": {
|
||||||
"appId": "com.automaker.app",
|
"appId": "com.automaker.app",
|
||||||
"productName": "Automaker",
|
"productName": "Automaker",
|
||||||
|
"artifactName": "${productName}-${version}-${arch}.${ext}",
|
||||||
"directories": {
|
"directories": {
|
||||||
"output": "dist"
|
"output": "dist"
|
||||||
},
|
},
|
||||||
@@ -143,7 +146,8 @@
|
|||||||
],
|
],
|
||||||
"category": "Development",
|
"category": "Development",
|
||||||
"icon": "public/logo_larger.png",
|
"icon": "public/logo_larger.png",
|
||||||
"maintainer": "webdevcody@gmail.com"
|
"maintainer": "webdevcody@gmail.com",
|
||||||
|
"executableName": "automaker"
|
||||||
},
|
},
|
||||||
"nsis": {
|
"nsis": {
|
||||||
"oneClick": false,
|
"oneClick": false,
|
||||||
|
Before Width: | Height: | Size: 391 B After Width: | Height: | Size: 391 B |
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 142 KiB After Width: | Height: | Size: 142 KiB |
|
Before Width: | Height: | Size: 147 KiB After Width: | Height: | Size: 147 KiB |
|
Before Width: | Height: | Size: 108 KiB After Width: | Height: | Size: 108 KiB |
|
Before Width: | Height: | Size: 262 KiB After Width: | Height: | Size: 262 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 128 B After Width: | Height: | Size: 128 B |
|
Before Width: | Height: | Size: 385 B After Width: | Height: | Size: 385 B |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
@@ -1,18 +1,8 @@
|
|||||||
import type { Metadata } from "next";
|
import type { Metadata } from "next";
|
||||||
import { Geist, Geist_Mono } from "next/font/google";
|
import { GeistSans } from "geist/font/sans";
|
||||||
|
import { GeistMono } from "geist/font/mono";
|
||||||
import { Toaster } from "sonner";
|
import { Toaster } from "sonner";
|
||||||
import "./globals.css";
|
import "./globals.css";
|
||||||
|
|
||||||
const geistSans = Geist({
|
|
||||||
variable: "--font-geist-sans",
|
|
||||||
subsets: ["latin"],
|
|
||||||
});
|
|
||||||
|
|
||||||
const geistMono = Geist_Mono({
|
|
||||||
variable: "--font-geist-mono",
|
|
||||||
subsets: ["latin"],
|
|
||||||
});
|
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: "Automaker - Autonomous AI Development Studio",
|
title: "Automaker - Autonomous AI Development Studio",
|
||||||
description: "Build software autonomously with intelligent orchestration",
|
description: "Build software autonomously with intelligent orchestration",
|
||||||
@@ -26,7 +16,7 @@ export default function RootLayout({
|
|||||||
return (
|
return (
|
||||||
<html lang="en" suppressHydrationWarning>
|
<html lang="en" suppressHydrationWarning>
|
||||||
<body
|
<body
|
||||||
className={`${geistSans.variable} ${geistMono.variable} antialiased`}
|
className={`${GeistSans.variable} ${GeistMono.variable} antialiased`}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
<Toaster richColors position="bottom-right" />
|
<Toaster richColors position="bottom-right" />
|
||||||
@@ -2322,11 +2322,11 @@ export function BoardView() {
|
|||||||
<div className="flex items-center space-x-2">
|
<div className="flex items-center space-x-2">
|
||||||
<Checkbox
|
<Checkbox
|
||||||
id="skip-tests"
|
id="skip-tests"
|
||||||
checked={newFeature.skipTests}
|
checked={!newFeature.skipTests}
|
||||||
onCheckedChange={(checked) =>
|
onCheckedChange={(checked) =>
|
||||||
setNewFeature({
|
setNewFeature({
|
||||||
...newFeature,
|
...newFeature,
|
||||||
skipTests: checked === true,
|
skipTests: checked !== true,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
data-testid="skip-tests-checkbox"
|
data-testid="skip-tests-checkbox"
|
||||||
@@ -2336,14 +2336,14 @@ export function BoardView() {
|
|||||||
htmlFor="skip-tests"
|
htmlFor="skip-tests"
|
||||||
className="text-sm cursor-pointer"
|
className="text-sm cursor-pointer"
|
||||||
>
|
>
|
||||||
Skip automated testing
|
Enable automated testing
|
||||||
</Label>
|
</Label>
|
||||||
<FlaskConical className="w-3.5 h-3.5 text-muted-foreground" />
|
<FlaskConical className="w-3.5 h-3.5 text-muted-foreground" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<p className="text-xs text-muted-foreground">
|
<p className="text-xs text-muted-foreground">
|
||||||
When enabled, this feature will require manual verification
|
When enabled, this feature will use automated TDD. When
|
||||||
instead of automated TDD.
|
disabled, it will require manual verification.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
{/* Verification Steps - Only shown when skipTests is enabled */}
|
{/* Verification Steps - Only shown when skipTests is enabled */}
|
||||||
@@ -2742,11 +2742,11 @@ export function BoardView() {
|
|||||||
<div className="flex items-center space-x-2">
|
<div className="flex items-center space-x-2">
|
||||||
<Checkbox
|
<Checkbox
|
||||||
id="edit-skip-tests"
|
id="edit-skip-tests"
|
||||||
checked={editingFeature.skipTests ?? false}
|
checked={!(editingFeature.skipTests ?? false)}
|
||||||
onCheckedChange={(checked) =>
|
onCheckedChange={(checked) =>
|
||||||
setEditingFeature({
|
setEditingFeature({
|
||||||
...editingFeature,
|
...editingFeature,
|
||||||
skipTests: checked === true,
|
skipTests: checked !== true,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
data-testid="edit-skip-tests-checkbox"
|
data-testid="edit-skip-tests-checkbox"
|
||||||
@@ -2756,14 +2756,14 @@ export function BoardView() {
|
|||||||
htmlFor="edit-skip-tests"
|
htmlFor="edit-skip-tests"
|
||||||
className="text-sm cursor-pointer"
|
className="text-sm cursor-pointer"
|
||||||
>
|
>
|
||||||
Skip automated testing
|
Enable automated testing
|
||||||
</Label>
|
</Label>
|
||||||
<FlaskConical className="w-3.5 h-3.5 text-muted-foreground" />
|
<FlaskConical className="w-3.5 h-3.5 text-muted-foreground" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<p className="text-xs text-muted-foreground">
|
<p className="text-xs text-muted-foreground">
|
||||||
When enabled, this feature will require manual verification
|
When enabled, this feature will use automated TDD. When
|
||||||
instead of automated TDD.
|
disabled, it will require manual verification.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
{/* Verification Steps - Only shown when skipTests is enabled */}
|
{/* Verification Steps - Only shown when skipTests is enabled */}
|
||||||