You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit a6828dc
Browse filesBrowse the repository at this point in the historyBrowse files
feat(engine-manager): publish installed engine CLIs on the user's PATH
When PAIR installs Ollama or LM Studio, add that engine's command-line
directory to the installing user's persistent PATH on that device, and give
back only what PAIR recorded when the engine or the application is removed.
Open a new terminal after either operation.
Local installs only. An install driven by a cluster peer deliberately skips
the PATH step, because rewriting the login shell of whoever is sitting at the
target node is not a paired peer's decision.
Ownership is recorded outside the engine directory and before the PATH is
touched, so a crash mid-update is retryable and an uninstall can delete
exactly what PAIR added. Existing entries, user-edited shell snippets, and
engines the user installed themselves are preserved. The record also notes
that PAIR ran the installer, which is what lets a reinstall re-adopt an engine
whose vendor owns its location: LM Studio writes ~/.lmstudio, so the path is
no evidence of who put it there. A record that exists but cannot be parsed
fails an uninstall rather than reporting a clean one.
Windows persists through HKCU\Environment; the other platforms append a
self-identifying block to the login shell's profiles. Both run under a
cross-process lock that covers the whole read-modify-write, bounded so a hung
peer times out instead of wedging the operation, and both publish through a
temporary file and an atomic rename. A profile rewrite re-checks the file's
fingerprint before renaming, so a concurrent editor's save is refused rather
than silently discarded.
The platform uninstallers release the entries before deleting the data
directory that holds the records, and keep that data when the release fails so
a reinstall can finish the cleanup.
Two changes are adaptations to this tree rather than part of the feature.
runCommand takes a variadic environment for install commands that declare
overrides, so the launch closure in lifecycle.go accepts and ignores it; a
launch carries its own environment separately. writeJSONAtomic keeps this
tree's unique temporary name and gains the file flush and directory flush that
the ownership records need, since a rename alone says nothing about bytes
reaching stable storage.
Signed-off-by: Chris Kelsey <ckelsey@nvidia.com>
; The release failed, so the ownership records are the only thing that can still
112
+
; identify the entries it left behind. Deleting the data root would strand them
113
+
; permanently — the outcome the whole ordering above exists to avoid — so the
114
+
; data stays and the user is told why. A reinstall retries the cleanup.
115
+
!macro pairWarnPathEntriesRemain
116
+
DetailPrint"Could not release every engine PATH entry; keeping user data so a reinstall can retry."
117
+
MessageBoxMB_OK|MB_ICONEXCLAMATION"Personal AI Router could not remove every engine entry from your PATH.$\n$\nYour data has been kept so that reinstalling can finish the cleanup. If you delete it by hand, remove those PATH entries yourself as well — nothing else will be able to identify them." /SD IDOK
118
+
!macroend
119
+
81
120
; Best-effort: when the user opts to remove data, stop any process whose
82
121
; executable lives UNDER one of the data roots (e.g. an engine like Ollama
83
122
; running from %LOCALAPPDATA%\Nvidia Corporation\Personal AI Router\engine-bin\)
|`run`| string[]| no | Argv to execute after download (e.g. run the installer, extract the archive). Placeholders resolved; OS env refs expanded. Requires a `fetch` (the artifact it unpacks). |
145
145
|`script`| string[]| no |**Escape hatch** for vendors that only ship a script installer. Runs **without** checksum verification (logged as unpinned) and replaces `fetch`+`run`. Prefer `fetch`+`run` whenever the vendor publishes a script or artifact: download it first, then execute the local file. **Make failures loud:** a piped bootstrap such as `curl … \| bash` can mask a failed fetch, while a separate fetch prevents the run and reports the error. |
146
146
|`mode`| string | no |`"user"` (default) or `"admin"`. The runner **refuses**`"admin"` (engine-manager is user-mode only); it is a deliberate, flagged exception, not a default. |
147
+
|`env`| object | no | Literal `KEY: "value"` overrides layered onto the inherited environment of the **installer subprocess only** — not this service's environment and not the engine's runtime (that is `runtime.env`). Values are used verbatim: no placeholders, no OS env expansion. |
148
+
149
+
`install.env` exists so a vendor quirk stays in the manifest. LM Studio's
150
+
installer edits the user's PATH unless `LMS_NO_MODIFY_PATH=1` is set, and PAIR
151
+
publishes that directory itself with an ownership record it can later remove —
152
+
two writers, one removable. Declaring it keeps the runner engine-agnostic, so a
153
+
third-party engine with the same quirk needs no Go change:
0 commit comments