@brainpilot/backend-core 0.0.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/dist/app.d.ts +31 -0
- package/dist/app.d.ts.map +1 -0
- package/dist/app.js +197 -0
- package/dist/app.js.map +1 -0
- package/dist/config.d.ts +46 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +161 -0
- package/dist/config.js.map +1 -0
- package/dist/create-orchestrator.d.ts +17 -0
- package/dist/create-orchestrator.d.ts.map +1 -0
- package/dist/create-orchestrator.js +35 -0
- package/dist/create-orchestrator.js.map +1 -0
- package/dist/docker-orchestrator.d.ts +75 -0
- package/dist/docker-orchestrator.d.ts.map +1 -0
- package/dist/docker-orchestrator.js +159 -0
- package/dist/docker-orchestrator.js.map +1 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -0
- package/dist/index.js.map +1 -0
- package/dist/local-orchestrator.d.ts +74 -0
- package/dist/local-orchestrator.d.ts.map +1 -0
- package/dist/local-orchestrator.js +225 -0
- package/dist/local-orchestrator.js.map +1 -0
- package/dist/orchestrator.d.ts +51 -0
- package/dist/orchestrator.d.ts.map +1 -0
- package/dist/orchestrator.js +39 -0
- package/dist/orchestrator.js.map +1 -0
- package/dist/runtime-client.d.ts +54 -0
- package/dist/runtime-client.d.ts.map +1 -0
- package/dist/runtime-client.js +67 -0
- package/dist/runtime-client.js.map +1 -0
- package/dist/runtime-paths.d.ts +8 -0
- package/dist/runtime-paths.d.ts.map +1 -0
- package/dist/runtime-paths.js +10 -0
- package/dist/runtime-paths.js.map +1 -0
- package/dist/server.d.ts +25 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +54 -0
- package/dist/server.js.map +1 -0
- package/dist/static-orchestrator.d.ts +37 -0
- package/dist/static-orchestrator.d.ts.map +1 -0
- package/dist/static-orchestrator.js +50 -0
- package/dist/static-orchestrator.js.map +1 -0
- package/package.json +41 -0
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
const defaultDockerLoader = async () => {
|
|
2
|
+
const mod = await import("dockerode");
|
|
3
|
+
return { default: mod.default };
|
|
4
|
+
};
|
|
5
|
+
async function defaultHealthProbe(baseUrl) {
|
|
6
|
+
try {
|
|
7
|
+
const res = await fetch(`${baseUrl}/health`);
|
|
8
|
+
return res.ok;
|
|
9
|
+
}
|
|
10
|
+
catch {
|
|
11
|
+
return false;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
const sleepDefault = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
15
|
+
/** True when a dockerode error signals the image is not present locally. */
|
|
16
|
+
function isNoSuchImage(err) {
|
|
17
|
+
const e = err;
|
|
18
|
+
return e?.statusCode === 404 || /no such image/i.test(e?.message ?? "");
|
|
19
|
+
}
|
|
20
|
+
export class DockerOrchestrator {
|
|
21
|
+
docker;
|
|
22
|
+
dockerLoader;
|
|
23
|
+
image;
|
|
24
|
+
containerPort;
|
|
25
|
+
hostPort;
|
|
26
|
+
host;
|
|
27
|
+
containerDataDir;
|
|
28
|
+
healthProbe;
|
|
29
|
+
healthTimeoutMs;
|
|
30
|
+
sleep;
|
|
31
|
+
dataDir;
|
|
32
|
+
env;
|
|
33
|
+
container = null;
|
|
34
|
+
constructor(options = {}) {
|
|
35
|
+
this.docker = options.docker ?? null;
|
|
36
|
+
this.dockerLoader = options.dockerLoader ?? defaultDockerLoader;
|
|
37
|
+
this.image = options.image ?? "brainpilot-sandbox:latest";
|
|
38
|
+
this.containerPort = options.containerPort ?? 8081;
|
|
39
|
+
this.hostPort = options.hostPort ?? this.containerPort;
|
|
40
|
+
this.host = options.host ?? "127.0.0.1";
|
|
41
|
+
this.containerDataDir = options.containerDataDir ?? "/root/.bp-root";
|
|
42
|
+
this.dataDir = options.dataDir;
|
|
43
|
+
this.env = options.env ?? {};
|
|
44
|
+
this.healthProbe = options.healthProbe ?? defaultHealthProbe;
|
|
45
|
+
this.healthTimeoutMs = options.healthTimeoutMs ?? 30_000;
|
|
46
|
+
this.sleep = options.sleep ?? sleepDefault;
|
|
47
|
+
}
|
|
48
|
+
/** Resolve a dockerode-like instance, loading dockerode lazily on first use. */
|
|
49
|
+
async getDocker() {
|
|
50
|
+
if (this.docker)
|
|
51
|
+
return this.docker;
|
|
52
|
+
let loaded;
|
|
53
|
+
try {
|
|
54
|
+
loaded = await this.dockerLoader();
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
throw new Error("Docker/dynamic mode requires 'dockerode'. Install it (npm i dockerode) " +
|
|
58
|
+
"or use the local/static orchestrator.");
|
|
59
|
+
}
|
|
60
|
+
this.docker = new loaded.default();
|
|
61
|
+
return this.docker;
|
|
62
|
+
}
|
|
63
|
+
get baseUrl() {
|
|
64
|
+
return `http://${this.host}:${this.hostPort}`;
|
|
65
|
+
}
|
|
66
|
+
async ensureRuntime(opts) {
|
|
67
|
+
if (opts?.dataDir)
|
|
68
|
+
this.dataDir = opts.dataDir;
|
|
69
|
+
if (opts?.env)
|
|
70
|
+
this.env = { ...this.env, ...opts.env };
|
|
71
|
+
if (this.container && (await this.health())) {
|
|
72
|
+
return { baseUrl: this.baseUrl };
|
|
73
|
+
}
|
|
74
|
+
const portKey = `${this.containerPort}/tcp`;
|
|
75
|
+
const envList = Object.entries({
|
|
76
|
+
BP_DATA_DIR: this.containerDataDir,
|
|
77
|
+
PORT: String(this.containerPort),
|
|
78
|
+
AGENT_RUNTIME_PORT: String(this.containerPort),
|
|
79
|
+
...this.env,
|
|
80
|
+
}).map(([k, v]) => `${k}=${v}`);
|
|
81
|
+
const createSpec = {
|
|
82
|
+
Image: this.image,
|
|
83
|
+
Env: envList,
|
|
84
|
+
ExposedPorts: { [portKey]: {} },
|
|
85
|
+
HostConfig: {
|
|
86
|
+
PortBindings: { [portKey]: [{ HostPort: String(this.hostPort) }] },
|
|
87
|
+
...(this.dataDir
|
|
88
|
+
? { Binds: [`${this.dataDir}:${this.containerDataDir}:rw`] }
|
|
89
|
+
: {}),
|
|
90
|
+
},
|
|
91
|
+
};
|
|
92
|
+
// `docker run` auto-pulls a missing image; dockerode's createContainer does
|
|
93
|
+
// NOT — it 404s. Mirror the CLI: on "no such image", pull then retry once.
|
|
94
|
+
const docker = await this.getDocker();
|
|
95
|
+
let container;
|
|
96
|
+
try {
|
|
97
|
+
container = await docker.createContainer(createSpec);
|
|
98
|
+
}
|
|
99
|
+
catch (err) {
|
|
100
|
+
if (isNoSuchImage(err) && typeof docker.pull === "function") {
|
|
101
|
+
await this.pullImage(docker);
|
|
102
|
+
container = await docker.createContainer(createSpec);
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
throw err;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
await container.start();
|
|
109
|
+
this.container = container;
|
|
110
|
+
await this.waitForHealth();
|
|
111
|
+
return { baseUrl: this.baseUrl };
|
|
112
|
+
}
|
|
113
|
+
/** Pull `this.image`, resolving once the pull stream finishes. */
|
|
114
|
+
pullImage(docker) {
|
|
115
|
+
return new Promise((resolve, reject) => {
|
|
116
|
+
docker.pull(this.image, (err, stream) => {
|
|
117
|
+
if (err || !stream)
|
|
118
|
+
return reject(err ?? new Error(`failed to pull ${this.image}`));
|
|
119
|
+
docker.modem.followProgress(stream, (done) => done ? reject(done) : resolve());
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
async health() {
|
|
124
|
+
if (!this.container)
|
|
125
|
+
return false;
|
|
126
|
+
return this.healthProbe(this.baseUrl);
|
|
127
|
+
}
|
|
128
|
+
async stopRuntime() {
|
|
129
|
+
const container = this.container;
|
|
130
|
+
this.container = null;
|
|
131
|
+
if (!container)
|
|
132
|
+
return;
|
|
133
|
+
try {
|
|
134
|
+
await container.stop({ t: 5 });
|
|
135
|
+
}
|
|
136
|
+
catch {
|
|
137
|
+
/* already stopped */
|
|
138
|
+
}
|
|
139
|
+
try {
|
|
140
|
+
await container.remove({ force: true });
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
/* already gone */
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
async waitForHealth() {
|
|
147
|
+
const deadline = Date.now() + this.healthTimeoutMs;
|
|
148
|
+
for (;;) {
|
|
149
|
+
if (await this.healthProbe(this.baseUrl))
|
|
150
|
+
return;
|
|
151
|
+
if (Date.now() >= deadline) {
|
|
152
|
+
throw new Error(`docker runtime did not become healthy at ${this.baseUrl} within ` +
|
|
153
|
+
`${this.healthTimeoutMs}ms`);
|
|
154
|
+
}
|
|
155
|
+
await this.sleep(250);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
//# sourceMappingURL=docker-orchestrator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"docker-orchestrator.js","sourceRoot":"","sources":["../src/docker-orchestrator.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @brainpilot/backend-core — host-side lightweight backend (Hono) that serves
|
|
3
|
+
* the web SPA and byte-proxies to the Runtime (修正4), plus the Orchestrator
|
|
4
|
+
* abstraction (Docker / Local). See TS_PI_REFACTOR_DESIGN §10, §11, §11A.
|
|
5
|
+
*/
|
|
6
|
+
export declare const BACKEND_NAME = "@brainpilot/backend-core";
|
|
7
|
+
export { createApp } from "./app.js";
|
|
8
|
+
export type { CreateAppOptions } from "./app.js";
|
|
9
|
+
export { startServer } from "./server.js";
|
|
10
|
+
export type { StartServerOptions, RunningServer } from "./server.js";
|
|
11
|
+
export { createOrchestrator } from "./create-orchestrator.js";
|
|
12
|
+
export type { CreateOrchestratorOptions } from "./create-orchestrator.js";
|
|
13
|
+
export { runtimeArtifactPaths } from "./runtime-paths.js";
|
|
14
|
+
export type { RuntimeArtifactPaths } from "./runtime-paths.js";
|
|
15
|
+
export { resolveOrchestratorMode, } from "./orchestrator.js";
|
|
16
|
+
export type { Orchestrator, OrchestratorMode, RuntimeHandle, EnsureRuntimeOptions, } from "./orchestrator.js";
|
|
17
|
+
export { LocalProcessOrchestrator, resolveRuntimeServerPath, } from "./local-orchestrator.js";
|
|
18
|
+
export type { LocalOrchestratorOptions, SpawnFn, SpawnedProcess, } from "./local-orchestrator.js";
|
|
19
|
+
export { DockerOrchestrator } from "./docker-orchestrator.js";
|
|
20
|
+
export type { DockerOrchestratorOptions } from "./docker-orchestrator.js";
|
|
21
|
+
export { StaticRuntimeOrchestrator } from "./static-orchestrator.js";
|
|
22
|
+
export type { StaticOrchestratorOptions } from "./static-orchestrator.js";
|
|
23
|
+
export { RuntimeClient, buildPath } from "./runtime-client.js";
|
|
24
|
+
export type { RuntimeClientOptions, ForwardOptions } from "./runtime-client.js";
|
|
25
|
+
export { resolveProvider, readLocalSettings, writeLocalSettings, parseDotenv, configPaths, } from "./config.js";
|
|
26
|
+
export type { ResolvedProvider, LocalSettings, ConfigPaths, ResolveProviderOptions, } from "./config.js";
|
|
27
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,eAAO,MAAM,YAAY,6BAA6B,CAAC;AAEvD,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACrC,YAAY,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAEjD,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,YAAY,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAErE,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAC9D,YAAY,EAAE,yBAAyB,EAAE,MAAM,0BAA0B,CAAC;AAE1E,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,YAAY,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAE/D,OAAO,EACL,uBAAuB,GACxB,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EACV,YAAY,EACZ,gBAAgB,EAChB,aAAa,EACb,oBAAoB,GACrB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,wBAAwB,EACxB,wBAAwB,GACzB,MAAM,yBAAyB,CAAC;AACjC,YAAY,EACV,wBAAwB,EACxB,OAAO,EACP,cAAc,GACf,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAC9D,YAAY,EAAE,yBAAyB,EAAE,MAAM,0BAA0B,CAAC;AAE1E,OAAO,EAAE,yBAAyB,EAAE,MAAM,0BAA0B,CAAC;AACrE,YAAY,EAAE,yBAAyB,EAAE,MAAM,0BAA0B,CAAC;AAE1E,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAC/D,YAAY,EAAE,oBAAoB,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAEhF,OAAO,EACL,eAAe,EACf,iBAAiB,EACjB,kBAAkB,EAClB,WAAW,EACX,WAAW,GACZ,MAAM,aAAa,CAAC;AACrB,YAAY,EACV,gBAAgB,EAChB,aAAa,EACb,WAAW,EACX,sBAAsB,GACvB,MAAM,aAAa,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @brainpilot/backend-core — host-side lightweight backend (Hono) that serves
|
|
3
|
+
* the web SPA and byte-proxies to the Runtime (修正4), plus the Orchestrator
|
|
4
|
+
* abstraction (Docker / Local). See TS_PI_REFACTOR_DESIGN §10, §11, §11A.
|
|
5
|
+
*/
|
|
6
|
+
export const BACKEND_NAME = "@brainpilot/backend-core";
|
|
7
|
+
export { createApp } from "./app.js";
|
|
8
|
+
export { startServer } from "./server.js";
|
|
9
|
+
export { createOrchestrator } from "./create-orchestrator.js";
|
|
10
|
+
export { runtimeArtifactPaths } from "./runtime-paths.js";
|
|
11
|
+
export { resolveOrchestratorMode, } from "./orchestrator.js";
|
|
12
|
+
export { LocalProcessOrchestrator, resolveRuntimeServerPath, } from "./local-orchestrator.js";
|
|
13
|
+
export { DockerOrchestrator } from "./docker-orchestrator.js";
|
|
14
|
+
export { StaticRuntimeOrchestrator } from "./static-orchestrator.js";
|
|
15
|
+
export { RuntimeClient, buildPath } from "./runtime-client.js";
|
|
16
|
+
export { resolveProvider, readLocalSettings, writeLocalSettings, parseDotenv, configPaths, } from "./config.js";
|
|
17
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,0BAA0B,CAAC;AAEvD,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAGrC,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAG1C,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAG9D,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAG1D,OAAO,EACL,uBAAuB,GACxB,MAAM,mBAAmB,CAAC;AAQ3B,OAAO,EACL,wBAAwB,EACxB,wBAAwB,GACzB,MAAM,yBAAyB,CAAC;AAOjC,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAG9D,OAAO,EAAE,yBAAyB,EAAE,MAAM,0BAA0B,CAAC;AAGrE,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAG/D,OAAO,EACL,eAAe,EACf,iBAAiB,EACjB,kBAAkB,EAClB,WAAW,EACX,WAAW,GACZ,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import type { EnsureRuntimeOptions, Orchestrator, RuntimeHandle } from "./orchestrator.js";
|
|
2
|
+
/** Minimal shape we need from a spawned process — eases stubbing in tests. */
|
|
3
|
+
export interface SpawnedProcess {
|
|
4
|
+
readonly pid?: number;
|
|
5
|
+
on(event: "exit", listener: (code: number | null, signal: NodeJS.Signals | null) => void): unknown;
|
|
6
|
+
on(event: "error", listener: (err: Error) => void): unknown;
|
|
7
|
+
kill(signal?: NodeJS.Signals): boolean;
|
|
8
|
+
}
|
|
9
|
+
export type SpawnFn = (command: string, args: readonly string[], options: {
|
|
10
|
+
env: NodeJS.ProcessEnv;
|
|
11
|
+
stdio?: unknown;
|
|
12
|
+
}) => SpawnedProcess;
|
|
13
|
+
export interface LocalOrchestratorOptions {
|
|
14
|
+
/** BP_DATA_DIR for the runtime (§11A.2). Default `./brainpilot`. */
|
|
15
|
+
dataDir?: string;
|
|
16
|
+
/** Runtime port. Default 8081 (backend 9001 + 1, stride-2 §16). */
|
|
17
|
+
port?: number;
|
|
18
|
+
host?: string;
|
|
19
|
+
/** Override `process.execPath` (node binary). */
|
|
20
|
+
execPath?: string;
|
|
21
|
+
/** Override the resolved runtime server entry path. */
|
|
22
|
+
runtimeServerPath?: string;
|
|
23
|
+
/** Injectable spawn (for tests). Defaults to node:child_process.spawn. */
|
|
24
|
+
spawnFn?: SpawnFn;
|
|
25
|
+
/** Max restarts within the sliding window before giving up. Default 5. */
|
|
26
|
+
maxRestarts?: number;
|
|
27
|
+
/** Sliding-window length in ms for counting restarts. Default 60_000. */
|
|
28
|
+
restartWindowMs?: number;
|
|
29
|
+
/** Base backoff in ms (exponential). Default 200. */
|
|
30
|
+
backoffBaseMs?: number;
|
|
31
|
+
/** Injectable health probe (for tests). Defaults to fetch GET /health. */
|
|
32
|
+
healthProbe?: (baseUrl: string) => Promise<boolean>;
|
|
33
|
+
/** Health wait timeout in ms when ensuring readiness. Default 30_000. */
|
|
34
|
+
healthTimeoutMs?: number;
|
|
35
|
+
/** Called when the restart budget is exhausted (§11A.5 fatal). */
|
|
36
|
+
onFatal?: (err: Error) => void;
|
|
37
|
+
/** Sleep impl (for tests). */
|
|
38
|
+
sleep?: (ms: number) => Promise<void>;
|
|
39
|
+
/** If set, the runtime child's stdout/stderr are appended to this file
|
|
40
|
+
* (replaces stdio:"inherit"). If unset, inherit is kept (zero behavior change). */
|
|
41
|
+
runtimeLogFile?: string;
|
|
42
|
+
/** If set, the runtime child's pid is written here; removed on clean exit / stopRuntime. */
|
|
43
|
+
runtimePidFile?: string;
|
|
44
|
+
}
|
|
45
|
+
/** Resolve `@brainpilot/runtime/server` to an absolute path WITHOUT importing it. */
|
|
46
|
+
export declare function resolveRuntimeServerPath(): string;
|
|
47
|
+
export declare class LocalProcessOrchestrator implements Orchestrator {
|
|
48
|
+
private readonly opts;
|
|
49
|
+
private child;
|
|
50
|
+
private handle;
|
|
51
|
+
private restartTimestamps;
|
|
52
|
+
/** Set when stopRuntime() is invoked — suppresses auto-restart. */
|
|
53
|
+
private stopping;
|
|
54
|
+
private gaveUp;
|
|
55
|
+
private lastEnv;
|
|
56
|
+
constructor(options?: LocalOrchestratorOptions);
|
|
57
|
+
get baseUrl(): string;
|
|
58
|
+
/** Build the exact argv used to spawn the runtime. Exposed for testing. */
|
|
59
|
+
buildArgv(): {
|
|
60
|
+
command: string;
|
|
61
|
+
args: string[];
|
|
62
|
+
};
|
|
63
|
+
/** Build the env injected into the runtime child. Exposed for testing. */
|
|
64
|
+
buildEnv(extra?: Record<string, string>): NodeJS.ProcessEnv;
|
|
65
|
+
ensureRuntime(opts?: EnsureRuntimeOptions): Promise<RuntimeHandle>;
|
|
66
|
+
health(): Promise<boolean>;
|
|
67
|
+
stopRuntime(): Promise<void>;
|
|
68
|
+
private spawnChild;
|
|
69
|
+
private writePidFile;
|
|
70
|
+
private removePidFile;
|
|
71
|
+
private handleExit;
|
|
72
|
+
private waitForHealth;
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=local-orchestrator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"local-orchestrator.d.ts","sourceRoot":"","sources":["../src/local-orchestrator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LocalProcessOrchestrator — 免 Docker 本地直跑 (§11A.3 / §11A.5).
|
|
3
|
+
*
|
|
4
|
+
* Spawns the runtime as a child process:
|
|
5
|
+
* spawn(process.execPath, [require.resolve('@brainpilot/runtime/server')],
|
|
6
|
+
* { env: { BP_DATA_DIR, PORT, ... } })
|
|
7
|
+
*
|
|
8
|
+
* IMPORTANT: we never `import` runtime symbols — the resolved server path is
|
|
9
|
+
* just a string handed to a child process (per the package brief / 决策 E).
|
|
10
|
+
*
|
|
11
|
+
* Crash self-healing (§11A.5 决策 F): on abnormal exit, restart a bounded
|
|
12
|
+
* number of times within a sliding window with exponential backoff; past the
|
|
13
|
+
* threshold, give up and mark the runtime dead (caller surfaces a fatal event).
|
|
14
|
+
*/
|
|
15
|
+
import { spawn } from "node:child_process";
|
|
16
|
+
import { createRequire } from "node:module";
|
|
17
|
+
import { openSync, closeSync, writeFileSync, mkdirSync, rmSync } from "node:fs";
|
|
18
|
+
import { dirname } from "node:path";
|
|
19
|
+
/** Resolve `@brainpilot/runtime/server` to an absolute path WITHOUT importing it. */
|
|
20
|
+
export function resolveRuntimeServerPath() {
|
|
21
|
+
const require = createRequire(import.meta.url);
|
|
22
|
+
return require.resolve("@brainpilot/runtime/server");
|
|
23
|
+
}
|
|
24
|
+
async function defaultHealthProbe(baseUrl) {
|
|
25
|
+
try {
|
|
26
|
+
const res = await fetch(`${baseUrl}/health`);
|
|
27
|
+
return res.ok;
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
const sleepDefault = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
34
|
+
export class LocalProcessOrchestrator {
|
|
35
|
+
opts;
|
|
36
|
+
child = null;
|
|
37
|
+
handle = null;
|
|
38
|
+
restartTimestamps = [];
|
|
39
|
+
/** Set when stopRuntime() is invoked — suppresses auto-restart. */
|
|
40
|
+
stopping = false;
|
|
41
|
+
gaveUp = false;
|
|
42
|
+
lastEnv = {};
|
|
43
|
+
constructor(options = {}) {
|
|
44
|
+
this.opts = {
|
|
45
|
+
dataDir: options.dataDir ?? process.env.BP_DATA_DIR ?? "./brainpilot",
|
|
46
|
+
port: options.port ?? Number(process.env.AGENT_RUNTIME_PORT ?? 8081),
|
|
47
|
+
host: options.host ?? "127.0.0.1",
|
|
48
|
+
execPath: options.execPath ?? process.execPath,
|
|
49
|
+
runtimeServerPath: options.runtimeServerPath,
|
|
50
|
+
spawnFn: options.spawnFn ??
|
|
51
|
+
((command, args, o) => spawn(command, args, {
|
|
52
|
+
env: o.env,
|
|
53
|
+
stdio: o.stdio ?? "inherit",
|
|
54
|
+
})),
|
|
55
|
+
maxRestarts: options.maxRestarts ?? 5,
|
|
56
|
+
restartWindowMs: options.restartWindowMs ?? 60_000,
|
|
57
|
+
backoffBaseMs: options.backoffBaseMs ?? 200,
|
|
58
|
+
healthProbe: options.healthProbe ?? defaultHealthProbe,
|
|
59
|
+
healthTimeoutMs: options.healthTimeoutMs ?? 30_000,
|
|
60
|
+
onFatal: options.onFatal,
|
|
61
|
+
sleep: options.sleep ?? sleepDefault,
|
|
62
|
+
runtimeLogFile: options.runtimeLogFile,
|
|
63
|
+
runtimePidFile: options.runtimePidFile,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
get baseUrl() {
|
|
67
|
+
return `http://${this.opts.host}:${this.opts.port}`;
|
|
68
|
+
}
|
|
69
|
+
/** Build the exact argv used to spawn the runtime. Exposed for testing. */
|
|
70
|
+
buildArgv() {
|
|
71
|
+
const serverPath = this.opts.runtimeServerPath ?? resolveRuntimeServerPath();
|
|
72
|
+
return { command: this.opts.execPath, args: [serverPath] };
|
|
73
|
+
}
|
|
74
|
+
/** Build the env injected into the runtime child. Exposed for testing. */
|
|
75
|
+
buildEnv(extra) {
|
|
76
|
+
return {
|
|
77
|
+
...process.env,
|
|
78
|
+
BP_DATA_DIR: this.opts.dataDir,
|
|
79
|
+
PORT: String(this.opts.port),
|
|
80
|
+
AGENT_RUNTIME_PORT: String(this.opts.port),
|
|
81
|
+
BP_MODE: process.env.BP_MODE ?? "single",
|
|
82
|
+
...(extra ?? {}),
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
async ensureRuntime(opts) {
|
|
86
|
+
if (opts?.dataDir)
|
|
87
|
+
this.opts.dataDir = opts.dataDir;
|
|
88
|
+
if (opts?.port)
|
|
89
|
+
this.opts.port = opts.port;
|
|
90
|
+
this.gaveUp = false;
|
|
91
|
+
this.stopping = false;
|
|
92
|
+
if (this.child && this.handle && (await this.health())) {
|
|
93
|
+
return this.handle;
|
|
94
|
+
}
|
|
95
|
+
this.lastEnv = this.buildEnv(opts?.env);
|
|
96
|
+
this.spawnChild(this.lastEnv);
|
|
97
|
+
await this.waitForHealth();
|
|
98
|
+
this.handle = { baseUrl: this.baseUrl };
|
|
99
|
+
return this.handle;
|
|
100
|
+
}
|
|
101
|
+
async health() {
|
|
102
|
+
if (!this.child)
|
|
103
|
+
return false;
|
|
104
|
+
return this.opts.healthProbe(this.baseUrl);
|
|
105
|
+
}
|
|
106
|
+
async stopRuntime() {
|
|
107
|
+
this.stopping = true;
|
|
108
|
+
const child = this.child;
|
|
109
|
+
this.child = null;
|
|
110
|
+
this.handle = null;
|
|
111
|
+
this.removePidFile();
|
|
112
|
+
if (child) {
|
|
113
|
+
try {
|
|
114
|
+
child.kill("SIGTERM");
|
|
115
|
+
}
|
|
116
|
+
catch {
|
|
117
|
+
/* already gone */
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
spawnChild(env) {
|
|
122
|
+
const { command, args } = this.buildArgv();
|
|
123
|
+
let logFd;
|
|
124
|
+
let stdio;
|
|
125
|
+
if (this.opts.runtimeLogFile) {
|
|
126
|
+
try {
|
|
127
|
+
mkdirSync(dirname(this.opts.runtimeLogFile), { recursive: true });
|
|
128
|
+
logFd = openSync(this.opts.runtimeLogFile, "a");
|
|
129
|
+
stdio = ["ignore", logFd, logFd];
|
|
130
|
+
}
|
|
131
|
+
catch (err) {
|
|
132
|
+
// Never fail runtime startup over logging — fall back to inherit.
|
|
133
|
+
// eslint-disable-next-line no-console
|
|
134
|
+
console.warn(`[orchestrator] cannot open runtime log ${this.opts.runtimeLogFile}: ` +
|
|
135
|
+
`${err.message}; falling back to inherit`);
|
|
136
|
+
logFd = undefined;
|
|
137
|
+
stdio = undefined;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
const child = this.opts.spawnFn(command, args, stdio ? { env, stdio } : { env });
|
|
141
|
+
this.child = child;
|
|
142
|
+
this.writePidFile(child.pid);
|
|
143
|
+
child.on("error", (err) => this.handleExit(err instanceof Error ? err : new Error(String(err))));
|
|
144
|
+
child.on("exit", (code, signal) => {
|
|
145
|
+
if (logFd !== undefined) {
|
|
146
|
+
try {
|
|
147
|
+
closeSync(logFd);
|
|
148
|
+
}
|
|
149
|
+
catch {
|
|
150
|
+
/* already closed */
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
if (this.stopping)
|
|
154
|
+
return;
|
|
155
|
+
// Clean exit (code 0, not killed) is treated as intentional shutdown.
|
|
156
|
+
if (code === 0 && signal === null) {
|
|
157
|
+
this.child = null;
|
|
158
|
+
this.handle = null;
|
|
159
|
+
this.removePidFile();
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
const err = new Error(`runtime exited (code=${String(code)} signal=${String(signal)})`);
|
|
163
|
+
void this.handleExit(err);
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
writePidFile(pid) {
|
|
167
|
+
if (!this.opts.runtimePidFile || pid === undefined)
|
|
168
|
+
return;
|
|
169
|
+
try {
|
|
170
|
+
mkdirSync(dirname(this.opts.runtimePidFile), { recursive: true });
|
|
171
|
+
writeFileSync(this.opts.runtimePidFile, String(pid));
|
|
172
|
+
}
|
|
173
|
+
catch (err) {
|
|
174
|
+
// eslint-disable-next-line no-console
|
|
175
|
+
console.warn(`[orchestrator] cannot write runtime pid file ${this.opts.runtimePidFile}: ` +
|
|
176
|
+
`${err.message}`);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
removePidFile() {
|
|
180
|
+
if (!this.opts.runtimePidFile)
|
|
181
|
+
return;
|
|
182
|
+
try {
|
|
183
|
+
rmSync(this.opts.runtimePidFile, { force: true });
|
|
184
|
+
}
|
|
185
|
+
catch {
|
|
186
|
+
/* nothing to remove */
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
async handleExit(err) {
|
|
190
|
+
if (this.stopping || this.gaveUp)
|
|
191
|
+
return;
|
|
192
|
+
const now = Date.now();
|
|
193
|
+
this.restartTimestamps = this.restartTimestamps.filter((ts) => now - ts < this.opts.restartWindowMs);
|
|
194
|
+
if (this.restartTimestamps.length >= this.opts.maxRestarts) {
|
|
195
|
+
this.gaveUp = true;
|
|
196
|
+
this.child = null;
|
|
197
|
+
this.handle = null;
|
|
198
|
+
const fatal = new Error(`runtime crashed ${this.restartTimestamps.length + 1} times within ` +
|
|
199
|
+
`${this.opts.restartWindowMs}ms; giving up. Last error: ${err.message}`);
|
|
200
|
+
this.opts.onFatal?.(fatal);
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
const attempt = this.restartTimestamps.length;
|
|
204
|
+
this.restartTimestamps.push(now);
|
|
205
|
+
const backoff = this.opts.backoffBaseMs * Math.pow(2, attempt);
|
|
206
|
+
await this.opts.sleep(backoff);
|
|
207
|
+
if (this.stopping || this.gaveUp)
|
|
208
|
+
return;
|
|
209
|
+
this.spawnChild(this.lastEnv);
|
|
210
|
+
}
|
|
211
|
+
async waitForHealth() {
|
|
212
|
+
const deadline = Date.now() + this.opts.healthTimeoutMs;
|
|
213
|
+
// Poll until healthy or timeout. Spacing is small for local startup.
|
|
214
|
+
for (;;) {
|
|
215
|
+
if (await this.opts.healthProbe(this.baseUrl))
|
|
216
|
+
return;
|
|
217
|
+
if (Date.now() >= deadline) {
|
|
218
|
+
throw new Error(`runtime did not become healthy at ${this.baseUrl} within ` +
|
|
219
|
+
`${this.opts.healthTimeoutMs}ms`);
|
|
220
|
+
}
|
|
221
|
+
await this.opts.sleep(200);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
//# sourceMappingURL=local-orchestrator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"local-orchestrator.js","sourceRoot":"","sources":["../src/local-orchestrator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Orchestrator abstraction — "how to start the Runtime" (TS_PI_REFACTOR_DESIGN
|
|
3
|
+
* §11A.3). The backend never speaks runtime symbols; it only needs a handle to
|
|
4
|
+
* a running runtime reachable over localhost HTTP/SSE (§10, 修正4).
|
|
5
|
+
*
|
|
6
|
+
* Three implementations:
|
|
7
|
+
* - DockerOrchestrator — `docker run` the brainpilot-sandbox image
|
|
8
|
+
* - StaticRuntimeOrchestrator — health-probe a pre-started sandbox (basic Docker compose)
|
|
9
|
+
* - LocalProcessOrchestrator — child_process.spawn the runtime entrypoint
|
|
10
|
+
*
|
|
11
|
+
* All expose the same surface so the Hono app and the runtime client are
|
|
12
|
+
* agnostic to deployment mode.
|
|
13
|
+
*/
|
|
14
|
+
/** A live runtime endpoint the backend can proxy to. */
|
|
15
|
+
export interface RuntimeHandle {
|
|
16
|
+
/** Base URL of the runtime, e.g. `http://127.0.0.1:8081`. No trailing slash. */
|
|
17
|
+
readonly baseUrl: string;
|
|
18
|
+
}
|
|
19
|
+
export interface EnsureRuntimeOptions {
|
|
20
|
+
/** Host data dir injected as BP_DATA_DIR (§11A.2). */
|
|
21
|
+
readonly dataDir?: string;
|
|
22
|
+
/** Force a specific runtime port; otherwise the orchestrator picks one. */
|
|
23
|
+
readonly port?: number;
|
|
24
|
+
/** Extra env vars forwarded to the runtime process/container. */
|
|
25
|
+
readonly env?: Record<string, string>;
|
|
26
|
+
}
|
|
27
|
+
export interface Orchestrator {
|
|
28
|
+
/**
|
|
29
|
+
* Start a runtime (idempotent — repeated calls return the same handle while
|
|
30
|
+
* the runtime is healthy) and resolve once it is reachable.
|
|
31
|
+
*/
|
|
32
|
+
ensureRuntime(opts?: EnsureRuntimeOptions): Promise<RuntimeHandle>;
|
|
33
|
+
/** Probe the runtime `GET /health` (§15.4). Returns false if not started. */
|
|
34
|
+
health(): Promise<boolean>;
|
|
35
|
+
/** Gracefully stop the runtime. Safe to call when not started. */
|
|
36
|
+
stopRuntime(): Promise<void>;
|
|
37
|
+
}
|
|
38
|
+
export type OrchestratorMode = "local" | "static" | "docker";
|
|
39
|
+
/**
|
|
40
|
+
* Decide which orchestrator to use. Explicit `BP_ORCHESTRATOR` / `BP_MODE`
|
|
41
|
+
* wins; otherwise default to `local` (the免 Docker path, §11A) — Docker is
|
|
42
|
+
* opt-in because it requires a daemon.
|
|
43
|
+
*
|
|
44
|
+
* Precedence (highest → lowest):
|
|
45
|
+
* 1. `BP_ORCHESTRATOR` explicit override
|
|
46
|
+
* 2. `BP_RUNTIME_URL` set → `static` (connect a fixed pre-started runtime, static sandbox)
|
|
47
|
+
* 3. `BP_MODE=docker` legacy switch
|
|
48
|
+
* 4. `local` (default)
|
|
49
|
+
*/
|
|
50
|
+
export declare function resolveOrchestratorMode(env?: Record<string, string | undefined>): OrchestratorMode;
|
|
51
|
+
//# sourceMappingURL=orchestrator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"orchestrator.d.ts","sourceRoot":"","sources":["../src/orchestrator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,wDAAwD;AACxD,MAAM,WAAW,aAAa;IAC5B,gFAAgF;IAChF,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,oBAAoB;IACnC,sDAAsD;IACtD,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,2EAA2E;IAC3E,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,iEAAiE;IACjE,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACvC;AAED,MAAM,WAAW,YAAY;IAC3B;;;OAGG;IACH,aAAa,CAAC,IAAI,CAAC,EAAE,oBAAoB,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;IACnE,6EAA6E;IAC7E,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;IAC3B,kEAAkE;IAClE,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9B;AAED,MAAM,MAAM,gBAAgB,GAAG,OAAO,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAE7D;;;;;;;;;;GAUG;AACH,wBAAgB,uBAAuB,CACrC,GAAG,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAe,GACpD,gBAAgB,CAWlB"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Orchestrator abstraction — "how to start the Runtime" (TS_PI_REFACTOR_DESIGN
|
|
3
|
+
* §11A.3). The backend never speaks runtime symbols; it only needs a handle to
|
|
4
|
+
* a running runtime reachable over localhost HTTP/SSE (§10, 修正4).
|
|
5
|
+
*
|
|
6
|
+
* Three implementations:
|
|
7
|
+
* - DockerOrchestrator — `docker run` the brainpilot-sandbox image
|
|
8
|
+
* - StaticRuntimeOrchestrator — health-probe a pre-started sandbox (basic Docker compose)
|
|
9
|
+
* - LocalProcessOrchestrator — child_process.spawn the runtime entrypoint
|
|
10
|
+
*
|
|
11
|
+
* All expose the same surface so the Hono app and the runtime client are
|
|
12
|
+
* agnostic to deployment mode.
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* Decide which orchestrator to use. Explicit `BP_ORCHESTRATOR` / `BP_MODE`
|
|
16
|
+
* wins; otherwise default to `local` (the免 Docker path, §11A) — Docker is
|
|
17
|
+
* opt-in because it requires a daemon.
|
|
18
|
+
*
|
|
19
|
+
* Precedence (highest → lowest):
|
|
20
|
+
* 1. `BP_ORCHESTRATOR` explicit override
|
|
21
|
+
* 2. `BP_RUNTIME_URL` set → `static` (connect a fixed pre-started runtime, static sandbox)
|
|
22
|
+
* 3. `BP_MODE=docker` legacy switch
|
|
23
|
+
* 4. `local` (default)
|
|
24
|
+
*/
|
|
25
|
+
export function resolveOrchestratorMode(env = process.env) {
|
|
26
|
+
// Explicit override always wins.
|
|
27
|
+
const explicit = (env.BP_ORCHESTRATOR ?? "").toLowerCase();
|
|
28
|
+
if (explicit === "docker" || explicit === "local" || explicit === "static") {
|
|
29
|
+
return explicit;
|
|
30
|
+
}
|
|
31
|
+
// A pre-provisioned runtime URL (static sandbox compose) selects `static`.
|
|
32
|
+
if ((env.BP_RUNTIME_URL ?? "").trim() !== "")
|
|
33
|
+
return "static";
|
|
34
|
+
// Dynamic per-user docker switch (downstream multi-user repo).
|
|
35
|
+
if ((env.BP_MODE ?? "").toLowerCase() === "docker")
|
|
36
|
+
return "docker";
|
|
37
|
+
return "local";
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=orchestrator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"orchestrator.js","sourceRoot":"","sources":["../src/orchestrator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AA+BH;;;;;;;;;;GAUG;AACH,MAAM,UAAU,uBAAuB,CACrC,MAA0C,OAAO,CAAC,GAAG;IAErD,iCAAiC;IACjC,MAAM,QAAQ,GAAG,CAAC,GAAG,CAAC,eAAe,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;IAC3D,IAAI,QAAQ,KAAK,QAAQ,IAAI,QAAQ,KAAK,OAAO,IAAI,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAC3E,OAAO,QAA4B,CAAC;IACtC,CAAC;IACD,2EAA2E;IAC3E,IAAI,CAAC,GAAG,CAAC,cAAc,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE;QAAE,OAAO,QAAQ,CAAC;IAC9D,+DAA+D;IAC/D,IAAI,CAAC,GAAG,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,KAAK,QAAQ;QAAE,OAAO,QAAQ,CAAC;IACpE,OAAO,OAAO,CAAC;AACjB,CAAC"}
|