From just-ship
Installs Just Ship globally if needed, auto-detects project tech stack, configures project.json and CLAUDE.md, connects to board via --board, --key, --project flags.
npx claudepluginhub yves-s/just-ship --plugin just-ship# /setup-just-ship — Projekt einrichten Installiert Just Ship im aktuellen Projekt (falls noch nicht geschehen), erkennt den Tech-Stack automatisch, befüllt `project.json` und `CLAUDE.md`, und verbindet optional das Just Ship Board. ## Argumente | Flag | Beschreibung | |---|---| | `--board` | Board URL (z.B. `https://board.just-ship.io`) | | `--key` | Workspace API Key (z.B. `adp_...`) — vom Board generiert | | `--project` | Projekt UUID | | `--workspace-id` | Workspace UUID (alternativ zu `--key`) | --- ## SCHNELLVERBINDUNG (Board-Flags übergeben) **Prüfe als allererstes:** Sind `--b...
Installiert Just Ship im aktuellen Projekt (falls noch nicht geschehen), erkennt den Tech-Stack automatisch, befüllt project.json und CLAUDE.md, und verbindet optional das Just Ship Board.
| Flag | Beschreibung |
|---|---|
--board | Board URL (z.B. https://board.just-ship.io) |
--key | Workspace API Key (z.B. adp_...) — vom Board generiert |
--project | Projekt UUID |
--workspace-id | Workspace UUID (alternativ zu --key) |
Prüfe als allererstes: Sind --board UND (--key ODER --workspace-id) UND --project übergeben worden?
Falls JA → führe NUR die folgenden Schritte aus und beende danach. Kein Stack-Analyse, kein Menü, keine Rückfragen. NICHT nach dem API-Key fragen — er wurde bereits als --key übergeben.
Merke dir die übergebenen Werte:
KEY = der Wert hinter --key (z.B. adp_abc123...)BOARD = der Wert hinter --board (z.B. https://board.just-ship.io)PROJECT = der Wert hinter --project (z.B. ddab92d9-...)Falls --key übergeben (kein --workspace-id): Rufe die Board-API mit dem bereits bekannten KEY auf:
RESPONSE=$(curl -s -H "X-Pipeline-Key: $KEY" "$BOARD/api/projects")
WORKSPACE_ID=$(echo "$RESPONSE" | node -e "
const d = JSON.parse(require('fs').readFileSync('/dev/stdin','utf-8'));
process.stdout.write(d.workspace_id || d.data?.workspace_id || '');
")
Falls WORKSPACE_ID leer: Ausgabe ⚠ Konnte Workspace-ID nicht ermitteln. Prüfe deinen API-Key. und abbrechen.
Falls --workspace-id direkt übergeben: diesen Wert als WORKSPACE_ID verwenden.
Führe beide Befehle mit den bereits bekannten Werten aus — ohne Rückfragen, ohne nach dem Key zu fragen:
"$HOME/.just-ship/scripts/write-config.sh" add-workspace \
--workspace-id "$WORKSPACE_ID" \
--key "$KEY" \
--board "$BOARD"
bash .claude/scripts/write-config.sh set-project \
--workspace-id "$WORKSPACE_ID" \
--project-id "$PROJECT"
Führe Schritt 6 (Sidekick) aus — nutze dabei WORKSPACE_ID, --key als api_key und --board als board_url.
Ausgabe:
✓ Board verbunden
✓ Projekt verknüpft
✓ project.json aktualisiert
Erstelle dein erstes Ticket mit /ticket.
STOP. Nicht weiter unten lesen.
0a) Global installiert? Prüfe ob ~/.just-ship als git-Repo existiert:
[ -d "$HOME/.just-ship/.git" ] && echo "OK" || echo "NOT_INSTALLED"
Falls NOT_INSTALLED:
Just Ship wird installiert...curl -fsSL https://just-ship.io/install | bash
✓ Just Ship installiert0b) Im Projekt installiert? Prüfe ob .claude/agents/ existiert:
ls .claude/agents/ 2>/dev/null | head -1 || echo "NOT_INSTALLED"
Falls NOT_INSTALLED:
Framework-Dateien werden kopiert...just-ship setup --auto
✓ Framework eingerichtet0c) Bestehendes Setup erkennen
Falls .claude/agents/ bereits existiert UND project.json bereits existiert mit gesetzten Stack-Feldern (mindestens stack.framework oder stack.language sind non-empty):
Prüfe den Status:
project.json → pipeline.workspace_id gesetzt? → Board verbunden~/.just-ship/config.json → Workspace-Einträge vorhanden?Falls Stack erkannt aber Board NICHT verbunden:
✓ project.json gefunden ({stack.framework}, {stack.language})
✓ CLAUDE.md gefunden
✓ .claude/agents/ vorhanden
⚠ Board nicht verbunden
Projekt ist bereits eingerichtet. Was möchtest du tun?
1. Board verbinden → zeige Anleitung für 'just-ship connect' im Terminal
2. Nein, CLI-only nutzen
3. Setup komplett neu ausführen → Stack-Erkennung + Config überschreiben
Falls Stack erkannt UND Board verbunden: Zeige Status und frage ob Re-Setup gewünscht:
✓ Projekt vollständig eingerichtet
Stack: {framework}, Board: verbunden
Setup erneut ausführen? (Überschreibt Stack-Erkennung)
1. Ja, neu erkennen
2. Nein, alles gut
Lies die vorhandenen Dateien im Projekt-Root um den Stack zu erkennen:
Package Manager & Dependencies:
package.json → Dependencies, Scripts, Namepnpm-lock.yaml → pnpmyarn.lock → yarnbun.lockb / bun.lock → bunpackage-lock.json → npmrequirements.txt / pyproject.toml / Pipfile → Pythongo.mod → GoCargo.toml → RustFramework-Erkennung (aus Dependencies oder Dateistruktur):
next → Next.js (prüfe next.config.* für App Router vs Pages Router)nuxt → Nuxt@angular/core → Angularsvelte / @sveltejs/kit → Svelte/SvelteKitreact (ohne next) → React (Vite/CRA)vue (ohne nuxt) → Vueexpress / fastify / hono → Node Backenddjango / flask / fastapi → Python Backendsections/ + layout/theme.liquid existieren → Shopify Theme (kein package.json nötig)Datenbank:
supabase/ Verzeichnis oder @supabase/supabase-js → Supabaseprisma/ Verzeichnis → Prismadrizzle.config.* → DrizzleWeitere Config-Dateien:
tsconfig.json → TypeScript (prüfe paths für Import-Aliase wie @/)tailwind.config.* → Tailwind CSS.env.example / .env.local → Env-Variablen-Mustervitest.config.* / jest.config.* → Test-Frameworkplaywright.config.* → E2E TestsDockerfile / docker-compose.* → DockerProjekt-Struktur:
src/app/ → App Router (Next.js) oder Angularsrc/pages/ → Pages Router oder Viteapp/ → Next.js App Router (ohne src)pages/ → Next.js Pages Router (ohne src)src/components/ / components/ → Component-Verzeichnissrc/lib/ / lib/ / utils/ → Utility-Verzeichnissrc/server/ / server/ / api/ → Backend-VerzeichnisLies die aktuelle project.json. Befülle/aktualisiere folgende Felder basierend auf der Analyse — überschreibe keine Werte die bereits sinnvoll gesetzt sind:
{
"name": "<aus package.json name oder bestehender Wert>",
"description": "<aus package.json description oder bestehender Wert>",
"stack": {
"framework": "<erkanntes Framework, z.B. 'Next.js 15 (App Router)'>",
"language": "<z.B. 'TypeScript'>",
"styling": "<z.B. 'Tailwind CSS'>",
"database": "<z.B. 'Supabase (PostgreSQL)'>",
"orm": "<z.B. 'Prisma' oder 'Drizzle' oder null>",
"testing": "<z.B. 'Vitest' oder 'Jest'>",
"package_manager": "<pnpm|yarn|bun|npm>"
},
"build": {
"web": "<package_manager> run build",
"dev": "<package_manager> run dev",
"test": "<erkannter Test-Runner, z.B. 'npx vitest run'>"
},
"paths": {
"components": "<erkannter Pfad, z.B. 'src/components'>",
"pages": "<erkannter Pfad, z.B. 'src/app'>",
"lib": "<erkannter Pfad, z.B. 'src/lib'>",
"api": "<erkannter Pfad, z.B. 'src/app/api'>"
}
}
Shopify-Projekte: Falls als Shopify-Theme erkannt:
stack.framework: "shopify"stack.language: "liquid"build.web: "shopify theme check --fail-level error"hosting: "shopify"shopify.store: Aus shopify.theme.toml ([environments.default].store) lesen, falls vorhanden. Sonst aus bestehendem project.json. Falls nicht vorhanden → User fragen: "Shopify Store URL? (z.B. client-store.myshopify.com)"Shopify Token einrichten (nur bei Shopify-Projekten, nach Store-URL):
SHOPIFY_CLI_THEME_TOKEN bereits in .env steht:
grep -q 'SHOPIFY_CLI_THEME_TOKEN' .env 2>/dev/null && echo "EXISTS" || echo "MISSING"
MISSING → User fragen:
Shopify Theme Access Token? (findest du im Shopify Admin unter Apps → Theme Access)
Format: shptka_...
Leer lassen um zu überspringen.
.env schreiben (erstellen falls nicht vorhanden): SHOPIFY_CLI_THEME_TOKEN=shptka_....env in .gitignore steht. Falls nicht → .env zu .gitignore hinzufügenshopify theme list --store "$STORE" --password "$TOKEN" 2>&1 | head -3✓ Shopify Token validiert⚠ Token konnte nicht validiert werden — prüfe ob er korrekt ist. Du kannst ihn später in .env anpassen.ℹ Kein Token hinterlegt. Du kannst später SHOPIFY_CLI_THEME_TOKEN=shptka_... in .env eintragen.Regeln:
build Commands aus package.json scripts ableiten wenn vorhandenpaths nur setzen wenn das Verzeichnis tatsächlich existiertLies die aktuelle CLAUDE.md. Falls dort noch TODO-Platzhalter stehen:
Projekt-Beschreibung (unter ## Projekt):
TODO: Kurze Projektbeschreibung mit einer Beschreibung basierend auf package.json description, README, oder erkanntem StackCode-Konventionen (unter ### Code):
TODO: Code-Konventionen mit erkannten Konventionen:
@/ Alias wenn in tsconfig erkannt)Architektur (unter ## Architektur):
TODO: Projektstruktur mit der tatsächlichen Top-Level-StrukturRegeln:
Zeige nur Zeilen für Felder die tatsächlich erkannt wurden (leere Felder weglassen):
✓ Just Ship eingerichtet
Stack : {framework} + {language} + {styling} ← nur wenn erkannt
Build : {build_command} ← nur wenn erkannt
Test : {test_command} ← nur wenn erkannt
Package Mgr : {package_manager} ← nur wenn erkannt
Geänderte Dateien:
✓ project.json
✓ CLAUDE.md
Falls gar kein Stack erkannt wurde (leeres Projekt):
✓ Just Ship eingerichtet
Stack noch nicht erkannt — wird automatisch befüllt sobald
du Abhängigkeiten installierst und /setup-just-ship erneut ausführst.
Geänderte Dateien:
✓ project.json
✓ CLAUDE.md
Falls pipeline.workspace_id in project.json noch nicht gesetzt ist, frage:
Möchtest du das Just Ship Board verbinden? (j/n)
Falls nein: Abschließen mit:
Fertig! Erstelle dein erstes Ticket mit /ticket.
Falls ja: Ausgabe (NICHT in einem Code-Block, damit der Link klickbar ist):
Öffne https://board.just-ship.io — das Board führt dich durch die Einrichtung. Sag Bescheid wenn du fertig bist.
Keine weiteren Erklärungen. Das Board hat einen Onboarding-Stepper der alles erklärt.
Wenn der User zurückkommt, prüfe ob die Verbindung eingerichtet wurde:
cat "$HOME/.just-ship/config.json" 2>/dev/null | node -e "
const c=JSON.parse(require('fs').readFileSync('/dev/stdin','utf-8'));
const ws=Object.keys(c.workspaces||{});
console.log(ws.length ? 'CONNECTED:' + ws.join(',') : 'NOT_CONNECTED');
"
Falls CONNECTED: Bestätige mit ✓ Board verbunden
Falls NOT_CONNECTED: Frage ob etwas nicht geklappt hat.
Nur ausführen wenn Board verbunden (pipeline.workspace_id und pipeline.project_id in project.json gesetzt). Falls kein Board verbunden: Schritt überspringen.
Ausgabe: Sidekick wird eingerichtet...
6a) Projekt-Slug ermitteln:
Workspace-Credentials auflösen (nutze workspace_id aus project.json pipeline.workspace_id):
WS_JSON=$(bash .claude/scripts/write-config.sh read-workspace --id <workspace_id>)
board_url=$(echo "$WS_JSON" | node -e "console.log(JSON.parse(require('fs').readFileSync('/dev/stdin','utf-8')).board_url || '')")
api_key=$(echo "$WS_JSON" | node -e "console.log(JSON.parse(require('fs').readFileSync('/dev/stdin','utf-8')).api_key || '')")
Projekt-ID aus project.json auslesen:
project_id=$(node -e "console.log(require('./project.json').pipeline?.project_id || '')")
Projekt-Slug vom Board holen:
if [ -n "$board_url" ] && [ -n "$api_key" ] && [ -n "$project_id" ]; then
SLUG=$(curl -s -H "X-Pipeline-Key: ${api_key}" \
"${board_url}/api/projects" | \
node -e "
try {
const d=JSON.parse(require('fs').readFileSync('/dev/stdin','utf-8'));
const p=(d.data?.projects||[]).find(p=>p.id==='${project_id}');
console.log(p?.slug||'');
} catch(e) { console.log(''); }
")
fi
Falls leer oder API-Aufruf fehlgeschlagen, Slug aus dem Projektnamen in project.json name ableiten (kebab-case):
project_name=$(node -e "console.log(require('./project.json').name || '')")
if [ -z "$SLUG" ] && [ -n "$project_name" ]; then
SLUG=$(echo "$project_name" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]/-/g' | sed 's/-\+/-/g' | sed 's/^-\|-$//g')
fi
Falls SLUG immer noch leer → Fehlerausgabe und Snippet mit Platzhalter zeigen:
if [ -z "$SLUG" ]; then
echo "⚠ Sidekick: Projekt-Slug nicht verfügbar"
echo ""
echo "Füge das Snippet manuell in dein HTML ein (ersetze DEIN-SLUG):"
echo " <script src=\"https://board.just-ship.io/sidekick.js\" data-project=\"DEIN-SLUG\"></script>"
echo ""
echo "Aktivierung: Ctrl+Shift+S oder ?sidekick in der URL"
return 0
fi
Dann zum nächsten Schritt (6b) gehen.
6b) Layout-Datei erkennen:
Basierend auf dem erkannten Stack, suche die Haupt-Layout-Datei. Prüfe die Dateien der Reihe nach — die erste existierende wird verwendet:
| Stack | Layout-Dateien (Priorität) |
|---|---|
| Next.js (App Router) | src/app/layout.tsx, app/layout.tsx, src/app/layout.jsx, app/layout.jsx |
| Next.js (Pages Router) | src/pages/_document.tsx, pages/_document.tsx, src/pages/_document.jsx, pages/_document.jsx |
| Nuxt | app.vue |
| SvelteKit | src/app.html |
| HTML / Vite / andere | index.html, public/index.html |
Falls Stack nicht erkannt wurde: alle Kandidaten durchprobieren.
6c) Snippet einfügen:
Falls Layout-Datei gefunden — lies die Datei und prüfe ob das Sidekick-Snippet bereits vorhanden ist (sidekick.js im Inhalt). Falls ja: ✓ Sidekick bereits installiert und Schritt beenden.
Falls noch nicht vorhanden — füge das Snippet framework-gerecht ein (ersetze {slug} mit dem Wert aus $SLUG):
Next.js (App Router / Pages Router) — .tsx / .jsx:
import Script from 'next/script' noch nicht vorhanden → folgende Zeile nach anderen Imports hinzufügen:
import Script from 'next/script'
</body> Tag einfügen:
<Script src="https://board.just-ship.io/sidekick.js" data-project="{slug}" strategy="afterInteractive" />
HTML / Vite / SvelteKit — .html:
</body> einfügen:
<script src="https://board.just-ship.io/sidekick.js" data-project="{slug}"></script>
Nuxt — app.vue:
<script setup> Block hinzufügen (oder <script setup> Block erstellen falls nicht vorhanden):
useHead({ script: [{ src: 'https://board.just-ship.io/sidekick.js', 'data-project': '{slug}' }] })
Erfolgreiche Ausgabe: ✓ Sidekick installiert ({layout-datei})
Falls KEINE Layout-Datei gefunden — Snippet für manuelle Installation anzeigen:
⚠ Sidekick: Layout-Datei nicht erkannt
Füge dieses Snippet in dein HTML ein:
<script src="https://board.just-ship.io/sidekick.js" data-project="{slug}"></script>
Aktivierung: Ctrl+Shift+S oder ?sidekick in der URL
6d) Fehlerbehandlung:
Falls beim Einfügen ein Fehler auftritt (Datei nicht schreibbar, unerwartetes Format):
⚠ Sidekick konnte nicht automatisch installiert werden
Füge dieses Snippet manuell in dein HTML ein:
<script src="https://board.just-ship.io/sidekick.js" data-project="{slug}"></script>
Aktivierung: Ctrl+Shift+S oder ?sidekick in der URL
Kein Abbruch des Setup-Flows — Sidekick-Fehler sind nicht kritisch. Setup gilt als erfolgreich auch wenn Sidekick manuell eingebettet werden muss.