cortexhawk 3.3.0 → 3.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +21 -1
- package/README.md +25 -7
- package/commands/cleanup.md +1 -0
- package/cortexhawk +7 -1
- package/hooks/branch-guard.sh +1 -2
- package/hooks/codex-dispatcher.sh +3 -0
- package/install.sh +55 -934
- package/mcp/context7.json +1 -1
- package/mcp/github.json +1 -1
- package/mcp/puppeteer.json +1 -1
- package/mcp/sequential-thinking.json +1 -1
- package/package.json +1 -1
- package/scripts/doctor.sh +164 -0
- package/scripts/install-claude.sh +179 -0
- package/scripts/post-merge-cleanup.sh +170 -80
- package/scripts/restore.sh +212 -0
- package/scripts/snapshot.sh +163 -0
- package/scripts/update.sh +280 -0
- package/templates/AGENT.md +19 -0
- package/templates/CLAUDE.md.template +41 -0
- package/templates/COMMAND.md +14 -0
- package/templates/ORCHESTRATION.md +79 -0
- package/templates/PERSONA.md +17 -0
- package/templates/SKILL.md +17 -0
- package/templates/github/PULL_REQUEST_TEMPLATE.md +26 -0
- package/templates/github/gitmessage +10 -0
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# snapshot.sh — CortexHawk snapshot creation and rotation
|
|
3
|
+
# Sourced by install.sh when --snapshot is used
|
|
4
|
+
# Uses shared functions: sed_inplace, compute_checksum (via manifest)
|
|
5
|
+
# Uses globals: GLOBAL, TARGET, PORTABLE_MODE, PROFILE_FILE, MAX_SNAPSHOTS
|
|
6
|
+
|
|
7
|
+
# --- rotate_snapshots() ---
|
|
8
|
+
# Keeps only the N most recent snapshots, deletes the rest
|
|
9
|
+
rotate_snapshots() {
|
|
10
|
+
local snap_dir="$1"
|
|
11
|
+
local snaps
|
|
12
|
+
snaps=$(find "$snap_dir" -maxdepth 1 -name '*.json' -type f 2>/dev/null)
|
|
13
|
+
[ -z "$snaps" ] && return 0
|
|
14
|
+
local count
|
|
15
|
+
count=$(echo "$snaps" | wc -l | tr -d ' ')
|
|
16
|
+
if [ "$count" -gt "$MAX_SNAPSHOTS" ]; then
|
|
17
|
+
local to_delete=$((count - MAX_SNAPSHOTS))
|
|
18
|
+
ls -1t "$snap_dir"/*.json | tail -n "$to_delete" | while read -r old_snap; do
|
|
19
|
+
rm -f "$old_snap"
|
|
20
|
+
done
|
|
21
|
+
echo " Rotated: removed $to_delete old snapshot(s), keeping $MAX_SNAPSHOTS"
|
|
22
|
+
fi
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
# --- do_snapshot() ---
|
|
26
|
+
do_snapshot() {
|
|
27
|
+
if [ "$GLOBAL" = true ]; then
|
|
28
|
+
TARGET="$HOME/.claude"
|
|
29
|
+
else
|
|
30
|
+
TARGET="$(pwd)/.claude"
|
|
31
|
+
fi
|
|
32
|
+
|
|
33
|
+
local manifest="$TARGET/.cortexhawk-manifest"
|
|
34
|
+
if [ ! -f "$manifest" ]; then
|
|
35
|
+
echo "Error: no CortexHawk manifest found at $manifest"
|
|
36
|
+
echo "Run install.sh first to create an installation"
|
|
37
|
+
exit 1
|
|
38
|
+
fi
|
|
39
|
+
|
|
40
|
+
# Read manifest metadata
|
|
41
|
+
local version
|
|
42
|
+
version=$(grep '"version"' "$manifest" | sed 's/.*: *"\([^"]*\)".*/\1/')
|
|
43
|
+
local profile
|
|
44
|
+
profile=$(grep '"profile"' "$manifest" | sed 's/.*: *"\([^"]*\)".*/\1/')
|
|
45
|
+
local source_type
|
|
46
|
+
source_type=$(grep '"source"' "$manifest" | head -1 | sed 's/.*: *"\([^"]*\)".*/\1/')
|
|
47
|
+
local source_url
|
|
48
|
+
source_url=$(grep '"source_url"' "$manifest" | sed 's/.*: *"\([^"]*\)".*/\1/')
|
|
49
|
+
local source_path
|
|
50
|
+
source_path=$(grep '"source_path"' "$manifest" | sed 's/.*: *"\([^"]*\)".*/\1/')
|
|
51
|
+
|
|
52
|
+
# Read settings.json
|
|
53
|
+
local settings_json="null"
|
|
54
|
+
if [ -f "$TARGET/settings.json" ]; then
|
|
55
|
+
settings_json=$(cat "$TARGET/settings.json")
|
|
56
|
+
fi
|
|
57
|
+
|
|
58
|
+
# Read git-workflow.conf
|
|
59
|
+
local git_branching="" git_commit="" git_pr="" git_push=""
|
|
60
|
+
if [ -f "$TARGET/git-workflow.conf" ]; then
|
|
61
|
+
git_branching=$(grep '^BRANCHING=' "$TARGET/git-workflow.conf" | cut -d= -f2)
|
|
62
|
+
git_commit=$(grep '^COMMIT_CONVENTION=' "$TARGET/git-workflow.conf" | cut -d= -f2)
|
|
63
|
+
git_pr=$(grep '^PR_PREFERENCE=' "$TARGET/git-workflow.conf" | cut -d= -f2)
|
|
64
|
+
git_push=$(grep '^AUTO_PUSH=' "$TARGET/git-workflow.conf" | cut -d= -f2)
|
|
65
|
+
fi
|
|
66
|
+
|
|
67
|
+
# Read custom profile if applicable (use PROFILE_FILE from current run, never glob /tmp/)
|
|
68
|
+
local profile_def="null"
|
|
69
|
+
if [ -n "$PROFILE_FILE" ] && [ -f "$PROFILE_FILE" ]; then
|
|
70
|
+
profile_def=$(cat "$PROFILE_FILE")
|
|
71
|
+
fi
|
|
72
|
+
|
|
73
|
+
# Build files checksums from manifest
|
|
74
|
+
local files_json
|
|
75
|
+
files_json=$(sed -n '/"files"/,/^ }/p' "$manifest" | sed '1d;$d')
|
|
76
|
+
|
|
77
|
+
# Collect file contents (base64 encoded for binary safety)
|
|
78
|
+
local git_workflow_content="" claude_md_content=""
|
|
79
|
+
if [ -f "$TARGET/git-workflow.conf" ]; then
|
|
80
|
+
git_workflow_content=$(base64 < "$TARGET/git-workflow.conf" | tr -d '\n')
|
|
81
|
+
fi
|
|
82
|
+
if [ -f "$TARGET/../CLAUDE.md" ]; then
|
|
83
|
+
claude_md_content=$(base64 < "$TARGET/../CLAUDE.md" | tr -d '\n')
|
|
84
|
+
fi
|
|
85
|
+
|
|
86
|
+
# Generate snapshot
|
|
87
|
+
local now
|
|
88
|
+
now=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
|
89
|
+
local snap_name
|
|
90
|
+
snap_name=$(date -u +"%Y-%m-%d-%H%M%S")
|
|
91
|
+
local snap_dir="$TARGET/.cortexhawk-snapshots"
|
|
92
|
+
local snap_file="$snap_dir/${snap_name}.json"
|
|
93
|
+
|
|
94
|
+
mkdir -p "$snap_dir"
|
|
95
|
+
|
|
96
|
+
# Write snapshot JSON
|
|
97
|
+
printf '{\n' > "$snap_file"
|
|
98
|
+
printf ' "snapshot_version": "2",\n' >> "$snap_file"
|
|
99
|
+
printf ' "snapshot_date": "%s",\n' "$now" >> "$snap_file"
|
|
100
|
+
printf ' "cortexhawk_version": "%s",\n' "$version" >> "$snap_file"
|
|
101
|
+
printf ' "target": "claude",\n' >> "$snap_file"
|
|
102
|
+
printf ' "profile": "%s",\n' "$profile" >> "$snap_file"
|
|
103
|
+
printf ' "profile_definition": %s,\n' "$profile_def" >> "$snap_file"
|
|
104
|
+
printf ' "source": "%s",\n' "$source_type" >> "$snap_file"
|
|
105
|
+
printf ' "source_url": "%s",\n' "$source_url" >> "$snap_file"
|
|
106
|
+
printf ' "source_path": "%s",\n' "$source_path" >> "$snap_file"
|
|
107
|
+
printf ' "settings": %s,\n' "$settings_json" >> "$snap_file"
|
|
108
|
+
printf ' "git_workflow": {\n' >> "$snap_file"
|
|
109
|
+
printf ' "BRANCHING": "%s",\n' "$git_branching" >> "$snap_file"
|
|
110
|
+
printf ' "COMMIT_CONVENTION": "%s",\n' "$git_commit" >> "$snap_file"
|
|
111
|
+
printf ' "PR_PREFERENCE": "%s",\n' "$git_pr" >> "$snap_file"
|
|
112
|
+
printf ' "AUTO_PUSH": "%s"\n' "$git_push" >> "$snap_file"
|
|
113
|
+
printf ' },\n' >> "$snap_file"
|
|
114
|
+
printf ' "files": {\n' >> "$snap_file"
|
|
115
|
+
printf '%s\n' "$files_json" >> "$snap_file"
|
|
116
|
+
printf ' },\n' >> "$snap_file"
|
|
117
|
+
printf ' "file_contents": {\n' >> "$snap_file"
|
|
118
|
+
[ -n "$git_workflow_content" ] && printf ' "git-workflow.conf": "%s",\n' "$git_workflow_content" >> "$snap_file"
|
|
119
|
+
[ -n "$claude_md_content" ] && printf ' "CLAUDE.md": "%s",\n' "$claude_md_content" >> "$snap_file"
|
|
120
|
+
# Remove trailing comma from last entry
|
|
121
|
+
sed_inplace '$ s/,$//' "$snap_file"
|
|
122
|
+
printf ' }\n' >> "$snap_file"
|
|
123
|
+
printf '}\n' >> "$snap_file"
|
|
124
|
+
|
|
125
|
+
echo "CortexHawk Snapshot"
|
|
126
|
+
echo "====================="
|
|
127
|
+
echo " Version: $version"
|
|
128
|
+
echo " Profile: $profile"
|
|
129
|
+
echo " Target: $TARGET"
|
|
130
|
+
echo " Saved to: $snap_file"
|
|
131
|
+
|
|
132
|
+
# Create portable archive if requested
|
|
133
|
+
if [ "$PORTABLE_MODE" = true ]; then
|
|
134
|
+
local archive_name="${snap_name}.tar.gz"
|
|
135
|
+
local archive_path="$snap_dir/$archive_name"
|
|
136
|
+
local tmp_dir
|
|
137
|
+
tmp_dir=$(mktemp -d)
|
|
138
|
+
|
|
139
|
+
# Copy snapshot and files to temp structure
|
|
140
|
+
cp "$snap_file" "$tmp_dir/snapshot.json"
|
|
141
|
+
mkdir -p "$tmp_dir/files"
|
|
142
|
+
cp -r "$TARGET/agents" "$tmp_dir/files/" 2>/dev/null || true
|
|
143
|
+
cp -r "$TARGET/commands" "$tmp_dir/files/" 2>/dev/null || true
|
|
144
|
+
cp -r "$TARGET/skills" "$tmp_dir/files/" 2>/dev/null || true
|
|
145
|
+
cp -r "$TARGET/hooks" "$tmp_dir/files/" 2>/dev/null || true
|
|
146
|
+
cp -r "$TARGET/modes" "$tmp_dir/files/" 2>/dev/null || true
|
|
147
|
+
cp -r "$TARGET/mcp" "$tmp_dir/files/" 2>/dev/null || true
|
|
148
|
+
cp "$TARGET/settings.json" "$tmp_dir/files/" 2>/dev/null || true
|
|
149
|
+
cp "$TARGET/git-workflow.conf" "$tmp_dir/files/" 2>/dev/null || true
|
|
150
|
+
|
|
151
|
+
# Create archive
|
|
152
|
+
tar -czf "$archive_path" -C "$tmp_dir" .
|
|
153
|
+
rm -rf "$tmp_dir"
|
|
154
|
+
|
|
155
|
+
echo " Archive: $archive_path"
|
|
156
|
+
echo ""
|
|
157
|
+
echo "Restore with: install.sh --restore $archive_path"
|
|
158
|
+
else
|
|
159
|
+
rotate_snapshots "$snap_dir"
|
|
160
|
+
echo ""
|
|
161
|
+
echo "Restore with: install.sh --restore $snap_file"
|
|
162
|
+
fi
|
|
163
|
+
}
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# update.sh — CortexHawk update flow
|
|
3
|
+
# Sourced by install.sh when --update is used
|
|
4
|
+
# Uses shared functions: detect_source_type, get_version, do_snapshot, update_source_git,
|
|
5
|
+
# update_source_release, compute_checksum, sync_all_components, generate_hooks_config,
|
|
6
|
+
# write_manifest, run_audit, update_gitignore, setup_templates, cleanup_update
|
|
7
|
+
|
|
8
|
+
do_update() {
|
|
9
|
+
# 1. Validate target
|
|
10
|
+
if [ "$TARGET_CLI" != "claude" ]; then
|
|
11
|
+
echo "Error: --update is currently supported for Claude Code only"
|
|
12
|
+
echo "For Kimi CLI, re-run: install.sh --target kimi"
|
|
13
|
+
exit 1
|
|
14
|
+
fi
|
|
15
|
+
|
|
16
|
+
if [ "$GLOBAL" = true ]; then
|
|
17
|
+
TARGET="$HOME/.claude"
|
|
18
|
+
else
|
|
19
|
+
TARGET="$(pwd)/.claude"
|
|
20
|
+
fi
|
|
21
|
+
|
|
22
|
+
if [ ! -d "$TARGET" ]; then
|
|
23
|
+
echo "Error: no CortexHawk installation found at $TARGET"
|
|
24
|
+
echo "Run install.sh without --update for a fresh install"
|
|
25
|
+
exit 1
|
|
26
|
+
fi
|
|
27
|
+
|
|
28
|
+
# 2. Read manifest
|
|
29
|
+
local manifest="$TARGET/.cortexhawk-manifest"
|
|
30
|
+
local current_version="unknown"
|
|
31
|
+
local current_profile="all"
|
|
32
|
+
local source_type
|
|
33
|
+
source_type=$(detect_source_type)
|
|
34
|
+
|
|
35
|
+
if [ -f "$manifest" ]; then
|
|
36
|
+
current_version=$(grep '"version"' "$manifest" | sed 's/.*: *"\([^"]*\)".*/\1/')
|
|
37
|
+
current_profile=$(grep '"profile"' "$manifest" | sed 's/.*: *"\([^"]*\)".*/\1/')
|
|
38
|
+
local manifest_source
|
|
39
|
+
manifest_source=$(grep '"source"' "$manifest" | head -1 | sed 's/.*: *"\([^"]*\)".*/\1/')
|
|
40
|
+
# Only trust manifest's "git" source if SCRIPT_DIR is actually a git repo
|
|
41
|
+
if [ -n "$manifest_source" ]; then
|
|
42
|
+
if [ "$manifest_source" = "git" ] && git -C "$SCRIPT_DIR" rev-parse --git-dir >/dev/null 2>&1; then
|
|
43
|
+
source_type="git"
|
|
44
|
+
elif [ "$manifest_source" != "git" ]; then
|
|
45
|
+
source_type="$manifest_source"
|
|
46
|
+
fi
|
|
47
|
+
fi
|
|
48
|
+
else
|
|
49
|
+
echo " No manifest found — treating as pre-update installation"
|
|
50
|
+
fi
|
|
51
|
+
|
|
52
|
+
# 3. Profile override
|
|
53
|
+
local update_profile="$current_profile"
|
|
54
|
+
if [ -n "$PROFILE" ]; then
|
|
55
|
+
update_profile="$PROFILE"
|
|
56
|
+
fi
|
|
57
|
+
|
|
58
|
+
if [ "$DRY_RUN" = true ]; then
|
|
59
|
+
echo "CortexHawk Dry Run (update)"
|
|
60
|
+
echo "============================"
|
|
61
|
+
else
|
|
62
|
+
echo "CortexHawk Update"
|
|
63
|
+
echo "==================="
|
|
64
|
+
fi
|
|
65
|
+
echo " Current version: $current_version"
|
|
66
|
+
echo " Profile: $update_profile"
|
|
67
|
+
echo " Source: $source_type"
|
|
68
|
+
echo ""
|
|
69
|
+
|
|
70
|
+
# 3b. Auto-snapshot before update (skip in dry-run)
|
|
71
|
+
if [ "$DRY_RUN" != true ] && [ -f "$manifest" ]; then
|
|
72
|
+
echo "Creating pre-update snapshot..."
|
|
73
|
+
do_snapshot || echo " Warning: pre-update snapshot failed — continuing without rollback point"
|
|
74
|
+
PRE_UPDATE_SNAP=$(ls -t "$TARGET/.cortexhawk-snapshots"/*.json 2>/dev/null | head -1)
|
|
75
|
+
[ -n "$PRE_UPDATE_SNAP" ] && echo " Saved: $(basename "$PRE_UPDATE_SNAP")"
|
|
76
|
+
echo ""
|
|
77
|
+
fi
|
|
78
|
+
|
|
79
|
+
# 4. Pull source (skip in dry-run — compare against current source)
|
|
80
|
+
if [ "$DRY_RUN" != true ]; then
|
|
81
|
+
if [ "$source_type" = "git" ]; then
|
|
82
|
+
echo "Updating CortexHawk source via git pull..."
|
|
83
|
+
update_source_git
|
|
84
|
+
else
|
|
85
|
+
echo "Updating CortexHawk source via download..."
|
|
86
|
+
update_source_release
|
|
87
|
+
fi
|
|
88
|
+
echo " Source updated successfully."
|
|
89
|
+
fi
|
|
90
|
+
|
|
91
|
+
# 5. Compare versions
|
|
92
|
+
local new_version
|
|
93
|
+
new_version=$(get_version)
|
|
94
|
+
echo " New version: $new_version"
|
|
95
|
+
echo ""
|
|
96
|
+
|
|
97
|
+
if [ "$current_version" = "$new_version" ] && [ "$FORCE_MODE" != true ]; then
|
|
98
|
+
# Same version — check if files actually changed (checksum comparison)
|
|
99
|
+
local files_changed=0
|
|
100
|
+
if [ -f "$manifest" ]; then
|
|
101
|
+
while IFS= read -r line; do
|
|
102
|
+
local fpath fhash
|
|
103
|
+
fpath=$(echo "$line" | sed 's/.*"\([^"]*\)": "sha256:\([^"]*\)".*/\1/')
|
|
104
|
+
fhash=$(echo "$line" | sed 's/.*"sha256:\([^"]*\)".*/\1/')
|
|
105
|
+
[ -z "$fpath" ] || [ -z "$fhash" ] && continue
|
|
106
|
+
local source_file="$SCRIPT_DIR/$fpath"
|
|
107
|
+
[ -f "$source_file" ] || continue
|
|
108
|
+
local source_hash
|
|
109
|
+
source_hash=$(compute_checksum "$source_file")
|
|
110
|
+
if [ "$fhash" != "$source_hash" ]; then
|
|
111
|
+
files_changed=$((files_changed + 1))
|
|
112
|
+
fi
|
|
113
|
+
done < <(grep '"sha256:' "$manifest")
|
|
114
|
+
fi
|
|
115
|
+
|
|
116
|
+
if [ "$files_changed" -eq 0 ] && [ "$DRY_RUN" != true ]; then
|
|
117
|
+
# Still apply install improvements even if no component files changed
|
|
118
|
+
local target_dir_name=".${TARGET_CLI:-claude}"
|
|
119
|
+
update_gitignore "$(dirname "$TARGET")" "$target_dir_name"
|
|
120
|
+
[ "$TARGET_CLI" = "codex" ] && update_gitignore "$(dirname "$TARGET")" ".agents"
|
|
121
|
+
if [ ! -f "$TARGET/git-workflow.conf" ]; then
|
|
122
|
+
GIT_BRANCHING="direct-main"
|
|
123
|
+
GIT_COMMIT_CONVENTION="conventional"
|
|
124
|
+
GIT_PR_PREFERENCE="on-demand"
|
|
125
|
+
GIT_AUTO_PUSH="after-commit"
|
|
126
|
+
GIT_WORK_BRANCH=""
|
|
127
|
+
source "$SCRIPT_DIR/scripts/git-workflow-init.sh" "$(dirname "$TARGET")" "$TARGET"
|
|
128
|
+
fi
|
|
129
|
+
echo "Already up to date ($new_version). No component files changed."
|
|
130
|
+
cleanup_update
|
|
131
|
+
exit 0
|
|
132
|
+
elif [ "$files_changed" -gt 0 ]; then
|
|
133
|
+
echo " Same version ($new_version) but $files_changed file(s) changed in source."
|
|
134
|
+
fi
|
|
135
|
+
fi
|
|
136
|
+
|
|
137
|
+
if [ "$DRY_RUN" = true ]; then
|
|
138
|
+
echo " Comparing source $new_version vs installed $current_version"
|
|
139
|
+
elif [ "$current_version" = "$new_version" ]; then
|
|
140
|
+
echo " Syncing changed files ($new_version)..."
|
|
141
|
+
else
|
|
142
|
+
echo " Updating $current_version -> $new_version"
|
|
143
|
+
fi
|
|
144
|
+
echo ""
|
|
145
|
+
|
|
146
|
+
# Set up profile file for skill filtering
|
|
147
|
+
if [ -n "$update_profile" ] && [ "$update_profile" != "all" ]; then
|
|
148
|
+
PROFILE_FILE="$SCRIPT_DIR/profiles/${update_profile}.json"
|
|
149
|
+
if [ ! -f "$PROFILE_FILE" ]; then
|
|
150
|
+
echo " Warning: profile '$update_profile' not found in source — installing all skills"
|
|
151
|
+
update_profile="all"
|
|
152
|
+
PROFILE_FILE=""
|
|
153
|
+
fi
|
|
154
|
+
fi
|
|
155
|
+
|
|
156
|
+
# 6. Reset counters and sync components
|
|
157
|
+
SYNC_ADDED=0
|
|
158
|
+
SYNC_UPDATED=0
|
|
159
|
+
SYNC_UNCHANGED=0
|
|
160
|
+
SYNC_SKIPPED=0
|
|
161
|
+
SYNC_CONFLICTS=0
|
|
162
|
+
|
|
163
|
+
sync_all_components "$update_profile"
|
|
164
|
+
|
|
165
|
+
# 6b. Sync agent personas from project root
|
|
166
|
+
local project_root
|
|
167
|
+
project_root="$(dirname "$TARGET")"
|
|
168
|
+
if [ -d "$project_root/.cortexhawk-agents" ] && [ "$DRY_RUN" != true ]; then
|
|
169
|
+
cp -r "$project_root/.cortexhawk-agents/"*.md "$TARGET/agents/" 2>/dev/null || true
|
|
170
|
+
local pc
|
|
171
|
+
pc=$(find "$project_root/.cortexhawk-agents" -name "*.md" -type f 2>/dev/null | wc -l | tr -d ' ')
|
|
172
|
+
[ "$pc" -gt 0 ] && echo " Synced $pc agent persona(s) from .cortexhawk-agents/"
|
|
173
|
+
fi
|
|
174
|
+
|
|
175
|
+
# 7. Detect removed upstream files
|
|
176
|
+
if [ -f "$manifest" ]; then
|
|
177
|
+
while IFS= read -r line; do
|
|
178
|
+
local file_relpath
|
|
179
|
+
file_relpath=$(echo "$line" | sed 's/.*"\([^"]*\)": "sha256:.*/\1/')
|
|
180
|
+
[ -z "$file_relpath" ] && continue
|
|
181
|
+
if [ ! -f "$SCRIPT_DIR/$file_relpath" ] && [ -f "$TARGET/$file_relpath" ]; then
|
|
182
|
+
echo " Warning: $file_relpath was removed upstream (kept locally)"
|
|
183
|
+
fi
|
|
184
|
+
done < <(grep '"sha256:' "$manifest")
|
|
185
|
+
fi
|
|
186
|
+
|
|
187
|
+
if [ "$DRY_RUN" != true ]; then
|
|
188
|
+
# Make executable components executable
|
|
189
|
+
for entry in "${COMPONENTS[@]}"; do
|
|
190
|
+
IFS=':' read -r name exec_flag <<< "$entry"
|
|
191
|
+
[ "$exec_flag" = "yes" ] && chmod +x "$TARGET/$name/"*.sh 2>/dev/null || true
|
|
192
|
+
done
|
|
193
|
+
|
|
194
|
+
# 7b. Regenerate settings.json hooks + merge new permissions from compose.yml
|
|
195
|
+
if [ -f "$SCRIPT_DIR/hooks/compose.yml" ]; then
|
|
196
|
+
local hooks_json
|
|
197
|
+
hooks_json=$(generate_hooks_config "$SCRIPT_DIR/hooks/compose.yml" ".claude/hooks")
|
|
198
|
+
if [ -n "$hooks_json" ] && [ "$hooks_json" != "{}" ] && command -v python3 >/dev/null 2>&1; then
|
|
199
|
+
echo "$hooks_json" | python3 -c "
|
|
200
|
+
import json, sys
|
|
201
|
+
hooks = json.load(sys.stdin)
|
|
202
|
+
current = {}
|
|
203
|
+
try:
|
|
204
|
+
with open(sys.argv[1]) as f:
|
|
205
|
+
current = json.load(f)
|
|
206
|
+
except:
|
|
207
|
+
pass
|
|
208
|
+
current['hooks'] = hooks
|
|
209
|
+
# Merge new permissions from source
|
|
210
|
+
try:
|
|
211
|
+
with open(sys.argv[2]) as f:
|
|
212
|
+
src_perms = json.load(f).get('permissions', {})
|
|
213
|
+
cur_perms = current.get('permissions', {})
|
|
214
|
+
for key in ('allow', 'deny'):
|
|
215
|
+
src_list = src_perms.get(key, [])
|
|
216
|
+
cur_list = cur_perms.get(key, [])
|
|
217
|
+
added = [p for p in src_list if p not in cur_list]
|
|
218
|
+
if added:
|
|
219
|
+
cur_list.extend(added)
|
|
220
|
+
cur_perms[key] = cur_list
|
|
221
|
+
current['permissions'] = cur_perms
|
|
222
|
+
except:
|
|
223
|
+
pass
|
|
224
|
+
with open(sys.argv[1], 'w') as f:
|
|
225
|
+
json.dump(current, f, indent=2)
|
|
226
|
+
f.write('\n')
|
|
227
|
+
" "$TARGET/settings.json" "$SCRIPT_DIR/settings.json"
|
|
228
|
+
echo " Regenerated settings.json hooks from compose.yml"
|
|
229
|
+
fi
|
|
230
|
+
fi
|
|
231
|
+
|
|
232
|
+
# 8. Write new manifest
|
|
233
|
+
write_manifest "$TARGET" "$update_profile" "$TARGET_CLI" true
|
|
234
|
+
|
|
235
|
+
# 9. Run audit
|
|
236
|
+
run_audit "$(dirname "$TARGET")"
|
|
237
|
+
|
|
238
|
+
# 10. Apply install improvements (gitignore, git-workflow defaults)
|
|
239
|
+
local target_dir_name=".${TARGET_CLI:-claude}"
|
|
240
|
+
update_gitignore "$(dirname "$TARGET")" "$target_dir_name"
|
|
241
|
+
[ "$TARGET_CLI" = "codex" ] && update_gitignore "$(dirname "$TARGET")" ".agents"
|
|
242
|
+
setup_templates "$(dirname "$TARGET")"
|
|
243
|
+
|
|
244
|
+
if [ ! -f "$TARGET/git-workflow.conf" ]; then
|
|
245
|
+
GIT_BRANCHING="direct-main"
|
|
246
|
+
GIT_COMMIT_CONVENTION="conventional"
|
|
247
|
+
GIT_PR_PREFERENCE="on-demand"
|
|
248
|
+
GIT_AUTO_PUSH="after-commit"
|
|
249
|
+
GIT_WORK_BRANCH=""
|
|
250
|
+
source "$SCRIPT_DIR/scripts/git-workflow-init.sh" "$(dirname "$TARGET")" "$TARGET"
|
|
251
|
+
fi
|
|
252
|
+
fi
|
|
253
|
+
|
|
254
|
+
# 10. Print summary
|
|
255
|
+
echo ""
|
|
256
|
+
if [ "$DRY_RUN" = true ]; then
|
|
257
|
+
echo "Dry run summary:"
|
|
258
|
+
echo " Would add: $SYNC_ADDED"
|
|
259
|
+
echo " Would update: $SYNC_UPDATED"
|
|
260
|
+
echo " Unchanged: $SYNC_UNCHANGED"
|
|
261
|
+
echo " Would skip: $SYNC_SKIPPED"
|
|
262
|
+
echo " Conflicts: $SYNC_CONFLICTS"
|
|
263
|
+
echo ""
|
|
264
|
+
echo "No files were modified (dry run)."
|
|
265
|
+
else
|
|
266
|
+
echo "Update complete: $current_version -> $new_version"
|
|
267
|
+
echo " Added: $SYNC_ADDED"
|
|
268
|
+
echo " Updated: $SYNC_UPDATED"
|
|
269
|
+
echo " Unchanged: $SYNC_UNCHANGED"
|
|
270
|
+
echo " Skipped: $SYNC_SKIPPED"
|
|
271
|
+
echo " Conflicts: $SYNC_CONFLICTS"
|
|
272
|
+
if [ -n "${PRE_UPDATE_SNAP:-}" ]; then
|
|
273
|
+
echo " Rollback: install.sh --restore $PRE_UPDATE_SNAP"
|
|
274
|
+
fi
|
|
275
|
+
echo ""
|
|
276
|
+
echo " To activate: exit your CLI (ctrl+c) and relaunch in this directory."
|
|
277
|
+
fi
|
|
278
|
+
|
|
279
|
+
cleanup_update
|
|
280
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: [agent-name]
|
|
3
|
+
description: [One sentence — what this agent does and when to activate it]
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# [Agent Name] Agent
|
|
7
|
+
|
|
8
|
+
You are a [role description].
|
|
9
|
+
|
|
10
|
+
## Process
|
|
11
|
+
1. [Step 1]
|
|
12
|
+
2. [Step 2]
|
|
13
|
+
3. [Step 3]
|
|
14
|
+
|
|
15
|
+
## Output Format
|
|
16
|
+
[What the agent should produce]
|
|
17
|
+
|
|
18
|
+
## Rules
|
|
19
|
+
[Constraints and guidelines — 5-7 items max]
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# [Project Name]
|
|
2
|
+
|
|
3
|
+
[One-line description of what the project does]
|
|
4
|
+
|
|
5
|
+
## Tech Stack
|
|
6
|
+
- **Language**: [e.g., TypeScript, Python]
|
|
7
|
+
- **Framework**: [e.g., Next.js, FastAPI]
|
|
8
|
+
- **Database**: [e.g., PostgreSQL, MongoDB]
|
|
9
|
+
- **Testing**: [e.g., vitest, pytest]
|
|
10
|
+
|
|
11
|
+
## Structure
|
|
12
|
+
```
|
|
13
|
+
src/
|
|
14
|
+
├── [main directories]
|
|
15
|
+
tests/
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Conventions
|
|
19
|
+
- **Naming**: [files: kebab-case, functions: camelCase, classes: PascalCase]
|
|
20
|
+
- **Commits**: `type(scope): description` (feat, fix, docs, refactor, test, chore)
|
|
21
|
+
- **Branches**: `feature/description`, `fix/description`, `hotfix/description`
|
|
22
|
+
|
|
23
|
+
## Commands
|
|
24
|
+
- `[dev command]` — Start dev server
|
|
25
|
+
- `[test command]` — Run tests
|
|
26
|
+
- `[build command]` — Build for production
|
|
27
|
+
- `[lint command]` — Run linter
|
|
28
|
+
|
|
29
|
+
## Architecture Decisions
|
|
30
|
+
- [Key decision 1 and why]
|
|
31
|
+
- [Key decision 2 and why]
|
|
32
|
+
|
|
33
|
+
## Security
|
|
34
|
+
- No hardcoded secrets — use environment variables
|
|
35
|
+
- Input validation on all endpoints
|
|
36
|
+
- Auth required on all protected routes
|
|
37
|
+
|
|
38
|
+
## Testing
|
|
39
|
+
- Unit tests for business logic
|
|
40
|
+
- Integration tests for API endpoints
|
|
41
|
+
- Coverage target: [80%]
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# /[command-name]
|
|
2
|
+
|
|
3
|
+
## Purpose
|
|
4
|
+
[One sentence — what this command does]
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
Activate the **[agent-name]** agent. Target: `$ARGUMENTS`
|
|
9
|
+
|
|
10
|
+
1. [Step 1]
|
|
11
|
+
2. [Step 2]
|
|
12
|
+
3. [Step 3]
|
|
13
|
+
|
|
14
|
+
[Any additional constraints or output format requirements]
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# Agent Orchestration Patterns
|
|
2
|
+
|
|
3
|
+
## Sequential Pipeline
|
|
4
|
+
|
|
5
|
+
Run agents one after another, each receiving the previous output.
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
/plan → planner → plan.md
|
|
9
|
+
/build → implementer → code changes (follows plan.md)
|
|
10
|
+
/test → tester → test results
|
|
11
|
+
/review → reviewer → review report
|
|
12
|
+
/ship → git-manager + reviewer → commit + PR
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
**Use when**: Feature development from scratch.
|
|
16
|
+
|
|
17
|
+
## Parallel Execution
|
|
18
|
+
|
|
19
|
+
Run independent agents simultaneously to save time.
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
┌─ tester (unit tests)
|
|
23
|
+
plan → implementer ─┤
|
|
24
|
+
└─ tester (integration tests)
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
**Use when**: Test generation can happen in parallel for different scopes.
|
|
28
|
+
|
|
29
|
+
## Gate Pattern
|
|
30
|
+
|
|
31
|
+
Agent B only runs if Agent A passes.
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
reviewer → [pass?] → git-manager → [commit]
|
|
35
|
+
→ [fail?] → STOP, report issues
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
**Use when**: `/ship` — don't commit if review finds critical issues.
|
|
39
|
+
|
|
40
|
+
## Loop Pattern
|
|
41
|
+
|
|
42
|
+
Repeat until quality gate passes.
|
|
43
|
+
|
|
44
|
+
```
|
|
45
|
+
implementer → tester → [tests pass?] → done
|
|
46
|
+
→ [tests fail?] → implementer (fix) → tester → ...
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
**Use when**: `/tdd` — red-green-refactor cycle.
|
|
50
|
+
|
|
51
|
+
## Escalation Pattern
|
|
52
|
+
|
|
53
|
+
Start simple, bring in specialists when needed.
|
|
54
|
+
|
|
55
|
+
```
|
|
56
|
+
debugger → [found root cause?] → fix
|
|
57
|
+
→ [needs architecture change?] → architect → planner → implementer
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
**Use when**: `/debug` — simple bugs stay with debugger, complex ones escalate.
|
|
61
|
+
|
|
62
|
+
## Multi-Agent Review
|
|
63
|
+
|
|
64
|
+
Multiple agents review the same code from different angles.
|
|
65
|
+
|
|
66
|
+
```
|
|
67
|
+
┌─ reviewer (correctness)
|
|
68
|
+
code ──┼─ security-auditor (security)
|
|
69
|
+
└─ code-simplifier (complexity)
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
**Use when**: Pre-release quality gate or critical code paths.
|
|
73
|
+
|
|
74
|
+
## Rules
|
|
75
|
+
- Each agent receives clear input and produces structured output
|
|
76
|
+
- Gate pattern prevents broken code from progressing
|
|
77
|
+
- Parallel agents must not modify the same files
|
|
78
|
+
- Always define a failure path — what happens when an agent flags issues
|
|
79
|
+
- Keep pipelines ≤5 steps — longer pipelines are harder to debug
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: [persona-name]
|
|
3
|
+
extends: [base-agent-name]
|
|
4
|
+
description: [One sentence — how this persona differs from the base agent]
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# [Persona Name]
|
|
8
|
+
|
|
9
|
+
Custom agent persona extending **[base-agent-name]**.
|
|
10
|
+
|
|
11
|
+
## Overrides
|
|
12
|
+
|
|
13
|
+
[Rules, style, or behavior that override or extend the base agent]
|
|
14
|
+
|
|
15
|
+
## Rules
|
|
16
|
+
|
|
17
|
+
[Additional rules specific to this persona — these are ADDED to the base agent's rules]
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: [skill-name]
|
|
3
|
+
description: [One sentence — when should Claude use this skill?]
|
|
4
|
+
detect: [base | <file> | <file>:<pattern> | dir:<path> — omit if not auto-detectable]
|
|
5
|
+
requires: [category/skill-name — space-separated list of required skills, omit if none]
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# [Skill Name]
|
|
9
|
+
|
|
10
|
+
## [Core Instructions]
|
|
11
|
+
[What Claude should do when this skill is active]
|
|
12
|
+
|
|
13
|
+
## Examples
|
|
14
|
+
[Concrete code/usage examples]
|
|
15
|
+
|
|
16
|
+
## Rules
|
|
17
|
+
[Do's and don'ts — keep it to 5-7 items max]
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
## Summary
|
|
2
|
+
<!-- What does this PR do and why? -->
|
|
3
|
+
|
|
4
|
+
## Type
|
|
5
|
+
<!-- Check one -->
|
|
6
|
+
- [ ] Feature
|
|
7
|
+
- [ ] Bug fix
|
|
8
|
+
- [ ] Refactor
|
|
9
|
+
- [ ] Docs
|
|
10
|
+
- [ ] Chore
|
|
11
|
+
|
|
12
|
+
## Changes
|
|
13
|
+
-
|
|
14
|
+
|
|
15
|
+
## Test Plan
|
|
16
|
+
- [ ]
|
|
17
|
+
|
|
18
|
+
## Checklist
|
|
19
|
+
- [ ] Tests pass
|
|
20
|
+
- [ ] No secrets or .env committed
|
|
21
|
+
- [ ] Docs updated (if applicable)
|
|
22
|
+
- [ ] No breaking changes (or documented below)
|
|
23
|
+
|
|
24
|
+
## Related
|
|
25
|
+
<!-- Link issues, backlog items, or conversations -->
|
|
26
|
+
<!-- Examples: Closes #123 | Backlog #119 | N/A -->
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
|
|
2
|
+
# type(scope): subject
|
|
3
|
+
#
|
|
4
|
+
# Types: feat, fix, docs, style, refactor, test, chore, perf, security
|
|
5
|
+
# Scope: optional module/component name
|
|
6
|
+
# Subject: imperative mood, lowercase, no period, max 72 chars
|
|
7
|
+
#
|
|
8
|
+
# Body: explain WHY, not WHAT (the diff shows the what)
|
|
9
|
+
#
|
|
10
|
+
# Footer: BREAKING CHANGE: description | Closes #123 | Backlog #N
|