mirror of
https://github.com/Droid-Deck/DroidDeck.git
synced 2026-11-12 03:21:08 +00:00
* feat(agent): an Agent tab in the launcher that talks to Claude Code outside any session * feat(agent): the agent in the session drawer and as a bubble over the game * fix(agent): connect loopback adb, show unread replies, and fit the drawer page to the screen * feat(agent): first-run setup in the Agent tab, a harness choice with Codex, and no permission prompts * fix(agent): install helpers off the main thread and offer sign-in only after the install * fix(agent): connect adb only for commands that use it and run setup checks one at a time * fix(agent): show why a setup check failed * fix(agent): each harness has its own setup state and conversation * fix(agent): start the adb server before connecting and retry the connection check * fix(agent): switching harness clears the previous harness's setup results * feat(agent): a header, a composer with send and stop, and Markdown replies in the agent chat * fix(agent): leave room under the chat composer * feat(agent): continue the conversation after a Lab build restarts the app * feat(agent): show and remove what the agent stores in the Linux userland * fix(agent): the build tools take about 5 GB * feat(agent): DroidDeck opens on the Agent tab after restarting on a Lab build * feat(agent): conversation history, model and plan mode, live replies, full tool input and output, processes, attachments, queued messages and a Stop that ends the turn * fix(agent): check the Lab build less often while nothing is happening * fix(agent): an old Lab build's progress is not shown as a failure, and a restart counts as success * feat(agent): rebuild a kept Lab build from Updates, and tidy the chat's tool rows, costs, processes and times * feat(agent): a setup step that prepares fast Lab builds for the installed version, kept alive while it runs * fix(agent): the notification names a prepare and shows its percent without repeating the title * fix(agent): run the agent's Lab builds in the app's own process and continue the conversation that asked after the restart * fix(agent): setup's prepare runs the build itself instead of handing it to the app * feat(agent): a turn that ends without a reply says so and offers Retry, the resume is retried once, and each turn's raw output is kept * fix(agent): keep the previous turn's raw output too * fix(agent): a resumed Claude Code turn no longer ends at the result for a background task the last run left behind * fix(agent): install Codex's code-mode host with it, without which Codex runs no commands * feat(agent): setup and storage collapse into a summary card like Setup's, and Codex tool rows show the command without its shell wrapper * feat(agent): drop the agent bubble over sessions for now; the drawer keeps the agent * fix(agent): the Agent tab shows once the Linux runtime is downloaded, even while its proot pack is still being fetched * fix(agent): before the install brings adb, the connection step checks the app's own pairing instead of failing with adb not found * fix(agent): proot's binding warnings are not shown as a setup step's reason * fix(agent): the session drawer's Agent page fills the height under the drawer's header instead of a guess from the screen height * fix(agent): write the browser and GitHub helpers before every setup step, not only the install * fix(agent): find Wireless debugging's current port when the saved one no longer answers, so sign-ins open the browser after it restarts * fix(agent): only take a Wireless debugging port that answers, since mDNS can still advertise an old one * fix(agent): find a loopback Wireless debugging port by scanning when mDNS advertises none * fix(agent): keep a Codex turn going through reconnect notices and read gh login's status reliably * fix(agent): time out hung setup checks and keep their results and actions with their harness * fix(agent): keep the draft across settings and show the Agent tab once the runtime installs * fix(agent): keep the backslash when quoting apostrophes in a URL the browser helper opens * fix(agent): refresh apt's package lists before installing, since a fresh Linux runtime ships without them * fix(agent): sign-in links open through the app itself, so they work without Wireless debugging * fix(agent): the connection step passes only when adb really reaches the device, not on adb's own error * fix(agent): say Wireless debugging isn't reachable instead of adb's error * fix(agent): keep prompts, tool ids, attachments and retries with their own turn and chat * fix(agent): the service stops only once foreground, and Rebuild waits for a ready agent * fix(agent): the Codex install says what it is downloading, so a long download doesn't look stuck * fix(agent): pass the prompt to both CLIs the way they were tested on devices * fix(agent): the browser helper uses the running app's files directory, falls back to adb when the app cannot open a link, and the link is not logged
78 lines
4.2 KiB
Bash
Executable File
78 lines
4.2 KiB
Bash
Executable File
#!/bin/bash
|
|
# Sets up the on-device agent inside DroidDeck's Linux userland: Claude Code, git and gh, loopback
|
|
# adb for droiddeckctl, and the toolchain dd-lab-build uses to build Lab builds on the device.
|
|
# Run it from the DroidDeck terminal, inside a checkout of the DroidDeck repository.
|
|
set -euo pipefail
|
|
here=$(cd "$(dirname "$0")" && pwd)
|
|
export DEBIAN_FRONTEND=noninteractive
|
|
tmp=$(mktemp -d)
|
|
trap 'rm -rf "$tmp"' EXIT
|
|
|
|
apt-get update
|
|
apt-get install -y --no-install-recommends git gh adb python3 zip unzip curl openjdk-17-jdk-headless qemu-user zipalign apksigner
|
|
|
|
command -v claude >/dev/null || [ -x "$HOME/.local/bin/claude" ] ||
|
|
{ curl -fsSL -o "$tmp/install-claude.sh" https://claude.ai/install.sh && bash "$tmp/install-claude.sh"; }
|
|
|
|
mkdir -p "$HOME/.local/bin"
|
|
for tool in dd-agent dd-lab-build dd-gh-login android-open; do install -m755 "$here/$tool" "$HOME/.local/bin/$tool"; done
|
|
grep -q 'droiddeck-agent-path' "$HOME/.bashrc" 2>/dev/null ||
|
|
printf '\n# droiddeck-agent-path\nexport PATH="$HOME/.local/bin:$PATH" ADB_SERIAL=127.0.0.1:5555 BROWSER="$HOME/.local/bin/android-open"\n' >> "$HOME/.bashrc"
|
|
|
|
# Google publishes aapt2 for x86-64 Linux only; it runs here under qemu-user with Ubuntu's x86-64 runtime.
|
|
x86=$HOME/x86root
|
|
mkdir -p "$HOME/aapt2/x86" "$x86/etc"
|
|
if [ ! -x "$HOME/aapt2/x86/aapt2" ]; then
|
|
agp=$(sed -n "s/.*com.android.tools.build:gradle:\([0-9.]*\).*/\1/p" "$here/../../build.gradle" | head -1)
|
|
[ -n "$agp" ] || { echo "setup: no Android Gradle plugin version in build.gradle" >&2; exit 1; }
|
|
aapt2=$(curl -fsSL "https://dl.google.com/android/maven2/com/android/tools/build/aapt2/maven-metadata.xml" |
|
|
{ grep -o "<version>$agp-[0-9]*</version>" || true; } | tail -1 | sed 's/<[^>]*>//g')
|
|
[ -n "$aapt2" ] || { echo "setup: Google publishes no aapt2 for AGP $agp" >&2; exit 1; }
|
|
curl -fsSL -o "$tmp/aapt2.jar" "https://dl.google.com/android/maven2/com/android/tools/build/aapt2/$aapt2/aapt2-$aapt2-linux.jar"
|
|
unzip -o -q "$tmp/aapt2.jar" aapt2 -d "$HOME/aapt2/x86"
|
|
chmod +x "$HOME/aapt2/x86/aapt2"
|
|
fi
|
|
if [ ! -e "$x86/lib64/ld-linux-x86-64.so.2" ]; then
|
|
codename=$(. /etc/os-release && echo "$VERSION_CODENAME")
|
|
curl -fsSL "https://archive.ubuntu.com/ubuntu/dists/$codename/main/binary-amd64/Packages.gz" | gunzip > "$tmp/amd64-packages"
|
|
for package in libc6 libgcc-s1 libstdc++6 zlib1g; do
|
|
read -r file sum < <(awk -v p="$package" '$0 == "Package: " p {found = 1} found && /^Filename:/ {f = $2}
|
|
found && /^SHA256:/ {s = $2} found && /^$/ {exit} END {print f, s}' "$tmp/amd64-packages")
|
|
[ -n "$sum" ] || { echo "setup: $package is not in Ubuntu $codename's amd64 index" >&2; exit 1; }
|
|
curl -fsSL -o "$tmp/$package.deb" "https://archive.ubuntu.com/ubuntu/$file"
|
|
echo "$sum $tmp/$package.deb" | sha256sum -c --quiet -
|
|
dpkg-deb -x "$tmp/$package.deb" "$x86"
|
|
done
|
|
ln -sfn usr/lib64 "$x86/lib64"
|
|
ln -sfn usr/lib "$x86/lib"
|
|
: > "$x86/etc/ld.so.preload"
|
|
fi
|
|
# AGP only accepts a custom aapt2 whose file is named aapt2.
|
|
printf '#!/bin/sh\nexec qemu-x86_64 -L %s %s/aapt2/x86/aapt2 "$@"\n' "$x86" "$HOME" > "$HOME/aapt2/aapt2"
|
|
chmod +x "$HOME/aapt2/aapt2"
|
|
"$HOME/aapt2/aapt2" version
|
|
|
|
sdk=$HOME/android-sdk
|
|
if [ ! -x "$sdk/cmdline-tools/latest/bin/sdkmanager" ]; then
|
|
mkdir -p "$sdk/cmdline-tools"
|
|
curl -fsSL -o "$tmp/cmdline-tools.zip" https://dl.google.com/android/repository/commandlinetools-linux-13114758_latest.zip
|
|
unzip -q -o "$tmp/cmdline-tools.zip" -d "$sdk/cmdline-tools"
|
|
rm -rf "$sdk/cmdline-tools/latest"
|
|
mv "$sdk/cmdline-tools/cmdline-tools" "$sdk/cmdline-tools/latest"
|
|
fi
|
|
export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-arm64
|
|
yes | "$sdk/cmdline-tools/latest/bin/sdkmanager" --licenses >/dev/null
|
|
"$sdk/cmdline-tools/latest/bin/sdkmanager" "platforms;android-34" "build-tools;35.0.0" >/dev/null
|
|
|
|
adb connect 127.0.0.1:5555 || true
|
|
# The first build compiles the whole app; doing it now makes the agent's Lab builds incremental.
|
|
if [ "${DD_SKIP_PREPARE:-}" != 1 ]; then
|
|
echo "Approve the USB debugging prompt if one appears."
|
|
if timeout 120 adb -s 127.0.0.1:5555 wait-for-device; then
|
|
"$here/dd-lab-build" --prepare || echo "The first Lab build will compile the whole app"
|
|
else
|
|
echo "adb did not connect, so the first Lab build will compile the whole app"
|
|
fi
|
|
fi
|
|
echo "Done. Run dd-agent."
|