Repository navigation
feat(cli): update installed extensions from their repo - #381
Open
arthware-dev wants to merge 8 commits into
Open
arthware-dev wants to merge 8 commits into
arthware-dev wants to merge 8 commits into
Conversation
arthware-dev
force-pushed
the
feat/extensions-update
branch
from
October 31, 2026 07:15
7407c74 to
edbfe72
Compare
`stack extensions update [<id>...] [--yes]` replaces installed extensions with the newest version of their path in their repo, on the branch they were installed from. Without an id it checks every extension that records its source. - An unchanged folder is replaced in one step, and the `.env` that `stack up` wrote into it is kept. - A folder that differs from what was installed (edited, added or removed files, a changed mode) is refused and left as it is. - An extension from a repo other than the catalog shows the same warning as `add`, then asks; `--yes` skips only the question. - Nothing is restarted. A set-up extension gets the hint `stack restart <id>`. `stack extensions list` names the update command when an update is available.
Add "How to update an extension" to the admin guide, with a warning that an edited extension is not updated, and a table of refusals. ADR-022 gets a decision section for `update`, and its consequences no longer list `update` as a next step. The stack reference and the operator command map name the command.
`stack extensions update` decided what to replace by hashing the folder with git. The extension's `.gitignore` hid local files from that hash, so an update deleted them (a local config, a `.venv`). An `export-ignore` attribute or a global `core.autocrlf` made an untouched folder count as edited for ever. `add` and `update` now record every file and symlink they write, with its content hash, in a `[files]` table in `.source.toml`. An update: - counts as an edit only a recorded file that is changed or missing; - moves every other file in the folder into the new version, and refuses when the new version has a file at the same path; - deletes the old folder only after the new one is in place, and puts it back with its kept files when a step fails; - checks for edits only when the repo has a newer version; - reads the repo's default branch, as `stack extensions list` does; - names `stack up <id>` to apply the new code, because `stack restart` does not reload the bot runner. A `.source.toml` without `[files]` counts as installed by hand.
The admin guide, ADR-022, the stack reference and the operator command map now describe the `[files]` record in `.source.toml`: an update refuses only when a file it wrote was changed, keeps every other file, reads the default branch, and names `stack up <id>` to apply the new code. The admin guide's warning says that files an admin adds are kept.
The second review of `stack extensions update` found ways to lose or strand the admin's files, and records that made an extension look installed by hand: - A Ctrl-C or a failed move while kept files moved into the new version deleted them. They now move back on any failure; a staging folder that still holds one is kept and named. - The old folder is renamed into its own directory in `.incoming`, in the same step that can fail, so a failure there puts everything back. - A file name outside ASCII (an emoji) made `.source.toml` unreadable. Its strings are now written as valid TOML. - A record without `[files]` reads again, so `list` and `stack up` still say where the extension came from. `update` refuses it by name. - An empty directory, such as a submodule, is not kept, and a directory in both versions keeps the admin's files inside it. - Edits are checked again after the question for a foreign repo. - A file or directory that cannot be read refuses that extension; the others go on. - `add` records a local repo path as an absolute path.
The admin guide now says to run `stack up <id>` right after an update, because a running extension keeps the old files until then, and lists the refusals for a record without `[files]` and for an unreadable file. ADR-022 and the stack reference describe what the second review changed: TOML strings, a record without `[files]`, empty and shared directories, the second edit check and the undo on any failure.
The third review of `stack extensions update` found these: - Ctrl-C between a move and its bookkeeping, or between the two renames, could lose a kept file or leave the extension folder in `.incoming`. Ctrl-C is now held back while files move and folders swap, in `add` and in `update`, and raised once that is done. - A directory nobody can read crashed the command. It now refuses that extension, and the others go on. - A repo that ships `.source.toml` as a symlink made `add` write the record outside the extension folder. The shipped file is removed first. - A repo that ships `.env` could never be updated, because `stack up` rewrites it. The copy now leaves out a `.env` at the extension's root. - The "updated to" line printed the subject of the repo's newest commit, often another extension's. It now prints the commit only. - `add` records a local path without resolving its symlinks, so it still matches a catalog configured through one. - A record without a list of files is written back without one.
`update` deletes the old folder, so a running container would read deleted files and lose what it writes. The admin guide now says to run `stack down <id>` first and `stack up <id>` after, shows the sample output in its real order without a commit subject, and says that a shipped `.env` is not copied. ADR-022, the stack reference and the operator command map say the same, and describe the held Ctrl-C and the replaced `.source.toml`.
arthware-dev
force-pushed
the
feat/extensions-update
branch
from
October 31, 2026 09:22
135df5d to
abc60b4
Compare
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.
Summary
stack extensions update [<id>...] [--yes]installs the newest version of installed extensions from the default branch of their repo, the versionstack extensions listcompares with. It stops and starts nothing: stop a running extension withstack down <id>first, and apply the new code withstack up <id>, which also reloads the bot runner.addandupdaterecord every file they write, with its content hash, in a[files]table in.source.toml. An update deletes only those files, and only while they are unchanged: a changed or missing recorded file refuses the extension and names the file, checked again after the question. Every other file (the.envfromstack up, a local config, a.venv, files inside a directory both versions have) moves into the new version. On any failure the old folder and the kept files go back, and Ctrl-C is held back until the folders are swapped. A file or directory that cannot be read refuses that extension, and the others go on..envthe repo ships and replaces a shipped.source.toml, even a symlink. Extensions from another repo show theaddwarning for the new version, then ask;--yesskips only the question. A record without[files]is refused by name and still names its origin inlistandstack up.Squash merge.