Skip to content
Merged
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
80 changes: 7 additions & 73 deletions .debugging/delete-all-sonarcloud-projects.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,72 +9,16 @@ if [ ! -f "$CONFIG_FILE" ]; then
fi

# Extract values from migrate-config.json
SQ_URL=$(node -e "const c=require('$CONFIG_FILE'); console.log(c.sonarqube.url)")
SQ_TOKEN=$(node -e "const c=require('$CONFIG_FILE'); console.log(c.sonarqube.token)")
ORG_KEY=$(node -e "const c=require('$CONFIG_FILE'); console.log(c.sonarcloud.organizations[0].key)")
SC_TOKEN=$(node -e "const c=require('$CONFIG_FILE'); console.log(c.sonarcloud.organizations[0].token)")
SC_URL=$(node -e "const c=require('$CONFIG_FILE'); console.log(c.sonarcloud.organizations[0].url)")

echo "SonarQube URL : $SQ_URL"
echo "SonarCloud Org : $ORG_KEY"
echo "SonarCloud URL : $SC_URL"
echo ""

# --- Fetch all project keys from SonarQube ---
echo "Fetching projects from SonarQube..."
SQ_PAGE=1
SQ_PAGE_SIZE=500
SQ_KEYS=()

while true; do
SQ_RESPONSE=$(curl -sf \
-u "$SQ_TOKEN:" \
"$SQ_URL/api/projects/search?ps=$SQ_PAGE_SIZE&p=$SQ_PAGE")

KEYS=$(echo "$SQ_RESPONSE" | node -e "
let data='';
process.stdin.on('data',d=>data+=d);
process.stdin.on('end',()=>{
const json=JSON.parse(data);
(json.components||[]).forEach(c=>console.log(c.key));
});
")

if [ -z "$KEYS" ]; then
break
fi

while IFS= read -r KEY; do
SQ_KEYS+=("$KEY")
done <<< "$KEYS"

SQ_TOTAL=$(echo "$SQ_RESPONSE" | node -e "
let data='';
process.stdin.on('data',d=>data+=d);
process.stdin.on('end',()=>{
const json=JSON.parse(data);
console.log(json.paging?.total||0);
});
")

SQ_FETCHED=${#SQ_KEYS[@]}
if [ "$SQ_FETCHED" -ge "$SQ_TOTAL" ]; then
break
fi

SQ_PAGE=$(( SQ_PAGE + 1 ))
done

echo "Found ${#SQ_KEYS[@]} project(s) in SonarQube."
echo ""

if [ "${#SQ_KEYS[@]}" -eq 0 ]; then
echo "No projects found in SonarQube. Nothing to delete."
exit 0
fi

# --- Fetch all project keys from SonarCloud ---
echo "Fetching projects from SonarCloud..."
echo "Fetching ALL projects from SonarCloud..."
SC_PAGE=1
SC_PAGE_SIZE=500
SC_KEYS=()
Expand Down Expand Up @@ -121,30 +65,20 @@ done
echo "Found ${#SC_KEYS[@]} project(s) in SonarCloud."
echo ""

# --- Find intersection: SonarCloud keys that also exist in SonarQube ---
SQ_KEYS_STR=$( IFS=$'\n'; echo "${SQ_KEYS[*]}" )

MATCHED_KEYS=()
for KEY in "${SC_KEYS[@]}"; do
if echo "$SQ_KEYS_STR" | grep -qxF "$KEY"; then
MATCHED_KEYS+=("$KEY")
fi
done

TOTAL_COUNT=${#MATCHED_KEYS[@]}
TOTAL_COUNT=${#SC_KEYS[@]}

if [ "$TOTAL_COUNT" -eq 0 ]; then
echo "No matching project keys found between SonarQube and SonarCloud. Nothing to delete."
echo "No projects found in SonarCloud. Nothing to delete."
exit 0
fi

echo "Found $TOTAL_COUNT SonarCloud project(s) matching SonarQube project keys:"
for KEY in "${MATCHED_KEYS[@]}"; do
echo "Will delete ALL $TOTAL_COUNT project(s) from SonarCloud:"
for KEY in "${SC_KEYS[@]}"; do
echo " - $KEY"
done
echo ""

read -r -p "Are you sure you want to permanently delete these $TOTAL_COUNT project(s) from SonarCloud? [yes/N] " CONFIRM
read -r -p "Are you sure you want to permanently delete ALL $TOTAL_COUNT project(s) from SonarCloud? [yes/N] " CONFIRM
if [ "$CONFIRM" != "yes" ]; then
echo "Aborted."
exit 0
Expand All @@ -154,7 +88,7 @@ echo ""
TMPDIR=$(mktemp -d)
trap 'rm -rf "$TMPDIR"' EXIT

for KEY in "${MATCHED_KEYS[@]}"; do
for KEY in "${SC_KEYS[@]}"; do
(
HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" \
-X POST \
Expand Down
4 changes: 0 additions & 4 deletions .debugging/test-migrate-verify.sh

This file was deleted.

3 changes: 3 additions & 0 deletions .debugging/test-migrate.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/bin/bash

./dist/bin/cloudvoyager-macos-arm64 migrate -c migrate-config.json
3 changes: 3 additions & 0 deletions .debugging/test-verify.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/bin/bash

./dist/bin/cloudvoyager-macos-arm64 verify -c migrate-config.json
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ config.json
**/*.md
!README.md
!CHANGELOG.md
!CLAUDE.md
!DESIGN.md
!docs/**/*.md
debug/
proto/
Expand All @@ -68,4 +70,4 @@ dist/desktop/
**/*.json.journal.backup
**/*.json.gz

sonar-local-scan.sh
sonar-local-scan.sh
51 changes: 51 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Cloud Voyager - CLAUDE CODE CLI Directives

## Skill routing

When the user's request matches an available skill, ALWAYS invoke it using the Skill
tool as your FIRST action. Do NOT answer directly, do NOT use other tools first.
The skill has specialized workflows that produce better results than ad-hoc answers.

Key routing rules:
- Product ideas, "is this worth building", brainstorming → invoke office-hours
- Bugs, errors, "why is this broken", 500 errors → invoke investigate
- Ship, deploy, push, create PR → invoke ship
- QA, test the site, find bugs → invoke qa
- Code review, check my diff → invoke review
- Update docs after shipping → invoke document-release
- Weekly retro → invoke retro
- Design system, brand → invoke design-consultation
- Visual audit, design polish → invoke design-review
- Architecture review → invoke plan-eng-review
- Save progress, checkpoint, resume → invoke checkpoint
- Code quality, health check → invoke health

## gstack (REQUIRED — global install)

**Before doing ANY work, verify gstack is installed:**

```bash
test -d ~/.claude/skills/gstack/bin && echo "GSTACK_OK" || echo "GSTACK_MISSING"
```

If GSTACK_MISSING: STOP. Do not proceed. Tell the user:

> gstack is required for all AI-assisted work in this repo.
> Install it:
> ```bash
> git clone --depth 1 https://github.com/garrytan/gstack.git ~/.claude/skills/gstack
> cd ~/.claude/skills/gstack && ./setup --team
> ```
> Then restart your AI coding tool.

Do not skip skills, ignore gstack errors, or work around missing gstack.

Using gstack skills: After install, skills like /qa, /ship, /review, /investigate,
and /browse are available. Use /browse for all web browsing.
Use ~/.claude/skills/gstack/... for gstack file paths (the global path).

## Design System
Always read DESIGN.md before making any visual or UI decisions.
All font choices, colors, spacing, and aesthetic direction are defined there.
Do not deviate without explicit user approval.
In QA mode, flag any code that doesn't match DESIGN.md.
125 changes: 125 additions & 0 deletions DESIGN.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
# Design System — CloudVoyager

## Product Context
- **What this is:** SonarQube-to-SonarCloud migration tool (CLI + Electron desktop app)
- **Who it's for:** DevOps engineers, platform teams, and SonarQube admins at enterprises
- **Space/industry:** Developer tooling, code quality, DevSecOps
- **Project type:** Desktop app (Electron) + CLI tool

## Aesthetic Direction
- **Direction:** Retro-Futuristic Developer Tool
- **Decoration level:** Intentional (glow effects, scanlines, and glass blur serve hierarchy, not decoration)
- **Mood:** A terminal that went to art school. Dark, precise, confident. The pixel-art whale gives it personality without undermining the seriousness of enterprise migration tooling.
- **Mascot:** Pixel-art whale (animated progress bar sprite). The whale IS the brand.

## Typography
- **Display/Hero:** Geist (700 weight) — geometric, built for developer tool UIs, clean at large sizes
- **Body:** Geist (400/500 weight) — same family for coherence, excellent readability on dark backgrounds
- **UI/Labels:** Geist (500 weight, 13px)
- **Data/Tables:** Geist Mono (tabular-nums built in) — ensures numbers align in columns
- **Code:** Geist Mono (400 weight)
- **Loading:** Bundle in Electron app (self-hosted, ~100KB). No CDN dependency.
- **Scale:**
- xs: 11px (badges, meta)
- sm: 13px (labels, hints, sidebar)
- base: 14px (body text, form inputs)
- lg: 16px (section headers)
- xl: 18px (page titles)
- 2xl: 22px (hero subheadings)
- 3xl: 28px (hero headings)
- display: 32px (welcome screen title)

## Color
- **Approach:** Restrained (1 accent + neutrals, color is rare and meaningful)

### Dark Theme (primary)
- **Background primary:** #0f1419
- **Background secondary:** #1a1f2e
- **Background tertiary:** #242938
- **Background card:** rgba(30, 36, 51, 0.7) + backdrop-filter: blur(12px)
- **Background input:** #161b27
- **Border:** #2d3548
- **Border focus:** #4a7dff
- **Text primary:** #e6edf3
- **Text secondary:** #9ba5af
- **Text muted:** #848d97
- **Accent:** #4a7dff
- **Accent hover:** #5c8bff
- **Accent background:** rgba(74, 125, 255, 0.12)
- **Glow accent:** rgba(74, 125, 255, 0.4)

### Light Theme
- **Background primary:** #ffffff
- **Background secondary:** #f6f8fa
- **Background tertiary:** #e9ecef
- **Background card:** rgba(255, 255, 255, 0.85) + backdrop-filter: blur(8px)
- **Border:** #d0d7de
- **Border focus:** #0969da
- **Text primary:** #1f2328
- **Text secondary:** #656d76
- **Text muted:** #8b949e
- **Accent:** #0969da
- **Accent hover:** #0860ca

### Semantic Colors (both themes)
- **Success:** #3fb950 (dark) / #1a7f37 (light) — bg: rgba(63, 185, 80, 0.12/0.08)
- **Warning:** #d29922 (dark) / #9a6700 (light) — bg: rgba(210, 153, 34, 0.12/0.08)
- **Danger:** #f85149 (dark) / #cf222e (light) — bg: rgba(248, 81, 73, 0.12/0.08)
- **Info/Cyan:** #38bdf8 (dark) / #0284c7 (light) — used for whale highlights and informational alerts

### ANSI Colors (log viewer)
- Red: #f85149, Green: #3fb950, Yellow: #d29922, Blue: #58a6ff
- Magenta: #bc8cff, Cyan: #39d2f5, White: #e6edf3, Gray: #848d97

## Spacing
- **Base unit:** 4px
- **Density:** Comfortable
- **Scale:**
- 2xs: 2px
- xs: 4px
- sm: 8px
- md: 16px
- lg: 24px
- xl: 32px
- 2xl: 48px
- 3xl: 64px
- **Rule:** No ad-hoc values. Round to nearest scale step. Former 10px becomes 8px or 12px. Former 14px becomes 16px. Former 20px becomes 24px. Former 28px becomes 24px or 32px.

## Layout
- **Approach:** Grid-disciplined (sidebar + content area)
- **Sidebar:** 260px fixed width, dark glassmorphic background
- **Content area:** flex: 1, padding 32px, auto-scroll
- **Max content width:** 800px (forms), unconstrained (execution/results screens)
- **Border radius:**
- sm: 4px (buttons, badges, inline code)
- md: 8px (cards, inputs, sections)
- lg: 12px (modals, large panels)
- full: 9999px (status badges, pills)

## Glass Effect
- **Card background:** rgba(30, 36, 51, 0.7)
- **Backdrop blur:** 12px (cards), 16px (overlays), 8px (subtle)
- **Glass border:** 1px solid rgba(255, 255, 255, 0.06)
- **Contrast rule:** All text on glass surfaces must maintain 4.5:1 contrast ratio. Add solid fallback background behind text areas if the blur alone doesn't guarantee readability.

## Motion
- **Approach:** Intentional (animations serve hierarchy and feedback, not decoration)
- **Easing:** enter: ease-out, exit: ease-in, move: ease-in-out
- **Duration tiers:**
- Micro (150ms): button hovers, input focus, tooltip show
- Standard (200-400ms): screen transitions, card entrance, progress updates
- Dramatic (600ms+): whale progress, completion celebration, glow pulses
- **Named animations:**
- screen-enter: 200ms ease-out (fade + scale(0.98) + blur(4px))
- card-entrance: 400ms ease-out, staggered by index
- glow-pulse: 2s ease-in-out infinite (active/running states)
- whale-swim: 600ms ease-out (progress bar width transition)

## Decisions Log
| Date | Decision | Rationale |
|------|----------|-----------|
| 2026-04-22 | Geist replaces system font stack | Intentional typography for developer tool identity. Same family across display/body/mono for coherence. |
| 2026-04-22 | Formalize 4px spacing scale | Kill ad-hoc values (10px, 14px, 20px, 28px). Consistent rhythm. |
| 2026-04-22 | Contrast rule for glass surfaces | Glassmorphic design risks WCAG failures when background shifts. Solid fallbacks required. |
| 2026-04-22 | 3-tier motion system | Micro/standard/dramatic prevents animation soup. Each tier has a clear purpose. |
| 2026-04-22 | Initial design system created | Extracted from existing CSS (wizard.css, main.css) and evolved via /design-consultation |
Loading