@addai/node 0.30.12 → 0.30.14
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 +31 -6
- package/dist/capabilities.js +48 -26
- package/dist/claude-models.d.ts +71 -0
- package/dist/claude-models.js +330 -0
- 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 +14 -8
- package/dist/codex-spawn.js +30 -10
- 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 +151 -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 +48 -3
- package/dist/supabase-client.js +4 -1
- package/package.json +5 -1
- package/scripts/copy-assets.js +4 -2
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.EntityboxControllerRecovery = void 0;
|
|
4
|
+
const child_process_1 = require("child_process");
|
|
5
|
+
const util_1 = require("util");
|
|
6
|
+
const crypto_1 = require("crypto");
|
|
7
|
+
const entitybox_execution_lease_1 = require("./entitybox-execution-lease");
|
|
8
|
+
const entitybox_mcp_contract_1 = require("./entitybox-mcp-contract");
|
|
9
|
+
const entitybox_application_boundary_1 = require("./entitybox-application-boundary");
|
|
10
|
+
const entitybox_display_binding_1 = require("./entitybox-display-binding");
|
|
11
|
+
const entitybox_host_process_1 = require("./entitybox-host-process");
|
|
12
|
+
const entitybox_recovery_store_1 = require("./entitybox-recovery-store");
|
|
13
|
+
const uuid = /^[0-9a-f]{8}(-[0-9a-f]{4}){3}-[0-9a-f]{12}$/, exec = (0, util_1.promisify)(child_process_1.execFile), fail = () => new entitybox_execution_lease_1.EntityboxExecutionError('Native controller recovery could not be verified');
|
|
14
|
+
const terminal = ['completed', 'failed', 'canceled', 'dead_letter', 'deleted'];
|
|
15
|
+
/** Retain this object across failed/lost replies: the recovery nonce is private,
|
|
16
|
+
* and retries use the same ID. No timeout hands recovery to another process.
|
|
17
|
+
* A completed attempt returns BEFORE any Docker operation, including replay
|
|
18
|
+
* after a replacement task has resumed the retained application. */
|
|
19
|
+
class EntityboxControllerRecovery {
|
|
20
|
+
options;
|
|
21
|
+
id = (0, crypto_1.randomUUID)();
|
|
22
|
+
nonce = (0, crypto_1.randomUUID)();
|
|
23
|
+
identity;
|
|
24
|
+
context;
|
|
25
|
+
docker;
|
|
26
|
+
owner;
|
|
27
|
+
pending;
|
|
28
|
+
completed;
|
|
29
|
+
constructor(options) {
|
|
30
|
+
this.options = options;
|
|
31
|
+
const i = options.identity;
|
|
32
|
+
if (!i || !uuid.test(i.requestId) || !uuid.test(i.attemptId))
|
|
33
|
+
throw fail();
|
|
34
|
+
this.identity = Object.freeze({ requestId: i.requestId, attemptId: i.attemptId, scope: (0, entitybox_mcp_contract_1.parseEntityboxMcpScope)(i.scope) });
|
|
35
|
+
this.context = options.dockerContext ?? 'desktop-linux';
|
|
36
|
+
if (!/^[-a-zA-Z0-9_.]{1,80}$/.test(this.context))
|
|
37
|
+
throw fail();
|
|
38
|
+
this.docker = options.docker ?? (async (args) => (await exec('docker', ['--context', this.context, ...args], { windowsHide: true, ...(args[0] === 'container' && args[1] === 'rm' ? {} : { timeout: 5000 }), maxBuffer: 1024 * 1024 })).stdout.trim());
|
|
39
|
+
}
|
|
40
|
+
run() {
|
|
41
|
+
if (this.completed)
|
|
42
|
+
return Promise.resolve(this.completed);
|
|
43
|
+
if (this.pending)
|
|
44
|
+
return this.pending;
|
|
45
|
+
this.pending = this.recover().then(status => { this.completed = status; return status; }).catch(() => { throw fail(); }).finally(() => { this.pending = undefined; });
|
|
46
|
+
return this.pending;
|
|
47
|
+
}
|
|
48
|
+
async call(name, args = {}) {
|
|
49
|
+
let timer;
|
|
50
|
+
try {
|
|
51
|
+
const raw = await Promise.race([this.options.rpc('entitybox_native_execution_recovery_' + name, { p_token: this.options.token(), p_attempt_id: this.identity.attemptId, ...args }), new Promise((_, reject) => { timer = setTimeout(() => reject(fail()), 4500); })]);
|
|
52
|
+
return this.snapshot(raw);
|
|
53
|
+
}
|
|
54
|
+
finally {
|
|
55
|
+
clearTimeout(timer);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
snapshot(raw) {
|
|
59
|
+
const s = raw;
|
|
60
|
+
if (!s || s.attemptId !== this.identity.attemptId || s.requestId !== this.identity.requestId || s.runId !== this.identity.scope.runId || !Number.isSafeInteger(s.epoch) || s.epoch < 1
|
|
61
|
+
|| (0, entitybox_recovery_store_1.entityboxCanonical)((0, entitybox_mcp_contract_1.parseEntityboxMcpScope)(s.scope)) !== (0, entitybox_recovery_store_1.entityboxCanonical)(this.identity.scope) || !['running', 'stop_requested', 'stopped'].includes(s.phase) || ![...terminal, 'starting', 'running'].includes(s.requestStatus))
|
|
62
|
+
throw fail();
|
|
63
|
+
return s;
|
|
64
|
+
}
|
|
65
|
+
ended(s) { if (s.phase !== 'stopped')
|
|
66
|
+
return; if (!terminal.includes(s.requestStatus))
|
|
67
|
+
throw fail(); return s.requestStatus; }
|
|
68
|
+
recovery(s) {
|
|
69
|
+
const r = s.recovery;
|
|
70
|
+
if (r === null)
|
|
71
|
+
return null;
|
|
72
|
+
if (!r || !uuid.test(r.id) || !Number.isSafeInteger(r.generation) || r.generation < 1 || r.hostId !== this.options.store.hostId || r.phase !== 'checking')
|
|
73
|
+
throw fail();
|
|
74
|
+
(0, entitybox_host_process_1.parseEntityboxHostProcess)(r.owner);
|
|
75
|
+
return r;
|
|
76
|
+
}
|
|
77
|
+
async recover() {
|
|
78
|
+
let snapshot = await this.call('status');
|
|
79
|
+
const ended = this.ended(snapshot);
|
|
80
|
+
if (ended)
|
|
81
|
+
return ended;
|
|
82
|
+
const h = (0, entitybox_recovery_store_1.parseEntityboxRecoveryHost)(snapshot.host), inventory = snapshot.inventory;
|
|
83
|
+
if (h.hostId !== this.options.store.hostId || h.dockerContext !== this.context || inventory?.sealed !== true || typeof inventory.hasExecution !== 'boolean' || !Array.isArray(inventory.resources) || inventory.resources.length !== (inventory.hasExecution ? 3 : 2))
|
|
84
|
+
throw fail();
|
|
85
|
+
const resource = (kind, keys) => { const list = inventory.resources.filter(r => r.kind === kind); if (list.length !== 1)
|
|
86
|
+
throw fail(); const b = list[0].binding; if (!b || Object.keys(b).sort().join(',') !== keys.sort().join(',') || !Object.values(b).every(v => typeof v === 'string'))
|
|
87
|
+
throw fail(); return b; };
|
|
88
|
+
const app = resource('application', ['capacityId', 'desktopId', 'runtimeId', 'containerId', 'imageId', 'startedAt']);
|
|
89
|
+
const display = resource('display', ['capacityId', 'desktopId', 'runtimeId', 'containerId', 'imageId', 'startedAt']);
|
|
90
|
+
if (app.capacityId !== display.capacityId || app.containerId === display.containerId)
|
|
91
|
+
throw fail();
|
|
92
|
+
const executor = inventory.hasExecution ? resource('execution', ['containerId', 'imageId', 'watchdogSha256']) : null;
|
|
93
|
+
if (executor && (!/^[a-f0-9]{64}$/.test(executor.containerId) || !/^sha256:[a-f0-9]{64}$/.test(executor.imageId) || !/^[a-f0-9]{64}$/.test(executor.watchdogSha256) || [app.containerId, display.containerId].includes(executor.containerId)))
|
|
94
|
+
throw fail();
|
|
95
|
+
const evidence = this.options.store.readProof(this.identity.attemptId), proof = evidence.value;
|
|
96
|
+
if ((0, entitybox_recovery_store_1.entityboxCanonical)(proof.host) !== (0, entitybox_recovery_store_1.entityboxCanonical)(h) || (0, entitybox_recovery_store_1.entityboxCanonical)(proof.identity) !== (0, entitybox_recovery_store_1.entityboxCanonical)(this.identity) || (0, entitybox_recovery_store_1.entityboxCanonical)(proof.application) !== (0, entitybox_recovery_store_1.entityboxCanonical)(app)
|
|
97
|
+
|| proof.proof?.attemptId !== this.identity.attemptId || proof.proof.capacityId !== app.capacityId || proof.proof.containerId !== app.containerId || !['paused', 'stopped'].includes(proof.proof.state) || !Number.isFinite(Date.parse(proof.proof.observedAt)))
|
|
98
|
+
throw fail();
|
|
99
|
+
const gone = this.options.assertGone ?? entitybox_host_process_1.assertEntityboxHostProcessGone;
|
|
100
|
+
await gone(h.controller);
|
|
101
|
+
await gone(h.guard);
|
|
102
|
+
if (!this.owner) {
|
|
103
|
+
const owner = await (this.options.readProcess ?? entitybox_host_process_1.readEntityboxHostProcess)();
|
|
104
|
+
if (!owner)
|
|
105
|
+
throw fail();
|
|
106
|
+
this.owner = (0, entitybox_host_process_1.parseEntityboxHostProcess)(owner);
|
|
107
|
+
}
|
|
108
|
+
if (this.owner.platform !== h.controller.platform)
|
|
109
|
+
throw fail();
|
|
110
|
+
const previous = this.recovery(snapshot);
|
|
111
|
+
if (previous && previous.id !== this.id)
|
|
112
|
+
await gone(previous.owner);
|
|
113
|
+
snapshot = await this.call('claim', { p_recovery_id: this.id, p_recovery_nonce: this.nonce, p_host_id: h.hostId, p_owner: this.owner, p_expected_id: previous?.id ?? null, p_expected_generation: previous?.generation ?? 0 });
|
|
114
|
+
const finished = this.ended(snapshot);
|
|
115
|
+
if (finished)
|
|
116
|
+
return finished;
|
|
117
|
+
const claimed = this.recovery(snapshot);
|
|
118
|
+
if (!claimed || claimed.id !== this.id || (0, entitybox_recovery_store_1.entityboxCanonical)(claimed.owner) !== (0, entitybox_recovery_store_1.entityboxCanonical)(this.owner) || snapshot.phase !== 'stop_requested')
|
|
119
|
+
throw fail();
|
|
120
|
+
// These are observations only. Recovery never unpauses, pauses, restarts or
|
|
121
|
+
// adopts an application/display. The old guard already joined its mutations.
|
|
122
|
+
await (0, entitybox_display_binding_1.verifyEntityboxDisplay)(display, this.identity.scope, this.docker);
|
|
123
|
+
let state = await (0, entitybox_application_boundary_1.inspectEntityboxApplication)(app, this.identity.scope, this.docker);
|
|
124
|
+
if (state === 'running')
|
|
125
|
+
throw fail();
|
|
126
|
+
if (executor)
|
|
127
|
+
await this.retire(executor);
|
|
128
|
+
state = await (0, entitybox_application_boundary_1.inspectEntityboxApplication)(app, this.identity.scope, this.docker);
|
|
129
|
+
if (state === 'running')
|
|
130
|
+
throw fail();
|
|
131
|
+
const final = await this.call('complete', { p_recovery_id: this.id, p_recovery_nonce: this.nonce, p_generation: claimed.generation, p_proof: { guardSha256: evidence.sha256, applicationState: state, executorRemoved: !!executor } });
|
|
132
|
+
const status = this.ended(final);
|
|
133
|
+
if (!status)
|
|
134
|
+
throw fail();
|
|
135
|
+
return status;
|
|
136
|
+
}
|
|
137
|
+
async retire(resource) {
|
|
138
|
+
const list = async () => { const value = (await this.docker(['container', 'ls', '--all', '--no-trunc', '--filter', 'id=' + resource.containerId, '--format', '{{.ID}}'])).trim(); if (value !== '' && value !== resource.containerId)
|
|
139
|
+
throw fail(); return value; };
|
|
140
|
+
if (await list() === '')
|
|
141
|
+
return;
|
|
142
|
+
const rows = JSON.parse(await this.docker(['container', 'inspect', resource.containerId]));
|
|
143
|
+
if (!Array.isArray(rows) || rows.length !== 1)
|
|
144
|
+
throw fail();
|
|
145
|
+
const c = rows[0], labels = c?.Config?.Labels;
|
|
146
|
+
if (c?.Id !== resource.containerId || c.Image !== resource.imageId || labels?.['ai.add.entitybox.execution'] !== this.identity.attemptId || labels?.['ai.add.entitybox.execution.request'] !== this.identity.requestId || labels?.['ai.add.entitybox.execution.watchdog'] !== resource.watchdogSha256
|
|
147
|
+
|| c.HostConfig?.RestartPolicy?.Name !== 'no' || c.State?.Running !== false || c.State.Pid !== 0 || c.State.Paused !== false || c.State.Restarting !== false || !['exited', 'dead', 'created'].includes(c.State.Status))
|
|
148
|
+
throw fail();
|
|
149
|
+
// Join the actual CLI lifecycle. No force and no mutation deadline. Even a
|
|
150
|
+
// late reply targets only this immutable, never-reused old executor ID.
|
|
151
|
+
await this.docker(['container', 'rm', resource.containerId]);
|
|
152
|
+
if (await list() !== '')
|
|
153
|
+
throw fail();
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
exports.EntityboxControllerRecovery = EntityboxControllerRecovery;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { EntityboxExecutionLease } from './entitybox-execution-lease';
|
|
2
|
+
import type { EntityboxExecutionContainer } from './entitybox-execution-container';
|
|
3
|
+
import type { EntityboxDesktopActionOwner } from './entitybox-mcp-broker';
|
|
4
|
+
import type { EntityboxMcpScope } from './entitybox-mcp-contract';
|
|
5
|
+
/** Host-only bridge for the actual native MCP. The isolated model has neither
|
|
6
|
+
* network access to this endpoint nor its bearer token. Native entity access
|
|
7
|
+
* checks remain in the MCP before every dispatch. */
|
|
8
|
+
export declare class EntityboxDesktopActionServer implements EntityboxDesktopActionOwner {
|
|
9
|
+
private readonly lease;
|
|
10
|
+
private readonly container;
|
|
11
|
+
readonly scope: EntityboxMcpScope;
|
|
12
|
+
private readonly server;
|
|
13
|
+
private readonly token;
|
|
14
|
+
private configuration?;
|
|
15
|
+
private readonly seen;
|
|
16
|
+
private readonly pending;
|
|
17
|
+
private stopping?;
|
|
18
|
+
private closing;
|
|
19
|
+
private constructor();
|
|
20
|
+
static start(lease: EntityboxExecutionLease, container: EntityboxExecutionContainer): Promise<EntityboxDesktopActionServer>;
|
|
21
|
+
get transport(): {
|
|
22
|
+
configuration: string;
|
|
23
|
+
token: string;
|
|
24
|
+
capability: {
|
|
25
|
+
version: number;
|
|
26
|
+
requestId: string;
|
|
27
|
+
attemptId: string;
|
|
28
|
+
scope: EntityboxMcpScope;
|
|
29
|
+
};
|
|
30
|
+
};
|
|
31
|
+
assertActive(): Promise<void>;
|
|
32
|
+
private handle;
|
|
33
|
+
stopAndVerify(): Promise<void>;
|
|
34
|
+
}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.EntityboxDesktopActionServer = void 0;
|
|
37
|
+
const http = __importStar(require("http"));
|
|
38
|
+
const crypto_1 = require("crypto");
|
|
39
|
+
const entitybox_execution_lease_1 = require("./entitybox-execution-lease");
|
|
40
|
+
/** Host-only bridge for the actual native MCP. The isolated model has neither
|
|
41
|
+
* network access to this endpoint nor its bearer token. Native entity access
|
|
42
|
+
* checks remain in the MCP before every dispatch. */
|
|
43
|
+
class EntityboxDesktopActionServer {
|
|
44
|
+
lease;
|
|
45
|
+
container;
|
|
46
|
+
scope;
|
|
47
|
+
server;
|
|
48
|
+
token = (0, crypto_1.randomBytes)(32).toString('hex');
|
|
49
|
+
configuration;
|
|
50
|
+
seen = new Set();
|
|
51
|
+
pending = new Set();
|
|
52
|
+
stopping;
|
|
53
|
+
closing = false;
|
|
54
|
+
constructor(lease, container) {
|
|
55
|
+
this.lease = lease;
|
|
56
|
+
this.container = container;
|
|
57
|
+
this.scope = lease.identity.scope;
|
|
58
|
+
if (!container.hasDedicatedDisplay || container.executionIdentity.requestId !== lease.identity.requestId
|
|
59
|
+
|| container.executionIdentity.attemptId !== lease.identity.attemptId)
|
|
60
|
+
throw new entitybox_execution_lease_1.EntityboxExecutionError('Contained desktop binding required');
|
|
61
|
+
this.server = http.createServer((req, res) => {
|
|
62
|
+
const done = this.handle(req, res).finally(() => this.pending.delete(done));
|
|
63
|
+
this.pending.add(done);
|
|
64
|
+
});
|
|
65
|
+
this.server.requestTimeout = 15000;
|
|
66
|
+
this.server.headersTimeout = 10000;
|
|
67
|
+
this.server.keepAliveTimeout = 1000;
|
|
68
|
+
this.server.maxRequestsPerSocket = 1;
|
|
69
|
+
this.server.on('error', () => lease.fence());
|
|
70
|
+
lease.signal.addEventListener('abort', () => { void this.stopAndVerify().catch(() => { }); }, { once: true });
|
|
71
|
+
}
|
|
72
|
+
static async start(lease, container) {
|
|
73
|
+
const bridge = new EntityboxDesktopActionServer(lease, container);
|
|
74
|
+
try {
|
|
75
|
+
await bridge.assertActive();
|
|
76
|
+
await new Promise((resolve, reject) => { bridge.server.once('error', reject); bridge.server.listen(0, '127.0.0.1', () => { bridge.server.removeListener('error', reject); resolve(); }); });
|
|
77
|
+
const address = bridge.server.address();
|
|
78
|
+
if (!address || typeof address === 'string')
|
|
79
|
+
throw new Error();
|
|
80
|
+
bridge.configuration = JSON.stringify({ version: 1, endpoint: 'http://127.0.0.1:' + address.port + '/entitybox/action', token: bridge.token, identity: lease.identity });
|
|
81
|
+
await bridge.assertActive();
|
|
82
|
+
return bridge;
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
lease.fence();
|
|
86
|
+
await bridge.stopAndVerify().catch(() => { });
|
|
87
|
+
throw new entitybox_execution_lease_1.EntityboxExecutionError('Contained desktop bridge could not start');
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
get transport() {
|
|
91
|
+
if (!this.configuration)
|
|
92
|
+
throw new entitybox_execution_lease_1.EntityboxExecutionError('Contained desktop bridge unavailable');
|
|
93
|
+
return { configuration: this.configuration, token: this.token, capability: { version: 1, requestId: this.lease.identity.requestId, attemptId: this.lease.identity.attemptId, scope: this.scope } };
|
|
94
|
+
}
|
|
95
|
+
async assertActive() {
|
|
96
|
+
try {
|
|
97
|
+
if (this.closing)
|
|
98
|
+
throw new Error();
|
|
99
|
+
await this.container.assertActive();
|
|
100
|
+
this.lease.assertActive();
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
this.lease.fence();
|
|
104
|
+
throw new entitybox_execution_lease_1.EntityboxExecutionError('Contained desktop authority ended');
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
async handle(req, res) {
|
|
108
|
+
const auth = Buffer.from(req.headers.authorization ?? ''), expected = Buffer.from('Bearer ' + this.token);
|
|
109
|
+
if (req.method !== 'POST' || req.url !== '/entitybox/action' || req.headers.origin !== undefined
|
|
110
|
+
|| auth.length !== expected.length || !(0, crypto_1.timingSafeEqual)(auth, expected)) {
|
|
111
|
+
res.writeHead(403);
|
|
112
|
+
res.end();
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
const abort = new AbortController();
|
|
116
|
+
const lost = () => { if (!res.writableFinished) {
|
|
117
|
+
abort.abort();
|
|
118
|
+
this.lease.fence();
|
|
119
|
+
} };
|
|
120
|
+
req.once('aborted', lost);
|
|
121
|
+
res.once('close', lost);
|
|
122
|
+
try {
|
|
123
|
+
await this.assertActive();
|
|
124
|
+
let input = '';
|
|
125
|
+
req.setEncoding('utf8');
|
|
126
|
+
for await (const part of req) {
|
|
127
|
+
input += part;
|
|
128
|
+
if (Buffer.byteLength(input) > 512 * 1024)
|
|
129
|
+
throw new Error();
|
|
130
|
+
}
|
|
131
|
+
const p = JSON.parse(input), i = p?.identity;
|
|
132
|
+
if (p?.version !== 1 || typeof p.actionId !== 'string' || !/^[0-9a-f]{8}(-[0-9a-f]{4}){3}-[0-9a-f]{12}$/.test(p.actionId)
|
|
133
|
+
|| i?.requestId !== this.lease.identity.requestId || i?.attemptId !== this.lease.identity.attemptId || i?.scope?.version !== 1
|
|
134
|
+
|| !['runId', 'desktopId', 'runtimeId'].every(k => i.scope[k] === this.scope[k])
|
|
135
|
+
|| p.desktopId !== this.scope.desktopId || p.runtimeId !== this.scope.runtimeId || p.display !== ':1'
|
|
136
|
+
|| typeof p.input !== 'string' || p.input.length % 4 !== 0 || !/^[A-Za-z0-9+/]*={0,2}$/.test(p.input)
|
|
137
|
+
|| this.seen.has(p.actionId) || this.seen.size >= 1024)
|
|
138
|
+
throw new Error();
|
|
139
|
+
this.seen.add(p.actionId);
|
|
140
|
+
const result = await this.container.executeAction({ argv: p.argv, input: Buffer.from(p.input, 'base64'), timeoutMs: p.timeoutMs, display: ':1', signal: abort.signal });
|
|
141
|
+
await this.assertActive();
|
|
142
|
+
res.writeHead(200, { 'content-type': 'application/json', 'cache-control': 'no-store' });
|
|
143
|
+
res.end(JSON.stringify({ version: 1, actionId: p.actionId, stdout: result.stdout.toString('base64'), stderr: result.stderr.toString('base64'), code: result.code }));
|
|
144
|
+
}
|
|
145
|
+
catch {
|
|
146
|
+
this.lease.fence();
|
|
147
|
+
if (!res.headersSent)
|
|
148
|
+
res.writeHead(409);
|
|
149
|
+
res.end();
|
|
150
|
+
}
|
|
151
|
+
finally {
|
|
152
|
+
req.removeListener('aborted', lost);
|
|
153
|
+
res.removeListener('close', lost);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
async stopAndVerify() {
|
|
157
|
+
if (this.stopping)
|
|
158
|
+
return this.stopping;
|
|
159
|
+
this.closing = true;
|
|
160
|
+
this.stopping = Promise.resolve().then(async () => {
|
|
161
|
+
const closed = new Promise(resolve => { this.server.close(() => resolve()); this.server.closeAllConnections(); });
|
|
162
|
+
await this.container.stopAndVerify();
|
|
163
|
+
await Promise.all([...this.pending]);
|
|
164
|
+
await closed;
|
|
165
|
+
});
|
|
166
|
+
this.lease.fence();
|
|
167
|
+
try {
|
|
168
|
+
await this.stopping;
|
|
169
|
+
}
|
|
170
|
+
catch (error) {
|
|
171
|
+
this.stopping = undefined;
|
|
172
|
+
throw error;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
exports.EntityboxDesktopActionServer = EntityboxDesktopActionServer;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { DesktopRow } from './desktop/spec';
|
|
2
|
+
export type EntityboxAdmission = {
|
|
3
|
+
allowed: true;
|
|
4
|
+
} | {
|
|
5
|
+
allowed: false;
|
|
6
|
+
reason: string;
|
|
7
|
+
};
|
|
8
|
+
export interface EntityboxDesktopBudget {
|
|
9
|
+
cpus: number;
|
|
10
|
+
memoryMb: number;
|
|
11
|
+
diskGb: number;
|
|
12
|
+
}
|
|
13
|
+
export interface EntityboxDesktopObservation {
|
|
14
|
+
row: DesktopRow;
|
|
15
|
+
exists: boolean;
|
|
16
|
+
running: boolean;
|
|
17
|
+
}
|
|
18
|
+
type Policy = (rows: DesktopRow[], id: string) => Promise<EntityboxAdmission>;
|
|
19
|
+
/** Opt-in host gate. With no EntityBox worker, existing native callers keep
|
|
20
|
+
* their original behavior and do not gain an extra RPC or engine inspection. */
|
|
21
|
+
export declare function entityboxAdmissionEnabled(): boolean;
|
|
22
|
+
export declare function entityboxDesktopAdmission(rows: DesktopRow[], id: string): Promise<EntityboxAdmission | undefined>;
|
|
23
|
+
export declare function entityboxWithDesktopStart<T>(action: () => Promise<T>): Promise<T>;
|
|
24
|
+
export declare function installEntityboxDesktopAdmission(check: Policy): {
|
|
25
|
+
close: () => Promise<void>;
|
|
26
|
+
};
|
|
27
|
+
export declare function validateEntityboxDesktopBudget(b: EntityboxDesktopBudget): boolean;
|
|
28
|
+
/** Reservation accounting for AddAI desktops, not an OS quota. A stopped
|
|
29
|
+
* computer retains disk; a claimed/uncertain dedicated computer retains every
|
|
30
|
+
* reservation until explicit lifecycle cleanup. Unclaimed new rows use none. */
|
|
31
|
+
export declare function entityboxDesktopBudget(observations: EntityboxDesktopObservation[], target: string, maxSlots: number, budget: EntityboxDesktopBudget): EntityboxAdmission;
|
|
32
|
+
export {};
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.entityboxAdmissionEnabled = entityboxAdmissionEnabled;
|
|
4
|
+
exports.entityboxDesktopAdmission = entityboxDesktopAdmission;
|
|
5
|
+
exports.entityboxWithDesktopStart = entityboxWithDesktopStart;
|
|
6
|
+
exports.installEntityboxDesktopAdmission = installEntityboxDesktopAdmission;
|
|
7
|
+
exports.validateEntityboxDesktopBudget = validateEntityboxDesktopBudget;
|
|
8
|
+
exports.entityboxDesktopBudget = entityboxDesktopBudget;
|
|
9
|
+
const unavailable = () => ({ allowed: false, reason: 'Desktop capacity could not be verified. Check the runtime and try again.' });
|
|
10
|
+
let installed;
|
|
11
|
+
/** Opt-in host gate. With no EntityBox worker, existing native callers keep
|
|
12
|
+
* their original behavior and do not gain an extra RPC or engine inspection. */
|
|
13
|
+
function entityboxAdmissionEnabled() { return installed !== undefined; }
|
|
14
|
+
async function entityboxDesktopAdmission(rows, id) {
|
|
15
|
+
const owner = installed;
|
|
16
|
+
if (!owner)
|
|
17
|
+
return undefined;
|
|
18
|
+
if (owner.closing)
|
|
19
|
+
return unavailable();
|
|
20
|
+
try {
|
|
21
|
+
return await owner.check(rows, id);
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return unavailable();
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
function entityboxWithDesktopStart(action) {
|
|
28
|
+
const owner = installed;
|
|
29
|
+
if (!owner)
|
|
30
|
+
return action();
|
|
31
|
+
if (owner.closing)
|
|
32
|
+
return Promise.reject(new Error('Desktop admission is stopping. Try again when the runtime is ready.'));
|
|
33
|
+
const result = owner.tail.then(action);
|
|
34
|
+
owner.tail = result.then(() => { }, () => { });
|
|
35
|
+
return result;
|
|
36
|
+
}
|
|
37
|
+
function installEntityboxDesktopAdmission(check) {
|
|
38
|
+
if (installed)
|
|
39
|
+
throw new Error('EntityBox desktop admission is already configured');
|
|
40
|
+
const owner = { check, tail: Promise.resolve(), closing: false };
|
|
41
|
+
installed = owner;
|
|
42
|
+
return { async close() { owner.closing = true; await owner.tail; if (installed === owner)
|
|
43
|
+
installed = undefined; } };
|
|
44
|
+
}
|
|
45
|
+
function validateEntityboxDesktopBudget(b) {
|
|
46
|
+
return !!b && Number.isFinite(b.cpus) && b.cpus >= 2 && b.cpus <= 128 && Number.isInteger(b.memoryMb) && b.memoryMb >= 2048 && b.memoryMb <= 262144 && Number.isInteger(b.diskGb) && b.diskGb >= 20 && b.diskGb <= 16384;
|
|
47
|
+
}
|
|
48
|
+
/** Reservation accounting for AddAI desktops, not an OS quota. A stopped
|
|
49
|
+
* computer retains disk; a claimed/uncertain dedicated computer retains every
|
|
50
|
+
* reservation until explicit lifecycle cleanup. Unclaimed new rows use none. */
|
|
51
|
+
function entityboxDesktopBudget(observations, target, maxSlots, budget) {
|
|
52
|
+
if (!validateEntityboxDesktopBudget(budget) || !Number.isInteger(maxSlots) || maxSlots < 1 || maxSlots > 16)
|
|
53
|
+
return unavailable();
|
|
54
|
+
const found = observations.filter(o => o.row.id === target);
|
|
55
|
+
if (found.length !== 1 || new Set(observations.map(o => o.row.id)).size !== observations.length)
|
|
56
|
+
return unavailable();
|
|
57
|
+
let slots = 0, cpus = 0, memory = 0, disk = 0;
|
|
58
|
+
for (const { row, exists, running } of observations) {
|
|
59
|
+
const selected = row.id === target, managed = row.entitybox_managed === true;
|
|
60
|
+
if (!['pending', 'creating', 'starting', 'running', 'stopped', 'failed', 'deleting', 'queued'].includes(row.status) || typeof exists !== 'boolean' || typeof running !== 'boolean' || running && !exists)
|
|
61
|
+
return unavailable();
|
|
62
|
+
const reserved = selected || (managed ? row.status !== 'pending' : running || ['creating', 'starting', 'deleting'].includes(row.status));
|
|
63
|
+
const retainsDisk = selected || exists || row.status !== 'pending';
|
|
64
|
+
if (reserved && (!Number.isFinite(row.cpus) || row.cpus <= 0 || !Number.isFinite(row.memory_mb) || row.memory_mb <= 0) || retainsDisk && (!Number.isFinite(row.disk_gb) || row.disk_gb <= 0))
|
|
65
|
+
return unavailable();
|
|
66
|
+
if (reserved) {
|
|
67
|
+
slots++;
|
|
68
|
+
cpus += row.cpus;
|
|
69
|
+
memory += row.memory_mb;
|
|
70
|
+
}
|
|
71
|
+
if (retainsDisk)
|
|
72
|
+
disk += row.disk_gb;
|
|
73
|
+
}
|
|
74
|
+
if (slots > maxSlots)
|
|
75
|
+
return { allowed: false, reason: 'This runtime has no free desktop slot. Waiting for capacity.' };
|
|
76
|
+
if (cpus > budget.cpus || memory > budget.memoryMb || disk > budget.diskGb)
|
|
77
|
+
return { allowed: false, reason: 'This runtime’s desktop resource budget is fully reserved. Waiting for capacity.' };
|
|
78
|
+
return { allowed: true };
|
|
79
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { EntityboxMcpScope } from './entitybox-mcp-contract';
|
|
2
|
+
/** Trusted descriptor for NEW dedicated native capacity. Existing desktops do
|
|
3
|
+
* not have these labels and cannot be silently adopted or recreated. */
|
|
4
|
+
export interface EntityboxDisplayBinding {
|
|
5
|
+
capacityId: string;
|
|
6
|
+
desktopId: string;
|
|
7
|
+
runtimeId: string;
|
|
8
|
+
containerId: string;
|
|
9
|
+
imageId: string;
|
|
10
|
+
startedAt: string;
|
|
11
|
+
}
|
|
12
|
+
export declare function entityboxDisplayVolume(binding: EntityboxDisplayBinding): string;
|
|
13
|
+
export declare function verifyEntityboxDisplay(binding: EntityboxDisplayBinding, scope: EntityboxMcpScope, docker: (args: string[]) => Promise<string>): Promise<void>;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.entityboxDisplayVolume = entityboxDisplayVolume;
|
|
4
|
+
exports.verifyEntityboxDisplay = verifyEntityboxDisplay;
|
|
5
|
+
const entitybox_execution_lease_1 = require("./entitybox-execution-lease");
|
|
6
|
+
function entityboxDisplayVolume(binding) {
|
|
7
|
+
if (!/^[0-9a-f]{8}(-[0-9a-f]{4}){3}-[0-9a-f]{12}$/.test(binding?.capacityId))
|
|
8
|
+
throw new entitybox_execution_lease_1.EntityboxExecutionError('Invalid dedicated display');
|
|
9
|
+
return 'entitybox-display-' + binding.capacityId;
|
|
10
|
+
}
|
|
11
|
+
async function verifyEntityboxDisplay(binding, scope, docker) {
|
|
12
|
+
const volume = entityboxDisplayVolume(binding);
|
|
13
|
+
if (binding.desktopId !== scope.desktopId || binding.runtimeId !== scope.runtimeId
|
|
14
|
+
|| !/^[0-9a-f]{64}$/.test(binding.containerId) || !/^sha256:[0-9a-f]{64}$/.test(binding.imageId)
|
|
15
|
+
|| typeof binding.startedAt !== 'string' || binding.startedAt.length > 80 || !Number.isFinite(Date.parse(binding.startedAt)))
|
|
16
|
+
throw new entitybox_execution_lease_1.EntityboxExecutionError('Invalid dedicated display');
|
|
17
|
+
const [containerText, volumeText] = await Promise.all([docker(['container', 'inspect', binding.containerId]), docker(['volume', 'inspect', volume])]);
|
|
18
|
+
const c = JSON.parse(containerText)[0], v = JSON.parse(volumeText)[0];
|
|
19
|
+
const labels = (value) => value?.['ai.add.entitybox.display.version'] === '1'
|
|
20
|
+
&& value['ai.add.entitybox.display.capacity'] === binding.capacityId
|
|
21
|
+
&& value['ai.add.entitybox.display.desktop'] === binding.desktopId
|
|
22
|
+
&& value['ai.add.entitybox.display.runtime'] === binding.runtimeId;
|
|
23
|
+
const socket = c?.Mounts?.filter((m) => m.Destination === '/tmp/.X11-unix');
|
|
24
|
+
if (c?.Id !== binding.containerId || c.Image !== binding.imageId || !labels(c.Config?.Labels)
|
|
25
|
+
|| !c.State?.Running || c.State.Pid <= 0 || c.State.StartedAt !== binding.startedAt
|
|
26
|
+
|| c.HostConfig?.Privileged || c.HostConfig?.Binds?.length || !['', 'private'].includes(c.HostConfig?.PidMode ?? '') || c.HostConfig?.NetworkMode === 'host'
|
|
27
|
+
|| !Array.isArray(c.Mounts) || c.Mounts.some((m) => m.Type !== 'tmpfs' && m.Destination !== '/tmp/.X11-unix')
|
|
28
|
+
|| socket?.length !== 1 || socket[0].Type !== 'volume' || socket[0].Name !== volume || socket[0].RW !== true
|
|
29
|
+
|| v?.Name !== volume || v.Driver !== 'local' || Object.keys(v.Options ?? {}).length || !labels(v.Labels))
|
|
30
|
+
throw new entitybox_execution_lease_1.EntityboxExecutionError('Dedicated display ownership changed');
|
|
31
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { type EntityboxExecutionLease } from './entitybox-execution-lease';
|
|
2
|
+
import { type EntityboxDisplayBinding } from './entitybox-display-binding';
|
|
3
|
+
import type { EntityboxBrokerEmit } from './entitybox-provider-broker';
|
|
4
|
+
export interface EntityboxActionOptions {
|
|
5
|
+
argv: readonly string[];
|
|
6
|
+
input?: Buffer;
|
|
7
|
+
timeoutMs?: number;
|
|
8
|
+
signal?: AbortSignal;
|
|
9
|
+
display?: ':1';
|
|
10
|
+
}
|
|
11
|
+
export interface EntityboxActionResult {
|
|
12
|
+
stdout: Buffer;
|
|
13
|
+
stderr: Buffer;
|
|
14
|
+
code: number;
|
|
15
|
+
}
|
|
16
|
+
export interface EntityboxExecutionResource {
|
|
17
|
+
containerId: string;
|
|
18
|
+
imageId: string;
|
|
19
|
+
watchdogSha256: string;
|
|
20
|
+
}
|
|
21
|
+
interface Options {
|
|
22
|
+
/** Durable public identity must settle before Docker start is issued. */
|
|
23
|
+
onCreated?: (resource: Readonly<EntityboxExecutionResource>) => Promise<void>;
|
|
24
|
+
imageId: string;
|
|
25
|
+
dockerContext?: string;
|
|
26
|
+
/** Trusted capacity setting. Small synthetic fixtures explicitly use 256. */
|
|
27
|
+
memoryMiB?: number;
|
|
28
|
+
/** Optional read-only socket of separately owned, dedicated native capacity. */
|
|
29
|
+
display?: EntityboxDisplayBinding;
|
|
30
|
+
/** Trusted adapter configuration, NEVER command text from a task or model. */
|
|
31
|
+
command: string[];
|
|
32
|
+
/** Public task data only. Credentialed tools/providers belong to a broker. */
|
|
33
|
+
task: unknown;
|
|
34
|
+
onOutput: (data: Buffer) => void;
|
|
35
|
+
onBroker?: (request: unknown, signal: AbortSignal, emit: EntityboxBrokerEmit) => Promise<void>;
|
|
36
|
+
}
|
|
37
|
+
/** Owns a new container by its immutable ID. It never enters, mounts, changes
|
|
38
|
+
* or stops a native desktop. External tool actions must acquire their own
|
|
39
|
+
* verified stop boundary before this can serve as a complete task executor. */
|
|
40
|
+
export declare class EntityboxExecutionContainer {
|
|
41
|
+
private readonly lease;
|
|
42
|
+
private readonly options;
|
|
43
|
+
private readonly proc;
|
|
44
|
+
private readonly docker;
|
|
45
|
+
private readonly watchdogDigest;
|
|
46
|
+
private readonly actionSource;
|
|
47
|
+
readonly done: Promise<number>;
|
|
48
|
+
readonly id: string;
|
|
49
|
+
failureCode: 'entitybox_broker_connection_failed' | undefined;
|
|
50
|
+
private stopped?;
|
|
51
|
+
private output;
|
|
52
|
+
private modelExit?;
|
|
53
|
+
private closed;
|
|
54
|
+
private stopping;
|
|
55
|
+
private ready;
|
|
56
|
+
private readonly started;
|
|
57
|
+
private startedResolve;
|
|
58
|
+
private startedReject;
|
|
59
|
+
private readonly actions;
|
|
60
|
+
private readonly requests;
|
|
61
|
+
private constructor();
|
|
62
|
+
static start(lease: EntityboxExecutionLease, options: Options): Promise<EntityboxExecutionContainer>;
|
|
63
|
+
private consume;
|
|
64
|
+
private broker;
|
|
65
|
+
private grant;
|
|
66
|
+
get scope(): import("./entitybox-mcp-contract").EntityboxMcpScope;
|
|
67
|
+
whenStarted(): Promise<void>;
|
|
68
|
+
get executionIdentity(): Readonly<import("./entitybox-execution-lease").EntityboxExecutionIdentity>;
|
|
69
|
+
get hasDedicatedDisplay(): boolean;
|
|
70
|
+
assertActive(): Promise<void>;
|
|
71
|
+
private inspectOwned;
|
|
72
|
+
/** Commands run only in this task's PID namespace. No native desktop, host
|
|
73
|
+
* execution or remote-queue fallback is permitted here. A lost exec transport
|
|
74
|
+
* fences the entire task: closing a Docker client is not proof of inner stop. */
|
|
75
|
+
executeAction(options: EntityboxActionOptions): Promise<EntityboxActionResult>;
|
|
76
|
+
stopAndVerify(): Promise<void>;
|
|
77
|
+
private stopOwned;
|
|
78
|
+
/** Keep the stopped resource until the caller has recorded its stop receipt.
|
|
79
|
+
* Missing/unverifiable resources cannot themselves prove process shutdown. */
|
|
80
|
+
removeStopped(): Promise<void>;
|
|
81
|
+
}
|
|
82
|
+
export {};
|