Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions INSTALL.md
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,21 @@ A checkout has no Rust PTY host until one is put in `bin/`: on a release tag,
`cargo build --release --manifest-path crates/pty-sidecar/Cargo.toml` builds one. Without either,
terminals run on Node 18+ where the PC has it, and are mirrored where it has none.

On Linux and macOS, a service manager may start with a smaller `PATH` than an interactive shell.
Use the existing launcher so Bun, Node and agents installed in `~/.local/bin` are discoverable.
For example, a systemd unit's `[Service]` section can use:

```ini
WorkingDirectory=/absolute/path/to/ovis
ExecStart=/bin/sh /absolute/path/to/ovis/scripts/with-bun.sh run start
```

Run the service as the user who installed the agents, with that user's `HOME`. The launcher adds
the usual user-local directories after the existing `PATH`, preserving its command choices.
If an installed agent such as Grok is missing from the new-session picker, check the service's
`PATH`: the picker hides agents the server cannot find. Restart the web UI after changing the
service configuration.

## 4. Verify

```bash
Expand Down
3 changes: 3 additions & 0 deletions changelog.d/source-service-agent-path.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
### Maintenance
- Document the existing launcher for source installs under a service manager, so a restricted
`PATH` does not hide user-local agents such as Grok from the new-session picker.
21 changes: 21 additions & 0 deletions scripts/with-bun.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,27 @@ describe.skipIf(process.platform === "win32")("Unix Bun discovery", () => {
expect(result.out.trim()).toBe("1.4.3");
});

it("lets the launched Bun discover Grok in ~/.local/bin with a service's bare PATH", async () => {
const bin = join(home, ".bun", "bin");
mkdirSync(bin, { recursive: true });
symlinkSync(process.execPath, join(bin, "bun"));
tool(join(home, ".local", "bin"), "grok", "fixture");
const result = await run(["/bin/sh", script, "-e", 'console.log(Bun.which("grok"))']);
expect(result.code).toBe(0);
expect(result.out.trim()).toBe(join(home, ".local", "bin", "grok"));
});

it("keeps a Grok already on PATH ahead of the user-local fallback", async () => {
const bin = join(home, ".bun", "bin");
mkdirSync(bin, { recursive: true });
symlinkSync(process.execPath, join(bin, "bun"));
tool(tools, "grok", "chosen");
tool(join(home, ".local", "bin"), "grok", "fallback");
const result = await run(["/bin/sh", script, "-e", 'console.log(Bun.which("grok"))']);
expect(result.code).toBe(0);
expect(result.out.trim()).toBe(join(tools, "grok"));
});

it("exits 127 when Bun is missing from PATH and the configured locations", async () => {
const result = await run(["/bin/sh", script, "x"], { WITH_BUN_EXTRA_DIRS: join(home, "missing") });
expect(result.code).toBe(127);
Expand Down
Loading