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/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-* skill without re-running
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 ~/.claude (DevRites is project-local only).
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
- dr_ok "pinned: /$ALIAS → /$DEST ($ALIAS_FILE)"
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