repo-nexus 0.4.4 → 0.4.7

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.
@@ -23,6 +23,34 @@
23
23
 
24
24
  repos_dir: ./repos
25
25
 
26
+ # ------------------------------------------------------------------------------
27
+ # ai_instructions — Main AI instructions routing file
28
+ # ------------------------------------------------------------------------------
29
+ # Main instructions file created and managed by Repo Nexus.
30
+ # Default: AGENTS.md (recognized by modern AI coding assistants)
31
+ #
32
+ # Examples:
33
+ # ai_instructions: AGENTS.md # default standard
34
+ # ai_instructions: CLAUDE.md # for Anthropic Claude Code CLI
35
+ # ai_instructions: GEMINI.md # for Google Gemini / Antigravity CLI
36
+ #
37
+ ai_instructions: AGENTS.md
38
+
39
+ # ------------------------------------------------------------------------------
40
+ # code_workspace — VS Code / Cursor multi-root workspace file
41
+ # ------------------------------------------------------------------------------
42
+ # Automatically generates and maintains a multi-root .code-workspace file mapping
43
+ # the workspace root and all active member repository clones.
44
+ #
45
+ # Default: false
46
+ #
47
+ # Examples:
48
+ # code_workspace: false # disabled (default)
49
+ # code_workspace: true # generates <workspace-name>.code-workspace
50
+ # code_workspace: workspace.code-workspace # custom filename
51
+ #
52
+ code_workspace: false
53
+
26
54
  # ------------------------------------------------------------------------------
27
55
  # plugins — Workspace plugins and AI instruction packs
28
56
  # ------------------------------------------------------------------------------
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "repo-nexus",
3
- "version": "0.4.4",
3
+ "version": "0.4.7",
4
4
  "description": "Lightweight, zero-dependency Virtual Meta-Repo companion for multi-repo workspaces and shared AI context (no git submodules)",
5
5
  "bin": {
6
6
  "repo-nexus": "rnex",
package/rnex CHANGED
@@ -118,6 +118,8 @@ require_workspace() {
118
118
  WORKSPACE_YAML="$_cfg_path"
119
119
  _init_local_yaml
120
120
  _load_repos_dir
121
+ _load_ai_instructions_file
122
+ _load_code_workspace
121
123
  log_info "Using workspace at ${_BOLD}$NEXUS_DIR${_NC} ${_DIM}(via config: $WORKSPACE_YAML)${_NC}"
122
124
  return 0
123
125
  fi
@@ -144,6 +146,8 @@ require_workspace() {
144
146
  fi
145
147
  _init_local_yaml
146
148
  _load_repos_dir
149
+ _load_ai_instructions_file
150
+ _load_code_workspace
147
151
 
148
152
  log_info "Using workspace at ${_BOLD}$NEXUS_DIR${_NC} ${_DIM}($(basename "$WORKSPACE_YAML") found)${_NC}"
149
153
  }
@@ -161,10 +165,10 @@ _init_local_yaml() {
161
165
  _load_repos_dir() {
162
166
  _rd=""
163
167
  if [ -f "$WORKSPACE_LOCAL_YAML" ]; then
164
- _rd="$(awk '/^repos_dir:/ { sub(/^repos_dir:[ ]*/, ""); sub(/[ ]*#.*/, ""); print }' "$WORKSPACE_LOCAL_YAML")"
168
+ _rd="$(awk '/^repos_dir:/ { sub(/^repos_dir:[ ]*/, ""); sub(/[ ]*#.*/, ""); val=$0 } END { if (val) print val }' "$WORKSPACE_LOCAL_YAML")"
165
169
  fi
166
170
  if [ -z "$_rd" ] && [ -f "$WORKSPACE_YAML" ]; then
167
- _rd="$(awk '/^repos_dir:/ { sub(/^repos_dir:[ ]*/, ""); sub(/[ ]*#.*/, ""); print }' "$WORKSPACE_YAML")"
171
+ _rd="$(awk '/^repos_dir:/ { sub(/^repos_dir:[ ]*/, ""); sub(/[ ]*#.*/, ""); val=$0 } END { if (val) print val }' "$WORKSPACE_YAML")"
168
172
  fi
169
173
  _rd="${_rd:-./repos}"
170
174
  case "$_rd" in
@@ -173,6 +177,44 @@ _load_repos_dir() {
173
177
  esac
174
178
  }
175
179
 
180
+ _load_ai_instructions_file() {
181
+ _aif=""
182
+ if [ -f "$WORKSPACE_LOCAL_YAML" ]; then
183
+ _aif="$(awk '/^(ai_instructions|ai_instructions_file):/ { sub(/^[a-zA-Z0-9_]+:[ ]*/, ""); sub(/[ ]*#.*/, ""); val=$0 } END { if (val) print val }' "$WORKSPACE_LOCAL_YAML")"
184
+ fi
185
+ if [ -z "$_aif" ] && [ -f "$WORKSPACE_YAML" ]; then
186
+ _aif="$(awk '/^(ai_instructions|ai_instructions_file):/ { sub(/^[a-zA-Z0-9_]+:[ ]*/, ""); sub(/[ ]*#.*/, ""); val=$0 } END { if (val) print val }' "$WORKSPACE_YAML")"
187
+ fi
188
+ _aif="$(echo "$_aif" | tr -d " \t\r\n'\"")"
189
+ AI_INSTRUCTIONS_FILE="${_aif:-AGENTS.md}"
190
+ }
191
+
192
+ _load_code_workspace() {
193
+ _cw=""
194
+ if [ -f "$WORKSPACE_LOCAL_YAML" ]; then
195
+ _cw="$(awk '/^(code_workspace|vscode_workspace):/ { sub(/^[a-zA-Z0-9_]+:[ ]*/, ""); sub(/[ ]*#.*/, ""); val=$0 } END { if (val) print val }' "$WORKSPACE_LOCAL_YAML")"
196
+ fi
197
+ if [ -z "$_cw" ] && [ -f "$WORKSPACE_YAML" ]; then
198
+ _cw="$(awk '/^(code_workspace|vscode_workspace):/ { sub(/^[a-zA-Z0-9_]+:[ ]*/, ""); sub(/[ ]*#.*/, ""); val=$0 } END { if (val) print val }' "$WORKSPACE_YAML")"
199
+ fi
200
+ _cw="$(echo "$_cw" | tr -d " \t\r\n'\"")"
201
+ case "$_cw" in
202
+ true|yes|1)
203
+ _ws_basename="$(basename "$NEXUS_DIR")"
204
+ CODE_WORKSPACE_FILE="$_ws_basename.code-workspace"
205
+ ;;
206
+ false|no|0|none|"")
207
+ CODE_WORKSPACE_FILE=""
208
+ ;;
209
+ *)
210
+ case "$_cw" in
211
+ *.code-workspace) CODE_WORKSPACE_FILE="$_cw" ;;
212
+ *) CODE_WORKSPACE_FILE="$_cw.code-workspace" ;;
213
+ esac
214
+ ;;
215
+ esac
216
+ }
217
+
176
218
  # ---- YAML Parser / Manipulator (for rnex.yaml & .local.rnex.yaml) ----------
177
219
 
178
220
  _yaml_list_plugins_from_file() {
@@ -509,7 +551,10 @@ resolve_repo_path() {
509
551
  fi
510
552
  }
511
553
 
512
- ensure_repos_dir() { mkdir -p "$REPOS_DIR"; }
554
+ ensure_repos_dir() {
555
+ mkdir -p "$REPOS_DIR"
556
+ [ -f "$REPOS_DIR/.gitkeep" ] || touch "$REPOS_DIR/.gitkeep"
557
+ }
513
558
 
514
559
  # ---- Member Repo .rnex Isolation ------------------------------------------
515
560
 
@@ -899,6 +944,74 @@ merge_rnex_instructions() {
899
944
  log_ok "Merged Repo Nexus routing instructions with existing $(basename "$_dst")"
900
945
  }
901
946
 
947
+ sync_code_workspace() {
948
+ [ -n "$CODE_WORKSPACE_FILE" ] || return 0
949
+ _ws_path="$NEXUS_DIR/$CODE_WORKSPACE_FILE"
950
+ _root_name="$(basename "$NEXUS_DIR")"
951
+
952
+ _f_tmp="$(mktemp)"
953
+
954
+ printf ' {\n "name": "%s (Workspace Root)",\n "path": "."\n }' "$_root_name" > "$_f_tmp"
955
+
956
+ _repos_rel="${REPOS_DIR#"$NEXUS_DIR"/}"
957
+ _repos_rel="${_repos_rel#./}"
958
+ [ -n "$_repos_rel" ] || _repos_rel="repos"
959
+
960
+ yaml_list_repos | while read -r _rname; do
961
+ [ -n "$_rname" ] || continue
962
+ if yaml_repo_enabled "$_rname"; then
963
+ _rdir="$(resolve_repo_path "$_rname")"
964
+ if [ -d "$_rdir" ]; then
965
+ printf ',\n {\n "name": "%s",\n "path": "%s/%s"\n }' "$_rname" "$_repos_rel" "$_rname" >> "$_f_tmp"
966
+ fi
967
+ fi
968
+ done
969
+
970
+ if [ ! -f "$_ws_path" ]; then
971
+ {
972
+ printf '{\n "folders": [\n'
973
+ cat "$_f_tmp"
974
+ printf '\n ],\n "settings": {\n "search.exclude": {\n "**/node_modules": true,\n "**/.git": true\n }\n }\n}\n'
975
+ } > "$_ws_path"
976
+ rm -f "$_f_tmp"
977
+ log_ok "Created $CODE_WORKSPACE_FILE (VS Code / Cursor multi-root workspace)"
978
+ return 0
979
+ fi
980
+
981
+ if grep -q '"folders"[ ]*:' "$_ws_path" 2>/dev/null; then
982
+ _tmp_out="$(mktemp)"
983
+ awk -v f_src="$_f_tmp" '
984
+ BEGIN { in_f = 0 }
985
+ /"folders"[ ]*:[ ]*\[/ {
986
+ in_f = 1
987
+ print " \"folders\": ["
988
+ while ((getline line < f_src) > 0) print line
989
+ close(f_src)
990
+ next
991
+ }
992
+ in_f {
993
+ if (/\]/) {
994
+ in_f = 0
995
+ has_comma = ($0 ~ /,[ ]*$/) ? "," : ""
996
+ print " ]" has_comma
997
+ }
998
+ next
999
+ }
1000
+ { print }
1001
+ ' "$_ws_path" > "$_tmp_out" && mv "$_tmp_out" "$_ws_path"
1002
+ rm -f "$_f_tmp"
1003
+ log_ok "Updated folders in $CODE_WORKSPACE_FILE"
1004
+ else
1005
+ {
1006
+ printf '{\n "folders": [\n'
1007
+ cat "$_f_tmp"
1008
+ printf '\n ],\n "settings": {\n "search.exclude": {\n "**/node_modules": true,\n "**/.git": true\n }\n }\n}\n'
1009
+ } > "$_ws_path"
1010
+ rm -f "$_f_tmp"
1011
+ log_ok "Updated $CODE_WORKSPACE_FILE"
1012
+ fi
1013
+ }
1014
+
902
1015
  # ============================================================================
903
1016
  # Commands
904
1017
  # ============================================================================
@@ -906,10 +1019,32 @@ merge_rnex_instructions() {
906
1019
  cmd_init() {
907
1020
  _non_interactive=0
908
1021
  _target_dir=""
1022
+ _cli_ai_instructions=""
1023
+ _cli_code_workspace=""
909
1024
 
910
1025
  while [ $# -gt 0 ]; do
911
1026
  case "$1" in
912
1027
  -y|--yes) _non_interactive=1 ;;
1028
+ --ai|--instructions|--ai-instructions)
1029
+ shift
1030
+ _cli_ai_instructions="$1"
1031
+ ;;
1032
+ --code-workspace|--vscode)
1033
+ _cli_code_workspace="true"
1034
+ if [ $# -ge 2 ]; then
1035
+ case "$2" in
1036
+ -*) ;;
1037
+ *)
1038
+ case "$2" in
1039
+ true|false|*.code-workspace)
1040
+ shift
1041
+ _cli_code_workspace="$1"
1042
+ ;;
1043
+ esac
1044
+ ;;
1045
+ esac
1046
+ fi
1047
+ ;;
913
1048
  *)
914
1049
  if [ -z "$_target_dir" ]; then
915
1050
  _target_dir="$1"
@@ -943,6 +1078,12 @@ cmd_init() {
943
1078
  # Directory for member repository clones
944
1079
  repos_dir: ./repos
945
1080
 
1081
+ # Main AI instructions routing file (default: AGENTS.md; e.g. CLAUDE.md, GEMINI.md)
1082
+ ai_instructions: ${_cli_ai_instructions:-AGENTS.md}
1083
+
1084
+ # VS Code / Cursor multi-root workspace file (default: false; e.g. true or workspace.code-workspace)
1085
+ code_workspace: ${_cli_code_workspace:-false}
1086
+
946
1087
  # Workspace plugins
947
1088
  plugins:
948
1089
 
@@ -953,51 +1094,79 @@ YAML_EOF
953
1094
  log_ok "Created $RNEX_CONFIG_FILE"
954
1095
  fi
955
1096
 
956
- # ---- 2. Merge routing instructions into AGENTS.md -------------------------
957
- _target_agents="$_target_dir/AGENTS.md"
958
- merge_rnex_instructions "$_target_agents"
959
-
960
- # ---- 3. Interactive assistant setup (if TTY and not -y) -------------------
961
- if [ "$_non_interactive" -eq 0 ] && [ -t 0 ] && [ -t 1 ]; then
962
- printf '\n%bOptional AI Assistant Routing Files:%b\n' "$_BOLD" "$_NC"
963
- printf 'Would you like to generate routing files for other assistants?\n'
964
- printf ' [1] Claude Code (CLAUDE.md)\n'
965
- printf ' [2] Cursor (.cursorrules)\n'
966
- printf ' [3] Both (CLAUDE.md & .cursorrules)\n'
967
- printf ' [Enter to skip]\n'
968
- printf 'Choice [1/2/3/skip]: '
969
- read -r _choice || _choice=""
970
- case "$_choice" in
971
- 1)
972
- merge_rnex_instructions "$_target_dir/CLAUDE.md"
973
- ;;
974
- 2)
975
- merge_rnex_instructions "$_target_dir/.cursorrules"
976
- ;;
977
- 3)
978
- merge_rnex_instructions "$_target_dir/CLAUDE.md"
979
- merge_rnex_instructions "$_target_dir/.cursorrules"
980
- ;;
981
- *)
982
- ;;
983
- esac
1097
+ # ---- 2. Merge routing instructions into main AI instructions file ---------
1098
+ _target_aif="$_cli_ai_instructions"
1099
+ if [ -z "$_target_aif" ] && [ -f "$_target_dir/$RNEX_LOCAL_CONFIG_FILE" ]; then
1100
+ _target_aif="$(awk '/^(ai_instructions|ai_instructions_file):/ { sub(/^[a-zA-Z0-9_]+:[ ]*/, ""); sub(/[ ]*#.*/, ""); val=$0 } END { if (val) print val }' "$_target_dir/$RNEX_LOCAL_CONFIG_FILE")"
1101
+ fi
1102
+ if [ -z "$_target_aif" ] && [ -f "$_target_yaml" ]; then
1103
+ _target_aif="$(awk '/^(ai_instructions|ai_instructions_file):/ { sub(/^[a-zA-Z0-9_]+:[ ]*/, ""); sub(/[ ]*#.*/, ""); val=$0 } END { if (val) print val }' "$_target_yaml")"
984
1104
  fi
1105
+ _target_aif="$(echo "$_target_aif" | tr -d " \t\r\n'\"")"
1106
+ _target_aif="${_target_aif:-AGENTS.md}"
1107
+
1108
+ _target_agents="$_target_dir/$_target_aif"
1109
+ merge_rnex_instructions "$_target_agents"
1110
+ [ -f "$_target_dir/AGENTS.md" ] && [ "$_target_aif" != "AGENTS.md" ] && merge_rnex_instructions "$_target_dir/AGENTS.md"
1111
+ [ -f "$_target_dir/CLAUDE.md" ] && [ "$_target_aif" != "CLAUDE.md" ] && merge_rnex_instructions "$_target_dir/CLAUDE.md"
1112
+ [ -f "$_target_dir/.cursorrules" ] && [ "$_target_aif" != ".cursorrules" ] && merge_rnex_instructions "$_target_dir/.cursorrules"
985
1113
 
986
- # ---- 4. Create repos directory -------------------------------------------
1114
+ # ---- 3. Create repos directory with .gitkeep -----------------------------
987
1115
  _repos_dir="$_target_dir/repos"
988
1116
  mkdir -p "$_repos_dir"
1117
+ [ -f "$_repos_dir/.gitkeep" ] || touch "$_repos_dir/.gitkeep"
989
1118
 
990
- # ---- 5. Create internal .rnex directory ----------------------------------
1119
+ # ---- 4. Create internal .rnex directory ----------------------------------
991
1120
  mkdir -p "$_target_dir/.rnex"
992
1121
  mkdir -p "$_target_dir/.rnex/plugins"
993
1122
 
994
- # ---- 6. Ensure repos/, .rnex/, and local configs are gitignored ---------
1123
+ # ---- 5. Ensure repos/, .rnex/, and local configs are gitignored ---------
995
1124
  reconcile_gitignore "$_target_dir"
996
1125
 
1126
+ # ---- 6. Generate VS Code / Cursor workspace if configured ----------------
1127
+ _target_cw="$_cli_code_workspace"
1128
+ if [ -z "$_target_cw" ] && [ -f "$_target_dir/$RNEX_LOCAL_CONFIG_FILE" ]; then
1129
+ _target_cw="$(awk '/^(code_workspace|vscode_workspace):/ { sub(/^[a-zA-Z0-9_]+:[ ]*/, ""); sub(/[ ]*#.*/, ""); val=$0 } END { if (val) print val }' "$_target_dir/$RNEX_LOCAL_CONFIG_FILE")"
1130
+ fi
1131
+ if [ -z "$_target_cw" ] && [ -f "$_target_yaml" ]; then
1132
+ _target_cw="$(awk '/^(code_workspace|vscode_workspace):/ { sub(/^[a-zA-Z0-9_]+:[ ]*/, ""); sub(/[ ]*#.*/, ""); val=$0 } END { if (val) print val }' "$_target_yaml")"
1133
+ fi
1134
+ _target_cw="$(echo "$_target_cw" | tr -d " \t\r\n'\"")"
1135
+ case "$_target_cw" in
1136
+ true|yes|1)
1137
+ _cw_name="$(basename "$_target_dir").code-workspace"
1138
+ ;;
1139
+ false|no|0|none|"")
1140
+ _cw_name=""
1141
+ ;;
1142
+ *)
1143
+ case "$_target_cw" in
1144
+ *.code-workspace) _cw_name="$_target_cw" ;;
1145
+ *) _cw_name="$_target_cw.code-workspace" ;;
1146
+ esac
1147
+ ;;
1148
+ esac
1149
+
1150
+ if [ -n "$_cw_name" ]; then
1151
+ _orig_nexus="$NEXUS_DIR"
1152
+ _orig_repos="$REPOS_DIR"
1153
+ _orig_cw="$CODE_WORKSPACE_FILE"
1154
+ CODE_WORKSPACE_FILE="$_cw_name"
1155
+ NEXUS_DIR="$_target_dir"
1156
+ _repos_rel="repos"
1157
+ REPOS_DIR="$_target_dir/$_repos_rel"
1158
+ sync_code_workspace
1159
+ NEXUS_DIR="$_orig_nexus"
1160
+ REPOS_DIR="$_orig_repos"
1161
+ CODE_WORKSPACE_FILE="$_orig_cw"
1162
+ fi
1163
+
997
1164
  if [ "$_config_created" -eq 1 ]; then
998
1165
  printf '\n'
999
1166
  log_ok "Initialized Repo Nexus workspace at ${_BOLD}$_target_dir${_NC}"
1000
- log_dim "Created $RNEX_CONFIG_FILE, AGENTS.md, .rnex/, and repos/"
1167
+ _created_items="$RNEX_CONFIG_FILE, $_target_aif, .rnex/, and repos/"
1168
+ [ -n "$_cw_name" ] && _created_items="$_created_items (and $_cw_name)"
1169
+ log_dim "Created $_created_items"
1001
1170
  printf '\n'
1002
1171
  log_info "Next steps:"
1003
1172
  log_dim "1. Add repositories with: rnex add <name> <git-url>"
@@ -1055,6 +1224,7 @@ cmd_add() {
1055
1224
  [ "$_rnex_dir" = "false" ] && yaml_set_local "$_name" "rnex_dir" "false"
1056
1225
  [ "$_enabled" = "false" ] && yaml_set_local "$_name" "enabled" "false"
1057
1226
  sync_repo_rnex "$_name"
1227
+ sync_code_workspace
1058
1228
  printf '\n'
1059
1229
  log_ok "Registered repo '${_name}' in $(basename "$WORKSPACE_LOCAL_YAML")"
1060
1230
  return 0
@@ -1070,6 +1240,7 @@ cmd_add() {
1070
1240
  [ "$_rnex_dir" = "false" ] && yaml_set "$_name" "rnex_dir" "false"
1071
1241
  [ "$_enabled" = "false" ] && yaml_set "$_name" "enabled" "false"
1072
1242
  sync_repo_rnex "$_name"
1243
+ sync_code_workspace
1073
1244
  printf '\n'
1074
1245
  log_ok "Updated repo '${_name}' in $(basename "$WORKSPACE_YAML")"
1075
1246
  return 0
@@ -1078,6 +1249,7 @@ cmd_add() {
1078
1249
 
1079
1250
  yaml_add_repo "$_name" "$_url" "$_rnex_dir" "$_enabled"
1080
1251
  sync_repo_rnex "$_name"
1252
+ sync_code_workspace
1081
1253
  printf '\n'
1082
1254
  log_ok "Registered and added repo '${_name}'"
1083
1255
  }
@@ -1121,6 +1293,7 @@ cmd_clone() {
1121
1293
  fi
1122
1294
  fi
1123
1295
  done
1296
+ sync_code_workspace
1124
1297
  printf '\n'
1125
1298
  }
1126
1299
 
@@ -1178,6 +1351,7 @@ cmd_enable() {
1178
1351
  log_ok "Enabled repo '$_name' in $(basename "$WORKSPACE_YAML")"
1179
1352
  fi
1180
1353
  sync_repo_rnex "$_name"
1354
+ sync_code_workspace
1181
1355
  }
1182
1356
 
1183
1357
  cmd_disable() {
@@ -1201,6 +1375,7 @@ cmd_disable() {
1201
1375
  yaml_set "$_name" "enabled" "false"
1202
1376
  log_ok "Disabled repo '$_name' in $(basename "$WORKSPACE_YAML")"
1203
1377
  fi
1378
+ sync_code_workspace
1204
1379
  }
1205
1380
 
1206
1381
  cmd_show() {
@@ -1225,6 +1400,7 @@ cmd_remove() {
1225
1400
  else
1226
1401
  log_ok "Unregistered repo '$_name'"
1227
1402
  fi
1403
+ sync_code_workspace
1228
1404
  }
1229
1405
 
1230
1406
  cmd_list() {
@@ -1282,6 +1458,10 @@ cmd_status() {
1282
1458
  printf ' %b○%b Local Config: %s %b(not found — using repo defaults)%b\n' "$_DIM" "$_NC" "$WORKSPACE_LOCAL_YAML" "$_DIM" "$_NC"
1283
1459
  fi
1284
1460
  printf ' %b●%b Repos Dir: %s\n' "$_DIM" "$_NC" "$REPOS_DIR"
1461
+ printf ' %b●%b AI File: %s\n' "$_DIM" "$_NC" "$AI_INSTRUCTIONS_FILE"
1462
+ if [ -n "$CODE_WORKSPACE_FILE" ]; then
1463
+ printf ' %b●%b Workspace: %s\n' "$_DIM" "$_NC" "$CODE_WORKSPACE_FILE"
1464
+ fi
1285
1465
 
1286
1466
  _gi="$NEXUS_DIR/.gitignore"
1287
1467
  _gi_repos=0; _gi_rnex=0; _gi_local=0; _gi_has_counter=0
@@ -1300,17 +1480,29 @@ cmd_status() {
1300
1480
  printf '\n'
1301
1481
 
1302
1482
  printf '%bWorkspace AI Context (Routing):%b\n' "$_BOLD" "$_NC"
1303
- if [ -e "$NEXUS_DIR/AGENTS.md" ]; then
1304
- printf ' %b✓%b %s\n' "$_G" "$_NC" "AGENTS.md"
1483
+ _main_ai="${AI_INSTRUCTIONS_FILE:-AGENTS.md}"
1484
+ if [ -e "$NEXUS_DIR/$_main_ai" ]; then
1485
+ printf ' %b✓%b %s %b(main instructions)%b\n' "$_G" "$_NC" "$_main_ai" "$_DIM" "$_NC"
1305
1486
  else
1306
- printf ' %b✗%b %s (missing from workspace root — run "rnex fix")\n' "$_R" "$_NC" "AGENTS.md"
1307
- fi
1308
- if [ -f "$NEXUS_DIR/CLAUDE.md" ]; then
1309
- printf ' %b✓%b %s\n' "$_G" "$_NC" "CLAUDE.md"
1487
+ printf ' %b✗%b %s %b(main instructions — MISSING; run "rnex fix" to create)%b\n' "$_R" "$_NC" "$_main_ai" "$_R" "$_NC"
1310
1488
  fi
1311
- if [ -f "$NEXUS_DIR/.cursorrules" ]; then
1312
- printf ' %b✓%b %s\n' "$_G" "$_NC" ".cursorrules"
1489
+ for _aux_ai in "AGENTS.md" "CLAUDE.md" "GEMINI.md" ".cursorrules"; do
1490
+ if [ "$_aux_ai" != "$_main_ai" ] && [ -f "$NEXUS_DIR/$_aux_ai" ]; then
1491
+ printf ' %b✓%b %s\n' "$_G" "$_NC" "$_aux_ai"
1492
+ fi
1493
+ done
1494
+ if [ -n "$CODE_WORKSPACE_FILE" ]; then
1495
+ if [ -f "$NEXUS_DIR/$CODE_WORKSPACE_FILE" ]; then
1496
+ printf ' %b✓%b %s %b(VS Code / Cursor workspace)%b\n' "$_G" "$_NC" "$CODE_WORKSPACE_FILE" "$_DIM" "$_NC"
1497
+ else
1498
+ printf ' %b✗%b %s %b(VS Code / Cursor workspace — MISSING; run "rnex fix" to create)%b\n' "$_R" "$_NC" "$CODE_WORKSPACE_FILE" "$_R" "$_NC"
1499
+ fi
1313
1500
  fi
1501
+ for _found_cw in "$NEXUS_DIR"/*.code-workspace; do
1502
+ if [ -f "$_found_cw" ] && [ "$(basename "$_found_cw")" != "$CODE_WORKSPACE_FILE" ]; then
1503
+ printf ' %b✓%b %s %b(VS Code / Cursor workspace)%b\n' "$_G" "$_NC" "$(basename "$_found_cw")" "$_DIM" "$_NC"
1504
+ fi
1505
+ done
1314
1506
  if [ -d "$NEXUS_DIR/.rnex" ]; then
1315
1507
  printf ' %b✓%b %s\n' "$_G" "$_NC" ".rnex/"
1316
1508
  fi
@@ -1380,10 +1572,11 @@ cmd_fix() {
1380
1572
  # 1. Ensure .gitignore ignores repos/, .rnex/, and local configs, and strips legacy counters
1381
1573
  reconcile_gitignore "$NEXUS_DIR"
1382
1574
 
1383
- # 2. Reconcile instructions in AGENTS.md (and optional AI assistant files if present)
1384
- merge_rnex_instructions "$NEXUS_DIR/AGENTS.md"
1385
- [ -f "$NEXUS_DIR/CLAUDE.md" ] && merge_rnex_instructions "$NEXUS_DIR/CLAUDE.md"
1386
- [ -f "$NEXUS_DIR/.cursorrules" ] && merge_rnex_instructions "$NEXUS_DIR/.cursorrules"
1575
+ # 2. Reconcile instructions in main AI instructions file (and optional AI assistant files if present)
1576
+ merge_rnex_instructions "$NEXUS_DIR/$AI_INSTRUCTIONS_FILE"
1577
+ [ -f "$NEXUS_DIR/AGENTS.md" ] && [ "$AI_INSTRUCTIONS_FILE" != "AGENTS.md" ] && merge_rnex_instructions "$NEXUS_DIR/AGENTS.md"
1578
+ [ -f "$NEXUS_DIR/CLAUDE.md" ] && [ "$AI_INSTRUCTIONS_FILE" != "CLAUDE.md" ] && merge_rnex_instructions "$NEXUS_DIR/CLAUDE.md"
1579
+ [ -f "$NEXUS_DIR/.cursorrules" ] && [ "$AI_INSTRUCTIONS_FILE" != ".cursorrules" ] && merge_rnex_instructions "$NEXUS_DIR/.cursorrules"
1387
1580
 
1388
1581
  # 3. Reconcile plugins
1389
1582
  sync_plugins
@@ -1401,6 +1594,9 @@ cmd_fix() {
1401
1594
  fi
1402
1595
  done
1403
1596
 
1597
+ # 5. Reconcile VS Code / Cursor multi-root workspace if configured
1598
+ sync_code_workspace
1599
+
1404
1600
  log_ok "Fix complete — workspace, plugins, and member .rnex directories reconciled"
1405
1601
  }
1406
1602
 
@@ -1736,7 +1932,8 @@ cmd_help() {
1736
1932
  -v, --version Show version
1737
1933
 
1738
1934
  WORKSPACE & SYSTEM SETUP
1739
- init [-y] [dir] Initialize a new Repo Nexus workspace in current (or specified) dir
1935
+ init [-y] [--ai <file>] [--code-workspace [file]] [dir]
1936
+ Initialize a new Repo Nexus workspace (default AI file: AGENTS.md)
1740
1937
  install [dir] Install rnex & repo-nexus globally into ~/.local/bin (or custom dir)
1741
1938
  fix Reconcile workspace, plugins & member .rnex/ directories (alias: sync)
1742
1939
  completion <shell> Generate shell completion script (bash, zsh, fish)