stackdeck 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json ADDED
@@ -0,0 +1,17 @@
1
+ {
2
+ "name": "stackdeck",
3
+ "version": "0.3.0",
4
+ "description": "Your projects folder, as a control panel. Browser dashboard to start, stop, and organize local dev services — git-branch aware, zero dependencies.",
5
+ "license": "MIT",
6
+ "author": "beingmechon",
7
+ "bin": { "stackdeck": "bin/stackdeck.js" },
8
+ "main": "server.js",
9
+ "files": ["server.js", "index.html", "bin/", "scripts/"],
10
+ "scripts": {
11
+ "start": "node server.js"
12
+ },
13
+ "engines": { "node": ">=18.13" },
14
+ "os": ["darwin", "linux"],
15
+ "keywords": ["process-manager", "dev-server", "dashboard", "local-development", "git", "procfile", "hotel"],
16
+ "repository": { "type": "git", "url": "https://github.com/beingmechon/stackdeck" }
17
+ }
Binary file
@@ -0,0 +1,90 @@
1
+ #!/usr/bin/env bash
2
+ # Spin up a self-contained demo board with fictional services — for README
3
+ # screenshots, GIFs, and trying Stackdeck without touching your real config.
4
+ #
5
+ # ./scripts/demo.sh → http://localhost:9899 (isolated STACKDECK_HOME)
6
+ # ./scripts/demo.sh stop → tear it down
7
+ set -euo pipefail
8
+ REPO="$(cd "$(dirname "$0")/.." && pwd)"
9
+ DEMO="${STACKDECK_DEMO_DIR:-/tmp/stackdeck-demo}"
10
+ PORT=9899
11
+
12
+ if [ "${1:-}" = "stop" ]; then
13
+ pkill -f "STACKDECK_DEMO_MARK" 2>/dev/null || true
14
+ [ -n "$(lsof -tnP -iTCP:$PORT -sTCP:LISTEN 2>/dev/null)" ] && kill "$(lsof -tnP -iTCP:$PORT -sTCP:LISTEN)"
15
+ rm -rf "$DEMO"
16
+ echo "demo stopped and removed"
17
+ exit 0
18
+ fi
19
+
20
+ rm -rf "$DEMO"
21
+ mkdir -p "$DEMO/home" "$DEMO/projects"
22
+
23
+ # ── fictional repos so the Projects section has content ──────────────────
24
+ mkrepo() { # name, extra-branch, kind
25
+ local d="$DEMO/projects/$1"
26
+ mkdir -p "$d"
27
+ cd "$d"
28
+ git init -q -b main
29
+ git config user.email demo@example.com && git config user.name demo
30
+ if [ "$3" = node ]; then
31
+ printf '{ "name": "%s", "scripts": { "dev": "node server.js" } }\n' "$1" > package.json
32
+ else
33
+ printf '[project]\nname = "%s"\n' "$1" > pyproject.toml
34
+ touch main.py
35
+ fi
36
+ git add -A && git commit -qm "init"
37
+ [ -n "$2" ] && git branch "$2"
38
+ cd - >/dev/null
39
+ }
40
+ mkrepo shopfront feature/checkout-v2 node
41
+ mkrepo orders-api feature/rate-limits node
42
+ mkrepo email-worker "" py
43
+ mkrepo ml-recommender experiment/embeddings py
44
+ mkrepo mobile-app "" node
45
+
46
+ # ── demo services: real processes, fictional purpose ─────────────────────
47
+ LOOP='STACKDECK_DEMO_MARK=1; while true; do'
48
+ cat > "$DEMO/home/config.json" <<JSON
49
+ {
50
+ "port": $PORT,
51
+ "projectRoots": ["$DEMO/projects"],
52
+ "groups": ["Shop", "Pipeline"],
53
+ "categoryOrder": ["Product", "Services", "Experiments"],
54
+ "projectCategories": {
55
+ "shopfront": "Product", "mobile-app": "Product",
56
+ "orders-api": "Services", "email-worker": "Services",
57
+ "ml-recommender": "Experiments"
58
+ },
59
+ "services": [
60
+ { "name": "shopfront", "dir": "$DEMO/projects/shopfront", "group": "Shop", "port": 7411,
61
+ "command": "python3 -m http.server \${PORT:-7411} --bind 127.0.0.1" },
62
+ { "name": "orders-api", "dir": "$DEMO/projects/orders-api", "group": "Shop", "port": 7412,
63
+ "dependsOn": ["session-cache"],
64
+ "command": "python3 -m http.server \${PORT:-7412} --bind 127.0.0.1" },
65
+ { "name": "session-cache", "dir": "$DEMO/projects/orders-api", "group": "Shop",
66
+ "command": "$LOOP echo \"GET session:\$RANDOM → hit (2ms)\"; sleep 3; done" },
67
+ { "name": "email-worker", "dir": "$DEMO/projects/email-worker", "group": "Pipeline", "restart": "on-failure",
68
+ "command": "$LOOP echo \"[worker] sent order confirmation #\$RANDOM\"; sleep 2; done" },
69
+ { "name": "search-indexer", "dir": "$DEMO/projects/ml-recommender", "group": "Pipeline",
70
+ "command": "$LOOP echo \"indexed \$((RANDOM % 90 + 10)) documents\"; sleep 4; done" }
71
+ ]
72
+ }
73
+ JSON
74
+
75
+ # ── daemon + start everything ─────────────────────────────────────────────
76
+ STACKDECK_HOME="$DEMO/home" STACKDECK_PORT=$PORT nohup node "$REPO/server.js" \
77
+ > "$DEMO/daemon.log" 2>&1 &
78
+ for _ in $(seq 1 20); do
79
+ curl -sf -m 1 -o /dev/null "http://localhost:$PORT/api/ping" && break
80
+ sleep 0.5
81
+ done
82
+ TOKEN=$(cat "$DEMO/home/secret")
83
+ H=(-H "X-Stackdeck-Token: $TOKEN" -H 'Content-Type: application/json')
84
+ curl -s "${H[@]}" -X POST "http://localhost:$PORT/api/start-all" -d '{"group":"Shop"}' >/dev/null
85
+ curl -s "${H[@]}" -X POST "http://localhost:$PORT/api/start-all" -d '{"group":"Pipeline"}' >/dev/null
86
+ # one worktree instance for the money shot
87
+ curl -s "${H[@]}" -X POST "http://localhost:$PORT/api/worktree/start" \
88
+ -d '{"name":"orders-api","branch":"feature/rate-limits"}' >/dev/null
89
+
90
+ echo "demo board: http://localhost:$PORT"
@@ -0,0 +1,47 @@
1
+ #!/usr/bin/env bash
2
+ # Build ~/Applications/Stackdeck.app from this checkout (self-contained copy).
3
+ set -euo pipefail
4
+ REPO="$(cd "$(dirname "$0")/.." && pwd)"
5
+ APP="$HOME/Applications/Stackdeck.app"
6
+
7
+ mkdir -p "$APP/Contents/MacOS" "$APP/Contents/Resources"
8
+ cp "$REPO/server.js" "$REPO/index.html" "$APP/Contents/Resources/"
9
+ [ -f "$REPO/scripts/Stackdeck.icns" ] && cp "$REPO/scripts/Stackdeck.icns" "$APP/Contents/Resources/"
10
+
11
+ cat > "$APP/Contents/Info.plist" <<'PLIST'
12
+ <?xml version="1.0" encoding="UTF-8"?>
13
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
14
+ <plist version="1.0">
15
+ <dict>
16
+ <key>CFBundleName</key> <string>Stackdeck</string>
17
+ <key>CFBundleDisplayName</key> <string>Stackdeck</string>
18
+ <key>CFBundleIdentifier</key> <string>dev.stackdeck.app</string>
19
+ <key>CFBundleVersion</key> <string>0.1.0</string>
20
+ <key>CFBundlePackageType</key> <string>APPL</string>
21
+ <key>CFBundleExecutable</key> <string>Stackdeck</string>
22
+ <key>CFBundleIconFile</key> <string>Stackdeck</string>
23
+ <key>LSUIElement</key> <true/>
24
+ </dict>
25
+ </plist>
26
+ PLIST
27
+
28
+ cat > "$APP/Contents/MacOS/Stackdeck" <<'LAUNCH'
29
+ #!/bin/bash
30
+ # Finder launches apps with a bare PATH; resolve node via the user's shell.
31
+ NODE="$(${SHELL:-/bin/zsh} -lc 'command -v node' 2>/dev/null || true)"
32
+ [ -z "$NODE" ] && { osascript -e 'display alert "Stackdeck" message "node not found in PATH"'; exit 1; }
33
+ RES="$(cd "$(dirname "$0")/../Resources" && pwd)"
34
+ PORT="${STACKDECK_PORT:-8899}"
35
+ if ! lsof -tnP -iTCP:$PORT -sTCP:LISTEN >/dev/null 2>&1; then
36
+ LOGDIR="${STACKDECK_HOME:-${XDG_CONFIG_HOME:-$HOME/.config}/stackdeck}/logs"
37
+ mkdir -p "$LOGDIR"
38
+ nohup "$NODE" "$RES/server.js" >> "$LOGDIR/daemon.log" 2>&1 &
39
+ for _ in $(seq 1 20); do
40
+ lsof -tnP -iTCP:$PORT -sTCP:LISTEN >/dev/null 2>&1 && break
41
+ sleep 0.25
42
+ done
43
+ fi
44
+ open "http://localhost:$PORT"
45
+ LAUNCH
46
+ chmod +x "$APP/Contents/MacOS/Stackdeck"
47
+ echo "built $APP"