Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions .github/workflows/docker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,18 @@ jobs:
test -s /tmp/user/hello.1.so
'

# The repl entrypoint mode (#538): pipe an expression into
# `docker run -i ... repl` (its own in-container orlyi; no port mapping
# needed, and no clash with the container above) and assert the value
# comes back. Gates node in the runtime stage, the baked orly-repl
# build, and the entrypoint's background-orlyi handshake at once.
- name: REPL mode against the image
run: |
printf '40 + 2;\n:quit\n' \
| docker run -i --rm ghcr.io/orlyatomics/orly:ci repl \
| tee /tmp/repl-out
grep -qE '(^|orly> )42$' /tmp/repl-out

- name: Container logs (for diagnosis)
if: always()
run: docker logs orly 2>&1 | tail -60
Expand Down
21 changes: 20 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
#
# The WebSocket + JSON protocol is then on ws://127.0.0.1:8082/ -- point any
# client driver (clients/{python,go,ts}) or the MCP server (clients/mcp) at it.
#
# Interactive orlyscript (#538): `docker run -it --rm ghcr.io/orlyatomics/orly repl`
# starts orlyi inside the container and drops straight into orly-repl.

# ---- build stage -----------------------------------------------------------

Expand All @@ -15,6 +18,7 @@ FROM ubuntu:24.04 AS build
RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
build-essential gcc g++ uuid-dev libgmp-dev libaio-dev libsnappy-dev \
libreadline-dev libboost-system-dev zlib1g-dev bison flex python3 \
nodejs npm \
&& rm -rf /var/lib/apt/lists/*

WORKDIR /src/orly
Expand All @@ -41,6 +45,15 @@ RUN mkdir -p /opt/orly-packages /tmp/pkgout && touch /opt/orly-packages/__orly__
&& /src/out_orly/release/orly/orlyc -o /tmp/pkgout /src/orly/examples/prediction-market/market.orly \
&& cp /tmp/pkgout/*.so /opt/orly-packages/

# Build the TS driver + orly-repl (#538); they reach the runtime stage inside
# the /src/orly -> /opt/orly/src copy, so prune dev deps (typescript et al.)
# down to what `node dist/index.js` needs. Order matters: the repl's npm
# install copies clients/ts (per its `files`), so ts builds first.
RUN cd /src/orly/clients/ts && npm install --silent && npx tsc \
&& cd /src/orly/clients/repl && npm install --silent && npx tsc \
&& npm prune --omit=dev \
&& cd /src/orly/clients/ts && npm prune --omit=dev

# ---- runtime stage ---------------------------------------------------------

FROM ubuntu:24.04
Expand All @@ -54,9 +67,10 @@ LABEL org.opencontainers.image.source="https://github.com/orlyatomics/orly" \
# package compiles need: g++ (orlyc execs `g++ -I$ORLY_SRC_ROOT ...`) and
# uuid-dev (generated code includes base/uuid.h -> <uuid/uuid.h>; the lib
# alone is not enough -- verified by compiling a package in the container).
# nodejs (no npm) runs the pre-built orly-repl.
RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
g++ uuid-dev libgmp10 libgmpxx4ldbl libaio1t64 libboost-system1.83.0 \
libreadline8t64 libsnappy1v5 zlib1g \
libreadline8t64 libsnappy1v5 zlib1g nodejs \
&& rm -rf /var/lib/apt/lists/*

COPY --from=build /src/out_orly/release/orly/server/orlyi /usr/local/bin/orlyi
Expand All @@ -65,6 +79,11 @@ COPY --from=build /src/out_orly/release/orly/orlyc /usr/local/bin/orlyc
COPY --from=build /src/orly /opt/orly/src
COPY --from=build /opt/orly-packages /var/lib/orly/packages
COPY docker/entrypoint.sh /usr/local/bin/orly-entrypoint
# Shim so `docker exec -it <ctr> orly-repl ...` works against a running
# default-entrypoint container, not just the `repl` entrypoint mode.
RUN printf '#!/bin/sh\nexec node /opt/orly/src/clients/repl/dist/index.js "$@"\n' \
> /usr/local/bin/orly-repl \
&& chmod +x /usr/local/bin/orly-repl

# Trailing slash matters: the compiler concatenates paths onto this directly.
ENV ORLY_SRC_ROOT=/opt/orly/src/
Expand Down
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,13 @@ image, so it compiles your own `.orly` packages too
`docker run ... <flags>` pass straight through to `orlyi`
([#530](https://github.com/orlyatomics/orly/issues/530)).

Or skip the client entirely and type orlyscript at it
([#538](https://github.com/orlyatomics/orly/issues/538)):

```sh
docker run -it --rm ghcr.io/orlyatomics/orly repl
```

**From source** — system dependencies (Ubuntu 24.04):

```sh
Expand Down
1 change: 1 addition & 0 deletions changelog.d/538-docker-repl-mode.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- **Added**: the docker image now bakes in `orly-repl` — `docker run -it --rm ghcr.io/orlyatomics/orly repl` starts the in-container orlyi and drops straight into an orlyscript prompt (zero host setup; flags after `repl` pass to the REPL, and an `orly-repl` shim on PATH serves `docker exec` against a default-entrypoint container). PR-gated in the docker workflow by piping an expression through the published entrypoint (#538).
12 changes: 9 additions & 3 deletions clients/repl/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,15 @@ Commands at the prompt: `:help`, `:defs`, `:drop <name>`, `:src` (show the synth

## Against the docker image

The image ships `orlyc` but the compile/install loop needs a package directory both sides can see, so start the container with one mounted at an identical path, and run `orlyc` inside the container:
The REPL is baked into the image ([#538](https://github.com/orlyatomics/orly/issues/538)), so the whole thing is one line — orlyi starts inside the container and the prompt appears when it's ready:

```sh
docker run -it --rm ghcr.io/orlyatomics/orly repl
```

Flags after `repl` go to orly-repl (e.g. `repl --shared`). Against an already-running default-entrypoint container, use the shim: `docker exec -it <ctr> orly-repl --package-dir /var/lib/orly/packages`.

If you'd rather run the REPL on the host against a containerized server (say, to join a pov your host-side agents are using), the compile/install loop needs a package directory both sides can see at the same path, and `orlyc` runs inside the container:

```sh
mkdir -p /tmp/orly-repl/packages && touch /tmp/orly-repl/packages/__orly__
Expand All @@ -55,8 +63,6 @@ npx tsc && node dist/index.js \
--orlyc "docker exec orly orlyc"
```

(Compiled `.so` paths land in the shared mount, so the container-side `orlyc` and the host-side REPL agree on where everything is.)

## Building and joining agents

`orly-repl --pov <id> ...` attaches to a POV your agents (e.g. via [`clients/mcp`](../mcp)) are already writing — the REPL then reads and writes the same live state, which makes it a debugger for agent shared memory.
Expand Down
55 changes: 37 additions & 18 deletions docker/entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,42 @@
# example packages (sample, graph, market) installable out of the box, WS on
# 8082. Extra `docker run ... <flags>` are appended verbatim, so any orlyi
# flag can be overridden or added. Sizing knobs via env for the common case.
#
# `docker run -it ... repl [orly-repl flags]` (#538) instead starts that same
# orlyi in the background (logs to /var/log/orly/orlyi.log) and drops into
# orly-repl pointed at it; when the REPL exits, the container exits.
set -e

exec orlyi \
--mem_sim \
--mem_sim_mb="${ORLY_MEM_SIM_MB:-256}" \
--mem_sim_slow_mb="${ORLY_MEM_SIM_SLOW_MB:-64}" \
--create=true \
--instance_name="${ORLY_INSTANCE_NAME:-orly}" \
--starting_state=SOLO \
--port_number=8080 \
--slave_port_number=8081 \
--ws_port_number=8082 \
--reporting_port_number=8083 \
--connection_backlog=32 \
--package_dir=/var/lib/orly/packages \
--max_parallel_frames 4000 \
--page_cache_size 256 \
--block_cache_size 64 \
--le --log_info \
"$@"
orlyi_args=(
--mem_sim
--mem_sim_mb="${ORLY_MEM_SIM_MB:-256}"
--mem_sim_slow_mb="${ORLY_MEM_SIM_SLOW_MB:-64}"
--create=true
--instance_name="${ORLY_INSTANCE_NAME:-orly}"
--starting_state=SOLO
--port_number=8080
--slave_port_number=8081
--ws_port_number=8082
--reporting_port_number=8083
--connection_backlog=32
--package_dir=/var/lib/orly/packages
--max_parallel_frames 4000
--page_cache_size 256
--block_cache_size 64
--le --log_info
)

if [ "$1" = "repl" ]; then
shift
mkdir -p /var/log/orly
orlyi "${orlyi_args[@]}" > /var/log/orly/orlyi.log 2>&1 &
for _ in $(seq 1 60); do
if (echo > /dev/tcp/127.0.0.1/8082) 2>/dev/null; then break; fi
sleep 1
done
export ORLY_URL="ws://127.0.0.1:8082/"
exec node /opt/orly/src/clients/repl/dist/index.js \
--package-dir /var/lib/orly/packages "$@"
fi

exec orlyi "${orlyi_args[@]}" "$@"
Loading