17 Commits
Author SHA1 Message Date
Vance IngallsandClaude Opus 4.8 3a28d3f6b8 fix(release): scope tag-monotonicity guard to tags reachable from HEAD
The guard blocked on any semver-higher v* tag, including orphan tags on dead
branches (e.g. a stray `chore: release v1.0.3` never merged or published).
Such tags can't appear in the release history and shouldn't block a legitimate
release. Now only tags that are BOTH higher AND reachable from HEAD block;
extracted `findBlockingTags` with unit coverage for orphan/reachable/lower cases.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 00:34:58 -07:00
Vance IngallsandClaude Opus 4.8 9cc3550f7e fix(release): stop advising 'git push --tags' in release next-steps (#1521)
set-version's stable-release next-steps printed `git push origin main --tags`,
which pushes every local tag and fails the whole push on any pre-existing tag
(it broke the v0.6.107 release). #1517 fixed CONTRIBUTING.md + annotated the tag
but missed this console message. Now prints `git push origin main` +
`git push origin v<version>`, matching the pre-release branch.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 21:26:49 -07:00
Vance IngallsandClaude Opus 4.8 ca3cab340b fix(release): annotate version tag + correct release push instructions (#1517)
- set-version: create the release tag with `git tag -a -m` instead of a
  lightweight `git tag`, which fails ("no tag message?") when a contributor has
  tag.forceSignAnnotated / required-annotation set globally — it silently broke
  the v0.6.107 tag step.
- CONTRIBUTING: replace `git push origin main --tags` (pushes every local tag →
  whole push rejected on any pre-existing collision) with pushing the specific
  tag, and document the monotonicity guard (stale higher tag blocks tagging).

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 13:30:15 -07:00
Kiyeon Jeon ad5229af83 fix(release): include sdk in fixed-version bump (#1363) 2026-06-12 14:04:42 -04:00
Miguel Ángel 24279c8c76 fix(release): guard against non-monotonic tags (#1283)
* fix(release): guard against non-monotonic tags in set-version

Add a pre-tag check that rejects stable releases when an existing tag
has a higher semver. This prevents tag-sorting installers (npx skills,
simple-git tags.latest) from resolving stale versions.

Closes #1282

* fix(review): add --skip-monotonicity-check escape hatch, fix formatting

Address review feedback:
- Add --skip-monotonicity-check flag for legitimate backport scenarios
- Soften error message to show both options (delete tag or skip check)
- Fix oxfmt formatting
- Add test for new flag parsing
2026-06-08 19:49:59 -04:00
James RussoandClaude Opus 4.8 4da567df22 feat(gcp-cloud-run): Google Cloud Run + Workflows distributed render adapter (#1253)
* feat(gcp-cloud-run): add Google Cloud Run + Workflows distributed render adapter

Adds @hyperframes/gcp-cloud-run, the GCP counterpart to @hyperframes/aws-lambda
(issue #932). The OSS distributed primitives (plan, renderChunk x N, assemble)
are unchanged; this package is the storage/compute/orchestration glue.

Package: Cloud Run handler (one image, three actions), runs under bun; GCS
transport; in-image chrome-headless-shell resolver; client SDK
(renderToCloudRun, getRenderProgress, deploySite, computeRenderCost); Dockerfile;
Cloud Workflows definition; Terraform module; CLI cloudrun
deploy|sites|render|render-batch|progress|destroy with --output-resolution and
--strict-variables; 62 unit tests + docs + live smoke script.

Shared extraction (removes ~640 lines of adapter duplication): move the
cloud-agnostic config validator + content-hash into producer/distributed; both
adapters import them. Validated end-to-end on GCP at 37.4 dB PSNR vs baseline.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(cli): resolve @hyperframes/gcp-cloud-run in the CLI build + root build

The CLI bundle (esbuild) couldn't resolve `@hyperframes/gcp-cloud-run/sdk`,
failing Build/Typecheck/CLI-smoke (and the perf/windows/regression jobs that
build first). Mirror the aws-lambda handling: mark the gcp adapter + its /sdk
subpath external in tsup.config.ts with a source alias, and add gcp-cloud-run
to the root `build` filter so its dist exists for publish + runtime.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(ci): copy gcp-cloud-run manifest in Dockerfile.test for frozen install

The regression test image runs `bun install --frozen-lockfile` after copying
each workspace package.json individually. The CLI now depends on
@hyperframes/gcp-cloud-run (workspace:*), so the frozen install fails to
resolve it unless its manifest is present. Add the COPY line.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat(cli): add machine-sizing flags to `cloudrun deploy`

Closes the parity gap with `lambda deploy` (which exposes --memory etc.).
`cloudrun deploy` now threads --cpu, --memory, --max-instances, and --timeout
into the Terraform apply; omitted flags keep the module defaults
(4 vCPU / 16Gi / 100 instances / 3600s). For finer control, apply the module
directly.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(gcp-cloud-run): address PR review (security, waste, limits, alerts)

- server.ts: bucket-allowlist guard no longer fails open silently. Unset env
  logs a one-time WARNING; "*" is an explicit opt-out; otherwise it enforces.
- server.ts: stop double-shipping audio.aac. It already rides in the plan
  tarball every consumer downloads, so drop the redundant standalone upload
  (plan) + re-download/overwrite (assemble); assemble reads it from the untar,
  falling back to a supplied AudioGcsUri for compat.
- server.ts: chunk extension via path.extname() instead of slice(lastIndexOf).
- workflow.yaml: clamp parallel concurrency_limit to math.min(chunkCount, 20)
  — Cloud Workflows hard-caps concurrent iterations at 20.
- Dockerfile: pin bun (bun-v1.3.9) so an interop change can't silently break
  the image rebuild.
- terraform: add min_instances var (default 0); add a workflow-failure alert
  (finished_execution_count status=FAILED) alongside the request-count one.
- costAccounting: document that displayCost excludes GCS storage/egress.

Verified against the actual APIs: @google-cloud/workflows@4.4.0
ICreateExecutionRequest has no executionId (so the idempotency-token suggestion
isn't available in this client); Workflows concurrency cap is 20; failure
metric is workflows.googleapis.com/finished_execution_count (status label).
174 adapter tests pass, fallow/oxlint/oxfmt/terraform clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(gcp-cloud-run): address round-2 review — error code + CFR forwarding

- workflow.yaml: rename the zero-chunk failure code PLAN_TOO_LARGE →
  PLAN_PRODUCED_ZERO_CHUNKS. The old code implied a size-ceiling breach (the
  opposite cause), misleading anyone triaging the alert.
- workflow.yaml: forward Config.cfr to the assemble step
  (`Cfr: ${("cfr" in config) and config.cfr}`). It was read by the handler
  but never sent, so exact-CFR was silently off for every Cloud Run render.
  Uses the same `in`-operator guard already proven in the retryable predicate.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(release): include gcp-cloud-run in set-version PACKAGES list

set-version.ts (driven by release:prepare) bumps an explicit package list to
the shared version on each release. gcp-cloud-run was wired into the build +
publish.yml but missing here, so a release would leave it at a stale version
and publish.yml would push the wrong version. Add it so the new package
version-bumps + publishes in lockstep with the others.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 14:43:38 -07:00
James Russo 8228932e17 fix(scripts): make release change-guard robust to git status prefix (#1198)
The set-version guard parsed `git status --porcelain` and extracted the
path with a fixed `line.slice(3)`. The porcelain "XY <path>" prefix width
can shift, and when it did the slice dropped a leading character —
misreading `.claude-plugin/plugin.json` as `claude-plugin/plugin.json`,
which failed the allowed-paths match and falsely blocked a legitimate
release with "Unexpected uncommitted changes". There was no escape hatch.

Collect changed paths from `git diff --name-only -z HEAD` (tracked) plus
`git ls-files --others --exclude-standard -z` (untracked) instead. Both
emit bare NUL-separated repo-relative paths with no status column to
misparse, so the allowed-paths comparison is exact. Extract the pure
helpers (splitNulList, findUnexpectedChanges) and cover them with tests.

Also document the release flow in CLAUDE.md (the repo had no release docs).
2026-06-04 00:58:09 -07:00
James Russo 17b0db1d3e chore: add release prepare command (#1165)
## What

- Add `bun run release:prepare <version>` as the maintainer-facing stable release entrypoint.
- Make the first run draft missing changelog artifacts and intentionally exit before tagging; rerunning after manual review delegates to `set-version`.
- Tighten the direct `set-version` guard so stable releases also fail when generated TODO changelog copy is still present.
- Update maintainer docs to recommend `release:prepare` while keeping `changelog:draft` as the lower-level regeneration tool.

## Why

Stable releases should be hard to run without reviewed GitHub release notes and Mintlify changelog copy. This keeps the existing manual rewrite step, but makes the expected path one command that engineers can rerun after review.

## How

- Added `scripts/release-prepare.ts` with parsing, draft/review/set-version action selection, and command forwarding.
- Added focused script tests for parser behavior, action selection, command forwarding, and TODO detection.
- Extracted shared script CLI parsing helpers so `changelog:draft` and `release:prepare` use the same option handling.
- Adjusted `changelog:draft --write` so an existing release file is left unchanged unless `--force` is passed, while still allowing a missing docs entry to be added.

## Test plan

- [x] Unit tests added/updated: `bun run test:scripts`
- [x] Format check: `bun run format:check`
- [x] Lint: `bun run lint`
- [x] Typecheck: `bun run --filter '*' typecheck`
- [x] Fallow audit: `bunx fallow audit --base origin/main --fail-on-issues`
- [x] Manual CLI checks: `bun run release:prepare --help`; `bun run set-version 9.9.9` fails before mutation when changelog artifacts are missing
- [x] Documentation updated
2026-06-02 20:34:29 -04:00
James RussoandClaude Opus 4.8 248f640734 feat(docs): add changelog release workflow (#1164)
* feat(docs): add changelog release workflow

* fix(scripts): resolve CodeQL findings in release scripts

- draft-changelog.ts: replace existsSync+writeFileSync check-then-act with
  an atomic exclusive-write flag (flag: wx) to fix the js/file-system-race
  TOCTOU finding; overwrite only under --force (flag: w).
- set-version.ts: switch execSync shell-string git calls to execFileSync with
  argument arrays so the interpolated version/paths can never be interpreted
  by a shell, resolving the js/indirect-command-line-injection findings.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(scripts): lower writeReleaseNotes complexity below CRAP threshold

The exclusive-write fix pushed writeReleaseNotes to cyclomatic 5 / CRAP 30.0
(fallow/high-crap-score, threshold 30.0). The '!force' guard in the catch is
redundant — EEXIST is only reachable under the 'wx' flag (force=false), since
'w' overwrites without throwing. Dropping it returns the function to cyclomatic
4 / CRAP 20 with identical behavior.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(docs): address changelog review feedback

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-02 15:51:16 -07:00
Akwasi Konadu Akuoko 1ee920b535 fix(release): bump plugin manifests in set-version
scripts/set-version.ts only bumped the npm package.json files, so the
Claude Code / Codex / Cursor plugin manifests stayed at 0.1.0 across every
release. Claude Code gates /plugin update on plugin.json's version, so users
never received accumulated changes (closes #1048).

Add a PLUGINS list and a parallel loop that rewrites each manifest's version,
and include the manifests in the clean-tree guard and the staged file set.
The loop replaces only the version string (not a JSON round-trip) to preserve
each file's exact formatting, since oxfmt keeps their short arrays inline and
JSON.stringify would expand them and fail the pre-commit format check.
2026-05-23 19:02:21 +00:00
James 6935eaabc4 chore(lambda): bump initial version to 0.6.20 + add to set-version
Two follow-ups to keep the new package in lockstep with the rest of the
@hyperframes/* release cadence from day one:

- Bump packages/aws-lambda/package.json version 0.6.18 → 0.6.20 so it
  matches what main released while this PR was in review. Without this,
  the package would land below the rest of the lockstep and the next
  release-bump would jump aws-lambda from 0.6.18 → 0.6.21 in one step.

- Add packages/aws-lambda to PACKAGES in scripts/set-version.ts so the
  next `chore: release vX.Y.Z` commit bumps aws-lambda alongside the
  other publishable packages. Without this, set-version silently skips
  aws-lambda — package.json stays frozen, pnpm publish would re-publish
  the same version on every release, and the npm-view precheck in
  publish.yml would skip-with-success and never actually push a new
  version of the package.
2026-05-17 23:06:19 +00:00
James RussoandClaude Opus 4.6 9bf4956fae chore(shader-transitions): add to CI publish pipeline and README (#264)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 22:07:19 -07:00
James Russo e6a38c9e0f feat(ci): add alpha/beta/rc pre-release support to publish workflow (#167) 2026-03-31 14:16:57 -07:00
James RussoandClaude Opus 4.6 24c4fa6041 fix: make set-version commit and tag by default (#143)
The --tag flag was optional, which led to v0.1.11 and v0.1.12 being
bumped without tags — skipping npm publish entirely. Invert the default:
always commit + tag, with --no-tag as the escape hatch.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 15:21:08 -07:00
Vance IngallsandClaude Opus 4.6 61c5257402 fix(ci): update publish workflow to use bun install (#36)
* fix(ci): update publish workflow to use bun install

pnpm-lock.yaml was removed in the bun migration but publish.yml
still referenced it. Use bun for install/build, keep pnpm for
publish (publishConfig overrides + --provenance).

* docs: update stale pnpm references to bun across docs and scripts

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 08:46:58 -07:00
Vance Ingalls 20be2ea1c2 style: apply oxfmt baseline formatting across all source files (#25)
## Summary
- Run `oxfmt .` across the entire codebase to establish formatted baseline
- 299 files changed — mechanical formatting only, no logic changes
- Double quotes, semicolons, 2-space indent, trailing commas, 100 print width

Part 3/4 of [VA-851](https://linear.app/heygen/issue/VA-851/pre-migration-configure-eslint-prettier-and-conventional-commits)

## Test plan
- [x] `pnpm format:check` — all 426 files pass
- [x] `pnpm -r typecheck` — all packages pass
- [x] `pnpm build` — all packages build
- [x] All 348 tests pass
2026-03-23 17:15:14 -07:00
James 306909534b ci: add tag-triggered npm publish workflow with OIDC provenance 2026-03-23 03:20:21 +00:00