Skip to content

Commit 9cd9ebb

Browse files
author
lpb-docs
committed
refactor(lpb-devstack): one repo map, status/sync/sync-pins, no compat layers
- repos: single 6-repo map (WORKSPACE_REPOS + CONFIG_REPO); TAG_REPOS and LPB_EXTENSION_REPOS now derived; repo_path()/stack_repos() helpers - workspace: drop 'ensure' (broken subset of sync: no clone/symlink/ff, config path lacked branch tracking); 'sync --extensions' becomes the 'sync-pins' subcommand; config handling unified via _status_config/ _sync_config - workspace sync: discard dependency-lockfile drift (package-manager rewrites, e.g. npm 12 dropping hasShrinkwrap) before the dirty check so extension clones can't be blocked by npm rewrites - version: expected_branch() covers config; new expected_pin_version() shared by validate + sync-pins; _devstack_root_candidates() unifies the triple repo-root discovery loops - _ensure_branch_tracked: capture fetched commit before follow-up fetches (fixes FETCH_HEAD overwrite on restricted-refspec clones); fewer fetches - delete localpibox._stack_lib compat shim; all callers import from localpibox.stack.* directly - CLIs: single canonical copy in scripts/ (support/ entries were symlinks to real files there; removed); Dockerfile + install.sh point at scripts/ - tests: patch targets move to owning modules; new lockfile-drift and expected_pin_version tests - docs: lpb-devstack.md, config-repo.md, lpb-config.md, manual-tagging-and-config-split.md
1 parent 232ebc2 commit 9cd9ebb

24 files changed

Lines changed: 1450 additions & 1502 deletions

Dockerfile

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -174,9 +174,13 @@ COPY support/validate-subagent-output.ts /opt/pi-support/validate-subagent-outpu
174174
COPY support/config/ /opt/pi-support/config/
175175
COPY support/docs/ /opt/pi-support/docs/
176176
COPY support/schemas/ /opt/pi-support/schemas/
177-
# Shared Python helpers used by the ported support tools (import via the
178-
# script directory, which Python adds to sys.path automatically).
177+
# ── Shared Python helpers + user-facing CLIs ─────────────────────────────
178+
# The localpibox package and the lpb-config/lpb-devstack CLIs are the source of
179+
# truth in scripts/ (single copy — no support/ duplicates). They must live
180+
# under /opt/pi-support/ for their sys.path resolution.
179181
COPY scripts/localpibox/ /opt/pi-support/localpibox/
182+
COPY --chmod=755 scripts/lpb-config /opt/pi-support/lpb-config
183+
COPY --chmod=755 scripts/lpb-devstack /opt/pi-support/lpb-devstack
180184

181185
# ── Devstack deployment scripts ──
182186
COPY --chmod=755 support/install-browser.py /opt/devstack/install-browser.py
@@ -204,8 +208,6 @@ RUN mkdir -p /home/lpb/.local/bin \
204208
# lpb-config / lpb-devstack need to live under /opt/pi-support/ for their
205209
# sys.path resolution (the localpibox package is copied there above).
206210
# Symlinks at ~/.local/bin give users the clean CLI names.
207-
COPY --chmod=755 support/lpb-config /opt/pi-support/lpb-config
208-
COPY --chmod=755 support/lpb-devstack /opt/pi-support/lpb-devstack
209211

210212
# ── Root operations: ownership + gitconfig + shell PATH ─────────────────────
211213
USER root

doc/config-repo.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ Extensions are pinned in the `packages` array of `settings.json` as
7171

7272
The `__LPB_VERSION__` placeholder in the template is replaced with the
7373
stack version at boot. Pins are synced to a new stack version by
74-
`lpb-devstack workspace sync --extensions`.
74+
`lpb-devstack workspace sync-pins`.
7575

7676
## Extension Clones
7777

@@ -142,7 +142,7 @@ lpb-config update
142142
lpb-devstack validate
143143

144144
# Sync extension pins to stack version
145-
lpb-devstack workspace sync --extensions
145+
lpb-devstack workspace sync-pins
146146

147147
# Reset config repo
148148
lpb-config reset

doc/lpb-config.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ Settings.json is **template-driven**, not git-tracked:
4747
1. Config repo ships `settings.json.template` with `__LPB_VERSION__` placeholders
4848
2. First boot: `start.sh` generates `settings.json` (replaces placeholders)
4949
3. No model/provider preconfigured — user runs `/login lemonade`
50-
4. Pin sync: `lpb-devstack workspace sync --extensions` (main pipeline reads
50+
4. Pin sync: `lpb-devstack workspace sync-pins` (main pipeline reads
5151
stable version from devstack `origin/main`)
5252
5. `lpb-devstack validate` checks pins match the current stack version
5353
6. Settings.json persists on the host volume — survives container rebuilds

doc/lpb-devstack.md

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,8 @@ partially-tagged stack is a release bug.
5050
| Command | Description |
5151
|---|---|
5252
| `lpb-devstack workspace status` | Show branches + alignment for all repos |
53-
| `lpb-devstack workspace sync` | Clone missing repos, create symlinks, align branches, pull latest |
54-
| `lpb-devstack workspace sync --extensions` | Sync settings.json pins to stack version |
55-
| `lpb-devstack workspace ensure [--fix]` | Check/fix branch alignment for the pipeline |
53+
| `lpb-devstack workspace sync` | Clone missing repos, create symlinks, align branches, pull latest (the single write path) |
54+
| `lpb-devstack workspace sync-pins` | Sync settings.json pins to the pipeline's stack version |
5655

5756
### Stack Validation
5857

@@ -116,7 +115,7 @@ lpb-devstack release status # readiness check
116115
lpb-devstack release promote --dry-run # inspect plan
117116
lpb-devstack release promote # dev → stable + push
118117
lpb-devstack tag-repos --branch main # tag the 5 repos on stable branches
119-
lpb-devstack --tag main workspace sync --extensions # pins → stable tag
118+
lpb-devstack --tag main workspace sync-pins # pins → stable tag
120119
pi update --extensions
121120
```
122121

doc/manual-tagging-and-config-split.md

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -105,9 +105,8 @@ lpb-devstack tag-repos --version v # explicit version
105105

106106
# Workspace management
107107
lpb-devstack workspace status — branches + alignment
108-
lpb-devstack workspace sync — clone/symlink/align/pull
109-
lpb-devstack workspace sync --extensions — sync settings.json pins
110-
lpb-devstack workspace ensure [--fix] — switch to correct branches
108+
lpb-devstack workspace sync — clone/symlink/align/pull (single write path)
109+
lpb-devstack workspace sync-pins — sync settings.json pins
111110

112111
# Stack validation
113112
lpb-devstack validate — full stack alignment check
@@ -129,7 +128,7 @@ lpb-devstack validate-hooks — run full pre-commit checks (tests + val
129128
| Memory config | ✅ | ❌ | Image-usable, needed inside container |
130129
| VERSION bumping | ❌ | ✅ | Devstack-specific, workspace tool |
131130
| Tag repos | ❌ | ✅ | Dev-time operation |
132-
| Workspace sync/ensure | ❌ | ✅ | Developer workspace maintenance |
131+
| Workspace sync/status | ❌ | ✅ | Developer workspace maintenance |
133132
| Stack validation | ❌ | ✅ | Dev-time operation |
134133
| Release promote | ❌ | ✅ | Dev→stable promotion |
135134
| Pre-commit validation | ❌ | ✅ | Dev-time operation |
@@ -138,18 +137,17 @@ lpb-devstack validate-hooks — run full pre-commit checks (tests + val
138137
139138
```
140139
devstack/
141-
├── support/
142-
│ ├── lpb-config ← slimmed down (config repo only, ~250 lines)
143-
│ └── lpb-devstack ← new (devops, ~600 lines)
144-
├── scripts/
145-
│ ├── lpb-config ← symlink → ../support/lpb-config
146-
│ ├── lpb-devstack ← symlink → ../support/lpb-devstack
140+
├── support/ ← runtime image tools (start.sh, browser*, validate.py, …)
141+
├── scripts/ ← single source for the CLIs + shared package
142+
│ ├── lpb-config ← config repo manager
143+
│ ├── lpb-devstack ← DevOps workspace tool
147144
│ ├── localpibox/
148-
│ │ ├── _stack_lib.py ← shared code (git, repo defs, pipeline detection)
145+
│ │ ├── stack/ ← gitutil / repos / version / workspace / validate / release
149146
│ │ └── ...
150-
│ └── install.sh ← install both scripts
147+
│ ├── install.sh ← installs both CLIs + localpibox (from scripts/)
148+
│ └── test_* ← test suite
151149
└── .githooks/
152-
└── pre-commit ← keep full check (tests included)
150+
└── pre-commit ← keep full check (tests included)
153151
```
154152
155153
---
@@ -219,7 +217,12 @@ intent):
219217
220218
8. Follow-up reorg (same day): `_stack_lib.py` was split into the
221219
`localpibox/stack/` package (`gitutil` / `repos` / `version` /
222-
`workspace` / `validate` / `release`); `_stack_lib.py` remains a thin
223-
compat shim so existing imports are unchanged. `test_env_bridge.sh`
220+
`workspace` / `validate` / `release`); `_stack_lib.py` remained a thin
221+
compat shim so existing imports were unchanged. `test_env_bridge.sh`
224222
(previously orphaned) is wired into CI and now isolates its subshells
225223
from the ambient environment.
224+
225+
(2026-08-21 cleanup: the compat shim was deleted — all callers import
226+
from `localpibox.stack.*` directly; the CLI canonical copies moved from
227+
`support/` to `scripts/` with the symlinks removed, and the Dockerfile /
228+
`install.sh` point at `scripts/`.)

scripts/install.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,11 @@ curl -fsSL "https://raw.githubusercontent.com/${OWNER_REPO}/main/VERSION" -o "${
4545
# localpibox package they import (resolved via ~/.lpb-stack/devstack/).
4646
echo "Installing lpb-config + lpb-devstack..."
4747
for tool in lpb-config lpb-devstack; do
48-
curl -fsSL "https://raw.githubusercontent.com/${OWNER_REPO}/main/support/${tool}" -o "${INSTALL_DIR}/${tool}"
48+
curl -fsSL "https://raw.githubusercontent.com/${OWNER_REPO}/main/scripts/${tool}" -o "${INSTALL_DIR}/${tool}"
4949
chmod +x "${INSTALL_DIR}/${tool}"
5050
done
5151
mkdir -p "${CONFIG_DIR}/localpibox/stack"
52-
for f in __init__.py cli.py env.py log.py run.py _stack_lib.py; do
52+
for f in __init__.py cli.py env.py log.py run.py; do
5353
curl -fsSL "https://raw.githubusercontent.com/${OWNER_REPO}/main/scripts/localpibox/${f}" -o "${CONFIG_DIR}/localpibox/${f}"
5454
done
5555
for f in __init__.py gitutil.py repos.py version.py workspace.py validate.py release.py; do

scripts/localpibox/__init__.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,8 @@
77
log — colored console output (info/warn/error/done/debug)
88
run — subprocess helpers, tool discovery, container detection
99
cli — argument-parser helpers, prompts, fatal-error exit
10-
stack/ — LocalPibox stack operations (git helpers, repo map, pipeline
11-
detection, VERSION bump math, workspace/validate/release)
12-
(legacy import path: localpibox._stack_lib shim)
10+
stack/ — LocalPibox stack operations (git helpers, single 6-repo map,
11+
pipeline detection, VERSION bump math, workspace/validate/release)
1312
"""
1413

1514
from .env import (

scripts/localpibox/_stack_lib.py

Lines changed: 0 additions & 65 deletions
This file was deleted.
Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,26 @@
11
"""localpibox.stack — LocalPibox stack operations library.
22
3-
Module layout (split from the former single _stack_lib module):
3+
Module layout:
44
55
gitutil — git helpers (plain + GitHub-auth aware)
6-
repos — path constants, 6-repo stack map, tagging repo list
7-
version — pipeline detection, VERSION discovery + bump math, stack env
8-
workspace — workspace sync/clone/ensure + settings.json pin helpers
6+
repos — path constants, single 6-repo stack map (workspace repos +
7+
config repo) and everything derived from it
8+
version — pipeline detection, VERSION discovery + bump math, stack env,
9+
expected branches/pins
10+
workspace — workspace sync/clone + settings.json pin helpers
911
validate — full-stack alignment validation
1012
release — stable-release promotion engine (dev → stable)
1113
12-
Import the public API from this package, or from the legacy
13-
``localpibox._stack_lib`` shim (kept for backwards compatibility).
14+
Import the public API from this package or from the owning module.
1415
"""
1516

1617
from .gitutil import git, git_auth, git_remote
1718
from .repos import (
1819
AGENT_GIT,
20+
CONFIG_REPO,
1921
DEFAULT_AGENT_DIR,
2022
DEFAULT_REMOTE,
2123
DEFAULT_REF,
22-
EXTENSION_REPOS,
2324
LPB_EXTENSION_REPOS,
2425
MIGRATE_KEEP,
2526
MEMORY_CONFIG_PATH,
@@ -29,30 +30,32 @@
2930
WORKSPACE_REPOS,
3031
WORKSPACE_ROOT,
3132
migrate_legacy_layout,
33+
repo_path,
34+
stack_repos,
3235
)
3336
from .version import (
3437
bump_version,
3538
detect_pipeline,
3639
expected_branch,
40+
expected_pin_version,
3741
get_stack_env,
3842
get_version,
3943
parse_version,
4044
)
4145
from .workspace import (
42-
cmd_workspace_ensure,
4346
cmd_workspace_status,
4447
cmd_workspace_sync,
45-
cmd_workspace_sync_extensions,
48+
cmd_workspace_sync_pins,
4649
)
4750
from .validate import cmd_validate
4851
from .release import cmd_release_promote, cmd_release_status
4952

5053
__all__ = [
5154
"AGENT_GIT",
55+
"CONFIG_REPO",
5256
"DEFAULT_AGENT_DIR",
5357
"DEFAULT_REMOTE",
5458
"DEFAULT_REF",
55-
"EXTENSION_REPOS",
5659
"LPB_EXTENSION_REPOS",
5760
"MIGRATE_KEEP",
5861
"MEMORY_CONFIG_PATH",
@@ -65,17 +68,19 @@
6568
"cmd_release_promote",
6669
"cmd_release_status",
6770
"cmd_validate",
68-
"cmd_workspace_ensure",
6971
"cmd_workspace_status",
7072
"cmd_workspace_sync",
71-
"cmd_workspace_sync_extensions",
73+
"cmd_workspace_sync_pins",
7274
"detect_pipeline",
7375
"expected_branch",
76+
"expected_pin_version",
7477
"get_stack_env",
7578
"get_version",
7679
"git",
7780
"git_auth",
7881
"git_remote",
7982
"migrate_legacy_layout",
8083
"parse_version",
84+
"repo_path",
85+
"stack_repos",
8186
]

scripts/localpibox/stack/release.py

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,19 +15,16 @@
1515
from ..cli import confirm
1616
from ..log import Console
1717
from .gitutil import git, git_auth
18-
from .repos import DEFAULT_AGENT_DIR, WORKSPACE_REPOS, WORKSPACE_ROOT
18+
from .repos import repo_path, stack_repos
1919
from .version import get_version
2020

2121

2222
def _release_repos() -> list[tuple[str, Path, str, str, str]]:
2323
"""All 6 stack repos: (label, path, dev_branch, main_branch, github_repo)."""
24-
repos: list[tuple[str, Path, str, str, str]] = []
25-
for name, _is_sym, _is_ext, dev_branch, main_branch in WORKSPACE_REPOS:
26-
repos.append((name, WORKSPACE_ROOT / name, dev_branch, main_branch,
27-
f"lpb-stack/{name}"))
28-
repos.append(("config", Path(DEFAULT_AGENT_DIR), "dev", "main",
29-
"lpb-stack/config"))
30-
return repos
24+
return [
25+
(name, repo_path(name), dev_branch, main_branch, f"lpb-stack/{name}")
26+
for name, dev_branch, main_branch in stack_repos()
27+
]
3128

3229

3330
def _repo_release_state(path: Path, dev_branch: str, main_branch: str,
@@ -355,7 +352,7 @@ def cmd_release_promote(*, assume_yes: bool, dry_run: bool, rebase: bool,
355352
cons.info(f"CI (main pipeline) now builds :{stable_version}-* / :main-* / :latest-*")
356353
cons.info("and tags the 5 repos at the stable branches.")
357354
cons.info("After CI passes:")
358-
cons.info(" 1. lpb-devstack --tag main workspace sync --extensions")
355+
cons.info(" 1. lpb-devstack --tag main workspace sync-pins")
359356
cons.info(" 2. pi update --extensions")
360357
cons.info(f" (If CI's tag-repos didn't run: lpb-devstack tag-repos --branch main --version {stable_version})")
361358
return 0

0 commit comments

Comments
 (0)