Skip to content

Commit 0ca77c1

Browse files
committed
Delete supervise docs/scaffolding and pm2 leftover; add repo-hygiene CI guard; scope MCP npx
1 parent de4649e commit 0ca77c1

4 files changed

Lines changed: 72 additions & 77 deletions

File tree

.github/workflows/cli.yml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,33 @@ jobs:
2121
run: |
2222
command -v caddy >/dev/null 2>&1 || brew install caddy
2323
24+
- name: Guard against committing private / generated files
25+
run: |
26+
# Fail if anything machine-specific, generated, or paid ever gets tracked.
27+
# .gitignore stops accidental `git add`; this catches a file already committed.
28+
forbidden=$(git ls-files | grep -E '(^|/)apps\.json$|^pids/|^logs/|^Caddyfile$|^dashboard\.html$|^\.claude/|(^|/)\.DS_Store$' || true)
29+
# The paid Mac app lives in the private devkit-app repo; only MenuBarApp/docs/ is public.
30+
paid=$(git ls-files 'MenuBarApp/*' | grep -vE '^MenuBarApp/docs/' || true)
31+
if [ -n "$forbidden$paid" ]; then
32+
echo "::error::forbidden files are tracked in this public repo:"
33+
printf '%s\n' "$forbidden" "$paid"
34+
exit 1
35+
fi
36+
echo "repo hygiene OK"
37+
2438
- name: Syntax check CLI and tests
2539
run: |
2640
bash -n bin/devkit
2741
bash -n install.sh
2842
bash -n test/test_registry.sh
43+
bash -n test/test_scan.sh
2944
bash -n test/test_install.sh
3045
3146
- name: Run CLI integration suite
3247
run: bash test/test_registry.sh
3348

49+
- name: Run scan suite
50+
run: bash test/test_scan.sh
51+
3452
- name: Run installer smoke test
3553
run: bash test/test_install.sh

CLAUDE.md

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,4 +46,20 @@ They are regenerated by `devkit reload`.
4646

4747
## Public release constraint
4848

49-
Avoid baking machine-specific paths, usernames, repo URLs, or private project names into committed files.
49+
This repo is **public**. Avoid baking machine-specific paths, usernames, or private
50+
project names into committed files.
51+
52+
**Never commit (privacy / paid product):**
53+
54+
- `apps.json` — the live registry; it contains your real project names and paths. Only the
55+
sanitized `apps.example.json` is tracked.
56+
- `pids/`, `logs/`, `Caddyfile`, `dashboard.html` — runtime + generated, machine-specific.
57+
- `.claude/settings.local.json` (local paths / allow-rules) and `.claude/` generally.
58+
- Anything under `MenuBarApp/` except `MenuBarApp/docs/` — the Mac app is the **paid**
59+
product and lives in the private `devkit-app` repo. Never let its source land here.
60+
61+
These are all in `.gitignore`, but `.gitignore` only stops accidental `git add` — it does
62+
not catch a file that is already tracked. The `cli.yml` workflow has a **repo-hygiene
63+
guard** that fails the build if any of the above ever becomes tracked. Do not weaken it.
64+
If you add a new kind of local/generated/private file, add it to both `.gitignore` and
65+
that guard.

README.md

Lines changed: 6 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -118,53 +118,17 @@ Browse everything at `http://dash.localhost`.
118118

119119
---
120120

121-
## Crash Recovery (opt-in)
122-
123-
By default devkit starts an app and steps back — if the app later dies, it stays down
124-
until you start it again. Opt a devkit-managed app into automatic recovery with a
125-
restart policy:
126-
127-
```bash
128-
devkit register api --port 3000 --cmd "npm start" --restart on-failure
129-
# or change it later:
130-
devkit update api --restart on-failure # policies: no (default) | on-failure | always
131-
```
132-
133-
Then install the background supervisor once:
134-
135-
```bash
136-
devkit supervise install # installs a launchd agent that watches your apps
137-
devkit supervise status # list supervised apps + agent state
138-
devkit supervise uninstall # remove it
139-
```
140-
141-
How it behaves:
142-
143-
- It only revives apps you actually want running. `devkit start` marks intent up;
144-
`devkit stop` / `stop-all` marks it down — so the supervisor **never restarts something
145-
you deliberately stopped**.
146-
- Crash loops are throttled with exponential backoff (5s → capped at 5min), reset once an
147-
app comes back healthy.
148-
- Each pass also re-checks the proxy, so `.localhost` routing self-heals even when no
149-
devkit command is running.
150-
151-
`devkit supervise tick` runs a single pass by hand (this is what the launchd agent calls).
152-
153-
Tuning env vars: `DEVKIT_SUPERVISE_INTERVAL` (seconds between checks, default 10),
154-
`DEVKIT_SUPERVISE_BACKOFF_BASE` (default 5), `DEVKIT_SUPERVISE_BACKOFF_CAP` (default 300).
155-
For a non-Homebrew Caddy setup, set `DEVKIT_CADDY_MANAGED=1` so reloads still apply.
156-
157-
---
158-
159121
## Reliability
160122

161-
- 97 CLI lifecycle tests (including crash recovery, restart policy, and the launchd plist)
123+
- 114 CLI lifecycle tests + 23 scan tests
162124
- 18 installer smoke tests
163125
- GitHub Actions on fresh macOS runners
164126

165-
Explicitly covers stale pid files, orphan recovery, restart pressure, port conflicts,
166-
failed starts, out-of-band `apps.json` edits, malformed registries, and supervised crash
167-
recovery.
127+
Explicitly covers stale pid files, orphan recovery, port conflicts, fail-fast on a
128+
crashing start, out-of-band `apps.json` edits, and malformed registries.
129+
130+
devkit manages an app's lifecycle on demand (`start` / `stop` / `restart`); it does not
131+
run a background daemon, so a crashed app stays down until you start it again.
168132

169133
```bash
170134
bash test/test_registry.sh

bin/devkit

Lines changed: 31 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -43,19 +43,12 @@ LOCK_DIR="$DEVKIT_HOME/.registry.lock"
4343
STAMP_FILE="$DEVKIT_HOME/.caddy.fingerprint"
4444
BREW_CADDYFILE="${DEVKIT_BREW_CADDYFILE:-/opt/homebrew/etc/Caddyfile}"
4545

46-
# ── Supervisor (opt-in crash recovery) ──────────────────────────────────────
47-
# wants/ records desired state (set on start, cleared on stop) so the supervisor only
48-
# revives apps you actually want up — it never fights a manual `devkit stop`.
49-
# state/ holds per-app backoff counters so a crash-looping app can't be hammered.
46+
# Desired-state markers. `wants/` records which apps were last started vs stopped. These
47+
# are advisory only today (written on start/stop, read by nothing) — kept as the seam for
48+
# a future reliability layer, which will be process-compose, not a hand-rolled supervisor.
49+
# TODO: fully remove these + the inert `restart` policy in a focused pass.
5050
WANTS_DIR="$DEVKIT_HOME/supervisor/wants"
5151
SUPERVISOR_STATE_DIR="$DEVKIT_HOME/supervisor/state"
52-
SUPERVISOR_LOCK="$DEVKIT_HOME/supervisor/.tick.lock"
53-
SUPERVISOR_LOG="$LOGS_DIR/_supervisor.log"
54-
SUPERVISOR_LABEL="com.devkit.supervisor"
55-
SUPERVISOR_PLIST="$HOME/Library/LaunchAgents/$SUPERVISOR_LABEL.plist"
56-
SUPERVISOR_INTERVAL="${DEVKIT_SUPERVISE_INTERVAL:-10}"
57-
SUPERVISOR_BACKOFF_BASE="${DEVKIT_SUPERVISE_BACKOFF_BASE:-5}"
58-
SUPERVISOR_BACKOFF_CAP="${DEVKIT_SUPERVISE_BACKOFF_CAP:-300}"
5952
DEVKIT_BIN_SELF="$SCRIPT_DIR/$(basename -- "${BASH_SOURCE[0]}")"
6053

6154
die() { echo "devkit: $*" >&2; exit 1; }
@@ -382,7 +375,6 @@ is_running() {
382375
# stopped — managed, down, no recorded failure (identical to never-started)
383376
app_state() {
384377
local name="$1" managed="$2"
385-
[[ "$managed" == "pm2" ]] && managed="devkit"
386378
case "$managed" in
387379
external) echo "external"; return 0 ;;
388380
devkit)
@@ -1512,45 +1504,50 @@ OUT
15121504
# Wire the devkit MCP server into an AI agent so it can register/manage apps as
15131505
# structured tool calls (instead of relying on a CLAUDE.md text instruction).
15141506
cmd_setup_mcp() {
1507+
# Prefer a local checkout (handy during development); otherwise run the published
1508+
# package with `npx -y devkit-mcp`, so a standalone CLI install needs nothing extra.
1509+
# Either way the agent gets the same stdio MCP server.
15151510
local candidates=(
15161511
"$REPO_HOME/../devkit-mcp/index.js"
15171512
"$REPO_HOME/devkit-mcp/index.js"
1518-
"$REPO_HOME/mcp-server/index.js"
15191513
"$DEVKIT_HOME/devkit-mcp/index.js"
1520-
"$DEVKIT_HOME/mcp-server/index.js"
15211514
)
15221515
local server="" c
15231516
for c in "${candidates[@]}"; do
1524-
if [[ -f "$c" ]]; then
1525-
server="$(cd "$(dirname "$c")" && pwd)/index.js"
1526-
break
1527-
fi
1517+
if [[ -f "$c" ]]; then server="$(cd "$(dirname "$c")" && pwd)/index.js"; break; fi
15281518
done
1529-
[[ -n "$server" ]] || die "could not find the devkit MCP server (index.js) — expected near $REPO_HOME/../devkit-mcp/"
1530-
1531-
need node
15321519

1533-
# Install the MCP's dependencies if missing, otherwise the server crashes on first
1534-
# call with "Cannot find module @modelcontextprotocol/sdk".
1535-
local server_dir; server_dir=$(dirname "$server")
1536-
if [[ ! -d "$server_dir/node_modules/@modelcontextprotocol" ]]; then
1537-
need npm
1538-
echo "installing devkit MCP dependencies..."
1539-
(cd "$server_dir" && npm install --silent) || die "npm install failed in $server_dir"
1520+
local -a runcmd
1521+
if [[ -n "$server" ]]; then
1522+
need node
1523+
# Install deps if missing, else the server crashes with "Cannot find module
1524+
# @modelcontextprotocol/sdk" on first call.
1525+
local server_dir; server_dir=$(dirname "$server")
1526+
if [[ ! -d "$server_dir/node_modules/@modelcontextprotocol" ]]; then
1527+
need npm
1528+
echo "installing devkit MCP dependencies..."
1529+
(cd "$server_dir" && npm install --silent) || die "npm install failed in $server_dir"
1530+
fi
1531+
runcmd=(node "$server")
1532+
else
1533+
# Unscoped "devkit-mcp" is taken by an unrelated package on npm, so we publish under
1534+
# the @djadmin scope. npx fetches it on first use (then caches).
1535+
need npx
1536+
runcmd=(npx -y @djadmin/devkit-mcp)
15401537
fi
15411538

15421539
if command -v claude >/dev/null 2>&1; then
1543-
if claude mcp add devkit -- node "$server"; then
1544-
echo "devkit MCP registered with Claude Code. Restart Claude Code to load it."
1540+
if claude mcp add devkit -- "${runcmd[@]}"; then
1541+
echo "devkit MCP registered with Claude Code (${runcmd[*]}). Restart Claude Code to load it."
15451542
else
1546-
die "failed to register the MCP with Claude Code (try: claude mcp add devkit -- node \"$server\")"
1543+
die "failed to register the MCP with Claude Code (try: claude mcp add devkit -- ${runcmd[*]})"
15471544
fi
15481545
else
15491546
echo "Claude Code CLI not found. Add the devkit MCP to your agent manually:"
1550-
echo " command: node"
1551-
echo " args: $server"
1547+
echo " command: ${runcmd[0]}"
1548+
echo " args: ${runcmd[*]:1}"
15521549
echo
1553-
echo " Claude Code: claude mcp add devkit -- node \"$server\""
1550+
echo " Claude Code: claude mcp add devkit -- ${runcmd[*]}"
15541551
echo " Cursor / Windsurf / other: see your agent's MCP config docs."
15551552
fi
15561553
}

0 commit comments

Comments
 (0)