xgem-cli 2.0.0-alpha.1 → 2.0.0-alpha.12

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.
Files changed (49) hide show
  1. package/README.md +53 -31
  2. package/bin/xgem +21 -14
  3. package/bin/xgem.js +235 -0
  4. package/lib/create.sh +334 -0
  5. package/lib/doctor.sh +13 -2
  6. package/lib/flutter.sh +163 -18
  7. package/lib/git.sh +157 -23
  8. package/lib/ios.sh +126 -47
  9. package/lib/scaffold.sh +24 -5
  10. package/lib/version.sh +1 -1
  11. package/lib-win/doctor.js +44 -0
  12. package/lib-win/flutter.js +101 -0
  13. package/lib-win/git.js +279 -0
  14. package/lib-win/logger.js +35 -0
  15. package/lib-win/scaffold.js +102 -0
  16. package/lib-win/utils.js +67 -0
  17. package/package.json +8 -7
  18. package/templates/node/build.sh.tmpl +9 -1
  19. package/templates/node/hard-clean.sh.tmpl +34 -2
  20. package/templates/node/lint.sh.tmpl +10 -0
  21. package/templates/node/start.sh.tmpl +9 -1
  22. package/templates/node/test.sh.tmpl +10 -0
  23. package/templates/webframework/build.sh.tmpl +10 -1
  24. package/templates/webframework/dev.sh.tmpl +9 -1
  25. package/templates/webframework/hard-clean.sh.tmpl +35 -2
  26. package/templates/webframework/lint.sh.tmpl +10 -0
  27. package/templates/webframework/test.sh.tmpl +10 -0
  28. package/templates-win/docker/build-up.mjs.tmpl +3 -0
  29. package/templates-win/docker/hard-clean.mjs.tmpl +4 -0
  30. package/templates-win/flutter/build-runner.mjs.tmpl +4 -0
  31. package/templates-win/flutter/build.mjs.tmpl +4 -0
  32. package/templates-win/flutter/hard-clean.mjs.tmpl +6 -0
  33. package/templates-win/go/build.mjs.tmpl +3 -0
  34. package/templates-win/go/hard-clean.mjs.tmpl +4 -0
  35. package/templates-win/node/build.mjs.tmpl +10 -0
  36. package/templates-win/node/hard-clean.mjs.tmpl +28 -0
  37. package/templates-win/node/lint.mjs.tmpl +10 -0
  38. package/templates-win/node/start.mjs.tmpl +10 -0
  39. package/templates-win/node/test.mjs.tmpl +10 -0
  40. package/templates-win/python/hard-clean.mjs.tmpl +8 -0
  41. package/templates-win/python/install.mjs.tmpl +12 -0
  42. package/templates-win/rust/build.mjs.tmpl +3 -0
  43. package/templates-win/rust/hard-clean.mjs.tmpl +3 -0
  44. package/templates-win/webframework/build.mjs.tmpl +10 -0
  45. package/templates-win/webframework/dev.mjs.tmpl +10 -0
  46. package/templates-win/webframework/hard-clean.mjs.tmpl +32 -0
  47. package/templates-win/webframework/lint.mjs.tmpl +10 -0
  48. package/templates-win/webframework/test.mjs.tmpl +10 -0
  49. package/scripts/check-platform.js +0 -17
package/README.md CHANGED
@@ -1,15 +1,25 @@
1
1
  # xgem
2
2
 
3
- A framework-aware automation CLI. `xgem init` scaffolds clean/build/dev scripts
4
- tailored to your project type (Flutter, Node, Python, React/Vue/Angular, Go,
5
- Rust, Docker, Swift), `xgem run <framework> <script>` runs them, `xgem doctor`
6
- reports on your environment, and `xgem git` wraps a common stage → commit →
7
- rebase-pull push workflow.
3
+ A framework-aware automation CLI. `xgem init` can create a brand-new project
4
+ (real `npm create vite`/`create-next-app`/`create-vue`/`ng new`/`flutter create`
5
+ scaffolding, framework-specific questions, dependency install, and launching
6
+ the dev server in your browser or the app on a picked device/simulator) or
7
+ just scaffold clean/build/dev scripts into a project you already have
8
+ (Flutter, Node, Python, React/Vue/Angular/Next, Go, Rust, Docker, Swift).
9
+ `xgem run <framework> <script>` runs those scripts, `xgem doctor` reports on
10
+ your environment, and `xgem git` wraps a common stage → commit → rebase-pull
11
+ → push workflow.
8
12
 
9
13
  Flutter's iOS builds go through a dedicated engine that detects whether your
10
14
  project uses CocoaPods or Swift Package Manager (SPM), figures out the actual
11
15
  deployment target your resolved SPM plugins require (instead of guessing),
12
- and reconciles it automatically — see [Why the iOS build engine exists](#why-the-ios-build-engine-exists).
16
+ and reconciles it automatically.
17
+
18
+ **Full documentation: [docs/](https://github.com/Code4Hacker/x-gem-cli/blob/xgem/docs/README.md)** — getting started, every command in
19
+ depth, exactly what each framework's project-creation wizard does, the iOS build
20
+ engine explained, Windows support, and troubleshooting. This README is a summary.
21
+ (Absolute link on purpose — `docs/` isn't shipped inside the npm package itself,
22
+ so a relative link would 404 on npmjs.com's rendered README.)
13
23
 
14
24
  ## Install
15
25
 
@@ -27,7 +37,8 @@ xgem isn't in Homebrew's central `homebrew-core` (that requires a formal submiss
27
37
  npm install -g xgem-cli
28
38
  ```
29
39
 
30
- *(not yet published to the npm registry)*
40
+ Works natively on Windows too (no WSL needed) npm's install runs a small Node.js
41
+ engine there instead of the bash one; see [Windows support](#windows-support).
31
42
 
32
43
  ### curl
33
44
 
@@ -48,6 +59,7 @@ xgem doctor ios [path] Report on iOS build readiness: CocoaPods vs SPM, d
48
59
  targets per config, and whether they're reconciled
49
60
  xgem git cmt "message" Auto-stage, commit, rebase-pull, and push
50
61
  xgem git init Setup local repo, attach remote tracker shortcuts
62
+ xgem git branch Pick, create, or switch branches; remembers your choice
51
63
  xgem git rm-remote Drop a configured remote
52
64
  xgem git rm-branch Safely drop local and/or remote branch
53
65
  xgem --version Print xgem's version
@@ -57,7 +69,18 @@ Flags (any command): --yes (skip confirmations), --dry-run (show, don't apply),
57
69
 
58
70
  ## Supported frameworks
59
71
 
60
- flutter, node, python, react, vue, angular, go, rust, docker, swift
72
+ flutter, node, python, react, vue, angular, next, go, rust, docker, swift
73
+
74
+ ## Creating a new project
75
+
76
+ `xgem init` asks, per framework, whether to create a brand-new project or use
77
+ what's already in the directory — real `create-vite`/`create-vue`/`ng new`/
78
+ `create-next-app`/`flutter create` scaffolding, with framework-specific
79
+ questions and a working dev-server/device launch at the end. Package manager
80
+ (npm/yarn/pnpm/bun) is auto-detected everywhere, never assumed. Answering
81
+ "existing" (the default) skips all of this and just scaffolds
82
+ `.xgem-automate/` into the current directory. Full detail, including exactly
83
+ what runs for each framework: **[docs/frameworks.md](https://github.com/Code4Hacker/x-gem-cli/blob/xgem/docs/frameworks.md)**.
61
84
 
62
85
  ## Architecture
63
86
 
@@ -69,8 +92,9 @@ lib/
69
92
  doctor.sh environment + feature detection ("xgem doctor")
70
93
  ios.sh the SwiftPM-aware iOS build engine
71
94
  flutter.sh flutter command group (build/hard-clean/build-runner), delegates iOS builds to ios.sh
72
- git.sh git cmt/init/rm-remote/rm-branch
95
+ git.sh git cmt/init/branch/rm-remote/rm-branch
73
96
  scaffold.sh generic clean/build/dev handling for the other, simpler frameworks
97
+ create.sh project creation wizards (react/vue/angular/next/simple frameworks)
74
98
  templates/ the actual clean/build/dev script content xgem scaffolds into your project's .xgem-automate/
75
99
  ```
76
100
 
@@ -82,29 +106,25 @@ of logic that can drift out of sync with two copies.
82
106
  ## Why the iOS build engine exists
83
107
 
84
108
  Flutter auto-generates a wrapper Swift package, `FlutterGeneratedPluginSwiftPackage`,
85
- that aggregates your plugins' SPM dependencies. Its declared minimum iOS platform can
86
- desync from your app's own `IPHONEOS_DEPLOYMENT_TARGET` — a confirmed, currently-open
87
- upstream Flutter bug ([flutter/flutter#186804](https://github.com/flutter/flutter/issues/186804),
109
+ whose declared minimum iOS platform can desync from your app's own
110
+ `IPHONEOS_DEPLOYMENT_TARGET` independently, even when your app's own target is
111
+ already high enough. This is a confirmed, currently-open upstream Flutter bug
112
+ ([flutter/flutter#186804](https://github.com/flutter/flutter/issues/186804),
88
113
  [#189422](https://github.com/flutter/flutter/issues/189422),
89
- [#162072](https://github.com/flutter/flutter/issues/162072)). A single `sed` patch to
90
- `project.pbxproj` doesn't reliably fix this: there are multiple deployment-target entries
91
- across Debug/Release/Profile × Runner/RunnerTests, and even a fully correct patch doesn't
92
- force Flutter to regenerate the generated package.
93
-
94
- `xgem run flutter build` (for the iOS target) instead:
95
-
96
- 1. Detects whether the project uses CocoaPods, SPM, or both.
97
- 2. Computes the deployment target actually required by your *resolved* SPM plugins
98
- (by reading their `ios/Package.swift` manifests via `.dart_tool/package_config.json`),
99
- instead of assuming a fixed value.
100
- 3. Shows a plan and asks for confirmation (unless `--yes`/`--dry-run`) before patching
101
- *every* `IPHONEOS_DEPLOYMENT_TARGET` occurrence in `project.pbxproj`.
102
- 4. Forces a clean regeneration (`flutter pub get` after clearing `ios/Flutter/ephemeral`)
103
- and verifies the regenerated package matches.
104
- 5. If it still doesn't (the upstream bug above), patches the generated package directly
105
- as a documented, loudly-logged last resort — never silently.
106
-
107
- Run `xgem doctor ios` any time for a standalone readiness report without doing a build.
114
+ [#162072](https://github.com/flutter/flutter/issues/162072)). `xgem run flutter build`
115
+ (iOS target) detects the actual requirement from your resolved SPM plugins, patches
116
+ every deployment-target occurrence, forces a clean regeneration, verifies it, and
117
+ falls back to a documented direct patch if the upstream bug is still biting — full
118
+ detail: **[docs/ios-build-engine.md](https://github.com/Code4Hacker/x-gem-cli/blob/xgem/docs/ios-build-engine.md)**. Run `xgem doctor ios`
119
+ any time for a standalone readiness report without doing a build.
120
+
121
+ ## Windows support
122
+
123
+ Homebrew and the curl installer are macOS/Linux only, same as any bash tool. npm is
124
+ different: it ships a small native Windows engine (`lib-win/`) so `npm install -g
125
+ xgem-cli` actually works in `cmd.exe`/PowerShell, no WSL required everything except
126
+ Flutter iOS/macOS builds (Xcode has no Windows equivalent) and the project-creation
127
+ wizards (not ported yet). Full detail: **[docs/windows.md](https://github.com/Code4Hacker/x-gem-cli/blob/xgem/docs/windows.md)**.
108
128
 
109
129
  ## Roadmap
110
130
 
@@ -114,6 +134,8 @@ Deferred to a follow-up pass, not yet in this release:
114
134
  - Shell completions, `--json` output, per-project config caching (stop re-prompting
115
135
  build name/number/platform every run)
116
136
  - Deeper Android SDK/Java detection
137
+ - Project creation wizards on the Windows engine (`lib-win/`) — react/vue/angular/next
138
+ scaffolding is pure Node.js tooling and would work fine there too, just not built yet
117
139
 
118
140
  ## License
119
141
 
package/bin/xgem CHANGED
@@ -33,6 +33,8 @@ source "$XGEM_HOME/lib/ios.sh"
33
33
  source "$XGEM_HOME/lib/flutter.sh"
34
34
  # shellcheck source=lib/scaffold.sh
35
35
  source "$XGEM_HOME/lib/scaffold.sh"
36
+ # shellcheck source=lib/create.sh
37
+ source "$XGEM_HOME/lib/create.sh"
36
38
 
37
39
  CONFIG_DIR=".xgem-automate"
38
40
 
@@ -70,6 +72,7 @@ print_usage() {
70
72
  echo " xgem doctor [ios] - Report on your environment / iOS SwiftPM build readiness"
71
73
  echo " xgem git cmt \"message\" - Auto-stage, commit, rebase-pull, and push"
72
74
  echo " xgem git init - Setup local repo, attach remote tracker shortcuts"
75
+ echo " xgem git branch - Pick, create, or switch branches; remembers your choice"
73
76
  echo " xgem git rm-remote - Drop specified target remote tracing rules"
74
77
  echo " xgem git rm-branch - Safely drop local and remote workspace branch states"
75
78
  echo " xgem --version - Print xgem's version"
@@ -84,28 +87,32 @@ case "${1:-}" in
84
87
  log_warn "Workspace configuration layer already exists! Use 'xgem add' to append frameworks."
85
88
  exit 0
86
89
  fi
87
- mkdir -p "$CONFIG_DIR"
88
-
89
90
  echo -e "\033[1;34mSelect your starting framework architecture:\033[0m"
90
91
  PS3="Enter target selection number: "
91
92
  select fw in "${ALL_FRAMEWORKS[@]}"; do
92
93
  if [ -n "$fw" ]; then
93
- scaffold_inject_templates "$fw" "$CONFIG_DIR"
94
- log_success "Successfully appended standard scripts for: $CONFIG_DIR/$fw"
94
+ # create_project_wizard handles ALL of xgem's own
95
+ # bookkeeping (.xgem-automate + .gitignore) internally now,
96
+ # at the earliest safe point for each framework — never
97
+ # after a slow/interruptible step, so a Ctrl-C during (say)
98
+ # `ng new`'s install can no longer lose it. See lib/create.sh.
99
+ create_project_wizard "$fw"
95
100
  break
96
101
  else
97
102
  echo "Invalid selection."
98
103
  fi
99
104
  done
100
105
 
101
- if [ -f .gitignore ]; then
102
- if ! grep -q "$CONFIG_DIR/" .gitignore; then
103
- echo -e "\n$CONFIG_DIR/" >> .gitignore
104
- log_success "Added automation tracking to .gitignore"
105
- fi
106
- else
107
- echo "$CONFIG_DIR/" > .gitignore
108
- log_success "Created .gitignore and hidden tracking layer folder references."
106
+ _ask_launch_dev_server
107
+
108
+ # A child process (this script) can never change the parent
109
+ # shell's cwd xgem's own process correctly cd'd into the new
110
+ # project folder for everything above, but your actual terminal
111
+ # is still wherever it started. Say so explicitly instead of
112
+ # leaving you to discover it the confusing way.
113
+ if [ -n "$XGEM_CREATED_NEW_FOLDER" ]; then
114
+ echo ""
115
+ log_info "Your project is in ./$XGEM_CREATED_NEW_FOLDER — your terminal is still in the original directory. Run: cd $XGEM_CREATED_NEW_FOLDER"
109
116
  fi
110
117
  exit 0
111
118
  ;;
@@ -182,7 +189,7 @@ case "${1:-}" in
182
189
  ;;
183
190
 
184
191
  git)
185
- [ -n "${2:-}" ] || die "Usage: xgem git <cmt|init|rm-remote|rm-branch>"
192
+ [ -n "${2:-}" ] || die "Usage: xgem git <cmt|init|branch|rm-remote|rm-branch>"
186
193
  cmd_git "$2" "${3:-}"
187
194
  exit 0
188
195
  ;;
@@ -197,7 +204,7 @@ case "${1:-}" in
197
204
  exit 0
198
205
  ;;
199
206
 
200
- flutter|node|python|react|vue|angular|go|rust|docker|swift)
207
+ flutter|node|python|react|vue|angular|next|go|rust|docker|swift)
201
208
  TARGET_FW=$1
202
209
  TARGET_FW_UPPER=$(echo "$TARGET_FW" | tr '[:lower:]' '[:upper:]')
203
210
 
package/bin/xgem.js ADDED
@@ -0,0 +1,235 @@
1
+ #!/usr/bin/env node
2
+ // xgem npm entrypoint. On macOS/Linux this is a thin passthrough to the
3
+ // real, already-tested bash bin/xgem sitting next to it — zero logic
4
+ // duplication, zero behavioral change for POSIX users. On Windows it runs
5
+ // the native lib-win/*.js engine, since bash doesn't exist there.
6
+
7
+ const path = require('node:path');
8
+ const { spawnSync } = require('node:child_process');
9
+
10
+ if (process.platform !== 'win32') {
11
+ const bashScript = path.join(__dirname, 'xgem');
12
+ const result = spawnSync(bashScript, process.argv.slice(2), { stdio: 'inherit' });
13
+ process.exit(result.status ?? 0);
14
+ }
15
+
16
+ // ---- Windows-native engine ----
17
+ const fs = require('node:fs');
18
+ const { logInfo, logSuccess, logWarn, logError, die, paint } = require('../lib-win/logger');
19
+ const { prompt } = require('../lib-win/utils');
20
+ const { cmdDoctor } = require('../lib-win/doctor');
21
+ const { cmdGit } = require('../lib-win/git');
22
+ const { cmdFlutter } = require('../lib-win/flutter');
23
+ const scaffold = require('../lib-win/scaffold');
24
+
25
+ const CONFIG_DIR = '.xgem-automate';
26
+
27
+ function printBanner() {
28
+ console.log(paint('yellow', ''));
29
+ console.log('██╗ ██╗ ██████╗ ███████╗███╗ ███╗██╗███╗ ██╗██╗');
30
+ console.log('╚██╗██╔╝ ██╔════╝ ██╔════╝████╗ ████║██║████╗ ██║██║');
31
+ console.log(' ╚███╔╝ █████╗██║ ███╗█████╗ ██╔████╔██║██║██╔██╗ ██║██║');
32
+ console.log(' ██╔██╗ ╚════╝██║ ██║██╔══╝ ██║╚██╔╝██║██║██║╚██╗██║██║');
33
+ console.log('██╔╝ ██╗ ╚██████╔╝███████╗██║ ╚═╝ ██║██║██║ ╚████║██║');
34
+ console.log('╚═╝ ╚═╝ ╚═════╝ ╚══════╝╚═╝ ╚═╝╚═╝╚═╝ ╚═══╝╚═╝');
35
+ console.log(paint('cyan', ' ....Windows engine....\n'));
36
+ }
37
+
38
+ function printUsage() {
39
+ console.log('Usage:');
40
+ console.log(' xgem init - Initialize tracking system and add first framework');
41
+ console.log(' xgem add - Interactive state-aware addition of remaining frameworks');
42
+ console.log(' xgem run <framework> <script> - Run a workspace automation command script');
43
+ console.log(' xgem terminate - Purge all generated automated layouts completely');
44
+ console.log(' xgem <framework> [help] - View tailored instructions for a specific script layout');
45
+ console.log(' xgem doctor [ios] - Report on your environment / iOS build availability');
46
+ console.log(' xgem git cmt "message" - Auto-stage, commit, rebase-pull, and push');
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');
49
+ console.log(' xgem git rm-remote - Drop specified target remote tracing rules');
50
+ console.log(' xgem git rm-branch - Safely drop local and remote workspace branch states');
51
+ console.log(' xgem --version - Print xgem\'s version');
52
+ console.log('');
53
+ console.log('Flags (any command): --yes (skip confirmations), --dry-run (show, don\'t apply), --verbose');
54
+ }
55
+
56
+ async function selectFramework(options) {
57
+ options.forEach((fw, i) => console.log(`${i + 1}) ${fw}`));
58
+ const choice = await prompt('Enter target selection number');
59
+ const idx = parseInt(choice, 10) - 1;
60
+ if (Number.isNaN(idx) || idx < 0 || idx >= options.length) return null;
61
+ return options[idx];
62
+ }
63
+
64
+ // Some teams want the generated scripts checked in so collaborators get the
65
+ // same automation; others want them private/local-only. Ask instead of
66
+ // always gitignoring.
67
+ async function updateGitignore() {
68
+ const gitignorePath = '.gitignore';
69
+ const ignoreChoice = ((await prompt(`Should ${CONFIG_DIR}/ be ignored by git (private to you), or tracked so collaborators get the same scripts? [ignore/track]`, 'ignore'))).toLowerCase();
70
+
71
+ if (ignoreChoice.startsWith('t')) {
72
+ if (fs.existsSync(gitignorePath)) {
73
+ const lines = fs.readFileSync(gitignorePath, 'utf8').split(/\r?\n/).filter((l) => l !== `${CONFIG_DIR}/`);
74
+ fs.writeFileSync(gitignorePath, lines.join('\n'));
75
+ logInfo(`Removed existing ${CONFIG_DIR}/ entry from .gitignore since you chose to track it.`);
76
+ }
77
+ logSuccess(`${CONFIG_DIR}/ will be tracked in git.`);
78
+ return;
79
+ }
80
+
81
+ if (fs.existsSync(gitignorePath)) {
82
+ const content = fs.readFileSync(gitignorePath, 'utf8');
83
+ if (!content.includes(`${CONFIG_DIR}/`)) {
84
+ fs.appendFileSync(gitignorePath, `\n${CONFIG_DIR}/\n`);
85
+ logSuccess('Added automation tracking to .gitignore');
86
+ }
87
+ } else {
88
+ fs.writeFileSync(gitignorePath, `${CONFIG_DIR}/\n`);
89
+ logSuccess('Created .gitignore and hidden tracking layer folder references.');
90
+ }
91
+ }
92
+
93
+ async function cmdInit() {
94
+ printBanner();
95
+ if (fs.existsSync(CONFIG_DIR)) {
96
+ logWarn("Workspace configuration layer already exists! Use 'xgem add' to append frameworks.");
97
+ return;
98
+ }
99
+ fs.mkdirSync(CONFIG_DIR, { recursive: true });
100
+
101
+ console.log('Select your starting framework architecture:');
102
+ const fw = await selectFramework(scaffold.ALL_FRAMEWORKS);
103
+ if (!fw) die('Invalid selection.');
104
+ scaffold.injectTemplates(fw, CONFIG_DIR);
105
+ logSuccess(`Successfully appended standard scripts for: ${CONFIG_DIR}/${fw}`);
106
+
107
+ await updateGitignore();
108
+ }
109
+
110
+ async function cmdAdd() {
111
+ if (!fs.existsSync(CONFIG_DIR)) die("System tracking layer not found. Run 'xgem init' first.");
112
+
113
+ const remaining = scaffold.getRemainingFrameworks(CONFIG_DIR);
114
+ if (remaining.length === 0) {
115
+ logWarn('All available framework blocks are already generated inside the workspace!');
116
+ const restore = (await prompt('Do you want to restore/regenerate all framework templates to defaults? (y/n)')).toLowerCase();
117
+ if (restore === 'y') {
118
+ for (const fw of scaffold.ALL_FRAMEWORKS) scaffold.injectTemplates(fw, CONFIG_DIR);
119
+ logSuccess('All framework automation layouts cleanly re-generated!');
120
+ }
121
+ return;
122
+ }
123
+
124
+ console.log('Select a framework script block to add:');
125
+ const fw = await selectFramework(remaining);
126
+ if (!fw) { console.log('Operation canceled.'); return; }
127
+ scaffold.injectTemplates(fw, CONFIG_DIR);
128
+ logSuccess(`Successfully loaded and updated files for: ${CONFIG_DIR}/${fw}`);
129
+ }
130
+
131
+ async function cmdRun(fw, script) {
132
+ if (!fw || !script) die('Usage: xgem run <framework> <script>');
133
+ if (fw === 'flutter' && ['hard-clean', 'build', 'build-runner'].includes(script)) {
134
+ await cmdFlutter(script);
135
+ } else {
136
+ scaffold.runScript(fw, script, CONFIG_DIR);
137
+ }
138
+ }
139
+
140
+ async function cmdTerminate() {
141
+ if (!fs.existsSync(CONFIG_DIR)) die(`Tracking layer ${CONFIG_DIR} not found. Nothing to terminate.`);
142
+
143
+ logWarn(`Initiating core termination sequence for ${CONFIG_DIR}...`);
144
+ const folders = fs.readdirSync(CONFIG_DIR, { withFileTypes: true })
145
+ .filter((d) => d.isDirectory())
146
+ .map((d) => d.name);
147
+
148
+ const { confirm } = require('../lib-win/utils');
149
+ const ok = await confirm(`This deletes ${CONFIG_DIR} and everything in it. Continue?`);
150
+ if (!ok) { logInfo('Cancelled.'); return; }
151
+
152
+ for (const fw of folders) {
153
+ console.log(` [ x ] Removing ${fw}...`);
154
+ fs.rmSync(path.join(CONFIG_DIR, fw), { recursive: true, force: true });
155
+ }
156
+ fs.rmSync(CONFIG_DIR, { recursive: true, force: true });
157
+
158
+ if (fs.existsSync('.gitignore')) {
159
+ const lines = fs.readFileSync('.gitignore', 'utf8').split(/\r?\n/).filter((l) => l !== `${CONFIG_DIR}/`);
160
+ fs.writeFileSync('.gitignore', lines.join('\n'));
161
+ logSuccess('Cleaned up .gitignore tracking records.');
162
+ }
163
+
164
+ logSuccess(`Termination complete. Total blocks destroyed: ${folders.length} (${folders.join(', ') || 'none'})`);
165
+ }
166
+
167
+ function printFrameworkHelp(fw) {
168
+ console.log(paint('cyan', `=== ${fw.toUpperCase()} Automation Blueprint (Windows) ===`));
169
+ if (!fs.existsSync(path.join(CONFIG_DIR, fw))) {
170
+ logWarn('Status: Not currently injected in this workspace.');
171
+ console.log("Run 'xgem add' to instantly append its structural scripts.\n");
172
+ } else {
173
+ logSuccess(`Status: Active & Mounted inside ${CONFIG_DIR}/${fw}/`);
174
+ console.log('');
175
+ }
176
+ console.log(`To execute scripts, use: xgem run ${fw} <script>\n`);
177
+ console.log('Configured Commands:');
178
+ for (const script of scaffold.frameworkScripts(fw) || []) {
179
+ console.log(` ${script}`);
180
+ }
181
+ if (fw === 'flutter') {
182
+ console.log('');
183
+ logInfo("Flutter builds on Windows support APK, App Bundle, and Windows desktop targets. Run 'xgem doctor ios' for why iOS/macOS aren't available here.");
184
+ }
185
+ console.log('');
186
+ }
187
+
188
+ async function main() {
189
+ const rawArgs = process.argv.slice(2);
190
+ const args = [];
191
+ for (const arg of rawArgs) {
192
+ if (arg === '--yes') process.env.XGEM_YES = '1';
193
+ else if (arg === '--dry-run') process.env.XGEM_DRY_RUN = '1';
194
+ else if (arg === '--verbose') process.env.XGEM_VERBOSE = '1';
195
+ else args.push(arg);
196
+ }
197
+
198
+ const [cmd, a2, a3] = args;
199
+
200
+ switch (cmd) {
201
+ case 'init': return cmdInit();
202
+ case 'add': return cmdAdd();
203
+ case 'run': return cmdRun(a2, a3);
204
+ case 'terminate': return cmdTerminate();
205
+ case 'git':
206
+ if (!a2) die('Usage: xgem git <cmt|init|branch|rm-remote|rm-branch>');
207
+ return cmdGit(a2, a3);
208
+ case 'doctor': return cmdDoctor(a2);
209
+ case '--version':
210
+ case '-V':
211
+ case 'version': {
212
+ const pkg = require('../package.json');
213
+ console.log(`xgem ${pkg.version} (Windows engine)`);
214
+ return;
215
+ }
216
+ case 'flutter':
217
+ case 'node':
218
+ case 'python':
219
+ case 'react':
220
+ case 'vue':
221
+ case 'angular':
222
+ case 'next':
223
+ case 'go':
224
+ case 'rust':
225
+ case 'docker':
226
+ return printFrameworkHelp(cmd);
227
+ default:
228
+ return printUsage();
229
+ }
230
+ }
231
+
232
+ main().catch((err) => {
233
+ logError(err.message || String(err));
234
+ process.exit(1);
235
+ });