diff --git a/docs/PHASE0.md b/docs/PHASE0.md index 71dac76..942cb65 100644 --- a/docs/PHASE0.md +++ b/docs/PHASE0.md @@ -43,6 +43,13 @@ Phase 0 is the minimal working skeleton. It establishes the REPL loop, input dis | Config format | Lua table (plain `.lua` file sourced at startup) | No parser dependency; native types; easily extended | | JSON encode/decode | dkjson 2.8 vendored under `vendor/dkjson.lua` | Pure Lua (preserves §3 "no compiled extensions" invariant); single-file vendor avoids `luarocks`; sourced from Debian's `lua-dkjson` package, originally from dkolf.de | +**FFI loader fallback.** `ffi.load("readline")` and `ffi.load("curl")` +look for the unversioned `lib.so` symlink, which is only installed +by the `-dev` package. Phase 0 loaders try the unversioned name first +then fall back to versioned sonames (`readline.so.8`, `readline.so.7`, +`curl.so.4`, `curl-gnutls.so.4`) so a runtime-only host (Debian/ALARM +without `lib-dev`) just works. + --- ## 4. Target Directory Layout @@ -153,7 +160,7 @@ The `CMD:` prefix convention is the extraction contract between the model and `e ## 7. Execution Model (Phase 0) ```lua --- executor.lua Phase 0 +-- executor.lua Phase 0 (illustrative — see note below) local function exec(cmd) local handle = io.popen(cmd .. " 2>&1", "r") local output = handle:read("*a") @@ -162,11 +169,21 @@ local function exec(cmd) end ``` +**LuaJIT 2.1 popen-close caveat.** The sketch above assumes Lua 5.2's +three-return `io.popen():close()` shape. LuaJIT 2.1 follows the Lua 5.1 +ABI and returns just `true` — no exit status. The Phase 0 implementation +recovers the exit code by appending a sentinel echo to the wrapped +command (`(cmd) 2>&1; echo __AISH_EXIT___$?`) and parsing it back +out. Phase 1's PTY work replaces this with `waitpid` via libc FFI; the +sketch becomes accurate at that point. + Output is captured and: 1. Printed to the terminal 2. Injected into `context.lua` as a `[exec output]` user turn -`cd` is intercepted before `popen` and handled via `posix.chdir` (libc FFI) so the working directory change persists across calls — `popen` forks a subprocess and `cd` inside it would otherwise be discarded. +`cd` is intercepted before `popen` and handled via `libc.chdir` (FFI) so +the working directory change persists across calls — `popen` forks a +subprocess and `cd` inside it would otherwise be discarded. --- @@ -270,11 +287,18 @@ return { ``` Config path resolution order: -1. `--config ` CLI argument +1. `--config ` CLI argument (explicit; failure if not openable, no fallback) 2. `$AISH_CONFIG` environment variable 3. `~/.config/aish/config.lua` 4. `./config.lua` (development fallback) +**Cwd-relative module resolution.** Phase 0 prepends `./?.lua;./vendor/?.lua` +to `package.path`, so `luajit main.lua` must be invoked with the repo +root as cwd. Cwd-independent resolution (relative to the script's own +directory) lands later — likely Phase 1 alongside the install path +work, or whenever the first user reports trying `luajit ~/aish/main.lua` +from somewhere else. + --- ## 11. Planned Phase Sequence