(sigil deps installed)
(sigil deps installed) - Fast installed-deps check + path helpers
The minimal "are this project's external deps installed on disk?" check used by cli/boot.sgl and cli/build-cmds.sgl's workspace-build path. Stays in BOOTSTRAP_MODULES; deliberately does NOT depend on (sigil git), (sigil deps fetch), (sigil deps lock), or (sigil deps semver) so those modules can drop from bootstrap and become extractable.
The check is filesystem-only: for each from-git / from-path dep, derive the symlink path (.sigil/deps/<name>) or resolve the from-path target and verify it exists. No git operations, no lockfile parsing, no semver resolution.
Also exports the path/collection helpers (local-deps-dir, collect-git-deps, collect-path-deps, resolve-path-dependency, get-dep-package-path) that fetch.sgl previously owned. fetch.sgl now re-exports these from here so post-bootstrap callers keep working.
Exports
local-deps-dirprocedureThe local deps directory for a project (.sigil/deps). Symlinks are placed here pointing at shared worktrees in $SIGIL_HOME/deps; from-path deps are resolved directly.
get-dep-package-pathprocedurePath to where a dependency's symlink lives in the project.
collect-git-depsprocedureCollect every from-git dependency from a package or workspace. Includes dev-dependencies and the auto-derived sigil-stdlib (and sigil-lib for c-source packages) peer deps. For workspaces, walks every member package and aggregates. Dependencies whose package names are already owned by the current workspace are omitted: the workspace copy wins over auto-derived peer deps and stale lock pins.
collect-path-depsprocedureCollect every from-path dependency that has a package: field (workspace references). Bare from-path deps without package: are resolved at build time and don't need installation, so they're excluded here.
collect-pkg-depsprocedureCollect every from-pkg (registry) dependency from a package or workspace. Mirrors collect-git-deps: walks effective deps, and for workspaces aggregates across members while omitting deps whose names are already owned by the workspace (the workspace copy wins).
resolve-path-dependencyprocedureResolve a from-path dependency to (pkg-name . pkg-path) or #f if the path doesn't exist or doesn't contain a package.sgl. Used both to load from-path deps for the build graph and to verify that redirected deps resolve.
git-dep-nameprocedureDerive the on-disk package name for a from-git dep. Priority: explicit name: > package: field > subpath basename > forge URL repo segment. Returns #f if none of those produce a name (most commonly when a full-URL dep declares neither name nor package nor subpath — that dep is treated as unresolvable by callers).
Used in two places:
- The bootstrap missing-deps check below — derive the symlink path under
.sigil/deps/<name>and check existence. build-cmds.sgl'sload-single-git-dep— same purpose, different stage. Prior to this refactor that code reached directly into(sigil git)'sparse-git-url+git-url-repo, pulling sigil-git into the bootstrap surface.
pkg-dep-nameprocedureThe on-disk package name for a from-pkg (registry) dep. The registry name IS the on-disk name (.sigil/deps/<name>), so this is just the declared name:.
missing-installed-depsprocedureReturn the list of dependencies that are not currently installed on disk. Each missing dep is represented by a string identifier (the package name when known, otherwise the URL or path).
Optional third argument is a redirects record (from (sigil deps redirects)). When passed, redirects are applied before checking, so redirected deps are checked at their target location.
deps-installed?procedurePredicate form. Returns #t when every declared dependency is installed on disk (after applying optional redirects), #f otherwise.
report-missing-sigil-fieldprocedurePrint the operator-facing diagnostic for a package missing its sigil: field. Extracted from validate-host-sigil-field so exception-free callers (see the export comment) can report the failure without going through the raise.
lean-bare-version?procedureDoes s have the shape parse-semver accepts — 1-3 dot-separated numeric parts, optional "-prerelease" suffix, no prefix?
sigil-field-operator-leanprocedureThe range operator carried by a sigil: value, or #f when the value is a bare version. "?" means the value parses as nothing.
sigil-field-replacement-leanprocedureThe bare replacement to suggest, or #f when none is derivable leanly. Covers the operators whose floor is the version they carry; the general form lives in (sigil deps semver).
lean-version-partsprocedureLean numeric compare of two bare version strings: #t when a < b. Only called on strings lean-bare-version? accepted. Missing components are ZERO, matching parse-semver's padding — treating a shorter equal prefix as "less" let (supports min: "0.16" max: "0.16.0") through validation as a window that admits nothing (adversarial review, 2026-08-25).
caret-tolerance-ended-for?procedureThe flag-day predicate, parameterized so the gate can hold it red/green without faking a compiler. version-parts is a list of integers, or #f for an unparseable version.
An unparseable self-version TOLERATES (pre-1.0 behaviour): failing closed here would refuse every grandfathered manifest in the estate over a defect in the BINARY's version string, not in any manifest — an estate-wide over-refusal, the documented worst failure direction.
grandfathered-caret-lean?procedureIs value a grandfathered caret — ^X with X a bare version whose floor is below the cutoff, while tolerance has not ended?
find-grandfathered-caret-fieldprocedureWalk the host package (or every workspace member) and return the first whose sigil: field is a grandfathered caret, as (pkg-file . pkg), or #f. Mirrors find-malformed-sigil-field's iteration; keep the two in sync. Used by the probe sites to emit ONE warning per invocation — per-member warnings on a workspace would be the verbose-warning failure the coherence check already taught (people disable what nags in bulk).
warn-grandfathered-caret-fieldprocedureThe ONE compact warning line for a grandfathered caret. THE MIGRATION ADVICE IS VERSION-GATED, and that is load-bearing: a bare sigil: value under a compiler predating this change is read as an EXACT range — measured on a real repo, that evicts the lockfile's runtime pin and silently downgrades, exit 0. So the advice names the minimum toolchain (the RUNNING compiler's own version: this binary provably reads bare floors, and every later release does too) instead of handing the reader an instruction that breaks their lock if followed early. The hard refusal never had this hazard — seeing the refusal proved you were on a new-enough compiler; a warning can be read from anywhere, so it must carry its own precondition.
sigil-field-problem-leanprocedureWhat is wrong with a sigil: value, or #f when it is acceptable. A grandfathered caret is ACCEPTABLE here (warned elsewhere, never refused). Returns a list describing the problem: (operator <op> <part> <text>) a range operator where a bare version belongs; part is 'field (string spelling) or 'min / 'max (supports spelling) (missing <part>) a supports form lacking min:/max: (unparseable <part> <text>) not a version at all (inverted <min> <max>) supports with min >= max
sigil-field-value->textprocedureRender a sigil: value for a diagnostic. A supports struct is shown in its manifest spelling.
report-malformed-sigil-fieldprocedurePrint the operator-facing diagnostic for a malformed host sigil: field — a range operator, an unparseable value, or a malformed (supports ...) form. Names what is wrong, the file, and the replacement, so the fix is copy-paste. HARD REFUSAL, no deprecation window — ruled by David 2026-08-25: the sweep ships in the same release, the remedy is one printed line, and this estate's deferred flips historically do not happen.
find-malformed-sigil-fieldprocedureWalk the host package (or every workspace member) and return the first whose sigil: field is malformed (operator, unparseable, or bad supports form), as (pkg-file . pkg), or #f when all declared fields are acceptable. Packages MISSING the field are find-missing-sigil-field's business, not this one's. Mirrors that function's iteration; keep the two in sync.
find-missing-sigil-fieldprocedureException-free scan for a host package (or workspace member) missing its sigil: field. Returns #f when every host package declares one, or (pkg-file . pkg) for the first offender. Mirrors the iteration in validate-host-sigil-fields-on exactly; keep the two in sync.
validate-host-sigil-fieldprocedureRaise a clean, copy-paste-ready error if pkg is missing the top-level sigil: field, or (since 2026-08-25, policy permitting) if the field carries a range operator. Returns the field's value when acceptable. pkg-file is the absolute or repo-relative path used in the diagnostic to point at the offending file.
Fires at command entry (e.g., sigil deps install, sigil build), not at parse time, so the bootstrap parse can still succeed before validation runs.
NOTE: the raises below do NOT survive a native-codegen binary (they are answered by a dead handler and converted into a value). Exit- code-bearing paths must use find-missing-sigil-field / find-operator-sigil-field + the matching reporter + plain exit instead — see build-cmds.sgl.
validate-host-sigil-fields-onprocedureValidate every host package's sigil: field for a workspace or standalone package. Loads each member package.sgl (workspace case) or validates the single host (standalone case). Errors with the same clean message produced by validate-host-sigil-field.
CORRECTION, 2026-08-25: the TODO that stood here since the 0.14.0 redesign (t-dc5d) proposed extending this to transitive deps via range intersection. That predicate measured declaration era, not compatibility (it refused the monorepo, which builds fine), and was never wired. The transitive check now exists as the FLOOR axis of the coherence check ((sigil deps coherence), axis D): resolved sigil >= each installed dep's declared floor. See decisions/2026-08-25-sigil-field-is-a-floor.