@agent-vm/managed-vm 0.0.115

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025-2026 Shravan Sunder
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,290 @@
1
+ //#region src/managed-vm-contracts.d.ts
2
+ /** A command executed in the guest. */
3
+ type ManagedVmExecCommand = string | readonly string[];
4
+ type ManagedVmExecStreamMode = {
5
+ readonly kind: 'discard';
6
+ } | {
7
+ readonly kind: 'pipe';
8
+ };
9
+ /**
10
+ * Explicit bounded streaming policy. Omitting this group preserves the
11
+ * backend's buffered execution behavior for existing non-streaming callers.
12
+ */
13
+ interface ManagedVmExecStreamingOptions {
14
+ readonly stderr: ManagedVmExecStreamMode;
15
+ readonly stdout: ManagedVmExecStreamMode;
16
+ readonly windowBytes: number;
17
+ }
18
+ interface ManagedVmExecOptions {
19
+ readonly argv?: readonly string[];
20
+ readonly cwd?: string;
21
+ readonly env?: readonly string[] | Readonly<Record<string, string>>;
22
+ readonly output?: ManagedVmExecStreamingOptions;
23
+ readonly pty?: boolean;
24
+ readonly signal?: AbortSignal;
25
+ readonly stdin?: string | Uint8Array | AsyncIterable<Uint8Array>;
26
+ }
27
+ interface ManagedVmExecResult {
28
+ readonly exitCode: number;
29
+ readonly ok: boolean;
30
+ readonly signal?: number;
31
+ readonly stderr: string;
32
+ readonly stderrBuffer: Uint8Array;
33
+ readonly stdout: string;
34
+ readonly stdoutBuffer: Uint8Array;
35
+ json<TValue>(): TValue;
36
+ lines(): readonly string[];
37
+ toString(): string;
38
+ }
39
+ /**
40
+ * A guest execution is awaitable and may also stream decoded output. The
41
+ * contract deliberately excludes backend process handles and Node streams.
42
+ */
43
+ interface ManagedVmExecProcess extends PromiseLike<ManagedVmExecResult>, AsyncIterable<string> {
44
+ catch<TResult = never>(onRejected?: (reason: Error) => TResult | PromiseLike<TResult>): Promise<ManagedVmExecResult | TResult>;
45
+ end(): void;
46
+ finally(onFinally?: () => void): Promise<ManagedVmExecResult>;
47
+ lines(): AsyncIterable<string>;
48
+ output(): AsyncIterable<ManagedVmExecOutputChunk>;
49
+ readonly result: Promise<ManagedVmExecResult>;
50
+ resize(rows: number, columns: number): void;
51
+ write(data: string | Uint8Array): void;
52
+ }
53
+ interface ManagedVmExecOutputChunk {
54
+ readonly data: Uint8Array;
55
+ readonly stream: 'stderr' | 'stdout';
56
+ readonly text: string;
57
+ }
58
+ interface ManagedVmSshServerHostKey {
59
+ readonly algorithm: 'ssh-ed25519';
60
+ readonly publicKeyBase64: string;
61
+ }
62
+ interface ManagedVmAccessHandle {
63
+ close(): Promise<void>;
64
+ readonly host: string;
65
+ readonly port: number;
66
+ readonly url?: string;
67
+ }
68
+ interface ManagedVmSshAccess extends ManagedVmAccessHandle {
69
+ readonly command: string;
70
+ readonly identityFile: string;
71
+ readonly serverHostKey: ManagedVmSshServerHostKey;
72
+ readonly user: string;
73
+ }
74
+ interface ManagedVmEnableSshOptions {
75
+ readonly listenHost?: string;
76
+ readonly listenPort?: number;
77
+ readonly user?: string;
78
+ }
79
+ interface ManagedVmIngressOptions {
80
+ readonly allowWebSockets?: boolean;
81
+ readonly listenHost?: string;
82
+ readonly bufferResponseBody?: boolean;
83
+ readonly listenPort?: number;
84
+ readonly maxBufferedResponseBodyBytes?: number;
85
+ readonly upstreamHeaderTimeoutMs?: number;
86
+ readonly upstreamResponseTimeoutMs?: number;
87
+ }
88
+ interface ManagedVmIngressRoute {
89
+ readonly port: number;
90
+ readonly prefix: string;
91
+ readonly stripPrefix: boolean;
92
+ }
93
+ interface ManagedVmResources {
94
+ readonly cpuCount: number;
95
+ readonly memory: string;
96
+ }
97
+ type ManagedVmRootfsMode = 'readonly' | 'memory' | 'cow';
98
+ interface ManagedVmCanonicalDirectoryIdentity {
99
+ /** Canonical path is descriptive identity; it is never a mount authority. */
100
+ readonly canonicalPath: string;
101
+ readonly device: number;
102
+ readonly inode: number;
103
+ }
104
+ type OwnedHostDirectoryState = 'acquired' | 'adapter-owned' | 'closed';
105
+ /**
106
+ * Single-use host-directory authority. Passing this object to createManagedVm
107
+ * authorizes the provider to call consume exactly once. It exposes no native
108
+ * handle, file descriptor, or raw-path fallback.
109
+ */
110
+ interface OwnedHostDirectory {
111
+ close(): void;
112
+ consume(): OwnedHostDirectoryTransfer;
113
+ readonly identity: ManagedVmCanonicalDirectoryIdentity;
114
+ readonly state: OwnedHostDirectoryState;
115
+ }
116
+ /** Ownership retained by the provider after successful consumption. */
117
+ interface OwnedHostDirectoryTransfer {
118
+ close(): void;
119
+ readonly identity: ManagedVmCanonicalDirectoryIdentity;
120
+ readonly state: 'adapter-owned' | 'closed';
121
+ }
122
+ type ManagedVmFilteredWorkspaceVisibility = {
123
+ readonly kind: 'whole-root-writable';
124
+ } | {
125
+ readonly kind: 'positive-paths';
126
+ readonly visiblePaths: readonly string[];
127
+ readonly writablePaths: readonly string[];
128
+ };
129
+ interface ManagedVmFilteredWorkspaceReadonlyInput {
130
+ readonly destinationRelativePath: string;
131
+ readonly sourceRelativePath: string;
132
+ }
133
+ /** Controller-authored policy over one owned canonical workspace root. */
134
+ interface ManagedVmFilteredWorkspacePolicy {
135
+ readonly hiddenPaths: readonly string[];
136
+ readonly readonlyInputs: readonly ManagedVmFilteredWorkspaceReadonlyInput[];
137
+ readonly temporaryPaths: readonly string[];
138
+ readonly visibility: ManagedVmFilteredWorkspaceVisibility;
139
+ }
140
+ type ManagedVmMount = {
141
+ readonly access: 'read-only' | 'read-write';
142
+ readonly hostPath: string;
143
+ readonly kind: 'host-directory';
144
+ } | {
145
+ readonly access: 'read-only' | 'read-write';
146
+ readonly directory: OwnedHostDirectory;
147
+ readonly kind: 'owned-host-directory';
148
+ } | {
149
+ readonly directory: OwnedHostDirectory;
150
+ readonly kind: 'owned-filtered-workspace';
151
+ readonly policy: ManagedVmFilteredWorkspacePolicy;
152
+ } | {
153
+ readonly kind: 'memory';
154
+ } | {
155
+ readonly deny: readonly string[];
156
+ readonly hostPath: string;
157
+ readonly kind: 'shadow';
158
+ readonly temporaryFilesystems: readonly string[];
159
+ };
160
+ interface ManagedVmMediatedSecretDescriptor {
161
+ readonly allowedHosts: readonly string[];
162
+ readonly environmentVariable: string;
163
+ /** Opaque, non-secret token used to represent the mediated value inside the guest. */
164
+ readonly guestPlaceholder?: string;
165
+ /**
166
+ * Resolved only at the trusted host/provider boundary. The provider must use
167
+ * this value solely for outbound HTTP mediation and must never inject the raw
168
+ * value into the guest environment or VM image.
169
+ */
170
+ readonly value: string;
171
+ }
172
+ interface ManagedVmRequestMediation {
173
+ readonly onRequest?: (request: Request) => Promise<Request | Response | void>;
174
+ readonly onResponse?: (response: Response) => Promise<Response | void>;
175
+ }
176
+ interface ManagedVmTcpHostMapping {
177
+ readonly guestHost: string;
178
+ readonly target: string;
179
+ }
180
+ interface ManagedVmGitReadOnlySshEgress {
181
+ readonly allowedHosts: readonly string[];
182
+ readonly allowedRepositories?: readonly string[];
183
+ readonly agentSocket?: string;
184
+ readonly kind: 'git-read-only';
185
+ readonly knownHostsFile?: string;
186
+ }
187
+ interface ManagedVmCreateRequest {
188
+ readonly allowedHosts: readonly string[];
189
+ readonly environment: Readonly<Record<string, string>>;
190
+ readonly imageReference: string;
191
+ readonly mediatedSecrets: readonly ManagedVmMediatedSecretDescriptor[];
192
+ readonly mediation?: ManagedVmRequestMediation;
193
+ readonly mounts: Readonly<Record<string, ManagedVmMount>>;
194
+ readonly resources: ManagedVmResources;
195
+ readonly rootfsMode: ManagedVmRootfsMode;
196
+ readonly runtimeRootfsSize?: string;
197
+ readonly sessionLabel: string;
198
+ readonly sshEgress?: ManagedVmGitReadOnlySshEgress;
199
+ readonly tcpHosts: readonly ManagedVmTcpHostMapping[];
200
+ }
201
+ interface ManagedVm {
202
+ close(): Promise<void>;
203
+ configureIngressRoutes(routes: readonly ManagedVmIngressRoute[]): void;
204
+ enableIngress(options?: ManagedVmIngressOptions): Promise<ManagedVmAccessHandle>;
205
+ enableSsh(options?: ManagedVmEnableSshOptions): Promise<ManagedVmSshAccess>;
206
+ exec(command: ManagedVmExecCommand, options?: ManagedVmExecOptions): ManagedVmExecProcess;
207
+ /** Null before start succeeds or after the owned host process exits. */
208
+ getHostProcessId(): number | null;
209
+ readonly id: string;
210
+ start(): Promise<void>;
211
+ }
212
+ /** Durable controller identity captured before authority admission. */
213
+ interface ManagedVmHostProcessIdentity {
214
+ readonly command: string;
215
+ readonly hostProcessId: number;
216
+ readonly processStartIdentity: string;
217
+ readonly vmId: string;
218
+ }
219
+ interface ManagedVmExactProcessTerminationRequest {
220
+ readonly contextLabel: string;
221
+ readonly identity: ManagedVmHostProcessIdentity;
222
+ }
223
+ type ManagedVmExactProcessTerminationOutcome = {
224
+ readonly hostProcessId: number;
225
+ readonly kind: 'already-absent';
226
+ } | {
227
+ readonly hostProcessId: number;
228
+ readonly kind: 'terminated';
229
+ };
230
+ interface ManagedVmExactProcessTerminationCapability {
231
+ terminateRecordedHostProcess(request: ManagedVmExactProcessTerminationRequest): Promise<ManagedVmExactProcessTerminationOutcome>;
232
+ }
233
+ interface ManagedVmFactory {
234
+ createManagedVm(request: ManagedVmCreateRequest): Promise<ManagedVm>;
235
+ }
236
+ interface ManagedVmImageBuildRequest {
237
+ readonly cacheDirectory: string;
238
+ readonly forceRebuild?: boolean;
239
+ readonly recipePath: string;
240
+ }
241
+ interface ManagedVmImageBuildResult {
242
+ readonly built: boolean;
243
+ readonly fingerprint: string;
244
+ readonly imageReference: string;
245
+ }
246
+ interface ManagedVmImageCapability {
247
+ prepareImage(request: ManagedVmImageBuildRequest): Promise<ManagedVmImageBuildResult>;
248
+ }
249
+ interface ManagedVmCompatibilityDiagnostic {
250
+ readonly code: string;
251
+ readonly message: string;
252
+ readonly severity: 'error' | 'warning';
253
+ }
254
+ interface ManagedVmDiagnosticsCapability {
255
+ checkCompatibility(): Promise<readonly ManagedVmCompatibilityDiagnostic[]>;
256
+ }
257
+ interface ManagedVmOwnedDirectoryCapability {
258
+ openHostDirectory(hostPath: string): OwnedHostDirectory;
259
+ }
260
+ /** Aggregate available only at application composition boundaries. */
261
+ interface ManagedVmProvider {
262
+ readonly diagnostics: ManagedVmDiagnosticsCapability;
263
+ readonly exactProcessTermination: ManagedVmExactProcessTerminationCapability;
264
+ readonly factory: ManagedVmFactory;
265
+ readonly images: ManagedVmImageCapability;
266
+ readonly ownedDirectories: ManagedVmOwnedDirectoryCapability;
267
+ }
268
+ //#endregion
269
+ //#region src/filtered-workspace-policy.d.ts
270
+ /**
271
+ * Validates the complete policy before VM construction reaches a native provider.
272
+ * Paths are rejected rather than silently normalized so one spelling has one meaning.
273
+ */
274
+ declare function validateManagedVmFilteredWorkspacePolicy(policy: ManagedVmFilteredWorkspacePolicy): ManagedVmFilteredWorkspacePolicy;
275
+ //#endregion
276
+ //#region src/owned-host-directory.d.ts
277
+ interface OwnedHostDirectoryControllerOptions {
278
+ readonly identity: ManagedVmCanonicalDirectoryIdentity;
279
+ readonly onClose: () => void;
280
+ readonly onConsume?: () => void;
281
+ }
282
+ /**
283
+ * Creates the backend-neutral half of an owned-directory capability. Native
284
+ * resources remain captured by provider callbacks and never enter this object.
285
+ */
286
+ declare function createOwnedHostDirectoryController(options: OwnedHostDirectoryControllerOptions): OwnedHostDirectory;
287
+ declare function assertPositiveHostProcessId(hostProcessId: number | null): number;
288
+ //#endregion
289
+ export { ManagedVm, ManagedVmAccessHandle, ManagedVmCanonicalDirectoryIdentity, ManagedVmCompatibilityDiagnostic, ManagedVmCreateRequest, ManagedVmDiagnosticsCapability, ManagedVmEnableSshOptions, ManagedVmExactProcessTerminationCapability, ManagedVmExactProcessTerminationOutcome, ManagedVmExactProcessTerminationRequest, ManagedVmExecCommand, ManagedVmExecOptions, ManagedVmExecOutputChunk, ManagedVmExecProcess, ManagedVmExecResult, ManagedVmExecStreamMode, ManagedVmExecStreamingOptions, ManagedVmFactory, ManagedVmFilteredWorkspacePolicy, ManagedVmFilteredWorkspaceReadonlyInput, ManagedVmFilteredWorkspaceVisibility, ManagedVmGitReadOnlySshEgress, ManagedVmHostProcessIdentity, ManagedVmImageBuildRequest, ManagedVmImageBuildResult, ManagedVmImageCapability, ManagedVmIngressOptions, ManagedVmIngressRoute, ManagedVmMediatedSecretDescriptor, ManagedVmMount, ManagedVmOwnedDirectoryCapability, ManagedVmProvider, ManagedVmRequestMediation, ManagedVmResources, ManagedVmRootfsMode, ManagedVmSshAccess, ManagedVmSshServerHostKey, ManagedVmTcpHostMapping, OwnedHostDirectory, OwnedHostDirectoryControllerOptions, OwnedHostDirectoryState, OwnedHostDirectoryTransfer, assertPositiveHostProcessId, createOwnedHostDirectoryController, validateManagedVmFilteredWorkspacePolicy };
290
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/managed-vm-contracts.ts","../src/filtered-workspace-policy.ts","../src/owned-host-directory.ts"],"mappings":"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"}
package/dist/index.js ADDED
@@ -0,0 +1,162 @@
1
+ import path from "node:path";
2
+ //#region src/filtered-workspace-policy.ts
3
+ function assertNormalizedRelativePath(relativePath, fieldName) {
4
+ if (relativePath.length === 0 || relativePath.includes("\0") || relativePath.includes("\\") || relativePath.endsWith("/") || path.posix.isAbsolute(relativePath) || path.posix.normalize(relativePath) !== relativePath || relativePath.split("/").some((segment) => segment === "." || segment === "..")) throw new Error(`${fieldName} must be a normalized workspace-relative path: ${relativePath}`);
5
+ }
6
+ function isEqualOrDescendant(candidatePath, ancestorPath) {
7
+ return candidatePath === ancestorPath || candidatePath.startsWith(`${ancestorPath}/`);
8
+ }
9
+ function pathsOverlap(firstPath, secondPath) {
10
+ return isEqualOrDescendant(firstPath, secondPath) || isEqualOrDescendant(secondPath, firstPath);
11
+ }
12
+ function validatePathSet(paths, label) {
13
+ for (const relativePath of paths) assertNormalizedRelativePath(relativePath, label);
14
+ const seenPaths = /* @__PURE__ */ new Set();
15
+ for (const relativePath of paths) {
16
+ if (seenPaths.has(relativePath)) throw new Error(`Managed filtered workspace policy has a duplicate ${label}: ${relativePath}`);
17
+ seenPaths.add(relativePath);
18
+ }
19
+ for (let pathIndex = 0; pathIndex < paths.length; pathIndex += 1) {
20
+ const firstPath = paths[pathIndex];
21
+ if (!firstPath) continue;
22
+ for (let comparedIndex = pathIndex + 1; comparedIndex < paths.length; comparedIndex += 1) {
23
+ const secondPath = paths[comparedIndex];
24
+ if (secondPath && pathsOverlap(firstPath, secondPath)) throw new Error(`Managed filtered workspace policy has overlapping ${label}s: ${firstPath} and ${secondPath}`);
25
+ }
26
+ }
27
+ }
28
+ function validateReadonlyInputs(readonlyInputs) {
29
+ for (const readonlyInput of readonlyInputs) {
30
+ assertNormalizedRelativePath(readonlyInput.sourceRelativePath, "Read-only input source path");
31
+ assertNormalizedRelativePath(readonlyInput.destinationRelativePath, "Read-only input destination path");
32
+ }
33
+ const destinationPaths = readonlyInputs.map((readonlyInput) => readonlyInput.destinationRelativePath);
34
+ const seenDestinations = /* @__PURE__ */ new Set();
35
+ for (const destinationPath of destinationPaths) {
36
+ if (seenDestinations.has(destinationPath)) throw new Error(`Managed filtered workspace policy has a duplicate read-only destination: ${destinationPath}`);
37
+ seenDestinations.add(destinationPath);
38
+ }
39
+ for (let inputIndex = 0; inputIndex < destinationPaths.length; inputIndex += 1) {
40
+ const firstDestination = destinationPaths[inputIndex];
41
+ if (!firstDestination) continue;
42
+ for (let comparedIndex = inputIndex + 1; comparedIndex < destinationPaths.length; comparedIndex += 1) {
43
+ const secondDestination = destinationPaths[comparedIndex];
44
+ if (secondDestination && pathsOverlap(firstDestination, secondDestination)) throw new Error(`Managed filtered workspace policy has overlapping read-only destinations: ${firstDestination} and ${secondDestination}`);
45
+ }
46
+ }
47
+ }
48
+ function assertWithinPositiveVisibility(relativePath, visiblePaths, fieldName) {
49
+ if (!visiblePaths.some((visiblePath) => isEqualOrDescendant(relativePath, visiblePath))) throw new Error(`${fieldName} '${relativePath}' is outside the positive visibility allowlist.`);
50
+ }
51
+ function readonlyInputSourceIsWritable(readonlyInput, policy) {
52
+ const sourcePath = readonlyInput.sourceRelativePath;
53
+ if (policy.hiddenPaths.some((hiddenPath) => isEqualOrDescendant(sourcePath, hiddenPath)) || policy.temporaryPaths.some((temporaryPath) => isEqualOrDescendant(sourcePath, temporaryPath)) || policy.readonlyInputs.some((candidateInput) => isEqualOrDescendant(sourcePath, candidateInput.destinationRelativePath))) return false;
54
+ if (policy.visibility.kind === "whole-root-writable") return true;
55
+ return policy.visibility.writablePaths.some((writablePath) => isEqualOrDescendant(sourcePath, writablePath));
56
+ }
57
+ /**
58
+ * Validates the complete policy before VM construction reaches a native provider.
59
+ * Paths are rejected rather than silently normalized so one spelling has one meaning.
60
+ */
61
+ function validateManagedVmFilteredWorkspacePolicy(policy) {
62
+ validatePathSet(policy.hiddenPaths, "hidden path");
63
+ validatePathSet(policy.temporaryPaths, "temporary path");
64
+ validateReadonlyInputs(policy.readonlyInputs);
65
+ if (policy.visibility.kind === "positive-paths") {
66
+ validatePathSet(policy.visibility.visiblePaths, "visible path");
67
+ validatePathSet(policy.visibility.writablePaths, "writable path");
68
+ if (policy.visibility.visiblePaths.length === 0) throw new Error("A positive filtered workspace policy must admit at least one visible path.");
69
+ for (const writablePath of policy.visibility.writablePaths) assertWithinPositiveVisibility(writablePath, policy.visibility.visiblePaths, "Writable path");
70
+ for (const temporaryPath of policy.temporaryPaths) assertWithinPositiveVisibility(temporaryPath, policy.visibility.visiblePaths, "Temporary path");
71
+ for (const readonlyInput of policy.readonlyInputs) assertWithinPositiveVisibility(readonlyInput.destinationRelativePath, policy.visibility.visiblePaths, "Read-only destination");
72
+ for (const hiddenPath of policy.hiddenPaths) if (!policy.visibility.visiblePaths.some((visiblePath) => pathsOverlap(hiddenPath, visiblePath))) throw new Error(`Hidden path '${hiddenPath}' is outside the positive visibility allowlist.`);
73
+ }
74
+ for (const readonlyInput of policy.readonlyInputs) {
75
+ if (readonlyInputSourceIsWritable(readonlyInput, policy)) throw new Error(`Read-only input source '${readonlyInput.sourceRelativePath}' remains writable at its original workspace path.`);
76
+ for (const writablePath of policy.visibility.kind === "positive-paths" ? policy.visibility.writablePaths : []) if (writablePath !== readonlyInput.destinationRelativePath && isEqualOrDescendant(writablePath, readonlyInput.destinationRelativePath)) throw new Error(`writable path '${writablePath}' has read-only ancestor '${readonlyInput.destinationRelativePath}'.`);
77
+ }
78
+ return {
79
+ hiddenPaths: [...policy.hiddenPaths],
80
+ readonlyInputs: policy.readonlyInputs.map((readonlyInput) => ({ ...readonlyInput })),
81
+ temporaryPaths: [...policy.temporaryPaths],
82
+ visibility: policy.visibility.kind === "whole-root-writable" ? { kind: "whole-root-writable" } : {
83
+ kind: "positive-paths",
84
+ visiblePaths: [...policy.visibility.visiblePaths],
85
+ writablePaths: [...policy.visibility.writablePaths]
86
+ }
87
+ };
88
+ }
89
+ //#endregion
90
+ //#region src/owned-host-directory.ts
91
+ /**
92
+ * Creates the backend-neutral half of an owned-directory capability. Native
93
+ * resources remain captured by provider callbacks and never enter this object.
94
+ */
95
+ function createOwnedHostDirectoryController(options) {
96
+ let currentState = "acquired";
97
+ let resourceClosed = false;
98
+ let resourceClosing = false;
99
+ const getInternalState = () => currentState;
100
+ const closeResource = () => {
101
+ if (resourceClosed) return true;
102
+ if (resourceClosing) return false;
103
+ resourceClosing = true;
104
+ try {
105
+ options.onClose();
106
+ resourceClosed = true;
107
+ return true;
108
+ } finally {
109
+ resourceClosing = false;
110
+ }
111
+ };
112
+ const transfer = {
113
+ close() {
114
+ if (currentState !== "adapter-owned") return;
115
+ if (closeResource()) currentState = "closed";
116
+ },
117
+ get identity() {
118
+ return options.identity;
119
+ },
120
+ get state() {
121
+ return currentState === "adapter-owned" ? "adapter-owned" : "closed";
122
+ }
123
+ };
124
+ return {
125
+ close() {
126
+ if (currentState === "adapter-owned") throw new Error("Owned host directory cannot be closed by its former owner after transfer.");
127
+ if (getInternalState() === "closed") return;
128
+ if (closeResource()) currentState = "closed";
129
+ },
130
+ consume() {
131
+ if (currentState !== "acquired") throw new Error(`Owned host directory cannot be consumed while ${currentState}.`);
132
+ currentState = "transferring";
133
+ try {
134
+ options.onConsume?.();
135
+ } catch (consumeError) {
136
+ try {
137
+ if (closeResource()) currentState = "closed";
138
+ } catch (closeError) {
139
+ throw new AggregateError([consumeError, closeError], "Owned host directory transfer and cleanup both failed.", { cause: consumeError });
140
+ }
141
+ throw consumeError;
142
+ }
143
+ if (getInternalState() === "closed") throw new Error("Owned host directory closed during ownership transfer.");
144
+ currentState = "adapter-owned";
145
+ return transfer;
146
+ },
147
+ get identity() {
148
+ return options.identity;
149
+ },
150
+ get state() {
151
+ return currentState === "transferring" ? "acquired" : currentState;
152
+ }
153
+ };
154
+ }
155
+ function assertPositiveHostProcessId(hostProcessId) {
156
+ if (!Number.isSafeInteger(hostProcessId) || hostProcessId === null || hostProcessId <= 0) throw new Error("A started managed VM must expose a positive stable host process ID.");
157
+ return hostProcessId;
158
+ }
159
+ //#endregion
160
+ export { assertPositiveHostProcessId, createOwnedHostDirectoryController, validateManagedVmFilteredWorkspacePolicy };
161
+
162
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/filtered-workspace-policy.ts","../src/owned-host-directory.ts"],"sourcesContent":["import path from 'node:path';\n\nimport type {\n\tManagedVmFilteredWorkspacePolicy,\n\tManagedVmFilteredWorkspaceReadonlyInput,\n} from './managed-vm-contracts.js';\n\nfunction assertNormalizedRelativePath(relativePath: string, fieldName: string): void {\n\tif (\n\t\trelativePath.length === 0 ||\n\t\trelativePath.includes('\\0') ||\n\t\trelativePath.includes('\\\\') ||\n\t\trelativePath.endsWith('/') ||\n\t\tpath.posix.isAbsolute(relativePath) ||\n\t\tpath.posix.normalize(relativePath) !== relativePath ||\n\t\trelativePath.split('/').some((segment) => segment === '.' || segment === '..')\n\t) {\n\t\tthrow new Error(`${fieldName} must be a normalized workspace-relative path: ${relativePath}`);\n\t}\n}\n\nfunction isEqualOrDescendant(candidatePath: string, ancestorPath: string): boolean {\n\treturn candidatePath === ancestorPath || candidatePath.startsWith(`${ancestorPath}/`);\n}\n\nfunction pathsOverlap(firstPath: string, secondPath: string): boolean {\n\treturn isEqualOrDescendant(firstPath, secondPath) || isEqualOrDescendant(secondPath, firstPath);\n}\n\nfunction validatePathSet(paths: readonly string[], label: string): void {\n\tfor (const relativePath of paths) {\n\t\tassertNormalizedRelativePath(relativePath, label);\n\t}\n\tconst seenPaths = new Set<string>();\n\tfor (const relativePath of paths) {\n\t\tif (seenPaths.has(relativePath)) {\n\t\t\tthrow new Error(\n\t\t\t\t`Managed filtered workspace policy has a duplicate ${label}: ${relativePath}`,\n\t\t\t);\n\t\t}\n\t\tseenPaths.add(relativePath);\n\t}\n\tfor (let pathIndex = 0; pathIndex < paths.length; pathIndex += 1) {\n\t\tconst firstPath = paths[pathIndex];\n\t\tif (!firstPath) {\n\t\t\tcontinue;\n\t\t}\n\t\tfor (let comparedIndex = pathIndex + 1; comparedIndex < paths.length; comparedIndex += 1) {\n\t\t\tconst secondPath = paths[comparedIndex];\n\t\t\tif (secondPath && pathsOverlap(firstPath, secondPath)) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Managed filtered workspace policy has overlapping ${label}s: ${firstPath} and ${secondPath}`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunction validateReadonlyInputs(\n\treadonlyInputs: readonly ManagedVmFilteredWorkspaceReadonlyInput[],\n): void {\n\tfor (const readonlyInput of readonlyInputs) {\n\t\tassertNormalizedRelativePath(readonlyInput.sourceRelativePath, 'Read-only input source path');\n\t\tassertNormalizedRelativePath(\n\t\t\treadonlyInput.destinationRelativePath,\n\t\t\t'Read-only input destination path',\n\t\t);\n\t}\n\tconst destinationPaths = readonlyInputs.map(\n\t\t(readonlyInput) => readonlyInput.destinationRelativePath,\n\t);\n\tconst seenDestinations = new Set<string>();\n\tfor (const destinationPath of destinationPaths) {\n\t\tif (seenDestinations.has(destinationPath)) {\n\t\t\tthrow new Error(\n\t\t\t\t`Managed filtered workspace policy has a duplicate read-only destination: ${destinationPath}`,\n\t\t\t);\n\t\t}\n\t\tseenDestinations.add(destinationPath);\n\t}\n\tfor (let inputIndex = 0; inputIndex < destinationPaths.length; inputIndex += 1) {\n\t\tconst firstDestination = destinationPaths[inputIndex];\n\t\tif (!firstDestination) {\n\t\t\tcontinue;\n\t\t}\n\t\tfor (\n\t\t\tlet comparedIndex = inputIndex + 1;\n\t\t\tcomparedIndex < destinationPaths.length;\n\t\t\tcomparedIndex += 1\n\t\t) {\n\t\t\tconst secondDestination = destinationPaths[comparedIndex];\n\t\t\tif (secondDestination && pathsOverlap(firstDestination, secondDestination)) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Managed filtered workspace policy has overlapping read-only destinations: ${firstDestination} and ${secondDestination}`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunction assertWithinPositiveVisibility(\n\trelativePath: string,\n\tvisiblePaths: readonly string[],\n\tfieldName: string,\n): void {\n\tif (!visiblePaths.some((visiblePath) => isEqualOrDescendant(relativePath, visiblePath))) {\n\t\tthrow new Error(`${fieldName} '${relativePath}' is outside the positive visibility allowlist.`);\n\t}\n}\n\nfunction readonlyInputSourceIsWritable(\n\treadonlyInput: ManagedVmFilteredWorkspaceReadonlyInput,\n\tpolicy: ManagedVmFilteredWorkspacePolicy,\n): boolean {\n\tconst sourcePath = readonlyInput.sourceRelativePath;\n\tif (\n\t\tpolicy.hiddenPaths.some((hiddenPath) => isEqualOrDescendant(sourcePath, hiddenPath)) ||\n\t\tpolicy.temporaryPaths.some((temporaryPath) => isEqualOrDescendant(sourcePath, temporaryPath)) ||\n\t\tpolicy.readonlyInputs.some((candidateInput) =>\n\t\t\tisEqualOrDescendant(sourcePath, candidateInput.destinationRelativePath),\n\t\t)\n\t) {\n\t\treturn false;\n\t}\n\tif (policy.visibility.kind === 'whole-root-writable') {\n\t\treturn true;\n\t}\n\treturn policy.visibility.writablePaths.some((writablePath) =>\n\t\tisEqualOrDescendant(sourcePath, writablePath),\n\t);\n}\n\n/**\n * Validates the complete policy before VM construction reaches a native provider.\n * Paths are rejected rather than silently normalized so one spelling has one meaning.\n */\nexport function validateManagedVmFilteredWorkspacePolicy(\n\tpolicy: ManagedVmFilteredWorkspacePolicy,\n): ManagedVmFilteredWorkspacePolicy {\n\tvalidatePathSet(policy.hiddenPaths, 'hidden path');\n\tvalidatePathSet(policy.temporaryPaths, 'temporary path');\n\tvalidateReadonlyInputs(policy.readonlyInputs);\n\n\tif (policy.visibility.kind === 'positive-paths') {\n\t\tvalidatePathSet(policy.visibility.visiblePaths, 'visible path');\n\t\tvalidatePathSet(policy.visibility.writablePaths, 'writable path');\n\t\tif (policy.visibility.visiblePaths.length === 0) {\n\t\t\tthrow new Error('A positive filtered workspace policy must admit at least one visible path.');\n\t\t}\n\t\tfor (const writablePath of policy.visibility.writablePaths) {\n\t\t\tassertWithinPositiveVisibility(writablePath, policy.visibility.visiblePaths, 'Writable path');\n\t\t}\n\t\tfor (const temporaryPath of policy.temporaryPaths) {\n\t\t\tassertWithinPositiveVisibility(\n\t\t\t\ttemporaryPath,\n\t\t\t\tpolicy.visibility.visiblePaths,\n\t\t\t\t'Temporary path',\n\t\t\t);\n\t\t}\n\t\tfor (const readonlyInput of policy.readonlyInputs) {\n\t\t\tassertWithinPositiveVisibility(\n\t\t\t\treadonlyInput.destinationRelativePath,\n\t\t\t\tpolicy.visibility.visiblePaths,\n\t\t\t\t'Read-only destination',\n\t\t\t);\n\t\t}\n\t\tfor (const hiddenPath of policy.hiddenPaths) {\n\t\t\tif (\n\t\t\t\t!policy.visibility.visiblePaths.some((visiblePath) => pathsOverlap(hiddenPath, visiblePath))\n\t\t\t) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Hidden path '${hiddenPath}' is outside the positive visibility allowlist.`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\tfor (const readonlyInput of policy.readonlyInputs) {\n\t\tif (readonlyInputSourceIsWritable(readonlyInput, policy)) {\n\t\t\tthrow new Error(\n\t\t\t\t`Read-only input source '${readonlyInput.sourceRelativePath}' remains writable at its original workspace path.`,\n\t\t\t);\n\t\t}\n\t\tfor (const writablePath of policy.visibility.kind === 'positive-paths'\n\t\t\t? policy.visibility.writablePaths\n\t\t\t: []) {\n\t\t\tif (\n\t\t\t\twritablePath !== readonlyInput.destinationRelativePath &&\n\t\t\t\tisEqualOrDescendant(writablePath, readonlyInput.destinationRelativePath)\n\t\t\t) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`writable path '${writablePath}' has read-only ancestor '${readonlyInput.destinationRelativePath}'.`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\treturn {\n\t\thiddenPaths: [...policy.hiddenPaths],\n\t\treadonlyInputs: policy.readonlyInputs.map((readonlyInput) => ({ ...readonlyInput })),\n\t\ttemporaryPaths: [...policy.temporaryPaths],\n\t\tvisibility:\n\t\t\tpolicy.visibility.kind === 'whole-root-writable'\n\t\t\t\t? { kind: 'whole-root-writable' }\n\t\t\t\t: {\n\t\t\t\t\t\tkind: 'positive-paths',\n\t\t\t\t\t\tvisiblePaths: [...policy.visibility.visiblePaths],\n\t\t\t\t\t\twritablePaths: [...policy.visibility.writablePaths],\n\t\t\t\t\t},\n\t};\n}\n","import type {\n\tManagedVmCanonicalDirectoryIdentity,\n\tOwnedHostDirectory,\n\tOwnedHostDirectoryState,\n\tOwnedHostDirectoryTransfer,\n} from './managed-vm-contracts.js';\n\nexport interface OwnedHostDirectoryControllerOptions {\n\treadonly identity: ManagedVmCanonicalDirectoryIdentity;\n\treadonly onClose: () => void;\n\treadonly onConsume?: () => void;\n}\n\n/**\n * Creates the backend-neutral half of an owned-directory capability. Native\n * resources remain captured by provider callbacks and never enter this object.\n */\nexport function createOwnedHostDirectoryController(\n\toptions: OwnedHostDirectoryControllerOptions,\n): OwnedHostDirectory {\n\ttype InternalOwnedHostDirectoryState = OwnedHostDirectoryState | 'transferring';\n\tlet currentState: InternalOwnedHostDirectoryState = 'acquired';\n\tlet resourceClosed = false;\n\tlet resourceClosing = false;\n\tconst getInternalState = (): InternalOwnedHostDirectoryState => currentState;\n\n\tconst closeResource = (): boolean => {\n\t\tif (resourceClosed) {\n\t\t\treturn true;\n\t\t}\n\t\tif (resourceClosing) {\n\t\t\treturn false;\n\t\t}\n\t\tresourceClosing = true;\n\t\ttry {\n\t\t\toptions.onClose();\n\t\t\tresourceClosed = true;\n\t\t\treturn true;\n\t\t} finally {\n\t\t\tresourceClosing = false;\n\t\t}\n\t};\n\n\tconst transfer: OwnedHostDirectoryTransfer = {\n\t\tclose(): void {\n\t\t\tif (currentState !== 'adapter-owned') {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (closeResource()) {\n\t\t\t\tcurrentState = 'closed';\n\t\t\t}\n\t\t},\n\t\tget identity(): ManagedVmCanonicalDirectoryIdentity {\n\t\t\treturn options.identity;\n\t\t},\n\t\tget state(): 'adapter-owned' | 'closed' {\n\t\t\treturn currentState === 'adapter-owned' ? 'adapter-owned' : 'closed';\n\t\t},\n\t};\n\n\treturn {\n\t\tclose(): void {\n\t\t\tif (currentState === 'adapter-owned') {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t'Owned host directory cannot be closed by its former owner after transfer.',\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (getInternalState() === 'closed') {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (closeResource()) {\n\t\t\t\tcurrentState = 'closed';\n\t\t\t}\n\t\t},\n\t\tconsume(): OwnedHostDirectoryTransfer {\n\t\t\tif (currentState !== 'acquired') {\n\t\t\t\tthrow new Error(`Owned host directory cannot be consumed while ${currentState}.`);\n\t\t\t}\n\t\t\tcurrentState = 'transferring';\n\t\t\ttry {\n\t\t\t\toptions.onConsume?.();\n\t\t\t} catch (consumeError) {\n\t\t\t\ttry {\n\t\t\t\t\tif (closeResource()) {\n\t\t\t\t\t\tcurrentState = 'closed';\n\t\t\t\t\t}\n\t\t\t\t} catch (closeError) {\n\t\t\t\t\t// oxlint-disable-next-line preserve-caught-error -- AggregateError.errors retains cleanup failure while cause retains the transfer failure.\n\t\t\t\t\tthrow new AggregateError(\n\t\t\t\t\t\t[consumeError, closeError],\n\t\t\t\t\t\t'Owned host directory transfer and cleanup both failed.',\n\t\t\t\t\t\t{ cause: consumeError },\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tthrow consumeError;\n\t\t\t}\n\t\t\tif (getInternalState() === 'closed') {\n\t\t\t\tthrow new Error('Owned host directory closed during ownership transfer.');\n\t\t\t}\n\t\t\tcurrentState = 'adapter-owned';\n\t\t\treturn transfer;\n\t\t},\n\t\tget identity(): ManagedVmCanonicalDirectoryIdentity {\n\t\t\treturn options.identity;\n\t\t},\n\t\tget state(): OwnedHostDirectoryState {\n\t\t\treturn currentState === 'transferring' ? 'acquired' : currentState;\n\t\t},\n\t};\n}\n\nexport function assertPositiveHostProcessId(hostProcessId: number | null): number {\n\tif (!Number.isSafeInteger(hostProcessId) || hostProcessId === null || hostProcessId <= 0) {\n\t\tthrow new Error('A started managed VM must expose a positive stable host process ID.');\n\t}\n\treturn hostProcessId;\n}\n"],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "@agent-vm/managed-vm",
3
+ "version": "0.0.115",
4
+ "description": "Backend-neutral managed VM contracts and ownership semantics for agent-vm.",
5
+ "homepage": "https://github.com/ShravanSunder/agent-vm#readme",
6
+ "bugs": {
7
+ "url": "https://github.com/ShravanSunder/agent-vm/issues"
8
+ },
9
+ "license": "MIT",
10
+ "author": "Shravan Sunder <ShravanSunder@users.noreply.github.com>",
11
+ "repository": {
12
+ "type": "git",
13
+ "url": "git+https://github.com/ShravanSunder/agent-vm.git",
14
+ "directory": "packages/managed-vm"
15
+ },
16
+ "files": [
17
+ "dist"
18
+ ],
19
+ "type": "module",
20
+ "main": "./dist/index.js",
21
+ "types": "./dist/index.d.ts",
22
+ "exports": {
23
+ ".": {
24
+ "types": "./dist/index.d.ts",
25
+ "import": "./dist/index.js"
26
+ }
27
+ },
28
+ "publishConfig": {
29
+ "access": "public"
30
+ },
31
+ "devDependencies": {
32
+ "vitest": "^4.1.5"
33
+ },
34
+ "scripts": {
35
+ "build": "tsdown",
36
+ "typecheck": "tsc -p tsconfig.json --noEmit",
37
+ "test": "pnpm test:unit",
38
+ "test:unit": "vitest run --root ../../ --config vitest.config.ts --project unit packages/managed-vm/src"
39
+ }
40
+ }