@ash-cloud/ash-ai 0.1.13 → 0.1.16
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/index.cjs +430 -557
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +35 -145
- package/dist/index.d.ts +35 -145
- package/dist/index.js +429 -555
- package/dist/index.js.map +1 -1
- package/dist/playground/components/ChatInput.d.ts.map +1 -1
- package/dist/playground/components/NormalizedMessageList.d.ts +4 -11
- package/dist/playground/components/NormalizedMessageList.d.ts.map +1 -1
- package/dist/playground/components/ToolCallCard.d.ts +20 -5
- package/dist/playground/components/ToolCallCard.d.ts.map +1 -1
- package/dist/playground/index.d.ts +19 -4
- package/dist/playground/index.d.ts.map +1 -1
- package/dist/playground/pages/ChatPage.d.ts.map +1 -1
- package/dist/playground.css +1 -1
- package/dist/playground.js +3090 -2296
- package/package.json +4 -2
package/dist/index.js
CHANGED
|
@@ -4205,6 +4205,50 @@ VERCEL_EOF`);
|
|
|
4205
4205
|
}
|
|
4206
4206
|
});
|
|
4207
4207
|
|
|
4208
|
+
// src/runtime/providers/firecracker/types.ts
|
|
4209
|
+
var init_types3 = __esm({
|
|
4210
|
+
"src/runtime/providers/firecracker/types.ts"() {
|
|
4211
|
+
}
|
|
4212
|
+
});
|
|
4213
|
+
|
|
4214
|
+
// src/runtime/providers/firecracker/image-manager.ts
|
|
4215
|
+
var init_image_manager = __esm({
|
|
4216
|
+
"src/runtime/providers/firecracker/image-manager.ts"() {
|
|
4217
|
+
}
|
|
4218
|
+
});
|
|
4219
|
+
|
|
4220
|
+
// src/runtime/providers/firecracker/network-manager.ts
|
|
4221
|
+
var init_network_manager = __esm({
|
|
4222
|
+
"src/runtime/providers/firecracker/network-manager.ts"() {
|
|
4223
|
+
}
|
|
4224
|
+
});
|
|
4225
|
+
|
|
4226
|
+
// src/runtime/providers/firecracker/ssh-executor.ts
|
|
4227
|
+
var init_ssh_executor = __esm({
|
|
4228
|
+
"src/runtime/providers/firecracker/ssh-executor.ts"() {
|
|
4229
|
+
}
|
|
4230
|
+
});
|
|
4231
|
+
|
|
4232
|
+
// src/runtime/providers/firecracker/vm-manager.ts
|
|
4233
|
+
var init_vm_manager = __esm({
|
|
4234
|
+
"src/runtime/providers/firecracker/vm-manager.ts"() {
|
|
4235
|
+
init_types3();
|
|
4236
|
+
}
|
|
4237
|
+
});
|
|
4238
|
+
|
|
4239
|
+
// src/runtime/providers/firecracker.ts
|
|
4240
|
+
var init_firecracker = __esm({
|
|
4241
|
+
"src/runtime/providers/firecracker.ts"() {
|
|
4242
|
+
init_types2();
|
|
4243
|
+
init_types3();
|
|
4244
|
+
init_image_manager();
|
|
4245
|
+
init_network_manager();
|
|
4246
|
+
init_ssh_executor();
|
|
4247
|
+
init_vm_manager();
|
|
4248
|
+
init_types3();
|
|
4249
|
+
}
|
|
4250
|
+
});
|
|
4251
|
+
|
|
4208
4252
|
// src/runtime/providers/index.ts
|
|
4209
4253
|
var init_providers = __esm({
|
|
4210
4254
|
"src/runtime/providers/index.ts"() {
|
|
@@ -4216,6 +4260,7 @@ var init_providers = __esm({
|
|
|
4216
4260
|
init_fly();
|
|
4217
4261
|
init_daytona();
|
|
4218
4262
|
init_vercel();
|
|
4263
|
+
init_firecracker();
|
|
4219
4264
|
init_local();
|
|
4220
4265
|
init_modal();
|
|
4221
4266
|
init_e2b();
|
|
@@ -4223,6 +4268,7 @@ var init_providers = __esm({
|
|
|
4223
4268
|
init_fly();
|
|
4224
4269
|
init_daytona();
|
|
4225
4270
|
init_vercel();
|
|
4271
|
+
init_firecracker();
|
|
4226
4272
|
}
|
|
4227
4273
|
});
|
|
4228
4274
|
|
|
@@ -5261,6 +5307,23 @@ function isSandboxRunning(sessionId) {
|
|
|
5261
5307
|
const cached = sandboxCache.get(sessionId);
|
|
5262
5308
|
return cached !== void 0 && !cached.isExpired;
|
|
5263
5309
|
}
|
|
5310
|
+
function getCachedSandbox(sessionId) {
|
|
5311
|
+
const cached = sandboxCache.get(sessionId);
|
|
5312
|
+
if (!cached || cached.isExpired) {
|
|
5313
|
+
return null;
|
|
5314
|
+
}
|
|
5315
|
+
cached.lastUsedAt = Date.now();
|
|
5316
|
+
return {
|
|
5317
|
+
sandbox: cached.sandbox,
|
|
5318
|
+
sandboxId: cached.sandbox.sandboxId,
|
|
5319
|
+
sdkInstalled: cached.sdkInstalled,
|
|
5320
|
+
startupScriptRan: cached.startupScriptRan,
|
|
5321
|
+
startupScriptHash: cached.startupScriptHash,
|
|
5322
|
+
isNew: false,
|
|
5323
|
+
configFileUrl: cached.configFileUrl,
|
|
5324
|
+
configInstalledAt: cached.configInstalledAt
|
|
5325
|
+
};
|
|
5326
|
+
}
|
|
5264
5327
|
async function writeFileToSandbox(sessionId, path15, content) {
|
|
5265
5328
|
const cached = sandboxCache.get(sessionId);
|
|
5266
5329
|
if (!cached) {
|
|
@@ -5329,6 +5392,54 @@ async function readFileFromSandbox(sessionId, path15) {
|
|
|
5329
5392
|
};
|
|
5330
5393
|
}
|
|
5331
5394
|
}
|
|
5395
|
+
async function executeCommandInSandbox(sessionId, command, options) {
|
|
5396
|
+
const cached = sandboxCache.get(sessionId);
|
|
5397
|
+
if (!cached) {
|
|
5398
|
+
return { success: false, error: "No active sandbox for session" };
|
|
5399
|
+
}
|
|
5400
|
+
if (cached.isExpired) {
|
|
5401
|
+
return { success: false, error: "Sandbox has expired" };
|
|
5402
|
+
}
|
|
5403
|
+
const startTime = Date.now();
|
|
5404
|
+
try {
|
|
5405
|
+
const sandbox = cached.sandbox;
|
|
5406
|
+
let fullCommand = command;
|
|
5407
|
+
if (options?.cwd) {
|
|
5408
|
+
fullCommand = `cd ${JSON.stringify(options.cwd)} && ${command}`;
|
|
5409
|
+
}
|
|
5410
|
+
const result = await sandbox.runCommand({
|
|
5411
|
+
cmd: "bash",
|
|
5412
|
+
args: ["-c", fullCommand],
|
|
5413
|
+
env: options?.env
|
|
5414
|
+
});
|
|
5415
|
+
const stdout = await result.stdout();
|
|
5416
|
+
const stderr = await result.stderr();
|
|
5417
|
+
const durationMs = Date.now() - startTime;
|
|
5418
|
+
cached.lastUsedAt = Date.now();
|
|
5419
|
+
return {
|
|
5420
|
+
success: result.exitCode === 0,
|
|
5421
|
+
exitCode: result.exitCode,
|
|
5422
|
+
stdout,
|
|
5423
|
+
stderr,
|
|
5424
|
+
durationMs
|
|
5425
|
+
};
|
|
5426
|
+
} catch (error) {
|
|
5427
|
+
const durationMs = Date.now() - startTime;
|
|
5428
|
+
if (isSandboxExpiredError(error)) {
|
|
5429
|
+
cached.isExpired = true;
|
|
5430
|
+
return {
|
|
5431
|
+
success: false,
|
|
5432
|
+
error: "Sandbox has expired",
|
|
5433
|
+
durationMs
|
|
5434
|
+
};
|
|
5435
|
+
}
|
|
5436
|
+
return {
|
|
5437
|
+
success: false,
|
|
5438
|
+
error: error instanceof Error ? error.message : "Unknown error",
|
|
5439
|
+
durationMs
|
|
5440
|
+
};
|
|
5441
|
+
}
|
|
5442
|
+
}
|
|
5332
5443
|
async function listFilesInSandbox(sessionId, path15) {
|
|
5333
5444
|
const cached = sandboxCache.get(sessionId);
|
|
5334
5445
|
if (!cached) {
|
|
@@ -5808,19 +5919,7 @@ function getFileWatcherManager() {
|
|
|
5808
5919
|
function createFileWatcherManager() {
|
|
5809
5920
|
return new FileWatcherManager();
|
|
5810
5921
|
}
|
|
5811
|
-
|
|
5812
|
-
return new RemoteSandboxFileWatcher(options);
|
|
5813
|
-
}
|
|
5814
|
-
function getRemoteFileWatcherManager() {
|
|
5815
|
-
if (!globalRemoteWatcherManager) {
|
|
5816
|
-
globalRemoteWatcherManager = new RemoteFileWatcherManager();
|
|
5817
|
-
}
|
|
5818
|
-
return globalRemoteWatcherManager;
|
|
5819
|
-
}
|
|
5820
|
-
function createRemoteFileWatcherManager() {
|
|
5821
|
-
return new RemoteFileWatcherManager();
|
|
5822
|
-
}
|
|
5823
|
-
var SandboxFileWatcher, FileWatcherManager, globalWatcherManager, RemoteSandboxFileWatcher, RemoteFileWatcherManager, globalRemoteWatcherManager;
|
|
5922
|
+
var SandboxFileWatcher, FileWatcherManager, globalWatcherManager;
|
|
5824
5923
|
var init_sandbox_file_watcher = __esm({
|
|
5825
5924
|
"src/runtime/sandbox-file-watcher.ts"() {
|
|
5826
5925
|
SandboxFileWatcher = class {
|
|
@@ -5846,7 +5945,18 @@ var init_sandbox_file_watcher = __esm({
|
|
|
5846
5945
|
this.watchPath = options.watchPath;
|
|
5847
5946
|
this.debounceMs = options.debounceMs ?? 300;
|
|
5848
5947
|
this.patterns = options.patterns ?? ["**/*"];
|
|
5849
|
-
this.ignored = options.ignored ?? [
|
|
5948
|
+
this.ignored = options.ignored ?? [
|
|
5949
|
+
"**/node_modules/**",
|
|
5950
|
+
"**/.git/**",
|
|
5951
|
+
"**/*.log",
|
|
5952
|
+
// Temporary files from atomic saves and editors
|
|
5953
|
+
"**/*.tmp",
|
|
5954
|
+
"**/*.tmp.*",
|
|
5955
|
+
"**/*~",
|
|
5956
|
+
"**/*.swp",
|
|
5957
|
+
"**/*.swo",
|
|
5958
|
+
"**/.DS_Store"
|
|
5959
|
+
];
|
|
5850
5960
|
this.emitInitialEvents = options.emitInitialEvents ?? false;
|
|
5851
5961
|
this.followSymlinks = options.followSymlinks ?? false;
|
|
5852
5962
|
this.usePolling = options.usePolling ?? false;
|
|
@@ -6062,214 +6172,343 @@ var init_sandbox_file_watcher = __esm({
|
|
|
6062
6172
|
}
|
|
6063
6173
|
};
|
|
6064
6174
|
globalWatcherManager = null;
|
|
6065
|
-
|
|
6175
|
+
}
|
|
6176
|
+
});
|
|
6177
|
+
|
|
6178
|
+
// src/runtime/in-sandbox-watcher.ts
|
|
6179
|
+
function createInSandboxWatcher(options) {
|
|
6180
|
+
return new InSandboxWatcher(options);
|
|
6181
|
+
}
|
|
6182
|
+
function getInSandboxWatcherManager() {
|
|
6183
|
+
if (!globalInSandboxManager) {
|
|
6184
|
+
globalInSandboxManager = new InSandboxWatcherManager();
|
|
6185
|
+
}
|
|
6186
|
+
return globalInSandboxManager;
|
|
6187
|
+
}
|
|
6188
|
+
function createInSandboxWatcherManager() {
|
|
6189
|
+
return new InSandboxWatcherManager();
|
|
6190
|
+
}
|
|
6191
|
+
var WATCHER_SCRIPT, InSandboxWatcher, InSandboxWatcherManager, globalInSandboxManager;
|
|
6192
|
+
var init_in_sandbox_watcher = __esm({
|
|
6193
|
+
"src/runtime/in-sandbox-watcher.ts"() {
|
|
6194
|
+
init_vercel_sandbox_executor();
|
|
6195
|
+
WATCHER_SCRIPT = `
|
|
6196
|
+
const fs = require('fs');
|
|
6197
|
+
const path = require('path');
|
|
6198
|
+
|
|
6199
|
+
const watchPath = process.argv[2] || '.';
|
|
6200
|
+
const ignoredDirs = new Set(['node_modules', '.git', '.cache', '__pycache__']);
|
|
6201
|
+
|
|
6202
|
+
// Track all watchers for cleanup
|
|
6203
|
+
const watchers = new Map();
|
|
6204
|
+
|
|
6205
|
+
// Debounce map to coalesce rapid changes
|
|
6206
|
+
const pending = new Map();
|
|
6207
|
+
const DEBOUNCE_MS = 100;
|
|
6208
|
+
|
|
6209
|
+
function emit(type, filePath) {
|
|
6210
|
+
const event = {
|
|
6211
|
+
type,
|
|
6212
|
+
path: filePath,
|
|
6213
|
+
timestamp: Date.now()
|
|
6214
|
+
};
|
|
6215
|
+
console.log(JSON.stringify(event));
|
|
6216
|
+
}
|
|
6217
|
+
|
|
6218
|
+
function shouldIgnore(name) {
|
|
6219
|
+
// Ignore hidden files/dirs (starting with .)
|
|
6220
|
+
if (name.startsWith('.')) return true;
|
|
6221
|
+
|
|
6222
|
+
// Ignore known directories
|
|
6223
|
+
if (ignoredDirs.has(name)) return true;
|
|
6224
|
+
|
|
6225
|
+
// Ignore temporary files from atomic saves and editors:
|
|
6226
|
+
// - filename.tmp (ends with .tmp)
|
|
6227
|
+
// - filename.tmp.123456789 (has .tmp. in middle - atomic write pattern)
|
|
6228
|
+
// - filename~ (editor backup files)
|
|
6229
|
+
// - filename.swp / filename.swo (Vim swap files)
|
|
6230
|
+
if (name.endsWith('.tmp')) return true;
|
|
6231
|
+
if (name.includes('.tmp.')) return true;
|
|
6232
|
+
if (name.endsWith('~')) return true;
|
|
6233
|
+
if (name.endsWith('.swp') || name.endsWith('.swo')) return true;
|
|
6234
|
+
|
|
6235
|
+
return false;
|
|
6236
|
+
}
|
|
6237
|
+
|
|
6238
|
+
function watchDir(dir) {
|
|
6239
|
+
try {
|
|
6240
|
+
const watcher = fs.watch(dir, { persistent: true }, (eventType, filename) => {
|
|
6241
|
+
if (!filename || shouldIgnore(filename)) return;
|
|
6242
|
+
|
|
6243
|
+
const fullPath = path.join(dir, filename);
|
|
6244
|
+
const key = fullPath;
|
|
6245
|
+
|
|
6246
|
+
// Debounce
|
|
6247
|
+
if (pending.has(key)) {
|
|
6248
|
+
clearTimeout(pending.get(key));
|
|
6249
|
+
}
|
|
6250
|
+
|
|
6251
|
+
pending.set(key, setTimeout(() => {
|
|
6252
|
+
pending.delete(key);
|
|
6253
|
+
|
|
6254
|
+
fs.stat(fullPath, (err, stats) => {
|
|
6255
|
+
if (err) {
|
|
6256
|
+
if (err.code === 'ENOENT') {
|
|
6257
|
+
emit('unlink', fullPath);
|
|
6258
|
+
// Stop watching if it was a directory
|
|
6259
|
+
if (watchers.has(fullPath)) {
|
|
6260
|
+
watchers.get(fullPath).close();
|
|
6261
|
+
watchers.delete(fullPath);
|
|
6262
|
+
}
|
|
6263
|
+
}
|
|
6264
|
+
} else {
|
|
6265
|
+
const type = eventType === 'rename' ? 'add' : 'change';
|
|
6266
|
+
emit(type, fullPath);
|
|
6267
|
+
|
|
6268
|
+
// If it's a new directory, start watching it
|
|
6269
|
+
if (stats.isDirectory() && !watchers.has(fullPath)) {
|
|
6270
|
+
watchDir(fullPath);
|
|
6271
|
+
}
|
|
6272
|
+
}
|
|
6273
|
+
});
|
|
6274
|
+
}, DEBOUNCE_MS));
|
|
6275
|
+
});
|
|
6276
|
+
|
|
6277
|
+
watchers.set(dir, watcher);
|
|
6278
|
+
|
|
6279
|
+
// Watch subdirectories
|
|
6280
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
6281
|
+
for (const entry of entries) {
|
|
6282
|
+
if (entry.isDirectory() && !shouldIgnore(entry.name)) {
|
|
6283
|
+
watchDir(path.join(dir, entry.name));
|
|
6284
|
+
}
|
|
6285
|
+
}
|
|
6286
|
+
} catch (err) {
|
|
6287
|
+
// Directory may not exist or be inaccessible
|
|
6288
|
+
console.error(JSON.stringify({ error: err.message, dir }));
|
|
6289
|
+
}
|
|
6290
|
+
}
|
|
6291
|
+
|
|
6292
|
+
// Start watching
|
|
6293
|
+
watchDir(watchPath);
|
|
6294
|
+
|
|
6295
|
+
// Keep alive
|
|
6296
|
+
process.on('SIGTERM', () => {
|
|
6297
|
+
for (const watcher of watchers.values()) {
|
|
6298
|
+
watcher.close();
|
|
6299
|
+
}
|
|
6300
|
+
process.exit(0);
|
|
6301
|
+
});
|
|
6302
|
+
|
|
6303
|
+
// Heartbeat to indicate we're running
|
|
6304
|
+
setInterval(() => {
|
|
6305
|
+
console.log(JSON.stringify({ heartbeat: true, timestamp: Date.now() }));
|
|
6306
|
+
}, 5000);
|
|
6307
|
+
|
|
6308
|
+
console.log(JSON.stringify({ started: true, path: watchPath }));
|
|
6309
|
+
`;
|
|
6310
|
+
InSandboxWatcher = class {
|
|
6066
6311
|
sessionId;
|
|
6067
|
-
|
|
6068
|
-
|
|
6069
|
-
|
|
6070
|
-
|
|
6071
|
-
pollTimer = null;
|
|
6072
|
-
previousFiles = /* @__PURE__ */ new Map();
|
|
6312
|
+
watchPath;
|
|
6313
|
+
outputPollIntervalMs;
|
|
6314
|
+
sandboxState = null;
|
|
6315
|
+
outputPollTimer = null;
|
|
6073
6316
|
subscribers = /* @__PURE__ */ new Set();
|
|
6074
|
-
|
|
6317
|
+
isRunning = false;
|
|
6075
6318
|
startedAt;
|
|
6076
|
-
|
|
6077
|
-
|
|
6319
|
+
lastHeartbeat;
|
|
6320
|
+
lastOutputPosition = 0;
|
|
6078
6321
|
onError;
|
|
6322
|
+
onReady;
|
|
6079
6323
|
constructor(options) {
|
|
6080
6324
|
this.sessionId = options.sessionId;
|
|
6081
|
-
this.
|
|
6082
|
-
this.
|
|
6083
|
-
this.pollIntervalMs = options.pollIntervalMs ?? 2e3;
|
|
6084
|
-
this.ignored = options.ignored ?? ["**/node_modules/**", "**/.git/**"];
|
|
6325
|
+
this.watchPath = options.watchPath;
|
|
6326
|
+
this.outputPollIntervalMs = options.outputPollIntervalMs ?? 1e3;
|
|
6085
6327
|
this.onError = options.onError;
|
|
6328
|
+
this.onReady = options.onReady;
|
|
6086
6329
|
if (options.onFileChange) {
|
|
6087
6330
|
this.subscribers.add(options.onFileChange);
|
|
6088
6331
|
}
|
|
6089
6332
|
}
|
|
6090
6333
|
/**
|
|
6091
|
-
* Start
|
|
6334
|
+
* Start the watcher process inside the sandbox
|
|
6092
6335
|
*/
|
|
6093
6336
|
async start() {
|
|
6094
|
-
if (this.
|
|
6095
|
-
console.warn(`[
|
|
6337
|
+
if (this.isRunning) {
|
|
6338
|
+
console.warn(`[IN_SANDBOX_WATCHER] Already running for session ${this.sessionId}`);
|
|
6096
6339
|
return;
|
|
6097
6340
|
}
|
|
6098
|
-
|
|
6099
|
-
|
|
6100
|
-
|
|
6101
|
-
|
|
6102
|
-
this.pollTimer = setInterval(async () => {
|
|
6103
|
-
try {
|
|
6104
|
-
await this.scan(false);
|
|
6105
|
-
} catch (error) {
|
|
6106
|
-
console.error(`[REMOTE_WATCHER] Poll error for session ${this.sessionId}:`, error);
|
|
6107
|
-
if (this.onError && error instanceof Error) {
|
|
6108
|
-
this.onError(error);
|
|
6109
|
-
}
|
|
6341
|
+
try {
|
|
6342
|
+
this.sandboxState = getCachedSandbox(this.sessionId);
|
|
6343
|
+
if (!this.sandboxState) {
|
|
6344
|
+
throw new Error(`No active sandbox found for session ${this.sessionId}. Sandbox must be created before starting file watcher.`);
|
|
6110
6345
|
}
|
|
6111
|
-
|
|
6112
|
-
|
|
6113
|
-
|
|
6114
|
-
|
|
6115
|
-
|
|
6116
|
-
|
|
6117
|
-
|
|
6118
|
-
|
|
6119
|
-
|
|
6120
|
-
|
|
6121
|
-
|
|
6122
|
-
|
|
6123
|
-
|
|
6124
|
-
|
|
6125
|
-
|
|
6346
|
+
const { sandbox } = this.sandboxState;
|
|
6347
|
+
const scriptPath = "/tmp/.file-watcher.js";
|
|
6348
|
+
const outputPath = "/tmp/.file-watcher-output.log";
|
|
6349
|
+
const writeScriptCmd = `cat > ${scriptPath} << 'WATCHER_EOF'
|
|
6350
|
+
${WATCHER_SCRIPT}
|
|
6351
|
+
WATCHER_EOF`;
|
|
6352
|
+
await sandbox.runCommand({
|
|
6353
|
+
cmd: "sh",
|
|
6354
|
+
args: ["-c", writeScriptCmd]
|
|
6355
|
+
});
|
|
6356
|
+
const startCmd = `nohup node ${scriptPath} "${this.watchPath}" > ${outputPath} 2>&1 &`;
|
|
6357
|
+
await sandbox.runCommand({
|
|
6358
|
+
cmd: "sh",
|
|
6359
|
+
args: ["-c", startCmd]
|
|
6360
|
+
});
|
|
6361
|
+
console.log(`[IN_SANDBOX_WATCHER] Started watcher in sandbox for ${this.watchPath}`);
|
|
6362
|
+
this.isRunning = true;
|
|
6363
|
+
this.startedAt = /* @__PURE__ */ new Date();
|
|
6364
|
+
this.outputPollTimer = setInterval(async () => {
|
|
6365
|
+
try {
|
|
6366
|
+
await this.pollOutput(outputPath);
|
|
6367
|
+
} catch (error) {
|
|
6368
|
+
console.error("[IN_SANDBOX_WATCHER] Error polling output:", error);
|
|
6369
|
+
if (this.onError && error instanceof Error) {
|
|
6370
|
+
this.onError(error);
|
|
6371
|
+
}
|
|
6372
|
+
}
|
|
6373
|
+
}, this.outputPollIntervalMs);
|
|
6374
|
+
setTimeout(() => {
|
|
6375
|
+
this.pollOutput(outputPath).catch(console.error);
|
|
6376
|
+
}, 500);
|
|
6377
|
+
} catch (error) {
|
|
6378
|
+
console.error(`[IN_SANDBOX_WATCHER] Failed to start watcher:`, error);
|
|
6379
|
+
throw error;
|
|
6126
6380
|
}
|
|
6127
|
-
this.isWatching = false;
|
|
6128
|
-
this.previousFiles.clear();
|
|
6129
|
-
console.log(`[REMOTE_WATCHER] Stopped watching session ${this.sessionId}`);
|
|
6130
6381
|
}
|
|
6131
6382
|
/**
|
|
6132
|
-
*
|
|
6383
|
+
* Poll the output file for new events
|
|
6133
6384
|
*/
|
|
6134
|
-
|
|
6135
|
-
this.
|
|
6136
|
-
|
|
6137
|
-
|
|
6138
|
-
|
|
6139
|
-
|
|
6140
|
-
|
|
6141
|
-
|
|
6142
|
-
|
|
6143
|
-
|
|
6144
|
-
|
|
6145
|
-
|
|
6146
|
-
|
|
6147
|
-
|
|
6148
|
-
|
|
6149
|
-
|
|
6150
|
-
|
|
6151
|
-
|
|
6152
|
-
|
|
6153
|
-
getStatus() {
|
|
6154
|
-
return {
|
|
6155
|
-
sessionId: this.sessionId,
|
|
6156
|
-
watchPath: this.basePath,
|
|
6157
|
-
isWatching: this.isWatching,
|
|
6158
|
-
watchedFileCount: this.previousFiles.size,
|
|
6159
|
-
pendingEventCount: 0,
|
|
6160
|
-
startedAt: this.startedAt,
|
|
6161
|
-
lastPollAt: this.lastPollAt,
|
|
6162
|
-
pollCount: this.pollCount
|
|
6163
|
-
};
|
|
6385
|
+
async pollOutput(outputPath) {
|
|
6386
|
+
if (!this.sandboxState?.sandbox) return;
|
|
6387
|
+
try {
|
|
6388
|
+
const result = await this.sandboxState.sandbox.runCommand({
|
|
6389
|
+
cmd: "sh",
|
|
6390
|
+
args: ["-c", `tail -c +${this.lastOutputPosition + 1} ${outputPath} 2>/dev/null || true`]
|
|
6391
|
+
});
|
|
6392
|
+
const output = await result.stdout();
|
|
6393
|
+
if (output && output.trim()) {
|
|
6394
|
+
const sizeResult = await this.sandboxState.sandbox.runCommand({
|
|
6395
|
+
cmd: "sh",
|
|
6396
|
+
args: ["-c", `stat -c%s ${outputPath} 2>/dev/null || echo 0`]
|
|
6397
|
+
});
|
|
6398
|
+
const sizeStr = await sizeResult.stdout();
|
|
6399
|
+
this.lastOutputPosition = parseInt(sizeStr.trim(), 10) || 0;
|
|
6400
|
+
this.processOutput(output);
|
|
6401
|
+
}
|
|
6402
|
+
} catch {
|
|
6403
|
+
}
|
|
6164
6404
|
}
|
|
6165
6405
|
/**
|
|
6166
|
-
*
|
|
6406
|
+
* Process output from the watcher script
|
|
6167
6407
|
*/
|
|
6168
|
-
|
|
6169
|
-
|
|
6408
|
+
processOutput(stdout) {
|
|
6409
|
+
const lines = stdout.split("\n").filter(Boolean);
|
|
6410
|
+
for (const line of lines) {
|
|
6411
|
+
try {
|
|
6412
|
+
const data = JSON.parse(line);
|
|
6413
|
+
if (data.started) {
|
|
6414
|
+
console.log(`[IN_SANDBOX_WATCHER] Watcher started for ${data.path}`);
|
|
6415
|
+
if (this.onReady) {
|
|
6416
|
+
this.onReady();
|
|
6417
|
+
}
|
|
6418
|
+
} else if (data.heartbeat) {
|
|
6419
|
+
this.lastHeartbeat = new Date(data.timestamp);
|
|
6420
|
+
} else if (data.error) {
|
|
6421
|
+
console.warn(`[IN_SANDBOX_WATCHER] Error in sandbox:`, data.error);
|
|
6422
|
+
} else if (data.type && data.path) {
|
|
6423
|
+
this.emitEvent({
|
|
6424
|
+
type: data.type,
|
|
6425
|
+
relativePath: data.path.replace(/^\.\//, ""),
|
|
6426
|
+
absolutePath: data.path,
|
|
6427
|
+
basePath: this.watchPath,
|
|
6428
|
+
sessionId: this.sessionId,
|
|
6429
|
+
timestamp: new Date(data.timestamp)
|
|
6430
|
+
});
|
|
6431
|
+
}
|
|
6432
|
+
} catch {
|
|
6433
|
+
}
|
|
6434
|
+
}
|
|
6170
6435
|
}
|
|
6171
6436
|
/**
|
|
6172
|
-
*
|
|
6437
|
+
* Stop the watcher process
|
|
6173
6438
|
*/
|
|
6174
|
-
async
|
|
6175
|
-
if (!this.
|
|
6176
|
-
console.warn(`[REMOTE_WATCHER] Sandbox stopped for session ${this.sessionId}`);
|
|
6177
|
-
await this.stop();
|
|
6439
|
+
async stop() {
|
|
6440
|
+
if (!this.isRunning) {
|
|
6178
6441
|
return;
|
|
6179
6442
|
}
|
|
6180
|
-
|
|
6181
|
-
|
|
6182
|
-
|
|
6183
|
-
}
|
|
6184
|
-
const currentFiles = /* @__PURE__ */ new Map();
|
|
6185
|
-
for (const filePath of listResult.files) {
|
|
6186
|
-
if (this.shouldIgnore(filePath)) {
|
|
6187
|
-
continue;
|
|
6188
|
-
}
|
|
6189
|
-
currentFiles.set(filePath, { path: filePath });
|
|
6190
|
-
}
|
|
6191
|
-
this.lastPollAt = /* @__PURE__ */ new Date();
|
|
6192
|
-
this.pollCount++;
|
|
6193
|
-
if (isInitial) {
|
|
6194
|
-
this.previousFiles = currentFiles;
|
|
6195
|
-
return;
|
|
6443
|
+
if (this.outputPollTimer) {
|
|
6444
|
+
clearInterval(this.outputPollTimer);
|
|
6445
|
+
this.outputPollTimer = null;
|
|
6196
6446
|
}
|
|
6197
|
-
|
|
6198
|
-
|
|
6199
|
-
|
|
6200
|
-
|
|
6201
|
-
|
|
6202
|
-
type: "add",
|
|
6203
|
-
relativePath: filePath,
|
|
6204
|
-
absolutePath: `${this.basePath}/${filePath}`,
|
|
6205
|
-
basePath: this.basePath,
|
|
6206
|
-
sessionId: this.sessionId,
|
|
6207
|
-
fileSize: info.size,
|
|
6208
|
-
timestamp: /* @__PURE__ */ new Date()
|
|
6447
|
+
try {
|
|
6448
|
+
if (this.sandboxState?.sandbox) {
|
|
6449
|
+
await this.sandboxState.sandbox.runCommand({
|
|
6450
|
+
cmd: "sh",
|
|
6451
|
+
args: ["-c", "pkill -f file-watcher.js 2>/dev/null || true"]
|
|
6209
6452
|
});
|
|
6210
|
-
|
|
6211
|
-
|
|
6212
|
-
|
|
6213
|
-
if (!currentFiles.has(filePath)) {
|
|
6214
|
-
changes.push({
|
|
6215
|
-
type: "unlink",
|
|
6216
|
-
relativePath: filePath,
|
|
6217
|
-
absolutePath: `${this.basePath}/${filePath}`,
|
|
6218
|
-
basePath: this.basePath,
|
|
6219
|
-
sessionId: this.sessionId,
|
|
6220
|
-
timestamp: /* @__PURE__ */ new Date()
|
|
6453
|
+
await this.sandboxState.sandbox.runCommand({
|
|
6454
|
+
cmd: "sh",
|
|
6455
|
+
args: ["-c", "rm -f /tmp/.file-watcher.js /tmp/.file-watcher-output.log"]
|
|
6221
6456
|
});
|
|
6222
6457
|
}
|
|
6458
|
+
} catch {
|
|
6223
6459
|
}
|
|
6224
|
-
this.
|
|
6225
|
-
|
|
6226
|
-
|
|
6227
|
-
}
|
|
6460
|
+
this.isRunning = false;
|
|
6461
|
+
this.sandboxState = null;
|
|
6462
|
+
this.lastOutputPosition = 0;
|
|
6463
|
+
console.log(`[IN_SANDBOX_WATCHER] Stopped watcher for session ${this.sessionId}`);
|
|
6228
6464
|
}
|
|
6229
6465
|
/**
|
|
6230
|
-
*
|
|
6466
|
+
* Subscribe to file change events
|
|
6231
6467
|
*/
|
|
6232
|
-
|
|
6233
|
-
|
|
6234
|
-
|
|
6235
|
-
return true;
|
|
6236
|
-
}
|
|
6237
|
-
}
|
|
6238
|
-
return false;
|
|
6468
|
+
subscribe(callback) {
|
|
6469
|
+
this.subscribers.add(callback);
|
|
6470
|
+
return () => this.subscribers.delete(callback);
|
|
6239
6471
|
}
|
|
6240
6472
|
/**
|
|
6241
|
-
*
|
|
6473
|
+
* Check if watcher is running
|
|
6242
6474
|
*/
|
|
6243
|
-
|
|
6244
|
-
|
|
6245
|
-
const regex = new RegExp(`^${regexPattern}$`);
|
|
6246
|
-
return regex.test(filePath);
|
|
6475
|
+
isActive() {
|
|
6476
|
+
return this.isRunning;
|
|
6247
6477
|
}
|
|
6248
6478
|
/**
|
|
6249
|
-
*
|
|
6479
|
+
* Get watcher status
|
|
6480
|
+
*/
|
|
6481
|
+
getStatus() {
|
|
6482
|
+
return {
|
|
6483
|
+
sessionId: this.sessionId,
|
|
6484
|
+
watchPath: this.watchPath,
|
|
6485
|
+
isRunning: this.isRunning,
|
|
6486
|
+
startedAt: this.startedAt,
|
|
6487
|
+
lastHeartbeat: this.lastHeartbeat
|
|
6488
|
+
};
|
|
6489
|
+
}
|
|
6490
|
+
/**
|
|
6491
|
+
* Emit event to all subscribers
|
|
6250
6492
|
*/
|
|
6251
6493
|
async emitEvent(event) {
|
|
6252
6494
|
for (const callback of this.subscribers) {
|
|
6253
6495
|
try {
|
|
6254
6496
|
await callback(event);
|
|
6255
6497
|
} catch (error) {
|
|
6256
|
-
console.error("[
|
|
6498
|
+
console.error("[IN_SANDBOX_WATCHER] Error in subscriber callback:", error);
|
|
6257
6499
|
}
|
|
6258
6500
|
}
|
|
6259
6501
|
}
|
|
6260
6502
|
};
|
|
6261
|
-
|
|
6503
|
+
InSandboxWatcherManager = class {
|
|
6262
6504
|
watchers = /* @__PURE__ */ new Map();
|
|
6263
6505
|
/**
|
|
6264
|
-
* Start watching a
|
|
6506
|
+
* Start watching a sandbox
|
|
6265
6507
|
*/
|
|
6266
6508
|
async startWatching(options) {
|
|
6267
6509
|
const { sessionId } = options;
|
|
6268
|
-
|
|
6269
|
-
|
|
6270
|
-
await existing.stop();
|
|
6271
|
-
}
|
|
6272
|
-
const watcher = new RemoteSandboxFileWatcher(options);
|
|
6510
|
+
await this.stopWatching(sessionId);
|
|
6511
|
+
const watcher = new InSandboxWatcher(options);
|
|
6273
6512
|
await watcher.start();
|
|
6274
6513
|
this.watchers.set(sessionId, watcher);
|
|
6275
6514
|
return watcher;
|
|
@@ -6285,17 +6524,16 @@ var init_sandbox_file_watcher = __esm({
|
|
|
6285
6524
|
}
|
|
6286
6525
|
}
|
|
6287
6526
|
/**
|
|
6288
|
-
* Get
|
|
6527
|
+
* Get watcher for a session
|
|
6289
6528
|
*/
|
|
6290
6529
|
getWatcher(sessionId) {
|
|
6291
6530
|
return this.watchers.get(sessionId);
|
|
6292
6531
|
}
|
|
6293
6532
|
/**
|
|
6294
|
-
* Check if
|
|
6533
|
+
* Check if watching
|
|
6295
6534
|
*/
|
|
6296
6535
|
isWatching(sessionId) {
|
|
6297
|
-
|
|
6298
|
-
return watcher?.isActive() ?? false;
|
|
6536
|
+
return this.watchers.get(sessionId)?.isActive() ?? false;
|
|
6299
6537
|
}
|
|
6300
6538
|
/**
|
|
6301
6539
|
* Stop all watchers
|
|
@@ -6306,7 +6544,7 @@ var init_sandbox_file_watcher = __esm({
|
|
|
6306
6544
|
this.watchers.clear();
|
|
6307
6545
|
}
|
|
6308
6546
|
};
|
|
6309
|
-
|
|
6547
|
+
globalInSandboxManager = null;
|
|
6310
6548
|
}
|
|
6311
6549
|
});
|
|
6312
6550
|
function extractErrorMessage(error) {
|
|
@@ -6355,6 +6593,7 @@ var SandboxFileSync;
|
|
|
6355
6593
|
var init_sandbox_file_sync = __esm({
|
|
6356
6594
|
"src/runtime/sandbox-file-sync.ts"() {
|
|
6357
6595
|
init_sandbox_file_watcher();
|
|
6596
|
+
init_in_sandbox_watcher();
|
|
6358
6597
|
init_types();
|
|
6359
6598
|
SandboxFileSync = class {
|
|
6360
6599
|
fileStore;
|
|
@@ -6365,7 +6604,7 @@ var init_sandbox_file_sync = __esm({
|
|
|
6365
6604
|
eventStorage;
|
|
6366
6605
|
webhookConfig;
|
|
6367
6606
|
// Watcher management
|
|
6368
|
-
|
|
6607
|
+
inSandboxWatchers = /* @__PURE__ */ new Map();
|
|
6369
6608
|
localWatchers = /* @__PURE__ */ new Map();
|
|
6370
6609
|
fileChangeSubscribers = /* @__PURE__ */ new Set();
|
|
6371
6610
|
// Sequence number cache per session (for event storage)
|
|
@@ -7156,34 +7395,27 @@ var init_sandbox_file_sync = __esm({
|
|
|
7156
7395
|
this.localWatchers.set(sessionId, watcher);
|
|
7157
7396
|
console.log(`[FILE_SYNC] Started local file watching for session ${sessionId} at ${opts.localPath}`);
|
|
7158
7397
|
} else {
|
|
7159
|
-
|
|
7160
|
-
throw new Error("Sandbox operations not configured. Call setSandboxOperations first.");
|
|
7161
|
-
}
|
|
7162
|
-
const watcher = new RemoteSandboxFileWatcher({
|
|
7398
|
+
const watcher = new InSandboxWatcher({
|
|
7163
7399
|
sessionId,
|
|
7164
|
-
|
|
7165
|
-
basePath: watchPath,
|
|
7166
|
-
// Use watchPath instead of sandboxBasePath
|
|
7167
|
-
pollIntervalMs: opts.pollIntervalMs ?? 2e3,
|
|
7168
|
-
ignored: opts.ignored ?? ["**/node_modules/**", "**/.git/**"],
|
|
7400
|
+
watchPath,
|
|
7169
7401
|
onFileChange: handleFileChange,
|
|
7170
7402
|
onError: (error) => {
|
|
7171
|
-
console.error(`[FILE_SYNC]
|
|
7403
|
+
console.error(`[FILE_SYNC] In-sandbox watcher error for session ${sessionId}:`, error);
|
|
7172
7404
|
}
|
|
7173
7405
|
});
|
|
7174
7406
|
await watcher.start();
|
|
7175
|
-
this.
|
|
7176
|
-
console.log(`[FILE_SYNC] Started
|
|
7407
|
+
this.inSandboxWatchers.set(sessionId, watcher);
|
|
7408
|
+
console.log(`[FILE_SYNC] Started in-sandbox file watching for session ${sessionId} at path: ${watchPath}`);
|
|
7177
7409
|
}
|
|
7178
7410
|
}
|
|
7179
7411
|
/**
|
|
7180
7412
|
* Stop watching a session's sandbox
|
|
7181
7413
|
*/
|
|
7182
7414
|
async stopWatching(sessionId) {
|
|
7183
|
-
const
|
|
7184
|
-
if (
|
|
7185
|
-
await
|
|
7186
|
-
this.
|
|
7415
|
+
const inSandboxWatcher = this.inSandboxWatchers.get(sessionId);
|
|
7416
|
+
if (inSandboxWatcher) {
|
|
7417
|
+
await inSandboxWatcher.stop();
|
|
7418
|
+
this.inSandboxWatchers.delete(sessionId);
|
|
7187
7419
|
}
|
|
7188
7420
|
const localWatcher = this.localWatchers.get(sessionId);
|
|
7189
7421
|
if (localWatcher) {
|
|
@@ -7195,7 +7427,7 @@ var init_sandbox_file_sync = __esm({
|
|
|
7195
7427
|
* Check if a session is being watched
|
|
7196
7428
|
*/
|
|
7197
7429
|
isWatching(sessionId) {
|
|
7198
|
-
return this.
|
|
7430
|
+
return this.inSandboxWatchers.has(sessionId) || this.localWatchers.has(sessionId);
|
|
7199
7431
|
}
|
|
7200
7432
|
/**
|
|
7201
7433
|
* Subscribe to file change events across all watched sessions.
|
|
@@ -7229,10 +7461,10 @@ var init_sandbox_file_sync = __esm({
|
|
|
7229
7461
|
* Stop all watchers and cleanup
|
|
7230
7462
|
*/
|
|
7231
7463
|
async stopAllWatching() {
|
|
7232
|
-
const
|
|
7464
|
+
const inSandboxPromises = Array.from(this.inSandboxWatchers.values()).map((w) => w.stop());
|
|
7233
7465
|
const localPromises = Array.from(this.localWatchers.values()).map((w) => w.stop());
|
|
7234
|
-
await Promise.all([...
|
|
7235
|
-
this.
|
|
7466
|
+
await Promise.all([...inSandboxPromises, ...localPromises]);
|
|
7467
|
+
this.inSandboxWatchers.clear();
|
|
7236
7468
|
this.localWatchers.clear();
|
|
7237
7469
|
}
|
|
7238
7470
|
/**
|
|
@@ -7240,8 +7472,8 @@ var init_sandbox_file_sync = __esm({
|
|
|
7240
7472
|
*/
|
|
7241
7473
|
getWatchingStatus() {
|
|
7242
7474
|
const statuses = [];
|
|
7243
|
-
for (const [sessionId, watcher] of this.
|
|
7244
|
-
statuses.push({ sessionId, type: "
|
|
7475
|
+
for (const [sessionId, watcher] of this.inSandboxWatchers) {
|
|
7476
|
+
statuses.push({ sessionId, type: "in-sandbox", isActive: watcher.isActive() });
|
|
7245
7477
|
}
|
|
7246
7478
|
for (const [sessionId, watcher] of this.localWatchers) {
|
|
7247
7479
|
statuses.push({ sessionId, type: "local", isActive: watcher.isActive() });
|
|
@@ -7252,364 +7484,6 @@ var init_sandbox_file_sync = __esm({
|
|
|
7252
7484
|
}
|
|
7253
7485
|
});
|
|
7254
7486
|
|
|
7255
|
-
// src/runtime/in-sandbox-watcher.ts
|
|
7256
|
-
function createInSandboxWatcher(options) {
|
|
7257
|
-
return new InSandboxWatcher(options);
|
|
7258
|
-
}
|
|
7259
|
-
function getInSandboxWatcherManager() {
|
|
7260
|
-
if (!globalInSandboxManager) {
|
|
7261
|
-
globalInSandboxManager = new InSandboxWatcherManager();
|
|
7262
|
-
}
|
|
7263
|
-
return globalInSandboxManager;
|
|
7264
|
-
}
|
|
7265
|
-
function createInSandboxWatcherManager() {
|
|
7266
|
-
return new InSandboxWatcherManager();
|
|
7267
|
-
}
|
|
7268
|
-
var WATCHER_SCRIPT, InSandboxWatcher, InSandboxWatcherManager, globalInSandboxManager;
|
|
7269
|
-
var init_in_sandbox_watcher = __esm({
|
|
7270
|
-
"src/runtime/in-sandbox-watcher.ts"() {
|
|
7271
|
-
init_vercel_sandbox_executor();
|
|
7272
|
-
WATCHER_SCRIPT = `
|
|
7273
|
-
const fs = require('fs');
|
|
7274
|
-
const path = require('path');
|
|
7275
|
-
|
|
7276
|
-
const watchPath = process.argv[2] || '.';
|
|
7277
|
-
const ignored = new Set(['node_modules', '.git', '.cache', '__pycache__']);
|
|
7278
|
-
|
|
7279
|
-
// Track all watchers for cleanup
|
|
7280
|
-
const watchers = new Map();
|
|
7281
|
-
|
|
7282
|
-
// Debounce map to coalesce rapid changes
|
|
7283
|
-
const pending = new Map();
|
|
7284
|
-
const DEBOUNCE_MS = 100;
|
|
7285
|
-
|
|
7286
|
-
function emit(type, filePath) {
|
|
7287
|
-
const event = {
|
|
7288
|
-
type,
|
|
7289
|
-
path: filePath,
|
|
7290
|
-
timestamp: Date.now()
|
|
7291
|
-
};
|
|
7292
|
-
console.log(JSON.stringify(event));
|
|
7293
|
-
}
|
|
7294
|
-
|
|
7295
|
-
function shouldIgnore(name) {
|
|
7296
|
-
return ignored.has(name) || name.startsWith('.');
|
|
7297
|
-
}
|
|
7298
|
-
|
|
7299
|
-
function watchDir(dir) {
|
|
7300
|
-
try {
|
|
7301
|
-
const watcher = fs.watch(dir, { persistent: true }, (eventType, filename) => {
|
|
7302
|
-
if (!filename || shouldIgnore(filename)) return;
|
|
7303
|
-
|
|
7304
|
-
const fullPath = path.join(dir, filename);
|
|
7305
|
-
const key = fullPath;
|
|
7306
|
-
|
|
7307
|
-
// Debounce
|
|
7308
|
-
if (pending.has(key)) {
|
|
7309
|
-
clearTimeout(pending.get(key));
|
|
7310
|
-
}
|
|
7311
|
-
|
|
7312
|
-
pending.set(key, setTimeout(() => {
|
|
7313
|
-
pending.delete(key);
|
|
7314
|
-
|
|
7315
|
-
fs.stat(fullPath, (err, stats) => {
|
|
7316
|
-
if (err) {
|
|
7317
|
-
if (err.code === 'ENOENT') {
|
|
7318
|
-
emit('unlink', fullPath);
|
|
7319
|
-
// Stop watching if it was a directory
|
|
7320
|
-
if (watchers.has(fullPath)) {
|
|
7321
|
-
watchers.get(fullPath).close();
|
|
7322
|
-
watchers.delete(fullPath);
|
|
7323
|
-
}
|
|
7324
|
-
}
|
|
7325
|
-
} else {
|
|
7326
|
-
const type = eventType === 'rename' ? 'add' : 'change';
|
|
7327
|
-
emit(type, fullPath);
|
|
7328
|
-
|
|
7329
|
-
// If it's a new directory, start watching it
|
|
7330
|
-
if (stats.isDirectory() && !watchers.has(fullPath)) {
|
|
7331
|
-
watchDir(fullPath);
|
|
7332
|
-
}
|
|
7333
|
-
}
|
|
7334
|
-
});
|
|
7335
|
-
}, DEBOUNCE_MS));
|
|
7336
|
-
});
|
|
7337
|
-
|
|
7338
|
-
watchers.set(dir, watcher);
|
|
7339
|
-
|
|
7340
|
-
// Watch subdirectories
|
|
7341
|
-
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
7342
|
-
for (const entry of entries) {
|
|
7343
|
-
if (entry.isDirectory() && !shouldIgnore(entry.name)) {
|
|
7344
|
-
watchDir(path.join(dir, entry.name));
|
|
7345
|
-
}
|
|
7346
|
-
}
|
|
7347
|
-
} catch (err) {
|
|
7348
|
-
// Directory may not exist or be inaccessible
|
|
7349
|
-
console.error(JSON.stringify({ error: err.message, dir }));
|
|
7350
|
-
}
|
|
7351
|
-
}
|
|
7352
|
-
|
|
7353
|
-
// Start watching
|
|
7354
|
-
watchDir(watchPath);
|
|
7355
|
-
|
|
7356
|
-
// Keep alive
|
|
7357
|
-
process.on('SIGTERM', () => {
|
|
7358
|
-
for (const watcher of watchers.values()) {
|
|
7359
|
-
watcher.close();
|
|
7360
|
-
}
|
|
7361
|
-
process.exit(0);
|
|
7362
|
-
});
|
|
7363
|
-
|
|
7364
|
-
// Heartbeat to indicate we're running
|
|
7365
|
-
setInterval(() => {
|
|
7366
|
-
console.log(JSON.stringify({ heartbeat: true, timestamp: Date.now() }));
|
|
7367
|
-
}, 5000);
|
|
7368
|
-
|
|
7369
|
-
console.log(JSON.stringify({ started: true, path: watchPath }));
|
|
7370
|
-
`;
|
|
7371
|
-
InSandboxWatcher = class {
|
|
7372
|
-
sessionId;
|
|
7373
|
-
watchPath;
|
|
7374
|
-
outputPollIntervalMs;
|
|
7375
|
-
sandboxState = null;
|
|
7376
|
-
outputPollTimer = null;
|
|
7377
|
-
subscribers = /* @__PURE__ */ new Set();
|
|
7378
|
-
isRunning = false;
|
|
7379
|
-
startedAt;
|
|
7380
|
-
lastHeartbeat;
|
|
7381
|
-
lastOutputPosition = 0;
|
|
7382
|
-
onError;
|
|
7383
|
-
onReady;
|
|
7384
|
-
constructor(options) {
|
|
7385
|
-
this.sessionId = options.sessionId;
|
|
7386
|
-
this.watchPath = options.watchPath;
|
|
7387
|
-
this.outputPollIntervalMs = options.outputPollIntervalMs ?? 1e3;
|
|
7388
|
-
this.onError = options.onError;
|
|
7389
|
-
this.onReady = options.onReady;
|
|
7390
|
-
if (options.onFileChange) {
|
|
7391
|
-
this.subscribers.add(options.onFileChange);
|
|
7392
|
-
}
|
|
7393
|
-
}
|
|
7394
|
-
/**
|
|
7395
|
-
* Start the watcher process inside the sandbox
|
|
7396
|
-
*/
|
|
7397
|
-
async start() {
|
|
7398
|
-
if (this.isRunning) {
|
|
7399
|
-
console.warn(`[IN_SANDBOX_WATCHER] Already running for session ${this.sessionId}`);
|
|
7400
|
-
return;
|
|
7401
|
-
}
|
|
7402
|
-
try {
|
|
7403
|
-
this.sandboxState = await getOrCreateSandbox({
|
|
7404
|
-
sessionId: this.sessionId,
|
|
7405
|
-
runtime: "node22",
|
|
7406
|
-
timeout: 600
|
|
7407
|
-
});
|
|
7408
|
-
const { sandbox } = this.sandboxState;
|
|
7409
|
-
const scriptPath = "/tmp/.file-watcher.js";
|
|
7410
|
-
const outputPath = "/tmp/.file-watcher-output.log";
|
|
7411
|
-
const writeScriptCmd = `cat > ${scriptPath} << 'WATCHER_EOF'
|
|
7412
|
-
${WATCHER_SCRIPT}
|
|
7413
|
-
WATCHER_EOF`;
|
|
7414
|
-
await sandbox.runCommand({
|
|
7415
|
-
cmd: "sh",
|
|
7416
|
-
args: ["-c", writeScriptCmd]
|
|
7417
|
-
});
|
|
7418
|
-
const startCmd = `nohup node ${scriptPath} "${this.watchPath}" > ${outputPath} 2>&1 &`;
|
|
7419
|
-
await sandbox.runCommand({
|
|
7420
|
-
cmd: "sh",
|
|
7421
|
-
args: ["-c", startCmd]
|
|
7422
|
-
});
|
|
7423
|
-
console.log(`[IN_SANDBOX_WATCHER] Started watcher in sandbox for ${this.watchPath}`);
|
|
7424
|
-
this.isRunning = true;
|
|
7425
|
-
this.startedAt = /* @__PURE__ */ new Date();
|
|
7426
|
-
this.outputPollTimer = setInterval(async () => {
|
|
7427
|
-
try {
|
|
7428
|
-
await this.pollOutput(outputPath);
|
|
7429
|
-
} catch (error) {
|
|
7430
|
-
console.error("[IN_SANDBOX_WATCHER] Error polling output:", error);
|
|
7431
|
-
if (this.onError && error instanceof Error) {
|
|
7432
|
-
this.onError(error);
|
|
7433
|
-
}
|
|
7434
|
-
}
|
|
7435
|
-
}, this.outputPollIntervalMs);
|
|
7436
|
-
setTimeout(() => {
|
|
7437
|
-
this.pollOutput(outputPath).catch(console.error);
|
|
7438
|
-
}, 500);
|
|
7439
|
-
} catch (error) {
|
|
7440
|
-
console.error(`[IN_SANDBOX_WATCHER] Failed to start watcher:`, error);
|
|
7441
|
-
throw error;
|
|
7442
|
-
}
|
|
7443
|
-
}
|
|
7444
|
-
/**
|
|
7445
|
-
* Poll the output file for new events
|
|
7446
|
-
*/
|
|
7447
|
-
async pollOutput(outputPath) {
|
|
7448
|
-
if (!this.sandboxState?.sandbox) return;
|
|
7449
|
-
try {
|
|
7450
|
-
const result = await this.sandboxState.sandbox.runCommand({
|
|
7451
|
-
cmd: "sh",
|
|
7452
|
-
args: ["-c", `tail -c +${this.lastOutputPosition + 1} ${outputPath} 2>/dev/null || true`]
|
|
7453
|
-
});
|
|
7454
|
-
const output = await result.stdout();
|
|
7455
|
-
if (output && output.trim()) {
|
|
7456
|
-
const sizeResult = await this.sandboxState.sandbox.runCommand({
|
|
7457
|
-
cmd: "sh",
|
|
7458
|
-
args: ["-c", `stat -c%s ${outputPath} 2>/dev/null || echo 0`]
|
|
7459
|
-
});
|
|
7460
|
-
const sizeStr = await sizeResult.stdout();
|
|
7461
|
-
this.lastOutputPosition = parseInt(sizeStr.trim(), 10) || 0;
|
|
7462
|
-
this.processOutput(output);
|
|
7463
|
-
}
|
|
7464
|
-
} catch {
|
|
7465
|
-
}
|
|
7466
|
-
}
|
|
7467
|
-
/**
|
|
7468
|
-
* Process output from the watcher script
|
|
7469
|
-
*/
|
|
7470
|
-
processOutput(stdout) {
|
|
7471
|
-
const lines = stdout.split("\n").filter(Boolean);
|
|
7472
|
-
for (const line of lines) {
|
|
7473
|
-
try {
|
|
7474
|
-
const data = JSON.parse(line);
|
|
7475
|
-
if (data.started) {
|
|
7476
|
-
console.log(`[IN_SANDBOX_WATCHER] Watcher started for ${data.path}`);
|
|
7477
|
-
if (this.onReady) {
|
|
7478
|
-
this.onReady();
|
|
7479
|
-
}
|
|
7480
|
-
} else if (data.heartbeat) {
|
|
7481
|
-
this.lastHeartbeat = new Date(data.timestamp);
|
|
7482
|
-
} else if (data.error) {
|
|
7483
|
-
console.warn(`[IN_SANDBOX_WATCHER] Error in sandbox:`, data.error);
|
|
7484
|
-
} else if (data.type && data.path) {
|
|
7485
|
-
this.emitEvent({
|
|
7486
|
-
type: data.type,
|
|
7487
|
-
relativePath: data.path.replace(/^\.\//, ""),
|
|
7488
|
-
absolutePath: data.path,
|
|
7489
|
-
basePath: this.watchPath,
|
|
7490
|
-
sessionId: this.sessionId,
|
|
7491
|
-
timestamp: new Date(data.timestamp)
|
|
7492
|
-
});
|
|
7493
|
-
}
|
|
7494
|
-
} catch {
|
|
7495
|
-
}
|
|
7496
|
-
}
|
|
7497
|
-
}
|
|
7498
|
-
/**
|
|
7499
|
-
* Stop the watcher process
|
|
7500
|
-
*/
|
|
7501
|
-
async stop() {
|
|
7502
|
-
if (!this.isRunning) {
|
|
7503
|
-
return;
|
|
7504
|
-
}
|
|
7505
|
-
if (this.outputPollTimer) {
|
|
7506
|
-
clearInterval(this.outputPollTimer);
|
|
7507
|
-
this.outputPollTimer = null;
|
|
7508
|
-
}
|
|
7509
|
-
try {
|
|
7510
|
-
if (this.sandboxState?.sandbox) {
|
|
7511
|
-
await this.sandboxState.sandbox.runCommand({
|
|
7512
|
-
cmd: "sh",
|
|
7513
|
-
args: ["-c", "pkill -f file-watcher.js 2>/dev/null || true"]
|
|
7514
|
-
});
|
|
7515
|
-
await this.sandboxState.sandbox.runCommand({
|
|
7516
|
-
cmd: "sh",
|
|
7517
|
-
args: ["-c", "rm -f /tmp/.file-watcher.js /tmp/.file-watcher-output.log"]
|
|
7518
|
-
});
|
|
7519
|
-
}
|
|
7520
|
-
} catch {
|
|
7521
|
-
}
|
|
7522
|
-
this.isRunning = false;
|
|
7523
|
-
this.sandboxState = null;
|
|
7524
|
-
this.lastOutputPosition = 0;
|
|
7525
|
-
console.log(`[IN_SANDBOX_WATCHER] Stopped watcher for session ${this.sessionId}`);
|
|
7526
|
-
}
|
|
7527
|
-
/**
|
|
7528
|
-
* Subscribe to file change events
|
|
7529
|
-
*/
|
|
7530
|
-
subscribe(callback) {
|
|
7531
|
-
this.subscribers.add(callback);
|
|
7532
|
-
return () => this.subscribers.delete(callback);
|
|
7533
|
-
}
|
|
7534
|
-
/**
|
|
7535
|
-
* Check if watcher is running
|
|
7536
|
-
*/
|
|
7537
|
-
isActive() {
|
|
7538
|
-
return this.isRunning;
|
|
7539
|
-
}
|
|
7540
|
-
/**
|
|
7541
|
-
* Get watcher status
|
|
7542
|
-
*/
|
|
7543
|
-
getStatus() {
|
|
7544
|
-
return {
|
|
7545
|
-
sessionId: this.sessionId,
|
|
7546
|
-
watchPath: this.watchPath,
|
|
7547
|
-
isRunning: this.isRunning,
|
|
7548
|
-
startedAt: this.startedAt,
|
|
7549
|
-
lastHeartbeat: this.lastHeartbeat
|
|
7550
|
-
};
|
|
7551
|
-
}
|
|
7552
|
-
/**
|
|
7553
|
-
* Emit event to all subscribers
|
|
7554
|
-
*/
|
|
7555
|
-
async emitEvent(event) {
|
|
7556
|
-
for (const callback of this.subscribers) {
|
|
7557
|
-
try {
|
|
7558
|
-
await callback(event);
|
|
7559
|
-
} catch (error) {
|
|
7560
|
-
console.error("[IN_SANDBOX_WATCHER] Error in subscriber callback:", error);
|
|
7561
|
-
}
|
|
7562
|
-
}
|
|
7563
|
-
}
|
|
7564
|
-
};
|
|
7565
|
-
InSandboxWatcherManager = class {
|
|
7566
|
-
watchers = /* @__PURE__ */ new Map();
|
|
7567
|
-
/**
|
|
7568
|
-
* Start watching a sandbox
|
|
7569
|
-
*/
|
|
7570
|
-
async startWatching(options) {
|
|
7571
|
-
const { sessionId } = options;
|
|
7572
|
-
await this.stopWatching(sessionId);
|
|
7573
|
-
const watcher = new InSandboxWatcher(options);
|
|
7574
|
-
await watcher.start();
|
|
7575
|
-
this.watchers.set(sessionId, watcher);
|
|
7576
|
-
return watcher;
|
|
7577
|
-
}
|
|
7578
|
-
/**
|
|
7579
|
-
* Stop watching a session
|
|
7580
|
-
*/
|
|
7581
|
-
async stopWatching(sessionId) {
|
|
7582
|
-
const watcher = this.watchers.get(sessionId);
|
|
7583
|
-
if (watcher) {
|
|
7584
|
-
await watcher.stop();
|
|
7585
|
-
this.watchers.delete(sessionId);
|
|
7586
|
-
}
|
|
7587
|
-
}
|
|
7588
|
-
/**
|
|
7589
|
-
* Get watcher for a session
|
|
7590
|
-
*/
|
|
7591
|
-
getWatcher(sessionId) {
|
|
7592
|
-
return this.watchers.get(sessionId);
|
|
7593
|
-
}
|
|
7594
|
-
/**
|
|
7595
|
-
* Check if watching
|
|
7596
|
-
*/
|
|
7597
|
-
isWatching(sessionId) {
|
|
7598
|
-
return this.watchers.get(sessionId)?.isActive() ?? false;
|
|
7599
|
-
}
|
|
7600
|
-
/**
|
|
7601
|
-
* Stop all watchers
|
|
7602
|
-
*/
|
|
7603
|
-
async stopAll() {
|
|
7604
|
-
const promises = Array.from(this.watchers.values()).map((w) => w.stop());
|
|
7605
|
-
await Promise.all(promises);
|
|
7606
|
-
this.watchers.clear();
|
|
7607
|
-
}
|
|
7608
|
-
};
|
|
7609
|
-
globalInSandboxManager = null;
|
|
7610
|
-
}
|
|
7611
|
-
});
|
|
7612
|
-
|
|
7613
7487
|
// src/runtime/index.ts
|
|
7614
7488
|
function generateDockerCommand(config) {
|
|
7615
7489
|
const args = ["docker", "run"];
|
|
@@ -8042,7 +7916,7 @@ var init_credentials = __esm({
|
|
|
8042
7916
|
}
|
|
8043
7917
|
});
|
|
8044
7918
|
var gitHubSkillSourceSchema, localSkillSourceSchema, skillSourceSchema, skillConfigSchema, fileEntrySchema;
|
|
8045
|
-
var
|
|
7919
|
+
var init_types4 = __esm({
|
|
8046
7920
|
"src/skills/types.ts"() {
|
|
8047
7921
|
gitHubSkillSourceSchema = z.object({
|
|
8048
7922
|
type: z.literal("github"),
|
|
@@ -8586,7 +8460,7 @@ var init_manager2 = __esm({
|
|
|
8586
8460
|
// src/skills/index.ts
|
|
8587
8461
|
var init_skills = __esm({
|
|
8588
8462
|
"src/skills/index.ts"() {
|
|
8589
|
-
|
|
8463
|
+
init_types4();
|
|
8590
8464
|
init_local_provider();
|
|
8591
8465
|
init_github_provider();
|
|
8592
8466
|
init_manager2();
|
|
@@ -18106,7 +17980,7 @@ var init_storage3 = __esm({
|
|
|
18106
17980
|
}
|
|
18107
17981
|
if (options.filePath) {
|
|
18108
17982
|
query = query.or(
|
|
18109
|
-
`event_data->>filePath.eq.${options.filePath},and(category.eq.tool,tool_name.in.(Read,Write,Edit),event_data->input->>file_path.eq.${options.filePath})`
|
|
17983
|
+
`event_data->>filePath.eq.${options.filePath},event_data->>canonicalPath.eq.${options.filePath},and(category.eq.tool,tool_name.in.(Read,Write,Edit),event_data->input->>file_path.eq.${options.filePath})`
|
|
18110
17984
|
);
|
|
18111
17985
|
}
|
|
18112
17986
|
const ascending = options.order !== "desc";
|
|
@@ -18990,6 +18864,6 @@ var init_src = __esm({
|
|
|
18990
18864
|
});
|
|
18991
18865
|
init_src();
|
|
18992
18866
|
|
|
18993
|
-
export { AVAILABLE_MODELS, AgentConfigSchema, AgentError, AgentHarness, AgentStatus, AshCloud, AshCloudApiError, AshCloudClient, AttachmentConfigSchema, AttachmentStorage, ClaudeSdkClient, CloudSandbox, CloudStorage, ConfigBuilder, ConfigError, CredentialManager, DEFAULT_MODELS, DEFAULT_SANDBOX_PROVIDER_CONFIG, EventCategory, FileWatcherManager, GCSBundleStore, GeminiCliClient, GitHubFileProvider, HarnessConfigSchema, HarnessError, HarnessErrorCode, HarnessEventEmitter, InSandboxWatcher, InSandboxWatcherManager, LocalBundleStore, LocalFileProvider, LocalSandbox, McpConfigBuilder, McpPresets, McpServers, MemoryBundleStore, MemoryCredentialStorage, MemoryQueueStorage, MemoryRateLimitStore, MemoryStorage, MessageRole, NotFoundError, PostgresQueueStorage, PostgresStorage, ProviderSandbox, QueueItemStatus, QueueProcessor,
|
|
18867
|
+
export { AVAILABLE_MODELS, AgentConfigSchema, AgentError, AgentHarness, AgentStatus, AshCloud, AshCloudApiError, AshCloudClient, AttachmentConfigSchema, AttachmentStorage, ClaudeSdkClient, CloudSandbox, CloudStorage, ConfigBuilder, ConfigError, CredentialManager, DEFAULT_MODELS, DEFAULT_SANDBOX_PROVIDER_CONFIG, EventCategory, FileWatcherManager, GCSBundleStore, GeminiCliClient, GitHubFileProvider, HarnessConfigSchema, HarnessError, HarnessErrorCode, HarnessEventEmitter, InSandboxWatcher, InSandboxWatcherManager, LocalBundleStore, LocalFileProvider, LocalSandbox, McpConfigBuilder, McpPresets, McpServers, MemoryBundleStore, MemoryCredentialStorage, MemoryQueueStorage, MemoryRateLimitStore, MemoryStorage, MessageRole, NotFoundError, PostgresQueueStorage, PostgresStorage, ProviderSandbox, QueueItemStatus, QueueProcessor, RuntimeConfigBuilder, RuntimePresets, S3BundleStore, S3FileStore, SENSITIVE_PATHS, SandboxFileSync, SandboxFileWatcher, SandboxGitRepo, SandboxLogger, SandboxPool, ServerConfigSchema, SessionError, SessionManager, SessionStatus, SkillCatalog, SkillManager, StorageConfigSchema, StorageError, StreamEventType, SupabaseBundleStore, SupabaseStorage, ToolCallProcessor, ToolError, ValidationError, Workspace, WorkspaceManager, attachmentSchema, attachmentToDataUrl, checkSecurityConfig, claudeClient, cleanupAllSandboxes, configureMcp, configureRuntime, convertClaudeMessage, createAgentsRouter, createAshCloud, createBackendExecutor, createCloudSandbox, createConfig, createCredentialManager, createOpenAPIServer as createDocumentedServer, createE2BSandbox, createEventHandler, createEventMiddlewareChain, createFileWatcher, createFileWatcherManager, createGCSBundleStore, createGeminiExecutor, createGitHubFileProvider, createGitRepo, createHarnessServer, createInSandboxWatcher, createInSandboxWatcherManager, createLocalBundleStore, createLocalFileProvider, createLocalSandbox, createLogger, createMemoryBundleStore, createMinioBundleStore, createMinioFileStore, createModalSandbox, createAgentsRouter2 as createOpenAPIAgentsRouter, createOpenAPIServer, createSessionsRouter2 as createOpenAPISessionsRouter, createSkillsRouter2 as createOpenAPISkillsRouter, createProviderSandbox, createQueueProcessor, createQueueRouter, createR2BundleStore, createR2FileStore, createS3BundleStore, createS3FileStore, createSandboxFileOperations, createSandboxFileSync, createSandboxLogger, createSandboxOptions, createSessionWorkspace, createSessionsRouter, createSkillCatalog, createSkillManager, createSupabaseBundleStore, createSupabaseBundleStoreFromEnv, createToolCall, createToolCallProcessor, createVercelSandbox, createVercelSandboxExecutor, createWorkspace, createWorkspaceHooks, createWorkspaceManager, dataUrlToBuffer, defineAgent, defineConfig, ensureSandboxPoolInitialized, env, envOptional, executeCommandInSandbox, extractTextContent, extractTextFromMessage, fileEntrySchema, formatToolName, generateDockerCommand, generateMcpServerPackage, generateMcpServers, generateProxyEnv, generateToolSummary, getActionIcon, getActionLabel, getAllHeartbeatStatuses, getApiKeyEnvVar, getCachedSandbox, getDefaultModel, getFileWatcherManager, getHeartbeatStatus, getInSandboxWatcherManager, getOrCreateSandbox, getSandboxCacheStats, getSandboxPool, getWorkspaceManager, gitHubSkillSourceSchema, globalEventEmitter, hasErrorCode, hashStartupScript, httpMcpWithAuth, initializeSandboxPool, introspectMcpServer, invalidateSandbox, isCommandRunAction, isDocumentMimeType, isErrorEntry, isFileEditAction, isFileReadAction, isFileWriteAction, isGenericToolAction, isGlobAction, isHarnessError, isHttpMcpConfig, isImageMimeType, isMcpToolAction, isSandboxExpiredError, isSandboxRunning, isSearchAction, isSensitivePath, isStdioMcpConfig, isTodoWriteAction, isToolCallEntry, isValidModel, isWebFetchAction, isWebSearchAction, listFilesInSandbox, loadConfig, loadGitHubSkill, loadGitHubSkills, loadWorkspaceState, localSkillSourceSchema, log, mapClaudeOptionsToGemini, mapToolToActionType, markConfigInstalled, markSdkInstalled, markStartupScriptRan, mcpAuthToHeaders, messageContentSchema, messageSchema, needsStartupScriptRerun, normalizeGitHubConfigs, normalizeMcpServers, normalizeMessages, normalizeToolResult, onHeartbeat, schemas_exports as openApiSchemas, parseCommandResult, parseGitHubUrl, parseMcpToolName, processStreamEvents, rateLimit, rateLimiters, readFileFromSandbox, rekeySessionId, releaseSandbox, requestLogger, saveWorkspaceState, schema_exports as schema, sessionSchema, shouldUseSandbox, shutdownSandboxPool, skillConfigSchema, skillSourceSchema, sseMcpWithAuth, startServer, updateToolCallWithResult, writeFileToSandbox };
|
|
18994
18868
|
//# sourceMappingURL=index.js.map
|
|
18995
18869
|
//# sourceMappingURL=index.js.map
|