@ash-cloud/ash-ai 0.1.13 → 0.1.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +353 -553
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +34 -144
- package/dist/index.d.ts +34 -144
- package/dist/index.js +352 -551
- package/dist/index.js.map +1 -1
- package/dist/playground/components/ChatInput.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 +897 -817
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -5261,6 +5261,23 @@ function isSandboxRunning(sessionId) {
|
|
|
5261
5261
|
const cached = sandboxCache.get(sessionId);
|
|
5262
5262
|
return cached !== void 0 && !cached.isExpired;
|
|
5263
5263
|
}
|
|
5264
|
+
function getCachedSandbox(sessionId) {
|
|
5265
|
+
const cached = sandboxCache.get(sessionId);
|
|
5266
|
+
if (!cached || cached.isExpired) {
|
|
5267
|
+
return null;
|
|
5268
|
+
}
|
|
5269
|
+
cached.lastUsedAt = Date.now();
|
|
5270
|
+
return {
|
|
5271
|
+
sandbox: cached.sandbox,
|
|
5272
|
+
sandboxId: cached.sandbox.sandboxId,
|
|
5273
|
+
sdkInstalled: cached.sdkInstalled,
|
|
5274
|
+
startupScriptRan: cached.startupScriptRan,
|
|
5275
|
+
startupScriptHash: cached.startupScriptHash,
|
|
5276
|
+
isNew: false,
|
|
5277
|
+
configFileUrl: cached.configFileUrl,
|
|
5278
|
+
configInstalledAt: cached.configInstalledAt
|
|
5279
|
+
};
|
|
5280
|
+
}
|
|
5264
5281
|
async function writeFileToSandbox(sessionId, path15, content) {
|
|
5265
5282
|
const cached = sandboxCache.get(sessionId);
|
|
5266
5283
|
if (!cached) {
|
|
@@ -5329,6 +5346,54 @@ async function readFileFromSandbox(sessionId, path15) {
|
|
|
5329
5346
|
};
|
|
5330
5347
|
}
|
|
5331
5348
|
}
|
|
5349
|
+
async function executeCommandInSandbox(sessionId, command, options) {
|
|
5350
|
+
const cached = sandboxCache.get(sessionId);
|
|
5351
|
+
if (!cached) {
|
|
5352
|
+
return { success: false, error: "No active sandbox for session" };
|
|
5353
|
+
}
|
|
5354
|
+
if (cached.isExpired) {
|
|
5355
|
+
return { success: false, error: "Sandbox has expired" };
|
|
5356
|
+
}
|
|
5357
|
+
const startTime = Date.now();
|
|
5358
|
+
try {
|
|
5359
|
+
const sandbox = cached.sandbox;
|
|
5360
|
+
let fullCommand = command;
|
|
5361
|
+
if (options?.cwd) {
|
|
5362
|
+
fullCommand = `cd ${JSON.stringify(options.cwd)} && ${command}`;
|
|
5363
|
+
}
|
|
5364
|
+
const result = await sandbox.runCommand({
|
|
5365
|
+
cmd: "bash",
|
|
5366
|
+
args: ["-c", fullCommand],
|
|
5367
|
+
env: options?.env
|
|
5368
|
+
});
|
|
5369
|
+
const stdout = await result.stdout();
|
|
5370
|
+
const stderr = await result.stderr();
|
|
5371
|
+
const durationMs = Date.now() - startTime;
|
|
5372
|
+
cached.lastUsedAt = Date.now();
|
|
5373
|
+
return {
|
|
5374
|
+
success: result.exitCode === 0,
|
|
5375
|
+
exitCode: result.exitCode,
|
|
5376
|
+
stdout,
|
|
5377
|
+
stderr,
|
|
5378
|
+
durationMs
|
|
5379
|
+
};
|
|
5380
|
+
} catch (error) {
|
|
5381
|
+
const durationMs = Date.now() - startTime;
|
|
5382
|
+
if (isSandboxExpiredError(error)) {
|
|
5383
|
+
cached.isExpired = true;
|
|
5384
|
+
return {
|
|
5385
|
+
success: false,
|
|
5386
|
+
error: "Sandbox has expired",
|
|
5387
|
+
durationMs
|
|
5388
|
+
};
|
|
5389
|
+
}
|
|
5390
|
+
return {
|
|
5391
|
+
success: false,
|
|
5392
|
+
error: error instanceof Error ? error.message : "Unknown error",
|
|
5393
|
+
durationMs
|
|
5394
|
+
};
|
|
5395
|
+
}
|
|
5396
|
+
}
|
|
5332
5397
|
async function listFilesInSandbox(sessionId, path15) {
|
|
5333
5398
|
const cached = sandboxCache.get(sessionId);
|
|
5334
5399
|
if (!cached) {
|
|
@@ -5808,19 +5873,7 @@ function getFileWatcherManager() {
|
|
|
5808
5873
|
function createFileWatcherManager() {
|
|
5809
5874
|
return new FileWatcherManager();
|
|
5810
5875
|
}
|
|
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;
|
|
5876
|
+
var SandboxFileWatcher, FileWatcherManager, globalWatcherManager;
|
|
5824
5877
|
var init_sandbox_file_watcher = __esm({
|
|
5825
5878
|
"src/runtime/sandbox-file-watcher.ts"() {
|
|
5826
5879
|
SandboxFileWatcher = class {
|
|
@@ -6062,214 +6115,327 @@ var init_sandbox_file_watcher = __esm({
|
|
|
6062
6115
|
}
|
|
6063
6116
|
};
|
|
6064
6117
|
globalWatcherManager = null;
|
|
6065
|
-
|
|
6118
|
+
}
|
|
6119
|
+
});
|
|
6120
|
+
|
|
6121
|
+
// src/runtime/in-sandbox-watcher.ts
|
|
6122
|
+
function createInSandboxWatcher(options) {
|
|
6123
|
+
return new InSandboxWatcher(options);
|
|
6124
|
+
}
|
|
6125
|
+
function getInSandboxWatcherManager() {
|
|
6126
|
+
if (!globalInSandboxManager) {
|
|
6127
|
+
globalInSandboxManager = new InSandboxWatcherManager();
|
|
6128
|
+
}
|
|
6129
|
+
return globalInSandboxManager;
|
|
6130
|
+
}
|
|
6131
|
+
function createInSandboxWatcherManager() {
|
|
6132
|
+
return new InSandboxWatcherManager();
|
|
6133
|
+
}
|
|
6134
|
+
var WATCHER_SCRIPT, InSandboxWatcher, InSandboxWatcherManager, globalInSandboxManager;
|
|
6135
|
+
var init_in_sandbox_watcher = __esm({
|
|
6136
|
+
"src/runtime/in-sandbox-watcher.ts"() {
|
|
6137
|
+
init_vercel_sandbox_executor();
|
|
6138
|
+
WATCHER_SCRIPT = `
|
|
6139
|
+
const fs = require('fs');
|
|
6140
|
+
const path = require('path');
|
|
6141
|
+
|
|
6142
|
+
const watchPath = process.argv[2] || '.';
|
|
6143
|
+
const ignored = new Set(['node_modules', '.git', '.cache', '__pycache__']);
|
|
6144
|
+
|
|
6145
|
+
// Track all watchers for cleanup
|
|
6146
|
+
const watchers = new Map();
|
|
6147
|
+
|
|
6148
|
+
// Debounce map to coalesce rapid changes
|
|
6149
|
+
const pending = new Map();
|
|
6150
|
+
const DEBOUNCE_MS = 100;
|
|
6151
|
+
|
|
6152
|
+
function emit(type, filePath) {
|
|
6153
|
+
const event = {
|
|
6154
|
+
type,
|
|
6155
|
+
path: filePath,
|
|
6156
|
+
timestamp: Date.now()
|
|
6157
|
+
};
|
|
6158
|
+
console.log(JSON.stringify(event));
|
|
6159
|
+
}
|
|
6160
|
+
|
|
6161
|
+
function shouldIgnore(name) {
|
|
6162
|
+
return ignored.has(name) || name.startsWith('.');
|
|
6163
|
+
}
|
|
6164
|
+
|
|
6165
|
+
function watchDir(dir) {
|
|
6166
|
+
try {
|
|
6167
|
+
const watcher = fs.watch(dir, { persistent: true }, (eventType, filename) => {
|
|
6168
|
+
if (!filename || shouldIgnore(filename)) return;
|
|
6169
|
+
|
|
6170
|
+
const fullPath = path.join(dir, filename);
|
|
6171
|
+
const key = fullPath;
|
|
6172
|
+
|
|
6173
|
+
// Debounce
|
|
6174
|
+
if (pending.has(key)) {
|
|
6175
|
+
clearTimeout(pending.get(key));
|
|
6176
|
+
}
|
|
6177
|
+
|
|
6178
|
+
pending.set(key, setTimeout(() => {
|
|
6179
|
+
pending.delete(key);
|
|
6180
|
+
|
|
6181
|
+
fs.stat(fullPath, (err, stats) => {
|
|
6182
|
+
if (err) {
|
|
6183
|
+
if (err.code === 'ENOENT') {
|
|
6184
|
+
emit('unlink', fullPath);
|
|
6185
|
+
// Stop watching if it was a directory
|
|
6186
|
+
if (watchers.has(fullPath)) {
|
|
6187
|
+
watchers.get(fullPath).close();
|
|
6188
|
+
watchers.delete(fullPath);
|
|
6189
|
+
}
|
|
6190
|
+
}
|
|
6191
|
+
} else {
|
|
6192
|
+
const type = eventType === 'rename' ? 'add' : 'change';
|
|
6193
|
+
emit(type, fullPath);
|
|
6194
|
+
|
|
6195
|
+
// If it's a new directory, start watching it
|
|
6196
|
+
if (stats.isDirectory() && !watchers.has(fullPath)) {
|
|
6197
|
+
watchDir(fullPath);
|
|
6198
|
+
}
|
|
6199
|
+
}
|
|
6200
|
+
});
|
|
6201
|
+
}, DEBOUNCE_MS));
|
|
6202
|
+
});
|
|
6203
|
+
|
|
6204
|
+
watchers.set(dir, watcher);
|
|
6205
|
+
|
|
6206
|
+
// Watch subdirectories
|
|
6207
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
6208
|
+
for (const entry of entries) {
|
|
6209
|
+
if (entry.isDirectory() && !shouldIgnore(entry.name)) {
|
|
6210
|
+
watchDir(path.join(dir, entry.name));
|
|
6211
|
+
}
|
|
6212
|
+
}
|
|
6213
|
+
} catch (err) {
|
|
6214
|
+
// Directory may not exist or be inaccessible
|
|
6215
|
+
console.error(JSON.stringify({ error: err.message, dir }));
|
|
6216
|
+
}
|
|
6217
|
+
}
|
|
6218
|
+
|
|
6219
|
+
// Start watching
|
|
6220
|
+
watchDir(watchPath);
|
|
6221
|
+
|
|
6222
|
+
// Keep alive
|
|
6223
|
+
process.on('SIGTERM', () => {
|
|
6224
|
+
for (const watcher of watchers.values()) {
|
|
6225
|
+
watcher.close();
|
|
6226
|
+
}
|
|
6227
|
+
process.exit(0);
|
|
6228
|
+
});
|
|
6229
|
+
|
|
6230
|
+
// Heartbeat to indicate we're running
|
|
6231
|
+
setInterval(() => {
|
|
6232
|
+
console.log(JSON.stringify({ heartbeat: true, timestamp: Date.now() }));
|
|
6233
|
+
}, 5000);
|
|
6234
|
+
|
|
6235
|
+
console.log(JSON.stringify({ started: true, path: watchPath }));
|
|
6236
|
+
`;
|
|
6237
|
+
InSandboxWatcher = class {
|
|
6066
6238
|
sessionId;
|
|
6067
|
-
|
|
6068
|
-
|
|
6069
|
-
|
|
6070
|
-
|
|
6071
|
-
pollTimer = null;
|
|
6072
|
-
previousFiles = /* @__PURE__ */ new Map();
|
|
6239
|
+
watchPath;
|
|
6240
|
+
outputPollIntervalMs;
|
|
6241
|
+
sandboxState = null;
|
|
6242
|
+
outputPollTimer = null;
|
|
6073
6243
|
subscribers = /* @__PURE__ */ new Set();
|
|
6074
|
-
|
|
6244
|
+
isRunning = false;
|
|
6075
6245
|
startedAt;
|
|
6076
|
-
|
|
6077
|
-
|
|
6246
|
+
lastHeartbeat;
|
|
6247
|
+
lastOutputPosition = 0;
|
|
6078
6248
|
onError;
|
|
6249
|
+
onReady;
|
|
6079
6250
|
constructor(options) {
|
|
6080
6251
|
this.sessionId = options.sessionId;
|
|
6081
|
-
this.
|
|
6082
|
-
this.
|
|
6083
|
-
this.pollIntervalMs = options.pollIntervalMs ?? 2e3;
|
|
6084
|
-
this.ignored = options.ignored ?? ["**/node_modules/**", "**/.git/**"];
|
|
6252
|
+
this.watchPath = options.watchPath;
|
|
6253
|
+
this.outputPollIntervalMs = options.outputPollIntervalMs ?? 1e3;
|
|
6085
6254
|
this.onError = options.onError;
|
|
6255
|
+
this.onReady = options.onReady;
|
|
6086
6256
|
if (options.onFileChange) {
|
|
6087
6257
|
this.subscribers.add(options.onFileChange);
|
|
6088
6258
|
}
|
|
6089
6259
|
}
|
|
6090
6260
|
/**
|
|
6091
|
-
* Start
|
|
6261
|
+
* Start the watcher process inside the sandbox
|
|
6092
6262
|
*/
|
|
6093
6263
|
async start() {
|
|
6094
|
-
if (this.
|
|
6095
|
-
console.warn(`[
|
|
6264
|
+
if (this.isRunning) {
|
|
6265
|
+
console.warn(`[IN_SANDBOX_WATCHER] Already running for session ${this.sessionId}`);
|
|
6096
6266
|
return;
|
|
6097
6267
|
}
|
|
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
|
-
}
|
|
6268
|
+
try {
|
|
6269
|
+
this.sandboxState = getCachedSandbox(this.sessionId);
|
|
6270
|
+
if (!this.sandboxState) {
|
|
6271
|
+
throw new Error(`No active sandbox found for session ${this.sessionId}. Sandbox must be created before starting file watcher.`);
|
|
6110
6272
|
}
|
|
6111
|
-
|
|
6112
|
-
|
|
6113
|
-
|
|
6114
|
-
|
|
6115
|
-
|
|
6116
|
-
|
|
6117
|
-
|
|
6118
|
-
|
|
6119
|
-
|
|
6120
|
-
|
|
6121
|
-
|
|
6122
|
-
|
|
6123
|
-
|
|
6124
|
-
|
|
6125
|
-
|
|
6273
|
+
const { sandbox } = this.sandboxState;
|
|
6274
|
+
const scriptPath = "/tmp/.file-watcher.js";
|
|
6275
|
+
const outputPath = "/tmp/.file-watcher-output.log";
|
|
6276
|
+
const writeScriptCmd = `cat > ${scriptPath} << 'WATCHER_EOF'
|
|
6277
|
+
${WATCHER_SCRIPT}
|
|
6278
|
+
WATCHER_EOF`;
|
|
6279
|
+
await sandbox.runCommand({
|
|
6280
|
+
cmd: "sh",
|
|
6281
|
+
args: ["-c", writeScriptCmd]
|
|
6282
|
+
});
|
|
6283
|
+
const startCmd = `nohup node ${scriptPath} "${this.watchPath}" > ${outputPath} 2>&1 &`;
|
|
6284
|
+
await sandbox.runCommand({
|
|
6285
|
+
cmd: "sh",
|
|
6286
|
+
args: ["-c", startCmd]
|
|
6287
|
+
});
|
|
6288
|
+
console.log(`[IN_SANDBOX_WATCHER] Started watcher in sandbox for ${this.watchPath}`);
|
|
6289
|
+
this.isRunning = true;
|
|
6290
|
+
this.startedAt = /* @__PURE__ */ new Date();
|
|
6291
|
+
this.outputPollTimer = setInterval(async () => {
|
|
6292
|
+
try {
|
|
6293
|
+
await this.pollOutput(outputPath);
|
|
6294
|
+
} catch (error) {
|
|
6295
|
+
console.error("[IN_SANDBOX_WATCHER] Error polling output:", error);
|
|
6296
|
+
if (this.onError && error instanceof Error) {
|
|
6297
|
+
this.onError(error);
|
|
6298
|
+
}
|
|
6299
|
+
}
|
|
6300
|
+
}, this.outputPollIntervalMs);
|
|
6301
|
+
setTimeout(() => {
|
|
6302
|
+
this.pollOutput(outputPath).catch(console.error);
|
|
6303
|
+
}, 500);
|
|
6304
|
+
} catch (error) {
|
|
6305
|
+
console.error(`[IN_SANDBOX_WATCHER] Failed to start watcher:`, error);
|
|
6306
|
+
throw error;
|
|
6126
6307
|
}
|
|
6127
|
-
this.isWatching = false;
|
|
6128
|
-
this.previousFiles.clear();
|
|
6129
|
-
console.log(`[REMOTE_WATCHER] Stopped watching session ${this.sessionId}`);
|
|
6130
|
-
}
|
|
6131
|
-
/**
|
|
6132
|
-
* Subscribe to file change events
|
|
6133
|
-
*/
|
|
6134
|
-
subscribe(callback) {
|
|
6135
|
-
this.subscribers.add(callback);
|
|
6136
|
-
return () => this.subscribers.delete(callback);
|
|
6137
6308
|
}
|
|
6138
6309
|
/**
|
|
6139
|
-
*
|
|
6310
|
+
* Poll the output file for new events
|
|
6140
6311
|
*/
|
|
6141
|
-
|
|
6142
|
-
this.
|
|
6312
|
+
async pollOutput(outputPath) {
|
|
6313
|
+
if (!this.sandboxState?.sandbox) return;
|
|
6314
|
+
try {
|
|
6315
|
+
const result = await this.sandboxState.sandbox.runCommand({
|
|
6316
|
+
cmd: "sh",
|
|
6317
|
+
args: ["-c", `tail -c +${this.lastOutputPosition + 1} ${outputPath} 2>/dev/null || true`]
|
|
6318
|
+
});
|
|
6319
|
+
const output = await result.stdout();
|
|
6320
|
+
if (output && output.trim()) {
|
|
6321
|
+
const sizeResult = await this.sandboxState.sandbox.runCommand({
|
|
6322
|
+
cmd: "sh",
|
|
6323
|
+
args: ["-c", `stat -c%s ${outputPath} 2>/dev/null || echo 0`]
|
|
6324
|
+
});
|
|
6325
|
+
const sizeStr = await sizeResult.stdout();
|
|
6326
|
+
this.lastOutputPosition = parseInt(sizeStr.trim(), 10) || 0;
|
|
6327
|
+
this.processOutput(output);
|
|
6328
|
+
}
|
|
6329
|
+
} catch {
|
|
6330
|
+
}
|
|
6143
6331
|
}
|
|
6144
6332
|
/**
|
|
6145
|
-
*
|
|
6333
|
+
* Process output from the watcher script
|
|
6146
6334
|
*/
|
|
6147
|
-
|
|
6148
|
-
|
|
6149
|
-
|
|
6150
|
-
|
|
6151
|
-
|
|
6152
|
-
|
|
6153
|
-
|
|
6154
|
-
|
|
6155
|
-
|
|
6156
|
-
|
|
6157
|
-
|
|
6158
|
-
|
|
6159
|
-
|
|
6160
|
-
|
|
6161
|
-
|
|
6162
|
-
|
|
6163
|
-
|
|
6164
|
-
|
|
6165
|
-
|
|
6166
|
-
|
|
6167
|
-
|
|
6168
|
-
|
|
6169
|
-
|
|
6335
|
+
processOutput(stdout) {
|
|
6336
|
+
const lines = stdout.split("\n").filter(Boolean);
|
|
6337
|
+
for (const line of lines) {
|
|
6338
|
+
try {
|
|
6339
|
+
const data = JSON.parse(line);
|
|
6340
|
+
if (data.started) {
|
|
6341
|
+
console.log(`[IN_SANDBOX_WATCHER] Watcher started for ${data.path}`);
|
|
6342
|
+
if (this.onReady) {
|
|
6343
|
+
this.onReady();
|
|
6344
|
+
}
|
|
6345
|
+
} else if (data.heartbeat) {
|
|
6346
|
+
this.lastHeartbeat = new Date(data.timestamp);
|
|
6347
|
+
} else if (data.error) {
|
|
6348
|
+
console.warn(`[IN_SANDBOX_WATCHER] Error in sandbox:`, data.error);
|
|
6349
|
+
} else if (data.type && data.path) {
|
|
6350
|
+
this.emitEvent({
|
|
6351
|
+
type: data.type,
|
|
6352
|
+
relativePath: data.path.replace(/^\.\//, ""),
|
|
6353
|
+
absolutePath: data.path,
|
|
6354
|
+
basePath: this.watchPath,
|
|
6355
|
+
sessionId: this.sessionId,
|
|
6356
|
+
timestamp: new Date(data.timestamp)
|
|
6357
|
+
});
|
|
6358
|
+
}
|
|
6359
|
+
} catch {
|
|
6360
|
+
}
|
|
6361
|
+
}
|
|
6170
6362
|
}
|
|
6171
6363
|
/**
|
|
6172
|
-
*
|
|
6364
|
+
* Stop the watcher process
|
|
6173
6365
|
*/
|
|
6174
|
-
async
|
|
6175
|
-
if (!this.
|
|
6176
|
-
console.warn(`[REMOTE_WATCHER] Sandbox stopped for session ${this.sessionId}`);
|
|
6177
|
-
await this.stop();
|
|
6366
|
+
async stop() {
|
|
6367
|
+
if (!this.isRunning) {
|
|
6178
6368
|
return;
|
|
6179
6369
|
}
|
|
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;
|
|
6370
|
+
if (this.outputPollTimer) {
|
|
6371
|
+
clearInterval(this.outputPollTimer);
|
|
6372
|
+
this.outputPollTimer = null;
|
|
6196
6373
|
}
|
|
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()
|
|
6374
|
+
try {
|
|
6375
|
+
if (this.sandboxState?.sandbox) {
|
|
6376
|
+
await this.sandboxState.sandbox.runCommand({
|
|
6377
|
+
cmd: "sh",
|
|
6378
|
+
args: ["-c", "pkill -f file-watcher.js 2>/dev/null || true"]
|
|
6209
6379
|
});
|
|
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()
|
|
6380
|
+
await this.sandboxState.sandbox.runCommand({
|
|
6381
|
+
cmd: "sh",
|
|
6382
|
+
args: ["-c", "rm -f /tmp/.file-watcher.js /tmp/.file-watcher-output.log"]
|
|
6221
6383
|
});
|
|
6222
6384
|
}
|
|
6385
|
+
} catch {
|
|
6223
6386
|
}
|
|
6224
|
-
this.
|
|
6225
|
-
|
|
6226
|
-
|
|
6227
|
-
}
|
|
6387
|
+
this.isRunning = false;
|
|
6388
|
+
this.sandboxState = null;
|
|
6389
|
+
this.lastOutputPosition = 0;
|
|
6390
|
+
console.log(`[IN_SANDBOX_WATCHER] Stopped watcher for session ${this.sessionId}`);
|
|
6228
6391
|
}
|
|
6229
6392
|
/**
|
|
6230
|
-
*
|
|
6393
|
+
* Subscribe to file change events
|
|
6231
6394
|
*/
|
|
6232
|
-
|
|
6233
|
-
|
|
6234
|
-
|
|
6235
|
-
return true;
|
|
6236
|
-
}
|
|
6237
|
-
}
|
|
6238
|
-
return false;
|
|
6395
|
+
subscribe(callback) {
|
|
6396
|
+
this.subscribers.add(callback);
|
|
6397
|
+
return () => this.subscribers.delete(callback);
|
|
6239
6398
|
}
|
|
6240
6399
|
/**
|
|
6241
|
-
*
|
|
6400
|
+
* Check if watcher is running
|
|
6242
6401
|
*/
|
|
6243
|
-
|
|
6244
|
-
|
|
6245
|
-
const regex = new RegExp(`^${regexPattern}$`);
|
|
6246
|
-
return regex.test(filePath);
|
|
6402
|
+
isActive() {
|
|
6403
|
+
return this.isRunning;
|
|
6247
6404
|
}
|
|
6248
6405
|
/**
|
|
6249
|
-
*
|
|
6406
|
+
* Get watcher status
|
|
6407
|
+
*/
|
|
6408
|
+
getStatus() {
|
|
6409
|
+
return {
|
|
6410
|
+
sessionId: this.sessionId,
|
|
6411
|
+
watchPath: this.watchPath,
|
|
6412
|
+
isRunning: this.isRunning,
|
|
6413
|
+
startedAt: this.startedAt,
|
|
6414
|
+
lastHeartbeat: this.lastHeartbeat
|
|
6415
|
+
};
|
|
6416
|
+
}
|
|
6417
|
+
/**
|
|
6418
|
+
* Emit event to all subscribers
|
|
6250
6419
|
*/
|
|
6251
6420
|
async emitEvent(event) {
|
|
6252
6421
|
for (const callback of this.subscribers) {
|
|
6253
6422
|
try {
|
|
6254
6423
|
await callback(event);
|
|
6255
6424
|
} catch (error) {
|
|
6256
|
-
console.error("[
|
|
6425
|
+
console.error("[IN_SANDBOX_WATCHER] Error in subscriber callback:", error);
|
|
6257
6426
|
}
|
|
6258
6427
|
}
|
|
6259
6428
|
}
|
|
6260
6429
|
};
|
|
6261
|
-
|
|
6430
|
+
InSandboxWatcherManager = class {
|
|
6262
6431
|
watchers = /* @__PURE__ */ new Map();
|
|
6263
6432
|
/**
|
|
6264
|
-
* Start watching a
|
|
6433
|
+
* Start watching a sandbox
|
|
6265
6434
|
*/
|
|
6266
6435
|
async startWatching(options) {
|
|
6267
6436
|
const { sessionId } = options;
|
|
6268
|
-
|
|
6269
|
-
|
|
6270
|
-
await existing.stop();
|
|
6271
|
-
}
|
|
6272
|
-
const watcher = new RemoteSandboxFileWatcher(options);
|
|
6437
|
+
await this.stopWatching(sessionId);
|
|
6438
|
+
const watcher = new InSandboxWatcher(options);
|
|
6273
6439
|
await watcher.start();
|
|
6274
6440
|
this.watchers.set(sessionId, watcher);
|
|
6275
6441
|
return watcher;
|
|
@@ -6285,17 +6451,16 @@ var init_sandbox_file_watcher = __esm({
|
|
|
6285
6451
|
}
|
|
6286
6452
|
}
|
|
6287
6453
|
/**
|
|
6288
|
-
* Get
|
|
6454
|
+
* Get watcher for a session
|
|
6289
6455
|
*/
|
|
6290
6456
|
getWatcher(sessionId) {
|
|
6291
6457
|
return this.watchers.get(sessionId);
|
|
6292
6458
|
}
|
|
6293
6459
|
/**
|
|
6294
|
-
* Check if
|
|
6460
|
+
* Check if watching
|
|
6295
6461
|
*/
|
|
6296
6462
|
isWatching(sessionId) {
|
|
6297
|
-
|
|
6298
|
-
return watcher?.isActive() ?? false;
|
|
6463
|
+
return this.watchers.get(sessionId)?.isActive() ?? false;
|
|
6299
6464
|
}
|
|
6300
6465
|
/**
|
|
6301
6466
|
* Stop all watchers
|
|
@@ -6306,7 +6471,7 @@ var init_sandbox_file_watcher = __esm({
|
|
|
6306
6471
|
this.watchers.clear();
|
|
6307
6472
|
}
|
|
6308
6473
|
};
|
|
6309
|
-
|
|
6474
|
+
globalInSandboxManager = null;
|
|
6310
6475
|
}
|
|
6311
6476
|
});
|
|
6312
6477
|
function extractErrorMessage(error) {
|
|
@@ -6355,6 +6520,7 @@ var SandboxFileSync;
|
|
|
6355
6520
|
var init_sandbox_file_sync = __esm({
|
|
6356
6521
|
"src/runtime/sandbox-file-sync.ts"() {
|
|
6357
6522
|
init_sandbox_file_watcher();
|
|
6523
|
+
init_in_sandbox_watcher();
|
|
6358
6524
|
init_types();
|
|
6359
6525
|
SandboxFileSync = class {
|
|
6360
6526
|
fileStore;
|
|
@@ -6365,7 +6531,7 @@ var init_sandbox_file_sync = __esm({
|
|
|
6365
6531
|
eventStorage;
|
|
6366
6532
|
webhookConfig;
|
|
6367
6533
|
// Watcher management
|
|
6368
|
-
|
|
6534
|
+
inSandboxWatchers = /* @__PURE__ */ new Map();
|
|
6369
6535
|
localWatchers = /* @__PURE__ */ new Map();
|
|
6370
6536
|
fileChangeSubscribers = /* @__PURE__ */ new Set();
|
|
6371
6537
|
// Sequence number cache per session (for event storage)
|
|
@@ -7156,34 +7322,27 @@ var init_sandbox_file_sync = __esm({
|
|
|
7156
7322
|
this.localWatchers.set(sessionId, watcher);
|
|
7157
7323
|
console.log(`[FILE_SYNC] Started local file watching for session ${sessionId} at ${opts.localPath}`);
|
|
7158
7324
|
} else {
|
|
7159
|
-
|
|
7160
|
-
throw new Error("Sandbox operations not configured. Call setSandboxOperations first.");
|
|
7161
|
-
}
|
|
7162
|
-
const watcher = new RemoteSandboxFileWatcher({
|
|
7325
|
+
const watcher = new InSandboxWatcher({
|
|
7163
7326
|
sessionId,
|
|
7164
|
-
|
|
7165
|
-
basePath: watchPath,
|
|
7166
|
-
// Use watchPath instead of sandboxBasePath
|
|
7167
|
-
pollIntervalMs: opts.pollIntervalMs ?? 2e3,
|
|
7168
|
-
ignored: opts.ignored ?? ["**/node_modules/**", "**/.git/**"],
|
|
7327
|
+
watchPath,
|
|
7169
7328
|
onFileChange: handleFileChange,
|
|
7170
7329
|
onError: (error) => {
|
|
7171
|
-
console.error(`[FILE_SYNC]
|
|
7330
|
+
console.error(`[FILE_SYNC] In-sandbox watcher error for session ${sessionId}:`, error);
|
|
7172
7331
|
}
|
|
7173
7332
|
});
|
|
7174
7333
|
await watcher.start();
|
|
7175
|
-
this.
|
|
7176
|
-
console.log(`[FILE_SYNC] Started
|
|
7334
|
+
this.inSandboxWatchers.set(sessionId, watcher);
|
|
7335
|
+
console.log(`[FILE_SYNC] Started in-sandbox file watching for session ${sessionId} at path: ${watchPath}`);
|
|
7177
7336
|
}
|
|
7178
7337
|
}
|
|
7179
7338
|
/**
|
|
7180
7339
|
* Stop watching a session's sandbox
|
|
7181
7340
|
*/
|
|
7182
7341
|
async stopWatching(sessionId) {
|
|
7183
|
-
const
|
|
7184
|
-
if (
|
|
7185
|
-
await
|
|
7186
|
-
this.
|
|
7342
|
+
const inSandboxWatcher = this.inSandboxWatchers.get(sessionId);
|
|
7343
|
+
if (inSandboxWatcher) {
|
|
7344
|
+
await inSandboxWatcher.stop();
|
|
7345
|
+
this.inSandboxWatchers.delete(sessionId);
|
|
7187
7346
|
}
|
|
7188
7347
|
const localWatcher = this.localWatchers.get(sessionId);
|
|
7189
7348
|
if (localWatcher) {
|
|
@@ -7195,7 +7354,7 @@ var init_sandbox_file_sync = __esm({
|
|
|
7195
7354
|
* Check if a session is being watched
|
|
7196
7355
|
*/
|
|
7197
7356
|
isWatching(sessionId) {
|
|
7198
|
-
return this.
|
|
7357
|
+
return this.inSandboxWatchers.has(sessionId) || this.localWatchers.has(sessionId);
|
|
7199
7358
|
}
|
|
7200
7359
|
/**
|
|
7201
7360
|
* Subscribe to file change events across all watched sessions.
|
|
@@ -7229,10 +7388,10 @@ var init_sandbox_file_sync = __esm({
|
|
|
7229
7388
|
* Stop all watchers and cleanup
|
|
7230
7389
|
*/
|
|
7231
7390
|
async stopAllWatching() {
|
|
7232
|
-
const
|
|
7391
|
+
const inSandboxPromises = Array.from(this.inSandboxWatchers.values()).map((w) => w.stop());
|
|
7233
7392
|
const localPromises = Array.from(this.localWatchers.values()).map((w) => w.stop());
|
|
7234
|
-
await Promise.all([...
|
|
7235
|
-
this.
|
|
7393
|
+
await Promise.all([...inSandboxPromises, ...localPromises]);
|
|
7394
|
+
this.inSandboxWatchers.clear();
|
|
7236
7395
|
this.localWatchers.clear();
|
|
7237
7396
|
}
|
|
7238
7397
|
/**
|
|
@@ -7240,8 +7399,8 @@ var init_sandbox_file_sync = __esm({
|
|
|
7240
7399
|
*/
|
|
7241
7400
|
getWatchingStatus() {
|
|
7242
7401
|
const statuses = [];
|
|
7243
|
-
for (const [sessionId, watcher] of this.
|
|
7244
|
-
statuses.push({ sessionId, type: "
|
|
7402
|
+
for (const [sessionId, watcher] of this.inSandboxWatchers) {
|
|
7403
|
+
statuses.push({ sessionId, type: "in-sandbox", isActive: watcher.isActive() });
|
|
7245
7404
|
}
|
|
7246
7405
|
for (const [sessionId, watcher] of this.localWatchers) {
|
|
7247
7406
|
statuses.push({ sessionId, type: "local", isActive: watcher.isActive() });
|
|
@@ -7252,364 +7411,6 @@ var init_sandbox_file_sync = __esm({
|
|
|
7252
7411
|
}
|
|
7253
7412
|
});
|
|
7254
7413
|
|
|
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
7414
|
// src/runtime/index.ts
|
|
7614
7415
|
function generateDockerCommand(config) {
|
|
7615
7416
|
const args = ["docker", "run"];
|
|
@@ -18990,6 +18791,6 @@ var init_src = __esm({
|
|
|
18990
18791
|
});
|
|
18991
18792
|
init_src();
|
|
18992
18793
|
|
|
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,
|
|
18794
|
+
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
18795
|
//# sourceMappingURL=index.js.map
|
|
18995
18796
|
//# sourceMappingURL=index.js.map
|