-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsetup
More file actions
executable file
·152 lines (137 loc) · 5.39 KB
/
setup
File metadata and controls
executable file
·152 lines (137 loc) · 5.39 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
#!/usr/bin/env bash
# pmstack installer — copies CLAUDE.md, skills, templates, and slash commands into a target project.
# Usage:
# ./setup # install into current dir (must be a project root)
# ./setup /path/to/project # install into a specific project dir
# ./setup --global # install commands + skills to ~/.claude (available in every session)
# ./setup --dry-run # show what would be copied
set -euo pipefail
SRC="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
TARGET="$(pwd)"
DRY_RUN=0
GLOBAL=0
for arg in "$@"; do
case "$arg" in
--global) GLOBAL=1 ;;
--dry-run) DRY_RUN=1 ;;
-h|--help)
# Print the leading comment block (lines 2..first non-# line) so help never drifts from the comment.
awk 'NR==1{next} /^#/{sub(/^# ?/,""); print; next} {exit}' "$0"
exit 0
;;
*)
if [[ -d "$arg" ]]; then
TARGET="$(cd "$arg" && pwd)"
else
echo "Unknown arg or missing dir: $arg" >&2
exit 1
fi
;;
esac
done
if [[ "$GLOBAL" == "1" ]]; then
TARGET="$HOME/.claude"
# Global install: commands live at ~/.claude/commands and Anthropic Skills at ~/.claude/skills (no nested .claude).
COMMANDS_DIR="$TARGET/commands"
AGENT_SKILLS_DIR="$TARGET/skills"
echo "→ Installing pmstack globally to $TARGET"
else
# Project install: commands live at <project>/.claude/commands.
# Note: pmstack uses skills/ in project mode for the per-command skill source files.
# Anthropic Agent Skills install to .claude/skills/ in project mode (Claude Code reads both).
COMMANDS_DIR="$TARGET/.claude/commands"
AGENT_SKILLS_DIR="$TARGET/.claude/skills"
echo "→ Installing pmstack into $TARGET"
fi
run() {
echo " $*"
if [[ "$DRY_RUN" == "0" ]]; then "$@"; fi
}
run mkdir -p "$COMMANDS_DIR" "$AGENT_SKILLS_DIR" "$TARGET/skills" "$TARGET/templates" "$TARGET/outputs" "$TARGET/bin" "$TARGET/docs" "$TARGET/evals/golden" "$TARGET/examples/golden"
# Slash commands — required for /eval, /prd, etc. to work.
for cmd in eval prd competitive metrics brief compare run-eval sprint eval-self; do
run cp "$SRC/.claude/commands/$cmd.md" "$COMMANDS_DIR/$cmd.md"
done
# Skills + templates — referenced by the commands.
for f in "$SRC"/skills/*.md; do
run cp "$f" "$TARGET/skills/$(basename "$f")"
done
for f in "$SRC"/templates/*; do
run cp "$f" "$TARGET/templates/$(basename "$f")"
done
# Anthropic Agent Skills — cross-platform (web/mobile/desktop/API/CLI).
for d in "$SRC"/claude-skills/*/; do
[[ -d "$d" ]] || continue
name="$(basename "$d")"
run mkdir -p "$AGENT_SKILLS_DIR/$name"
for f in "$d"*; do
[[ -f "$f" ]] && run cp "$f" "$AGENT_SKILLS_DIR/$name/$(basename "$f")"
done
done
# bin/ — runner script for /run-eval. Required for actual eval execution.
for f in "$SRC"/bin/*; do
[[ -f "$f" ]] && run cp "$f" "$TARGET/bin/$(basename "$f")"
[[ -f "$f" ]] && run chmod +x "$TARGET/bin/$(basename "$f")"
done
# evals/ — runner.py + regression-check.py + golden baseline + suite definition.
run mkdir -p "$TARGET/evals"
for f in "$SRC"/evals/runner.py "$SRC"/evals/regression-check.py "$SRC"/evals/pmstack-self.yaml "$SRC"/evals/README.md; do
[[ -f "$f" ]] && run cp "$f" "$TARGET/evals/$(basename "$f")"
done
[[ -f "$SRC/evals/runner.py" ]] && run chmod +x "$TARGET/evals/runner.py"
[[ -f "$SRC/evals/regression-check.py" ]] && run chmod +x "$TARGET/evals/regression-check.py"
for f in "$SRC"/evals/golden/*; do
[[ -f "$f" ]] && run cp "$f" "$TARGET/evals/golden/$(basename "$f")"
done
# examples/golden/ — anchor outputs index.
for f in "$SRC"/examples/golden/*; do
[[ -f "$f" ]] && run cp "$f" "$TARGET/examples/golden/$(basename "$f")"
done
# docs/ — learn-by-doing guides for PMs new to evals etc.
for f in "$SRC"/docs/*; do
[[ -f "$f" ]] && run cp "$f" "$TARGET/docs/$(basename "$f")"
done
# CLAUDE.md — only at project scope, never overwrite.
if [[ "$GLOBAL" == "0" ]]; then
if [[ -f "$TARGET/CLAUDE.md" ]]; then
echo " ⚠ CLAUDE.md already exists at $TARGET — leaving it alone."
echo " Merge in pmstack's CLAUDE.md by hand if you want the PM persona."
else
run cp "$SRC/CLAUDE.md" "$TARGET/CLAUDE.md"
fi
fi
# .gitignore — keep user-generated PM artifacts out of git history by default.
# Project scope only. Append idempotently — never clobber existing rules.
if [[ "$GLOBAL" == "0" ]]; then
GI="$TARGET/.gitignore"
MARKER="# >>> pmstack >>>"
if [[ -f "$GI" ]] && grep -q "$MARKER" "$GI" 2>/dev/null; then
echo " ⓘ .gitignore already has pmstack block — leaving alone."
else
if [[ "$DRY_RUN" == "0" ]]; then
{
[[ -f "$GI" ]] && echo ""
echo "$MARKER"
echo "# Generated by pmstack ./setup. Edit if you want different rules."
echo "outputs/"
echo "evals/results/"
echo "# <<< pmstack <<<"
} >> "$GI"
fi
echo " appended pmstack block to $GI"
fi
fi
echo ""
echo "✓ pmstack installed."
echo ""
echo "Try it:"
echo " claude"
echo " > /prd \"Customers say onboarding takes 3 days\""
echo " > /sprint \"Customers want pricing transparency\""
echo " > /compare Cursor Windsurf"
echo " > /eval Claude Ultraplan"
echo " > /run-eval outputs/eval-<feature>-<date>.yaml"
echo " > /eval-self # score pmstack itself"
echo ""
echo "Anthropic Agent Skills installed (work in Claude.ai web/mobile + API too):"
echo " Upload claude-skills/<name>/ folders to a Claude.ai Project."