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.
This commit is contained in:
Mason Daugherty
2026-06-22 17:34:04 -04:00
committed by GitHub
parent 7574fea88b
commit 156e118524
3 changed files with 486 additions and 5 deletions
+135 -4
View File
@@ -241,6 +241,71 @@ can_prompt() {
{ : < /dev/tty; } 2>/dev/null
}
path_is_under_home() {
local path="$1"
local home_real=""
local path_real=""
[ -n "${HOME:-}" ] || return 1
[ -d "$path" ] || return 1
home_real=$(cd "$HOME" 2>/dev/null && pwd -P) || return 1
path_real=$(cd "$path" 2>/dev/null && pwd -P) || return 1
case "$path_real" in
"$home_real"/*) return 0 ;;
*) return 1 ;;
esac
}
prepare_install_log_dir() {
local cache_root="$1"
local dir="${cache_root}/deepagents-code"
[ -n "$cache_root" ] || return 1
[ ! -L "$cache_root" ] || return 1
[ ! -L "$dir" ] || return 1
if [ ! -d "$cache_root" ]; then
mkdir -m 700 -p "$cache_root" 2>/dev/null || return 1
fi
[ -d "$cache_root" ] && [ ! -L "$cache_root" ] || return 1
if [ -e "$dir" ]; then
[ -d "$dir" ] && [ ! -L "$dir" ] || return 1
else
mkdir -m 700 "$dir" 2>/dev/null || return 1
fi
if [ "$(id -u)" -eq 0 ]; then
path_is_under_home "$dir" || return 1
fi
printf '%s\n' "$dir"
}
fix_install_log_owner() {
[ -n "${INSTALL_LOG:-}" ] || return 0
[ "$(id -u)" -eq 0 ] || return 0
[ -n "${TARGET_USER:-}" ] && [ "$TARGET_USER" != "root" ] || return 0
[ -d "$install_log_dir" ] && [ ! -L "$install_log_dir" ] || return 0
path_is_under_home "$install_log_dir" || return 0
if ! chown -h "$TARGET_USER" "$install_log_dir" 2>&1; then
log_warn "Could not fix ownership of $install_log_dir for user ${TARGET_USER}."
fi
if [ -f "$INSTALL_LOG" ] && [ ! -L "$INSTALL_LOG" ]; then
if ! chown -h "$TARGET_USER" "$INSTALL_LOG" 2>&1; then
log_warn "Could not fix ownership of $INSTALL_LOG for user ${TARGET_USER}."
fi
fi
}
copy_install_log() {
[ -n "${INSTALL_LOG:-}" ] || return 1
[ -n "${install_log_dir:-}" ] || return 1
[ -d "$install_log_dir" ] && [ ! -L "$install_log_dir" ] || return 1
if [ "$(id -u)" -eq 0 ]; then
path_is_under_home "$install_log_dir" || return 1
fi
[ ! -L "$INSTALL_LOG" ] || return 1
rm -f "$INSTALL_LOG" 2>/dev/null || return 1
# Publish the already-captured stderr without opening the destination for
# writing. `ln` fails if an attacker wins the race by creating install.log.
ln "$uv_stderr" "$INSTALL_LOG" 2>/dev/null
}
# ---------------------------------------------------------------------------
# Config
# ---------------------------------------------------------------------------
@@ -488,10 +553,45 @@ fi
# a Verified line with the binary name and version.
# 3. Reformat the `- pkg==X` / `+ pkg==Y` diff into an aligned
# "pkg X → Y" table under a single header.
# 4. Detect whether uv actually moved any packages (those same
# `- pkg==X` / `+ pkg==Y` lines). A same-version reinstall that still
# bumps dependencies must report differently from a true no-op, so a
# later grep over this raw tempfile sets UV_REPORTED_PACKAGE_CHANGES.
# 5. Persist the raw output to a log file (see INSTALL_LOG below) so a
# same-version dependency bump — or a failed install — can point the
# user at the full details after the terminal scrolls away.
# Using a tempfile (vs. process substitution) ensures we see uv's full exit
# status and don't race the warning past later log lines.
# status, don't race the warning past later log lines, and can re-scan the
# raw output for (4) after the awk pass above has already reformatted it.
uv_stderr=$(mktemp 2>/dev/null) || uv_stderr="/tmp/deepagents-install.$$.err"
uv_rc=0
UV_REPORTED_PACKAGE_CHANGES=false
# Mirror uv's raw output to a persistent log under the XDG cache dir. A
# same-version dependency bump prints only a one-line summary and a failed
# install scrolls past, so the log preserves the full diff/errors for later.
# Prefer $XDG_CACHE_HOME, falling back to ~/.cache. INSTALL_LOG is the real
# path used for writes; INSTALL_LOG_DISPLAY is the tilde-collapsed form shown
# to the user. Both stay empty when the dir can't be created, which every
# consumer treats as "feature disabled" so messages degrade cleanly.
INSTALL_LOG=""
INSTALL_LOG_DISPLAY=""
cache_root="${XDG_CACHE_HOME:-}"
if [ "$(id -u)" -eq 0 ] && [ -n "${HOME:-}" ]; then
cache_root="${HOME}/.cache"
elif [ -z "$cache_root" ] && [ -n "${HOME:-}" ]; then
cache_root="${HOME}/.cache"
fi
if [ -n "$cache_root" ]; then
if install_log_dir=$(prepare_install_log_dir "$cache_root"); then
INSTALL_LOG="${install_log_dir}/install.log"
INSTALL_LOG_DISPLAY="$INSTALL_LOG"
if [ -n "${HOME:-}" ]; then
case "$INSTALL_LOG" in
"$HOME"/*) INSTALL_LOG_DISPLAY="~${INSTALL_LOG#"$HOME"}" ;;
esac
fi
fi
fi
if [[ -n "$PRERELEASE" ]]; then
"$UV_BIN" tool install -U --python "$PYTHON_VERSION" \
--prerelease "$PRERELEASE" "$PACKAGE" 2>"$uv_stderr" || uv_rc=$?
@@ -570,9 +670,21 @@ if [ "$VERBOSE" != "1" ] && command -v awk >/dev/null 2>&1; then
else
cat "$uv_stderr" >&2
fi
if grep -Eq '^[[:space:]]+[-+][[:space:]]+[^=]+==' "$uv_stderr"; then
UV_REPORTED_PACKAGE_CHANGES=true
fi
if [ -n "$INSTALL_LOG" ]; then
copy_install_log || { INSTALL_LOG=""; INSTALL_LOG_DISPLAY=""; }
fi
rm -f "$uv_stderr"
if [ "$uv_rc" -ne 0 ]; then
log_error "Failed to install ${PACKAGE}. See errors above."
# The log captured uv's full stderr (copied just above, before this exit), so
# point the user at it — non-verbose mode trims uv's lines from the terminal
# and piped `curl | bash` runs lose scrollback.
if [ -n "$INSTALL_LOG" ]; then
log_error "Full install log: ${INSTALL_LOG_DISPLAY}"
fi
log_error "Common fixes: check your network, try a different Python version (DEEPAGENTS_CODE_PYTHON=3.12), or install manually."
exit 1
fi
@@ -582,6 +694,9 @@ if [ "$OS" = "macos" ] && [ -d "${HOME}/Library/Caches/uv" ]; then
elif [ -d "${HOME}/.cache/uv" ]; then
fix_owner "${HOME}/.cache/uv"
fi
# Restore ownership for the log path without recursively chowning a cache path
# that could have been swapped after creation.
fix_install_log_owner
# ---------------------------------------------------------------------------
# Post-install verification + contextual status
# ---------------------------------------------------------------------------
@@ -623,7 +738,19 @@ if [ "$IS_EDITABLE" = true ]; then
elif [ -z "$PRE_VERSION" ]; then
log_success "deepagents-code${NEW_VERSION:+ ${NEW_VERSION}} installed."
elif [ -n "$NEW_VERSION" ] && [ "$PRE_VERSION" = "$NEW_VERSION" ]; then
log_success "deepagents-code ${NEW_VERSION} already up to date."
# Same app version, but uv may have refreshed transitive deps (security or
# compat bumps). The final status line is the user-facing summary, so a flat
# "already up to date" would contradict the package diff printed just above
# (and, in non-verbose mode where an addition-only diff is suppressed, hide
# the dep move entirely). UV_REPORTED_PACKAGE_CHANGES (set far above) is the
# signal that the reinstall actually moved packages.
if [ "$UV_REPORTED_PACKAGE_CHANGES" = true ]; then
# INSTALL_LOG_DISPLAY is empty exactly when no log was written, so the
# `:+` suffix appends the pointer only when there's a log to point at.
log_success "deepagents-code ${NEW_VERSION} was already up to date; dependencies were updated.${INSTALL_LOG_DISPLAY:+ Details: ${INSTALL_LOG_DISPLAY}}"
else
log_success "deepagents-code ${NEW_VERSION} already up to date."
fi
elif [ -n "$NEW_VERSION" ]; then
log_success "deepagents-code updated: ${PRE_VERSION}${NEW_VERSION}."
else
@@ -783,11 +910,15 @@ if [ "$SKIP_OPTIONAL" != "1" ]; then
fi
# ---------------------------------------------------------------------------
# Done — footer wording depends on whether anything changed:
# - already up to date → "Already installed"
# Done — footer wording depends on what changed:
# - same app version + dependency changes → "Dependencies updated"
# - already up to date → "Already installed"
# - fresh install / upgrade / editable→PyPI swap → "Setup complete"
# ---------------------------------------------------------------------------
if [ "$IS_EDITABLE" = false ] && [ -n "$PRE_VERSION" ] && [ -n "$NEW_VERSION" ] \
&& [ "$PRE_VERSION" = "$NEW_VERSION" ] && [ "$UV_REPORTED_PACKAGE_CHANGES" = true ]; then
footer_msg="Dependencies updated."
elif [ "$IS_EDITABLE" = false ] && [ -n "$PRE_VERSION" ] && [ -n "$NEW_VERSION" ] \
&& [ "$PRE_VERSION" = "$NEW_VERSION" ]; then
footer_msg="Already installed."
else
@@ -63,7 +63,7 @@ if [ "${{1:-}}" = "tool" ] && [ "${{2:-}}" = "install" ]; then
if [ -n "${{FAKE_UV_INSTALL_STDERR:-}}" ]; then
printf '%s\n' "$FAKE_UV_INSTALL_STDERR" >&2
fi
exit 0
exit "${{FAKE_UV_INSTALL_RC:-0}}"
fi
printf 'unexpected uv args: %s\n' "$*" >&2
exit 1
@@ -112,6 +112,7 @@ def _env(
return {
**os.environ,
"HOME": str(home),
"XDG_CACHE_HOME": str(home / ".cache"),
"PATH": f"{bin_dir}{os.pathsep}{os.environ['PATH']}",
"UV_BIN": str(uv),
"DEEPAGENTS_CODE_SKIP_OPTIONAL": "1",
@@ -562,6 +563,15 @@ _REMOVAL_DIFF = (
" - deepagents-code==0.1.18\n + deepagents-code==0.1.19\n - dropped-dep==2.0.0"
)
_DEPENDENCY_UPDATE_DIFF = " - boto3==1.43.33\n + boto3==1.43.34"
# A pure-addition diff: uv pulled in a brand-new transitive dep without any
# version change to an existing package.
_DEPENDENCY_ADDITION_DIFF = " + brand-new-dep==1.0.0"
# uv ran but moved nothing — only timing/summary noise, no `± pkg==ver` lines.
_NO_PACKAGE_CHANGE_STDERR = "Resolved 5 packages in 12ms\nAudited 5 packages in 1ms"
def test_install_script_fresh_install_hides_packages(tmp_path: Path) -> None:
"""A fresh install hides every dependency touched by uv."""
@@ -608,6 +618,294 @@ def test_install_script_upgrade_still_shows_diff(tmp_path: Path) -> None:
assert "Installed 3 packages" not in proc.stderr
def test_install_script_same_version_with_dependency_updates_says_dependencies_updated(
tmp_path: Path,
) -> None:
"""Unchanged app version + a uv dependency diff reports the deps were updated.
The fake `dcode -v` reports the same version before and after install, so
`PRE_VERSION == NEW_VERSION` and the same-version branch fires; the `± pkg==`
diff in stderr must steer it away from the flat "already up to date" message.
Also verifies the raw uv diff is persisted to the cache install log and that
the success line points the user at it via the `Details:` suffix.
"""
proc, _ = _invoke(
tmp_path,
{"FAKE_UV_INSTALL_STDERR": _DEPENDENCY_UPDATE_DIFF},
installed_version="0.1.8",
latest_version="0.1.20",
)
assert proc.returncode == 0
assert (
"deepagents-code 0.1.8 was already up to date; dependencies were updated. "
"Details: ~/.cache/deepagents-code/install.log"
) in proc.stdout
assert "deepagents-code 0.1.8 already up to date" not in proc.stdout
assert (tmp_path / "home/.cache/deepagents-code/install.log").read_text() == (
f"{_DEPENDENCY_UPDATE_DIFF}\n"
)
assert "✔ Dependencies updated. Run: dcode" in proc.stdout
assert "✔ Already installed. Run: dcode" not in proc.stdout
def test_install_script_same_version_no_dependency_changes_says_up_to_date(
tmp_path: Path,
) -> None:
"""Unchanged app version + no uv package diff keeps the flat no-op message.
The negative mirror of the dependency-update test: when uv runs but moves
nothing (only timing/summary noise), the flag must stay false so the plain
"already up to date" message is emitted. Guards against the flag defaulting
on, the conditional inverting, or the grep matching uv's noise lines. The
log is still written (the no-op stderr) but the `Details:` suffix is
suppressed, since there's no dependency change worth pointing at.
"""
proc, _ = _invoke(
tmp_path,
{"FAKE_UV_INSTALL_STDERR": _NO_PACKAGE_CHANGE_STDERR},
installed_version="0.1.8",
latest_version="0.1.20",
)
assert proc.returncode == 0
assert "deepagents-code 0.1.8 already up to date." in proc.stdout
assert "dependencies were updated" not in proc.stdout
assert "Details: ~/.cache/deepagents-code/install.log" not in proc.stdout
assert (tmp_path / "home/.cache/deepagents-code/install.log").read_text() == (
f"{_NO_PACKAGE_CHANGE_STDERR}\n"
)
assert "✔ Already installed. Run: dcode" in proc.stdout
def test_install_script_same_version_with_new_dependency_says_dependencies_updated(
tmp_path: Path,
) -> None:
"""A pure-addition diff also counts as a dependency change.
A new transitive dep (a `+ pkg==` line with no matching `-`) trips the flag
just like an upgrade does, so the same-version branch reports the change
rather than a flat no-op. Pins this `+`-only semantics deliberately, and
verifies the addition-only diff is persisted to the install log.
"""
proc, _ = _invoke(
tmp_path,
{"FAKE_UV_INSTALL_STDERR": _DEPENDENCY_ADDITION_DIFF},
installed_version="0.1.8",
latest_version="0.1.20",
)
assert proc.returncode == 0
assert (
"deepagents-code 0.1.8 was already up to date; dependencies were updated. "
"Details: ~/.cache/deepagents-code/install.log"
) in proc.stdout
assert (tmp_path / "home/.cache/deepagents-code/install.log").read_text() == (
f"{_DEPENDENCY_ADDITION_DIFF}\n"
)
def test_install_script_dependency_update_without_writable_log_omits_details(
tmp_path: Path,
) -> None:
"""When the log dir can't be created, the message drops the `Details:` suffix.
Points `XDG_CACHE_HOME` under a regular file so `mkdir -p` fails, leaving
`INSTALL_LOG` empty. The dependency-update message must still fire, just
without a pointer to a log that was never written — guards against the
suffix being appended unconditionally.
"""
blocker = tmp_path / "blocker"
blocker.write_text("") # regular file; mkdir -p underneath must fail
proc, _ = _invoke(
tmp_path,
{
"FAKE_UV_INSTALL_STDERR": _DEPENDENCY_UPDATE_DIFF,
"XDG_CACHE_HOME": str(blocker / "cache"),
},
installed_version="0.1.8",
latest_version="0.1.20",
)
assert proc.returncode == 0
assert (
"deepagents-code 0.1.8 was already up to date; dependencies were updated."
in proc.stdout
)
assert "Details:" not in proc.stdout
assert not (blocker / "cache").exists()
def test_install_script_dependency_update_with_failed_log_copy_omits_details(
tmp_path: Path,
) -> None:
"""When log creation succeeds but copying fails, the message omits `Details:`."""
if hasattr(os, "geteuid") and os.geteuid() == 0:
pytest.skip("root can write through directory permissions")
cache = tmp_path / "cache"
install_log_dir = cache / "deepagents-code"
install_log_dir.mkdir(parents=True)
install_log_dir.chmod(0o500)
try:
proc, _ = _invoke(
tmp_path,
{
"FAKE_UV_INSTALL_STDERR": _DEPENDENCY_UPDATE_DIFF,
"XDG_CACHE_HOME": str(cache),
},
installed_version="0.1.8",
latest_version="0.1.20",
)
finally:
install_log_dir.chmod(0o700)
assert proc.returncode == 0
assert (
"deepagents-code 0.1.8 was already up to date; dependencies were updated."
in proc.stdout
)
assert "Details:" not in proc.stdout
assert not (install_log_dir / "install.log").exists()
def test_install_script_refuses_symlinked_log_dir(tmp_path: Path) -> None:
"""A pre-existing log-dir symlink disables the persistent install log."""
cache = tmp_path / "cache"
target = tmp_path / "target"
install_log_dir = cache / "deepagents-code"
cache.mkdir()
target.mkdir()
install_log_dir.symlink_to(target, target_is_directory=True)
proc, _ = _invoke(
tmp_path,
{
"FAKE_UV_INSTALL_STDERR": _DEPENDENCY_UPDATE_DIFF,
"XDG_CACHE_HOME": str(cache),
},
installed_version="0.1.8",
latest_version="0.1.20",
)
assert proc.returncode == 0
assert (
"deepagents-code 0.1.8 was already up to date; dependencies were updated."
in proc.stdout
)
assert "Details:" not in proc.stdout
assert not (target / "install.log").exists()
def test_install_script_refuses_symlinked_log_file(tmp_path: Path) -> None:
"""A pre-existing log-file symlink disables the persistent install log."""
cache = tmp_path / "cache"
install_log_dir = cache / "deepagents-code"
target = tmp_path / "target.log"
install_log_dir.mkdir(parents=True)
target.write_text("keep me\n")
(install_log_dir / "install.log").symlink_to(target)
proc, _ = _invoke(
tmp_path,
{
"FAKE_UV_INSTALL_STDERR": _DEPENDENCY_UPDATE_DIFF,
"XDG_CACHE_HOME": str(cache),
},
installed_version="0.1.8",
latest_version="0.1.20",
)
assert proc.returncode == 0
assert (
"deepagents-code 0.1.8 was already up to date; dependencies were updated."
in proc.stdout
)
assert "Details:" not in proc.stdout
assert target.read_text() == "keep me\n"
def test_install_script_unset_xdg_cache_home_falls_back_to_home_cache(
tmp_path: Path,
) -> None:
"""An empty `XDG_CACHE_HOME` falls back to `~/.cache` for the log path.
`_env` always sets `XDG_CACHE_HOME`, which would otherwise mask the
fallback branch — the primary path on machines (e.g. macOS) that don't
export it. Overriding it to empty exercises that branch directly.
"""
proc, _ = _invoke(
tmp_path,
{
"FAKE_UV_INSTALL_STDERR": _DEPENDENCY_UPDATE_DIFF,
"XDG_CACHE_HOME": "",
},
installed_version="0.1.8",
latest_version="0.1.20",
)
assert proc.returncode == 0
assert (
"deepagents-code 0.1.8 was already up to date; dependencies were updated. "
"Details: ~/.cache/deepagents-code/install.log"
) in proc.stdout
assert (tmp_path / "home/.cache/deepagents-code/install.log").read_text() == (
f"{_DEPENDENCY_UPDATE_DIFF}\n"
)
def test_install_script_log_path_outside_home_stays_absolute(tmp_path: Path) -> None:
"""A log path outside `$HOME` is shown verbatim, not tilde-collapsed.
The `~` collapse only fires for paths under `$HOME`; an `XDG_CACHE_HOME`
elsewhere must surface the absolute path in the `Details:` suffix.
"""
external = tmp_path / "external-cache"
proc, _ = _invoke(
tmp_path,
{
"FAKE_UV_INSTALL_STDERR": _DEPENDENCY_UPDATE_DIFF,
"XDG_CACHE_HOME": str(external),
},
installed_version="0.1.8",
latest_version="0.1.20",
)
assert proc.returncode == 0
expected_log = external / "deepagents-code" / "install.log"
assert f"Details: {expected_log}" in proc.stdout
assert "Details: ~/" not in proc.stdout
assert expected_log.read_text() == f"{_DEPENDENCY_UPDATE_DIFF}\n"
def test_install_script_failed_install_points_to_log(tmp_path: Path) -> None:
"""A failed `uv tool install` still writes the log and points the user at it.
The log is copied from uv's captured stderr before the failure exit, so the
error path can hand the user the full output — the case where a persistent
log matters most. Guards the `cp`-before-`exit` ordering.
"""
proc, _ = _invoke(
tmp_path,
{
"FAKE_UV_INSTALL_STDERR": _DEPENDENCY_UPDATE_DIFF,
"FAKE_UV_INSTALL_RC": "1",
},
installed_version="0.1.8",
latest_version="0.1.20",
)
assert proc.returncode != 0
assert "Failed to install" in proc.stderr
assert "Full install log: ~/.cache/deepagents-code/install.log" in proc.stderr
assert (tmp_path / "home/.cache/deepagents-code/install.log").read_text() == (
f"{_DEPENDENCY_UPDATE_DIFF}\n"
)
def test_install_script_upgrade_marks_removed_packages(tmp_path: Path) -> None:
"""An upgrade that drops a transitive dependency labels it `(removed)`."""
proc, _ = _invoke(
+52
View File
@@ -439,6 +439,56 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/9d/2a/9186535ce58db529927f6cf5990a849aa9e052eea3e2cfefe20b9e1802da/bracex-2.6-py3-none-any.whl", hash = "sha256:0b0049264e7340b3ec782b5cb99beb325f36c3782a32e36e876452fd49a09952", size = 11508, upload-time = "2025-06-22T19:12:29.781Z" },
]
[[package]]
name = "bsdiff4"
version = "1.2.6"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/53/b9/4559ede9a4c8c4451688303544da84654643fdc7f28790aca85be80b4b7c/bsdiff4-1.2.6.tar.gz", hash = "sha256:2ab57d01a78b39e29e5accc9cfead4130982ded9dccbc4261bd0e9c51d6b751d", size = 13259, upload-time = "2025-02-19T17:42:33.612Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/10/08/6472d5c2527688b16ad2c2dd09e324281f5e78eea5e4dba5f65a7949f39c/bsdiff4-1.2.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b151c28098b3c522b1735cdfe5e84e8f164f0ef4a592adb227d7a10727034673", size = 16212, upload-time = "2025-02-19T17:39:53.399Z" },
{ url = "https://files.pythonhosted.org/packages/33/41/4d1fa5980c01faa0d5c578e41ce73b4df98cd74e33f92323880df0da035e/bsdiff4-1.2.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:29def064f6bcd13d0d7a82e5caa4848158b7f49c3a8fe44fbef3031456fb7dd2", size = 16031, upload-time = "2025-02-19T17:39:54.481Z" },
{ url = "https://files.pythonhosted.org/packages/9e/41/188f858a71eb529145b6706f8ac618fd9f719807f46e0cebe2ea482bfe78/bsdiff4-1.2.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e6f4cf8e00116e14e9e6c3fb5747478022a27215a9a65ed223fed82d2cfbc4d3", size = 33763, upload-time = "2025-02-19T17:39:55.438Z" },
{ url = "https://files.pythonhosted.org/packages/27/ea/84cc364a0c0f6eb3e503bf1625aa62eb411aa7474d1c91ec201812295fcb/bsdiff4-1.2.6-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:897a260d30acc4df9803f500682eb7951fdc104a3e155787e1e581258f38df50", size = 35705, upload-time = "2025-02-19T17:39:56.601Z" },
{ url = "https://files.pythonhosted.org/packages/fe/54/c235fd3e95aa3a4ac53de83605723a149a33eb11aff64e49488132b857f8/bsdiff4-1.2.6-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d994ee6113c3f030bb9f373e917f00db13c026c295fe9f314f23171935d88371", size = 33807, upload-time = "2025-02-19T17:39:57.601Z" },
{ url = "https://files.pythonhosted.org/packages/d2/8b/010d14d3ab321c1c35fc4145b020c1e76ed8a29a214ce6bcc093ddedee13/bsdiff4-1.2.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba5028a2aaa8e4cacb224031af9140e05d9c407ba15b59471380badcc4845777", size = 33250, upload-time = "2025-02-19T17:39:58.552Z" },
{ url = "https://files.pythonhosted.org/packages/2c/91/ae41950f7b823e8061520f3b28d47534b47f314b4148690c4a002d764bd7/bsdiff4-1.2.6-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1edd3069dc14cecaa804faaae776a5d14f85217c41b3180b794e5fbf684d35dd", size = 35919, upload-time = "2025-02-19T17:40:00.052Z" },
{ url = "https://files.pythonhosted.org/packages/6c/b4/f29c451e7718d4366a72f9a87a7f3cc76cb56cb5e9305eae087eab83f7a0/bsdiff4-1.2.6-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0fb562e451d5b3a7523c67ce04fe541d3a004914e5760a47116883972f5ff8bc", size = 33740, upload-time = "2025-02-19T17:40:01.893Z" },
{ url = "https://files.pythonhosted.org/packages/3a/73/004b3c4511df3df0d5e591ecd7aaf92c851b22be200283428d3577f4400b/bsdiff4-1.2.6-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:b7309380d8edbd3d46c4ed3930f7062b793bac8f004b32139db7af7c4612e241", size = 37325, upload-time = "2025-02-19T17:40:02.911Z" },
{ url = "https://files.pythonhosted.org/packages/d9/ea/5fa1d331c4a2e73e4e90a851768749a9960cefcb443da3abaae69e891f06/bsdiff4-1.2.6-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f2f7504f08181227717fee04f25169d5901322c29d3fd054e4cb61bd60b3ffb4", size = 35791, upload-time = "2025-02-19T17:40:03.866Z" },
{ url = "https://files.pythonhosted.org/packages/10/04/7616e8abec54562c86742c7bacaaba53c0c4733565ea00e8c5ffe2c5c9ce/bsdiff4-1.2.6-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:6ad599216e7ee3db5737951d06c43b8e65d5b0db5c42300e85f18d399ec0bc5e", size = 35413, upload-time = "2025-02-19T17:40:05.692Z" },
{ url = "https://files.pythonhosted.org/packages/c6/d6/3fff18a97e127cc783e02de3c934bca63fabc0d4a379e091973b006cbae6/bsdiff4-1.2.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:cd133a9475c9dfba6243dd07f118ee58a0b7f136c00d316e2d92d3f82169bd9e", size = 32939, upload-time = "2025-02-19T17:40:06.639Z" },
{ url = "https://files.pythonhosted.org/packages/36/32/2943637e17eca717cdd091625d4198cf7a49dd7d235944a86f1a8a6134fe/bsdiff4-1.2.6-cp311-cp311-win32.whl", hash = "sha256:403e8cc003451a8c4672c345a50aee3cf89d20983701e38fbbb67e07cb808c57", size = 18257, upload-time = "2025-02-19T17:40:07.59Z" },
{ url = "https://files.pythonhosted.org/packages/b1/f8/83f087ab62bebde26956f084ab272e19d11db5df6700f4f48d29647235fd/bsdiff4-1.2.6-cp311-cp311-win_amd64.whl", hash = "sha256:164a059e1e07932f91d90471a4ef4dac749f2dee780f08501522805398b32ed8", size = 19530, upload-time = "2025-02-19T17:40:08.504Z" },
{ url = "https://files.pythonhosted.org/packages/9a/58/044dd110fb0a0160f5cacecbfb9904043c8179f8c14093e22b6d8c6b9391/bsdiff4-1.2.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:69c5052e94ad991c397b5a46f8eab42f2e256c42aa5677896b7a3ea9e3d06adc", size = 16267, upload-time = "2025-02-19T17:40:10.376Z" },
{ url = "https://files.pythonhosted.org/packages/37/a1/70b74154344486bac9bf438ec309ae502f07df8cd7ca713d58f658769ff4/bsdiff4-1.2.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:223ae0fc9f386dcf919a09a2029c391a0f0afaf4a5892b9a6e1b622bf42e1ae5", size = 16090, upload-time = "2025-02-19T17:40:11.334Z" },
{ url = "https://files.pythonhosted.org/packages/1a/90/36531261d8a150fcb8193fe2ad46d939b8a91549976424852f6a2a335689/bsdiff4-1.2.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:48ea2298a281068d82b78454ee58ac7306ed38c9af55afddb04cf796df932d63", size = 33675, upload-time = "2025-02-19T17:40:13.218Z" },
{ url = "https://files.pythonhosted.org/packages/4a/97/8b73b3684c63e88508ad308229f33a8a5be6c4762e4160f96e2a6fc46906/bsdiff4-1.2.6-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2534e286ef5ae58767b9b17be64742424ca1e52ec748b0d8f8e24eecd12bc28a", size = 35648, upload-time = "2025-02-19T17:40:14.296Z" },
{ url = "https://files.pythonhosted.org/packages/52/39/0b1dd6494c743fa2c62bd7c35f5dec9f5802d01c1da1ef75a2e20a481ed4/bsdiff4-1.2.6-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4ff079b0f4cf874af4b6816983557b6b9d45996f88736046653e2d2311fa1876", size = 33772, upload-time = "2025-02-19T17:40:15.341Z" },
{ url = "https://files.pythonhosted.org/packages/88/23/98fc7482f957602c611203a9e485b9dbf4caf9d918e92453e3729cf5f0b4/bsdiff4-1.2.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56c2728c96d1d4eb8e089e4797c018a56be3f905f440fb507773f44c567fcd38", size = 33238, upload-time = "2025-02-19T17:40:16.343Z" },
{ url = "https://files.pythonhosted.org/packages/75/04/c3db957b7a324a3f25f721a82c288e9abe60059a0a2d2f9b3c19fb49cdb2/bsdiff4-1.2.6-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9deb9b3cdb4d327e43b8c7bd11ed3707587f1183b35fb8a4c06c4f34bce62c6a", size = 35889, upload-time = "2025-02-19T17:40:18.237Z" },
{ url = "https://files.pythonhosted.org/packages/c3/a8/73d2abfd98a33cd74a0fc491e527d734c222ae18b499a10689f3adbc8d5c/bsdiff4-1.2.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e87c67b06ac96af6171b774dc8c03d2bde70c67c6488078eff44e0af4864acf6", size = 33606, upload-time = "2025-02-19T17:40:21.398Z" },
{ url = "https://files.pythonhosted.org/packages/6b/c3/713b3bb3711b62e51f6f67d6d9f63098e4d3a51d8b91e52c962f5c01a2b7/bsdiff4-1.2.6-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:04bb2948301ad48123d308bf2342c83cae81d7edb52d11bdde00266d89ca071e", size = 37211, upload-time = "2025-02-19T17:40:22.365Z" },
{ url = "https://files.pythonhosted.org/packages/0b/c5/40559695ea0bd3332c37ef8182fc0f96ceed838ae6b03ca9ddcd8cf0f7df/bsdiff4-1.2.6-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:43649a44fc21f017be902e19ccf7fb8bac6ef2d7f93d871bbc6bc49acec9ffee", size = 35750, upload-time = "2025-02-19T17:40:23.554Z" },
{ url = "https://files.pythonhosted.org/packages/bb/9b/eb4683896119ec9d26d1eb3f12efc0d8a902451f4025db12c21c5a82992a/bsdiff4-1.2.6-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:baa76ec557dc48847c3ed1ff5720b5095c439c868f7568da30dcabbabceb2b92", size = 35364, upload-time = "2025-02-19T17:40:24.485Z" },
{ url = "https://files.pythonhosted.org/packages/d6/ad/0968b67aecf00873e0e5c07e97ba2300594505d4dbce62702b9f56a62d66/bsdiff4-1.2.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:701168e2931da777e6e72ae17f22eb519e9ce25ec5108d149c9da7b3b80e1184", size = 32831, upload-time = "2025-02-19T17:40:25.571Z" },
{ url = "https://files.pythonhosted.org/packages/6c/18/adfcf72780f19cea1fe9948cbfb49890599424e94c752bf7d614093c0fc5/bsdiff4-1.2.6-cp312-cp312-win32.whl", hash = "sha256:f9f2e5e716d35af3252f69a15afc2b166970c98596a1114af4c6d2834fe8e871", size = 18308, upload-time = "2025-02-19T17:40:26.571Z" },
{ url = "https://files.pythonhosted.org/packages/9d/5d/31672172bb4566c1f1187fa28a1437125d4b5106bc55f9f7b9a75371094c/bsdiff4-1.2.6-cp312-cp312-win_amd64.whl", hash = "sha256:0b29568d1e33e32ea075c12a696b32e4d6cea344d0270a2292075254efd86014", size = 19553, upload-time = "2025-02-19T17:40:27.592Z" },
{ url = "https://files.pythonhosted.org/packages/4f/56/887d90b0e52ce7b5533a6f1390ab9a68215a70ba34848441730e215ffc1c/bsdiff4-1.2.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a98d7975a670fc360d894ef2ec00294e6b7b19790c58457e40c8a5d57a1865b0", size = 16260, upload-time = "2025-02-19T17:40:28.614Z" },
{ url = "https://files.pythonhosted.org/packages/d8/4c/825a16932605d305501ed144ae5567a3dc90c9164a393c61cc0ed68df3f0/bsdiff4-1.2.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ee4417341712a4bf736694ce9ad3902b8c6fbd3425aadca44df9b66a51bbefa4", size = 16080, upload-time = "2025-02-19T17:40:29.612Z" },
{ url = "https://files.pythonhosted.org/packages/c2/e2/0cf538a786f47b08e26f3970a6f98c2b7b9d555c01e085425282944a2c7f/bsdiff4-1.2.6-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:39ddfa2137de44c9743a611d71d263d0cc8c45e5b18ee84ca5ff6b6240be1740", size = 33664, upload-time = "2025-02-19T17:40:31.646Z" },
{ url = "https://files.pythonhosted.org/packages/1f/c0/44ac255f1d16865e39ef941470e30bb5c362dd216b62837bb13880d1dd36/bsdiff4-1.2.6-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6474d8f34f89d25fa1803c639cc8ed49121752a56a15b4cd21e9267154cdaf70", size = 35648, upload-time = "2025-02-19T17:40:32.793Z" },
{ url = "https://files.pythonhosted.org/packages/cb/6b/d5871af38cbb8527652b65463c3dd736b6250828d8d6daf48be712a2ebfe/bsdiff4-1.2.6-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f8e9c876929c03ef5d448e2626e8b2961040c3a9f0dd3d483643dbccd0e7ff7a", size = 33792, upload-time = "2025-02-19T17:40:35.498Z" },
{ url = "https://files.pythonhosted.org/packages/5a/1e/7027849a6dc02b580e352b1528899053bd919029b185fbaa14c6f268180b/bsdiff4-1.2.6-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:46313f0eb8f63efb54a3c4219cd7b5b8a7795012b535f9d0838fe3f2b3349849", size = 33238, upload-time = "2025-02-19T17:40:37.165Z" },
{ url = "https://files.pythonhosted.org/packages/97/df/c4a3e2bb1c1f9f09c2c5f8a9025c67f5ec7fcc8949338e54cb2d4fba9009/bsdiff4-1.2.6-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f6b5757b1a83829f00ef34953c6865ea82e9c71126e465bc32d029c55da9e45b", size = 35866, upload-time = "2025-02-19T17:40:38.789Z" },
{ url = "https://files.pythonhosted.org/packages/83/03/76a5aaaa0ccc282b239b3f148f6dd6033d37f79c1d1a89846b712224d132/bsdiff4-1.2.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:734552992ecc86749a8ef55d03f999f9a47576cc609d7d4d9a7aec274b43ee4d", size = 33688, upload-time = "2025-02-19T17:40:39.762Z" },
{ url = "https://files.pythonhosted.org/packages/b3/b3/b240d4840a16d923c60e8e9eacf0777cf9378e30610037f6c85324daea85/bsdiff4-1.2.6-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:853c3221daac6f8d347f12eb0b73ca9dbb7db483e7b5f40b1e2fbb05730645a7", size = 37273, upload-time = "2025-02-19T17:40:41.626Z" },
{ url = "https://files.pythonhosted.org/packages/7d/84/2223a09c4950a3e419ce94eb0af6d90c1ee562b9962ef2d72515f4ad6271/bsdiff4-1.2.6-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:94526dc11e56f330c2f4b1e2e9389b958a7891f6c86b5aac83bd9c7a90eb088a", size = 35844, upload-time = "2025-02-19T17:40:42.646Z" },
{ url = "https://files.pythonhosted.org/packages/18/7b/c02f703b449feb20b245eb803e7d446508b80d5b4065d1eb9cc75d02ae3b/bsdiff4-1.2.6-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:f5474e1d9253564ed0823e2685a403d9dfdbba3c7b70a80f5066d61427848253", size = 35418, upload-time = "2025-02-19T17:40:44.562Z" },
{ url = "https://files.pythonhosted.org/packages/eb/52/623ee28011b6935f0dfe67397ec27c2a900b9f0bda1b1ec2a5b174c53fb7/bsdiff4-1.2.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5529731ac88151345a8bb76dad4fdb218af10a8a505161d1aa3d669e49cb7b77", size = 32892, upload-time = "2025-02-19T17:40:45.552Z" },
{ url = "https://files.pythonhosted.org/packages/44/6c/e740e347bb46ea08ceacf39df56c2ffd2bd20b95d458409ea303fbf2b946/bsdiff4-1.2.6-cp313-cp313-win32.whl", hash = "sha256:c8089827c41b37f7c9192492742289929097c5ab2a6b3a120919fee27fbc01b8", size = 18304, upload-time = "2025-02-19T17:40:47.37Z" },
{ url = "https://files.pythonhosted.org/packages/88/d1/9be6f6124afab9837db1ffc5801ca1aa86f2077d4224ff729e88fabada71/bsdiff4-1.2.6-cp313-cp313-win_amd64.whl", hash = "sha256:37ff935ba714e0726584dad2bc4c063218b588b110115e8554ebc438ee7bccf3", size = 19543, upload-time = "2025-02-19T17:40:48.369Z" },
]
[[package]]
name = "build"
version = "1.5.0"
@@ -2940,6 +2990,7 @@ name = "langchain-quickjs"
version = "0.3.0"
source = { editable = "../partners/quickjs" }
dependencies = [
{ name = "bsdiff4" },
{ name = "deepagents" },
{ name = "langchain" },
{ name = "langchain-core" },
@@ -2949,6 +3000,7 @@ dependencies = [
[package.metadata]
requires-dist = [
{ name = "bsdiff4", specifier = ">=1.2.6,<2.0.0" },
{ name = "deepagents", editable = "../deepagents" },
{ name = "langchain", specifier = ">=1.3.9,<2.0.0" },
{ name = "langchain-core", specifier = ">=1.4.7,<2.0.0" },