Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 11 additions & 5 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -79,16 +79,17 @@ jobs:
retention-days: 7

# Publish to npm on tagged releases only (npm versions are immutable, so the
# rolling "latest" main builds are not published here). Uses Trusted
# Publishing (OIDC): no token in the repo, provenance generated automatically.
# rolling "latest" main builds are not published here). Authenticates with the
# NPM_TOKEN secret (an Automation token, which bypasses 2FA); id-token: write
# is kept so --provenance can attach a signed build attestation.
npm-publish:
name: publish npm packages
needs: build
if: github.ref_type == 'tag'
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write # required for OIDC trusted publishing
id-token: write # required for npm --provenance attestation
steps:
- uses: actions/checkout@v4

Expand All @@ -110,12 +111,17 @@ jobs:
run: node npm/scripts/build-packages.mjs "${{ github.ref_name }}" artifacts

- name: Publish (platform packages first, then the root)
env:
# Automation token (bypasses 2FA). setup-node wrote an .npmrc that
# reads this. --provenance still attaches a signed attestation via the
# job's id-token: write permission.
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
run: |
set -euo pipefail
for d in npm/dist/csdd-*/; do
npm publish "$d" --access public
npm publish "$d" --access public --provenance
done
npm publish npm/dist/csdd --access public
npm publish npm/dist/csdd --access public --provenance

release:
name: publish release
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,4 @@ go.work.sum
# Anchored with a leading slash so they do NOT match the npm/csdd/ package dir.
/csdd
/csdd.md
/dist
101 changes: 101 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
# csdd — build, test, and npm release tasks.
#
# Day-to-day:
# make build # local binary -> ./csdd
# make check # gofmt + vet + race tests (the CI gate)
#
# Release (recommended — CI builds + publishes to npm on the pushed tag):
# make release VERSION=v0.2.0
#
# Manual npm publish (bootstrap / fallback, when CI can't do it):
# make dist VERSION=v0.2.0 # cross-compile all 5 targets into dist/
# make npm-build VERSION=v0.2.0 # assemble npm/dist/ from those artifacts
# make npm-dry-run # validate all 6 packages without publishing
# make npm-publish [OTP=123456] # publish the 6 packages (skips already-published)
#
# Auth for a manual publish: either an Automation token
# npm config set //registry.npmjs.org/:_authToken <token>
# or pass a fresh 2FA code: make npm-publish OTP=123456

SHELL := bash
MODULE := github.com/protonspy/csdd
VERSION ?= dev
LDFLAGS := -s -w -X $(MODULE)/cmd.version=$(VERSION)
DIST ?= dist
ARTIFACTS ?= $(DIST)

# GOOS/GOARCH targets shipped to npm — must match npm/scripts/build-packages.mjs.
PLATFORMS := linux/amd64 linux/arm64 darwin/amd64 darwin/arm64 windows/amd64

.DEFAULT_GOAL := help

.PHONY: help
help: ## Show this help
@grep -hE '^[a-zA-Z0-9_-]+:.*## ' $(MAKEFILE_LIST) \
| awk 'BEGIN{FS=":.*## "}{printf " \033[36m%-14s\033[0m %s\n",$$1,$$2}'

.PHONY: build
build: ## Build the binary locally (-> ./csdd); set VERSION to stamp it
go build -trimpath -ldflags '$(LDFLAGS)' -o csdd .

.PHONY: test
test: ## Run tests (race + coverage)
go test -race -coverprofile=coverage.out ./...

.PHONY: fmt
fmt: ## Fail if any file is not gofmt-clean
@unformatted=$$(gofmt -l .); \
if [ -n "$$unformatted" ]; then echo "not gofmt-clean:"; echo "$$unformatted"; exit 1; fi; \
echo "gofmt clean"

.PHONY: vet
vet: ## go vet ./...
go vet ./...

.PHONY: check
check: fmt vet test ## Run the full CI gate (gofmt + vet + race tests)

.PHONY: dist
dist: ## Cross-compile every npm target into $(DIST)/ (set VERSION=vX.Y.Z)
@rm -rf '$(DIST)' && mkdir -p '$(DIST)'
@set -euo pipefail; for p in $(PLATFORMS); do \
goos=$${p%/*}; goarch=$${p#*/}; bin=csdd; [ "$$goos" = windows ] && bin=csdd.exe; \
echo ">> $$goos/$$goarch"; \
GOOS=$$goos GOARCH=$$goarch CGO_ENABLED=0 go build -trimpath -ldflags '$(LDFLAGS)' -o '$(DIST)'/$$bin .; \
name=csdd_$(VERSION)_$${goos}_$${goarch}; \
if [ "$$goos" = windows ]; then (cd '$(DIST)' && zip -q $$name.zip $$bin); \
else (cd '$(DIST)' && tar -czf $$name.tar.gz $$bin); fi; \
rm -f '$(DIST)'/$$bin; \
done; \
echo "artifacts in $(DIST)/"

.PHONY: npm-build
npm-build: ## Assemble npm/dist/ from artifacts (set VERSION=vX.Y.Z; ARTIFACTS=dir)
node npm/scripts/build-packages.mjs '$(VERSION)' '$(ARTIFACTS)'

.PHONY: npm-dry-run
npm-dry-run: ## Dry-run publish every assembled package
@set -euo pipefail; for d in npm/dist/csdd-*/ npm/dist/csdd/; do \
echo "== $$d"; npm publish "$$d" --access public --dry-run; done

.PHONY: npm-publish
npm-publish: ## Publish the 6 packages, platforms first (skips already-published; OTP=123456 if 2FA)
@set -euo pipefail; \
otp=; if [ -n "$(OTP)" ]; then otp="--otp=$(OTP)"; fi; \
for d in npm/dist/csdd-*/ npm/dist/csdd/; do \
name=$$(cd "$$d" && node -p "require('./package.json').name"); \
ver=$$(cd "$$d" && node -p "require('./package.json').version"); \
if npm view "$$name@$$ver" version >/dev/null 2>&1; then \
echo "skip $$name@$$ver (already published)"; continue; fi; \
echo ">> publishing $$name@$$ver"; npm publish "$$d" --access public $$otp; \
done

.PHONY: release
release: ## Tag VERSION and push -> CI builds + publishes (set VERSION=vX.Y.Z)
@case '$(VERSION)' in v*.*.*) : ;; *) echo "VERSION must look like v1.2.3 (got '$(VERSION)')"; exit 1 ;; esac
git tag -a '$(VERSION)' -m 'csdd $(VERSION)'
git push origin '$(VERSION)'

.PHONY: clean
clean: ## Remove build artifacts (dist/, npm/dist/, ./csdd, coverage)
rm -rf '$(DIST)' npm/dist csdd csdd.exe coverage.out
13 changes: 11 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,17 +48,26 @@ csdd # no args → interactive TUI

## Install

**npm** (cross-platform — installs the right prebuilt binary for your OS/arch):
**npx** (cross-platform — fetches the right prebuilt binary for your OS/arch, no install):

```bash
npx @protonspy/csdd --help # run instantly, no install
npx @protonspy/csdd # interactive TUI
```

Prefer the short `csdd` command on your `PATH`? Install it globally:

```bash
npm install -g @protonspy/csdd # then: csdd
npx @protonspy/csdd --help # or run without installing
```

**Prebuilt binaries:** grab the archive for your platform from the
[releases page](https://github.com/protonspy/csdd/releases) and put `csdd` on
your `PATH`. **From source:** `go install github.com/protonspy/csdd@latest`.

> The examples below call `csdd` directly. Running via npx? Prefix them with
> `npx @protonspy/csdd`, or alias it: `alias csdd='npx @protonspy/csdd'`.

---

## The 5 resources csdd governs
Expand Down
17 changes: 11 additions & 6 deletions npm/csdd/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,19 @@
workflow for [Claude Code](https://claude.com/claude-code) into a contract that
is validated mechanically — for humans *and* AI agents.

## Install
## Run

No install needed — `npx` fetches the right prebuilt binary for your platform:

```bash
npm install -g @protonspy/csdd
npx @protonspy/csdd --help
npx @protonspy/csdd # interactive TUI
```

Or run it without installing:
Prefer the short `csdd` command on your `PATH`? Install it globally:

```bash
npx @protonspy/csdd --help
npm install -g @protonspy/csdd # then: csdd
```

This package ships a thin launcher; the native binary for your platform is
Expand All @@ -25,10 +28,12 @@ download at install time). Prebuilt for linux, macOS, and Windows on x64/arm64.
## Usage

```bash
csdd # interactive TUI
csdd spec generate photo-albums --artifact requirements # headless / CI
npx @protonspy/csdd # interactive TUI
npx @protonspy/csdd spec generate photo-albums --artifact requirements # headless / CI
```

> Installed globally? Drop the `npx @protonspy/` prefix and just call `csdd`.

See the [full documentation](https://github.com/protonspy/csdd#readme).

## License
Expand Down
Loading