Commit Graph

13 Commits

Author SHA1 Message Date
Jeremy McSpadden
0a049149e1 fix(sdk): decouple from build-from-source install, close #2441 #2453 (#2457)
* fix(sdk): decouple SDK from build-from-source install path, close #2441 and #2453

Ship sdk/dist prebuilt in the tarball and replace the npm-install-g
sub-install with a parent-package bin shim (bin/gsd-sdk.js). npm chmods
bin entries from a packed tarball correctly, eliminating the mode-644
failure (#2453) and the full class of NPM_CONFIG_PREFIX/ignore-scripts/
corepack/air-gapped failure modes that caused #2439 and #2441.

Changes:
- sdk/package.json: prepublishOnly runs `rm -rf dist && tsc && chmod +x
  dist/cli.js` (stale-build guard + execute-bit fix at publish time)
- package.json: add "gsd-sdk": "bin/gsd-sdk.js" bin entry; add sdk/dist
  to files so the prebuilt CLI ships in the tarball
- bin/gsd-sdk.js: new back-compat shim — resolves sdk/dist/cli.js relative
  to the package root and delegates via `node`, so all existing PATH call
  sites (slash commands, agents, hooks) continue to work unchanged (S1 shim)
- bin/install.js: replace installSdkIfNeeded() build-from-source + global-
  install dance with a dist-verify + chmod-in-place guard; delete
  resolveGsdSdk(), detectShellRc(), emitSdkFatal() helpers now unused
- .github/workflows/install-smoke.yml: add smoke-unpacked job that strips
  execute bit from sdk/dist/cli.js before install to reproduce the exact
  #2453 failure mode
- tests/bug-2441-sdk-decouple.test.cjs: new regression tests asserting all
  invariants (no npm install -g from sdk/, shim exists, sdk/dist in files,
  prepublishOnly has rm -rf + chmod)
- tests/bugs-1656-1657.test.cjs: update stale assertions that required
  build-from-source behavior (now asserts new prebuilt-dist invariants)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* chore(release): bump to 1.38.2, wire release.yml to build SDK dist

- Bump version 1.38.1 -> 1.38.2 for the #2441/#2453 fix shipped in 0f6903d.
- Add `build:sdk` script (`cd sdk && npm ci && npm run build`).
- `prepublishOnly` now runs hooks + SDK builds as a safety net.
- release.yml (rc + finalize): build SDK dist before `npm publish` so the
  published tarball always ships fresh `sdk/dist/` (kept gitignored).
- CHANGELOG: document 1.38.2 entry and `--sdk` flag semantics change.

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

* ci: build SDK dist before tests and smoke jobs

sdk/dist/ is gitignored (built fresh at publish time via release.yml),
but both the test suite and install-smoke jobs run `bin/install.js`
or `npm pack` against the checked-out tree where dist doesn't exist yet.

- test.yml: `npm run build:sdk` before `npm run test:coverage`, so tests
  that spawn `bin/install.js` don't hit `installSdkIfNeeded()`'s fatal
  missing-dist check.
- install-smoke.yml (both smoke and smoke-unpacked): build SDK before
  pack/chmod so the published tarball contains dist and the unpacked
  install has a file to strip exec-bit from.

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

* fix(sdk): lift SDK runtime deps to parent so tarball install can resolve them

The SDK's runtime deps (ws, @anthropic-ai/claude-agent-sdk) live in
sdk/package.json, but sdk/node_modules is NOT shipped in the parent
tarball — only sdk/dist, sdk/src, sdk/prompts, and sdk/package.json are.
When a user runs `npm install -g get-shit-done-cc`, npm installs the
parent's node_modules but never runs `npm install` inside the nested
sdk/ directory.

Result: `node sdk/dist/cli.js` fails with ERR_MODULE_NOT_FOUND for 'ws'.
The smoke tarball job caught this; the unpacked variant masked it
because `npm install -g <dir>` copies the entire workspace including
sdk/node_modules (left over from `npm run build:sdk`).

Fix: declare the same deps in the parent package.json so they land in
<pkg>/node_modules, which Node's resolution walks up to from
<pkg>/sdk/dist/cli.js. Keep them declared in sdk/package.json too so
the SDK remains a self-contained package for standalone dev.

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

* fix(lockfile): regenerate package-lock.json cleanly

The previous `npm install` run left the lockfile internally inconsistent
(resolved esbuild@0.27.7 referenced but not fully written), causing
`npm ci` to fail in CI with "Missing from lock file" errors.

Clean regen via rm + npm install fixes all three failed jobs
(test, smoke, smoke-unpacked), which were all hitting the same
`npm ci` sync check.

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

* fix(deps): remove unused esbuild + vitest from root devDependencies

Both were declared but never imported anywhere in the root package
(confirmed via grep of bin/, scripts/, tests/). They lived in sdk/
already, which is the only place they're actually used.

The transitive tree they pulled in (vitest → vite → esbuild 0.28 →
@esbuild/openharmony-arm64) was the root of the CI npm ci failures:
the openharmony platform package's `optional: true` flag was not being
applied correctly by npm 10 on Linux runners, causing EBADPLATFORM.

After removal: 800+ transitive packages → 155. Lockfile regenerated
cleanly. All 4170 tests pass.

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

* fix(sdk): pretest:coverage builds sdk; tighten shim test assertions

Add "pretest:coverage": "npm run build:sdk" so npm run test:coverage
works in clean checkouts where sdk/dist/ hasn't been built yet.

Tighten the two loose shim assertions in bug-2441-sdk-decouple.test.cjs:
- forwards-to test now asserts path.resolve() is called with the
  'sdk','dist','cli.js' path segments, not just substring presence
- node-invocation test now asserts spawnSync(process.execPath, [...])
  pattern, ruling out matches in comments or the shebang line

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix: address PR review — pretest:coverage + tighten shim tests

Review feedback from trek-e on PR 2457:

1. pretest:coverage + pretest hooks now run `npm run build:sdk` so
   `npm run test[:coverage]` in a clean checkout produces the required
   sdk/dist/ artifacts before running the installer-dependent tests.
   CI already does this explicitly; local contributors benefit.

2. Shim tests in bug-2441-sdk-decouple.test.cjs tightened from loose
   substring matches (which would pass on comments/shebangs alone) to
   regex assertions on the actual path.resolve call, spawnSync with
   process.execPath, process.argv.slice(2), and process.exit pattern.
   These now provide real regression protection for #2453-class bugs.

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

* fix: correct CHANGELOG entry and add [1.38.2] reference link

Two issues in the 1.38.2 CHANGELOG entry:
- installSdkIfNeeded() was described as deleted but it still exists in
  bin/install.js (repurposed to verify sdk/dist/cli.js and fix execute bit).
  Corrected the description to say 'repurposes' rather than 'deletes'.
- The reference-link block at the bottom of the file was missing a [1.38.2]
  compare URL and [Unreleased] still pointed to v1.37.1...HEAD. Added the
  [1.38.2] link and updated [Unreleased] to compare/v1.38.2...HEAD.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(sdk): double-cast WorkflowConfig to Record for strict tsc build

TypeScript error on main (introduced in #2611) blocks `npm run build`
in sdk/, which now runs as part of this PR's tarball build path. Apply
the double-cast via `unknown` as the compiler suggests.

Same fix as #2622; can be dropped if that lands first.

* test: remove bug-2598 test obsoleted by SDK decoupling

The bug-2598 test guards the Windows CVE-2024-27980 fix in the old
build-from-source path (npm spawnSync with shell:true + formatSpawnFailure
diagnostics). This PR removes that entire code path — installSdkIfNeeded
no longer spawns npm, it just verifies the prebuilt sdk/dist/cli.js
shipped in the tarball.

The test asserts `installSdkIfNeeded.toString()` contains a
formatSpawnFailure helper. After decoupling, no such helper exists
(nothing to format — there's no spawn). Keeping the test would assert
invariants of the rejected architecture.

The original #2598 defect (silent failure of npm spawn on Windows) is
structurally impossible in the shim path: bin/gsd-sdk.js invokes
`node sdk/dist/cli.js` directly via child_process.spawn with an
explicit argv array. No .cmd wrapper, no shell delegation.

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Tom Boucher <trekkie@nomorestars.com>
2026-04-23 08:36:03 -04:00
Lex Christopherson
43ea92578b Merge remote-tracking branch 'origin/main' into hotfix/1.38.2
# Conflicts:
#	CHANGELOG.md
#	bin/install.js
#	sdk/src/query/init.ts
2026-04-21 09:16:24 -06:00
Tom Boucher
ebbe74de72 feat(release): publish @gsd-build/sdk alongside get-shit-done-cc in release pipeline (#2468)
* fix(sdk): bump engines.node from >=20 to >=22.0.0

Node 20 reaches EOL April 30 2026. The root package already declares
>=22.0.0 and CI only runs Node 22 and 24. Align sdk/package.json so
`npm install` on Node 20 fails with a clear engines mismatch rather
than a silent install that breaks at runtime.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(release): publish @gsd-build/sdk alongside get-shit-done-cc in release pipeline

Closes #2309

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-19 23:13:14 -04:00
Jeremy McSpadden
f98ef1e460 fix(install): fatal SDK install failures + CI smoke gate (#2439)
## Why
#2386 added `installSdkIfNeeded()` to build @gsd-build/sdk from bundled
source and `npm install -g .`, because the npm-published @gsd-build/sdk
is intentionally frozen and version-mismatched with get-shit-done-cc.

But every failure path in that function was warning-only — including
the final `which gsd-sdk` verification. When npm's global bin is off a
user's PATH (common on macOS), the installer printed a yellow warning
then exited 0. Users saw "install complete" and then every `/gsd-*`
command crashed with `command not found: gsd-sdk` (the #2439 symptom).

No CI job executed the install path, so this class of regression could
ship undetected — existing "install" tests only read bin/install.js as
a string.

## What changed

**bin/install.js — installSdkIfNeeded() is now transactional**
- All build/install failures exit non-zero (not just warn).
- Post-install `which gsd-sdk` check is fatal: if the binary landed
  globally but is off PATH, we exit 1 with a red banner showing the
  resolved npm bin dir, the user's shell, the target rc file, and the
  exact `export PATH=…` line to add.
- Escape hatch: `GSD_ALLOW_OFF_PATH=1` downgrades off-PATH to exit 2
  for users with intentionally restricted PATH who will wire up the
  binary manually.
- Resolver uses POSIX `command -v` via `sh -c` (replaces `which`) so
  behavior is consistent across sh/bash/zsh/fish.
- Factored `resolveGsdSdk()`, `detectShellRc()`, `emitSdkFatal()`.

**.github/workflows/install-smoke.yml (new)**
- Executes the real install path: `npm pack` → `npm install -g <tgz>`
  → run installer non-interactively → `command -v gsd-sdk` → run
  `gsd-sdk --version`.
- PRs: path-filtered to installer-adjacent files, ubuntu + Node 22 only.
- main/release branches: full matrix (ubuntu+macos × Node 22+24).
- Reusable via workflow_call with `ref` input for release gating.

**.github/workflows/release.yml — pre-publish gate**
- New `install-smoke-rc` and `install-smoke-finalize` jobs invoke the
  reusable workflow against the release branch. `rc` and `finalize`
  now `needs: [validate-version, install-smoke-*]`, so a broken SDK
  install blocks `npm publish`.

## Test plan
- Local full suite: 4154/4154 pass
- install-smoke.yml will self-validate on this PR (ubuntu+Node22 only)

Addresses root cause of #2439 (the per-command pre-flight in #2440 is
the complementary defensive layer).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 18:39:32 -05:00
Jeremy McSpadden
af66cd89ca fix(install): fatal SDK install failures + CI smoke gate (#2439)
## Why
#2386 added `installSdkIfNeeded()` to build @gsd-build/sdk from bundled
source and `npm install -g .`, because the npm-published @gsd-build/sdk
is intentionally frozen and version-mismatched with get-shit-done-cc.

But every failure path in that function was warning-only — including
the final `which gsd-sdk` verification. When npm's global bin is off a
user's PATH (common on macOS), the installer printed a yellow warning
then exited 0. Users saw "install complete" and then every `/gsd-*`
command crashed with `command not found: gsd-sdk` (the #2439 symptom).

No CI job executed the install path, so this class of regression could
ship undetected — existing "install" tests only read bin/install.js as
a string.

## What changed

**bin/install.js — installSdkIfNeeded() is now transactional**
- All build/install failures exit non-zero (not just warn).
- Post-install `which gsd-sdk` check is fatal: if the binary landed
  globally but is off PATH, we exit 1 with a red banner showing the
  resolved npm bin dir, the user's shell, the target rc file, and the
  exact `export PATH=…` line to add.
- Escape hatch: `GSD_ALLOW_OFF_PATH=1` downgrades off-PATH to exit 2
  for users with intentionally restricted PATH who will wire up the
  binary manually.
- Resolver uses POSIX `command -v` via `sh -c` (replaces `which`) so
  behavior is consistent across sh/bash/zsh/fish.
- Factored `resolveGsdSdk()`, `detectShellRc()`, `emitSdkFatal()`.

**.github/workflows/install-smoke.yml (new)**
- Executes the real install path: `npm pack` → `npm install -g <tgz>`
  → run installer non-interactively → `command -v gsd-sdk` → run
  `gsd-sdk --version`.
- PRs: path-filtered to installer-adjacent files, ubuntu + Node 22 only.
- main/release branches: full matrix (ubuntu+macos × Node 22+24).
- Reusable via workflow_call with `ref` input for release gating.

**.github/workflows/release.yml — pre-publish gate**
- New `install-smoke-rc` and `install-smoke-finalize` jobs invoke the
  reusable workflow against the release branch. `rc` and `finalize`
  now `needs: [validate-version, install-smoke-*]`, so a broken SDK
  install blocks `npm publish`.

## Test plan
- Local full suite: 4154/4154 pass
- install-smoke.yml will self-validate on this PR (ubuntu+Node22 only)

Addresses root cause of #2439 (the per-command pre-flight in #2440 is
the complementary defensive layer).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 16:31:15 -05:00
Jeremy McSpadden
e3bd06c9fd fix(release): make merge-back PR step non-fatal
Repos that disable "Allow GitHub Actions to create and approve pull
requests" (org-level policy or repo-level setting) cause the "Create PR
to merge release back to main" step to fail with a GraphQL 403. That
failure cascades: Tag and push, npm publish, GitHub Release creation
are all skipped, and the entire release aborts.

The merge-back PR is a convenience — it's re-openable manually after
the release. Making it non-fatal with continue-on-error lets the rest
of the release complete. The step now emits ::warning:: annotations
pointing at the manual-recovery command when it fails.

Shell pipelines also fall through with `|| echo "::warning::..."` so
transient gh CLI failures don't mask the underlying policy issue.

Covers the failure mode seen on run 24596079637 where dry-run publish
validation passed but the release halted at the PR-creation step.
2026-04-17 22:45:22 -05:00
Tom Boucher
6b7b6a0ae8 ci: fix release pipeline — update actions, add GH releases, extend CI triggers (#1956)
- Update actions/checkout and actions/setup-node to v6 in release.yml and
  hotfix.yml (Node.js 24 compat, prevents June 2026 breakage)
- Add GitHub Release creation to release finalize, release RC, and hotfix
  finalize steps (populates Releases page automatically)
- Extend test.yml push triggers to release/** and hotfix/** branches
- Extend security-scan.yml PR triggers to release/** and hotfix/** branches

Closes #1955

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-11 15:10:12 -04:00
Tibsfox
bad9c63fcb ci: update action versions to v6 and extend CI to release/hotfix branches (#1955) (#1965)
- Update actions/checkout from v4.2.2 to v6.0.2 in release.yml and
  hotfix.yml (prevents breakage after June 2026 Node.js 20 deprecation)
- Update actions/setup-node from v4.1.0 to v6.3.0 in both workflows
- Add release/** and hotfix/** to test.yml push triggers
- Add release/** and hotfix/** to security-scan.yml PR triggers

test.yml already used v6 pins — this aligns the release pipelines.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 10:48:14 -04:00
Tom Boucher
85316d62d5 feat: 3-tier release strategy with hotfix, release, and CI workflows (#1289)
* feat: 3-tier release strategy with hotfix, release, and CI workflows

Supersedes PRs #1208 and #1210 with a consolidated approach:

- VERSIONING.md: Strategy document with 3 release tiers (patch/minor/major)
- hotfix.yml: Emergency patch releases to latest
- release.yml: Standard release cycle with RC/beta pre-releases to next
- auto-branch.yml: Create branches from issue labels
- branch-naming.yml: Convention validation (advisory)
- pr-gate.yml: PR size analysis and labeling
- stale.yml: Weekly cleanup of inactive issues/PRs
- dependabot.yml: Automated dependency updates

npm dist-tags: latest (stable) and next (pre-release) only,
following Angular/Next.js convention.

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

* fix: address PR review findings for release workflow security and correctness

- Move all ${{ }} expression interpolation from run: blocks into env: mappings
  in both hotfix.yml (~12 instances) and release.yml (~16 instances) to prevent
  potential command injection via GitHub Actions expression evaluation
- Reorder rc job in release.yml to run npm ci and test:coverage before pushing
  the git tag, preventing broken tagged commits when tests fail
- Update VERSIONING.md to accurately describe the implementation: major releases
  use beta pre-releases only, minor releases use rc pre-releases only (no
  beta-then-rc progression)

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

* security: harden release workflows — SHA pinning, provenance, dry-run guards

Addresses deep adversarial review + best practices research:

HIGH:
- Fix release.yml rc/finalize: dry_run now gates tag+push (not just npm publish)
- Fix hotfix.yml finalize: reorder tag-before-publish (was publish-before-tag)

MEDIUM — Security hardening:
- Pin ALL actions to SHA hashes (actions/checkout@11bd7190,
  actions/setup-node@39370e39, actions/github-script@60a0d830)
- Add --provenance --access public to all npm publish commands
- Add id-token: write permission for npm provenance OIDC
- Add concurrency groups (cancel-in-progress: false) on both workflows
- Add branch-naming.yml permissions: {} (deny-all default)
- Scope permissions per-job instead of workflow-level where possible

MEDIUM — Reliability:
- Add post-publish verification (npm view + dist-tag check) after every publish
- Add npm publish --dry-run validation step before actual publish
- Add branch existence pre-flight check in create jobs

LOW:
- Fix VERSIONING.md Semver Rules: MINOR = "enhancements" not "new features"
  (aligns with Release Tiers table)

Tests: 1166/1166 pass

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

* security: pin actions/stale to SHA hash

Last remaining action using a mutable version tag. Now all actions
across all workflow files are pinned to immutable SHA hashes.

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

* fix: address all Copilot review findings on release strategy workflows

- Configure git identity in all committing jobs (hotfix + release)
- Base hotfix on latest patch tag instead of vX.Y.0
- Add issues: write permission for PR size labeling
- Remove stale size labels before adding new one
- Make tagging and PR creation idempotent for reruns
- Run dry-run publish validation unconditionally
- Paginate listFiles for large PRs
- Fix VERSIONING.md table formatting and docs accuracy

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

* fix: clean up next dist-tag after finalize in release and hotfix workflows

After finalizing a release, the next dist-tag was left pointing at the
last RC pre-release. Anyone running npm install @next would get a stale
version older than @latest. Now both workflows point next to the stable
release after finalize, matching Angular/Next.js convention.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(ci): address blocking issues in 3-tier release workflows

- Move back-merge PR creation before npm publish in hotfix/release finalize
- Move version bump commit after test step in rc workflow
- Gate hotfix create branch push behind dry_run check
- Add confirmed-bug and confirmed to stale.yml exempt labels
- Fix auto-branch priority: critical prefix collision with hotfix/ naming

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 23:08:31 -04:00
Lex Christopherson
339e911299 chore: remove GitHub Actions release workflow
npm publish is the only distribution channel needed.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-25 18:53:56 -06:00
Lex Christopherson
d27d5a350b ci: restore auto-release workflow for GitHub Releases 2026-01-23 17:07:11 -06:00
Lex Christopherson
3a6a900c10 chore: remove GitHub Actions workflows
Manual npm publish preferred over automated CI/CD.
2026-01-23 17:03:45 -06:00
Lex Christopherson
a3a16be296 feat: add CI/CD and release automation
- Add GitHub Actions CI for cross-platform testing (ubuntu/windows/macos × node 18/20/22)
- Add release workflow that auto-creates GitHub Releases and publishes to npm on tag push
- Add CONTRIBUTING.md with branching strategy (maintainers direct commit, contributors PR)
- Add MAINTAINERS.md with release workflows and recovery procedures
- Add PR template for contributors

Closes #221

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-22 10:37:22 -06:00