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/LICENSE +21 -0
- package/README.md +173 -0
- package/bin/stackdeck.js +213 -0
- package/index.html +1134 -0
- package/package.json +17 -0
- package/scripts/Stackdeck.icns +0 -0
- package/scripts/demo.sh +90 -0
- package/scripts/macos-app.sh +47 -0
- package/server.js +1466 -0
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
|
package/scripts/demo.sh
ADDED
|
@@ -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"
|