@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.
Files changed (79) hide show
  1. package/dist/{chunk-4YJ5Z52Z.js → chunk-7E2ZSCZK.js} +6 -6
  2. package/dist/{chunk-4YJ5Z52Z.js.map → chunk-7E2ZSCZK.js.map} +1 -1
  3. package/dist/{chunk-HHWIZHQM.js → chunk-GNEGANUF.js} +942 -300
  4. package/dist/chunk-GNEGANUF.js.map +1 -0
  5. package/dist/codex-tool-search.d.ts +100 -0
  6. package/dist/context-compaction.d.ts +236 -0
  7. package/dist/history-sanitizer.d.ts +320 -0
  8. package/dist/index.d.ts +186 -718
  9. package/dist/index.js +612 -126
  10. package/dist/index.js.map +1 -1
  11. package/dist/{localSources-T3HZ6KY4.js → localSources-BXHBKGF4.js} +2 -2
  12. package/dist/mcp-network.d.ts +32 -35
  13. package/dist/metrics.d.ts +33 -0
  14. package/dist/sandbox/capabilities.d.ts +11 -0
  15. package/dist/sandbox/channel-a.d.ts +226 -0
  16. package/dist/sandbox/display-stack.d.ts +99 -0
  17. package/dist/sandbox/errors.d.ts +16 -0
  18. package/dist/sandbox/exec-banner.d.ts +19 -0
  19. package/dist/sandbox/index.d.ts +190 -6
  20. package/dist/sandbox/index.js +20 -4
  21. package/dist/sandbox/op-correlation.d.ts +24 -0
  22. package/dist/sandbox/provider-errors.d.ts +32 -0
  23. package/dist/sandbox/provider-operation-gate.d.ts +12 -0
  24. package/dist/sandbox/providers/blaxel.d.ts +2 -0
  25. package/dist/sandbox/providers/cloudflare.d.ts +2 -0
  26. package/dist/sandbox/providers/daytona.d.ts +2 -0
  27. package/dist/sandbox/providers/docker.d.ts +2 -0
  28. package/dist/sandbox/providers/e2b.d.ts +2 -0
  29. package/dist/sandbox/providers/index.d.ts +11 -0
  30. package/dist/sandbox/providers/local.d.ts +2 -0
  31. package/dist/sandbox/providers/modal.d.ts +132 -0
  32. package/dist/sandbox/providers/none.d.ts +2 -0
  33. package/dist/sandbox/providers/runloop.d.ts +2 -0
  34. package/dist/sandbox/providers/selfhosted.d.ts +2 -0
  35. package/dist/sandbox/providers/types.d.ts +30 -0
  36. package/dist/sandbox/providers/vercel.d.ts +2 -0
  37. package/dist/sandbox/recording.d.ts +80 -0
  38. package/dist/sandbox/routing/backend-resolver.d.ts +173 -0
  39. package/dist/sandbox/routing/routing-session.d.ts +401 -0
  40. package/dist/sandbox/run-credentials.d.ts +65 -0
  41. package/dist/sandbox/select.d.ts +120 -0
  42. package/dist/sandbox/selfhosted/capabilities.d.ts +91 -0
  43. package/dist/sandbox/selfhosted/control-rpc.d.ts +175 -0
  44. package/dist/sandbox/selfhosted/fault-rendering.d.ts +40 -0
  45. package/dist/sandbox/selfhosted/op-observer.d.ts +40 -0
  46. package/dist/sandbox/selfhosted/op-stream.d.ts +104 -0
  47. package/dist/sandbox/selfhosted/op-testing.d.ts +108 -0
  48. package/dist/sandbox/selfhosted/op-transport.d.ts +60 -0
  49. package/dist/sandbox/selfhosted/retry-policy.d.ts +106 -0
  50. package/dist/sandbox/selfhosted/session.d.ts +552 -0
  51. package/dist/sandbox/selfhosted/testing.d.ts +48 -0
  52. package/dist/sandbox/stream-port.d.ts +80 -0
  53. package/dist/sandbox/stream-token.d.ts +44 -0
  54. package/dist/sandbox/terminal-server.d.ts +67 -0
  55. package/dist/sandbox/toolspace-token.d.ts +23 -0
  56. package/dist/sandbox/turn-tool-cancellation.d.ts +72 -0
  57. package/dist/sandbox/workspace-archive.d.ts +39 -0
  58. package/dist/sandbox-computer.d.ts +227 -0
  59. package/dist/screenshot-error-card.d.ts +1 -0
  60. package/dist/skill-library.d.ts +10 -12
  61. package/dist/usage-telemetry.d.ts +45 -0
  62. package/dist/workspace-skills.d.ts +31 -0
  63. package/package.json +7 -7
  64. package/src/context-compaction.ts +600 -6
  65. package/src/history-sanitizer.ts +10 -92
  66. package/src/index.ts +301 -62
  67. package/src/sandbox/channel-a.ts +267 -81
  68. package/src/sandbox/index.ts +56 -94
  69. package/src/sandbox/provider-operation-gate.ts +110 -0
  70. package/src/sandbox/providers/docker.ts +13 -1
  71. package/src/sandbox/providers/modal.ts +433 -3
  72. package/src/sandbox/routing/routing-session.ts +84 -8
  73. package/src/sandbox/selfhosted/session.ts +7 -6
  74. package/src/sandbox/turn-tool-cancellation.ts +47 -7
  75. package/src/sandbox/workspace-archive.ts +176 -73
  76. package/src/sandbox-computer.ts +25 -75
  77. package/dist/chunk-HHWIZHQM.js.map +0 -1
  78. package/dist/index-BraazrAO.d.ts +0 -2931
  79. /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-4YJ5Z52Z.js";
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-T3HZ6KY4.js.map
15
+ //# sourceMappingURL=localSources-BXHBKGF4.js.map
@@ -1,33 +1,32 @@
1
- import { Settings } from '@opengeni/config';
2
- import { DnsLookup, isNonPublicAddress } from '@opengeni/network';
3
- export { undiciFetch } from '@opengeni/network';
4
-
5
- declare const MCP_MAX_RESPONSE_BYTES: number;
6
- declare const MCP_MAX_INBOUND_REQUEST_BYTES: number;
7
- declare const MCP_MAX_TOOL_DEFINITION_BYTES: number;
8
- declare const MCP_MAX_TOOL_LIST_BYTES: number;
9
- declare const MCP_MAX_TOOL_LIST_ENTRIES = 1000;
10
- declare const MCP_MAX_TOOL_RESULT_BYTES: number;
11
- declare const MCP_MAX_TOOL_SEARCH_DISCLOSURE_BYTES: number;
12
- declare const MCP_MAX_SELECTED_SERVERS = 64;
13
- declare const MCP_MAX_CONCURRENT_SERVER_OPERATIONS = 8;
14
- declare const MCP_DEFAULT_OUTER_CONNECT_TIMEOUT_MS = 10000;
15
- declare const MCP_MAX_AGGREGATE_TOOL_LIST_ENTRIES = 4096;
16
- declare const MCP_MAX_AGGREGATE_TOOL_LIST_BYTES: number;
17
- declare const MCP_MAX_TOOL_SEARCH_SOURCES = 64;
18
- declare const MCP_MAX_TOOL_SEARCH_SOURCE_LABEL_LENGTH = 120;
19
- declare const MCP_MAX_TOOL_SEARCH_DESCRIPTION_BYTES: number;
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;