xgem-cli 2.0.0-alpha.7 → 2.0.0-alpha.8

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/README.md CHANGED
@@ -49,6 +49,7 @@ xgem doctor ios [path] Report on iOS build readiness: CocoaPods vs SPM, d
49
49
  targets per config, and whether they're reconciled
50
50
  xgem git cmt "message" Auto-stage, commit, rebase-pull, and push
51
51
  xgem git init Setup local repo, attach remote tracker shortcuts
52
+ xgem git branch Pick, create, or switch branches; remembers your choice
52
53
  xgem git rm-remote Drop a configured remote
53
54
  xgem git rm-branch Safely drop local and/or remote branch
54
55
  xgem --version Print xgem's version
@@ -70,7 +71,7 @@ lib/
70
71
  doctor.sh environment + feature detection ("xgem doctor")
71
72
  ios.sh the SwiftPM-aware iOS build engine
72
73
  flutter.sh flutter command group (build/hard-clean/build-runner), delegates iOS builds to ios.sh
73
- git.sh git cmt/init/rm-remote/rm-branch
74
+ git.sh git cmt/init/branch/rm-remote/rm-branch
74
75
  scaffold.sh generic clean/build/dev handling for the other, simpler frameworks
75
76
  templates/ the actual clean/build/dev script content xgem scaffolds into your project's .xgem-automate/
76
77
  ```
package/bin/xgem CHANGED
@@ -70,6 +70,7 @@ print_usage() {
70
70
  echo " xgem doctor [ios] - Report on your environment / iOS SwiftPM build readiness"
71
71
  echo " xgem git cmt \"message\" - Auto-stage, commit, rebase-pull, and push"
72
72
  echo " xgem git init - Setup local repo, attach remote tracker shortcuts"
73
+ echo " xgem git branch - Pick, create, or switch branches; remembers your choice"
73
74
  echo " xgem git rm-remote - Drop specified target remote tracing rules"
74
75
  echo " xgem git rm-branch - Safely drop local and remote workspace branch states"
75
76
  echo " xgem --version - Print xgem's version"
@@ -182,7 +183,7 @@ case "${1:-}" in
182
183
  ;;
183
184
 
184
185
  git)
185
- [ -n "${2:-}" ] || die "Usage: xgem git <cmt|init|rm-remote|rm-branch>"
186
+ [ -n "${2:-}" ] || die "Usage: xgem git <cmt|init|branch|rm-remote|rm-branch>"
186
187
  cmd_git "$2" "${3:-}"
187
188
  exit 0
188
189
  ;;
package/bin/xgem.js CHANGED
@@ -45,6 +45,7 @@ function printUsage() {
45
45
  console.log(' xgem doctor [ios] - Report on your environment / iOS build availability');
46
46
  console.log(' xgem git cmt "message" - Auto-stage, commit, rebase-pull, and push');
47
47
  console.log(' xgem git init - Setup local repo, attach remote tracker shortcuts');
48
+ console.log(' xgem git branch - Pick, create, or switch branches; remembers your choice');
48
49
  console.log(' xgem git rm-remote - Drop specified target remote tracing rules');
49
50
  console.log(' xgem git rm-branch - Safely drop local and remote workspace branch states');
50
51
  console.log(' xgem --version - Print xgem\'s version');
@@ -187,7 +188,7 @@ async function main() {
187
188
  case 'run': return cmdRun(a2, a3);
188
189
  case 'terminate': return cmdTerminate();
189
190
  case 'git':
190
- if (!a2) die('Usage: xgem git <cmt|init|rm-remote|rm-branch>');
191
+ if (!a2) die('Usage: xgem git <cmt|init|branch|rm-remote|rm-branch>');
191
192
  return cmdGit(a2, a3);
192
193
  case 'doctor': return cmdDoctor(a2);
193
194
  case '--version':
package/lib/git.sh CHANGED
@@ -46,6 +46,29 @@ cmd_git_cmt() {
46
46
  return 0
47
47
  fi
48
48
 
49
+ # A pull needs something to pull FROM. If this branch has never been
50
+ # pushed before, there's no remote ref to pull, and `git pull --rebase`
51
+ # fails with "couldn't find remote ref <branch>" — which is not a
52
+ # connection problem or a conflict, just a brand-new branch. Check for
53
+ # that specific case first so it gets its own accurate message instead
54
+ # of being lumped in with real connectivity failures.
55
+ git ls-remote --exit-code --heads "$remote_name" "$current_branch" >/dev/null 2>&1
56
+ local ls_remote_status=$?
57
+
58
+ if [ "$ls_remote_status" -eq 2 ]; then
59
+ log_info "'$current_branch' doesn't exist on '$remote_name' yet — pushing to create it..."
60
+ if git push -u "$remote_name" "$current_branch"; then
61
+ log_success "Git workflow complete! Branch created and pushed."
62
+ else
63
+ die "Push operation failed."
64
+ fi
65
+ return 0
66
+ elif [ "$ls_remote_status" -ne 0 ]; then
67
+ log_error "Could not reach '$remote_name' to check for '$current_branch' — this looks like a real connection problem."
68
+ log_warn "Your commit is safe locally. Re-run 'xgem git cmt' once connectivity is restored, or push manually: git push $remote_name $current_branch"
69
+ exit 1
70
+ fi
71
+
49
72
  local ahead_count
50
73
  ahead_count=$(git rev-list --count "$remote_name/$current_branch..$current_branch" 2>/dev/null)
51
74
  if [ "$ahead_count" = "0" ]; then
@@ -163,13 +186,69 @@ cmd_git_rm_branch() {
163
186
  fi
164
187
  }
165
188
 
166
- # xgem git <cmt|init|rm-remote|rm-branch> ...
189
+ # cmd_git_branch: lists local branches, lets the user pick one (or create a
190
+ # new one), checks it out, and remembers it as this repo's default so
191
+ # there's a quick way back to it later. `xgem git cmt` always operates on
192
+ # whatever's actually checked out (that's the only thing that's correct for
193
+ # a commit), so this command's job is the checkout + remembering, not
194
+ # changing how cmt picks its branch.
195
+ cmd_git_branch() {
196
+ local -a branches=()
197
+ while IFS= read -r line; do
198
+ [ -n "$line" ] && branches+=("$line")
199
+ done < <(git branch --format='%(refname:short)' 2>/dev/null)
200
+
201
+ [ ${#branches[@]} -gt 0 ] || die "No local branches found."
202
+
203
+ local current_branch
204
+ current_branch=$(git branch --show-current 2>/dev/null)
205
+
206
+ echo "Available branches:"
207
+ local i=1 b
208
+ for b in "${branches[@]}"; do
209
+ if [ "$b" = "$current_branch" ]; then
210
+ echo "$i) $b (current)"
211
+ else
212
+ echo "$i) $b"
213
+ fi
214
+ i=$((i + 1))
215
+ done
216
+ local create_option=$i
217
+ echo "$create_option) Create new branch"
218
+
219
+ local choice
220
+ read -r -p "Select [1-$create_option]: " choice
221
+
222
+ if [ "$choice" = "$create_option" ]; then
223
+ local new_branch
224
+ read -r -p "Enter new branch name: " new_branch
225
+ [ -n "$new_branch" ] || die "Branch name cannot be empty."
226
+ git checkout -b "$new_branch" || die "Could not create branch '$new_branch'."
227
+ git config --local xgem.default-branch "$new_branch"
228
+ log_success "Created and switched to '$new_branch', set as default for this repo."
229
+ return 0
230
+ fi
231
+
232
+ if ! [[ "$choice" =~ ^[0-9]+$ ]] || [ "$choice" -lt 1 ] || [ "$choice" -gt ${#branches[@]} ]; then
233
+ die "Invalid selection."
234
+ fi
235
+
236
+ local selected="${branches[$((choice - 1))]}"
237
+ if [ "$selected" != "$current_branch" ]; then
238
+ git checkout "$selected" || die "Could not switch to branch '$selected'."
239
+ fi
240
+ git config --local xgem.default-branch "$selected"
241
+ log_success "Switched to '$selected' and set as default for this repo."
242
+ }
243
+
244
+ # xgem git <cmt|init|rm-remote|rm-branch|branch> ...
167
245
  cmd_git() {
168
246
  case "$1" in
169
247
  cmt) cmd_git_cmt "$2" ;;
170
248
  init) cmd_git_init ;;
171
249
  rm-remote) cmd_git_rm_remote ;;
172
250
  rm-branch) cmd_git_rm_branch ;;
173
- *) die "Unknown git subcommand '$1'. Usage: xgem git <cmt|init|rm-remote|rm-branch>" ;;
251
+ branch) cmd_git_branch ;;
252
+ *) die "Unknown git subcommand '$1'. Usage: xgem git <cmt|init|rm-remote|rm-branch|branch>" ;;
174
253
  esac
175
254
  }
package/lib/version.sh CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/bin/bash
2
2
  # xgem version info.
3
3
 
4
- XGEM_VERSION="2.0.0-alpha.7"
4
+ XGEM_VERSION="2.0.0-alpha.8"
5
5
 
6
6
  print_version() {
7
7
  echo "xgem $XGEM_VERSION"
package/lib-win/git.js CHANGED
@@ -60,6 +60,26 @@ async function cmdCmt(commitMsg) {
60
60
  return;
61
61
  }
62
62
 
63
+ // A pull needs something to pull FROM. If this branch has never been
64
+ // pushed before, there's no remote ref, and `git pull --rebase` fails
65
+ // with "couldn't find remote ref <branch>" — not a connection problem
66
+ // or a conflict, just a brand-new branch. Check for that case first.
67
+ const lsRemoteStatus = spawnSync('git', ['ls-remote', '--exit-code', '--heads', remoteName, currentBranch]).status;
68
+
69
+ if (lsRemoteStatus === 2) {
70
+ logInfo(`'${currentBranch}' doesn't exist on '${remoteName}' yet — pushing to create it...`);
71
+ if (git(['push', '-u', remoteName, currentBranch]).status === 0) {
72
+ logSuccess('Git workflow complete! Branch created and pushed.');
73
+ } else {
74
+ die('Push operation failed.');
75
+ }
76
+ return;
77
+ } else if (lsRemoteStatus !== 0) {
78
+ logError(`Could not reach '${remoteName}' to check for '${currentBranch}' — this looks like a real connection problem.`);
79
+ logWarn(`Your commit is safe locally. Re-run 'xgem git cmt' once connectivity is restored, or push manually: git push ${remoteName} ${currentBranch}`);
80
+ process.exit(1);
81
+ }
82
+
63
83
  const aheadCount = gitCapture(['rev-list', '--count', `${remoteName}/${currentBranch}..${currentBranch}`]);
64
84
  if (aheadCount === '0') {
65
85
  logSuccess(`Already up to date with '${remoteName}/${currentBranch}' — nothing to push.`);
@@ -168,13 +188,53 @@ async function cmdRmBranch() {
168
188
  }
169
189
  }
170
190
 
191
+ // Lists local branches, lets the user pick one (or create a new one),
192
+ // checks it out, and remembers it as this repo's default. cmt always
193
+ // operates on whatever's actually checked out — this command's job is the
194
+ // checkout + remembering, not changing how cmt picks its branch.
195
+ async function cmdBranch() {
196
+ const branches = gitCapture(['branch', '--format=%(refname:short)']).split(/\r?\n/).filter(Boolean);
197
+ if (branches.length === 0) die('No local branches found.');
198
+
199
+ const currentBranch = gitCapture(['branch', '--show-current']);
200
+
201
+ console.log('Available branches:');
202
+ branches.forEach((b, i) => {
203
+ console.log(`${i + 1}) ${b}${b === currentBranch ? ' (current)' : ''}`);
204
+ });
205
+ const createOption = branches.length + 1;
206
+ console.log(`${createOption}) Create new branch`);
207
+
208
+ const choice = await prompt(`Select [1-${createOption}]`);
209
+
210
+ if (choice === String(createOption)) {
211
+ const newBranch = await prompt('Enter new branch name');
212
+ if (!newBranch) die('Branch name cannot be empty.');
213
+ if (git(['checkout', '-b', newBranch]).status !== 0) die(`Could not create branch '${newBranch}'.`);
214
+ git(['config', '--local', 'xgem.default-branch', newBranch]);
215
+ logSuccess(`Created and switched to '${newBranch}', set as default for this repo.`);
216
+ return;
217
+ }
218
+
219
+ const idx = parseInt(choice, 10) - 1;
220
+ if (Number.isNaN(idx) || idx < 0 || idx >= branches.length) die('Invalid selection.');
221
+
222
+ const selected = branches[idx];
223
+ if (selected !== currentBranch) {
224
+ if (git(['checkout', selected]).status !== 0) die(`Could not switch to branch '${selected}'.`);
225
+ }
226
+ git(['config', '--local', 'xgem.default-branch', selected]);
227
+ logSuccess(`Switched to '${selected}' and set as default for this repo.`);
228
+ }
229
+
171
230
  async function cmdGit(sub, arg) {
172
231
  switch (sub) {
173
232
  case 'cmt': return cmdCmt(arg);
174
233
  case 'init': return cmdInit();
234
+ case 'branch': return cmdBranch();
175
235
  case 'rm-remote': return cmdRmRemote();
176
236
  case 'rm-branch': return cmdRmBranch();
177
- default: die(`Unknown git subcommand '${sub}'. Usage: xgem git <cmt|init|rm-remote|rm-branch>`);
237
+ default: die(`Unknown git subcommand '${sub}'. Usage: xgem git <cmt|init|branch|rm-remote|rm-branch>`);
178
238
  }
179
239
  }
180
240
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xgem-cli",
3
- "version": "2.0.0-alpha.7",
3
+ "version": "2.0.0-alpha.8",
4
4
  "description": "Framework-aware automation CLI: scaffolds and runs clean/build/dev scripts per project type, an environment doctor, a SwiftPM-aware iOS build engine, and a git workflow helper. Runs natively on macOS, Linux, and Windows.",
5
5
  "bin": {
6
6
  "xgem": "bin/xgem.js"