idx-cli/.agents/setup
Amp 44b9c16d82
chore: warm orb local data during setup
`.agents/setup` now pre-loads the CLI's local data after the build: it
installs the published ownership snapshot (`idx ownership sync`, the
repo's preferred bootstrap path) and warms the file cache for the shipped
`stocks` read commands, so a fresh orb can query ownership data and serve
`--offline` reads immediately.

Setup also adopts the dev shell environment for its remaining steps via
`nix print-dev-env` (the same mechanism the login-shell hook uses), and
the orb guidance block is replaced in place so text updates reach orbs
that already have one without accumulating blank lines.

Amp-Thread-ID: https://ampcode.com/threads/T-01a0ba76-221d-728b-9d68-45ab48750d3d
Co-authored-by: The Diligence Dev <thediligencedev@gmail.com>
2026-09-20 14:30:52 +00:00

204 lines
7.7 KiB
Bash
Executable file

#!/usr/bin/env bash
#
# Orb setup for idx-cli.
#
# A fresh orb has no Rust toolchain and no Nix, while the repository builds and
# verifies through its flake dev shell (`nix develop`). This script installs Nix
# (single-user), realizes the dev shell, makes that environment available to the
# login shells Amp and orb services start, warms the Cargo build, and pre-loads
# local data (ownership snapshot + market cache) so the first agent command is
# incremental and the shipped read commands have something to serve.
#
# Idempotent by design: an orb restored from a stale snapshot re-runs this and
# keeps /nix, ~/.cargo, and target/ instead of rebuilding them.
set -euo pipefail
repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
nix_profile="$HOME/.nix-profile"
nix_bin="$nix_profile/bin/nix"
nix_conf="$HOME/.config/nix/nix.conf"
bash_profile="$HOME/.bash_profile"
agent_guidance="$HOME/.config/amp/AGENTS.md"
profile_marker="# idx-cli orb dev shell (managed by .agents/setup)"
idx_bin="$repo_root/target/debug/idx"
guidance_start="<!-- idx-cli-orb-setup -->"
guidance_end="<!-- idx-cli-orb-setup-end -->"
# Amp runs setup from the repository root; be explicit so relative paths and
# the dev shell shellHook behave the same however the script is invoked.
cd "$repo_root"
step() { printf '\n==> %s\n' "$*"; }
# Runs "$@" with timing so setup.log shows which step is slow or failing.
run() {
local label="$1"
shift
local start=$SECONDS
if "$@"; then
printf ' ok: %s (%ss)\n' "$label" "$((SECONDS - start))"
return 0
fi
local status=$?
printf ' FAILED: %s (%ss, exit %s)\n' "$label" "$((SECONDS - start))" "$status" >&2
return "$status"
}
# Warm-up work whose failure should not stop snapshot publication.
run_warn() {
if ! run "$@"; then
printf 'warning: %s failed; rerun .agents/setup once the cause is fixed\n' "$1" >&2
fi
}
step "Nix package manager"
if [ -x "$nix_bin" ]; then
printf ' ok: already installed (%s)\n' "$("$nix_bin" --version)"
else
installer="$(mktemp)"
curl -fsSL https://nixos.org/nix/install -o "$installer"
run "install nix (single-user)" sh "$installer" --no-daemon --no-modify-profile --yes
rm -f "$installer"
fi
# The installer cannot update the environment of this already-running script.
# shellcheck source=/dev/null
if [ -f "$nix_profile/etc/profile.d/nix.sh" ]; then
. "$nix_profile/etc/profile.d/nix.sh"
fi
step "Nix flake support"
mkdir -p "$(dirname "$nix_conf")"
touch "$nix_conf"
if ! grep -qE '^[[:space:]]*experimental-features[[:space:]]*=.*nix-command' "$nix_conf"; then
printf 'experimental-features = nix-command flakes\n' >>"$nix_conf"
fi
if ! grep -qE '^[[:space:]]*warn-dirty[[:space:]]*=' "$nix_conf"; then
printf 'warn-dirty = false\n' >>"$nix_conf"
fi
printf ' ok: %s\n' "$nix_conf"
step "Flake dev shell"
run "realize dev shell" "$nix_bin" develop --command true
# Adopt the dev shell environment for the rest of this script. This is the same
# `nix print-dev-env` mechanism the login-shell hook uses below, so a broken
# dev shell fails setup loudly instead of only failing later for agents.
dev_shell_env="$("$nix_bin" print-dev-env "$repo_root")"
eval "$dev_shell_env"
unset dev_shell_env
step "Warm Cargo build (kept in the snapshot for the first agent command)"
run_warn "cargo build --locked" cargo build --locked
run_warn "cargo test --no-run --locked" cargo test --no-run --locked
run_warn "cargo clippy --locked -- -D warnings" cargo clippy --locked -- -D warnings
step "Warm local data"
# Preferred ownership bootstrap: installs the maintained SQLite snapshot from
# the published manifest, so `ownership releases|ticker|changes` work in a
# fresh orb without a first sync. Re-running against a current DB is a no-op.
run_warn "ownership sync" "$idx_bin" -q ownership sync
# Warm the file cache for the shipped read commands. TTLs are short (5 min for
# quotes, 1 h for fundamentals), so this mainly keeps the first commands
# instant and makes `--offline` work; a miss just refetches from the provider.
warm_market_cache() {
local -a commands=(
"stocks quote BBCA"
"stocks history BBCA --period 1mo"
"stocks technical BBCA"
"stocks growth BBCA"
"stocks valuation BBCA"
"stocks risk BBCA"
"stocks fundamental BBCA"
"stocks profile BBCA"
"stocks financials BBCA"
"stocks earnings BBCA"
"stocks sentiment BBCA"
"stocks insights BBCA"
"stocks news BBCA --limit 5"
"stocks screen --limit 10"
"stocks compare BBCA,BBRI"
)
local failures=0 command
for command in "${commands[@]}"; do
# shellcheck disable=SC2086 # the command line is intentionally re-split
if ! "$idx_bin" -q $command >/dev/null 2>&1; then
printf ' could not warm: idx %s\n' "$command" >&2
failures=$((failures + 1))
fi
done
[ "$failures" -eq 0 ]
}
run_warn "market cache warm" warm_market_cache
step "Login shell environment"
# Amp starts its login shells (the headless executor and orb services) from /,
# so activate the dev shell by repository path instead of by $PWD. The
# IN_NIX_SHELL guard keeps nested shells and `nix develop` itself cheap.
profile_hook() {
cat <<EOF
$profile_marker
if [ -f "$nix_profile/etc/profile.d/nix.sh" ]; then
# shellcheck disable=SC1091
. "$nix_profile/etc/profile.d/nix.sh"
fi
if [ -z "\${IN_NIX_SHELL:-}" ] && [ -f "$repo_root/flake.nix" ]; then
eval "\$("$nix_bin" print-dev-env "$repo_root")"
fi
if [ "\$PWD" = "$repo_root" ]; then
case ":\$PATH:" in
*":$repo_root/target/debug:"*) ;;
*) PATH="$repo_root/target/debug:\$PATH" ;;
esac
export PATH
fi
EOF
}
if grep -Fqx "$profile_marker" "$bash_profile" 2>/dev/null; then
printf ' ok: dev shell hook already present in %s\n' "$bash_profile"
else
printf '\n' >>"$bash_profile"
profile_hook >>"$bash_profile"
printf ' ok: added dev shell hook to %s\n' "$bash_profile"
fi
step "Orb guidance for agents"
mkdir -p "$(dirname "$agent_guidance")"
if grep -Fq "$guidance_start" "$agent_guidance" 2>/dev/null; then
# Replace a previous block so text updates reach orbs that already have one.
sed -i "/$guidance_start/,/$guidance_end/d" "$agent_guidance"
# Drop the blank separator lines the removed block left at the end of file.
sed -i -e :a -e '/^[[:space:]]*$/{$d;N;ba' -e '}' "$agent_guidance"
fi
cat >>"$agent_guidance" <<EOF
$guidance_start
# idx-cli inside the orb
- The idx-cli Nix dev shell is already active for login shells: \`cargo\`, \`rustc\`, \`cargo clippy\`, \`cargo fmt\`, \`cargo nextest\`, \`prek\`, \`mutool\`, and the \`curl_chrome*\` binaries are on \`PATH\`.
- \`.agents/setup\` already ran \`cargo build --locked\`, so \`target/\` is warm; run \`cargo build\`, \`cargo clippy -- -D warnings\`, and \`cargo test\` directly.
- The ownership DB is pre-synced from the published snapshot and \`~/.cache/idx\` is warmed for the \`stocks\` read commands, so \`idx ownership releases\` and friends work immediately (and with \`--offline\`).
- \`nix develop\` still works when you want the shell explicitly.
$guidance_end
EOF
printf ' ok: wrote orb guidance to %s\n' "$agent_guidance"
step "Verify"
# A minimal environment proves the hook works for the login shells Amp starts,
# not just for this script's already-modified environment.
if run "cargo resolves in a clean login shell" \
env -i HOME="$HOME" USER="${USER:-user}" PATH=/usr/bin:/bin /bin/bash -lc 'command -v cargo && cargo --version'; then
printf ' ok: orb environment ready\n'
else
printf 'error: the Nix dev shell is not active in a clean login shell\n' >&2
exit 1
fi
ownership_db="$HOME/.local/share/idx/ownership.db"
if [ -f "$ownership_db" ]; then
printf ' ok: ownership DB present (%s)\n' "$ownership_db"
else
printf 'warning: no ownership DB at %s; `idx ownership sync` will install it on demand\n' "$ownership_db" >&2
fi