Commit Graph

27 Commits

Author SHA1 Message Date
Mason Daugherty 9a5bbeb755 fix(code): harden installer downloads and paths (#4871)
The install script now respects the configured uv tool binary directory,
retries transient downloads, and avoids unsafe fallback files and broad
ownership changes. Existing installations that are current but shadowed
on `PATH` are reinstalled into the uv tool directory instead of being
incorrectly treated as up to date.

---

The installer previously assumed uv placed executables in
`~/.local/bin`, so custom uv configuration could make version detection,
verification, `PATH` setup, and ownership repair target the wrong files.
A single transient PyPI or uv bootstrap failure also immediately fell
back or failed, and predictable `/tmp` fallbacks were used when `mktemp`
was unavailable.

This resolves the tool bin through `uv tool dir --bin` with legacy
fallbacks, compares executable paths by inode, preserves existing
regular files when adding links, retries downloads three times, and
fails closed for required temporary files. Root and MDM installs avoid
running pre-existing user executables and narrow ownership changes to
paths created by the installer.

Regression tests cover custom and legacy uv bin locations, shadowed
installs, root execution, retries, and secure temporary-file failures.
2026-07-21 11:22:59 -04:00
Mason Daugherty aad530c099 chore(code): compare installs by inode in shadowing check (#4577)
The installer no longer prints a spurious "shadowing install" warning
when `~/.local/bin` appears on `PATH` under a non-normalized alias (such
as `~/.local/share/../bin`) that resolves to the same directory.

---

The `deepagents-code` installer printed a spurious "shadowing install"
warning on every run for users whose `PATH` contains a non-normalized
alias of `~/.local/bin` — most commonly `~/.local/share/../bin`, where
`share/..` collapses back to `.local`. Some third-party tools write that
un-normalized spelling into a shell profile (derived from
`$XDG_DATA_HOME/../bin`), and it can sort before the canonical entry.
Both spellings resolve to the same uv-tool symlink the installer just
created, but `detect_shadowing_install` compared `PATH` strings, so the
alias looked like a separate, older install.

The primary fix makes the guard compare by inode using bash's `-ef` test
(same device+inode, resolves `..` and symlinks) in addition to the
existing string equality, so same-file aliases short-circuit and never
warn. Both operands are guaranteed to exist at that point, and a
genuinely different binary at a distinct inode still fails `-ef` and
correctly warns, so only the false positive is suppressed. Secondarily,
`local_bin_in_profile` now also recognizes the `~/.local/share/../bin`
spelling so the installer doesn't append a duplicate `~/.local/bin` PATH
line; this covers the common alias only and isn't a full path
normalizer.

Made by [Open
SWE](https://openswe.vercel.app/agents/870c16ab-41c7-3eee-e0d1-55385367ec4f)

---------

Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>
2026-07-08 18:50:56 -04:00
Mason Daugherty cac389c344 chore(code): trim up-to-date installer output (#4576)
The installer's "already installed / up to date" message is now more
concise.

Before:
```
▸ deepagents-code 0.1.34 found — checking for updates...
✔ deepagents-code is already up to date.
```
After:
```
▸ dcode 0.1.34 found — checking for updates...
✔ Already up to date!
```

Made by [Open
SWE](https://openswe.vercel.app/agents/6b29a6dc-fc2b-12bc-52d1-98a3bed3785d)

Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>
2026-07-08 18:35:47 -04:00
Mason Daugherty f183c1b217 chore(code): install script enhancements (#4571)
**deepagents-code installer (`install.sh`):**
- Accepts a positional version: `curl -LsSf https://langch.in/dcode |
bash -s -- 0.1.0rc1`
- Uses a managed, rewriteable PATH block in shell profiles (`# >>>
deepagents-code installer >>>`)
- Warns when an existing `dcode`/`deepagents-code` on `PATH` shadows the
uv tool install
- Shows actionable hints for signal kills (e.g., OOM on Linux: exit 137)
- Serializes concurrent installs with a cross-process lock
(`flock`/`mkdir` fallback)
- Accepts `DEEPAGENTS_CODE_YES=true|yes|TRUE| YES ` for non-interactive
installs
- Propagates uv's real exit code on failure

---

### User-facing changes
- **Positional version argument**: `curl ... | bash -s -- 0.1.0rc1` now
works alongside the existing `DEEPAGENTS_CODE_VERSION` env var
- **Managed PATH block**: Shell profiles now get a delimited `# >>>
deepagents-code installer >>>` block that the installer owns and
rewrites in place (instead of appending loose lines)
- **Shadowing detection**: Warns when an older `dcode`/`deepagents-code`
binary earlier on `PATH` would be used instead of the newly installed uv
tool
- **Signal-aware failure hints**: Exit codes ≥128 now surface actionable
messages (e.g., exit 137 on Linux → "ran out of memory, free up memory
or use a larger machine")
- **Concurrent install safety**: A cross-process lock (`flock`
preferred, `mkdir` fallback with stale-lock reclamation) prevents racing
`curl | bash` runs from corrupting the shared uv tool directory

### Internal hardening
- `DEEPAGENTS_CODE_YES` now accepts truthy values (`true`, `TRUE`,
`yes`, ` YES `)
- Installer propagates uv's real exit code instead of flattening to `1`
- Early up-to-date exit no longer creates a lock directory
- macOS path avoids `lockf` (command-scoped, not fd-based)
2026-07-08 17:31:50 -04:00
Mason Daugherty bdd4f1e014 chore(code): add --help/--version flags and verify uv installer download (#4503)
The `dcode` install script now supports `--help`/`-h` and
`--version`/`-v` flags, and the uv installer download is verified before
execution to guard against non-shell responses from proxies or captive
portals.

## Release note

- `curl -LsSf https://langch.in/dcode | bash -s -- --help` now prints a
full usage reference (all environment variables, valid extras, and a
docs link) and exits 0 without touching the network. `--version`/`-v`
prints the installer version string and exits 0. Unknown flags (e.g. a
typo like `--verison`) are rejected with a non-zero exit and an
actionable message instead of silently proceeding to a full install.
- The uv bootstrap no longer pipes the downloader directly into `sh`. It
downloads the installer to a tempfile first, verifies the first line is
a shell shebang, and only then executes it. A 200 response containing
HTML from a transparent proxy or captive portal is caught and rejected
with a clear error before it can reach `sh`.
- On a failed download, the downloader's own stderr (curl DNS errors,
TLS failures, HTTP status) is now surfaced to the user alongside the
generic failure message, instead of being discarded.

## Changes

- Added a CLI-flag loop at the top of `install.sh` that handles
`--help`/`-h` (prints a `print_help` reference of all env vars and valid
extras), `--version`/`-v` (prints `INSTALLER_VERSION`), and rejects
unknown flags with exit code 2 — all before any install work begins.
- Rewrote `install_uv` to download the uv installer to a tempfile via
`curl -o` / `wget -O` (capturing the downloader's stderr) instead of
piping directly to `sh`. On download failure, the captured stderr is
printed before the generic error. On success, the script's first line is
checked for a shell shebang (`^#!.*(sh|bash)`) before execution; a
non-shell response exits with an actionable message.
- Updated the `media` extra in the env-var documentation within the help
text (was previously listed only as `quickjs` under standalone
integrations).
- Added unit tests covering: `--help`/`-h` output and early exit,
`--version`/`-v` output and early exit, unknown-flag rejection, shebang
verification rejection (HTML response), download-failure error
surfacing, and the wget download path with verbose output.
2026-07-04 21:29:56 -04:00
Mason Daugherty aa9ccc6201 chore(code): automatic PATH setup, snap-curl detection, and temp cleanup in install script (#4464)
The installer now actively fixes `dcode` PATH resolution instead of just
warning the user, detects snap-sandboxed `curl` that silently fails
downloads, and cleans up temp files on Ctrl-C without printing a
contradictory failure message.

## Changes
- **Automatic PATH setup** — `ensure_path_setup` symlinks the verified
binary into an existing PATH dir (`~/.local/bin`, `~/bin`, `~/.bin`); if
none are on PATH, creates `~/.local/bin`, symlinks there, and appends a
PATH export to the detected shell profile (`.zshrc`, `.bashrc`,
`.bash_profile`, `config.fish`). Prompts interactively before modifying
a profile, auto-adds in non-interactive mode, and skips entirely when
uv's `~/.local/bin/env` already handles PATH.
- **Snap `curl` detection** — `is_snap_curl` checks whether `curl` lives
under `/snap/`, in which case it has sandbox permission issues that
cause silent download failures. `install_uv` and the new
`download_to_stdout` helper fall back to `wget`, or emit a clear error
if no working downloader exists.
- **Interrupt-safe temp cleanup** — a `TEMP_FILES` registry
(`register_temp` / `cleanup_temp_files`) tracks every `mktemp` so
they're removed on both normal exit and Ctrl-C. A dedicated
`cleanup_on_interrupt` handler for INT/TERM disarms the EXIT trap first,
so the user sees only "Installation interrupted." rather than that
followed by a contradictory "Installation failed (exit code 1)."
- **`download_to_stdout` helper** — consolidates the duplicated
curl-or-wget logic from `install_uv` and `fetch_latest_version` into one
function with snap detection built in.
2026-07-03 02:30:02 -04:00
Mason Daugherty a52c18d3ef fix(code): quiet routine ripgrep installer output (#4417)
`dcode` install no longer prints routine ripgrep setup messages unless
verbose mode is enabled or ripgrep setup fails.

---

Routine ripgrep provisioning is an implementation detail of `dcode`
installation, so successful managed setup no longer adds extra status
lines to default installer output. Verbose installs and failure paths
still expose the setup command output for debugging.
2026-07-01 20:20:51 -04:00
Mason Daugherty e645adf7ec hotfix(code): avoid reinstalling existing uv (#4314)
The install script now resolves an existing `uv` before invoking the
upstream installer, including installs that are present in
`~/.local/bin` but hidden by a minimal MDM or cron PATH. Bad `UV_BIN`
values fail fast with a clear error instead of falling through to a
network install attempt.

## Changes
- Added `resolve_uv_bin` to check `UV_BIN`, PATH, uv’s generated env
file, and `~/.local/bin/uv` before installing uv.
- Hardened env-file sourcing so stale or hand-written `~/.local/bin/env`
files with non-zero commands do not abort the installer.
- Tightened `UV_BIN` path validation so directories are rejected before
`uv tool install` runs.
- Added installer regression coverage for minimal-PATH uv detection,
defensive env-file sourcing, and invalid `UV_BIN` values.
2026-06-26 03:18:52 -04:00
Mason Daugherty 09ad92f637 hotfix(code): allow prerelease dependencies in installer (#4308)
Follow-up to fd0b17deb0, which changed the
installer to use `--prerelease if-necessary` but still allowed uv to
resolve `deepagents-code==0.1.22` instead of the latest release that
pins `deepagents==0.7.0a2`.

`if-necessary` is not enough here because uv can satisfy the top-level
`deepagents-code` requirement with an older stable candidate. The
installer now defaults to `--prerelease allow`, which lets the latest
stable `deepagents-code` release resolve even when it depends on a
prerelease SDK.
2026-06-26 02:23:19 -04:00
Mason Daugherty fd0b17deb0 hotfix(code): use if-necessary for installer prerelease resolution (#4306)
Stable `deepagents-code` releases can temporarily depend on pre-release
packages, which made the default installer path fail when uv refused
pre-release resolution. The installer now applies uv's `if-necessary`
strategy for unpinned installs while keeping exact version pins mutually
exclusive with explicitly requested pre-release settings.

## Changes

- Default unpinned installs to `--prerelease if-necessary`, but avoid
forwarding that default when `DEEPAGENTS_CODE_VERSION` selects an exact
package version.
- Keep the mutual-exclusion error for explicit
`DEEPAGENTS_CODE_PRERELEASE` plus `DEEPAGENTS_CODE_VERSION`, preserving
pinned install behavior.
- Filter uv download/build progress and newer timing summary variants
from non-verbose output while preserving them under
`DEEPAGENTS_CODE_VERBOSE=1`.
- Shorten the managed ripgrep setup message so the installer no longer
advertises the opt-out path during the normal setup flow.
2026-06-26 02:15:49 -04:00
Mason Daugherty cf536f3399 fix(code): eager managed ripgrep install via dcode tools install (#4199)
`dcode tools install` provisions the managed ripgrep binary; the install
script now sets it up by default (opt out with
`DEEPAGENTS_CODE_RIPGREP_INSTALLER=system` or
`DEEPAGENTS_CODE_OFFLINE=1`).

---

Today the pinned, SHA-256-verified ripgrep binary only lands on first
run (via `managed_tools.ensure_ripgrep`), so a fresh user pays a
one-time download the first time they launch. This makes the install
script provision it eagerly so `rg` is ready immediately, without
reaching for `sudo` package managers by default.

Rather than re-encoding the pinned version + checksum table in bash
(drift risk), a new `dcode tools install` verb reuses the existing
managed-install code, and `scripts/install.sh` invokes the freshly
installed binary. The verb is also handy on its own to repair a missing
or stale `rg`.

Power users can keep their own toolchain with
`DEEPAGENTS_CODE_RIPGREP_INSTALLER=system`, which preserves the existing
brew/apt/cargo path in the install script and skips the managed download
at runtime. A system `rg` already on `PATH` is reused under either
setting, and `DEEPAGENTS_CODE_OFFLINE` / `DEEPAGENTS_CODE_SKIP_OPTIONAL`
continue to apply. The default eager install is announced and honors
those opt-outs, per the package's "default shell-outs must announce +
offer a documented opt-out" rule.

---------

Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>
2026-06-25 01:28:38 -04:00
Mason Daugherty 5d080df277 fix(code): drop redundant version from "already up to date" message (#4223)
The `libs/code` install script already prints the version on the
preceding `deepagents-code <ver> found — checking for updates...` line,
so repeating it on the `is already up to date` status line is redundant.
Simplified both the `log_info` (rebuild-with-extras) and `log_success`
(no-op exit) lines to `deepagents-code is already up to date`.

Made by [Open
SWE](https://openswe.vercel.app/agents/deff72b5-ac91-9dff-439e-934b65a8e99f)

Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>
2026-06-24 16:43:21 -04:00
Mason Daugherty 785c8d0061 fix(code): quiet uv installer output and require Xcode CLT on macOS (#4180)
The install script now hides the uv installer's output by default and
exits early on macOS when Xcode Command Line Tools are not installed.

---

The uv installer's verbose download/PATH output cluttered a fresh
`dcode` install; it's now hidden by default and shown only with
`DEEPAGENTS_CODE_VERBOSE=1` or on failure. On macOS, the installer now
fails fast with an actionable message when the Xcode Command Line Tools
are missing, instead of letting a downstream tool (uv interpreter
discovery / git) trigger the blocking macOS "install developer tools"
GUI popup mid-install.

## Test Plan
- [ ] On a fresh macOS without CLT, run the installer and confirm it
exits with the `xcode-select --install` message instead of showing the
GUI popup.
- [ ] On a machine without uv, run the installer and confirm the uv
installer's output is hidden unless `DEEPAGENTS_CODE_VERBOSE=1`.

Made by [Open
SWE](https://openswe.vercel.app/agents/c4c6c178-52dd-957a-68b7-dcba7f3223e0)

---------

Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>
2026-06-23 21:17:50 -04:00
Mason Daugherty 156e118524 fix(code): report same-version dependency updates (#4146)
The installer now distinguishes a true no-op reinstall from a
same-version reinstall that still moves transitive packages. When `uv`
reports dependency changes, the final status and footer say dependencies
were updated, and the raw install output is saved so users can inspect
the full details after abbreviated terminal output.
2026-06-22 17:34:04 -04:00
Mason Daugherty de2c9fd8c7 feat(code): quiet install script's full dependency list (#4058)
The `dcode` install script printed every transitive dependency (~130
lines) on a fresh install, which is noise for the common `curl | bash`
path. The full list only ever appeared on fresh installs, since uv's
diff reports every package as newly added.

Now a fresh install suppresses the per-package list entirely — the user
still sees the `Installing…` line and the final `✔ deepagents-code
<version> installed.` / `Setup complete.` confirmation, just not the
wall of transitive dependencies. The full list stays available behind
the existing `DEEPAGENTS_CODE_VERBOSE=1` env var.

Upgrades are unaffected: they still show the compact changed-package
diff under `Updated packages:` (`→` for version bumps, `(new)` for added
packages, `(removed)` for dropped ones), which is small and genuinely
useful.

The two cases are told apart by whether uv's diff contains any removals:
a fresh install — or a pure-addition re-run, e.g. adding an extra to an
existing env — has only added rows and is suppressed, while an upgrade
mixes removed/added rows and is printed.

Made by [Open
SWE](https://openswe.vercel.app/agents/b1a5995a-8994-73b4-9bc3-05755afa197e)

---------

Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>
2026-06-17 15:32:54 -04:00
Mason Daugherty 619207c8d4 feat(code): prompt to install provider when selecting an uninstalled model (#3981)
The `/model` picker now lists recommended models from uninstalled
providers and offers to install the provider automatically when you
select one.

---

The `/model` selector only listed models from already-installed
providers, so common OSS providers (e.g. `baseten`) were invisible until
the user manually ran `/install`. This surfaces recommended models from
not-yet-installed providers in the selector and, when one is picked,
opens a confirmation modal that installs the provider's extra (reusing
the existing `/install` flow + restart offer) before switching to the
model. Installed models always rank above install-required ones in
search so the common case is never displaced.

Made by [Open SWE](https://openswe.vercel.app)

---------

Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>
2026-06-16 23:52:08 -04:00
Mason Daugherty a5ec6dd0fe feat(code): prompt before updating an out-of-date dcode install (#3995)
The `deepagents-code` install script now prompts before updating an
out-of-date install in interactive shells (and skips work when already
up to date); set `DEEPAGENTS_CODE_YES=1` to auto-accept.

---

The `deepagents-code` installer (`scripts/install.sh`) ran `uv tool
install -U` unconditionally, silently pulling the latest version on
every run. It now probes PyPI for the latest release so it can be
deliberate about updates: it exits early when already up to date, and
for an existing default-path install it prompts before upgrading in an
interactive shell. Piped/non-interactive runs with no usable TTY still
upgrade automatically (preserving prior behavior), and
`DEEPAGENTS_CODE_YES=1` accepts the update without prompting. Pinned
versions (`DEEPAGENTS_CODE_VERSION`) and pre-release strategies
(`DEEPAGENTS_CODE_PRERELEASE`) express explicit intent and install
directly without a prompt.

A `can_prompt` helper verifies `/dev/tty` is actually openable, since
`IS_INTERACTIVE` only access-checks it and can be wrong under
cron/systemd/CI.

Made by [Open SWE](https://openswe.vercel.app)

---------

Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>
2026-06-15 19:10:43 -04:00
Mason Daugherty c99cc47f79 docs(code): list valid DEEPAGENTS_CODE_EXTRAS options in install.sh (#3975)
The install script documented the `DEEPAGENTS_CODE_EXTRAS` environment
variable but only pointed readers to `pyproject.toml` for valid values.
This enumerates the available extras directly in the header comment —
grouped into model providers, sandbox providers, and standalone
integrations — so users can discover supported options without leaving
the script. The authoritative list still lives in `pyproject.toml`,
which the comment notes.

Made by [Open SWE](https://openswe.vercel.app)

Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>
2026-06-15 10:26:03 -04:00
Mason Daugherty d1c6946218 chore(code): support pinned and pre-release installs (#3945)
The `dcode` install script can now install exact `deepagents-code`
versions or ask `uv` to resolve pre-release versions using an explicit
strategy. Invalid version pins, invalid pre-release strategies, and
conflicting version/pre-release settings fail before invoking `uv` so
the installer does not forward ambiguous or unsafe arguments.
2026-06-13 02:58:27 -04:00
Mason Daugherty 727d022cd1 fix(code): allow recovery commands when startup fails (#3706)
When a configured model's provider package can't be imported, the model
is built *before* the LangGraph server starts, so construction fails and
the app holds a `_server_startup_error` state that parks queued slash
commands until a successful start drains them. `/install` — the command
that installs the missing package — is `QUEUED`, so it was trapped
behind the very failure it repairs: typing `/install <pkg>` appeared to
hang because it never ran. `/model` and `/auth` already escaped this
wedge via `IMMEDIATE_UI`, but the package-recovery path did not.
2026-06-02 14:16:46 -04:00
Mason Daugherty 61f7753b8d style(code): quiet install script output by default (#3605)
Trim the `curl … | bash` install output to the lines users actually
need. The full `dcode -v` dump, the "Checking optional tools" header,
and the multi-line docs footer were noisy on every run — particularly on
the common already-up-to-date path. Verbose behavior is preserved behind
`DEEPAGENTS_CODE_VERBOSE=1`.
2026-05-26 16:43:31 -04:00
Mason Daugherty af9d04a9a8 chore(code): namespace install-script env vars under DEEPAGENTS_CODE_* (#3604)
The install-script env vars (`DEEPAGENTS_EXTRAS`, `DEEPAGENTS_PYTHON`,
`DEEPAGENTS_SKIP_OPTIONAL`) didn't signal that they only configured the
`deepagents-code` installer, conflicting with the per-package prefix the
rest of the ecosystem already uses (`DEEPAGENTS_CLI_*`, etc.). Renames
them under a `DEEPAGENTS_CODE_*` namespace and adds one new flag for
debugging the install output.
2026-05-26 16:13:32 -04:00
Mason Daugherty 475f470c01 style(code): tighten install-script output (#3603)
The `curl … | bash` install flow currently dumps every line uv prints —
timing, prep counts, an unformatted `- pkg==X` / `+ pkg==Y` diff — and
always logs `deepagents-code installed.` even when nothing changed.
Re-frames the output so the user immediately sees what changed and what
actually happened.
2026-05-26 16:03:39 -04:00
Mason Daugherty 5e4306feed feat(code): clarify install-script messaging for editable installs (#3600)
The `curl … | bash` install for `deepagents-code` now tells users
plainly when it's about to replace an existing editable install or
rebuild the venv, instead of leaking uv's internal warning verbatim.
Motivated by a confusing run where a previous `uv tool install -e …`
install made uv print `Ignoring existing environment for
`deepagents-code`: the requested Python interpreter does not match the
environment interpreter` — accurate, but unhelpful to non-technical
readers.
2026-05-26 15:04:06 -04:00
Mason Daugherty f8977a6376 fix(code): install script binary checks reference dcode (#3546)
The bundled install script probed for a `deepagents` binary that the
`deepagents-code` package never installs (its entry points are `dcode`
and `deepagents-code`), so the pre-install upgrade detection and
post-install verification were effectively no-ops on a real install.
2026-05-22 15:45:12 +00:00
Mason Daugherty b0e8d83f97 fix(code): correct LangSmith sandbox working directory (#3415)
The `deepagents-code` package still referenced `deepagents/cli` in its
documentation URLs and had an incorrect working directory for the
`langsmith` sandbox backend. Both issues are corrected across the
package and its tests.
2026-05-15 17:06:15 -07:00
Mason Daugherty 2ac7d41533 feat(code): port from libs/cli (#3388)
Release-As: 0.1.0
2026-05-12 20:45:09 +00:00