mirror of
https://github.com/garrytan/gstack.git
synced 2026-09-11 07:29:00 +02:00
feat(setup): wire --host cursor through the full install path
'./setup --host cursor' was accepted by the flag parser and then did nothing: no INSTALL_CURSOR branch existed, so the script built binaries, printed no 'ready' line, and installed zero skills — Cursor users had no way to install gstack at all. Full install slice, re-derived from PR #2547 by @szsunyuan onto the current installers: generate .cursor/ skill docs (host config already existed), create a minimal ~/.cursor/skills/gstack runtime root (root SKILL.md + bin/lib/browse assets + review checklist pair + ETHOS.md + supabase config — bin and lib travel together because bin scripts import ../lib), link the generated gstack-* skills, and plant the repo-local .cursor/skills/gstack sidecar WITHOUT ever wiping the generated SKILL.md files it shares a directory with (link-before-sidecar ordering keeps the generation fallback alive). Auto mode detects Cursor via the cursor binary or the ~/.cursor footprint. gstack-uninstall removes ~/.cursor/skills/gstack* and per-project .cursor/skills/gstack* — and never rmdir's .cursor itself, where Cursor stores user rules. Re-derivation deltas from the PR: the link guards carry the #2444 IS_WINDOWS bypass (re-runs refresh real-dir copies), lib/ and supabase/config.sh ride along like every other runtime root, and the hosts/cursor.ts sidecar field is omitted (HostConfig no longer carries one — sidecar behavior lives in setup). Fixes #1358 Co-authored-by: Yuan Sun <forrest.sun527@gmail.com> Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Yuan Sun
Claude Fable 5
parent
c84246845e
commit
2be9bd0660
@@ -58,6 +58,8 @@ FACTORY_SKILLS="$HOME/.factory/skills"
|
||||
FACTORY_GSTACK="$FACTORY_SKILLS/gstack"
|
||||
OPENCODE_SKILLS="$HOME/.config/opencode/skills"
|
||||
OPENCODE_GSTACK="$OPENCODE_SKILLS/gstack"
|
||||
CURSOR_SKILLS="$HOME/.cursor/skills"
|
||||
CURSOR_GSTACK="$CURSOR_SKILLS/gstack"
|
||||
|
||||
IS_WINDOWS=0
|
||||
case "$(uname -s)" in
|
||||
@@ -239,14 +241,19 @@ INSTALL_CODEX=0
|
||||
INSTALL_KIRO=0
|
||||
INSTALL_FACTORY=0
|
||||
INSTALL_OPENCODE=0
|
||||
INSTALL_CURSOR=0
|
||||
if [ "$HOST" = "auto" ]; then
|
||||
command -v claude >/dev/null 2>&1 && INSTALL_CLAUDE=1
|
||||
command -v codex >/dev/null 2>&1 && INSTALL_CODEX=1
|
||||
command -v kiro-cli >/dev/null 2>&1 && INSTALL_KIRO=1
|
||||
command -v droid >/dev/null 2>&1 && INSTALL_FACTORY=1
|
||||
command -v opencode >/dev/null 2>&1 && INSTALL_OPENCODE=1
|
||||
# Cursor's `cursor` CLI shim isn't always on PATH; ~/.cursor is the
|
||||
# reliable footprint of an installed Cursor IDE.
|
||||
command -v cursor >/dev/null 2>&1 && INSTALL_CURSOR=1
|
||||
[ -d "$HOME/.cursor" ] && INSTALL_CURSOR=1
|
||||
# If none found, default to claude
|
||||
if [ "$INSTALL_CLAUDE" -eq 0 ] && [ "$INSTALL_CODEX" -eq 0 ] && [ "$INSTALL_KIRO" -eq 0 ] && [ "$INSTALL_FACTORY" -eq 0 ] && [ "$INSTALL_OPENCODE" -eq 0 ]; then
|
||||
if [ "$INSTALL_CLAUDE" -eq 0 ] && [ "$INSTALL_CODEX" -eq 0 ] && [ "$INSTALL_KIRO" -eq 0 ] && [ "$INSTALL_FACTORY" -eq 0 ] && [ "$INSTALL_OPENCODE" -eq 0 ] && [ "$INSTALL_CURSOR" -eq 0 ]; then
|
||||
INSTALL_CLAUDE=1
|
||||
fi
|
||||
elif [ "$HOST" = "claude" ]; then
|
||||
@@ -259,6 +266,8 @@ elif [ "$HOST" = "factory" ]; then
|
||||
INSTALL_FACTORY=1
|
||||
elif [ "$HOST" = "opencode" ]; then
|
||||
INSTALL_OPENCODE=1
|
||||
elif [ "$HOST" = "cursor" ]; then
|
||||
INSTALL_CURSOR=1
|
||||
fi
|
||||
|
||||
migrate_direct_codex_install() {
|
||||
@@ -593,6 +602,16 @@ if [ "$INSTALL_OPENCODE" -eq 1 ] && [ "$NEEDS_BUILD" -eq 0 ]; then
|
||||
)
|
||||
fi
|
||||
|
||||
# 1e. Generate .cursor/ Cursor skill docs
|
||||
if [ "$INSTALL_CURSOR" -eq 1 ] && [ "$NEEDS_BUILD" -eq 0 ]; then
|
||||
log "Generating .cursor/ skill docs..."
|
||||
(
|
||||
cd "$SOURCE_GSTACK_DIR"
|
||||
bun_cmd install --frozen-lockfile 2>/dev/null || bun_cmd install
|
||||
bun_cmd run gen:skill-docs --host cursor
|
||||
)
|
||||
fi
|
||||
|
||||
# 2. Ensure Playwright's Chromium is available
|
||||
# Detect Ubuntu 26.04: Playwright does not yet ship a native chromium build for
|
||||
# ubuntu26.04-x64. Override the platform to ubuntu24.04-x64 so the installer
|
||||
@@ -1234,6 +1253,143 @@ link_opencode_skill_dirs() {
|
||||
fi
|
||||
}
|
||||
|
||||
# ─── Helper: create a minimal ~/.cursor/skills/gstack runtime root ──────────
|
||||
# Cursor scans ~/.cursor/skills. Same shape as the Codex/Factory/OpenCode
|
||||
# runtime roots: root SKILL.md from the generated tree + runtime assets only.
|
||||
# Contributed by @szsunyuan (PR #2547), re-derived onto the current installers.
|
||||
create_cursor_runtime_root() {
|
||||
local gstack_dir="$1"
|
||||
local cursor_gstack="$2"
|
||||
local cursor_dir="$gstack_dir/.cursor/skills"
|
||||
local generated_root="$cursor_dir/gstack"
|
||||
|
||||
if [ -L "$cursor_gstack" ]; then
|
||||
rm -f "$cursor_gstack"
|
||||
elif [ -d "$cursor_gstack" ] && [ "$cursor_gstack" != "$gstack_dir" ] && [ "$cursor_gstack" != "$generated_root" ]; then
|
||||
rm -rf "$cursor_gstack"
|
||||
fi
|
||||
|
||||
mkdir -p "$cursor_gstack" "$cursor_gstack/browse" "$cursor_gstack/gstack-upgrade" "$cursor_gstack/review"
|
||||
|
||||
if [ -f "$cursor_dir/gstack/SKILL.md" ]; then
|
||||
_link_or_copy "$cursor_dir/gstack/SKILL.md" "$cursor_gstack/SKILL.md"
|
||||
fi
|
||||
# bin scripts import shared modules via ../lib — bin and lib travel together.
|
||||
if [ -d "$gstack_dir/bin" ]; then
|
||||
_link_or_copy "$gstack_dir/bin" "$cursor_gstack/bin"
|
||||
fi
|
||||
if [ -d "$gstack_dir/lib" ]; then
|
||||
_link_or_copy "$gstack_dir/lib" "$cursor_gstack/lib"
|
||||
fi
|
||||
if [ -d "$gstack_dir/browse/dist" ]; then
|
||||
_link_or_copy "$gstack_dir/browse/dist" "$cursor_gstack/browse/dist"
|
||||
fi
|
||||
if [ -d "$gstack_dir/browse/bin" ]; then
|
||||
_link_or_copy "$gstack_dir/browse/bin" "$cursor_gstack/browse/bin"
|
||||
fi
|
||||
if [ -f "$cursor_dir/gstack-upgrade/SKILL.md" ]; then
|
||||
_link_or_copy "$cursor_dir/gstack-upgrade/SKILL.md" "$cursor_gstack/gstack-upgrade/SKILL.md"
|
||||
fi
|
||||
# Review runtime assets — the cursor host config ships the lean pair.
|
||||
for f in checklist.md TODOS-format.md; do
|
||||
if [ -f "$gstack_dir/review/$f" ]; then
|
||||
_link_or_copy "$gstack_dir/review/$f" "$cursor_gstack/review/$f"
|
||||
fi
|
||||
done
|
||||
if [ -f "$gstack_dir/ETHOS.md" ]; then
|
||||
_link_or_copy "$gstack_dir/ETHOS.md" "$cursor_gstack/ETHOS.md"
|
||||
fi
|
||||
# supabase/config.sh — required by gstack-telemetry-sync to resolve GSTACK_SUPABASE_URL
|
||||
if [ -f "$gstack_dir/supabase/config.sh" ]; then
|
||||
mkdir -p "$cursor_gstack/supabase"
|
||||
_link_or_copy "$gstack_dir/supabase/config.sh" "$cursor_gstack/supabase/config.sh"
|
||||
fi
|
||||
}
|
||||
|
||||
# Plant runtime assets into the repo-local generated skill dir so in-repo
|
||||
# GSTACK_ROOT (preamble prefers $_ROOT/.cursor/skills/gstack) has bin/.
|
||||
# NEVER wipe this directory — it holds the generated SKILL.md files.
|
||||
create_cursor_sidecar() {
|
||||
local repo_root="$1"
|
||||
local cursor_gstack="$repo_root/.cursor/skills/gstack"
|
||||
local cursor_dir="$repo_root/.cursor/skills"
|
||||
|
||||
mkdir -p "$cursor_gstack" "$cursor_gstack/browse" "$cursor_gstack/gstack-upgrade" "$cursor_gstack/review"
|
||||
|
||||
if [ -d "$repo_root/bin" ]; then
|
||||
if [ "$IS_WINDOWS" -eq 1 ] || [ -L "$cursor_gstack/bin" ] || [ ! -e "$cursor_gstack/bin" ]; then
|
||||
_link_or_copy "$repo_root/bin" "$cursor_gstack/bin"
|
||||
fi
|
||||
fi
|
||||
if [ -d "$repo_root/lib" ]; then
|
||||
if [ "$IS_WINDOWS" -eq 1 ] || [ -L "$cursor_gstack/lib" ] || [ ! -e "$cursor_gstack/lib" ]; then
|
||||
_link_or_copy "$repo_root/lib" "$cursor_gstack/lib"
|
||||
fi
|
||||
fi
|
||||
if [ -d "$repo_root/browse/dist" ]; then
|
||||
if [ "$IS_WINDOWS" -eq 1 ] || [ -L "$cursor_gstack/browse/dist" ] || [ ! -e "$cursor_gstack/browse/dist" ]; then
|
||||
_link_or_copy "$repo_root/browse/dist" "$cursor_gstack/browse/dist"
|
||||
fi
|
||||
fi
|
||||
if [ -d "$repo_root/browse/bin" ]; then
|
||||
if [ "$IS_WINDOWS" -eq 1 ] || [ -L "$cursor_gstack/browse/bin" ] || [ ! -e "$cursor_gstack/browse/bin" ]; then
|
||||
_link_or_copy "$repo_root/browse/bin" "$cursor_gstack/browse/bin"
|
||||
fi
|
||||
fi
|
||||
if [ -f "$cursor_dir/gstack-upgrade/SKILL.md" ]; then
|
||||
if [ "$IS_WINDOWS" -eq 1 ] || [ -L "$cursor_gstack/gstack-upgrade/SKILL.md" ] || [ ! -e "$cursor_gstack/gstack-upgrade/SKILL.md" ]; then
|
||||
_link_or_copy "$cursor_dir/gstack-upgrade/SKILL.md" "$cursor_gstack/gstack-upgrade/SKILL.md"
|
||||
fi
|
||||
fi
|
||||
for f in checklist.md TODOS-format.md; do
|
||||
if [ -f "$repo_root/review/$f" ]; then
|
||||
if [ "$IS_WINDOWS" -eq 1 ] || [ -L "$cursor_gstack/review/$f" ] || [ ! -e "$cursor_gstack/review/$f" ]; then
|
||||
_link_or_copy "$repo_root/review/$f" "$cursor_gstack/review/$f"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
if [ -f "$repo_root/ETHOS.md" ]; then
|
||||
if [ "$IS_WINDOWS" -eq 1 ] || [ -L "$cursor_gstack/ETHOS.md" ] || [ ! -e "$cursor_gstack/ETHOS.md" ]; then
|
||||
_link_or_copy "$repo_root/ETHOS.md" "$cursor_gstack/ETHOS.md"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
link_cursor_skill_dirs() {
|
||||
local gstack_dir="$1"
|
||||
local skills_dir="$2"
|
||||
local cursor_dir="$gstack_dir/.cursor/skills"
|
||||
local linked=()
|
||||
|
||||
if [ ! -d "$cursor_dir" ]; then
|
||||
echo " Generating .cursor/ skill docs..."
|
||||
( cd "$gstack_dir" && bun_cmd run gen:skill-docs --host cursor )
|
||||
fi
|
||||
|
||||
if [ ! -d "$cursor_dir" ]; then
|
||||
echo " warning: .cursor/skills/ generation failed — run 'bun run gen:skill-docs --host cursor' manually" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
for skill_dir in "$cursor_dir"/gstack*/; do
|
||||
if [ -f "$skill_dir/SKILL.md" ]; then
|
||||
skill_name="$(basename "$skill_dir")"
|
||||
[ "$skill_name" = "gstack" ] && continue
|
||||
target="$skills_dir/$skill_name"
|
||||
# #2444: IS_WINDOWS bypass — real-dir copies never match -L, so re-runs
|
||||
# skipped the refresh. Only replace a symlink or a missing path
|
||||
# otherwise; never an unowned real Cursor skill dir (#2142).
|
||||
if [ "$IS_WINDOWS" -eq 1 ] || [ -L "$target" ] || [ ! -e "$target" ]; then
|
||||
_link_or_copy "$skill_dir" "$target"
|
||||
linked+=("$skill_name")
|
||||
fi
|
||||
fi
|
||||
done
|
||||
if [ ${#linked[@]} -gt 0 ]; then
|
||||
echo " linked skills: ${linked[*]}"
|
||||
fi
|
||||
}
|
||||
|
||||
# 4. Install for Claude (default)
|
||||
SKILLS_BASENAME="$(basename "$INSTALL_SKILLS_DIR")"
|
||||
SKILLS_PARENT_BASENAME="$(basename "$(dirname "$INSTALL_SKILLS_DIR")")"
|
||||
@@ -1468,6 +1624,19 @@ if [ "$INSTALL_OPENCODE" -eq 1 ]; then
|
||||
echo " opencode skills: $OPENCODE_SKILLS"
|
||||
fi
|
||||
|
||||
# 6d. Install for Cursor
|
||||
if [ "$INSTALL_CURSOR" -eq 1 ]; then
|
||||
mkdir -p "$CURSOR_SKILLS"
|
||||
create_cursor_runtime_root "$SOURCE_GSTACK_DIR" "$CURSOR_GSTACK"
|
||||
# Link before sidecar. Sidecar mkdir -p creates .cursor/skills/gstack, which
|
||||
# would make link_cursor_skill_dirs' "[ ! -d generated ]" gen fallback a no-op.
|
||||
link_cursor_skill_dirs "$SOURCE_GSTACK_DIR" "$CURSOR_SKILLS"
|
||||
create_cursor_sidecar "$SOURCE_GSTACK_DIR"
|
||||
echo "gstack ready (cursor)."
|
||||
echo " browse: $BROWSE_BIN"
|
||||
echo " cursor skills: $CURSOR_SKILLS"
|
||||
fi
|
||||
|
||||
# 7. Create .agents/ sidecar symlinks for the real Codex skill target.
|
||||
# The root Codex skill ends up pointing at $SOURCE_GSTACK_DIR/.agents/skills/gstack,
|
||||
# so the runtime assets must live there for both global and repo-local installs.
|
||||
|
||||
Reference in New Issue
Block a user