@rivet-dev/agentos-core 0.0.0-nathan-agentos-combined.e833bb7 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent-os.d.ts +1 -0
- package/dist/agent-os.js +241 -26
- package/dist/host-tools.js +9 -0
- package/dist/options-schema.d.ts +2 -2
- package/dist/options-schema.js +1 -1
- package/dist/packages.d.ts +22 -0
- package/dist/packages.js +31 -0
- package/dist/runtime-compat.d.ts +2 -2
- package/dist/runtime-compat.js +67 -49
- package/dist/runtime.d.ts +2 -2
- package/dist/sidecar/native-process-client.d.ts +3 -1
- package/dist/sidecar/native-process-client.js +3 -1
- package/dist/sidecar/permissions.js +3 -3
- package/dist/sidecar/rpc-client.d.ts +26 -3
- package/dist/sidecar/rpc-client.js +74 -6
- package/package.json +6 -6
package/dist/agent-os.d.ts
CHANGED
package/dist/agent-os.js
CHANGED
|
@@ -50,7 +50,7 @@ import { snapshotVirtualFilesystem, sortFilesystemEntries, } from "./filesystem-
|
|
|
50
50
|
import { createHostDirBackend } from "./host-dir-mount.js";
|
|
51
51
|
import { serializeMountConfigForSidecar, } from "./js-bridge.js";
|
|
52
52
|
import { createSnapshotExport, } from "./layers.js";
|
|
53
|
-
import { processSoftware, resolvePackageDir, } from "./packages.js";
|
|
53
|
+
import { processSoftware, resolveAgentSnapshotBundle, resolvePackageDir, } from "./packages.js";
|
|
54
54
|
import { allowAll } from "./runtime-compat.js";
|
|
55
55
|
import { AcpRuntimeKind, decodeAcpCallback, decodeAcpEvent, decodeAcpResponse, encodeAcpCallbackResponse, encodeAcpRequest, } from "./sidecar/agentos-protocol.js";
|
|
56
56
|
import { serializePermissionsForSidecar } from "./sidecar/permissions.js";
|
|
@@ -802,6 +802,16 @@ function collectSidecarMountPlan(options) {
|
|
|
802
802
|
}
|
|
803
803
|
for (const mount of options.mounts ?? []) {
|
|
804
804
|
if (!isNativeMountConfig(mount)) {
|
|
805
|
+
sidecarMounts.push({
|
|
806
|
+
guestPath: mount.path,
|
|
807
|
+
readOnly: isOverlayMountConfig(mount)
|
|
808
|
+
? (mount.filesystem.mode ?? "ephemeral") === "read-only"
|
|
809
|
+
: (mount.readOnly ?? false),
|
|
810
|
+
plugin: {
|
|
811
|
+
id: "js_bridge",
|
|
812
|
+
config: {},
|
|
813
|
+
},
|
|
814
|
+
});
|
|
805
815
|
continue;
|
|
806
816
|
}
|
|
807
817
|
pushMount(mount);
|
|
@@ -1044,7 +1054,7 @@ async function handleHostCallback(request, context) {
|
|
|
1044
1054
|
return {
|
|
1045
1055
|
type: "host_callback_result",
|
|
1046
1056
|
invocation_id: payload.invocation_id,
|
|
1047
|
-
error: `EACCES: blocked by
|
|
1057
|
+
error: `EACCES: blocked by binding.invoke policy for ${payload.callback_key}`,
|
|
1048
1058
|
};
|
|
1049
1059
|
}
|
|
1050
1060
|
const parsed = tool.inputSchema.safeParse(payload.input);
|
|
@@ -1079,6 +1089,134 @@ function buildToolMap(toolKits) {
|
|
|
1079
1089
|
}
|
|
1080
1090
|
return toolMap;
|
|
1081
1091
|
}
|
|
1092
|
+
function bridgeErrorMessage(error) {
|
|
1093
|
+
return error instanceof Error ? error.message : String(error);
|
|
1094
|
+
}
|
|
1095
|
+
function toBridgeArgs(value) {
|
|
1096
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
1097
|
+
throw new Error("js_bridge args must be an object");
|
|
1098
|
+
}
|
|
1099
|
+
return value;
|
|
1100
|
+
}
|
|
1101
|
+
function bridgePath(mountId, value) {
|
|
1102
|
+
if (!mountId.startsWith("/")) {
|
|
1103
|
+
throw new Error(`Unsupported js_bridge mount id: ${mountId}`);
|
|
1104
|
+
}
|
|
1105
|
+
if (typeof value !== "string") {
|
|
1106
|
+
throw new Error("js_bridge path argument must be a string");
|
|
1107
|
+
}
|
|
1108
|
+
return posixPath.normalize(posixPath.join(mountId, value));
|
|
1109
|
+
}
|
|
1110
|
+
function requireBridgeNumber(value, field) {
|
|
1111
|
+
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
1112
|
+
throw new Error(`js_bridge args.${field} must be a number`);
|
|
1113
|
+
}
|
|
1114
|
+
return value;
|
|
1115
|
+
}
|
|
1116
|
+
function decodeBridgeBytes(value, field) {
|
|
1117
|
+
if (typeof value === "string") {
|
|
1118
|
+
return new Uint8Array(Buffer.from(value, "base64"));
|
|
1119
|
+
}
|
|
1120
|
+
if (Array.isArray(value) &&
|
|
1121
|
+
value.every((entry) => Number.isInteger(entry) && entry >= 0 && entry <= 255)) {
|
|
1122
|
+
return new Uint8Array(value);
|
|
1123
|
+
}
|
|
1124
|
+
throw new Error(`js_bridge args.${field} must be base64 bytes`);
|
|
1125
|
+
}
|
|
1126
|
+
async function handleJsBridgeCall(request, context) {
|
|
1127
|
+
try {
|
|
1128
|
+
const args = toBridgeArgs(request.args);
|
|
1129
|
+
const fs = context.filesystem;
|
|
1130
|
+
const path = () => bridgePath(request.mount_id, args.path);
|
|
1131
|
+
let result;
|
|
1132
|
+
switch (request.operation) {
|
|
1133
|
+
case "readFile":
|
|
1134
|
+
result = Buffer.from(await fs.readFile(path())).toString("base64");
|
|
1135
|
+
break;
|
|
1136
|
+
case "readDir":
|
|
1137
|
+
result = await fs.readDir(path());
|
|
1138
|
+
break;
|
|
1139
|
+
case "readDirWithTypes":
|
|
1140
|
+
result = await fs.readDirWithTypes(path());
|
|
1141
|
+
break;
|
|
1142
|
+
case "writeFile":
|
|
1143
|
+
await fs.writeFile(path(), decodeBridgeBytes(args.content, "content"));
|
|
1144
|
+
break;
|
|
1145
|
+
case "createDir":
|
|
1146
|
+
await fs.createDir(path());
|
|
1147
|
+
break;
|
|
1148
|
+
case "mkdir":
|
|
1149
|
+
await fs.mkdir(path(), { recursive: args.recursive !== false });
|
|
1150
|
+
break;
|
|
1151
|
+
case "exists":
|
|
1152
|
+
result = await fs.exists(path());
|
|
1153
|
+
break;
|
|
1154
|
+
case "stat":
|
|
1155
|
+
result = await fs.stat(path());
|
|
1156
|
+
break;
|
|
1157
|
+
case "removeFile":
|
|
1158
|
+
await fs.removeFile(path());
|
|
1159
|
+
break;
|
|
1160
|
+
case "removeDir":
|
|
1161
|
+
await fs.removeDir(path());
|
|
1162
|
+
break;
|
|
1163
|
+
case "rename":
|
|
1164
|
+
await fs.rename(bridgePath(request.mount_id, args.oldPath), bridgePath(request.mount_id, args.newPath));
|
|
1165
|
+
break;
|
|
1166
|
+
case "realpath":
|
|
1167
|
+
result = await fs.realpath(path());
|
|
1168
|
+
break;
|
|
1169
|
+
case "symlink": {
|
|
1170
|
+
if (typeof args.target !== "string") {
|
|
1171
|
+
throw new Error("js_bridge args.target must be a string");
|
|
1172
|
+
}
|
|
1173
|
+
await fs.symlink(args.target, bridgePath(request.mount_id, args.linkPath));
|
|
1174
|
+
break;
|
|
1175
|
+
}
|
|
1176
|
+
case "readlink":
|
|
1177
|
+
result = await fs.readlink(path());
|
|
1178
|
+
break;
|
|
1179
|
+
case "lstat":
|
|
1180
|
+
result = await fs.lstat(path());
|
|
1181
|
+
break;
|
|
1182
|
+
case "link":
|
|
1183
|
+
await fs.link(bridgePath(request.mount_id, args.oldPath), bridgePath(request.mount_id, args.newPath));
|
|
1184
|
+
break;
|
|
1185
|
+
case "chmod":
|
|
1186
|
+
await fs.chmod(path(), requireBridgeNumber(args.mode, "mode"));
|
|
1187
|
+
break;
|
|
1188
|
+
case "chown":
|
|
1189
|
+
await fs.chown(path(), requireBridgeNumber(args.uid, "uid"), requireBridgeNumber(args.gid, "gid"));
|
|
1190
|
+
break;
|
|
1191
|
+
case "utimes":
|
|
1192
|
+
await fs.utimes(path(), requireBridgeNumber(args.atimeMs, "atimeMs"), requireBridgeNumber(args.mtimeMs, "mtimeMs"));
|
|
1193
|
+
break;
|
|
1194
|
+
case "truncate":
|
|
1195
|
+
await fs.truncate(path(), requireBridgeNumber(args.length, "length"));
|
|
1196
|
+
break;
|
|
1197
|
+
case "pread":
|
|
1198
|
+
result = Buffer.from(await fs.pread(path(), requireBridgeNumber(args.offset, "offset"), requireBridgeNumber(args.length, "length"))).toString("base64");
|
|
1199
|
+
break;
|
|
1200
|
+
case "pwrite":
|
|
1201
|
+
await fs.pwrite(path(), requireBridgeNumber(args.offset, "offset"), decodeBridgeBytes(args.content, "content"));
|
|
1202
|
+
break;
|
|
1203
|
+
default:
|
|
1204
|
+
throw new Error(`Unsupported js_bridge operation: ${request.operation}`);
|
|
1205
|
+
}
|
|
1206
|
+
return {
|
|
1207
|
+
type: "js_bridge_result",
|
|
1208
|
+
call_id: request.call_id,
|
|
1209
|
+
...(result === undefined ? {} : { result }),
|
|
1210
|
+
};
|
|
1211
|
+
}
|
|
1212
|
+
catch (error) {
|
|
1213
|
+
return {
|
|
1214
|
+
type: "js_bridge_result",
|
|
1215
|
+
call_id: request.call_id,
|
|
1216
|
+
error: bridgeErrorMessage(error),
|
|
1217
|
+
};
|
|
1218
|
+
}
|
|
1219
|
+
}
|
|
1082
1220
|
function parseHostCommandCallbackInput(input) {
|
|
1083
1221
|
const value = asRecord(input);
|
|
1084
1222
|
if (value.type !== "command" ||
|
|
@@ -1159,7 +1297,7 @@ async function invokeHostTool({ toolKit, toolName, args, cwd, context, }) {
|
|
|
1159
1297
|
const callbackKey = `${toolKit.name}:${toolName}`;
|
|
1160
1298
|
const permissionMode = toolPermissionMode(context.permissions, callbackKey);
|
|
1161
1299
|
if (permissionMode !== "allow") {
|
|
1162
|
-
throw new Error(`EACCES: blocked by
|
|
1300
|
+
throw new Error(`EACCES: blocked by binding.invoke policy for ${callbackKey}`);
|
|
1163
1301
|
}
|
|
1164
1302
|
const input = await parseHostToolInput(tool, args, cwd, context.readFile);
|
|
1165
1303
|
return executeHostTool(tool, callbackKey, input);
|
|
@@ -1315,7 +1453,7 @@ function describeToolPayload(toolKit, toolName) {
|
|
|
1315
1453
|
};
|
|
1316
1454
|
}
|
|
1317
1455
|
function toolPermissionMode(permissions, callbackKey) {
|
|
1318
|
-
const scope = permissions.
|
|
1456
|
+
const scope = permissions.binding;
|
|
1319
1457
|
if (!scope) {
|
|
1320
1458
|
return "deny";
|
|
1321
1459
|
}
|
|
@@ -1403,13 +1541,14 @@ export class AgentOs {
|
|
|
1403
1541
|
_hostMounts;
|
|
1404
1542
|
_env;
|
|
1405
1543
|
_rootFilesystem;
|
|
1544
|
+
_additionalInstructions;
|
|
1406
1545
|
_sidecarLease = null;
|
|
1407
1546
|
_sidecarClient;
|
|
1408
1547
|
_sidecarSession;
|
|
1409
1548
|
_sidecarVm;
|
|
1410
1549
|
_disposeSidecarEventListener;
|
|
1411
1550
|
_agentStderrHandler;
|
|
1412
|
-
constructor(kernel, sidecar, softwareRoots, softwareAgentConfigs, hostMounts, env, rootFilesystem, sidecarClient, sidecarSession, sidecarVm, agentStderrHandler) {
|
|
1551
|
+
constructor(kernel, sidecar, softwareRoots, softwareAgentConfigs, hostMounts, env, rootFilesystem, sidecarClient, sidecarSession, sidecarVm, additionalInstructions, agentStderrHandler) {
|
|
1413
1552
|
this.#kernel = kernel;
|
|
1414
1553
|
this.sidecar = sidecar;
|
|
1415
1554
|
this._softwareRoots = softwareRoots;
|
|
@@ -1420,6 +1559,7 @@ export class AgentOs {
|
|
|
1420
1559
|
this._sidecarClient = sidecarClient;
|
|
1421
1560
|
this._sidecarSession = sidecarSession;
|
|
1422
1561
|
this._sidecarVm = sidecarVm;
|
|
1562
|
+
this._additionalInstructions = additionalInstructions;
|
|
1423
1563
|
this._agentStderrHandler = agentStderrHandler;
|
|
1424
1564
|
this._disposeSidecarEventListener = this._sidecarClient.onEvent((event) => {
|
|
1425
1565
|
this._handleSidecarEvent(event);
|
|
@@ -1443,11 +1583,17 @@ export class AgentOs {
|
|
|
1443
1583
|
? (options.software ?? [])
|
|
1444
1584
|
: [commonSoftware, ...(options?.software ?? [])];
|
|
1445
1585
|
const processed = processSoftware(software);
|
|
1586
|
+
// Agent-SDK snapshot bundle (loaded once per sidecar into the V8 startup
|
|
1587
|
+
// snapshot, reused across sessions) for any snapshot-enabled agent.
|
|
1588
|
+
const snapshotUserlandCode = resolveAgentSnapshotBundle(software);
|
|
1446
1589
|
const localMounts = await resolveCompatLocalMounts(options?.mounts);
|
|
1447
1590
|
const toolKits = options?.toolKits;
|
|
1448
1591
|
if (toolKits && toolKits.length > 0) {
|
|
1449
1592
|
validateToolkits(toolKits);
|
|
1450
1593
|
}
|
|
1594
|
+
// Resolve the sidecar handle up front so every VM created here leases the
|
|
1595
|
+
// one shared native sidecar process owned by that handle.
|
|
1596
|
+
const sidecar = resolveAgentOsSidecar(options?.sidecar);
|
|
1451
1597
|
const createVmAdmin = async () => {
|
|
1452
1598
|
const preparedCommandDirs = prepareCommandDirs(processed.commandPackages);
|
|
1453
1599
|
const toolBootstrapCommands = collectToolkitBootstrapCommands(toolKits ?? []);
|
|
@@ -1460,6 +1606,8 @@ export class AgentOs {
|
|
|
1460
1606
|
let rootBridge = null;
|
|
1461
1607
|
let kernel = null;
|
|
1462
1608
|
let client = null;
|
|
1609
|
+
let createdNativeVm = null;
|
|
1610
|
+
let nativeSession = null;
|
|
1463
1611
|
let toolShimDir = null;
|
|
1464
1612
|
let cleanedUp = false;
|
|
1465
1613
|
const cleanup = async () => {
|
|
@@ -1498,16 +1646,15 @@ export class AgentOs {
|
|
|
1498
1646
|
commandDirs: preparedCommandDirs.commandDirs,
|
|
1499
1647
|
shimDir: toolShimDir,
|
|
1500
1648
|
});
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
const session = await client.authenticateAndOpenSession();
|
|
1649
|
+
// Reuse the sidecar handle's single shared native process; this VM
|
|
1650
|
+
// becomes another tenant of it rather than spawning its own process.
|
|
1651
|
+
const shared = await ensureSharedSidecarNativeProcess(sidecar);
|
|
1652
|
+
client = shared.client;
|
|
1653
|
+
const session = shared.session;
|
|
1654
|
+
nativeSession = session;
|
|
1508
1655
|
const hostPermissions = options?.permissions ?? {
|
|
1509
1656
|
...allowAll,
|
|
1510
|
-
|
|
1657
|
+
binding: "allow",
|
|
1511
1658
|
};
|
|
1512
1659
|
const sidecarPermissions = serializePermissionsForSidecar(hostPermissions);
|
|
1513
1660
|
const createVmConfig = {
|
|
@@ -1522,12 +1669,18 @@ export class AgentOs {
|
|
|
1522
1669
|
// module resolution keep their engine defaults (full Node
|
|
1523
1670
|
// emulation), matching the prior behavior where Agent OS only
|
|
1524
1671
|
// constrained the builtin allow-list.
|
|
1525
|
-
...(options?.allowedNodeBuiltins !== undefined
|
|
1672
|
+
...(options?.allowedNodeBuiltins !== undefined ||
|
|
1673
|
+
snapshotUserlandCode !== undefined
|
|
1526
1674
|
? {
|
|
1527
1675
|
jsRuntime: {
|
|
1528
1676
|
platform: "node",
|
|
1529
1677
|
moduleResolution: "node",
|
|
1530
|
-
|
|
1678
|
+
...(options?.allowedNodeBuiltins !== undefined
|
|
1679
|
+
? { allowedBuiltins: options.allowedNodeBuiltins }
|
|
1680
|
+
: {}),
|
|
1681
|
+
...(snapshotUserlandCode !== undefined
|
|
1682
|
+
? { snapshotUserlandCode }
|
|
1683
|
+
: {}),
|
|
1531
1684
|
},
|
|
1532
1685
|
}
|
|
1533
1686
|
: {}),
|
|
@@ -1536,8 +1689,13 @@ export class AgentOs {
|
|
|
1536
1689
|
runtime: "java_script",
|
|
1537
1690
|
config: createVmConfig,
|
|
1538
1691
|
});
|
|
1692
|
+
createdNativeVm = nativeVm;
|
|
1693
|
+
// Scope the readiness wait to THIS VM's ownership; on a shared process
|
|
1694
|
+
// other VMs are emitting their own lifecycle events concurrently.
|
|
1539
1695
|
await client.waitForEvent((event) => event.payload.type === "vm_lifecycle" &&
|
|
1540
|
-
event.payload.state === "ready"
|
|
1696
|
+
event.payload.state === "ready" &&
|
|
1697
|
+
event.ownership.scope === "vm" &&
|
|
1698
|
+
event.ownership.vm_id === nativeVm.vmId, 10_000);
|
|
1541
1699
|
await client.configureVm(session, nativeVm, {
|
|
1542
1700
|
mounts: sidecarMounts,
|
|
1543
1701
|
permissions: sidecarPermissions,
|
|
@@ -1558,8 +1716,15 @@ export class AgentOs {
|
|
|
1558
1716
|
env,
|
|
1559
1717
|
cwd: "/workspace",
|
|
1560
1718
|
localMounts,
|
|
1719
|
+
sidecarMounts,
|
|
1720
|
+
permissions: sidecarPermissions,
|
|
1721
|
+
commandPermissions: processed.commandPermissions,
|
|
1722
|
+
loopbackExemptPorts: options?.loopbackExemptPorts,
|
|
1561
1723
|
commandGuestPaths,
|
|
1562
1724
|
onDispose: cleanup,
|
|
1725
|
+
// The native process is owned by the AgentOsSidecar handle and
|
|
1726
|
+
// shared across VMs; disposing this VM must not kill the process.
|
|
1727
|
+
ownsClient: false,
|
|
1563
1728
|
});
|
|
1564
1729
|
await bootstrapLiveBootstrapDirectories(client, session, nativeVm, options?.rootFilesystem);
|
|
1565
1730
|
kernel = rootBridge;
|
|
@@ -1569,6 +1734,10 @@ export class AgentOs {
|
|
|
1569
1734
|
hostMounts,
|
|
1570
1735
|
kernel,
|
|
1571
1736
|
rootView: rootBridge.createRootView(),
|
|
1737
|
+
sidecarMounts,
|
|
1738
|
+
sidecarPermissions,
|
|
1739
|
+
commandPermissions: processed.commandPermissions,
|
|
1740
|
+
loopbackExemptPorts: options?.loopbackExemptPorts,
|
|
1572
1741
|
sidecarClient: client,
|
|
1573
1742
|
sidecarSession: session,
|
|
1574
1743
|
sidecarVm: nativeVm,
|
|
@@ -1593,6 +1762,8 @@ export class AgentOs {
|
|
|
1593
1762
|
};
|
|
1594
1763
|
}
|
|
1595
1764
|
catch (error) {
|
|
1765
|
+
// The native process is shared and owned by the sidecar handle, so
|
|
1766
|
+
// never dispose the client here — only tear down this VM's resources.
|
|
1596
1767
|
if (kernel) {
|
|
1597
1768
|
await kernel.dispose().catch(() => { });
|
|
1598
1769
|
}
|
|
@@ -1600,20 +1771,23 @@ export class AgentOs {
|
|
|
1600
1771
|
await rootBridge.dispose().catch(() => { });
|
|
1601
1772
|
}
|
|
1602
1773
|
else {
|
|
1603
|
-
|
|
1774
|
+
if (createdNativeVm && nativeSession && client) {
|
|
1775
|
+
await client
|
|
1776
|
+
.disposeVm(nativeSession, createdNativeVm)
|
|
1777
|
+
.catch(() => { });
|
|
1778
|
+
}
|
|
1604
1779
|
await cleanup();
|
|
1605
1780
|
}
|
|
1606
1781
|
throw error;
|
|
1607
1782
|
}
|
|
1608
1783
|
};
|
|
1609
|
-
const sidecar = resolveAgentOsSidecar(options?.sidecar);
|
|
1610
1784
|
let sidecarLease = null;
|
|
1611
1785
|
try {
|
|
1612
1786
|
sidecarLease = await leaseAgentOsSidecarVm(sidecar, {
|
|
1613
1787
|
createVm: async () => createVmAdmin(),
|
|
1614
1788
|
});
|
|
1615
1789
|
const vmAdmin = sidecarLease.admin;
|
|
1616
|
-
const vm = new AgentOs(vmAdmin.kernel, sidecar, processed.softwareRoots, processed.agentConfigs, vmAdmin.hostMounts, vmAdmin.env, vmAdmin.rootView, vmAdmin.sidecarClient, vmAdmin.sidecarSession, vmAdmin.sidecarVm, options?.onAgentStderr ?? defaultAgentStderrHandler);
|
|
1790
|
+
const vm = new AgentOs(vmAdmin.kernel, sidecar, processed.softwareRoots, processed.agentConfigs, vmAdmin.hostMounts, vmAdmin.env, vmAdmin.rootView, vmAdmin.sidecarClient, vmAdmin.sidecarSession, vmAdmin.sidecarVm, options?.additionalInstructions, options?.onAgentStderr ?? defaultAgentStderrHandler);
|
|
1617
1791
|
vm._sidecarLease = sidecarLease;
|
|
1618
1792
|
vm._toolKits = vmAdmin.toolKits;
|
|
1619
1793
|
vm._toolReference = vmAdmin.toolReference;
|
|
@@ -1929,7 +2103,7 @@ export class AgentOs {
|
|
|
1929
2103
|
}
|
|
1930
2104
|
async delete(path, options) {
|
|
1931
2105
|
this._assertSafeAbsolutePath(path);
|
|
1932
|
-
const s = await this
|
|
2106
|
+
const s = await this._vfs().lstat(path);
|
|
1933
2107
|
if (s.isDirectory) {
|
|
1934
2108
|
if (options?.recursive) {
|
|
1935
2109
|
const entries = await this.#kernel.readdir(path);
|
|
@@ -2585,7 +2759,10 @@ export class AgentOs {
|
|
|
2585
2759
|
mcpServers: JSON.stringify(options?.mcpServers ?? []),
|
|
2586
2760
|
protocolVersion: ACP_PROTOCOL_VERSION,
|
|
2587
2761
|
clientCapabilities: JSON.stringify(defaultAcpClientCapabilities()),
|
|
2588
|
-
additionalInstructions: combineInstructions(options?.additionalInstructions
|
|
2762
|
+
additionalInstructions: combineInstructions([this._additionalInstructions, options?.additionalInstructions]
|
|
2763
|
+
.map((part) => part?.trim())
|
|
2764
|
+
.filter((part) => Boolean(part))
|
|
2765
|
+
.join("\n\n") || undefined, this._toolReference),
|
|
2589
2766
|
skipOsInstructions: options?.skipOsInstructions ?? false,
|
|
2590
2767
|
},
|
|
2591
2768
|
});
|
|
@@ -2672,6 +2849,10 @@ export class AgentOs {
|
|
|
2672
2849
|
}
|
|
2673
2850
|
const { sessionId: liveSessionId, mode } = response.val;
|
|
2674
2851
|
// Register + hydrate the live session so subsequent prompts route to it.
|
|
2852
|
+
const existing = this._sessions.get(liveSessionId);
|
|
2853
|
+
if (existing !== undefined && !existing.closed) {
|
|
2854
|
+
throw new Error(`session id collision: ${liveSessionId}`);
|
|
2855
|
+
}
|
|
2675
2856
|
const session = sessionEntryFromInit(liveSessionId, String(agentType), {});
|
|
2676
2857
|
this._closedSessionIds.delete(liveSessionId);
|
|
2677
2858
|
this._sessions.set(liveSessionId, session);
|
|
@@ -2755,11 +2936,7 @@ export class AgentOs {
|
|
|
2755
2936
|
case "host_callback":
|
|
2756
2937
|
return handleHostCallback(request, context);
|
|
2757
2938
|
case "js_bridge_call":
|
|
2758
|
-
return
|
|
2759
|
-
type: "js_bridge_result",
|
|
2760
|
-
call_id: request.payload.call_id,
|
|
2761
|
-
error: `unsupported sidecar request type: ${request.payload.type}`,
|
|
2762
|
-
});
|
|
2939
|
+
return handleJsBridgeCall(request.payload, { filesystem: this.#kernel.vfs });
|
|
2763
2940
|
case "ext":
|
|
2764
2941
|
return this._handleAcpExtSidecarRequest(request.payload.envelope);
|
|
2765
2942
|
}
|
|
@@ -3476,6 +3653,42 @@ function resolveAgentOsSidecar(config) {
|
|
|
3476
3653
|
}
|
|
3477
3654
|
const sidecarStates = new WeakMap();
|
|
3478
3655
|
const sharedSidecars = new Map();
|
|
3656
|
+
/**
|
|
3657
|
+
* Spawn-once accessor for a sidecar handle's shared native process. Concurrent
|
|
3658
|
+
* callers await the same promise, so one `AgentOsSidecar` maps to exactly one
|
|
3659
|
+
* `agent-os-sidecar` OS process for its whole lifetime.
|
|
3660
|
+
*/
|
|
3661
|
+
function ensureSharedSidecarNativeProcess(sidecar) {
|
|
3662
|
+
const state = getSidecarState(sidecar);
|
|
3663
|
+
if (!state.nativeProcess) {
|
|
3664
|
+
state.nativeProcess = (async () => {
|
|
3665
|
+
const client = SidecarProcess.spawn({
|
|
3666
|
+
cwd: REPO_ROOT,
|
|
3667
|
+
command: ensureNativeSidecarBinary(),
|
|
3668
|
+
args: [],
|
|
3669
|
+
frameTimeoutMs: NATIVE_SIDECAR_FRAME_TIMEOUT_MS,
|
|
3670
|
+
});
|
|
3671
|
+
const session = await client.authenticateAndOpenSession();
|
|
3672
|
+
return { client, session };
|
|
3673
|
+
})();
|
|
3674
|
+
}
|
|
3675
|
+
return state.nativeProcess;
|
|
3676
|
+
}
|
|
3677
|
+
/** Dispose a sidecar handle's shared native process, if one was spawned. */
|
|
3678
|
+
async function disposeSharedSidecarNativeProcess(state) {
|
|
3679
|
+
const pending = state.nativeProcess;
|
|
3680
|
+
if (!pending) {
|
|
3681
|
+
return;
|
|
3682
|
+
}
|
|
3683
|
+
state.nativeProcess = undefined;
|
|
3684
|
+
try {
|
|
3685
|
+
const { client } = await pending;
|
|
3686
|
+
await client.dispose();
|
|
3687
|
+
}
|
|
3688
|
+
catch {
|
|
3689
|
+
// Process may have already exited; nothing to reclaim.
|
|
3690
|
+
}
|
|
3691
|
+
}
|
|
3479
3692
|
export class AgentOsSidecar {
|
|
3480
3693
|
constructor(sidecarId, placement, sharedPool) {
|
|
3481
3694
|
sidecarStates.set(this, {
|
|
@@ -3510,6 +3723,8 @@ export class AgentOsSidecar {
|
|
|
3510
3723
|
}
|
|
3511
3724
|
state.activeLeases.clear();
|
|
3512
3725
|
state.description.activeVmCount = 0;
|
|
3726
|
+
// Tear down the shared native process after all leased VMs are gone.
|
|
3727
|
+
await disposeSharedSidecarNativeProcess(state);
|
|
3513
3728
|
state.description.state = "disposed";
|
|
3514
3729
|
if (state.sharedPool && sharedSidecars.get(state.sharedPool) === this) {
|
|
3515
3730
|
sharedSidecars.delete(state.sharedPool);
|
package/dist/host-tools.js
CHANGED
|
@@ -8,16 +8,25 @@ export function hostTool(def) {
|
|
|
8
8
|
export function toolKit(def) {
|
|
9
9
|
return def;
|
|
10
10
|
}
|
|
11
|
+
const TOOLKIT_COMMAND_NAME_RE = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
12
|
+
function validateToolCommandName(kind, name) {
|
|
13
|
+
if (TOOLKIT_COMMAND_NAME_RE.test(name)) {
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
throw new Error(`${kind} name "${name}" must be lowercase alphanumeric with optional single hyphen separators`);
|
|
17
|
+
}
|
|
11
18
|
/**
|
|
12
19
|
* Validate all description lengths in the given toolkits.
|
|
13
20
|
* Throws if any toolkit or tool description exceeds MAX_TOOL_DESCRIPTION_LENGTH.
|
|
14
21
|
*/
|
|
15
22
|
export function validateToolkits(toolKits) {
|
|
16
23
|
for (const tk of toolKits) {
|
|
24
|
+
validateToolCommandName("Toolkit", tk.name);
|
|
17
25
|
if (tk.description.length > MAX_TOOL_DESCRIPTION_LENGTH) {
|
|
18
26
|
throw new Error(`Toolkit "${tk.name}" description is ${tk.description.length} characters, max is ${MAX_TOOL_DESCRIPTION_LENGTH}`);
|
|
19
27
|
}
|
|
20
28
|
for (const [toolName, tool] of Object.entries(tk.tools)) {
|
|
29
|
+
validateToolCommandName("Tool", toolName);
|
|
21
30
|
if (tool.description.length > MAX_TOOL_DESCRIPTION_LENGTH) {
|
|
22
31
|
throw new Error(`Tool "${tk.name}/${toolName}" description is ${tool.description.length} characters, max is ${MAX_TOOL_DESCRIPTION_LENGTH}`);
|
|
23
32
|
}
|
package/dist/options-schema.d.ts
CHANGED
|
@@ -87,7 +87,7 @@ export declare const permissionsSchema: z.ZodObject<{
|
|
|
87
87
|
patterns: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
88
88
|
}, z.core.$strict>>;
|
|
89
89
|
}, z.core.$strict>]>>;
|
|
90
|
-
|
|
90
|
+
binding: z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
|
|
91
91
|
allow: "allow";
|
|
92
92
|
deny: "deny";
|
|
93
93
|
}>, z.ZodObject<{
|
|
@@ -344,7 +344,7 @@ export declare const agentOsOptionFieldSchemas: {
|
|
|
344
344
|
patterns: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
345
345
|
}, z.core.$strict>>;
|
|
346
346
|
}, z.core.$strict>]>>;
|
|
347
|
-
|
|
347
|
+
binding: z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
|
|
348
348
|
allow: "allow";
|
|
349
349
|
deny: "deny";
|
|
350
350
|
}>, z.ZodObject<{
|
package/dist/options-schema.js
CHANGED
|
@@ -42,7 +42,7 @@ export const permissionsSchema = z
|
|
|
42
42
|
childProcess: patternPermissionsSchema.optional(),
|
|
43
43
|
process: patternPermissionsSchema.optional(),
|
|
44
44
|
env: patternPermissionsSchema.optional(),
|
|
45
|
-
|
|
45
|
+
binding: patternPermissionsSchema.optional(),
|
|
46
46
|
})
|
|
47
47
|
.strict();
|
|
48
48
|
export const agentOsLimitsSchema = z
|
package/dist/packages.d.ts
CHANGED
|
@@ -25,6 +25,19 @@ export interface AgentSoftwareDescriptor extends SoftwareDescriptor {
|
|
|
25
25
|
acpAdapter: string;
|
|
26
26
|
/** npm package name of the agent CLI. Must be in requires. */
|
|
27
27
|
agentPackage: string;
|
|
28
|
+
/**
|
|
29
|
+
* Whether to evaluate this agent's SDK into the per-sidecar V8 heap
|
|
30
|
+
* snapshot so it is loaded once per sidecar and reused across sessions
|
|
31
|
+
* (instead of re-evaluated on every `createSession`). Opt-in: the agent's
|
|
32
|
+
* SDK must be **snapshot-safe** — its module-init must not create native
|
|
33
|
+
* (`.node` addon / WASM / External) handles, open fds/sockets, start
|
|
34
|
+
* timers, read per-session config, or leave pending promises. SDKs that
|
|
35
|
+
* are not snapshot-safe (or where snapshot creation fails) automatically
|
|
36
|
+
* fall back to the per-session dynamic-import path, so this flag is a
|
|
37
|
+
* safety/performance switch, not a correctness requirement. Defaults to
|
|
38
|
+
* `false`. See the Custom Agents / dependencies docs for the full rules.
|
|
39
|
+
*/
|
|
40
|
+
snapshot?: boolean;
|
|
28
41
|
/** Static env vars passed when spawning the adapter. */
|
|
29
42
|
staticEnv?: Record<string, string>;
|
|
30
43
|
/** Dynamic env vars computed at boot time. */
|
|
@@ -103,6 +116,15 @@ export interface CommandPackageMetadata {
|
|
|
103
116
|
* validates the descriptor shape at compile time.
|
|
104
117
|
*/
|
|
105
118
|
export declare function defineSoftware<T extends AnySoftwareDescriptor>(desc: T): T;
|
|
119
|
+
/**
|
|
120
|
+
* Resolve the agent-SDK snapshot bundle (an esbuild IIFE at
|
|
121
|
+
* `<packageDir>/dist/sdk-snapshot.js`) for the first snapshot-enabled agent in
|
|
122
|
+
* the software set. Returns its source so it can be evaluated once into the
|
|
123
|
+
* per-sidecar V8 startup snapshot (`jsRuntime.snapshotUserlandCode`) and reused
|
|
124
|
+
* across sessions. Returns `undefined` when no agent opts in (`agent.snapshot`)
|
|
125
|
+
* or the bundle is absent — the runtime then keeps the per-session import path.
|
|
126
|
+
*/
|
|
127
|
+
export declare function resolveAgentSnapshotBundle(software: SoftwareInput[]): string | undefined;
|
|
106
128
|
/** Result of processing all software descriptors at boot time. */
|
|
107
129
|
export interface ProcessedSoftware {
|
|
108
130
|
/** WASM command directories to pass to the WasmVM driver. */
|
package/dist/packages.js
CHANGED
|
@@ -118,6 +118,29 @@ function createSoftwareContext(packageDir, requires) {
|
|
|
118
118
|
export function defineSoftware(desc) {
|
|
119
119
|
return desc;
|
|
120
120
|
}
|
|
121
|
+
/**
|
|
122
|
+
* Resolve the agent-SDK snapshot bundle (an esbuild IIFE at
|
|
123
|
+
* `<packageDir>/dist/sdk-snapshot.js`) for the first snapshot-enabled agent in
|
|
124
|
+
* the software set. Returns its source so it can be evaluated once into the
|
|
125
|
+
* per-sidecar V8 startup snapshot (`jsRuntime.snapshotUserlandCode`) and reused
|
|
126
|
+
* across sessions. Returns `undefined` when no agent opts in (`agent.snapshot`)
|
|
127
|
+
* or the bundle is absent — the runtime then keeps the per-session import path.
|
|
128
|
+
*/
|
|
129
|
+
export function resolveAgentSnapshotBundle(software) {
|
|
130
|
+
const descriptors = software.flat();
|
|
131
|
+
for (const desc of descriptors) {
|
|
132
|
+
if (desc.type !== "agent")
|
|
133
|
+
continue;
|
|
134
|
+
const agent = desc;
|
|
135
|
+
if (!agent.agent.snapshot)
|
|
136
|
+
continue;
|
|
137
|
+
const bundlePath = join(agent.packageDir, "dist", "sdk-snapshot.js");
|
|
138
|
+
if (existsSync(bundlePath)) {
|
|
139
|
+
return readFileSync(bundlePath, "utf-8");
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return undefined;
|
|
143
|
+
}
|
|
121
144
|
/** Check if a descriptor is a typed software descriptor (has a `type` field). */
|
|
122
145
|
function isTypedDescriptor(desc) {
|
|
123
146
|
return ("type" in desc && typeof desc.type === "string");
|
|
@@ -270,6 +293,10 @@ export function processSoftware(software) {
|
|
|
270
293
|
if (!isTypedDescriptor(pkg)) {
|
|
271
294
|
// Duck-typed: any object with commandDir is a WASM command source.
|
|
272
295
|
const commandMetadata = collectCommandMetadata(pkg);
|
|
296
|
+
if (!existsSync(commandMetadata.commandDir)) {
|
|
297
|
+
console.warn(`[agentos] skipping WASM command source with missing commandDir: ${commandMetadata.commandDir} (build its wasm artifacts to enable these commands)`);
|
|
298
|
+
continue;
|
|
299
|
+
}
|
|
273
300
|
commandDirs.push(commandMetadata.commandDir);
|
|
274
301
|
commandPackages.push(commandMetadata);
|
|
275
302
|
collectRegistryPackagePermissions(commandPermissions, pkg);
|
|
@@ -278,6 +305,10 @@ export function processSoftware(software) {
|
|
|
278
305
|
switch (pkg.type) {
|
|
279
306
|
case "wasm-commands": {
|
|
280
307
|
const commandMetadata = collectCommandMetadata(pkg);
|
|
308
|
+
if (!existsSync(commandMetadata.commandDir)) {
|
|
309
|
+
console.warn(`[agentos] skipping WASM command source with missing commandDir: ${commandMetadata.commandDir} (build its wasm artifacts to enable these commands)`);
|
|
310
|
+
break;
|
|
311
|
+
}
|
|
281
312
|
commandDirs.push(commandMetadata.commandDir);
|
|
282
313
|
commandPackages.push(commandMetadata);
|
|
283
314
|
collectTypedDescriptorPermissions(commandPermissions, pkg);
|
package/dist/runtime-compat.d.ts
CHANGED
|
@@ -81,7 +81,7 @@ export type NetworkPermissions = PermissionMode | RulePermissions<PatternPermiss
|
|
|
81
81
|
export type ChildProcessPermissions = PermissionMode | RulePermissions<PatternPermissionRule>;
|
|
82
82
|
export type ProcessPermissions = PermissionMode | RulePermissions<PatternPermissionRule>;
|
|
83
83
|
export type EnvPermissions = PermissionMode | RulePermissions<PatternPermissionRule>;
|
|
84
|
-
export type
|
|
84
|
+
export type BindingPermissions = PermissionMode | RulePermissions<PatternPermissionRule>;
|
|
85
85
|
export interface ProcessInfo {
|
|
86
86
|
pid: number;
|
|
87
87
|
ppid: number;
|
|
@@ -168,7 +168,7 @@ export interface Permissions {
|
|
|
168
168
|
childProcess?: ChildProcessPermissions;
|
|
169
169
|
process?: ProcessPermissions;
|
|
170
170
|
env?: EnvPermissions;
|
|
171
|
-
|
|
171
|
+
binding?: BindingPermissions;
|
|
172
172
|
}
|
|
173
173
|
export interface ResourceBudgets {
|
|
174
174
|
maxOutputBytes?: number;
|
package/dist/runtime-compat.js
CHANGED
|
@@ -119,7 +119,7 @@ export class InMemoryFileSystem {
|
|
|
119
119
|
throw errnoError("ENOENT", `open '${targetPath}'`);
|
|
120
120
|
}
|
|
121
121
|
entry.atimeMs = Date.now();
|
|
122
|
-
return entry.data;
|
|
122
|
+
return new Uint8Array(entry.data);
|
|
123
123
|
}
|
|
124
124
|
async readTextFile(targetPath) {
|
|
125
125
|
return new TextDecoder().decode(await this.readFile(targetPath));
|
|
@@ -152,7 +152,9 @@ export class InMemoryFileSystem {
|
|
|
152
152
|
async writeFile(targetPath, content) {
|
|
153
153
|
const normalized = normalizePath(targetPath);
|
|
154
154
|
await this.mkdir(dirnameVirtual(normalized), { recursive: true });
|
|
155
|
-
const data = typeof content === "string"
|
|
155
|
+
const data = typeof content === "string"
|
|
156
|
+
? new TextEncoder().encode(content)
|
|
157
|
+
: new Uint8Array(content);
|
|
156
158
|
const existing = this.entries.get(normalized);
|
|
157
159
|
if (existing?.type === "file") {
|
|
158
160
|
existing.data = data;
|
|
@@ -212,7 +214,7 @@ export class InMemoryFileSystem {
|
|
|
212
214
|
return this.toStat(entry);
|
|
213
215
|
}
|
|
214
216
|
async removeFile(targetPath) {
|
|
215
|
-
const resolved =
|
|
217
|
+
const resolved = normalizePath(targetPath);
|
|
216
218
|
const entry = this.entries.get(resolved);
|
|
217
219
|
if (!entry || entry.type === "dir") {
|
|
218
220
|
throw errnoError("ENOENT", `unlink '${targetPath}'`);
|
|
@@ -374,7 +376,7 @@ export class InMemoryFileSystem {
|
|
|
374
376
|
const nextSize = Math.max(entry.data.length, offset + data.length);
|
|
375
377
|
const updated = new Uint8Array(nextSize);
|
|
376
378
|
updated.set(entry.data);
|
|
377
|
-
updated.set(data, offset);
|
|
379
|
+
updated.set(new Uint8Array(data), offset);
|
|
378
380
|
entry.data = updated;
|
|
379
381
|
entry.mtimeMs = Date.now();
|
|
380
382
|
entry.ctimeMs = Date.now();
|
|
@@ -1607,6 +1609,35 @@ function bindLiveFilesystem(target, getFilesystem) {
|
|
|
1607
1609
|
},
|
|
1608
1610
|
};
|
|
1609
1611
|
}
|
|
1612
|
+
function serializeLocalCompatMountForSidecar(mount) {
|
|
1613
|
+
return (mount.sidecarMount ??
|
|
1614
|
+
(mount.fs instanceof NodeFileSystem
|
|
1615
|
+
? serializeMountConfigForSidecar({
|
|
1616
|
+
path: mount.path,
|
|
1617
|
+
readOnly: mount.readOnly,
|
|
1618
|
+
plugin: {
|
|
1619
|
+
id: "host_dir",
|
|
1620
|
+
config: {
|
|
1621
|
+
hostPath: mount.fs.rootPath,
|
|
1622
|
+
readOnly: mount.readOnly,
|
|
1623
|
+
},
|
|
1624
|
+
},
|
|
1625
|
+
})
|
|
1626
|
+
: serializeMountConfigForSidecar({
|
|
1627
|
+
path: mount.path,
|
|
1628
|
+
driver: mount.fs,
|
|
1629
|
+
readOnly: mount.readOnly,
|
|
1630
|
+
})));
|
|
1631
|
+
}
|
|
1632
|
+
function makeLocalCompatMount(options) {
|
|
1633
|
+
const localMount = {
|
|
1634
|
+
path: normalizePath(options.path),
|
|
1635
|
+
fs: options.fs,
|
|
1636
|
+
readOnly: options.readOnly ?? false,
|
|
1637
|
+
};
|
|
1638
|
+
localMount.sidecarMount = serializeLocalCompatMountForSidecar(localMount);
|
|
1639
|
+
return localMount;
|
|
1640
|
+
}
|
|
1610
1641
|
class NativeKernel {
|
|
1611
1642
|
options;
|
|
1612
1643
|
env;
|
|
@@ -1646,11 +1677,11 @@ class NativeKernel {
|
|
|
1646
1677
|
};
|
|
1647
1678
|
this.loopbackExemptPorts = [...(options.loopbackExemptPorts ?? [])];
|
|
1648
1679
|
for (const mount of options.mounts ?? []) {
|
|
1649
|
-
this.pendingLocalMounts.push({
|
|
1650
|
-
path:
|
|
1680
|
+
this.pendingLocalMounts.push(makeLocalCompatMount({
|
|
1681
|
+
path: mount.path,
|
|
1651
1682
|
fs: mount.fs,
|
|
1652
|
-
readOnly: mount.readOnly
|
|
1653
|
-
});
|
|
1683
|
+
readOnly: mount.readOnly,
|
|
1684
|
+
}));
|
|
1654
1685
|
}
|
|
1655
1686
|
this.vfs = new DeferredFileSystem(() => this.rootFilesystem);
|
|
1656
1687
|
this.liveFilesystemBinding = bindLiveFilesystem(this.options.filesystem, () => this.rootFilesystem);
|
|
@@ -1696,23 +1727,7 @@ class NativeKernel {
|
|
|
1696
1727
|
},
|
|
1697
1728
|
},
|
|
1698
1729
|
}));
|
|
1699
|
-
const localMounts = this.pendingLocalMounts.map((mount) => mount
|
|
1700
|
-
? serializeMountConfigForSidecar({
|
|
1701
|
-
path: mount.path,
|
|
1702
|
-
readOnly: mount.readOnly,
|
|
1703
|
-
plugin: {
|
|
1704
|
-
id: "host_dir",
|
|
1705
|
-
config: {
|
|
1706
|
-
hostPath: mount.fs.rootPath,
|
|
1707
|
-
readOnly: mount.readOnly,
|
|
1708
|
-
},
|
|
1709
|
-
},
|
|
1710
|
-
})
|
|
1711
|
-
: serializeMountConfigForSidecar({
|
|
1712
|
-
path: mount.path,
|
|
1713
|
-
driver: mount.fs,
|
|
1714
|
-
readOnly: mount.readOnly,
|
|
1715
|
-
}));
|
|
1730
|
+
const localMounts = this.pendingLocalMounts.map((mount) => serializeLocalCompatMountForSidecar(mount));
|
|
1716
1731
|
await this.client.configureVm(this.session, this.vm, {
|
|
1717
1732
|
mounts: [...localMounts, ...sidecarMounts],
|
|
1718
1733
|
loopbackExemptPorts: this.loopbackExemptPorts,
|
|
@@ -1818,17 +1833,27 @@ class NativeKernel {
|
|
|
1818
1833
|
return this.proxy.connectTerminal(options);
|
|
1819
1834
|
}
|
|
1820
1835
|
mountFs(mountPath, filesystem, options) {
|
|
1836
|
+
const localMount = makeLocalCompatMount({
|
|
1837
|
+
path: mountPath,
|
|
1838
|
+
fs: filesystem,
|
|
1839
|
+
readOnly: options?.readOnly,
|
|
1840
|
+
});
|
|
1841
|
+
this.pendingLocalMounts.unshift(localMount);
|
|
1842
|
+
this.pendingLocalMounts.sort((left, right) => right.path.length - left.path.length);
|
|
1821
1843
|
if (!this.proxy) {
|
|
1822
|
-
this.pendingLocalMounts.push({
|
|
1823
|
-
path: normalizePath(mountPath),
|
|
1824
|
-
fs: filesystem,
|
|
1825
|
-
readOnly: options?.readOnly ?? false,
|
|
1826
|
-
});
|
|
1827
1844
|
return;
|
|
1828
1845
|
}
|
|
1829
|
-
this.proxy.mountFs(mountPath, filesystem,
|
|
1846
|
+
this.proxy.mountFs(mountPath, filesystem, {
|
|
1847
|
+
readOnly: localMount.readOnly,
|
|
1848
|
+
sidecarMount: localMount.sidecarMount,
|
|
1849
|
+
});
|
|
1830
1850
|
}
|
|
1831
1851
|
unmountFs(mountPath) {
|
|
1852
|
+
const normalized = normalizePath(mountPath);
|
|
1853
|
+
const pendingIndex = this.pendingLocalMounts.findIndex((mount) => mount.path === normalized);
|
|
1854
|
+
if (pendingIndex >= 0) {
|
|
1855
|
+
this.pendingLocalMounts.splice(pendingIndex, 1);
|
|
1856
|
+
}
|
|
1832
1857
|
this.proxy?.unmountFs(mountPath);
|
|
1833
1858
|
}
|
|
1834
1859
|
async readFile(targetPath) {
|
|
@@ -1955,33 +1980,23 @@ class NativeKernel {
|
|
|
1955
1980
|
await materializeSnapshotEntriesIntoVm(client, session, vm, snapshotEntries);
|
|
1956
1981
|
}
|
|
1957
1982
|
if (rootPassthroughPlan.mounts.length > 0) {
|
|
1958
|
-
this.pendingLocalMounts.push(...rootPassthroughPlan.mounts)
|
|
1983
|
+
this.pendingLocalMounts.push(...rootPassthroughPlan.mounts.map((mount) => makeLocalCompatMount({
|
|
1984
|
+
path: mount.path,
|
|
1985
|
+
fs: mount.fs,
|
|
1986
|
+
readOnly: mount.readOnly,
|
|
1987
|
+
})));
|
|
1959
1988
|
}
|
|
1960
1989
|
if (this.pendingLocalMounts.length > 0 ||
|
|
1961
1990
|
this.loopbackExemptPorts.length > 0 ||
|
|
1962
1991
|
requestedPermissions) {
|
|
1992
|
+
const sidecarMounts = this.pendingLocalMounts.map((mount) => serializeLocalCompatMountForSidecar(mount));
|
|
1963
1993
|
await client.configureVm(session, vm, {
|
|
1964
|
-
mounts:
|
|
1965
|
-
? serializeMountConfigForSidecar({
|
|
1966
|
-
path: mount.path,
|
|
1967
|
-
readOnly: mount.readOnly,
|
|
1968
|
-
plugin: {
|
|
1969
|
-
id: "host_dir",
|
|
1970
|
-
config: {
|
|
1971
|
-
hostPath: mount.fs.rootPath,
|
|
1972
|
-
readOnly: mount.readOnly,
|
|
1973
|
-
},
|
|
1974
|
-
},
|
|
1975
|
-
})
|
|
1976
|
-
: serializeMountConfigForSidecar({
|
|
1977
|
-
path: mount.path,
|
|
1978
|
-
driver: mount.fs,
|
|
1979
|
-
readOnly: mount.readOnly,
|
|
1980
|
-
})),
|
|
1994
|
+
mounts: sidecarMounts,
|
|
1981
1995
|
permissions: requestedPermissions,
|
|
1982
1996
|
loopbackExemptPorts: this.loopbackExemptPorts,
|
|
1983
1997
|
});
|
|
1984
1998
|
}
|
|
1999
|
+
const configuredSidecarMounts = this.pendingLocalMounts.map((mount) => serializeLocalCompatMountForSidecar(mount));
|
|
1985
2000
|
const proxy = new NativeSidecarKernelProxy({
|
|
1986
2001
|
client,
|
|
1987
2002
|
session,
|
|
@@ -1990,6 +2005,9 @@ class NativeKernel {
|
|
|
1990
2005
|
cwd: this.cwd,
|
|
1991
2006
|
defaultExecCwd: this.options.cwd === undefined ? "/workspace" : this.cwd,
|
|
1992
2007
|
localMounts: this.pendingLocalMounts,
|
|
2008
|
+
sidecarMounts: configuredSidecarMounts,
|
|
2009
|
+
permissions: requestedPermissions,
|
|
2010
|
+
loopbackExemptPorts: this.loopbackExemptPorts,
|
|
1993
2011
|
commandGuestPaths: new Map(),
|
|
1994
2012
|
onWasmCommandResolved: (command) => {
|
|
1995
2013
|
this.recordModuleExecution(command);
|
package/dist/runtime.d.ts
CHANGED
|
@@ -76,7 +76,7 @@ export type NetworkPermissions = PermissionMode | RulePermissions<PatternPermiss
|
|
|
76
76
|
export type ChildProcessPermissions = PermissionMode | RulePermissions<PatternPermissionRule>;
|
|
77
77
|
export type ProcessPermissions = PermissionMode | RulePermissions<PatternPermissionRule>;
|
|
78
78
|
export type EnvPermissions = PermissionMode | RulePermissions<PatternPermissionRule>;
|
|
79
|
-
export type
|
|
79
|
+
export type BindingPermissions = PermissionMode | RulePermissions<PatternPermissionRule>;
|
|
80
80
|
export interface ProcessInfo {
|
|
81
81
|
pid: number;
|
|
82
82
|
ppid: number;
|
|
@@ -163,7 +163,7 @@ export interface Permissions {
|
|
|
163
163
|
childProcess?: ChildProcessPermissions;
|
|
164
164
|
process?: ProcessPermissions;
|
|
165
165
|
env?: EnvPermissions;
|
|
166
|
-
|
|
166
|
+
binding?: BindingPermissions;
|
|
167
167
|
}
|
|
168
168
|
export interface ResourceBudgets {
|
|
169
169
|
maxOutputBytes?: number;
|
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
import "@secure-exec/core/native-client";
|
|
2
|
-
|
|
2
|
+
import { SidecarProcess } from "@secure-exec/core/sidecar-client";
|
|
3
|
+
export { NATIVE_SIDECAR_FRAME_TIMEOUT_MS, SidecarEventBufferOverflow, SidecarProcess, SidecarProcessError, SidecarProcessExited, } from "@secure-exec/core/sidecar-client";
|
|
4
|
+
export declare const NativeSidecarProcessClient: typeof SidecarProcess;
|
|
3
5
|
export type { AuthenticatedSession, CreatedVm, ExtEnvelope, GuestFilesystemStat, RootFilesystemEntry, RootFilesystemLowerDescriptor, SidecarEventSelector, SidecarFsPermissionRule, SidecarMountDescriptor, SidecarMountPluginDescriptor, SidecarPatternPermissionRule, SidecarPermissionMode, SidecarPermissionScope, SidecarPermissionsPolicy, SidecarProcessSnapshotEntry, SidecarProjectedModuleDescriptor, SidecarRegisteredHostCallbackDefinition, SidecarRegisteredHostCallbackExample, SidecarRequestFrame, SidecarRequestHandler, SidecarRequestPayload, SidecarResponseFrame, SidecarResponsePayload, SidecarRulePermissions, SidecarSessionState, SidecarSignalHandlerRegistration, SidecarSignalState, SidecarSocketStateEntry, SidecarSoftwareDescriptor, SidecarSpawnOptions, SidecarSpawnOptions as NativeSidecarSpawnOptions, SidecarZombieTimerCount, } from "@secure-exec/core/sidecar-client";
|
|
@@ -3,4 +3,6 @@
|
|
|
3
3
|
// separately-registered factory; importing native-client wires it up so
|
|
4
4
|
// SidecarProcess.spawn works in this native runtime.
|
|
5
5
|
import "@secure-exec/core/native-client";
|
|
6
|
-
|
|
6
|
+
import { SidecarProcess } from "@secure-exec/core/sidecar-client";
|
|
7
|
+
export { NATIVE_SIDECAR_FRAME_TIMEOUT_MS, SidecarEventBufferOverflow, SidecarProcess, SidecarProcessError, SidecarProcessExited, } from "@secure-exec/core/sidecar-client";
|
|
8
|
+
export const NativeSidecarProcessClient = SidecarProcess;
|
|
@@ -47,8 +47,8 @@ export function serializePermissionsForSidecar(permissions) {
|
|
|
47
47
|
env: typeof permissions.env === "string" || !permissions.env
|
|
48
48
|
? permissions.env
|
|
49
49
|
: serializePatternScope(permissions.env),
|
|
50
|
-
binding: typeof permissions.
|
|
51
|
-
? permissions.
|
|
52
|
-
: serializePatternScope(permissions.
|
|
50
|
+
binding: typeof permissions.binding === "string" || !permissions.binding
|
|
51
|
+
? permissions.binding
|
|
52
|
+
: serializePatternScope(permissions.binding),
|
|
53
53
|
};
|
|
54
54
|
}
|
|
@@ -2,12 +2,13 @@ import type { RootFilesystemConfig as VmConfigRootFilesystemConfig, RootFilesyst
|
|
|
2
2
|
import type { NativeMountConfig, PlainMountConfig, RootFilesystemConfig } from "../agent-os.js";
|
|
3
3
|
import type { RootSnapshotExport } from "../layers.js";
|
|
4
4
|
import type { ConnectTerminalOptions, KernelExecOptions, KernelExecResult, KernelSpawnOptions, ManagedProcess, OpenShellOptions, ProcessInfo, ShellHandle, VirtualFileSystem, VirtualStat } from "../runtime-compat.js";
|
|
5
|
-
import type { AuthenticatedSession, CreatedVm, SidecarProcess, SidecarSignalHandlerRegistration } from "./native-process-client.js";
|
|
5
|
+
import type { AuthenticatedSession, CreatedVm, SidecarProcess, SidecarPermissionsPolicy, SidecarSignalHandlerRegistration } from "./native-process-client.js";
|
|
6
6
|
export declare function toSidecarSignalName(signal: number): string;
|
|
7
7
|
export interface LocalCompatMount {
|
|
8
8
|
path: string;
|
|
9
9
|
fs: VirtualFileSystem;
|
|
10
10
|
readOnly: boolean;
|
|
11
|
+
sidecarMount?: SidecarMountDescriptor;
|
|
11
12
|
}
|
|
12
13
|
interface KernelSocketSnapshot {
|
|
13
14
|
processId: string;
|
|
@@ -30,9 +31,21 @@ interface NativeSidecarKernelProxyOptions {
|
|
|
30
31
|
cwd: string;
|
|
31
32
|
defaultExecCwd?: string;
|
|
32
33
|
localMounts: LocalCompatMount[];
|
|
34
|
+
sidecarMounts: SidecarMountDescriptor[];
|
|
35
|
+
permissions?: SidecarPermissionsPolicy;
|
|
36
|
+
commandPermissions?: Parameters<SidecarProcess["configureVm"]>[2]["commandPermissions"];
|
|
37
|
+
loopbackExemptPorts?: number[];
|
|
33
38
|
commandGuestPaths: ReadonlyMap<string, string>;
|
|
34
39
|
onWasmCommandResolved?: (command: string) => void;
|
|
35
40
|
onDispose?: () => Promise<void>;
|
|
41
|
+
/**
|
|
42
|
+
* Whether this proxy owns the underlying sidecar process. When VMs share one
|
|
43
|
+
* sidecar process (the default for VMs leased from an `AgentOsSidecar`
|
|
44
|
+
* handle), each proxy tears down only its own VM on `dispose()`; the shared
|
|
45
|
+
* process is disposed when the sidecar handle is disposed. Defaults to true
|
|
46
|
+
* for the legacy one-process-per-VM path.
|
|
47
|
+
*/
|
|
48
|
+
ownsClient?: boolean;
|
|
36
49
|
}
|
|
37
50
|
export declare class NativeSidecarKernelProxy {
|
|
38
51
|
readonly env: Record<string, string>;
|
|
@@ -44,7 +57,12 @@ export declare class NativeSidecarKernelProxy {
|
|
|
44
57
|
private readonly client;
|
|
45
58
|
private readonly session;
|
|
46
59
|
private readonly vm;
|
|
60
|
+
private readonly ownsClient;
|
|
47
61
|
private readonly localMounts;
|
|
62
|
+
private readonly baseSidecarMounts;
|
|
63
|
+
private readonly permissions;
|
|
64
|
+
private readonly commandPermissions;
|
|
65
|
+
private readonly loopbackExemptPorts;
|
|
48
66
|
private readonly commandDrivers;
|
|
49
67
|
private readonly onWasmCommandResolved;
|
|
50
68
|
private readonly onDispose;
|
|
@@ -62,6 +80,7 @@ export declare class NativeSidecarKernelProxy {
|
|
|
62
80
|
private zombieTimerCountRefresh;
|
|
63
81
|
private disposed;
|
|
64
82
|
private pumpError;
|
|
83
|
+
private mountReconfigurePromise;
|
|
65
84
|
private nextSyntheticPid;
|
|
66
85
|
private readonly eventPumpAbortController;
|
|
67
86
|
private readonly eventPump;
|
|
@@ -86,8 +105,12 @@ export declare class NativeSidecarKernelProxy {
|
|
|
86
105
|
rename(oldPath: string, newPath: string): Promise<void>;
|
|
87
106
|
mountFs(path: string, driver: VirtualFileSystem, options?: {
|
|
88
107
|
readOnly?: boolean;
|
|
108
|
+
sidecarMount?: SidecarMountDescriptor;
|
|
89
109
|
}): void;
|
|
90
110
|
unmountFs(path: string): void;
|
|
111
|
+
private desiredSidecarMounts;
|
|
112
|
+
private reconfigureSidecarMounts;
|
|
113
|
+
private waitForMountReconfigure;
|
|
91
114
|
snapshotProcesses(): ProcessInfo[];
|
|
92
115
|
findListener(request: {
|
|
93
116
|
host?: string;
|
|
@@ -125,8 +148,8 @@ export declare class NativeSidecarKernelProxy {
|
|
|
125
148
|
private assertLocalWritable;
|
|
126
149
|
private updateTrackedProcessSnapshot;
|
|
127
150
|
}
|
|
128
|
-
export type { AuthenticatedSession, CreatedVm, GuestFilesystemStat,
|
|
129
|
-
export { NATIVE_SIDECAR_FRAME_TIMEOUT_MS,
|
|
151
|
+
export type { AuthenticatedSession, CreatedVm, GuestFilesystemStat, RootFilesystemEntry, SidecarEventSelector, SidecarPermissionsPolicy, SidecarRegisteredHostCallbackDefinition, SidecarRequestFrame, SidecarResponsePayload, SidecarSessionState, SidecarSignalHandlerRegistration, SidecarSocketStateEntry, SidecarSpawnOptions, } from "./native-process-client.js";
|
|
152
|
+
export { NATIVE_SIDECAR_FRAME_TIMEOUT_MS, NativeSidecarProcessClient, SidecarEventBufferOverflow, SidecarProcess, SidecarProcessError, SidecarProcessExited, } from "./native-process-client.js";
|
|
130
153
|
export type AgentOsSidecarPlacement = {
|
|
131
154
|
kind: "shared";
|
|
132
155
|
pool?: string;
|
|
@@ -181,7 +181,12 @@ export class NativeSidecarKernelProxy {
|
|
|
181
181
|
client;
|
|
182
182
|
session;
|
|
183
183
|
vm;
|
|
184
|
+
ownsClient;
|
|
184
185
|
localMounts;
|
|
186
|
+
baseSidecarMounts;
|
|
187
|
+
permissions;
|
|
188
|
+
commandPermissions;
|
|
189
|
+
loopbackExemptPorts;
|
|
185
190
|
commandDrivers;
|
|
186
191
|
onWasmCommandResolved;
|
|
187
192
|
onDispose;
|
|
@@ -199,6 +204,7 @@ export class NativeSidecarKernelProxy {
|
|
|
199
204
|
zombieTimerCountRefresh = null;
|
|
200
205
|
disposed = false;
|
|
201
206
|
pumpError = null;
|
|
207
|
+
mountReconfigurePromise = null;
|
|
202
208
|
nextSyntheticPid = SYNTHETIC_PID_BASE;
|
|
203
209
|
eventPumpAbortController = new AbortController();
|
|
204
210
|
eventPump;
|
|
@@ -206,10 +212,17 @@ export class NativeSidecarKernelProxy {
|
|
|
206
212
|
this.client = options.client;
|
|
207
213
|
this.session = options.session;
|
|
208
214
|
this.vm = options.vm;
|
|
215
|
+
this.ownsClient = options.ownsClient ?? true;
|
|
209
216
|
this.env = { ...options.env };
|
|
210
217
|
this.cwd = options.cwd;
|
|
211
218
|
this.defaultExecCwd = options.defaultExecCwd;
|
|
212
219
|
this.localMounts = [...options.localMounts].sort((left, right) => right.path.length - left.path.length);
|
|
220
|
+
const localMountPaths = new Set(this.localMounts.map((mount) => mount.path));
|
|
221
|
+
this.baseSidecarMounts = options.sidecarMounts.filter((mount) => mount.plugin.id !== "js_bridge" ||
|
|
222
|
+
!localMountPaths.has(posixPath.normalize(mount.guestPath)));
|
|
223
|
+
this.permissions = options.permissions;
|
|
224
|
+
this.commandPermissions = options.commandPermissions;
|
|
225
|
+
this.loopbackExemptPorts = options.loopbackExemptPorts;
|
|
213
226
|
this.commandDrivers = buildCommandMap(options.commandGuestPaths);
|
|
214
227
|
this.onWasmCommandResolved = options.onWasmCommandResolved;
|
|
215
228
|
this.onDispose = options.onDispose;
|
|
@@ -239,6 +252,7 @@ export class NativeSidecarKernelProxy {
|
|
|
239
252
|
}
|
|
240
253
|
this.disposed = true;
|
|
241
254
|
this.eventPumpAbortController.abort();
|
|
255
|
+
await this.mountReconfigurePromise?.catch(() => { });
|
|
242
256
|
const liveProcesses = [...this.trackedProcesses.values()].filter((entry) => entry.exitCode === null);
|
|
243
257
|
await Promise.allSettled(liveProcesses.map((entry) => this.signalProcess(entry, 15)));
|
|
244
258
|
await this.client.disposeVm(this.session, this.vm).catch(() => { });
|
|
@@ -251,7 +265,12 @@ export class NativeSidecarKernelProxy {
|
|
|
251
265
|
this.finishProcess(entry, 143);
|
|
252
266
|
}
|
|
253
267
|
}
|
|
254
|
-
|
|
268
|
+
// Only tear down the shared sidecar process when this proxy owns it. VMs
|
|
269
|
+
// leased from an `AgentOsSidecar` handle share one process, which is
|
|
270
|
+
// disposed when the handle is disposed.
|
|
271
|
+
if (this.ownsClient) {
|
|
272
|
+
await this.client.dispose().catch(() => { });
|
|
273
|
+
}
|
|
255
274
|
await this.eventPump.catch(() => { });
|
|
256
275
|
await this.onDispose?.().catch(() => { });
|
|
257
276
|
}
|
|
@@ -1011,14 +1030,57 @@ export class NativeSidecarKernelProxy {
|
|
|
1011
1030
|
path: posixPath.normalize(path),
|
|
1012
1031
|
fs: driver,
|
|
1013
1032
|
readOnly: options?.readOnly ?? false,
|
|
1033
|
+
sidecarMount: options?.sidecarMount,
|
|
1014
1034
|
});
|
|
1015
1035
|
this.localMounts.sort((left, right) => right.path.length - left.path.length);
|
|
1036
|
+
void this.reconfigureSidecarMounts().catch(() => { });
|
|
1016
1037
|
}
|
|
1017
1038
|
unmountFs(path) {
|
|
1018
1039
|
const normalized = posixPath.normalize(path);
|
|
1019
1040
|
const index = this.localMounts.findIndex((mount) => mount.path === normalized);
|
|
1020
1041
|
if (index >= 0) {
|
|
1021
1042
|
this.localMounts.splice(index, 1);
|
|
1043
|
+
void this.reconfigureSidecarMounts().catch(() => { });
|
|
1044
|
+
}
|
|
1045
|
+
}
|
|
1046
|
+
desiredSidecarMounts() {
|
|
1047
|
+
return [
|
|
1048
|
+
...this.baseSidecarMounts,
|
|
1049
|
+
...this.localMounts.map((mount) => mount.sidecarMount ?? {
|
|
1050
|
+
guestPath: mount.path,
|
|
1051
|
+
readOnly: mount.readOnly,
|
|
1052
|
+
plugin: {
|
|
1053
|
+
id: "js_bridge",
|
|
1054
|
+
config: {},
|
|
1055
|
+
},
|
|
1056
|
+
}),
|
|
1057
|
+
];
|
|
1058
|
+
}
|
|
1059
|
+
reconfigureSidecarMounts() {
|
|
1060
|
+
const run = async () => {
|
|
1061
|
+
if (this.disposed) {
|
|
1062
|
+
return;
|
|
1063
|
+
}
|
|
1064
|
+
await this.client.configureVm(this.session, this.vm, {
|
|
1065
|
+
mounts: this.desiredSidecarMounts(),
|
|
1066
|
+
permissions: this.permissions,
|
|
1067
|
+
commandPermissions: this.commandPermissions,
|
|
1068
|
+
loopbackExemptPorts: this.loopbackExemptPorts,
|
|
1069
|
+
});
|
|
1070
|
+
};
|
|
1071
|
+
const previous = this.mountReconfigurePromise ?? Promise.resolve();
|
|
1072
|
+
const next = previous.then(run, run);
|
|
1073
|
+
const tracked = next.finally(() => {
|
|
1074
|
+
if (this.mountReconfigurePromise === tracked) {
|
|
1075
|
+
this.mountReconfigurePromise = null;
|
|
1076
|
+
}
|
|
1077
|
+
});
|
|
1078
|
+
this.mountReconfigurePromise = tracked;
|
|
1079
|
+
return tracked;
|
|
1080
|
+
}
|
|
1081
|
+
async waitForMountReconfigure() {
|
|
1082
|
+
if (this.mountReconfigurePromise) {
|
|
1083
|
+
await this.mountReconfigurePromise;
|
|
1022
1084
|
}
|
|
1023
1085
|
}
|
|
1024
1086
|
snapshotProcesses() {
|
|
@@ -1132,6 +1194,7 @@ export class NativeSidecarKernelProxy {
|
|
|
1132
1194
|
}
|
|
1133
1195
|
}
|
|
1134
1196
|
async startTrackedProcess(entry) {
|
|
1197
|
+
await this.waitForMountReconfigure();
|
|
1135
1198
|
const started = await this.client.execute(this.session, this.vm, {
|
|
1136
1199
|
processId: entry.processId,
|
|
1137
1200
|
command: entry.command,
|
|
@@ -1157,11 +1220,14 @@ export class NativeSidecarKernelProxy {
|
|
|
1157
1220
|
}
|
|
1158
1221
|
}
|
|
1159
1222
|
async runEventPump() {
|
|
1223
|
+
// Scope the pump to THIS VM's ownership so multiple proxies can share one
|
|
1224
|
+
// sidecar process: events for other VMs stay buffered for their own pumps
|
|
1225
|
+
// rather than being consumed (and dropped) here.
|
|
1226
|
+
const vmId = this.vm.vmId;
|
|
1160
1227
|
while (!this.disposed) {
|
|
1161
1228
|
try {
|
|
1162
|
-
const event = await this.client.waitForEvent(
|
|
1163
|
-
signal: this.eventPumpAbortController.signal
|
|
1164
|
-
});
|
|
1229
|
+
const event = await this.client.waitForEvent((frame) => frame.ownership.scope === "vm" &&
|
|
1230
|
+
frame.ownership.vm_id === vmId, undefined, { signal: this.eventPumpAbortController.signal });
|
|
1165
1231
|
if (event.payload.type === "process_output") {
|
|
1166
1232
|
const entry = this.trackedProcessesById.get(event.payload.process_id);
|
|
1167
1233
|
if (!entry) {
|
|
@@ -1580,7 +1646,8 @@ export class NativeSidecarKernelProxy {
|
|
|
1580
1646
|
}
|
|
1581
1647
|
return this.dispatchNativeRead(path);
|
|
1582
1648
|
}
|
|
1583
|
-
dispatchNativeRead(path) {
|
|
1649
|
+
async dispatchNativeRead(path) {
|
|
1650
|
+
await this.waitForMountReconfigure();
|
|
1584
1651
|
return this.client.readFile(this.session, this.vm, path);
|
|
1585
1652
|
}
|
|
1586
1653
|
async dispatchWrite(path, handler, nativeHandler, includeLocalMounts = true) {
|
|
@@ -1591,6 +1658,7 @@ export class NativeSidecarKernelProxy {
|
|
|
1591
1658
|
await handler(local.mount, local.relativePath);
|
|
1592
1659
|
return;
|
|
1593
1660
|
}
|
|
1661
|
+
await this.waitForMountReconfigure();
|
|
1594
1662
|
await nativeHandler();
|
|
1595
1663
|
}
|
|
1596
1664
|
resolveLocalMount(path) {
|
|
@@ -1750,7 +1818,7 @@ function socketLookupKey(kind, request) {
|
|
|
1750
1818
|
path: request.path ?? null,
|
|
1751
1819
|
});
|
|
1752
1820
|
}
|
|
1753
|
-
export { NATIVE_SIDECAR_FRAME_TIMEOUT_MS,
|
|
1821
|
+
export { NATIVE_SIDECAR_FRAME_TIMEOUT_MS, NativeSidecarProcessClient, SidecarEventBufferOverflow, SidecarProcess, SidecarProcessError, SidecarProcessExited, } from "./native-process-client.js";
|
|
1754
1822
|
export class AgentOsSidecarVmHandle {
|
|
1755
1823
|
client;
|
|
1756
1824
|
sessionId;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rivet-dev/agentos-core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -56,9 +56,9 @@
|
|
|
56
56
|
"dependencies": {
|
|
57
57
|
"@agentos-software/common": "0.3.0-rc.2",
|
|
58
58
|
"@aws-sdk/client-s3": "^3.1019.0",
|
|
59
|
-
"@rivet-dev/agentos-sidecar": "0.
|
|
59
|
+
"@rivet-dev/agentos-sidecar": "0.2.0",
|
|
60
60
|
"@rivetkit/bare-ts": "^0.6.2",
|
|
61
|
-
"@secure-exec/core": "0.
|
|
61
|
+
"@secure-exec/core": "0.3.1",
|
|
62
62
|
"@xterm/headless": "^6.0.0",
|
|
63
63
|
"better-sqlite3": "^12.8.0",
|
|
64
64
|
"croner": "^10.0.1",
|
|
@@ -79,11 +79,11 @@
|
|
|
79
79
|
"@copilotkit/llmock": "^1.6.0",
|
|
80
80
|
"@rivet-dev/agentos-sandbox": "link:../agentos-sandbox",
|
|
81
81
|
"@agentos-software/git": "0.3.0-rc.2",
|
|
82
|
-
"@secure-exec/google-drive": "0.
|
|
83
|
-
"@secure-exec/s3": "0.
|
|
82
|
+
"@secure-exec/google-drive": "0.3.1",
|
|
83
|
+
"@secure-exec/s3": "0.3.1",
|
|
84
84
|
"@mariozechner/pi-coding-agent": "^0.60.0",
|
|
85
85
|
"@agentos-software/claude-code": "0.0.0-nathan-binding-workspace.9be0a88",
|
|
86
|
-
"@agentos-software/codex-cli": "0.
|
|
86
|
+
"@agentos-software/codex-cli": "0.0.0-codex-claude-runtime-fixes.9cbef3a",
|
|
87
87
|
"@agentos-software/codex": "0.3.0-rc.2",
|
|
88
88
|
"@agentos-software/coreutils": "0.3.0-rc.2",
|
|
89
89
|
"@agentos-software/curl": "0.3.0-rc.2",
|