458 lines
26 KiB
Bash
Executable File
458 lines
26 KiB
Bash
Executable File
#!/bin/bash
|
|
# Post-create setup for the Explore devcontainer.
|
|
set -euo pipefail
|
|
|
|
# Install every harness a worker can author with, and point each at the LLM proxy.
|
|
# Driven by scripts/harness-registry.toml, so adding a harness is a registry entry
|
|
# rather than an edit here and in the sibling container's post-create.
|
|
set -a; . /workspace/.env 2>/dev/null || true; set +a
|
|
. /workspace/scripts/setup-harnesses.sh
|
|
# Explore is where capture happens, so it is the only surface that gets the capture
|
|
# hooks — their commands ship in explore/plugins/.
|
|
RACCOON_SURFACE=explore harness_setup_all
|
|
|
|
# Allow git operations on bind-mounted repo (owned by different uid on host)
|
|
git config --global --add safe.directory '*'
|
|
|
|
# Check out the default commit from toolkit.json. SINGLE-REPO ONLY: a polyglot toolkit
|
|
# has no single /workspace/repo and no top-level defaultCommit — each member repo lives
|
|
# at /workspace/repos/<slug> and is checked out + set up lazily by run-app/setup_repo.
|
|
IS_POLYGLOT=$(node -e "try{process.stdout.write(require('/workspace/toolkit.json').polyglot?'1':'')}catch{}" 2>/dev/null || true)
|
|
if [ -z "$IS_POLYGLOT" ]; then
|
|
DEFAULT_COMMIT=$(node -e "process.stdout.write(require('/workspace/toolkit.json').defaultCommit)")
|
|
git -C /workspace/repo -c advice.detachedHead=false checkout "$DEFAULT_COMMIT"
|
|
fi
|
|
|
|
# Install repo-specific runtime deps against the live-mounted /workspace/repo.
|
|
# Bringing postgres up (and creating the role/db) lives in post-start.sh so it
|
|
# also runs on every later container start, not just first create; call it here
|
|
# so the database is ready before db:create / prisma migrate runs below.
|
|
REPO_NAME=$(node -e "process.stdout.write(require('/workspace/toolkit.json').repo)" 2>/dev/null || true)
|
|
bash /workspace/.devcontainer/post-start.sh
|
|
|
|
# Symlink ./node_modules (cwd = the dir being installed) to a container-local tree keyed by
|
|
# <key> — see the call sites below for why. The target must itself be named `node_modules`
|
|
# (Node resolves the symlink, then walks ancestors for that literal name), and its parent
|
|
# needs a stub manifest: postinstall scripts that locate the project by truncating their
|
|
# realpath at `node_modules` require() `<parent>/package.json`, and die without it.
|
|
_nm_link() {
|
|
local root="/opt/raccoon-node-modules/$1"
|
|
[ -L node_modules ] || rm -rf node_modules
|
|
mkdir -p "$root/node_modules"
|
|
[ -f "$root/package.json" ] \
|
|
|| printf '{"name":"raccoon-node-modules-root","version":"0.0.0","private":true}\n' > "$root/package.json"
|
|
ln -sfn "$root/node_modules" node_modules
|
|
}
|
|
|
|
case "$REPO_NAME" in
|
|
ZenBill-006)
|
|
# Install deps + create databases
|
|
#
|
|
# node_modules goes to a CONTAINER-LOCAL path, not the bind-mounted repo dir.
|
|
# On macOS Docker Desktop the repo is a host bind mount; writing yarn's huge,
|
|
# deeply-nested node_modules tree across the file-sharing layer exhausts the
|
|
# host open-file table -> ENFILE "file table overflow", failing the install.
|
|
# Keeping node_modules inside the Linux VM confines that churn to the VM; the
|
|
# repo stays bind-mounted (worker sees edits) and node_modules is a symlink.
|
|
# (ZenBill is yarn-classic with a single root node_modules, so one symlink
|
|
# relocates the whole tree cleanly — unlike Palolo's pnpm workspace, which
|
|
# uses copy mode instead.)
|
|
#
|
|
# The symlink TARGET must itself be named `node_modules`: Node resolves the
|
|
# symlink to its real path, then walks ancestors looking for a dir literally
|
|
# named node_modules. If the target were .../zeta-<x> (not node_modules),
|
|
# child processes spawned by postinstall scripts (e.g. cypress's `node
|
|
# index.js` requiring minimist) can't resolve hoisted deps -> MODULE_NOT_FOUND.
|
|
( cd /workspace/repo \
|
|
&& cp .env.sample .env 2>/dev/null \
|
|
&& sed -i "s/^ruby '3\.1\.2'/ruby '~> 3.1.0'/" Gemfile \
|
|
&& rm -f .ruby-version \
|
|
&& bundle install \
|
|
&& _nm_link zenbill-006 \
|
|
&& yarn install --ignore-engines \
|
|
&& bundle update jwt \
|
|
&& (bundle exec rails db:create db:migrate || true) \
|
|
&& (RAILS_ENV=test bundle exec rails db:create db:migrate || true) )
|
|
;;
|
|
zeta-heimdall)
|
|
# API-only Rails 7; Postgres-only; no JS runtime needed. config/database.yml
|
|
# and .env are gitignored, so materialize them from the committed .example
|
|
# files. The base image is the exact pinned Ruby (3.2.1), so the Gemfile's
|
|
# ruby pin needs no loosening. --full-index works around stale-lockfile
|
|
# transitive deps (the masked repo's lockfile omits a few). db:prepare loads
|
|
# db/schema.rb into the dev DB; the test DB is created + loaded too (rspec's
|
|
# maintain_test_schema! reloads it on first run).
|
|
( cd /workspace/repo \
|
|
&& cp config/database.yml.example config/database.yml 2>/dev/null \
|
|
&& cp .env.example .env 2>/dev/null \
|
|
&& bundle install --full-index \
|
|
&& (bundle exec rails db:prepare || true) \
|
|
&& (RAILS_ENV=test bundle exec rails db:create db:schema:load || true) )
|
|
;;
|
|
zeta-platform)
|
|
# Rails 5.1 / Ruby 2.6.6 banking monorepo; Postgres + Redis. config/database.yml
|
|
# is committed (only .env is gitignored → copy from .env.example for dotenv).
|
|
# Bundler 1.17.3 matches the lockfile (installed in the image), and the base is
|
|
# the exact pinned Ruby (2.6.6), so no Gemfile loosening. db:schema:load loads
|
|
# db/schema.rb into the dev + test DBs.
|
|
( cd /workspace/repo \
|
|
&& cp .env.example .env 2>/dev/null \
|
|
&& bundle install \
|
|
&& (bundle exec rails db:create db:schema:load || true) \
|
|
&& (RAILS_ENV=test bundle exec rails db:create db:schema:load || true) )
|
|
# React client (Create React App, react-scripts 2.1.1). Install its JS deps so
|
|
# `run-app` can boot the full UI (dev server proxies /graphql → the Rails API).
|
|
# node_modules goes to a CONTAINER-LOCAL path, not the bind-mounted repo dir:
|
|
# on macOS Docker Desktop the repo is a host bind mount, and writing CRA's huge
|
|
# node_modules tree across the file-sharing layer is slow AND exhausts the host's
|
|
# open-file table. Keeping it inside the Linux VM confines that churn; the repo
|
|
# stays bind-mounted (worker sees edits) and node_modules is a symlink. The
|
|
# symlink TARGET must itself be named `node_modules` (Node's resolver walks
|
|
# parents looking for a dir literally named node_modules). yarn is v1 (classic),
|
|
# matching the committed yarn.lock.
|
|
( cd /workspace/repo \
|
|
&& _nm_link zeta-platform \
|
|
&& yarn install --frozen-lockfile )
|
|
;;
|
|
Palolo-031)
|
|
# Install deps. packages/server/scripts/prisma greps `.env` for
|
|
# PUBLIC_PALOLO_ENV inside an `if [ -t 0 ]` block — designed for
|
|
# interactive use where the dev's local .env points at staging/prod
|
|
# and the script wants confirmation before destructive ops. In a
|
|
# fresh clone the file doesn't exist, so the grep fails and `set -e`
|
|
# aborts. We materialize a `local`-pointing stub so the script
|
|
# finds what it expects, the safety check skips correctly (env is
|
|
# local, no confirmation needed), and downstream interactive worker
|
|
# invocations of `pnpm run prisma …` also succeed instead of hitting
|
|
# the same failure.
|
|
( cd /workspace/repo \
|
|
&& git config core.hooksPath /dev/null \
|
|
&& echo "PUBLIC_PALOLO_ENV=local" > packages/server/.env \
|
|
&& pnpm install --frozen-lockfile \
|
|
&& pnpm run --dir packages/server prisma generate \
|
|
&& (pnpm run --dir packages/server prisma migrate deploy || true) )
|
|
|
|
# Seed the dev DB with a superuser, the global/superuser orgs, and a set
|
|
# of test users so a worker can actually log in when running the app
|
|
# locally. Without this the schema exists but every table is empty, and
|
|
# the login screen errors out before you can get into the app. Test
|
|
# users are <name>@exhalefi.com with password "test" (e.g. zaniyah@exhalefi.com).
|
|
# Convenience only — wrapped in `|| true` so a seed hiccup never blocks
|
|
# the explore container from coming up.
|
|
#
|
|
# `--small` keeps every organization the seed builds but caps each at 10
|
|
# members per status. The default size gives the last one 200 per status,
|
|
# which opens 200 concurrent Prisma interactive transactions and exhausts
|
|
# the connection pool (`P2028`) on a machine with few cores, so the seed
|
|
# dies partway and leaves perks un-activated.
|
|
( cd /workspace/repo/packages/server \
|
|
&& DEFAULT_BAAS_PROVIDER=Liquid PUBLIC_BAAS_ENABLED=yes TESTING_SEED=yes \
|
|
pnpm run seed --small ) || true
|
|
|
|
# Leave a fresh container's `git status` clean. The two artifacts below
|
|
# are side effects of bootstrap, not edits anyone made:
|
|
#
|
|
# 1. .pnpm-store/ — pnpm's content-addressable store. It must sit on the
|
|
# same filesystem as node_modules to hardlink; /workspace/repo is a
|
|
# bind mount on a different fs than HOME, so pnpm can't use the global
|
|
# ~/.pnpm-store and drops a project-local store instead. The repo's
|
|
# .gitignore covers it as of commit 3af4366a6, but older commits a
|
|
# worker may check out don't. Exclude it locally too (idempotent;
|
|
# the create-snapshot checkpoint hook excludes it as well).
|
|
# 2. deploy_to_eks.sh — the repo's only symlink (-> ../scripts/...). The
|
|
# toolkit's zip/unzip packaging path materializes it as a regular file,
|
|
# so git reports a "typechange". Restore the symlink from the index
|
|
# (no-op if the filesystem can't represent symlinks).
|
|
grep -qxF '.pnpm-store/' /workspace/repo/.git/info/exclude 2>/dev/null \
|
|
|| printf '\n# raccoon-explore: in-repo pnpm store (bind-mount hardlink fallback)\n.pnpm-store/\n' >> /workspace/repo/.git/info/exclude
|
|
git -C /workspace/repo checkout -- provisioning/kubernetes/palolo-app/deploy_to_eks.sh 2>/dev/null || true
|
|
;;
|
|
human-essentials)
|
|
# Rails 8 / Ruby 3.4; pure importmap (no JS bundler → no node_modules). The
|
|
# base image is exact Ruby 3.4.3, so no Gemfile loosening. .env is gitignored;
|
|
# copy the committed .env.example (public reCAPTCHA test keys etc.) for dotenv,
|
|
# then drop its empty PG_USERNAME/PG_PASSWORD lines so they don't override the
|
|
# image ENV (PG_USERNAME=postgres). db:schema:load loads db/schema.rb into the
|
|
# dev + test DBs; assets:precompile is needed by the Cuprite system specs.
|
|
# db:seed (dev, offline via Faker) gives a working login out of the box — the app
|
|
# has no usable self-service signup (a fresh user lands org-less/role-less).
|
|
( cd /workspace/repo \
|
|
&& cp .env.example .env 2>/dev/null || true; \
|
|
sed -i '/^PG_USERNAME=/d; /^PG_PASSWORD=/d' .env 2>/dev/null || true; \
|
|
bundle install \
|
|
&& (bundle exec rails db:create db:schema:load || true) \
|
|
&& (RAILS_ENV=test bundle exec rails db:create db:schema:load || true) \
|
|
&& (bundle exec rails db:seed || true) \
|
|
&& (bundle exec rails assets:precompile || true) )
|
|
;;
|
|
endsideout)
|
|
# Rails 8.1 / Ruby 4.0; SQLite + importmap (no Node build — tailwindcss-rails
|
|
# ships its own binary). No .env (no .env.example; tests need no secrets). The
|
|
# SQLite dev + test DBs are plain files created by db:prepare / db:test:prepare.
|
|
# db:seed (dev, offline) creates admin@example.com / password — there is no
|
|
# self-service signup route, so seeding is the only way into the UI.
|
|
# tailwindcss:build writes the gitignored app/assets/builds/ the layout links;
|
|
# run-app starts the server alone, without Procfile.dev's tailwindcss:watch.
|
|
( cd /workspace/repo \
|
|
&& bundle install \
|
|
&& (bin/rails db:prepare || true) \
|
|
&& (bin/rails db:test:prepare || true) \
|
|
&& (bin/rails db:seed || true) \
|
|
&& (bin/rails tailwindcss:build || true) )
|
|
;;
|
|
community-foundation)
|
|
# Rails 8.1 / Ruby 4.0; SQLite + importmap + tailwind (no Node). Encrypted
|
|
# credentials aren't needed for tests. SQLite dev + test DBs.
|
|
# db:seed (dev, offline) creates the 'arlington' tenant + owner@example.com /
|
|
# password. Self-signup is a dead end here (needs a pre-existing org + a working
|
|
# mailer for confirmation), so seeding is the only offline way into the UI. The
|
|
# app is subdomain-multi-tenant — reach the tenant at arlington.lvh.me, not plain
|
|
# localhost (see welcome.sh).
|
|
# tailwindcss:build writes the gitignored app/assets/builds/ the layout links;
|
|
# run-app starts the server alone, without Procfile.dev's tailwindcss:watch.
|
|
( cd /workspace/repo \
|
|
&& bundle install \
|
|
&& (bin/rails db:prepare || true) \
|
|
&& (bin/rails db:test:prepare || true) \
|
|
&& (bin/rails db:seed || true) \
|
|
&& (bin/rails tailwindcss:build || true) )
|
|
;;
|
|
stocks-in-the-future)
|
|
# Rails 8.1 / Ruby 3.4.4; Postgres + Redis; importmap (no Node build).
|
|
# config/database.yml is gitignored — materialize from the committed sample.
|
|
# PGHOST/PGUSER (set in the image) point rails at the postgres superuser.
|
|
# db:seed (dev, offline) creates login-by-username accounts (Admin / password);
|
|
# self-signup is disabled (GET /users/sign_up redirects to /), so seed to get in.
|
|
# tailwindcss:build writes the gitignored app/assets/builds/ the layout links;
|
|
# run-app starts the server alone, without Procfile.dev's tailwindcss:watch.
|
|
( cd /workspace/repo \
|
|
&& (cp config/database.yml.sample config/database.yml 2>/dev/null || true) \
|
|
&& bundle install \
|
|
&& (bin/rails db:create db:schema:load || true) \
|
|
&& (RAILS_ENV=test bin/rails db:create db:schema:load || true) \
|
|
&& (bin/rails db:seed || true) \
|
|
&& (bin/rails tailwindcss:build || true) )
|
|
;;
|
|
casa)
|
|
# Rails 8.0 / Ruby 4.0.3; Postgres + Node 24 (jsbundling: esbuild + sass).
|
|
# DB env (POSTGRES_USER/DATABASE_HOST/POSTGRES_PASSWORD) is pinned in the image.
|
|
# npm ci installs JS deps; `npm run build` + `build:css` (esbuild + sass) write the
|
|
# bundles to app/assets/builds. The Selenium system specs serve from there because
|
|
# the test env runs with config.assets.compile=true (Sprockets compiles on demand).
|
|
# Deliberately NOT `assets:precompile`: that fingerprints untracked copies into
|
|
# public/assets which the specs don't need and which make `npm run lint` (standard)
|
|
# report ~197k errors over machine-generated bundles. app/assets/builds is already in
|
|
# standard's ignore list, so the dev build leaves the tree lint-clean and faithful.
|
|
# db:seed (dev, offline via Faker + local logo) creates casa_admin1@example.com /
|
|
# 12345678 — users are admin-invited only (ADR 0002), so seeding is the way in.
|
|
( cd /workspace/repo \
|
|
&& (cp .env.example .env 2>/dev/null || true) \
|
|
&& bundle install \
|
|
&& npm ci \
|
|
&& (bin/rails db:create db:schema:load || true) \
|
|
&& (RAILS_ENV=test bin/rails db:create db:schema:load || true) \
|
|
&& (bin/rails db:seed || true) \
|
|
&& (npm run build && npm run build:css || true) )
|
|
;;
|
|
awbw)
|
|
# Rails 8.1 / Ruby 4.0.1; MySQL 8 (Percona, Trilogy) + Node 22 (Vite). .env from
|
|
# .env.sample; DATABASE_URL (image) points Trilogy at 127.0.0.1 root. npm ci + a
|
|
# test-mode Vite build for the Selenium system specs.
|
|
# Use db:schema:load (NOT migrate): the committed schema.rb is clean native-MySQL-8
|
|
# JSON; running migrate re-dumps schema.rb from the live DB (which corrupts it under
|
|
# a non-MySQL-8 engine). tz tables are loaded by post-start.sh (Ahoy charts need them).
|
|
# db:seed (dev, offline; the seed disables mailer delivery itself) creates the
|
|
# pre-confirmed umberto.user@example.com / password super_user — no self-service
|
|
# signup exists and :confirmable would block a hand-made user without a mailer.
|
|
( cd /workspace/repo \
|
|
&& (cp .env.sample .env 2>/dev/null || true) \
|
|
&& bundle install \
|
|
&& npm ci \
|
|
&& (bin/vite build --mode test || true) \
|
|
&& (bin/rails db:create db:schema:load || true) \
|
|
&& (RAILS_ENV=test bin/rails db:create db:schema:load || true) \
|
|
&& (bin/rails db:seed || true) )
|
|
;;
|
|
alongwithyou)
|
|
# Rails 8.1 / Ruby 4.0.5; SQLite + importmap (no app-side Node). No .env / credentials
|
|
# needed to boot. This is a young app (a fresh scaffold with no migrations yet), so
|
|
# db:prepare just materializes an empty dev/test DB; db:seed is a no-op on the default
|
|
# seeds.rb. All wrapped in `|| true` so an empty schema never blocks container startup.
|
|
( cd /workspace/repo \
|
|
&& bundle install \
|
|
&& (bin/rails db:prepare || true) \
|
|
&& (bin/rails db:test:prepare || true) \
|
|
&& (bin/rails db:seed || true) )
|
|
;;
|
|
flaredown)
|
|
# Polyglot: backend/ Rails 7.1 (Ruby 3.2.3, Mongoid on MongoDB + Postgres + Redis +
|
|
# Sidekiq) and frontend/ Ember (Node 14). Postgres/Mongo/Redis are started by
|
|
# post-start.sh (called above). .env is gitignored — materialize from the committed
|
|
# backend/env-example (public dev secrets). Mongoid creates collections lazily, so
|
|
# there's no Mongo schema to load; Postgres holds a small relational slice with a
|
|
# committed db/schema.rb → db:schema:load (NOT db:migrate, which re-dumps schema.rb
|
|
# from the live DB on a bind-mounted repo).
|
|
# env-example points PG at host `postgresql` (the docker-compose service name); in this
|
|
# single container everything is on localhost, so rewrite the PG host. Redis defaults to
|
|
# localhost already; Mongoid reads MONGODB_HOST (unset → localhost).
|
|
( cd /workspace/repo/backend \
|
|
&& (cp -n env-example .env 2>/dev/null || true) \
|
|
&& sed -i 's/^PG_DATABASE_HOST=.*/PG_DATABASE_HOST=localhost/' .env 2>/dev/null || true; \
|
|
bundle install \
|
|
&& (bundle exec rails db:create db:schema:load || true) \
|
|
&& (RAILS_ENV=test bundle exec rails db:create db:schema:load || true) )
|
|
# Ember frontend on Node 14 (frontend/.nvmrc = v14.21.3; npm pinned to 6 in the image).
|
|
# node_modules to a container-local symlink (bind-mount file-sharing exhausts the host fd
|
|
# table on big node_modules trees). OPENSSL_CONF=/dev/null lets the old webpack md4 hashing
|
|
# run on bookworm's OpenSSL 3. --unsafe-perm so npm (running as root) actually executes the
|
|
# postinstall (patch-package + bower install) instead of skipping it with a "cannot run in
|
|
# wd" warning; without it bower_components is never populated and `ember build` fails.
|
|
NODE14_BIN=$(ls -d /usr/local/nvm/versions/node/v14.* 2>/dev/null | sort -V | tail -1)/bin
|
|
( cd /workspace/repo/frontend \
|
|
&& export PATH="$NODE14_BIN:$PATH" OPENSSL_CONF=/dev/null \
|
|
&& _nm_link flaredown-frontend \
|
|
&& (npm install --unsafe-perm --no-audit --no-fund || echo "WARNING: frontend npm install failed (explore-only)" >&2) ) || true
|
|
;;
|
|
breezy-complete)
|
|
# Monorepo: Rails 7.0 / Ruby 3.2.0 API (backend/) + Next.js 14 frontend
|
|
# (frontend/); Postgres + Redis baked in the image. The offline Clerk-bypass
|
|
# env is injected by run-app at server start only — the ambient env stays
|
|
# upstream-CI-shaped so a worker's `cd backend && bundle exec rspec` runs
|
|
# green (ambient DISABLE_CLERK 403s several controller specs, and ambient
|
|
# RAILS_ENV leaks through rails_helper's `ENV['RAILS_ENV'] ||= 'test'`).
|
|
#
|
|
# backend: gems + yarn asset-pipeline deps; db:prepare (retried once — the
|
|
# first run can race the just-started postgres) + db:seed (offline-safe demo
|
|
# tenant; the only way into the UI, auth is invite-less) + test DB. Fresh-DB
|
|
# db:test:prepare trips check_protected_environments → stamp the env first.
|
|
# db:prepare seeds the DB it creates and the seeds are not idempotent, so the
|
|
# explicit db:seed is for the retry case only — skip it on a seeded DB.
|
|
# frontend: npm install (not ci) so platform-specific optional deps resolve
|
|
# on arm64 + x64. Both node_modules go to CONTAINER-LOCAL paths via symlink
|
|
# (bind-mount ENFILE; see the ZenBill comment above — target must itself be
|
|
# named node_modules).
|
|
( cd /workspace/repo/backend \
|
|
&& bundle install --jobs 4 --retry 3 \
|
|
&& _nm_link breezy-backend \
|
|
&& yarn install --frozen-lockfile \
|
|
&& (bundle exec rails db:prepare || bundle exec rails db:prepare) \
|
|
&& ( psql -tAc 'select 1 from breezy_professionals limit 1' socratic_systems_development 2>/dev/null | grep -q 1 \
|
|
|| bundle exec rails db:seed || true ) \
|
|
&& (RAILS_ENV=test bundle exec rails db:environment:set || true) \
|
|
&& (RAILS_ENV=test bundle exec rails db:test:prepare || true) )
|
|
( cd /workspace/repo/frontend \
|
|
&& _nm_link breezy-frontend \
|
|
&& npm install --include=optional )
|
|
;;
|
|
esac
|
|
|
|
# Mirror Harbor's reduced toolset in the interactive Explore session. Use
|
|
# Harbor's /opt path when available, but fall back to a user-writable path for
|
|
# generic devcontainer fixtures that run lifecycle hooks as a non-root user.
|
|
AGENT_CLI_DIR="/opt/agent-cli"
|
|
if ! mkdir -p "$AGENT_CLI_DIR" 2>/dev/null; then
|
|
AGENT_CLI_DIR="$HOME/.agent-cli"
|
|
mkdir -p "$AGENT_CLI_DIR"
|
|
fi
|
|
cp -R /workspace/scripts/str_replace_editor /workspace/scripts/str_replace_editor_vendor "$AGENT_CLI_DIR/"
|
|
chmod +x "$AGENT_CLI_DIR/str_replace_editor"
|
|
mkdir -p "$HOME/.local/bin"
|
|
# Explore launchers (one per authoring harness) come from setup-harnesses.sh,
|
|
# which reads harness-registry.toml. AGENT_CLI_DIR is where the reduced-toolset
|
|
# editor was staged above, and the launcher rewrites the toolset note to match.
|
|
AGENT_CLI_DIR="$AGENT_CLI_DIR" harness_install_launchers
|
|
|
|
mkdir -p "$HOME/.claude"
|
|
# SKIP_FAST_MODE_NETWORK_ERRORS: the LLM proxy doesn't forward claude's fast-mode
|
|
# availability probe, and claude reads the failed probe as "no network" and refuses
|
|
# /fast. The override makes /fast toggleable; fast serving stays OFF until toggled.
|
|
# Names this container as the surface a proxy call came from: claude reads it from the
|
|
# settings env below, codex from the shell (its config maps the header to this var name).
|
|
# Only on the proxy — a provider endpoint must not carry this attribution.
|
|
CALL_METADATA=""
|
|
case "$(set -a; . /workspace/.env 2>/dev/null || true; set +a; printf '%s' "${ANTHROPIC_BASE_URL:-}")" in
|
|
*/llm_proxy/*) CALL_METADATA='{"origin":"explore"}' ;;
|
|
esac
|
|
|
|
CALL_METADATA="$CALL_METADATA" node -e '
|
|
const fs = require("fs");
|
|
const home = process.env.HOME;
|
|
const env = {
|
|
CLAUDE_CODE_DISABLE_AUTO_MEMORY: "1",
|
|
CLAUDE_CODE_SKIP_FAST_MODE_NETWORK_ERRORS: "1",
|
|
};
|
|
if (process.env.CALL_METADATA) {
|
|
env.ANTHROPIC_CUSTOM_HEADERS =
|
|
`X-Surge-Client-Metadata: ${process.env.CALL_METADATA}`;
|
|
}
|
|
fs.writeFileSync(
|
|
`${home}/.claude/settings.json`,
|
|
JSON.stringify({ env }, null, 2) + "\n"
|
|
);
|
|
'
|
|
|
|
# Reference-data corpus: expose it at the stable /data/zeta-corpus path (the same path a trial
|
|
# uses) by symlinking to the toolkit's bind-mounted copy. No-op if this toolkit ships no corpus.
|
|
if [ -d /workspace/data/zeta-corpus ]; then
|
|
{ mkdir -p /data || sudo mkdir -p /data; } 2>/dev/null || true
|
|
{ ln -sfn /workspace/data/zeta-corpus /data/zeta-corpus \
|
|
|| sudo ln -sfn /workspace/data/zeta-corpus /data/zeta-corpus; } 2>/dev/null || true
|
|
fi
|
|
|
|
# Shell setup
|
|
# Ahead of the block below so every shell exports it, interactive or not.
|
|
if [ -n "$CALL_METADATA" ]; then
|
|
# A file rather than a .bashrc line alone: the launcher and refresh-harness-auth
|
|
# read it too, so a non-login shell does not silently lose the attribution.
|
|
printf 'export LLM_CALL_METADATA=%s\n' "'$CALL_METADATA'" > ~/.raccoon-call-origin
|
|
printf '. "$HOME/.raccoon-call-origin"\n' >> ~/.bashrc
|
|
fi
|
|
cat >> ~/.bashrc <<'BASHRC'
|
|
export PATH="$HOME/.local/bin:$PATH"
|
|
set -a && source /workspace/.env && set +a
|
|
|
|
# Everything below this line is for interactive shells only. An agent's shell tool
|
|
# sources .bashrc too, so without this guard the welcome banner prints into command
|
|
# output and container_start fires once per command instead of once per session.
|
|
case $- in
|
|
*i*) ;;
|
|
*) return ;;
|
|
esac
|
|
|
|
alias run-app="bash /workspace/run-app.sh"
|
|
[ -f /workspace/corpus-viewer/view-corpus.sh ] && alias view-corpus="bash /workspace/corpus-viewer/view-corpus.sh"
|
|
export PS1="\[\033[1;36m\][raccoon-explore]\[\033[0m\] \w\$ "
|
|
bash /workspace/welcome.sh explore 2>/dev/null
|
|
|
|
_AK="fde503c3bdb6e5cc9c48b1f8e4c2abeb"
|
|
_DK="e966e45af5ad1a18005f9fdb831186ea"
|
|
_WID="w-mu1wvj9k-gtnk"
|
|
_VER="037cfcf94b"
|
|
_CT="explore"
|
|
_RP=$(node -e "try{process.stdout.write(require('/workspace/toolkit.json').repo)}catch{}" 2>/dev/null)
|
|
_SID="$(date +%s)-$$"
|
|
_LAT=0
|
|
_ev() {
|
|
[ -z "$_AK" ] && return
|
|
{ curl -s -X POST "https://api2.amplitude.com/2/httpapi" \
|
|
-H "Content-Type: application/json" \
|
|
-d "{\"api_key\":\"$_AK\",\"events\":[{\"user_id\":\"$_WID\",\"event_type\":\"raccoon.$1\",\"event_properties\":{\"product\":\"raccoon\",\"container\":\"$_CT\",\"repo\":\"$_RP\",\"toolkit_version\":\"$_VER\",\"session_id\":\"$_SID\"},\"session_id\":$(date +%s000)}]}" \
|
|
>/dev/null 2>&1 & } 2>/dev/null; disown 2>/dev/null
|
|
}
|
|
_dl() {
|
|
[ -z "$_DK" ] && return
|
|
{ curl -s -X POST "https://http-intake.logs.datadoghq.com/api/v2/logs" \
|
|
-H "DD-API-KEY: $_DK" -H "Content-Type: application/json" \
|
|
-d "[{\"ddsource\":\"raccoon\",\"service\":\"toolkit\",\"hostname\":\"$(hostname)\",\"status\":\"$1\",\"message\":\"$2\",\"ddtags\":\"container:$_CT,worker:$_WID,repo:$_RP,toolkit_version:$_VER\"}]" \
|
|
>/dev/null 2>&1 & } 2>/dev/null; disown 2>/dev/null
|
|
}
|
|
_pc() { local n; n=$(date +%s); if (( n - _LAT >= 300 )); then _LAT=$n; _ev active; fi; }
|
|
PROMPT_COMMAND="_pc;${PROMPT_COMMAND:-}"
|
|
trap '_ev container_stop; _dl info container_stop; wait' EXIT
|
|
_ev container_start
|
|
_dl info container_start
|
|
BASHRC
|
|
|
|
# One alias per authoring harness: `claude` runs claude, `codex` runs codex.
|
|
harness_alias_lines >> ~/.bashrc
|