mirror of
https://github.com/AutoMaker-Org/automaker.git
synced 2026-02-05 09:33:07 +00:00
feat: enhance development environment with Docker support and UI improvements
- Introduced a new `docker-compose.dev.yml` for development mode, enabling live reload and improved container management. - Updated `dev.mjs` to utilize `launchDockerDevContainers` for starting development containers with live reload capabilities. - Refactored `printModeMenu` to differentiate between development and production Docker options. - Enhanced the `BoardView` and `KanbanBoard` components by streamlining props and improving UI interactions. - Removed the `start.mjs` script, consolidating production launch logic into `dev.mjs` for a more unified approach.
This commit is contained in:
@@ -55,6 +55,10 @@ RUN npm run build:packages && npm run build --workspace=apps/server
|
|||||||
# =============================================================================
|
# =============================================================================
|
||||||
FROM node:22-slim AS server
|
FROM node:22-slim AS server
|
||||||
|
|
||||||
|
# Build argument for tracking which commit this image was built from
|
||||||
|
ARG GIT_COMMIT_SHA=unknown
|
||||||
|
LABEL automaker.git.commit.sha="${GIT_COMMIT_SHA}"
|
||||||
|
|
||||||
# Install git, curl, bash (for terminal), gosu (for user switching), and GitHub CLI (pinned version, multi-arch)
|
# Install git, curl, bash (for terminal), gosu (for user switching), and GitHub CLI (pinned version, multi-arch)
|
||||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||||
git curl bash gosu ca-certificates openssh-client \
|
git curl bash gosu ca-certificates openssh-client \
|
||||||
@@ -184,6 +188,10 @@ RUN npm run build:packages && npm run build --workspace=apps/ui
|
|||||||
# =============================================================================
|
# =============================================================================
|
||||||
FROM nginx:alpine AS ui
|
FROM nginx:alpine AS ui
|
||||||
|
|
||||||
|
# Build argument for tracking which commit this image was built from
|
||||||
|
ARG GIT_COMMIT_SHA=unknown
|
||||||
|
LABEL automaker.git.commit.sha="${GIT_COMMIT_SHA}"
|
||||||
|
|
||||||
# Copy built files
|
# Copy built files
|
||||||
COPY --from=ui-builder /app/apps/ui/dist /usr/share/nginx/html
|
COPY --from=ui-builder /app/apps/ui/dist /usr/share/nginx/html
|
||||||
|
|
||||||
|
|||||||
80
Dockerfile.dev
Normal file
80
Dockerfile.dev
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
# Automaker Development Dockerfile
|
||||||
|
# For development with live reload via volume mounting
|
||||||
|
# Source code is NOT copied - it's mounted as a volume
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
# docker compose -f docker-compose.dev.yml up
|
||||||
|
|
||||||
|
FROM node:22-slim
|
||||||
|
|
||||||
|
# Install build dependencies for native modules (node-pty) and runtime tools
|
||||||
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||||
|
python3 make g++ \
|
||||||
|
git curl bash gosu ca-certificates openssh-client \
|
||||||
|
&& GH_VERSION="2.63.2" \
|
||||||
|
&& ARCH=$(uname -m) \
|
||||||
|
&& case "$ARCH" in \
|
||||||
|
x86_64) GH_ARCH="amd64" ;; \
|
||||||
|
aarch64|arm64) GH_ARCH="arm64" ;; \
|
||||||
|
*) echo "Unsupported architecture: $ARCH" && exit 1 ;; \
|
||||||
|
esac \
|
||||||
|
&& curl -L "https://github.com/cli/cli/releases/download/v${GH_VERSION}/gh_${GH_VERSION}_linux_${GH_ARCH}.tar.gz" -o gh.tar.gz \
|
||||||
|
&& tar -xzf gh.tar.gz \
|
||||||
|
&& mv gh_${GH_VERSION}_linux_${GH_ARCH}/bin/gh /usr/local/bin/gh \
|
||||||
|
&& rm -rf gh.tar.gz gh_${GH_VERSION}_linux_${GH_ARCH} \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
# Install Claude CLI globally
|
||||||
|
RUN npm install -g @anthropic-ai/claude-code
|
||||||
|
|
||||||
|
# Create non-root user
|
||||||
|
RUN groupadd -g 1001 automaker && \
|
||||||
|
useradd -u 1001 -g automaker -m -d /home/automaker -s /bin/bash automaker && \
|
||||||
|
mkdir -p /home/automaker/.local/bin && \
|
||||||
|
mkdir -p /home/automaker/.cursor && \
|
||||||
|
chown -R automaker:automaker /home/automaker && \
|
||||||
|
chmod 700 /home/automaker/.cursor
|
||||||
|
|
||||||
|
# Install Cursor CLI as automaker user
|
||||||
|
USER automaker
|
||||||
|
ENV HOME=/home/automaker
|
||||||
|
RUN curl https://cursor.com/install -fsS | bash || true
|
||||||
|
USER root
|
||||||
|
|
||||||
|
# Add PATH to profile for Cursor CLI
|
||||||
|
RUN mkdir -p /etc/profile.d && \
|
||||||
|
echo 'export PATH="/home/automaker/.local/bin:$PATH"' > /etc/profile.d/cursor-cli.sh && \
|
||||||
|
chmod +x /etc/profile.d/cursor-cli.sh
|
||||||
|
|
||||||
|
# Add to user bashrc files
|
||||||
|
RUN echo 'export PATH="/home/automaker/.local/bin:$PATH"' >> /home/automaker/.bashrc && \
|
||||||
|
chown automaker:automaker /home/automaker/.bashrc
|
||||||
|
RUN echo 'export PATH="/home/automaker/.local/bin:$PATH"' >> /root/.bashrc
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Create directories with proper permissions
|
||||||
|
RUN mkdir -p /data /projects && chown automaker:automaker /data /projects
|
||||||
|
|
||||||
|
# Configure git for mounted volumes
|
||||||
|
RUN git config --system --add safe.directory '*' && \
|
||||||
|
git config --system credential.helper '!gh auth git-credential'
|
||||||
|
|
||||||
|
# Copy entrypoint script
|
||||||
|
COPY docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh
|
||||||
|
RUN chmod +x /usr/local/bin/docker-entrypoint.sh
|
||||||
|
|
||||||
|
# Environment variables
|
||||||
|
ENV PORT=3008
|
||||||
|
ENV DATA_DIR=/data
|
||||||
|
ENV HOME=/home/automaker
|
||||||
|
ENV PATH="/home/automaker/.local/bin:${PATH}"
|
||||||
|
|
||||||
|
# Expose both dev ports
|
||||||
|
EXPOSE 3007 3008
|
||||||
|
|
||||||
|
# Use entrypoint for permission handling
|
||||||
|
ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"]
|
||||||
|
|
||||||
|
# Default command - will be overridden by docker-compose
|
||||||
|
CMD ["npm", "run", "dev:web"]
|
||||||
19
README.md
19
README.md
@@ -117,24 +117,16 @@ cd automaker
|
|||||||
# 2. Install dependencies
|
# 2. Install dependencies
|
||||||
npm install
|
npm install
|
||||||
|
|
||||||
# 3. Build shared packages (Now can be skipped npm install / run dev does it automaticly)
|
# 3. Build shared packages (can be skipped - npm run dev does it automatically)
|
||||||
npm run build:packages
|
npm run build:packages
|
||||||
|
|
||||||
# 4. Start Automaker (production mode)
|
# 4. Start Automaker
|
||||||
npm run start
|
npm run dev
|
||||||
# Choose between:
|
# Choose between:
|
||||||
# 1. Web Application (browser at localhost:3007)
|
# 1. Web Application (browser at localhost:3007)
|
||||||
# 2. Desktop Application (Electron - recommended)
|
# 2. Desktop Application (Electron - recommended)
|
||||||
```
|
```
|
||||||
|
|
||||||
**Note:** The `npm run start` command will:
|
|
||||||
|
|
||||||
- Check for dependencies and install if needed
|
|
||||||
- Build the application if needed
|
|
||||||
- Kill any processes on ports 3007/3008
|
|
||||||
- Present an interactive menu to choose your run mode
|
|
||||||
- Run in production mode (no hot reload)
|
|
||||||
|
|
||||||
**Authentication Setup:** On first run, Automaker will automatically show a setup wizard where you can configure authentication. You can choose to:
|
**Authentication Setup:** On first run, Automaker will automatically show a setup wizard where you can configure authentication. You can choose to:
|
||||||
|
|
||||||
- Use **Claude Code CLI** (recommended) - Automaker will detect your CLI credentials automatically
|
- Use **Claude Code CLI** (recommended) - Automaker will detect your CLI credentials automatically
|
||||||
@@ -150,7 +142,7 @@ export ANTHROPIC_API_KEY="sk-ant-..."
|
|||||||
echo "ANTHROPIC_API_KEY=sk-ant-..." > .env
|
echo "ANTHROPIC_API_KEY=sk-ant-..." > .env
|
||||||
```
|
```
|
||||||
|
|
||||||
**For Development:** If you want to develop on Automaker with Vite live reload and hot module replacement, use `npm run dev` instead. This will start the development server with fast refresh and instant updates as you make changes.
|
**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.
|
||||||
|
|
||||||
## How to Run
|
## How to Run
|
||||||
|
|
||||||
@@ -194,9 +186,6 @@ npm run dev:web
|
|||||||
```bash
|
```bash
|
||||||
# Build for web deployment (uses Vite)
|
# Build for web deployment (uses Vite)
|
||||||
npm run build
|
npm run build
|
||||||
|
|
||||||
# Run production build
|
|
||||||
npm run start
|
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Desktop Application
|
#### Desktop Application
|
||||||
|
|||||||
@@ -1151,8 +1151,6 @@ export function BoardView() {
|
|||||||
onDetailLevelChange={setKanbanCardDetailLevel}
|
onDetailLevelChange={setKanbanCardDetailLevel}
|
||||||
boardViewMode={boardViewMode}
|
boardViewMode={boardViewMode}
|
||||||
onBoardViewModeChange={setBoardViewMode}
|
onBoardViewModeChange={setBoardViewMode}
|
||||||
isSelectionMode={isSelectionMode}
|
|
||||||
onToggleSelectionMode={toggleSelectionMode}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{/* View Content - Kanban or Graph */}
|
{/* View Content - Kanban or Graph */}
|
||||||
@@ -1175,7 +1173,6 @@ export function BoardView() {
|
|||||||
onManualVerify={handleManualVerify}
|
onManualVerify={handleManualVerify}
|
||||||
onMoveBackToInProgress={handleMoveBackToInProgress}
|
onMoveBackToInProgress={handleMoveBackToInProgress}
|
||||||
onFollowUp={handleOpenFollowUp}
|
onFollowUp={handleOpenFollowUp}
|
||||||
onCommit={handleCommitFeature}
|
|
||||||
onComplete={handleCompleteFeature}
|
onComplete={handleCompleteFeature}
|
||||||
onImplement={handleStartImplementation}
|
onImplement={handleStartImplementation}
|
||||||
onViewPlan={(feature) => setViewPlanFeature(feature)}
|
onViewPlan={(feature) => setViewPlanFeature(feature)}
|
||||||
@@ -1186,8 +1183,6 @@ export function BoardView() {
|
|||||||
}}
|
}}
|
||||||
featuresWithContext={featuresWithContext}
|
featuresWithContext={featuresWithContext}
|
||||||
runningAutoTasks={runningAutoTasks}
|
runningAutoTasks={runningAutoTasks}
|
||||||
shortcuts={shortcuts}
|
|
||||||
onStartNextFeatures={handleStartNextFeatures}
|
|
||||||
onArchiveAllVerified={() => setShowArchiveAllVerifiedDialog(true)}
|
onArchiveAllVerified={() => setShowArchiveAllVerifiedDialog(true)}
|
||||||
pipelineConfig={
|
pipelineConfig={
|
||||||
currentProject?.path ? pipelineConfigByProject[currentProject.path] || null : null
|
currentProject?.path ? pipelineConfigByProject[currentProject.path] || null : null
|
||||||
@@ -1196,6 +1191,7 @@ export function BoardView() {
|
|||||||
isSelectionMode={isSelectionMode}
|
isSelectionMode={isSelectionMode}
|
||||||
selectedFeatureIds={selectedFeatureIds}
|
selectedFeatureIds={selectedFeatureIds}
|
||||||
onToggleFeatureSelection={toggleFeatureSelection}
|
onToggleFeatureSelection={toggleFeatureSelection}
|
||||||
|
onToggleSelectionMode={toggleSelectionMode}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<GraphView
|
<GraphView
|
||||||
|
|||||||
@@ -1,15 +1,6 @@
|
|||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip';
|
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip';
|
||||||
import {
|
import { ImageIcon, Archive, Minimize2, Square, Maximize2, Columns3, Network } from 'lucide-react';
|
||||||
ImageIcon,
|
|
||||||
Archive,
|
|
||||||
Minimize2,
|
|
||||||
Square,
|
|
||||||
Maximize2,
|
|
||||||
Columns3,
|
|
||||||
Network,
|
|
||||||
CheckSquare,
|
|
||||||
} from 'lucide-react';
|
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
import { BoardViewMode } from '@/store/app-store';
|
import { BoardViewMode } from '@/store/app-store';
|
||||||
|
|
||||||
@@ -22,8 +13,6 @@ interface BoardControlsProps {
|
|||||||
onDetailLevelChange: (level: 'minimal' | 'standard' | 'detailed') => void;
|
onDetailLevelChange: (level: 'minimal' | 'standard' | 'detailed') => void;
|
||||||
boardViewMode: BoardViewMode;
|
boardViewMode: BoardViewMode;
|
||||||
onBoardViewModeChange: (mode: BoardViewMode) => void;
|
onBoardViewModeChange: (mode: BoardViewMode) => void;
|
||||||
isSelectionMode?: boolean;
|
|
||||||
onToggleSelectionMode?: () => void;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function BoardControls({
|
export function BoardControls({
|
||||||
@@ -35,8 +24,6 @@ export function BoardControls({
|
|||||||
onDetailLevelChange,
|
onDetailLevelChange,
|
||||||
boardViewMode,
|
boardViewMode,
|
||||||
onBoardViewModeChange,
|
onBoardViewModeChange,
|
||||||
isSelectionMode = false,
|
|
||||||
onToggleSelectionMode,
|
|
||||||
}: BoardControlsProps) {
|
}: BoardControlsProps) {
|
||||||
if (!isMounted) return null;
|
if (!isMounted) return null;
|
||||||
|
|
||||||
@@ -88,24 +75,6 @@ export function BoardControls({
|
|||||||
</Tooltip>
|
</Tooltip>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Selection Mode Toggle */}
|
|
||||||
<Tooltip>
|
|
||||||
<TooltipTrigger asChild>
|
|
||||||
<Button
|
|
||||||
variant={isSelectionMode ? 'default' : 'outline'}
|
|
||||||
size="sm"
|
|
||||||
onClick={onToggleSelectionMode}
|
|
||||||
className={cn('h-8 px-2', isSelectionMode && 'bg-brand-500 hover:bg-brand-600')}
|
|
||||||
data-testid="selection-mode-button"
|
|
||||||
>
|
|
||||||
<CheckSquare className="w-4 h-4" />
|
|
||||||
</Button>
|
|
||||||
</TooltipTrigger>
|
|
||||||
<TooltipContent>
|
|
||||||
<p>{isSelectionMode ? 'Exit Select Mode' : 'Select Mode'}</p>
|
|
||||||
</TooltipContent>
|
|
||||||
</Tooltip>
|
|
||||||
|
|
||||||
{/* Board Background Button */}
|
{/* Board Background Button */}
|
||||||
<Tooltip>
|
<Tooltip>
|
||||||
<TooltipTrigger asChild>
|
<TooltipTrigger asChild>
|
||||||
|
|||||||
@@ -2,13 +2,11 @@ import { useMemo } from 'react';
|
|||||||
import { DndContext, DragOverlay } from '@dnd-kit/core';
|
import { DndContext, DragOverlay } from '@dnd-kit/core';
|
||||||
import { SortableContext, verticalListSortingStrategy } from '@dnd-kit/sortable';
|
import { SortableContext, verticalListSortingStrategy } from '@dnd-kit/sortable';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { HotkeyButton } from '@/components/ui/hotkey-button';
|
|
||||||
import { KanbanColumn, KanbanCard } from './components';
|
import { KanbanColumn, KanbanCard } from './components';
|
||||||
import { Feature } from '@/store/app-store';
|
import { Feature } from '@/store/app-store';
|
||||||
import { FastForward, Archive, Plus, Settings2 } from 'lucide-react';
|
import { Archive, Settings2, CheckSquare, GripVertical } from 'lucide-react';
|
||||||
import { useKeyboardShortcutsConfig } from '@/hooks/use-keyboard-shortcuts';
|
|
||||||
import { useResponsiveKanban } from '@/hooks/use-responsive-kanban';
|
import { useResponsiveKanban } from '@/hooks/use-responsive-kanban';
|
||||||
import { getColumnsWithPipeline, type Column, type ColumnId } from './constants';
|
import { getColumnsWithPipeline, type ColumnId } from './constants';
|
||||||
import type { PipelineConfig } from '@automaker/types';
|
import type { PipelineConfig } from '@automaker/types';
|
||||||
|
|
||||||
interface KanbanBoardProps {
|
interface KanbanBoardProps {
|
||||||
@@ -37,7 +35,6 @@ interface KanbanBoardProps {
|
|||||||
onManualVerify: (feature: Feature) => void;
|
onManualVerify: (feature: Feature) => void;
|
||||||
onMoveBackToInProgress: (feature: Feature) => void;
|
onMoveBackToInProgress: (feature: Feature) => void;
|
||||||
onFollowUp: (feature: Feature) => void;
|
onFollowUp: (feature: Feature) => void;
|
||||||
onCommit: (feature: Feature) => void;
|
|
||||||
onComplete: (feature: Feature) => void;
|
onComplete: (feature: Feature) => void;
|
||||||
onImplement: (feature: Feature) => void;
|
onImplement: (feature: Feature) => void;
|
||||||
onViewPlan: (feature: Feature) => void;
|
onViewPlan: (feature: Feature) => void;
|
||||||
@@ -45,8 +42,6 @@ interface KanbanBoardProps {
|
|||||||
onSpawnTask?: (feature: Feature) => void;
|
onSpawnTask?: (feature: Feature) => void;
|
||||||
featuresWithContext: Set<string>;
|
featuresWithContext: Set<string>;
|
||||||
runningAutoTasks: string[];
|
runningAutoTasks: string[];
|
||||||
shortcuts: ReturnType<typeof useKeyboardShortcutsConfig>;
|
|
||||||
onStartNextFeatures: () => void;
|
|
||||||
onArchiveAllVerified: () => void;
|
onArchiveAllVerified: () => void;
|
||||||
pipelineConfig: PipelineConfig | null;
|
pipelineConfig: PipelineConfig | null;
|
||||||
onOpenPipelineSettings?: () => void;
|
onOpenPipelineSettings?: () => void;
|
||||||
@@ -54,6 +49,7 @@ interface KanbanBoardProps {
|
|||||||
isSelectionMode?: boolean;
|
isSelectionMode?: boolean;
|
||||||
selectedFeatureIds?: Set<string>;
|
selectedFeatureIds?: Set<string>;
|
||||||
onToggleFeatureSelection?: (featureId: string) => void;
|
onToggleFeatureSelection?: (featureId: string) => void;
|
||||||
|
onToggleSelectionMode?: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function KanbanBoard({
|
export function KanbanBoard({
|
||||||
@@ -74,7 +70,6 @@ export function KanbanBoard({
|
|||||||
onManualVerify,
|
onManualVerify,
|
||||||
onMoveBackToInProgress,
|
onMoveBackToInProgress,
|
||||||
onFollowUp,
|
onFollowUp,
|
||||||
onCommit,
|
|
||||||
onComplete,
|
onComplete,
|
||||||
onImplement,
|
onImplement,
|
||||||
onViewPlan,
|
onViewPlan,
|
||||||
@@ -82,14 +77,13 @@ export function KanbanBoard({
|
|||||||
onSpawnTask,
|
onSpawnTask,
|
||||||
featuresWithContext,
|
featuresWithContext,
|
||||||
runningAutoTasks,
|
runningAutoTasks,
|
||||||
shortcuts,
|
|
||||||
onStartNextFeatures,
|
|
||||||
onArchiveAllVerified,
|
onArchiveAllVerified,
|
||||||
pipelineConfig,
|
pipelineConfig,
|
||||||
onOpenPipelineSettings,
|
onOpenPipelineSettings,
|
||||||
isSelectionMode = false,
|
isSelectionMode = false,
|
||||||
selectedFeatureIds = new Set(),
|
selectedFeatureIds = new Set(),
|
||||||
onToggleFeatureSelection,
|
onToggleFeatureSelection,
|
||||||
|
onToggleSelectionMode,
|
||||||
}: KanbanBoardProps) {
|
}: KanbanBoardProps) {
|
||||||
// Generate columns including pipeline steps
|
// Generate columns including pipeline steps
|
||||||
const columns = useMemo(() => getColumnsWithPipeline(pipelineConfig), [pipelineConfig]);
|
const columns = useMemo(() => getColumnsWithPipeline(pipelineConfig), [pipelineConfig]);
|
||||||
@@ -133,20 +127,26 @@ export function KanbanBoard({
|
|||||||
Complete All
|
Complete All
|
||||||
</Button>
|
</Button>
|
||||||
) : column.id === 'backlog' ? (
|
) : column.id === 'backlog' ? (
|
||||||
columnFeatures.length > 0 && (
|
<Button
|
||||||
<HotkeyButton
|
variant="ghost"
|
||||||
variant="ghost"
|
size="sm"
|
||||||
size="sm"
|
className={`h-6 px-2 text-xs ${isSelectionMode ? 'text-primary bg-primary/10' : 'text-muted-foreground hover:text-foreground'}`}
|
||||||
className="h-6 px-2 text-xs text-primary hover:text-primary hover:bg-primary/10"
|
onClick={onToggleSelectionMode}
|
||||||
onClick={onStartNextFeatures}
|
title={isSelectionMode ? 'Switch to Drag Mode' : 'Select Multiple'}
|
||||||
hotkey={shortcuts.startNext}
|
data-testid="selection-mode-button"
|
||||||
hotkeyActive={false}
|
>
|
||||||
data-testid="start-next-button"
|
{isSelectionMode ? (
|
||||||
>
|
<>
|
||||||
<FastForward className="w-3 h-3 mr-1" />
|
<GripVertical className="w-3.5 h-3.5 mr-1" />
|
||||||
Make
|
Drag
|
||||||
</HotkeyButton>
|
</>
|
||||||
)
|
) : (
|
||||||
|
<>
|
||||||
|
<CheckSquare className="w-3.5 h-3.5 mr-1" />
|
||||||
|
Select
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Button>
|
||||||
) : column.id === 'in_progress' ? (
|
) : column.id === 'in_progress' ? (
|
||||||
<Button
|
<Button
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
|
|||||||
6
dev.mjs
6
dev.mjs
@@ -26,7 +26,7 @@ import {
|
|||||||
startServerAndWait,
|
startServerAndWait,
|
||||||
ensureDependencies,
|
ensureDependencies,
|
||||||
prompt,
|
prompt,
|
||||||
launchDockerContainers,
|
launchDockerDevContainers,
|
||||||
} from './scripts/launcher-utils.mjs';
|
} from './scripts/launcher-utils.mjs';
|
||||||
|
|
||||||
const __filename = fileURLToPath(import.meta.url);
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
@@ -88,7 +88,7 @@ async function main() {
|
|||||||
const { webPort, serverPort, corsOriginEnv } = await resolvePortConfiguration();
|
const { webPort, serverPort, corsOriginEnv } = await resolvePortConfiguration();
|
||||||
|
|
||||||
// Show mode selection menu
|
// Show mode selection menu
|
||||||
printModeMenu();
|
printModeMenu({ isDev: true });
|
||||||
|
|
||||||
// Setup cleanup handlers
|
// Setup cleanup handlers
|
||||||
const cleanup = createCleanupHandler(processes);
|
const cleanup = createCleanupHandler(processes);
|
||||||
@@ -170,7 +170,7 @@ async function main() {
|
|||||||
break;
|
break;
|
||||||
} else if (choice === '3') {
|
} else if (choice === '3') {
|
||||||
console.log('');
|
console.log('');
|
||||||
await launchDockerContainers({ baseDir: __dirname, processes });
|
await launchDockerDevContainers({ baseDir: __dirname, processes });
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
log('Invalid choice. Please enter 1, 2, or 3.', 'red');
|
log('Invalid choice. Please enter 1, 2, or 3.', 'red');
|
||||||
|
|||||||
142
docker-compose.dev.yml
Normal file
142
docker-compose.dev.yml
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
# Automaker Docker Compose - Development Mode
|
||||||
|
# Runs Automaker with live reload for development.
|
||||||
|
# Source code is volume mounted for instant changes.
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
# docker compose -f docker-compose.dev.yml up
|
||||||
|
# Then open http://localhost:3007
|
||||||
|
#
|
||||||
|
# This mode:
|
||||||
|
# - Mounts source code as volumes (live reload)
|
||||||
|
# - Runs npm install inside container
|
||||||
|
# - Uses Vite dev server with HMR
|
||||||
|
# - Server runs with tsx watch for TypeScript changes
|
||||||
|
|
||||||
|
services:
|
||||||
|
# Development server (backend API)
|
||||||
|
server:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: Dockerfile.dev
|
||||||
|
container_name: automaker-dev-server
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- '3008:3008'
|
||||||
|
environment:
|
||||||
|
# Required
|
||||||
|
- ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}
|
||||||
|
|
||||||
|
# Optional - Claude CLI OAuth credentials
|
||||||
|
- CLAUDE_OAUTH_CREDENTIALS=${CLAUDE_OAUTH_CREDENTIALS:-}
|
||||||
|
|
||||||
|
# Optional - Cursor CLI OAuth token
|
||||||
|
- CURSOR_AUTH_TOKEN=${CURSOR_AUTH_TOKEN:-}
|
||||||
|
|
||||||
|
# Optional - authentication
|
||||||
|
- AUTOMAKER_API_KEY=${AUTOMAKER_API_KEY:-}
|
||||||
|
|
||||||
|
# Development settings
|
||||||
|
- NODE_ENV=development
|
||||||
|
- PORT=3008
|
||||||
|
- CORS_ORIGIN=http://localhost:3007
|
||||||
|
|
||||||
|
# Optional - restrict to specific directory within container
|
||||||
|
- ALLOWED_ROOT_DIRECTORY=${ALLOWED_ROOT_DIRECTORY:-/projects}
|
||||||
|
- DATA_DIR=/data
|
||||||
|
|
||||||
|
# Internal - indicates containerized environment
|
||||||
|
- IS_CONTAINERIZED=true
|
||||||
|
volumes:
|
||||||
|
# Mount source code for live reload
|
||||||
|
- .:/app:cached
|
||||||
|
|
||||||
|
# Use named volume for node_modules to avoid platform conflicts
|
||||||
|
# This ensures native modules are built for the container's architecture
|
||||||
|
- automaker-dev-node-modules:/app/node_modules
|
||||||
|
|
||||||
|
# Persist data across restarts
|
||||||
|
- automaker-data:/data
|
||||||
|
|
||||||
|
# Persist CLI configurations
|
||||||
|
- automaker-claude-config:/home/automaker/.claude
|
||||||
|
- automaker-cursor-config:/home/automaker/.cursor
|
||||||
|
|
||||||
|
# Note: Workspace mount (/projects) comes from docker-compose.override.yml
|
||||||
|
|
||||||
|
# Install deps, build packages, then start server in watch mode
|
||||||
|
# Note: We override the entrypoint to handle permissions properly
|
||||||
|
entrypoint: /bin/sh
|
||||||
|
command:
|
||||||
|
- -c
|
||||||
|
- |
|
||||||
|
# Fix permissions on node_modules (created as root by Docker volume)
|
||||||
|
echo 'Fixing node_modules permissions...'
|
||||||
|
chown -R automaker:automaker /app/node_modules 2>/dev/null || true
|
||||||
|
|
||||||
|
# Run the rest as automaker user
|
||||||
|
exec gosu automaker sh -c "
|
||||||
|
echo 'Installing dependencies...' &&
|
||||||
|
npm install &&
|
||||||
|
echo 'Building shared packages...' &&
|
||||||
|
npm run build:packages &&
|
||||||
|
echo 'Starting server in development mode...' &&
|
||||||
|
npm run _dev:server
|
||||||
|
"
|
||||||
|
healthcheck:
|
||||||
|
test: ['CMD', 'curl', '-f', 'http://localhost:3008/api/health']
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
start_period: 60s
|
||||||
|
|
||||||
|
# Development UI (frontend with HMR)
|
||||||
|
ui:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: Dockerfile.dev
|
||||||
|
container_name: automaker-dev-ui
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- '3007:3007'
|
||||||
|
environment:
|
||||||
|
- NODE_ENV=development
|
||||||
|
- VITE_SERVER_URL=http://localhost:3008
|
||||||
|
- TEST_PORT=3007
|
||||||
|
- VITE_SKIP_ELECTRON=true
|
||||||
|
volumes:
|
||||||
|
# Mount source code for live reload
|
||||||
|
- .:/app:cached
|
||||||
|
|
||||||
|
# Share node_modules with server container
|
||||||
|
- automaker-dev-node-modules:/app/node_modules
|
||||||
|
depends_on:
|
||||||
|
server:
|
||||||
|
condition: service_healthy
|
||||||
|
working_dir: /app/apps/ui
|
||||||
|
# Start Vite dev server for UI with HMR
|
||||||
|
# --host flag makes Vite bind to 0.0.0.0 for Docker access
|
||||||
|
# Note: We override the entrypoint to run as automaker user
|
||||||
|
entrypoint: /bin/sh
|
||||||
|
command:
|
||||||
|
- -c
|
||||||
|
- |
|
||||||
|
exec gosu automaker sh -c "
|
||||||
|
echo 'Waiting for dependencies to be ready...' &&
|
||||||
|
while [ ! -d /app/node_modules/.bin ]; do sleep 2; done &&
|
||||||
|
echo 'Starting UI development server...' &&
|
||||||
|
cd /app/apps/ui && npx vite --host
|
||||||
|
"
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
automaker-dev-node-modules:
|
||||||
|
name: automaker-dev-node-modules
|
||||||
|
# Named volume for container-specific node_modules
|
||||||
|
|
||||||
|
automaker-data:
|
||||||
|
name: automaker-data
|
||||||
|
|
||||||
|
automaker-claude-config:
|
||||||
|
name: automaker-claude-config
|
||||||
|
|
||||||
|
automaker-cursor-config:
|
||||||
|
name: automaker-cursor-config
|
||||||
107
package-lock.json
generated
107
package-lock.json
generated
@@ -20,7 +20,8 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"husky": "9.1.7",
|
"husky": "9.1.7",
|
||||||
"lint-staged": "16.2.7",
|
"lint-staged": "16.2.7",
|
||||||
"prettier": "3.7.4"
|
"prettier": "3.7.4",
|
||||||
|
"vitest": "4.0.16"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=22.0.0 <23.0.0"
|
"node": ">=22.0.0 <23.0.0"
|
||||||
@@ -28,7 +29,7 @@
|
|||||||
},
|
},
|
||||||
"apps/server": {
|
"apps/server": {
|
||||||
"name": "@automaker/server",
|
"name": "@automaker/server",
|
||||||
"version": "0.7.3",
|
"version": "0.8.0",
|
||||||
"license": "SEE LICENSE IN LICENSE",
|
"license": "SEE LICENSE IN LICENSE",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@anthropic-ai/claude-agent-sdk": "0.1.76",
|
"@anthropic-ai/claude-agent-sdk": "0.1.76",
|
||||||
@@ -78,7 +79,7 @@
|
|||||||
},
|
},
|
||||||
"apps/ui": {
|
"apps/ui": {
|
||||||
"name": "@automaker/ui",
|
"name": "@automaker/ui",
|
||||||
"version": "0.7.3",
|
"version": "0.8.0",
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"license": "SEE LICENSE IN LICENSE",
|
"license": "SEE LICENSE IN LICENSE",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -675,7 +676,6 @@
|
|||||||
"integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==",
|
"integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/code-frame": "^7.27.1",
|
"@babel/code-frame": "^7.27.1",
|
||||||
"@babel/generator": "^7.28.5",
|
"@babel/generator": "^7.28.5",
|
||||||
@@ -1259,7 +1259,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.39.4.tgz",
|
"resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.39.4.tgz",
|
||||||
"integrity": "sha512-xMF6OfEAUVY5Waega4juo1QGACfNkNF+aJLqpd8oUJz96ms2zbfQ9Gh35/tI3y8akEV31FruKfj7hBnIU/nkqA==",
|
"integrity": "sha512-xMF6OfEAUVY5Waega4juo1QGACfNkNF+aJLqpd8oUJz96ms2zbfQ9Gh35/tI3y8akEV31FruKfj7hBnIU/nkqA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/state": "^6.5.0",
|
"@codemirror/state": "^6.5.0",
|
||||||
"crelt": "^1.0.6",
|
"crelt": "^1.0.6",
|
||||||
@@ -1302,7 +1301,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@dnd-kit/core/-/core-6.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/@dnd-kit/core/-/core-6.3.1.tgz",
|
||||||
"integrity": "sha512-xkGBRQQab4RLwgXxoqETICr6S5JlogafbhNsidmrkVv2YRs5MLwpjoF2qpiGjQt8S9AoxtIV603s0GIUpY5eYQ==",
|
"integrity": "sha512-xkGBRQQab4RLwgXxoqETICr6S5JlogafbhNsidmrkVv2YRs5MLwpjoF2qpiGjQt8S9AoxtIV603s0GIUpY5eYQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@dnd-kit/accessibility": "^3.1.1",
|
"@dnd-kit/accessibility": "^3.1.1",
|
||||||
"@dnd-kit/utilities": "^3.2.2",
|
"@dnd-kit/utilities": "^3.2.2",
|
||||||
@@ -2123,6 +2121,7 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "BSD-2-Clause",
|
"license": "BSD-2-Clause",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"cross-dirname": "^0.1.0",
|
"cross-dirname": "^0.1.0",
|
||||||
"debug": "^4.3.4",
|
"debug": "^4.3.4",
|
||||||
@@ -2144,6 +2143,7 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"graceful-fs": "^4.2.0",
|
"graceful-fs": "^4.2.0",
|
||||||
"jsonfile": "^6.0.1",
|
"jsonfile": "^6.0.1",
|
||||||
@@ -2160,6 +2160,7 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"universalify": "^2.0.0"
|
"universalify": "^2.0.0"
|
||||||
},
|
},
|
||||||
@@ -2174,6 +2175,7 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 10.0.0"
|
"node": ">= 10.0.0"
|
||||||
}
|
}
|
||||||
@@ -2941,6 +2943,7 @@
|
|||||||
"integrity": "sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==",
|
"integrity": "sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
@@ -3065,6 +3068,7 @@
|
|||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
],
|
],
|
||||||
|
"peer": true,
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://opencollective.com/libvips"
|
"url": "https://opencollective.com/libvips"
|
||||||
}
|
}
|
||||||
@@ -3081,6 +3085,7 @@
|
|||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
],
|
],
|
||||||
|
"peer": true,
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://opencollective.com/libvips"
|
"url": "https://opencollective.com/libvips"
|
||||||
}
|
}
|
||||||
@@ -3097,6 +3102,7 @@
|
|||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
],
|
],
|
||||||
|
"peer": true,
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://opencollective.com/libvips"
|
"url": "https://opencollective.com/libvips"
|
||||||
}
|
}
|
||||||
@@ -3205,6 +3211,7 @@
|
|||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
],
|
],
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||||
},
|
},
|
||||||
@@ -3227,6 +3234,7 @@
|
|||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
],
|
],
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||||
},
|
},
|
||||||
@@ -3249,6 +3257,7 @@
|
|||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
],
|
],
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||||
},
|
},
|
||||||
@@ -3334,6 +3343,7 @@
|
|||||||
],
|
],
|
||||||
"license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT",
|
"license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@emnapi/runtime": "^1.7.0"
|
"@emnapi/runtime": "^1.7.0"
|
||||||
},
|
},
|
||||||
@@ -3356,6 +3366,7 @@
|
|||||||
"os": [
|
"os": [
|
||||||
"win32"
|
"win32"
|
||||||
],
|
],
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||||
},
|
},
|
||||||
@@ -3375,6 +3386,7 @@
|
|||||||
"os": [
|
"os": [
|
||||||
"win32"
|
"win32"
|
||||||
],
|
],
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||||
},
|
},
|
||||||
@@ -3774,7 +3786,8 @@
|
|||||||
"version": "16.0.10",
|
"version": "16.0.10",
|
||||||
"resolved": "https://registry.npmjs.org/@next/env/-/env-16.0.10.tgz",
|
"resolved": "https://registry.npmjs.org/@next/env/-/env-16.0.10.tgz",
|
||||||
"integrity": "sha512-8tuaQkyDVgeONQ1MeT9Mkk8pQmZapMKFh5B+OrFUlG3rVmYTXcXlBetBgTurKXGaIZvkoqRT9JL5K3phXcgang==",
|
"integrity": "sha512-8tuaQkyDVgeONQ1MeT9Mkk8pQmZapMKFh5B+OrFUlG3rVmYTXcXlBetBgTurKXGaIZvkoqRT9JL5K3phXcgang==",
|
||||||
"license": "MIT"
|
"license": "MIT",
|
||||||
|
"peer": true
|
||||||
},
|
},
|
||||||
"node_modules/@next/swc-darwin-arm64": {
|
"node_modules/@next/swc-darwin-arm64": {
|
||||||
"version": "16.0.10",
|
"version": "16.0.10",
|
||||||
@@ -3788,6 +3801,7 @@
|
|||||||
"os": [
|
"os": [
|
||||||
"darwin"
|
"darwin"
|
||||||
],
|
],
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 10"
|
"node": ">= 10"
|
||||||
}
|
}
|
||||||
@@ -3804,6 +3818,7 @@
|
|||||||
"os": [
|
"os": [
|
||||||
"darwin"
|
"darwin"
|
||||||
],
|
],
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 10"
|
"node": ">= 10"
|
||||||
}
|
}
|
||||||
@@ -3820,6 +3835,7 @@
|
|||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
],
|
],
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 10"
|
"node": ">= 10"
|
||||||
}
|
}
|
||||||
@@ -3836,6 +3852,7 @@
|
|||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
],
|
],
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 10"
|
"node": ">= 10"
|
||||||
}
|
}
|
||||||
@@ -3852,6 +3869,7 @@
|
|||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
],
|
],
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 10"
|
"node": ">= 10"
|
||||||
}
|
}
|
||||||
@@ -3868,6 +3886,7 @@
|
|||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
],
|
],
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 10"
|
"node": ">= 10"
|
||||||
}
|
}
|
||||||
@@ -3884,6 +3903,7 @@
|
|||||||
"os": [
|
"os": [
|
||||||
"win32"
|
"win32"
|
||||||
],
|
],
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 10"
|
"node": ">= 10"
|
||||||
}
|
}
|
||||||
@@ -3900,6 +3920,7 @@
|
|||||||
"os": [
|
"os": [
|
||||||
"win32"
|
"win32"
|
||||||
],
|
],
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 10"
|
"node": ">= 10"
|
||||||
}
|
}
|
||||||
@@ -3990,7 +4011,6 @@
|
|||||||
"integrity": "sha512-6TyEnHgd6SArQO8UO2OMTxshln3QMWBtPGrOCgs3wVEmQmwyuNtB10IZMfmYDE0riwNR1cu4q+pPcxMVtaG3TA==",
|
"integrity": "sha512-6TyEnHgd6SArQO8UO2OMTxshln3QMWBtPGrOCgs3wVEmQmwyuNtB10IZMfmYDE0riwNR1cu4q+pPcxMVtaG3TA==",
|
||||||
"devOptional": true,
|
"devOptional": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"playwright": "1.57.0"
|
"playwright": "1.57.0"
|
||||||
},
|
},
|
||||||
@@ -5431,6 +5451,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz",
|
"resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz",
|
||||||
"integrity": "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==",
|
"integrity": "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"tslib": "^2.8.0"
|
"tslib": "^2.8.0"
|
||||||
}
|
}
|
||||||
@@ -5764,7 +5785,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@tanstack/react-router/-/react-router-1.141.6.tgz",
|
"resolved": "https://registry.npmjs.org/@tanstack/react-router/-/react-router-1.141.6.tgz",
|
||||||
"integrity": "sha512-qWFxi2D6eGc1L03RzUuhyEOplZ7Q6q62YOl7Of9Y0q4YjwQwxRm4zxwDVtvUIoy4RLVCpqp5UoE+Nxv2PY9trg==",
|
"integrity": "sha512-qWFxi2D6eGc1L03RzUuhyEOplZ7Q6q62YOl7Of9Y0q4YjwQwxRm4zxwDVtvUIoy4RLVCpqp5UoE+Nxv2PY9trg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tanstack/history": "1.141.0",
|
"@tanstack/history": "1.141.0",
|
||||||
"@tanstack/react-store": "^0.8.0",
|
"@tanstack/react-store": "^0.8.0",
|
||||||
@@ -6191,7 +6211,6 @@
|
|||||||
"integrity": "sha512-sKYVuV7Sv9fbPIt/442koC7+IIwK5olP1KWeD88e/idgoJqDm3JV/YUiPwkoKK92ylff2MGxSz1CSjsXelx0YA==",
|
"integrity": "sha512-sKYVuV7Sv9fbPIt/442koC7+IIwK5olP1KWeD88e/idgoJqDm3JV/YUiPwkoKK92ylff2MGxSz1CSjsXelx0YA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/body-parser": "*",
|
"@types/body-parser": "*",
|
||||||
"@types/express-serve-static-core": "^5.0.0",
|
"@types/express-serve-static-core": "^5.0.0",
|
||||||
@@ -6334,7 +6353,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.7.tgz",
|
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.7.tgz",
|
||||||
"integrity": "sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg==",
|
"integrity": "sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"csstype": "^3.2.2"
|
"csstype": "^3.2.2"
|
||||||
}
|
}
|
||||||
@@ -6345,7 +6363,6 @@
|
|||||||
"integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==",
|
"integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==",
|
||||||
"devOptional": true,
|
"devOptional": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@types/react": "^19.2.0"
|
"@types/react": "^19.2.0"
|
||||||
}
|
}
|
||||||
@@ -6451,7 +6468,6 @@
|
|||||||
"integrity": "sha512-6/cmF2piao+f6wSxUsJLZjck7OQsYyRtcOZS02k7XINSNlz93v6emM8WutDQSXnroG2xwYlEVHJI+cPA7CPM3Q==",
|
"integrity": "sha512-6/cmF2piao+f6wSxUsJLZjck7OQsYyRtcOZS02k7XINSNlz93v6emM8WutDQSXnroG2xwYlEVHJI+cPA7CPM3Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/scope-manager": "8.50.0",
|
"@typescript-eslint/scope-manager": "8.50.0",
|
||||||
"@typescript-eslint/types": "8.50.0",
|
"@typescript-eslint/types": "8.50.0",
|
||||||
@@ -6945,8 +6961,7 @@
|
|||||||
"version": "5.5.0",
|
"version": "5.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/@xterm/xterm/-/xterm-5.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/@xterm/xterm/-/xterm-5.5.0.tgz",
|
||||||
"integrity": "sha512-hqJHYaQb5OptNunnyAnkHyM8aCjZ1MEIDTQu1iIbbTD/xops91NB5yq1ZK/dC2JDbVWtF23zUtl9JE2NqwT87A==",
|
"integrity": "sha512-hqJHYaQb5OptNunnyAnkHyM8aCjZ1MEIDTQu1iIbbTD/xops91NB5yq1ZK/dC2JDbVWtF23zUtl9JE2NqwT87A==",
|
||||||
"license": "MIT",
|
"license": "MIT"
|
||||||
"peer": true
|
|
||||||
},
|
},
|
||||||
"node_modules/@xyflow/react": {
|
"node_modules/@xyflow/react": {
|
||||||
"version": "12.10.0",
|
"version": "12.10.0",
|
||||||
@@ -7044,7 +7059,6 @@
|
|||||||
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
|
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"bin": {
|
"bin": {
|
||||||
"acorn": "bin/acorn"
|
"acorn": "bin/acorn"
|
||||||
},
|
},
|
||||||
@@ -7105,7 +7119,6 @@
|
|||||||
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
|
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"fast-deep-equal": "^3.1.1",
|
"fast-deep-equal": "^3.1.1",
|
||||||
"fast-json-stable-stringify": "^2.0.0",
|
"fast-json-stable-stringify": "^2.0.0",
|
||||||
@@ -7704,7 +7717,6 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"baseline-browser-mapping": "^2.9.0",
|
"baseline-browser-mapping": "^2.9.0",
|
||||||
"caniuse-lite": "^1.0.30001759",
|
"caniuse-lite": "^1.0.30001759",
|
||||||
@@ -8236,7 +8248,8 @@
|
|||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz",
|
||||||
"integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==",
|
"integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==",
|
||||||
"license": "MIT"
|
"license": "MIT",
|
||||||
|
"peer": true
|
||||||
},
|
},
|
||||||
"node_modules/cliui": {
|
"node_modules/cliui": {
|
||||||
"version": "8.0.1",
|
"version": "8.0.1",
|
||||||
@@ -8541,7 +8554,8 @@
|
|||||||
"integrity": "sha512-+R08/oI0nl3vfPcqftZRpytksBXDzOUveBq/NBVx0sUp1axwzPQrKinNx5yd5sxPu8j1wIy8AfnVQ+5eFdha6Q==",
|
"integrity": "sha512-+R08/oI0nl3vfPcqftZRpytksBXDzOUveBq/NBVx0sUp1axwzPQrKinNx5yd5sxPu8j1wIy8AfnVQ+5eFdha6Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true
|
"optional": true,
|
||||||
|
"peer": true
|
||||||
},
|
},
|
||||||
"node_modules/cross-env": {
|
"node_modules/cross-env": {
|
||||||
"version": "10.1.0",
|
"version": "10.1.0",
|
||||||
@@ -8638,7 +8652,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz",
|
||||||
"integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==",
|
"integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"peer": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=12"
|
||||||
}
|
}
|
||||||
@@ -8940,7 +8953,6 @@
|
|||||||
"integrity": "sha512-59CAAjAhTaIMCN8y9kD573vDkxbs1uhDcrFLHSgutYdPcGOU35Rf95725snvzEOy4BFB7+eLJ8djCNPmGwG67w==",
|
"integrity": "sha512-59CAAjAhTaIMCN8y9kD573vDkxbs1uhDcrFLHSgutYdPcGOU35Rf95725snvzEOy4BFB7+eLJ8djCNPmGwG67w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"app-builder-lib": "26.0.12",
|
"app-builder-lib": "26.0.12",
|
||||||
"builder-util": "26.0.11",
|
"builder-util": "26.0.11",
|
||||||
@@ -9267,6 +9279,7 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@electron/asar": "^3.2.1",
|
"@electron/asar": "^3.2.1",
|
||||||
"debug": "^4.1.1",
|
"debug": "^4.1.1",
|
||||||
@@ -9287,6 +9300,7 @@
|
|||||||
"integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==",
|
"integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"graceful-fs": "^4.1.2",
|
"graceful-fs": "^4.1.2",
|
||||||
"jsonfile": "^4.0.0",
|
"jsonfile": "^4.0.0",
|
||||||
@@ -9537,7 +9551,6 @@
|
|||||||
"integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==",
|
"integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint-community/eslint-utils": "^4.8.0",
|
"@eslint-community/eslint-utils": "^4.8.0",
|
||||||
"@eslint-community/regexpp": "^4.12.1",
|
"@eslint-community/regexpp": "^4.12.1",
|
||||||
@@ -9852,7 +9865,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz",
|
||||||
"integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==",
|
"integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"accepts": "^2.0.0",
|
"accepts": "^2.0.0",
|
||||||
"body-parser": "^2.2.1",
|
"body-parser": "^2.2.1",
|
||||||
@@ -11520,6 +11532,7 @@
|
|||||||
"os": [
|
"os": [
|
||||||
"android"
|
"android"
|
||||||
],
|
],
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 12.0.0"
|
"node": ">= 12.0.0"
|
||||||
},
|
},
|
||||||
@@ -11541,6 +11554,7 @@
|
|||||||
"os": [
|
"os": [
|
||||||
"darwin"
|
"darwin"
|
||||||
],
|
],
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 12.0.0"
|
"node": ">= 12.0.0"
|
||||||
},
|
},
|
||||||
@@ -11562,6 +11576,7 @@
|
|||||||
"os": [
|
"os": [
|
||||||
"darwin"
|
"darwin"
|
||||||
],
|
],
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 12.0.0"
|
"node": ">= 12.0.0"
|
||||||
},
|
},
|
||||||
@@ -11583,6 +11598,7 @@
|
|||||||
"os": [
|
"os": [
|
||||||
"freebsd"
|
"freebsd"
|
||||||
],
|
],
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 12.0.0"
|
"node": ">= 12.0.0"
|
||||||
},
|
},
|
||||||
@@ -11604,6 +11620,7 @@
|
|||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
],
|
],
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 12.0.0"
|
"node": ">= 12.0.0"
|
||||||
},
|
},
|
||||||
@@ -11625,6 +11642,7 @@
|
|||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
],
|
],
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 12.0.0"
|
"node": ">= 12.0.0"
|
||||||
},
|
},
|
||||||
@@ -11646,6 +11664,7 @@
|
|||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
],
|
],
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 12.0.0"
|
"node": ">= 12.0.0"
|
||||||
},
|
},
|
||||||
@@ -11667,6 +11686,7 @@
|
|||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
],
|
],
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 12.0.0"
|
"node": ">= 12.0.0"
|
||||||
},
|
},
|
||||||
@@ -11688,6 +11708,7 @@
|
|||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
],
|
],
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 12.0.0"
|
"node": ">= 12.0.0"
|
||||||
},
|
},
|
||||||
@@ -11709,6 +11730,7 @@
|
|||||||
"os": [
|
"os": [
|
||||||
"win32"
|
"win32"
|
||||||
],
|
],
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 12.0.0"
|
"node": ">= 12.0.0"
|
||||||
},
|
},
|
||||||
@@ -11730,6 +11752,7 @@
|
|||||||
"os": [
|
"os": [
|
||||||
"win32"
|
"win32"
|
||||||
],
|
],
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 12.0.0"
|
"node": ">= 12.0.0"
|
||||||
},
|
},
|
||||||
@@ -14017,6 +14040,7 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"nanoid": "^3.3.6",
|
"nanoid": "^3.3.6",
|
||||||
"picocolors": "^1.0.0",
|
"picocolors": "^1.0.0",
|
||||||
@@ -14033,6 +14057,7 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"commander": "^9.4.0"
|
"commander": "^9.4.0"
|
||||||
},
|
},
|
||||||
@@ -14050,6 +14075,7 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^12.20.0 || >=14"
|
"node": "^12.20.0 || >=14"
|
||||||
}
|
}
|
||||||
@@ -14238,7 +14264,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/react/-/react-19.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/react/-/react-19.2.3.tgz",
|
||||||
"integrity": "sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==",
|
"integrity": "sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
@@ -14248,7 +14273,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.3.tgz",
|
||||||
"integrity": "sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg==",
|
"integrity": "sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"scheduler": "^0.27.0"
|
"scheduler": "^0.27.0"
|
||||||
},
|
},
|
||||||
@@ -14607,6 +14631,7 @@
|
|||||||
"deprecated": "Rimraf versions prior to v4 are no longer supported",
|
"deprecated": "Rimraf versions prior to v4 are no longer supported",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"glob": "^7.1.3"
|
"glob": "^7.1.3"
|
||||||
},
|
},
|
||||||
@@ -14795,7 +14820,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/seroval/-/seroval-1.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/seroval/-/seroval-1.4.0.tgz",
|
||||||
"integrity": "sha512-BdrNXdzlofomLTiRnwJTSEAaGKyHHZkbMXIywOh7zlzp4uZnXErEwl9XZ+N1hJSNpeTtNxWvVwN0wUzAIQ4Hpg==",
|
"integrity": "sha512-BdrNXdzlofomLTiRnwJTSEAaGKyHHZkbMXIywOh7zlzp4uZnXErEwl9XZ+N1hJSNpeTtNxWvVwN0wUzAIQ4Hpg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
}
|
}
|
||||||
@@ -14844,6 +14868,7 @@
|
|||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@img/colour": "^1.0.0",
|
"@img/colour": "^1.0.0",
|
||||||
"detect-libc": "^2.1.2",
|
"detect-libc": "^2.1.2",
|
||||||
@@ -14894,6 +14919,7 @@
|
|||||||
"os": [
|
"os": [
|
||||||
"darwin"
|
"darwin"
|
||||||
],
|
],
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||||
},
|
},
|
||||||
@@ -14916,6 +14942,7 @@
|
|||||||
"os": [
|
"os": [
|
||||||
"darwin"
|
"darwin"
|
||||||
],
|
],
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||||
},
|
},
|
||||||
@@ -14938,6 +14965,7 @@
|
|||||||
"os": [
|
"os": [
|
||||||
"darwin"
|
"darwin"
|
||||||
],
|
],
|
||||||
|
"peer": true,
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://opencollective.com/libvips"
|
"url": "https://opencollective.com/libvips"
|
||||||
}
|
}
|
||||||
@@ -14954,6 +14982,7 @@
|
|||||||
"os": [
|
"os": [
|
||||||
"darwin"
|
"darwin"
|
||||||
],
|
],
|
||||||
|
"peer": true,
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://opencollective.com/libvips"
|
"url": "https://opencollective.com/libvips"
|
||||||
}
|
}
|
||||||
@@ -14970,6 +14999,7 @@
|
|||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
],
|
],
|
||||||
|
"peer": true,
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://opencollective.com/libvips"
|
"url": "https://opencollective.com/libvips"
|
||||||
}
|
}
|
||||||
@@ -14986,6 +15016,7 @@
|
|||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
],
|
],
|
||||||
|
"peer": true,
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://opencollective.com/libvips"
|
"url": "https://opencollective.com/libvips"
|
||||||
}
|
}
|
||||||
@@ -15002,6 +15033,7 @@
|
|||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
],
|
],
|
||||||
|
"peer": true,
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://opencollective.com/libvips"
|
"url": "https://opencollective.com/libvips"
|
||||||
}
|
}
|
||||||
@@ -15018,6 +15050,7 @@
|
|||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
],
|
],
|
||||||
|
"peer": true,
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://opencollective.com/libvips"
|
"url": "https://opencollective.com/libvips"
|
||||||
}
|
}
|
||||||
@@ -15034,6 +15067,7 @@
|
|||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
],
|
],
|
||||||
|
"peer": true,
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://opencollective.com/libvips"
|
"url": "https://opencollective.com/libvips"
|
||||||
}
|
}
|
||||||
@@ -15050,6 +15084,7 @@
|
|||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
],
|
],
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||||
},
|
},
|
||||||
@@ -15072,6 +15107,7 @@
|
|||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
],
|
],
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||||
},
|
},
|
||||||
@@ -15094,6 +15130,7 @@
|
|||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
],
|
],
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||||
},
|
},
|
||||||
@@ -15116,6 +15153,7 @@
|
|||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
],
|
],
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||||
},
|
},
|
||||||
@@ -15138,6 +15176,7 @@
|
|||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
],
|
],
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||||
},
|
},
|
||||||
@@ -15160,6 +15199,7 @@
|
|||||||
"os": [
|
"os": [
|
||||||
"win32"
|
"win32"
|
||||||
],
|
],
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||||
},
|
},
|
||||||
@@ -15628,6 +15668,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.6.tgz",
|
"resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.6.tgz",
|
||||||
"integrity": "sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==",
|
"integrity": "sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"client-only": "0.0.1"
|
"client-only": "0.0.1"
|
||||||
},
|
},
|
||||||
@@ -15797,6 +15838,7 @@
|
|||||||
"integrity": "sha512-yYrrsWnrXMcdsnu/7YMYAofM1ktpL5By7vZhf15CrXijWWrEYZks5AXBudalfSWJLlnen/QUJUB5aoB0kqZUGA==",
|
"integrity": "sha512-yYrrsWnrXMcdsnu/7YMYAofM1ktpL5By7vZhf15CrXijWWrEYZks5AXBudalfSWJLlnen/QUJUB5aoB0kqZUGA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"mkdirp": "^0.5.1",
|
"mkdirp": "^0.5.1",
|
||||||
"rimraf": "~2.6.2"
|
"rimraf": "~2.6.2"
|
||||||
@@ -15860,6 +15902,7 @@
|
|||||||
"integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
|
"integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"minimist": "^1.2.6"
|
"minimist": "^1.2.6"
|
||||||
},
|
},
|
||||||
@@ -15957,7 +16000,6 @@
|
|||||||
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=12"
|
||||||
},
|
},
|
||||||
@@ -16162,7 +16204,6 @@
|
|||||||
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"peer": true,
|
|
||||||
"bin": {
|
"bin": {
|
||||||
"tsc": "bin/tsc",
|
"tsc": "bin/tsc",
|
||||||
"tsserver": "bin/tsserver"
|
"tsserver": "bin/tsserver"
|
||||||
@@ -16534,7 +16575,6 @@
|
|||||||
"integrity": "sha512-dZwN5L1VlUBewiP6H9s2+B3e3Jg96D0vzN+Ry73sOefebhYr9f94wwkMNN/9ouoU8pV1BqA1d1zGk8928cx0rg==",
|
"integrity": "sha512-dZwN5L1VlUBewiP6H9s2+B3e3Jg96D0vzN+Ry73sOefebhYr9f94wwkMNN/9ouoU8pV1BqA1d1zGk8928cx0rg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"esbuild": "^0.27.0",
|
"esbuild": "^0.27.0",
|
||||||
"fdir": "^6.5.0",
|
"fdir": "^6.5.0",
|
||||||
@@ -16624,8 +16664,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/vite-plugin-electron-renderer/-/vite-plugin-electron-renderer-0.14.6.tgz",
|
"resolved": "https://registry.npmjs.org/vite-plugin-electron-renderer/-/vite-plugin-electron-renderer-0.14.6.tgz",
|
||||||
"integrity": "sha512-oqkWFa7kQIkvHXG7+Mnl1RTroA4sP0yesKatmAy0gjZC4VwUqlvF9IvOpHd1fpLWsqYX/eZlVxlhULNtaQ78Jw==",
|
"integrity": "sha512-oqkWFa7kQIkvHXG7+Mnl1RTroA4sP0yesKatmAy0gjZC4VwUqlvF9IvOpHd1fpLWsqYX/eZlVxlhULNtaQ78Jw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT"
|
||||||
"peer": true
|
|
||||||
},
|
},
|
||||||
"node_modules/vite/node_modules/fdir": {
|
"node_modules/vite/node_modules/fdir": {
|
||||||
"version": "6.5.0",
|
"version": "6.5.0",
|
||||||
@@ -16651,7 +16690,6 @@
|
|||||||
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=12"
|
||||||
},
|
},
|
||||||
@@ -16694,7 +16732,6 @@
|
|||||||
"integrity": "sha512-E4t7DJ9pESL6E3I8nFjPa4xGUd3PmiWDLsDztS2qXSJWfHtbQnwAWylaBvSNY48I3vr8PTqIZlyK8TE3V3CA4Q==",
|
"integrity": "sha512-E4t7DJ9pESL6E3I8nFjPa4xGUd3PmiWDLsDztS2qXSJWfHtbQnwAWylaBvSNY48I3vr8PTqIZlyK8TE3V3CA4Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vitest/expect": "4.0.16",
|
"@vitest/expect": "4.0.16",
|
||||||
"@vitest/mocker": "4.0.16",
|
"@vitest/mocker": "4.0.16",
|
||||||
@@ -16952,7 +16989,6 @@
|
|||||||
"integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==",
|
"integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"peer": true,
|
|
||||||
"bin": {
|
"bin": {
|
||||||
"yaml": "bin.mjs"
|
"yaml": "bin.mjs"
|
||||||
},
|
},
|
||||||
@@ -17021,7 +17057,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/zod/-/zod-4.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/zod/-/zod-4.2.1.tgz",
|
||||||
"integrity": "sha512-0wZ1IRqGGhMP76gLqz8EyfBXKk0J2qo2+H3fi4mcUP/KtTocoX08nmIAHl1Z2kJIZbZee8KOpBCSNPRgauucjw==",
|
"integrity": "sha512-0wZ1IRqGGhMP76gLqz8EyfBXKk0J2qo2+H3fi4mcUP/KtTocoX08nmIAHl1Z2kJIZbZee8KOpBCSNPRgauucjw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://github.com/sponsors/colinhacks"
|
"url": "https://github.com/sponsors/colinhacks"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,6 @@
|
|||||||
"postinstall": "node -e \"const fs=require('fs');if(process.platform==='darwin'){['darwin-arm64','darwin-x64'].forEach(a=>{const p='node_modules/node-pty/prebuilds/'+a+'/spawn-helper';if(fs.existsSync(p))fs.chmodSync(p,0o755)})}\" && node scripts/fix-lockfile-urls.mjs",
|
"postinstall": "node -e \"const fs=require('fs');if(process.platform==='darwin'){['darwin-arm64','darwin-x64'].forEach(a=>{const p='node_modules/node-pty/prebuilds/'+a+'/spawn-helper';if(fs.existsSync(p))fs.chmodSync(p,0o755)})}\" && node scripts/fix-lockfile-urls.mjs",
|
||||||
"fix:lockfile": "node scripts/fix-lockfile-urls.mjs",
|
"fix:lockfile": "node scripts/fix-lockfile-urls.mjs",
|
||||||
"dev": "node dev.mjs",
|
"dev": "node dev.mjs",
|
||||||
"start": "node start.mjs",
|
|
||||||
"_dev:web": "npm run dev:web --workspace=apps/ui",
|
"_dev:web": "npm run dev:web --workspace=apps/ui",
|
||||||
"_dev:electron": "npm run dev:electron --workspace=apps/ui",
|
"_dev:electron": "npm run dev:electron --workspace=apps/ui",
|
||||||
"_dev:electron:debug": "npm run dev:electron:debug --workspace=apps/ui",
|
"_dev:electron:debug": "npm run dev:electron:debug --workspace=apps/ui",
|
||||||
@@ -27,6 +26,7 @@
|
|||||||
"dev:electron:wsl:gpu": "npm run build:packages && npm run _dev:electron:wsl:gpu",
|
"dev:electron:wsl:gpu": "npm run build:packages && npm run _dev:electron:wsl:gpu",
|
||||||
"dev:server": "npm run build:packages && npm run _dev:server",
|
"dev:server": "npm run build:packages && npm run _dev:server",
|
||||||
"dev:docker": "docker compose up",
|
"dev:docker": "docker compose up",
|
||||||
|
"dev:docker:rebuild": "docker compose build --no-cache && docker compose up",
|
||||||
"dev:full": "npm run build:packages && concurrently \"npm run _dev:server\" \"npm run _dev:web\"",
|
"dev:full": "npm run build:packages && concurrently \"npm run _dev:server\" \"npm run _dev:web\"",
|
||||||
"build": "npm run build:packages && npm run build --workspace=apps/ui",
|
"build": "npm run build:packages && npm run build --workspace=apps/ui",
|
||||||
"build:packages": "npm run build -w @automaker/types && npm run build -w @automaker/platform && npm run build -w @automaker/utils && npm run build -w @automaker/prompts -w @automaker/model-resolver -w @automaker/dependency-resolver && npm run build -w @automaker/git-utils",
|
"build:packages": "npm run build -w @automaker/types && npm run build -w @automaker/platform && npm run build -w @automaker/utils && npm run build -w @automaker/prompts -w @automaker/model-resolver -w @automaker/dependency-resolver && npm run build -w @automaker/git-utils",
|
||||||
@@ -51,6 +51,7 @@
|
|||||||
"lint:lockfile": "node scripts/lint-lockfile.mjs",
|
"lint:lockfile": "node scripts/lint-lockfile.mjs",
|
||||||
"format": "prettier --write .",
|
"format": "prettier --write .",
|
||||||
"format:check": "prettier --check .",
|
"format:check": "prettier --check .",
|
||||||
|
"rebuild": "rm -rf node_modules apps/*/node_modules libs/*/node_modules && npm install",
|
||||||
"prepare": "husky && npm run build:packages"
|
"prepare": "husky && npm run build:packages"
|
||||||
},
|
},
|
||||||
"lint-staged": {
|
"lint-staged": {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Shared utilities for Automaker launcher scripts (dev.mjs and start.mjs)
|
* Shared utilities for Automaker launcher scripts (dev.mjs)
|
||||||
*
|
*
|
||||||
* This module contains cross-platform utilities for:
|
* This module contains cross-platform utilities for:
|
||||||
* - Process management (ports, killing processes)
|
* - Process management (ports, killing processes)
|
||||||
@@ -489,14 +489,20 @@ export function printHeader(title) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Print the application mode menu
|
* Print the application mode menu
|
||||||
|
* @param {object} options - Menu options
|
||||||
|
* @param {boolean} options.isDev - Whether this is dev mode (changes Docker option description)
|
||||||
*/
|
*/
|
||||||
export function printModeMenu() {
|
export function printModeMenu({ isDev = false } = {}) {
|
||||||
console.log('═══════════════════════════════════════════════════════');
|
console.log('═══════════════════════════════════════════════════════');
|
||||||
console.log(' Select Application Mode:');
|
console.log(' Select Application Mode:');
|
||||||
console.log('═══════════════════════════════════════════════════════');
|
console.log('═══════════════════════════════════════════════════════');
|
||||||
console.log(' 1) Web Application (Browser)');
|
console.log(' 1) Web Application (Browser)');
|
||||||
console.log(' 2) Desktop Application (Electron)');
|
console.log(' 2) Desktop Application (Electron)');
|
||||||
console.log(' 3) Docker Container (Isolated)');
|
if (isDev) {
|
||||||
|
console.log(' 3) Docker Container (Dev with Live Reload)');
|
||||||
|
} else {
|
||||||
|
console.log(' 3) Docker Container (Isolated)');
|
||||||
|
}
|
||||||
console.log('═══════════════════════════════════════════════════════');
|
console.log('═══════════════════════════════════════════════════════');
|
||||||
console.log('');
|
console.log('');
|
||||||
}
|
}
|
||||||
@@ -678,19 +684,58 @@ export function sanitizeProjectName(name) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if Docker images need to be rebuilt based on Dockerfile or package.json changes
|
* Get the current git commit SHA
|
||||||
* @param {string} baseDir - Base directory containing Dockerfile and package.json
|
* @param {string} baseDir - Base directory of the git repository
|
||||||
* @returns {boolean} - Whether images need to be rebuilt
|
* @returns {string|null} - Current commit SHA or null if not available
|
||||||
|
*/
|
||||||
|
export function getCurrentCommitSha(baseDir) {
|
||||||
|
try {
|
||||||
|
const sha = execSync('git rev-parse HEAD', {
|
||||||
|
encoding: 'utf-8',
|
||||||
|
cwd: baseDir,
|
||||||
|
stdio: ['pipe', 'pipe', 'pipe'],
|
||||||
|
}).trim();
|
||||||
|
return sha || null;
|
||||||
|
} catch {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the commit SHA from a Docker image label
|
||||||
|
* @param {string} imageName - Docker image name
|
||||||
|
* @returns {string|null} - Commit SHA from image label or null if not found
|
||||||
|
*/
|
||||||
|
export function getImageCommitSha(imageName) {
|
||||||
|
try {
|
||||||
|
const labelValue = execSync(
|
||||||
|
`docker image inspect ${imageName} --format "{{index .Config.Labels \\"automaker.git.commit.sha\\"}}" 2>/dev/null`,
|
||||||
|
{ encoding: 'utf-8' }
|
||||||
|
).trim();
|
||||||
|
return labelValue && labelValue !== 'unknown' && labelValue !== '' ? labelValue : null;
|
||||||
|
} catch {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if Docker images need to be rebuilt based on git commit SHA
|
||||||
|
* Compares the current git commit with the commit SHA stored in the image labels
|
||||||
|
* @param {string} baseDir - Base directory containing Dockerfile and docker-compose.yml
|
||||||
|
* @returns {{needsRebuild: boolean, reason: string, currentSha: string|null, imageSha: string|null}}
|
||||||
*/
|
*/
|
||||||
export function shouldRebuildDockerImages(baseDir) {
|
export function shouldRebuildDockerImages(baseDir) {
|
||||||
try {
|
try {
|
||||||
const dockerfilePath = path.join(baseDir, 'Dockerfile');
|
// Get current git commit SHA
|
||||||
const packageJsonPath = path.join(baseDir, 'package.json');
|
const currentSha = getCurrentCommitSha(baseDir);
|
||||||
|
if (!currentSha) {
|
||||||
// Get modification times of source files
|
return {
|
||||||
const dockerfileMtime = statSync(dockerfilePath).mtimeMs;
|
needsRebuild: true,
|
||||||
const packageJsonMtime = statSync(packageJsonPath).mtimeMs;
|
reason: 'Could not determine current git commit',
|
||||||
const latestSourceMtime = Math.max(dockerfileMtime, packageJsonMtime);
|
currentSha: null,
|
||||||
|
imageSha: null,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// Get project name from docker-compose config, falling back to directory name
|
// Get project name from docker-compose config, falling back to directory name
|
||||||
let projectName;
|
let projectName;
|
||||||
@@ -701,76 +746,94 @@ export function shouldRebuildDockerImages(baseDir) {
|
|||||||
});
|
});
|
||||||
const config = JSON.parse(composeConfig);
|
const config = JSON.parse(composeConfig);
|
||||||
projectName = config.name;
|
projectName = config.name;
|
||||||
} catch (error) {
|
} catch {
|
||||||
// Fallback handled below
|
// Fallback handled below
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sanitize project name (whether from config or fallback)
|
// Sanitize project name
|
||||||
// This prevents command injection and ensures valid Docker image names
|
|
||||||
const sanitizedProjectName = sanitizeProjectName(projectName || path.basename(baseDir));
|
const sanitizedProjectName = sanitizeProjectName(projectName || path.basename(baseDir));
|
||||||
const serverImageName = `${sanitizedProjectName}_server`;
|
const serverImageName = `${sanitizedProjectName}-server`;
|
||||||
const uiImageName = `${sanitizedProjectName}_ui`;
|
const uiImageName = `${sanitizedProjectName}-ui`;
|
||||||
|
|
||||||
// Check if images exist and get their creation times
|
// Check if images exist
|
||||||
let needsRebuild = false;
|
const serverExists = checkImageExists(serverImageName);
|
||||||
|
const uiExists = checkImageExists(uiImageName);
|
||||||
|
|
||||||
try {
|
if (!serverExists || !uiExists) {
|
||||||
// Check server image
|
return {
|
||||||
const serverImageInfo = execSync(
|
needsRebuild: true,
|
||||||
`docker image inspect ${serverImageName} --format "{{.Created}}" 2>/dev/null || echo ""`,
|
reason: 'Docker images do not exist',
|
||||||
{ encoding: 'utf-8', cwd: baseDir }
|
currentSha,
|
||||||
).trim();
|
imageSha: null,
|
||||||
|
};
|
||||||
// Check UI image
|
|
||||||
const uiImageInfo = execSync(
|
|
||||||
`docker image inspect ${uiImageName} --format "{{.Created}}" 2>/dev/null || echo ""`,
|
|
||||||
{ encoding: 'utf-8', cwd: baseDir }
|
|
||||||
).trim();
|
|
||||||
|
|
||||||
// If either image doesn't exist, we need to rebuild
|
|
||||||
if (!serverImageInfo || !uiImageInfo) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse image creation times (ISO 8601 format)
|
|
||||||
const serverCreated = new Date(serverImageInfo).getTime();
|
|
||||||
const uiCreated = new Date(uiImageInfo).getTime();
|
|
||||||
const oldestImageTime = Math.min(serverCreated, uiCreated);
|
|
||||||
|
|
||||||
// If source files are newer than images, rebuild
|
|
||||||
needsRebuild = latestSourceMtime > oldestImageTime;
|
|
||||||
} catch (error) {
|
|
||||||
// If images don't exist or inspect fails, rebuild
|
|
||||||
needsRebuild = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return needsRebuild;
|
// Get commit SHA from server image (both should have the same)
|
||||||
|
const imageSha = getImageCommitSha(serverImageName);
|
||||||
|
|
||||||
|
if (!imageSha) {
|
||||||
|
return {
|
||||||
|
needsRebuild: true,
|
||||||
|
reason: 'Docker images have no commit SHA label (legacy build)',
|
||||||
|
currentSha,
|
||||||
|
imageSha: null,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compare commit SHAs
|
||||||
|
if (currentSha !== imageSha) {
|
||||||
|
return {
|
||||||
|
needsRebuild: true,
|
||||||
|
reason: `Code changed: ${imageSha.substring(0, 8)} -> ${currentSha.substring(0, 8)}`,
|
||||||
|
currentSha,
|
||||||
|
imageSha,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
needsRebuild: false,
|
||||||
|
reason: 'Images are up to date',
|
||||||
|
currentSha,
|
||||||
|
imageSha,
|
||||||
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// If we can't check, err on the side of rebuilding
|
return {
|
||||||
log('Could not check Docker image status, will rebuild to be safe', 'yellow');
|
needsRebuild: true,
|
||||||
return true;
|
reason: 'Could not check Docker image status',
|
||||||
|
currentSha: null,
|
||||||
|
imageSha: null,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Launch Docker containers with docker-compose
|
* Check if a Docker image exists
|
||||||
|
* @param {string} imageName - Docker image name
|
||||||
|
* @returns {boolean} - Whether the image exists
|
||||||
|
*/
|
||||||
|
function checkImageExists(imageName) {
|
||||||
|
try {
|
||||||
|
execSync(`docker image inspect ${imageName} 2>/dev/null`, {
|
||||||
|
encoding: 'utf-8',
|
||||||
|
stdio: ['pipe', 'pipe', 'pipe'],
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Launch Docker containers for development with live reload
|
||||||
|
* Uses docker-compose.dev.yml which volume mounts the source code
|
||||||
|
* Also includes docker-compose.override.yml if it exists (for workspace mounts)
|
||||||
* @param {object} options - Configuration options
|
* @param {object} options - Configuration options
|
||||||
* @param {string} options.baseDir - Base directory containing docker-compose.yml
|
* @param {string} options.baseDir - Base directory containing docker-compose.dev.yml
|
||||||
* @param {object} options.processes - Processes object to track docker process
|
* @param {object} options.processes - Processes object to track docker process
|
||||||
* @returns {Promise<void>}
|
* @returns {Promise<void>}
|
||||||
*/
|
*/
|
||||||
export async function launchDockerContainers({ baseDir, processes }) {
|
export async function launchDockerDevContainers({ baseDir, processes }) {
|
||||||
log('Launching Docker Container (Isolated Mode)...', 'blue');
|
log('Launching Docker Container (Development Mode with Live Reload)...', 'blue');
|
||||||
|
|
||||||
// Check if Dockerfile or package.json changed and rebuild if needed
|
|
||||||
const needsRebuild = shouldRebuildDockerImages(baseDir);
|
|
||||||
const buildFlag = needsRebuild ? ['--build'] : [];
|
|
||||||
|
|
||||||
if (needsRebuild) {
|
|
||||||
log('Dockerfile or package.json changed - rebuilding images...', 'yellow');
|
|
||||||
} else {
|
|
||||||
log('Starting Docker containers...', 'yellow');
|
|
||||||
}
|
|
||||||
console.log('');
|
console.log('');
|
||||||
|
|
||||||
// Check if ANTHROPIC_API_KEY is set
|
// Check if ANTHROPIC_API_KEY is set
|
||||||
@@ -781,9 +844,26 @@ export async function launchDockerContainers({ baseDir, processes }) {
|
|||||||
console.log('');
|
console.log('');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start containers with docker-compose
|
log('Starting development container...', 'yellow');
|
||||||
// Will rebuild if Dockerfile or package.json changed
|
log('Source code is volume mounted for live reload', 'yellow');
|
||||||
processes.docker = crossSpawn('docker', ['compose', 'up', ...buildFlag], {
|
log('Running npm install inside container (this may take a moment on first run)...', 'yellow');
|
||||||
|
console.log('');
|
||||||
|
|
||||||
|
// Build compose file arguments
|
||||||
|
// Start with dev compose file, then add override if it exists
|
||||||
|
const composeArgs = ['compose', '-f', 'docker-compose.dev.yml'];
|
||||||
|
|
||||||
|
// Check if docker-compose.override.yml exists and include it for workspace mounts
|
||||||
|
const overridePath = path.join(baseDir, 'docker-compose.override.yml');
|
||||||
|
if (fsNative.existsSync(overridePath)) {
|
||||||
|
composeArgs.push('-f', 'docker-compose.override.yml');
|
||||||
|
log('Using docker-compose.override.yml for workspace mount', 'yellow');
|
||||||
|
}
|
||||||
|
|
||||||
|
composeArgs.push('up', '--build');
|
||||||
|
|
||||||
|
// Use docker-compose.dev.yml for development
|
||||||
|
processes.docker = crossSpawn('docker', composeArgs, {
|
||||||
stdio: 'inherit',
|
stdio: 'inherit',
|
||||||
cwd: baseDir,
|
cwd: baseDir,
|
||||||
env: {
|
env: {
|
||||||
@@ -791,6 +871,96 @@ export async function launchDockerContainers({ baseDir, processes }) {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
log('Development container starting...', 'blue');
|
||||||
|
log('UI will be available at: http://localhost:3007 (with HMR)', 'green');
|
||||||
|
log('API will be available at: http://localhost:3008', 'green');
|
||||||
|
console.log('');
|
||||||
|
log('Changes to source files will automatically reload.', 'yellow');
|
||||||
|
log('Press Ctrl+C to stop the container.', 'yellow');
|
||||||
|
|
||||||
|
await new Promise((resolve) => {
|
||||||
|
processes.docker.on('close', resolve);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Launch Docker containers with docker-compose (production mode)
|
||||||
|
* Uses git commit SHA to determine if rebuild is needed
|
||||||
|
* @param {object} options - Configuration options
|
||||||
|
* @param {string} options.baseDir - Base directory containing docker-compose.yml
|
||||||
|
* @param {object} options.processes - Processes object to track docker process
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
|
export async function launchDockerContainers({ baseDir, processes }) {
|
||||||
|
log('Launching Docker Container (Isolated Mode)...', 'blue');
|
||||||
|
|
||||||
|
// Check if ANTHROPIC_API_KEY is set
|
||||||
|
if (!process.env.ANTHROPIC_API_KEY) {
|
||||||
|
log('Warning: ANTHROPIC_API_KEY environment variable is not set.', 'yellow');
|
||||||
|
log('The server will require an API key to function.', 'yellow');
|
||||||
|
log('Set it with: export ANTHROPIC_API_KEY=your-key', 'yellow');
|
||||||
|
console.log('');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if rebuild is needed based on git commit SHA
|
||||||
|
const rebuildCheck = shouldRebuildDockerImages(baseDir);
|
||||||
|
|
||||||
|
if (rebuildCheck.needsRebuild) {
|
||||||
|
log(`Rebuild needed: ${rebuildCheck.reason}`, 'yellow');
|
||||||
|
|
||||||
|
if (rebuildCheck.currentSha) {
|
||||||
|
log(`Building images for commit: ${rebuildCheck.currentSha.substring(0, 8)}`, 'blue');
|
||||||
|
}
|
||||||
|
console.log('');
|
||||||
|
|
||||||
|
// Build with commit SHA label
|
||||||
|
const buildArgs = ['compose', 'build'];
|
||||||
|
if (rebuildCheck.currentSha) {
|
||||||
|
buildArgs.push('--build-arg', `GIT_COMMIT_SHA=${rebuildCheck.currentSha}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const buildProcess = crossSpawn('docker', buildArgs, {
|
||||||
|
stdio: 'inherit',
|
||||||
|
cwd: baseDir,
|
||||||
|
});
|
||||||
|
|
||||||
|
await new Promise((resolve, reject) => {
|
||||||
|
buildProcess.on('close', (code) => {
|
||||||
|
if (code !== 0) {
|
||||||
|
log('Build failed. Exiting.', 'red');
|
||||||
|
reject(new Error(`Docker build failed with code ${code}`));
|
||||||
|
} else {
|
||||||
|
log('Build complete. Starting containers...', 'green');
|
||||||
|
console.log('');
|
||||||
|
resolve();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
buildProcess.on('error', (err) => reject(err));
|
||||||
|
});
|
||||||
|
|
||||||
|
// Start containers (already built above)
|
||||||
|
processes.docker = crossSpawn('docker', ['compose', 'up'], {
|
||||||
|
stdio: 'inherit',
|
||||||
|
cwd: baseDir,
|
||||||
|
env: {
|
||||||
|
...process.env,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
log(`Images are up to date (commit: ${rebuildCheck.currentSha?.substring(0, 8) || 'unknown'})`, 'green');
|
||||||
|
log('Starting Docker containers...', 'yellow');
|
||||||
|
console.log('');
|
||||||
|
|
||||||
|
// Start containers without rebuilding
|
||||||
|
processes.docker = crossSpawn('docker', ['compose', 'up'], {
|
||||||
|
stdio: 'inherit',
|
||||||
|
cwd: baseDir,
|
||||||
|
env: {
|
||||||
|
...process.env,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
log('Docker containers starting...', 'blue');
|
log('Docker containers starting...', 'blue');
|
||||||
log('UI will be available at: http://localhost:3007', 'green');
|
log('UI will be available at: http://localhost:3007', 'green');
|
||||||
log('API will be available at: http://localhost:3008', 'green');
|
log('API will be available at: http://localhost:3008', 'green');
|
||||||
|
|||||||
247
start.mjs
247
start.mjs
@@ -1,247 +0,0 @@
|
|||||||
#!/usr/bin/env node
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Automaker - Production Mode Launch Script
|
|
||||||
*
|
|
||||||
* This script runs the application in production mode (no Vite dev server).
|
|
||||||
* It builds everything if needed, then serves static files via vite preview.
|
|
||||||
*
|
|
||||||
* Key differences from dev.mjs:
|
|
||||||
* - Uses pre-built static files instead of Vite dev server (faster startup)
|
|
||||||
* - No HMR or hot reloading
|
|
||||||
* - Server runs from compiled dist/ directory
|
|
||||||
* - Uses "vite preview" to serve static UI files
|
|
||||||
*
|
|
||||||
* Usage: npm run start
|
|
||||||
*/
|
|
||||||
|
|
||||||
import path from 'path';
|
|
||||||
import { fileURLToPath } from 'url';
|
|
||||||
|
|
||||||
import {
|
|
||||||
createRestrictedFs,
|
|
||||||
log,
|
|
||||||
runNpmAndWait,
|
|
||||||
runNpx,
|
|
||||||
printHeader,
|
|
||||||
printModeMenu,
|
|
||||||
resolvePortConfiguration,
|
|
||||||
createCleanupHandler,
|
|
||||||
setupSignalHandlers,
|
|
||||||
startServerAndWait,
|
|
||||||
ensureDependencies,
|
|
||||||
prompt,
|
|
||||||
killProcessTree,
|
|
||||||
sleep,
|
|
||||||
launchDockerContainers,
|
|
||||||
} from './scripts/launcher-utils.mjs';
|
|
||||||
|
|
||||||
const __filename = fileURLToPath(import.meta.url);
|
|
||||||
const __dirname = path.dirname(__filename);
|
|
||||||
|
|
||||||
// Create restricted fs for this script's directory
|
|
||||||
const fs = createRestrictedFs(__dirname, 'start.mjs');
|
|
||||||
|
|
||||||
// Track background processes for cleanup
|
|
||||||
const processes = {
|
|
||||||
server: null,
|
|
||||||
web: null,
|
|
||||||
electron: null,
|
|
||||||
docker: null,
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Build all production artifacts
|
|
||||||
*/
|
|
||||||
async function ensureProductionBuilds() {
|
|
||||||
// Always build shared packages first to ensure they're up to date
|
|
||||||
log('Building shared packages...', 'blue');
|
|
||||||
try {
|
|
||||||
await runNpmAndWait(['run', 'build:packages'], { stdio: 'inherit' }, __dirname);
|
|
||||||
log('✓ Shared packages built', 'green');
|
|
||||||
} catch (error) {
|
|
||||||
log(`Failed to build shared packages: ${error.message}`, 'red');
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Always rebuild server to ensure it's in sync with packages
|
|
||||||
log('Building server...', 'blue');
|
|
||||||
try {
|
|
||||||
await runNpmAndWait(
|
|
||||||
['run', 'build'],
|
|
||||||
{ stdio: 'inherit' },
|
|
||||||
path.join(__dirname, 'apps', 'server')
|
|
||||||
);
|
|
||||||
log('✓ Server built', 'green');
|
|
||||||
} catch (error) {
|
|
||||||
log(`Failed to build server: ${error.message}`, 'red');
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Always rebuild UI to ensure it's in sync with latest code
|
|
||||||
log('Building UI...', 'blue');
|
|
||||||
try {
|
|
||||||
await runNpmAndWait(['run', 'build'], { stdio: 'inherit' }, __dirname);
|
|
||||||
log('✓ UI built', 'green');
|
|
||||||
console.log('');
|
|
||||||
} catch (error) {
|
|
||||||
log(`Failed to build UI: ${error.message}`, 'red');
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Main function
|
|
||||||
*/
|
|
||||||
async function main() {
|
|
||||||
// Change to script directory
|
|
||||||
process.chdir(__dirname);
|
|
||||||
|
|
||||||
printHeader('Automaker Production Mode');
|
|
||||||
|
|
||||||
// Ensure dependencies are installed
|
|
||||||
await ensureDependencies(fs, __dirname);
|
|
||||||
|
|
||||||
// Build production artifacts if needed
|
|
||||||
await ensureProductionBuilds();
|
|
||||||
|
|
||||||
// Resolve port configuration (check/kill/change ports)
|
|
||||||
const { webPort, serverPort, corsOriginEnv } = await resolvePortConfiguration();
|
|
||||||
|
|
||||||
// Show mode selection menu
|
|
||||||
printModeMenu();
|
|
||||||
|
|
||||||
// Setup cleanup handlers
|
|
||||||
const cleanup = createCleanupHandler(processes);
|
|
||||||
setupSignalHandlers(cleanup);
|
|
||||||
|
|
||||||
// Prompt for choice
|
|
||||||
while (true) {
|
|
||||||
const choice = await prompt('Enter your choice (1, 2, or 3): ');
|
|
||||||
|
|
||||||
if (choice === '1') {
|
|
||||||
console.log('');
|
|
||||||
log('Launching Web Application (Production Mode)...', 'blue');
|
|
||||||
|
|
||||||
// Start the backend server in PRODUCTION mode
|
|
||||||
// Uses "npm run start" in apps/server which runs the compiled dist/
|
|
||||||
// NOT the Vite dev server (no HMR, faster startup)
|
|
||||||
processes.server = await startServerAndWait({
|
|
||||||
serverPort,
|
|
||||||
corsOriginEnv,
|
|
||||||
npmArgs: ['run', 'start'],
|
|
||||||
cwd: path.join(__dirname, 'apps', 'server'),
|
|
||||||
fs,
|
|
||||||
baseDir: __dirname,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!processes.server) {
|
|
||||||
await cleanup();
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
log(`Starting web server...`, 'blue');
|
|
||||||
|
|
||||||
// Start vite preview to serve pre-built static files
|
|
||||||
// This is NOT Vite dev server - it just serves the dist/ folder
|
|
||||||
// No HMR, no compilation, just static file serving
|
|
||||||
processes.web = runNpx(
|
|
||||||
['vite', 'preview', '--port', String(webPort)],
|
|
||||||
{
|
|
||||||
stdio: 'inherit',
|
|
||||||
env: {
|
|
||||||
VITE_SERVER_URL: `http://localhost:${serverPort}`,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
path.join(__dirname, 'apps', 'ui')
|
|
||||||
);
|
|
||||||
|
|
||||||
log(`The application is available at: http://localhost:${webPort}`, 'green');
|
|
||||||
console.log('');
|
|
||||||
|
|
||||||
await new Promise((resolve) => {
|
|
||||||
processes.web.on('close', resolve);
|
|
||||||
});
|
|
||||||
|
|
||||||
break;
|
|
||||||
} else if (choice === '2') {
|
|
||||||
console.log('');
|
|
||||||
log('Launching Desktop Application (Production Mode)...', 'blue');
|
|
||||||
log('(Electron will start its own backend server)', 'yellow');
|
|
||||||
console.log('');
|
|
||||||
|
|
||||||
// Run electron directly with the built main.js
|
|
||||||
const electronMainPath = path.join(__dirname, 'apps', 'ui', 'dist-electron', 'main.js');
|
|
||||||
|
|
||||||
if (!fs.existsSync(electronMainPath)) {
|
|
||||||
log('Error: Electron main process not built. Run build first.', 'red');
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start vite preview to serve built static files for electron
|
|
||||||
// (Electron in non-packaged mode needs a server to load from)
|
|
||||||
log('Starting static file server...', 'blue');
|
|
||||||
processes.web = runNpx(
|
|
||||||
['vite', 'preview', '--port', String(webPort)],
|
|
||||||
{
|
|
||||||
stdio: ['ignore', 'pipe', 'pipe'],
|
|
||||||
env: {
|
|
||||||
VITE_SERVER_URL: `http://localhost:${serverPort}`,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
path.join(__dirname, 'apps', 'ui')
|
|
||||||
);
|
|
||||||
|
|
||||||
// Wait for vite preview to start
|
|
||||||
await sleep(2000);
|
|
||||||
|
|
||||||
// Use electron from node_modules with NODE_ENV=production
|
|
||||||
// This ensures electron loads from the preview server, not Vite dev
|
|
||||||
processes.electron = runNpx(
|
|
||||||
['electron', electronMainPath],
|
|
||||||
{
|
|
||||||
stdio: 'inherit',
|
|
||||||
env: {
|
|
||||||
TEST_PORT: String(webPort),
|
|
||||||
PORT: String(serverPort),
|
|
||||||
VITE_DEV_SERVER_URL: `http://localhost:${webPort}`,
|
|
||||||
VITE_SERVER_URL: `http://localhost:${serverPort}`,
|
|
||||||
CORS_ORIGIN: corsOriginEnv,
|
|
||||||
NODE_ENV: 'production',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
path.join(__dirname, 'apps', 'ui')
|
|
||||||
);
|
|
||||||
|
|
||||||
await new Promise((resolve) => {
|
|
||||||
processes.electron.on('close', () => {
|
|
||||||
// Also kill vite preview when electron closes
|
|
||||||
if (processes.web && !processes.web.killed && processes.web.pid) {
|
|
||||||
killProcessTree(processes.web.pid);
|
|
||||||
}
|
|
||||||
resolve();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
break;
|
|
||||||
} else if (choice === '3') {
|
|
||||||
console.log('');
|
|
||||||
await launchDockerContainers({ baseDir: __dirname, processes });
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
log('Invalid choice. Please enter 1, 2, or 3.', 'red');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run main function
|
|
||||||
main().catch(async (err) => {
|
|
||||||
console.error(err);
|
|
||||||
const cleanup = createCleanupHandler(processes);
|
|
||||||
try {
|
|
||||||
await cleanup();
|
|
||||||
} catch (cleanupErr) {
|
|
||||||
console.error('Cleanup error:', cleanupErr);
|
|
||||||
}
|
|
||||||
process.exit(1);
|
|
||||||
});
|
|
||||||
Reference in New Issue
Block a user