devrites 2.5.1 → 2.6.0
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 +12 -0
- package/README.md +31 -19
- package/SECURITY.md +1 -1
- package/bin/devrites.mjs +2 -1
- package/docs/cli-mcp.md +9 -4
- package/docs/skills.md +3 -3
- package/docs/usage.md +2 -2
- package/install.sh +558 -9
- package/mcp/devrites-mcp.mjs +2 -0
- package/pack/.claude/hooks/devrites-a1-guard.sh +34 -16
- package/pack/.claude/hooks/devrites-reviewer-readonly.sh +11 -2
- package/pack/.claude/hooks/devrites-wright-scope.sh +38 -9
- package/pack/.claude/skills/devrites-browser-proof/SKILL.md +18 -12
- package/pack/.claude/skills/devrites-lib/scripts/doctor.sh +68 -4
- package/pack/.claude/skills/rite-doctor/SKILL.md +2 -1
- package/pack/.claude/skills/rite-polish/reference/harden-checklist.md +1 -1
- package/pack/.claude/skills/rite-prove/SKILL.md +1 -1
- package/pack/.claude/skills/rite-prove/reference/browser-proof.md +1 -1
- package/pack/.claude/skills/rite-prove/reference/proof-ladder.md +8 -6
- package/package.json +3 -2
- package/scripts/check-no-global-writes.sh +4 -4
- package/scripts/install-lib.sh +11 -1
- package/scripts/merge-codex-hooks.mjs +78 -0
- package/scripts/pin.sh +42 -5
- package/uninstall.sh +60 -0
package/scripts/pin.sh
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
#
|
|
4
4
|
# Adopts the same "thin wrapper SKILL.md that delegates" pattern as install.sh
|
|
5
5
|
# uses for --short-aliases=all, but exposes it as a runtime verb so users can
|
|
6
|
-
# add / remove arbitrary aliases against any rite-*
|
|
6
|
+
# add / remove arbitrary aliases against any rite-* skill without re-running
|
|
7
7
|
# the installer.
|
|
8
8
|
#
|
|
9
9
|
# Usage:
|
|
@@ -18,11 +18,12 @@
|
|
|
18
18
|
# ./scripts/pin.sh remove b
|
|
19
19
|
#
|
|
20
20
|
# Targets:
|
|
21
|
-
# - Default: $PWD (the installed project, which holds .claude/skills/
|
|
21
|
+
# - Default: $PWD (the installed project, which holds .claude/skills/
|
|
22
|
+
# and may also hold .agents/skills/ for Codex).
|
|
22
23
|
# - --target <dir> to operate on a project elsewhere.
|
|
23
24
|
#
|
|
24
25
|
# Safety:
|
|
25
|
-
# - Refuses to write inside
|
|
26
|
+
# - Refuses to write inside global Claude/Codex homes (DevRites is project-local only).
|
|
26
27
|
# - Refuses to overwrite a non-alias skill at .claude/skills/<alias>/.
|
|
27
28
|
# - Refuses if <target> is not a known rite-* skill in the target's pack.
|
|
28
29
|
# - Manifest-managed: pinned wrappers are recorded in .claude/devrites.manifest
|
|
@@ -66,8 +67,10 @@ done
|
|
|
66
67
|
|
|
67
68
|
TARGET="$(dr_abspath_dir "$TARGET")" || dr_die "target dir not found: $TARGET"
|
|
68
69
|
dr_is_global_claude "$TARGET" && dr_die "refusing to operate on ~/.claude — DevRites is project-local only"
|
|
70
|
+
dr_is_global_codex "$TARGET" && dr_die "refusing to operate on ~/.codex — DevRites is project-local only"
|
|
69
71
|
|
|
70
72
|
SKILLS_DIR="$TARGET/.claude/skills"
|
|
73
|
+
CODEX_SKILLS_DIR="$TARGET/.agents/skills"
|
|
71
74
|
MF="$TARGET/$DR_MANIFEST_NAME"
|
|
72
75
|
|
|
73
76
|
[ -d "$SKILLS_DIR" ] || dr_die "no .claude/skills at $TARGET — run install.sh first?"
|
|
@@ -97,6 +100,11 @@ is_pinned_alias() {
|
|
|
97
100
|
grep -q 'description: Alias of DevRites /' "$SKILLS_DIR/$1/SKILL.md"
|
|
98
101
|
}
|
|
99
102
|
|
|
103
|
+
is_pinned_alias_file() {
|
|
104
|
+
[ -f "$1" ] || return 1
|
|
105
|
+
grep -q 'description: Alias of DevRites /' "$1"
|
|
106
|
+
}
|
|
107
|
+
|
|
100
108
|
# ---- subcommands ---------------------------------------------------------
|
|
101
109
|
do_add() {
|
|
102
110
|
valid_alias_name "$ALIAS" || dr_die "invalid alias name '$ALIAS' (lowercase / digits / hyphens; not 'rite' or 'rite-*')"
|
|
@@ -106,6 +114,9 @@ do_add() {
|
|
|
106
114
|
ALIAS_DIR="$SKILLS_DIR/$ALIAS"
|
|
107
115
|
ALIAS_FILE="$ALIAS_DIR/SKILL.md"
|
|
108
116
|
ALIAS_REL=".claude/skills/$ALIAS/SKILL.md"
|
|
117
|
+
CODEX_ALIAS_DIR="$CODEX_SKILLS_DIR/$ALIAS"
|
|
118
|
+
CODEX_ALIAS_FILE="$CODEX_ALIAS_DIR/SKILL.md"
|
|
119
|
+
CODEX_ALIAS_REL=".agents/skills/$ALIAS/SKILL.md"
|
|
109
120
|
|
|
110
121
|
if [ -e "$ALIAS_FILE" ]; then
|
|
111
122
|
if is_pinned_alias "$ALIAS"; then
|
|
@@ -114,15 +125,33 @@ do_add() {
|
|
|
114
125
|
dr_die "$ALIAS_FILE exists and is NOT a pinned alias — refusing to overwrite"
|
|
115
126
|
fi
|
|
116
127
|
fi
|
|
128
|
+
if [ -d "$CODEX_SKILLS_DIR" ] && [ -e "$CODEX_ALIAS_FILE" ]; then
|
|
129
|
+
if is_pinned_alias_file "$CODEX_ALIAS_FILE"; then
|
|
130
|
+
dr_warn "already pinned for Codex: /$ALIAS — overwriting"
|
|
131
|
+
else
|
|
132
|
+
dr_die "$CODEX_ALIAS_FILE exists and is NOT a pinned alias — refusing to overwrite"
|
|
133
|
+
fi
|
|
134
|
+
fi
|
|
117
135
|
|
|
118
136
|
mkdir -p "$ALIAS_DIR"
|
|
119
137
|
dr_gen_alias_wrapper "$ALIAS" "$DEST" "$ALIAS_FILE"
|
|
138
|
+
if [ -d "$CODEX_SKILLS_DIR" ]; then
|
|
139
|
+
mkdir -p "$CODEX_ALIAS_DIR"
|
|
140
|
+
dr_gen_alias_wrapper "$ALIAS" "$DEST" "$CODEX_ALIAS_FILE"
|
|
141
|
+
fi
|
|
120
142
|
|
|
121
143
|
if ! dr_manifest_contains "$MF" "$ALIAS_REL"; then
|
|
122
144
|
printf '%s\n' "$ALIAS_REL" >> "$MF"
|
|
123
145
|
fi
|
|
146
|
+
if [ -d "$CODEX_SKILLS_DIR" ] && ! dr_manifest_contains "$MF" "$CODEX_ALIAS_REL"; then
|
|
147
|
+
printf '%s\n' "$CODEX_ALIAS_REL" >> "$MF"
|
|
148
|
+
fi
|
|
124
149
|
|
|
125
|
-
|
|
150
|
+
if [ -d "$CODEX_SKILLS_DIR" ]; then
|
|
151
|
+
dr_ok "pinned: /$ALIAS → /$DEST ($ALIAS_FILE, $CODEX_ALIAS_FILE)"
|
|
152
|
+
else
|
|
153
|
+
dr_ok "pinned: /$ALIAS → /$DEST ($ALIAS_FILE)"
|
|
154
|
+
fi
|
|
126
155
|
}
|
|
127
156
|
|
|
128
157
|
do_remove() {
|
|
@@ -130,16 +159,24 @@ do_remove() {
|
|
|
130
159
|
ALIAS_DIR="$SKILLS_DIR/$ALIAS"
|
|
131
160
|
ALIAS_FILE="$ALIAS_DIR/SKILL.md"
|
|
132
161
|
ALIAS_REL=".claude/skills/$ALIAS/SKILL.md"
|
|
162
|
+
CODEX_ALIAS_DIR="$CODEX_SKILLS_DIR/$ALIAS"
|
|
163
|
+
CODEX_ALIAS_FILE="$CODEX_ALIAS_DIR/SKILL.md"
|
|
164
|
+
CODEX_ALIAS_REL=".agents/skills/$ALIAS/SKILL.md"
|
|
133
165
|
|
|
134
166
|
[ -f "$ALIAS_FILE" ] || dr_die "no pinned alias at $ALIAS_FILE"
|
|
135
167
|
is_pinned_alias "$ALIAS" || dr_die "$ALIAS_FILE exists but is not a pinned alias — refusing to remove"
|
|
136
168
|
|
|
137
169
|
rm -f "$ALIAS_FILE"
|
|
138
170
|
rmdir "$ALIAS_DIR" 2>/dev/null || true
|
|
171
|
+
if [ -f "$CODEX_ALIAS_FILE" ]; then
|
|
172
|
+
is_pinned_alias_file "$CODEX_ALIAS_FILE" || dr_die "$CODEX_ALIAS_FILE exists but is not a pinned alias — refusing to remove"
|
|
173
|
+
rm -f "$CODEX_ALIAS_FILE"
|
|
174
|
+
rmdir "$CODEX_ALIAS_DIR" 2>/dev/null || true
|
|
175
|
+
fi
|
|
139
176
|
|
|
140
177
|
# Drop the alias line from the manifest (preserve header + the rest)
|
|
141
178
|
TMP="$(mktemp)"
|
|
142
|
-
grep -Fvx "$ALIAS_REL" "$MF" > "$TMP" && mv "$TMP" "$MF"
|
|
179
|
+
grep -Fvx "$ALIAS_REL" "$MF" | grep -Fvx "$CODEX_ALIAS_REL" > "$TMP" && mv "$TMP" "$MF"
|
|
143
180
|
|
|
144
181
|
dr_ok "unpinned: /$ALIAS"
|
|
145
182
|
}
|
package/uninstall.sh
CHANGED
|
@@ -86,10 +86,70 @@ PRUNE_TMP="$(mktemp 2>/dev/null || echo "${TMPDIR:-/tmp}/devrites-prune.$$")"
|
|
|
86
86
|
: > "$PRUNE_TMP"
|
|
87
87
|
trap 'rm -f "$PRUNE_TMP"' EXIT
|
|
88
88
|
|
|
89
|
+
# If DevRites was merged into a pre-existing AGENTS.md, remove only the managed
|
|
90
|
+
# marker block. Fresh AGENTS.md files created by DevRites are still removed
|
|
91
|
+
# below through the ordinary manifest entry.
|
|
92
|
+
if [ -f "$TARGET/.claude/devrites.agents-merge" ] && [ -f "$TARGET/AGENTS.md" ]; then
|
|
93
|
+
if [ "$DRYRUN" -eq 1 ]; then
|
|
94
|
+
dr_say " [merge-remove] AGENTS.md DevRites block"
|
|
95
|
+
else
|
|
96
|
+
tmp_agents="$(mktemp 2>/dev/null || echo "${TMPDIR:-/tmp}/devrites-agents.$$")"
|
|
97
|
+
awk '
|
|
98
|
+
$0 == "<!-- BEGIN DEVRITES CODEX -->" { in_block = 1; next }
|
|
99
|
+
$0 == "<!-- END DEVRITES CODEX -->" { in_block = 0; next }
|
|
100
|
+
in_block { next }
|
|
101
|
+
{ print }
|
|
102
|
+
' "$TARGET/AGENTS.md" > "$tmp_agents" && cp "$tmp_agents" "$TARGET/AGENTS.md"
|
|
103
|
+
rm -f "$tmp_agents"
|
|
104
|
+
grep -q '[^[:space:]]' "$TARGET/AGENTS.md" 2>/dev/null || rm -f "$TARGET/AGENTS.md"
|
|
105
|
+
fi
|
|
106
|
+
fi
|
|
107
|
+
|
|
108
|
+
if [ -f "$TARGET/.claude/devrites.codex-config-merge" ] && [ -f "$TARGET/.codex/config.toml" ]; then
|
|
109
|
+
if [ "$DRYRUN" -eq 1 ]; then
|
|
110
|
+
dr_say " [merge-remove] .codex/config.toml DevRites MCP block"
|
|
111
|
+
else
|
|
112
|
+
tmp_codex_config="$(mktemp 2>/dev/null || echo "${TMPDIR:-/tmp}/devrites-codex-config.$$")"
|
|
113
|
+
awk '
|
|
114
|
+
$0 == "# BEGIN DEVRITES CODEX MCP" { in_block = 1; next }
|
|
115
|
+
$0 == "# END DEVRITES CODEX MCP" { in_block = 0; next }
|
|
116
|
+
in_block { next }
|
|
117
|
+
{ print }
|
|
118
|
+
' "$TARGET/.codex/config.toml" > "$tmp_codex_config" && cp "$tmp_codex_config" "$TARGET/.codex/config.toml"
|
|
119
|
+
rm -f "$tmp_codex_config"
|
|
120
|
+
grep -q '[^[:space:]]' "$TARGET/.codex/config.toml" 2>/dev/null || rm -f "$TARGET/.codex/config.toml"
|
|
121
|
+
fi
|
|
122
|
+
fi
|
|
123
|
+
|
|
124
|
+
if [ -f "$TARGET/.claude/devrites.codex-hooks-merge" ] && [ -f "$TARGET/.codex/hooks.json" ]; then
|
|
125
|
+
if [ "$DRYRUN" -eq 1 ]; then
|
|
126
|
+
dr_say " [merge-remove] .codex/hooks.json DevRites hooks"
|
|
127
|
+
else
|
|
128
|
+
if grep -q 'DevRites hooks for Codex' "$TARGET/.codex/hooks.json" 2>/dev/null \
|
|
129
|
+
&& ! grep '"command"[[:space:]]*:' "$TARGET/.codex/hooks.json" 2>/dev/null | grep -vq 'devrites-\|DEVRITES_\|DevRites:'; then
|
|
130
|
+
rm -f "$TARGET/.codex/hooks.json" || dr_die "cannot remove .codex/hooks.json"
|
|
131
|
+
else
|
|
132
|
+
command -v node >/dev/null 2>&1 || dr_die "node is required to remove DevRites hooks from .codex/hooks.json"
|
|
133
|
+
tmp_codex_hooks="$(mktemp 2>/dev/null || echo "${TMPDIR:-/tmp}/devrites-codex-hooks.$$")"
|
|
134
|
+
node "$SELF_DIR/scripts/merge-codex-hooks.mjs" strip "$TARGET/.codex/hooks.json" "$tmp_codex_hooks" \
|
|
135
|
+
|| dr_die "cannot remove DevRites hooks from .codex/hooks.json"
|
|
136
|
+
cp "$tmp_codex_hooks" "$TARGET/.codex/hooks.json" || dr_die "cannot write .codex/hooks.json"
|
|
137
|
+
rm -f "$tmp_codex_hooks"
|
|
138
|
+
[ "$(tr -d '[:space:]' < "$TARGET/.codex/hooks.json" 2>/dev/null)" != "{}" ] || rm -f "$TARGET/.codex/hooks.json"
|
|
139
|
+
fi
|
|
140
|
+
[ -e "$TARGET/.codex/hooks.json" ] || printf '%s\n' "$TARGET/.codex" >> "$PRUNE_TMP"
|
|
141
|
+
fi
|
|
142
|
+
fi
|
|
143
|
+
|
|
89
144
|
# Remove each manifest-listed file.
|
|
90
145
|
while IFS= read -r rel; do
|
|
91
146
|
case "$rel" in ''|\#*) continue ;; esac # skip blanks/comments
|
|
92
147
|
case "$rel" in /*|*..*) dr_warn "ignoring suspicious manifest entry: $rel"; continue ;; esac
|
|
148
|
+
case "$rel" in
|
|
149
|
+
AGENTS.md) [ -f "$TARGET/.claude/devrites.agents-merge" ] && continue ;;
|
|
150
|
+
.codex/config.toml) [ -f "$TARGET/.claude/devrites.codex-config-merge" ] && continue ;;
|
|
151
|
+
.codex/hooks.json) [ -f "$TARGET/.claude/devrites.codex-hooks-merge" ] && continue ;;
|
|
152
|
+
esac
|
|
93
153
|
dest="$TARGET/$rel"
|
|
94
154
|
if [ -e "$dest" ] || [ -L "$dest" ]; then
|
|
95
155
|
if [ "$DRYRUN" -eq 1 ]; then
|