@founderos/runner 0.1.1
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/LICENSE +21 -0
- package/README.md +175 -0
- package/dist/api.d.ts +137 -0
- package/dist/api.d.ts.map +1 -0
- package/dist/api.js +148 -0
- package/dist/api.js.map +1 -0
- package/dist/cli.d.ts +28 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +182 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +47 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +68 -0
- package/dist/config.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -0
- package/dist/main.d.ts +42 -0
- package/dist/main.d.ts.map +1 -0
- package/dist/main.js +237 -0
- package/dist/main.js.map +1 -0
- package/dist/spawn.d.ts +86 -0
- package/dist/spawn.d.ts.map +1 -0
- package/dist/spawn.js +264 -0
- package/dist/spawn.js.map +1 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +5 -0
- package/dist/version.js.map +1 -0
- package/package.json +48 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Paperclip AI
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
# @founderos/runner
|
|
2
|
+
|
|
3
|
+
Local execution runner for [FounderOS](https://founderos.fly.dev). Polls the FounderOS cloud for queued AI-agent jobs, spawns the `claude` CLI under your existing Claude Pro subscription, streams events back, and reports completion.
|
|
4
|
+
|
|
5
|
+
> **Why this exists.** FounderOS runs as a hosted control plane, but the actual LLM execution happens on _your_ machine — under _your_ authed CLI session and _your_ subscription billing. The cloud never sees your Anthropic API keys; it just enqueues work and reads back the events. See [ADR-011](https://github.com/founderos-ai/founderos/blob/main/docs/adr/011-byo-runner.md) for the full rationale.
|
|
6
|
+
|
|
7
|
+
## Quickstart
|
|
8
|
+
|
|
9
|
+
No install required — `npx` runs the runner directly:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npx @founderos/runner start \
|
|
13
|
+
--token=fos_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx \
|
|
14
|
+
--server-url=https://founderos.fly.dev
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
### Windows (PowerShell)
|
|
18
|
+
|
|
19
|
+
```powershell
|
|
20
|
+
npx @founderos/runner start --token=fos_xxx --server-url=https://founderos.fly.dev
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
> **Common typo:** `npm install -g @founderos/` (with a trailing slash, no
|
|
24
|
+
> package name) makes npm look for a local `@founderos\package.json` and
|
|
25
|
+
> fail with `ENOENT`. The package name is `@founderos/runner` — and you
|
|
26
|
+
> don't actually need to install it globally; `npx` is enough.
|
|
27
|
+
|
|
28
|
+
### Prerequisites
|
|
29
|
+
|
|
30
|
+
- **Node.js ≥ 20** — `node --version` to check.
|
|
31
|
+
- **`claude` CLI** installed and authenticated — `claude --version` should work in your shell. If you use a different LLM CLI, the multi-CLI dispatcher (PHASE-S7, in progress) will support Codex, Gemini, OpenCode, Pi, and Cursor.
|
|
32
|
+
|
|
33
|
+
### Get a token
|
|
34
|
+
|
|
35
|
+
Issue a runner token from the FounderOS dashboard → Settings → Runner Tokens. The plaintext is shown **once** at issuance — store it in a password manager. Tokens are scoped to a single company; revoke from the dashboard whenever a machine is decommissioned.
|
|
36
|
+
|
|
37
|
+
## Install (optional)
|
|
38
|
+
|
|
39
|
+
For long-running setups (a dedicated runner machine, a service file), install the binary globally instead of using `npx`:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
npm install -g @founderos/runner
|
|
43
|
+
founderos-runner start --token=fos_xxx --server-url=https://founderos.fly.dev
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Configuration reference
|
|
47
|
+
|
|
48
|
+
Every option can be set via flag OR environment variable. Flags override env vars when both are present.
|
|
49
|
+
|
|
50
|
+
| Flag | Env var | Required | Default | Notes |
|
|
51
|
+
|---|---|---|---|---|
|
|
52
|
+
| `--token=<...>` | `FOUNDEROS_RUNNER_TOKEN` | yes | — | Bearer token (`fos_<32 chars>`) |
|
|
53
|
+
| `--server-url=<...>` | `FOUNDEROS_RUNNER_URL` | yes | — | e.g. `https://founderos.fly.dev` |
|
|
54
|
+
| `--claude-bin=<...>` | `FOUNDEROS_CLAUDE_BIN` | no | `claude` | Override if `claude` isn't on `PATH` |
|
|
55
|
+
| `--timeout-sec=<n>` | `FOUNDEROS_RUNNER_TIMEOUT_SEC` | no | `600` | Per-job hard ceiling, 1..3600 |
|
|
56
|
+
| `--log-level=<...>` | `FOUNDEROS_RUNNER_LOG_LEVEL` | no | `info` | `debug` \| `info` \| `warn` \| `error` |
|
|
57
|
+
|
|
58
|
+
### Env-var form (macOS/Linux shells, scripts, systemd unit files)
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
export FOUNDEROS_RUNNER_URL=https://founderos.fly.dev
|
|
62
|
+
export FOUNDEROS_RUNNER_TOKEN=fos_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
|
63
|
+
founderos-runner start
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Output:
|
|
67
|
+
|
|
68
|
+
```
|
|
69
|
+
[info ] founderos-runner v0.1.0 starting {"serverUrl":"https://founderos.fly.dev","claudeBin":"claude"}
|
|
70
|
+
[info ] got job {"jobId":"...","agent":"Sarah"}
|
|
71
|
+
[info ] job completed {"jobId":"...","status":"completed","exitCode":0}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
The process loops until you `^C` it; SIGINT/SIGTERM finishes the current job before exiting.
|
|
75
|
+
|
|
76
|
+
## Run as a service (macOS)
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
# ~/Library/LaunchAgents/dev.founderos.runner.plist
|
|
80
|
+
cat > ~/Library/LaunchAgents/dev.founderos.runner.plist <<EOF
|
|
81
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
82
|
+
<plist version="1.0">
|
|
83
|
+
<dict>
|
|
84
|
+
<key>Label</key><string>dev.founderos.runner</string>
|
|
85
|
+
<key>ProgramArguments</key>
|
|
86
|
+
<array>
|
|
87
|
+
<string>/usr/local/bin/founderos-runner</string>
|
|
88
|
+
<string>start</string>
|
|
89
|
+
</array>
|
|
90
|
+
<key>EnvironmentVariables</key>
|
|
91
|
+
<dict>
|
|
92
|
+
<key>FOUNDEROS_RUNNER_URL</key><string>https://founderos.fly.dev</string>
|
|
93
|
+
<key>FOUNDEROS_RUNNER_TOKEN</key><string>fos_...</string>
|
|
94
|
+
</dict>
|
|
95
|
+
<key>RunAtLoad</key><true/>
|
|
96
|
+
<key>KeepAlive</key><true/>
|
|
97
|
+
</dict>
|
|
98
|
+
</plist>
|
|
99
|
+
EOF
|
|
100
|
+
launchctl load ~/Library/LaunchAgents/dev.founderos.runner.plist
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Run as a service (Windows, NSSM)
|
|
104
|
+
|
|
105
|
+
Windows ships no equivalent to launchd / systemd, but [NSSM](https://nssm.cc) wraps any executable as a service:
|
|
106
|
+
|
|
107
|
+
```powershell
|
|
108
|
+
# After `npm install -g @founderos/runner`
|
|
109
|
+
nssm install FounderOSRunner "C:\Program Files\nodejs\founderos-runner.cmd"
|
|
110
|
+
nssm set FounderOSRunner AppParameters "start --token=fos_xxx --server-url=https://founderos.fly.dev"
|
|
111
|
+
nssm set FounderOSRunner Start SERVICE_AUTO_START
|
|
112
|
+
nssm start FounderOSRunner
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Run as a service (Linux, systemd)
|
|
116
|
+
|
|
117
|
+
```ini
|
|
118
|
+
# /etc/systemd/system/founderos-runner.service
|
|
119
|
+
[Unit]
|
|
120
|
+
Description=FounderOS local runner
|
|
121
|
+
After=network.target
|
|
122
|
+
|
|
123
|
+
[Service]
|
|
124
|
+
Type=simple
|
|
125
|
+
ExecStart=/usr/local/bin/founderos-runner start
|
|
126
|
+
Restart=always
|
|
127
|
+
Environment="FOUNDEROS_RUNNER_URL=https://founderos.fly.dev"
|
|
128
|
+
Environment="FOUNDEROS_RUNNER_TOKEN=fos_..."
|
|
129
|
+
User=YOUR_USER
|
|
130
|
+
|
|
131
|
+
[Install]
|
|
132
|
+
WantedBy=default.target
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
## What does the runner do, exactly?
|
|
136
|
+
|
|
137
|
+
1. **Long-poll** `GET /api/runner/jobs/next` (≤ 30 s) for queued work.
|
|
138
|
+
2. **Atomic claim** `POST /api/runner/jobs/:id/claim` — the cloud transitions the job from `queued` → `claimed` in a single SQL `UPDATE…WHERE status='queued'`. Multiple runners polling the same token race; the lowest-latency one wins.
|
|
139
|
+
3. **Spawn** `claude --print --output-format stream-json --verbose` with the prompt on stdin. If the cloud passed `--resume sessionId`, it threads through.
|
|
140
|
+
4. **Stream events** — every line of stream-json (assistant messages, tool uses, tool results, the final result) is parsed and POSTed in 50 ms / 32-event batches to `POST /api/runner/jobs/:id/events`.
|
|
141
|
+
5. **Complete** — when claude exits, post the exit code, total cost (parsed from the `result` event), `sessionId` (for `--resume` next time), and CLI version to `POST /api/runner/jobs/:id/complete`.
|
|
142
|
+
|
|
143
|
+
## Security
|
|
144
|
+
|
|
145
|
+
- Token is hashed at rest server-side (sha256). Constant-time compare on every request.
|
|
146
|
+
- Tokens scope to a single company. A token issued for company A cannot read jobs for company B.
|
|
147
|
+
- Plaintext tokens are never logged. Audit-log entries store an 8-char preview only.
|
|
148
|
+
- Revoke from the dashboard whenever a machine is decommissioned; revoked tokens get a 401 on the next request.
|
|
149
|
+
|
|
150
|
+
See the [runner threat model](https://github.com/founderos-ai/founderos/blob/main/docs/security/runner-threat-model.md).
|
|
151
|
+
|
|
152
|
+
## Troubleshooting
|
|
153
|
+
|
|
154
|
+
| Symptom | Likely cause | Fix |
|
|
155
|
+
|---|---|---|
|
|
156
|
+
| `npm error code ENOENT` ... `@founderos\package.json` | Trailing slash typo (`npm install -g @founderos/`) | Use `npx @founderos/runner start --token=...` |
|
|
157
|
+
| `config error: FOUNDEROS_RUNNER_TOKEN is required` | No token passed | Add `--token=fos_...` or set `FOUNDEROS_RUNNER_TOKEN` |
|
|
158
|
+
| `config error: ... must match fos_<32 alphanumeric>` | Token format wrong | Re-issue a fresh token from the dashboard |
|
|
159
|
+
| `unknown or malformed flag(s): --token` | Flag without value (`--token` not `--token=fos_...`) | Use `--token=fos_xxx` form |
|
|
160
|
+
| `claude: command not found` (during a job) | `claude` CLI not on `PATH` | Install Claude Code, or pass `--claude-bin=/full/path/to/claude` |
|
|
161
|
+
| 401 Unauthorized on every request | Token revoked or expired | Re-issue from dashboard → Settings → Runner Tokens |
|
|
162
|
+
|
|
163
|
+
For anything else, the runner emits structured `[debug]` logs when `--log-level=debug` is set — open an issue with the relevant log lines.
|
|
164
|
+
|
|
165
|
+
## Local development
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
pnpm install
|
|
169
|
+
pnpm --filter @founderos/runner test # unit tests, no live spawn
|
|
170
|
+
pnpm --filter @founderos/runner build # tsc → dist/
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
## License
|
|
174
|
+
|
|
175
|
+
MIT
|
package/dist/api.d.ts
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Typed HTTP client for the four runner-side endpoints in
|
|
3
|
+
* docs/api/runner-openapi.yaml. Uses Node's built-in fetch (Node 20+).
|
|
4
|
+
*
|
|
5
|
+
* Idempotency:
|
|
6
|
+
* - /events POST is server-side append-only; the runner is responsible for
|
|
7
|
+
* not re-sending the same eventId on retry. We track sent eventIds per
|
|
8
|
+
* job in memory; only retry on 5xx (network errors).
|
|
9
|
+
* - /complete is server-rejected on double-submit (409). We swallow the 409
|
|
10
|
+
* gracefully so a crashed-and-restarted runner that already completed a
|
|
11
|
+
* job before crashing doesn't loop on it.
|
|
12
|
+
*/
|
|
13
|
+
import type { RunnerConfig } from "./config.js";
|
|
14
|
+
export interface JobDescriptor {
|
|
15
|
+
jobId: string;
|
|
16
|
+
agentId: string;
|
|
17
|
+
agentName: string;
|
|
18
|
+
createdAt: string;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Adapter type carried from the cloud through to the runner.
|
|
22
|
+
*
|
|
23
|
+
* S7.0.1 — kept as a plain string union here (NOT `AgentAdapterType` from
|
|
24
|
+
* `@founderos/shared`) so the runner package can stay free of the shared
|
|
25
|
+
* deep dep. The DB CHECK constraint at migration 0105 + the cloud-side
|
|
26
|
+
* Zod schema enforce validity before this field reaches the runner.
|
|
27
|
+
*
|
|
28
|
+
* Default fallback: "claude_local". Pre-S7 rows that wrote "byo_runner"
|
|
29
|
+
* still map to claude via the dispatcher's legacy-fallback path.
|
|
30
|
+
*/
|
|
31
|
+
export type RunnerAdapterType = "claude_local" | "codex_local" | "gemini_local" | "opencode_local" | "pi_local" | "cursor_local" | "openclaw_gateway" | "hermes_local" | "byo_runner" | "process" | "http" | (string & {});
|
|
32
|
+
export interface JobPayload {
|
|
33
|
+
jobId: string;
|
|
34
|
+
agentId: string;
|
|
35
|
+
agentName?: string;
|
|
36
|
+
prompt: string;
|
|
37
|
+
sessionId: string | null;
|
|
38
|
+
runtimeConfig: {
|
|
39
|
+
model?: string | null;
|
|
40
|
+
maxTurns?: number | null;
|
|
41
|
+
timeoutSec?: number;
|
|
42
|
+
instructionsFileContent?: string | null;
|
|
43
|
+
[k: string]: unknown;
|
|
44
|
+
};
|
|
45
|
+
promptHash: string;
|
|
46
|
+
/**
|
|
47
|
+
* S7.0.1 — adapter type the runner should dispatch on. Server returns
|
|
48
|
+
* this from the claim API (`server/src/routes/runner.ts:303`). May be
|
|
49
|
+
* absent on responses from a pre-S7.0.1 server build — defaults to
|
|
50
|
+
* "claude_local" at the consumer.
|
|
51
|
+
*/
|
|
52
|
+
adapterType?: RunnerAdapterType;
|
|
53
|
+
addDirs?: string[];
|
|
54
|
+
}
|
|
55
|
+
export type RunnerEventKind = "stdout_line" | "stderr_line" | "claude_message" | "claude_tool_use" | "claude_tool_result" | "claude_result";
|
|
56
|
+
export interface RunnerEvent {
|
|
57
|
+
eventId: string;
|
|
58
|
+
kind: RunnerEventKind;
|
|
59
|
+
ts: string;
|
|
60
|
+
payload?: Record<string, unknown> | string;
|
|
61
|
+
}
|
|
62
|
+
export interface CompletionBody {
|
|
63
|
+
status: "completed" | "failed" | "cancelled";
|
|
64
|
+
exitCode: number;
|
|
65
|
+
signal?: string | null;
|
|
66
|
+
elapsedSec?: number;
|
|
67
|
+
costMicros?: number;
|
|
68
|
+
sessionId?: string | null;
|
|
69
|
+
cliVersion?: string;
|
|
70
|
+
errorMessage?: string | null;
|
|
71
|
+
}
|
|
72
|
+
export declare class ApiError extends Error {
|
|
73
|
+
readonly status: number;
|
|
74
|
+
readonly body: string;
|
|
75
|
+
constructor(status: number, body: string, message?: string);
|
|
76
|
+
}
|
|
77
|
+
/** Generate a runner-side event id. Exposed so the spawner can stamp events
|
|
78
|
+
* before they reach the API client. */
|
|
79
|
+
export declare function makeEventId(): string;
|
|
80
|
+
export declare class RunnerApiClient {
|
|
81
|
+
private readonly config;
|
|
82
|
+
private readonly fetchImpl;
|
|
83
|
+
constructor(config: RunnerConfig, fetchImpl?: typeof fetch);
|
|
84
|
+
private url;
|
|
85
|
+
private headers;
|
|
86
|
+
/**
|
|
87
|
+
* Long-poll for the next claimable job. Server holds the connection up to
|
|
88
|
+
* 30s. Returns:
|
|
89
|
+
* - { kind: "job", job } on a hit
|
|
90
|
+
* - { kind: "empty" } on 204 timeout (caller re-polls)
|
|
91
|
+
* - throws ApiError on non-2xx
|
|
92
|
+
*/
|
|
93
|
+
getNext(signal?: AbortSignal): Promise<{
|
|
94
|
+
kind: "job";
|
|
95
|
+
job: JobDescriptor;
|
|
96
|
+
} | {
|
|
97
|
+
kind: "empty";
|
|
98
|
+
}>;
|
|
99
|
+
/**
|
|
100
|
+
* Atomic claim. Returns:
|
|
101
|
+
* - { kind: "claimed", payload } on success
|
|
102
|
+
* - { kind: "lost" } on 409 (race lost)
|
|
103
|
+
* - { kind: "gone" } on 404 (cancelled / unknown)
|
|
104
|
+
* - throws ApiError on other non-2xx
|
|
105
|
+
*/
|
|
106
|
+
claim(jobId: string): Promise<{
|
|
107
|
+
kind: "claimed";
|
|
108
|
+
payload: JobPayload;
|
|
109
|
+
} | {
|
|
110
|
+
kind: "lost";
|
|
111
|
+
} | {
|
|
112
|
+
kind: "gone";
|
|
113
|
+
}>;
|
|
114
|
+
/**
|
|
115
|
+
* Append a batch of events. Caller batches with a 50ms / 32-event window.
|
|
116
|
+
* Idempotent on eventId; the server doesn't dedup but does reject when the
|
|
117
|
+
* job is in a terminal state (409). We retry on 5xx + network errors with
|
|
118
|
+
* a small backoff; on 409 we surface the terminal state to the caller so
|
|
119
|
+
* it can stop spawning.
|
|
120
|
+
*/
|
|
121
|
+
appendEvents(jobId: string, events: RunnerEvent[]): Promise<{
|
|
122
|
+
kind: "ok";
|
|
123
|
+
} | {
|
|
124
|
+
kind: "terminal";
|
|
125
|
+
}>;
|
|
126
|
+
/**
|
|
127
|
+
* Mark the job terminal. 409 (already terminal) is swallowed — the runner
|
|
128
|
+
* may have crashed mid-complete and the cloud already accepted the prior
|
|
129
|
+
* call. We log + move on rather than spinning forever.
|
|
130
|
+
*/
|
|
131
|
+
complete(jobId: string, body: CompletionBody): Promise<{
|
|
132
|
+
kind: "ok";
|
|
133
|
+
} | {
|
|
134
|
+
kind: "already_terminal";
|
|
135
|
+
}>;
|
|
136
|
+
}
|
|
137
|
+
//# sourceMappingURL=api.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAKH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;;;;GAUG;AACH,MAAM,MAAM,iBAAiB,GACzB,cAAc,GACd,aAAa,GACb,cAAc,GACd,gBAAgB,GAChB,UAAU,GACV,cAAc,GACd,kBAAkB,GAClB,cAAc,GACd,YAAY,GACZ,SAAS,GACT,MAAM,GACN,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;AAElB,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,aAAa,EAAE;QACb,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QACtB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QACzB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,uBAAuB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QACxC,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;KACtB,CAAC;IACF,UAAU,EAAE,MAAM,CAAC;IACnB;;;;;OAKG;IACH,WAAW,CAAC,EAAE,iBAAiB,CAAC;IAChC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,MAAM,MAAM,eAAe,GACvB,aAAa,GACb,aAAa,GACb,gBAAgB,GAChB,iBAAiB,GACjB,oBAAoB,GACpB,eAAe,CAAC;AAEpB,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,eAAe,CAAC;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC;CAC5C;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,WAAW,GAAG,QAAQ,GAAG,WAAW,CAAC;IAC7C,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AAED,qBAAa,QAAS,SAAQ,KAAK;aAEf,MAAM,EAAE,MAAM;aACd,IAAI,EAAE,MAAM;gBADZ,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EAC5B,OAAO,CAAC,EAAE,MAAM;CAKnB;AAED;wCACwC;AACxC,wBAAgB,WAAW,IAAI,MAAM,CAEpC;AAED,qBAAa,eAAe;IAExB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,SAAS;gBADT,MAAM,EAAE,YAAY,EACpB,SAAS,GAAE,OAAO,KAAa;IAGlD,OAAO,CAAC,GAAG;IAIX,OAAO,CAAC,OAAO;IAQf;;;;;;OAMG;IACG,OAAO,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAC1C;QAAE,IAAI,EAAE,KAAK,CAAC;QAAC,GAAG,EAAE,aAAa,CAAA;KAAE,GAAG;QAAE,IAAI,EAAE,OAAO,CAAA;KAAE,CACxD;IAcD;;;;;;OAMG;IACG,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CACjC;QAAE,IAAI,EAAE,SAAS,CAAC;QAAC,OAAO,EAAE,UAAU,CAAA;KAAE,GAAG;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAC/E;IAcD;;;;;;OAMG;IACG,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,IAAI,CAAA;KAAE,GAAG;QAAE,IAAI,EAAE,UAAU,CAAA;KAAE,CAAC;IA+BxG;;;;OAIG;IACG,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,IAAI,CAAA;KAAE,GAAG;QAAE,IAAI,EAAE,kBAAkB,CAAA;KAAE,CAAC;CAU5G"}
|
package/dist/api.js
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Typed HTTP client for the four runner-side endpoints in
|
|
3
|
+
* docs/api/runner-openapi.yaml. Uses Node's built-in fetch (Node 20+).
|
|
4
|
+
*
|
|
5
|
+
* Idempotency:
|
|
6
|
+
* - /events POST is server-side append-only; the runner is responsible for
|
|
7
|
+
* not re-sending the same eventId on retry. We track sent eventIds per
|
|
8
|
+
* job in memory; only retry on 5xx (network errors).
|
|
9
|
+
* - /complete is server-rejected on double-submit (409). We swallow the 409
|
|
10
|
+
* gracefully so a crashed-and-restarted runner that already completed a
|
|
11
|
+
* job before crashing doesn't loop on it.
|
|
12
|
+
*/
|
|
13
|
+
import { randomUUID } from "node:crypto";
|
|
14
|
+
import { setTimeout as sleep } from "node:timers/promises";
|
|
15
|
+
export class ApiError extends Error {
|
|
16
|
+
status;
|
|
17
|
+
body;
|
|
18
|
+
constructor(status, body, message) {
|
|
19
|
+
super(message ?? `API ${status}: ${body.slice(0, 200)}`);
|
|
20
|
+
this.status = status;
|
|
21
|
+
this.body = body;
|
|
22
|
+
this.name = "ApiError";
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
/** Generate a runner-side event id. Exposed so the spawner can stamp events
|
|
26
|
+
* before they reach the API client. */
|
|
27
|
+
export function makeEventId() {
|
|
28
|
+
return randomUUID();
|
|
29
|
+
}
|
|
30
|
+
export class RunnerApiClient {
|
|
31
|
+
config;
|
|
32
|
+
fetchImpl;
|
|
33
|
+
constructor(config, fetchImpl = fetch) {
|
|
34
|
+
this.config = config;
|
|
35
|
+
this.fetchImpl = fetchImpl;
|
|
36
|
+
}
|
|
37
|
+
url(path) {
|
|
38
|
+
return `${this.config.serverUrl}${path}`;
|
|
39
|
+
}
|
|
40
|
+
headers(extra) {
|
|
41
|
+
return {
|
|
42
|
+
authorization: `Bearer ${this.config.token}`,
|
|
43
|
+
"user-agent": "founderos-runner",
|
|
44
|
+
...(extra ?? {}),
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Long-poll for the next claimable job. Server holds the connection up to
|
|
49
|
+
* 30s. Returns:
|
|
50
|
+
* - { kind: "job", job } on a hit
|
|
51
|
+
* - { kind: "empty" } on 204 timeout (caller re-polls)
|
|
52
|
+
* - throws ApiError on non-2xx
|
|
53
|
+
*/
|
|
54
|
+
async getNext(signal) {
|
|
55
|
+
const res = await this.fetchImpl(this.url("/api/runner/jobs/next"), {
|
|
56
|
+
method: "GET",
|
|
57
|
+
headers: this.headers(),
|
|
58
|
+
signal,
|
|
59
|
+
});
|
|
60
|
+
if (res.status === 204)
|
|
61
|
+
return { kind: "empty" };
|
|
62
|
+
if (!res.ok) {
|
|
63
|
+
throw new ApiError(res.status, await res.text().catch(() => ""));
|
|
64
|
+
}
|
|
65
|
+
const job = (await res.json());
|
|
66
|
+
return { kind: "job", job };
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Atomic claim. Returns:
|
|
70
|
+
* - { kind: "claimed", payload } on success
|
|
71
|
+
* - { kind: "lost" } on 409 (race lost)
|
|
72
|
+
* - { kind: "gone" } on 404 (cancelled / unknown)
|
|
73
|
+
* - throws ApiError on other non-2xx
|
|
74
|
+
*/
|
|
75
|
+
async claim(jobId) {
|
|
76
|
+
const res = await this.fetchImpl(this.url(`/api/runner/jobs/${jobId}/claim`), {
|
|
77
|
+
method: "POST",
|
|
78
|
+
headers: this.headers({ "content-type": "application/json" }),
|
|
79
|
+
});
|
|
80
|
+
if (res.status === 409)
|
|
81
|
+
return { kind: "lost" };
|
|
82
|
+
if (res.status === 404)
|
|
83
|
+
return { kind: "gone" };
|
|
84
|
+
if (!res.ok) {
|
|
85
|
+
throw new ApiError(res.status, await res.text().catch(() => ""));
|
|
86
|
+
}
|
|
87
|
+
const payload = (await res.json());
|
|
88
|
+
return { kind: "claimed", payload };
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Append a batch of events. Caller batches with a 50ms / 32-event window.
|
|
92
|
+
* Idempotent on eventId; the server doesn't dedup but does reject when the
|
|
93
|
+
* job is in a terminal state (409). We retry on 5xx + network errors with
|
|
94
|
+
* a small backoff; on 409 we surface the terminal state to the caller so
|
|
95
|
+
* it can stop spawning.
|
|
96
|
+
*/
|
|
97
|
+
async appendEvents(jobId, events) {
|
|
98
|
+
if (events.length === 0)
|
|
99
|
+
return { kind: "ok" };
|
|
100
|
+
const body = JSON.stringify({ events });
|
|
101
|
+
const headers = this.headers({ "content-type": "application/json" });
|
|
102
|
+
const maxAttempts = 4;
|
|
103
|
+
let lastErr;
|
|
104
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
105
|
+
try {
|
|
106
|
+
const res = await this.fetchImpl(this.url(`/api/runner/jobs/${jobId}/events`), {
|
|
107
|
+
method: "POST",
|
|
108
|
+
headers,
|
|
109
|
+
body,
|
|
110
|
+
});
|
|
111
|
+
if (res.status === 204)
|
|
112
|
+
return { kind: "ok" };
|
|
113
|
+
if (res.status === 409)
|
|
114
|
+
return { kind: "terminal" };
|
|
115
|
+
if (res.status >= 500) {
|
|
116
|
+
lastErr = new ApiError(res.status, await res.text().catch(() => ""));
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
throw new ApiError(res.status, await res.text().catch(() => ""));
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
catch (err) {
|
|
123
|
+
lastErr = err;
|
|
124
|
+
}
|
|
125
|
+
// 100ms, 300ms, 700ms backoff between retries.
|
|
126
|
+
await sleep(100 * (attempt * attempt));
|
|
127
|
+
}
|
|
128
|
+
throw lastErr instanceof Error ? lastErr : new Error("appendEvents: unreachable");
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Mark the job terminal. 409 (already terminal) is swallowed — the runner
|
|
132
|
+
* may have crashed mid-complete and the cloud already accepted the prior
|
|
133
|
+
* call. We log + move on rather than spinning forever.
|
|
134
|
+
*/
|
|
135
|
+
async complete(jobId, body) {
|
|
136
|
+
const res = await this.fetchImpl(this.url(`/api/runner/jobs/${jobId}/complete`), {
|
|
137
|
+
method: "POST",
|
|
138
|
+
headers: this.headers({ "content-type": "application/json" }),
|
|
139
|
+
body: JSON.stringify(body),
|
|
140
|
+
});
|
|
141
|
+
if (res.status === 204)
|
|
142
|
+
return { kind: "ok" };
|
|
143
|
+
if (res.status === 409)
|
|
144
|
+
return { kind: "already_terminal" };
|
|
145
|
+
throw new ApiError(res.status, await res.text().catch(() => ""));
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
//# sourceMappingURL=api.js.map
|
package/dist/api.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* `founderos-runner` CLI entry. Supports a single command:
|
|
4
|
+
*
|
|
5
|
+
* founderos-runner start [--token=...] [--server-url=...] [--claude-bin=...]
|
|
6
|
+
* [--timeout-sec=N] [--log-level=info]
|
|
7
|
+
* founderos-runner --version
|
|
8
|
+
* founderos-runner --help
|
|
9
|
+
*
|
|
10
|
+
* Flags override the matching FOUNDEROS_* environment variables. Both
|
|
11
|
+
* forms are supported because Windows PowerShell users find env-var
|
|
12
|
+
* setup awkward (`$env:FOUNDEROS_RUNNER_TOKEN="..."` vs `--token=...`),
|
|
13
|
+
* and macOS/Linux users in shell scripts often prefer env vars.
|
|
14
|
+
*/
|
|
15
|
+
import { type RunnerConfigOverrides } from "./config.js";
|
|
16
|
+
/**
|
|
17
|
+
* Parse `--key=value` and `--key value` flag forms. Returns parsed
|
|
18
|
+
* overrides + any unknown args (which we treat as errors today).
|
|
19
|
+
*
|
|
20
|
+
* Argv shape: caller has already stripped node + script + the "start"
|
|
21
|
+
* subcommand. Only flag tokens remain.
|
|
22
|
+
*/
|
|
23
|
+
export declare function parseFlags(argv: string[]): {
|
|
24
|
+
overrides: RunnerConfigOverrides;
|
|
25
|
+
unknown: string[];
|
|
26
|
+
};
|
|
27
|
+
export declare function main(argv?: string[]): Promise<number>;
|
|
28
|
+
//# sourceMappingURL=cli.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;GAYG;AAKH,OAAO,EAAiC,KAAK,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAwCxF;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG;IAC1C,SAAS,EAAE,qBAAqB,CAAC;IACjC,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB,CAuDA;AAED,wBAAsB,IAAI,CAAC,IAAI,GAAE,MAAM,EAA0B,GAAG,OAAO,CAAC,MAAM,CAAC,CAqClF"}
|