Getting set for release
This commit is contained in:
@@ -1,11 +1,9 @@
|
|||||||
{
|
{
|
||||||
"enabledMcpjsonServers": [
|
"enabledMcpjsonServers": ["story-kit"],
|
||||||
"story-kit"
|
|
||||||
],
|
|
||||||
"permissions": {
|
"permissions": {
|
||||||
"allow": [
|
"allow": [
|
||||||
"Bash(./server/target/debug/story-kit-server:*)",
|
"Bash(./server/target/debug/story-kit:*)",
|
||||||
"Bash(./target/debug/story-kit-server:*)",
|
"Bash(./target/debug/story-kit:*)",
|
||||||
"Bash(STORYKIT_PORT=*)",
|
"Bash(STORYKIT_PORT=*)",
|
||||||
"Bash(cargo build:*)",
|
"Bash(cargo build:*)",
|
||||||
"Bash(cargo check:*)",
|
"Bash(cargo check:*)",
|
||||||
|
|||||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,6 +1,9 @@
|
|||||||
# Claude Code
|
# Claude Code
|
||||||
.claude/settings.local.json
|
.claude/settings.local.json
|
||||||
|
|
||||||
|
# Local environment (secrets)
|
||||||
|
.env
|
||||||
|
|
||||||
# App specific
|
# App specific
|
||||||
store.json
|
store.json
|
||||||
.story_kit_port
|
.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
|
- URL to visit in the browser
|
||||||
- Things to check in the UI
|
- Things to check in the UI
|
||||||
- curl commands to exercise relevant API endpoints
|
- 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
|
### 4. Produce Structured Report
|
||||||
Print your QA report to stdout before your process exits. The server will automatically run acceptance gates. Use this format:
|
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
|
- URL to visit in the browser
|
||||||
- Things to check in the UI
|
- Things to check in the UI
|
||||||
- curl commands to exercise relevant API endpoints
|
- 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
|
### 4. Produce Structured Report
|
||||||
Print your QA report to stdout before your process exits. The server will automatically run acceptance gates. Use this format:
|
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
|
## How to Reproduce
|
||||||
|
|
||||||
1. Create an empty directory or navigate to a project without `.story_kit/`
|
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
|
3. Open the project via the UI file chooser
|
||||||
4. Try to chat using the claude-code provider
|
4. Try to chat using the claude-code provider
|
||||||
|
|
||||||
|
|||||||
@@ -6,13 +6,13 @@ name: "Accept optional positional path argument on startup"
|
|||||||
|
|
||||||
## User Story
|
## 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
|
## Acceptance Criteria
|
||||||
|
|
||||||
- [ ] Running `story-kit-server` with no args behaves as today (auto-detect from cwd)
|
- [ ] Running `story-kit` with no args behaves as today (auto-detect from cwd)
|
||||||
- [ ] Running `story-kit-server .` opens the current directory as the project
|
- [ ] Running `story-kit .` opens the current directory as the project
|
||||||
- [ ] Running `story-kit-server /some/path` opens that path 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
|
- [ ] If the path has no .story_kit/, it is scaffolded automatically
|
||||||
- [ ] Invalid paths produce a clear error message
|
- [ ] Invalid paths produce a clear error message
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ name: "Skip selection screen when CLI path argument provided"
|
|||||||
|
|
||||||
## User Story
|
## 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
|
## 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"
|
checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "story-kit-server"
|
name = "story-kit"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-stream",
|
"async-stream",
|
||||||
|
|||||||
18
Makefile
18
Makefile
@@ -1,22 +1,23 @@
|
|||||||
.PHONY: help build-macos build-linux
|
.PHONY: help build-macos build-linux release
|
||||||
|
|
||||||
help:
|
help:
|
||||||
@echo "Story Kit – cross-platform build targets"
|
@echo "Story Kit – cross-platform build targets"
|
||||||
@echo ""
|
@echo ""
|
||||||
@echo " make build-macos Build native macOS release binary"
|
@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 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 ""
|
||||||
@echo "Prerequisites:"
|
@echo "Prerequisites:"
|
||||||
@echo " build-macos: Rust stable toolchain, pnpm"
|
@echo " build-macos: Rust stable toolchain, pnpm"
|
||||||
@echo " build-linux: cargo install cross AND Docker Desktop running"
|
@echo " build-linux: cargo install cross AND Docker Desktop running"
|
||||||
@echo ""
|
@echo ""
|
||||||
@echo "Output:"
|
@echo "Output:"
|
||||||
@echo " macOS : target/release/story-kit-server"
|
@echo " macOS : target/release/story-kit"
|
||||||
@echo " Linux : target/x86_64-unknown-linux-musl/release/story-kit-server"
|
@echo " Linux : target/x86_64-unknown-linux-musl/release/story-kit"
|
||||||
|
|
||||||
## Build a native macOS release binary.
|
## Build a native macOS release binary.
|
||||||
## The frontend is compiled by build.rs (pnpm build) and embedded via rust-embed.
|
## 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:
|
build-macos:
|
||||||
cargo build --release
|
cargo build --release
|
||||||
|
|
||||||
@@ -26,3 +27,12 @@ build-macos:
|
|||||||
## The resulting binary has zero dynamic library dependencies (ldd reports "not a dynamic executable").
|
## The resulting binary has zero dynamic library dependencies (ldd reports "not a dynamic executable").
|
||||||
build-linux:
|
build-linux:
|
||||||
cross build --release --target x86_64-unknown-linux-musl
|
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
|
cargo build --release
|
||||||
|
|
||||||
# Run the server (serves embedded frontend/dist/)
|
# Run the server (serves embedded frontend/dist/)
|
||||||
./target/release/story-kit-server
|
./target/release/story-kit
|
||||||
```
|
```
|
||||||
|
|
||||||
## Cross-Platform Distribution
|
## Cross-Platform Distribution
|
||||||
@@ -37,10 +37,10 @@ Story Kit ships as a **single self-contained binary** with the React frontend em
|
|||||||
```bash
|
```bash
|
||||||
# Native build – no extra tools required beyond Rust + pnpm
|
# Native build – no extra tools required beyond Rust + pnpm
|
||||||
make build-macos
|
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.)
|
# 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)
|
### Linux (static x86_64, zero dynamic deps)
|
||||||
@@ -60,13 +60,13 @@ cargo install cross
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
make build-linux
|
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
|
# 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
|
# 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
|
# Expected: not a dynamic executable
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -74,7 +74,7 @@ ldd target/x86_64-unknown-linux-musl/release/story-kit-server
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
# No Rust, Node, glibc, or any other library needed – just copy and run
|
# No Rust, Node, glibc, or any other library needed – just copy and run
|
||||||
./story-kit-server
|
./story-kit
|
||||||
```
|
```
|
||||||
|
|
||||||
## Testing
|
## 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