Commit7e7c8873Recorded3 Aug 2026Repositorysigil

Release v0.18.2: guard dispatch fixes, loud exit doors, structured shell

Changed
 RELEASES.md | 35 +++++++++++++++++++++++++++++++++++
 package.sgl |  2 +-
 2 files changed, 36 insertions(+), 1 deletion(-)
Diff
RELEASES.mdmodified
@@ -17,6 +17,41 @@ slug: releases
17
# Sigil Releases
18
19
+20
## 0.18.2
+21
+22
A runtime correctness release, plus a headline feature: Sigil now has first-class shell scripting support via `(sigil shell)`. On the correctness side, four distinct defects in exception dispatch are fixed, the most serious Sigil has shipped: a raise could remove the wrong handler, corrupt a live stack frame, or end the process with exit code 0 while work was still pending. Nine subcommand paths that used to die silently now fail loudly, and scoped package ids resolve local paths correctly. Anything long-lived built on 0.17.x (a server, an MCP tool, a CI controller) should be rebuilt on this release; consumers on a 0.18 caret range pick it up on relock.
+23
+24
### First-class shell scripting with `(sigil shell)`
+25
+26
Sigil is now a real alternative to bash for the scripts around your project. `(sigil shell)` runs external programs with structured command forms instead of concatenated strings, returns outcomes you can match on instead of exit codes you remember to check, and pumps pipelines through the VM so your script can sit between two processes. A script declares the executables it requires up front and fails closed immediately when one is missing. And a single file with `#!/usr/bin/env sigil` now runs directly with a preloaded set of useful modules, so automation no longer needs a package around it.
+27
+28
### A more flexible package build format
+29
+30
The package format can now describe how software actually gets built, not just how Sigil code compiles. A package declares run phases (arbitrary build steps that run in order and fail the build honestly when one fails), the build inputs those steps consume, and the environment they require, each verified by its own gate. That makes packaging software with its own build process straightforward: a configure step, generated code, bundled assets. The release build itself now declares the tools it depends on and fails in seconds when one is absent instead of late and confusingly.
+31
+32
### A raise after a caught exception no longer escapes the enclosing guard
+33
+34
When a guard caught a raise, dispatch popped one handler too many, so a later raise escaped the guard that should have caught it. Ten lines of plain synchronous code reproduce it, and on 0.17.x and 0.18.0 the escaped raise ended the process with exit code 0; 0.18.1 at least exited 1. A fired handler's entry now stays on the stack until its own continuation retires it, on every dispatch path, including a native-compiled function raising under a bytecode guard.
+35
+36
### A handler that suspends no longer corrupts the program
+37
+38
A guard handler that suspended (a sleep, blocking I/O, a channel operation) could resume into a corrupted machine: one defect overwrote a live frame's saved instruction offset, so execution continued into foreign bytecode; another delivered a tail-position handler's result as if the raising call had returned, so the body resumed from the raise site. Handlers now run as ordinary frames in the same dispatch loop, so return delivery is correct whether or not the handler suspended.
+39
+40
### Native builds keep their handlers across fiber interleaving
+41
+42
The native backend tracked handlers with absolute indexes, but capturing a continuation across a suspension relocates handler entries without moving that bookkeeping. One rebasing suspension left the runtime convinced an unwind was still in progress, and every later native call silently short-circuited: a process that dies with nothing in the log. Handler entries now travel inside the captured continuation and re-push rebased on resume. This is the defect that killed Kiln's static controller on 7 of 9 setup-failure cases; the same Kiln code on this runtime passes 9 of 9, and the runtime was the only variable in the pair.
+43
+44
One narrow, pre-existing case remains open and is tracked: a native-compiled function that raises more than one bytecode frame below its enclosing guard may still resume the intermediate frame.
+45
+46
### Nine silent exit doors now fail loudly
+47
+48
Nine subcommand paths used to end the process silently when something raised: deps install, update, and upgrade, task and buildtask raises under run, and the four extb doors. All nine now exit 1 with a real error trace. Most were the guard defect seen from the outside: the subcommand's handler fired, the enclosing guard in main was already gone, and the process fell off the end reporting success.
+49
+50
### Scoped package ids resolve local paths
+51
+52
A scoped package id (the sigil/name form the registry uses) broke local path resolution and died with exit 0 when it failed. Scoped ids now resolve correctly, and a failure on that path exits loudly with the reason.
+53
+54
55
## 0.18.1
56
57
Every way into the Sigil CLI now reports failure honestly. Before this release a
package.sglmodified
@@ -15,7 +15,7 @@
15
16
(workspace
17
name: "sigil"
18
version: "0.18.1"
+18
version: "0.18.2"
19
description: "A practical Scheme for building standalone applications"
20
url: "https://codeberg.org/sigil/sigil"
21
license: "BSD-3-Clause"