Project-2 baseline
This commit is contained in:
@@ -35,7 +35,7 @@ ENV DEBIAN_FRONTEND=noninteractive
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
build-essential git curl ca-certificates gnupg procps sudo xz-utils \
|
||||
libssl-dev zlib1g-dev \
|
||||
postgresql postgresql-client \
|
||||
postgresql postgresql-client ffmpeg \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# --- Node via nvm: 14 / 16 / 18 / 20 (prebuilt). Default 20 symlinked to /usr/local/bin so the
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"build": {
|
||||
"dockerfile": "Dockerfile",
|
||||
"args": {
|
||||
"TOOLKIT_BUILD_ID": "1789430760274-eddbpv"
|
||||
"TOOLKIT_BUILD_ID": "1790712369311-8xr6mu"
|
||||
}
|
||||
},
|
||||
"appPort": [
|
||||
|
||||
@@ -76,7 +76,10 @@ dnsjail_apply() {
|
||||
drop_ours
|
||||
# cache-size=0: every lookup goes upstream, so a jailed container sees what an unjailed
|
||||
# one would rather than an answer this resolver decided to keep.
|
||||
dnsmasq --no-resolv --no-hosts --listen-address=127.0.0.1 --bind-interfaces \
|
||||
# -u root: dnsmasq 2.80 (buster and older bases) drops to "nobody" and calls capset to
|
||||
# retain CAP_NET_ADMIN, which docker's default cap set does not grant -- so it exits and
|
||||
# the jail fails open on every such image.
|
||||
dnsmasq -u root --no-resolv --no-hosts --listen-address=127.0.0.1 --bind-interfaces \
|
||||
--cache-size=0 --pid-file="$STATE/dnsmasq.pid" --address=/#/ $srv \
|
||||
>/dev/null 2>>"$STATE/dnsmasq.err" || true
|
||||
fi
|
||||
|
||||
@@ -156,6 +156,8 @@ if (!instance)
|
||||
const tk = JSON.parse(fs.readFileSync('toolkit.json', 'utf-8'));
|
||||
expected = tk.explorePorts && tk.explorePorts.serverHost ? [3000, 3001] : [3000];
|
||||
if (tk.explorePorts && tk.explorePorts.corpusHost) expected.push(3002);
|
||||
if (tk.explorePorts && tk.explorePorts.companionHost)
|
||||
expected.push(tk.explorePorts.companionHost);
|
||||
} catch {}
|
||||
|
||||
const folder = process.cwd();
|
||||
|
||||
@@ -44,6 +44,34 @@ _nm_link() {
|
||||
ln -sfn "$root/node_modules" node_modules
|
||||
}
|
||||
|
||||
# g++ peaks near 400MiB on this codebase's biggest translation units, and nproc reports the
|
||||
# HOST's core count, so a many-core laptop with a small Docker VM OOMs mid-build. Bound the
|
||||
# job count by whichever of the VM's memory and the cgroup cap is smaller.
|
||||
_frepple_jobs() {
|
||||
local n mem cg j
|
||||
n=$(nproc)
|
||||
mem=$(awk '/^MemTotal:/{print $2*1024}' /proc/meminfo)
|
||||
cg=$(cat /sys/fs/cgroup/memory.max 2>/dev/null \
|
||||
|| cat /sys/fs/cgroup/memory/memory.limit_in_bytes 2>/dev/null || echo)
|
||||
case "$cg" in ''|max|*[!0-9]*) ;; *) [ "$cg" -lt "$mem" ] && mem=$cg ;; esac
|
||||
j=$(( mem / 734003200 ))
|
||||
[ "$j" -lt 1 ] && j=1
|
||||
[ "$j" -gt "$n" ] && j=$n
|
||||
echo "$j"
|
||||
}
|
||||
|
||||
# Docker Desktop's macOS bind mount can write a compiled wheel with the right length and
|
||||
# the wrong bytes, so the venv imports die on a signal (132/135/139) rather than an error.
|
||||
# A reinstall lands the authentic file; a Django-level failure exits 1 and is not retried.
|
||||
_frepple_migrate() {
|
||||
local rc=0
|
||||
./frepplectl.py migrate --noinput || rc=$?
|
||||
if [ "$rc" -le 128 ]; then return "$rc"; fi
|
||||
echo "venv extension died on signal $rc — reinstalling requirements and retrying" >&2
|
||||
python3 -m pip install --force-reinstall --no-cache-dir -r requirements.txt -q
|
||||
./frepplectl.py migrate --noinput
|
||||
}
|
||||
|
||||
case "$REPO_NAME" in
|
||||
ZenBill-006)
|
||||
# Install deps + create databases
|
||||
@@ -313,6 +341,70 @@ case "$REPO_NAME" in
|
||||
&& _nm_link flaredown-frontend \
|
||||
&& (npm install --unsafe-perm --no-audit --no-fund || echo "WARNING: frontend npm install failed (explore-only)" >&2) ) || true
|
||||
;;
|
||||
frepple)
|
||||
# The minified JS the app serves is tracked, so pnpm+grunt are for a worker who
|
||||
# edits frontend source, not a prerequisite. The cmake build creates venv/ and
|
||||
# pip-installs into it. odoo_addon is pinned, NOT --remote like upstream CI.
|
||||
# DEBUG_JS=DEBUG, and DEBUG is true under runserver, which points the two Vue
|
||||
# screens at a Vite dev server on :5173 that nothing starts. FREPPLE_PORT is where
|
||||
# the BROWSER posts forecast saves, so the service has to bind 0.0.0.0 to be
|
||||
# reachable. localsettings.py is upstream's own gitignored override hook.
|
||||
# `demo` alone holds no forecasts, which leaves the forecast screens empty; adding
|
||||
# distribution_demo and planning it reproduces upstream's own scenario1 content.
|
||||
# The `doc` target is not in `all`, so without it the Help menu and the help icon on
|
||||
# 89 report screens 404; its own symlink is absolute, so relink it relatively or the
|
||||
# host sees a dangling link into the container's /workspace.
|
||||
( cd /workspace/repo \
|
||||
&& git submodule update --init freppledb/odoo/odoo_addon \
|
||||
&& pnpm install --frozen-lockfile \
|
||||
&& grunt \
|
||||
&& cmake -S . -B build -DCMAKE_BUILD_TYPE=Release \
|
||||
&& cmake --build build --parallel "$(_frepple_jobs)" \
|
||||
&& { cmake --build build --target doc \
|
||||
&& ln -sfn ../../../build/doc/_build/html freppledb/common/static/doc \
|
||||
|| echo "NOTE: the docs did not build; in-app help links will 404" >&2; } \
|
||||
&& printf 'DEBUG_JS = False\nfor _a in DATABASES:\n DATABASES[_a]["FREPPLE_PORT"] = DATABASES[_a]["FREPPLE_PORT"].replace("127.0.0.1:", "0.0.0.0:")\n' \
|
||||
> localsettings.py \
|
||||
&& _frepple_migrate \
|
||||
&& ./frepplectl.py loaddata demo \
|
||||
&& ./frepplectl.py loaddata distribution_demo \
|
||||
&& ./frepplectl.py runplan --env=fcst,supply --background \
|
||||
&& ./frepplectl.py shell -c "
|
||||
from django.contrib.auth import get_user_model
|
||||
U = get_user_model()
|
||||
u, _ = U.objects.get_or_create(username='admin', defaults={'email': 'admin@example.com'})
|
||||
u.is_superuser = True; u.is_staff = True; u.set_password('frepple'); u.save()
|
||||
print('admin user ready')
|
||||
" ) \
|
||||
|| { echo "FATAL: frepple setup did not complete — the app would not serve." >&2; exit 1; }
|
||||
;;
|
||||
freeitsm)
|
||||
# Plain PHP / Apache, no composer. config.php is left exactly as upstream tracks it
|
||||
# (the image puts its Windows-path require on include_path); db_config.php is the
|
||||
# doc-root stub the test scripts require, excluded locally so git status stays clean.
|
||||
# Apache writes attachments and imports as www-data, but a bind mount can force those
|
||||
# dirs root-owned and swallow the chown, so the directory mode is what has to give.
|
||||
( cd /workspace/repo \
|
||||
&& cp docker/db_config.php db_config.php \
|
||||
&& _fi_ex="$(git rev-parse --git-path info/exclude)" \
|
||||
&& mkdir -p "$(dirname "$_fi_ex")" \
|
||||
&& { grep -qxF 'db_config.php' "$_fi_ex" 2>/dev/null \
|
||||
|| echo 'db_config.php' >> "$_fi_ex"; } \
|
||||
&& for _fi_d in tickets/attachments change-management/attachments \
|
||||
uploads/asset-imports uploads/documents; do \
|
||||
mkdir -p "$_fi_d"; \
|
||||
chown -R www-data:www-data "$_fi_d" 2>/dev/null || true; \
|
||||
find "$_fi_d" -type d -exec chmod a+rwx {} +; \
|
||||
done \
|
||||
&& if [ "$(mysql -u root -N -e "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema='freeitsm'" 2>/dev/null || echo 0)" -lt 10 ]; then
|
||||
mysql -u root freeitsm < database/freeitsm.sql \
|
||||
|| { echo "FATAL: could not load database/freeitsm.sql — is the freeitsm database present?" >&2; exit 1; }
|
||||
fi \
|
||||
&& apache2ctl -k start 2>/dev/null \
|
||||
&& /usr/local/bin/freeitsm-seed.sh \
|
||||
&& apache2ctl -k stop 2>/dev/null ) \
|
||||
|| { echo "FATAL: freeitsm setup did not complete — the app would not log in." >&2; exit 1; }
|
||||
;;
|
||||
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
|
||||
@@ -389,6 +481,16 @@ CALL_METADATA="$CALL_METADATA" node -e '
|
||||
`${home}/.claude/settings.json`,
|
||||
JSON.stringify({ env }, null, 2) + "\n"
|
||||
);
|
||||
|
||||
// Onboarding preflights api.anthropic.com + platform.claude.com, neither from
|
||||
// ANTHROPIC_BASE_URL, and exits 1 unresolved, so a jailed container never records it done.
|
||||
const cfgPath = `${home}/.claude.json`;
|
||||
let cfg = {};
|
||||
try {
|
||||
cfg = JSON.parse(fs.readFileSync(cfgPath, "utf-8"));
|
||||
} catch {}
|
||||
cfg.hasCompletedOnboarding = true;
|
||||
fs.writeFileSync(cfgPath, JSON.stringify(cfg, null, 2) + "\n");
|
||||
'
|
||||
|
||||
# Reference-data corpus: expose it at the stable /data/zeta-corpus path (the same path a trial
|
||||
@@ -426,8 +528,8 @@ bash /workspace/welcome.sh explore 2>/dev/null
|
||||
|
||||
_AK="fde503c3bdb6e5cc9c48b1f8e4c2abeb"
|
||||
_DK="e966e45af5ad1a18005f9fdb831186ea"
|
||||
_WID="w-mu1wvj9k-gtnk"
|
||||
_VER="037cfcf94b"
|
||||
_WID="w-mun3wr6n-v83f"
|
||||
_VER="1.0.0"
|
||||
_CT="explore"
|
||||
_RP=$(node -e "try{process.stdout.write(require('/workspace/toolkit.json').repo)}catch{}" 2>/dev/null)
|
||||
_SID="$(date +%s)-$$"
|
||||
|
||||
@@ -209,6 +209,20 @@ case "$REPO_NAME" in
|
||||
wait_for_pg
|
||||
for _ in $(seq 1 60); do mongo_up && break; sleep 0.5; done
|
||||
;;
|
||||
frepple)
|
||||
# Provisioned at image build time (the CLI overrides ENTRYPOINT); just start it.
|
||||
pg_ctlcluster "$(ls /etc/postgresql | head -1)" main start 2>/dev/null || true
|
||||
for i in $(seq 1 60); do pg_isready -h 127.0.0.1 -q && break; sleep 0.5; done
|
||||
;;
|
||||
freeitsm)
|
||||
# MySQL 8 (Percona). The database and app user are created at image BUILD time —
|
||||
# the devcontainer CLI overrides ENTRYPOINT, so nothing there would run.
|
||||
if ! mysqladmin ping >/dev/null 2>&1; then
|
||||
sudo mkdir -p /var/run/mysqld && sudo chown -R mysql:mysql /var/run/mysqld /var/lib/mysql 2>/dev/null || true
|
||||
sudo service mysql start >/dev/null 2>&1 || (sudo mysqld_safe --user=mysql >/dev/null 2>&1 &) || echo "warning: mysql start failed" >&2
|
||||
fi
|
||||
for i in $(seq 1 120); do mysqladmin ping >/dev/null 2>&1 && break; sleep 0.5; done
|
||||
;;
|
||||
breezy-complete)
|
||||
# Postgres + Redis (Sidekiq). Start both; wait_for_pg is the gate. Trust
|
||||
# auth (set in the image) — PGPASSWORD is baked but inert, no role seeding.
|
||||
|
||||
@@ -177,6 +177,12 @@ async function create(name) {
|
||||
// so a collision would silently point the client's livereload at the other container.
|
||||
if (ports.livereloadHost)
|
||||
env.EXPLORE_LIVERELOAD_PORT = String(await freePort(ports.livereloadHost + 10));
|
||||
// Above clientPort, not just near its own base: freePort releases each probe before it
|
||||
// resolves, so two independent calls can hand back the same number.
|
||||
if (ports.companionHost)
|
||||
env.EXPLORE_COMPANION_PORT = String(
|
||||
await freePort(Math.max(Number(ports.companionHost) + 10, clientPort + 1))
|
||||
);
|
||||
up(name, env);
|
||||
reportUp(name, tk);
|
||||
}
|
||||
|
||||
@@ -652,6 +652,13 @@ if (gitRepo) {
|
||||
git('read-tree HEAD', { env: indexEnv });
|
||||
git('add -A', { env: indexEnv });
|
||||
patch = git('diff --cached --binary --full-index HEAD', diffOpts);
|
||||
if (patch) {
|
||||
console.error(
|
||||
'Warning: no turn checkpoint was found, so snapshot.patch holds every change in the ' +
|
||||
'working tree, including edits the agent made during the captured turn. Check it ' +
|
||||
'and remove those before converting the snapshot to a task.'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
@@ -86,3 +86,14 @@ never a numeric magnitude, never points, never a cap or pinned score: the
|
||||
grader sizes the subtraction itself. Always state the behavior that does NOT trip the penalty.
|
||||
Never describe how criteria combine into an overall score.>
|
||||
`;
|
||||
|
||||
/** The title names the task, not its author: a leading `<EUID>-` (the worker's 12-char id,
|
||||
* which workers put on their task dir) is dropped. Anything else is used as given. */
|
||||
export function rubricTitleSlug(slug: string): string {
|
||||
return slug.replace(/^(?=[A-Z0-9]*\d)[A-Z0-9]{12}-(?=\S)/, '');
|
||||
}
|
||||
|
||||
/** The scaffold with `<task-slug>` filled in for a task whose name is already known. */
|
||||
export function holisticRubricScaffoldFor(slug: string): string {
|
||||
return HOLISTIC_RUBRIC_SCAFFOLD.replace('<task-slug>', rubricTitleSlug(slug));
|
||||
}
|
||||
|
||||
@@ -2,4 +2,4 @@
|
||||
* Plugin-side re-export, so snapshot-to-task.ts resolves `./lib/copy-tree`
|
||||
* both here and in the toolkit's flat scripts/ dir.
|
||||
*/
|
||||
export * from '../../../../raccoon-worker-toolkit/static/scripts/lib/copy-tree';
|
||||
export * from '../../../../static/scripts/lib/copy-tree';
|
||||
|
||||
@@ -24,7 +24,7 @@ import { hideBin } from 'yargs/helpers';
|
||||
|
||||
import { stripAuthoringScaffolding, truncationIndex, turnsFromLines } from './harness-session.mjs';
|
||||
// This script must not call cpSync — it fails EACCES on a macOS docker bind mount.
|
||||
import { HOLISTIC_RUBRIC_SCAFFOLD } from './holistic-rubric-scaffold';
|
||||
import { holisticRubricScaffoldFor } from './holistic-rubric-scaffold';
|
||||
import { copyTree } from './lib/copy-tree';
|
||||
import { collectCwds, sanitizeSessionJsonl } from './sanitize-session-jsonl';
|
||||
|
||||
@@ -234,6 +234,7 @@ mkdirSync(join(taskDir, 'reference-runs'), { recursive: true });
|
||||
// task-shared/ are skipped by the existsSync guard below.
|
||||
const sharedFiles = [
|
||||
{ src: 'test.sh', dest: 'tests/test.sh' },
|
||||
{ src: 'codex-grader.py', dest: 'tests/codex-grader.py' },
|
||||
{
|
||||
src: 'grader-system-prompt-consolidated.md',
|
||||
dest: 'tests/grader-system-prompt-consolidated.md',
|
||||
@@ -663,6 +664,7 @@ gpus = 0
|
||||
allow_internet = true
|
||||
|
||||
[verifier.env]
|
||||
GRADER_HARNESS = "codex"
|
||||
ANTHROPIC_API_KEY = "\${ANTHROPIC_API_KEY}"
|
||||
ANTHROPIC_BASE_URL = "\${ANTHROPIC_BASE_URL}"
|
||||
|
||||
@@ -764,7 +766,7 @@ const holisticRubricMd = `<!--
|
||||
when you are done.
|
||||
-->
|
||||
|
||||
${HOLISTIC_RUBRIC_SCAFFOLD}`;
|
||||
${holisticRubricScaffoldFor(slug)}`;
|
||||
|
||||
writeFileSync(join(taskDir, 'tests', 'holistic-rubric.md'), holisticRubricMd);
|
||||
log.info('Scaffolded tests/holistic-rubric.md (needs manual editing)');
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
/home/eric/workspaces/dataannotation/current-project/worker-toolkit-potion-polyglot/repos
|
||||
@@ -29,6 +29,9 @@ REPO_NAME=$(node -e "try{process.stdout.write(require('/workspace/toolkit.json')
|
||||
# $EXPLORE_CLIENT_PORT; prefer it, falling back to toolkit.json then 3000 for
|
||||
# older containers built before this var existed.
|
||||
CLIENT_HOST_PORT="${EXPLORE_CLIENT_PORT:-$(node -e "try{process.stdout.write(String(require('/workspace/toolkit.json').explorePorts.clientHost))}catch{process.stdout.write('3000')}" 2>/dev/null || echo 3000)}"
|
||||
# Companion services publish host:container IDENTICAL (see package-worker-toolkit), so this one
|
||||
# value is both what the service binds and what the browser reaches.
|
||||
COMPANION_PORT="${EXPLORE_COMPANION_PORT:-$(node -e "try{process.stdout.write(String(require('/workspace/toolkit.json').explorePorts.companionHost||4201))}catch{process.stdout.write('4201')}" 2>/dev/null || echo 4201)}"
|
||||
|
||||
# --- process helpers ---------------------------------------------------------
|
||||
|
||||
@@ -82,6 +85,10 @@ stop_app() {
|
||||
_kill_pidfile "$pf"
|
||||
stopped=1
|
||||
done
|
||||
# frePPLe's planning engine daemonizes itself, so no pidfile covers it.
|
||||
if [ "${REPO_NAME:-}" = "frepple" ] && [ -x /workspace/repo/frepplectl.py ]; then
|
||||
( cd /workspace/repo && ./frepplectl.py stopwebservice ) >/dev/null 2>&1 || true
|
||||
fi
|
||||
if [ "$stopped" = 1 ]; then printf "${GRAY}Stopped the app.${RESET}\n"; else printf "${GRAY}Nothing to stop.${RESET}\n"; fi
|
||||
}
|
||||
|
||||
@@ -500,17 +507,20 @@ setup_repo() {
|
||||
printf " ${GRAY}first-time setup for %s (%s) \xe2\x80\x94 runs once\xe2\x80\xa6${RESET}\n" "$repo" "${runtime:-explore-only}"
|
||||
case "$kind" in
|
||||
elixir)
|
||||
# asdf-only (no rbenv/nvm estate has elixir). Version comes from the member's
|
||||
# .tool-versions; shims are already on PATH. deps + a MIX_ENV=test compile so the
|
||||
# Version comes from the member's .tool-versions where asdf manages it, else from
|
||||
# the image. dev.secret.exs is seeded BEFORE any mix task: every task evaluates
|
||||
# config/<env>.exs, so a member whose config imports it can't even run local.hex
|
||||
# without it. deps + a MIX_ENV=test compile so the
|
||||
# suite is warm and compile errors surface at setup, not mid-explore. bootEnv covers
|
||||
# any compile-time env a member reads (e.g. epihub's ZOOM_* module attributes). DB/ecto
|
||||
# prep is member-specific → leave it to setupCmd; a worker runs `mix test` with it.
|
||||
( cd "$dir" \
|
||||
&& for kv in $bootenv; do export "$kv"; done \
|
||||
&& mix local.hex --force >/dev/null 2>&1 \
|
||||
&& mix local.rebar --force >/dev/null 2>&1 \
|
||||
&& { [ -f config/dev.secret.exs.example ] && [ ! -f config/dev.secret.exs ] && cp config/dev.secret.exs.example config/dev.secret.exs; true; } \
|
||||
&& mix deps.get \
|
||||
&& { mix local.hex --force >/dev/null 2>&1 \
|
||||
|| printf " ${GRAY}(hex not refreshed \xe2\x80\x94 using the image's copy)${RESET}\n"; } \
|
||||
&& { mix local.rebar --force >/dev/null 2>&1 || true; } \
|
||||
&& mix deps.get </dev/null \
|
||||
&& MIX_ENV=test mix compile ) || return 1 ;;
|
||||
ruby)
|
||||
if _asdf_ok; then
|
||||
@@ -855,19 +865,61 @@ start_poly() {
|
||||
cmd="env $bootenv CARGO_TARGET_DIR=/opt/raccoon-cargo-target/$repo $startcmd" ;;
|
||||
*) printf "${YELLOW}runtime '%s' for %s isn't runnable here \xe2\x80\x94 explore-only.${RESET}\n" "$runtime" "$repo"; return 0 ;;
|
||||
esac
|
||||
# Companion services a member cannot work without. strongsuit-app is a front end to the
|
||||
# strongsuit_phx Phoenix backend, and it does not degrade when that is absent:
|
||||
# getImportantDateRecommendations rethrows the connection failure and none of its four
|
||||
# callers catch it, so those pages throw instead of rendering an empty list.
|
||||
case "$repo" in
|
||||
strongsuit-app)
|
||||
local phx_dir=/workspace/repos/strongsuit_phx
|
||||
# Every absolute link the app renders is built from DOMAIN, so it has to carry the
|
||||
# port the worker's browser reaches — which instance.js moves per named instance.
|
||||
cmd="env DOMAIN=http://localhost:$CLIENT_HOST_PORT PHX_DOMAIN=localhost:$COMPANION_PORT $cmd"
|
||||
# Members are set up lazily, and nothing else ever runs setup_repo for a member that
|
||||
# is never itself the target. After strongsuit-app's own setup, so the database it
|
||||
# creates and seeds exists before phx's migration baseline and seed read it.
|
||||
setup_repo strongsuit_phx \
|
||||
|| printf " ${YELLOW}\xe2\x9a\xa0 strongsuit_phx setup failed \xe2\x80\x94 ${RESET}${GRAY}run-app --logs${RESET}\n"
|
||||
# The DB-dependent half runs on EVERY boot, not once: setup_repo's marker is set even
|
||||
# when its work was skipped, so a worker who ran `run-app strongsuit_phx` first (no
|
||||
# database yet) would otherwise be stuck with phx 503ing on unbaselined migrations.
|
||||
# Both scripts are idempotent and cheap once prepared.
|
||||
( bash /workspace/scripts/seed/setup-strongsuit-phx.sh "$phx_dir" \
|
||||
&& bash /workspace/scripts/seed/seed-important-date-recommendations.sh ) \
|
||||
>> "$RUN_DIR/setup-strongsuit_phx.log" 2>&1 \
|
||||
|| printf " ${YELLOW}\xe2\x9a\xa0 strongsuit_phx database prep failed \xe2\x80\x94 ${RESET}${GRAY}run-app --logs${RESET}\n"
|
||||
if [ -d "$phx_dir/deps" ] && [ -d "$phx_dir/_build" ]; then
|
||||
printf " ${CYAN}\xe2\x96\xb6${RESET} starting strongsuit_phx (elixir)\xe2\x80\xa6\n"
|
||||
# Derived, not a second env var: the app sends PHX_AUTH_TOKEN and the phx plug
|
||||
# compares against API_AUTH_TOKEN, and a drift shows up only as silent 401s.
|
||||
_spawn phx "$phx_dir" "env MIX_ENV=dev PHX_PORT=$COMPANION_PORT API_AUTH_TOKEN=${PHX_AUTH_TOKEN:-dummy} mix phx.server"
|
||||
_wait_tcp "$COMPANION_PORT" 45 || printf " ${YELLOW}\xe2\x9a\xa0 strongsuit_phx didn't come up \xe2\x80\x94 ${RESET}${GRAY}run-app --logs${RESET}\n"
|
||||
else
|
||||
printf " ${GRAY}strongsuit_phx isn't built \xe2\x80\x94 the backend on :%s will be absent.\n" "$COMPANION_PORT"
|
||||
printf " build it: ${RESET}${GRAY}bash /workspace/scripts/seed/setup-strongsuit-phx.sh${RESET}\n"
|
||||
fi ;;
|
||||
esac
|
||||
printf " ${CYAN}\xe2\x96\xb6${RESET} starting %s (%s)\xe2\x80\xa6\n" "$repo" "$runtime"
|
||||
_spawn app "$dir" "$cmd"
|
||||
if _wait_tcp 3000; then
|
||||
printf " ${CYAN}\xe2\x9c\x85 %s is up${RESET} open ${CYAN}http://localhost:%s${RESET}\n" "$repo" "$CLIENT_HOST_PORT"
|
||||
# Members whose usable entry point isn't "/". strongsuit-app's is the local dev-login
|
||||
# route: "/" redirects to a hosted Auth0 tenant that can't be reached offline, so the
|
||||
# URL printed here — the one a terminal makes clickable — has to be the one that works.
|
||||
local landing=""
|
||||
case "$repo" in
|
||||
strongsuit-app) landing="/dev-login" ;;
|
||||
esac
|
||||
printf " ${CYAN}\xe2\x9c\x85 %s is up${RESET} open ${CYAN}http://localhost:%s%s${RESET}\n" "$repo" "$CLIENT_HOST_PORT" "$landing"
|
||||
# Per-member "how do I actually get in" notes. Only members whose landing page needs
|
||||
# more than the URL need an entry here (e.g. an app whose real sign-in is a hosted
|
||||
# third-party login that can't be reached offline).
|
||||
case "$repo" in
|
||||
strongsuit-app)
|
||||
printf " ${GRAY}Sign-in normally goes through a hosted Auth0 page, which isn't reachable\n"
|
||||
printf " offline, so this app ships a local-only dev-login route. Open\n"
|
||||
printf " ${RESET}${CYAN}http://localhost:%s/dev-login${RESET}${GRAY} to sign in as a seeded admin\n" "$CLIENT_HOST_PORT"
|
||||
printf " (${RESET}${GRAY}?role=MSS${RESET}${GRAY} or ${RESET}${GRAY}?role=MEMBER${RESET}${GRAY} for the other roles). The DB was seeded during setup.${RESET}\n"
|
||||
printf " offline; the link above is a local-only dev-login route that signs you in\n"
|
||||
printf " as a seeded admin (${RESET}${GRAY}?role=MSS${RESET}${GRAY} or ${RESET}${GRAY}?role=MEMBER${RESET}${GRAY} for the other roles).\n"
|
||||
printf " The DB was seeded during setup. Plain ${RESET}${GRAY}http://localhost:%s/${RESET}${GRAY} redirects to\n" "$CLIENT_HOST_PORT"
|
||||
printf " Auth0 and cannot work offline.${RESET}\n"
|
||||
;;
|
||||
ABDM-FE)
|
||||
printf " ${GRAY}This app is served under a ${RESET}${GRAY}/app${RESET}${GRAY} basename, so the bare URL above renders\n"
|
||||
@@ -902,6 +954,53 @@ start_poly() {
|
||||
# passes the demo login to print. Optional $2 is a one-line note printed above the
|
||||
# login (e.g. a subdomain caveat).
|
||||
# start_rails <login-hint> [url-note]
|
||||
start_frepple() {
|
||||
# Django dev server; the C++ engine is already built in-tree by post-create.
|
||||
_spawn app /workspace/repo "./frepplectl.py runserver 0.0.0.0:3000"
|
||||
printf " ${YELLOW}\xe2\x96\xb6${RESET} starting the frePPLe web app (Django)\xe2\x80\xa6\n"
|
||||
printf " ${GRAY}\xe2\x8f\xb3 waiting for the app to come up\xe2\x80\xa6${RESET}\n"
|
||||
if _wait_tcp 3000; then
|
||||
printf " ${YELLOW}\xe2\x9c\x85 app is up${RESET}\n"
|
||||
# Django serves plan data read-only; the forecast editor and the plan screens save by
|
||||
# POSTing from the browser to the engine's web service on 8002. Django starts it on
|
||||
# first login, so start it here instead and the first save can't race the plan load.
|
||||
printf " ${YELLOW}\xe2\x96\xb6${RESET} loading the plan into the planning engine\xe2\x80\xa6\n"
|
||||
( cd /workspace/repo && ./frepplectl.py runwebservice --daemon --forcerestart \
|
||||
>>"$RUN_DIR/webservice.log" 2>&1 ) || true
|
||||
if _wait_tcp 8002 300; then
|
||||
printf " ${YELLOW}\xe2\x9c\x85 planning engine is up${RESET}\n"
|
||||
else
|
||||
printf " ${RED}\xe2\x9a\xa0 the planning engine didn't come up \xe2\x80\x94 editing a forecast won't save${RESET}\n"
|
||||
printf " check the logs: ${GRAY}%s/webservice.log${RESET}\n" "$RUN_DIR"
|
||||
fi
|
||||
printf " open ${YELLOW}http://localhost:%s${RESET}\n" "$CLIENT_HOST_PORT"
|
||||
printf " login ${GRAY}admin / frepple${RESET}\n"
|
||||
else
|
||||
printf " ${RED}\xe2\x9a\xa0 the app didn't come up in time${RESET}\n"
|
||||
printf " check the logs: ${GRAY}run-app --logs${RESET}\n"
|
||||
fi
|
||||
printf " logs ${GRAY}%s/app.log${RESET}\n" "$RUN_DIR"
|
||||
printf " stop ${GRAY}run-app --stop${RESET}\n"
|
||||
}
|
||||
|
||||
start_freeitsm() {
|
||||
# Plain PHP behind Apache — no dev server. -DFOREGROUND keeps it in _spawn's
|
||||
# process group so --logs and --stop behave like every other repo.
|
||||
_spawn app /workspace/repo "apache2ctl -DFOREGROUND"
|
||||
printf " ${YELLOW}\xe2\x96\xb6${RESET} starting Apache (mod_php)\xe2\x80\xa6\n"
|
||||
printf " ${GRAY}\xe2\x8f\xb3 waiting for the app to come up\xe2\x80\xa6${RESET}\n"
|
||||
if _wait_tcp 3000; then
|
||||
printf " ${YELLOW}\xe2\x9c\x85 app is up${RESET}\n"
|
||||
printf " open ${YELLOW}http://localhost:%s${RESET}\n" "$CLIENT_HOST_PORT"
|
||||
printf " login ${GRAY}admin / freeitsm123 (staff sign-in; setup already cleared the forced change)${RESET}\n"
|
||||
else
|
||||
printf " ${RED}\xe2\x9a\xa0 the app didn't come up in time${RESET}\n"
|
||||
printf " check the logs: ${GRAY}run-app --logs${RESET}\n"
|
||||
fi
|
||||
printf " logs ${GRAY}%s/app.log${RESET}\n" "$RUN_DIR"
|
||||
printf " stop ${GRAY}run-app --stop${RESET}\n"
|
||||
}
|
||||
|
||||
start_rails() {
|
||||
local login_hint="${1:-}" url_note="${2:-}"
|
||||
_spawn app /workspace/repo "bin/rails server -b 0.0.0.0 -p 3000"
|
||||
@@ -952,6 +1051,8 @@ start_app() {
|
||||
# welcome page. No login to print. The app grows over time.
|
||||
start_rails "" "young app — no routes defined yet, so this shows the default Rails welcome page" ;;
|
||||
breezy-complete) start_breezy_complete ;;
|
||||
frepple) start_frepple ;;
|
||||
freeitsm) start_freeitsm ;;
|
||||
*)
|
||||
printf "${YELLOW}run-app isn't configured for repo '%s'.${RESET}\n" "${REPO_NAME:-unknown}"
|
||||
printf "Start the app with the project's own dev command from ${GRAY}/workspace/repo${RESET}.\n"
|
||||
|
||||
@@ -53,6 +53,38 @@ _harness_trim() {
|
||||
printf '%s' "${out:-$1}"
|
||||
}
|
||||
|
||||
# Every env var a harness authenticates from, registry-derived so a new harness row is
|
||||
# covered without touching this. ANTHROPIC_* unconditionally: it is what .env carries and
|
||||
# what harbor-run hands the trial sandbox, registry or not.
|
||||
_harness_credential_vars() {
|
||||
local id key_env base_url_env proxy_path
|
||||
printf '%s\n' ANTHROPIC_API_KEY ANTHROPIC_BASE_URL
|
||||
while IFS=$'\t' read -r id key_env base_url_env proxy_path; do
|
||||
if [ -n "$key_env" ]; then printf '%s\n' "$key_env"; fi
|
||||
if [ -n "$base_url_env" ]; then printf '%s\n' "$base_url_env"; fi
|
||||
done < <(_harness_query --authoring-credentials 2>/dev/null || true)
|
||||
}
|
||||
|
||||
# Source .env into the CALLER's environment and trim what a harness reads its key from.
|
||||
# For codex the live value is now the env var, not the auth file harness_write_auth
|
||||
# cleans, so a raw `set -a; . .env` is the 401 all over again on a Windows-saved file.
|
||||
harness_load_env() {
|
||||
local file="${1:-${RACCOON_ENV_FILE:-/workspace/.env}}" v
|
||||
if [ -f "$file" ]; then
|
||||
set -a
|
||||
# shellcheck disable=SC1090
|
||||
. "$file" 2>/dev/null || true
|
||||
set +a
|
||||
fi
|
||||
# Trimming twice is a no-op, so a var named by several rows needs no dedupe.
|
||||
while read -r v; do
|
||||
[ -n "$v" ] || continue
|
||||
if [ -n "${!v:-}" ]; then
|
||||
export "$v=$(_harness_trim "${!v}")"
|
||||
fi
|
||||
done < <(_harness_credential_vars)
|
||||
}
|
||||
|
||||
# The proxy root: the worker's ANTHROPIC_BASE_URL minus its provider path.
|
||||
_harness_proxy_root() {
|
||||
local base_url
|
||||
|
||||
@@ -40,7 +40,12 @@ _scripts_dir="${HARNESS_SCRIPTS_DIR:-/workspace/scripts}"
|
||||
# .bashrc (the key, the call origin) nor the profile that puts the CLI on PATH.
|
||||
# Failures stay swallowed — an unreadable .env must not stop the agent starting.
|
||||
export PATH="$HOME/.local/bin:$PATH"
|
||||
if [ -f "${RACCOON_ENV_FILE:-/workspace/.env}" ]; then
|
||||
# shellcheck disable=SC1091
|
||||
HARNESS_SCRIPTS_DIR="$_scripts_dir" . "$_scripts_dir/lib/harness-credentials.sh" 2>/dev/null || true
|
||||
if command -v harness_load_env >/dev/null 2>&1; then
|
||||
harness_load_env || true
|
||||
elif [ -f "${RACCOON_ENV_FILE:-/workspace/.env}" ]; then
|
||||
# Untrimmed, but a key with a stray \r beats no key at all.
|
||||
set -a
|
||||
# shellcheck disable=SC1090
|
||||
. "${RACCOON_ENV_FILE:-/workspace/.env}" 2>/dev/null || true
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
#!/usr/bin/env bash
|
||||
# Give the personalization surface something to work on, offline.
|
||||
#
|
||||
# important_date_recommendation rows are what the member and MSS home pages count and what
|
||||
# /member/important-date-recommendations lists. In production the Phoenix NewAccountWorker
|
||||
# produces them from a member's Cronofy calendar plus an LLM call — neither reachable offline,
|
||||
# so the table stays empty however long the app runs and the feature looks broken when it is
|
||||
# only unfed. This synthesizes the same rows from the seed's own contacts and their birthdays.
|
||||
# cronofy_event_id is left null: the column is nullable with no foreign key, only the Ecto
|
||||
# changeset requires it, and the read path preloads it to nil.
|
||||
#
|
||||
# Runs inside the Explore container, from run-app's strongsuit-app companion block:
|
||||
#
|
||||
# bash /workspace/scripts/seed/seed-important-date-recommendations.sh [database]
|
||||
set -euo pipefail
|
||||
DB="${1:-${PGDATABASE:-strongsuit}}"
|
||||
|
||||
# The app's own setup creates and seeds this database; without it there is nothing to read.
|
||||
if ! PGPASSWORD="${PGPASSWORD:-postgres}" psql -h "${PGHOST:-localhost}" -U "${PGUSER:-postgres}" \
|
||||
-d "$DB" -tAc "select 1 from important_date_recommendation limit 1" >/dev/null 2>&1; then
|
||||
echo " database \"$DB\" has no app schema yet — nothing to seed."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
PGPASSWORD="${PGPASSWORD:-postgres}" psql -h "${PGHOST:-localhost}" -U "${PGUSER:-postgres}" \
|
||||
-d "$DB" -v ON_ERROR_STOP=1 <<'SQL'
|
||||
with member_family as (
|
||||
select u.id as user_id, u.person_id, fu.family_id
|
||||
from "user" u
|
||||
join family_user fu on fu.user_id = u.id
|
||||
where u.role = 'MEMBER' and u.deleted_at is null
|
||||
),
|
||||
-- A family's contacts hang off its principal person, who is often NOT a user: the seeded member
|
||||
-- user is a spouse, and the birthdays sit on the principal's relationships. So expand one hop
|
||||
-- (either direction) from the member's own person before reading contacts off person1, which is
|
||||
-- the direction app/models/person.server.ts queries.
|
||||
member_people as (
|
||||
select user_id, family_id, person_id from member_family
|
||||
union
|
||||
select mf.user_id, mf.family_id,
|
||||
case when r.person1_id = mf.person_id then r.person2_id else r.person1_id end
|
||||
from member_family mf
|
||||
join relationship r
|
||||
on (r.person1_id = mf.person_id or r.person2_id = mf.person_id)
|
||||
and r.deleted_at is null
|
||||
)
|
||||
insert into important_date_recommendation
|
||||
(id, important_date_type, date, member_user_id, cronofy_event_id,
|
||||
created_at, updated_at, status, first_name, last_name, family_id)
|
||||
select
|
||||
-- family_id is part of the key: a member in two families gets one row per family. The guard
|
||||
-- below keys on names rather than d.id, so it is the coarser of the two.
|
||||
'seed_idr_' || substr(md5(mf.user_id || p2.id || d.id || coalesce(mf.family_id, '')), 1, 20),
|
||||
lower(d.type::text),
|
||||
occ.occurs_on + time '09:00',
|
||||
mf.user_id,
|
||||
null,
|
||||
now(), now(), 'pending',
|
||||
p2.first_name, p2.last_name,
|
||||
mf.family_id
|
||||
from member_family mf
|
||||
join member_people mp on mp.user_id = mf.user_id and mp.family_id = mf.family_id
|
||||
join relationship r on r.person1_id = mp.person_id and r.deleted_at is null
|
||||
join person p2 on p2.id = r.person2_id
|
||||
join important_date d on d.person_id = p2.id and d.type in ('BIRTHDAY', 'ANNIVERSARY')
|
||||
and d.deleted_at is null
|
||||
-- The next occurrence, so the list reads as something upcoming rather than a set of
|
||||
-- anniversaries that all fell in 1970. The day is clamped to the last of its month because a
|
||||
-- Feb-29 date has no counterpart in a common year and make_date() raises rather than rounding,
|
||||
-- which under ON_ERROR_STOP would abort the whole seed rather than skip one row.
|
||||
cross join lateral (
|
||||
select occurs_on from (
|
||||
select make_date(gs.yr, d.month,
|
||||
least(d.day,
|
||||
extract(day from (make_date(gs.yr, d.month, 1)
|
||||
+ interval '1 month' - interval '1 day'))::int)) as occurs_on
|
||||
from generate_series(extract(year from current_date)::int,
|
||||
extract(year from current_date)::int + 1) as gs(yr)
|
||||
) c
|
||||
where c.occurs_on >= current_date
|
||||
order by c.occurs_on
|
||||
limit 1
|
||||
) occ
|
||||
where p2.id <> mf.person_id
|
||||
-- Skips any member/family/person/date-type that already has a recommendation, including ones
|
||||
-- the member has since accepted or declined; `on conflict` covers rows an earlier run wrote.
|
||||
and not exists (
|
||||
select 1 from important_date_recommendation x
|
||||
where x.member_user_id = mf.user_id
|
||||
and x.family_id is not distinct from mf.family_id
|
||||
and x.important_date_type = lower(d.type::text)
|
||||
and x.first_name is not distinct from p2.first_name
|
||||
and x.last_name is not distinct from p2.last_name
|
||||
)
|
||||
on conflict (id) do nothing;
|
||||
|
||||
select count(*) as pending_recommendations
|
||||
from important_date_recommendation where status = 'pending';
|
||||
SQL
|
||||
98
worker-toolkit-potion-polyglot/explore/scripts/seed/setup-strongsuit-phx.sh
Executable file
98
worker-toolkit-potion-polyglot/explore/scripts/seed/setup-strongsuit-phx.sh
Executable file
@@ -0,0 +1,98 @@
|
||||
#!/usr/bin/env bash
|
||||
# Prepare strongsuit_phx to run against the same database the Remix app uses.
|
||||
#
|
||||
# Three things stand between a checkout and a working service, none of them a code change:
|
||||
#
|
||||
# 1. config/dev.exs ends with `import_config "dev.secret.exs"`, so mix won't boot without that
|
||||
# gitignored file. run-app's elixir setup seeds it from dev.secret.exs.example, which carries
|
||||
# no Repo override — so this script OVERWRITES rather than skipping when it already exists.
|
||||
# 2. dev.exs points Ecto at the database "postgres", but the two services share ONE database and
|
||||
# the toolkit seeds "strongsuit". Left alone, phx 401s every request from an empty user table.
|
||||
# 3. Prisma owns the schema, so the tables exist but Ecto's schema_migrations is empty. The
|
||||
# migrations are recorded as applied rather than run; otherwise the dev-only CheckRepoStatus
|
||||
# plug 503s every request.
|
||||
#
|
||||
# Idempotent. Run after the strongsuit-app setup, which creates and seeds the database.
|
||||
set -euo pipefail
|
||||
REPO_DIR="${1:-/workspace/repos/strongsuit_phx}"
|
||||
DB="${PGDATABASE:-strongsuit}"
|
||||
|
||||
cat > "$REPO_DIR/config/dev.secret.exs" <<'ELIXIR'
|
||||
# Local development config for the offline toolkit container. Generated by
|
||||
# explore/scripts/seed/setup-strongsuit-phx.sh; gitignored, so not a change to the repo.
|
||||
# Every credential here is an inert dummy: none of these services is reachable offline.
|
||||
import Config
|
||||
|
||||
# The Remix app and this service share one database, and the toolkit seeds "strongsuit".
|
||||
config :scrubbed011_phx, Scrubbed011Phx.Repo, database: "strongsuit"
|
||||
|
||||
# The port both sides of PHX_DOMAIN agree on. dev.exs hardcodes 4000, which this toolkit already
|
||||
# publishes for another estate, so the caller passes its own.
|
||||
# Only the port is overridden here: Config deep-merges keyword lists, so a `watchers: []` would
|
||||
# merge INTO dev.exs's list rather than replace it. The esbuild watcher therefore still runs and
|
||||
# still fails on the missing assets/vendor/topbar -- once, without restarting, and the endpoint
|
||||
# serves throughout. The API the Remix app calls needs no bundle.
|
||||
config :scrubbed011_phx, Scrubbed011PhxWeb.Endpoint,
|
||||
http: [ip: {0, 0, 0, 0}, port: String.to_integer(System.get_env("PHX_PORT") || "4201")]
|
||||
|
||||
config :scrubbed011_phx, Scrubbed011Phx.ApiClients.Cio,
|
||||
host: "https://track.customer.io",
|
||||
site_id: "dummy",
|
||||
api_key: "dummy"
|
||||
|
||||
config :scrubbed011_phx, Scrubbed011Phx.ApiClients.Twilio,
|
||||
account_sid: "dummy",
|
||||
auth_token: "dummy",
|
||||
messaging_service_sid: "dummy"
|
||||
|
||||
config :scrubbed011_phx, Scrubbed011Phx.TalkJsMessages, twilio_from_number: "+15005550006"
|
||||
config :scrubbed011_phx, Scrubbed011PhxWeb.Plugs.TalkJsWebhook, secret_key: "dummy"
|
||||
config :langchain, :anthropic_key, "dummy"
|
||||
|
||||
config :scrubbed011_phx, Scrubbed011Phx.ApiClients.Talkjs,
|
||||
app_id: "dummy",
|
||||
secret_key: "dummy"
|
||||
|
||||
config :scrubbed011_phx, Scrubbed011Phx.ApiClients.CronofyApi,
|
||||
host: "https://api.cronofy.com",
|
||||
client_id: "dummy",
|
||||
client_secret: "dummy"
|
||||
|
||||
# The Remix app, as this service sees it: same container, its own port.
|
||||
config :scrubbed011_phx, Scrubbed011Phx.ApiClients.Scrubbed011App,
|
||||
host: "http://localhost:3000",
|
||||
ss_app_api_key: "dummy"
|
||||
ELIXIR
|
||||
echo " wrote config/dev.secret.exs"
|
||||
|
||||
cd "$REPO_DIR"
|
||||
mix local.hex --force >/dev/null 2>&1 || true
|
||||
mix local.rebar --force >/dev/null 2>&1 || true
|
||||
MIX_ENV=dev mix deps.get
|
||||
# assets.setup only downloads the esbuild/tailwind binaries, which has to happen while there is
|
||||
# still a network; it does NOT build a bundle (see the watchers note above). NOT `mix setup`:
|
||||
# that alias runs ecto.setup, and Prisma owns this schema.
|
||||
MIX_ENV=dev mix assets.setup
|
||||
MIX_ENV=dev mix compile
|
||||
|
||||
# Record the migrations Prisma has already applied the equivalent of. Skipped when the database
|
||||
# isn't there yet, which is what `run-app strongsuit_phx` on its own looks like — the app's own
|
||||
# setup is what creates and seeds it.
|
||||
if ! PGPASSWORD="${PGPASSWORD:-postgres}" psql -h "${PGHOST:-localhost}" -U "${PGUSER:-postgres}" \
|
||||
-d "$DB" -tAc 'select 1' >/dev/null 2>&1; then
|
||||
echo " database \"$DB\" not ready — run \`run-app strongsuit-app\`, which creates it and"
|
||||
echo " starts this service alongside the app."
|
||||
exit 0
|
||||
fi
|
||||
versions=$(ls priv/repo/migrations | sed 's/_.*//' | awk '{printf "(%s, now()),", $1}' | sed 's/,$//')
|
||||
if [ -n "$versions" ]; then
|
||||
PGPASSWORD="${PGPASSWORD:-postgres}" psql -h "${PGHOST:-localhost}" -U "${PGUSER:-postgres}" \
|
||||
-d "$DB" -v ON_ERROR_STOP=1 -q \
|
||||
-c "create table if not exists schema_migrations (
|
||||
version bigint primary key, inserted_at timestamp(0));" \
|
||||
-c "insert into schema_migrations (version, inserted_at) values $versions on conflict (version) do nothing;"
|
||||
echo " baselined $(ls priv/repo/migrations | wc -l | tr -d ' ') migrations in schema_migrations"
|
||||
fi
|
||||
echo "strongsuit_phx ready — start it with: MIX_ENV=dev mix phx.server (listens on :${PHX_PORT:-4201})"
|
||||
echo " its own HTML pages render unstyled, and phx.log carries one esbuild error for the"
|
||||
echo " missing assets/vendor/topbar -- neither affects the JSON API the app uses"
|
||||
@@ -156,7 +156,12 @@ set -euo pipefail
|
||||
# ~/.local/bin, where the CLI itself lives. Both are set here so a launch works the
|
||||
# same either way, with the key .env holds right now.
|
||||
export PATH="\$HOME/.local/bin:\$PATH"
|
||||
if [ -f "\${RACCOON_ENV_FILE:-/workspace/.env}" ]; then
|
||||
# Through the lib, not a bare source: the key a custom codex provider authenticates with
|
||||
# is this env var, and a .env saved on Windows leaves a \\r on it that the proxy 401s.
|
||||
HARNESS_SCRIPTS_DIR="$_HARNESS_REGISTRY_DIR" . "$_HARNESS_REGISTRY_DIR/lib/harness-credentials.sh" 2>/dev/null || true
|
||||
if command -v harness_load_env >/dev/null 2>&1; then
|
||||
harness_load_env || true
|
||||
elif [ -f "\${RACCOON_ENV_FILE:-/workspace/.env}" ]; then
|
||||
set -a
|
||||
. "\${RACCOON_ENV_FILE:-/workspace/.env}"
|
||||
set +a
|
||||
|
||||
@@ -1,298 +0,0 @@
|
||||
{
|
||||
"polyglot": true,
|
||||
"repos": [
|
||||
{
|
||||
"repo": "lambda-cloudwatch-logs-to-loggly",
|
||||
"defaultCommit": "f17e2d3",
|
||||
"runtime": "node:14"
|
||||
},
|
||||
{
|
||||
"repo": "lambda-potion-engagement",
|
||||
"defaultCommit": "c64365b",
|
||||
"runtime": "node:14"
|
||||
},
|
||||
{
|
||||
"repo": "lambda-potion-schedular",
|
||||
"defaultCommit": "0843570",
|
||||
"runtime": "node:14"
|
||||
},
|
||||
{
|
||||
"repo": "lambda-potion-transcription-scheduler",
|
||||
"defaultCommit": "1a2e3d5",
|
||||
"runtime": "node:14"
|
||||
},
|
||||
{
|
||||
"repo": "lambda-video-processing",
|
||||
"defaultCommit": "0e4a9b5",
|
||||
"runtime": "node:18"
|
||||
},
|
||||
{
|
||||
"repo": "microservice-dynamic-screen-recording",
|
||||
"defaultCommit": "31e142b",
|
||||
"runtime": "node:18"
|
||||
},
|
||||
{
|
||||
"repo": "microservice-potion-voice",
|
||||
"defaultCommit": "b65ca17",
|
||||
"runtime": "node:14"
|
||||
},
|
||||
{
|
||||
"repo": "potion-dynamic-screen-recording-lambda",
|
||||
"defaultCommit": "57ed9e6",
|
||||
"runtime": "node:14"
|
||||
},
|
||||
{
|
||||
"repo": "potion-job-consumer",
|
||||
"defaultCommit": "93f8a10",
|
||||
"runtime": "node:18"
|
||||
},
|
||||
{
|
||||
"repo": "potion-job-producer",
|
||||
"defaultCommit": "04663d1",
|
||||
"runtime": "node:18"
|
||||
},
|
||||
{
|
||||
"repo": "potion-video-processing",
|
||||
"defaultCommit": "59c6af9",
|
||||
"runtime": "node:14"
|
||||
},
|
||||
{
|
||||
"repo": "potion-voice",
|
||||
"defaultCommit": "fcd8a9d",
|
||||
"runtime": "node:14"
|
||||
},
|
||||
{
|
||||
"repo": "potion-watcher",
|
||||
"defaultCommit": "0e5973b",
|
||||
"runtime": "node:18"
|
||||
},
|
||||
{
|
||||
"repo": "potion-website-recording-handler",
|
||||
"defaultCommit": "c58a9bb",
|
||||
"runtime": "node:18"
|
||||
},
|
||||
{
|
||||
"repo": "potion-app",
|
||||
"defaultCommit": "f89abccf",
|
||||
"runtime": "node:16",
|
||||
"startCmd": "bash -c \"cp -n .env.client.development .env.local 2>/dev/null || true; export POTION_APP_ENV=local; [ -f .nuxt/store.js ] || npx nuxt build; node scripts/seed-dev-user.js || true; node server/index.js\"",
|
||||
"setupCmd": "bash -c \"cp -n .env.client.development .env.local 2>/dev/null || true; export POTION_APP_ENV=local; [ -f .nuxt/store.js ] || npx nuxt build\""
|
||||
},
|
||||
{
|
||||
"repo": "potion-custom-domain-app",
|
||||
"defaultCommit": "01a7034",
|
||||
"runtime": "none"
|
||||
},
|
||||
{
|
||||
"repo": "potion-website",
|
||||
"defaultCommit": "27995f8",
|
||||
"runtime": "node:16"
|
||||
},
|
||||
{
|
||||
"repo": "browser-extensions",
|
||||
"defaultCommit": "b5e75d4",
|
||||
"runtime": "node:18"
|
||||
},
|
||||
{
|
||||
"repo": "gcp-application",
|
||||
"defaultCommit": "469056f",
|
||||
"runtime": "node:18"
|
||||
},
|
||||
{
|
||||
"repo": "lambda-text-to-speech",
|
||||
"defaultCommit": "99054ac",
|
||||
"runtime": "node:18"
|
||||
},
|
||||
{
|
||||
"repo": "potion-multi-dsr-watcher",
|
||||
"defaultCommit": "c275d7f",
|
||||
"runtime": "node:18",
|
||||
"startCmd": "npx @google-cloud/functions-framework --target=potion-multi-dsr-watcher",
|
||||
"bootEnv": "MONGODB_URI=mongodb://127.0.0.1:27017/potion_dev"
|
||||
},
|
||||
{
|
||||
"repo": "potion-qa",
|
||||
"defaultCommit": "3920e6c",
|
||||
"runtime": "node:18"
|
||||
},
|
||||
{
|
||||
"repo": "potion-snapshot-testing",
|
||||
"defaultCommit": "a80eb8d",
|
||||
"runtime": "node:18"
|
||||
},
|
||||
{
|
||||
"repo": "potion-web",
|
||||
"defaultCommit": "0a7e699",
|
||||
"runtime": "node:18",
|
||||
"startCmd": "npx nuxt dev --host 0.0.0.0 --port 3000",
|
||||
"bootEnv": "POTION_APP_ENV=development BUGSNAG_FRONTEND_KEY=00000000000000000000000000000000 API_BASE_URL=http://localhost:4300 POTION_BASE_URL=http://localhost:4300"
|
||||
},
|
||||
{
|
||||
"repo": "potion-analytics",
|
||||
"defaultCommit": "43a7d23",
|
||||
"runtime": "node:20"
|
||||
},
|
||||
{
|
||||
"repo": "potion-api",
|
||||
"defaultCommit": "5abe18f",
|
||||
"runtime": "node:20"
|
||||
},
|
||||
{
|
||||
"repo": "MODNet-with-training",
|
||||
"defaultCommit": "dace325",
|
||||
"runtime": "python:3.10"
|
||||
},
|
||||
{
|
||||
"repo": "avds-cleaner",
|
||||
"defaultCommit": "bd3a503",
|
||||
"runtime": "python:3.10"
|
||||
},
|
||||
{
|
||||
"repo": "avspeech",
|
||||
"defaultCommit": "ca0f90d",
|
||||
"runtime": "python:3.10"
|
||||
},
|
||||
{
|
||||
"repo": "lambda-datadog-forwarder",
|
||||
"defaultCommit": "a57ae74",
|
||||
"runtime": "python:3.10"
|
||||
},
|
||||
{
|
||||
"repo": "potion-ai",
|
||||
"defaultCommit": "0e454d8",
|
||||
"runtime": "python:3.10"
|
||||
},
|
||||
{
|
||||
"repo": "potion-ai-cpu",
|
||||
"defaultCommit": "ad61fa7",
|
||||
"runtime": "python:3.10"
|
||||
},
|
||||
{
|
||||
"repo": "potion-ai-gpu",
|
||||
"defaultCommit": "8413d71",
|
||||
"runtime": "python:3.10"
|
||||
},
|
||||
{
|
||||
"repo": "potion-stitch",
|
||||
"defaultCommit": "cfaed2f",
|
||||
"runtime": "python:3.10"
|
||||
},
|
||||
{
|
||||
"repo": "potion-tryon",
|
||||
"defaultCommit": "b7da6a2",
|
||||
"runtime": "python:3.10"
|
||||
},
|
||||
{
|
||||
"repo": "potion-video-background-change",
|
||||
"defaultCommit": "e6f2ea4",
|
||||
"runtime": "python:3.10"
|
||||
},
|
||||
{
|
||||
"repo": "potion-voice-dataset",
|
||||
"defaultCommit": "f3d79d6",
|
||||
"runtime": "python:3.10"
|
||||
},
|
||||
{
|
||||
"repo": "potion-voice-utils",
|
||||
"defaultCommit": "eadc48b",
|
||||
"runtime": "python:3.10"
|
||||
},
|
||||
{
|
||||
"repo": "sentence-split-service",
|
||||
"defaultCommit": "32356d2",
|
||||
"runtime": "python:3.10"
|
||||
},
|
||||
{
|
||||
"repo": "urlbox-experiments",
|
||||
"defaultCommit": "141fe18",
|
||||
"runtime": "python:3.10"
|
||||
},
|
||||
{
|
||||
"repo": "video-synth-api",
|
||||
"defaultCommit": "167fcd7",
|
||||
"runtime": "python:3.10"
|
||||
},
|
||||
{
|
||||
"repo": "wav2lip-fa",
|
||||
"defaultCommit": "8448ef0",
|
||||
"runtime": "python:3.10"
|
||||
},
|
||||
{
|
||||
"repo": "yeahsure-tryon",
|
||||
"defaultCommit": "c8dee39",
|
||||
"runtime": "python:3.10"
|
||||
},
|
||||
{
|
||||
"repo": "gcp-infrastructure",
|
||||
"defaultCommit": "a7dc5cc",
|
||||
"runtime": "none"
|
||||
},
|
||||
{
|
||||
"repo": "potion-ai-pretrained-models-infra",
|
||||
"defaultCommit": "8a88770",
|
||||
"runtime": "none"
|
||||
},
|
||||
{
|
||||
"repo": "potion-app-infra",
|
||||
"defaultCommit": "2107464",
|
||||
"runtime": "none"
|
||||
},
|
||||
{
|
||||
"repo": "potion-bastion",
|
||||
"defaultCommit": "062af16",
|
||||
"runtime": "none"
|
||||
},
|
||||
{
|
||||
"repo": "potion-video-processing-devops",
|
||||
"defaultCommit": "566286d",
|
||||
"runtime": "none"
|
||||
},
|
||||
{
|
||||
"repo": "elasticmq-container",
|
||||
"defaultCommit": "de8acb5",
|
||||
"runtime": "none"
|
||||
},
|
||||
{
|
||||
"repo": "gcp-cloud-infrastructure",
|
||||
"defaultCommit": "aa033c8",
|
||||
"runtime": "none"
|
||||
},
|
||||
{
|
||||
"repo": "potion-devops",
|
||||
"defaultCommit": "84a4532",
|
||||
"runtime": "none"
|
||||
},
|
||||
{
|
||||
"repo": "potion-wp-site",
|
||||
"defaultCommit": "cb71e3a",
|
||||
"runtime": "none"
|
||||
}
|
||||
],
|
||||
"defaultRepo": "potion-app",
|
||||
"version": "037cfcf94b",
|
||||
"blockedHosts": [
|
||||
"sendpotion.com",
|
||||
"www.sendpotion.com",
|
||||
"app.sendpotion.com",
|
||||
"staging.sendpotion.com",
|
||||
"development.sendpotion.com",
|
||||
"devleopment.sendpotion.com",
|
||||
"meawww.sendpotion.com",
|
||||
"blog.sendpotion.com",
|
||||
"help.sendpotion.com",
|
||||
"terms.sendpotion.com",
|
||||
"pricing.sendpotion.com",
|
||||
"videoassets.sendpotion.com",
|
||||
"subtitleassets.sendpotion.com",
|
||||
"audioassets.sendpotion.com",
|
||||
"videoassets.staging.sendpotion.com",
|
||||
"subtitleassets.staging.sendpotion.com",
|
||||
"audioassets.staging.sendpotion.com"
|
||||
],
|
||||
"explorePorts": {
|
||||
"clientHost": 4300,
|
||||
"serverHost": null,
|
||||
"livereloadHost": null,
|
||||
"corpusHost": null
|
||||
}
|
||||
}
|
||||
@@ -208,6 +208,38 @@ case "$REPO" in
|
||||
printf "${GRAY}Want another container with its own separate working tree (e.g. a different commit / repo state)?${RESET}\n"
|
||||
printf "${GRAY}On the host, from explore/: node instance.js b then: node instance.js shell b${RESET}\n\n"
|
||||
;;
|
||||
frepple)
|
||||
printf "${COLOR}Run the app${RESET} in one command: ${GRAY}run-app${RESET} — starts the Django web app.\n"
|
||||
printf "Open ${GRAY}http://localhost:${CLIENT_PORT}/${RESET} and sign in as ${GRAY}admin${RESET} / ${GRAY}frepple${RESET}\n"
|
||||
printf "Setup loaded the ${GRAY}demo${RESET} dataset, so items, buffers, operations and demands are\n"
|
||||
printf "already there. Other datasets: ${GRAY}frepplectl.py loaddata manufacturing_demo${RESET} (also\n"
|
||||
printf "distribution_demo, jobshop, flow_line).\n\n"
|
||||
printf "${YELLOW}Three languages, one app${RESET} — a C++ planning engine (${GRAY}src/${RESET}, built in-tree to\n"
|
||||
printf "${GRAY}bin/frepple${RESET}), a Django app (${GRAY}freppledb/${RESET}) and a Vue frontend.\n"
|
||||
printf "Two test suites:\n"
|
||||
printf "${GRAY}cd test && ./runtest.py${RESET} the 83 engine scenarios, seconds, no database\n"
|
||||
printf "${GRAY}./frepplectl.py test freppledb${RESET} the Django suite, a few minutes\n"
|
||||
printf "Rebuild the engine after editing ${GRAY}src/${RESET}: ${GRAY}cmake --build build --parallel${RESET}\n\n"
|
||||
printf "${GRAY}The two browser tests (freppledb/*/tests/test_frontend.py) need Chrome and fail${RESET}\n"
|
||||
printf "${GRAY}here; that is expected, not your environment.${RESET}\n\n"
|
||||
printf "${GRAY}Want another container with its own separate working tree (e.g. a different commit / repo state)?${RESET}\n"
|
||||
printf "${GRAY}On the host, from explore/: node instance.js b then: node instance.js shell b${RESET}\n\n"
|
||||
;;
|
||||
freeitsm)
|
||||
printf "${COLOR}Run the app${RESET} in one command: ${GRAY}run-app${RESET} — boots Apache (mod_php).\n"
|
||||
printf "Open ${GRAY}http://localhost:${CLIENT_PORT}/${RESET} and sign in as ${GRAY}admin${RESET} / ${GRAY}freeitsm123${RESET}\n"
|
||||
printf "(staff sign-in; setup already cleared the forced password change). Setup seeds demo\n"
|
||||
printf "data for 19 of the 20 modules; the LMS importer refuses and is left empty.\n\n"
|
||||
printf "${YELLOW}No framework and no composer${RESET} — plain PHP served from the repo root.\n"
|
||||
printf "Verifier: the ${GRAY}27 standalone scripts in tests/${RESET}, run one at a time:\n"
|
||||
printf "${GRAY}su -s /bin/bash www-data -c 'cd /workspace/repo && php tests/cmdb-typed-fields.php'${RESET}\n"
|
||||
printf "Run them as ${YELLOW}www-data${RESET}: they write a PHP session file that Apache reopens, so as\n"
|
||||
printf "root the HTTP-driving ones fail with ${GRAY}Not authenticated${RESET}.\n"
|
||||
printf "${GRAY}calendar-sync-tasks.php${RESET} and ${GRAY}task-recurrence-spawn.php${RESET} exit non-zero printing\n"
|
||||
printf "nothing — a pre-existing defect in those two scripts, not your environment.\n\n"
|
||||
printf "${GRAY}Want another container with its own separate working tree (e.g. a different commit / repo state)?${RESET}\n"
|
||||
printf "${GRAY}On the host, from explore/: node instance.js b then: node instance.js shell b${RESET}\n\n"
|
||||
;;
|
||||
breezy-complete)
|
||||
printf "${COLOR}Run the app${RESET} in one command: ${GRAY}run-app${RESET} — boots the Rails API (${GRAY}backend/${RESET}) and the\n"
|
||||
printf "Next.js frontend (${GRAY}frontend/${RESET}). Open ${GRAY}http://localhost:${CLIENT_PORT}/pro_signin${RESET} — auth is\n"
|
||||
@@ -219,4 +251,10 @@ case "$REPO" in
|
||||
printf "${GRAY}Want another container with its own separate working tree (e.g. a different commit / repo state)?${RESET}\n"
|
||||
printf "${GRAY}On the host, from explore/: node instance.js b then: node instance.js shell b${RESET}\n\n"
|
||||
;;
|
||||
*)
|
||||
printf "${COLOR}Run the app${RESET} in one command: ${GRAY}run-app${RESET}, then open ${GRAY}http://localhost:${CLIENT_PORT}/${RESET}\n"
|
||||
printf "See ${GRAY}README.md${RESET} for this toolkit's verifier command and any repo-specific setup.\n\n"
|
||||
printf "${GRAY}Want another container with its own separate working tree (e.g. a different commit / repo state)?${RESET}\n"
|
||||
printf "${GRAY}On the host, from explore/: node instance.js b then: node instance.js shell b${RESET}\n\n"
|
||||
;;
|
||||
esac
|
||||
Reference in New Issue
Block a user