(See README.md.upstream for the original README)
A pure bash drop-in replacement for npx gsd-opencode installer adapted using claude-haiku-4.5.
Location: gsd-opencode/bin/install.sh
Requirements: Only standard Linux utilities (bash, grep, sed, find, cp, mkdir)
✓ Command-line argument parsing (-g, -l, -c, -h)
✓ Interactive user prompts (location selection, overwrite confirmation)
✓ Global installation (~/.config/opencode or custom $OPENCODE_CONFIG_DIR)
✓ Local installation (./.opencode in current directory)
✓ Path replacements in markdown files (sed-based, pure bash)
✓ Version file creation from package.json
✓ Sanity check for unresolved repo-local tokens
✓ Simple, minimal output (no colors, no banner)
✓ Comprehensive error handling
bash ./install.sh [OPTIONS]-g, --global Install globally (~/.config/opencode)
-l, --local Install locally (./.opencode)
-c, --config-dir <path> Specify custom config directory
-h, --help Show help message
# Interactive prompt (will ask where to install)
bash ./install.sh
# Install globally (default location)
bash ./install.sh --global
# Install locally to this project only
bash ./install.sh --local
# Install to custom global location
bash ./install.sh --global --config-dir ~/my-opencode
# Use environment variable for config directory
OPENCODE_CONFIG_DIR=~/.opencode-dev bash ./install.sh --globalThe script copies three main directories:
1. command/gsd/ → {dest}/command/gsd/
2. agents/ → {dest}/agents/
3. get-shit-done/ → {dest}/get-shit-done/
Global installation (default):
~/.config/opencode/
├── command/
│ └── gsd/
├── agents/
└── get-shit-done/
Local installation:
./.opencode/
├── command/
│ └── gsd/
├── agents/
└── get-shit-done/
The script automatically replaces paths in all .md files during installation. This ensures prompts and references work correctly from the installation location.
Replacement patterns (applied in order):
| Source Pattern | Replacement | Purpose |
|---|---|---|
@gsd-opencode/ |
@{install_path}/ |
Install-relative references in prompts |
gsd-opencode/ |
{install_path}/ |
Install-relative paths in markdown |
~/.claude/ |
{install_path}/ |
Legacy Claude paths (backward compatibility) |
./.claude/ |
./.opencode/ |
Legacy local Claude paths |
Example path prefix values:
- Global:
~/.config/opencode/or{full_path}/(if custom directory) - Local:
./.opencode/
| Function | Purpose |
|---|---|
parse_arguments() |
Handle CLI flags with validation |
expand_tilde() |
Convert ~/ to home directory path |
get_version() |
Extract version from package.json |
copy_with_replacements() |
Recursive copy with sed replacements for .md files |
scan_unresolved_tokens() |
Sanity check for unresolved repo-local tokens |
prompt_for_overwrite() |
Ask user before overwriting existing installation |
install() |
Main installation logic |
prompt_location() |
Interactive menu for global/local selection |
main() |
Entry point and control flow |
- Parse command-line arguments
- Validate argument combinations
- Show help if
-hrequested, or proceed to install - If no flags provided: prompt user for location (global/local)
- Validate source directories exist
- Determine destination path (with tilde expansion)
- Check if destination exists → prompt for overwrite if yes
- Create destination directories recursively
- Copy
command/gsd/with path replacements - Copy
agents/with path replacements - Copy
get-shit-done/with path replacements - Create
VERSIONfile with version string - Run sanity check for unresolved tokens
- Print success message
The script validates and handles errors at multiple points:
- Argument validation: Rejects conflicting flags (
-g+-l,-c+-l) - Source validation: Checks all required source directories exist
- Destination validation: Prompts user if destination already exists
- Path expansion: Handles tilde (
~) and environment variables - Sanity check: Warns if unresolved repo-local tokens remain after installation
- Clear error messages: Errors sent to stderr with descriptive text
- Graceful failures: Permission errors handled by OS with clear messages
- No Node.js, npm, jq, or external tools required
- Uses only standard Linux utilities: bash, grep, sed, find, cp, mkdir
- Version extraction uses
grep+sed(nojqneeded)
- No colors or fancy formatting
- No ASCII art or banner
- Clear, straightforward output messages
- Minimal dependencies on external tools
- Interactive prompts for unclear situations
- Help text available via
-hflag - Confirmation prompts before destructive operations
- Informative status messages during installation
- Drop-in replacement for
npx gsd-opencode - Same command-line interface
- Same behavior and options
- Same file structure after installation
Usage: bash ./install.sh [OPTIONS]
Options:
-g, --global Install globally (~/.config/opencode or $OPENCODE_CONFIG_DIR)
-l, --local Install locally (./.opencode in current directory)
-c, --config-dir <path> Specify custom config directory (overrides $OPENCODE_CONFIG_DIR)
-h, --help Show this help message
Examples:
bash ./install.sh --global
bash ./install.sh --local
bash ./install.sh --global --config-dir ~/my-opencode
Installing to /home/user/.config/opencode
✓ Installed command/gsd
✓ Installed agents
✓ Installed get-shit-done
✓ Created VERSION file
Done! Run /gsd-help to get started.
Warning: Unresolved repo-local tokens found (sanity check)
- command/gsd/some-file.md:42
This is a line with @gsd-opencode/ that wasn't replaced
Where would you like to install?
1) Global (~/.config/opencode) - available in all projects
2) Local (./.opencode) - this project only
Choice [1]:
| Feature | Node.js | Bash |
|---|---|---|
| Entry point | npx gsd-opencode |
bash ./install.sh |
| CLI options | -g, -l, -c, -h |
-g, -l, -c, -h |
| Interactive prompt | Yes | Yes |
| Overwrite confirmation | Yes | Yes |
| Path replacements | sed-based | sed-based |
| Version file | Yes | Yes |
| Sanity check | Yes | Yes |
| Banner output | Yes (with colors) | No (plain text) |
| Dependencies | Node.js 16.7.0+ | bash, grep, sed, find, cp, mkdir |
The script uses sed with process substitution to apply replacements:
sed -e "s|@gsd-opencode/|@${path_prefix}|g" \
-e "s|gsd-opencode/|${path_prefix}|g" \
-e "s|~/.claude/|${path_prefix}|g" \
-e "s|./.claude/|./.opencode/|g" \
"$src_file" > "$dest_file"Order matters: Replacements are applied sequentially to avoid double-rewrites.
Uses find with process substitution for robust file handling:
find "$src_dir" -type f | while IFS= read -r src_file; do
# Process each file
doneThis handles filenames with spaces and special characters correctly.
Extracts version from package.json using pure bash:
version=$(grep '"version"' "$SOURCE_DIR/package.json" | sed 's/.*"version": "\([^"]*\)".*/\1/' | head -1)Fallback to "unknown" if version cannot be determined.
The script couldn't find the source directories. Make sure:
- You're running the script from
gsd-opencode/bin/directory - All required subdirectories exist:
command/gsd/,agents/,get-shit-done/
You used both -g and -l flags. Choose one:
bash ./install.sh --global # OR
bash ./install.sh --localThe -c flag only works with -g for global installation:
bash ./install.sh --global --config-dir ~/my-pathThe script will prompt you. Answer y to overwrite or n to cancel:
Destination already exists: /home/user/.config/opencode
Overwrite? (y/n):
Some paths weren't replaced correctly. This is a sanity check warning. The installation succeeded, but you should investigate the listed files.
- Total lines: 335
- Functions: 9
- Lines of comments: ~40
- No external dependencies: Pure bash + standard Linux tools