cf-node-bootstrap/cf-apps
pyr0ball bc9d1e564f fix: stop double-executing git clone / setup hooks via run()
run() re-splits its argument as a bare string with no eval, so any
call like run "git clone \"$url\" \"$dir\"" corrupts the quoted
arguments (embedded escaped quotes survive as literal characters,
e.g. git sees the protocol as '"https). Each of the 4 affected call
sites papered over this by following run() with a second, correctly
quoted manual execution of the same command - meaning every real run
double-executed (git clone twice, pip install -e twice, conda env
create twice), with the first, corrupted attempt's failure masked by
the working second attempt.

Fixed by dropping run() at these sites entirely and gating on
$dry_run directly with a single, properly quoted real execution path
(matches the pattern already used in the new model-cache-redirect
extra):
- lib/cf-apps.functions: install-cf-app's clone, provision-orchard-node's clone
- cf-apps/circuitforge-core.manifest: pip install -e setup hook
- cf-apps/kiwi.manifest: conda env create setup hook

Verified on sif via a scratch-dir harness (install-cf-app
circuitforge-core): first run now clones cleanly with no mangled-URL
error, second run correctly skips the clone and re-runs the
idempotent pip install; state.conf stays single-entry across both.
2026-07-18 22:12:05 -07:00
..
circuitforge-core.manifest fix: stop double-executing git clone / setup hooks via run() 2026-07-18 22:12:05 -07:00
kiwi.manifest fix: stop double-executing git clone / setup hooks via run() 2026-07-18 22:12:05 -07:00
linnet.manifest feat: interactive CF Apps install menu with oem/collaborator/orchard profiles 2026-07-17 20:42:21 -07:00
pagepiper.manifest feat: interactive CF Apps install menu with oem/collaborator/orchard profiles 2026-07-17 20:42:21 -07:00
peregrine.manifest feat: interactive CF Apps install menu with oem/collaborator/orchard profiles 2026-07-17 20:42:21 -07:00
README.md feat: interactive CF Apps install menu with oem/collaborator/orchard profiles 2026-07-17 20:42:21 -07:00
snipe.manifest feat: interactive CF Apps install menu with oem/collaborator/orchard profiles 2026-07-17 20:42:21 -07:00
turnstone.manifest feat: interactive CF Apps install menu with oem/collaborator/orchard profiles 2026-07-17 20:42:21 -07:00

CF Apps manifests

One .manifest file per CircuitForge product, sourced by lib/cf-apps.functions. Each is a plain bash file defining these variables (see any existing manifest for a concrete example):

app_name=""                    # matches the filename minus .manifest
app_desc=""                    # one line, shown in the selection menu
app_repo_url_github=""         # public CircuitForgeLLC mirror, used for the oem profile
app_repo_url_forgejo=""        # private Circuit-Forge Forgejo, used for the collaborator profile
app_available_profiles=()      # which of: oem collaborator
app_install_types=()           # which of: bare-metal docker podman, in menu display order
app_conda_env=""               # empty string if not applicable
app_env_template=""            # path relative to repo root, empty if none
app_needs_core=false           # true if circuitforge-core must be installed first

Optionally define hook functions for whichever install types the app actually supports (skip the ones it doesn't):

app_setup_bare_metal() { local dir="$1"; ... }
app_setup_docker()     { local dir="$1"; ... }
app_setup_podman()     { local dir="$1"; ... }

$1 is the app's clone directory. Prefer shelling out to the app's own install.sh/Makefile/docker compose rather than reimplementing its setup steps here — most CF products already have one.

If a hook is left undefined for an install type the app declares in app_install_types, the dispatcher clones the repo and prints a warning telling the user to finish setup manually, rather than silently doing nothing.

See circuitforge-plans/cf-node-bootstrap/superpowers/plans/2026-07-17-cf-apps-install-menu.md for the full design rationale, including the OEM/collaborator/orchard provisioning-profile split.