Archived
nsbx: add one-command dev onboarding (branch + worktree + isolated engram)
El SDK CI - dev / build-and-test (pull_request) Successful in 6m30s
El SDK CI - dev / build-and-test (pull_request) Successful in 6m30s
Add 'nsbx dev <name>' / 'nsbx dev-down <name>' plus a Makefile so a newcomer goes from clone to coding on an isolated cloned engram in one command. The worktree is created on a real named branch at a persistent path (never /tmp, guarded), and the whole worktree is pinned to the clone via an emitted .nsbx-env so live :8742 / ~/.neuron/engram is unreachable by accident. Optimizes the El edit->build->run loop so provisional work is built in El against a throwaway clone instead of prototyped in Python and re-ported. Additive over the proven primitives; no live cutover.
This commit is contained in:
@@ -623,10 +623,181 @@ cmd_status(){
|
||||
[ -f "$(sdir "$name")/validate.json" ] && { echo "--- last validation ---"; python3 -m json.tool "$(sdir "$name")/validate.json"; }
|
||||
}
|
||||
|
||||
# ================================================================ dev ==========
|
||||
# ONE-COMMAND isolated dev environment. Everything a newcomer (Tim, any agent)
|
||||
# needs to go from clone -> coding on an isolated running mind, in a single shot:
|
||||
# 1) a git BRANCH (dev/<name>, or --prefix)
|
||||
# 2) a git WORKTREE for it, at a visible path they can open + edit
|
||||
# 3) an ISOLATED engram bound to a NON-default port, on a clone of the live store
|
||||
# (stock prod binary by default — instant + safe; --build to compile the
|
||||
# worktree's own runtime instead). Prod :$LIVE_BIND_PORT/:$SOUL_PORT is untouchable.
|
||||
#
|
||||
# This is additive sugar over the proven primitives (git worktree + cmd_create).
|
||||
# It never binds a forbidden port and never touches ~/.neuron/engram (the live store)
|
||||
# except the same READ-only snapshot cmd_create already performs.
|
||||
#
|
||||
# nsbx dev <name> [--repo R] [--base REF] [--worktree DIR] [--port N]
|
||||
# [--prefix P] [--build] [--no-engram]
|
||||
cmd_dev(){
|
||||
local name="" repo="$EL_REPO" base="" wt="" port="" prefix="dev/" build=0 no_engram=0
|
||||
[ $# -gt 0 ] && [ "${1#-}" = "$1" ] && { name="$1"; shift; } || die "usage: nsbx dev <name> [flags]"
|
||||
while [ $# -gt 0 ]; do case "$1" in
|
||||
--repo) repo="$2"; shift 2;;
|
||||
--base) base="$2"; shift 2;;
|
||||
--worktree|--wt) wt="$2"; shift 2;;
|
||||
--port) port="$2"; shift 2;;
|
||||
--prefix) prefix="$2"; shift 2;;
|
||||
--build) build=1; shift;;
|
||||
--no-engram) no_engram=1; shift;;
|
||||
*) die "unknown flag: $1";;
|
||||
esac; done
|
||||
need git
|
||||
git -C "$repo" rev-parse --git-dir >/dev/null 2>&1 || die "not a git repo: $repo"
|
||||
|
||||
local branch="${prefix}${name}"
|
||||
local sbx="dev-${name}"
|
||||
# default worktree path: a PERSISTENT, git-managed dir — NEVER /tmp (which is
|
||||
# ablated on compaction). Default root = <repo-grandparent>/el-worktrees, i.e.
|
||||
# ~/Development/neuron-technologies/el-worktrees/<name>. Override with NSBX_DEV_WT_ROOT.
|
||||
local wt_root="${NSBX_DEV_WT_ROOT:-$(cd "$(dirname "$(dirname "$repo")")" && pwd -P)/el-worktrees}"
|
||||
[ -n "$wt" ] || wt="${wt_root}/${name}"
|
||||
case "$wt" in /tmp/*|/private/tmp/*|/var/tmp/*)
|
||||
die "refusing worktree under a temp dir ($wt) — temp dirs are ablated on compaction; set NSBX_DEV_WT_ROOT to a persistent path";;
|
||||
esac
|
||||
# default base: whatever the repo's working checkout is on now
|
||||
[ -n "$base" ] || base="$(git -C "$repo" rev-parse --abbrev-ref HEAD 2>/dev/null)"
|
||||
|
||||
# pre-flight (fail before creating anything)
|
||||
[ "$no_engram" -eq 1 ] || ! mexists "$sbx" || die "engram sandbox '$sbx' already exists (nsbx dev-down $name first)"
|
||||
[ -e "$wt" ] && die "worktree path already exists: $wt"
|
||||
if [ -n "$port" ]; then
|
||||
{ [ "$port" = "$LIVE_BIND_PORT" ] || [ "$port" = "$SOUL_PORT" ]; } && die "refusing forbidden port $port (live)"
|
||||
fi
|
||||
|
||||
log "dev env '$name' (branch=$branch worktree=$wt base=$base)"
|
||||
|
||||
# ---- 1+2) branch + worktree in one shot ----
|
||||
local gerr
|
||||
if git -C "$repo" show-ref --verify --quiet "refs/heads/$branch"; then
|
||||
info "branch $branch exists — checking it out into a new worktree"
|
||||
gerr="$(git -C "$repo" worktree add "$wt" "$branch" 2>&1)" \
|
||||
|| die "git worktree add failed for existing branch $branch:"$'\n'" $gerr"
|
||||
else
|
||||
gerr="$(git -C "$repo" worktree add -b "$branch" "$wt" "$base" 2>&1)" \
|
||||
|| die "git worktree add -b $branch (base $base) failed:"$'\n'" $gerr"$'\n'" (a bare 'dev' branch blocks 'dev/*' names — try --prefix, e.g. nsbx dev $name --prefix wt/)"
|
||||
fi
|
||||
ok "worktree ready: $wt (branch $branch)"
|
||||
|
||||
# ---- 3) isolated engram ----
|
||||
local eport="(none)"
|
||||
if [ "$no_engram" -eq 1 ]; then
|
||||
warn "--no-engram: skipped standing up an engram"
|
||||
else
|
||||
if [ "$build" -eq 1 ]; then
|
||||
log "isolated engram: building the worktree's own runtime"
|
||||
cmd_create "$sbx" ${port:+--port "$port"} --source "$wt" || die "engram create (--build) failed"
|
||||
else
|
||||
log "isolated engram: stock prod binary on a clone of the live store"
|
||||
cmd_create "$sbx" ${port:+--port "$port"} || die "engram create failed"
|
||||
fi
|
||||
eport="$(mget "$sbx" "['port']")"
|
||||
# record the dev linkage next to the sandbox so dev-down can clean up
|
||||
python3 - "$(sdir "$sbx")/dev.json" "$name" "$branch" "$wt" "$repo" "$eport" <<'PY'
|
||||
import json,sys
|
||||
p,name,branch,wt,repo,port=sys.argv[1:7]
|
||||
json.dump({"name":name,"branch":branch,"worktree":wt,"repo":repo,"port":int(port)},
|
||||
open(p,'w'),indent=2)
|
||||
PY
|
||||
# ---- pin the WHOLE worktree to the CLONE ----
|
||||
# Every var any El tooling in this worktree might read for an engram target now
|
||||
# points at the isolated clone. Sourcing .nsbx-env makes hitting live :$LIVE_BIND_PORT
|
||||
# or ~/.neuron/engram by accident structurally impossible from this shell.
|
||||
local edata ekey eurl ebin
|
||||
edata="$(sdir "$sbx")/data"; ekey="sbx-$sbx"; eurl="http://127.0.0.1:$eport"; ebin="$(sdir "$sbx")/bin/engram"
|
||||
cat > "$wt/.nsbx-env" <<ENV
|
||||
# nsbx dev env for '$name' — SOURCE this to pin THIS shell to the isolated clone.
|
||||
# The live mind (:$LIVE_BIND_PORT engram / :$SOUL_PORT soul / $LIVE_DATA_DIR) is deliberately
|
||||
# NOT referenced here. Regenerated by 'nsbx dev'. -> source .nsbx-env
|
||||
export NSBX_NAME="$sbx"
|
||||
export ENGRAM_URL="$eurl"
|
||||
export ENGRAM_BIND=":$eport"
|
||||
export ENGRAM_PORT="$eport"
|
||||
export ENGRAM_HOST="127.0.0.1"
|
||||
export ENGRAM_DATA_DIR="$edata"
|
||||
export ENGRAM_API_KEY="$ekey"
|
||||
export NEURON_ENGRAM_URL="$eurl"
|
||||
export NEURON_ENGRAM_KEY="$ekey"
|
||||
# nsbx run compatibility (same names 'nsbx run' exports)
|
||||
export SBX_NAME="$sbx" SBX_PORT="$eport" SBX_URL="$eurl" SBX_KEY="$ekey" SBX_DATA="$edata" SBX_BIN="$ebin"
|
||||
ENV
|
||||
# direnv users get it automatically on cd; everyone else runs 'source .nsbx-env'
|
||||
[ -e "$wt/.envrc" ] || printf 'source_env .nsbx-env 2>/dev/null || source .nsbx-env\n' > "$wt/.envrc"
|
||||
ok "wrote $wt/.nsbx-env (pins this worktree to the clone)"
|
||||
fi
|
||||
|
||||
# ---- summary ----
|
||||
echo >&2
|
||||
printf '%s DEV ENV READY — %s%s\n' "$C_BLD" "$name" "$C_0" >&2
|
||||
printf ' %-10s %s\n' "worktree" "$wt" >&2
|
||||
printf ' %-10s %s\n' "branch" "$branch" >&2
|
||||
if [ "$no_engram" -ne 1 ]; then
|
||||
printf ' %-10s %s\n' "engram" "http://127.0.0.1:$eport (isolated clone; prod :$LIVE_BIND_PORT untouchable)" >&2
|
||||
printf ' %-10s %s\n' "sandbox" "$sbx" >&2
|
||||
echo >&2
|
||||
printf '%s env exported into %s/.nsbx-env (source it -> pinned to the clone):%s\n' "$C_DIM" "$wt" "$C_0" >&2
|
||||
grep '^export' "$wt/.nsbx-env" | sed 's/^/ /' >&2
|
||||
fi
|
||||
echo >&2
|
||||
info "code in: cd $wt && source .nsbx-env # now every engram var points at the clone"
|
||||
[ "$no_engram" -ne 1 ] && info "poke it: nsbx run $sbx api /api/stats (or: make run NAME=$name)"
|
||||
[ "$no_engram" -ne 1 ] && info "edit->test: make build NAME=$name && make run NAME=$name # El change -> clone, seconds"
|
||||
info "tear down: nsbx dev-down $name (destroys engram + removes worktree; branch kept)"
|
||||
}
|
||||
|
||||
# nsbx dev-down <name> [--delete-branch] [--repo R]
|
||||
# Teardown counterpart: destroy the isolated engram, remove the git worktree,
|
||||
# and (optionally) delete the branch. Live prod is never touched.
|
||||
cmd_dev_down(){
|
||||
local name="" repo="$EL_REPO" del_branch=0
|
||||
[ $# -gt 0 ] && [ "${1#-}" = "$1" ] && { name="$1"; shift; } || die "usage: nsbx dev-down <name> [--delete-branch]"
|
||||
while [ $# -gt 0 ]; do case "$1" in
|
||||
--repo) repo="$2"; shift 2;;
|
||||
--delete-branch) del_branch=1; shift;;
|
||||
*) die "unknown flag: $1";;
|
||||
esac; done
|
||||
local sbx="dev-${name}" wt="" branch="dev/${name}"
|
||||
# recover worktree/branch/repo from the dev linkage if present
|
||||
if mexists "$sbx" && [ -f "$(sdir "$sbx")/dev.json" ]; then
|
||||
local dj; dj="$(sdir "$sbx")/dev.json"
|
||||
wt="$(python3 -c "import json;print(json.load(open('$dj'))['worktree'])" 2>/dev/null)"
|
||||
branch="$(python3 -c "import json;print(json.load(open('$dj'))['branch'])" 2>/dev/null)"
|
||||
repo="$(python3 -c "import json;print(json.load(open('$dj'))['repo'])" 2>/dev/null)"
|
||||
fi
|
||||
# 1) engram
|
||||
if mexists "$sbx"; then cmd_destroy "$sbx"; else info "no engram sandbox '$sbx'"; fi
|
||||
# 2) worktree
|
||||
if [ -n "$wt" ] && [ -d "$wt" ]; then
|
||||
log "removing git worktree $wt"
|
||||
git -C "$repo" worktree remove --force "$wt" 2>/dev/null || rm -rf "$wt"
|
||||
git -C "$repo" worktree prune 2>/dev/null || true
|
||||
ok "worktree removed"
|
||||
else info "no worktree to remove"; fi
|
||||
# 3) branch (opt-in)
|
||||
if [ "$del_branch" -eq 1 ]; then
|
||||
git -C "$repo" branch -D "$branch" 2>/dev/null && ok "deleted branch $branch" || warn "could not delete branch $branch"
|
||||
else info "branch $branch kept (use --delete-branch to remove)"; fi
|
||||
ok "dev-down '$name' complete (live untouched)"
|
||||
}
|
||||
|
||||
usage(){ cat >&2 <<EOF
|
||||
${C_BLD}nsbx${C_0} — Neuron Sandbox: experiments + code changes against the REAL engram
|
||||
runtime on an isolated snapshot of the live mind, with a gated promote-to-prod path.
|
||||
|
||||
nsbx dev <name> [--base REF] [--worktree DIR] ONE command onboarding: new branch (dev/<name>) + git
|
||||
[--port N] [--prefix P] [--build] worktree (persistent, never /tmp) + isolated engram on a
|
||||
[--no-engram] [--repo R] non-default port. clone -> coding on the mind in one shot.
|
||||
nsbx dev-down <name> [--delete-branch] [--repo R] teardown: destroy the engram + remove the worktree
|
||||
(branch kept unless --delete-branch). live untouched.
|
||||
nsbx up [name] [flags…] one command: your private, isolated copy of the mind
|
||||
(creates on first run, starts thereafter; prod untouchable)
|
||||
nsbx create [name] [--port N] [--source DIR | --branch REF [--repo R] | --binary PATH]
|
||||
@@ -647,6 +818,8 @@ EOF
|
||||
main(){
|
||||
local cmd="${1:-}"; shift || true
|
||||
case "$cmd" in
|
||||
dev) cmd_dev "$@";;
|
||||
dev-down) cmd_dev_down "$@";;
|
||||
up) cmd_up "$@";;
|
||||
create) cmd_create "$@";;
|
||||
build) cmd_build "$@";;
|
||||
|
||||
Reference in New Issue
Block a user