@opengeni/runtime 0.14.1 → 0.14.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/{chunk-4YJ5Z52Z.js → chunk-7E2ZSCZK.js} +6 -6
- package/dist/{chunk-4YJ5Z52Z.js.map → chunk-7E2ZSCZK.js.map} +1 -1
- package/dist/{chunk-HHWIZHQM.js → chunk-GNEGANUF.js} +942 -300
- package/dist/chunk-GNEGANUF.js.map +1 -0
- package/dist/codex-tool-search.d.ts +100 -0
- package/dist/context-compaction.d.ts +236 -0
- package/dist/history-sanitizer.d.ts +320 -0
- package/dist/index.d.ts +186 -718
- package/dist/index.js +612 -126
- package/dist/index.js.map +1 -1
- package/dist/{localSources-T3HZ6KY4.js → localSources-BXHBKGF4.js} +2 -2
- package/dist/mcp-network.d.ts +32 -35
- package/dist/metrics.d.ts +33 -0
- package/dist/sandbox/capabilities.d.ts +11 -0
- package/dist/sandbox/channel-a.d.ts +226 -0
- package/dist/sandbox/display-stack.d.ts +99 -0
- package/dist/sandbox/errors.d.ts +16 -0
- package/dist/sandbox/exec-banner.d.ts +19 -0
- package/dist/sandbox/index.d.ts +190 -6
- package/dist/sandbox/index.js +20 -4
- package/dist/sandbox/op-correlation.d.ts +24 -0
- package/dist/sandbox/provider-errors.d.ts +32 -0
- package/dist/sandbox/provider-operation-gate.d.ts +12 -0
- package/dist/sandbox/providers/blaxel.d.ts +2 -0
- package/dist/sandbox/providers/cloudflare.d.ts +2 -0
- package/dist/sandbox/providers/daytona.d.ts +2 -0
- package/dist/sandbox/providers/docker.d.ts +2 -0
- package/dist/sandbox/providers/e2b.d.ts +2 -0
- package/dist/sandbox/providers/index.d.ts +11 -0
- package/dist/sandbox/providers/local.d.ts +2 -0
- package/dist/sandbox/providers/modal.d.ts +132 -0
- package/dist/sandbox/providers/none.d.ts +2 -0
- package/dist/sandbox/providers/runloop.d.ts +2 -0
- package/dist/sandbox/providers/selfhosted.d.ts +2 -0
- package/dist/sandbox/providers/types.d.ts +30 -0
- package/dist/sandbox/providers/vercel.d.ts +2 -0
- package/dist/sandbox/recording.d.ts +80 -0
- package/dist/sandbox/routing/backend-resolver.d.ts +173 -0
- package/dist/sandbox/routing/routing-session.d.ts +401 -0
- package/dist/sandbox/run-credentials.d.ts +65 -0
- package/dist/sandbox/select.d.ts +120 -0
- package/dist/sandbox/selfhosted/capabilities.d.ts +91 -0
- package/dist/sandbox/selfhosted/control-rpc.d.ts +175 -0
- package/dist/sandbox/selfhosted/fault-rendering.d.ts +40 -0
- package/dist/sandbox/selfhosted/op-observer.d.ts +40 -0
- package/dist/sandbox/selfhosted/op-stream.d.ts +104 -0
- package/dist/sandbox/selfhosted/op-testing.d.ts +108 -0
- package/dist/sandbox/selfhosted/op-transport.d.ts +60 -0
- package/dist/sandbox/selfhosted/retry-policy.d.ts +106 -0
- package/dist/sandbox/selfhosted/session.d.ts +552 -0
- package/dist/sandbox/selfhosted/testing.d.ts +48 -0
- package/dist/sandbox/stream-port.d.ts +80 -0
- package/dist/sandbox/stream-token.d.ts +44 -0
- package/dist/sandbox/terminal-server.d.ts +67 -0
- package/dist/sandbox/toolspace-token.d.ts +23 -0
- package/dist/sandbox/turn-tool-cancellation.d.ts +72 -0
- package/dist/sandbox/workspace-archive.d.ts +39 -0
- package/dist/sandbox-computer.d.ts +227 -0
- package/dist/screenshot-error-card.d.ts +1 -0
- package/dist/skill-library.d.ts +10 -12
- package/dist/usage-telemetry.d.ts +45 -0
- package/dist/workspace-skills.d.ts +31 -0
- package/package.json +7 -7
- package/src/context-compaction.ts +600 -6
- package/src/history-sanitizer.ts +10 -92
- package/src/index.ts +301 -62
- package/src/sandbox/channel-a.ts +267 -81
- package/src/sandbox/index.ts +56 -94
- package/src/sandbox/provider-operation-gate.ts +110 -0
- package/src/sandbox/providers/docker.ts +13 -1
- package/src/sandbox/providers/modal.ts +433 -3
- package/src/sandbox/routing/routing-session.ts +84 -8
- package/src/sandbox/selfhosted/session.ts +7 -6
- package/src/sandbox/turn-tool-cancellation.ts +47 -7
- package/src/sandbox/workspace-archive.ts +176 -73
- package/src/sandbox-computer.ts +25 -75
- package/dist/chunk-HHWIZHQM.js.map +0 -1
- package/dist/index-BraazrAO.d.ts +0 -2931
- /package/dist/{localSources-T3HZ6KY4.js.map → localSources-BXHBKGF4.js.map} +0 -0
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
applyLocalSourceManifestToState,
|
|
4
4
|
materializeLocalSourceManifest,
|
|
5
5
|
materializeLocalSourceManifestEntry
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-7E2ZSCZK.js";
|
|
7
7
|
import "./chunk-K4V4QYCL.js";
|
|
8
8
|
import "./chunk-PZ5AY32C.js";
|
|
9
9
|
export {
|
|
@@ -12,4 +12,4 @@ export {
|
|
|
12
12
|
materializeLocalSourceManifest,
|
|
13
13
|
materializeLocalSourceManifestEntry
|
|
14
14
|
};
|
|
15
|
-
//# sourceMappingURL=localSources-
|
|
15
|
+
//# sourceMappingURL=localSources-BXHBKGF4.js.map
|
package/dist/mcp-network.d.ts
CHANGED
|
@@ -1,33 +1,32 @@
|
|
|
1
|
-
import { Settings } from
|
|
2
|
-
import {
|
|
3
|
-
export { undiciFetch } from
|
|
4
|
-
|
|
5
|
-
declare const
|
|
6
|
-
declare const
|
|
7
|
-
declare const
|
|
8
|
-
declare const
|
|
9
|
-
declare const
|
|
10
|
-
declare const
|
|
11
|
-
declare const
|
|
12
|
-
declare const
|
|
13
|
-
declare const
|
|
14
|
-
declare const
|
|
15
|
-
declare const
|
|
16
|
-
declare const
|
|
17
|
-
declare const
|
|
18
|
-
declare const
|
|
19
|
-
declare
|
|
20
|
-
declare class McpPayloadTooLargeError extends Error {
|
|
1
|
+
import type { Settings } from "@opengeni/config";
|
|
2
|
+
import { isNonPublicAddress, type DnsLookup } from "@opengeni/network";
|
|
3
|
+
export { undiciFetch } from "@opengeni/network";
|
|
4
|
+
export declare const MCP_MAX_RESPONSE_BYTES: number;
|
|
5
|
+
export declare const MCP_MAX_INBOUND_REQUEST_BYTES: number;
|
|
6
|
+
export declare const MCP_MAX_TOOL_DEFINITION_BYTES: number;
|
|
7
|
+
export declare const MCP_MAX_TOOL_LIST_BYTES: number;
|
|
8
|
+
export declare const MCP_MAX_TOOL_LIST_ENTRIES = 1000;
|
|
9
|
+
export declare const MCP_MAX_TOOL_RESULT_BYTES: number;
|
|
10
|
+
export declare const MCP_MAX_TOOL_SEARCH_DISCLOSURE_BYTES: number;
|
|
11
|
+
export declare const MCP_MAX_SELECTED_SERVERS = 64;
|
|
12
|
+
export declare const MCP_MAX_CONCURRENT_SERVER_OPERATIONS = 8;
|
|
13
|
+
export declare const MCP_DEFAULT_OUTER_CONNECT_TIMEOUT_MS = 10000;
|
|
14
|
+
export declare const MCP_MAX_AGGREGATE_TOOL_LIST_ENTRIES = 4096;
|
|
15
|
+
export declare const MCP_MAX_AGGREGATE_TOOL_LIST_BYTES: number;
|
|
16
|
+
export declare const MCP_MAX_TOOL_SEARCH_SOURCES = 64;
|
|
17
|
+
export declare const MCP_MAX_TOOL_SEARCH_SOURCE_LABEL_LENGTH = 120;
|
|
18
|
+
export declare const MCP_MAX_TOOL_SEARCH_DESCRIPTION_BYTES: number;
|
|
19
|
+
export declare class McpPayloadTooLargeError extends Error {
|
|
21
20
|
readonly label: string;
|
|
22
21
|
readonly actualBytes: number;
|
|
23
22
|
readonly maxBytes: number;
|
|
24
23
|
constructor(label: string, actualBytes: number, maxBytes: number);
|
|
25
24
|
}
|
|
26
|
-
declare function mcpSerializedSizeBytes(value: unknown): number;
|
|
27
|
-
declare function assertMcpPayloadWithinBytes(value: unknown, maxBytes: number, label: string): void;
|
|
28
|
-
declare function assertMcpToolListWithinBounds<T>(tools: readonly T[]): readonly T[];
|
|
29
|
-
declare function assertMcpServerSelectionWithinBounds<T>(servers: readonly T[]): readonly T[];
|
|
30
|
-
declare function mcpOuterConnectTimeoutMs(configuredTimeouts: readonly (number | undefined)[]): number;
|
|
25
|
+
export declare function mcpSerializedSizeBytes(value: unknown): number;
|
|
26
|
+
export declare function assertMcpPayloadWithinBytes(value: unknown, maxBytes: number, label: string): void;
|
|
27
|
+
export declare function assertMcpToolListWithinBounds<T>(tools: readonly T[]): readonly T[];
|
|
28
|
+
export declare function assertMcpServerSelectionWithinBounds<T>(servers: readonly T[]): readonly T[];
|
|
29
|
+
export declare function mcpOuterConnectTimeoutMs(configuredTimeouts: readonly (number | undefined)[]): number;
|
|
31
30
|
type McpToolListContribution = {
|
|
32
31
|
entries: number;
|
|
33
32
|
bytes: number;
|
|
@@ -38,7 +37,7 @@ type McpToolListContribution = {
|
|
|
38
37
|
* cache invalidation/relisting cannot ratchet the budget upward. Failed
|
|
39
38
|
* replacements leave the previous accounting intact.
|
|
40
39
|
*/
|
|
41
|
-
declare class McpAggregateToolListBudget {
|
|
40
|
+
export declare class McpAggregateToolListBudget {
|
|
42
41
|
private readonly label;
|
|
43
42
|
private readonly maxEntries;
|
|
44
43
|
private readonly maxBytes;
|
|
@@ -51,7 +50,7 @@ declare class McpAggregateToolListBudget {
|
|
|
51
50
|
snapshot(): Readonly<McpToolListContribution>;
|
|
52
51
|
}
|
|
53
52
|
/** Stable-order parallel map with a hard in-flight ceiling and fail-stop drain. */
|
|
54
|
-
declare function boundedParallelMap<T, R>(values: readonly T[], concurrency: number, mapper: (value: T, index: number) => Promise<R>): Promise<R[]>;
|
|
53
|
+
export declare function boundedParallelMap<T, R>(values: readonly T[], concurrency: number, mapper: (value: T, index: number) => Promise<R>): Promise<R[]>;
|
|
55
54
|
/**
|
|
56
55
|
* Guard normal MCP traffic with the same deployment policy as OAuth traffic.
|
|
57
56
|
* The pinned transport resolves and policy-checks the destination after the
|
|
@@ -63,19 +62,17 @@ declare function boundedParallelMap<T, R>(values: readonly T[], concurrency: num
|
|
|
63
62
|
* This module is deliberately agent-loop-free. API code imports the explicit
|
|
64
63
|
* `@opengeni/runtime/mcp-network` leaf rather than the runtime root barrel.
|
|
65
64
|
*/
|
|
66
|
-
declare function guardedMcpFetch<TInput extends string | URL | Request>(settings: Pick<Settings, "environment" | "integrationsAllowPrivateNetworkTargets">, fetchImpl: (input: TInput, init?: RequestInit) => Promise<Response>, options?: {
|
|
65
|
+
export declare function guardedMcpFetch<TInput extends string | URL | Request>(settings: Pick<Settings, "environment" | "integrationsAllowPrivateNetworkTargets">, fetchImpl: (input: TInput, init?: RequestInit) => Promise<Response>, options?: {
|
|
67
66
|
maxResponseBytes?: number;
|
|
68
67
|
dnsLookup?: DnsLookup;
|
|
69
68
|
pinResolvedDestination?: boolean;
|
|
70
69
|
requireHttpsOutsideLocalTest?: boolean;
|
|
71
70
|
}): (input: TInput, init?: RequestInit) => Promise<Response>;
|
|
72
|
-
declare function boundMcpResponseBody(response: Response, maxBytes: number): Response;
|
|
73
|
-
declare function cancelMcpResponseBody(response: Response): Promise<void>;
|
|
71
|
+
export declare function boundMcpResponseBody(response: Response, maxBytes: number): Response;
|
|
72
|
+
export declare function cancelMcpResponseBody(response: Response): Promise<void>;
|
|
74
73
|
/** Read and rebuild an inbound MCP request before the SDK parses it. */
|
|
75
|
-
declare function boundedMcpRequest(request: Request, maxBytes?: number): Promise<Request>;
|
|
76
|
-
declare function assertMcpDestinationAllowed(rawUrl: string, settings: Pick<Settings, "environment" | "integrationsAllowPrivateNetworkTargets">, options?: {
|
|
74
|
+
export declare function boundedMcpRequest(request: Request, maxBytes?: number): Promise<Request>;
|
|
75
|
+
export declare function assertMcpDestinationAllowed(rawUrl: string, settings: Pick<Settings, "environment" | "integrationsAllowPrivateNetworkTargets">, options?: {
|
|
77
76
|
dnsLookup?: DnsLookup;
|
|
78
77
|
}): Promise<void>;
|
|
79
|
-
declare const isNonPublicMcpAddress: typeof isNonPublicAddress;
|
|
80
|
-
|
|
81
|
-
export { MCP_DEFAULT_OUTER_CONNECT_TIMEOUT_MS, MCP_MAX_AGGREGATE_TOOL_LIST_BYTES, MCP_MAX_AGGREGATE_TOOL_LIST_ENTRIES, MCP_MAX_CONCURRENT_SERVER_OPERATIONS, MCP_MAX_INBOUND_REQUEST_BYTES, MCP_MAX_RESPONSE_BYTES, MCP_MAX_SELECTED_SERVERS, MCP_MAX_TOOL_DEFINITION_BYTES, MCP_MAX_TOOL_LIST_BYTES, MCP_MAX_TOOL_LIST_ENTRIES, MCP_MAX_TOOL_RESULT_BYTES, MCP_MAX_TOOL_SEARCH_DESCRIPTION_BYTES, MCP_MAX_TOOL_SEARCH_DISCLOSURE_BYTES, MCP_MAX_TOOL_SEARCH_SOURCES, MCP_MAX_TOOL_SEARCH_SOURCE_LABEL_LENGTH, McpAggregateToolListBudget, McpPayloadTooLargeError, assertMcpDestinationAllowed, assertMcpPayloadWithinBytes, assertMcpServerSelectionWithinBounds, assertMcpToolListWithinBounds, boundMcpResponseBody, boundedMcpRequest, boundedParallelMap, cancelMcpResponseBody, guardedMcpFetch, isNonPublicMcpAddress, mcpOuterConnectTimeoutMs, mcpSerializedSizeBytes };
|
|
78
|
+
export declare const isNonPublicMcpAddress: typeof isNonPublicAddress;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export type RuntimeMetricsHooks = {
|
|
2
|
+
onModelCall?: (input: {
|
|
3
|
+
provider: string;
|
|
4
|
+
outcome: "completed" | "failed";
|
|
5
|
+
durationSeconds: number;
|
|
6
|
+
}) => void;
|
|
7
|
+
onSandboxCreate?: (input: {
|
|
8
|
+
backend: string;
|
|
9
|
+
outcome: "completed" | "failed";
|
|
10
|
+
durationSeconds: number;
|
|
11
|
+
}) => void;
|
|
12
|
+
onSandboxWarmingTimeout?: (input: {
|
|
13
|
+
backend: string;
|
|
14
|
+
}) => void;
|
|
15
|
+
/**
|
|
16
|
+
* One completed Connected Machine (selfhosted) control op — the out-of-band
|
|
17
|
+
* telemetry twin of the in-band fault rendering. `code` is the typed wire-code
|
|
18
|
+
* NAME on a failure (bounded label cardinality); `healed` marks a success that
|
|
19
|
+
* only landed after ≥1 retry (the leading indicator of the next unhealed fault);
|
|
20
|
+
* `replyBytes` is set only on a payload-wall fault. Wired from the runtime's
|
|
21
|
+
* `SelfhostedOpObserver` seam.
|
|
22
|
+
*/
|
|
23
|
+
onSandboxOp?: (input: {
|
|
24
|
+
backend: string;
|
|
25
|
+
op: string;
|
|
26
|
+
outcome: "ok" | "failed";
|
|
27
|
+
code?: string;
|
|
28
|
+
healed: boolean;
|
|
29
|
+
retries: number;
|
|
30
|
+
durationSeconds: number;
|
|
31
|
+
replyBytes?: number;
|
|
32
|
+
}) => void;
|
|
33
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { CAPABILITY_DESCRIPTORS, DESKTOP_STREAM_PORT, type CapabilityDescriptor } from "@opengeni/contracts";
|
|
2
|
+
export { CAPABILITY_DESCRIPTORS, DESKTOP_STREAM_PORT };
|
|
3
|
+
export type { CapabilityDescriptor };
|
|
4
|
+
/**
|
|
5
|
+
* Descriptor-table invariants, asserted once at registry build (and from a unit
|
|
6
|
+
* test). This is the guardrail that keeps the static matrix internally coherent.
|
|
7
|
+
* It validates the descriptor data only; the descriptor.backendId === SDK
|
|
8
|
+
* client.backendId assertion (the deferred-from-P0.1 check) lives in
|
|
9
|
+
* providers/index.ts because it must construct the real SDK clients.
|
|
10
|
+
*/
|
|
11
|
+
export declare function assertDescriptorRegistryInvariants(): void;
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
import type { FsDeleteRequest, FsDeleteResponse, FsListRequest, FsListResponse, FsMkdirRequest, FsMkdirResponse, FsMoveRequest, FsMoveResponse, FsReadRequest, FsReadResponse, FsWriteRequest, FsWriteResponse, GitChangedPayload, GitDiffHunk, GitDiffRequest, GitDiffResponse, GitFileStatusCode, GitLogRequest, GitLogResponse, GitShowRequest, GitShowResponse, GitStatusRequest, GitStatusResponse, PtyCloseRequest, PtyOpenRequest, PtyOpenResponse, PtyResizeRequest, PtyWriteRequest, SessionEventType, SessionStructuredCapabilities, TerminalExecRequest, TerminalExecResponse } from "@opengeni/contracts";
|
|
2
|
+
export { isExecSessionLostBanner, parseExecBannerExitCode, parseExecBannerSessionId, } from "./exec-banner";
|
|
3
|
+
export type ChannelAExecResult = {
|
|
4
|
+
output?: string;
|
|
5
|
+
stdout?: string;
|
|
6
|
+
stderr?: string;
|
|
7
|
+
exitCode?: number | null;
|
|
8
|
+
sessionId?: number;
|
|
9
|
+
wallTimeSeconds?: number;
|
|
10
|
+
};
|
|
11
|
+
export type ChannelAExecArgs = {
|
|
12
|
+
cmd: string;
|
|
13
|
+
workdir?: string | undefined;
|
|
14
|
+
shell?: string | undefined;
|
|
15
|
+
login?: boolean | undefined;
|
|
16
|
+
tty?: boolean | undefined;
|
|
17
|
+
yieldTimeMs?: number | undefined;
|
|
18
|
+
maxOutputTokens?: number | undefined;
|
|
19
|
+
runAs?: string | undefined;
|
|
20
|
+
};
|
|
21
|
+
export type ChannelAEditor = {
|
|
22
|
+
createFile?(op: unknown): Promise<unknown>;
|
|
23
|
+
updateFile?(op: unknown): Promise<unknown>;
|
|
24
|
+
deleteFile?(op: unknown): Promise<unknown>;
|
|
25
|
+
};
|
|
26
|
+
export type ChannelASession = {
|
|
27
|
+
exec?(args: ChannelAExecArgs): Promise<ChannelAExecResult>;
|
|
28
|
+
execCommand?(args: ChannelAExecArgs): Promise<string>;
|
|
29
|
+
readFile?(args: {
|
|
30
|
+
path: string;
|
|
31
|
+
runAs?: string;
|
|
32
|
+
maxBytes?: number;
|
|
33
|
+
}): Promise<string | Uint8Array>;
|
|
34
|
+
writeStdin?(args: {
|
|
35
|
+
sessionId: number;
|
|
36
|
+
chars?: string;
|
|
37
|
+
yieldTimeMs?: number;
|
|
38
|
+
maxOutputTokens?: number;
|
|
39
|
+
}): Promise<string>;
|
|
40
|
+
writeStdinForProcessMutation?(args: {
|
|
41
|
+
sessionId: number;
|
|
42
|
+
chars?: string;
|
|
43
|
+
yieldTimeMs?: number;
|
|
44
|
+
maxOutputTokens?: number;
|
|
45
|
+
}): Promise<string>;
|
|
46
|
+
writeStdinForProcessControl?(args: {
|
|
47
|
+
sessionId: number;
|
|
48
|
+
chars?: string;
|
|
49
|
+
yieldTimeMs?: number;
|
|
50
|
+
maxOutputTokens?: number;
|
|
51
|
+
}): Promise<string>;
|
|
52
|
+
cancelExecCommand?(opId: string): Promise<boolean>;
|
|
53
|
+
hasRetainedProcess?(providerSessionId: number): boolean;
|
|
54
|
+
execCommandForProcessControl?(providerSessionId: number, args: ChannelAExecArgs): Promise<string>;
|
|
55
|
+
createEditor?(runAs?: string): ChannelAEditor;
|
|
56
|
+
supportsPty?(): boolean;
|
|
57
|
+
};
|
|
58
|
+
export declare class ChannelAValidationError extends Error {
|
|
59
|
+
constructor(message: string);
|
|
60
|
+
}
|
|
61
|
+
/** A structurally valid Channel-A request could not be completed because the
|
|
62
|
+
* sandbox/provider control plane was temporarily unavailable. Callers may retry
|
|
63
|
+
* this class; it must never be presented as a bad user path. */
|
|
64
|
+
export declare class ChannelAUnavailableError extends Error {
|
|
65
|
+
constructor(message: string);
|
|
66
|
+
}
|
|
67
|
+
export declare class ChannelAConflictError extends Error {
|
|
68
|
+
constructor(message: string);
|
|
69
|
+
}
|
|
70
|
+
export declare class ChannelANotFoundError extends Error {
|
|
71
|
+
constructor(message: string);
|
|
72
|
+
}
|
|
73
|
+
export declare class ChannelAUnsupportedError extends Error {
|
|
74
|
+
constructor(message: string);
|
|
75
|
+
}
|
|
76
|
+
export type ChannelAEmitter = (events: {
|
|
77
|
+
type: SessionEventType;
|
|
78
|
+
payload: unknown;
|
|
79
|
+
}[]) => Promise<void>;
|
|
80
|
+
export type SandboxChannelAServiceOptions = {
|
|
81
|
+
session: ChannelASession;
|
|
82
|
+
workspaceRoot?: string;
|
|
83
|
+
leaseEpoch?: number;
|
|
84
|
+
revision?: number;
|
|
85
|
+
emit?: ChannelAEmitter;
|
|
86
|
+
runAs?: string;
|
|
87
|
+
};
|
|
88
|
+
export declare const REPOSITORY_DISCOVERY_LIMIT = 256;
|
|
89
|
+
export type RepositoryDiscoveryDegradedReason = "command_failed" | "command_timed_out" | "result_limit_exceeded";
|
|
90
|
+
export type RepositoryDiscoveryResult = {
|
|
91
|
+
repos: string[];
|
|
92
|
+
complete: boolean;
|
|
93
|
+
degradedReason: RepositoryDiscoveryDegradedReason | null;
|
|
94
|
+
};
|
|
95
|
+
export declare class SandboxChannelAService {
|
|
96
|
+
private readonly session;
|
|
97
|
+
private readonly workspaceRoot;
|
|
98
|
+
private readonly leaseEpoch;
|
|
99
|
+
private revision;
|
|
100
|
+
private readonly emit?;
|
|
101
|
+
private readonly runAs?;
|
|
102
|
+
constructor(opts: SandboxChannelAServiceOptions);
|
|
103
|
+
/** Capability probe — the compact Channel-A projection. */
|
|
104
|
+
capabilities(repos?: string[]): SessionStructuredCapabilities;
|
|
105
|
+
private run;
|
|
106
|
+
fsList(req: FsListRequest): Promise<FsListResponse>;
|
|
107
|
+
/**
|
|
108
|
+
* Worker-only fast path for a bounded whole-workspace index. Matching
|
|
109
|
+
* directory nodes are emitted but pruned by `find` before descent, so residue
|
|
110
|
+
* such as node_modules cannot consume the result budget. The public fs/list
|
|
111
|
+
* wire remains unchanged; interactive callers still expand every directory
|
|
112
|
+
* they explicitly request.
|
|
113
|
+
*/
|
|
114
|
+
fsListPruned(req: FsListRequest, pruneDirectoryNames: readonly string[]): Promise<FsListResponse>;
|
|
115
|
+
private fsListInternal;
|
|
116
|
+
fsRead(req: FsReadRequest): Promise<FsReadResponse>;
|
|
117
|
+
private assertConfinedExistingDirectory;
|
|
118
|
+
private assertConfinedMutationParent;
|
|
119
|
+
private assertConfinementResult;
|
|
120
|
+
/** Binary-safe fallback for sessions without native reads. The file is opened
|
|
121
|
+
* before checking `/proc/.../fd/3`, so a symlink swap cannot redirect the
|
|
122
|
+
* subsequent read after confinement has been established. */
|
|
123
|
+
private fsReadViaExec;
|
|
124
|
+
private shapeRead;
|
|
125
|
+
fsWrite(req: FsWriteRequest): Promise<FsWriteResponse>;
|
|
126
|
+
private tryEditorWrite;
|
|
127
|
+
fsDelete(req: FsDeleteRequest): Promise<FsDeleteResponse>;
|
|
128
|
+
fsMove(req: FsMoveRequest): Promise<FsMoveResponse>;
|
|
129
|
+
fsMkdir(req: FsMkdirRequest): Promise<FsMkdirResponse>;
|
|
130
|
+
/** Measure one Git command without returning its potentially large or
|
|
131
|
+
* NUL-bearing output through the provider's text transport. */
|
|
132
|
+
private measureConfinedCommandBytes;
|
|
133
|
+
/** Read an exact prefix of a command's output in chunks that remain below
|
|
134
|
+
* every supported execCommand retained-output ceiling. The producer is
|
|
135
|
+
* intentionally rerun per chunk; turn-end capture calls this only after the
|
|
136
|
+
* durable mutation authority has quiesced the workspace. */
|
|
137
|
+
private readConfinedCommandPrefix;
|
|
138
|
+
private readConfinedCommandBytes;
|
|
139
|
+
/** Bind an untracked regular-file descriptor to its repository root and its
|
|
140
|
+
* lstat identity before producing bytes. The final producer reads fd 3 rather
|
|
141
|
+
* than reopening the path, so a check→read symlink swap cannot disclose a
|
|
142
|
+
* target outside the repository (or substitute another in-repository inode). */
|
|
143
|
+
private confinedUntrackedRegularFileCommand;
|
|
144
|
+
/** Read a regular untracked file without routing its body through one large
|
|
145
|
+
* execCommand response. Native provider reads are binary-safe; providers
|
|
146
|
+
* without that surface use the same bounded chunk protocol as Git patches. */
|
|
147
|
+
private readUntrackedRegularFile;
|
|
148
|
+
gitStatus(req: GitStatusRequest): Promise<GitStatusResponse>;
|
|
149
|
+
gitDiff(req: GitDiffRequest): Promise<GitDiffResponse>;
|
|
150
|
+
gitLog(req: GitLogRequest): Promise<GitLogResponse>;
|
|
151
|
+
gitShow(req: GitShowRequest): Promise<GitShowResponse>;
|
|
152
|
+
/**
|
|
153
|
+
* Detect repo roots within every supported workspace layout.
|
|
154
|
+
*
|
|
155
|
+
* The platform normally seeds repositories at
|
|
156
|
+
* `repos/<encoded-host>/<owner>/<repo>`, while explicit mount paths and
|
|
157
|
+
* connected-machine layouts can be deeper. Do not reintroduce a fixed
|
|
158
|
+
* maxdepth here. Traversal is
|
|
159
|
+
* bounded instead by pruning known machine/build residue, a wall-clock
|
|
160
|
+
* timeout, and a result limit. `.git` may be either a directory (ordinary
|
|
161
|
+
* clone/submodule) or a file (linked worktree).
|
|
162
|
+
*
|
|
163
|
+
* Callers that persist an authoritative snapshot must use this detailed
|
|
164
|
+
* result and surface an incomplete discovery. The compact `detectRepos()`
|
|
165
|
+
* wrapper remains for capability negotiation, where the best available list
|
|
166
|
+
* is preferable to failing the whole capabilities document.
|
|
167
|
+
*/
|
|
168
|
+
detectReposDetailed(): Promise<RepositoryDiscoveryResult>;
|
|
169
|
+
/** Detect repo roots within the workspace (for the Git.repos capability). */
|
|
170
|
+
detectRepos(): Promise<string[]>;
|
|
171
|
+
/** Run a bounded command to physical completion and return buffered output.
|
|
172
|
+
* A deadline cancels the exact provider operation, proves its process group
|
|
173
|
+
* absent, and settles any retained-process admission before returning 124. */
|
|
174
|
+
terminalExec(req: TerminalExecRequest): Promise<TerminalExecResponse>;
|
|
175
|
+
/** Open an interactive PTY: exec the shell with tty:true, yielding the numeric
|
|
176
|
+
* exec-session id the caller persists (ptyId<->execSessionId) so subsequent
|
|
177
|
+
* writeStdin can drive it. Returns the supportsInput gate (false when the
|
|
178
|
+
* backend has no writeStdin). The caller emits terminal.pty.started after it
|
|
179
|
+
* persists the row. */
|
|
180
|
+
ptyOpen(req: PtyOpenRequest, ptyId: string): Promise<{
|
|
181
|
+
response: PtyOpenResponse;
|
|
182
|
+
execSessionId: number | null;
|
|
183
|
+
shell: string;
|
|
184
|
+
initialOutput: string;
|
|
185
|
+
}>;
|
|
186
|
+
/** Drive an open PTY's stdin. Returns the drained output (the caller publishes
|
|
187
|
+
* it as terminal.pty.output.delta). Throws ChannelAUnsupportedError when the
|
|
188
|
+
* backend has no writeStdin. */
|
|
189
|
+
ptyWrite(_req: PtyWriteRequest, execSessionId: number, data: string): Promise<string>;
|
|
190
|
+
/** Resize an open PTY (SIGWINCH via stty against the exec-session). The SDK has
|
|
191
|
+
* no resize method; stty in the same tty session updates the geometry. */
|
|
192
|
+
ptyResize(req: PtyResizeRequest, execSessionId: number): Promise<void>;
|
|
193
|
+
/** Ask an open PTY to exit and return the exact provider banner. The routing
|
|
194
|
+
* session settles durable process authority only when that banner proves this
|
|
195
|
+
* locator exited or was lost; callers must keep metadata open otherwise. */
|
|
196
|
+
ptyClose(_req: PtyCloseRequest, execSessionId: number | null): Promise<string>;
|
|
197
|
+
/** The current FS revision (for the caller to persist/seed). */
|
|
198
|
+
currentRevision(): number;
|
|
199
|
+
private joinRoot;
|
|
200
|
+
/** Validate and enter an FS/Git directory in the same remote command that
|
|
201
|
+
* performs the operation. This preserves confinement without adding a full
|
|
202
|
+
* provider round-trip to every tree expansion or Git query. */
|
|
203
|
+
private runInConfinedDirectory;
|
|
204
|
+
private repoWorkdir;
|
|
205
|
+
private terminalWorkdir;
|
|
206
|
+
private emitEvents;
|
|
207
|
+
private emitFsChanged;
|
|
208
|
+
/** Re-probe git after a mutation and emit git.changed (best-effort, used by the
|
|
209
|
+
* worker agent-turn side after FS-mutating tools). */
|
|
210
|
+
emitGitChanged(repoPath: string, reason: GitChangedPayload["reason"]): Promise<void>;
|
|
211
|
+
}
|
|
212
|
+
export declare function stripExecBanner(raw: string): string;
|
|
213
|
+
export declare function assertSafeRelPath(p: string): string;
|
|
214
|
+
export declare function parsePorcelainV2(z: string): Omit<GitStatusResponse, "revision">;
|
|
215
|
+
export type NumstatEntry = {
|
|
216
|
+
additions: number;
|
|
217
|
+
deletions: number;
|
|
218
|
+
binary: boolean;
|
|
219
|
+
oldPath: string | null;
|
|
220
|
+
newPath: string;
|
|
221
|
+
};
|
|
222
|
+
export declare function parseNumstatZ(z: string): NumstatEntry[];
|
|
223
|
+
export declare function parseUnifiedPatch(patch: string): {
|
|
224
|
+
hunks: GitDiffHunk[];
|
|
225
|
+
status: GitFileStatusCode;
|
|
226
|
+
};
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { DESKTOP_STREAM_PORT } from "@opengeni/contracts";
|
|
2
|
+
export { DESKTOP_STREAM_PORT };
|
|
3
|
+
export declare const STREAM_PORT = 6080;
|
|
4
|
+
export declare const DISPLAY_STACK_TIMEOUT_MS = 90000;
|
|
5
|
+
/** Desktop geometry for the framebuffer. v1 has no live RANDR: a resolution
|
|
6
|
+
* change is a full down -> up restart (a separate op). */
|
|
7
|
+
export type DesktopGeometry = {
|
|
8
|
+
width: number;
|
|
9
|
+
height: number;
|
|
10
|
+
dpi: number;
|
|
11
|
+
};
|
|
12
|
+
export declare const DEFAULT_DESKTOP_GEOMETRY: DesktopGeometry;
|
|
13
|
+
/** Thrown when a stage of the launch script failed. exitCode 11/12/13 map to
|
|
14
|
+
* Xvfb / x11vnc / websockify respectively (the stage that died); 14 is the
|
|
15
|
+
* PAINTABLE-FRAME gate (ports listening but scrot still yields an empty frame —
|
|
16
|
+
* the display is up but not actually painting). Degradation is surfaced as a
|
|
17
|
+
* value to viewers by the caller; this error is for diagnostics. */
|
|
18
|
+
export declare class DisplayStackError extends Error {
|
|
19
|
+
readonly exitCode: number;
|
|
20
|
+
readonly stage: "xvfb" | "x11vnc" | "websockify" | "paint" | "lock" | "timeout" | "unknown";
|
|
21
|
+
constructor(exitCode: number, output: string);
|
|
22
|
+
}
|
|
23
|
+
/** Thrown when the provider session cannot run commands (a headless-only
|
|
24
|
+
* backend with neither `exec` nor `execCommand`). The desktop tier degrades to
|
|
25
|
+
* Channel-A-only — the caller maps this to `DesktopStream.transport: null`. */
|
|
26
|
+
export declare class DisplayStackUnsupportedError extends Error {
|
|
27
|
+
constructor(message: string);
|
|
28
|
+
}
|
|
29
|
+
export type DisplayStackCallerKind = "viewer" | "computer" | "unknown";
|
|
30
|
+
export type DisplayStackClassification = "cold" | "already_ready" | "contention" | "unknown";
|
|
31
|
+
export type DisplayStackTelemetryStatus = "started" | "waiting" | "completed" | "failed";
|
|
32
|
+
/** Secret-free, bounded-cardinality stage observation. Provider/sandbox IDs are
|
|
33
|
+
* log correlation fields, never metric labels. */
|
|
34
|
+
export type DisplayStackTelemetryEvent = {
|
|
35
|
+
type: "display_stack.stage";
|
|
36
|
+
requestId: string;
|
|
37
|
+
stage: string;
|
|
38
|
+
status: DisplayStackTelemetryStatus;
|
|
39
|
+
elapsedMs: number;
|
|
40
|
+
source: "host" | "sandbox";
|
|
41
|
+
classification: DisplayStackClassification;
|
|
42
|
+
callerKind: DisplayStackCallerKind;
|
|
43
|
+
sandboxId?: string;
|
|
44
|
+
leaseEpoch?: number;
|
|
45
|
+
providerSessionId?: number;
|
|
46
|
+
};
|
|
47
|
+
export type DisplayStackTelemetryContext = {
|
|
48
|
+
callerKind: DisplayStackCallerKind;
|
|
49
|
+
sandboxId?: string;
|
|
50
|
+
leaseEpoch?: number;
|
|
51
|
+
};
|
|
52
|
+
export type EnsureDisplayStackOptions = {
|
|
53
|
+
geometry?: DesktopGeometry;
|
|
54
|
+
/** The exposed stream port; defaults to 6080. */
|
|
55
|
+
port?: number;
|
|
56
|
+
/** Whole-operation wall-clock timeout; defaults to DISPLAY_STACK_TIMEOUT_MS. */
|
|
57
|
+
timeoutMs?: number;
|
|
58
|
+
/** Caller correlation. Supplying it enables the default structured log sink. */
|
|
59
|
+
telemetryContext?: DisplayStackTelemetryContext;
|
|
60
|
+
/** Optional non-blocking telemetry sink (tests/embedders may replace logging). */
|
|
61
|
+
onTelemetry?: (event: DisplayStackTelemetryEvent) => void | Promise<void>;
|
|
62
|
+
};
|
|
63
|
+
export type EnsureDisplayStackResult = {
|
|
64
|
+
/** The exposed port the stack listens on (websockify/noVNC). */
|
|
65
|
+
port: number;
|
|
66
|
+
geometry: DesktopGeometry;
|
|
67
|
+
/** The raw `OPENGENI_DESKTOP_UP …` marker line, for diagnostics. Never
|
|
68
|
+
* surfaced to viewers. */
|
|
69
|
+
marker: string;
|
|
70
|
+
};
|
|
71
|
+
/**
|
|
72
|
+
* Build the shell command that runs the idempotent up-script under an in-box
|
|
73
|
+
* `flock`. The script is shipped in the image at /usr/local/bin/opengeni-desktop-up
|
|
74
|
+
* (the canonical desktop image); we set the geometry/port env and wrap the call
|
|
75
|
+
* in `flock` so two concurrent ensureDisplayStack callers (the API viewer op +
|
|
76
|
+
* the agent turn, both racing after a rollover) serialize without a double
|
|
77
|
+
* launch. The up-script's own per-stage PID guards make the second call a no-op.
|
|
78
|
+
*
|
|
79
|
+
* Exported (pure, side-effect-free) so the ensureDisplayStack unit test can
|
|
80
|
+
* assert the exact command sequence without a live box.
|
|
81
|
+
*/
|
|
82
|
+
export declare function buildDisplayStackScript(options?: EnsureDisplayStackOptions): string;
|
|
83
|
+
/**
|
|
84
|
+
* Idempotently bring up the desktop display stack on the live box. Safe to call
|
|
85
|
+
* N times (the in-box flock + the up-script's PID guards make a second call a
|
|
86
|
+
* no-op). Resolves with the exposed port + geometry on success; throws
|
|
87
|
+
* `DisplayStackError` on a stage failure and `DisplayStackUnsupportedError` when
|
|
88
|
+
* the session cannot run commands.
|
|
89
|
+
*
|
|
90
|
+
* `session` is the externally-owned provider session (the `established.session`
|
|
91
|
+
* from establishSandboxSessionFromEnvelope, or any SandboxSessionLike). We
|
|
92
|
+
* prefer `session.exec` (structured `{exitCode}`) and fall back to
|
|
93
|
+
* `session.execCommand` (bare string), inferring success from the up-script's
|
|
94
|
+
* marker line in the fallback case.
|
|
95
|
+
*/
|
|
96
|
+
export declare function ensureDisplayStack(session: unknown, options?: EnsureDisplayStackOptions): Promise<EnsureDisplayStackResult>;
|
|
97
|
+
/** Tear the stack down (down-script). Best-effort; never throws on a missing
|
|
98
|
+
* process. Used by the geometry-change restart and cold/drain. */
|
|
99
|
+
export declare function tearDownDisplayStack(session: unknown): Promise<void>;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { SandboxBackend } from "@opengeni/contracts";
|
|
2
|
+
export declare class SandboxConfigError extends Error {
|
|
3
|
+
readonly backend: SandboxBackend | string;
|
|
4
|
+
constructor(backend: SandboxBackend | string, message: string);
|
|
5
|
+
}
|
|
6
|
+
/** A resume-only caller was handed a warm lease without a provider identity it
|
|
7
|
+
* can resume. The lease-aware caller must retire that exact epoch and re-enter
|
|
8
|
+
* admission; silently creating here would bypass the single-spawner guard. */
|
|
9
|
+
export declare class SandboxResumeStateUnavailableError extends Error {
|
|
10
|
+
readonly backend: SandboxBackend | string;
|
|
11
|
+
constructor(backend: SandboxBackend | string);
|
|
12
|
+
}
|
|
13
|
+
export declare class SandboxProviderUnavailableError extends Error {
|
|
14
|
+
readonly backend: SandboxBackend | string;
|
|
15
|
+
constructor(backend: SandboxBackend | string);
|
|
16
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export type ExecResponseBanner = {
|
|
2
|
+
kind: "absent";
|
|
3
|
+
} | {
|
|
4
|
+
kind: "invalid";
|
|
5
|
+
} | {
|
|
6
|
+
kind: "running";
|
|
7
|
+
sessionId: number;
|
|
8
|
+
} | {
|
|
9
|
+
kind: "exited";
|
|
10
|
+
exitCode: number;
|
|
11
|
+
};
|
|
12
|
+
/** Parse exactly one terminal status from the SDK metadata header. Responses
|
|
13
|
+
* that resemble SDK output but lack a complete delimiter/header are invalid,
|
|
14
|
+
* while raw provider output without SDK metadata remains `absent` so callers
|
|
15
|
+
* may use their provider-specific body markers. */
|
|
16
|
+
export declare function parseExecResponseBanner(raw: string): ExecResponseBanner;
|
|
17
|
+
export declare function parseExecBannerSessionId(raw: string): number | null;
|
|
18
|
+
export declare function parseExecBannerExitCode(raw: string): number | null;
|
|
19
|
+
export declare function isExecSessionLostBanner(out: string, execSessionId: number): boolean;
|