xgem-cli 2.0.0-alpha.10 → 2.0.0-alpha.14
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 +37 -63
- package/bin/xgem +46 -15
- package/bin/xgem.js +22 -20
- package/lib/bootstrap.sh +165 -0
- package/lib/ci.sh +44 -0
- package/lib/create.sh +140 -71
- package/lib/flutter.sh +10 -8
- package/lib/git.sh +291 -29
- package/lib/registry.sh +45 -0
- package/lib/release.sh +185 -0
- package/lib/scaffold.sh +21 -2
- package/lib/status.sh +42 -0
- package/lib/utils.sh +11 -0
- package/lib/version.sh +1 -1
- package/lib-win/bootstrap.js +189 -0
- package/lib-win/ci.js +43 -0
- package/lib-win/git.js +275 -21
- package/lib-win/registry.js +43 -0
- package/lib-win/release.js +143 -0
- package/lib-win/scaffold.js +64 -2
- package/lib-win/status.js +53 -0
- package/lib-win/utils.js +6 -1
- package/package.json +1 -1
- package/templates/node/build.sh.tmpl +9 -1
- package/templates/node/hard-clean.sh.tmpl +34 -2
- package/templates/node/lint.sh.tmpl +10 -0
- package/templates/node/start.sh.tmpl +9 -1
- package/templates/node/test.sh.tmpl +10 -0
- package/templates/webframework/build.sh.tmpl +10 -1
- package/templates/webframework/dev.sh.tmpl +9 -1
- package/templates/webframework/hard-clean.sh.tmpl +35 -2
- package/templates/webframework/lint.sh.tmpl +10 -0
- package/templates/webframework/test.sh.tmpl +10 -0
- package/templates-win/node/build.mjs.tmpl +8 -2
- package/templates-win/node/hard-clean.mjs.tmpl +24 -5
- package/templates-win/node/lint.mjs.tmpl +10 -0
- package/templates-win/node/start.mjs.tmpl +8 -1
- package/templates-win/node/test.mjs.tmpl +10 -0
- package/templates-win/webframework/build.mjs.tmpl +8 -1
- package/templates-win/webframework/dev.mjs.tmpl +8 -1
- package/templates-win/webframework/hard-clean.mjs.tmpl +28 -5
- package/templates-win/webframework/lint.mjs.tmpl +10 -0
- package/templates-win/webframework/test.mjs.tmpl +10 -0
package/lib/create.sh
CHANGED
|
@@ -1,29 +1,77 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
|
-
# xgem project creation wizards — runs from `xgem init`,
|
|
3
|
-
#
|
|
4
|
-
#
|
|
5
|
-
#
|
|
6
|
-
#
|
|
2
|
+
# xgem project creation wizards — runs from `xgem init`, for frameworks
|
|
3
|
+
# with a real "ask sub-choice -> scaffold -> install -> launch" story
|
|
4
|
+
# worth building (react/vue/angular/next/flutter). The rest (node/python/
|
|
5
|
+
# go/rust/docker/swift) get a lighter "create with the ecosystem's own
|
|
6
|
+
# standard init command" step.
|
|
7
7
|
#
|
|
8
|
-
# Depends on lib/logger.sh, lib/utils.sh. Uses `cd`
|
|
9
|
-
# subshells) so a newly created project directory persists as
|
|
10
|
-
# the rest of `xgem init
|
|
11
|
-
# caller needing to track/re-cd into a returned path.
|
|
8
|
+
# Depends on lib/logger.sh, lib/utils.sh, lib/scaffold.sh. Uses `cd`
|
|
9
|
+
# directly (no subshells) so a newly created project directory persists as
|
|
10
|
+
# the cwd for the rest of `xgem init`.
|
|
12
11
|
#
|
|
13
|
-
#
|
|
14
|
-
#
|
|
15
|
-
#
|
|
16
|
-
#
|
|
12
|
+
# Ordering principle (this file's main correctness property): xgem's own
|
|
13
|
+
# bookkeeping (.xgem-automate + .gitignore, via _xgem_bookkeeping) always
|
|
14
|
+
# runs BEFORE the slow, interruptible step of each framework (an install,
|
|
15
|
+
# or an atomic scaffold+install like `ng new`) — never after. A real user
|
|
16
|
+
# hit this: Ctrl-C during `ng new`'s multi-minute install killed the whole
|
|
17
|
+
# xgem process before .xgem-automate was ever created, since it used to run
|
|
18
|
+
# only at the very end. Where a tool supports decoupling scaffold-from-
|
|
19
|
+
# install (--no-immediate, --skip-install, --no-pub), xgem scaffolds first
|
|
20
|
+
# (fast), does its own bookkeeping, then runs the install itself. Where a
|
|
21
|
+
# tool has no such flag (create-react-app), bookkeeping runs right after
|
|
22
|
+
# that one atomic call returns — a small residual risk, documented at the
|
|
23
|
+
# call site, not silently left as-was.
|
|
24
|
+
#
|
|
25
|
+
# Dev-server / device-run launch is deliberately deferred: creators only
|
|
26
|
+
# set XGEM_POST_INIT_LAUNCH_CMD (an array) rather than launching
|
|
27
|
+
# immediately, so `xgem init` finishes well before handing the terminal
|
|
28
|
+
# over to a long-running dev server.
|
|
17
29
|
XGEM_POST_INIT_LAUNCH_CMD=()
|
|
18
30
|
|
|
19
31
|
# Set by creators when a NEW folder was created (not "current directory").
|
|
20
32
|
# A child process can never change its parent shell's cwd, so once `xgem
|
|
21
33
|
# init` exits, the user's actual terminal is back wherever it started —
|
|
22
34
|
# xgem's own process is correctly cd'd into the new folder for the rest of
|
|
23
|
-
# ITS run
|
|
24
|
-
#
|
|
35
|
+
# ITS run, but that never propagates back. bin/xgem prints a "cd <name>"
|
|
36
|
+
# reminder using this at the very end.
|
|
25
37
|
XGEM_CREATED_NEW_FOLDER=""
|
|
26
38
|
|
|
39
|
+
# _xgem_bookkeeping <framework>
|
|
40
|
+
# Creates .xgem-automate + updates .gitignore. Called as early as the
|
|
41
|
+
# target directory allows, always before any slow/interruptible step.
|
|
42
|
+
_xgem_bookkeeping() {
|
|
43
|
+
local fw=$1
|
|
44
|
+
mkdir -p "$CONFIG_DIR"
|
|
45
|
+
registry_add "$(pwd)"
|
|
46
|
+
scaffold_inject_templates "$fw" "$CONFIG_DIR"
|
|
47
|
+
log_success "Successfully appended standard scripts for: $CONFIG_DIR/$fw"
|
|
48
|
+
|
|
49
|
+
# Some teams want the generated scripts checked in so collaborators get
|
|
50
|
+
# the same automation; others want them private/local-only. Ask instead
|
|
51
|
+
# of always gitignoring.
|
|
52
|
+
local ignore_choice
|
|
53
|
+
read -r -p "Should $CONFIG_DIR/ be ignored by git (private to you), or tracked so collaborators get the same scripts? [ignore/track] (default: ignore): " ignore_choice
|
|
54
|
+
ignore_choice=${ignore_choice:-ignore}
|
|
55
|
+
|
|
56
|
+
if [[ "$ignore_choice" == t* || "$ignore_choice" == T* ]]; then
|
|
57
|
+
if [ -f .gitignore ] && grep -qx "$CONFIG_DIR/" .gitignore; then
|
|
58
|
+
local tmp
|
|
59
|
+
tmp=$(mktemp)
|
|
60
|
+
grep -vx "$CONFIG_DIR/" .gitignore > "$tmp" && mv "$tmp" .gitignore
|
|
61
|
+
log_info "Removed existing $CONFIG_DIR/ entry from .gitignore since you chose to track it."
|
|
62
|
+
fi
|
|
63
|
+
log_success "$CONFIG_DIR/ will be tracked in git."
|
|
64
|
+
elif [ -f .gitignore ]; then
|
|
65
|
+
if ! grep -qx "$CONFIG_DIR/" .gitignore; then
|
|
66
|
+
echo -e "\n$CONFIG_DIR/" >> .gitignore
|
|
67
|
+
log_success "Added automation tracking to .gitignore"
|
|
68
|
+
fi
|
|
69
|
+
else
|
|
70
|
+
echo "$CONFIG_DIR/" > .gitignore
|
|
71
|
+
log_success "Created .gitignore and hidden tracking layer folder references."
|
|
72
|
+
fi
|
|
73
|
+
}
|
|
74
|
+
|
|
27
75
|
# _prompt_project_location <human label> -> echoes "." or a new folder name.
|
|
28
76
|
# Pure prompt-and-echo, no other stdout output, so it's safe to capture via
|
|
29
77
|
# command substitution.
|
|
@@ -42,13 +90,13 @@ _prompt_project_location() {
|
|
|
42
90
|
echo "$name"
|
|
43
91
|
}
|
|
44
92
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
93
|
+
# _enter_project_dir <project_dir> — mkdir+cd if a new folder was chosen,
|
|
94
|
+
# and records XGEM_CREATED_NEW_FOLDER. No-op for "." (current directory).
|
|
95
|
+
_enter_project_dir() {
|
|
96
|
+
local project_dir=$1
|
|
97
|
+
[ "$project_dir" = "." ] && return 0
|
|
98
|
+
XGEM_CREATED_NEW_FOLDER="$project_dir"
|
|
99
|
+
mkdir -p "$project_dir" && cd "$project_dir" || die "Could not enter $project_dir"
|
|
52
100
|
}
|
|
53
101
|
|
|
54
102
|
# _launch_dev_server_and_open_browser <cmd...>
|
|
@@ -89,13 +137,11 @@ _launch_dev_server_and_open_browser() {
|
|
|
89
137
|
_ask_launch_dev_server() {
|
|
90
138
|
[ ${#XGEM_POST_INIT_LAUNCH_CMD[@]} -gt 0 ] || return 0
|
|
91
139
|
|
|
92
|
-
# `flutter run` isn't a web dev server —
|
|
93
|
-
#
|
|
94
|
-
#
|
|
95
|
-
#
|
|
96
|
-
#
|
|
97
|
-
# _flutter_offer_run_on_device before this command was ever set, so
|
|
98
|
-
# this doesn't ask again.)
|
|
140
|
+
# `flutter run` isn't a web dev server — no localhost URL to detect/
|
|
141
|
+
# open, and it depends on fully-inherited interactive stdin for its
|
|
142
|
+
# own hot-reload keybindings, which the background+log-tail approach
|
|
143
|
+
# would break. Run it directly. (Whether to run at all was already
|
|
144
|
+
# confirmed in _flutter_offer_run_on_device, so this doesn't ask again.)
|
|
99
145
|
if [ "${XGEM_POST_INIT_LAUNCH_CMD[0]}" = "flutter" ]; then
|
|
100
146
|
"${XGEM_POST_INIT_LAUNCH_CMD[@]}"
|
|
101
147
|
return 0
|
|
@@ -114,27 +160,33 @@ _create_react() {
|
|
|
114
160
|
read -r -p "TypeScript or JavaScript? [ts/js] (default: ts): " lang
|
|
115
161
|
lang=${lang:-ts}
|
|
116
162
|
project_dir=$(_prompt_project_location "React")
|
|
117
|
-
|
|
163
|
+
_enter_project_dir "$project_dir"
|
|
118
164
|
|
|
119
165
|
if [[ "$variant" == cra* || "$variant" == CRA* ]]; then
|
|
120
166
|
require_cmd npx "Install Node.js (npm ships with it): https://nodejs.org"
|
|
121
|
-
|
|
122
|
-
|
|
167
|
+
# create-react-app has no flag to decouple scaffold-from-install
|
|
168
|
+
# (confirmed: nothing in --help), so this one atomic call does
|
|
169
|
+
# both — a Ctrl-C during its own install (it's known to be slow)
|
|
170
|
+
# would still lose xgem's bookkeeping below. Accepted residual
|
|
171
|
+
# risk for this specific, non-default, legacy-leaning option.
|
|
172
|
+
log_info "Create React App scaffolds and installs in one step and can take a few minutes — best to let it finish without interrupting."
|
|
173
|
+
local -a args=(create-react-app .)
|
|
123
174
|
[ "$lang" = "ts" ] && args+=(--template typescript)
|
|
124
175
|
npx "${args[@]}" || die "create-react-app failed."
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
local template="react"
|
|
128
|
-
[ "$lang" = "ts" ] && template="react-ts"
|
|
129
|
-
# --no-immediate: create-vite's own "install deps and start dev
|
|
130
|
-
# server" prompt would otherwise block here and, if Ctrl-C'd, kill
|
|
131
|
-
# this whole xgem process before it ever reaches template
|
|
132
|
-
# injection / .gitignore setup below. xgem handles install/launch
|
|
133
|
-
# itself instead, after everything else is done.
|
|
134
|
-
npm create vite@latest "$project_dir" -- --template "$template" --no-immediate || die "npm create vite failed."
|
|
176
|
+
_xgem_bookkeeping react
|
|
177
|
+
return 0
|
|
135
178
|
fi
|
|
136
179
|
|
|
137
|
-
|
|
180
|
+
require_cmd npm "Install Node.js (npm ships with it): https://nodejs.org"
|
|
181
|
+
local template="react"
|
|
182
|
+
[ "$lang" = "ts" ] && template="react-ts"
|
|
183
|
+
# --no-immediate: create-vite's own "install deps and start dev server"
|
|
184
|
+
# prompt would otherwise block here (and if Ctrl-C'd, kill this whole
|
|
185
|
+
# xgem process). --overwrite: harmless here since the only files that
|
|
186
|
+
# could exist at this point are ones xgem itself hasn't created yet
|
|
187
|
+
# (bookkeeping happens after this call, deliberately).
|
|
188
|
+
npm create vite@latest . -- --template "$template" --no-immediate --overwrite || die "npm create vite failed."
|
|
189
|
+
_xgem_bookkeeping react
|
|
138
190
|
log_info "Installing dependencies..."
|
|
139
191
|
npm install
|
|
140
192
|
XGEM_POST_INIT_LAUNCH_CMD=(npm run dev)
|
|
@@ -144,9 +196,13 @@ _create_vue() {
|
|
|
144
196
|
require_cmd npm "Install Node.js (npm ships with it): https://nodejs.org"
|
|
145
197
|
local project_dir
|
|
146
198
|
project_dir=$(_prompt_project_location "Vue")
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
199
|
+
_enter_project_dir "$project_dir"
|
|
200
|
+
# create-vue doesn't install automatically (confirmed: no node_modules
|
|
201
|
+
# after it runs), so there's already a natural gap here to bookkeep in
|
|
202
|
+
# before the slow step. --force since this dir may be genuinely empty
|
|
203
|
+
# or (for "current directory") may already contain unrelated files.
|
|
204
|
+
npm create vue@latest . --force || die "npm create vue failed."
|
|
205
|
+
_xgem_bookkeeping vue
|
|
150
206
|
log_info "Installing dependencies..."
|
|
151
207
|
npm install
|
|
152
208
|
XGEM_POST_INIT_LAUNCH_CMD=(npm run dev)
|
|
@@ -155,16 +211,20 @@ _create_vue() {
|
|
|
155
211
|
_create_angular() {
|
|
156
212
|
local project_dir
|
|
157
213
|
project_dir=$(_prompt_project_location "Angular")
|
|
158
|
-
|
|
214
|
+
_enter_project_dir "$project_dir"
|
|
159
215
|
local -a ng_cmd=(ng)
|
|
160
216
|
has_cmd ng || ng_cmd=(npx @angular/cli@latest)
|
|
161
217
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
218
|
+
# --skip-install: ng new's own install is a multi-minute step (Angular
|
|
219
|
+
# dependency trees are large) — decoupling it is exactly what let a
|
|
220
|
+
# real user's Ctrl-C lose xgem's bookkeeping before this fix.
|
|
221
|
+
# --skip-git: xgem has its own `xgem git init`; ng new's own auto-
|
|
222
|
+
# commit would happen before .xgem-automate even exists.
|
|
223
|
+
"${ng_cmd[@]}" new "$(basename "$PWD")" --directory=. --skip-install --skip-git \
|
|
224
|
+
|| die "ng new failed."
|
|
225
|
+
_xgem_bookkeeping angular
|
|
226
|
+
log_info "Installing dependencies..."
|
|
227
|
+
npm install
|
|
168
228
|
XGEM_POST_INIT_LAUNCH_CMD=(npm run start)
|
|
169
229
|
}
|
|
170
230
|
|
|
@@ -172,20 +232,26 @@ _create_next() {
|
|
|
172
232
|
require_cmd npx "Install Node.js (npm ships with it): https://nodejs.org"
|
|
173
233
|
local project_dir
|
|
174
234
|
project_dir=$(_prompt_project_location "Next.js")
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
235
|
+
_enter_project_dir "$project_dir"
|
|
236
|
+
# --skip-install: decouple from create-next-app's own install, same
|
|
237
|
+
# reasoning as Angular above.
|
|
238
|
+
npx create-next-app@latest . --skip-install || die "create-next-app failed."
|
|
239
|
+
_xgem_bookkeeping next
|
|
240
|
+
log_info "Installing dependencies..."
|
|
241
|
+
npm install
|
|
178
242
|
XGEM_POST_INIT_LAUNCH_CMD=(npm run dev)
|
|
179
243
|
}
|
|
180
244
|
|
|
181
245
|
# Lighter path for frameworks without a dev-server/browser story — just the
|
|
182
|
-
# ecosystem's own standard init command, no sub-wizard.
|
|
246
|
+
# ecosystem's own standard init command, no sub-wizard. These are all fast
|
|
247
|
+
# (no multi-minute install step), so bookkeeping-then-init is low-risk
|
|
248
|
+
# regardless of ordering, but it's kept bookkeeping-first for consistency.
|
|
183
249
|
_create_simple() {
|
|
184
250
|
local fw=$1
|
|
185
251
|
local project_dir
|
|
186
252
|
project_dir=$(_prompt_project_location "$fw")
|
|
187
|
-
|
|
188
|
-
|
|
253
|
+
_enter_project_dir "$project_dir"
|
|
254
|
+
_xgem_bookkeeping "$fw"
|
|
189
255
|
|
|
190
256
|
case "$fw" in
|
|
191
257
|
node)
|
|
@@ -206,13 +272,7 @@ _create_simple() {
|
|
|
206
272
|
;;
|
|
207
273
|
rust)
|
|
208
274
|
require_cmd cargo "Install Rust: https://www.rust-lang.org/tools/install"
|
|
209
|
-
|
|
210
|
-
cd .. || return 1
|
|
211
|
-
cargo new "$project_dir" || die "cargo new failed."
|
|
212
|
-
cd "$project_dir" || die "Could not enter $project_dir"
|
|
213
|
-
else
|
|
214
|
-
cargo init || die "cargo init failed."
|
|
215
|
-
fi
|
|
275
|
+
cargo init || die "cargo init failed."
|
|
216
276
|
;;
|
|
217
277
|
swift)
|
|
218
278
|
require_cmd swift "Install Swift: https://www.swift.org/install/"
|
|
@@ -235,15 +295,21 @@ EOF
|
|
|
235
295
|
}
|
|
236
296
|
|
|
237
297
|
# create_project_wizard <framework>
|
|
238
|
-
# Asks whether to create a new project or use what's already here
|
|
239
|
-
#
|
|
240
|
-
#
|
|
298
|
+
# Asks whether to create a new project or use what's already here. Either
|
|
299
|
+
# way, xgem's own bookkeeping (.xgem-automate + .gitignore) is guaranteed
|
|
300
|
+
# to happen — for "existing", immediately (nothing to interrupt); for
|
|
301
|
+
# "new", each creator handles it internally at the earliest safe point,
|
|
302
|
+
# per the ordering principle documented at the top of this file.
|
|
241
303
|
create_project_wizard() {
|
|
242
304
|
local fw=$1
|
|
243
305
|
local create_choice
|
|
244
306
|
read -r -p "Create a brand-new $fw project, or use what's already in this directory? [new/existing] (default: existing): " create_choice
|
|
245
307
|
create_choice=${create_choice:-existing}
|
|
246
|
-
|
|
308
|
+
|
|
309
|
+
if [[ "$create_choice" != n* && "$create_choice" != N* ]]; then
|
|
310
|
+
_xgem_bookkeeping "$fw"
|
|
311
|
+
return 0
|
|
312
|
+
fi
|
|
247
313
|
|
|
248
314
|
case "$fw" in
|
|
249
315
|
react) _create_react ;;
|
|
@@ -252,6 +318,9 @@ create_project_wizard() {
|
|
|
252
318
|
next) _create_next ;;
|
|
253
319
|
flutter) create_flutter_project ;;
|
|
254
320
|
node|python|go|rust|docker|swift) _create_simple "$fw" ;;
|
|
255
|
-
*)
|
|
321
|
+
*)
|
|
322
|
+
log_debug "No creation wizard for '$fw'; using current directory as-is."
|
|
323
|
+
_xgem_bookkeeping "$fw"
|
|
324
|
+
;;
|
|
256
325
|
esac
|
|
257
326
|
}
|
package/lib/flutter.sh
CHANGED
|
@@ -239,18 +239,20 @@ flutter_run_native_command() {
|
|
|
239
239
|
}
|
|
240
240
|
|
|
241
241
|
# create_flutter_project — used by lib/create.sh's create_project_wizard.
|
|
242
|
-
#
|
|
242
|
+
# --no-pub decouples scaffolding from the (slower, network-dependent)
|
|
243
|
+
# `flutter pub get` step, so xgem's own bookkeeping (_xgem_bookkeeping) can
|
|
244
|
+
# happen in between — same ordering principle as the other creators in
|
|
245
|
+
# lib/create.sh: bookkeeping before any slow/interruptible step, never after.
|
|
243
246
|
create_flutter_project() {
|
|
244
247
|
require_cmd flutter "Install Flutter: https://docs.flutter.dev/get-started/install"
|
|
245
248
|
local project_dir
|
|
246
249
|
project_dir=$(_prompt_project_location "Flutter")
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
fi
|
|
250
|
+
_enter_project_dir "$project_dir"
|
|
251
|
+
|
|
252
|
+
flutter create --no-pub . || die "flutter create failed."
|
|
253
|
+
_xgem_bookkeeping flutter
|
|
254
|
+
log_info "Resolving packages..."
|
|
255
|
+
flutter pub get
|
|
254
256
|
_flutter_offer_run_on_device
|
|
255
257
|
}
|
|
256
258
|
|