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/install.sh
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
# ./install.sh --dry-run show planned operations, change nothing
|
|
7
7
|
# ./install.sh --force overwrite existing non-DevRites files
|
|
8
8
|
# ./install.sh --no-agents skip the review subagents
|
|
9
|
+
# ./install.sh --no-codex skip Codex support files (.agents, .codex, AGENTS.md)
|
|
9
10
|
# ./install.sh --no-rules skip the DevRites engineering rules
|
|
10
11
|
# ./install.sh --rules-only install only the engineering rules
|
|
11
12
|
# ./install.sh --short-aliases=all install /define /build /prove /seal aliases
|
|
@@ -14,7 +15,7 @@
|
|
|
14
15
|
# curl -fsSL https://raw.githubusercontent.com/ViktorsBaikers/DevRites/main/install.sh | bash
|
|
15
16
|
# curl -fsSL https://raw.githubusercontent.com/ViktorsBaikers/DevRites/main/install.sh | bash -s -- --target /path
|
|
16
17
|
#
|
|
17
|
-
# Never writes to ~/.claude. Records every installed file in
|
|
18
|
+
# Never writes to ~/.claude or ~/.codex. Records every installed file in
|
|
18
19
|
# .claude/devrites.manifest so uninstall removes exactly what it added.
|
|
19
20
|
|
|
20
21
|
set -u
|
|
@@ -120,6 +121,7 @@ FORCE=0
|
|
|
120
121
|
WITH_SKILLS=1
|
|
121
122
|
WITH_AGENTS=1
|
|
122
123
|
WITH_RULES=1
|
|
124
|
+
WITH_CODEX=1
|
|
123
125
|
ALIAS_MODE="safe" # safe | off | all
|
|
124
126
|
|
|
125
127
|
# ---- parse args ----------------------------------------------------------
|
|
@@ -131,8 +133,9 @@ while [ $# -gt 0 ]; do
|
|
|
131
133
|
--force) FORCE=1 ;;
|
|
132
134
|
--no-skills) WITH_SKILLS=0 ;; # accepted so a --rules-only manifest round-trips through update.sh's flag replay
|
|
133
135
|
--no-agents) WITH_AGENTS=0 ;;
|
|
136
|
+
--no-codex) WITH_CODEX=0 ;;
|
|
134
137
|
--no-rules) WITH_RULES=0 ;;
|
|
135
|
-
--rules-only) WITH_SKILLS=0; WITH_AGENTS=0; WITH_RULES=1; ALIAS_MODE="off" ;;
|
|
138
|
+
--rules-only) WITH_SKILLS=0; WITH_AGENTS=0; WITH_RULES=1; WITH_CODEX=0; ALIAS_MODE="off" ;;
|
|
136
139
|
--no-short-aliases) ALIAS_MODE="off" ;; # accepted for backward compat; aliases are off by default now
|
|
137
140
|
--short-aliases) dr_warn "--short-aliases with no value is a no-op (aliases default off); use --short-aliases=all to install /define /build /prove /seal."; ALIAS_MODE="off" ;; # /polish + /normalize were removed in favor of /rite-polish argument-hint modes
|
|
138
141
|
--short-aliases=all) ALIAS_MODE="all" ;;
|
|
@@ -148,10 +151,11 @@ done
|
|
|
148
151
|
[ -d "$TARGET" ] || dr_die "target is not a directory: $TARGET"
|
|
149
152
|
TARGET="$(dr_abspath_dir "$TARGET")" || dr_die "cannot resolve target: $TARGET"
|
|
150
153
|
|
|
151
|
-
# GUARD:no-global — refuse to install into
|
|
154
|
+
# GUARD:no-global — refuse to install into global agent configuration trees.
|
|
152
155
|
TARGET_CLAUDE="$TARGET/.claude"
|
|
153
|
-
|
|
154
|
-
|
|
156
|
+
TARGET_CODEX="$TARGET/.codex"
|
|
157
|
+
if dr_is_global_claude "$TARGET_CLAUDE" || dr_is_global_codex "$TARGET_CODEX" || [ "$TARGET" = "$HOME" ]; then
|
|
158
|
+
dr_die "refusing to target a global agent home. DevRites is project-local; choose a project directory."
|
|
155
159
|
fi
|
|
156
160
|
|
|
157
161
|
PREV_MANIFEST="$TARGET/$DR_MANIFEST_NAME"
|
|
@@ -195,6 +199,22 @@ install_file() {
|
|
|
195
199
|
esac
|
|
196
200
|
}
|
|
197
201
|
|
|
202
|
+
install_marker_file() {
|
|
203
|
+
_rel="$1"; _text="$2"; _dest="$TARGET/$_rel"
|
|
204
|
+
if [ "$DRYRUN" -eq 1 ]; then
|
|
205
|
+
dr_say " [install] $_rel"
|
|
206
|
+
else
|
|
207
|
+
mkdir -p "$(dirname "$_dest")" || dr_die "cannot create $(dirname "$_dest")"
|
|
208
|
+
if [ -f "$_dest" ] && printf '%s\n' "$_text" | cmp -s - "$_dest"; then
|
|
209
|
+
printf '%s\n' "$_rel" >> "$MANIFEST_TMP"
|
|
210
|
+
return 0
|
|
211
|
+
fi
|
|
212
|
+
printf '%s\n' "$_text" > "$_dest" || dr_die "cannot write $_dest"
|
|
213
|
+
fi
|
|
214
|
+
printf '%s\n' "$_rel" >> "$MANIFEST_TMP"
|
|
215
|
+
N_INSTALL=$((N_INSTALL+1))
|
|
216
|
+
}
|
|
217
|
+
|
|
198
218
|
# install_tree SRC_DIR REL_PREFIX — install every file under SRC_DIR.
|
|
199
219
|
install_tree() {
|
|
200
220
|
_sd="$1"; _pre="$2"
|
|
@@ -210,6 +230,488 @@ install_tree() {
|
|
|
210
230
|
# scripts/pin.sh for ad-hoc user pins).
|
|
211
231
|
gen_alias_wrapper() { dr_gen_alias_wrapper "$@"; }
|
|
212
232
|
|
|
233
|
+
gen_codex_markdown_file() {
|
|
234
|
+
_src="$1"; _out="$2"
|
|
235
|
+
mkdir -p "$(dirname "$_out")"
|
|
236
|
+
sed -E \
|
|
237
|
+
-e 's#pack/\.claude/rules/#.agents/devrites/rules/#g' \
|
|
238
|
+
-e 's#pack/\.claude/rules#.agents/devrites/rules#g' \
|
|
239
|
+
-e 's#pack/\.claude/skills/devrites-lib/scripts/#.agents/skills/devrites-lib/scripts/#g' \
|
|
240
|
+
-e 's#pack/\.claude/skills/#.agents/skills/#g' \
|
|
241
|
+
-e 's#pack/\.claude/agents/(devrites-[A-Za-z0-9_-]+)\.md#.codex/agents/\1.toml#g' \
|
|
242
|
+
-e 's#pack/\.claude/agents/#.codex/agents/#g' \
|
|
243
|
+
-e 's#\.claude/rules/#.agents/devrites/rules/#g' \
|
|
244
|
+
-e 's#\.claude/rules#.agents/devrites/rules#g' \
|
|
245
|
+
-e 's#\.claude/skills/devrites-lib/scripts/#.agents/skills/devrites-lib/scripts/#g' \
|
|
246
|
+
-e 's#\.claude/skills/#.agents/skills/#g' \
|
|
247
|
+
-e 's#\.claude/agents/(devrites-[A-Za-z0-9_-]+)\.md#.codex/agents/\1.toml#g' \
|
|
248
|
+
-e 's#\.claude/agents/#.codex/agents/#g' \
|
|
249
|
+
-e 's#\.\./\.\./\.\./agents/(devrites-[A-Za-z0-9_-]+)\.md#.codex/agents/\1.toml#g' \
|
|
250
|
+
-e 's#\.\./\.\./agents/(devrites-[A-Za-z0-9_-]+)\.md#.codex/agents/\1.toml#g' \
|
|
251
|
+
-e 's#\.\./\.\./\.\./rules/#../../../devrites/rules/#g' \
|
|
252
|
+
-e 's#\.\./\.\./rules/#../../devrites/rules/#g' \
|
|
253
|
+
"$_src" > "$_out"
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
strip_codex_agents_md_block() {
|
|
257
|
+
_file="$1"
|
|
258
|
+
[ -f "$_file" ] || return 0
|
|
259
|
+
_tmp="$TMP_GEN_DIR/AGENTS.strip.md"
|
|
260
|
+
awk '
|
|
261
|
+
$0 == "<!-- BEGIN DEVRITES CODEX -->" { in_block = 1; next }
|
|
262
|
+
$0 == "<!-- END DEVRITES CODEX -->" { in_block = 0; next }
|
|
263
|
+
in_block { next }
|
|
264
|
+
{ print }
|
|
265
|
+
' "$_file" > "$_tmp" || dr_die "cannot strip DevRites block from $_file"
|
|
266
|
+
cp "$_tmp" "$_file" || dr_die "cannot write $_file"
|
|
267
|
+
grep -q '[^[:space:]]' "$_file" 2>/dev/null || rm -f "$_file"
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
strip_codex_config_block() {
|
|
271
|
+
_file="$1"
|
|
272
|
+
[ -f "$_file" ] || return 0
|
|
273
|
+
_tmp="$TMP_GEN_DIR/codex-config.strip.toml"
|
|
274
|
+
awk '
|
|
275
|
+
$0 == "# BEGIN DEVRITES CODEX MCP" { in_block = 1; next }
|
|
276
|
+
$0 == "# END DEVRITES CODEX MCP" { in_block = 0; next }
|
|
277
|
+
in_block { next }
|
|
278
|
+
{ print }
|
|
279
|
+
' "$_file" > "$_tmp" || dr_die "cannot strip DevRites MCP block from $_file"
|
|
280
|
+
cp "$_tmp" "$_file" || dr_die "cannot write $_file"
|
|
281
|
+
grep -q '[^[:space:]]' "$_file" 2>/dev/null || rm -f "$_file"
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
strip_codex_hooks_entries() {
|
|
285
|
+
_file="$1"
|
|
286
|
+
[ -f "$_file" ] || return 0
|
|
287
|
+
_tmp="$TMP_GEN_DIR/codex-hooks.strip.json"
|
|
288
|
+
command -v node >/dev/null 2>&1 || dr_die "node is required to merge existing .codex/hooks.json"
|
|
289
|
+
node "$SELF_DIR/scripts/merge-codex-hooks.mjs" strip "$_file" "$_tmp" || dr_die "cannot strip DevRites hooks from $_file"
|
|
290
|
+
cp "$_tmp" "$_file" || dr_die "cannot write $_file"
|
|
291
|
+
[ "$(tr -d '[:space:]' < "$_file" 2>/dev/null)" != "{}" ] || rm -f "$_file"
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
gen_codex_skill_file() {
|
|
295
|
+
_src="$1"; _out="$2"
|
|
296
|
+
_tmp="$TMP_GEN_DIR/codex-skill-raw-$(basename "$(dirname "$_src")").md"
|
|
297
|
+
mkdir -p "$(dirname "$_out")"
|
|
298
|
+
awk '
|
|
299
|
+
BEGIN { fm = 0; inserted = 0 }
|
|
300
|
+
NR == 1 && $0 == "---" { print; fm = 1; next }
|
|
301
|
+
fm && $0 == "---" {
|
|
302
|
+
print
|
|
303
|
+
print ""
|
|
304
|
+
print "## Codex compatibility"
|
|
305
|
+
print ""
|
|
306
|
+
print "This is the Codex mirror of a DevRites skill. In Codex:"
|
|
307
|
+
print ""
|
|
308
|
+
print "- Load DevRites engineering rules from `.agents/devrites/rules/`. Read `.agents/devrites/rules/core.md` before workflow work, then load the other `.agents/devrites/rules/*.md` files exactly when this skill asks for them."
|
|
309
|
+
print "- Use `.agents/skills/devrites-lib/scripts/` as the canonical runtime helper location unless this skill resolves another installed path."
|
|
310
|
+
print "- When this skill asks for a DevRites specialist or writer agent, spawn the matching Codex custom agent from `.codex/agents/devrites-*.toml` through Codex subagents. Wait for the subagent result and reconcile it as the skill instructs."
|
|
311
|
+
print "- If Codex subagents are unavailable in the current surface, use the skill documented inline fallback and label the result as an inline fallback, not an independent subagent review."
|
|
312
|
+
print "- Codex project hooks are installed in `.codex/hooks.json` and `.codex/hooks/`. Review and trust them with `/hooks` before relying on hook enforcement."
|
|
313
|
+
print ""
|
|
314
|
+
fm = 0
|
|
315
|
+
inserted = 1
|
|
316
|
+
next
|
|
317
|
+
}
|
|
318
|
+
{ print }
|
|
319
|
+
END {
|
|
320
|
+
if (!inserted) {
|
|
321
|
+
print ""
|
|
322
|
+
print "## Codex compatibility"
|
|
323
|
+
print ""
|
|
324
|
+
print "Load DevRites rules from `.agents/devrites/rules/`, use matching `.codex/agents/devrites-*.toml` custom agents for DevRites subagent dispatch, and trust `.codex/hooks.json` with `/hooks` before relying on hooks."
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
' "$_src" > "$_tmp"
|
|
328
|
+
gen_codex_markdown_file "$_tmp" "$_out"
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
install_codex_skill_tree() {
|
|
332
|
+
_sd="$1"; _pre="$2"
|
|
333
|
+
[ -d "$_sd" ] || return 0
|
|
334
|
+
while IFS= read -r f; do
|
|
335
|
+
_r="${f#$_sd/}"
|
|
336
|
+
case "$_r" in
|
|
337
|
+
SKILL.md)
|
|
338
|
+
_gen="$TMP_GEN_DIR/codex-skill-$(basename "$_sd").md"
|
|
339
|
+
gen_codex_skill_file "$f" "$_gen"
|
|
340
|
+
install_file "$_gen" "$_pre/$_r"
|
|
341
|
+
;;
|
|
342
|
+
*.md)
|
|
343
|
+
_gen="$TMP_GEN_DIR/codex-md-$(basename "$_sd")-$(printf '%s' "$_r" | tr '/ ' '__').md"
|
|
344
|
+
gen_codex_markdown_file "$f" "$_gen"
|
|
345
|
+
install_file "$_gen" "$_pre/$_r"
|
|
346
|
+
;;
|
|
347
|
+
*)
|
|
348
|
+
install_file "$f" "$_pre/$_r"
|
|
349
|
+
;;
|
|
350
|
+
esac
|
|
351
|
+
done < <(find "$_sd" -type f)
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
toml_escape() {
|
|
355
|
+
printf '%s' "$1" | sed 's/\\/\\\\/g; s/"/\\"/g'
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
# Generate a Codex custom-agent TOML file from a Claude Code markdown agent.
|
|
359
|
+
# Codex does not consume .claude/agents/*.md directly; it loads project agents
|
|
360
|
+
# from .codex/agents/*.toml.
|
|
361
|
+
gen_codex_agent() {
|
|
362
|
+
_src="$1"; _out="$2"
|
|
363
|
+
_name="$(awk 'NR==1 && $0=="---"{fm=1; next} fm && $0=="---"{exit} fm && /^name:[[:space:]]*/{sub(/^name:[[:space:]]*/, ""); print; exit}' "$_src")"
|
|
364
|
+
_desc="$(awk 'NR==1 && $0=="---"{fm=1; next} fm && $0=="---"{exit} fm && /^description:[[:space:]]*/{sub(/^description:[[:space:]]*/, ""); print; exit}' "$_src")"
|
|
365
|
+
[ -n "$_name" ] || _name="$(basename "$_src" .md)"
|
|
366
|
+
[ -n "$_desc" ] || _desc="DevRites custom agent."
|
|
367
|
+
_tools="$(awk 'NR==1 && $0=="---"{fm=1; next} fm && $0=="---"{exit} fm && /^tools:[[:space:]]*/{sub(/^tools:[[:space:]]*/, ""); print; exit}' "$_src")"
|
|
368
|
+
mkdir -p "$(dirname "$_out")"
|
|
369
|
+
{
|
|
370
|
+
printf 'name = "%s"\n' "$(toml_escape "$_name")"
|
|
371
|
+
printf 'description = "%s"\n' "$(toml_escape "$_desc")"
|
|
372
|
+
case "$_tools" in
|
|
373
|
+
*Edit*|*Write*|*MultiEdit*) : ;;
|
|
374
|
+
*) printf 'sandbox_mode = "read-only"\n' ;;
|
|
375
|
+
esac
|
|
376
|
+
printf "%s\n" "developer_instructions = '''"
|
|
377
|
+
printf 'You are the Codex custom-agent version of DevRites `%s`.\n' "$_name"
|
|
378
|
+
printf 'Follow the source agent instructions below. Treat any Claude Code-specific hook/tool metadata as unavailable in Codex unless the current session exposes an equivalent capability.\n\n'
|
|
379
|
+
_body_tmp="$TMP_GEN_DIR/codex-agent-body-$(basename "$_src").md"
|
|
380
|
+
_body_codex="$TMP_GEN_DIR/codex-agent-body-$(basename "$_src").codex.md"
|
|
381
|
+
awk 'NR==1 && $0=="---"{fm=1; next} fm && $0=="---"{fm=0; body=1; next} body{print}' "$_src" > "$_body_tmp"
|
|
382
|
+
gen_codex_markdown_file "$_body_tmp" "$_body_codex"
|
|
383
|
+
cat "$_body_codex"
|
|
384
|
+
printf "\n%s\n" "'''"
|
|
385
|
+
} > "$_out"
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
gen_codex_agents_bridge() {
|
|
389
|
+
_out="$1"
|
|
390
|
+
cat > "$_out" <<'EOF'
|
|
391
|
+
<!-- BEGIN DEVRITES CODEX -->
|
|
392
|
+
## DevRites For Codex
|
|
393
|
+
|
|
394
|
+
This project has DevRites installed for both Claude Code and Codex.
|
|
395
|
+
|
|
396
|
+
## Codex usage
|
|
397
|
+
|
|
398
|
+
- DevRites workflow skills are available to Codex from `.agents/skills`.
|
|
399
|
+
- Use `$rite` or `$rite-<verb>` through Codex skills, or open `/skills` and select the matching DevRites skill.
|
|
400
|
+
- If the user mentions a DevRites slash command such as `/rite spec`, `/rite-build`, or `/rite-seal`, treat that as an explicit request to use the corresponding DevRites skill.
|
|
401
|
+
- DevRites runtime helpers are mirrored for Codex under `.agents/skills/devrites-lib/scripts/`.
|
|
402
|
+
- Before using any DevRites workflow skill, read `.agents/devrites/rules/core.md`. Load other `.agents/devrites/rules/*.md` files when the skill or rule index asks for them. These are DevRites engineering rules, not Codex exec-policy `.rules` files.
|
|
403
|
+
- Custom Codex subagents generated from the DevRites review agents live in `.codex/agents`.
|
|
404
|
+
- When DevRites skill prose asks for a DevRites specialist or writer agent, use the matching Codex custom agent from `.codex/agents/devrites-*.toml` through Codex subagents. If Codex subagents are unavailable in the current surface, run the skill's documented inline fallback and say that the result was not an independent subagent review.
|
|
405
|
+
- Claude Code agent hook metadata is not active in Codex. The generated Codex agents preserve read-only intent with Codex sandbox settings where possible; still follow DevRites' scope and no-mutation rules explicitly.
|
|
406
|
+
|
|
407
|
+
## Workflow contract
|
|
408
|
+
|
|
409
|
+
- Keep all feature state in `.devrites/work/<slug>/` and preserve `.devrites/ACTIVE`.
|
|
410
|
+
- Follow the DevRites lifecycle: spec -> define -> build -> prove -> polish -> review -> seal -> ship.
|
|
411
|
+
- Claims of completion need recorded evidence in the feature workspace, not confidence alone.
|
|
412
|
+
<!-- END DEVRITES CODEX -->
|
|
413
|
+
EOF
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
install_codex_agents_md() {
|
|
417
|
+
_src="$1"
|
|
418
|
+
_rel="AGENTS.md"
|
|
419
|
+
_dest="$TARGET/$_rel"
|
|
420
|
+
_marker=".claude/devrites.agents-merge"
|
|
421
|
+
|
|
422
|
+
if [ -e "$_dest" ]; then
|
|
423
|
+
if [ "$DRYRUN" -eq 1 ]; then
|
|
424
|
+
if grep -q '<!-- BEGIN DEVRITES CODEX -->' "$_dest" 2>/dev/null; then
|
|
425
|
+
dr_say " [merge] AGENTS.md ${DR_Y}(refresh DevRites block)${DR_R}"
|
|
426
|
+
else
|
|
427
|
+
dr_say " [merge] AGENTS.md ${DR_Y}(append DevRites block)${DR_R}"
|
|
428
|
+
fi
|
|
429
|
+
else
|
|
430
|
+
_merged="$TMP_GEN_DIR/AGENTS.merged.md"
|
|
431
|
+
awk -v block_file="$_src" '
|
|
432
|
+
BEGIN {
|
|
433
|
+
while ((getline line < block_file) > 0) block = block line "\n"
|
|
434
|
+
close(block_file)
|
|
435
|
+
in_block = 0
|
|
436
|
+
found = 0
|
|
437
|
+
}
|
|
438
|
+
$0 == "<!-- BEGIN DEVRITES CODEX -->" {
|
|
439
|
+
printf "%s", block
|
|
440
|
+
in_block = 1
|
|
441
|
+
found = 1
|
|
442
|
+
next
|
|
443
|
+
}
|
|
444
|
+
$0 == "<!-- END DEVRITES CODEX -->" {
|
|
445
|
+
in_block = 0
|
|
446
|
+
next
|
|
447
|
+
}
|
|
448
|
+
in_block { next }
|
|
449
|
+
{ print }
|
|
450
|
+
END {
|
|
451
|
+
if (!found) {
|
|
452
|
+
print ""
|
|
453
|
+
printf "%s", block
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
' "$_dest" > "$_merged" || dr_die "cannot merge AGENTS.md"
|
|
457
|
+
cp "$_merged" "$_dest" || dr_die "cannot write $_dest"
|
|
458
|
+
fi
|
|
459
|
+
install_marker_file "$_marker" "AGENTS.md contains a DevRites managed block between BEGIN/END DEVRITES CODEX markers."
|
|
460
|
+
return 0
|
|
461
|
+
fi
|
|
462
|
+
|
|
463
|
+
if [ "$DRYRUN" -eq 1 ]; then
|
|
464
|
+
dr_say " [merge] AGENTS.md ${DR_Y}(create DevRites block)${DR_R}"
|
|
465
|
+
else
|
|
466
|
+
mkdir -p "$(dirname "$_dest")" || dr_die "cannot create $(dirname "$_dest")"
|
|
467
|
+
cp "$_src" "$_dest" || dr_die "cannot write $_dest"
|
|
468
|
+
fi
|
|
469
|
+
install_marker_file "$_marker" "AGENTS.md contains a DevRites managed block between BEGIN/END DEVRITES CODEX markers."
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
gen_codex_config_block() {
|
|
473
|
+
_out="$1"
|
|
474
|
+
cat > "$_out" <<'EOF'
|
|
475
|
+
# BEGIN DEVRITES CODEX MCP
|
|
476
|
+
[mcp_servers.devrites]
|
|
477
|
+
command = "node"
|
|
478
|
+
args = [".codex/mcp/devrites-mcp.mjs"]
|
|
479
|
+
cwd = "."
|
|
480
|
+
enabled = true
|
|
481
|
+
default_tools_approval_mode = "prompt"
|
|
482
|
+
startup_timeout_sec = 10
|
|
483
|
+
tool_timeout_sec = 60
|
|
484
|
+
# END DEVRITES CODEX MCP
|
|
485
|
+
EOF
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
install_codex_config_toml() {
|
|
489
|
+
_src="$1"
|
|
490
|
+
_rel=".codex/config.toml"
|
|
491
|
+
_dest="$TARGET/$_rel"
|
|
492
|
+
_marker=".claude/devrites.codex-config-merge"
|
|
493
|
+
|
|
494
|
+
if [ -e "$_dest" ]; then
|
|
495
|
+
if grep -q '^\[mcp_servers\.devrites\]' "$_dest" 2>/dev/null && ! grep -q '# BEGIN DEVRITES CODEX MCP' "$_dest" 2>/dev/null; then
|
|
496
|
+
[ "$DRYRUN" -eq 1 ] && dr_say " [skip] .codex/config.toml ${DR_Y}(already defines mcp_servers.devrites)${DR_R}"
|
|
497
|
+
[ "$DRYRUN" -eq 1 ] || dr_warn "skip .codex/config.toml DevRites MCP block (already defines mcp_servers.devrites)"
|
|
498
|
+
N_SKIP=$((N_SKIP+1))
|
|
499
|
+
return 0
|
|
500
|
+
fi
|
|
501
|
+
if [ "$DRYRUN" -eq 1 ]; then
|
|
502
|
+
if grep -q '# BEGIN DEVRITES CODEX MCP' "$_dest" 2>/dev/null; then
|
|
503
|
+
dr_say " [merge] .codex/config.toml ${DR_Y}(refresh DevRites MCP block)${DR_R}"
|
|
504
|
+
else
|
|
505
|
+
dr_say " [merge] .codex/config.toml ${DR_Y}(append DevRites MCP block)${DR_R}"
|
|
506
|
+
fi
|
|
507
|
+
else
|
|
508
|
+
_merged="$TMP_GEN_DIR/codex-config.merged.toml"
|
|
509
|
+
awk -v block_file="$_src" '
|
|
510
|
+
BEGIN {
|
|
511
|
+
while ((getline line < block_file) > 0) block = block line "\n"
|
|
512
|
+
close(block_file)
|
|
513
|
+
in_block = 0
|
|
514
|
+
found = 0
|
|
515
|
+
}
|
|
516
|
+
$0 == "# BEGIN DEVRITES CODEX MCP" {
|
|
517
|
+
printf "%s", block
|
|
518
|
+
in_block = 1
|
|
519
|
+
found = 1
|
|
520
|
+
next
|
|
521
|
+
}
|
|
522
|
+
$0 == "# END DEVRITES CODEX MCP" {
|
|
523
|
+
in_block = 0
|
|
524
|
+
next
|
|
525
|
+
}
|
|
526
|
+
in_block { next }
|
|
527
|
+
{ print }
|
|
528
|
+
END {
|
|
529
|
+
if (!found) {
|
|
530
|
+
print ""
|
|
531
|
+
printf "%s", block
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
' "$_dest" > "$_merged" || dr_die "cannot merge .codex/config.toml"
|
|
535
|
+
cp "$_merged" "$_dest" || dr_die "cannot write $_dest"
|
|
536
|
+
fi
|
|
537
|
+
install_marker_file "$_marker" ".codex/config.toml contains a DevRites managed block between BEGIN/END DEVRITES CODEX MCP markers."
|
|
538
|
+
return 0
|
|
539
|
+
fi
|
|
540
|
+
|
|
541
|
+
if [ "$DRYRUN" -eq 1 ]; then
|
|
542
|
+
dr_say " [merge] .codex/config.toml ${DR_Y}(create DevRites MCP block)${DR_R}"
|
|
543
|
+
else
|
|
544
|
+
mkdir -p "$(dirname "$_dest")" || dr_die "cannot create $(dirname "$_dest")"
|
|
545
|
+
cp "$_src" "$_dest" || dr_die "cannot write $_dest"
|
|
546
|
+
fi
|
|
547
|
+
install_marker_file "$_marker" ".codex/config.toml contains a DevRites managed block between BEGIN/END DEVRITES CODEX MCP markers."
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
gen_codex_hooks_json() {
|
|
551
|
+
_out="$1"
|
|
552
|
+
cat > "$_out" <<'EOF'
|
|
553
|
+
{
|
|
554
|
+
"$comment": "DevRites hooks for Codex. Project hooks load only after the project .codex layer is trusted; use /hooks in Codex to review and trust these non-managed hooks. Commands resolve the git root first so hooks work when Codex starts from a subdirectory.",
|
|
555
|
+
"hooks": {
|
|
556
|
+
"PreToolUse": [
|
|
557
|
+
{
|
|
558
|
+
"matcher": "Bash",
|
|
559
|
+
"hooks": [
|
|
560
|
+
{
|
|
561
|
+
"type": "command",
|
|
562
|
+
"command": "root=\"$(git rev-parse --show-toplevel 2>/dev/null || pwd)\"; cd \"$root\" && DEVRITES_REVIEWER_AGENT_REQUIRED=1 bash \"$root/.codex/hooks/devrites-reviewer-readonly.sh\"",
|
|
563
|
+
"statusMessage": "DevRites: checking reviewer read-only boundary"
|
|
564
|
+
}
|
|
565
|
+
]
|
|
566
|
+
},
|
|
567
|
+
{
|
|
568
|
+
"matcher": "Bash",
|
|
569
|
+
"hooks": [
|
|
570
|
+
{
|
|
571
|
+
"type": "command",
|
|
572
|
+
"command": "root=\"$(git rev-parse --show-toplevel 2>/dev/null || pwd)\"; cd \"$root\" && bash \"$root/.codex/hooks/devrites-allow.sh\"",
|
|
573
|
+
"statusMessage": "DevRites: checking read-only helper approval"
|
|
574
|
+
}
|
|
575
|
+
]
|
|
576
|
+
},
|
|
577
|
+
{
|
|
578
|
+
"matcher": "Edit|Write|apply_patch",
|
|
579
|
+
"hooks": [
|
|
580
|
+
{
|
|
581
|
+
"type": "command",
|
|
582
|
+
"command": "root=\"$(git rev-parse --show-toplevel 2>/dev/null || pwd)\"; cd \"$root\" && bash \"$root/.codex/hooks/devrites-a1-guard.sh\"",
|
|
583
|
+
"statusMessage": "DevRites: checking build write boundary"
|
|
584
|
+
},
|
|
585
|
+
{
|
|
586
|
+
"type": "command",
|
|
587
|
+
"command": "root=\"$(git rev-parse --show-toplevel 2>/dev/null || pwd)\"; cd \"$root\" && DEVRITES_WRIGHT_AGENT_REQUIRED=1 bash \"$root/.codex/hooks/devrites-wright-scope.sh\"",
|
|
588
|
+
"statusMessage": "DevRites: checking slice file scope"
|
|
589
|
+
}
|
|
590
|
+
]
|
|
591
|
+
}
|
|
592
|
+
],
|
|
593
|
+
"PostToolUse": [
|
|
594
|
+
{
|
|
595
|
+
"matcher": "Bash",
|
|
596
|
+
"hooks": [
|
|
597
|
+
{
|
|
598
|
+
"type": "command",
|
|
599
|
+
"command": "root=\"$(git rev-parse --show-toplevel 2>/dev/null || pwd)\"; cd \"$root\" && bash \"$root/.codex/hooks/devrites-redwatch.sh\"",
|
|
600
|
+
"statusMessage": "DevRites: checking test/build result"
|
|
601
|
+
}
|
|
602
|
+
]
|
|
603
|
+
}
|
|
604
|
+
],
|
|
605
|
+
"Stop": [
|
|
606
|
+
{
|
|
607
|
+
"hooks": [
|
|
608
|
+
{
|
|
609
|
+
"type": "command",
|
|
610
|
+
"command": "root=\"$(git rev-parse --show-toplevel 2>/dev/null || pwd)\"; cd \"$root\" && bash \"$root/.codex/hooks/devrites-stop-gate.sh\"",
|
|
611
|
+
"statusMessage": "DevRites: checking workspace stop gate"
|
|
612
|
+
}
|
|
613
|
+
]
|
|
614
|
+
},
|
|
615
|
+
{
|
|
616
|
+
"hooks": [
|
|
617
|
+
{
|
|
618
|
+
"type": "command",
|
|
619
|
+
"command": "root=\"$(git rev-parse --show-toplevel 2>/dev/null || pwd)\"; cd \"$root\" && bash \"$root/.codex/hooks/devrites-refresh-indexes.sh\"",
|
|
620
|
+
"statusMessage": "DevRites: refreshing code indexes"
|
|
621
|
+
}
|
|
622
|
+
]
|
|
623
|
+
}
|
|
624
|
+
],
|
|
625
|
+
"UserPromptSubmit": [
|
|
626
|
+
{
|
|
627
|
+
"hooks": [
|
|
628
|
+
{
|
|
629
|
+
"type": "command",
|
|
630
|
+
"command": "root=\"$(git rev-parse --show-toplevel 2>/dev/null || pwd)\"; cd \"$root\" && bash \"$root/.codex/hooks/devrites-cursor.sh\""
|
|
631
|
+
}
|
|
632
|
+
]
|
|
633
|
+
}
|
|
634
|
+
],
|
|
635
|
+
"SubagentStart": [
|
|
636
|
+
{
|
|
637
|
+
"matcher": "devrites-slice-wright",
|
|
638
|
+
"hooks": [
|
|
639
|
+
{
|
|
640
|
+
"type": "command",
|
|
641
|
+
"command": "printf '%s\\n' 'DevRites: this subagent is the single write-capable slice-wright. Stay within the current slice contract and touched-files.md; write no .devrites bookkeeping.'"
|
|
642
|
+
}
|
|
643
|
+
]
|
|
644
|
+
},
|
|
645
|
+
{
|
|
646
|
+
"matcher": "devrites-(code|test|frontend|security|performance|devex|doubt|simplifier|strategy|plan|spec)-reviewer|devrites-retrospector|devrites-forge-judge",
|
|
647
|
+
"hooks": [
|
|
648
|
+
{
|
|
649
|
+
"type": "command",
|
|
650
|
+
"command": "printf '%s\\n' 'DevRites: this subagent is read-only. Inspect with read/search/test commands and return findings only; do not mutate the tree.'"
|
|
651
|
+
}
|
|
652
|
+
]
|
|
653
|
+
}
|
|
654
|
+
],
|
|
655
|
+
"SubagentStop": [
|
|
656
|
+
{
|
|
657
|
+
"matcher": "devrites-slice-wright|devrites-.*reviewer|devrites-retrospector|devrites-forge-judge",
|
|
658
|
+
"hooks": [
|
|
659
|
+
{
|
|
660
|
+
"type": "command",
|
|
661
|
+
"command": "printf '%s\\n' 'DevRites: reconcile this subagent result against the active DevRites skill contract before claiming completion.'"
|
|
662
|
+
}
|
|
663
|
+
]
|
|
664
|
+
}
|
|
665
|
+
],
|
|
666
|
+
"SessionStart": [
|
|
667
|
+
{
|
|
668
|
+
"matcher": "startup|resume|clear|compact",
|
|
669
|
+
"hooks": [
|
|
670
|
+
{
|
|
671
|
+
"type": "command",
|
|
672
|
+
"command": "root=\"$(git rev-parse --show-toplevel 2>/dev/null || pwd)\"; cd \"$root\" && bash \"$root/.codex/hooks/devrites-orient.sh\"",
|
|
673
|
+
"statusMessage": "DevRites: loading project orientation"
|
|
674
|
+
}
|
|
675
|
+
]
|
|
676
|
+
}
|
|
677
|
+
]
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
EOF
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
install_codex_hooks_json() {
|
|
684
|
+
_src="$1"
|
|
685
|
+
_rel=".codex/hooks.json"
|
|
686
|
+
_dest="$TARGET/$_rel"
|
|
687
|
+
_marker=".claude/devrites.codex-hooks-merge"
|
|
688
|
+
|
|
689
|
+
if [ -e "$_dest" ]; then
|
|
690
|
+
if [ "$DRYRUN" -eq 1 ]; then
|
|
691
|
+
if grep -q 'devrites-' "$_dest" 2>/dev/null; then
|
|
692
|
+
dr_say " [merge] .codex/hooks.json ${DR_Y}(refresh DevRites hooks)${DR_R}"
|
|
693
|
+
else
|
|
694
|
+
dr_say " [merge] .codex/hooks.json ${DR_Y}(append DevRites hooks)${DR_R}"
|
|
695
|
+
fi
|
|
696
|
+
else
|
|
697
|
+
command -v node >/dev/null 2>&1 || dr_die "node is required to merge existing .codex/hooks.json"
|
|
698
|
+
_merged="$TMP_GEN_DIR/codex-hooks.merged.json"
|
|
699
|
+
node "$SELF_DIR/scripts/merge-codex-hooks.mjs" merge "$_dest" "$_src" "$_merged" || dr_die "cannot merge .codex/hooks.json"
|
|
700
|
+
cp "$_merged" "$_dest" || dr_die "cannot write $_dest"
|
|
701
|
+
fi
|
|
702
|
+
install_marker_file "$_marker" ".codex/hooks.json contains DevRites managed hook entries."
|
|
703
|
+
return 0
|
|
704
|
+
fi
|
|
705
|
+
|
|
706
|
+
if [ "$DRYRUN" -eq 1 ]; then
|
|
707
|
+
dr_say " [merge] .codex/hooks.json ${DR_Y}(create DevRites hooks)${DR_R}"
|
|
708
|
+
else
|
|
709
|
+
mkdir -p "$(dirname "$_dest")" || dr_die "cannot create $(dirname "$_dest")"
|
|
710
|
+
cp "$_src" "$_dest" || dr_die "cannot write $_dest"
|
|
711
|
+
fi
|
|
712
|
+
install_marker_file "$_marker" ".codex/hooks.json contains DevRites managed hook entries."
|
|
713
|
+
}
|
|
714
|
+
|
|
213
715
|
# ---- plan + execute ------------------------------------------------------
|
|
214
716
|
dr_info "DevRites installer"
|
|
215
717
|
dr_say " source : $SELF_DIR"
|
|
@@ -217,6 +719,7 @@ dr_say " target : $TARGET"
|
|
|
217
719
|
dr_say " skills : $([ "$WITH_SKILLS" -eq 1 ] && echo yes || echo no)"
|
|
218
720
|
dr_say " rules : $([ "$WITH_RULES" -eq 1 ] && echo 'DevRites engineering rules' || echo 'skipped')"
|
|
219
721
|
dr_say " agents : $([ "$WITH_AGENTS" -eq 1 ] && echo yes || echo no)"
|
|
722
|
+
dr_say " codex : $([ "$WITH_CODEX" -eq 1 ] && echo yes || echo no)"
|
|
220
723
|
dr_say " aliases: $ALIAS_MODE"
|
|
221
724
|
[ "$DRYRUN" -eq 1 ] && dr_info " (dry run — no changes will be made)"
|
|
222
725
|
dr_say ""
|
|
@@ -228,6 +731,7 @@ if [ "$WITH_SKILLS" -eq 1 ]; then
|
|
|
228
731
|
while IFS= read -r d; do
|
|
229
732
|
name="$(basename "$d")"
|
|
230
733
|
install_tree "$d" ".claude/skills/$name"
|
|
734
|
+
[ "$WITH_CODEX" -eq 1 ] && install_codex_skill_tree "$d" ".agents/skills/$name"
|
|
231
735
|
done < <(find "$PACK_SRC/skills" -mindepth 1 -maxdepth 1 -type d)
|
|
232
736
|
fi
|
|
233
737
|
|
|
@@ -237,17 +741,41 @@ if [ "$WITH_SKILLS" -eq 1 ] && [ "$ALIAS_MODE" = "all" ]; then
|
|
|
237
741
|
a="${pair%%:*}"; to="${pair#*:}"
|
|
238
742
|
gen_alias_wrapper "$a" "$to" "$TMP_GEN_DIR/$a.md"
|
|
239
743
|
install_file "$TMP_GEN_DIR/$a.md" ".claude/skills/$a/SKILL.md"
|
|
744
|
+
[ "$WITH_CODEX" -eq 1 ] && install_file "$TMP_GEN_DIR/$a.md" ".agents/skills/$a/SKILL.md"
|
|
240
745
|
done
|
|
241
746
|
fi
|
|
242
747
|
|
|
243
748
|
# 3) agents
|
|
244
749
|
if [ "$WITH_AGENTS" -eq 1 ]; then
|
|
245
750
|
install_tree "$PACK_SRC/agents" ".claude/agents"
|
|
751
|
+
if [ "$WITH_CODEX" -eq 1 ]; then
|
|
752
|
+
mkdir -p "$TMP_GEN_DIR/codex-agents"
|
|
753
|
+
while IFS= read -r f; do
|
|
754
|
+
name="$(basename "$f" .md)"
|
|
755
|
+
gen_codex_agent "$f" "$TMP_GEN_DIR/codex-agents/$name.toml"
|
|
756
|
+
install_file "$TMP_GEN_DIR/codex-agents/$name.toml" ".codex/agents/$name.toml"
|
|
757
|
+
done < <(find "$PACK_SRC/agents" -maxdepth 1 -type f -name '*.md')
|
|
758
|
+
fi
|
|
759
|
+
fi
|
|
760
|
+
|
|
761
|
+
# 3b) Codex project instructions. Codex discovers repository guidance from
|
|
762
|
+
# AGENTS.md, so install or merge a small bridge when skills are installed.
|
|
763
|
+
if [ "$WITH_CODEX" -eq 1 ] && [ "$WITH_SKILLS" -eq 1 ]; then
|
|
764
|
+
CODEX_AGENTS_MD="$TMP_GEN_DIR/AGENTS.md"
|
|
765
|
+
gen_codex_agents_bridge "$CODEX_AGENTS_MD"
|
|
766
|
+
install_codex_agents_md "$CODEX_AGENTS_MD"
|
|
767
|
+
if [ -f "$SELF_DIR/mcp/devrites-mcp.mjs" ]; then
|
|
768
|
+
install_file "$SELF_DIR/mcp/devrites-mcp.mjs" ".codex/mcp/devrites-mcp.mjs"
|
|
769
|
+
CODEX_CONFIG_TOML="$TMP_GEN_DIR/codex-config.toml"
|
|
770
|
+
gen_codex_config_block "$CODEX_CONFIG_TOML"
|
|
771
|
+
install_codex_config_toml "$CODEX_CONFIG_TOML"
|
|
772
|
+
fi
|
|
246
773
|
fi
|
|
247
774
|
|
|
248
775
|
# 4) DevRites engineering rules
|
|
249
776
|
if [ "$WITH_RULES" -eq 1 ]; then
|
|
250
777
|
install_tree "$PACK_SRC/rules" ".claude/rules"
|
|
778
|
+
[ "$WITH_CODEX" -eq 1 ] && install_tree "$PACK_SRC/rules" ".agents/devrites/rules"
|
|
251
779
|
fi
|
|
252
780
|
|
|
253
781
|
# 4b) hooks — auto-approve the read-only orientation/gate scripts (no per-run permission
|
|
@@ -256,6 +784,12 @@ fi
|
|
|
256
784
|
# manifest, so it is preserved on uninstall/update and the user's own settings stay safe.
|
|
257
785
|
if [ "$WITH_SKILLS" -eq 1 ] && [ -d "$PACK_SRC/hooks" ]; then
|
|
258
786
|
install_tree "$PACK_SRC/hooks" ".claude/hooks"
|
|
787
|
+
if [ "$WITH_CODEX" -eq 1 ]; then
|
|
788
|
+
install_tree "$PACK_SRC/hooks" ".codex/hooks"
|
|
789
|
+
CODEX_HOOKS_JSON="$TMP_GEN_DIR/codex-hooks.json"
|
|
790
|
+
gen_codex_hooks_json "$CODEX_HOOKS_JSON"
|
|
791
|
+
install_codex_hooks_json "$CODEX_HOOKS_JSON"
|
|
792
|
+
fi
|
|
259
793
|
if [ ! -e "$TARGET/.claude/settings.json" ]; then
|
|
260
794
|
if [ "$DRYRUN" -eq 1 ]; then
|
|
261
795
|
dr_say " [seed] .claude/settings.json ${DR_Y}(DevRites hooks — preserved on uninstall/update)${DR_R}"
|
|
@@ -318,6 +852,7 @@ fi
|
|
|
318
852
|
DR_INSTALL_FLAGS=""
|
|
319
853
|
[ "$WITH_SKILLS" -eq 0 ] && DR_INSTALL_FLAGS="$DR_INSTALL_FLAGS --no-skills"
|
|
320
854
|
[ "$WITH_AGENTS" -eq 0 ] && DR_INSTALL_FLAGS="$DR_INSTALL_FLAGS --no-agents"
|
|
855
|
+
[ "$WITH_CODEX" -eq 0 ] && DR_INSTALL_FLAGS="$DR_INSTALL_FLAGS --no-codex"
|
|
321
856
|
[ "$WITH_RULES" -eq 0 ] && DR_INSTALL_FLAGS="$DR_INSTALL_FLAGS --no-rules"
|
|
322
857
|
case "$ALIAS_MODE" in
|
|
323
858
|
off) DR_INSTALL_FLAGS="$DR_INSTALL_FLAGS --no-short-aliases" ;;
|
|
@@ -335,14 +870,26 @@ if [ -f "$PREV_MANIFEST" ]; then
|
|
|
335
870
|
while IFS= read -r _rel; do
|
|
336
871
|
case "$_rel" in ''|\#*) continue ;; esac # skip comments + blank lines
|
|
337
872
|
case "$_rel" in .devrites/*) continue ;; esac # never touch runtime state
|
|
873
|
+
case "$_rel" in AGENTS.md|.codex/config.toml|.codex/hooks.json) continue ;; esac
|
|
338
874
|
grep -Fxq -- "$_rel" "$MANIFEST_TMP" && continue # still shipped → keep
|
|
339
875
|
_dead="$TARGET/$_rel"
|
|
340
876
|
[ -e "$_dead" ] || continue # already gone
|
|
341
877
|
if [ "$DRYRUN" -eq 1 ]; then
|
|
342
878
|
dr_say " [prune] $_rel ${DR_Y}(dropped from pack)${DR_R}"
|
|
343
879
|
else
|
|
880
|
+
case "$_rel" in
|
|
881
|
+
.claude/devrites.agents-merge)
|
|
882
|
+
strip_codex_agents_md_block "$TARGET/AGENTS.md"
|
|
883
|
+
;;
|
|
884
|
+
.claude/devrites.codex-config-merge)
|
|
885
|
+
strip_codex_config_block "$TARGET/.codex/config.toml"
|
|
886
|
+
;;
|
|
887
|
+
.claude/devrites.codex-hooks-merge)
|
|
888
|
+
strip_codex_hooks_entries "$TARGET/.codex/hooks.json"
|
|
889
|
+
;;
|
|
890
|
+
esac
|
|
344
891
|
rm -f "$_dead"
|
|
345
|
-
# tidy now-empty parent dirs, bounded strictly below
|
|
892
|
+
# tidy now-empty parent dirs, bounded strictly below the target
|
|
346
893
|
_d="$(dirname "$_dead")"
|
|
347
894
|
while [ "$_d" != "$TARGET/.claude" ] && [ "$_d" != "$TARGET" ] && [ "$_d" != "/" ]; do
|
|
348
895
|
rmdir "$_d" 2>/dev/null || break
|
|
@@ -376,11 +923,13 @@ dr_say "${DR_B}Utilities:${DR_R} /rite-pressure-test /rite-zoom-out /rite-prot
|
|
|
376
923
|
if [ "$ALIAS_MODE" = "all" ]; then
|
|
377
924
|
dr_say "${DR_B}Aliases:${DR_R} /define /build /prove /seal"
|
|
378
925
|
fi
|
|
379
|
-
[ "$WITH_RULES" -eq 1 ] && dr_say "${DR_B}Rules:${DR_R} engineering rules installed to .claude/rules/"
|
|
926
|
+
[ "$WITH_RULES" -eq 1 ] && dr_say "${DR_B}Rules:${DR_R} engineering rules installed to .claude/rules/$([ "$WITH_CODEX" -eq 1 ] && echo ' and mirrored to .agents/devrites/rules/')"
|
|
927
|
+
[ "$WITH_CODEX" -eq 1 ] && [ "$WITH_SKILLS" -eq 1 ] && dr_say "${DR_B}Codex:${DR_R} skills mirrored to .agents/skills/; project guidance in AGENTS.md"
|
|
380
928
|
dr_say ""
|
|
381
929
|
dr_say "${DR_B}Next:${DR_R}"
|
|
382
|
-
dr_say " 1. Open the project in Claude Code and accept the workspace trust prompt."
|
|
383
|
-
dr_say " 2.
|
|
930
|
+
dr_say " 1. Open the project in Claude Code or Codex and accept the workspace trust prompt."
|
|
931
|
+
dr_say " 2. Claude Code: run ${DR_C}/rite${DR_R} for the menu, or ${DR_C}/rite-spec <feature>${DR_R} to start."
|
|
932
|
+
[ "$WITH_CODEX" -eq 1 ] && [ "$WITH_SKILLS" -eq 1 ] && dr_say " Codex: use ${DR_C}\$rite${DR_R} / ${DR_C}\$rite-spec${DR_R} through skills, or pick DevRites from ${DR_C}/skills${DR_R}."
|
|
384
933
|
dr_say " 3. ${DR_B}HITL by default${DR_R} — HITL slices pause at typed gates; resume with ${DR_C}/rite-resolve <qid> \"<answer>\"${DR_R}."
|
|
385
934
|
dr_say " For unattended runs: ${DR_C}touch .devrites/AFK${DR_R} (see .claude/rules/afk-hitl.md for the contract)."
|
|
386
935
|
[ "$N_SKIP" -gt 0 ] && dr_say " • $N_SKIP file(s) were skipped (already present). Re-run with --force to overwrite."
|