Skip to content

feat(cli): update installed extensions from their repo - #381

Open
arthware-dev wants to merge 8 commits into
feature/0.5.0-beta.1from
feat/extensions-update
Open

arthware-dev wants to merge 8 commits into
feature/0.5.0-beta.1from
feat/extensions-update

Conversation

@arthware-dev

@arthware-dev arthware-dev commented Oct 31, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • stack extensions update [<id>...] [--yes] installs the newest version of installed extensions from the default branch of their repo, the version stack extensions list compares with. It stops and starts nothing: stop a running extension with stack down <id> first, and apply the new code with stack up <id>, which also reloads the bot runner.
  • add and update record 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 .env from stack 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.
  • The copy leaves out a .env the repo ships and replaces a shipped .source.toml, even a symlink. Extensions from another repo show the add warning for the new version, then ask; --yes skips only the question. A record without [files] is refused by name and still names its origin in list and stack up.
  • Docs: "How to update an extension" in the admin guide, a decision section in ADR-022 (still Proposed), the stack reference and the operator command map.

Squash merge.

@arthware-dev
arthware-dev force-pushed the feat/extensions-update branch from 7407c74 to edbfe72 Compare October 31, 2026 07:15
`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
arthware-dev force-pushed the feat/extensions-update branch from 135df5d to abc60b4 Compare October 31, 2026 09:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant