build: Build the plugin half of self-update on top of the service endpoints the previous step created (its report is your brief #11

Merged
Joel merged 1 commit from build/291ada59 into main 2026-09-06 02:28:13 +00:00
Owner

Build the plugin half of self-update on top of the service endpoints the previous step created (its report is your brief). On load, and on a manual check button, ask Connor for the current version; if it is newer than this manifest's version, show an "update available -> update now" row in the settings tab naming both versions. Update now downloads every artifact to a temp location, verifies each against the served hash, and only then swaps them into the plugin dir, then reloads the plugin in place via the app's plugin manager (disable+enable of this plugin id) so no Obsidian restart is needed. ATOMICITY IS THE POINT: a failed download, a hash mismatch, or a crash mid-write must leave the previously working plugin intact and running - write to temp, verify all, swap last, and keep a rollback copy. Report failures in the settings row, never silently. Tests for the version compare, the hash verify, the refusal-to-swap-on-mismatch, and the rollback. Full npm run gate.

This task is one step of my plan: obsidian-connor updates itself from Connor — no disable/quit/reinstall/re-enable cycle

Result of earlier step 1 (backend: In the Connor repo, build the service half of plugin self-update. Serve the curr):
Done. Here's where it stands.

What I built

connor/plugindist.py (new) — the service half of plugin self-update, plus two routes in connor/service.py:

  • GET /vault/plugin — the plugin's manifest.json verbatim, plus sha256 and size for each file in the set.
  • GET /vault/plugin/file?name=… — one artifact as raw bytes, with X-Connor-Plugin-Version and X-Connor-Artifact-SHA256 headers so the plugin can verify before it writes, without a second round trip.

Where the artifacts come from — the decision. The mapped obsidian-connor checkout, resolved through dispatch.REPOS (env-configurable, CONNOR_PLUGIN_DIR overrides for a deploy host). Same map every backend/session dispatch cuts from, so "the version I serve" and "the version I build against" can't name two different trees. Nothing is generated: I don't run npm, because a service that shells out to a build on a GET is a remote build trigger wearing a download's clothes. The checkout's files as they stand are the offer — committed manifest.json/styles.css, built main.js.

Refusal beats a partial set. Validated on every request, including a request for one file: no mapped checkout; `mani


Built by Connor's frontend backburner (dispatch 291ada59) in an isolated clone; shipped deterministically by ship.py. The full build notes were spoken in conversation and stored in memory (agent-dispatch:291ada59). Review is the gate. Gate: npm run gate.

Build the plugin half of self-update on top of the service endpoints the previous step created (its report is your brief). On load, and on a manual check button, ask Connor for the current version; if it is newer than this manifest's version, show an "update available -> update now" row in the settings tab naming both versions. Update now downloads every artifact to a temp location, verifies each against the served hash, and only then swaps them into the plugin dir, then reloads the plugin in place via the app's plugin manager (disable+enable of this plugin id) so no Obsidian restart is needed. ATOMICITY IS THE POINT: a failed download, a hash mismatch, or a crash mid-write must leave the previously working plugin intact and running - write to temp, verify all, swap last, and keep a rollback copy. Report failures in the settings row, never silently. Tests for the version compare, the hash verify, the refusal-to-swap-on-mismatch, and the rollback. Full npm run gate. This task is one step of my plan: obsidian-connor updates itself from Connor — no disable/quit/reinstall/re-enable cycle Result of earlier step 1 (backend: In the Connor repo, build the service half of plugin self-update. Serve the curr): Done. Here's where it stands. ## What I built **`connor/plugindist.py`** (new) — the service half of plugin self-update, plus two routes in `connor/service.py`: - `GET /vault/plugin` — the plugin's `manifest.json` verbatim, plus `sha256` and `size` for each file in the set. - `GET /vault/plugin/file?name=…` — one artifact as raw bytes, with `X-Connor-Plugin-Version` and `X-Connor-Artifact-SHA256` headers so the plugin can verify before it writes, without a second round trip. **Where the artifacts come from — the decision.** The mapped `obsidian-connor` checkout, resolved through `dispatch.REPOS` (env-configurable, `CONNOR_PLUGIN_DIR` overrides for a deploy host). Same map every backend/session dispatch cuts from, so "the version I serve" and "the version I build against" can't name two different trees. Nothing is generated: I don't run `npm`, because a service that shells out to a build on a GET is a remote build trigger wearing a download's clothes. The checkout's files as they stand are the offer — committed `manifest.json`/`styles.css`, built `main.js`. **Refusal beats a partial set.** Validated on *every* request, including a request for one file: no mapped checkout; `mani --- Built by Connor's frontend backburner (dispatch `291ada59`) in an isolated clone; shipped deterministically by `ship.py`. The full build notes were spoken in conversation and stored in memory (`agent-dispatch:291ada59`). Review is the gate. Gate: `npm run gate`.
build: Build the plugin half of self-update on top of the service endpoints the
All checks were successful
gate / gate (pull_request) Successful in 8s
708de85107
Build the plugin half of self-update on top of the service endpoints the previous step created (its report is your brief). On load, and on a manual check button, ask Connor for the current version; if it is newer than this manifest's version, show an "update available -> update now" row in the settings tab naming both versions. Update now downloads every artifact to a temp location, verifies each against the served hash, and only then swaps them into the plugin dir, then reloads the plugin in place via the app's plugin manager (disable+enable of this plugin id) so no Obsidian restart is needed. ATOMICITY IS THE POINT: a failed download, a hash mismatch, or a crash mid-write must leave the previously working plugin intact and running - write to temp, verify all, swap last, and keep a rollback copy. Report failures in the settings row, never silently. Tests for the version compare, the hash verify, the refusal-to-swap-on-mismatch, and the rollback. Full npm run gate.

This task is one step of my plan: obsidian-connor updates itself from Connor — no disable/quit/reinstall/re-enable cycle

Result of earlier step 1 (backend: In the Connor repo, build the service half of plugin self-update. Serve the curr):
Done. Here's where it stands.

## What I built

**`connor/plugindist.py`** (new) — the service half of plugin self-update, plus two routes in `connor/service.py`:

- `GET /vault/plugin` — the plugin's `manifest.json` verbatim, plus `sha256` and `size` for each file in the set.
- `GET /vault/plugin/file?name=…` — one artifact as raw bytes, with `X-Connor-Plugin-Version` and `X-Connor-Artifact-SHA256` headers so the plugin can verify before it writes, without a second round trip.

**Where the artifacts come from — the decision.** The mapped `obsidian-connor` checkout, resolved through `dispatch.REPOS` (env-configurable, `CONNOR_PLUGIN_DIR` overrides for a deploy host). Same map every backend/session dispatch cuts from, so "the version I serve" and "the version I build against" can't name two different trees. Nothing is generated: I don't run `npm`, because a service that shells out to a build on a GET is a remote build trigger wearing a download's clothes. The checkout's files as they stand are the offer — committed `manifest.json`/`styles.css`, built `main.js`.

**Refusal beats a partial set.** Validated on *every* request, including a request for one file: no mapped checkout; `mani

Built by my frontend backburner (dispatch 291ada59), diff verified by git; shipped by ship.py. Nothing merges without review.
Joel approved these changes 2026-09-06 01:16:07 +00:00
Dismissed
Joel approved these changes 2026-09-06 02:28:09 +00:00
Joel merged commit 100561af39 into main 2026-09-06 02:28:13 +00:00
Joel deleted branch build/291ada59 2026-09-06 02:28:13 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
ZSDev/obsidian-connor!11
No description provided.