-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathinit.sh
More file actions
executable file
·115 lines (99 loc) · 5.32 KB
/
Copy pathinit.sh
File metadata and controls
executable file
·115 lines (99 loc) · 5.32 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
#!/usr/bin/env bash
# knowledge-layer — scaffold the mechanical structure into a target repo.
# Idempotent and merge-aware: safe to re-run; never clobbles an existing
# knowledge/ or overwrites an existing .claude/settings.json (merges the hook).
#
# Usage: init.sh [repo-path] (defaults to the git repo root, else $PWD)
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ASSETS="$(dirname "$SCRIPT_DIR")/assets"
# --- locate the target repo ---------------------------------------------------
target="${1:-}"
if [ -z "$target" ]; then
target="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
fi
cd "$target" || { echo "✗ cannot cd into $target" >&2; exit 1; }
echo "→ scaffolding knowledge layer into: $target"
# --- directories --------------------------------------------------------------
mkdir -p knowledge/wiki knowledge/journal knowledge/decisions .claude/hooks
echo "✓ knowledge/{wiki,journal,decisions} + .claude/hooks"
# --- breadcrumb hook ----------------------------------------------------------
cp "$ASSETS/journal-breadcrumb.sh" .claude/hooks/journal-breadcrumb.sh
chmod +x .claude/hooks/journal-breadcrumb.sh
echo "✓ .claude/hooks/journal-breadcrumb.sh"
# --- codemap refresh hook -----------------------------------------------------
cp "$ASSETS/codemap-refresh.sh" .claude/hooks/codemap-refresh.sh
chmod +x .claude/hooks/codemap-refresh.sh
echo "✓ .claude/hooks/codemap-refresh.sh"
# --- settings.json (merge both PostToolUse hooks, don't clobber) --------------
# Breadcrumb hook — emits the nudge agent note
CRUMB_BLOCK='{"matcher":"Bash","hooks":[{"type":"command","if":"Bash(git commit*)","command":"\"$CLAUDE_PROJECT_DIR/.claude/hooks/journal-breadcrumb.sh\"","timeout":15,"statusMessage":"Journaling commit…"}]}'
# Codemap refresh hook — regenerates the structural map in the background (no agent note)
CODEMAP_BLOCK='{"matcher":"Bash","hooks":[{"type":"command","if":"Bash(git commit*)","command":"\"$CLAUDE_PROJECT_DIR/.claude/hooks/codemap-refresh.sh\"","timeout":35,"statusMessage":"Refreshing code map…"}]}'
settings=".claude/settings.json"
merge_hook() {
local settings="$1" block="$2"
if [ -f "$settings" ]; then
local tmp
tmp="$(mktemp)"
jq --argjson h "$block" '
.hooks //= {} |
.hooks.PostToolUse //= [] |
if any(.hooks.PostToolUse[]?; (.hooks // [])[]?.command == ($h.hooks[0].command))
then .
else .hooks.PostToolUse += [$h] end
' "$settings" > "$tmp" && mv "$tmp" "$settings"
else
jq -n --argjson h "$block" \
'{"$schema":"https://json.schemastore.org/claude-code-settings.json","hooks":{"PostToolUse":[$h]}}' \
> "$settings"
fi
}
merge_hook "$settings" "$CRUMB_BLOCK"
merge_hook "$settings" "$CODEMAP_BLOCK"
echo "✓ merged hooks into $settings"
# --- gitignore the hook's local state ----------------------------------------
ignore=".gitignore"
if ! { [ -f "$ignore" ] && grep -q 'knowledge/journal/.last-breadcrumb' "$ignore"; }; then
printf '\n# knowledge-layer breadcrumb hook state\nknowledge/journal/.last-breadcrumb\n' >> "$ignore"
echo "✓ gitignored knowledge/journal/.last-breadcrumb"
fi
# --- union merge-driver for generated codemap files --------------------------
# Generated files must never throw merge conflicts — git's built-in union driver
# lets each branch's lines union, and the next commit's hook regenerates a clean file.
git config merge.union.name "union merge driver" 2>/dev/null || true
git config merge.union.driver "true" 2>/dev/null || true
attrs=".gitattributes"
if ! { [ -f "$attrs" ] && grep -q 'knowledge/wiki/_codemap.md' "$attrs"; }; then
{
printf '\n# knowledge-layer generated files — union merge to avoid conflicts\n'
printf 'knowledge/wiki/_codemap.md merge=union\n'
printf 'knowledge/_codemap.json merge=union\n'
} >> "$attrs"
echo "✓ .gitattributes union merge-driver for _codemap.md + _codemap.json"
fi
# --- gitignore the generated codemap files -----------------------------------
# They are always regeneratable so we commit them if the project wants, but
# the project may opt out; ensure at minimum the .last-codemap state is ignored.
# (Projects may commit the codemap itself — it diffs cleanly; up to the project.)
if ! { [ -f "$ignore" ] && grep -q 'knowledge/journal/.last-codemap' "$ignore"; }; then
printf '# knowledge-layer codemap hook state\nknowledge/journal/.last-codemap\n' >> "$ignore"
echo "✓ gitignored knowledge/journal/.last-codemap"
fi
# --- template knowledge/CLAUDE.md (only if absent) ---------------------------
if [ -f knowledge/CLAUDE.md ]; then
echo "• knowledge/CLAUDE.md already exists — left untouched"
else
cp "$ASSETS/knowledge-CLAUDE.md.tmpl" knowledge/CLAUDE.md
echo "✓ knowledge/CLAUDE.md (TEMPLATE — fill in the {{PLACEHOLDERS}})"
fi
cat <<'EOF'
Mechanical scaffold complete. Next (the agent does these):
1. Fill the {{PLACEHOLDERS}} in knowledge/CLAUDE.md with real project context.
2. Seed decisions/ + a backfill journal entry from the project's current state.
3. Point the repo-root CLAUDE.md / README at knowledge/CLAUDE.md.
4. Run the code-map generator to build the initial structural index:
uv run --with tree-sitter --with tree-sitter-language-pack \
python3 ~/.claude/skills/knowledge-layer/scripts/codemap.py [repo-root]
5. Activate the hooks: open /hooks once, or restart the session.
EOF