Files
obsidian-claude-pkm/scripts/setup.sh
eiszazel c2ee446009 Fix setup.sh failures and improve user experience (#6)
Five improvements to the setup wizard:

1. Relative path handling:
   Convert relative paths to absolute paths after user input to prevent
   failures when `claude init` changes the working directory.

2. Git push error handling:
   Detect actual branch name and show real errors instead of suppressing
   them and falling back to non-existent `master`.

3. Interactive push recovery:
   When push fails (e.g., remote has existing content), offer interactive
   options: force push with confirmation, or skip with manual command.

4. GitHub Actions setup after failed push:
   Only copy workflow files if push succeeds to avoid confusion.

5. OAuth token setup guidance:
   Replace cryptic "Remember to add CLAUDE_CODE_OAUTH_TOKEN" with:
   - Step-by-step instructions
   - Direct link to token documentation
   - Link to repository secrets page
   - Option to open setup page in browser

Co-authored-by: eiszazel <eiszazel@users.noreply.github.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-14 13:49:50 -08:00

372 lines
12 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/bin/bash
# Obsidian + Claude Code PKM Setup Script
# This script automates the initial setup of your PKM system
set -e # Exit on error
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Banner
echo -e "${BLUE}"
echo "╔═══════════════════════════════════════════════════╗"
echo "║ Obsidian + Claude Code PKM Setup Wizard ║"
echo "║ Version 1.0 ║"
echo "╚═══════════════════════════════════════════════════╝"
echo -e "${NC}"
# Function to print colored messages
print_success() {
echo -e "${GREEN}${NC} $1"
}
print_error() {
echo -e "${RED}${NC} $1"
}
print_warning() {
echo -e "${YELLOW}${NC} $1"
}
print_info() {
echo -e "${BLUE}${NC} $1"
}
# Function to check if command exists
command_exists() {
command -v "$1" >/dev/null 2>&1
}
# Step 1: Check Prerequisites
echo -e "\n${BLUE}Step 1: Checking Prerequisites${NC}"
echo "================================"
# Check for Git
if command_exists git; then
print_success "Git is installed ($(git --version))"
else
print_error "Git is not installed"
echo "Please install Git from: https://git-scm.com/"
exit 1
fi
# Check for Claude Code
if command_exists claude; then
print_success "Claude Code is installed ($(claude --version 2>/dev/null || echo 'version check failed'))"
else
print_warning "Claude Code CLI not found"
echo "Install from: https://code.claude.com/docs"
read -p "Continue without Claude Code? (y/n): " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
exit 1
fi
fi
# Step 2: Get Vault Location
echo -e "\n${BLUE}Step 2: Choose Vault Location${NC}"
echo "================================"
# Default location
DEFAULT_VAULT="$HOME/Documents/ObsidianPKM"
read -p "Where should we create your vault? [$DEFAULT_VAULT]: " VAULT_PATH
VAULT_PATH=${VAULT_PATH:-$DEFAULT_VAULT}
# Expand tilde if present
VAULT_PATH="${VAULT_PATH/#\~/$HOME}"
# Convert to absolute path if relative
if [[ "$VAULT_PATH" != /* ]]; then
VAULT_PATH="$(pwd)/$VAULT_PATH"
fi
# Check if directory exists
if [ -d "$VAULT_PATH" ]; then
print_warning "Directory already exists: $VAULT_PATH"
read -p "Use existing directory? Files may be overwritten (y/n): " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
echo "Setup cancelled"
exit 1
fi
else
mkdir -p "$VAULT_PATH"
print_success "Created vault directory: $VAULT_PATH"
fi
# Step 3: Copy Vault Template
echo -e "\n${BLUE}Step 3: Setting Up Vault Structure${NC}"
echo "====================================="
# Get script directory
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
TEMPLATE_DIR="$SCRIPT_DIR/../vault-template"
# Copy template files
print_info "Copying template files..."
cp -r "$TEMPLATE_DIR"/* "$VAULT_PATH/" 2>/dev/null || true
cp -r "$TEMPLATE_DIR"/.* "$VAULT_PATH/" 2>/dev/null || true
print_success "Vault structure created"
# Step 4: Set Up Claude Commands
echo -e "\n${BLUE}Step 4: Setting Up Claude Commands${NC}"
echo "======================================"
if command_exists claude; then
# Commands are already in vault-template/.claude/commands/
# Just need to initialize Claude
cd "$VAULT_PATH"
# Check if commands were copied
if [ -d "$VAULT_PATH/.claude/commands" ]; then
print_success "Claude commands already in place"
else
print_warning "Claude commands directory not found"
fi
# Initialize Claude in vault
if claude init >/dev/null 2>&1; then
print_success "Claude Code initialized in vault"
else
print_warning "Claude Code initialization did not complete. You can run 'claude init' inside '$VAULT_PATH' later."
fi
else
print_warning "Skipping Claude Code setup (not installed)"
fi
# Step 5: Initialize Git
echo -e "\n${BLUE}Step 5: Git Repository Setup${NC}"
echo "==============================="
cd "$VAULT_PATH"
if [ -d .git ]; then
print_warning "Git repository already exists"
else
git init
print_success "Git repository initialized"
fi
# Configure Git
read -p "Enter your name for Git commits: " GIT_NAME
read -p "Enter your email for Git commits: " GIT_EMAIL
if [ -n "$GIT_NAME" ]; then
git config user.name "$GIT_NAME"
print_success "Git user name set"
fi
if [ -n "$GIT_EMAIL" ]; then
git config user.email "$GIT_EMAIL"
print_success "Git user email set"
fi
# Initial commit
git add .
git commit -m "Initial PKM setup" 2>/dev/null || print_warning "Nothing to commit"
# Step 6: GitHub Setup (Optional)
echo -e "\n${BLUE}Step 6: GitHub Integration (Optional)${NC}"
echo "========================================="
read -p "Do you want to set up GitHub integration? (y/n): " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
read -p "Enter your GitHub repository URL (or press Enter to skip): " GITHUB_URL
if [ -n "$GITHUB_URL" ]; then
git remote add origin "$GITHUB_URL" 2>/dev/null || git remote set-url origin "$GITHUB_URL"
print_success "GitHub remote configured"
read -p "Push to GitHub now? (y/n): " -n 1 -r
echo
PUSH_SUCCESS=false
if [[ $REPLY =~ ^[Yy]$ ]]; then
# Get current branch name
CURRENT_BRANCH=$(git branch --show-current)
if git push -u origin "$CURRENT_BRANCH" 2>&1; then
print_success "Pushed to GitHub"
PUSH_SUCCESS=true
else
print_warning "Push failed - the remote repository may already have content"
echo ""
echo "How would you like to proceed?"
echo " 1) Force push (overwrites remote content - use for fresh vault repos)"
echo " 2) Skip (push manually later)"
read -p "Choose [1/2]: " -n 1 -r PUSH_CHOICE
echo ""
case $PUSH_CHOICE in
1)
print_warning "Force pushing will overwrite any existing content in the remote repository"
read -p "Are you sure? (y/n): " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
if git push -u origin "$CURRENT_BRANCH" --force; then
print_success "Force pushed to GitHub"
PUSH_SUCCESS=true
else
print_error "Force push failed"
fi
else
print_info "Skipping push"
fi
;;
*)
print_info "Skipping push. You can push manually later with:"
echo " cd \"$VAULT_PATH\" && git push -u origin $CURRENT_BRANCH"
;;
esac
fi
fi
# Set up GitHub Action only if push succeeded
if [ "$PUSH_SUCCESS" = true ]; then
mkdir -p "$VAULT_PATH/.github/workflows"
cp "$SCRIPT_DIR/../github-actions/claude.yml" "$VAULT_PATH/.github/workflows/"
print_success "GitHub Action workflow copied"
echo ""
print_warning "GitHub Actions requires a Claude Code OAuth token to work"
echo ""
echo "To set up the token:"
echo " 1. Get your token from: https://code.claude.com/docs/en/github-actions"
echo " 2. Go to your repo: $GITHUB_URL/settings/secrets/actions"
echo " 3. Click 'New repository secret'"
echo " 4. Name: CLAUDE_CODE_OAUTH_TOKEN"
echo " 5. Value: [paste your token]"
echo ""
# Offer to open the setup page
read -p "Open token setup page in browser? (y/n): " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
TOKEN_URL="https://code.claude.com/docs/en/github-actions"
if command_exists xdg-open; then
xdg-open "$TOKEN_URL" 2>/dev/null || print_info "Visit: $TOKEN_URL"
elif command_exists open; then
open "$TOKEN_URL" 2>/dev/null || print_info "Visit: $TOKEN_URL"
else
print_info "Visit: $TOKEN_URL"
fi
fi
fi
fi
fi
# Step 7: Personalization
echo -e "\n${BLUE}Step 7: Initial Personalization${NC}"
echo "===================================="
print_info "Let's personalize your system..."
# Get personal mission
echo -e "\nWhat's your personal mission or life purpose?"
echo "(Example: 'Build meaningful technology while maintaining balance')"
read -p "Your mission: " MISSION
if [ -n "$MISSION" ]; then
# Update CLAUDE.md
if [[ "$OSTYPE" == "darwin"* ]]; then
# macOS
sed -i '' "s/\[CUSTOMIZE THIS: Add your personal mission statement or life purpose here\]/$MISSION/" "$VAULT_PATH/CLAUDE.md"
else
# Linux
sed -i "s/\[CUSTOMIZE THIS: Add your personal mission statement or life purpose here\]/$MISSION/" "$VAULT_PATH/CLAUDE.md"
fi
print_success "Personal mission added"
fi
# Get current focus
echo -e "\nWhat's your main focus right now?"
read -p "Current focus: " FOCUS
# Create first daily note
TODAY=$(date +%Y-%m-%d)
DAILY_NOTE="$VAULT_PATH/Daily Notes/$TODAY.md"
if [ ! -f "$DAILY_NOTE" ]; then
print_info "Creating your first daily note..."
cp "$VAULT_PATH/Templates/Daily Template.md" "$DAILY_NOTE"
# Add focus to daily note
if [ -n "$FOCUS" ]; then
if [[ "$OSTYPE" == "darwin"* ]]; then
sed -i '' "s/\*\*Today's Priority:\*\*/\*\*Today's Priority:\*\* $FOCUS/" "$DAILY_NOTE"
else
sed -i "s/\*\*Today's Priority:\*\*/\*\*Today's Priority:\*\* $FOCUS/" "$DAILY_NOTE"
fi
fi
print_success "First daily note created: $TODAY.md"
fi
# Step 8: Final Setup
echo -e "\n${BLUE}Step 8: Finalizing Setup${NC}"
echo "==========================="
# Create a setup completion marker
echo "Setup completed on $(date)" > "$VAULT_PATH/.setup_complete"
# Commit personalization
cd "$VAULT_PATH"
git add .
git commit -m "Personalized PKM setup" 2>/dev/null || true
# Summary
echo -e "\n${GREEN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
echo -e "${GREEN}✨ Setup Complete!${NC}"
echo -e "${GREEN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}\n"
echo "Your PKM system is ready at: $VAULT_PATH"
echo ""
echo "Next steps:"
echo "1. Open Obsidian and select your vault folder"
echo "2. Explore the Goals folder to set your objectives"
echo "3. Start using daily notes with: claude code /daily"
echo "4. Run weekly reviews with: claude code /weekly"
echo ""
echo "Quick Commands:"
echo " cd \"$VAULT_PATH\" # Navigate to your vault"
echo " claude code /onboard # Load context into Claude"
echo " claude code /daily # Create today's note"
echo " claude code /push # Save changes to Git"
echo ""
print_info "Read the documentation in docs/ for detailed guidance"
print_success "Happy note-taking! 🚀"
# Offer to open Obsidian
if [[ "$OSTYPE" == "darwin"* ]]; then
if [ -d "/Applications/Obsidian.app" ]; then
read -p "Open Obsidian now? (y/n): " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
# Try to open directly to this vault via obsidian URL
if command_exists python3; then
ENCODED_PATH=$(python3 -c "import urllib.parse,sys;print(urllib.parse.quote(sys.argv[1]))" "$VAULT_PATH")
open "obsidian://open?path=$ENCODED_PATH" || open -a Obsidian
else
open -a Obsidian
fi
print_success "Obsidian launched"
fi
fi
elif command_exists obsidian; then
read -p "Open Obsidian now? (y/n): " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
# On Linux, try obsidian URL first if xdg-open available
if command_exists xdg-open && command_exists python3; then
ENCODED_PATH=$(python3 -c "import urllib.parse,sys;print(urllib.parse.quote(sys.argv[1]))" "$VAULT_PATH")
xdg-open "obsidian://open?path=$ENCODED_PATH" >/dev/null 2>&1 || obsidian &
else
obsidian &
fi
print_success "Obsidian launched"
fi
fi