diff --git a/.changeset/README.md b/.changeset/README.md new file mode 100644 index 0000000..05b3e78 --- /dev/null +++ b/.changeset/README.md @@ -0,0 +1,5 @@ +# Changesets + +Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works +with multi-package repos, or single-package repos to help you version and publish your code. You can find +the full documentation for it [in the changesets repo](https://github.com/changesets/changesets). diff --git a/.changeset/config.json b/.changeset/config.json new file mode 100644 index 0000000..a6e4a9d --- /dev/null +++ b/.changeset/config.json @@ -0,0 +1,11 @@ +{ + "$schema": "https://unpkg.com/@changesets/config@3.1.3/schema.json", + "changelog": "@changesets/cli/changelog", + "commit": false, + "fixed": [], + "linked": [], + "access": "restricted", + "baseBranch": "main", + "updateInternalDependencies": "patch", + "ignore": [] +} diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..6cbbef0 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,132 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +## [Unreleased] + +### πŸš€ Features + +- V2 phase 1 β€” array access, timer, string interpolation +- Step sequencer demo β€” reactive pads, playhead, BPM +- V2 built-in functions β€” 90+ native functions +- V2 module system β€” import/export with multi-file compilation +- V2 codegen hardening β€” scoped local variables +- Todo app demo β€” streamable, showcases v2 builtins +- Bidirectional signal streaming sync +- Peer mode relay + self-echo filtering for true bidirectional sync +- Per-signal version counters for conflict resolution +- Explicit signal output API for stream declarations +- 4-app signal composition demo with explicit outputs +- Chained signal composition β€” 3β†’1β†’final + mood mixing +- Stream composition API β€” select, schema, relay filtering +- Dependent types β€” refinement types, type aliases, type annotations +- Dependent types review β€” cycle detection, precision, error quality +- Component registry with styled variants, dreamstack add/convert CLI, and showcase +- Container variant props, 11-component registry, rich dashboard +- Each loop, dreamstack init, expanded registry +- When/else conditional branching +- Slot/children composition for components +- Dev server improvements - recursive watching, auto-open browser +- Dynamic lists (push/remove/pop) + TodoMVC demo +- Component event callbacks + function prop forwarding +- Upgrade init starter app to showcase all DreamStack features +- Multi-page routing demo with 4 routes +- Project Manager demo β€” comprehensive 4-page routed app +- Multi-statement event handlers with semicolons +- Streaming dashboard with imported components + live data +- Comprehensive streaming improvements +- HTTP /meta API, signal dedup, periodic auto-sync +- Enhanced 14 registry components + component gallery +- Expanded variant system β€” 30+ new CSS class mappings +- *= /= operators + 6 new array methods +- Snake game streaming via relay +- Game-pong.ds + two compiler improvements +- Keyboard input, Web Audio synthesis, and multiplayer demo +- Pong spectator viewer + stream proxy reactivity fix +- Beats viewer, score sounds, audio early-exit guards +- Core language & stream improvements +- Complete type system β€” HM unification, signal-aware types, effect scoping +- Tetris β€” signal composition showcase with 6 reactive layers +- Live signal debug panel for tetris +- Full grid collision, freeze, and T-piece support (20 rows) +- Complete tetris rewrite β€” flat grid, SRS rotation, ghost piece toggle +- Add Waveshare P4 panel device integration with display streaming and touch input, alongside core streaming engine +- Implement Panel IR emitter to generate JSON UI descriptions for LVGL panels. +- Implement ds-screencast engine, panel preview, and Waveshare ESP-NOW communication. + +### πŸ› Bug Fixes + +- Bidirectional streaming sync β€” phoneβ†’laptop now works +- Add _streamDiff to push/pop/reverse built-ins +- Streaming polish β€” bind diff, state snapshot, dead code cleanup +- Signal composition β€” stream derived signals, fix identity check, correct relay routing +- Use explicit /peer/counter channel for streaming-counter +- Integer division + streaming restart +- Component prop signal wrapping + import demo +- When/else parentNode null guard for slot context + match parser boundaries + showcase demo +- Match parser allows container bodies in arms +- Merge duplicate click props + upgrade streaming examples +- For-in parser token mismatch + enhanced step sequencer +- Reactive component props + breakout improvements +- Tetris collision detection β€” pieces now stack properly +- Collision off-by-one β€” pieces now stack adjacently +- Keyboard inputs now respect collision β€” soft drop and hard drop gated on blocked +- Complete collision β€” checks both top row and bottom cell +- Piece-type aware collision β€” only T-piece checks bottom cell +- No-overlap rendering β€” hide foot cell for non-T pieces, render all 20 rows +- I-piece now persists all 4 cells and renders at correct row + +### πŸ”§ Refactoring + +- Type system second pass β€” deeper unification throughout +- Complete collision system rewrite β€” decomposed sub-signals + +### πŸ“š Documentation + +- Add STREAM_COMPOSITION.md β€” full API reference and protocol spec +- Comprehensive documentation update + +### ⚑ Performance + +- Streaming core improvements β€” batched diffs, RTT tracking, relay merging +- Merge same-interval timers + breakout game + beats viewer + +## [0.1.0] - 2026-02-26 + +### πŸš€ Features + +- Add DreamStack project vision and detailed implementation plan documentation. +- DreamStack compiler foundation β€” Phase 0/1 +- TodoMVC example with full reactivity +- Phase 2+3 β€” effects, streams, springs, search + dashboard +- Phase 3+4 β€” Cassowary constraint solver + type system +- Phase 5 β€” Live Playground with editor, preview, signal graph, console +- Showcase β€” What DreamStack Does That Nothing Else Can +- Dev server with file watching + poll-based HMR +- Signal propagation benchmarks + dev server HMR fix +- For-in list rendering + component system +- Hash-based router + keyed list reconciliation +- Two-way binding, form props, and async resources +- Universal bitstream streaming β€” any input β†’ any output +- Physics language integration β€” scene container with Rapier2D WASM +- **ds-stream:** RLE compression, input events, keyframe caching +- **demos:** Sync protocol with Rust codec, add touch/gamepad support +- **compiler:** Full bitstream integration across 7 pipeline stages +- **compiler:** Complete bitstream integration β€” all 9 changes +- **examples:** Add streaming .ds examples β€” compiler-native streaming +- **wasm:** Add ds-stream-wasm crate β€” browser codec via WebAssembly +- **relay:** Multi-source routing β€” /source/{name} and /stream/{name} +- **examples:** Add streaming-physics.ds, mark all roadmap items complete +- WebRTC transport β€” peer-to-peer data channels with auto-fallback +- Production hardening β€” relay v1.0.0, receiver protocol completeness + +### πŸ“š Documentation + +- Add implementation status, benchmarks, and React comparison to DREAMSTACK.md +- Add router to DREAMSTACK.md features and comparison +- Mark all integration spec changes as implemented, update test counts +- Add Next Steps roadmap (Phases A-C) to integration spec +- Add compiler-native streaming syntax to language reference +- Add USE_CASES.md β€” vision, revenue paths, and demo roadmap + + diff --git a/Cargo.toml b/Cargo.toml index f4e7f6d..b67afce 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,7 +17,7 @@ members = [ [workspace.package] version = "0.1.0" edition = "2024" -license = "MIT" +license = "" [workspace.dependencies] ds-parser = { path = "compiler/ds-parser" } diff --git a/cliff.toml b/cliff.toml new file mode 100644 index 0000000..6175cff --- /dev/null +++ b/cliff.toml @@ -0,0 +1,66 @@ +# git-cliff configuration for DreamStack +# https://git-cliff.org/docs/configuration +# +# Per-package changelogs: +# git-cliff --include-path "compiler/ds-parser/**" -o compiler/ds-parser/CHANGELOG.md +# git-cliff --include-path "engine/ds-stream/**" -o engine/ds-stream/CHANGELOG.md +# +# Full workspace changelog: +# git-cliff -o CHANGELOG.md + +[changelog] +header = """ +# Changelog + +All notable changes to this project will be documented in this file. + +""" +body = """ +{% if version -%} + ## [{{ version | trim_start_matches(pat="v") }}] - {{ timestamp | date(format="%Y-%m-%d") }} +{% else -%} + ## [Unreleased] +{% endif -%} + +{% for group, commits in commits | group_by(attribute="group") %} + ### {{ group | striptags | trim | upper_first }} + {% for commit in commits %} + - {% if commit.scope %}**{{ commit.scope }}:** {% endif %}\ + {% if commit.breaking %}[**BREAKING**] {% endif %}\ + {{ commit.message | upper_first }} + {%- endfor %} +{% endfor %}\n +""" +footer = """ + +""" +trim = true + +[git] +conventional_commits = true +filter_unconventional = true +split_commits = false +commit_preprocessors = [ + # Truncate overly long commit messages to keep the changelog scannable + { pattern = "^(.{0,120}).*$", replace = "$1" }, +] +commit_parsers = [ + { message = "^feat", group = "πŸš€ Features" }, + { message = "^fix", group = "πŸ› Bug Fixes" }, + { message = "^refactor", group = "πŸ”§ Refactoring" }, + { message = "^doc", group = "πŸ“š Documentation" }, + { message = "^perf", group = "⚑ Performance" }, + { message = "^improve", group = "πŸš€ Features" }, + { message = "^refine", group = "πŸ”§ Refactoring" }, + { message = "^style", group = "🎨 Styling" }, + { message = "^test", group = "πŸ§ͺ Testing" }, + { message = "^chore\\(release\\)", skip = true }, + { message = "^chore\\(deps\\)", skip = true }, + { message = "^chore|^ci", group = "βš™οΈ Miscellaneous" }, + { body = ".*security", group = "πŸ”’ Security" }, +] +protect_breaking_commits = false +filter_commits = false +topo_order = false +sort_commits = "oldest" +tag_pattern = "v[0-9].*" diff --git a/compiler/ds-analyzer/CHANGELOG.md b/compiler/ds-analyzer/CHANGELOG.md new file mode 100644 index 0000000..54813ca --- /dev/null +++ b/compiler/ds-analyzer/CHANGELOG.md @@ -0,0 +1,11 @@ +# Changelog + +All notable changes to this package will be documented in this file. + +## [Unreleased] + +## [0.1.0] - 2026-02-26 + +### πŸš€ Features + +- Initial release β€” Signal graph extraction, source/derived classification, topological sort, DOM binding analysis diff --git a/compiler/ds-analyzer/Cargo.toml b/compiler/ds-analyzer/Cargo.toml index d1dd536..26aedfc 100644 --- a/compiler/ds-analyzer/Cargo.toml +++ b/compiler/ds-analyzer/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ds-analyzer" -version.workspace = true +version = "0.1.0" edition.workspace = true [dependencies] diff --git a/compiler/ds-cli/CHANGELOG.md b/compiler/ds-cli/CHANGELOG.md new file mode 100644 index 0000000..4f9e641 --- /dev/null +++ b/compiler/ds-cli/CHANGELOG.md @@ -0,0 +1,11 @@ +# Changelog + +All notable changes to this package will be documented in this file. + +## [Unreleased] + +## [0.1.0] - 2026-02-26 + +### πŸš€ Features + +- Initial release β€” CLI with build, dev, check, stream, init, add, convert commands diff --git a/compiler/ds-cli/Cargo.toml b/compiler/ds-cli/Cargo.toml index 058d81f..365f9e4 100644 --- a/compiler/ds-cli/Cargo.toml +++ b/compiler/ds-cli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ds-cli" -version.workspace = true +version = "0.1.0" edition.workspace = true [[bin]] diff --git a/compiler/ds-codegen/CHANGELOG.md b/compiler/ds-codegen/CHANGELOG.md new file mode 100644 index 0000000..198351e --- /dev/null +++ b/compiler/ds-codegen/CHANGELOG.md @@ -0,0 +1,11 @@ +# Changelog + +All notable changes to this package will be documented in this file. + +## [Unreleased] + +## [0.1.0] - 2026-02-26 + +### πŸš€ Features + +- Initial release β€” JavaScript emitter, reactive runtime, CSS design system, component codegen, streaming layer diff --git a/compiler/ds-codegen/Cargo.toml b/compiler/ds-codegen/Cargo.toml index 0a95c2f..3ba2847 100644 --- a/compiler/ds-codegen/Cargo.toml +++ b/compiler/ds-codegen/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ds-codegen" -version.workspace = true +version = "0.1.0" edition.workspace = true [dependencies] diff --git a/compiler/ds-incremental/CHANGELOG.md b/compiler/ds-incremental/CHANGELOG.md new file mode 100644 index 0000000..d299223 --- /dev/null +++ b/compiler/ds-incremental/CHANGELOG.md @@ -0,0 +1,11 @@ +# Changelog + +All notable changes to this package will be documented in this file. + +## [Unreleased] + +## [0.1.0] - 2026-02-26 + +### πŸš€ Features + +- Initial release β€” Incremental compilation support diff --git a/compiler/ds-incremental/Cargo.toml b/compiler/ds-incremental/Cargo.toml index d6ef6f4..2b103ea 100644 --- a/compiler/ds-incremental/Cargo.toml +++ b/compiler/ds-incremental/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ds-incremental" -version.workspace = true +version = "0.1.0" edition.workspace = true [dependencies] diff --git a/compiler/ds-layout/CHANGELOG.md b/compiler/ds-layout/CHANGELOG.md new file mode 100644 index 0000000..a7c24f0 --- /dev/null +++ b/compiler/ds-layout/CHANGELOG.md @@ -0,0 +1,11 @@ +# Changelog + +All notable changes to this package will be documented in this file. + +## [Unreleased] + +## [0.1.0] - 2026-02-26 + +### πŸš€ Features + +- Initial release β€” Cassowary constraint solver with eq/gte/lte/sum_eq/ratio constraints diff --git a/compiler/ds-parser/CHANGELOG.md b/compiler/ds-parser/CHANGELOG.md new file mode 100644 index 0000000..dc7e425 --- /dev/null +++ b/compiler/ds-parser/CHANGELOG.md @@ -0,0 +1,11 @@ +# Changelog + +All notable changes to this package will be documented in this file. + +## [Unreleased] + +## [0.1.0] - 2026-02-26 + +### πŸš€ Features + +- Initial release β€” Lexer, recursive descent parser, AST types, operator precedence, string interpolation diff --git a/compiler/ds-parser/Cargo.toml b/compiler/ds-parser/Cargo.toml index 8a2182e..09bd4d2 100644 --- a/compiler/ds-parser/Cargo.toml +++ b/compiler/ds-parser/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ds-parser" -version.workspace = true +version = "0.1.0" edition.workspace = true [dependencies] diff --git a/compiler/ds-types/CHANGELOG.md b/compiler/ds-types/CHANGELOG.md new file mode 100644 index 0000000..15d6bd3 --- /dev/null +++ b/compiler/ds-types/CHANGELOG.md @@ -0,0 +1,11 @@ +# Changelog + +All notable changes to this package will be documented in this file. + +## [Unreleased] + +## [0.1.0] - 2026-02-26 + +### πŸš€ Features + +- Initial release β€” Hindley-Milner type checker, Signal/Derived/Stream/Spring/View types, Elm-style errors diff --git a/engine/ds-physics/CHANGELOG.md b/engine/ds-physics/CHANGELOG.md new file mode 100644 index 0000000..e60efbc --- /dev/null +++ b/engine/ds-physics/CHANGELOG.md @@ -0,0 +1,11 @@ +# Changelog + +All notable changes to this package will be documented in this file. + +## [Unreleased] + +## [0.1.0] - 2026-02-26 + +### πŸš€ Features + +- Initial release β€” Rapier2D WASM integration, scene container, reactive physics bodies diff --git a/engine/ds-physics/Cargo.toml b/engine/ds-physics/Cargo.toml index 2f8b0e3..29e3f6c 100644 --- a/engine/ds-physics/Cargo.toml +++ b/engine/ds-physics/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ds-physics" -version.workspace = true +version = "0.1.0" edition.workspace = true license.workspace = true diff --git a/engine/ds-stream-wasm/CHANGELOG.md b/engine/ds-stream-wasm/CHANGELOG.md new file mode 100644 index 0000000..3686e5d --- /dev/null +++ b/engine/ds-stream-wasm/CHANGELOG.md @@ -0,0 +1,11 @@ +# Changelog + +All notable changes to this package will be documented in this file. + +## [Unreleased] + +## [0.1.0] - 2026-02-26 + +### πŸš€ Features + +- Initial release β€” Browser WASM codec for ds-stream protocol diff --git a/engine/ds-stream-wasm/Cargo.toml b/engine/ds-stream-wasm/Cargo.toml index b039b80..eec70d0 100644 --- a/engine/ds-stream-wasm/Cargo.toml +++ b/engine/ds-stream-wasm/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ds-stream-wasm" -version.workspace = true +version = "0.1.0" edition.workspace = true license.workspace = true description = "WebAssembly codec for DreamStack bitstream protocol" diff --git a/engine/ds-stream/CHANGELOG.md b/engine/ds-stream/CHANGELOG.md new file mode 100644 index 0000000..d26bc16 --- /dev/null +++ b/engine/ds-stream/CHANGELOG.md @@ -0,0 +1,11 @@ +# Changelog + +All notable changes to this package will be documented in this file. + +## [Unreleased] + +## [0.1.0] - 2026-02-26 + +### πŸš€ Features + +- Initial release β€” Binary streaming protocol, WebSocket relay, RLE/XOR codecs, peer mode, channel routing diff --git a/engine/ds-stream/Cargo.toml b/engine/ds-stream/Cargo.toml index d2a191d..21dad47 100644 --- a/engine/ds-stream/Cargo.toml +++ b/engine/ds-stream/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ds-stream" -version.workspace = true +version = "0.1.0" edition.workspace = true license.workspace = true description = "Universal bitstream streaming β€” any input to any output" diff --git a/scripts/release.sh b/scripts/release.sh new file mode 100755 index 0000000..42c7a21 --- /dev/null +++ b/scripts/release.sh @@ -0,0 +1,356 @@ +#!/usr/bin/env bash +# +# DreamStack Release Script +# +# Reads .changeset/*.md files (YAML frontmatter with package bump types), +# bumps per-package versions, regenerates changelogs, commits, and tags. +# +# Usage: +# ./scripts/release.sh # apply changesets +# ./scripts/release.sh --dry-run # preview without committing +# ./scripts/release.sh --all # bump all packages (patch|minor|major) +# +set -euo pipefail + +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +CYAN='\033[0;36m' +NC='\033[0m' + +ROOT_DIR="$(cd "$(dirname "$0")/.." && pwd)" +WORKSPACE_TOML="$ROOT_DIR/Cargo.toml" +CHANGELOG="$ROOT_DIR/CHANGELOG.md" +CHANGESET_DIR="$ROOT_DIR/.changeset" + +DRY_RUN=false +BUMP_ALL="" + +# ── Package registry ───────────────────────────────────────────────── +# name:path pairs for all workspace crates +declare -A PKG_PATH=( + [ds-parser]="compiler/ds-parser" + [ds-analyzer]="compiler/ds-analyzer" + [ds-codegen]="compiler/ds-codegen" + [ds-layout]="compiler/ds-layout" + [ds-types]="compiler/ds-types" + [ds-incremental]="compiler/ds-incremental" + [ds-cli]="compiler/ds-cli" + [ds-physics]="engine/ds-physics" + [ds-stream]="engine/ds-stream" + [ds-stream-wasm]="engine/ds-stream-wasm" +) + +# ── Parse flags ────────────────────────────────────────────────────── + +while [[ $# -gt 0 ]]; do + case "$1" in + --dry-run) DRY_RUN=true; shift ;; + --all) + shift + if [[ -z "${1:-}" ]]; then + echo -e "${RED}Error:${NC} --all requires a bump type (patch|minor|major)" + exit 1 + fi + BUMP_ALL="$1"; shift + ;; + *) echo -e "${RED}Error:${NC} Unknown argument: $1"; exit 1 ;; + esac +done + +# ── Helpers ────────────────────────────────────────────────────────── + +get_pkg_version() { + local cargo_toml="$1/Cargo.toml" + grep '^version' "$cargo_toml" | head -1 | sed 's/.*"\(.*\)".*/\1/' +} + +bump_version() { + local current="$1" bump="$2" + local major minor patch + IFS='.' read -r major minor patch <<< "$current" + case "$bump" in + major) echo "$((major + 1)).0.0" ;; + minor) echo "$major.$((minor + 1)).0" ;; + patch) echo "$major.$minor.$((patch + 1))" ;; + *) echo "" ;; + esac +} + +set_pkg_version() { + local cargo_toml="$1/Cargo.toml" + local old_ver="$2" new_ver="$3" + sed -i "0,/^version = \"$old_ver\"/s//version = \"$new_ver\"/" "$cargo_toml" +} + +# ── Parse changesets ───────────────────────────────────────────────── +# Reads YAML frontmatter from .changeset/*.md files +# Format: +# --- +# "ds-parser": minor +# "ds-codegen": patch +# --- +# Description of the change. + +declare -A BUMPS # package -> highest bump (major > minor > patch) +declare -a DESCRIPTIONS # changeset descriptions + +BUMP_RANK_patch=1 +BUMP_RANK_minor=2 +BUMP_RANK_major=3 + +higher_bump() { + local current="$1" candidate="$2" + if [[ -z "$current" ]]; then echo "$candidate"; return; fi + local cur_rank="BUMP_RANK_$current" + local cand_rank="BUMP_RANK_$candidate" + if [[ "${!cand_rank}" -gt "${!cur_rank}" ]]; then + echo "$candidate" + else + echo "$current" + fi +} + +parse_changesets() { + shopt -s nullglob + local files=("$CHANGESET_DIR"/*.md) + shopt -u nullglob + + for f in "${files[@]}"; do + [[ "$(basename "$f")" == "README.md" ]] && continue + + local in_frontmatter=false + local description="" + + while IFS= read -r line; do + if [[ "$line" == "---" ]]; then + if [[ "$in_frontmatter" == false ]]; then + in_frontmatter=true + continue + else + in_frontmatter=false + continue + fi + fi + + if [[ "$in_frontmatter" == true ]]; then + # Parse: "pkg-name": bump_type + local pkg bump + pkg=$(echo "$line" | sed -n 's/^"\([^"]*\)":.*/\1/p') + bump=$(echo "$line" | sed -n 's/^"[^"]*": *\(.*\)/\1/p' | tr -d ' ') + if [[ -n "$pkg" && -n "$bump" ]]; then + BUMPS[$pkg]=$(higher_bump "${BUMPS[$pkg]:-}" "$bump") + fi + else + if [[ -n "$line" ]]; then + description+="$line"$'\n' + fi + fi + done < "$f" + + if [[ -n "$description" ]]; then + DESCRIPTIONS+=("$description") + fi + done +} + +# ── Collect bumps ──────────────────────────────────────────────────── + +DESCRIPTIONS=() + +if [[ -n "$BUMP_ALL" ]]; then + for pkg in "${!PKG_PATH[@]}"; do + BUMPS[$pkg]="$BUMP_ALL" + done + echo -e "${CYAN}Bumping all packages:${NC} $BUMP_ALL" +else + parse_changesets +fi + +if [[ ${#BUMPS[@]} -eq 0 ]]; then + echo -e "${YELLOW}No changesets found.${NC} Nothing to release." + echo "Add changesets in .changeset/ or use --all " + exit 0 +fi + +# ── Preview ────────────────────────────────────────────────────────── + +echo -e "${CYAN}DreamStack Release${NC}" +echo "" + +for pkg in $(echo "${!BUMPS[@]}" | tr ' ' '\n' | sort); do + local_path="${PKG_PATH[$pkg]:-}" + if [[ -z "$local_path" ]]; then + echo -e " ${YELLOW}⚠${NC} Unknown package: $pkg (skipping)" + continue + fi + + current=$(get_pkg_version "$ROOT_DIR/$local_path") + new=$(bump_version "$current" "${BUMPS[$pkg]}") + echo -e " ${GREEN}$pkg${NC} $current β†’ $new (${BUMPS[$pkg]})" +done + +echo "" + +if [[ ${#DESCRIPTIONS[@]} -gt 0 ]]; then + echo -e "${CYAN}Changeset descriptions:${NC}" + for desc in "${DESCRIPTIONS[@]}"; do + echo " - $(echo "$desc" | head -1)" + done + echo "" +fi + +if [[ "$DRY_RUN" == true ]]; then + echo -e "${YELLOW}[DRY RUN]${NC} No changes made." + exit 0 +fi + +# ── Check prerequisites ───────────────────────────────────────────── + +if ! command -v git-cliff &>/dev/null; then + echo -e "${RED}Error:${NC} git-cliff not found. Install with: cargo install git-cliff" + exit 1 +fi + +if [[ -n "$(git -C "$ROOT_DIR" status --porcelain)" ]]; then + echo -e "${RED}Error:${NC} Working directory is not clean. Commit or stash changes first." + exit 1 +fi + +# ── Step 1: Bump per-package versions ──────────────────────────────── + +echo -e "${GREEN}β†’${NC} Bumping package versions..." + +HIGHEST_BUMP="" +for pkg in "${!BUMPS[@]}"; do + local_path="${PKG_PATH[$pkg]:-}" + [[ -z "$local_path" ]] && continue + + pkg_dir="$ROOT_DIR/$local_path" + current=$(get_pkg_version "$pkg_dir") + new=$(bump_version "$current" "${BUMPS[$pkg]}") + + if [[ -z "$new" ]]; then + echo -e " ${RED}βœ—${NC} $pkg β€” invalid bump '${BUMPS[$pkg]}'" + continue + fi + + set_pkg_version "$pkg_dir" "$current" "$new" + echo -e " ${GREEN}βœ“${NC} $pkg $current β†’ $new" + + HIGHEST_BUMP=$(higher_bump "$HIGHEST_BUMP" "${BUMPS[$pkg]}") +done + +# ── Step 2: Bump workspace version ────────────────────────────────── + +WORKSPACE_VERSION=$(grep -A2 '^\[workspace\.package\]' "$WORKSPACE_TOML" \ + | grep '^version' | sed 's/version = "\(.*\)"/\1/') +NEW_WORKSPACE=$(bump_version "$WORKSPACE_VERSION" "$HIGHEST_BUMP") + +if [[ -n "$NEW_WORKSPACE" ]]; then + sed -i "s/^version = \"$WORKSPACE_VERSION\"/version = \"$NEW_WORKSPACE\"/" "$WORKSPACE_TOML" + echo -e " ${GREEN}βœ“${NC} workspace $WORKSPACE_VERSION β†’ $NEW_WORKSPACE" +fi + +VERSION_TAG="v${NEW_WORKSPACE:-$WORKSPACE_VERSION}" + +# ── Step 3: Generate root changelog ───────────────────────────────── + +echo -e "${GREEN}β†’${NC} Generating root changelog..." +git-cliff --config "$ROOT_DIR/cliff.toml" --tag "$VERSION_TAG" --output "$CHANGELOG" + +# ── Step 4: Update per-package changelogs from changesets ───────────── +# Writes changeset descriptions into each affected crate's CHANGELOG.md +# under the new version heading. This avoids git-cliff's --include-path +# limitation where tag boundaries are lost if the tag commit doesn't +# touch the crate's files. + +echo -e "${GREEN}β†’${NC} Updating per-package changelogs..." +updated=0 + +for pkg in "${!BUMPS[@]}"; do + local_path="${PKG_PATH[$pkg]:-}" + [[ -z "$local_path" ]] && continue + + pkg_dir="$ROOT_DIR/$local_path" + pkg_changelog="$pkg_dir/CHANGELOG.md" + new_ver=$(bump_version "$(get_pkg_version "$pkg_dir")" "${BUMPS[$pkg]}") + today=$(date +%Y-%m-%d) + + # Collect descriptions from changesets that mention this package + pkg_entries="" + for desc in "${DESCRIPTIONS[@]}"; do + pkg_entries+="- $desc" + done + + # If --all with no changesets, add a generic entry + if [[ -z "$pkg_entries" && -n "$BUMP_ALL" ]]; then + pkg_entries="- Version bump"$'\n' + fi + + # Build the new version section + version_section="## [$new_ver] - $today"$'\n'$'\n' + if [[ -n "$pkg_entries" ]]; then + version_section+="### πŸš€ Changes"$'\n'$'\n' + version_section+="$pkg_entries"$'\n' + fi + + if [[ -f "$pkg_changelog" ]]; then + # Insert new version section after "## [Unreleased]" line + TEMP_FILE=$(mktemp) + awk -v section="$version_section" ' + /^## \[Unreleased\]/ { + print + print "" + printf "%s", section + next + } + { print } + ' "$pkg_changelog" > "$TEMP_FILE" + mv "$TEMP_FILE" "$pkg_changelog" + else + # Create changelog from scratch + cat > "$pkg_changelog" << EOF +# Changelog + +All notable changes to this package will be documented in this file. + +## [Unreleased] + +$version_section +EOF + fi + + updated=$((updated + 1)) + echo -e " ${GREEN}βœ“${NC} $pkg β†’ $new_ver" +done +echo -e " Updated ${GREEN}$updated${NC} package changelogs" + +# ── Step 5: Clean up changeset files ──────────────────────────────── + +shopt -s nullglob +changeset_files=("$CHANGESET_DIR"/*.md) +shopt -u nullglob +cleaned=0 + +for f in "${changeset_files[@]}"; do + [[ "$(basename "$f")" == "README.md" ]] && continue + rm "$f" + cleaned=$((cleaned + 1)) +done + +if [[ "$cleaned" -gt 0 ]]; then + echo -e "${GREEN}β†’${NC} Cleaned up $cleaned changeset files." +fi + +# ── Step 6: Commit and tag ────────────────────────────────────────── + +echo -e "${GREEN}β†’${NC} Committing release..." +git -C "$ROOT_DIR" add -A +git -C "$ROOT_DIR" commit -m "chore(release): $VERSION_TAG" +git -C "$ROOT_DIR" tag -a "$VERSION_TAG" -m "Release $VERSION_TAG" + +echo "" +echo -e "${GREEN}βœ“ Released $VERSION_TAG${NC}" +echo "" +echo -e " Push with: ${CYAN}git push && git push --tags${NC}"