@addai/node 0.30.13 → 0.30.15
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/auto-update.d.ts +3 -0
- package/dist/auto-update.js +15 -0
- package/dist/capabilities.d.ts +17 -3
- package/dist/capabilities.js +18 -8
- package/dist/claude-models.d.ts +4 -12
- package/dist/claude-models.js +12 -88
- package/dist/claude-print.d.ts +15 -0
- package/dist/claude-print.js +16 -0
- package/dist/codex-models.d.ts +81 -0
- package/dist/codex-models.js +385 -0
- package/dist/codex-spawn.d.ts +19 -8
- package/dist/codex-spawn.js +68 -16
- package/dist/command-runner.js +31 -9
- package/dist/desktop/docker.js +2 -0
- package/dist/desktop/manager.d.ts +2 -1
- package/dist/desktop/manager.js +51 -1
- package/dist/desktop/provider.d.ts +1 -1
- package/dist/desktop/provider.js +2 -0
- package/dist/desktop/relay-client.js +7 -0
- package/dist/desktop/spec.d.ts +2 -0
- package/dist/direct/aios-bridge.d.ts +13 -0
- package/dist/direct/aios-bridge.js +177 -0
- package/dist/direct/aios-mcp.d.ts +2 -0
- package/dist/direct/aios-mcp.js +132 -0
- package/dist/direct/aios-tools.d.ts +351 -0
- package/dist/direct/aios-tools.js +120 -0
- package/dist/direct/board-chat-provider.d.ts +64 -0
- package/dist/direct/board-chat-provider.js +154 -0
- package/dist/direct/board-chat.d.ts +40 -0
- package/dist/direct/board-chat.js +414 -0
- package/dist/direct/config.d.ts +2 -0
- package/dist/direct/config.js +60 -0
- package/dist/direct/launch.d.ts +14 -0
- package/dist/direct/launch.js +121 -0
- package/dist/direct/protocol.d.ts +46 -0
- package/dist/direct/protocol.js +84 -0
- package/dist/direct/relay-main.d.ts +1 -0
- package/dist/direct/relay-main.js +21 -0
- package/dist/direct/relay.d.ts +26 -0
- package/dist/direct/relay.js +334 -0
- package/dist/direct/sessions.d.ts +61 -0
- package/dist/direct/sessions.js +368 -0
- package/dist/direct/supervisor.d.ts +9 -0
- package/dist/direct/supervisor.js +137 -0
- package/dist/direct/terminal.d.ts +1 -0
- package/dist/direct/terminal.js +106 -0
- package/dist/direct/worker.d.ts +1 -0
- package/dist/direct/worker.js +278 -0
- package/dist/entitybox/container-action.cjs +85 -0
- package/dist/entitybox/container-watchdog.cjs +70 -0
- package/dist/entitybox/model-entry.d.ts +3 -0
- package/dist/entitybox/model-entry.js +233 -0
- package/dist/entitybox/model-mcp-proxy.d.ts +3 -0
- package/dist/entitybox/model-mcp-proxy.js +85 -0
- package/dist/entitybox-application-boundary.d.ts +59 -0
- package/dist/entitybox-application-boundary.js +161 -0
- package/dist/entitybox-application-guard-core.d.ts +44 -0
- package/dist/entitybox-application-guard-core.js +164 -0
- package/dist/entitybox-application-guard-process.d.ts +1 -0
- package/dist/entitybox-application-guard-process.js +83 -0
- package/dist/entitybox-application-guard.d.ts +46 -0
- package/dist/entitybox-application-guard.js +239 -0
- package/dist/entitybox-capacity-health-host.d.ts +12 -0
- package/dist/entitybox-capacity-health-host.js +80 -0
- package/dist/entitybox-capacity-health-worker.d.ts +22 -0
- package/dist/entitybox-capacity-health-worker.js +168 -0
- package/dist/entitybox-capacity-host.d.ts +17 -0
- package/dist/entitybox-capacity-host.js +155 -0
- package/dist/entitybox-capacity-owner-process.d.ts +1 -0
- package/dist/entitybox-capacity-owner-process.js +32 -0
- package/dist/entitybox-capacity-owner.d.ts +16 -0
- package/dist/entitybox-capacity-owner.js +90 -0
- package/dist/entitybox-capacity-programs.d.ts +7 -0
- package/dist/entitybox-capacity-programs.js +49 -0
- package/dist/entitybox-capacity-provisioner.d.ts +82 -0
- package/dist/entitybox-capacity-provisioner.js +404 -0
- package/dist/entitybox-capacity-publication.d.ts +29 -0
- package/dist/entitybox-capacity-publication.js +199 -0
- package/dist/entitybox-capacity-registration.d.ts +36 -0
- package/dist/entitybox-capacity-registration.js +75 -0
- package/dist/entitybox-capacity-worker.d.ts +29 -0
- package/dist/entitybox-capacity-worker.js +113 -0
- package/dist/entitybox-computer-task.d.ts +69 -0
- package/dist/entitybox-computer-task.js +176 -0
- package/dist/entitybox-controller-recovery.d.ts +40 -0
- package/dist/entitybox-controller-recovery.js +156 -0
- package/dist/entitybox-desktop-action-server.d.ts +34 -0
- package/dist/entitybox-desktop-action-server.js +176 -0
- package/dist/entitybox-desktop-admission.d.ts +32 -0
- package/dist/entitybox-desktop-admission.js +79 -0
- package/dist/entitybox-display-binding.d.ts +13 -0
- package/dist/entitybox-display-binding.js +31 -0
- package/dist/entitybox-execution-container.d.ts +82 -0
- package/dist/entitybox-execution-container.js +450 -0
- package/dist/entitybox-execution-host.d.ts +40 -0
- package/dist/entitybox-execution-host.js +168 -0
- package/dist/entitybox-execution-lease.d.ts +81 -0
- package/dist/entitybox-execution-lease.js +332 -0
- package/dist/entitybox-file-inputs.d.ts +51 -0
- package/dist/entitybox-file-inputs.js +182 -0
- package/dist/entitybox-file-session.d.ts +38 -0
- package/dist/entitybox-file-session.js +82 -0
- package/dist/entitybox-host-process.d.ts +12 -0
- package/dist/entitybox-host-process.js +120 -0
- package/dist/entitybox-install.d.ts +10 -0
- package/dist/entitybox-install.js +40 -0
- package/dist/entitybox-mcp-broker.d.ts +77 -0
- package/dist/entitybox-mcp-broker.js +420 -0
- package/dist/entitybox-mcp-contract.d.ts +10 -0
- package/dist/entitybox-mcp-contract.js +24 -0
- package/dist/entitybox-mcp-guard.d.ts +3 -0
- package/dist/entitybox-mcp-guard.js +167 -0
- package/dist/entitybox-model-artifact.d.ts +9 -0
- package/dist/entitybox-model-artifact.js +83 -0
- package/dist/entitybox-native-services.d.ts +33 -0
- package/dist/entitybox-native-services.js +172 -0
- package/dist/entitybox-operation.d.ts +4 -0
- package/dist/entitybox-operation.js +34 -0
- package/dist/entitybox-provider-broker.d.ts +41 -0
- package/dist/entitybox-provider-broker.js +149 -0
- package/dist/entitybox-queue-request.d.ts +32 -0
- package/dist/entitybox-queue-request.js +141 -0
- package/dist/entitybox-recovery-host.d.ts +12 -0
- package/dist/entitybox-recovery-host.js +80 -0
- package/dist/entitybox-recovery-store.d.ts +33 -0
- package/dist/entitybox-recovery-store.js +150 -0
- package/dist/entitybox-recovery-worker.d.ts +30 -0
- package/dist/entitybox-recovery-worker.js +134 -0
- package/dist/entitybox-vault-provider.d.ts +27 -0
- package/dist/entitybox-vault-provider.js +127 -0
- package/dist/harness-registry.js +3 -1
- package/dist/index.js +72 -38
- package/dist/install.d.ts +14 -2
- package/dist/install.js +115 -10
- package/dist/model-cache.d.ts +38 -0
- package/dist/model-cache.js +137 -0
- package/dist/request-pump.d.ts +3 -0
- package/dist/request-pump.js +21 -7
- package/dist/session-runner.d.ts +8 -1
- package/dist/session-runner.js +56 -3
- package/dist/supabase-client.js +4 -1
- package/package.json +5 -1
- package/scripts/copy-assets.js +4 -2
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.entityboxModelMcpProxySource = entityboxModelMcpProxySource;
|
|
4
|
+
/** Public, credential-free stdio shim placed inside the isolated model's own
|
|
5
|
+
* workspace. It talks only to that container's loopback broker endpoint. */
|
|
6
|
+
function entityboxModelMcpProxySource(endpoint) {
|
|
7
|
+
if (!/^http:\/\/127\.0\.0\.1:[0-9]{1,5}\/entitybox\/mcp$/.test(endpoint))
|
|
8
|
+
throw new Error('Invalid isolated MCP endpoint');
|
|
9
|
+
return '(' + proxyMain.toString() + ')(' + JSON.stringify(endpoint) + ');\n';
|
|
10
|
+
}
|
|
11
|
+
// Keep this function self-contained: its compiled source runs in a separate
|
|
12
|
+
// Node process without imports, credentials or references to the outer bundle.
|
|
13
|
+
function proxyMain(endpoint) {
|
|
14
|
+
const http = require('node:http');
|
|
15
|
+
let input = '', queued = 0, serial = Promise.resolve();
|
|
16
|
+
const requests = new Set();
|
|
17
|
+
const fail = () => { process.stderr.write('The required desktop connection ended.\n'); process.exit(70); };
|
|
18
|
+
const exchange = (message) => new Promise((resolve, reject) => {
|
|
19
|
+
const body = JSON.stringify(message);
|
|
20
|
+
const req = http.request(endpoint, { method: 'POST', headers: { 'content-type': 'application/json', 'content-length': Buffer.byteLength(body) } }, res => {
|
|
21
|
+
const chunks = [];
|
|
22
|
+
let bytes = 0;
|
|
23
|
+
res.on('data', (chunk) => { bytes += chunk.length; if (bytes > 32 * 1024 * 1024) {
|
|
24
|
+
req.destroy();
|
|
25
|
+
reject(Error());
|
|
26
|
+
}
|
|
27
|
+
else
|
|
28
|
+
chunks.push(chunk); });
|
|
29
|
+
res.on('error', reject);
|
|
30
|
+
res.on('end', () => {
|
|
31
|
+
try {
|
|
32
|
+
if (res.statusCode !== 200)
|
|
33
|
+
throw Error();
|
|
34
|
+
const value = JSON.parse(Buffer.concat(chunks).toString('utf8'));
|
|
35
|
+
if (message.id === undefined ? value !== null : (!value || value.jsonrpc !== '2.0' || value.id !== message.id || !value.result))
|
|
36
|
+
throw Error();
|
|
37
|
+
resolve(value);
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
reject(Error());
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
requests.add(req);
|
|
45
|
+
req.on('close', () => requests.delete(req));
|
|
46
|
+
req.on('error', reject);
|
|
47
|
+
req.setTimeout(130000, () => { req.destroy(); reject(Error()); });
|
|
48
|
+
req.end(body);
|
|
49
|
+
});
|
|
50
|
+
const consume = async (message) => {
|
|
51
|
+
const value = await exchange(message);
|
|
52
|
+
if (value !== null)
|
|
53
|
+
await new Promise((resolve, reject) => process.stdout.write(JSON.stringify(value) + '\n', error => error ? reject(error) : resolve()));
|
|
54
|
+
};
|
|
55
|
+
process.stdin.setEncoding('utf8');
|
|
56
|
+
process.stdin.on('data', chunk => {
|
|
57
|
+
try {
|
|
58
|
+
input += chunk;
|
|
59
|
+
if (Buffer.byteLength(input) > 512 * 1024)
|
|
60
|
+
throw Error();
|
|
61
|
+
let end;
|
|
62
|
+
while ((end = input.indexOf('\n')) >= 0) {
|
|
63
|
+
const message = JSON.parse(input.slice(0, end));
|
|
64
|
+
input = input.slice(end + 1);
|
|
65
|
+
if (!message || message.jsonrpc !== '2.0' || typeof message.method !== 'string' || ++queued > 8)
|
|
66
|
+
throw Error();
|
|
67
|
+
// MCP cancellation is urgent even while an earlier tool response is
|
|
68
|
+
// pending. The host broker fences the whole external-action task.
|
|
69
|
+
if (message.method === 'notifications/cancelled')
|
|
70
|
+
void consume(message).then(() => queued--).catch(fail);
|
|
71
|
+
else {
|
|
72
|
+
serial = serial.then(() => consume(message)).then(() => { queued--; });
|
|
73
|
+
serial.catch(fail);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
fail();
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
process.stdin.on('end', () => { for (const req of requests)
|
|
82
|
+
req.destroy(); process.exit(0); });
|
|
83
|
+
process.stdin.on('error', fail);
|
|
84
|
+
process.stdout.on('error', fail);
|
|
85
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { type EntityboxExecutionLease } from './entitybox-execution-lease';
|
|
2
|
+
import type { EntityboxMcpScope } from './entitybox-mcp-contract';
|
|
3
|
+
/** One application's persistent process namespace, separate from the native
|
|
4
|
+
* display and from a task's short-lived model/command namespace. This accepts
|
|
5
|
+
* only newly provisioned, labeled capacity; it never discovers or adopts an
|
|
6
|
+
* ordinary desktop. Registration and crash recovery belong to the adapter. */
|
|
7
|
+
export interface EntityboxApplicationBinding {
|
|
8
|
+
capacityId: string;
|
|
9
|
+
desktopId: string;
|
|
10
|
+
runtimeId: string;
|
|
11
|
+
containerId: string;
|
|
12
|
+
imageId: string;
|
|
13
|
+
startedAt: string;
|
|
14
|
+
}
|
|
15
|
+
export interface EntityboxApplicationQuiescence {
|
|
16
|
+
capacityId: string;
|
|
17
|
+
containerId: string;
|
|
18
|
+
attemptId: string;
|
|
19
|
+
state: 'paused' | 'stopped';
|
|
20
|
+
observedAt: string;
|
|
21
|
+
}
|
|
22
|
+
export type EntityboxApplicationDocker = (args: string[]) => Promise<string>;
|
|
23
|
+
export declare function entityboxApplicationVolumes(binding: EntityboxApplicationBinding): {
|
|
24
|
+
socket: string;
|
|
25
|
+
profile: string;
|
|
26
|
+
work: string;
|
|
27
|
+
};
|
|
28
|
+
export declare function entityboxApplicationLabels(binding: EntityboxApplicationBinding): {
|
|
29
|
+
'ai.add.entitybox.application.version': string;
|
|
30
|
+
'ai.add.entitybox.application.capacity': string;
|
|
31
|
+
'ai.add.entitybox.application.desktop': string;
|
|
32
|
+
'ai.add.entitybox.application.runtime': string;
|
|
33
|
+
};
|
|
34
|
+
/** Inspect all mounts as well as immutable identities. A Docker success code,
|
|
35
|
+
* a matching container name, or a stopped model is never sufficient proof. */
|
|
36
|
+
export declare function inspectEntityboxApplication(binding: EntityboxApplicationBinding, scope: EntityboxMcpScope, docker: EntityboxApplicationDocker): Promise<'running' | 'paused' | 'stopped'>;
|
|
37
|
+
/** One-use owner for an already paused application. It resumes only after a
|
|
38
|
+
* fresh native lease check, and freezes the entire namespace when fenced.
|
|
39
|
+
* A successful pause is final for this object: a late callback from an old
|
|
40
|
+
* task cannot pause a replacement owner. The adapter must keep the SQL
|
|
41
|
+
* reservation until this proof AND task/MCP stop proof both succeed.
|
|
42
|
+
*
|
|
43
|
+
* This is not a daemon-crash watchdog or a human-control grant. A durable
|
|
44
|
+
* capacity owner and independent watchdog are required before registration
|
|
45
|
+
* in the production request pump. */
|
|
46
|
+
export declare class EntityboxApplicationBoundary {
|
|
47
|
+
private readonly lease;
|
|
48
|
+
readonly binding: Readonly<EntityboxApplicationBinding>;
|
|
49
|
+
private readonly docker;
|
|
50
|
+
private used;
|
|
51
|
+
private startup;
|
|
52
|
+
private quiescing?;
|
|
53
|
+
private proven?;
|
|
54
|
+
private abort;
|
|
55
|
+
private constructor();
|
|
56
|
+
static attach(lease: EntityboxExecutionLease, binding: EntityboxApplicationBinding, docker: EntityboxApplicationDocker): Promise<EntityboxApplicationBoundary>;
|
|
57
|
+
resume(): Promise<void>;
|
|
58
|
+
pauseAndVerify(): Promise<EntityboxApplicationQuiescence>;
|
|
59
|
+
}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.EntityboxApplicationBoundary = void 0;
|
|
4
|
+
exports.entityboxApplicationVolumes = entityboxApplicationVolumes;
|
|
5
|
+
exports.entityboxApplicationLabels = entityboxApplicationLabels;
|
|
6
|
+
exports.inspectEntityboxApplication = inspectEntityboxApplication;
|
|
7
|
+
const entitybox_execution_lease_1 = require("./entitybox-execution-lease");
|
|
8
|
+
const uuid = /^[0-9a-f]{8}(-[0-9a-f]{4}){3}-[0-9a-f]{12}$/;
|
|
9
|
+
const failure = () => new entitybox_execution_lease_1.EntityboxExecutionError('The dedicated application boundary could not be verified');
|
|
10
|
+
function entityboxApplicationVolumes(binding) {
|
|
11
|
+
if (!uuid.test(binding?.capacityId))
|
|
12
|
+
throw failure();
|
|
13
|
+
return { socket: 'entitybox-display-' + binding.capacityId, profile: 'entitybox-app-profile-' + binding.capacityId, work: 'entitybox-app-work-' + binding.capacityId };
|
|
14
|
+
}
|
|
15
|
+
function entityboxApplicationLabels(binding) {
|
|
16
|
+
return { 'ai.add.entitybox.application.version': '1', 'ai.add.entitybox.application.capacity': binding.capacityId, 'ai.add.entitybox.application.desktop': binding.desktopId, 'ai.add.entitybox.application.runtime': binding.runtimeId };
|
|
17
|
+
}
|
|
18
|
+
function labelMatch(actual, expected) { return !!actual && Object.entries(expected).every(([k, v]) => actual[k] === v); }
|
|
19
|
+
function validBinding(binding, scope) {
|
|
20
|
+
if (!binding || !uuid.test(binding.capacityId) || !uuid.test(binding.desktopId) || !uuid.test(binding.runtimeId)
|
|
21
|
+
|| binding.desktopId !== scope.desktopId || binding.runtimeId !== scope.runtimeId || !/^[0-9a-f]{64}$/.test(binding.containerId)
|
|
22
|
+
|| !/^sha256:[0-9a-f]{64}$/.test(binding.imageId) || typeof binding.startedAt !== 'string' || binding.startedAt.length > 80
|
|
23
|
+
|| !Number.isFinite(Date.parse(binding.startedAt)))
|
|
24
|
+
throw failure();
|
|
25
|
+
}
|
|
26
|
+
/** Inspect all mounts as well as immutable identities. A Docker success code,
|
|
27
|
+
* a matching container name, or a stopped model is never sufficient proof. */
|
|
28
|
+
async function inspectEntityboxApplication(binding, scope, docker) {
|
|
29
|
+
validBinding(binding, scope);
|
|
30
|
+
const volumes = entityboxApplicationVolumes(binding), labels = entityboxApplicationLabels(binding);
|
|
31
|
+
const inspected = await Promise.all([docker(['container', 'inspect', binding.containerId]), docker(['volume', 'inspect', volumes.socket, volumes.profile, volumes.work])]);
|
|
32
|
+
let c, rows;
|
|
33
|
+
try {
|
|
34
|
+
const containers = JSON.parse(inspected[0]);
|
|
35
|
+
rows = JSON.parse(inspected[1]);
|
|
36
|
+
if (!Array.isArray(containers) || containers.length !== 1 || !Array.isArray(rows) || rows.length !== 3)
|
|
37
|
+
throw Error();
|
|
38
|
+
c = containers[0];
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
throw failure();
|
|
42
|
+
}
|
|
43
|
+
const h = c?.HostConfig, security = (h?.SecurityOpt ?? []);
|
|
44
|
+
if (c?.Id !== binding.containerId || c.Image !== binding.imageId || c.State?.StartedAt !== binding.startedAt || !labelMatch(c.Config?.Labels, labels)
|
|
45
|
+
|| c.Config?.User !== '10001:10001' || !h?.ReadonlyRootfs || h.Privileged || h.Binds?.length || h.CapAdd?.length
|
|
46
|
+
|| !Array.isArray(h.CapDrop) || !h.CapDrop.includes('ALL') || !Array.isArray(security) || !security.length || !security.every(s => s === 'no-new-privileges' || s === 'no-new-privileges:true')
|
|
47
|
+
|| !['', 'private'].includes(h.PidMode ?? '') || !['', 'private'].includes(h.UsernsMode ?? '') || !['', 'private'].includes(h.UTSMode ?? '') || !['', 'private'].includes(h.CgroupnsMode ?? '') || h.IpcMode !== 'private' || h.NetworkMode !== 'none'
|
|
48
|
+
|| h.Devices?.length || h.DeviceRequests?.length || h.VolumesFrom?.length || h.RestartPolicy?.Name !== 'no'
|
|
49
|
+
|| !Number.isSafeInteger(h.Memory) || h.Memory < 128 * 1024 * 1024 || h.Memory > 4 * 1024 * 1024 * 1024 || h.MemorySwap !== h.Memory
|
|
50
|
+
|| !Number.isSafeInteger(h.PidsLimit) || h.PidsLimit < 16 || h.PidsLimit > 512
|
|
51
|
+
|| !Array.isArray(c.Mounts))
|
|
52
|
+
throw failure();
|
|
53
|
+
const expected = [{ name: volumes.socket, destination: '/tmp/.X11-unix', rw: false }, { name: volumes.profile, destination: '/home/entitybox', rw: true }, { name: volumes.work, destination: '/work', rw: true }];
|
|
54
|
+
const actual = c.Mounts.filter((m) => m.Type !== 'tmpfs');
|
|
55
|
+
if (actual.length !== expected.length)
|
|
56
|
+
throw failure();
|
|
57
|
+
for (const e of expected) {
|
|
58
|
+
const matches = actual.filter((m) => m.Type === 'volume' && m.Name === e.name && m.Destination === e.destination && m.RW === e.rw);
|
|
59
|
+
if (matches.length !== 1)
|
|
60
|
+
throw failure();
|
|
61
|
+
const v = rows.find(r => r.Name === e.name);
|
|
62
|
+
const volumeLabels = e.name === volumes.socket ? { 'ai.add.entitybox.display.version': '1', 'ai.add.entitybox.display.capacity': binding.capacityId, 'ai.add.entitybox.display.desktop': binding.desktopId, 'ai.add.entitybox.display.runtime': binding.runtimeId } : labels;
|
|
63
|
+
if (!v || v.Driver !== 'local' || Object.keys(v.Options ?? {}).length || !labelMatch(v.Labels, volumeLabels))
|
|
64
|
+
throw failure();
|
|
65
|
+
}
|
|
66
|
+
if (c.Mounts.some((m) => m.Type === 'tmpfs' && !['/tmp', '/run'].includes(m.Destination)))
|
|
67
|
+
throw failure();
|
|
68
|
+
if (c.State.Restarting)
|
|
69
|
+
throw failure();
|
|
70
|
+
if (c.State.Running === true && Number.isSafeInteger(c.State.Pid) && c.State.Pid > 0 && c.State.Paused === true && c.State.Status === 'paused')
|
|
71
|
+
return 'paused';
|
|
72
|
+
if (c.State.Running === true && Number.isSafeInteger(c.State.Pid) && c.State.Pid > 0 && c.State.Paused === false && c.State.Status === 'running')
|
|
73
|
+
return 'running';
|
|
74
|
+
if (c.State.Running === false && c.State.Pid === 0 && c.State.Paused === false && ['exited', 'dead'].includes(c.State.Status))
|
|
75
|
+
return 'stopped';
|
|
76
|
+
throw failure();
|
|
77
|
+
}
|
|
78
|
+
/** One-use owner for an already paused application. It resumes only after a
|
|
79
|
+
* fresh native lease check, and freezes the entire namespace when fenced.
|
|
80
|
+
* A successful pause is final for this object: a late callback from an old
|
|
81
|
+
* task cannot pause a replacement owner. The adapter must keep the SQL
|
|
82
|
+
* reservation until this proof AND task/MCP stop proof both succeed.
|
|
83
|
+
*
|
|
84
|
+
* This is not a daemon-crash watchdog or a human-control grant. A durable
|
|
85
|
+
* capacity owner and independent watchdog are required before registration
|
|
86
|
+
* in the production request pump. */
|
|
87
|
+
class EntityboxApplicationBoundary {
|
|
88
|
+
lease;
|
|
89
|
+
binding;
|
|
90
|
+
docker;
|
|
91
|
+
used = false;
|
|
92
|
+
startup = Promise.resolve();
|
|
93
|
+
quiescing;
|
|
94
|
+
proven;
|
|
95
|
+
abort = () => { void this.pauseAndVerify().catch(() => { }); };
|
|
96
|
+
constructor(lease, binding, docker) {
|
|
97
|
+
this.lease = lease;
|
|
98
|
+
this.binding = binding;
|
|
99
|
+
this.docker = docker;
|
|
100
|
+
}
|
|
101
|
+
static async attach(lease, binding, docker) {
|
|
102
|
+
lease.assertActive();
|
|
103
|
+
const copy = Object.freeze({ ...binding });
|
|
104
|
+
if (await inspectEntityboxApplication(copy, lease.identity.scope, docker) !== 'paused')
|
|
105
|
+
throw new entitybox_execution_lease_1.EntityboxExecutionError('Dedicated applications must be paused before a task takes ownership');
|
|
106
|
+
lease.assertActive();
|
|
107
|
+
return new EntityboxApplicationBoundary(lease, copy, docker);
|
|
108
|
+
}
|
|
109
|
+
resume() {
|
|
110
|
+
if (this.used || this.proven)
|
|
111
|
+
throw new entitybox_execution_lease_1.EntityboxExecutionError('Application ownership cannot be reused');
|
|
112
|
+
this.used = true;
|
|
113
|
+
this.startup = Promise.resolve().then(async () => {
|
|
114
|
+
this.lease.assertActive();
|
|
115
|
+
await this.lease.authorizeChallenge();
|
|
116
|
+
this.lease.assertActive();
|
|
117
|
+
if (await inspectEntityboxApplication(this.binding, this.lease.identity.scope, this.docker) !== 'paused')
|
|
118
|
+
throw failure();
|
|
119
|
+
this.lease.assertActive();
|
|
120
|
+
await this.docker(['container', 'unpause', this.binding.containerId]);
|
|
121
|
+
this.lease.assertActive();
|
|
122
|
+
if (await inspectEntityboxApplication(this.binding, this.lease.identity.scope, this.docker) !== 'running')
|
|
123
|
+
throw failure();
|
|
124
|
+
this.lease.assertActive();
|
|
125
|
+
});
|
|
126
|
+
this.lease.signal.addEventListener('abort', this.abort, { once: true });
|
|
127
|
+
if (this.lease.signal.aborted)
|
|
128
|
+
this.abort();
|
|
129
|
+
return this.startup.catch(async () => { this.lease.fence(); try {
|
|
130
|
+
await this.pauseAndVerify();
|
|
131
|
+
}
|
|
132
|
+
catch { } throw new entitybox_execution_lease_1.EntityboxExecutionError('Dedicated applications could not resume under verified ownership'); });
|
|
133
|
+
}
|
|
134
|
+
pauseAndVerify() {
|
|
135
|
+
if (this.proven)
|
|
136
|
+
return Promise.resolve(this.proven);
|
|
137
|
+
if (this.quiescing)
|
|
138
|
+
return this.quiescing;
|
|
139
|
+
this.quiescing = Promise.resolve().then(async () => {
|
|
140
|
+
// Join an unpause already in flight. An observation timeout must not
|
|
141
|
+
// turn that unknown operation into successful pause proof.
|
|
142
|
+
try {
|
|
143
|
+
await this.startup;
|
|
144
|
+
}
|
|
145
|
+
catch { }
|
|
146
|
+
let state = await inspectEntityboxApplication(this.binding, this.lease.identity.scope, this.docker);
|
|
147
|
+
if (state === 'running') {
|
|
148
|
+
await this.docker(['container', 'pause', this.binding.containerId]);
|
|
149
|
+
state = await inspectEntityboxApplication(this.binding, this.lease.identity.scope, this.docker);
|
|
150
|
+
}
|
|
151
|
+
if (state === 'running')
|
|
152
|
+
throw failure();
|
|
153
|
+
this.proven = Object.freeze({ capacityId: this.binding.capacityId, containerId: this.binding.containerId, attemptId: this.lease.identity.attemptId, state, observedAt: new Date().toISOString() });
|
|
154
|
+
this.lease.signal.removeEventListener('abort', this.abort);
|
|
155
|
+
return this.proven;
|
|
156
|
+
});
|
|
157
|
+
this.lease.fence();
|
|
158
|
+
return this.quiescing.catch(error => { this.quiescing = undefined; throw error; });
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
exports.EntityboxApplicationBoundary = EntityboxApplicationBoundary;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { type EntityboxApplicationBinding, type EntityboxApplicationDocker, type EntityboxApplicationQuiescence } from './entitybox-application-boundary';
|
|
2
|
+
import { type EntityboxExecutionIdentity } from './entitybox-execution-lease';
|
|
3
|
+
type Packet = {
|
|
4
|
+
type: string;
|
|
5
|
+
[key: string]: unknown;
|
|
6
|
+
};
|
|
7
|
+
/** Trusted independent host process state machine. It is the sole application
|
|
8
|
+
* mutator while attached. A lost Docker mutation reply poisons reuse until
|
|
9
|
+
* the same namespace is actually stopped; observing paused is not sufficient
|
|
10
|
+
* when an earlier unpause/pause may still reach the engine. */
|
|
11
|
+
export declare class EntityboxApplicationGuardCore {
|
|
12
|
+
private readonly docker;
|
|
13
|
+
private readonly emit;
|
|
14
|
+
private readonly now;
|
|
15
|
+
readonly identity: Readonly<EntityboxExecutionIdentity>;
|
|
16
|
+
readonly binding: Readonly<EntityboxApplicationBinding>;
|
|
17
|
+
readonly finished: Promise<EntityboxApplicationQuiescence>;
|
|
18
|
+
private resolve;
|
|
19
|
+
private phase;
|
|
20
|
+
private pending?;
|
|
21
|
+
private deadline;
|
|
22
|
+
private nextChallenge;
|
|
23
|
+
private nextInspect;
|
|
24
|
+
private uncertainty;
|
|
25
|
+
private attached;
|
|
26
|
+
private reported;
|
|
27
|
+
private startup;
|
|
28
|
+
private stopping?;
|
|
29
|
+
constructor(identity: EntityboxExecutionIdentity, binding: EntityboxApplicationBinding, docker: EntityboxApplicationDocker, emit: (packet: Packet) => void, now?: () => number);
|
|
30
|
+
state(): {
|
|
31
|
+
phase: "running" | "ready" | "initial" | "resuming" | "fenced" | "finished";
|
|
32
|
+
uncertain: boolean;
|
|
33
|
+
};
|
|
34
|
+
start(): Promise<void>;
|
|
35
|
+
message(packet: unknown): void;
|
|
36
|
+
tick(): void;
|
|
37
|
+
fence(): void;
|
|
38
|
+
private active;
|
|
39
|
+
private challenge;
|
|
40
|
+
private send;
|
|
41
|
+
private unverified;
|
|
42
|
+
private quiesce;
|
|
43
|
+
}
|
|
44
|
+
export {};
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.EntityboxApplicationGuardCore = void 0;
|
|
4
|
+
const crypto_1 = require("crypto");
|
|
5
|
+
const perf_hooks_1 = require("perf_hooks");
|
|
6
|
+
const entitybox_application_boundary_1 = require("./entitybox-application-boundary");
|
|
7
|
+
const entitybox_execution_lease_1 = require("./entitybox-execution-lease");
|
|
8
|
+
const entitybox_mcp_contract_1 = require("./entitybox-mcp-contract");
|
|
9
|
+
const uuid = /^[0-9a-f]{8}(-[0-9a-f]{4}){3}-[0-9a-f]{12}$/;
|
|
10
|
+
/** Trusted independent host process state machine. It is the sole application
|
|
11
|
+
* mutator while attached. A lost Docker mutation reply poisons reuse until
|
|
12
|
+
* the same namespace is actually stopped; observing paused is not sufficient
|
|
13
|
+
* when an earlier unpause/pause may still reach the engine. */
|
|
14
|
+
class EntityboxApplicationGuardCore {
|
|
15
|
+
docker;
|
|
16
|
+
emit;
|
|
17
|
+
now;
|
|
18
|
+
identity;
|
|
19
|
+
binding;
|
|
20
|
+
finished;
|
|
21
|
+
resolve;
|
|
22
|
+
phase = 'initial';
|
|
23
|
+
pending;
|
|
24
|
+
deadline = 0;
|
|
25
|
+
nextChallenge = Infinity;
|
|
26
|
+
nextInspect = 0;
|
|
27
|
+
uncertainty = false;
|
|
28
|
+
attached = false;
|
|
29
|
+
reported = false;
|
|
30
|
+
startup = Promise.resolve();
|
|
31
|
+
stopping;
|
|
32
|
+
constructor(identity, binding, docker, emit, now = () => perf_hooks_1.performance.now()) {
|
|
33
|
+
this.docker = docker;
|
|
34
|
+
this.emit = emit;
|
|
35
|
+
this.now = now;
|
|
36
|
+
if (!identity || !uuid.test(identity.requestId) || !uuid.test(identity.attemptId))
|
|
37
|
+
throw new entitybox_execution_lease_1.EntityboxExecutionError('Invalid application guard identity');
|
|
38
|
+
this.identity = Object.freeze({ ...identity, scope: (0, entitybox_mcp_contract_1.parseEntityboxMcpScope)(identity.scope) });
|
|
39
|
+
this.binding = Object.freeze({ ...binding });
|
|
40
|
+
this.finished = new Promise(resolve => { this.resolve = resolve; });
|
|
41
|
+
}
|
|
42
|
+
state() { return { phase: this.phase, uncertain: this.uncertainty }; }
|
|
43
|
+
async start() {
|
|
44
|
+
if (this.phase !== 'initial')
|
|
45
|
+
throw new entitybox_execution_lease_1.EntityboxExecutionError('Application guard cannot be reused');
|
|
46
|
+
if (await (0, entitybox_application_boundary_1.inspectEntityboxApplication)(this.binding, this.identity.scope, this.docker) !== 'paused')
|
|
47
|
+
throw new entitybox_execution_lease_1.EntityboxExecutionError('Application guard requires paused capacity');
|
|
48
|
+
this.attached = true;
|
|
49
|
+
if (this.phase !== 'initial') {
|
|
50
|
+
this.quiesce();
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
this.phase = 'ready';
|
|
54
|
+
this.send({ type: 'ready' });
|
|
55
|
+
}
|
|
56
|
+
message(packet) {
|
|
57
|
+
const p = packet;
|
|
58
|
+
if (this.phase === 'finished')
|
|
59
|
+
return;
|
|
60
|
+
if (p?.type === 'stop') {
|
|
61
|
+
this.fence();
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
if (p?.type === 'resume' && this.phase === 'ready') {
|
|
65
|
+
this.phase = 'resuming';
|
|
66
|
+
this.deadline = this.now() + 10000;
|
|
67
|
+
this.challenge();
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
if (p?.type === 'grant' && typeof p.id === 'string' && this.pending && p.id === this.pending.id && (this.phase === 'resuming' || this.phase === 'running')) {
|
|
71
|
+
const deadline = this.pending.at + 10000;
|
|
72
|
+
if (this.now() >= this.deadline || this.now() >= deadline) {
|
|
73
|
+
this.fence();
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
this.deadline = deadline;
|
|
77
|
+
this.pending = undefined;
|
|
78
|
+
if (this.phase === 'resuming') {
|
|
79
|
+
// Assign before any asynchronous work; fence joins this exact resume.
|
|
80
|
+
this.startup = Promise.resolve().then(async () => {
|
|
81
|
+
if (await (0, entitybox_application_boundary_1.inspectEntityboxApplication)(this.binding, this.identity.scope, this.docker) !== 'paused')
|
|
82
|
+
throw Error();
|
|
83
|
+
if (!this.active())
|
|
84
|
+
return;
|
|
85
|
+
try {
|
|
86
|
+
await this.docker(['container', 'unpause', this.binding.containerId]);
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
this.uncertainty = true;
|
|
90
|
+
throw Error();
|
|
91
|
+
}
|
|
92
|
+
if (!this.active())
|
|
93
|
+
return;
|
|
94
|
+
if (await (0, entitybox_application_boundary_1.inspectEntityboxApplication)(this.binding, this.identity.scope, this.docker) !== 'running')
|
|
95
|
+
throw Error();
|
|
96
|
+
if (!this.active())
|
|
97
|
+
return;
|
|
98
|
+
this.phase = 'running';
|
|
99
|
+
this.nextChallenge = this.now() + 3000;
|
|
100
|
+
this.send({ type: 'started' });
|
|
101
|
+
}).catch(() => { this.fence(); });
|
|
102
|
+
}
|
|
103
|
+
else
|
|
104
|
+
this.nextChallenge = this.now() + 3000;
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
this.fence();
|
|
108
|
+
}
|
|
109
|
+
tick() {
|
|
110
|
+
if (this.phase === 'finished')
|
|
111
|
+
return;
|
|
112
|
+
if ((this.phase === 'running' || this.phase === 'resuming') && this.now() >= this.deadline)
|
|
113
|
+
this.fence();
|
|
114
|
+
if (this.phase === 'running' && this.now() >= this.nextChallenge)
|
|
115
|
+
this.challenge();
|
|
116
|
+
if (this.phase === 'fenced' && this.now() >= this.nextInspect)
|
|
117
|
+
this.quiesce();
|
|
118
|
+
}
|
|
119
|
+
fence() { if (this.phase === 'finished')
|
|
120
|
+
return; this.phase = 'fenced'; this.pending = undefined; this.nextChallenge = Infinity; this.quiesce(); }
|
|
121
|
+
active() { if (this.phase === 'fenced' || this.phase === 'finished')
|
|
122
|
+
return false; if (this.now() >= this.deadline) {
|
|
123
|
+
this.fence();
|
|
124
|
+
return false;
|
|
125
|
+
} return true; }
|
|
126
|
+
challenge() { if (this.pending || !this.active())
|
|
127
|
+
return; this.nextChallenge = Infinity; this.pending = { id: (0, crypto_1.randomUUID)(), at: this.now() }; this.send({ type: 'challenge', id: this.pending.id }); }
|
|
128
|
+
send(packet) { try {
|
|
129
|
+
this.emit(packet);
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
this.fence();
|
|
133
|
+
} }
|
|
134
|
+
unverified() { if (this.reported)
|
|
135
|
+
return; this.reported = true; this.send({ type: 'unverified' }); }
|
|
136
|
+
quiesce() {
|
|
137
|
+
if (!this.attached || this.stopping || this.phase === 'finished')
|
|
138
|
+
return;
|
|
139
|
+
this.stopping = Promise.resolve().then(async () => {
|
|
140
|
+
await this.startup;
|
|
141
|
+
let state = await (0, entitybox_application_boundary_1.inspectEntityboxApplication)(this.binding, this.identity.scope, this.docker);
|
|
142
|
+
if (state === 'running') {
|
|
143
|
+
try {
|
|
144
|
+
await this.docker(['container', 'pause', this.binding.containerId]);
|
|
145
|
+
}
|
|
146
|
+
catch {
|
|
147
|
+
this.uncertainty = true;
|
|
148
|
+
throw Error();
|
|
149
|
+
}
|
|
150
|
+
state = await (0, entitybox_application_boundary_1.inspectEntityboxApplication)(this.binding, this.identity.scope, this.docker);
|
|
151
|
+
}
|
|
152
|
+
// A stopped namespace cannot be restarted by a delayed pause/unpause.
|
|
153
|
+
if (state === 'running' || (state === 'paused' && this.uncertainty)) {
|
|
154
|
+
this.unverified();
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
const proof = Object.freeze({ capacityId: this.binding.capacityId, containerId: this.binding.containerId, attemptId: this.identity.attemptId, state, observedAt: new Date().toISOString() });
|
|
158
|
+
this.phase = 'finished';
|
|
159
|
+
this.resolve(proof);
|
|
160
|
+
this.send({ type: 'stopped', proof });
|
|
161
|
+
}).catch(() => { this.unverified(); }).finally(() => { this.stopping = undefined; this.nextInspect = this.now() + 1000; });
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
exports.EntityboxApplicationGuardCore = EntityboxApplicationGuardCore;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const child_process_1 = require("child_process");
|
|
4
|
+
const util_1 = require("util");
|
|
5
|
+
const entitybox_application_guard_core_1 = require("./entitybox-application-guard-core");
|
|
6
|
+
const entitybox_host_process_1 = require("./entitybox-host-process");
|
|
7
|
+
const entitybox_recovery_store_1 = require("./entitybox-recovery-store");
|
|
8
|
+
// Only the native host starts this child. No RPC token, pairing, provider key,
|
|
9
|
+
// Docker socket or guard IPC channel enters the application container.
|
|
10
|
+
if (!process.send)
|
|
11
|
+
process.exit(78);
|
|
12
|
+
const exec = (0, util_1.promisify)(child_process_1.execFile);
|
|
13
|
+
let core, configured = false;
|
|
14
|
+
const timer = setInterval(() => core?.tick(), 50);
|
|
15
|
+
const startup = setTimeout(() => { if (!configured)
|
|
16
|
+
process.exit(78); }, 10000);
|
|
17
|
+
function fence() { if (core)
|
|
18
|
+
core.fence();
|
|
19
|
+
else
|
|
20
|
+
process.exit(78); }
|
|
21
|
+
function send(packet) { if (process.connected)
|
|
22
|
+
process.send?.(packet, error => { if (error)
|
|
23
|
+
fence(); });
|
|
24
|
+
else
|
|
25
|
+
fence(); }
|
|
26
|
+
process.on('message', async (packet) => {
|
|
27
|
+
try {
|
|
28
|
+
if (Buffer.byteLength(JSON.stringify(packet)) > 16000)
|
|
29
|
+
throw Error();
|
|
30
|
+
if (!configured) {
|
|
31
|
+
const p = packet;
|
|
32
|
+
if (p?.type !== 'configure' || !/^[-a-zA-Z0-9_.]{1,80}$/.test(p.context))
|
|
33
|
+
throw Error();
|
|
34
|
+
configured = true;
|
|
35
|
+
clearTimeout(startup);
|
|
36
|
+
const docker = async (args) => {
|
|
37
|
+
// Mutations are never killed at an observation deadline. The guard
|
|
38
|
+
// joins the actual CLI lifecycle; any failed reply poisons reuse.
|
|
39
|
+
const mutation = ['pause', 'unpause'].includes(args[1]);
|
|
40
|
+
return (await exec('docker', ['--context', p.context, ...args], { windowsHide: true, ...(mutation ? {} : { timeout: 5000 }), maxBuffer: 1024 * 1024 })).stdout.trim();
|
|
41
|
+
};
|
|
42
|
+
let emit = send;
|
|
43
|
+
if (p.recovery) {
|
|
44
|
+
const store = new entitybox_recovery_store_1.EntityboxRecoveryStore(p.recovery.directory), guard = await (0, entitybox_host_process_1.readEntityboxHostProcess)();
|
|
45
|
+
if (store.hostId !== p.recovery.hostId || !guard)
|
|
46
|
+
throw Error();
|
|
47
|
+
const host = (0, entitybox_recovery_store_1.parseEntityboxRecoveryHost)({ hostId: store.hostId, dockerContext: p.context, controller: p.recovery.controller, guard });
|
|
48
|
+
emit = (packet) => {
|
|
49
|
+
const event = packet;
|
|
50
|
+
if (event?.type === 'stopped') {
|
|
51
|
+
// Core has joined every mutation and becomes permanently finished
|
|
52
|
+
// BEFORE emitting. Durable publication precedes any IPC receipt.
|
|
53
|
+
try {
|
|
54
|
+
store.writeProof({ version: 1, host, identity: p.identity, application: p.binding, proof: event.proof });
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
send({ type: 'unverified' });
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
send(event?.type === 'ready' ? { ...event, process: guard } : packet);
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
if (!process.connected)
|
|
65
|
+
throw Error();
|
|
66
|
+
core = new entitybox_application_guard_core_1.EntityboxApplicationGuardCore(p.identity, p.binding, docker, emit);
|
|
67
|
+
void core.finished.then(() => { clearInterval(timer); if (process.connected)
|
|
68
|
+
process.disconnect(); });
|
|
69
|
+
void core.start().catch(() => { send({ type: 'unverified' }); clearInterval(timer); if (process.connected)
|
|
70
|
+
process.disconnect(); });
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
core?.message(packet);
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
fence();
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
process.on('disconnect', fence);
|
|
80
|
+
process.on('SIGTERM', fence);
|
|
81
|
+
process.on('SIGINT', fence);
|
|
82
|
+
process.on('uncaughtException', fence);
|
|
83
|
+
process.on('unhandledRejection', fence);
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { type EntityboxExecutionLease } from './entitybox-execution-lease';
|
|
2
|
+
import { type EntityboxApplicationBinding, type EntityboxApplicationQuiescence } from './entitybox-application-boundary';
|
|
3
|
+
import { type EntityboxRecoveryStore } from './entitybox-recovery-store';
|
|
4
|
+
/** Host-side handle. Production adapters must retain this owner until stop
|
|
5
|
+
* proof and child exit settle. A disappeared guard never grants reuse. */
|
|
6
|
+
export declare class EntityboxApplicationGuard {
|
|
7
|
+
private readonly lease;
|
|
8
|
+
readonly binding: Readonly<EntityboxApplicationBinding>;
|
|
9
|
+
private readonly proc;
|
|
10
|
+
private readonly context;
|
|
11
|
+
private readonly requireInventory;
|
|
12
|
+
private readonly recovery?;
|
|
13
|
+
readonly processId: number;
|
|
14
|
+
readonly closed: Promise<void>;
|
|
15
|
+
private readonly ready;
|
|
16
|
+
private readonly started;
|
|
17
|
+
private readonly stopped;
|
|
18
|
+
private readyResolve;
|
|
19
|
+
private readyReject;
|
|
20
|
+
private startResolve;
|
|
21
|
+
private startReject;
|
|
22
|
+
private stopResolve;
|
|
23
|
+
private stopReject;
|
|
24
|
+
private proof?;
|
|
25
|
+
private guardIdentity?;
|
|
26
|
+
private used;
|
|
27
|
+
private closing;
|
|
28
|
+
private didClose;
|
|
29
|
+
private stopping?;
|
|
30
|
+
private abort;
|
|
31
|
+
private constructor();
|
|
32
|
+
static attach(lease: EntityboxExecutionLease, binding: EntityboxApplicationBinding, options?: {
|
|
33
|
+
dockerContext?: string;
|
|
34
|
+
requireInventory?: boolean;
|
|
35
|
+
recoveryStore?: EntityboxRecoveryStore;
|
|
36
|
+
onOwner?: (owner: EntityboxApplicationGuard) => void;
|
|
37
|
+
}): Promise<EntityboxApplicationGuard>;
|
|
38
|
+
resume(): Promise<void>;
|
|
39
|
+
pauseAndVerify(): Promise<EntityboxApplicationQuiescence>;
|
|
40
|
+
private docker;
|
|
41
|
+
private emergencyPause;
|
|
42
|
+
private send;
|
|
43
|
+
private message;
|
|
44
|
+
private grant;
|
|
45
|
+
private deadline;
|
|
46
|
+
}
|