windows-development-sandbox 1.11.7 → 1.13.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/README.md +13 -6
- package/config.example.json +15 -4
- package/dist/app/features/access/access.def.d.ts +190 -0
- package/dist/app/features/access/access.def.js +273 -0
- package/dist/app/features/access/access.run.d.ts +79 -0
- package/dist/app/features/access/access.run.js +129 -0
- package/dist/app/features/access/index.d.ts +2 -0
- package/dist/app/features/access/index.js +3 -0
- package/dist/app/features/agents/agent-entry.js +5 -0
- package/dist/app/features/agents/agents.def.js +1 -0
- package/dist/app/features/apps/apps-rows.d.ts +4 -1
- package/dist/app/features/apps/apps-rows.js +7 -2
- package/dist/app/features/apps/apps.def.d.ts +19 -0
- package/dist/app/features/apps/apps.def.js +50 -12
- package/dist/app/features/apps/apps.run.d.ts +2 -0
- package/dist/app/features/apps/apps.run.js +1 -1
- package/dist/app/features/audit/audit.def.d.ts +350 -0
- package/dist/app/features/audit/audit.def.js +457 -0
- package/dist/app/features/audit/audit.run.d.ts +110 -0
- package/dist/app/features/audit/audit.run.js +133 -0
- package/dist/app/features/audit/index.d.ts +2 -0
- package/dist/app/features/audit/index.js +3 -0
- package/dist/app/features/defs.d.ts +349 -4
- package/dist/app/features/defs.js +16 -1
- package/dist/app/features/files/files.def.js +1 -0
- package/dist/app/features/health/health.def.js +1 -0
- package/dist/app/features/sandbox/sandbox.def.js +3 -0
- package/dist/app/features/sessions/sessions.def.d.ts +36 -0
- package/dist/app/features/sessions/sessions.def.js +77 -9
- package/dist/app/features/sessions/sessions.run.d.ts +25 -2
- package/dist/app/features/sessions/sessions.run.js +71 -3
- package/dist/app/features/settings/settings.def.d.ts +8 -0
- package/dist/app/features/settings/settings.def.js +17 -0
- package/dist/app/features/settings/settings.run.d.ts +3 -0
- package/dist/app/features/settings/settings.run.js +16 -2
- package/dist/app/features/web/web.def.d.ts +9 -0
- package/dist/app/features/web/web.def.js +26 -1
- package/dist/app/features/web/web.run.d.ts +3 -0
- package/dist/app/features/web/web.run.js +11 -3
- package/dist/app/kernel/access.d.ts +33 -0
- package/dist/app/kernel/access.js +44 -0
- package/dist/app/kernel/define.d.ts +26 -2
- package/dist/app/kernel/index.d.ts +1 -0
- package/dist/app/kernel/index.js +1 -0
- package/dist/app/kernel/rpc.d.ts +5 -2
- package/dist/app/registry.d.ts +4 -1
- package/dist/app/registry.js +26 -4
- package/dist/cli/args.d.ts +0 -3
- package/dist/cli/args.js +3 -4
- package/dist/cli/commands/index.d.ts +1 -1
- package/dist/cli/commands/index.js +1 -1
- package/dist/cli/commands/launch/prepare.js +1 -1
- package/dist/cli/commands/maintenance/index.d.ts +0 -1
- package/dist/cli/commands/maintenance/index.js +0 -1
- package/dist/cli/commands/registry.js +3 -2
- package/dist/cli/commands/remote.d.ts +2 -0
- package/dist/cli/commands/remote.js +49 -0
- package/dist/cli/commands/sessions/reopen.js +3 -0
- package/dist/cli/commands/web.js +66 -0
- package/dist/cli/manifest.d.ts +63 -45
- package/dist/cli/manifest.js +33 -18
- package/dist/cli/menu/io-menu.d.ts +5 -3
- package/dist/cli/menu/io-menu.js +12 -5
- package/dist/cli/menu/pages/apps-page.js +2 -15
- package/dist/cli/menu/pages/maintenance-page.d.ts +4 -0
- package/dist/cli/menu/pages/maintenance-page.js +51 -8
- package/dist/cli/menu/remote-menu.d.ts +19 -0
- package/dist/cli/menu/remote-menu.js +108 -0
- package/dist/cli/menu/views.js +4 -0
- package/dist/cli/operations/handler.js +15 -1
- package/dist/cli/services/remote-client.d.ts +16 -0
- package/dist/cli/services/remote-client.js +141 -0
- package/dist/cli/services/sessions-service.d.ts +5 -0
- package/dist/cli/services/sessions-service.js +17 -1
- package/dist/core/config/defaults.js +12 -2
- package/dist/core/local-config/file.js +16 -2
- package/dist/core/local-config/overrides.js +7 -0
- package/dist/core/run/versions.js +9 -8
- package/dist/core/schema/apps.d.ts +9 -0
- package/dist/core/schema/apps.js +9 -0
- package/dist/core/schema/config.d.ts +23 -3
- package/dist/core/schema/config.js +42 -5
- package/dist/core/schema/sandbox.d.ts +1 -0
- package/dist/core/schema/sandbox.js +11 -3
- package/dist/core/schema/web.d.ts +51 -0
- package/dist/core/schema/web.js +46 -1
- package/dist/core/util/fs.d.ts +5 -0
- package/dist/core/util/fs.js +23 -0
- package/dist/core/util/index.d.ts +1 -1
- package/dist/core/util/index.js +1 -1
- package/dist/guest/apps/app-installer.js +50 -4
- package/dist/guest/apps/index.d.ts +1 -1
- package/dist/guest/apps/index.js +1 -1
- package/dist/guest/apps/sources.js +1 -1
- package/dist/guest/audit/parse.d.ts +32 -2
- package/dist/guest/audit/parse.js +43 -5
- package/dist/guest/audit/process-audit.d.ts +3 -1
- package/dist/guest/audit/process-audit.js +9 -6
- package/dist/guest/boot/boot.js +12 -3
- package/dist/guest/boot/guide.d.ts +1 -1
- package/dist/guest/boot/guide.js +27 -3
- package/dist/guest/daemon/daemon.js +2 -0
- package/dist/guest/daemon/idle-shutdown.js +2 -1
- package/dist/guest/daemon/sessions.d.ts +23 -2
- package/dist/guest/daemon/sessions.js +151 -20
- package/dist/guest/entries/daemon.js +2 -1
- package/dist/guest/git/decision.js +7 -0
- package/dist/guest/sessions/cmdline.d.ts +14 -0
- package/dist/guest/sessions/cmdline.js +10 -0
- package/dist/guest/setup/addon-mcp.d.ts +2 -0
- package/dist/guest/setup/addon-mcp.js +49 -0
- package/dist/guest/setup/agent-addons.d.ts +9 -0
- package/dist/guest/setup/agent-addons.js +22 -0
- package/dist/guest/setup/headroom.d.ts +7 -0
- package/dist/guest/setup/headroom.js +60 -0
- package/dist/guest/setup/managed-policy.d.ts +2 -1
- package/dist/guest/setup/managed-policy.js +15 -6
- package/dist/guest/toolchains/plan.js +8 -3
- package/dist/guest/toolchains/setup.js +3 -0
- package/dist/host/audit/attribute.d.ts +46 -0
- package/dist/host/audit/attribute.js +76 -0
- package/dist/host/audit/collect.d.ts +29 -3
- package/dist/host/audit/collect.js +256 -61
- package/dist/host/audit/git-commits.d.ts +29 -0
- package/dist/host/audit/git-commits.js +157 -0
- package/dist/host/audit/index.d.ts +5 -0
- package/dist/host/audit/index.js +6 -0
- package/dist/host/audit/log.d.ts +45 -7
- package/dist/host/audit/log.js +148 -45
- package/dist/host/audit/redact.d.ts +2 -0
- package/dist/host/audit/redact.js +67 -0
- package/dist/host/channel/channel.d.ts +5 -1
- package/dist/host/channel/channel.js +12 -0
- package/dist/host/guard/agent-files.js +7 -1
- package/dist/host/guard/commands.js +13 -1
- package/dist/host/guard/git-config.js +27 -7
- package/dist/host/guard/git-dirs.js +78 -3
- package/dist/host/guard/mark-of-the-web.js +3 -1
- package/dist/host/guard/nested-repos.js +7 -2
- package/dist/host/guard/store.js +1 -0
- package/dist/host/guard/types.d.ts +2 -0
- package/dist/host/launch/mappings.js +11 -1
- package/dist/host/launch/project-scan.js +2 -21
- package/dist/host/launch/stage.js +4 -0
- package/dist/host/life/session-ledger.js +2 -1
- package/dist/host/remote/access-store.d.ts +156 -0
- package/dist/host/remote/access-store.js +308 -0
- package/dist/host/remote/cert.d.ts +20 -0
- package/dist/host/remote/cert.js +103 -0
- package/dist/host/remote/door-client.d.ts +13 -0
- package/dist/host/remote/door-client.js +54 -0
- package/dist/host/remote/firewall.d.ts +44 -0
- package/dist/host/remote/firewall.js +118 -0
- package/dist/host/remote/gate.d.ts +125 -0
- package/dist/host/remote/gate.js +391 -0
- package/dist/host/remote/index.d.ts +8 -0
- package/dist/host/remote/index.js +10 -0
- package/dist/host/remote/lan.d.ts +24 -0
- package/dist/host/remote/lan.js +88 -0
- package/dist/host/remote/tls-store.d.ts +22 -0
- package/dist/host/remote/tls-store.js +63 -0
- package/dist/host/remote/windows-helper.d.ts +67 -0
- package/dist/host/remote/windows-helper.js +129 -0
- package/dist/host/web/bridge.d.ts +5 -1
- package/dist/host/web/bridge.js +6 -2
- package/dist/host/web/browser.js +1 -1
- package/dist/host/web/control.d.ts +4 -1
- package/dist/host/web/control.js +28 -4
- package/dist/host/web/rpc.d.ts +16 -2
- package/dist/host/web/rpc.js +37 -4
- package/dist/host/web/runner.d.ts +4 -0
- package/dist/host/web/runner.js +12 -0
- package/dist/host/web/server.d.ts +18 -2
- package/dist/host/web/server.js +97 -24
- package/dist/host/web/state.d.ts +5 -0
- package/dist/host/web/state.js +8 -0
- package/dist/runtime/agent.js +184 -18
- package/dist/runtime/daemon.js +772 -338
- package/dist/runtime/db.js +184 -18
- package/dist/runtime/gitguard.js +6 -0
- package/dist/runtime/main.js +966 -553
- package/dist/runtime/netproxy.js +184 -18
- package/dist/runtime/view.js +186 -18
- package/dist/selftest/app.test.js +66 -7
- package/dist/selftest/audit.test.js +354 -47
- package/dist/selftest/channel.test.js +16 -0
- package/dist/selftest/cmdline.test.js +16 -0
- package/dist/selftest/git-access.test.js +8 -0
- package/dist/selftest/hcs.test.js +35 -0
- package/dist/selftest/hostile-input.test.js +12 -1
- package/dist/selftest/index.js +2 -0
- package/dist/selftest/live-daemon.test.js +25 -0
- package/dist/selftest/local-config.test.js +30 -0
- package/dist/selftest/menu-screens.js +1 -1
- package/dist/selftest/menu.test.js +3 -3
- package/dist/selftest/remote.test.d.ts +2 -0
- package/dist/selftest/remote.test.js +536 -0
- package/dist/selftest/repo-guard.test.js +56 -2
- package/dist/selftest/resume.test.js +2 -1
- package/dist/selftest/sharing.test.js +9 -2
- package/dist/selftest/support/engine-golden.js +9 -0
- package/dist/selftest/support/fixtures.d.ts +14 -0
- package/dist/selftest/support/web-preview.js +157 -0
- package/dist/selftest/toolchains.test.js +147 -2
- package/dist/selftest/web.test.js +2 -0
- package/dist/shared/apps/agent-addons.d.ts +64 -0
- package/dist/shared/apps/agent-addons.js +95 -0
- package/dist/shared/apps/catalogue.d.ts +33 -2
- package/dist/shared/apps/catalogue.js +102 -11
- package/dist/shared/apps/index.d.ts +3 -2
- package/dist/shared/apps/index.js +3 -2
- package/dist/shared/apps/selection.d.ts +2 -0
- package/dist/shared/apps/selection.js +7 -0
- package/dist/shared/channel/schema.d.ts +23 -0
- package/dist/shared/channel/schema.js +8 -0
- package/dist/shared/pty/protocol.d.ts +2 -0
- package/dist/shared/pty/protocol.js +2 -0
- package/dist/sync/watcher.js +9 -1
- package/dist/web/index.html +2 -2
- package/dist/web/{main-RQFN4WBY.css → main-UAQPI5XD.css} +1 -1
- package/dist/web/main-Z2WYAE2Z.js +221 -0
- package/native/csharp/HcsHost/AssemblyInfo.cs +5 -3
- package/native/csharp/HcsHost/Hcs.cs +9 -0
- package/native/csharp/HcsHost/Program.cs +26 -1
- package/native/csharp/HcsHost/Share.cs +173 -0
- package/native/csharp/HostTools/AssemblyInfo.cs +3 -3
- package/native/csharp/HostTools/Program.cs +17 -1
- package/native/csharp/HostTools/WebHelper.cs +499 -0
- package/native/scripts/get-network-profile.ps1 +19 -0
- package/native/scripts/set-folder-access.ps1 +11 -0
- package/native/scripts/set-web-firewall.ps1 +103 -0
- package/package.json +1 -1
- package/sandbox/addons/ccusage/package-lock.json +111 -0
- package/sandbox/addons/ccusage/package.json +7 -0
- package/sandbox/addons/context7/package-lock.json +1313 -0
- package/sandbox/addons/context7/package.json +7 -0
- package/sandbox/addons/headroom/requirements.in +1 -0
- package/sandbox/addons/headroom/requirements.txt +2922 -0
- package/sandbox/addons/playwright-mcp/package-lock.json +56 -0
- package/sandbox/addons/playwright-mcp/package.json +7 -0
- package/sandbox/csharp/PtyHost.cs +20 -0
- package/schemas/config.schema.json +78 -4
- package/schemas/sandbox-config.schema.json +2 -20
- package/dist/cli/commands/maintenance/audit.d.ts +0 -3
- package/dist/cli/commands/maintenance/audit.js +0 -58
- package/dist/web/main-K2JMCAZI.js +0 -219
package/dist/host/web/server.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
// The web UI's HTTP server: the app's files, a small JSON API for sessions, the terminal WebSocket and the RPC
|
|
2
2
|
// WebSocket of the shared core. Loopback only; nothing works without the token's cookie, and Host / Origin / CSRF
|
|
3
3
|
// checks keep other sites out (docs/web-ui.md).
|
|
4
|
+
import crypto from 'node:crypto';
|
|
4
5
|
import fs from 'node:fs';
|
|
5
6
|
import http from 'node:http';
|
|
6
7
|
import { WebSocketServer } from 'ws';
|
|
8
|
+
import { allows, callerAccess, callerLabel, OWNER } from '../../app/kernel/index.js';
|
|
7
9
|
import { UserError, safeText } from '../../core/util/index.js';
|
|
8
10
|
import { MAX_CLIENT_MESSAGE_BYTES, MAX_COLS, MAX_ROWS, MIN_COLS, MIN_ROWS } from '../../shared/web/index.js';
|
|
9
11
|
import { cookieHeader, csrfOk, hostAllowed, originAllowed, WebAuth } from './auth.js';
|
|
@@ -28,6 +30,9 @@ export const IDLE_EXIT_MS = 20 * 60_000;
|
|
|
28
30
|
export const IDLE_NO_SANDBOX_MS = 5 * 60_000;
|
|
29
31
|
const SESSION_PATH = /^\/api\/sessions\/([A-Za-z0-9_-]{1,64})\/terminal$/;
|
|
30
32
|
export const RPC_PATH = '/api/rpc';
|
|
33
|
+
/** What a service worker registered on this origin by someone else gets when the browser updates it: gone. */
|
|
34
|
+
const UNREGISTER_WORKER = "self.addEventListener('install',()=>self.skipWaiting());" +
|
|
35
|
+
"self.addEventListener('activate',(e)=>e.waitUntil(self.registration.unregister()));";
|
|
31
36
|
class HttpFailure extends Error {
|
|
32
37
|
status;
|
|
33
38
|
constructor(status, message) {
|
|
@@ -80,7 +85,19 @@ export class WebServer {
|
|
|
80
85
|
this.idleCheck = setInterval(() => void this.checkIdle(), Math.min(60_000, this.quietMs()));
|
|
81
86
|
this.idleCheck.unref();
|
|
82
87
|
}
|
|
83
|
-
|
|
88
|
+
const gate = this.options.gate;
|
|
89
|
+
if (!gate)
|
|
90
|
+
return resolve();
|
|
91
|
+
gate.start();
|
|
92
|
+
void gate
|
|
93
|
+
.startLan({
|
|
94
|
+
request: (req, res) => void this.handle(req, res),
|
|
95
|
+
upgrade: (req, socket, head) => {
|
|
96
|
+
this.lastUsed = Date.now();
|
|
97
|
+
this.upgrade(req, socket, head);
|
|
98
|
+
},
|
|
99
|
+
})
|
|
100
|
+
.finally(resolve);
|
|
84
101
|
});
|
|
85
102
|
});
|
|
86
103
|
}
|
|
@@ -155,7 +172,8 @@ export class WebServer {
|
|
|
155
172
|
for (const client of this.sockets.clients)
|
|
156
173
|
client.close(1001, 'server stopping');
|
|
157
174
|
this.server.closeAllConnections();
|
|
158
|
-
|
|
175
|
+
const gate = this.options.gate?.stop();
|
|
176
|
+
return new Promise((resolve) => this.server.close(() => void Promise.resolve(gate).then(() => resolve())));
|
|
159
177
|
}
|
|
160
178
|
headers(extra = {}) {
|
|
161
179
|
return {
|
|
@@ -175,7 +193,7 @@ export class WebServer {
|
|
|
175
193
|
async handle(req, res) {
|
|
176
194
|
this.lastUsed = Date.now();
|
|
177
195
|
try {
|
|
178
|
-
if (!
|
|
196
|
+
if (!this.hostOk(req))
|
|
179
197
|
throw new HttpFailure(421, 'Wrong host name.');
|
|
180
198
|
const url = new URL(req.url ?? '/', 'http://127.0.0.1');
|
|
181
199
|
if (url.pathname.startsWith('/api/'))
|
|
@@ -192,9 +210,35 @@ export class WebServer {
|
|
|
192
210
|
this.json(res, 500, { error: 'Something went wrong.' });
|
|
193
211
|
}
|
|
194
212
|
}
|
|
213
|
+
/** The LAN listener's own address:port, or loopback with our port. */
|
|
214
|
+
hostOk(req) {
|
|
215
|
+
const gate = this.options.gate;
|
|
216
|
+
if (gate?.isLan(req.socket))
|
|
217
|
+
return gate.lanHostAllowed(req.headers.host);
|
|
218
|
+
return hostAllowed(req.headers.host, this.actualPort);
|
|
219
|
+
}
|
|
220
|
+
originOk(req) {
|
|
221
|
+
const gate = this.options.gate;
|
|
222
|
+
if (gate?.isLan(req.socket))
|
|
223
|
+
return gate.lanOriginAllowed(req.headers.origin, req.headers.host);
|
|
224
|
+
return originAllowed(req.headers.origin, req.headers.host, this.actualPort);
|
|
225
|
+
}
|
|
226
|
+
/** Who sent the request: the owner's token cookie (loopback only), or whoever the gate lets in. Null: nobody. */
|
|
227
|
+
async callerOf(req) {
|
|
228
|
+
const gate = this.options.gate;
|
|
229
|
+
const ownerCookie = !gate?.isLan(req.socket) && this.auth.signedIn(req.headers.cookie);
|
|
230
|
+
if (!gate)
|
|
231
|
+
return { caller: ownerCookie ? OWNER : null, ownerCookie };
|
|
232
|
+
return { caller: await gate.caller(req, ownerCookie), ownerCookie };
|
|
233
|
+
}
|
|
195
234
|
serveFile(req, res, pathname) {
|
|
196
235
|
if (req.method !== 'GET' && req.method !== 'HEAD')
|
|
197
236
|
throw new HttpFailure(405, 'Not allowed.');
|
|
237
|
+
if (req.headers['service-worker'] === 'script') {
|
|
238
|
+
res.writeHead(200, this.headers({ 'Content-Type': 'text/javascript; charset=utf-8', 'Cache-Control': 'no-store' }));
|
|
239
|
+
res.end(UNREGISTER_WORKER);
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
198
242
|
const file = this.files.find(pathname);
|
|
199
243
|
if (!file)
|
|
200
244
|
throw new HttpFailure(404, 'Not found.');
|
|
@@ -211,14 +255,21 @@ export class WebServer {
|
|
|
211
255
|
}
|
|
212
256
|
/** A call that changes something: the custom header, and an Origin that is this page. */
|
|
213
257
|
requireSameSite(req) {
|
|
214
|
-
if (!csrfOk(req.headers) || !
|
|
258
|
+
if (!csrfOk(req.headers) || !this.originOk(req))
|
|
215
259
|
throw new HttpFailure(403, 'Refused.');
|
|
216
260
|
}
|
|
217
261
|
async api(req, res, pathname) {
|
|
218
262
|
const method = req.method ?? 'GET';
|
|
219
263
|
const { backend } = this.options;
|
|
220
264
|
if (pathname === '/api/health' && method === 'GET')
|
|
221
|
-
return this.json(res, 200,
|
|
265
|
+
return this.json(res, 200, this.health(req));
|
|
266
|
+
if (this.options.gate &&
|
|
267
|
+
(await this.options.gate.route(req, pathname, {
|
|
268
|
+
body: () => this.body(req),
|
|
269
|
+
json: (status, body, headers) => this.json(res, status, body, headers),
|
|
270
|
+
requireSameSite: () => this.requireSameSite(req),
|
|
271
|
+
})))
|
|
272
|
+
return;
|
|
222
273
|
if (pathname === '/api/login' && method === 'POST') {
|
|
223
274
|
this.requireSameSite(req);
|
|
224
275
|
const body = await this.body(req);
|
|
@@ -227,14 +278,19 @@ export class WebServer {
|
|
|
227
278
|
throw new HttpFailure(result.status, result.status === 429 ? 'Too many tries.' : 'Wrong token.');
|
|
228
279
|
return this.json(res, 200, { ok: true }, { 'Set-Cookie': cookieHeader(result.cookie) });
|
|
229
280
|
}
|
|
230
|
-
|
|
281
|
+
const { caller } = await this.callerOf(req);
|
|
282
|
+
if (!caller)
|
|
231
283
|
throw new HttpFailure(401, 'Not signed in.');
|
|
284
|
+
if (pathname === '/api/me' && method === 'GET')
|
|
285
|
+
return this.json(res, 200, { kind: caller.kind, who: callerLabel(caller), access: callerAccess(caller) });
|
|
232
286
|
if (pathname === '/api/info' && method === 'GET')
|
|
233
287
|
return this.json(res, 200, await backend.info());
|
|
234
288
|
if (pathname === '/api/sessions' && method === 'GET')
|
|
235
289
|
return this.json(res, 200, await backend.sessions());
|
|
236
290
|
if (pathname === '/api/stop' && method === 'POST') {
|
|
237
291
|
this.requireSameSite(req);
|
|
292
|
+
if (caller.kind !== 'owner')
|
|
293
|
+
throw new HttpFailure(403, 'Only the owner of this PC can stop the web UI.');
|
|
238
294
|
this.json(res, 200, { ok: true });
|
|
239
295
|
setTimeout(() => this.options.onStop?.(), 100);
|
|
240
296
|
return;
|
|
@@ -278,31 +334,48 @@ export class WebServer {
|
|
|
278
334
|
if (!match && !rpc)
|
|
279
335
|
return refuse('404 Not Found');
|
|
280
336
|
// The Origin must be this page (a page of another site can open WebSockets too) and the cookie is the login.
|
|
281
|
-
if (!
|
|
337
|
+
if (!this.hostOk(req) || !this.originOk(req))
|
|
282
338
|
return refuse('403 Forbidden');
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
339
|
+
void this.callerOf(req).then(({ caller, ownerCookie }) => {
|
|
340
|
+
if (!caller)
|
|
341
|
+
return refuse('401 Unauthorized');
|
|
342
|
+
if (rpc)
|
|
343
|
+
return this.upgradeRpc(req, socket, head, rpc, caller, ownerCookie);
|
|
344
|
+
if (!match)
|
|
345
|
+
return refuse('404 Not Found');
|
|
346
|
+
const endpoint = this.options.backend.endpoint(match[1]);
|
|
347
|
+
if (!endpoint)
|
|
348
|
+
return refuse('404 Not Found');
|
|
349
|
+
const cols = bounded(url.searchParams.get('cols'), MIN_COLS, MAX_COLS, 120);
|
|
350
|
+
const rows = bounded(url.searchParams.get('rows'), MIN_ROWS, MAX_ROWS, 30);
|
|
351
|
+
// View only: the terminal shows, and the bridge drops every keystroke and resize.
|
|
352
|
+
const readOnly = !allows(caller, 'control');
|
|
353
|
+
this.sockets.handleUpgrade(req, socket, head, (ws) => {
|
|
354
|
+
this.track(ws, 'terminal', MAX_TERMINALS);
|
|
355
|
+
this.options.gate?.track(ws, req, ownerCookie, caller);
|
|
356
|
+
void new TerminalBridge(ws, endpoint, cols, rows, this.options.dial, readOnly).start();
|
|
357
|
+
});
|
|
297
358
|
});
|
|
298
359
|
}
|
|
299
|
-
/** The RPC socket (after the same Origin and
|
|
300
|
-
upgradeRpc(req, socket, head, rpc) {
|
|
360
|
+
/** The RPC socket (after the same Origin and caller checks as a terminal). */
|
|
361
|
+
upgradeRpc(req, socket, head, rpc, caller, ownerCookie) {
|
|
301
362
|
this.sockets.handleUpgrade(req, socket, head, (ws) => {
|
|
302
363
|
this.track(ws, 'rpc', MAX_RPC_SOCKETS);
|
|
303
|
-
|
|
364
|
+
const gate = this.options.gate;
|
|
365
|
+
const now = gate ? gate.track(ws, req, ownerCookie, caller) : () => caller;
|
|
366
|
+
new RpcSession(ws, rpc, this.live, now, gate ? (entry) => gate.recordCall(entry) : undefined).start();
|
|
304
367
|
});
|
|
305
368
|
}
|
|
369
|
+
/**
|
|
370
|
+
* GET /api/health: alive, and with ?challenge=<hex> on loopback the proof that this server holds the token (an
|
|
371
|
+
* HMAC of the challenge), so the CLI never hands the token link to another program on the port.
|
|
372
|
+
*/
|
|
373
|
+
health(req) {
|
|
374
|
+
const challenge = new URL(req.url ?? '/', 'http://127.0.0.1').searchParams.get('challenge') ?? '';
|
|
375
|
+
if (this.options.gate?.isLan(req.socket) || !/^[0-9a-f]{32,128}$/.test(challenge))
|
|
376
|
+
return { ok: true };
|
|
377
|
+
return { ok: true, proof: crypto.createHmac('sha256', this.options.token).update(challenge).digest('hex') };
|
|
378
|
+
}
|
|
306
379
|
}
|
|
307
380
|
function bounded(text, min, max, fallback) {
|
|
308
381
|
const n = Number(text);
|
package/dist/host/web/state.d.ts
CHANGED
|
@@ -5,6 +5,11 @@ export declare const WebStateSchema: z.ZodObject<{
|
|
|
5
5
|
token: z.ZodString;
|
|
6
6
|
startedAt: z.ZodString;
|
|
7
7
|
version: z.ZodOptional<z.ZodString>;
|
|
8
|
+
lan: z.ZodOptional<z.ZodObject<{
|
|
9
|
+
url: z.ZodNullable<z.ZodString>;
|
|
10
|
+
fingerprint: z.ZodNullable<z.ZodString>;
|
|
11
|
+
problem: z.ZodNullable<z.ZodString>;
|
|
12
|
+
}, z.core.$strict>>;
|
|
8
13
|
}, z.core.$strict>;
|
|
9
14
|
export type WebState = z.output<typeof WebStateSchema>;
|
|
10
15
|
export declare class WebStore {
|
package/dist/host/web/state.js
CHANGED
|
@@ -12,6 +12,14 @@ export const WebStateSchema = z.strictObject({
|
|
|
12
12
|
startedAt: z.string().max(64),
|
|
13
13
|
/** The version that started it (missing: an older one). Another version is replaced, never reused. */
|
|
14
14
|
version: z.string().max(64).optional(),
|
|
15
|
+
/** LAN mode (docs/design/remote-access.md): its address for phones, the certificate, or why it is not running. */
|
|
16
|
+
lan: z
|
|
17
|
+
.strictObject({
|
|
18
|
+
url: z.string().max(64).nullable(),
|
|
19
|
+
fingerprint: z.string().max(100).nullable(),
|
|
20
|
+
problem: z.string().max(500).nullable(),
|
|
21
|
+
})
|
|
22
|
+
.optional(),
|
|
15
23
|
});
|
|
16
24
|
export class WebStore {
|
|
17
25
|
storageRoot;
|
package/dist/runtime/agent.js
CHANGED
|
@@ -25541,14 +25541,19 @@ var NetworkSchema = external_exports.strictObject({
|
|
|
25541
25541
|
});
|
|
25542
25542
|
var AuditSchema = external_exports.strictObject({
|
|
25543
25543
|
enabled: external_exports.boolean().describe(
|
|
25544
|
-
"Keep an audit log on this PC of what
|
|
25544
|
+
"Keep an audit log on this PC of what your agents did: programs started (with their command lines, secrets hidden), files changed in the projects, git commits, sessions, and what the repo guard caught, each linked to the agent session that did it where that can be known. The sandbox cannot change it. Read it with sandbox audit or on the Activity page."
|
|
25545
|
+
),
|
|
25546
|
+
days: external_exports.number().int().min(1).max(365).describe(
|
|
25547
|
+
"Days the audit log is kept (1 to 30; a larger number keeps 30); older days are deleted when a sandbox starts and once a day."
|
|
25545
25548
|
),
|
|
25546
|
-
days: external_exports.number().int().min(1).max(365).describe("Days the audit log is kept."),
|
|
25547
25549
|
maxMb: external_exports.number().int().min(5).max(5e3).describe("Most space the audit log may take, in MB (older days go first). Days before today are compressed."),
|
|
25548
25550
|
processes: external_exports.boolean().describe(
|
|
25549
25551
|
"Record every program started in the sandbox with its command line (Windows process auditing; repeated runs are counted, not listed)."
|
|
25550
25552
|
),
|
|
25551
|
-
files: external_exports.boolean().describe("Record the files changed in the
|
|
25553
|
+
files: external_exports.boolean().describe("Record the files changed in the projects while the sandbox runs."),
|
|
25554
|
+
commits: external_exports.boolean().describe(
|
|
25555
|
+
"Record the git commits made in the projects while the sandbox runs (read from each project's .git folder on this PC)."
|
|
25556
|
+
)
|
|
25552
25557
|
});
|
|
25553
25558
|
var WorkspaceFilterSchema = external_exports.strictObject({
|
|
25554
25559
|
enabled: external_exports.boolean().describe(
|
|
@@ -25751,7 +25756,100 @@ var ToolchainsSchema = external_exports.strictObject({
|
|
|
25751
25756
|
|
|
25752
25757
|
// src/shared/apps/catalogue.ts
|
|
25753
25758
|
var gh = (github, asset) => ({ github, asset });
|
|
25759
|
+
var RTK_VERSION = "1.0.1";
|
|
25760
|
+
var RTK_URL = "https://github.com/rtk-ai/rtk/releases/download/v" + RTK_VERSION + "/rtk-oss-x86_64-pc-windows-msvc.zip";
|
|
25761
|
+
var RTK_SHA256 = "0e53e2eca471e15fbd3636e64e6bc0b182cbc278ed0339c80450a2dd03f4cd6b";
|
|
25762
|
+
var HEADROOM_VERSION = "0.41.0";
|
|
25763
|
+
var CCUSAGE_VERSION = "20.0.36";
|
|
25764
|
+
var PLAYWRIGHT_MCP_VERSION = "0.0.83";
|
|
25765
|
+
var CONTEXT7_MCP_VERSION = "4.4.2";
|
|
25754
25766
|
var APPS = [
|
|
25767
|
+
// ---- agent add-ons
|
|
25768
|
+
{
|
|
25769
|
+
id: "rtk",
|
|
25770
|
+
name: "rtk (Rust Token Killer)",
|
|
25771
|
+
category: "agents",
|
|
25772
|
+
about: "Compacts the output of shell commands (git, tests, builds, ls ...) before the agent reads it, so it uses fewer tokens. Claude Code's Bash commands go through it on their own.",
|
|
25773
|
+
size: "6 MB",
|
|
25774
|
+
source: { url: RTK_URL, sha256: RTK_SHA256 },
|
|
25775
|
+
exe: "rtk.exe",
|
|
25776
|
+
cli: true,
|
|
25777
|
+
plugsInto: "Claude Code through a hook in the sandbox's managed settings; other agents are told to use it",
|
|
25778
|
+
userOnly: true
|
|
25779
|
+
},
|
|
25780
|
+
{
|
|
25781
|
+
id: "headroom",
|
|
25782
|
+
name: "Headroom",
|
|
25783
|
+
category: "agents",
|
|
25784
|
+
about: "Compresses what Claude Code sends to the model (tool output, logs, files) so it uses fewer tokens: a local proxy on 127.0.0.1:8787 that sits in Claude Code's API path, offline apart from forwarding to api.anthropic.com.",
|
|
25785
|
+
size: "150 MB",
|
|
25786
|
+
source: { locked: "uv", package: "headroom-ai", version: HEADROOM_VERSION },
|
|
25787
|
+
exe: "headroom.exe",
|
|
25788
|
+
service: true,
|
|
25789
|
+
plugsInto: "Claude Code: the sandbox starts the proxy and points Claude Code at it (managed settings)",
|
|
25790
|
+
userOnly: true
|
|
25791
|
+
},
|
|
25792
|
+
{
|
|
25793
|
+
id: "ccusage",
|
|
25794
|
+
name: "ccusage",
|
|
25795
|
+
category: "agents",
|
|
25796
|
+
about: "Reports the agents' token use and cost by day, month or session from their logs in the sandbox (`ccusage daily`; add --offline to skip fetching prices).",
|
|
25797
|
+
size: "5 MB",
|
|
25798
|
+
source: { locked: "npm", package: "ccusage", version: CCUSAGE_VERSION },
|
|
25799
|
+
exe: "ccusage.cmd",
|
|
25800
|
+
cli: true,
|
|
25801
|
+
plugsInto: "Reads Claude Code's session logs in the sandbox; changes nothing",
|
|
25802
|
+
userOnly: true
|
|
25803
|
+
},
|
|
25804
|
+
{
|
|
25805
|
+
id: "playwright-mcp",
|
|
25806
|
+
name: "Playwright MCP",
|
|
25807
|
+
category: "agents",
|
|
25808
|
+
about: "Lets Claude Code drive a browser (Microsoft Edge, already in the sandbox) to open pages, click, fill forms and take screenshots: the MCP server of microsoft/playwright-mcp.",
|
|
25809
|
+
size: "20 MB",
|
|
25810
|
+
source: { locked: "npm", package: "@playwright/mcp", version: PLAYWRIGHT_MCP_VERSION },
|
|
25811
|
+
exe: "playwright-mcp.cmd",
|
|
25812
|
+
service: true,
|
|
25813
|
+
mcp: { name: "sbx-playwright", script: "node_modules/@playwright/mcp/cli.js", args: ["--browser", "msedge"] },
|
|
25814
|
+
plugsInto: "Claude Code as the MCP server sbx-playwright (the sandbox's Claude settings)",
|
|
25815
|
+
userOnly: true
|
|
25816
|
+
},
|
|
25817
|
+
{
|
|
25818
|
+
id: "context7",
|
|
25819
|
+
name: "Context7 MCP",
|
|
25820
|
+
category: "agents",
|
|
25821
|
+
about: "Up-to-date documentation and code examples for libraries, looked up by Claude Code while it works (upstash/context7). The library names and questions go to Upstash's context7.com.",
|
|
25822
|
+
size: "55 MB",
|
|
25823
|
+
source: { locked: "npm", package: "@upstash/context7-mcp", version: CONTEXT7_MCP_VERSION },
|
|
25824
|
+
exe: "context7-mcp.cmd",
|
|
25825
|
+
service: true,
|
|
25826
|
+
mcp: { name: "sbx-context7", script: "node_modules/@upstash/context7-mcp/dist/index.js" },
|
|
25827
|
+
plugsInto: "Claude Code as the MCP server sbx-context7 (the sandbox's Claude settings)",
|
|
25828
|
+
userOnly: true
|
|
25829
|
+
},
|
|
25830
|
+
{
|
|
25831
|
+
id: "claude-mem",
|
|
25832
|
+
name: "claude-mem",
|
|
25833
|
+
category: "agents",
|
|
25834
|
+
about: "Persistent memory for Claude Code (a plugin you install on this PC): its database is brought into the sandbox.",
|
|
25835
|
+
size: "",
|
|
25836
|
+
source: { resolve: "setting" },
|
|
25837
|
+
exe: "",
|
|
25838
|
+
setting: "claudeProfile.syncClaudeMem",
|
|
25839
|
+
plugsInto: "Claude Code, with your Claude settings copied from this PC",
|
|
25840
|
+
userOnly: true
|
|
25841
|
+
},
|
|
25842
|
+
{
|
|
25843
|
+
id: "rea",
|
|
25844
|
+
name: "REA (Reverse Engineer Anything)",
|
|
25845
|
+
category: "agents",
|
|
25846
|
+
about: "Agent-driven reverse engineering (MCP server and CLI, by morluto). Run `rea setup` once to add it to Claude Code and Codex. Native binaries need Ghidra; needs Node 22.19+.",
|
|
25847
|
+
size: "8 MB",
|
|
25848
|
+
source: { npm: "rea-agents" },
|
|
25849
|
+
exe: "rea.cmd",
|
|
25850
|
+
cli: true,
|
|
25851
|
+
plugsInto: "Claude Code and Codex as an MCP server, after `rea setup`"
|
|
25852
|
+
},
|
|
25755
25853
|
// ---- editors
|
|
25756
25854
|
{
|
|
25757
25855
|
id: "vscode",
|
|
@@ -26213,16 +26311,6 @@ var APPS = [
|
|
|
26213
26311
|
cli: true
|
|
26214
26312
|
},
|
|
26215
26313
|
// ---- reverse engineering
|
|
26216
|
-
{
|
|
26217
|
-
id: "rea",
|
|
26218
|
-
name: "REA (Reverse Engineer Anything)",
|
|
26219
|
-
category: "reversing",
|
|
26220
|
-
about: "Agent-driven reverse engineering (MCP server and CLI, by morluto). Run `rea setup` once to add it to Claude Code and Codex. Native binaries need Ghidra; needs Node 22.19+.",
|
|
26221
|
-
size: "8 MB",
|
|
26222
|
-
source: { npm: "rea-agents" },
|
|
26223
|
-
exe: "rea.cmd",
|
|
26224
|
-
cli: true
|
|
26225
|
-
},
|
|
26226
26314
|
{
|
|
26227
26315
|
id: "ghidra",
|
|
26228
26316
|
name: "Ghidra",
|
|
@@ -26502,6 +26590,8 @@ var APPS = [
|
|
|
26502
26590
|
// src/core/schema/apps.ts
|
|
26503
26591
|
var CATALOGUE_IDS = APPS.filter((a) => !a.setting).map((a) => a.id);
|
|
26504
26592
|
var AppIdSchema = external_exports.enum(CATALOGUE_IDS);
|
|
26593
|
+
var PROJECT_IDS = APPS.filter((a) => !a.setting && !a.userOnly).map((a) => a.id);
|
|
26594
|
+
var ProjectAppIdSchema = external_exports.enum(PROJECT_IDS);
|
|
26505
26595
|
var CustomAppIdSchema = external_exports.string().regex(/^[a-z0-9][a-z0-9-]{0,40}$/, "lower-case letters, digits and - only");
|
|
26506
26596
|
var compiles = (pattern) => {
|
|
26507
26597
|
try {
|
|
@@ -26525,6 +26615,11 @@ var CustomAppSchema = external_exports.strictObject({
|
|
|
26525
26615
|
}).refine((a) => a.github && a.asset ? !a.url : Boolean(a.url) && !a.github && !a.asset, {
|
|
26526
26616
|
message: "give github + asset, or url (not both)"
|
|
26527
26617
|
});
|
|
26618
|
+
var ProjectAppsSchema = external_exports.strictObject({
|
|
26619
|
+
install: external_exports.array(ProjectAppIdSchema).describe(
|
|
26620
|
+
"Apps from the catalogue this project adds to yours (agent add-ons such as rtk, Headroom and the MCP servers are set in your own settings only)."
|
|
26621
|
+
)
|
|
26622
|
+
});
|
|
26528
26623
|
var AppsSchema = external_exports.strictObject({
|
|
26529
26624
|
install: external_exports.array(AppIdSchema).describe(
|
|
26530
26625
|
"Apps from the catalogue to install in every sandbox (the Apps screen in the menu lists them by category). Each is downloaded once and kept."
|
|
@@ -26565,12 +26660,39 @@ var ResumeSchema = external_exports.strictObject({
|
|
|
26565
26660
|
});
|
|
26566
26661
|
|
|
26567
26662
|
// src/core/schema/web.ts
|
|
26663
|
+
var REMOTE_ROLES = ["view", "control"];
|
|
26664
|
+
var WindowsUserNameSchema = external_exports.string().trim().min(1).max(120).regex(
|
|
26665
|
+
/^(?:[A-Za-z0-9][A-Za-z0-9._ -]{0,62}\\)?[^\\/"[\]:;|=,+*?<>@]{1,64}$/,
|
|
26666
|
+
"a Windows user name (name or DOMAIN\\name)"
|
|
26667
|
+
);
|
|
26668
|
+
var RemoteUserSchema = external_exports.strictObject({
|
|
26669
|
+
name: WindowsUserNameSchema.describe("The Windows user (name, or DOMAIN\\name)"),
|
|
26670
|
+
role: external_exports.enum(REMOTE_ROLES).describe("view: sees everything, terminals read-only. control: everything but remote access, logins and tokens.")
|
|
26671
|
+
});
|
|
26672
|
+
var WebLanSchema = external_exports.strictObject({
|
|
26673
|
+
enabled: external_exports.boolean().describe(
|
|
26674
|
+
"(Beta) Devices on your network (a phone): an HTTPS address on this PC for devices you pair with a one-time code (sandbox web pair). Needs a firewall rule (sandbox web lan on asks Windows once). Off: every paired device is signed out."
|
|
26675
|
+
),
|
|
26676
|
+
port: external_exports.number().int().min(1024).max(65535).describe("HTTPS port for paired devices on your network."),
|
|
26677
|
+
address: external_exports.string().trim().max(15).regex(/^$|^\d{1,3}(\.\d{1,3}){3}$/, "an IPv4 address or empty").describe("This PC's private address to listen on. Empty: the one of its network adapter (never a public one).")
|
|
26678
|
+
});
|
|
26679
|
+
var WebRemoteSchema = external_exports.strictObject({
|
|
26680
|
+
windowsSignIn: external_exports.boolean().describe(
|
|
26681
|
+
"(Beta) Other Windows users of this PC named in web.remote.users sign in to your web UI (and sandbox remote) with their own Windows account: no password, no link."
|
|
26682
|
+
),
|
|
26683
|
+
users: external_exports.array(RemoteUserSchema).max(32).describe("Who else may sign in with Windows, and their role (view or control)."),
|
|
26684
|
+
rememberDays: external_exports.number().int().min(1).max(90).describe(
|
|
26685
|
+
"How many days a paired device or a Windows sign-in stays signed in (from when it signed in, not renewed)."
|
|
26686
|
+
),
|
|
26687
|
+
lan: WebLanSchema
|
|
26688
|
+
});
|
|
26568
26689
|
var WebSchema = external_exports.strictObject({
|
|
26569
26690
|
enabled: external_exports.boolean().describe(
|
|
26570
26691
|
"(Beta) The web UI: your sandbox sessions in a browser on this PC (http://127.0.0.1:<port>, this PC only). On: every sandbox start also starts it in the background (it keeps running until sandbox web stop or a restart of the PC). Off: only sandbox web start runs it. Open it signed in with sandbox web open."
|
|
26571
26692
|
),
|
|
26572
26693
|
port: external_exports.number().int().min(1024).max(65535).describe("Port of the web UI on 127.0.0.1 (this PC only). Pick another when it is taken."),
|
|
26573
|
-
openOnLaunch: external_exports.boolean().describe("(Beta) With the web UI on: open it in your browser, already signed in, every time a sandbox starts.")
|
|
26694
|
+
openOnLaunch: external_exports.boolean().describe("(Beta) With the web UI on: open it in your browser, already signed in, every time a sandbox starts."),
|
|
26695
|
+
remote: WebRemoteSchema.describe("(Beta) Access for other Windows users of this PC and for paired devices.")
|
|
26574
26696
|
});
|
|
26575
26697
|
|
|
26576
26698
|
// src/core/schema/vpn.ts
|
|
@@ -26600,6 +26722,36 @@ var GithubSchema = external_exports.strictObject({
|
|
|
26600
26722
|
});
|
|
26601
26723
|
|
|
26602
26724
|
// src/core/schema/config.ts
|
|
26725
|
+
var RESERVED_ENV_PREFIX = /^(AGENT_|GIT_|GH_|GITHUB_|NODE_|NPM_CONFIG_(USERCONFIG|GLOBALCONFIG|PREFIX|SCRIPT_SHELL)|SSL_|CLAUDE|ANTHROPIC_|OPENAI_|CODEX_|GEMINI_|GOOGLE_|COPILOT_|AWS_|AZURE_)/i;
|
|
26726
|
+
var RESERVED_ENV_SUFFIX = /(_PROXY|_BASE_URL|_ENDPOINT|_CA_BUNDLE|_CA_CERTS)$/i;
|
|
26727
|
+
var RESERVED_ENV_NAMES = new Set(
|
|
26728
|
+
[
|
|
26729
|
+
"PATH",
|
|
26730
|
+
"PATHEXT",
|
|
26731
|
+
"BASH_ENV",
|
|
26732
|
+
"ENV",
|
|
26733
|
+
"COMSPEC",
|
|
26734
|
+
"PSMODULEPATH",
|
|
26735
|
+
"PYTHONPATH",
|
|
26736
|
+
"PYTHONSTARTUP",
|
|
26737
|
+
"PERL5OPT",
|
|
26738
|
+
"RUBYOPT",
|
|
26739
|
+
"JAVA_TOOL_OPTIONS",
|
|
26740
|
+
"LD_PRELOAD",
|
|
26741
|
+
"SYSTEMROOT",
|
|
26742
|
+
"WINDIR",
|
|
26743
|
+
"HOME",
|
|
26744
|
+
"USERPROFILE",
|
|
26745
|
+
"APPDATA",
|
|
26746
|
+
"LOCALAPPDATA",
|
|
26747
|
+
"PROGRAMDATA",
|
|
26748
|
+
"TEMP",
|
|
26749
|
+
"TMP"
|
|
26750
|
+
].map((n) => n.toUpperCase())
|
|
26751
|
+
);
|
|
26752
|
+
function reservedEnvName(name) {
|
|
26753
|
+
return RESERVED_ENV_PREFIX.test(name) || RESERVED_ENV_SUFFIX.test(name) || RESERVED_ENV_NAMES.has(name.toUpperCase());
|
|
26754
|
+
}
|
|
26603
26755
|
var ConfigSchema = external_exports.strictObject({
|
|
26604
26756
|
$schema: SchemaRefSchema.optional(),
|
|
26605
26757
|
defaultHarness: NameSchema.describe("Agent started by `sandbox launch` (sandbox claude always runs claude)."),
|
|
@@ -26666,10 +26818,14 @@ var LocalOverridesSchema = external_exports.strictObject({
|
|
|
26666
26818
|
scripts: StringsSchema.describe(
|
|
26667
26819
|
"Scripts (.ps1 / .mjs / .cmd, relative to this file) run inside the sandbox before the agent."
|
|
26668
26820
|
),
|
|
26669
|
-
// This PC's resources are yours to share: CPU
|
|
26821
|
+
// This PC's resources are yours to share: CPU, paging file (this PC's disk) and the RAM kept for this PC are not a
|
|
26822
|
+
// project's to set.
|
|
26670
26823
|
sandbox: SandboxSchema.omit({
|
|
26671
26824
|
cpuLimit: true,
|
|
26672
26825
|
pageFileMb: true,
|
|
26826
|
+
reserveHostMb: true,
|
|
26827
|
+
maxMemoryPercent: true,
|
|
26828
|
+
maxMemoryMb: true,
|
|
26673
26829
|
engine: true,
|
|
26674
26830
|
agentMemoryHeadroomMb: true,
|
|
26675
26831
|
pressureResponse: true
|
|
@@ -26683,14 +26839,17 @@ var LocalOverridesSchema = external_exports.strictObject({
|
|
|
26683
26839
|
// Every toolchain setting, each one optional (a project usually only switches languages on or pins a version).
|
|
26684
26840
|
toolchains: external_exports.strictObject({
|
|
26685
26841
|
...import_lodash.default.mapValues(import_lodash.default.omit(ToolchainsSchema.shape, "environment"), (shape) => shape.partial()),
|
|
26686
|
-
environment: ToolchainsSchema.shape.environment
|
|
26842
|
+
environment: ToolchainsSchema.shape.environment.refine(
|
|
26843
|
+
(env) => !Object.keys(env).some(reservedEnvName),
|
|
26844
|
+
"names the sandbox sets or that carry logins (AGENT_*, GIT_*, PATH, BASH_ENV, NODE_*, proxies, ANTHROPIC_*, CLAUDE_* ...) cannot be set by a project"
|
|
26845
|
+
)
|
|
26687
26846
|
}).partial(),
|
|
26688
26847
|
databases: external_exports.strictObject(import_lodash.default.mapValues(DatabasesSchema.shape, (shape) => shape.partial())).partial(),
|
|
26689
26848
|
attach: AttachSchema.partial(),
|
|
26690
26849
|
personalization: toggle("Copy your desktop look into the sandbox.").partial(),
|
|
26691
26850
|
// Catalogue apps only (a vetted list): your own programs (apps.custom) download anything, so a repo cannot add
|
|
26692
|
-
// them.
|
|
26693
|
-
apps:
|
|
26851
|
+
// them, nor agent add-ons that are yours only (rtk hooks every agent command, Headroom sits in its API path).
|
|
26852
|
+
apps: ProjectAppsSchema.partial(),
|
|
26694
26853
|
claudeProfile: ClaudeProfileSchema.pick({
|
|
26695
26854
|
enabled: true,
|
|
26696
26855
|
overwrite: true,
|
|
@@ -26753,6 +26912,7 @@ var ProjectSpecSchema = external_exports.strictObject({
|
|
|
26753
26912
|
/** Its hooks were staged in C:\AgentLaunch\projects\<name>\hooks. */
|
|
26754
26913
|
hooks: external_exports.boolean()
|
|
26755
26914
|
});
|
|
26915
|
+
var ShellChoiceSchema = external_exports.enum(["auto", "pwsh", "powershell", "cmd"]);
|
|
26756
26916
|
var GuestRequestSchema = external_exports.discriminatedUnion("kind", [
|
|
26757
26917
|
external_exports.strictObject({
|
|
26758
26918
|
kind: external_exports.literal("session"),
|
|
@@ -26762,8 +26922,12 @@ var GuestRequestSchema = external_exports.discriminatedUnion("kind", [
|
|
|
26762
26922
|
cwd: Text(),
|
|
26763
26923
|
project: ProjectSpecSchema.optional(),
|
|
26764
26924
|
harnessSpec: HarnessSchema.optional(),
|
|
26925
|
+
/** A plain shell instead of an agent (harness is then "shell" and args are ignored). */
|
|
26926
|
+
shell: ShellChoiceSchema.optional(),
|
|
26765
26927
|
createdAt: TimeSchema
|
|
26766
26928
|
}),
|
|
26929
|
+
/** End a running session (an agent or a shell) and everything it started. */
|
|
26930
|
+
external_exports.strictObject({ kind: external_exports.literal("close"), id: IdSchema, session: IdSchema, createdAt: TimeSchema }),
|
|
26767
26931
|
/** Provision a registered project without starting an agent (sandbox start / exec / db from its folder). */
|
|
26768
26932
|
external_exports.strictObject({ kind: external_exports.literal("project"), id: IdSchema, project: ProjectSpecSchema, createdAt: TimeSchema }),
|
|
26769
26933
|
external_exports.strictObject({
|
|
@@ -26829,6 +26993,8 @@ var SessionStatusSchema = external_exports.object({
|
|
|
26829
26993
|
id: IdSchema,
|
|
26830
26994
|
launchId: Text(64),
|
|
26831
26995
|
harness: Text(64),
|
|
26996
|
+
/** A plain shell (harness is then the shell: pwsh, powershell or cmd); absent: an agent. */
|
|
26997
|
+
kind: external_exports.enum(["agent", "shell"]).optional(),
|
|
26832
26998
|
cwd: Text(),
|
|
26833
26999
|
/** The project it runs in: its hub name, or the launch folder's for the first project. */
|
|
26834
27000
|
project: Text(64).optional(),
|