io-cli 0.15.0 - #42
Merged
Merged
Conversation
… into it io-harness resolves $IO_CONFIG, then $IO_CONFIG_HOME, then the platform's own place, reading the environment at call time — and exposes no caller-supplied home. So the home is named by setting that variable once, before the first Config::discover, and the run store follows because settings::store_path derives it from the configuration file's own directory. The migration moves io.toml and the store together, and the store's -wal and -shm with it: a runs.db moved without its write-ahead log opens without complaint and simply does not contain the last session. Nothing is moved onto a file that exists, and a source is removed only after its copy has been read back. An operator who set either variable is not moved at all. A variable pointing at io-cli's own home reads as 'default' rather than as their choice, so a status row cannot credit them for this crate's default — which is what an origin read from the raw environment did, because adopt is what put the variable there.
home::adopt runs immediately before Config::discover, the only discovery either arm reaches, because user_path reads the environment at call time: a config discovered first would come from the old location while the store answered from the new one, which is a silently emptied /resume. The report is committed through App::record rather than App::say — it belongs to the conversation, not to the keystroke that happened to be next — and takes its own Tone::Muted vec rather than joining the notices, which are Warning and would paint a permanent yellow line at every launch. In the headless arm the same lines go to stderr before the handoff, never to stdout. tests/structure.rs pins the ordering by reading src/main.rs with every comment stripped first, so a comment naming adopt cannot satisfy the gate.
Spawns the built binary, because the printing lives in main.rs and no integration test links it. `exec --policy ask-writes` is refused on exec::main's first line, before a store, a session or a provider — so the run terminates with no credential and no network while still executing everything that runs before the branch, which is where the report is written.
…s a home
Skills::discover does not walk away from a directory that is not there — it
returns Err, and discover_skills propagates that at run start, before the first
completion. So an unconditional default would have failed every turn for every
operator who had never made the directory. adopt creates <home>/skills with the
home, and the default is filtered on is_dir() besides.
io-harness substitutes ${env:} and ${file:} and nothing else, so a ~ written in
[run] skills or [app.io-cli] skills reached Skills::discover as a directory one
character long. The expansion happens once, after both keys have had their say.
attach.rs's own twelve lines of it now call the same helper.
Precedence, weakest to strongest: <home>/skills, [run] skills, [app.io-cli] skills.
…ded it Derived from home::in_force and never from home::path: under IO_CONFIG the file is somewhere io-cli did not choose, and reporting the home this crate would have picked would be wrong in the one case the row exists for. tests/plain.rs asserts every row of the plain page is ASCII, and the new row carries a directory read from the environment — an assertion about whoever runs the suite. Pinned to a literal, not to a temporary directory, because a temporary directory is $TMPDIR and that is the same ambient answer one step on.
…nnot work The resolution order is io-harness's and unchanged; what changed is that io-cli answers its second rung by default. The migration and its opt-out are stated up front, along with the fact that the variable is set in io-cli's own process and inherited by every child a session starts. The skills example named ~/.config/io/skills, which was wrong twice: the location moved, and io-harness expands no tilde at all. The README's discovery prose had no gate, which is how it could go stale. The new one derives the directory name from home::path and walks the four rungs by byte position, so a README naming all four in the wrong order fails.
The version and the notes. The migration is the first thing the notes say, because it moves files io-cli did not create on the first run of the new binary, and rolling back is a variable or a move rather than a loss.
Found by running the binary, twice. With a file io-harness cannot parse the run ends at the discovery; with an unreadable store it ends at Store::open. Both are before either arm reaches the place the report was written, so an operator saw an error naming a path they had never seen, one keystroke after their old directory emptied, with nothing anywhere saying their install had just moved. That is the 'my sessions are gone' reading this release exists to prevent. The report is now owed until somebody delivers it: run fills a vec main owns, io exec drains it onto stderr, a session takes it into the scrollback, and main says whatever is left. Patching each early return would have left the next one out. The test spawns the binary, because the ordering lives in main.rs and nothing under tests/ links it. Its sabotage — report only after a successful discovery — fails it and nothing else.
…oing it Windows CI found this and this machine could not. Windows refuses to rename a file another process holds open, so a second io running while this one starts would let io.toml reach the new home while runs.db stayed in the old one — a configuration and a store in two directories, and a /resume that finds nothing. That partial state is worse than not migrating at all, and adopt was ignoring the failed move. Now the variable is set only once every file that had to move has moved. A file that will not move takes everything already moved back with it, leaves the environment alone, and is named on screen with the directory still in force. f4's fixture was the shape that hid it: it held the store open across the move, which is legal on unix and impossible on Windows. It now builds the store in a staging directory, copies it while the write-ahead log is live, and drops the connection before anything moves — which is byte for byte what a crashed io leaves, on either platform, with nothing holding it.
io-cli 0.15.0 — one home, `~/.io-cli`
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Release PR for io-cli 0.15.0 — one home,
~/.io-cli.Everything io-cli keeps now lives in one directory with one name on every
platform: the configuration file, the run store, the durable memory that is rows
inside that store, and a skills directory created with the home. An existing
install is moved into it on the first run, with each file that moved named on
screen, nothing overwritten and nothing deleted. An operator who has set
IO_CONFIGorIO_CONFIG_HOMEis not moved at all.Merged from
feat/0.15.0in #41 with 8/8 checks green on three platforms.The Windows row earned its place this round. Its first run failed on a real
defect that no macOS or Linux run could see: Windows refuses to rename a file
another process holds open, and
adoptwas ignoring the failed move — so a secondiorunning would have letio.tomlreach the new home whileruns.dbstayed inthe old one, which is the config-and-store-in-two-places split this whole release
exists to prevent. It now moves everything or nothing, takes back whatever already
moved, and names the file that was in the way.
The UltraShip record is sealed and pinned
(
sha256:51848093d751c7ccee5cd96977453c069a1386d1865127a22a06b7255d9bdcc4,validateexit 0 over 45 checks);.ultraship/is gitignored here, so it lives ondisk and never in the history. The Windows fix landed after the seal and the seal
was not amended — the record's own
known_limitationsalready says the Windowsarm runs on CI and nowhere else, which is exactly how it was found.
Suite: 57 binaries, 719 passed, 0 failed, 24 ignored (0.14.0 finished at 696).