jekyll-theme-zer0 0.22.21 → 0.22.22

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.
@@ -0,0 +1,184 @@
1
+ #!/usr/bin/env bash
2
+ # scripts/lib/install/upgrade.sh
3
+ #
4
+ # `install upgrade` — version-aware migration over an existing site.
5
+ #
6
+ # Strategy:
7
+ # 1. Detect installed version from .zer0-installed (drop-marker) or
8
+ # _config.yml's `version:` field, or fall back to "unknown".
9
+ # 2. Print a diff-summary of what will change (theme files only — never
10
+ # touches user content under pages/, _posts/, _drafts/).
11
+ # 3. Re-runs the agent-files install (always safe, additive) and offers
12
+ # to refresh templated workflows under .github/workflows/.
13
+ # 4. Writes a fresh .zer0-installed marker with the new version + date.
14
+ #
15
+ # Public API:
16
+ # upgrade_run <target_dir> <repo_root> [--from <version>] [--force]
17
+ # [--dry-run] [--auto-accept]
18
+ #
19
+ # Bash 3.2-compatible. Idempotent. Never destructive without explicit --force.
20
+
21
+ # shellcheck disable=SC2034
22
+ UPGRADE_LIB_VERSION="1.0.0"
23
+
24
+ UPGRADE_MARKER=".zer0-installed"
25
+
26
+ # Read theme version from lib/jekyll-theme-zer0/version.rb
27
+ _upgrade_theme_version() {
28
+ local repo_root="$1"
29
+ local vfile="$repo_root/lib/jekyll-theme-zer0/version.rb"
30
+ [[ -f "$vfile" ]] || { echo "unknown"; return; }
31
+ grep -E 'VERSION\s*=' "$vfile" | head -n1 | sed -E 's/.*"([^"]+)".*/\1/'
32
+ }
33
+
34
+ # Detect the previously installed version (best-effort).
35
+ _upgrade_detect_installed() {
36
+ local target_dir="$1"
37
+ if [[ -f "$target_dir/$UPGRADE_MARKER" ]]; then
38
+ grep -E '^version:' "$target_dir/$UPGRADE_MARKER" 2>/dev/null \
39
+ | head -n1 | sed -E 's/version:[[:space:]]*//'
40
+ return
41
+ fi
42
+ # Fallback: probe _config.yml for a `version:` line
43
+ if [[ -f "$target_dir/_config.yml" ]]; then
44
+ local v
45
+ v="$(grep -E '^version:' "$target_dir/_config.yml" 2>/dev/null \
46
+ | head -n1 | sed -E 's/version:[[:space:]]*//' \
47
+ | tr -d '"' | tr -d "'")"
48
+ [[ -n "$v" ]] && { echo "$v"; return; }
49
+ fi
50
+ echo "unknown"
51
+ }
52
+
53
+ # Write/update the install marker.
54
+ _upgrade_write_marker() {
55
+ local target_dir="$1" version="$2" dry_run="$3"
56
+ local marker="$target_dir/$UPGRADE_MARKER"
57
+ local content
58
+ content="$(cat <<EOF
59
+ # zer0-mistakes install marker — do not edit manually
60
+ version: $version
61
+ upgraded_at: $(date -u +%Y-%m-%dT%H:%M:%SZ)
62
+ EOF
63
+ )"
64
+ if [[ "$dry_run" = "1" ]]; then
65
+ log_info "[dry-run] Would write marker: $marker"
66
+ return
67
+ fi
68
+ printf '%s\n' "$content" > "$marker"
69
+ log_success "Wrote $UPGRADE_MARKER (version: $version)"
70
+ }
71
+
72
+ # Re-run agents install in --force mode (theme files are safe to refresh).
73
+ _upgrade_refresh_agents() {
74
+ local target_dir="$1" repo_root="$2" force="$3" dry_run="$4"
75
+ if ! declare -F agents_install >/dev/null 2>&1; then
76
+ log_warning "agents.sh not loaded — skipping agent-file refresh"
77
+ return 0
78
+ fi
79
+ if [[ "$dry_run" = "1" ]]; then
80
+ log_info "[dry-run] Would refresh agent files in $target_dir"
81
+ return 0
82
+ fi
83
+ local force_flag=""
84
+ [[ "$force" = "1" ]] && force_flag="--force"
85
+ log_info "Refreshing AI agent files..."
86
+ agents_install "$target_dir" "$repo_root" $force_flag || true
87
+ }
88
+
89
+ # Compare a workflow file in target_dir vs theme template — list
90
+ # differences so user can decide whether to merge.
91
+ _upgrade_check_workflows() {
92
+ local target_dir="$1" repo_root="$2"
93
+ local wf_dir="$target_dir/.github/workflows"
94
+ [[ -d "$wf_dir" ]] || return 0
95
+ local f base tpl
96
+ log_info "Checking .github/workflows/ for theme-managed files..."
97
+ local found=0
98
+ for f in "$wf_dir"/*.yml "$wf_dir"/*.yaml; do
99
+ [[ -f "$f" ]] || continue
100
+ base="$(basename "$f")"
101
+ # Look for a matching template under templates/deploy/*/
102
+ for tpl in "$repo_root/templates/deploy"/*/"$base.template" \
103
+ "$repo_root/templates/deploy"/*/"$base"; do
104
+ [[ -f "$tpl" ]] || continue
105
+ found=$((found+1))
106
+ if diff -q "$f" "$tpl" >/dev/null 2>&1; then
107
+ log_success " $base — up to date"
108
+ else
109
+ log_warning " $base — differs from theme template"
110
+ log_info " Compare: diff $f $tpl"
111
+ fi
112
+ break
113
+ done
114
+ done
115
+ [[ "$found" = "0" ]] && log_info " No theme-managed workflows detected"
116
+ }
117
+
118
+ # Public entrypoint.
119
+ upgrade_run() {
120
+ local target_dir="$1" repo_root="$2"
121
+ shift 2 || true
122
+
123
+ local from_version="" force=0 dry_run=0 auto_accept=0
124
+ while [[ $# -gt 0 ]]; do
125
+ case "$1" in
126
+ --from) from_version="${2:-}"; shift ;;
127
+ -f|--force) force=1 ;;
128
+ -n|--dry-run) dry_run=1 ;;
129
+ --auto-accept) auto_accept=1 ;;
130
+ *) log_warning "upgrade_run: ignoring unknown flag: $1" ;;
131
+ esac
132
+ shift
133
+ done
134
+
135
+ if [[ ! -d "$target_dir" ]]; then
136
+ log_error "Target directory does not exist: $target_dir"
137
+ return 1
138
+ fi
139
+
140
+ local installed_version theme_version
141
+ installed_version="${from_version:-$(_upgrade_detect_installed "$target_dir")}"
142
+ theme_version="$(_upgrade_theme_version "$repo_root")"
143
+
144
+ log_info "🔧 Upgrading site at: $target_dir"
145
+ log_info " From version: $installed_version"
146
+ log_info " To version: $theme_version"
147
+ [[ "$dry_run" = "1" ]] && log_warning " Mode: dry-run (no files will be changed)"
148
+ echo
149
+
150
+ if [[ "$installed_version" = "$theme_version" ]] && [[ "$force" != "1" ]]; then
151
+ log_success "Already on $theme_version. Use --force to re-run anyway."
152
+ return 0
153
+ fi
154
+
155
+ # Confirmation gate (skipped when --auto-accept or --dry-run)
156
+ if [[ "$auto_accept" != "1" ]] && [[ "$dry_run" != "1" ]]; then
157
+ printf "Proceed with upgrade? [y/N] "
158
+ local reply
159
+ read -r reply || reply=""
160
+ case "$reply" in
161
+ y|Y|yes|YES) ;;
162
+ *) log_warning "Upgrade cancelled by user."; return 0 ;;
163
+ esac
164
+ fi
165
+
166
+ # 1. Refresh agent files (always additive/safe)
167
+ _upgrade_refresh_agents "$target_dir" "$repo_root" "$force" "$dry_run"
168
+ echo
169
+
170
+ # 2. Check workflows (read-only — never auto-overwrite)
171
+ _upgrade_check_workflows "$target_dir" "$repo_root"
172
+ echo
173
+
174
+ # 3. Write/update marker (only if not dry-run)
175
+ _upgrade_write_marker "$target_dir" "$theme_version" "$dry_run"
176
+ echo
177
+
178
+ log_success "Upgrade complete."
179
+ log_info "Next steps:"
180
+ log_info " 1. Run 'install doctor' to verify environment"
181
+ log_info " 2. Review any workflow files flagged above"
182
+ log_info " 3. Check CHANGELOG.md in the theme repo for breaking changes"
183
+ return 0
184
+ }
@@ -0,0 +1,189 @@
1
+ #!/usr/bin/env bash
2
+ # scripts/lib/install/wizard_interactive.sh
3
+ #
4
+ # Non-AI interactive wizard. Prompts the user for site config + profile,
5
+ # then dispatches to `install init` with the chosen options.
6
+ #
7
+ # Complementary to ai/wizard.sh (which uses OpenAI). This one is fully
8
+ # offline and works in any environment.
9
+ #
10
+ # Public API:
11
+ # wizard_interactive_run <target_dir> <repo_root> [--auto-accept]
12
+ #
13
+ # Bash 3.2-compatible.
14
+
15
+ # shellcheck disable=SC2034
16
+ WIZARD_INTERACTIVE_LIB_VERSION="1.0.0"
17
+
18
+ # Prompt with a default value. Returns the user's input on stdout.
19
+ # args: prompt default
20
+ _wiz_prompt() {
21
+ local prompt="$1" default="$2" reply
22
+ if [[ -n "$default" ]]; then
23
+ printf " %s [%s]: " "$prompt" "$default" >&2
24
+ else
25
+ printf " %s: " "$prompt" >&2
26
+ fi
27
+ read -r reply || reply=""
28
+ [[ -z "$reply" ]] && reply="$default"
29
+ printf '%s\n' "$reply"
30
+ }
31
+
32
+ # Prompt for a yes/no answer. Returns 0 for yes, 1 for no.
33
+ # args: prompt default(y|n)
34
+ _wiz_confirm() {
35
+ local prompt="$1" default="${2:-n}" reply hint
36
+ case "$default" in
37
+ y|Y) hint="[Y/n]" ;;
38
+ *) hint="[y/N]" ;;
39
+ esac
40
+ printf " %s %s: " "$prompt" "$hint" >&2
41
+ read -r reply || reply=""
42
+ [[ -z "$reply" ]] && reply="$default"
43
+ case "$reply" in
44
+ y|Y|yes|YES) return 0 ;;
45
+ *) return 1 ;;
46
+ esac
47
+ }
48
+
49
+ # Pick from a numbered list. Returns the chosen value on stdout.
50
+ # args: prompt default option1 option2 ...
51
+ _wiz_choose() {
52
+ local prompt="$1" default="$2"
53
+ shift 2
54
+ local options=("$@")
55
+ local i=1 opt
56
+ echo " $prompt" >&2
57
+ for opt in "${options[@]}"; do
58
+ if [[ "$opt" = "$default" ]]; then
59
+ printf " %d) %s (default)\n" "$i" "$opt" >&2
60
+ else
61
+ printf " %d) %s\n" "$i" "$opt" >&2
62
+ fi
63
+ i=$((i+1))
64
+ done
65
+ printf " Choice [%s]: " "$default" >&2
66
+ local reply
67
+ read -r reply || reply=""
68
+ [[ -z "$reply" ]] && { printf '%s\n' "$default"; return; }
69
+ # Numeric or by-name
70
+ case "$reply" in
71
+ ''|*[!0-9]*)
72
+ # by name; verify it exists
73
+ for opt in "${options[@]}"; do
74
+ [[ "$opt" = "$reply" ]] && { printf '%s\n' "$reply"; return; }
75
+ done
76
+ printf '%s\n' "$default" ;;
77
+ *)
78
+ local idx=$((reply))
79
+ if (( idx >= 1 && idx <= ${#options[@]} )); then
80
+ printf '%s\n' "${options[$((idx-1))]}"
81
+ else
82
+ printf '%s\n' "$default"
83
+ fi ;;
84
+ esac
85
+ }
86
+
87
+ # Public entrypoint.
88
+ wizard_interactive_run() {
89
+ local target_dir="$1" repo_root="$2"
90
+ shift 2 || true
91
+ local auto_accept=0
92
+ while [[ $# -gt 0 ]]; do
93
+ case "$1" in
94
+ --auto-accept) auto_accept=1 ;;
95
+ *) log_warning "wizard_interactive_run: ignoring unknown flag: $1" ;;
96
+ esac
97
+ shift
98
+ done
99
+
100
+ log_info "🧙 Interactive wizard (non-AI)"
101
+ log_info " This wizard collects site settings and runs 'install init'."
102
+ log_info " Press Enter to accept defaults shown in [brackets]."
103
+ echo
104
+
105
+ # Discover available profiles dynamically if loader is present.
106
+ local default_profile="full"
107
+ local profiles_csv="minimal full fork github remote"
108
+ if declare -F list_profile_names >/dev/null 2>&1; then
109
+ local discovered
110
+ discovered="$(list_profile_names "$repo_root" 2>/dev/null | tr '\n' ' ')"
111
+ [[ -n "$discovered" ]] && profiles_csv="$discovered"
112
+ fi
113
+ # shellcheck disable=SC2206
114
+ local profile_options=( $profiles_csv )
115
+
116
+ log_info "── Site basics ──────────────────────────"
117
+ local site_name site_desc author email
118
+ site_name="$(_wiz_prompt "Site name" "$(basename "$target_dir")")"
119
+ site_desc="$(_wiz_prompt "Description" "A Jekyll site powered by zer0-mistakes")"
120
+ author="$(_wiz_prompt "Author name" "${USER:-author}")"
121
+ email="$(_wiz_prompt "Author email" "${USER:-author}@example.com")"
122
+ echo
123
+
124
+ log_info "── Profile ──────────────────────────────"
125
+ local profile
126
+ profile="$(_wiz_choose "Choose an install profile:" "$default_profile" "${profile_options[@]}")"
127
+ echo
128
+
129
+ log_info "── Optional integrations ────────────────"
130
+ local want_agents=0 want_docker=0
131
+ _wiz_confirm "Install AI agent guidance files?" "y" && want_agents=1
132
+ _wiz_confirm "Add docker-prod deploy target?" "n" && want_docker=1
133
+ echo
134
+
135
+ log_info "── Summary ──────────────────────────────"
136
+ log_info " Target dir: $target_dir"
137
+ log_info " Site name: $site_name"
138
+ log_info " Description: $site_desc"
139
+ log_info " Author: $author <$email>"
140
+ log_info " Profile: $profile"
141
+ log_info " Agents: $([ "$want_agents" = "1" ] && echo yes || echo no)"
142
+ log_info " docker-prod: $([ "$want_docker" = "1" ] && echo yes || echo no)"
143
+ echo
144
+
145
+ if [[ "$auto_accept" != "1" ]]; then
146
+ if ! _wiz_confirm "Proceed with these settings?" "y"; then
147
+ log_warning "Wizard cancelled."
148
+ return 0
149
+ fi
150
+ fi
151
+
152
+ # Export for any downstream consumers (legacy install.sh reads SITE_NAME etc.)
153
+ export SITE_NAME="$site_name"
154
+ export SITE_DESCRIPTION="$site_desc"
155
+ export AUTHOR_NAME="$author"
156
+ export AUTHOR_EMAIL="$email"
157
+
158
+ # Dispatch
159
+ local install_bin="$repo_root/scripts/bin/install"
160
+ if [[ ! -x "$install_bin" ]]; then
161
+ log_error "Cannot find $install_bin"
162
+ return 1
163
+ fi
164
+
165
+ log_info "Running: install init --profile $profile $target_dir"
166
+ "$install_bin" init --profile "$profile" --skip-doctor "$target_dir" || {
167
+ log_error "init failed"
168
+ return 1
169
+ }
170
+
171
+ if [[ "$want_agents" = "1" ]]; then
172
+ echo
173
+ log_info "Running: install agents $target_dir"
174
+ "$install_bin" agents "$target_dir" || log_warning "agents install reported issues"
175
+ fi
176
+
177
+ if [[ "$want_docker" = "1" ]]; then
178
+ echo
179
+ log_info "Running: install deploy docker-prod $target_dir"
180
+ "$install_bin" deploy docker-prod "$target_dir" || log_warning "docker-prod install reported issues"
181
+ fi
182
+
183
+ echo
184
+ log_success "Wizard complete!"
185
+ log_info "Next steps:"
186
+ log_info " cd $target_dir"
187
+ log_info " docker compose up # or: bundle exec jekyll serve"
188
+ return 0
189
+ }
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jekyll-theme-zer0
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.22.21
4
+ version: 0.22.22
5
5
  platform: ruby
6
6
  authors:
7
7
  - Amr Abdel
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-04-19 00:00:00.000000000 Z
11
+ date: 2026-04-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: jekyll
@@ -355,6 +355,7 @@ files:
355
355
  - scripts/README.md
356
356
  - scripts/analyze-commits.sh
357
357
  - scripts/bin/build
358
+ - scripts/bin/install
358
359
  - scripts/bin/release
359
360
  - scripts/bin/test
360
361
  - scripts/build
@@ -378,6 +379,27 @@ files:
378
379
  - scripts/lib/frontmatter.sh
379
380
  - scripts/lib/gem.sh
380
381
  - scripts/lib/git.sh
382
+ - scripts/lib/install/README.md
383
+ - scripts/lib/install/agents.sh
384
+ - scripts/lib/install/ai/diagnose.sh
385
+ - scripts/lib/install/ai/openai.sh
386
+ - scripts/lib/install/ai/suggest.sh
387
+ - scripts/lib/install/ai/wizard.sh
388
+ - scripts/lib/install/config.sh
389
+ - scripts/lib/install/deploy/README.md
390
+ - scripts/lib/install/deploy/azure-swa.sh
391
+ - scripts/lib/install/deploy/docker-prod.sh
392
+ - scripts/lib/install/deploy/github-pages.sh
393
+ - scripts/lib/install/deploy/registry.sh
394
+ - scripts/lib/install/doctor.sh
395
+ - scripts/lib/install/fs.sh
396
+ - scripts/lib/install/logging.sh
397
+ - scripts/lib/install/pages.sh
398
+ - scripts/lib/install/platform.sh
399
+ - scripts/lib/install/profile.sh
400
+ - scripts/lib/install/template.sh
401
+ - scripts/lib/install/upgrade.sh
402
+ - scripts/lib/install/wizard_interactive.sh
381
403
  - scripts/lib/migrate.sh
382
404
  - scripts/lib/preview_generator.py
383
405
  - scripts/lib/template.sh