@opengeni/runtime 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunk-2PO56VAL.js +3478 -0
- package/dist/chunk-2PO56VAL.js.map +1 -0
- package/dist/index.d.ts +912 -0
- package/dist/index.js +3663 -0
- package/dist/index.js.map +1 -0
- package/dist/sandbox/index.d.ts +1738 -0
- package/dist/sandbox/index.js +187 -0
- package/dist/sandbox/index.js.map +1 -0
- package/package.json +49 -0
- package/src/bundled_hashicorp_terraform_skills/LICENSE +373 -0
- package/src/bundled_hashicorp_terraform_skills/README.md +18 -0
- package/src/bundled_hashicorp_terraform_skills/UPSTREAM_GIT_SHA +1 -0
- package/src/bundled_hashicorp_terraform_skills/azure-verified-modules/SKILL.md +613 -0
- package/src/bundled_hashicorp_terraform_skills/checkov/SKILL.md +43 -0
- package/src/bundled_hashicorp_terraform_skills/refactor-module/SKILL.md +538 -0
- package/src/bundled_hashicorp_terraform_skills/social-media-marketing/SKILL.md +35 -0
- package/src/bundled_hashicorp_terraform_skills/terraform-search-import/SKILL.md +372 -0
- package/src/bundled_hashicorp_terraform_skills/terraform-search-import/references/MANUAL-IMPORT.md +113 -0
- package/src/bundled_hashicorp_terraform_skills/terraform-search-import/scripts/list_resources.sh +38 -0
- package/src/bundled_hashicorp_terraform_skills/terraform-stacks/SKILL.md +480 -0
- package/src/bundled_hashicorp_terraform_skills/terraform-stacks/references/api-monitoring.md +543 -0
- package/src/bundled_hashicorp_terraform_skills/terraform-stacks/references/component-blocks.md +476 -0
- package/src/bundled_hashicorp_terraform_skills/terraform-stacks/references/deployment-blocks.md +391 -0
- package/src/bundled_hashicorp_terraform_skills/terraform-stacks/references/examples.md +1529 -0
- package/src/bundled_hashicorp_terraform_skills/terraform-stacks/references/linked-stacks.md +187 -0
- package/src/bundled_hashicorp_terraform_skills/terraform-stacks/references/troubleshooting.md +671 -0
- package/src/bundled_hashicorp_terraform_skills/terraform-style-guide/SKILL.md +353 -0
- package/src/bundled_hashicorp_terraform_skills/terraform-test/SKILL.md +451 -0
- package/src/bundled_hashicorp_terraform_skills/terraform-test/references/CI_CD.md +80 -0
- package/src/bundled_hashicorp_terraform_skills/terraform-test/references/EXAMPLES.md +314 -0
- package/src/bundled_hashicorp_terraform_skills/terraform-test/references/MOCK_PROVIDERS.md +171 -0
- package/src/codex-tool-search.ts +267 -0
- package/src/context-compaction.ts +538 -0
- package/src/history-sanitizer.ts +719 -0
- package/src/index.ts +3299 -0
- package/src/sandbox/capabilities.ts +69 -0
- package/src/sandbox/channel-a.ts +1031 -0
- package/src/sandbox/display-stack.ts +231 -0
- package/src/sandbox/errors.ts +34 -0
- package/src/sandbox/index.ts +832 -0
- package/src/sandbox/providers/blaxel.ts +35 -0
- package/src/sandbox/providers/cloudflare.ts +24 -0
- package/src/sandbox/providers/daytona.ts +34 -0
- package/src/sandbox/providers/docker.ts +17 -0
- package/src/sandbox/providers/e2b.ts +36 -0
- package/src/sandbox/providers/index.ts +107 -0
- package/src/sandbox/providers/local.ts +13 -0
- package/src/sandbox/providers/modal.ts +55 -0
- package/src/sandbox/providers/none.ts +13 -0
- package/src/sandbox/providers/runloop.ts +32 -0
- package/src/sandbox/providers/selfhosted.ts +96 -0
- package/src/sandbox/providers/types.ts +38 -0
- package/src/sandbox/providers/vercel.ts +29 -0
- package/src/sandbox/recording.ts +286 -0
- package/src/sandbox/routing/backend-resolver.ts +189 -0
- package/src/sandbox/routing/routing-session.ts +455 -0
- package/src/sandbox/select.ts +371 -0
- package/src/sandbox/selfhosted/capabilities.ts +255 -0
- package/src/sandbox/selfhosted/control-rpc.ts +351 -0
- package/src/sandbox/selfhosted/session.ts +930 -0
- package/src/sandbox/selfhosted/testing.ts +230 -0
- package/src/sandbox/stream-port.ts +185 -0
- package/src/sandbox/stream-token.ts +90 -0
- package/src/sandbox/terminal-server.ts +203 -0
- package/src/sandbox-computer.ts +835 -0
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
// @opengeni/runtime/sandbox — the desktop display-stack launcher (P4.1).
|
|
2
|
+
//
|
|
3
|
+
// The agent-loop-free home for `ensureDisplayStack`: the exec-launched,
|
|
4
|
+
// flock-idempotent procedure that brings up the Channel-B pixel stack
|
|
5
|
+
// (Xvfb :0 -> XFCE -> x11vnc -> websockify:6080 -> noVNC) on a live,
|
|
6
|
+
// externally-owned box. It is driven over the box's `exec`/`execCommand` channel
|
|
7
|
+
// (NOT a container CMD) so it re-establishes after a snapshot rollover / box
|
|
8
|
+
// re-election, and it is safe to call from the API on a viewer op OR from the
|
|
9
|
+
// agent turn — a second concurrent call serializes on the in-box flock and
|
|
10
|
+
// no-ops when the stack is already up.
|
|
11
|
+
//
|
|
12
|
+
// It lives under @opengeni/runtime/sandbox so the API-direct control plane
|
|
13
|
+
// (apps/api) and the worker (apps/worker) both pull it from the same single
|
|
14
|
+
// agent-loop-free leaf.
|
|
15
|
+
//
|
|
16
|
+
// Productionized from the PROVEN spike (spikes/desktop-stack PASSED locally:
|
|
17
|
+
// noVNC 200, WS 101 + RFB banner, OCR'd a secret off the framebuffer) + the
|
|
18
|
+
// gVisor harness (V2 PASSED live on Modal: XTEST input read-back under runsc).
|
|
19
|
+
|
|
20
|
+
import { DESKTOP_STREAM_PORT } from "@opengeni/contracts";
|
|
21
|
+
|
|
22
|
+
// Re-export under the canonical name the module spec uses (STREAM_PORT) while
|
|
23
|
+
// keeping DESKTOP_STREAM_PORT as the single source of truth (contracts).
|
|
24
|
+
export { DESKTOP_STREAM_PORT };
|
|
25
|
+
export const STREAM_PORT = DESKTOP_STREAM_PORT;
|
|
26
|
+
|
|
27
|
+
// The whole-stack launch is bounded by the readiness gates inside the script
|
|
28
|
+
// (four loops of 50 * 0.1s = ~5s each, ~20s worst case) PLUS first-boot XFCE/dbus
|
|
29
|
+
// + font-cache warm-up on a cold gVisor box. 60s gives headroom over the spike's
|
|
30
|
+
// observed ~5-10s warm path without masking a genuine wedge.
|
|
31
|
+
export const DISPLAY_STACK_TIMEOUT_MS = 60_000;
|
|
32
|
+
|
|
33
|
+
/** Desktop geometry for the framebuffer. v1 has no live RANDR: a resolution
|
|
34
|
+
* change is a full down -> up restart (a separate op). */
|
|
35
|
+
export type DesktopGeometry = {
|
|
36
|
+
width: number; // default 1280
|
|
37
|
+
height: number; // default 800
|
|
38
|
+
dpi: number; // default 96
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export const DEFAULT_DESKTOP_GEOMETRY: DesktopGeometry = { width: 1280, height: 800, dpi: 96 };
|
|
42
|
+
|
|
43
|
+
/** Thrown when a stage of the launch script failed. exitCode 11/12/13 map to
|
|
44
|
+
* Xvfb / x11vnc / websockify respectively (the stage that died). Degradation is
|
|
45
|
+
* surfaced as a value to viewers by the caller; this error is for diagnostics. */
|
|
46
|
+
export class DisplayStackError extends Error {
|
|
47
|
+
readonly exitCode: number;
|
|
48
|
+
readonly stage: "xvfb" | "x11vnc" | "websockify" | "unknown";
|
|
49
|
+
|
|
50
|
+
constructor(exitCode: number, output: string) {
|
|
51
|
+
const stage =
|
|
52
|
+
exitCode === 11 ? "xvfb" : exitCode === 12 ? "x11vnc" : exitCode === 13 ? "websockify" : "unknown";
|
|
53
|
+
super(`desktop display stack failed at stage "${stage}" (exit ${exitCode})${output ? `:\n${output}` : ""}`);
|
|
54
|
+
this.name = "DisplayStackError";
|
|
55
|
+
this.exitCode = exitCode;
|
|
56
|
+
this.stage = stage;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** Thrown when the provider session cannot run commands (a headless-only
|
|
61
|
+
* backend with neither `exec` nor `execCommand`). The desktop tier degrades to
|
|
62
|
+
* Channel-A-only — the caller maps this to `DesktopStream.transport: null`. */
|
|
63
|
+
export class DisplayStackUnsupportedError extends Error {
|
|
64
|
+
constructor(message: string) {
|
|
65
|
+
super(message);
|
|
66
|
+
this.name = "DisplayStackUnsupportedError";
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// The structural slice of a provider session we need: run a command (preferring
|
|
71
|
+
// `exec` for the structured exit code, falling back to `execCommand`).
|
|
72
|
+
type ExecResultLike = {
|
|
73
|
+
output?: string;
|
|
74
|
+
stdout?: string;
|
|
75
|
+
stderr?: string;
|
|
76
|
+
exitCode?: number | null;
|
|
77
|
+
};
|
|
78
|
+
type ExecCapableSession = {
|
|
79
|
+
exec?: (args: { cmd: string; yieldTimeMs?: number; maxOutputTokens?: number }) => Promise<ExecResultLike>;
|
|
80
|
+
execCommand?: (args: { cmd: string; yieldTimeMs?: number; maxOutputTokens?: number }) => Promise<string>;
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
export type EnsureDisplayStackOptions = {
|
|
84
|
+
geometry?: DesktopGeometry;
|
|
85
|
+
/** The exposed stream port; defaults to 6080. */
|
|
86
|
+
port?: number;
|
|
87
|
+
/** Per-exec timeout; defaults to DISPLAY_STACK_TIMEOUT_MS. */
|
|
88
|
+
timeoutMs?: number;
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
export type EnsureDisplayStackResult = {
|
|
92
|
+
/** The exposed port the stack listens on (websockify/noVNC). */
|
|
93
|
+
port: number;
|
|
94
|
+
geometry: DesktopGeometry;
|
|
95
|
+
/** The raw `OPENGENI_DESKTOP_UP …` marker line, for diagnostics. Never
|
|
96
|
+
* surfaced to viewers. */
|
|
97
|
+
marker: string;
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Build the shell command that runs the idempotent up-script under an in-box
|
|
102
|
+
* `flock`. The script is shipped in the image at /usr/local/bin/opengeni-desktop-up
|
|
103
|
+
* (the canonical desktop image); we set the geometry/port env and wrap the call
|
|
104
|
+
* in `flock` so two concurrent ensureDisplayStack callers (the API viewer op +
|
|
105
|
+
* the agent turn, both racing after a rollover) serialize without a double
|
|
106
|
+
* launch. The up-script's own per-stage PID guards make the second call a no-op.
|
|
107
|
+
*
|
|
108
|
+
* Exported (pure, side-effect-free) so the ensureDisplayStack unit test can
|
|
109
|
+
* assert the exact command sequence without a live box.
|
|
110
|
+
*/
|
|
111
|
+
export function buildDisplayStackScript(options: EnsureDisplayStackOptions = {}): string {
|
|
112
|
+
const geometry = options.geometry ?? DEFAULT_DESKTOP_GEOMETRY;
|
|
113
|
+
const port = options.port ?? DESKTOP_STREAM_PORT;
|
|
114
|
+
const env =
|
|
115
|
+
`DESKTOP_W=${geometry.width} DESKTOP_H=${geometry.height} ` +
|
|
116
|
+
`DESKTOP_DPI=${geometry.dpi} STREAM_PORT=${port}`;
|
|
117
|
+
// FAST PRE-CHECK (lock-free) before the outer flock: if the exposed port and
|
|
118
|
+
// x11vnc are ALREADY listening, the stack is up — print the marker and short-
|
|
119
|
+
// circuit, so a no-op caller (the agent turn re-ensuring after a viewer attach
|
|
120
|
+
// already brought the stack up) never serializes behind a lock holder and never
|
|
121
|
+
// burns the 45s flock -w timeout. `nc -z` to the two loopback ports is the cheap
|
|
122
|
+
// (sub-millisecond) "already up?" signal; on a miss we fall through to the
|
|
123
|
+
// flock-wrapped up-script (which ALSO pre-checks under its own lock).
|
|
124
|
+
//
|
|
125
|
+
// flock -w bounds the wait so a wedged holder can't deadlock the caller; the
|
|
126
|
+
// up-script itself ALSO takes the same lock (belt + braces) so this works even
|
|
127
|
+
// against an older image that predates the wrapper.
|
|
128
|
+
return (
|
|
129
|
+
`if nc -z 127.0.0.1 ${port} >/dev/null 2>&1 && nc -z 127.0.0.1 5900 >/dev/null 2>&1; then ` +
|
|
130
|
+
`echo "OPENGENI_DESKTOP_UP port=${port} geometry=${geometry.width}x${geometry.height} dpi=${geometry.dpi} (precheck)"; ` +
|
|
131
|
+
`else ` +
|
|
132
|
+
`mkdir -p /tmp/opengeni-desktop && ` +
|
|
133
|
+
`flock -w 45 /tmp/opengeni-desktop/up.outer.lock ` +
|
|
134
|
+
`env ${env} opengeni-desktop-up; ` +
|
|
135
|
+
`fi`
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function execResultOutput(result: ExecResultLike | string): string {
|
|
140
|
+
if (typeof result === "string") {
|
|
141
|
+
return result;
|
|
142
|
+
}
|
|
143
|
+
return [result.output, result.stderr, result.stdout]
|
|
144
|
+
.filter((v): v is string => typeof v === "string" && v.length > 0)
|
|
145
|
+
.join("\n");
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function execResultExitCode(result: ExecResultLike | string): number | null {
|
|
149
|
+
if (typeof result === "string") {
|
|
150
|
+
return null; // execCommand returns a bare string — no exit code available.
|
|
151
|
+
}
|
|
152
|
+
return typeof result.exitCode === "number" ? result.exitCode : null;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Parse the exit code the up-script signals via its trailing marker. When we ran
|
|
156
|
+
// through `exec` we have the real exitCode; when we only had `execCommand` (a
|
|
157
|
+
// bare string), we infer success from the OPENGENI_DESKTOP_UP marker and infer
|
|
158
|
+
// the failing stage from the stage-failure message the script prints to stderr.
|
|
159
|
+
function inferExitFromOutput(output: string): number {
|
|
160
|
+
if (/OPENGENI_DESKTOP_UP\b/.test(output)) {
|
|
161
|
+
return 0;
|
|
162
|
+
}
|
|
163
|
+
if (/Xvfb failed to come up/.test(output)) {
|
|
164
|
+
return 11;
|
|
165
|
+
}
|
|
166
|
+
if (/x11vnc failed on/.test(output)) {
|
|
167
|
+
return 12;
|
|
168
|
+
}
|
|
169
|
+
if (/websockify failed on/.test(output)) {
|
|
170
|
+
return 13;
|
|
171
|
+
}
|
|
172
|
+
return -1;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Idempotently bring up the desktop display stack on the live box. Safe to call
|
|
177
|
+
* N times (the in-box flock + the up-script's PID guards make a second call a
|
|
178
|
+
* no-op). Resolves with the exposed port + geometry on success; throws
|
|
179
|
+
* `DisplayStackError` on a stage failure and `DisplayStackUnsupportedError` when
|
|
180
|
+
* the session cannot run commands.
|
|
181
|
+
*
|
|
182
|
+
* `session` is the externally-owned provider session (the `established.session`
|
|
183
|
+
* from establishSandboxSessionFromEnvelope, or any SandboxSessionLike). We
|
|
184
|
+
* prefer `session.exec` (structured `{exitCode}`) and fall back to
|
|
185
|
+
* `session.execCommand` (bare string), inferring success from the up-script's
|
|
186
|
+
* marker line in the fallback case.
|
|
187
|
+
*/
|
|
188
|
+
export async function ensureDisplayStack(
|
|
189
|
+
session: unknown,
|
|
190
|
+
options: EnsureDisplayStackOptions = {},
|
|
191
|
+
): Promise<EnsureDisplayStackResult> {
|
|
192
|
+
const s = session as ExecCapableSession;
|
|
193
|
+
if (typeof s?.exec !== "function" && typeof s?.execCommand !== "function") {
|
|
194
|
+
throw new DisplayStackUnsupportedError(
|
|
195
|
+
"provider session cannot run commands (no exec/execCommand) — desktop tier unavailable",
|
|
196
|
+
);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const geometry = options.geometry ?? DEFAULT_DESKTOP_GEOMETRY;
|
|
200
|
+
const port = options.port ?? DESKTOP_STREAM_PORT;
|
|
201
|
+
const timeoutMs = options.timeoutMs ?? DISPLAY_STACK_TIMEOUT_MS;
|
|
202
|
+
const cmd = buildDisplayStackScript({ geometry, port });
|
|
203
|
+
|
|
204
|
+
const result =
|
|
205
|
+
typeof s.exec === "function"
|
|
206
|
+
? await s.exec({ cmd, yieldTimeMs: timeoutMs, maxOutputTokens: 20_000 })
|
|
207
|
+
: await s.execCommand!({ cmd, yieldTimeMs: timeoutMs, maxOutputTokens: 20_000 });
|
|
208
|
+
|
|
209
|
+
const output = execResultOutput(result);
|
|
210
|
+
const exitCode = execResultExitCode(result) ?? inferExitFromOutput(output);
|
|
211
|
+
|
|
212
|
+
if (exitCode !== 0) {
|
|
213
|
+
throw new DisplayStackError(exitCode, output);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
const marker = (output.match(/OPENGENI_DESKTOP_UP[^\n]*/) ?? [""])[0];
|
|
217
|
+
return { port, geometry, marker };
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/** Tear the stack down (down-script). Best-effort; never throws on a missing
|
|
221
|
+
* process. Used by the geometry-change restart and cold/drain. */
|
|
222
|
+
export async function tearDownDisplayStack(session: unknown): Promise<void> {
|
|
223
|
+
const s = session as ExecCapableSession;
|
|
224
|
+
if (typeof s?.exec === "function") {
|
|
225
|
+
await s.exec({ cmd: "opengeni-desktop-down", yieldTimeMs: 10_000, maxOutputTokens: 4_000 });
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
if (typeof s?.execCommand === "function") {
|
|
229
|
+
await s.execCommand({ cmd: "opengeni-desktop-down", yieldTimeMs: 10_000, maxOutputTokens: 4_000 });
|
|
230
|
+
}
|
|
231
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// Typed sandbox-construction errors for the provider registry (module 03 §5.1).
|
|
2
|
+
//
|
|
3
|
+
// SandboxConfigError is thrown by validateCredentials() and the factory on any
|
|
4
|
+
// missing/contradictory provider config — a fail-fast typed error so an
|
|
5
|
+
// unknown/misconfigured backend surfaces clearly instead of failing deep inside
|
|
6
|
+
// the SDK at create() time.
|
|
7
|
+
|
|
8
|
+
import type { SandboxBackend } from "@opengeni/contracts";
|
|
9
|
+
|
|
10
|
+
export class SandboxConfigError extends Error {
|
|
11
|
+
readonly backend: SandboxBackend | string;
|
|
12
|
+
|
|
13
|
+
constructor(backend: SandboxBackend | string, message: string) {
|
|
14
|
+
super(`[sandbox:${backend}] ${message}`);
|
|
15
|
+
this.name = "SandboxConfigError";
|
|
16
|
+
this.backend = backend;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Thrown by a provider's build() when its SDK client class is genuinely not
|
|
21
|
+
// available in the installed @openai/agents-extensions. Per the P0.3 ruling we
|
|
22
|
+
// NEVER fake a build body; if a provider cannot be constructed we register the
|
|
23
|
+
// descriptor and make build() throw this. (As of @openai/agents-extensions
|
|
24
|
+
// 0.11.6 every provider ships a concrete client, so this is currently unused —
|
|
25
|
+
// it is the documented contract for a future drop that loses a provider.)
|
|
26
|
+
export class SandboxProviderUnavailableError extends Error {
|
|
27
|
+
readonly backend: SandboxBackend | string;
|
|
28
|
+
|
|
29
|
+
constructor(backend: SandboxBackend | string) {
|
|
30
|
+
super(`provider ${backend} not available in installed @openai/agents-extensions`);
|
|
31
|
+
this.name = "SandboxProviderUnavailableError";
|
|
32
|
+
this.backend = backend;
|
|
33
|
+
}
|
|
34
|
+
}
|