Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 66 additions & 0 deletions .claude/agents/project-structure-validator.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
---
name: project-structure-validator
description: Validates project structure against co-location and architecture patterns defined in AGENTS.md
color: blue
---

You are a project structure validator for the Superset monorepo.

## Speed Optimization

**ALWAYS** build component graph first:
```bash
bash .claude/agents/project-structure-validator/build-component-graph.sh [directory]
cat .claude/agents/project-structure-validator/.component-graph.json
```

This avoids slow grep operations for import counting.

## Analysis Approach

**1. Find components** (fast):
```bash
find [directory] -name "*.tsx" -type f ! -name "*.test.tsx" ! -name "*.stories.tsx"
```

**2. Count imports** (use graph, else grep):
```bash
grep -r "from.*ComponentName" [directory] --include="*.tsx" --include="*.ts" | wc -l
```

**3. Multi-component check**:
```bash
grep -c "^export function\|^export const.*=>" File.tsx
```

## Rules from AGENTS.md

1. Used once → nest under parent's `components/`
2. Used 2+ → promote to shared parent's `components/`
3. One component per file
4. Co-locate utils/hooks/constants/tests/stories

## Output Format (CONCISE)

```markdown
## Summary
Score: [%] | [N] components | [N] violations

## Critical Issues
[VIOLATION] Component at wrong location (used Nx, at Y)
Fix: mv X Y

## Metrics
- Components: [N], avg depth [N]
- Violations: [N] location, [N] multi-component

## Performance Analysis
- Tool calls: [N] ([breakdown])
- Slowest: [operation] ([reason])
- Used component graph: [yes/no]
- Optimization: [suggestion]
```

## Self-Improvement

At end of report, suggest modifications to THIS file (.claude/agents/project-structure-validator.md) that would make you faster/better.
2 changes: 2 additions & 0 deletions .claude/agents/project-structure-validator/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Generated component dependency graph
.component-graph.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#!/bin/bash
# Builds component dependency graph for fast lookup
# Output: .claude/agents/project-structure-validator/.component-graph.json

DIR="${1:-.}"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
OUTPUT="$SCRIPT_DIR/.component-graph.json"

echo "{" > "$OUTPUT"
echo ' "components": {' >> "$OUTPUT"

first=true
find "$DIR" -name "*.tsx" -type f ! -path "*/node_modules/*" ! -name "*.test.tsx" ! -name "*.stories.tsx" | while read file; do
component=$(basename "$file" .tsx)
path="${file#$DIR/}"

# Count imports
count=$(grep -r "from.*['\"].*$component['\"]" "$DIR" --include="*.tsx" --include="*.ts" 2>/dev/null | grep -v "$file" | wc -l | tr -d ' ')

# Get importers
importers=$(grep -l "from.*['\"].*$component['\"]" "$DIR" --include="*.tsx" --include="*.ts" -r 2>/dev/null | grep -v "$file" | sed "s|^$DIR/||" | paste -sd "," -)

if [ "$first" = true ]; then
first=false
else
echo "," >> "$OUTPUT"
fi

echo -n " \"$path\": {\"component\": \"$component\", \"imports\": $count, \"importers\": [" >> "$OUTPUT"
if [ -n "$importers" ]; then
echo "$importers" | sed 's/,/","/g' | sed 's/^/"/' | sed 's/$/"/' | tr -d '\n' >> "$OUTPUT"
fi
echo -n "]}" >> "$OUTPUT"
done

echo "" >> "$OUTPUT"
echo ' },' >> "$OUTPUT"
echo " \"generated\": \"$(date -u +%Y-%m-%dT%H:%M:%SZ)\"" >> "$OUTPUT"
echo "}" >> "$OUTPUT"

echo "Built component graph: $OUTPUT"
13 changes: 1 addition & 12 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,14 +1,3 @@
# Database connection URL for local PostgreSQL
# Connect to the 'superset' database
DATABASE_URL=postgresql://postgres:postgres@localhost:5432/superset

STUB_API_KEY=

# Electron Desktop App
# Vite dev server port for Electron renderer process
# Default: 4927. Auto-increments when creating new worktrees to avoid port conflicts
VITE_DEV_SERVER_PORT=4927

# Enable new UI layout (workspace tabs at top, worktree sidebar)
# Set to 'true' to enable the new mock UI for visual iteration
ENABLE_NEW_UI=false
DATABASE_URL=postgresql://postgres:postgres@localhost:5432/superset
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,6 @@ mise.toml
# Turbo
.turbo
.envrc

# Superset
.superset
94 changes: 58 additions & 36 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ Bun + Turbo monorepo with:
- `apps/docs` - Documentation site
- `apps/blog` - Blog site
- **Packages**:
- `packages/ui` - Shared UI components (shadcn/ui + TailwindCSS v4)
- `packages/ui` - Shared UI components (shadcn/ui + TailwindCSS v4).
- Add components: `npx shadcn@latest add <component>` (run in `packages/ui/`)
- `packages/db` - Drizzle ORM database schema
- `packages/constants` - Shared constants
- `packages/models` - Shared data models
Expand Down Expand Up @@ -52,16 +53,6 @@ bun run clean # Clean root node_modules
bun run clean:workspaces # Clean all workspace node_modules
```

## UI Components

All components in `packages/ui`:
- **Import**: `@superset/ui/button`, `@superset/ui/input`, etc.
- **Icons**: `@superset/ui/icons`
- **Utils**: `@superset/ui/utils`
- **Hooks**: `@superset/ui/hooks`
- **Styles**: `@superset/ui/globals.css`
- **Add shadcn component**: `npx shadcn@latest add <component>` (run in `packages/ui/`)

## Code Quality

**Biome runs at root level** (not per-package) for speed:
Expand All @@ -74,9 +65,62 @@ All components in `packages/ui`:

1. **Keep diffs minimal** - targeted edits only
2. **Follow existing patterns** - match the codebase style
5. **Type safety** - avoid `any` unless necessary
6. **Don't run dev servers** in automation
7. **Search narrowly** - avoid reading large files/assets
3. **Type safety** - avoid `any` unless necessary
4. **Don't run dev servers** in automation
5. **Search narrowly** - avoid reading large files/assets

## Project Structure

All projects in this repo should be structured like this:

```
app/
├── page.tsx
├── dashboard/
│ ├── page.tsx
│ └── components/
│ └── MetricsChart/
│ ├── MetricsChart.tsx
│ ├── MetricsChart.test.tsx # Tests co-located
│ ├── index.ts
│ ├── useMetricsData.ts # Hook used only here
│ └── constants.ts
└── components/
├── Sidebar/
│ ├── Sidebar.tsx
│ ├── Sidebar.test.tsx # Tests co-located
│ ├── index.ts
│ ├── components/ # Used 2+ times IN Sidebar
│ │ └── SidebarButton/ # Shared by SidebarNav + SidebarFooter
│ │ ├── SidebarButton.tsx
│ │ ├── SidebarButton.test.tsx
│ │ └── index.ts
│ ├── SidebarNav/
│ │ ├── SidebarNav.tsx
│ │ └── index.ts
│ └── SidebarFooter/
│ ├── SidebarFooter.tsx
│ └── index.ts
└── HeroSection/
├── HeroSection.tsx
├── HeroSection.test.tsx # Tests co-located
├── index.ts
└── components/ # Used ONLY by HeroSection
└── HeroCanvas/
├── HeroCanvas.tsx
├── HeroCanvas.test.tsx
├── HeroCanvas.stories.tsx
├── index.ts
└── config.ts

components/ # Used in 2+ pages (last resort)
└── Header/
```

1. **One folder per component**: `ComponentName/ComponentName.tsx` + `index.ts` for barrel export
2. **Co-locate by usage**: If used once, nest under parent's `components/`. If used 2+ times, promote to **highest shared parent's** `components/` (or `components/` as last resort)
3. **One component per file**: No multi-component files
4. **Co-locate dependencies**: Utils, hooks, constants, config, tests, stories live next to the file using them

## Database Rules

Expand Down Expand Up @@ -179,28 +223,6 @@ const result = await window.ipcRenderer.invoke("my-channel", {
- `types.ts` - Data models
- `ipc-channels.ts` - IPC type definitions

### Running Multiple Instances

You can run multiple Electron instances simultaneously for parallel development. See `apps/desktop/MULTIPLE_INSTANCES.md` for full documentation.

**Quick start:**
```bash
# Method 1: Auto-increment port when creating worktrees
# The update-port.sh script runs automatically during worktree setup
# and increments VITE_DEV_SERVER_PORT in the root .env

# Method 2: Manual port update
./update-port.sh # Increments port in root .env
cd apps/desktop && bun dev

# Method 3: Helper scripts (override .env)
./dev-instance.sh instance2 4928
```

Each instance needs:
- **Separate dev server port** - Set via `VITE_DEV_SERVER_PORT` in root `.env`
- **Separate user data directory** - Pass via `--user-data-dir` flag

### Environment Variable Loading

The desktop app loads environment variables from the monorepo root `.env` file:
Expand Down
1 change: 1 addition & 0 deletions apps/blog/tsconfig.tsbuildinfo

Large diffs are not rendered by default.

3 changes: 0 additions & 3 deletions apps/desktop/electron.vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,6 @@ export default defineConfig({
define: {
"process.env.NODE_ENV": JSON.stringify(process.env.NODE_ENV),
"process.platform": JSON.stringify(process.platform),
"import.meta.env.ENABLE_NEW_UI": JSON.stringify(
process.env.ENABLE_NEW_UI || "false",
),
"import.meta.env.DEV_SERVER_PORT": JSON.stringify(getPortSync()),
},

Expand Down
26 changes: 6 additions & 20 deletions apps/desktop/src/main/lib/tmux-manager.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { spawnSync } from "node:child_process";
import { randomUUID } from "node:crypto";
import { existsSync, readFileSync, writeFileSync } from "node:fs";
import { mkdir } from "node:fs/promises";
import os from "node:os";
import { dirname, join } from "node:path";
import { spawnSync } from "node:child_process";
import type { BrowserWindow } from "electron";
import { app } from "electron";
import * as pty from "node-pty";
Expand Down Expand Up @@ -231,7 +231,9 @@ class TmuxManager {

// Resize the tmux window BEFORE attaching to ensure proper dimensions
// This is crucial for reconnection after restart
console.log(`[TmuxManager] Resizing tmux window ${sid} to ${cols}x${rows} before attach`);
console.log(
`[TmuxManager] Resizing tmux window ${sid} to ${cols}x${rows} before attach`,
);
const resizeResult = spawnSync("tmux", [
"-L",
this.TMUX_SOCKET,
Expand All @@ -253,13 +255,7 @@ class TmuxManager {

// Force tmux to refresh and reflow content at new size
// This ensures the pane content is properly wrapped for the new dimensions
spawnSync("tmux", [
"-L",
this.TMUX_SOCKET,
"refresh-client",
"-t",
sid,
]);
spawnSync("tmux", ["-L", this.TMUX_SOCKET, "refresh-client", "-t", sid]);

// Attach to the session via node-pty
console.log(`[TmuxManager] Attaching to session: ${sid}`);
Expand Down Expand Up @@ -289,10 +285,6 @@ class TmuxManager {

// Set up data listener
ptyProcess.onData((data: string) => {
// Debug: log what's coming from PTY
if (data.includes("1;2c") || data.includes("0;276")) {
console.log(`[TmuxManager] PTY output from ${sid}:`, JSON.stringify(data), `(length: ${data.length})`);
}
this.addTerminalMessage(sid, data);
});

Expand Down Expand Up @@ -445,7 +437,6 @@ class TmuxManager {
const session = this.sessions.get(sid);
if (session?.pty) {
// Debug: log what's being written
console.log(`[TmuxManager] Writing to ${sid}:`, JSON.stringify(data), `(length: ${data.length})`);
session.pty.write(data);
return true;
}
Expand Down Expand Up @@ -561,11 +552,8 @@ class TmuxManager {

// Return in-memory history if available
if (session.outputHistory.length > 0) {
console.log(`[TmuxManager] Returning ${session.outputHistory.length} bytes of cached history for ${sid}`);
return session.outputHistory;
}

console.log(`[TmuxManager] No cached history for ${sid}, tmux will send content on attach`);
return undefined;
}

Expand Down Expand Up @@ -631,9 +619,7 @@ class TmuxManager {
"utf-8",
);

console.log(
`[TmuxManager] Saved ${metadata.length} sessions to disk`,
);
console.log(`[TmuxManager] Saved ${metadata.length} sessions to disk`);
} catch (error) {
console.error("[TmuxManager] Failed to save sessions to disk:", error);
}
Expand Down
Loading
Loading