@replayio/app-building 1.2.0 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +38 -7
- package/dist/container.d.ts +4 -0
- package/dist/container.js +8 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -33,14 +33,12 @@ const config: ContainerConfig = {
|
|
|
33
33
|
flyApp: envVars.FLY_APP_NAME,
|
|
34
34
|
};
|
|
35
35
|
|
|
36
|
-
// Start a
|
|
36
|
+
// Start a detached container with an initial prompt — it will process and exit when done
|
|
37
|
+
config.detached = true;
|
|
38
|
+
config.initialPrompt = "Build the app";
|
|
37
39
|
const repo: RepoOptions = { repoUrl: "https://github.com/...", cloneBranch: "main", pushBranch: "main" };
|
|
38
40
|
const state = await startRemoteContainer(config, repo);
|
|
39
41
|
|
|
40
|
-
// Send a prompt and wait for completion
|
|
41
|
-
const httpOpts = httpOptsFor(state);
|
|
42
|
-
const { id } = await httpPost(`${state.baseUrl}/message`, { prompt: "Build the app" }, httpOpts);
|
|
43
|
-
|
|
44
42
|
// Check status
|
|
45
43
|
const status = await httpGet(`${state.baseUrl}/status`, httpOpts);
|
|
46
44
|
|
|
@@ -57,7 +55,7 @@ await stopRemoteContainer(config, state);
|
|
|
57
55
|
|
|
58
56
|
| Export | Description |
|
|
59
57
|
|---|---|
|
|
60
|
-
| `ContainerConfig` | Interface bundling all external state: optional `projectRoot` (only needed for local Docker operations), `envVars`, `registry`, optional `flyToken`/`flyApp`/`imageRef`/`webhookUrl`. See [Webhooks](#webhooks) below. |
|
|
58
|
+
| `ContainerConfig` | Interface bundling all external state: optional `projectRoot` (only needed for local Docker operations), `envVars`, `registry`, optional `flyToken`/`flyApp`/`imageRef`/`webhookUrl`/`detached`/`initialPrompt`. See [Webhooks](#webhooks) and [Container lifecycle](#container-lifecycle) below. |
|
|
61
59
|
| `RepoOptions` | Per-invocation git settings: `repoUrl`, `cloneBranch`, `pushBranch`. |
|
|
62
60
|
| `ContainerRegistry` | Interface for container registry storage. Methods: `log`, `markStopped`, `clearStopped`, `getRecent`, `find`, `findAlive`. |
|
|
63
61
|
| `FileContainerRegistry` | Built-in file-backed implementation of `ContainerRegistry`, backed by a `.jsonl` file. |
|
|
@@ -123,9 +121,42 @@ await stopRemoteContainer(config, state);
|
|
|
123
121
|
|---|---|
|
|
124
122
|
| `getImageRef()` | Returns `CONTAINER_IMAGE_REF` env var, or `ghcr.io/replayio/app-building:latest` by default. Used by `startRemoteContainer`. |
|
|
125
123
|
|
|
124
|
+
## Container HTTP API
|
|
125
|
+
|
|
126
|
+
Each container runs an HTTP server that accepts the following requests:
|
|
127
|
+
|
|
128
|
+
| Method | Path | Description |
|
|
129
|
+
|---|---|---|
|
|
130
|
+
| `POST /message` | `{ prompt: string }` | Queue a message for processing. Returns `{ id }`. |
|
|
131
|
+
| `GET /message/:id` | | Poll message status. Returns `{ id, status, result, error }`. |
|
|
132
|
+
| `POST /detach` | | Signal the container to exit once all queued messages and tasks are done. |
|
|
133
|
+
| `POST /stop` | | Force-stop the container immediately. Interrupts any running work, commits remaining changes, then exits. |
|
|
134
|
+
| `POST /interrupt` | | Kill the currently running Claude process without stopping the container. |
|
|
135
|
+
| `GET /status` | | Container state, queue depth, iteration count, cost, revision, etc. |
|
|
136
|
+
| `GET /events?offset=N` | | Stream of Claude events (JSON lines) since offset. |
|
|
137
|
+
| `GET /logs?offset=N` | | Stream of log lines since offset. |
|
|
138
|
+
|
|
139
|
+
### Container lifecycle
|
|
140
|
+
|
|
141
|
+
A container stays running and accepts messages until it receives a **detach** or **stop** signal:
|
|
142
|
+
|
|
143
|
+
- **Detached at startup** (`config.detached = true`): Set `detached` on `ContainerConfig` to start
|
|
144
|
+
the container in detached mode. Use `config.initialPrompt` to provide a prompt that is queued
|
|
145
|
+
before the HTTP server starts accepting requests. The container processes the initial prompt
|
|
146
|
+
and any queued tasks, then exits cleanly. This is the preferred way to run fire-and-forget
|
|
147
|
+
jobs — no race between container startup and a subsequent `POST /message` or `POST /detach`.
|
|
148
|
+
- **Detach** (`POST /detach`): Signal a running container to exit once all in-flight and queued
|
|
149
|
+
work is done. In the CLI, interactive mode (`npm run agent -- -i`) sends `/detach` automatically
|
|
150
|
+
when the user disconnects (Ctrl+C/D).
|
|
151
|
+
- **Stop** (`POST /stop`): The container exits immediately, interrupting any running Claude
|
|
152
|
+
process. It commits any remaining work before shutting down. This is the forced shutdown path.
|
|
153
|
+
|
|
154
|
+
Without either signal, the container waits indefinitely for new messages — this is intentional
|
|
155
|
+
so that interactive users can send follow-up messages at any time.
|
|
156
|
+
|
|
126
157
|
## Webhooks
|
|
127
158
|
|
|
128
|
-
Set `webhookUrl` on `ContainerConfig` to receive real-time notifications of container activity. The container POSTs
|
|
159
|
+
Set `webhookUrl` on `ContainerConfig` to receive real-time notifications of container activity. The container POSTs JSON to that URL on key events (no retries; failures are logged to stderr). If `WEBHOOK_SECRET` is set in the environment, the container sends it as a `Bearer` token in the `Authorization` header.
|
|
129
160
|
|
|
130
161
|
### Payload format
|
|
131
162
|
|
package/dist/container.d.ts
CHANGED
|
@@ -15,6 +15,10 @@ export interface ContainerConfig {
|
|
|
15
15
|
flyApp?: string;
|
|
16
16
|
imageRef?: string;
|
|
17
17
|
webhookUrl?: string;
|
|
18
|
+
/** Start the container in detached mode. It will exit after processing all messages and tasks. */
|
|
19
|
+
detached?: boolean;
|
|
20
|
+
/** Initial prompt to queue at container startup (before the HTTP server accepts external requests). */
|
|
21
|
+
initialPrompt?: string;
|
|
18
22
|
}
|
|
19
23
|
export interface RepoOptions {
|
|
20
24
|
repoUrl: string;
|
package/dist/container.js
CHANGED
|
@@ -100,6 +100,10 @@ export async function startContainer(config, repo) {
|
|
|
100
100
|
};
|
|
101
101
|
if (config.webhookUrl)
|
|
102
102
|
extra.WEBHOOK_URL = config.webhookUrl;
|
|
103
|
+
if (config.detached)
|
|
104
|
+
extra.DETACHED = "1";
|
|
105
|
+
if (config.initialPrompt)
|
|
106
|
+
extra.INITIAL_PROMPT = config.initialPrompt;
|
|
103
107
|
const containerEnv = buildContainerEnv(repo, config.envVars, extra);
|
|
104
108
|
// Build docker run args
|
|
105
109
|
const args = ["run", "-d", "--rm", "--name", containerName];
|
|
@@ -174,6 +178,10 @@ export async function startRemoteContainer(config, repo) {
|
|
|
174
178
|
};
|
|
175
179
|
if (config.webhookUrl)
|
|
176
180
|
remoteExtra.WEBHOOK_URL = config.webhookUrl;
|
|
181
|
+
if (config.detached)
|
|
182
|
+
remoteExtra.DETACHED = "1";
|
|
183
|
+
if (config.initialPrompt)
|
|
184
|
+
remoteExtra.INITIAL_PROMPT = config.initialPrompt;
|
|
177
185
|
const containerEnv = buildContainerEnv(repo, config.envVars, remoteExtra);
|
|
178
186
|
// Log existing machines (but don't destroy — multiple containers may run concurrently)
|
|
179
187
|
const existing = await listMachines(config.flyApp, config.flyToken);
|