repo-nexus 0.7.30 → 0.7.32

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/lib/ai.sh CHANGED
@@ -1,10 +1,10 @@
1
1
  #!/bin/sh
2
2
  # shellcheck shell=sh
3
3
  # ============================================================================
4
- # lib/ai.sh — AI Instructions, workspace context, and AI provider synchronization
4
+ # lib/ai.sh — Workspace AI context, .gitignore/.ignore, and skill orchestration
5
5
  # ============================================================================
6
6
 
7
- # ---- AI Instructions Management (Routing-Only) ----------------------------
7
+ # ---- Gitignore & Search Tool Ignore Reconciliation -------------------------
8
8
 
9
9
  reconcile_gitignore() {
10
10
  _dir="${1:-$NEXUS_DIR}"
@@ -31,7 +31,7 @@ GI_EOF
31
31
  log_ok "Removed legacy lint trigger counter entries from .gitignore"
32
32
  fi
33
33
 
34
- # 2. Strip legacy .rnex/ entries if present (.rnex/ contains tracked prompts, plugins, and hooks)
34
+ # 2. Strip legacy .rnex/ entries if present (.rnex/ contains tracked plugins, skills, and hooks)
35
35
  if grep -qE '^[ ]*#?[ ]*Repo Nexus internal state' "$_gi" 2>/dev/null || grep -qE '^\.rnex/?$' "$_gi" 2>/dev/null; then
36
36
  _tmp="$(mktemp)"
37
37
  grep -vE '(^[ ]*#?[ ]*Repo Nexus internal state|^\.rnex/?$)' "$_gi" > "$_tmp" && mv "$_tmp" "$_gi"
@@ -54,28 +54,12 @@ GI_EOF
54
54
  fi
55
55
 
56
56
  # Universal search tool ignore file (ripgrep, Claude Code, VS Code, Zed)
57
- # Un-ignores member repositories for search tools while Git continues to ignore them
58
- _ign="$_dir/.ignore"
59
- if [ ! -f "$_ign" ]; then
60
- cat > "$_ign" <<IGN_EOF
61
- # Member repos (un-ignored for ripgrep, Claude Code, VS Code, and search tools)
62
- !repos/*
63
- IGN_EOF
64
- log_ok "Created .ignore (un-ignoring member repos for search tools)"
65
- elif ! grep -q '!repos/\*' "$_ign" 2>/dev/null; then
66
- printf '\n# Member repos (un-ignored for search tools)\n!repos/*\n' >> "$_ign"
67
- log_dim "Added !repos/* to .ignore"
68
- fi
57
+ ensure_provider_ignore "$_dir/.ignore" \
58
+ "Member repos (un-ignored for ripgrep, Claude Code, VS Code, and search tools)" \
59
+ "Created .ignore (un-ignoring member repos for search tools)"
69
60
  }
70
61
 
71
- # ---- AI Instructions Management (Routing-Only) ----------------------------
72
-
73
- AI_MARKER_START="<!-- REPO-NEXUS:START -->"
74
- AI_MARKER_END="<!-- REPO-NEXUS:END -->"
75
-
76
- get_rnex_instructions() {
77
- printf "CRITICAL: You MUST read and strictly follow all instructions in \`.rnex/ai-instructions.md\` before executing any task or answering any query in this workspace.\n"
78
- }
62
+ # ---- AI Instructions Compilation (.rnex/ai-instructions.md) ----------------
79
63
 
80
64
  build_ai_instructions() {
81
65
  _dir="${1:-$NEXUS_DIR}"
@@ -165,135 +149,7 @@ BASE_AI_EOF
165
149
  mv "$_out_tmp" "$_ai_file"
166
150
  }
167
151
 
168
- merge_rnex_instructions() {
169
- _dst="$1"
170
- _body_tmp="$(mktemp)"
171
- get_rnex_instructions > "$_body_tmp"
172
-
173
- if [ ! -f "$_dst" ]; then
174
- mkdir -p "$(dirname "$_dst")"
175
- {
176
- printf '%s\n' "$AI_MARKER_START"
177
- cat "$_body_tmp"
178
- printf '%s\n' "$AI_MARKER_END"
179
- } > "$_dst"
180
- rm -f "$_body_tmp"
181
- log_ok "Created $(basename "$_dst") with Repo Nexus routing instructions"
182
- return 0
183
- fi
184
-
185
- if grep -q "CRITICAL: You MUST read and strictly follow all instructions in \`.rnex/ai-instructions.md\`" "$_dst" 2>/dev/null && ! grep -qF "$AI_MARKER_START" "$_dst" 2>/dev/null; then
186
- {
187
- printf '%s\n' "$AI_MARKER_START"
188
- cat "$_body_tmp"
189
- printf '%s\n' "$AI_MARKER_END"
190
- } > "$_dst"
191
- rm -f "$_body_tmp"
192
- return 0
193
- fi
194
-
195
- # Case 1: If delimiters already exist, update the block in-place
196
- if grep -qF "$AI_MARKER_START" "$_dst" 2>/dev/null; then
197
- _tmp="$(mktemp)"
198
- awk -v s="$AI_MARKER_START" -v e="$AI_MARKER_END" -v src="$_body_tmp" '
199
- $0 == s {
200
- in_b = 1
201
- print s
202
- while ((getline line < src) > 0) print line
203
- close(src)
204
- next
205
- }
206
- $0 == e {
207
- in_b = 0
208
- print e
209
- next
210
- }
211
- !in_b { print }
212
- ' "$_dst" > "$_tmp" && mv "$_tmp" "$_dst"
213
- rm -f "$_body_tmp"
214
- log_ok "Updated Repo Nexus routing instructions in $(basename "$_dst")"
215
- return 0
216
- fi
217
-
218
- # Case 2: If no delimiters, check for legacy un-delimited Repo Nexus block
219
- # (e.g. starting with "# Multi-Repo AI Workspace Context" or containing "Symlink Write-Through")
220
- if grep -q "Multi-Repo AI Workspace Context" "$_dst" 2>/dev/null || grep -q "Symlink Write-Through" "$_dst" 2>/dev/null; then
221
- _tmp="$(mktemp)"
222
- awk -v s="$AI_MARKER_START" -v e="$AI_MARKER_END" -v src="$_body_tmp" '
223
- BEGIN { in_legacy = 0; replaced = 0 }
224
- /^# Multi-Repo AI Workspace Context/ {
225
- in_legacy = 1
226
- if (!replaced) {
227
- print s
228
- while ((getline line < src) > 0) print line
229
- close(src)
230
- print e
231
- replaced = 1
232
- }
233
- next
234
- }
235
- in_legacy {
236
- if (/^# [^#]/ && !/^# Multi-Repo/) {
237
- in_legacy = 0
238
- print
239
- next
240
- }
241
- next
242
- }
243
- !in_legacy { print }
244
- END {
245
- if (!replaced) {
246
- print s
247
- while ((getline line < src) > 0) print line
248
- close(src)
249
- print e
250
- }
251
- }
252
- ' "$_dst" > "$_tmp" && mv "$_tmp" "$_dst"
253
- rm -f "$_body_tmp"
254
- log_ok "Upgraded legacy instructions to Repo Nexus routing block in $(basename "$_dst")"
255
- return 0
256
- fi
257
-
258
- # Case 3: Completely custom instructions file without rnex context — append delimited block
259
- _tmp="$(mktemp)"
260
- cp "$_dst" "$_tmp"
261
- if [ -s "$_tmp" ] && [ -n "$(tail -c 1 "$_tmp" 2>/dev/null)" ]; then
262
- printf '\n' >> "$_tmp"
263
- fi
264
- {
265
- printf '\n%s\n' "$AI_MARKER_START"
266
- cat "$_body_tmp"
267
- printf '\n%s\n' "$AI_MARKER_END"
268
- } >> "$_tmp"
269
- mv "$_tmp" "$_dst"
270
- rm -f "$_body_tmp"
271
- log_ok "Merged Repo Nexus routing instructions with existing $(basename "$_dst")"
272
- }
273
-
274
- clean_rnex_instructions() {
275
- _dst="$1"
276
- [ -f "$_dst" ] || return 0
277
- if grep -qF "$AI_MARKER_START" "$_dst" 2>/dev/null; then
278
- _non_rnex="$(awk -v s="$AI_MARKER_START" -v e="$AI_MARKER_END" '
279
- $0 == s { skip=1; next }
280
- $0 == e { skip=0; next }
281
- !skip { print }
282
- ' "$_dst" | tr -d " \t\r\n")"
283
- if [ -z "$_non_rnex" ]; then
284
- rm -f "$_dst"
285
- log_ok "Removed $(basename "$_dst")"
286
- else
287
- _tmp="$(mktemp)"
288
- awk -v s="$AI_MARKER_START" -v e="$AI_MARKER_END" '
289
- $0 == s { skip=1; next }
290
- $0 == e { skip=0; next }
291
- !skip { print }
292
- ' "$_dst" > "$_tmp" && mv "$_tmp" "$_dst"
293
- log_ok "Removed Repo Nexus routing instructions from $(basename "$_dst")"
294
- fi
295
- fi
296
- }
152
+ # ---- Multi-Root IDE Workspace (.code-workspace) ----------------------------
297
153
 
298
154
  sync_code_workspace() {
299
155
  [ -n "$CODE_WORKSPACE_FILE" ] || return 0
@@ -363,27 +219,28 @@ sync_code_workspace() {
363
219
  fi
364
220
  }
365
221
 
366
- # ---- Provider Skill Directory & User Skill Generator API -------------------
222
+ # ---- Provider Skill Directory & Base Asset Synchronization -----------------
367
223
 
368
224
  write_rnex_env_script() {
369
225
  _dir="${1:-$NEXUS_DIR}"
370
226
  _bin_dir="$_dir/.rnex/bin"
371
227
  mkdir -p "$_bin_dir"
372
228
  _env_script="$_bin_dir/rnex-env.sh"
373
- _tmpl_env=""
229
+ _src_sdk=""
374
230
  for _cand in \
231
+ "${RNEX_LIB_DIR:-}/sdk.sh" \
232
+ "$SCRIPT_LOCATION/lib/sdk.sh" \
233
+ "$(dirname "$SCRIPT_LOCATION")/lib/sdk.sh" \
234
+ "$_dir/lib/sdk.sh" \
375
235
  "$_dir/templates/rnex-env.sh" \
376
- "$SCRIPT_LOCATION/templates/rnex-env.sh" \
377
- "$(dirname "$SCRIPT_LOCATION")/templates/rnex-env.sh" \
378
- "${RNEX_LIB_DIR:-}/../templates/rnex-env.sh" \
379
- "./templates/rnex-env.sh"; do
380
- if [ -f "$_cand" ]; then
381
- _tmpl_env="$_cand"
236
+ "$SCRIPT_LOCATION/templates/rnex-env.sh"; do
237
+ if [ -n "$_cand" ] && [ -f "$_cand" ]; then
238
+ _src_sdk="$_cand"
382
239
  break
383
240
  fi
384
241
  done
385
- if [ -n "$_tmpl_env" ]; then
386
- cp "$_tmpl_env" "$_env_script"
242
+ if [ -n "$_src_sdk" ]; then
243
+ cp "$_src_sdk" "$_env_script"
387
244
  fi
388
245
  chmod +x "$_env_script" 2>/dev/null || true
389
246
  }
@@ -419,172 +276,6 @@ get_active_provider_skill_dirs() {
419
276
  printf '%s' "$_dirs"
420
277
  }
421
278
 
422
- _tmpl_env=""
423
- for _cand in \
424
- "$SCRIPT_LOCATION/templates/rnex-env.sh" \
425
- "$(dirname "$SCRIPT_LOCATION")/templates/rnex-env.sh" \
426
- "${RNEX_LIB_DIR:-}/../templates/rnex-env.sh" \
427
- "./templates/rnex-env.sh"; do
428
- if [ -f "$_cand" ]; then
429
- _tmpl_env="$_cand"
430
- break
431
- fi
432
- done
433
- if [ -n "$_tmpl_env" ]; then
434
- # shellcheck source=/dev/null
435
- . "$_tmpl_env"
436
- fi
437
-
438
- clean_provider_user_skills() {
439
- _sk_dir="$1"
440
- [ -d "$_sk_dir" ] || return 0
441
- rm -f "$_sk_dir"/rnex-*.md 2>/dev/null || true
442
- for _d in "$_sk_dir"/rnex-*; do
443
- [ -d "$_d" ] || continue
444
- rm -rf "$_d" 2>/dev/null || true
445
- done
446
- rmdir "$_sk_dir" 2>/dev/null || true
447
- }
448
-
449
- clean_plugin_user_skills() {
450
- _pdir="$1"
451
- [ -d "$_pdir" ] || return 0
452
- _pname="$(basename "$_pdir")"
453
- if [ -d "$_pdir/skills" ]; then
454
- for _sk_file in "$_pdir/skills"/*.md; do
455
- [ -f "$_sk_file" ] || continue
456
- _sk_name="$(basename "$_sk_file" .md)"
457
- rnex_unregister_user_skill "$_sk_name" "$_pname"
458
- rnex_unregister_user_skill "$_sk_name"
459
- done
460
- fi
461
- }
462
-
463
- clean_provider_ignore() {
464
- _file="$1"
465
- [ -f "$_file" ] || return 0
466
- if grep -q '!repos/\*' "$_file" 2>/dev/null; then
467
- _non_rnex="$(grep -vE '^[ ]*#.*(Cursor|Gemini|Repo Nexus|member repos)' "$_file" 2>/dev/null | grep -v '^!repos/\*' | tr -d " \t\r\n")"
468
- if [ -z "$_non_rnex" ]; then
469
- rm -f "$_file"
470
- log_ok "Removed $(basename "$_file")"
471
- else
472
- _tmp="$(mktemp)"
473
- grep -vE '(^[ ]*#.*(Cursor|Gemini|Repo Nexus|member repos)|!repos/\*)' "$_file" > "$_tmp" && mv "$_tmp" "$_file"
474
- log_ok "Removed !repos/* un-ignore from $(basename "$_file")"
475
- fi
476
- fi
477
- }
478
-
479
- clean_provider_agents() {
480
- _ag_dir="$1"
481
- _ext="${2:-.md}"
482
- [ -d "$_ag_dir" ] || return 0
483
-
484
- for _pdir in "$SCRIPT_LOCATION/toolkit/plugins"/* "$NEXUS_DIR/toolkit/plugins"/* "$NEXUS_DIR/.rnex/plugins"/*; do
485
- [ -d "$_pdir" ] || continue
486
- [ -d "$_pdir/agents" ] || continue
487
- for _afile in "$_pdir/agents"/*.md; do
488
- [ -f "$_afile" ] || continue
489
- _aname="$(basename "$_afile" .agent.md)"
490
- _aname="$(basename "$_aname" .md)"
491
- rm -f "$_ag_dir/${_aname}${_ext}" 2>/dev/null || true
492
- done
493
- done
494
-
495
- rmdir "$_ag_dir" 2>/dev/null || true
496
- }
497
-
498
- clean_claude_auto_sync_hook() {
499
- _settings="$1"
500
- [ -f "$_settings" ] || return 0
501
- if grep -q "auto-sync.sh" "$_settings" 2>/dev/null; then
502
- _tmp="$(mktemp)"
503
- awk '
504
- /\{[ \t]*"command"[ \t]*:[ \t]*"\.rnex\/bin\/auto-sync\.sh"[ \t]*\}/ { next }
505
- /"command"[ \t]*:[ \t]*"\.rnex\/bin\/auto-sync\.sh"/ { next }
506
- { print }
507
- ' "$_settings" > "$_tmp"
508
- _clean="$(sed -e 's/"hooks"//g' -e 's/"SessionStart"//g' < "$_tmp" | tr -d ' \t\r\n[]{}:,"')"
509
- if [ -z "$_clean" ]; then
510
- rm -f "$_tmp" "$_settings"
511
- else
512
- awk '
513
- { lines[NR] = $0 }
514
- END {
515
- for (i = 1; i <= NR; i++) {
516
- if (i < NR && lines[i] ~ /,[ \t]*$/) {
517
- next_is_bracket = 0
518
- for (j = i + 1; j <= NR; j++) {
519
- if (lines[j] ~ /^[ \t]*$/) continue
520
- if (lines[j] ~ /^[ \t]*[\]\}]/) next_is_bracket = 1
521
- break
522
- }
523
- if (next_is_bracket) {
524
- sub(/,[ \t]*$/, "", lines[i])
525
- }
526
- }
527
- print lines[i]
528
- }
529
- }
530
- ' "$_tmp" > "$_settings"
531
- rm -f "$_tmp"
532
- fi
533
- fi
534
- }
535
-
536
- clean_agents_auto_sync_hook() {
537
- _hooks="$1"
538
- [ -f "$_hooks" ] || return 0
539
- if grep -q '"rnex-auto-sync"' "$_hooks" 2>/dev/null; then
540
- _tmp="$(mktemp)"
541
- awk '
542
- BEGIN { skip=0; depth=0 }
543
- /"rnex-auto-sync"[ \t]*:[ \t]*\{/ { skip=1; depth=1; next }
544
- skip {
545
- for (i=1; i<=length($0); i++) {
546
- c = substr($0, i, 1)
547
- if (c == "{") depth++
548
- if (c == "}") {
549
- depth--
550
- if (depth == 0) {
551
- skip = 0
552
- next
553
- }
554
- }
555
- }
556
- next
557
- }
558
- { print }
559
- ' "$_hooks" > "$_tmp"
560
- _clean="$(tr -d " \t\r\n{}" < "$_tmp")"
561
- if [ -z "$_clean" ]; then
562
- rm -f "$_tmp" "$_hooks"
563
- else
564
- awk '
565
- { lines[NR] = $0 }
566
- END {
567
- for (i = 1; i <= NR; i++) {
568
- if (i < NR && lines[i] ~ /,[ \t]*$/) {
569
- next_is_brace = 0
570
- for (j = i + 1; j <= NR; j++) {
571
- if (lines[j] ~ /^[ \t]*$/) continue
572
- if (lines[j] ~ /^[ \t]*\}/) next_is_brace = 1
573
- break
574
- }
575
- if (next_is_brace) {
576
- sub(/,[ \t]*$/, "", lines[i])
577
- }
578
- }
579
- print lines[i]
580
- }
581
- }
582
- ' "$_tmp" > "$_hooks"
583
- rm -f "$_tmp"
584
- fi
585
- fi
586
- }
587
-
588
279
  sync_rnex_base_assets() {
589
280
  _src_toolkit=""
590
281
  if [ -d "$SCRIPT_LOCATION/toolkit" ]; then
@@ -636,52 +327,7 @@ sync_rnex_base_assets() {
636
327
  done
637
328
  }
638
329
 
639
- sync_claude() {
640
- if yaml_plugin_enabled "claude" 2>/dev/null; then
641
- run_plugin_hook "claude" "after_sync"
642
- else
643
- run_plugin_hook "claude" "before_plugin_disable"
644
- fi
645
- }
646
-
647
- sync_gemini() {
648
- if yaml_plugin_enabled "gemini" 2>/dev/null; then
649
- run_plugin_hook "gemini" "after_sync"
650
- else
651
- run_plugin_hook "gemini" "before_plugin_disable"
652
- fi
653
- }
654
-
655
- sync_cursor() {
656
- if yaml_plugin_enabled "cursor" 2>/dev/null; then
657
- run_plugin_hook "cursor" "after_sync"
658
- else
659
- run_plugin_hook "cursor" "before_plugin_disable"
660
- fi
661
- }
662
-
663
- sync_windsurf() {
664
- if yaml_plugin_enabled "windsurf" 2>/dev/null; then
665
- run_plugin_hook "windsurf" "after_sync"
666
- else
667
- run_plugin_hook "windsurf" "before_plugin_disable"
668
- fi
669
- }
670
-
671
- sync_copilot() {
672
- if yaml_plugin_enabled "copilot" 2>/dev/null; then
673
- run_plugin_hook "copilot" "after_sync"
674
- else
675
- run_plugin_hook "copilot" "before_plugin_disable"
676
- fi
677
- }
678
-
679
- sync_ai_providers() {
680
- :
681
- }
682
-
683
330
  sync_skills() {
684
331
  write_rnex_env_script "$NEXUS_DIR"
685
332
  sync_rnex_base_assets
686
333
  }
687
-
@@ -238,7 +238,6 @@ YAML_EOF
238
238
  fi
239
239
 
240
240
  _write_auto_sync_script "$_init_dir"
241
- _sync_ai_session_start_hooks "$_init_dir"
242
241
  update_sync_stamp "$_init_dir"
243
242
 
244
243
  NEXUS_DIR="$_init_dir"
@@ -32,11 +32,6 @@ EOF
32
32
  chmod +x "$_script"
33
33
  }
34
34
 
35
- _sync_ai_session_start_hooks() {
36
- # Claude and other providers manage their own session start hooks in hooks/after_sync.sh
37
- :
38
- }
39
-
40
35
  cmd_sync() {
41
36
  require_workspace
42
37
  ensure_repos_dir
@@ -88,9 +83,8 @@ cmd_sync() {
88
83
  merge_rnex_instructions "$NEXUS_DIR/AGENTS.md"
89
84
  fi
90
85
 
91
- # 1.3. Generate auto-sync script and AI session-start hooks (hardcoded harness)
86
+ # 1.3. Generate auto-sync script (hardcoded harness)
92
87
  _write_auto_sync_script "$NEXUS_DIR"
93
- _sync_ai_session_start_hooks "$NEXUS_DIR"
94
88
 
95
89
  # 1.4. Sync core agentic skills into .rnex/skills/ and write rnex-env.sh
96
90
  sync_skills
@@ -124,12 +118,7 @@ cmd_sync() {
124
118
  if [ "$_cur_hp" != ".rnex/hooks" ] && [ "$_cur_hp" != "$NEXUS_DIR/.rnex/hooks" ]; then
125
119
  cmd_hooks_install_dir "$NEXUS_DIR"
126
120
  elif [ "${_RNEX_INSIDE_HOOK:-0}" -ne 1 ]; then
127
- _hooks_dir="$NEXUS_DIR/.rnex/hooks"
128
- _create_hook_script "$_hooks_dir/post-merge" "post-merge"
129
- _create_hook_script "$_hooks_dir/post-checkout" "post-checkout"
130
- _create_hook_script "$_hooks_dir/post-commit" "post-commit"
131
- _create_hook_script "$_hooks_dir/pre-commit" "pre-commit"
132
- _create_hook_script "$_hooks_dir/pre-push" "pre-push"
121
+ _install_managed_hook_scripts "$NEXUS_DIR/.rnex/hooks"
133
122
  fi
134
123
  fi
135
124
  ;;
@@ -137,12 +126,7 @@ cmd_sync() {
137
126
  _cur_hp="$(git -C "$NEXUS_DIR" config --get core.hooksPath 2>/dev/null || true)"
138
127
  if [ "$_cur_hp" = ".rnex/hooks" ] || [ "$_cur_hp" = "$NEXUS_DIR/.rnex/hooks" ]; then
139
128
  if [ "${_RNEX_INSIDE_HOOK:-0}" -ne 1 ]; then
140
- _hooks_dir="$NEXUS_DIR/.rnex/hooks"
141
- _create_hook_script "$_hooks_dir/post-merge" "post-merge"
142
- _create_hook_script "$_hooks_dir/post-checkout" "post-checkout"
143
- _create_hook_script "$_hooks_dir/post-commit" "post-commit"
144
- _create_hook_script "$_hooks_dir/pre-commit" "pre-commit"
145
- _create_hook_script "$_hooks_dir/pre-push" "pre-push"
129
+ _install_managed_hook_scripts "$NEXUS_DIR/.rnex/hooks"
146
130
  fi
147
131
  fi
148
132
  ;;