Getting set for release
This commit is contained in:
@@ -1,11 +1,9 @@
|
||||
{
|
||||
"enabledMcpjsonServers": [
|
||||
"story-kit"
|
||||
],
|
||||
"enabledMcpjsonServers": ["story-kit"],
|
||||
"permissions": {
|
||||
"allow": [
|
||||
"Bash(./server/target/debug/story-kit-server:*)",
|
||||
"Bash(./target/debug/story-kit-server:*)",
|
||||
"Bash(./server/target/debug/story-kit:*)",
|
||||
"Bash(./target/debug/story-kit:*)",
|
||||
"Bash(STORYKIT_PORT=*)",
|
||||
"Bash(cargo build:*)",
|
||||
"Bash(cargo check:*)",
|
||||
@@ -61,4 +59,4 @@
|
||||
"Write"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,6 +1,9 @@
|
||||
# Claude Code
|
||||
.claude/settings.local.json
|
||||
|
||||
# Local environment (secrets)
|
||||
.env
|
||||
|
||||
# App specific
|
||||
store.json
|
||||
.story_kit_port
|
||||
|
||||
@@ -102,7 +102,7 @@ Read CLAUDE.md first, then .story_kit/README.md to understand the dev process.
|
||||
- URL to visit in the browser
|
||||
- Things to check in the UI
|
||||
- curl commands to exercise relevant API endpoints
|
||||
- Kill the test server when done: `pkill -f story-kit-server || true`
|
||||
- Kill the test server when done: `pkill -f story-kit || true`
|
||||
|
||||
### 4. Produce Structured Report
|
||||
Print your QA report to stdout before your process exits. The server will automatically run acceptance gates. Use this format:
|
||||
@@ -179,7 +179,7 @@ Read CLAUDE.md first, then .story_kit/README.md to understand the dev process.
|
||||
- URL to visit in the browser
|
||||
- Things to check in the UI
|
||||
- curl commands to exercise relevant API endpoints
|
||||
- Kill the test server when done: `pkill -f story-kit-server || true`
|
||||
- Kill the test server when done: `pkill -f story-kit || true`
|
||||
|
||||
### 4. Produce Structured Report
|
||||
Print your QA report to stdout before your process exits. The server will automatically run acceptance gates. Use this format:
|
||||
|
||||
@@ -13,7 +13,7 @@ Additionally, there is no way for the user to trigger scaffolding from the CLI
|
||||
## How to Reproduce
|
||||
|
||||
1. Create an empty directory or navigate to a project without `.story_kit/`
|
||||
2. Run `story-kit-server`
|
||||
2. Run `story-kit`
|
||||
3. Open the project via the UI file chooser
|
||||
4. Try to chat using the claude-code provider
|
||||
|
||||
|
||||
@@ -6,13 +6,13 @@ name: "Accept optional positional path argument on startup"
|
||||
|
||||
## User Story
|
||||
|
||||
As a user, I want to run `story-kit-server .` or `story-kit-server /path/to/project` to start the server with that directory as the project, so that I don't have to use the UI file chooser.
|
||||
As a user, I want to run `story-kit .` or `story-kit /path/to/project` to start the server with that directory as the project, so that I don't have to use the UI file chooser.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- [ ] Running `story-kit-server` with no args behaves as today (auto-detect from cwd)
|
||||
- [ ] Running `story-kit-server .` opens the current directory as the project
|
||||
- [ ] Running `story-kit-server /some/path` opens that path as the project
|
||||
- [ ] Running `story-kit` with no args behaves as today (auto-detect from cwd)
|
||||
- [ ] Running `story-kit .` opens the current directory as the project
|
||||
- [ ] Running `story-kit /some/path` opens that path as the project
|
||||
- [ ] If the path has no .story_kit/, it is scaffolded automatically
|
||||
- [ ] Invalid paths produce a clear error message
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ name: "Skip selection screen when CLI path argument provided"
|
||||
|
||||
## User Story
|
||||
|
||||
As a user, I want the frontend to go straight to the project workspace when I start the server with an explicit path argument (e.g. `story-kit-server .`), so that I don't have to click through the selection screen for a project the server already opened.
|
||||
As a user, I want the frontend to go straight to the project workspace when I start the server with an explicit path argument (e.g. `story-kit .`), so that I don't have to click through the selection screen for a project the server already opened.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
|
||||
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -4078,7 +4078,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596"
|
||||
|
||||
[[package]]
|
||||
name = "story-kit-server"
|
||||
name = "story-kit"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"async-stream",
|
||||
|
||||
18
Makefile
18
Makefile
@@ -1,22 +1,23 @@
|
||||
.PHONY: help build-macos build-linux
|
||||
.PHONY: help build-macos build-linux release
|
||||
|
||||
help:
|
||||
@echo "Story Kit – cross-platform build targets"
|
||||
@echo ""
|
||||
@echo " make build-macos Build native macOS release binary"
|
||||
@echo " make build-linux Build static Linux x86_64 release binary (requires cross + Docker)"
|
||||
@echo " make release V=x.y.z Build both targets and publish a Gitea release"
|
||||
@echo ""
|
||||
@echo "Prerequisites:"
|
||||
@echo " build-macos: Rust stable toolchain, pnpm"
|
||||
@echo " build-linux: cargo install cross AND Docker Desktop running"
|
||||
@echo ""
|
||||
@echo "Output:"
|
||||
@echo " macOS : target/release/story-kit-server"
|
||||
@echo " Linux : target/x86_64-unknown-linux-musl/release/story-kit-server"
|
||||
@echo " macOS : target/release/story-kit"
|
||||
@echo " Linux : target/x86_64-unknown-linux-musl/release/story-kit"
|
||||
|
||||
## Build a native macOS release binary.
|
||||
## The frontend is compiled by build.rs (pnpm build) and embedded via rust-embed.
|
||||
## Verify dynamic deps afterwards: otool -L target/release/story-kit-server
|
||||
## Verify dynamic deps afterwards: otool -L target/release/story-kit
|
||||
build-macos:
|
||||
cargo build --release
|
||||
|
||||
@@ -26,3 +27,12 @@ build-macos:
|
||||
## The resulting binary has zero dynamic library dependencies (ldd reports "not a dynamic executable").
|
||||
build-linux:
|
||||
cross build --release --target x86_64-unknown-linux-musl
|
||||
|
||||
## Publish a release to Gitea with macOS and Linux binaries.
|
||||
## Requires: GITEA_TOKEN env var, cross, Docker running.
|
||||
## Usage: make release V=0.2.0
|
||||
release:
|
||||
ifndef V
|
||||
$(error Usage: make release V=x.y.z)
|
||||
endif
|
||||
script/release $(V)
|
||||
|
||||
14
README.md
14
README.md
@@ -24,7 +24,7 @@ cargo run
|
||||
cargo build --release
|
||||
|
||||
# Run the server (serves embedded frontend/dist/)
|
||||
./target/release/story-kit-server
|
||||
./target/release/story-kit
|
||||
```
|
||||
|
||||
## Cross-Platform Distribution
|
||||
@@ -37,10 +37,10 @@ Story Kit ships as a **single self-contained binary** with the React frontend em
|
||||
```bash
|
||||
# Native build – no extra tools required beyond Rust + pnpm
|
||||
make build-macos
|
||||
# Output: target/release/story-kit-server
|
||||
# Output: target/release/story-kit
|
||||
|
||||
# Verify only system frameworks are linked (Security.framework, libSystem.B.dylib, etc.)
|
||||
otool -L target/release/story-kit-server
|
||||
otool -L target/release/story-kit
|
||||
```
|
||||
|
||||
### Linux (static x86_64, zero dynamic deps)
|
||||
@@ -60,13 +60,13 @@ cargo install cross
|
||||
|
||||
```bash
|
||||
make build-linux
|
||||
# Output: target/x86_64-unknown-linux-musl/release/story-kit-server
|
||||
# Output: target/x86_64-unknown-linux-musl/release/story-kit
|
||||
|
||||
# Verify the binary is statically linked
|
||||
file target/x86_64-unknown-linux-musl/release/story-kit-server
|
||||
file target/x86_64-unknown-linux-musl/release/story-kit
|
||||
# Expected: ELF 64-bit LSB executable, x86-64, statically linked
|
||||
|
||||
ldd target/x86_64-unknown-linux-musl/release/story-kit-server
|
||||
ldd target/x86_64-unknown-linux-musl/release/story-kit
|
||||
# Expected: not a dynamic executable
|
||||
```
|
||||
|
||||
@@ -74,7 +74,7 @@ ldd target/x86_64-unknown-linux-musl/release/story-kit-server
|
||||
|
||||
```bash
|
||||
# No Rust, Node, glibc, or any other library needed – just copy and run
|
||||
./story-kit-server
|
||||
./story-kit
|
||||
```
|
||||
|
||||
## Testing
|
||||
|
||||
97
script/release
Executable file
97
script/release
Executable file
@@ -0,0 +1,97 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# ── Configuration ──────────────────────────────────────────────
|
||||
GITEA_URL="https://code.crashlabs.io"
|
||||
REPO="dave/story-kit"
|
||||
BINARY_NAME="story-kit"
|
||||
|
||||
# ── Load .env if present ───────────────────────────────────────
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
|
||||
if [ -f "${SCRIPT_DIR}/.env" ]; then
|
||||
set -a
|
||||
source "${SCRIPT_DIR}/.env"
|
||||
set +a
|
||||
fi
|
||||
|
||||
# ── Preflight ──────────────────────────────────────────────────
|
||||
if [ -z "${GITEA_TOKEN:-}" ]; then
|
||||
echo "Error: GITEA_TOKEN is not set."
|
||||
echo "Create a token at ${GITEA_URL}/user/settings/applications"
|
||||
echo "Then add to .env: GITEA_TOKEN=your_token"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
VERSION="${1:-}"
|
||||
if [ -z "$VERSION" ]; then
|
||||
echo "Usage: script/release <version>"
|
||||
echo "Example: script/release 0.2.0"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
TAG="v${VERSION}"
|
||||
|
||||
if git rev-parse "$TAG" >/dev/null 2>&1; then
|
||||
echo "Error: Tag ${TAG} already exists."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! command -v cross >/dev/null 2>&1; then
|
||||
echo "Error: 'cross' is not installed. Run: cargo install cross"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! docker info >/dev/null 2>&1; then
|
||||
echo "Error: Docker is not running. Start Docker Desktop first."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "==> Releasing ${TAG}"
|
||||
|
||||
# ── Build ──────────────────────────────────────────────────────
|
||||
echo "==> Building macOS (native)..."
|
||||
cargo build --release
|
||||
|
||||
echo "==> Building Linux (static musl via cross)..."
|
||||
cross build --release --target x86_64-unknown-linux-musl
|
||||
|
||||
# ── Package ────────────────────────────────────────────────────
|
||||
DIST="target/dist"
|
||||
rm -rf "$DIST"
|
||||
mkdir -p "$DIST"
|
||||
|
||||
cp "target/release/${BINARY_NAME}" "${DIST}/${BINARY_NAME}-macos-arm64"
|
||||
cp "target/x86_64-unknown-linux-musl/release/${BINARY_NAME}" "${DIST}/${BINARY_NAME}-linux-amd64"
|
||||
chmod +x "${DIST}"/*
|
||||
|
||||
echo "==> Binaries:"
|
||||
ls -lh "${DIST}"/
|
||||
|
||||
# ── Tag & Push ─────────────────────────────────────────────────
|
||||
echo "==> Tagging ${TAG}..."
|
||||
git tag -a "$TAG" -m "Release ${TAG}"
|
||||
git push origin "$TAG"
|
||||
|
||||
# ── Create Gitea Release ──────────────────────────────────────
|
||||
echo "==> Creating release on Gitea..."
|
||||
RELEASE_RESPONSE=$(curl -sf -X POST \
|
||||
-H "Authorization: token ${GITEA_TOKEN}" \
|
||||
-H "Content-Type: application/json" \
|
||||
"${GITEA_URL}/api/v1/repos/${REPO}/releases" \
|
||||
-d "{\"tag_name\": \"${TAG}\", \"name\": \"${TAG}\", \"body\": \"Release ${TAG}\"}")
|
||||
|
||||
RELEASE_ID=$(echo "$RELEASE_RESPONSE" | python3 -c "import sys,json; print(json.load(sys.stdin)['id'])")
|
||||
|
||||
# ── Upload Binaries ───────────────────────────────────────────
|
||||
for file in "${DIST}"/*; do
|
||||
filename=$(basename "$file")
|
||||
echo "==> Uploading ${filename}..."
|
||||
curl -sf -X POST \
|
||||
-H "Authorization: token ${GITEA_TOKEN}" \
|
||||
-F "attachment=@${file};filename=${filename}" \
|
||||
"${GITEA_URL}/api/v1/repos/${REPO}/releases/${RELEASE_ID}/assets" > /dev/null
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo "==> Done! Release ${TAG} published:"
|
||||
echo " ${GITEA_URL}/${REPO}/releases/tag/${TAG}"
|
||||
Reference in New Issue
Block a user