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
10 changes: 9 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -107,17 +107,25 @@ jobs:
path: artifacts
merge-multiple: true

# The MCP server ships in lockstep with the CLI; build-packages.mjs stamps
# its version + optionalDependencies and stages it as npm/dist/csdd-mcp.
- name: Build MCP server
run: |
npm --prefix mcp-server ci
npm --prefix mcp-server run build

- name: Assemble npm packages
run: node npm/scripts/build-packages.mjs "${{ github.ref_name }}" artifacts

- name: Publish (platform packages first, then the root)
- name: Publish (platform packages + mcp-server 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
# csdd-*/ covers the 5 platform binaries and csdd-mcp; csdd/ is the root launcher.
for d in npm/dist/csdd-*/; do
npm publish "$d" --access public --provenance
done
Expand Down
29 changes: 21 additions & 8 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@
#
# 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)
# make mcp-dist # build the MCP server (tsc)
# make npm-build VERSION=v0.2.0 # assemble npm/dist/ (7 packages) from those
# make npm-dry-run # validate all 7 packages without publishing
# make npm-publish [OTP=123456] # publish the 7 packages (skips already-published)
#
# Auth for a manual publish: either an Automation token
# npm config set //registry.npmjs.org/:_authToken <token>
Expand Down Expand Up @@ -55,8 +56,16 @@ vet: ## go vet ./...
.PHONY: check
check: fmt vet test ## Run the full CI gate (gofmt + vet + race tests)

# require-version fails fast when the release VERSION is left at the 'dev'
# default. Without it, dist/npm-build produce 'dev'-named tarballs (and an
# invalid npm semver), which only surfaces later as a cryptic `tar: Cannot open`
# when npm-build can't find a matching artifact.
.PHONY: require-version
require-version:
@case '$(VERSION)' in v*.*.*) : ;; *) echo "set a release VERSION like v0.1.1 (got '$(VERSION)'); e.g. make $(MAKECMDGOALS) VERSION=v0.1.1" >&2; exit 1 ;; esac

.PHONY: dist
dist: ## Cross-compile every npm target into $(DIST)/ (set VERSION=vX.Y.Z)
dist: require-version ## 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; \
Expand All @@ -69,8 +78,13 @@ dist: ## Cross-compile every npm target into $(DIST)/ (set VERSION=vX.Y.Z)
done; \
echo "artifacts in $(DIST)/"

.PHONY: mcp-dist
mcp-dist: ## Build the MCP server (tsc) so npm-build can stage @protonspy/csdd-mcp
npm --prefix mcp-server ci
npm --prefix mcp-server run build

.PHONY: npm-build
npm-build: ## Assemble npm/dist/ from artifacts (set VERSION=vX.Y.Z; ARTIFACTS=dir)
npm-build: require-version ## Assemble npm/dist/ (CLI + mcp-server) from artifacts (VERSION=vX.Y.Z; ARTIFACTS=dir; needs `make dist` + `make mcp-dist`)
node npm/scripts/build-packages.mjs '$(VERSION)' '$(ARTIFACTS)'

.PHONY: npm-dry-run
Expand All @@ -79,7 +93,7 @@ npm-dry-run: ## Dry-run publish every assembled package
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)
npm-publish: ## Publish the assembled packages (CLI + mcp-server), 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 \
Expand All @@ -91,8 +105,7 @@ npm-publish: ## Publish the 6 packages, platforms first (skips already-published
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
release: require-version ## Tag VERSION and push -> CI builds + publishes (set VERSION=vX.Y.Z)
git tag -a '$(VERSION)' -m 'csdd $(VERSION)'
git push origin '$(VERSION)'

Expand Down
9 changes: 9 additions & 0 deletions mcp-server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,15 @@
"name": "@protonspy/csdd-mcp",
"version": "0.1.0",
"description": "MCP server exposing the csdd CLI over stdio (one tool per subcommand).",
"homepage": "https://github.com/protonspy/csdd/tree/main/mcp-server#readme",
"bugs": {
"url": "https://github.com/protonspy/csdd/issues"
},
"repository": {
"type": "git",
"url": "git+https://github.com/protonspy/csdd.git",
"directory": "mcp-server"
},
"type": "module",
"bin": {
"csdd-mcp": "dist/index.js"
Expand Down
31 changes: 31 additions & 0 deletions npm/scripts/build-packages.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { execFileSync } from "node:child_process";
import {
chmodSync,
cpSync,
existsSync,
mkdirSync,
readFileSync,
rmSync,
Expand Down Expand Up @@ -114,3 +115,33 @@ rootPkg.version = version;
rootPkg.optionalDependencies = optionalDependencies;
writeFileSync(join(rootOut, "package.json"), JSON.stringify(rootPkg, null, 2) + "\n");
console.log(`built ${rootPkg.name}@${version}`);

// --- mcp-server package ----------------------------------------------------
// Ship @protonspy/csdd-mcp in lockstep with the CLI: stamp it to the same
// release version and pin the per-platform csdd binaries it resolves to that
// exact version, then stage its pre-built dist/ for publish. Build it first:
// npm --prefix mcp-server ci && npm --prefix mcp-server run build
const mcpSrc = join(repoRoot, "mcp-server");
const mcpDist = join(mcpSrc, "dist");
if (!existsSync(mcpDist)) {
console.error(
"error: mcp-server/dist not found — build it first:\n" +
" npm --prefix mcp-server ci && npm --prefix mcp-server run build\n" +
" (or `make mcp-dist`)"
);
process.exit(1);
}
const mcpOut = join(outDir, "csdd-mcp");
mkdirSync(mcpOut, { recursive: true });
cpSync(mcpDist, join(mcpOut, "dist"), { recursive: true });
cpSync(join(mcpSrc, "README.md"), join(mcpOut, "README.md"));

const mcpPkg = JSON.parse(readFileSync(join(mcpSrc, "package.json"), "utf8"));
mcpPkg.version = version;
for (const k of Object.keys(mcpPkg.optionalDependencies ?? {})) {
mcpPkg.optionalDependencies[k] = version; // exact, in lockstep with the binary
}
delete mcpPkg.devDependencies; // not needed by consumers of the published package
delete mcpPkg.scripts; // prepublishOnly would re-run tsc against a src/ we don't ship
writeFileSync(join(mcpOut, "package.json"), JSON.stringify(mcpPkg, null, 2) + "\n");
console.log(`built ${mcpPkg.name}@${version}`);
Loading