@suwujs/king-ai 0.2.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 +96 -0
- package/dist/src/agent-config-validation.d.ts +9 -0
- package/dist/src/agent-config-validation.js +30 -0
- package/dist/src/api.d.ts +4 -0
- package/dist/src/api.js +48 -0
- package/dist/src/attachments.d.ts +45 -0
- package/dist/src/attachments.js +322 -0
- package/dist/src/cli.d.ts +20 -0
- package/dist/src/cli.js +1697 -0
- package/dist/src/config.d.ts +3 -0
- package/dist/src/config.js +20 -0
- package/dist/src/cron.d.ts +11 -0
- package/dist/src/cron.js +65 -0
- package/dist/src/daemon.d.ts +36 -0
- package/dist/src/daemon.js +373 -0
- package/dist/src/engine.d.ts +32 -0
- package/dist/src/engine.js +1014 -0
- package/dist/src/heartbeat.d.ts +18 -0
- package/dist/src/heartbeat.js +28 -0
- package/dist/src/host-api.d.ts +40 -0
- package/dist/src/host-api.js +59 -0
- package/dist/src/host-control.d.ts +48 -0
- package/dist/src/host-control.js +1279 -0
- package/dist/src/host-export.d.ts +50 -0
- package/dist/src/host-export.js +187 -0
- package/dist/src/host-feedback.d.ts +78 -0
- package/dist/src/host-feedback.js +178 -0
- package/dist/src/host-home.d.ts +13 -0
- package/dist/src/host-home.js +54 -0
- package/dist/src/host-ledger.d.ts +261 -0
- package/dist/src/host-ledger.js +554 -0
- package/dist/src/host-loop-events.d.ts +69 -0
- package/dist/src/host-loop-events.js +288 -0
- package/dist/src/host-permission.d.ts +36 -0
- package/dist/src/host-permission.js +180 -0
- package/dist/src/host-policy.d.ts +15 -0
- package/dist/src/host-policy.js +36 -0
- package/dist/src/host-run-executor.d.ts +13 -0
- package/dist/src/host-run-executor.js +221 -0
- package/dist/src/host-run-heartbeat.d.ts +40 -0
- package/dist/src/host-run-heartbeat.js +103 -0
- package/dist/src/host-run-layout.d.ts +17 -0
- package/dist/src/host-run-layout.js +387 -0
- package/dist/src/host-run-meta.d.ts +41 -0
- package/dist/src/host-run-meta.js +115 -0
- package/dist/src/host-run-spec.d.ts +149 -0
- package/dist/src/host-run-spec.js +465 -0
- package/dist/src/host-runs.d.ts +77 -0
- package/dist/src/host-runs.js +195 -0
- package/dist/src/host-sdk.d.ts +412 -0
- package/dist/src/host-sdk.js +628 -0
- package/dist/src/host-server.d.ts +26 -0
- package/dist/src/host-server.js +921 -0
- package/dist/src/host-timeline.d.ts +24 -0
- package/dist/src/host-timeline.js +161 -0
- package/dist/src/jsonl.d.ts +13 -0
- package/dist/src/jsonl.js +47 -0
- package/dist/src/lifecycle.d.ts +5 -0
- package/dist/src/lifecycle.js +18 -0
- package/dist/src/message-routing.d.ts +32 -0
- package/dist/src/message-routing.js +119 -0
- package/dist/src/paths.d.ts +19 -0
- package/dist/src/paths.js +26 -0
- package/dist/src/project-profile.d.ts +49 -0
- package/dist/src/project-profile.js +356 -0
- package/dist/src/remediation.d.ts +14 -0
- package/dist/src/remediation.js +114 -0
- package/dist/src/remote-devices.d.ts +41 -0
- package/dist/src/remote-devices.js +156 -0
- package/dist/src/remote-diagnostics.d.ts +39 -0
- package/dist/src/remote-diagnostics.js +199 -0
- package/dist/src/remote-ssh.d.ts +39 -0
- package/dist/src/remote-ssh.js +129 -0
- package/dist/src/run-stream.d.ts +57 -0
- package/dist/src/run-stream.js +119 -0
- package/dist/src/runner.d.ts +131 -0
- package/dist/src/runner.js +1161 -0
- package/dist/src/runtime-data.d.ts +68 -0
- package/dist/src/runtime-data.js +172 -0
- package/dist/src/service.d.ts +114 -0
- package/dist/src/service.js +631 -0
- package/dist/src/shared-skills.d.ts +26 -0
- package/dist/src/shared-skills.js +85 -0
- package/dist/src/shim.d.ts +1 -0
- package/dist/src/shim.js +64 -0
- package/dist/src/skill-check.d.ts +17 -0
- package/dist/src/skill-check.js +158 -0
- package/dist/src/sse.d.ts +9 -0
- package/dist/src/sse.js +36 -0
- package/dist/src/team-routing.d.ts +55 -0
- package/dist/src/team-routing.js +131 -0
- package/dist/src/team-workflow.d.ts +78 -0
- package/dist/src/team-workflow.js +253 -0
- package/dist/src/text.d.ts +7 -0
- package/dist/src/text.js +27 -0
- package/dist/src/types.d.ts +98 -0
- package/dist/src/types.js +1 -0
- package/dist/src/usage.d.ts +116 -0
- package/dist/src/usage.js +350 -0
- package/dist/src/workspace.d.ts +9 -0
- package/dist/src/workspace.js +56 -0
- package/dist/src/worktree.d.ts +47 -0
- package/dist/src/worktree.js +201 -0
- package/package.json +63 -0
|
@@ -0,0 +1,628 @@
|
|
|
1
|
+
import { DEFAULT_SSE_MAX_BUFFER_BYTES } from "./sse.js";
|
|
2
|
+
export function createDefaultHostSdkRunOptions(overrides = {}) {
|
|
3
|
+
const infinite = overrides.infinite ?? overrides.loops === Infinity;
|
|
4
|
+
return {
|
|
5
|
+
...overrides,
|
|
6
|
+
loops: infinite ? Infinity : Math.max(1, Math.floor(overrides.loops ?? 100)),
|
|
7
|
+
pollIntervalSeconds: Math.max(1, Math.floor(overrides.pollIntervalSeconds ?? overrides.pollInterval ?? 15)),
|
|
8
|
+
infinite,
|
|
9
|
+
engine: overrides.engine ?? overrides.runtime,
|
|
10
|
+
model: cleanSdkString(overrides.model ?? overrides.codexModel),
|
|
11
|
+
fastModel: cleanSdkString(overrides.fastModel),
|
|
12
|
+
configPath: cleanSdkString(overrides.configPath),
|
|
13
|
+
workerUrl: cleanSdkString(overrides.workerUrl),
|
|
14
|
+
workerModel: cleanSdkString(overrides.workerModel),
|
|
15
|
+
workerKey: cleanSdkString(overrides.workerKey) ?? "lmstudio",
|
|
16
|
+
noBrain: overrides.noBrain ?? (overrides.enableBrain === undefined ? false : !overrides.enableBrain),
|
|
17
|
+
outputDir: cleanSdkString(overrides.outputDir ?? overrides.output) ?? "./deliverables",
|
|
18
|
+
keepArtifacts: overrides.keepArtifacts ?? overrides.keep ?? false,
|
|
19
|
+
errorLimit: Math.max(1, Math.floor(overrides.errorLimit ?? 20))
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
export function createHostSdkRunOptions(overrides = {}) {
|
|
23
|
+
return createDefaultHostSdkRunOptions(overrides);
|
|
24
|
+
}
|
|
25
|
+
export function createHostSdkTakeoverRunOptions(overrides = {}) {
|
|
26
|
+
return createDefaultHostSdkRunOptions({
|
|
27
|
+
infinite: true,
|
|
28
|
+
loops: Infinity,
|
|
29
|
+
...overrides
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
export const createDefaultRunOptions = createDefaultHostSdkRunOptions;
|
|
33
|
+
export const createRunOptions = createHostSdkRunOptions;
|
|
34
|
+
export const createTakeoverRunOptions = createHostSdkTakeoverRunOptions;
|
|
35
|
+
export function createHostSdk(options = {}) {
|
|
36
|
+
const baseUrl = normalizeBaseUrl(options.baseUrl ?? "http://127.0.0.1:8799");
|
|
37
|
+
const fetchImpl = options.fetch ?? fetch;
|
|
38
|
+
return {
|
|
39
|
+
health: () => getJson(fetchImpl, baseUrl, "/health"),
|
|
40
|
+
status: () => getJson(fetchImpl, baseUrl, "/status"),
|
|
41
|
+
statusStream: (streamOptions) => streamHostStatus(fetchImpl, baseUrl, streamOptions),
|
|
42
|
+
events: () => getJson(fetchImpl, baseUrl, "/events"),
|
|
43
|
+
usage: () => getJson(fetchImpl, baseUrl, "/usage"),
|
|
44
|
+
expenses: () => getJson(fetchImpl, baseUrl, "/expenses"),
|
|
45
|
+
doctor: () => getJson(fetchImpl, baseUrl, "/doctor"),
|
|
46
|
+
commands: () => getJson(fetchImpl, baseUrl, "/commands"),
|
|
47
|
+
capabilities: () => getJson(fetchImpl, baseUrl, "/capabilities"),
|
|
48
|
+
snapshot: (limit = 20, status) => getJson(fetchImpl, baseUrl, pathWithQuery("/host/snapshot", { limit, status })),
|
|
49
|
+
waitForReady: (waitOptions) => waitForHostReady(fetchImpl, baseUrl, waitOptions),
|
|
50
|
+
watch: (watchOptions) => watchHost(fetchImpl, baseUrl, watchOptions),
|
|
51
|
+
hostStream: (streamOptions) => streamHostFrames(fetchImpl, baseUrl, streamOptions),
|
|
52
|
+
timelineStream: (streamOptions) => streamHostTimeline(fetchImpl, baseUrl, streamOptions),
|
|
53
|
+
run: (goal, options = {}, spec = {}) => {
|
|
54
|
+
return postJson(fetchImpl, baseUrl, "/runs/preflight", hostRunSpecFromSdk(goal, createHostSdkRunOptions(options), spec, "run"));
|
|
55
|
+
},
|
|
56
|
+
runAndWatch: (goal, options = {}, spec = {}, watchOptions) => {
|
|
57
|
+
return submitAndWatchHostRun(fetchImpl, baseUrl, hostRunSubmitInputFromSdk(goal, createHostSdkRunOptions(options), spec, "run"), watchOptions);
|
|
58
|
+
},
|
|
59
|
+
runAndWatchState: (goal, options = {}, spec = {}, watchOptions) => {
|
|
60
|
+
return submitAndWatchHostRunState(fetchImpl, baseUrl, hostRunSubmitInputFromSdk(goal, createHostSdkRunOptions(options), spec, "run"), watchOptions);
|
|
61
|
+
},
|
|
62
|
+
takeover: async (options, runOptions = {}) => (await prepareHostSdkTakeover(fetchImpl, baseUrl, options, runOptions)).preflight,
|
|
63
|
+
prepareTakeover: (options, runOptions = {}) => prepareHostSdkTakeover(fetchImpl, baseUrl, options, runOptions),
|
|
64
|
+
executePreparedTakeover: (prepared, spec = {}, watchOptions) => {
|
|
65
|
+
const goal = prepared.input.goal;
|
|
66
|
+
return submitAndWatchHostRun(fetchImpl, baseUrl, hostRunSubmitInputFromSdk(goal, prepared.runOptions, {
|
|
67
|
+
...prepared.input,
|
|
68
|
+
...spec,
|
|
69
|
+
options: {
|
|
70
|
+
...prepared.input.options,
|
|
71
|
+
...spec.options
|
|
72
|
+
}
|
|
73
|
+
}, "takeover"), watchOptions);
|
|
74
|
+
},
|
|
75
|
+
executePreparedTakeoverState: (prepared, spec = {}, watchOptions) => {
|
|
76
|
+
const goal = prepared.input.goal;
|
|
77
|
+
return submitAndWatchHostRunState(fetchImpl, baseUrl, hostRunSubmitInputFromSdk(goal, prepared.runOptions, {
|
|
78
|
+
...prepared.input,
|
|
79
|
+
...spec,
|
|
80
|
+
options: {
|
|
81
|
+
...prepared.input.options,
|
|
82
|
+
...spec.options
|
|
83
|
+
}
|
|
84
|
+
}, "takeover"), watchOptions);
|
|
85
|
+
},
|
|
86
|
+
takeoverAndWatch: (options, runOptions = {}, spec = {}, watchOptions) => {
|
|
87
|
+
const merged = { ...runOptions, ...options };
|
|
88
|
+
const goal = options.goalOverride ?? `Take over ${options.projectPath ?? options.projectDir ?? options.repoSourceDir ?? "project"}`;
|
|
89
|
+
return submitAndWatchHostRun(fetchImpl, baseUrl, hostRunSubmitInputFromSdk(goal, createHostSdkTakeoverRunOptions({
|
|
90
|
+
...merged,
|
|
91
|
+
projectDir: options.projectPath ?? merged.projectDir
|
|
92
|
+
}), spec, "takeover"), watchOptions);
|
|
93
|
+
},
|
|
94
|
+
takeoverAndWatchState: (options, runOptions = {}, spec = {}, watchOptions) => {
|
|
95
|
+
const merged = { ...runOptions, ...options };
|
|
96
|
+
const goal = options.goalOverride ?? `Take over ${options.projectPath ?? options.projectDir ?? options.repoSourceDir ?? "project"}`;
|
|
97
|
+
return submitAndWatchHostRunState(fetchImpl, baseUrl, hostRunSubmitInputFromSdk(goal, createHostSdkTakeoverRunOptions({
|
|
98
|
+
...merged,
|
|
99
|
+
projectDir: options.projectPath ?? merged.projectDir
|
|
100
|
+
}), spec, "takeover"), watchOptions);
|
|
101
|
+
},
|
|
102
|
+
runCommand: (request) => runHostSdkCommand(fetchImpl, baseUrl, request),
|
|
103
|
+
planRun: (input) => postJson(fetchImpl, baseUrl, "/runs/plan", input),
|
|
104
|
+
preflight: (input) => postJson(fetchImpl, baseUrl, "/runs/preflight", input),
|
|
105
|
+
prepareRunLayout: (input) => postJson(fetchImpl, baseUrl, "/runs/prepare-layout", input),
|
|
106
|
+
submitRun: (input) => postJson(fetchImpl, baseUrl, "/runs", input),
|
|
107
|
+
submitAndExecuteRun: (input) => submitAndExecuteHostRun(fetchImpl, baseUrl, input),
|
|
108
|
+
submitAndWatchRun: (input, watchOptions) => submitAndWatchHostRun(fetchImpl, baseUrl, input, watchOptions),
|
|
109
|
+
submitAndWatchRunState: (input, watchOptions) => submitAndWatchHostRunState(fetchImpl, baseUrl, input, watchOptions),
|
|
110
|
+
runRequests: (limit = 20, status) => getJson(fetchImpl, baseUrl, pathWithQuery("/runs", { limit, status })),
|
|
111
|
+
runRequestsStream: (streamOptions) => streamHostRunRequests(fetchImpl, baseUrl, streamOptions),
|
|
112
|
+
runRequest: (id) => getJson(fetchImpl, baseUrl, `/runs/${encodeURIComponent(id)}`),
|
|
113
|
+
runRequestStream: (id, streamOptions) => streamHostRunRequest(fetchImpl, baseUrl, id, streamOptions),
|
|
114
|
+
runStateStream: (id, streamOptions) => streamHostRunState(fetchImpl, baseUrl, id, streamOptions),
|
|
115
|
+
emitRunEvent: (id, event) => postJson(fetchImpl, baseUrl, `/runs/${encodeURIComponent(id)}/events`, { event }),
|
|
116
|
+
runEvents: (id, eventsOptions = {}) => getJson(fetchImpl, baseUrl, pathWithQuery(`/runs/${encodeURIComponent(id)}/events`, eventsOptions)),
|
|
117
|
+
watchRun: (id, eventsOptions = {}) => getJson(fetchImpl, baseUrl, pathWithQuery(`/runs/${encodeURIComponent(id)}/events`, eventsOptions)),
|
|
118
|
+
runResults: (id, resultsOptions = {}) => getJson(fetchImpl, baseUrl, pathWithQuery(`/runs/${encodeURIComponent(id)}/results`, resultsOptions)),
|
|
119
|
+
runHeartbeat: (id, heartbeatOptions = {}) => getJson(fetchImpl, baseUrl, pathWithQuery(`/runs/${encodeURIComponent(id)}/heartbeat`, heartbeatOptions)),
|
|
120
|
+
runMeta: (id, metaOptions = {}) => getJson(fetchImpl, baseUrl, pathWithQuery(`/runs/${encodeURIComponent(id)}/meta`, metaOptions)),
|
|
121
|
+
waitForRun: (id, waitOptions) => waitForHostRun(fetchImpl, baseUrl, id, waitOptions),
|
|
122
|
+
updateRun: (id, status, detail) => patchJson(fetchImpl, baseUrl, `/runs/${encodeURIComponent(id)}`, { status, detail }),
|
|
123
|
+
completeRun: (id, detail) => patchJson(fetchImpl, baseUrl, `/runs/${encodeURIComponent(id)}`, { status: "completed", detail }),
|
|
124
|
+
failRun: (id, detail) => patchJson(fetchImpl, baseUrl, `/runs/${encodeURIComponent(id)}`, { status: "failed", detail }),
|
|
125
|
+
cancelRun: (id, detail) => deleteJson(fetchImpl, baseUrl, `/runs/${encodeURIComponent(id)}`, { detail }),
|
|
126
|
+
executeRun: (id) => postJson(fetchImpl, baseUrl, id ? `/runs/${encodeURIComponent(id)}/execute` : "/runs/execute", {}),
|
|
127
|
+
planExport: (input) => postJson(fetchImpl, baseUrl, "/exports/plan", input),
|
|
128
|
+
exportArtifacts: (input) => postJson(fetchImpl, baseUrl, "/exports", input),
|
|
129
|
+
policy: (command, input = {}) => {
|
|
130
|
+
const path = `/policy/${encodeURIComponent(command)}`;
|
|
131
|
+
return input.confirmed !== undefined || input.confirmation !== undefined
|
|
132
|
+
? postJson(fetchImpl, baseUrl, path, input)
|
|
133
|
+
: getJson(fetchImpl, baseUrl, path);
|
|
134
|
+
},
|
|
135
|
+
timeline: (limit = 20) => getJson(fetchImpl, baseUrl, pathWithQuery("/timeline", { limit }))
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
export function createKingHostSdk(config = {}, adapters) {
|
|
139
|
+
if (!adapters)
|
|
140
|
+
return createHostSdk(config);
|
|
141
|
+
const bindings = {
|
|
142
|
+
hostEnv: {
|
|
143
|
+
...process.env,
|
|
144
|
+
...(config.env ?? {})
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
const sdk = {
|
|
148
|
+
async run(goal, options = {}, spec = {}) {
|
|
149
|
+
await adapters.runGoal(goal, createRunOptions(options), spec, bindings);
|
|
150
|
+
},
|
|
151
|
+
prepareTakeover(options) {
|
|
152
|
+
return adapters.prepareTakeoverPlan(adapters.normalizeTakeoverOptions(options));
|
|
153
|
+
},
|
|
154
|
+
async executePreparedTakeover(plan, options = {}) {
|
|
155
|
+
await adapters.executePreparedTakeoverPlan(plan, createTakeoverRunOptions(options), bindings);
|
|
156
|
+
},
|
|
157
|
+
async takeover(options, runOptions = {}) {
|
|
158
|
+
const plan = sdk.prepareTakeover(options);
|
|
159
|
+
await sdk.executePreparedTakeover(plan, runOptions);
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
return sdk;
|
|
163
|
+
}
|
|
164
|
+
export function createEnvBackedHostSdk(env = process.env, options = {}) {
|
|
165
|
+
return createHostSdk({
|
|
166
|
+
...options,
|
|
167
|
+
baseUrl: hostBaseUrlFromEnv(env)
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
export function createEnvBackedKingHostSdk(env = process.env, config = {}, adapters) {
|
|
171
|
+
if (!adapters)
|
|
172
|
+
return createEnvBackedHostSdk(env, config);
|
|
173
|
+
return createKingHostSdk({ ...config, env }, adapters);
|
|
174
|
+
}
|
|
175
|
+
export function createBrowserHostSdk(options = {}) {
|
|
176
|
+
return createHostSdk({
|
|
177
|
+
...options,
|
|
178
|
+
baseUrl: options.baseUrl ?? hostBaseUrlFromLocation(options.location ?? globalLocationLike(), options)
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
export function hostBaseUrlFromEnv(env = process.env) {
|
|
182
|
+
if (env.KING_AI_HOST_URL)
|
|
183
|
+
return env.KING_AI_HOST_URL;
|
|
184
|
+
const host = env.KING_AI_HOST || "127.0.0.1";
|
|
185
|
+
const port = env.KING_AI_HOST_PORT || "8799";
|
|
186
|
+
return `http://${host}:${port}`;
|
|
187
|
+
}
|
|
188
|
+
export function hostBaseUrlFromLocation(location, options = {}) {
|
|
189
|
+
if (options.useCurrentOrigin && location?.origin)
|
|
190
|
+
return location.origin;
|
|
191
|
+
const port = options.port ?? location?.port ?? "8799";
|
|
192
|
+
const hostname = location && isLocalHostName(location.hostname) ? location.hostname : "127.0.0.1";
|
|
193
|
+
const protocol = location?.protocol === "https:" ? "https:" : "http:";
|
|
194
|
+
return `${protocol}//${hostname}${port ? `:${port}` : ""}`;
|
|
195
|
+
}
|
|
196
|
+
export async function waitForHostReady(fetchImpl, baseUrl, options = {}) {
|
|
197
|
+
const timeoutMs = Math.max(1, Math.floor(options.timeoutMs ?? 10_000));
|
|
198
|
+
const intervalMs = Math.max(1, Math.floor(options.intervalMs ?? 250));
|
|
199
|
+
const deadline = Date.now() + timeoutMs;
|
|
200
|
+
let lastError;
|
|
201
|
+
while (Date.now() <= deadline) {
|
|
202
|
+
try {
|
|
203
|
+
const health = await getJson(fetchImpl, baseUrl, "/health");
|
|
204
|
+
if (health.ok) {
|
|
205
|
+
const status = await getJson(fetchImpl, baseUrl, "/status");
|
|
206
|
+
if (!options.requireDaemon || status.ok)
|
|
207
|
+
return status;
|
|
208
|
+
lastError = new Error("host server is reachable but daemon state is not ready");
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
catch (err) {
|
|
212
|
+
lastError = err;
|
|
213
|
+
}
|
|
214
|
+
await delay(intervalMs);
|
|
215
|
+
}
|
|
216
|
+
const reason = lastError instanceof Error ? `: ${lastError.message}` : "";
|
|
217
|
+
throw new Error(`host server did not become ready within ${timeoutMs}ms${reason}`);
|
|
218
|
+
}
|
|
219
|
+
export async function waitForHostRun(fetchImpl, baseUrl, id, options = {}) {
|
|
220
|
+
const timeoutMs = Math.max(1, Math.floor(options.timeoutMs ?? 30_000));
|
|
221
|
+
const intervalMs = Math.max(1, Math.floor(options.intervalMs ?? 250));
|
|
222
|
+
const terminals = new Set(options.terminalStatuses ?? ["completed", "failed", "cancelled"]);
|
|
223
|
+
const deadline = Date.now() + timeoutMs;
|
|
224
|
+
let last;
|
|
225
|
+
while (Date.now() <= deadline) {
|
|
226
|
+
last = await getJson(fetchImpl, baseUrl, `/runs/${encodeURIComponent(id)}`);
|
|
227
|
+
const status = last.json?.request.status;
|
|
228
|
+
if (status && terminals.has(status))
|
|
229
|
+
return last;
|
|
230
|
+
await delay(intervalMs);
|
|
231
|
+
}
|
|
232
|
+
const status = last?.json?.request.status;
|
|
233
|
+
throw new Error(`host run ${id} did not reach a terminal status within ${timeoutMs}ms${status ? `; last status=${status}` : ""}`);
|
|
234
|
+
}
|
|
235
|
+
export async function submitAndExecuteHostRun(fetchImpl, baseUrl, input) {
|
|
236
|
+
const submitted = await postJson(fetchImpl, baseUrl, "/runs", input);
|
|
237
|
+
const id = submitted.json?.request.id;
|
|
238
|
+
if (!submitted.ok || !id) {
|
|
239
|
+
return {
|
|
240
|
+
submitted,
|
|
241
|
+
executed: {
|
|
242
|
+
ok: false,
|
|
243
|
+
command: "execute-run",
|
|
244
|
+
exitCode: 1,
|
|
245
|
+
text: "host run was not submitted",
|
|
246
|
+
error: submitted.error ?? "host run was not submitted"
|
|
247
|
+
}
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
const executed = await postJson(fetchImpl, baseUrl, `/runs/${encodeURIComponent(id)}/execute`, {});
|
|
251
|
+
return { submitted, executed };
|
|
252
|
+
}
|
|
253
|
+
export async function* submitAndWatchHostRun(fetchImpl, baseUrl, input, options = {}) {
|
|
254
|
+
const submitted = await postJson(fetchImpl, baseUrl, "/runs", input);
|
|
255
|
+
yield { event: "submitted", data: submitted };
|
|
256
|
+
const id = submitted.json?.request.id;
|
|
257
|
+
if (!submitted.ok || !id)
|
|
258
|
+
return;
|
|
259
|
+
const terminalStatuses = new Set(options.terminalStatuses ?? ["completed", "failed", "cancelled"]);
|
|
260
|
+
for await (const request of streamHostRunRequest(fetchImpl, baseUrl, id, options)) {
|
|
261
|
+
yield { event: "run", data: request };
|
|
262
|
+
if (request && terminalStatuses.has(request.status))
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
export async function* submitAndWatchHostRunState(fetchImpl, baseUrl, input, options = {}) {
|
|
267
|
+
const submitted = await postJson(fetchImpl, baseUrl, "/runs", input);
|
|
268
|
+
yield { event: "submitted", data: submitted };
|
|
269
|
+
const id = submitted.json?.request.id;
|
|
270
|
+
if (!submitted.ok || !id)
|
|
271
|
+
return;
|
|
272
|
+
const terminalStatuses = new Set(options.terminalStatuses ?? ["completed", "failed", "cancelled"]);
|
|
273
|
+
for await (const state of streamHostRunState(fetchImpl, baseUrl, id, options)) {
|
|
274
|
+
yield { event: "state", data: state };
|
|
275
|
+
const status = state.request?.status;
|
|
276
|
+
if (status && terminalStatuses.has(status))
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
export async function prepareHostSdkTakeover(fetchImpl, baseUrl, options, runOptions = {}) {
|
|
281
|
+
const merged = { ...runOptions, ...options };
|
|
282
|
+
const normalizedRunOptions = createHostSdkTakeoverRunOptions({
|
|
283
|
+
...merged,
|
|
284
|
+
projectDir: options.projectPath ?? merged.projectDir
|
|
285
|
+
});
|
|
286
|
+
const goal = options.goalOverride ?? `Take over ${options.projectPath ?? options.projectDir ?? options.repoSourceDir ?? "project"}`;
|
|
287
|
+
const input = hostRunSpecFromSdk(goal, normalizedRunOptions, {}, "takeover");
|
|
288
|
+
const preflight = await postJson(fetchImpl, baseUrl, "/runs/preflight", input);
|
|
289
|
+
return {
|
|
290
|
+
options,
|
|
291
|
+
runOptions: normalizedRunOptions,
|
|
292
|
+
input,
|
|
293
|
+
preflight
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
export async function* streamHostStatus(fetchImpl, baseUrl, options = {}) {
|
|
297
|
+
const path = pathWithQuery("/status/stream", { interval: options.intervalMs });
|
|
298
|
+
const response = await fetchImpl(urlFor(baseUrl, path), {
|
|
299
|
+
headers: {
|
|
300
|
+
Accept: "text/event-stream"
|
|
301
|
+
},
|
|
302
|
+
signal: options.signal
|
|
303
|
+
});
|
|
304
|
+
if (!response.ok || !response.body) {
|
|
305
|
+
throw new Error(`host status stream failed with HTTP ${response.status}`);
|
|
306
|
+
}
|
|
307
|
+
for await (const parsed of streamSseFrames(response.body)) {
|
|
308
|
+
if (parsed.event === "status" && parsed.data)
|
|
309
|
+
yield parsed.data;
|
|
310
|
+
if (parsed.event === "error" && parsed.data && typeof parsed.data === "object") {
|
|
311
|
+
const message = parsed.data.error;
|
|
312
|
+
throw new Error(typeof message === "string" ? message : "host status stream error");
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
export async function* streamHostTimeline(fetchImpl, baseUrl, options = {}) {
|
|
317
|
+
const path = pathWithQuery("/timeline/stream", { interval: options.intervalMs, limit: options.limit });
|
|
318
|
+
const response = await fetchImpl(urlFor(baseUrl, path), {
|
|
319
|
+
headers: {
|
|
320
|
+
Accept: "text/event-stream"
|
|
321
|
+
},
|
|
322
|
+
signal: options.signal
|
|
323
|
+
});
|
|
324
|
+
if (!response.ok || !response.body) {
|
|
325
|
+
throw new Error(`host timeline stream failed with HTTP ${response.status}`);
|
|
326
|
+
}
|
|
327
|
+
for await (const parsed of streamSseFrames(response.body)) {
|
|
328
|
+
if (parsed.event === "timeline" && Array.isArray(parsed.data))
|
|
329
|
+
yield parsed.data;
|
|
330
|
+
if (parsed.event === "error" && parsed.data && typeof parsed.data === "object") {
|
|
331
|
+
const message = parsed.data.error;
|
|
332
|
+
throw new Error(typeof message === "string" ? message : "host timeline stream error");
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
export async function* streamHostFrames(fetchImpl, baseUrl, options = {}) {
|
|
337
|
+
const path = pathWithQuery("/host/stream", {
|
|
338
|
+
interval: options.intervalMs,
|
|
339
|
+
limit: options.limit,
|
|
340
|
+
timelineLimit: options.timelineLimit,
|
|
341
|
+
runLimit: options.runLimit,
|
|
342
|
+
status: options.status
|
|
343
|
+
});
|
|
344
|
+
const response = await fetchImpl(urlFor(baseUrl, path), {
|
|
345
|
+
headers: {
|
|
346
|
+
Accept: "text/event-stream"
|
|
347
|
+
},
|
|
348
|
+
signal: options.signal
|
|
349
|
+
});
|
|
350
|
+
if (!response.ok || !response.body) {
|
|
351
|
+
throw new Error(`host stream failed with HTTP ${response.status}`);
|
|
352
|
+
}
|
|
353
|
+
for await (const parsed of streamSseFrames(response.body)) {
|
|
354
|
+
if (parsed.event === "status" && parsed.data && typeof parsed.data === "object") {
|
|
355
|
+
yield { event: "status", data: parsed.data };
|
|
356
|
+
}
|
|
357
|
+
if (parsed.event === "timeline" && Array.isArray(parsed.data)) {
|
|
358
|
+
yield { event: "timeline", data: parsed.data };
|
|
359
|
+
}
|
|
360
|
+
if (parsed.event === "runs" && parsed.data && typeof parsed.data === "object") {
|
|
361
|
+
const requests = parsed.data.requests;
|
|
362
|
+
if (Array.isArray(requests))
|
|
363
|
+
yield { event: "runs", data: requests };
|
|
364
|
+
}
|
|
365
|
+
if (parsed.event === "error" && parsed.data && typeof parsed.data === "object") {
|
|
366
|
+
const message = parsed.data.error;
|
|
367
|
+
throw new Error(typeof message === "string" ? message : "host stream error");
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
export async function* watchHost(fetchImpl, baseUrl, options = {}) {
|
|
372
|
+
if (options.includeInitialSnapshot !== false) {
|
|
373
|
+
const limit = options.limit ?? Math.max(options.timelineLimit ?? 0, options.runLimit ?? 0, 20);
|
|
374
|
+
yield {
|
|
375
|
+
event: "snapshot",
|
|
376
|
+
data: await getJson(fetchImpl, baseUrl, pathWithQuery("/host/snapshot", { limit, status: options.status }))
|
|
377
|
+
};
|
|
378
|
+
}
|
|
379
|
+
yield* streamHostFrames(fetchImpl, baseUrl, options);
|
|
380
|
+
}
|
|
381
|
+
export async function* streamHostRunRequests(fetchImpl, baseUrl, options = {}) {
|
|
382
|
+
const path = pathWithQuery("/runs/stream", { interval: options.intervalMs, limit: options.limit, status: options.status });
|
|
383
|
+
const response = await fetchImpl(urlFor(baseUrl, path), {
|
|
384
|
+
headers: {
|
|
385
|
+
Accept: "text/event-stream"
|
|
386
|
+
},
|
|
387
|
+
signal: options.signal
|
|
388
|
+
});
|
|
389
|
+
if (!response.ok || !response.body) {
|
|
390
|
+
throw new Error(`host run requests stream failed with HTTP ${response.status}`);
|
|
391
|
+
}
|
|
392
|
+
for await (const parsed of streamSseFrames(response.body)) {
|
|
393
|
+
if (parsed.event === "runs" && parsed.data && typeof parsed.data === "object") {
|
|
394
|
+
const requests = parsed.data.requests;
|
|
395
|
+
if (Array.isArray(requests))
|
|
396
|
+
yield requests;
|
|
397
|
+
}
|
|
398
|
+
if (parsed.event === "error" && parsed.data && typeof parsed.data === "object") {
|
|
399
|
+
const message = parsed.data.error;
|
|
400
|
+
throw new Error(typeof message === "string" ? message : "host run requests stream error");
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
export async function* streamHostRunRequest(fetchImpl, baseUrl, id, options = {}) {
|
|
405
|
+
for await (const frame of streamHostRunState(fetchImpl, baseUrl, id, options)) {
|
|
406
|
+
yield frame.request;
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
export async function* streamHostRunState(fetchImpl, baseUrl, id, options = {}) {
|
|
410
|
+
const path = pathWithQuery(`/runs/${encodeURIComponent(id)}/stream`, { interval: options.intervalMs });
|
|
411
|
+
const response = await fetchImpl(urlFor(baseUrl, path), {
|
|
412
|
+
headers: {
|
|
413
|
+
Accept: "text/event-stream"
|
|
414
|
+
},
|
|
415
|
+
signal: options.signal
|
|
416
|
+
});
|
|
417
|
+
if (!response.ok || !response.body) {
|
|
418
|
+
throw new Error(`host run request stream failed with HTTP ${response.status}`);
|
|
419
|
+
}
|
|
420
|
+
for await (const parsed of streamSseFrames(response.body)) {
|
|
421
|
+
if (parsed.event === "run" && parsed.data && typeof parsed.data === "object") {
|
|
422
|
+
yield parseHostRunStateFrame(parsed.data);
|
|
423
|
+
}
|
|
424
|
+
if (parsed.event === "error" && parsed.data && typeof parsed.data === "object") {
|
|
425
|
+
const message = parsed.data.error;
|
|
426
|
+
throw new Error(typeof message === "string" ? message : "host run request stream error");
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
function parseHostRunStateFrame(data) {
|
|
431
|
+
const value = data && typeof data === "object" ? data : {};
|
|
432
|
+
return {
|
|
433
|
+
request: value.request && typeof value.request === "object" ? value.request : null,
|
|
434
|
+
heartbeat: value.heartbeat && typeof value.heartbeat === "object" ? value.heartbeat : null,
|
|
435
|
+
meta: value.meta && typeof value.meta === "object" ? value.meta : null
|
|
436
|
+
};
|
|
437
|
+
}
|
|
438
|
+
export async function runHostSdkCommand(fetchImpl, baseUrl, request) {
|
|
439
|
+
const response = await fetchImpl(urlFor(baseUrl, "/commands/run"), {
|
|
440
|
+
method: "POST",
|
|
441
|
+
headers: {
|
|
442
|
+
"Content-Type": "application/json"
|
|
443
|
+
},
|
|
444
|
+
body: JSON.stringify(request)
|
|
445
|
+
});
|
|
446
|
+
const result = await readJson(response);
|
|
447
|
+
if (!response.ok && !result.error) {
|
|
448
|
+
result.error = `host command failed with HTTP ${response.status}`;
|
|
449
|
+
}
|
|
450
|
+
return result;
|
|
451
|
+
}
|
|
452
|
+
async function getJson(fetchImpl, baseUrl, path) {
|
|
453
|
+
const response = await fetchImpl(urlFor(baseUrl, path));
|
|
454
|
+
return readJson(response);
|
|
455
|
+
}
|
|
456
|
+
async function postJson(fetchImpl, baseUrl, path, body) {
|
|
457
|
+
const response = await fetchImpl(urlFor(baseUrl, path), {
|
|
458
|
+
method: "POST",
|
|
459
|
+
headers: {
|
|
460
|
+
"Content-Type": "application/json"
|
|
461
|
+
},
|
|
462
|
+
body: JSON.stringify(body)
|
|
463
|
+
});
|
|
464
|
+
return readJson(response);
|
|
465
|
+
}
|
|
466
|
+
async function patchJson(fetchImpl, baseUrl, path, body) {
|
|
467
|
+
const response = await fetchImpl(urlFor(baseUrl, path), {
|
|
468
|
+
method: "PATCH",
|
|
469
|
+
headers: {
|
|
470
|
+
"Content-Type": "application/json"
|
|
471
|
+
},
|
|
472
|
+
body: JSON.stringify(body)
|
|
473
|
+
});
|
|
474
|
+
return readJson(response);
|
|
475
|
+
}
|
|
476
|
+
async function deleteJson(fetchImpl, baseUrl, path, body) {
|
|
477
|
+
const response = await fetchImpl(urlFor(baseUrl, path), {
|
|
478
|
+
method: "DELETE",
|
|
479
|
+
headers: {
|
|
480
|
+
"Content-Type": "application/json"
|
|
481
|
+
},
|
|
482
|
+
body: JSON.stringify(body)
|
|
483
|
+
});
|
|
484
|
+
return readJson(response);
|
|
485
|
+
}
|
|
486
|
+
async function readJson(response) {
|
|
487
|
+
const text = await response.text();
|
|
488
|
+
try {
|
|
489
|
+
return JSON.parse(text);
|
|
490
|
+
}
|
|
491
|
+
catch {
|
|
492
|
+
throw new Error(`host SDK expected JSON response from ${response.url || "host server"}`);
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
function normalizeBaseUrl(value) {
|
|
496
|
+
const url = new URL(value);
|
|
497
|
+
if (url.protocol !== "http:" && url.protocol !== "https:")
|
|
498
|
+
throw new Error("host SDK baseUrl must be http or https");
|
|
499
|
+
return url.toString().replace(/\/+$/, "");
|
|
500
|
+
}
|
|
501
|
+
function cleanSdkString(value) {
|
|
502
|
+
return typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
503
|
+
}
|
|
504
|
+
function globalLocationLike() {
|
|
505
|
+
const location = globalThis.location;
|
|
506
|
+
if (!location || typeof location.protocol !== "string" || typeof location.hostname !== "string")
|
|
507
|
+
return undefined;
|
|
508
|
+
return {
|
|
509
|
+
protocol: location.protocol,
|
|
510
|
+
hostname: location.hostname,
|
|
511
|
+
port: typeof location.port === "string" ? location.port : undefined,
|
|
512
|
+
origin: typeof location.origin === "string" ? location.origin : undefined
|
|
513
|
+
};
|
|
514
|
+
}
|
|
515
|
+
function isLocalHostName(value) {
|
|
516
|
+
return value === "localhost" || value === "127.0.0.1" || value === "::1" || value === "[::1]";
|
|
517
|
+
}
|
|
518
|
+
function urlFor(baseUrl, path) {
|
|
519
|
+
return `${baseUrl}${path.startsWith("/") ? path : `/${path}`}`;
|
|
520
|
+
}
|
|
521
|
+
function pathWithQuery(path, query) {
|
|
522
|
+
const params = new URLSearchParams();
|
|
523
|
+
for (const [key, value] of Object.entries(query)) {
|
|
524
|
+
if (value !== undefined && value !== "")
|
|
525
|
+
params.set(key, String(value));
|
|
526
|
+
}
|
|
527
|
+
const serialized = params.toString();
|
|
528
|
+
return serialized ? `${path}?${serialized}` : path;
|
|
529
|
+
}
|
|
530
|
+
function parseSseFrame(frame) {
|
|
531
|
+
let event = "message";
|
|
532
|
+
const data = [];
|
|
533
|
+
for (const line of frame.split(/\r?\n/)) {
|
|
534
|
+
if (line.startsWith("event:"))
|
|
535
|
+
event = line.slice("event:".length).trim();
|
|
536
|
+
else if (line.startsWith("data:"))
|
|
537
|
+
data.push(line.slice("data:".length).trimStart());
|
|
538
|
+
}
|
|
539
|
+
if (data.length === 0)
|
|
540
|
+
return { event };
|
|
541
|
+
try {
|
|
542
|
+
return { event, data: JSON.parse(data.join("\n")) };
|
|
543
|
+
}
|
|
544
|
+
catch {
|
|
545
|
+
return { event, data: data.join("\n") };
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
function isAsyncIterableBody(body) {
|
|
549
|
+
return typeof body[Symbol.asyncIterator] === "function";
|
|
550
|
+
}
|
|
551
|
+
async function* readBodyChunks(body) {
|
|
552
|
+
if (isAsyncIterableBody(body)) {
|
|
553
|
+
yield* body;
|
|
554
|
+
return;
|
|
555
|
+
}
|
|
556
|
+
const reader = body.getReader();
|
|
557
|
+
try {
|
|
558
|
+
while (true) {
|
|
559
|
+
const chunk = await reader.read();
|
|
560
|
+
if (chunk.done)
|
|
561
|
+
return;
|
|
562
|
+
if (chunk.value)
|
|
563
|
+
yield chunk.value;
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
finally {
|
|
567
|
+
reader.releaseLock?.();
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
async function* streamSseFrames(body) {
|
|
571
|
+
const decoder = new TextDecoder();
|
|
572
|
+
let buffer = "";
|
|
573
|
+
for await (const chunk of readBodyChunks(body)) {
|
|
574
|
+
buffer += decoder.decode(chunk, { stream: true });
|
|
575
|
+
if (Buffer.byteLength(buffer, "utf8") > DEFAULT_SSE_MAX_BUFFER_BYTES) {
|
|
576
|
+
throw new Error(`SSE frame exceeded ${DEFAULT_SSE_MAX_BUFFER_BYTES} bytes without a terminator`);
|
|
577
|
+
}
|
|
578
|
+
let index = buffer.indexOf("\n\n");
|
|
579
|
+
while (index !== -1) {
|
|
580
|
+
const frame = buffer.slice(0, index);
|
|
581
|
+
buffer = buffer.slice(index + 2);
|
|
582
|
+
yield parseSseFrame(frame);
|
|
583
|
+
index = buffer.indexOf("\n\n");
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
function hostRunSpecFromSdk(goal, options, spec, mode) {
|
|
588
|
+
const loopMode = options.infinite ? "infinite" : spec.options?.loopMode;
|
|
589
|
+
return {
|
|
590
|
+
...spec,
|
|
591
|
+
goal,
|
|
592
|
+
mode,
|
|
593
|
+
projectDir: spec.projectDir ?? options.projectDir,
|
|
594
|
+
repoSourceDir: spec.repoSourceDir ?? options.repoSourceDir,
|
|
595
|
+
repoCloneUrl: spec.repoCloneUrl ?? options.repoCloneUrl,
|
|
596
|
+
workspaceRoot: spec.workspaceRoot ?? options.workspaceRoot,
|
|
597
|
+
gitRoot: spec.gitRoot ?? options.gitRoot,
|
|
598
|
+
options: {
|
|
599
|
+
...spec.options,
|
|
600
|
+
engine: options.engine ?? spec.options?.engine,
|
|
601
|
+
model: options.model ?? spec.options?.model,
|
|
602
|
+
fastModel: options.fastModel ?? spec.options?.fastModel,
|
|
603
|
+
codexReasoningEffort: options.codexReasoningEffort ?? spec.options?.codexReasoningEffort,
|
|
604
|
+
configPath: options.configPath ?? spec.options?.configPath,
|
|
605
|
+
workerUrl: options.workerUrl ?? spec.options?.workerUrl,
|
|
606
|
+
workerModel: options.workerModel ?? spec.options?.workerModel,
|
|
607
|
+
workerKey: options.workerKey ?? spec.options?.workerKey,
|
|
608
|
+
noBrain: options.noBrain ?? spec.options?.noBrain,
|
|
609
|
+
loops: options.infinite ? undefined : options.loops ?? spec.options?.loops,
|
|
610
|
+
loopMode,
|
|
611
|
+
pollIntervalSeconds: options.pollIntervalSeconds ?? spec.options?.pollIntervalSeconds,
|
|
612
|
+
outputDir: options.outputDir ?? spec.options?.outputDir,
|
|
613
|
+
keepArtifacts: options.keepArtifacts ?? spec.options?.keepArtifacts,
|
|
614
|
+
errorLimit: options.errorLimit ?? spec.options?.errorLimit
|
|
615
|
+
}
|
|
616
|
+
};
|
|
617
|
+
}
|
|
618
|
+
function hostRunSubmitInputFromSdk(goal, options, spec, mode) {
|
|
619
|
+
const { requestId, executor, ...planSpec } = spec;
|
|
620
|
+
return {
|
|
621
|
+
...hostRunSpecFromSdk(goal, options, planSpec, mode),
|
|
622
|
+
requestId,
|
|
623
|
+
executor
|
|
624
|
+
};
|
|
625
|
+
}
|
|
626
|
+
function delay(ms) {
|
|
627
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
628
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { Server } from "node:http";
|
|
2
|
+
import type { HostCommandRequest, HostCommandResult } from "./host-control.js";
|
|
3
|
+
import type { HostTimelineEvent } from "./host-timeline.js";
|
|
4
|
+
import type { HostRunListInput, HostRunRequest } from "./host-runs.js";
|
|
5
|
+
import type { RunningState } from "./service.js";
|
|
6
|
+
import type { UsagePricingRule } from "./usage.js";
|
|
7
|
+
export declare const DEFAULT_HOST_SERVER_HOST = "127.0.0.1";
|
|
8
|
+
export declare const DEFAULT_HOST_SERVER_PORT = 8799;
|
|
9
|
+
export type HostStatusServerOptions = {
|
|
10
|
+
host?: string;
|
|
11
|
+
port?: number;
|
|
12
|
+
readState?: () => Promise<RunningState | null>;
|
|
13
|
+
tokenBudget?: () => number | null | undefined;
|
|
14
|
+
usagePricing?: () => UsagePricingRule[];
|
|
15
|
+
readTimeline?: (limit?: number) => Promise<HostTimelineEvent[]>;
|
|
16
|
+
readRuns?: (input?: HostRunListInput) => Promise<HostRunRequest[]>;
|
|
17
|
+
runCommand?: (request: HostCommandRequest) => Promise<HostCommandResult>;
|
|
18
|
+
executeRuns?: boolean;
|
|
19
|
+
executeRunsIntervalMs?: number;
|
|
20
|
+
statusStreamIntervalMs?: number;
|
|
21
|
+
};
|
|
22
|
+
export declare function hostServerPortFromEnv(env?: NodeJS.ProcessEnv): number;
|
|
23
|
+
export declare function normalizeHostServerHost(host?: string): string;
|
|
24
|
+
export declare function createHostStatusServer(options?: HostStatusServerOptions): Server;
|
|
25
|
+
export declare function startHostStatusServer(options?: HostStatusServerOptions): Promise<Server>;
|
|
26
|
+
export declare function serveHostStatus(options?: HostStatusServerOptions): Promise<void>;
|