ultimate-pi 0.19.0 → 0.20.0

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 (85) hide show
  1. package/.agents/skills/web-retrieval/SKILL.md +163 -0
  2. package/.agents/skills/wiki-autoresearch/SKILL.md +6 -6
  3. package/.pi/SYSTEM.md +30 -12
  4. package/.pi/agents/harness/planning/implementation-researcher.md +1 -1
  5. package/.pi/agents/harness/planning/stack-researcher.md +5 -1
  6. package/.pi/agents/harness/running/executor.md +42 -1
  7. package/.pi/agents/harness/web-retrieval/web-answerer.md +35 -0
  8. package/.pi/agents/harness/web-retrieval/web-criteria-verifier.md +28 -0
  9. package/.pi/agents/harness/web-retrieval/web-gap-analyzer.md +31 -0
  10. package/.pi/agents/harness/web-retrieval/web-query-expander-fast.md +34 -0
  11. package/.pi/agents/harness/web-retrieval/web-query-expander.md +60 -0
  12. package/.pi/agents/harness/web-retrieval/web-summarizer.md +18 -0
  13. package/.pi/extensions/harness-anchored-edit.ts +141 -0
  14. package/.pi/extensions/harness-web-guard.ts +2 -1
  15. package/.pi/extensions/harness-web-tools.ts +689 -51
  16. package/.pi/harness/agents.manifest.json +30 -6
  17. package/.pi/harness/agents.policy.yaml +37 -4
  18. package/.pi/harness/docs/adrs/0050-agentic-web-retrieval-stack.md +46 -0
  19. package/.pi/harness/docs/adrs/0051-hash-anchored-executor-edits.md +41 -0
  20. package/.pi/harness/docs/adrs/README.md +2 -0
  21. package/.pi/harness/docs/harness-web-search.md +97 -0
  22. package/.pi/harness/docs/practice-map.md +11 -0
  23. package/.pi/harness/env.harness.template +9 -1
  24. package/.pi/harness/examples/web-heuristic-angles.project.yaml +22 -0
  25. package/.pi/harness/web-heuristic-angles.json +278 -0
  26. package/.pi/harness/web-heuristic-angles.yaml +182 -0
  27. package/.pi/lib/agents-policy.d.mts +4 -0
  28. package/.pi/lib/agents-policy.mjs +49 -1
  29. package/.pi/lib/agents-policy.ts +1 -0
  30. package/.pi/lib/harness-anchored-edit/.hash_anchors +1721 -0
  31. package/.pi/lib/harness-anchored-edit/anchor-state.ts +320 -0
  32. package/.pi/lib/harness-anchored-edit/apply-anchored-edits.ts +161 -0
  33. package/.pi/lib/harness-anchored-edit/edit-executor.ts +146 -0
  34. package/.pi/lib/harness-anchored-edit/index.ts +9 -0
  35. package/.pi/lib/harness-anchored-edit/line-protocol.ts +38 -0
  36. package/.pi/lib/harness-anchored-edit/settings.ts +1 -0
  37. package/.pi/lib/harness-anchored-edit/task-id.ts +8 -0
  38. package/.pi/lib/harness-anchored-edit/types.ts +19 -0
  39. package/.pi/lib/harness-lens/clients/anchored-edit-autopatch.ts +158 -0
  40. package/.pi/lib/harness-lens/index.ts +24 -7
  41. package/.pi/lib/harness-subagent-auth.ts +39 -9
  42. package/.pi/lib/harness-subagents-bridge.ts +24 -1
  43. package/.pi/lib/harness-web/artifacts.ts +200 -0
  44. package/.pi/lib/harness-web/cache.ts +369 -0
  45. package/.pi/lib/harness-web/run-cli.ts +42 -2
  46. package/.pi/prompts/harness-plan.md +1 -0
  47. package/.pi/prompts/harness-setup.md +3 -1
  48. package/.pi/prompts/harness-steer.md +1 -1
  49. package/.pi/scripts/gen-web-heuristic-angles-json.mjs +24 -0
  50. package/.pi/scripts/harness-anchored-edit-smoke.mjs +45 -0
  51. package/.pi/scripts/harness-cli-verify.sh +5 -0
  52. package/.pi/scripts/harness-verify.mjs +145 -0
  53. package/.pi/scripts/harness-web-policy-guard.mjs +1 -1
  54. package/.pi/scripts/harness-web.py +218 -15
  55. package/.pi/scripts/harness_web/deep_search.py +55 -0
  56. package/.pi/scripts/harness_web/evidence_bundle.py +47 -0
  57. package/.pi/scripts/harness_web/find_similar.py +88 -0
  58. package/.pi/scripts/harness_web/heuristic_angles_shipped.py +85 -0
  59. package/.pi/scripts/harness_web/heuristic_config.py +251 -0
  60. package/.pi/scripts/harness_web/highlights.py +47 -0
  61. package/.pi/scripts/harness_web/multi_search.py +59 -0
  62. package/.pi/scripts/harness_web/output.py +24 -0
  63. package/.pi/scripts/harness_web/query_angles.py +116 -0
  64. package/.pi/scripts/harness_web/rank.py +163 -0
  65. package/.pi/scripts/harness_web/scrape.py +30 -0
  66. package/.pi/scripts/run-tests.mjs +64 -0
  67. package/.pi/scripts/tests/test_harness_web_heuristic_config.py +132 -0
  68. package/.pi/scripts/tests/test_harness_web_query_angles.py +45 -0
  69. package/.pi/scripts/tests/test_harness_web_rank.py +56 -0
  70. package/AGENTS.md +2 -2
  71. package/CHANGELOG.md +12 -0
  72. package/THIRD_PARTY_NOTICES.md +7 -0
  73. package/package.json +7 -4
  74. package/vendor/pi-subagents/src/agents.ts +5 -0
  75. package/vendor/pi-subagents/src/subagents.ts +22 -3
  76. package/.agents/skills/scrapling-web/SKILL.md +0 -98
  77. package/.pi/extensions/00-posthog-network-bootstrap.ts +0 -11
  78. package/.pi/scripts/harness_web/__pycache__/__init__.cpython-314.pyc +0 -0
  79. package/.pi/scripts/harness_web/__pycache__/config.cpython-314.pyc +0 -0
  80. package/.pi/scripts/harness_web/__pycache__/output.cpython-314.pyc +0 -0
  81. package/.pi/scripts/harness_web/__pycache__/scrape.cpython-314.pyc +0 -0
  82. package/.pi/scripts/harness_web/__pycache__/search.cpython-314.pyc +0 -0
  83. package/.pi/scripts/harness_web/__pycache__/search_ddg.cpython-314.pyc +0 -0
  84. package/.pi/scripts/harness_web/__pycache__/search_searxng.cpython-314.pyc +0 -0
  85. package/.pi/scripts/release.sh +0 -338
@@ -1,98 +0,0 @@
1
- ---
2
- name: scrapling-web
3
- description: |
4
- Harness web search and scrape via pi tools web_search and web_fetch (harness-web.py).
5
- Use for any non-API web task: search, scrape URLs, map site links, bulk research fetches.
6
- Replaces Firecrawl in ultimate-pi harness agents. Triggers on: search the web,
7
- scrape URL, fetch page, research online, web_search, web_fetch, .web/ artifacts.
8
- ---
9
-
10
- # scrapling-web (harness-web)
11
-
12
- Local web layer for harness agents — **no API keys** for default search/scrape.
13
- Pi registers **`web_search`** and **`web_fetch`** (wrap `harness-web.py` with Scrapling bootstrap).
14
- Optional **self-hosted SearXNG** — see `/harness-setup` Step 4.0b.
15
-
16
- ## Agent tools (preferred)
17
-
18
- | Task | Tool |
19
- |------|------|
20
- | Search (SERP) | `web_search` with `query` |
21
- | Search + multi-scrape | `web_search` with `bulk: true` |
22
- | Scrape URL | `web_fetch` with `url` (default mode `scrape`) |
23
- | Map same-host links | `web_fetch` with `mode: map` |
24
- | Static / simple page | `web_fetch` with `fast: true` |
25
-
26
- **Never before search/fetch:** resolve `UP_PKG`, `ls harness-web.py`, `python3 -c "import scrapling"`, or Firecrawl/curl/wget/scrapling CLI for SERP or page fetch.
27
-
28
- Full JSON/markdown lives under **`.web/`** (gitignored). Use `read` on `output` paths after tool calls.
29
-
30
- ## Install (once per machine — setup/humans only)
31
-
32
- ```bash
33
- command -v uv &>/dev/null || curl -LsSf https://astral.sh/uv/install.sh | sh
34
- uv tool install "scrapling[fetchers]"
35
- scrapling install # browser binaries for default stealth scrape
36
- ```
37
-
38
- Verify: `bash "$UP_PKG/.pi/scripts/harness-cli-verify.sh"`
39
- Config diagnostics: `python3 "$UP_PKG/.pi/scripts/harness-web.py" status` (JSON; setup only)
40
-
41
- ## Bash fallback (if pi tools unavailable)
42
-
43
- | Task | Command |
44
- |------|---------|
45
- | Search | `python3 "$UP_PKG/.pi/scripts/harness-web.py" search "query" -o .web/search.json --limit 5` |
46
- | Scrape | `python3 "$UP_PKG/.pi/scripts/harness-web.py" scrape "<url>" -o .web/page.md` |
47
- | Fast/static | add `--fast` |
48
- | Map | `python3 "$UP_PKG/.pi/scripts/harness-web.py" map "<url>" -o .web/map.json` |
49
- | Bulk | `python3 "$UP_PKG/.pi/scripts/harness-web.py" bulk-scrape "query" -o .web/bulk/` |
50
-
51
- ## Search JSON shape (Firecrawl-compatible)
52
-
53
- ```bash
54
- jq -r '.data.web[].url' .web/search.json
55
- ```
56
-
57
- Each entry: `url`, `title`, `description`.
58
-
59
- ## Fetch modes
60
-
61
- | Mode | When |
62
- |------|------|
63
- | **stealth** (default) | Arbitrary URLs, JS-heavy sites |
64
- | **fast** (`fast: true` / `--fast`) | Static docs, example.com, localhost |
65
- | **auto** (`HARNESS_WEB_FETCH_MODE=auto`) | fast for known-static hosts, else stealth |
66
-
67
- | Search backend | Behavior |
68
- |--------------|----------|
69
- | `ddg_html` (default) | DuckDuckGo HTML SERP |
70
- | `searxng` | JSON at `HARNESS_WEB_SEARXNG_URL` — bootstrap via `harness-searxng-bootstrap.mjs` |
71
-
72
- ## Environment
73
-
74
- | Variable | Default | Purpose |
75
- |----------|---------|---------|
76
- | `HARNESS_WEB_FETCH_MODE` | `stealth` | `stealth` \| `fast` \| `auto` |
77
- | `HARNESS_WEB_SEARCH_ENGINE` | `ddg_html` | `ddg_html` \| `searxng` |
78
- | `HARNESS_WEB_SEARXNG_URL` | (unset) | Required when `SEARCH_ENGINE=searxng` |
79
-
80
- ## Escalation
81
-
82
- 1. `web_search` / `web_fetch`
83
- 2. `web_fetch` with `fast: true` for static hosts
84
- 3. `web_fetch` with `mode: map` then targeted fetches
85
- 4. Site-specific Scrapling only when tools are insufficient (not for routine SERP/fetch)
86
-
87
- ## Gaps vs Firecrawl
88
-
89
- | Firecrawl | Harness path |
90
- |-----------|----------------|
91
- | `interact` | gstack browse or manual browser |
92
- | `agent` | Agent reasoning + graphify |
93
- | `parse` (PDF) | pypdf, markitdown |
94
- | `crawl` | `web_search` bulk or map + multiple `web_fetch` |
95
-
96
- ## Ethics
97
-
98
- Respect site terms and rate limits. SERP scraping is for dev research, not high-volume harvesting.
@@ -1,11 +0,0 @@
1
- /**
2
- * Load before other extensions: IPv4-first fetch for *.posthog.com (@posthog/pi uses global fetch).
3
- */
4
-
5
- import { installPostHogFetchPatch } from "../lib/posthog-client.js";
6
-
7
- installPostHogFetchPatch();
8
-
9
- export default function posthogNetworkBootstrap() {
10
- // Side effects run at module load; no hooks required.
11
- }
@@ -1,338 +0,0 @@
1
- #!/usr/bin/env bash
2
- #
3
- # release.sh — Version bump, changelog, tag, and push
4
- # Usage: ./.pi/scripts/release.sh [patch|minor|major] [--dry-run]
5
- #
6
- set -euo pipefail
7
-
8
- # ─── Helpers ──────────────────────────────────────────────────────────────────
9
- warn() { echo "⚠ $*" >&2; }
10
- abort() { echo "✗ $*" >&2; exit 1; }
11
- ok() { echo "✓ $*"; }
12
-
13
- # ─── Step 0 — Parse arguments ─────────────────────────────────────────────────
14
- BUMP_TYPE=""
15
- DRY_RUN=false
16
-
17
- for arg in "$@"; do
18
- case "$arg" in
19
- patch|minor|major) BUMP_TYPE="$arg" ;;
20
- --dry-run) DRY_RUN=true ;;
21
- *) abort "Unknown argument: $arg" ;;
22
- esac
23
- done
24
-
25
- # ─── Step 1 — Infer bump type from commits if not provided ────────────────────
26
- LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
27
-
28
- if [ -z "$BUMP_TYPE" ]; then
29
- ok "No bump type provided. Scanning commits since last tag…"
30
-
31
- if [ -z "$LAST_TAG" ]; then
32
- COMMIT_LOG=$(git log --format="%s" HEAD 2>/dev/null || true)
33
- else
34
- COMMIT_LOG=$(git log --format="%s" "${LAST_TAG}..HEAD" 2>/dev/null || true)
35
- fi
36
-
37
- if [ -z "$COMMIT_LOG" ]; then
38
- abort "No commits since last tag. Nothing to release."
39
- fi
40
-
41
- # Inference rules
42
- if echo "$COMMIT_LOG" | grep -qE '^feat!:|BREAKING CHANGE'; then
43
- BUMP_TYPE="major"
44
- elif echo "$COMMIT_LOG" | grep -qE '^feat:'; then
45
- BUMP_TYPE="minor"
46
- else
47
- BUMP_TYPE="patch"
48
- fi
49
-
50
- ok "Inferred bump type: $BUMP_TYPE"
51
- fi
52
-
53
- # ─── Step 2 — Read current version and validate semver ────────────────────────
54
- CURRENT_VERSION=$(node -e "console.log(require('./package.json').version)" 2>/dev/null) \
55
- || abort "Failed to read version from package.json"
56
-
57
- if ! [[ "$CURRENT_VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
58
- abort "Invalid semver in package.json: $CURRENT_VERSION"
59
- fi
60
-
61
- NEW_VERSION=$(node -e "
62
- const [maj, min, pat] = '$CURRENT_VERSION'.split('.').map(Number);
63
- const bump = '$BUMP_TYPE';
64
- if (bump === 'major') console.log((maj + 1) + '.0.0');
65
- else if (bump === 'minor') console.log(maj + '.' + (min + 1) + '.0');
66
- else console.log(maj + '.' + min + '.' + (pat + 1));
67
- ")
68
-
69
- ok "Version: $CURRENT_VERSION → $NEW_VERSION"
70
-
71
- # ─── Step 3 — Pre-flight checks ───────────────────────────────────────────────
72
-
73
- # Must be in a git repo
74
- git rev-parse --is-inside-work-tree >/dev/null 2>&1 \
75
- || abort "Not a git repository."
76
-
77
- # Must have origin remote
78
- git remote -v | grep -q origin \
79
- || abort "No 'origin' remote configured."
80
-
81
- # Must be on a branch (not detached HEAD)
82
- BRANCH=$(git symbolic-ref -q HEAD 2>/dev/null | sed 's|^refs/heads/||') \
83
- || abort "Detached HEAD. Switch to a branch first."
84
-
85
- # Must have clean working tree (warn only in dry-run)
86
- git diff --quiet && git diff --cached --quiet
87
- if [ $? -ne 0 ]; then
88
- if [ "$DRY_RUN" = true ]; then
89
- warn "Working tree is dirty — actual release would be blocked."
90
- else
91
- abort "Working tree is dirty. Commit or stash changes first."
92
- fi
93
- fi
94
-
95
- # No duplicate tag locally or on remote
96
- if git rev-parse "v$NEW_VERSION" >/dev/null 2>&1; then
97
- abort "Tag v$NEW_VERSION already exists locally."
98
- fi
99
- if git ls-remote --tags origin "refs/tags/v$NEW_VERSION" >/dev/null 2>&1; then
100
- abort "Tag v$NEW_VERSION already exists on remote."
101
- fi
102
-
103
- # ─── Step 4 — Gather commits since last tag ───────────────────────────────────
104
- if [ -z "$LAST_TAG" ]; then
105
- COMMITS=$(git log --oneline --no-merges HEAD)
106
- else
107
- COMMITS=$(git log --oneline --no-merges "${LAST_TAG}..HEAD")
108
- fi
109
-
110
- COMMIT_COUNT=$(echo "$COMMITS" | grep -c '^' || echo 0)
111
-
112
- if [ "$COMMIT_COUNT" -eq 0 ]; then
113
- abort "No commits since last tag. Nothing to release."
114
- fi
115
-
116
- # ─── Step 5 — Generate changelog entry ────────────────────────────────────────
117
-
118
- # Map conventional commit prefix → section
119
- map_prefix() {
120
- local msg="$1"
121
- case "$msg" in
122
- feat!:*|*"BREAKING CHANGE"*) echo "breaking" ;;
123
- feat:*) echo "features" ;;
124
- fix:*) echo "fixes" ;;
125
- perf:*) echo "perf" ;;
126
- refactor:*) echo "refactor" ;;
127
- docs:*) echo "docs" ;;
128
- style:*) echo "style" ;;
129
- test:*) echo "tests" ;;
130
- chore:*) echo "chores" ;;
131
- ci:*) echo "ci" ;;
132
- build:*) echo "build" ;;
133
- *) echo "chores" ;;
134
- esac
135
- }
136
-
137
- declare -A SECTIONS=(
138
- [breaking]="⚠️ Breaking Changes"
139
- [features]="✨ Features"
140
- [fixes]="🐛 Fixes"
141
- [perf]="⚡ Performance"
142
- [refactor]="♻️ Refactoring"
143
- [docs]="📖 Documentation"
144
- [style]="🎨 Style"
145
- [tests]="✅ Tests"
146
- [chores]="🔧 Chores"
147
- [ci]="🔄 CI/CD"
148
- [build]="📦 Build"
149
- )
150
-
151
- # Build per-section entries
152
- entries_breaking=""
153
- entries_features=""
154
- entries_fixes=""
155
- entries_perf=""
156
- entries_refactor=""
157
- entries_docs=""
158
- entries_style=""
159
- entries_tests=""
160
- entries_chores=""
161
- entries_ci=""
162
- entries_build=""
163
-
164
- while IFS= read -r line; do
165
- [ -z "$line" ] && continue
166
- # Strip the short sha prefix (first word)
167
- msg="${line#* }"
168
- # Strip conventional commit prefix for display
169
- display="$msg"
170
- display=$(echo "$display" | sed -E 's/^[a-z]+(\([a-z0-9_-]+\))?!?:\s*//')
171
- prefix=$(map_prefix "$msg")
172
- case "$prefix" in
173
- breaking) entries_breaking="${entries_breaking}- $display
174
- " ;;
175
- features) entries_features="${entries_features}- $display
176
- " ;;
177
- fixes) entries_fixes="${entries_fixes}- $display
178
- " ;;
179
- perf) entries_perf="${entries_perf}- $display
180
- " ;;
181
- refactor) entries_refactor="${entries_refactor}- $display
182
- " ;;
183
- docs) entries_docs="${entries_docs}- $display
184
- " ;;
185
- style) entries_style="${entries_style}- $display
186
- " ;;
187
- tests) entries_tests="${entries_tests}- $display
188
- " ;;
189
- ci) entries_ci="${entries_ci}- $display
190
- " ;;
191
- build) entries_build="${entries_build}- $display
192
- " ;;
193
- *) entries_chores="${entries_chores}- $display
194
- " ;;
195
- esac
196
- done <<< "$COMMITS"
197
-
198
- # Assemble the changelog block
199
- TODAY=$(date +%Y-%m-%d)
200
- CHANGELOG_BLOCK="## [v$NEW_VERSION] — $TODAY
201
- "
202
-
203
- for key in breaking features fixes perf refactor docs style tests ci build chores; do
204
- eval "content=\"\$entries_$key\""
205
- if [ -n "$content" ]; then
206
- CHANGELOG_BLOCK="${CHANGELOG_BLOCK}
207
- ### ${SECTIONS[$key]}
208
-
209
- $content"
210
- fi
211
- done
212
-
213
- # ─── Step 6 — Dry run check ───────────────────────────────────────────────────
214
- if [ "$DRY_RUN" = true ]; then
215
- echo ""
216
- echo "═══════════════════════════════════════════════════════════════"
217
- echo " DRY RUN — no changes made"
218
- echo "═══════════════════════════════════════════════════════════════"
219
- echo " Version: $CURRENT_VERSION → $NEW_VERSION"
220
- echo " Bump: $BUMP_TYPE"
221
- echo " Commits: $COMMIT_COUNT since ${LAST_TAG:-<none>}"
222
- echo " Branch: $BRANCH"
223
- echo ""
224
- echo " Files that would change:"
225
- echo " - package.json (version → $NEW_VERSION)"
226
- echo " - CHANGELOG.md (new entry below)"
227
- echo ""
228
- echo " Tag that would be created: v$NEW_VERSION"
229
- echo ""
230
- echo " Changelog entry:"
231
- echo "───────────────────────────────────────────────────────────────"
232
- echo "$CHANGELOG_BLOCK"
233
- echo "───────────────────────────────────────────────────────────────"
234
- exit 0
235
- fi
236
-
237
- # ─── Step 7 — Bump version in package.json ────────────────────────────────────
238
- npm pkg set version="$NEW_VERSION"
239
-
240
- node -e "
241
- const v = require('./package.json').version;
242
- if (v !== '$NEW_VERSION') {
243
- console.error('✗ version mismatch: expected $NEW_VERSION, got ' + v);
244
- process.exit(1);
245
- }
246
- console.log('✓ version bumped to $NEW_VERSION');
247
- "
248
-
249
- # ─── Step 8 — Write CHANGELOG.md ──────────────────────────────────────────────
250
- if [ -f CHANGELOG.md ]; then
251
- # Prepend after the first heading line
252
- {
253
- head -n 1 CHANGELOG.md
254
- echo ""
255
- echo "$CHANGELOG_BLOCK"
256
- tail -n +2 CHANGELOG.md
257
- } > CHANGELOG.md.tmp && mv CHANGELOG.md.tmp CHANGELOG.md
258
- else
259
- {
260
- echo "# Changelog"
261
- echo ""
262
- echo "All notable changes to this project are documented in this file."
263
- echo ""
264
- echo "$CHANGELOG_BLOCK"
265
- } > CHANGELOG.md
266
- fi
267
-
268
- ok "CHANGELOG.md updated"
269
-
270
- # ─── Step 9 — Read co-author config ───────────────────────────────────────────
271
- CO_AUTHOR="pi-mono <261679550+pi-mono@users.noreply.github.com>"
272
- if [ -f .pi/auto-commit.json ]; then
273
- CO_AUTHOR=$(node -e "
274
- const fs = require('fs');
275
- const cfg = JSON.parse(fs.readFileSync('.pi/auto-commit.json', 'utf8'));
276
- const ca = cfg.coAuthor || {};
277
- console.log((ca.login || 'pi-mono') + ' <' + (ca.email || '261679550+pi-mono@users.noreply.github.com') + '>');
278
- " 2>/dev/null) || true
279
- fi
280
-
281
- # ─── Step 10 — Commit ─────────────────────────────────────────────────────────
282
- git add package.json CHANGELOG.md
283
-
284
- COMMIT_BODY=$(cat <<EOF
285
- - Bump version in package.json
286
- - Add changelog entry for v$NEW_VERSION
287
-
288
- Commits included:
289
- $(echo "$COMMITS" | sed 's/^/- /')
290
- EOF
291
- )
292
-
293
- git commit -m "chore(release): bump to v$NEW_VERSION" \
294
- -m "$COMMIT_BODY" \
295
- -m "Co-authored-by: $CO_AUTHOR"
296
-
297
- ok "Committed version bump + changelog"
298
-
299
- # ─── Step 11 — Create and push tag ────────────────────────────────────────────
300
- TAG_BODY=$(cat <<EOF
301
- Release v$NEW_VERSION — $BUMP_TYPE bump
302
-
303
- $COMMITS
304
- EOF
305
- )
306
-
307
- git tag -a "v$NEW_VERSION" -m "$TAG_BODY"
308
- ok "Created tag v$NEW_VERSION"
309
-
310
- git push origin "v$NEW_VERSION"
311
- ok "Pushed tag v$NEW_VERSION to origin"
312
-
313
- # ─── Step 12 — Optionally push branch commit ──────────────────────────────────
314
- echo ""
315
- read -rp "Push the version-bump commit to the current branch ($BRANCH) too? [Y/n] " PUSH_BRANCH
316
- if [[ "$PUSH_BRANCH" =~ ^[Yy]?$ ]]; then
317
- git push origin "$BRANCH"
318
- ok "Pushed commit to $BRANCH"
319
- else
320
- echo "Skipped branch push."
321
- fi
322
-
323
- # ─── Step 13 — Report ─────────────────────────────────────────────────────────
324
- echo ""
325
- echo "═══════════════════════════════════════════════════════════════"
326
- echo " ✓ Released v$NEW_VERSION ($BUMP_TYPE)"
327
- echo "═══════════════════════════════════════════════════════════════"
328
- echo " Tag: v$NEW_VERSION — pushed to origin"
329
- echo " Commit: $(git rev-parse --short HEAD)"
330
- echo " Branch: $BRANCH"
331
- echo ""
332
- echo " Workflows triggered:"
333
- echo " - .github/workflows/publish-github-packages.yml"
334
- echo " - .github/workflows/publish-npm.yml"
335
- echo ""
336
- echo " Changelog: CHANGELOG.md updated"
337
- echo " Monitor: https://github.com/aryaniyaps/ultimate-pi/actions"
338
- echo "═══════════════════════════════════════════════════════════════"