Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,5 @@ wip/

# rendered by bug-logs/pending-github-issues/render-paste-ready.sh — regenerate, never commit
bug-logs/pending-github-issues/paste-ready/
# Machine-local tool locations read by project-bin/_common.sh — never commit paths
.claude/toolkit.env
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ Credit the person or project that surfaced the change — the credit line is the
- learn(bug-logs): BUG-115 addendum + its upstream draft (`bug115-file-manager-widget-not-authorable.md`) — a second project independently found that MDL cannot author a **File Manager** widget (six spellings all `mismatched input … expecting '}'`), and added the costly half: `DESCRIBE PAGE` of a page that HAS one emits it as a `-- NOT re-executable` comment, and that script **passes `check --references` clean** — so the documented describe → edit → `CREATE OR REPLACE PAGE` loop deletes the widget with no error at any gate. Verified against `AgentCommons.AgentImportExportFile_NewEdit`, which ships one. The comment is good behaviour and the draft says so; the ask is a grammar production, or failing that a `check` warning on the marker, since a pipeline reads the gate and not the comment — a sales-coaching build (logged on its branch as BUG-116; folded into master's BUG-115 at merge, the same defect)
- learn(bug-logs): BUG-127 (`ALTER PAGE … REPLACE` of a **pluggable** widget silently drops properties you did write — a Combobox came back with no `Attribute`, quoted and unquoted alike, and still rendered a normal-looking dropdown bound to nothing; `check --references` and mxbuild both clean, only `DESCRIBE PAGE` shows it), BUG-128 (`CREATE MODULE ROLE` has no `OR MODIFY` / `IF NOT EXISTS`, so a re-run aborts on it and every statement *after* it silently does not run — keep non-idempotent statements in their own once-applied script), BUG-129 (`exec` logged `Created microflow:` ×7 plus a page, passed the mxbuild gate and exited 0, and the model afterwards held the role and all six grants from the same script and **none** of the documents; root cause not established, logged as observed rather than diagnosed). The practice BUG-129 forces is worth having regardless of the bug: **read the model back with `SHOW` after every exec — exit 0 plus a log of `Created …` lines is a claim about what the tool tried, not a fact about the model** — a sales-coaching build (renumbered from BUG-113/114/115 at merge; those numbers, and 107–109 before them, were taken on master while the branch was open)
- new(guide/README): "Where you run this" visual — three lanes (cloud, devcontainer, local) on one shared project, the Windows Docker-on-WSL2 vs WSL-as-shell distinction, the build-headless/polish-in-Studio-Pro rhythm with the one-writer rule, and a side-by-side "why a Dev Container instead of local" table; SVG in `toolkit-guide.html` §5 (later sections renumbered), mermaid + prose in `README.md`; `doctor.sh`'s devcontainer note now says SP modes are unavailable *here*, not unavailable — same onboarding thread as the line below — Clinton Chee, via Maurits Visser
- fix(doctor/_common): four Windows onboarding defects from one field run (Git Bash, Studio Pro 10.24 + 11.8 + 11.11 side by side, project shared with a Dev Container). (1) `find_sp_app` glued two `ls` listings without a newline and listed the same Program Files root twice, producing ".../Mendix/gradle-8.5//c/Program Files/Mendix/10.24..." as the "highest" install — now newline-joined, deduped, and only version-shaped dirs count. (2) `check-scripts.sh` reported FAIL on a project without `bin/` — now a WARN pointing at init-project. (3) A project's `./mxcli` can be the Dev Container's Linux ELF binary, which Git Bash can never run and `chmod +x` cannot fix — new `find_project_mxcli` prefers `mxcli.exe` on Windows and names the ELF case; doctor `--install` fetches mxcli.exe beside it instead of refusing; exec.sh, lint-gate, review-module, conformance-check, fixture-manifest, page-scope use the resolver. (4) The macOS-only save-sp/restart-sp section is a note, not a WARN, off macOS. Plus `toolkit.env` — `<project>/.claude/toolkit.env` or `~/.mxcli-toolkit.env`, KEY=VALUE, Windows paths pasted as-is — loaded by `_common.sh` for MENDIX_APP / JAVA_HOME / MXBUILD_PATH / MXCLI_VERSION / PYTHON; doctor reports which loaded, self-gitignores the project file, flags a JRE-without-javac, and its gate/verdict wording now guides instead of alarms. Fixture-proven here (glue, precedence, .exe-over-ELF); Windows field run still owed — the PR stays draft until that run is cited here (and a golden `ls -d` capture of the glued Studio Pro path sits beside a fixture); merge review 2026-09-08 also routed the pasted `.exe` probe in page-scope.sh and fixture-manifest.sh through `find_project_mxcli`, dropped a dead `MXCLI_LINUX_SEEN`, corrected the "gitignored by init-project" comment (doctor.sh appends it) and the WARN verdict wording — Clinton Chee, via Maurits Visser
- new(guide/README): "Where you run this" visual — three lanes (cloud, devcontainer, local) on one shared project, the Windows Docker-on-WSL2 vs WSL-as-shell distinction, the build-headless/polish-in-Studio-Pro rhythm with the one-writer rule, and a side-by-side "why a Dev Container instead of local" table; SVG in `toolkit-guide.html` §5 (later sections renumbered), the same SVG exported to `docs/where-you-run-this.svg` and embedded in `README.md` (replaces the mermaid draft) + prose; `doctor.sh`'s devcontainer note now says SP modes are unavailable *here*, not unavailable — same onboarding thread as the line below — Clinton Chee, via Maurits Visser
- fix(docs/README): the "Git Bash, not WSL" warning now says explicitly that Docker Desktop's WSL2 backend (the "install Docker on WSL" prompt from `mxcli new`'s Dev Container) is fine and is the `devcontainer` lane, and that the lanes mix freely on one project with one writer on the `.mpr` at a time — a colleague onboarding via `mxcli new` read the warning as "say No to Docker on WSL" — Clinton Chee, via Maurits Visser

Expand Down
8 changes: 7 additions & 1 deletion bin/check-scripts.sh
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,13 @@ if [ -n "$PROJECT_DIR" ]; then
# The installed copies. bin/ exists on every wired project; tests/e2e/ only after
# install-tests.sh — its absence is install-manifest's finding, not a parse failure,
# so probe it only when present.
check_sh "project bin/*.sh" "$PROJECT_DIR"/bin/*.sh
if [ -d "$PROJECT_DIR/bin" ]; then
check_sh "project bin/*.sh" "$PROJECT_DIR"/bin/*.sh
else
# Not wired yet is not a parse failure — bin/ arrives with init-project.sh. Reported as
# FAIL once (Windows onboarding, 2026-09-08) and read as "something is broken".
printf ' WARN project has no bin/ yet — run bin/init-project.sh %s first; nothing to parse-check until then\n' "$PROJECT_DIR"
fi
if [ -d "$PROJECT_DIR/tests/e2e" ]; then
check_js "project tests/e2e/*.js" "$PROJECT_DIR"/tests/e2e/*.js
fi
Expand Down
100 changes: 74 additions & 26 deletions bin/doctor.sh
Original file line number Diff line number Diff line change
Expand Up @@ -307,10 +307,12 @@ case "$PLATFORM" in
fi
;;
gitbash|wsl|linux|unknown)
warn "The Studio Pro scripts (save-sp.sh, restart-sp.sh, and the SP handling in exec.sh)"
note "are macOS-only: they are built on osascript, lsof and 'open -a', and Studio Pro is"
note "discovered by looking in /Applications. There is no Windows port yet."
note "Everything else in the toolkit works here. Drive Studio Pro by hand on this platform."
# Informational only. Nobody needs these scripts to use the toolkit — Studio Pro is
# opened and saved by hand at the points where they would run — so on the platforms
# they do not exist for, this is not a warning. (It was one; a Windows onboarding
# counted it among "6 warnings" and asked what to do about it. Nothing.)
note "save-sp.sh / restart-sp.sh (macOS conveniences) are not on this platform — you open"
note "and save Studio Pro yourself at those points. Nothing else depends on them."
;;
esac

Expand Down Expand Up @@ -342,6 +344,18 @@ MXBUILD="$(find_mxbuild 2>/dev/null || true)"
JAVA_HOME_FOUND="$(find_java 2>/dev/null || true)"
JAVA_EXE="$(find_java_exe 2>/dev/null || true)"

# toolkit.env — the human-editable answer to "doctor guessed the wrong Studio Pro / Java".
# _common.sh already loaded it (project file, then ~/.mxcli-toolkit.env; a variable set in
# the shell wins over both). Say what was read, so a stale value is findable.
if [ -n "${MXTK_ENV_LOADED:-}" ]; then
ok "toolkit.env loaded: $MXTK_ENV_LOADED"
else
note "No toolkit.env — discovery guesses below. To pin tool locations for this machine, create"
note " ${PROJECT_DIR:-<project>}/.claude/toolkit.env (this project) or ~/.mxcli-toolkit.env (every project)"
note " with lines like: MENDIX_APP=C:\\Program Files\\Mendix\\11.11.0 JAVA_HOME=C:\\Software\\Java\\jdk-21"
note " (Windows paths can be pasted as-is; MXBUILD_PATH, MXCLI_VERSION and PYTHON work too.)"
fi

# --install: when no runnable mxbuild was discovered, download the standalone toolchain
# through the project's own mxcli — `./mxcli setup mxbuild -p <app>.mpr`, the exact download
# the headless container build runs, cached at ~/.mxcli/mxbuild/<version>/ and shared across
Expand All @@ -357,15 +371,15 @@ install_toolchain() {
bad "--install: no .mpr in $PROJECT_DIR — setup mxbuild needs the model to pick a version."
return
fi
note "downloading the mxbuild toolchain (./mxcli setup mxbuild — same as the container build)..."
if (cd "$PROJECT_DIR" && ./mxcli setup mxbuild -p "$(basename "$INSTALL_MPR")"); then
note "downloading the mxbuild toolchain (mxcli setup mxbuild — same as the container build)..."
if (cd "$PROJECT_DIR" && "$PMXCLI" setup mxbuild -p "$(basename "$INSTALL_MPR")"); then
SP_APP="$(find_sp_app 2>/dev/null || true)"
MXBUILD="$(find_mxbuild 2>/dev/null || true)"
JAVA_HOME_FOUND="$(find_java 2>/dev/null || true)"
JAVA_EXE="$(find_java_exe 2>/dev/null || true)"
ok "toolchain downloaded to ~/.mxcli/mxbuild/ (shared cache, reused by every project)"
else
bad "'./mxcli setup mxbuild' failed — see its output above."
bad "'mxcli setup mxbuild' failed — see its output above."
note "A blocked network/proxy is the usual cause; the download comes from the Mendix CDN."
fi
}
Expand All @@ -376,7 +390,8 @@ if [ "$INSTALL" -eq 1 ]; then
NEED_TOOLCHAIN=1
if [ -n "$MXBUILD" ] && [ -x "$MXBUILD" ] && probe_runs "$MXBUILD"; then NEED_TOOLCHAIN=0; fi
NEED_MXCLI=0
if [ -n "$PROJECT_DIR" ] && [ ! -x "$PROJECT_DIR/mxcli" ] && [ ! -f "$PROJECT_DIR/mxcli" ]; then
PMXCLI="$(find_project_mxcli 2>/dev/null || true)"
if [ -n "$PROJECT_DIR" ] && [ -z "$PMXCLI" ]; then
NEED_MXCLI=1
fi

Expand All @@ -386,7 +401,14 @@ if [ "$INSTALL" -eq 1 ]; then
bad "--install needs a project directory: bin/doctor.sh --install <project-dir>"
note "The download runs through that project's own ./mxcli, which reads the model's"
note "Mendix version and fetches the matching toolchain."
elif [ -f "$PROJECT_DIR/mxcli" ] && [ ! -x "$PROJECT_DIR/mxcli" ]; then
elif [ "$NEED_MXCLI" -eq 1 ] && [ "$PLATFORM" = gitbash ] && mxtk_is_elf "$PROJECT_DIR/mxcli"; then
# Not a permissions problem, and chmod cannot fix it (Git Bash derives the executable bit
# from the extension/header, so `chmod +x` looks like it "reverts"). The file is the Linux
# build the Dev Container uses on this same folder. Windows needs mxcli.exe beside it.
note "--install: $PROJECT_DIR/mxcli is the Linux build (the Dev Container's) — fine, leave it."
note "Git Bash needs mxcli.exe next to it; fetching that now, the two coexist."
NEED_MXCLI=1; PMXCLI=""
elif [ -f "$PROJECT_DIR/mxcli" ] && [ ! -x "$PROJECT_DIR/mxcli" ] && [ "$PLATFORM" != gitbash ]; then
bad "--install: mxcli in $PROJECT_DIR is present but not executable — chmod +x mxcli, re-run."
else
# The release assets follow one naming scheme (verified against the published releases,
Expand Down Expand Up @@ -445,9 +467,9 @@ if [ "$INSTALL" -eq 1 ]; then
note " $_STEP. mxbuild toolchain (~800 MB, one-time) -> ~/.mxcli/mxbuild/<version>/"
note " verifies every model write (the exec.sh gate); from cdn.mendix.com, exact"
note " version read from the project's .mpr — the same download the container build uses."
if [ "$NEED_MXCLI" -eq 0 ] && [ -x "$PROJECT_DIR/mxcli" ]; then
if [ "$NEED_MXCLI" -eq 0 ] && [ -n "$PMXCLI" ]; then
_PLAN_MPR="$(ls "$PROJECT_DIR"/*.mpr 2>/dev/null | head -1)"
[ -n "$_PLAN_MPR" ] && (cd "$PROJECT_DIR" && ./mxcli setup mxbuild -p "$(basename "$_PLAN_MPR")" --dry-run 2>/dev/null) \
[ -n "$_PLAN_MPR" ] && (cd "$PROJECT_DIR" && "$PMXCLI" setup mxbuild -p "$(basename "$_PLAN_MPR")" --dry-run 2>/dev/null) \
| grep -E 'Version:|URL:' | while IFS= read -r l; do note " $l"; done
fi
fi
Expand Down Expand Up @@ -478,6 +500,7 @@ if [ "$INSTALL" -eq 1 ]; then
if $MXCLI_FETCH "$PROJECT_DIR/$MXCLI_DEST" "$MXCLI_URL" && chmod +x "$PROJECT_DIR/$MXCLI_DEST" \
&& probe_runs "$PROJECT_DIR/$MXCLI_DEST"; then
ok "mxcli fetched into the project root: $(probe_line)"
PMXCLI="$PROJECT_DIR/$MXCLI_DEST"
else
rm -f "$PROJECT_DIR/$MXCLI_DEST" 2>/dev/null
MXCLI_READY=0
Expand Down Expand Up @@ -542,8 +565,9 @@ else
else
bad "mxbuild not found/executable: ${MXBUILD:-<none>}"
fi
note "Fix without Studio Pro: bin/doctor.sh --install <project-dir> (downloads it locally,"
note "like the container build). Or set MXBUILD_PATH=/path/to/mxbuild."
note "Have Studio Pro? Point at it: MENDIX_APP=<its version folder> in toolkit.env (see above)."
note "No Studio Pro: bin/doctor.sh --install <project-dir> downloads a standalone mxbuild,"
note "like the container build. MXBUILD_PATH=<path to mxbuild> also works."
fi

# Java: mxbuild is invoked with an explicit --java-exe-path; if none resolves, the gate skips.
Expand All @@ -553,6 +577,15 @@ if [ -n "$JAVA_EXE" ] && [ -x "$JAVA_EXE" ]; then
JV="$("$JAVA_EXE" -version 2>&1 | grep -i 'version' | head -1)" || JV=""
if [ -n "$JV" ]; then
ok "java runs: $JV ($JAVA_EXE)"
# mxbuild compiles the model's Java actions, which takes javac — a JRE has none. Studio
# Pro's bundled runtime is a JRE that mxbuild is paired with, so only flag a system Java.
case "$JAVA_HOME_FOUND" in
"${SP_APP:-<none>}"/*) ;;
*) if [ ! -x "$(dirname "$JAVA_EXE")/javac" ] && [ ! -x "$(dirname "$JAVA_EXE")/javac.exe" ]; then
note "this Java is a JRE (no javac). Java actions in the model need a JDK to compile:"
note "set JAVA_HOME=<a JDK 21 folder> in toolkit.env if a build complains about javac."
fi ;;
esac
else
GATE_OK=0
bad "java exists but produced no version output: $JAVA_EXE"
Expand Down Expand Up @@ -580,14 +613,15 @@ else
if [ "$PLATFORM" = linux ] && [ -z "$SP_APP" ] && [ -z "${MXBUILD_PATH:-}" ]; then
warn "exec.sh mxbuild gate WILL BE SKIPPED on this machine."
else
bad "exec.sh mxbuild gate WILL BE SKIPPED on this machine. Fix the FAIL lines above"
note "before writing to any model from this machine."
bad "the mxbuild gate would be skipped on this machine — sort out the mxbuild/java lines"
note "above before the first model write, so every write gets verified."
fi
note "Every MDL exec here will report gate=skipped and go through UNVERIFIED: consistency"
note "errors (CE) are never captured, and BSON corruption — which mxbuild is the only"
note "reliable detector for — reaches Studio Pro undetected."
note "Fastest fix on ANY platform: bin/doctor.sh --install <project-dir> — downloads the"
note "toolchain locally through the project's ./mxcli, exactly like the container build."
note "Why it matters: without mxbuild, MDL execs report gate=skipped and consistency errors"
note "go uncaught until Studio Pro opens the model. Usually one of these fixes it:"
note " - Studio Pro is installed: put its folder in toolkit.env, e.g."
note " MENDIX_APP=C:\\Program Files\\Mendix\\11.11.0 (pick the version your .mpr uses)"
note " - No Studio Pro here: bin/doctor.sh --install <project-dir> downloads a standalone"
note " mxbuild (the same one the container build uses)."
fi

if [ "$QUICK" != 1 ]; then
Expand Down Expand Up @@ -706,18 +740,26 @@ if [ -n "$PROJECT_DIR" ]; then
warn "no .mpr found in the project root"
note "If the model lives elsewhere, point doctor at the folder that contains it;"
note "a brand-new project gets its .mpr from 'mxcli init' or a Studio Pro export."; }
if [ -x "$PROJECT_DIR/mxcli" ]; then
PMXCLI_PROBE="$(find_project_mxcli 2>/dev/null || true)"
if [ -n "$PMXCLI_PROBE" ]; then
# Present is not enough — a wrong-platform binary is present, executable, and exits 126.
MXCLI_EXIT=0
probe_runs "$PROJECT_DIR/mxcli" || MXCLI_EXIT=$?
probe_runs "$PMXCLI_PROBE" || MXCLI_EXIT=$?
if [ "$MXCLI_EXIT" -eq 0 ]; then
ok "mxcli runs ($PROBE_HOW): $(probe_line)"
note "at: $PMXCLI_PROBE"
else
bad "mxcli exists but cannot run (exit $MXCLI_EXIT)"
bad "mxcli exists but cannot run (exit $MXCLI_EXIT): $PMXCLI_PROBE"
printf '%s\n' "$PROBE_OUT" | grep -v '^[[:space:]]*$' | head -3 | while IFS= read -r l; do note " $l"; done
note "Exit 126 usually means a binary built for another platform/architecture —"
note "re-download the mxcli build for this OS."
fi
elif [ "$PLATFORM" = gitbash ] && mxtk_is_elf "$PROJECT_DIR/mxcli"; then
warn "the project's mxcli is the Linux build (the Dev Container's) — Git Bash needs mxcli.exe beside it."
note "Not a permissions problem: chmod cannot make a Linux binary run here, which is why it"
note "looked like it 'reverted'. Leave the file for the container and add the Windows build:"
note " bin/doctor.sh --install $PROJECT_DIR (fetches mxcli.exe; the two coexist)"
note " or copy the mxcli.exe you already have on PATH into the project root."
elif [ -f "$PROJECT_DIR/mxcli" ]; then bad "mxcli is present but not executable — chmod +x mxcli"
else
warn "no mxcli in the project root"
Expand Down Expand Up @@ -755,14 +797,20 @@ if [ -n "$PROJECT_DIR" ] && [ -d "$PROJECT_DIR" ]; then
>> "$PROJECT_DIR/.gitignore" 2>/dev/null || true
note "(added /.claude/.doctor-receipt to the project's .gitignore — the receipt is machine-local)"
fi
# toolkit.env holds this machine's paths — never something to commit.
if [ -d "$PROJECT_DIR/.git" ] && ! git -C "$PROJECT_DIR" check-ignore -q .claude/toolkit.env 2>/dev/null; then
printf '\n# Machine-local tool locations (bin/doctor.sh / project-bin/_common.sh)\n/.claude/toolkit.env\n' \
>> "$PROJECT_DIR/.gitignore" 2>/dev/null || true
note "(added /.claude/toolkit.env to the project's .gitignore — it holds this machine's paths)"
fi
fi

if [ "$FAIL" -gt 0 ]; then
printf ' %s problem(s) that will break a pipeline stage, %s warning(s).\n' "$FAIL" "$WARN"
printf ' Fix the FAIL lines above before running anything else.\n'
printf ' %s thing(s) to sort out before the first model write (FAIL lines), %s note(s) worth reading (WARN).\n' "$FAIL" "$WARN"
printf ' Analysis and planning stages run fine meanwhile; each FAIL line says what fixes it.\n'
exit 2
elif [ "$WARN" -gt 0 ]; then
printf ' Ready, with %s warning(s). Read them — each one names something that will not work.\n' "$WARN"
printf ' Ready. %s warning(s) above — read each one: some are optional, a missing .mpr or CLAUDE.local.md is not.\n' "$WARN"
exit 1
else
printf ' Ready.\n'
Expand Down
Loading
Loading