agent-web-os 0.3.4 → 0.4.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser-bash-session-kzgy0g4v.d.cts +122 -0
- package/dist/browser-bash-session-kzgy0g4v.d.ts +122 -0
- package/dist/chunk-THD7G37K.js +1028 -0
- package/dist/chunk-THD7G37K.js.map +1 -0
- package/dist/index.cjs +34202 -75108
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +5 -143
- package/dist/index.d.ts +5 -143
- package/dist/index.js +9 -950
- package/dist/index.js.map +1 -1
- package/dist/node.cjs +78690 -0
- package/dist/node.cjs.map +1 -0
- package/dist/node.d.cts +34 -0
- package/dist/node.d.ts +34 -0
- package/dist/{almostnode-session-2FPETBKJ.js → node.js} +62 -5
- package/dist/node.js.map +1 -0
- package/package.json +7 -2
- package/dist/almostnode-session-2FPETBKJ.js.map +0 -1
- package/dist/chunk-FNHNA3XU.js +0 -90
- package/dist/chunk-FNHNA3XU.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,958 +1,19 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
DEFAULT_BASH_SHELL_ENV,
|
|
3
|
+
ObservableInMemoryFs,
|
|
4
|
+
assertObservableInMemoryFs,
|
|
5
|
+
createBrowserBashSession,
|
|
6
|
+
executeBrowserBash,
|
|
7
|
+
executeFd
|
|
8
|
+
} from "./chunk-THD7G37K.js";
|
|
6
9
|
import {
|
|
7
10
|
Dx,
|
|
8
|
-
Ir,
|
|
9
11
|
Ju
|
|
10
12
|
} from "./chunk-JTZ3QUCT.js";
|
|
11
13
|
import "./chunk-PR4QN5HX.js";
|
|
12
14
|
|
|
13
|
-
// src/observable-in-memory-fs.ts
|
|
14
|
-
function isObservableInMemoryFsLike(value) {
|
|
15
|
-
if (!value || typeof value !== "object") {
|
|
16
|
-
return false;
|
|
17
|
-
}
|
|
18
|
-
const candidate = value;
|
|
19
|
-
return typeof candidate.subscribe === "function" && typeof candidate.exists === "function" && typeof candidate.readFile === "function" && typeof candidate.readdir === "function" && typeof candidate.stat === "function";
|
|
20
|
-
}
|
|
21
|
-
function assertObservableInMemoryFs(value) {
|
|
22
|
-
if (!isObservableInMemoryFsLike(value)) {
|
|
23
|
-
throw new Error("Expected ObservableInMemoryFs-backed just-bash filesystem");
|
|
24
|
-
}
|
|
25
|
-
return value;
|
|
26
|
-
}
|
|
27
|
-
async function readPathState(fs, path) {
|
|
28
|
-
const exists = await fs.exists(path);
|
|
29
|
-
if (!exists) {
|
|
30
|
-
return { exists: false };
|
|
31
|
-
}
|
|
32
|
-
if (isObservableInMemoryFsLike(fs) && fs.isPathLazy(path)) {
|
|
33
|
-
return {
|
|
34
|
-
exists: true,
|
|
35
|
-
entryType: "file"
|
|
36
|
-
};
|
|
37
|
-
}
|
|
38
|
-
try {
|
|
39
|
-
const stat = await fs.lstat(path);
|
|
40
|
-
const entryType = stat.isDirectory ? "directory" : stat.isSymbolicLink ? "symlink" : "file";
|
|
41
|
-
return {
|
|
42
|
-
exists: true,
|
|
43
|
-
entryType
|
|
44
|
-
};
|
|
45
|
-
} catch {
|
|
46
|
-
return { exists: false };
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
function mapAddEvent(entryType) {
|
|
50
|
-
return entryType === "directory" ? "addDir" : "add";
|
|
51
|
-
}
|
|
52
|
-
function normalizeFsPathForLogScope(fsPath) {
|
|
53
|
-
const normalized = posixPath.normalize(fsPath);
|
|
54
|
-
return normalized === "." ? "/" : normalized;
|
|
55
|
-
}
|
|
56
|
-
var ObservableInMemoryFs = class extends Ir {
|
|
57
|
-
listeners;
|
|
58
|
-
lazyPaths = /* @__PURE__ */ new Set();
|
|
59
|
-
suppressSyncEventCount = 0;
|
|
60
|
-
suppressConsoleLogCount = 0;
|
|
61
|
-
suppressChangeEmissionCount = 0;
|
|
62
|
-
consoleLogChanges;
|
|
63
|
-
isLoggableWorkspacePath;
|
|
64
|
-
constructor(options) {
|
|
65
|
-
super();
|
|
66
|
-
this.consoleLogChanges = options?.consoleLogChanges ?? false;
|
|
67
|
-
const normalizedWorkspaceRoot = normalizeFsPathForLogScope(options?.workspaceRoot ?? "/");
|
|
68
|
-
this.isLoggableWorkspacePath = (fsPath) => {
|
|
69
|
-
const normalizedPath = normalizeFsPathForLogScope(fsPath);
|
|
70
|
-
if (normalizedPath !== normalizedWorkspaceRoot && !normalizedPath.startsWith(`${normalizedWorkspaceRoot}/`)) {
|
|
71
|
-
return false;
|
|
72
|
-
}
|
|
73
|
-
const relativePath = posixPath.relative(normalizedWorkspaceRoot, normalizedPath);
|
|
74
|
-
if (!relativePath || relativePath === ".") {
|
|
75
|
-
return true;
|
|
76
|
-
}
|
|
77
|
-
return relativePath.split("/").every((segment) => segment.length > 0 && !segment.startsWith("."));
|
|
78
|
-
};
|
|
79
|
-
}
|
|
80
|
-
isPathLazy(filePath) {
|
|
81
|
-
return this.lazyPaths.has(normalizeFsPathForLogScope(filePath));
|
|
82
|
-
}
|
|
83
|
-
clearLazyPath(filePath) {
|
|
84
|
-
this.lazyPaths.delete(normalizeFsPathForLogScope(filePath));
|
|
85
|
-
}
|
|
86
|
-
clearLazyPathsUnder(rootPath) {
|
|
87
|
-
const normalizedRootPath = normalizeFsPathForLogScope(rootPath);
|
|
88
|
-
for (const filePath of Array.from(this.lazyPaths)) {
|
|
89
|
-
if (filePath === normalizedRootPath || filePath.startsWith(`${normalizedRootPath}/`)) {
|
|
90
|
-
this.lazyPaths.delete(filePath);
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
subscribe(listener) {
|
|
95
|
-
const listeners = this.listeners ??= /* @__PURE__ */ new Set();
|
|
96
|
-
listeners.add(listener);
|
|
97
|
-
return () => {
|
|
98
|
-
listeners.delete(listener);
|
|
99
|
-
if (listeners.size === 0 && this.listeners === listeners) {
|
|
100
|
-
this.listeners = void 0;
|
|
101
|
-
}
|
|
102
|
-
};
|
|
103
|
-
}
|
|
104
|
-
shouldEmitChanges() {
|
|
105
|
-
if (this.suppressChangeEmissionCount > 0) {
|
|
106
|
-
return false;
|
|
107
|
-
}
|
|
108
|
-
return this.consoleLogChanges || (this.listeners?.size ?? 0) > 0;
|
|
109
|
-
}
|
|
110
|
-
async suppressObservability(operation) {
|
|
111
|
-
this.suppressChangeEmissionCount += 1;
|
|
112
|
-
this.suppressSyncEventCount += 1;
|
|
113
|
-
this.suppressConsoleLogCount += 1;
|
|
114
|
-
try {
|
|
115
|
-
return await operation();
|
|
116
|
-
} finally {
|
|
117
|
-
this.suppressConsoleLogCount -= 1;
|
|
118
|
-
this.suppressSyncEventCount -= 1;
|
|
119
|
-
this.suppressChangeEmissionCount -= 1;
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
queueChangeEmission(emission) {
|
|
123
|
-
void emission.catch((error) => {
|
|
124
|
-
console.error("[ObservableInMemoryFs] Failed to emit change event", error);
|
|
125
|
-
});
|
|
126
|
-
}
|
|
127
|
-
areConsoleLogsSuppressed() {
|
|
128
|
-
return this.suppressConsoleLogCount > 0;
|
|
129
|
-
}
|
|
130
|
-
async runWithSuppressedConsoleLogs(operation) {
|
|
131
|
-
this.suppressConsoleLogCount += 1;
|
|
132
|
-
try {
|
|
133
|
-
return await operation();
|
|
134
|
-
} finally {
|
|
135
|
-
this.suppressConsoleLogCount -= 1;
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
shouldConsoleLogChangeEvent(event) {
|
|
139
|
-
if (!this.isLoggableWorkspacePath(event.path)) {
|
|
140
|
-
return false;
|
|
141
|
-
}
|
|
142
|
-
if (event.previousPath && !this.isLoggableWorkspacePath(event.previousPath)) {
|
|
143
|
-
return false;
|
|
144
|
-
}
|
|
145
|
-
return true;
|
|
146
|
-
}
|
|
147
|
-
emit(event, options) {
|
|
148
|
-
const shouldConsoleLog = options?.shouldConsoleLog ?? this.shouldConsoleLogChangeEvent(event);
|
|
149
|
-
if (this.consoleLogChanges && shouldConsoleLog && !this.areConsoleLogsSuppressed()) {
|
|
150
|
-
console.log(`[ObservableInMemoryFs] ${event.event} ${event.entryType} ${event.path}${event.previousPath ? ` (from ${event.previousPath})` : ""}`);
|
|
151
|
-
}
|
|
152
|
-
if (!this.listeners) {
|
|
153
|
-
return;
|
|
154
|
-
}
|
|
155
|
-
for (const listener of this.listeners) {
|
|
156
|
-
try {
|
|
157
|
-
listener(event);
|
|
158
|
-
} catch (error) {
|
|
159
|
-
console.error("[ObservableInMemoryFs] Change listener failed", error);
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
areSyncEventsSuppressed() {
|
|
164
|
-
return this.suppressSyncEventCount > 0;
|
|
165
|
-
}
|
|
166
|
-
async runWithSuppressedSyncEvents(operation) {
|
|
167
|
-
this.suppressSyncEventCount += 1;
|
|
168
|
-
try {
|
|
169
|
-
return await operation();
|
|
170
|
-
} finally {
|
|
171
|
-
this.suppressSyncEventCount -= 1;
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
writeFileSync(path, content, options, metadata) {
|
|
175
|
-
const previous = this.areSyncEventsSuppressed() || !this.shouldEmitChanges() ? null : readPathState(this, path);
|
|
176
|
-
super.writeFileSync(path, content, options, metadata);
|
|
177
|
-
this.clearLazyPath(path);
|
|
178
|
-
if (!previous) {
|
|
179
|
-
return;
|
|
180
|
-
}
|
|
181
|
-
this.queueChangeEmission(previous.then((state) => this.emitWriteEvent(path, state)));
|
|
182
|
-
}
|
|
183
|
-
writeFileLazy(path, lazy, metadata) {
|
|
184
|
-
const previous = this.areSyncEventsSuppressed() || !this.shouldEmitChanges() ? null : readPathState(this, path);
|
|
185
|
-
super.writeFileLazy(path, lazy, metadata);
|
|
186
|
-
this.lazyPaths.add(normalizeFsPathForLogScope(path));
|
|
187
|
-
if (!previous) {
|
|
188
|
-
return;
|
|
189
|
-
}
|
|
190
|
-
this.queueChangeEmission(previous.then((state) => this.emitWriteEvent(path, state)));
|
|
191
|
-
}
|
|
192
|
-
async emitWriteEvent(path, previous) {
|
|
193
|
-
const current = await readPathState(this, path);
|
|
194
|
-
if (!current.exists || !current.entryType) {
|
|
195
|
-
return;
|
|
196
|
-
}
|
|
197
|
-
if (!previous.exists) {
|
|
198
|
-
this.emit({
|
|
199
|
-
event: mapAddEvent(current.entryType),
|
|
200
|
-
path,
|
|
201
|
-
entryType: current.entryType
|
|
202
|
-
});
|
|
203
|
-
return;
|
|
204
|
-
}
|
|
205
|
-
this.emit({
|
|
206
|
-
event: "change",
|
|
207
|
-
path,
|
|
208
|
-
entryType: current.entryType
|
|
209
|
-
});
|
|
210
|
-
}
|
|
211
|
-
async emitMkdirEvent(path, previous) {
|
|
212
|
-
const current = await readPathState(this, path);
|
|
213
|
-
if (!current.exists || current.entryType !== "directory" || previous.exists) {
|
|
214
|
-
return;
|
|
215
|
-
}
|
|
216
|
-
this.emit({
|
|
217
|
-
event: "addDir",
|
|
218
|
-
path,
|
|
219
|
-
entryType: "directory"
|
|
220
|
-
});
|
|
221
|
-
}
|
|
222
|
-
emitRemovalEvent(path, previous, options) {
|
|
223
|
-
if (!previous.exists || !previous.entryType) {
|
|
224
|
-
return;
|
|
225
|
-
}
|
|
226
|
-
this.emit({
|
|
227
|
-
event: previous.entryType === "directory" ? "unlinkDir" : "unlink",
|
|
228
|
-
path,
|
|
229
|
-
entryType: previous.entryType
|
|
230
|
-
}, options);
|
|
231
|
-
}
|
|
232
|
-
mkdirSync(path, options) {
|
|
233
|
-
const previous = this.areSyncEventsSuppressed() || !this.shouldEmitChanges() ? null : readPathState(this, path);
|
|
234
|
-
super.mkdirSync(path, options);
|
|
235
|
-
if (!previous) {
|
|
236
|
-
return;
|
|
237
|
-
}
|
|
238
|
-
this.queueChangeEmission(previous.then((state) => this.emitMkdirEvent(path, state)));
|
|
239
|
-
}
|
|
240
|
-
async readFileBuffer(path) {
|
|
241
|
-
const content = await super.readFileBuffer(path);
|
|
242
|
-
this.clearLazyPath(path);
|
|
243
|
-
return content;
|
|
244
|
-
}
|
|
245
|
-
async stat(path) {
|
|
246
|
-
const stat = await super.stat(path);
|
|
247
|
-
this.clearLazyPath(path);
|
|
248
|
-
return stat;
|
|
249
|
-
}
|
|
250
|
-
async lstat(path) {
|
|
251
|
-
const stat = await super.lstat(path);
|
|
252
|
-
this.clearLazyPath(path);
|
|
253
|
-
return stat;
|
|
254
|
-
}
|
|
255
|
-
async writeFile(path, content, options) {
|
|
256
|
-
if (!this.shouldEmitChanges()) {
|
|
257
|
-
await super.writeFile(path, content, options);
|
|
258
|
-
return;
|
|
259
|
-
}
|
|
260
|
-
const previous = await readPathState(this, path);
|
|
261
|
-
await this.runWithSuppressedSyncEvents(() => super.writeFile(path, content, options));
|
|
262
|
-
await this.emitWriteEvent(path, previous);
|
|
263
|
-
}
|
|
264
|
-
async appendFile(path, content, options) {
|
|
265
|
-
if (!this.shouldEmitChanges()) {
|
|
266
|
-
await super.appendFile(path, content, options);
|
|
267
|
-
return;
|
|
268
|
-
}
|
|
269
|
-
const previous = await readPathState(this, path);
|
|
270
|
-
await this.runWithSuppressedSyncEvents(() => super.appendFile(path, content, options));
|
|
271
|
-
await this.emitWriteEvent(path, previous);
|
|
272
|
-
}
|
|
273
|
-
async mkdir(path, options) {
|
|
274
|
-
if (!this.shouldEmitChanges()) {
|
|
275
|
-
await super.mkdir(path, options);
|
|
276
|
-
return;
|
|
277
|
-
}
|
|
278
|
-
const previous = await readPathState(this, path);
|
|
279
|
-
await this.runWithSuppressedSyncEvents(() => super.mkdir(path, options));
|
|
280
|
-
await this.emitMkdirEvent(path, previous);
|
|
281
|
-
}
|
|
282
|
-
async rm(path, options) {
|
|
283
|
-
if (!this.shouldEmitChanges()) {
|
|
284
|
-
await super.rm(path, options);
|
|
285
|
-
this.clearLazyPathsUnder(path);
|
|
286
|
-
return;
|
|
287
|
-
}
|
|
288
|
-
const previous = await readPathState(this, path);
|
|
289
|
-
await super.rm(path, options);
|
|
290
|
-
this.clearLazyPathsUnder(path);
|
|
291
|
-
this.emitRemovalEvent(path, previous);
|
|
292
|
-
}
|
|
293
|
-
async cp(src, dest, options) {
|
|
294
|
-
if (!this.shouldEmitChanges()) {
|
|
295
|
-
await super.cp(src, dest, options);
|
|
296
|
-
this.clearLazyPathsUnder(dest);
|
|
297
|
-
return;
|
|
298
|
-
}
|
|
299
|
-
const previous = await readPathState(this, dest);
|
|
300
|
-
await super.cp(src, dest, options);
|
|
301
|
-
this.clearLazyPathsUnder(dest);
|
|
302
|
-
const current = await readPathState(this, dest);
|
|
303
|
-
if (!current.exists || !current.entryType) {
|
|
304
|
-
return;
|
|
305
|
-
}
|
|
306
|
-
this.emit({
|
|
307
|
-
event: previous.exists ? "change" : mapAddEvent(current.entryType),
|
|
308
|
-
path: dest,
|
|
309
|
-
entryType: current.entryType
|
|
310
|
-
});
|
|
311
|
-
}
|
|
312
|
-
async mv(src, dest) {
|
|
313
|
-
if (!this.shouldEmitChanges()) {
|
|
314
|
-
await super.mv(src, dest);
|
|
315
|
-
const normalizedSourcePath2 = normalizeFsPathForLogScope(src);
|
|
316
|
-
const normalizedDestinationPath2 = normalizeFsPathForLogScope(dest);
|
|
317
|
-
this.clearLazyPathsUnder(normalizedDestinationPath2);
|
|
318
|
-
for (const filePath of Array.from(this.lazyPaths)) {
|
|
319
|
-
if (filePath === normalizedSourcePath2 || filePath.startsWith(`${normalizedSourcePath2}/`)) {
|
|
320
|
-
this.lazyPaths.delete(filePath);
|
|
321
|
-
this.lazyPaths.add(`${normalizedDestinationPath2}${filePath.slice(normalizedSourcePath2.length)}`);
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
|
-
return;
|
|
325
|
-
}
|
|
326
|
-
const sourceState = await readPathState(this, src);
|
|
327
|
-
const destinationState = await readPathState(this, dest);
|
|
328
|
-
const shouldConsoleLogMove = this.shouldConsoleLogChangeEvent({
|
|
329
|
-
event: destinationState.exists ? "change" : mapAddEvent(sourceState.entryType ?? "file"),
|
|
330
|
-
path: dest,
|
|
331
|
-
previousPath: src,
|
|
332
|
-
entryType: sourceState.entryType ?? "file"
|
|
333
|
-
});
|
|
334
|
-
if (shouldConsoleLogMove) {
|
|
335
|
-
await super.mv(src, dest);
|
|
336
|
-
} else {
|
|
337
|
-
await this.runWithSuppressedConsoleLogs(() => super.mv(src, dest));
|
|
338
|
-
}
|
|
339
|
-
const normalizedSourcePath = normalizeFsPathForLogScope(src);
|
|
340
|
-
const normalizedDestinationPath = normalizeFsPathForLogScope(dest);
|
|
341
|
-
this.clearLazyPathsUnder(normalizedDestinationPath);
|
|
342
|
-
for (const filePath of Array.from(this.lazyPaths)) {
|
|
343
|
-
if (filePath === normalizedSourcePath || filePath.startsWith(`${normalizedSourcePath}/`)) {
|
|
344
|
-
this.lazyPaths.delete(filePath);
|
|
345
|
-
this.lazyPaths.add(`${normalizedDestinationPath}${filePath.slice(normalizedSourcePath.length)}`);
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
this.emitRemovalEvent(src, sourceState, {
|
|
349
|
-
shouldConsoleLog: shouldConsoleLogMove
|
|
350
|
-
});
|
|
351
|
-
const currentDestinationState = await readPathState(this, dest);
|
|
352
|
-
if (!currentDestinationState.exists || !currentDestinationState.entryType) {
|
|
353
|
-
return;
|
|
354
|
-
}
|
|
355
|
-
this.emit({
|
|
356
|
-
event: destinationState.exists ? "change" : mapAddEvent(currentDestinationState.entryType),
|
|
357
|
-
path: dest,
|
|
358
|
-
previousPath: src,
|
|
359
|
-
entryType: currentDestinationState.entryType
|
|
360
|
-
}, {
|
|
361
|
-
shouldConsoleLog: shouldConsoleLogMove
|
|
362
|
-
});
|
|
363
|
-
}
|
|
364
|
-
async chmod(path, mode) {
|
|
365
|
-
if (!this.shouldEmitChanges()) {
|
|
366
|
-
await super.chmod(path, mode);
|
|
367
|
-
return;
|
|
368
|
-
}
|
|
369
|
-
await super.chmod(path, mode);
|
|
370
|
-
const current = await readPathState(this, path);
|
|
371
|
-
if (!current.exists || !current.entryType) {
|
|
372
|
-
return;
|
|
373
|
-
}
|
|
374
|
-
this.emit({
|
|
375
|
-
event: "change",
|
|
376
|
-
path,
|
|
377
|
-
entryType: current.entryType
|
|
378
|
-
});
|
|
379
|
-
}
|
|
380
|
-
async symlink(target, linkPath) {
|
|
381
|
-
if (!this.shouldEmitChanges()) {
|
|
382
|
-
await super.symlink(target, linkPath);
|
|
383
|
-
return;
|
|
384
|
-
}
|
|
385
|
-
const previous = await readPathState(this, linkPath);
|
|
386
|
-
await super.symlink(target, linkPath);
|
|
387
|
-
await this.emitWriteEvent(linkPath, previous);
|
|
388
|
-
}
|
|
389
|
-
async link(existingPath, newPath) {
|
|
390
|
-
if (!this.shouldEmitChanges()) {
|
|
391
|
-
await super.link(existingPath, newPath);
|
|
392
|
-
return;
|
|
393
|
-
}
|
|
394
|
-
const previous = await readPathState(this, newPath);
|
|
395
|
-
await super.link(existingPath, newPath);
|
|
396
|
-
await this.emitWriteEvent(newPath, previous);
|
|
397
|
-
}
|
|
398
|
-
async utimes(path, atime, mtime) {
|
|
399
|
-
if (!this.shouldEmitChanges()) {
|
|
400
|
-
await super.utimes(path, atime, mtime);
|
|
401
|
-
return;
|
|
402
|
-
}
|
|
403
|
-
await super.utimes(path, atime, mtime);
|
|
404
|
-
const current = await readPathState(this, path);
|
|
405
|
-
if (!current.exists || !current.entryType) {
|
|
406
|
-
return;
|
|
407
|
-
}
|
|
408
|
-
this.emit({
|
|
409
|
-
event: "change",
|
|
410
|
-
path,
|
|
411
|
-
entryType: current.entryType
|
|
412
|
-
});
|
|
413
|
-
}
|
|
414
|
-
};
|
|
415
|
-
|
|
416
|
-
// src/fd-command.ts
|
|
417
|
-
function parseFdArgs(args) {
|
|
418
|
-
const opts = {
|
|
419
|
-
glob: false,
|
|
420
|
-
fixedStrings: false,
|
|
421
|
-
hidden: false,
|
|
422
|
-
noIgnore: false,
|
|
423
|
-
typeFilter: null,
|
|
424
|
-
extensions: [],
|
|
425
|
-
excludes: [],
|
|
426
|
-
maxDepth: Infinity,
|
|
427
|
-
maxResults: Infinity,
|
|
428
|
-
ignoreFiles: [],
|
|
429
|
-
absolutePath: false,
|
|
430
|
-
fullPath: false,
|
|
431
|
-
pattern: "",
|
|
432
|
-
searchPaths: []
|
|
433
|
-
};
|
|
434
|
-
const positional = [];
|
|
435
|
-
let i = 0;
|
|
436
|
-
while (i < args.length) {
|
|
437
|
-
const arg = args[i];
|
|
438
|
-
if (arg === "--") {
|
|
439
|
-
positional.push(...args.slice(i + 1));
|
|
440
|
-
break;
|
|
441
|
-
}
|
|
442
|
-
if (arg === "--glob" || arg === "-g") {
|
|
443
|
-
opts.glob = true;
|
|
444
|
-
i++;
|
|
445
|
-
continue;
|
|
446
|
-
}
|
|
447
|
-
if (arg === "--fixed-strings" || arg === "-F") {
|
|
448
|
-
opts.fixedStrings = true;
|
|
449
|
-
i++;
|
|
450
|
-
continue;
|
|
451
|
-
}
|
|
452
|
-
if (arg === "--hidden" || arg === "-H") {
|
|
453
|
-
opts.hidden = true;
|
|
454
|
-
i++;
|
|
455
|
-
continue;
|
|
456
|
-
}
|
|
457
|
-
if (arg === "--no-ignore" || arg === "-I") {
|
|
458
|
-
opts.noIgnore = true;
|
|
459
|
-
i++;
|
|
460
|
-
continue;
|
|
461
|
-
}
|
|
462
|
-
if (arg === "--absolute-path" || arg === "-a") {
|
|
463
|
-
opts.absolutePath = true;
|
|
464
|
-
i++;
|
|
465
|
-
continue;
|
|
466
|
-
}
|
|
467
|
-
if (arg === "--full-path" || arg === "-p") {
|
|
468
|
-
opts.fullPath = true;
|
|
469
|
-
i++;
|
|
470
|
-
continue;
|
|
471
|
-
}
|
|
472
|
-
if (arg === "-1") {
|
|
473
|
-
opts.maxResults = 1;
|
|
474
|
-
i++;
|
|
475
|
-
continue;
|
|
476
|
-
}
|
|
477
|
-
if (arg === "--type" || arg === "-t") {
|
|
478
|
-
const val = args[++i];
|
|
479
|
-
if (val === "f" || val === "file") opts.typeFilter = "f";
|
|
480
|
-
else if (val === "d" || val === "dir" || val === "directory") opts.typeFilter = "d";
|
|
481
|
-
i++;
|
|
482
|
-
continue;
|
|
483
|
-
}
|
|
484
|
-
if (arg === "--extension" || arg === "-e") {
|
|
485
|
-
const ext = args[++i];
|
|
486
|
-
if (ext) opts.extensions.push(ext.startsWith(".") ? ext.slice(1) : ext);
|
|
487
|
-
i++;
|
|
488
|
-
continue;
|
|
489
|
-
}
|
|
490
|
-
if (arg === "--exclude" || arg === "-E") {
|
|
491
|
-
const pat = args[++i];
|
|
492
|
-
if (pat) opts.excludes.push(pat);
|
|
493
|
-
i++;
|
|
494
|
-
continue;
|
|
495
|
-
}
|
|
496
|
-
if (arg === "--max-depth" || arg === "-d") {
|
|
497
|
-
const n = Number.parseInt(args[++i] ?? "", 10);
|
|
498
|
-
if (!Number.isNaN(n)) opts.maxDepth = n;
|
|
499
|
-
i++;
|
|
500
|
-
continue;
|
|
501
|
-
}
|
|
502
|
-
if (arg === "--max-results") {
|
|
503
|
-
const n = Number.parseInt(args[++i] ?? "", 10);
|
|
504
|
-
if (!Number.isNaN(n)) opts.maxResults = n;
|
|
505
|
-
i++;
|
|
506
|
-
continue;
|
|
507
|
-
}
|
|
508
|
-
if (arg === "--ignore-file") {
|
|
509
|
-
const p = args[++i];
|
|
510
|
-
if (p) opts.ignoreFiles.push(p);
|
|
511
|
-
i++;
|
|
512
|
-
continue;
|
|
513
|
-
}
|
|
514
|
-
if (arg === "--color" || arg === "--colour") {
|
|
515
|
-
i += 2;
|
|
516
|
-
continue;
|
|
517
|
-
}
|
|
518
|
-
if (arg.startsWith("--color=") || arg.startsWith("--colour=")) {
|
|
519
|
-
i++;
|
|
520
|
-
continue;
|
|
521
|
-
}
|
|
522
|
-
if (arg === "-L" || arg === "--follow") {
|
|
523
|
-
i++;
|
|
524
|
-
continue;
|
|
525
|
-
}
|
|
526
|
-
if (arg === "-s" || arg === "--case-sensitive") {
|
|
527
|
-
i++;
|
|
528
|
-
continue;
|
|
529
|
-
}
|
|
530
|
-
if (arg === "-i" || arg === "--ignore-case") {
|
|
531
|
-
i++;
|
|
532
|
-
continue;
|
|
533
|
-
}
|
|
534
|
-
if (arg === "-S" || arg === "--smart-case") {
|
|
535
|
-
i++;
|
|
536
|
-
continue;
|
|
537
|
-
}
|
|
538
|
-
if (arg === "--version" || arg === "-V") {
|
|
539
|
-
return { error: "__version__" };
|
|
540
|
-
}
|
|
541
|
-
if (arg === "--help" || arg === "-h") {
|
|
542
|
-
return { error: "__help__" };
|
|
543
|
-
}
|
|
544
|
-
if (arg.startsWith("-")) {
|
|
545
|
-
return { error: `Unknown flag: ${arg}` };
|
|
546
|
-
}
|
|
547
|
-
positional.push(arg);
|
|
548
|
-
i++;
|
|
549
|
-
}
|
|
550
|
-
if (positional.length > 0) {
|
|
551
|
-
opts.pattern = positional[0];
|
|
552
|
-
opts.searchPaths = positional.slice(1);
|
|
553
|
-
}
|
|
554
|
-
return { options: opts };
|
|
555
|
-
}
|
|
556
|
-
function globToRegex(pattern) {
|
|
557
|
-
let regex = "";
|
|
558
|
-
let i = 0;
|
|
559
|
-
while (i < pattern.length) {
|
|
560
|
-
const ch = pattern[i];
|
|
561
|
-
if (ch === "*") {
|
|
562
|
-
if (pattern[i + 1] === "*") {
|
|
563
|
-
regex += ".*";
|
|
564
|
-
i += 2;
|
|
565
|
-
if (pattern[i] === "/") i++;
|
|
566
|
-
continue;
|
|
567
|
-
}
|
|
568
|
-
regex += "[^/]*";
|
|
569
|
-
} else if (ch === "?") {
|
|
570
|
-
regex += "[^/]";
|
|
571
|
-
} else if (ch === "[") {
|
|
572
|
-
const close = pattern.indexOf("]", i + 1);
|
|
573
|
-
if (close !== -1) {
|
|
574
|
-
regex += pattern.slice(i, close + 1);
|
|
575
|
-
i = close + 1;
|
|
576
|
-
continue;
|
|
577
|
-
}
|
|
578
|
-
regex += "\\[";
|
|
579
|
-
} else if (ch === "{") {
|
|
580
|
-
const close = pattern.indexOf("}", i + 1);
|
|
581
|
-
if (close !== -1) {
|
|
582
|
-
const alternatives = pattern.slice(i + 1, close).split(",").map((a) => a.trim());
|
|
583
|
-
regex += `(?:${alternatives.map(escapeRegex).join("|")})`;
|
|
584
|
-
i = close + 1;
|
|
585
|
-
continue;
|
|
586
|
-
}
|
|
587
|
-
regex += "\\{";
|
|
588
|
-
} else if (".+^$|()\\".includes(ch)) {
|
|
589
|
-
regex += `\\${ch}`;
|
|
590
|
-
} else {
|
|
591
|
-
regex += ch;
|
|
592
|
-
}
|
|
593
|
-
i++;
|
|
594
|
-
}
|
|
595
|
-
return new RegExp(`^${regex}$`, "i");
|
|
596
|
-
}
|
|
597
|
-
function escapeRegex(s) {
|
|
598
|
-
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
599
|
-
}
|
|
600
|
-
async function loadIgnoreFile(fs, filePath) {
|
|
601
|
-
let content;
|
|
602
|
-
try {
|
|
603
|
-
content = await fs.readFile(filePath);
|
|
604
|
-
} catch {
|
|
605
|
-
return [];
|
|
606
|
-
}
|
|
607
|
-
const matchers = [];
|
|
608
|
-
for (const raw of content.split("\n")) {
|
|
609
|
-
const line = raw.trim();
|
|
610
|
-
if (!line || line.startsWith("#")) continue;
|
|
611
|
-
if (line.startsWith("!")) continue;
|
|
612
|
-
let pattern = line;
|
|
613
|
-
const dirOnly = pattern.endsWith("/");
|
|
614
|
-
if (dirOnly) pattern = pattern.slice(0, -1);
|
|
615
|
-
const re = globToRegex(pattern);
|
|
616
|
-
matchers.push((relPath, isDir) => {
|
|
617
|
-
if (dirOnly && !isDir) return false;
|
|
618
|
-
const basename = relPath.split("/").pop() ?? relPath;
|
|
619
|
-
return re.test(basename) || re.test(relPath);
|
|
620
|
-
});
|
|
621
|
-
}
|
|
622
|
-
return matchers;
|
|
623
|
-
}
|
|
624
|
-
function resolvePath(base, rel) {
|
|
625
|
-
const p = rel.startsWith("/") ? rel : `${base}/${rel}`;
|
|
626
|
-
const parts = p.split("/").filter(Boolean);
|
|
627
|
-
const result = [];
|
|
628
|
-
for (const part of parts) {
|
|
629
|
-
if (part === "..") result.pop();
|
|
630
|
-
else if (part !== ".") result.push(part);
|
|
631
|
-
}
|
|
632
|
-
return `/${result.join("/")}`;
|
|
633
|
-
}
|
|
634
|
-
async function executeFd(args, ctx) {
|
|
635
|
-
const parsed = parseFdArgs(args);
|
|
636
|
-
if ("error" in parsed) {
|
|
637
|
-
if (parsed.error === "__version__") {
|
|
638
|
-
return { stdout: "fd 10.2.0 (just-bash)\n", stderr: "", exitCode: 0 };
|
|
639
|
-
}
|
|
640
|
-
if (parsed.error === "__help__") {
|
|
641
|
-
return {
|
|
642
|
-
stdout: [
|
|
643
|
-
"Usage: fd [OPTIONS] [pattern] [path...]",
|
|
644
|
-
"",
|
|
645
|
-
"Options:",
|
|
646
|
-
" -H, --hidden Include hidden files/directories",
|
|
647
|
-
" -I, --no-ignore Don't respect .gitignore",
|
|
648
|
-
" -g, --glob Glob-based search",
|
|
649
|
-
" -F, --fixed-strings Literal string search",
|
|
650
|
-
" -t, --type <type> Filter by type: f(ile), d(irectory)",
|
|
651
|
-
" -e, --extension <ext> Filter by extension",
|
|
652
|
-
" -E, --exclude <pat> Exclude pattern",
|
|
653
|
-
" -d, --max-depth <n> Maximum search depth",
|
|
654
|
-
" --max-results <n> Maximum number of results",
|
|
655
|
-
" -a, --absolute-path Show absolute paths",
|
|
656
|
-
" -p, --full-path Match against full path",
|
|
657
|
-
" --ignore-file <f> Additional ignore file",
|
|
658
|
-
" --color <when> (always off in browser)",
|
|
659
|
-
" -1 Stop after first result",
|
|
660
|
-
""
|
|
661
|
-
].join("\n"),
|
|
662
|
-
stderr: "",
|
|
663
|
-
exitCode: 0
|
|
664
|
-
};
|
|
665
|
-
}
|
|
666
|
-
return { stdout: "", stderr: `error: ${parsed.error}
|
|
667
|
-
`, exitCode: 1 };
|
|
668
|
-
}
|
|
669
|
-
const opts = parsed.options;
|
|
670
|
-
const fs = ctx.fs;
|
|
671
|
-
const cwd = ctx.cwd ?? "/";
|
|
672
|
-
const searchRoots = opts.searchPaths.length > 0 ? opts.searchPaths.map((p) => resolvePath(cwd, p)) : [cwd];
|
|
673
|
-
let matchRegex = null;
|
|
674
|
-
if (opts.pattern) {
|
|
675
|
-
if (opts.fixedStrings) {
|
|
676
|
-
matchRegex = new RegExp(escapeRegex(opts.pattern), "i");
|
|
677
|
-
} else if (opts.glob) {
|
|
678
|
-
matchRegex = globToRegex(opts.pattern);
|
|
679
|
-
} else {
|
|
680
|
-
try {
|
|
681
|
-
matchRegex = new RegExp(opts.pattern, "i");
|
|
682
|
-
} catch {
|
|
683
|
-
return { stdout: "", stderr: `error: invalid regex: ${opts.pattern}
|
|
684
|
-
`, exitCode: 1 };
|
|
685
|
-
}
|
|
686
|
-
}
|
|
687
|
-
}
|
|
688
|
-
const excludeMatchers = opts.excludes.map((p) => globToRegex(p));
|
|
689
|
-
const ignoreMatchers = [];
|
|
690
|
-
for (const ignoreFile of opts.ignoreFiles) {
|
|
691
|
-
const absPath = resolvePath(cwd, ignoreFile);
|
|
692
|
-
const loaded = await loadIgnoreFile(fs, absPath);
|
|
693
|
-
ignoreMatchers.push(...loaded);
|
|
694
|
-
}
|
|
695
|
-
const results = [];
|
|
696
|
-
let limitReached = false;
|
|
697
|
-
async function walk(dirPath, rootPath, depth) {
|
|
698
|
-
if (limitReached) return;
|
|
699
|
-
if (depth > opts.maxDepth) return;
|
|
700
|
-
let entries;
|
|
701
|
-
try {
|
|
702
|
-
entries = await fs.readdir(dirPath);
|
|
703
|
-
} catch {
|
|
704
|
-
return;
|
|
705
|
-
}
|
|
706
|
-
for (const entry of entries) {
|
|
707
|
-
if (limitReached) return;
|
|
708
|
-
if (!opts.hidden && entry.startsWith(".")) continue;
|
|
709
|
-
const fullPath = `${dirPath}/${entry}`;
|
|
710
|
-
let isDir = false;
|
|
711
|
-
let isFile = false;
|
|
712
|
-
try {
|
|
713
|
-
const st = await fs.stat(fullPath);
|
|
714
|
-
isDir = st.isDirectory;
|
|
715
|
-
isFile = st.isFile;
|
|
716
|
-
} catch {
|
|
717
|
-
continue;
|
|
718
|
-
}
|
|
719
|
-
const relPath = fullPath.slice(rootPath.length + 1) || entry;
|
|
720
|
-
if (!opts.noIgnore && ignoreMatchers.some((m) => m(relPath, isDir))) continue;
|
|
721
|
-
const basename = entry;
|
|
722
|
-
if (excludeMatchers.some((re) => re.test(basename) || re.test(relPath))) continue;
|
|
723
|
-
if (opts.typeFilter === "f" && !isFile) {
|
|
724
|
-
if (isDir) await walk(fullPath, rootPath, depth + 1);
|
|
725
|
-
continue;
|
|
726
|
-
}
|
|
727
|
-
if (opts.typeFilter === "d" && !isDir) continue;
|
|
728
|
-
if (opts.extensions.length > 0) {
|
|
729
|
-
const dotIdx = entry.lastIndexOf(".");
|
|
730
|
-
const ext = dotIdx >= 0 ? entry.slice(dotIdx + 1) : "";
|
|
731
|
-
if (!opts.extensions.some((e) => e.toLowerCase() === ext.toLowerCase())) {
|
|
732
|
-
if (isDir) await walk(fullPath, rootPath, depth + 1);
|
|
733
|
-
continue;
|
|
734
|
-
}
|
|
735
|
-
}
|
|
736
|
-
if (matchRegex) {
|
|
737
|
-
const target = opts.fullPath ? relPath : basename;
|
|
738
|
-
if (!matchRegex.test(target)) {
|
|
739
|
-
if (isDir) await walk(fullPath, rootPath, depth + 1);
|
|
740
|
-
continue;
|
|
741
|
-
}
|
|
742
|
-
}
|
|
743
|
-
const output = opts.absolutePath ? fullPath : relPath;
|
|
744
|
-
results.push(output);
|
|
745
|
-
if (results.length >= opts.maxResults) {
|
|
746
|
-
limitReached = true;
|
|
747
|
-
return;
|
|
748
|
-
}
|
|
749
|
-
if (isDir) {
|
|
750
|
-
await walk(fullPath, rootPath, depth + 1);
|
|
751
|
-
}
|
|
752
|
-
}
|
|
753
|
-
}
|
|
754
|
-
for (const root of searchRoots) {
|
|
755
|
-
if (limitReached) break;
|
|
756
|
-
try {
|
|
757
|
-
const st = await fs.stat(root);
|
|
758
|
-
if (!st.isDirectory) {
|
|
759
|
-
return { stdout: "", stderr: `error: '${root}' is not a directory
|
|
760
|
-
`, exitCode: 1 };
|
|
761
|
-
}
|
|
762
|
-
} catch {
|
|
763
|
-
return { stdout: "", stderr: `error: '${root}': No such file or directory
|
|
764
|
-
`, exitCode: 1 };
|
|
765
|
-
}
|
|
766
|
-
if (!opts.noIgnore) {
|
|
767
|
-
const rootGitignore = `${root}/.gitignore`;
|
|
768
|
-
const loaded = await loadIgnoreFile(fs, rootGitignore);
|
|
769
|
-
ignoreMatchers.push(...loaded);
|
|
770
|
-
}
|
|
771
|
-
await walk(root, root, 1);
|
|
772
|
-
}
|
|
773
|
-
results.sort();
|
|
774
|
-
if (results.length === 0) {
|
|
775
|
-
return { stdout: "", stderr: "", exitCode: 1 };
|
|
776
|
-
}
|
|
777
|
-
return { stdout: results.join("\n") + "\n", stderr: "", exitCode: 0 };
|
|
778
|
-
}
|
|
779
|
-
|
|
780
|
-
// src/browser-bash-session.ts
|
|
781
|
-
var DEFAULT_BASH_SHELL_ENV = {
|
|
782
|
-
LANG: "C.UTF-8",
|
|
783
|
-
LC_ALL: "C.UTF-8",
|
|
784
|
-
PYTHONIOENCODING: "utf-8",
|
|
785
|
-
PYTHONUTF8: "1",
|
|
786
|
-
PI_OFFLINE: "1"
|
|
787
|
-
};
|
|
788
|
-
var DEFAULT_BASH_COMMAND_TIMEOUT_MS = 5 * 60 * 1e3;
|
|
789
|
-
var DEFAULT_BASH_OUTPUT_LIMIT = 1e4;
|
|
790
|
-
function normalizeBashPath(input) {
|
|
791
|
-
const posixPath2 = input.trim().replace(/\\/g, "/") || "/";
|
|
792
|
-
const segments = [];
|
|
793
|
-
const isAbsolute = posixPath2.startsWith("/");
|
|
794
|
-
for (const segment of posixPath2.split("/")) {
|
|
795
|
-
if (segment === "..") {
|
|
796
|
-
segments.pop();
|
|
797
|
-
} else if (segment !== "." && segment !== "") {
|
|
798
|
-
segments.push(segment);
|
|
799
|
-
}
|
|
800
|
-
}
|
|
801
|
-
return (isAbsolute ? "/" : "") + segments.join("/") || "/";
|
|
802
|
-
}
|
|
803
|
-
function truncateBashOutput(output, limitBytes = DEFAULT_BASH_OUTPUT_LIMIT) {
|
|
804
|
-
if (!output || output.length <= limitBytes) {
|
|
805
|
-
return output;
|
|
806
|
-
}
|
|
807
|
-
const headBytes = Math.ceil(limitBytes * 0.3);
|
|
808
|
-
const tailBytes = limitBytes - headBytes;
|
|
809
|
-
const omittedBytes = output.length - headBytes - tailBytes;
|
|
810
|
-
return `${output.slice(0, headBytes)}
|
|
811
|
-
|
|
812
|
-
... [${omittedBytes} bytes truncated] ...
|
|
813
|
-
|
|
814
|
-
${output.slice(-tailBytes)}`;
|
|
815
|
-
}
|
|
816
|
-
function createBrowserBashSession(options = {}) {
|
|
817
|
-
const rootPath = normalizeBashPath(options.rootPath ?? "/workspace");
|
|
818
|
-
const env = options.env ?? { ...DEFAULT_BASH_SHELL_ENV };
|
|
819
|
-
const fs = new ObservableInMemoryFs(options.fsOptions);
|
|
820
|
-
fs.mkdirSync(rootPath, { recursive: true });
|
|
821
|
-
const piBinDir = "/home/user/.pi/agent/bin";
|
|
822
|
-
fs.mkdirSync(piBinDir, { recursive: true });
|
|
823
|
-
fs.writeFileSync(`${piBinDir}/rg`, '#!/bin/sh\nrg "$@"\n');
|
|
824
|
-
fs.writeFileSync(`${piBinDir}/fd`, '#!/bin/sh\nfd "$@"\n');
|
|
825
|
-
let almostNodeSession = null;
|
|
826
|
-
let almostNodeSessionPromise = null;
|
|
827
|
-
let pyodideSession = null;
|
|
828
|
-
let pyodideSessionPromise = null;
|
|
829
|
-
async function getAlmostNodeSession() {
|
|
830
|
-
if (almostNodeSession) return almostNodeSession;
|
|
831
|
-
if (almostNodeSessionPromise) return almostNodeSessionPromise;
|
|
832
|
-
almostNodeSessionPromise = import(["./almostnode", "-session-2FPETBKJ.js"].join("")).then((mod) => {
|
|
833
|
-
almostNodeSession = new mod.AlmostNodeSession(fs);
|
|
834
|
-
almostNodeSession.setBinCommandRegistrar((name, handler) => {
|
|
835
|
-
bash.registerCommand(Dx(name, handler));
|
|
836
|
-
});
|
|
837
|
-
if (currentStdoutWriter) almostNodeSession.setStdoutWriter(currentStdoutWriter);
|
|
838
|
-
return almostNodeSession;
|
|
839
|
-
});
|
|
840
|
-
return almostNodeSessionPromise;
|
|
841
|
-
}
|
|
842
|
-
async function getPyodideSession() {
|
|
843
|
-
if (pyodideSession) return pyodideSession;
|
|
844
|
-
if (pyodideSessionPromise) return pyodideSessionPromise;
|
|
845
|
-
pyodideSessionPromise = import("./pyodide-session-OEKAVNSL.js").then((mod) => {
|
|
846
|
-
pyodideSession = new mod.PyodideSession(fs);
|
|
847
|
-
if (currentStdoutWriter) pyodideSession.setStdoutWriter(currentStdoutWriter);
|
|
848
|
-
return pyodideSession;
|
|
849
|
-
});
|
|
850
|
-
return pyodideSessionPromise;
|
|
851
|
-
}
|
|
852
|
-
let currentStdoutWriter;
|
|
853
|
-
const runtimeCommands = [];
|
|
854
|
-
if (options.node) {
|
|
855
|
-
runtimeCommands.push(
|
|
856
|
-
Dx("node", async (args, ctx) => (await getAlmostNodeSession()).executeNode(args, ctx)),
|
|
857
|
-
Dx("npm", async (args, ctx) => (await getAlmostNodeSession()).executeNpm(args, ctx))
|
|
858
|
-
);
|
|
859
|
-
}
|
|
860
|
-
if (options.python) {
|
|
861
|
-
runtimeCommands.push(
|
|
862
|
-
Dx("python", async (args, ctx) => (await getPyodideSession()).executePython(args, ctx)),
|
|
863
|
-
Dx("python3", async (args, ctx) => (await getPyodideSession()).executePython(args, ctx)),
|
|
864
|
-
Dx("pip", async (args, ctx) => (await getPyodideSession()).executePip(args, ctx))
|
|
865
|
-
);
|
|
866
|
-
}
|
|
867
|
-
const bash = new Ju({
|
|
868
|
-
cwd: rootPath,
|
|
869
|
-
env: { ...env },
|
|
870
|
-
fs,
|
|
871
|
-
customCommands: [
|
|
872
|
-
...runtimeCommands,
|
|
873
|
-
Dx("fd", async (args, ctx) => executeFd(args, ctx)),
|
|
874
|
-
...options.customCommands ?? []
|
|
875
|
-
]
|
|
876
|
-
});
|
|
877
|
-
return {
|
|
878
|
-
fs,
|
|
879
|
-
bash,
|
|
880
|
-
rootPath,
|
|
881
|
-
cwd: rootPath,
|
|
882
|
-
setStdoutWriter: (writer) => {
|
|
883
|
-
currentStdoutWriter = writer;
|
|
884
|
-
almostNodeSession?.setStdoutWriter(writer);
|
|
885
|
-
pyodideSession?.setStdoutWriter(writer);
|
|
886
|
-
},
|
|
887
|
-
writeStdin: (data) => almostNodeSession?.writeStdin(data),
|
|
888
|
-
setTerminalSize: (columns, rows) => almostNodeSession?.setTerminalSize(columns, rows),
|
|
889
|
-
dispose: () => {
|
|
890
|
-
almostNodeSession?.dispose();
|
|
891
|
-
pyodideSession?.dispose();
|
|
892
|
-
}
|
|
893
|
-
};
|
|
894
|
-
}
|
|
895
|
-
async function executeBrowserBash(session, command, options = {}) {
|
|
896
|
-
const trimmedCommand = command.trim();
|
|
897
|
-
if (!trimmedCommand) {
|
|
898
|
-
return { success: false, error: "Command is required", stderr: "Command is required", exit_code: 1, command: trimmedCommand, backend: "just-bash" };
|
|
899
|
-
}
|
|
900
|
-
const startedAt = Date.now();
|
|
901
|
-
const outputLimit = options.outputLimit ?? DEFAULT_BASH_OUTPUT_LIMIT;
|
|
902
|
-
const timeoutMs = options.commandTimeoutMs ?? DEFAULT_BASH_COMMAND_TIMEOUT_MS;
|
|
903
|
-
const timeoutController = new AbortController();
|
|
904
|
-
const combinedController = new AbortController();
|
|
905
|
-
const abort = (reason) => {
|
|
906
|
-
combinedController.abort(reason instanceof Error ? reason : new Error(String(reason ?? "Command aborted")));
|
|
907
|
-
};
|
|
908
|
-
if (options.signal) {
|
|
909
|
-
if (options.signal.aborted) {
|
|
910
|
-
abort(options.signal.reason);
|
|
911
|
-
} else {
|
|
912
|
-
options.signal.addEventListener("abort", () => abort(options.signal.reason), { once: true });
|
|
913
|
-
}
|
|
914
|
-
}
|
|
915
|
-
timeoutController.signal.addEventListener("abort", () => abort(timeoutController.signal.reason), { once: true });
|
|
916
|
-
const timeoutId = globalThis.setTimeout(() => {
|
|
917
|
-
timeoutController.abort(new Error(`Command timed out after ${timeoutMs}ms`));
|
|
918
|
-
}, timeoutMs);
|
|
919
|
-
try {
|
|
920
|
-
const result = await session.bash.exec(trimmedCommand, {
|
|
921
|
-
cwd: session.cwd,
|
|
922
|
-
env: {
|
|
923
|
-
...DEFAULT_BASH_SHELL_ENV,
|
|
924
|
-
PWD: session.cwd
|
|
925
|
-
},
|
|
926
|
-
signal: combinedController.signal
|
|
927
|
-
});
|
|
928
|
-
const nextCwd = result.env?.PWD?.trim();
|
|
929
|
-
if (nextCwd) {
|
|
930
|
-
session.cwd = normalizeBashPath(nextCwd);
|
|
931
|
-
}
|
|
932
|
-
const stdout = options.truncateOutput === false ? result.stdout : truncateBashOutput(result.stdout, outputLimit);
|
|
933
|
-
const stderr = options.truncateOutput === false ? result.stderr : truncateBashOutput(result.stderr, outputLimit);
|
|
934
|
-
const error = result.exitCode === 0 ? void 0 : stderr || void 0;
|
|
935
|
-
return {
|
|
936
|
-
success: result.exitCode === 0,
|
|
937
|
-
command: trimmedCommand,
|
|
938
|
-
stdout,
|
|
939
|
-
stderr,
|
|
940
|
-
output: stdout,
|
|
941
|
-
exit_code: result.exitCode,
|
|
942
|
-
duration_ms: Date.now() - startedAt,
|
|
943
|
-
backend: "just-bash",
|
|
944
|
-
...error ? { error } : {}
|
|
945
|
-
};
|
|
946
|
-
} catch (error) {
|
|
947
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
948
|
-
return { success: false, command: trimmedCommand, error: message, stderr: message, exit_code: 1, duration_ms: Date.now() - startedAt, backend: "just-bash" };
|
|
949
|
-
} finally {
|
|
950
|
-
globalThis.clearTimeout(timeoutId);
|
|
951
|
-
}
|
|
952
|
-
}
|
|
953
|
-
|
|
954
15
|
// src/index.ts
|
|
955
|
-
var AGENT_WEB_OS_VERSION = "0.
|
|
16
|
+
var AGENT_WEB_OS_VERSION = "0.4.0-beta.0";
|
|
956
17
|
console.log(`[agent-web-os] v${AGENT_WEB_OS_VERSION}`);
|
|
957
18
|
export {
|
|
958
19
|
AGENT_WEB_OS_VERSION,
|
|
@@ -963,8 +24,6 @@ export {
|
|
|
963
24
|
createBrowserBashSession,
|
|
964
25
|
Dx as defineCommand,
|
|
965
26
|
executeBrowserBash,
|
|
966
|
-
executeFd
|
|
967
|
-
getServerBridge,
|
|
968
|
-
resetServerBridge
|
|
27
|
+
executeFd
|
|
969
28
|
};
|
|
970
29
|
//# sourceMappingURL=index.js.map
|