agent-web-os 0.3.0-beta.0 → 0.3.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/{almostnode-session-NGSXCNAV.js → almostnode-session-HTOIWX4Y.js} +2 -6
- package/dist/{almostnode-session-NGSXCNAV.js.map → almostnode-session-HTOIWX4Y.js.map} +1 -1
- package/dist/index.cjs +10 -27
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +5 -5
- package/dist/index.js.map +1 -1
- package/dist/{pyodide-session-I7LP2GQO.js → pyodide-session-OEKAVNSL.js} +5 -18
- package/dist/pyodide-session-OEKAVNSL.js.map +1 -0
- package/package.json +1 -1
- package/dist/pyodide-session-I7LP2GQO.js.map +0 -1
package/dist/index.d.cts
CHANGED
|
@@ -148,7 +148,7 @@ declare function executeBrowserBash(session: BrowserBashSession, command: string
|
|
|
148
148
|
|
|
149
149
|
declare function executeFd(args: string[], ctx: CommandContext): Promise<ExecResult>;
|
|
150
150
|
|
|
151
|
-
declare const AGENT_WEB_OS_VERSION = "0.3.0
|
|
151
|
+
declare const AGENT_WEB_OS_VERSION = "0.3.0";
|
|
152
152
|
|
|
153
153
|
type ServerBridge = {
|
|
154
154
|
initServiceWorker(): Promise<void>;
|
package/dist/index.d.ts
CHANGED
|
@@ -148,7 +148,7 @@ declare function executeBrowserBash(session: BrowserBashSession, command: string
|
|
|
148
148
|
|
|
149
149
|
declare function executeFd(args: string[], ctx: CommandContext): Promise<ExecResult>;
|
|
150
150
|
|
|
151
|
-
declare const AGENT_WEB_OS_VERSION = "0.3.0
|
|
151
|
+
declare const AGENT_WEB_OS_VERSION = "0.3.0";
|
|
152
152
|
|
|
153
153
|
type ServerBridge = {
|
|
154
154
|
initServiceWorker(): Promise<void>;
|
package/dist/index.js
CHANGED
|
@@ -827,8 +827,8 @@ function createBrowserBashSession(options = {}) {
|
|
|
827
827
|
async function getAlmostNodeSession() {
|
|
828
828
|
if (almostNodeSession) return almostNodeSession;
|
|
829
829
|
if (almostNodeSessionPromise) return almostNodeSessionPromise;
|
|
830
|
-
almostNodeSessionPromise = import("./almostnode-session-
|
|
831
|
-
almostNodeSession =
|
|
830
|
+
almostNodeSessionPromise = import("./almostnode-session-HTOIWX4Y.js").then((mod) => {
|
|
831
|
+
almostNodeSession = new mod.AlmostNodeSession(fs);
|
|
832
832
|
almostNodeSession.setBinCommandRegistrar((name, handler) => {
|
|
833
833
|
bash.registerCommand(Dx(name, handler));
|
|
834
834
|
});
|
|
@@ -840,8 +840,8 @@ function createBrowserBashSession(options = {}) {
|
|
|
840
840
|
async function getPyodideSession() {
|
|
841
841
|
if (pyodideSession) return pyodideSession;
|
|
842
842
|
if (pyodideSessionPromise) return pyodideSessionPromise;
|
|
843
|
-
pyodideSessionPromise = import("./pyodide-session-
|
|
844
|
-
pyodideSession =
|
|
843
|
+
pyodideSessionPromise = import("./pyodide-session-OEKAVNSL.js").then((mod) => {
|
|
844
|
+
pyodideSession = new mod.PyodideSession(fs);
|
|
845
845
|
if (currentStdoutWriter) pyodideSession.setStdoutWriter(currentStdoutWriter);
|
|
846
846
|
return pyodideSession;
|
|
847
847
|
});
|
|
@@ -950,7 +950,7 @@ async function executeBrowserBash(session, command, options = {}) {
|
|
|
950
950
|
}
|
|
951
951
|
|
|
952
952
|
// src/index.ts
|
|
953
|
-
var AGENT_WEB_OS_VERSION = "0.3.0
|
|
953
|
+
var AGENT_WEB_OS_VERSION = "0.3.0";
|
|
954
954
|
console.log(`[agent-web-os] v${AGENT_WEB_OS_VERSION}`);
|
|
955
955
|
var getServerBridge2 = getServerBridge;
|
|
956
956
|
var resetServerBridge2 = resetServerBridge;
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/observable-in-memory-fs.ts","../src/fd-command.ts","../src/browser-bash-session.ts","../src/index.ts"],"sourcesContent":["import {\n InMemoryFs,\n type CpOptions,\n type FileContent,\n type MkdirOptions,\n type RmOptions,\n} from \"just-bash\"\nimport { posixPath as path } from \"./posix-path\"\n\ntype ObservableInMemoryFsWriteFileSyncOptions = Parameters<InMemoryFs[\"writeFileSync\"]>[2]\ntype ObservableInMemoryFsWriteFileSyncMetadata = Parameters<InMemoryFs[\"writeFileSync\"]>[3]\ntype ObservableInMemoryFsWriteFileLazy = Parameters<InMemoryFs[\"writeFileLazy\"]>[1]\ntype ObservableInMemoryFsWriteFileLazyMetadata = Parameters<InMemoryFs[\"writeFileLazy\"]>[2]\ntype ObservableInMemoryFsWriteOptions = Parameters<InMemoryFs[\"writeFile\"]>[2]\n\ntype ObservableInMemoryFsEntryType = \"file\" | \"directory\" | \"symlink\"\n\nexport type ObservableInMemoryFsChangeEventName =\n | \"add\"\n | \"addDir\"\n | \"change\"\n | \"unlink\"\n | \"unlinkDir\"\n\nexport type ObservableInMemoryFsChangeEvent = {\n event: ObservableInMemoryFsChangeEventName\n path: string\n entryType: ObservableInMemoryFsEntryType\n previousPath?: string\n}\n\nexport type ObservableInMemoryFsOptions = {\n /** Whether to console.log change events (default: false) */\n consoleLogChanges?: boolean\n /** Root path used to filter which changes are console-logged (default: \"/\") */\n workspaceRoot?: string\n}\n\nfunction isObservableInMemoryFsLike(value: unknown): value is ObservableInMemoryFs {\n if (!value || typeof value !== \"object\") {\n return false\n }\n\n const candidate = value as Partial<Record<keyof ObservableInMemoryFs, unknown>>\n\n return typeof candidate.subscribe === \"function\"\n && typeof candidate.exists === \"function\"\n && typeof candidate.readFile === \"function\"\n && typeof candidate.readdir === \"function\"\n && typeof candidate.stat === \"function\"\n}\n\nexport function assertObservableInMemoryFs(value: unknown): ObservableInMemoryFs {\n if (!isObservableInMemoryFsLike(value)) {\n throw new Error(\"Expected ObservableInMemoryFs-backed just-bash filesystem\")\n }\n\n return value\n}\n\ntype ObservableInMemoryFsListener = (event: ObservableInMemoryFsChangeEvent) => void\n\ntype ObservableInMemoryFsPathState = {\n exists: boolean\n entryType?: ObservableInMemoryFsEntryType\n}\n\ntype ObservableInMemoryFsEmitOptions = {\n shouldConsoleLog?: boolean\n}\n\nasync function readPathState(\n fs: InMemoryFs,\n path: string,\n): Promise<ObservableInMemoryFsPathState> {\n const exists = await fs.exists(path)\n if (!exists) {\n return { exists: false }\n }\n\n if (isObservableInMemoryFsLike(fs) && fs.isPathLazy(path)) {\n return {\n exists: true,\n entryType: \"file\",\n }\n }\n\n try {\n const stat = await fs.lstat(path)\n const entryType: ObservableInMemoryFsEntryType = stat.isDirectory\n ? \"directory\"\n : stat.isSymbolicLink\n ? \"symlink\"\n : \"file\"\n return {\n exists: true,\n entryType,\n }\n } catch {\n // Path may have been removed between exists() and lstat() (TOCTOU race)\n return { exists: false }\n }\n}\n\nfunction mapAddEvent(entryType: ObservableInMemoryFsEntryType): ObservableInMemoryFsChangeEventName {\n return entryType === \"directory\" ? \"addDir\" : \"add\"\n}\n\nfunction normalizeFsPathForLogScope(fsPath: string): string {\n const normalized = path.normalize(fsPath)\n return normalized === \".\" ? \"/\" : normalized\n}\n\nexport class ObservableInMemoryFs extends InMemoryFs {\n private listeners: Set<ObservableInMemoryFsListener> | undefined\n private lazyPaths = new Set<string>()\n private suppressSyncEventCount = 0\n private suppressConsoleLogCount = 0\n private suppressChangeEmissionCount = 0\n private readonly consoleLogChanges: boolean\n private readonly isLoggableWorkspacePath: (fsPath: string) => boolean\n\n constructor(options?: ObservableInMemoryFsOptions) {\n super()\n this.consoleLogChanges = options?.consoleLogChanges ?? false\n\n const normalizedWorkspaceRoot = normalizeFsPathForLogScope(options?.workspaceRoot ?? \"/\")\n this.isLoggableWorkspacePath = (fsPath: string) => {\n const normalizedPath = normalizeFsPathForLogScope(fsPath)\n\n if (normalizedPath !== normalizedWorkspaceRoot && !normalizedPath.startsWith(`${normalizedWorkspaceRoot}/`)) {\n return false\n }\n\n const relativePath = path.relative(normalizedWorkspaceRoot, normalizedPath)\n if (!relativePath || relativePath === \".\") {\n return true\n }\n\n return relativePath\n .split(\"/\")\n .every((segment) => segment.length > 0 && !segment.startsWith(\".\"))\n }\n }\n\n isPathLazy(filePath: string): boolean {\n return this.lazyPaths.has(normalizeFsPathForLogScope(filePath))\n }\n\n private clearLazyPath(filePath: string): void {\n this.lazyPaths.delete(normalizeFsPathForLogScope(filePath))\n }\n\n private clearLazyPathsUnder(rootPath: string): void {\n const normalizedRootPath = normalizeFsPathForLogScope(rootPath)\n\n for (const filePath of Array.from(this.lazyPaths)) {\n if (filePath === normalizedRootPath || filePath.startsWith(`${normalizedRootPath}/`)) {\n this.lazyPaths.delete(filePath)\n }\n }\n }\n\n subscribe(listener: ObservableInMemoryFsListener): () => void {\n const listeners = this.listeners ??= new Set<ObservableInMemoryFsListener>()\n listeners.add(listener)\n\n return () => {\n listeners.delete(listener)\n\n if (listeners.size === 0 && this.listeners === listeners) {\n this.listeners = undefined\n }\n }\n }\n\n private shouldEmitChanges(): boolean {\n if (this.suppressChangeEmissionCount > 0) {\n return false\n }\n\n return this.consoleLogChanges || (this.listeners?.size ?? 0) > 0\n }\n\n async suppressObservability<T>(operation: () => Promise<T>): Promise<T> {\n this.suppressChangeEmissionCount += 1\n this.suppressSyncEventCount += 1\n this.suppressConsoleLogCount += 1\n\n try {\n return await operation()\n } finally {\n this.suppressConsoleLogCount -= 1\n this.suppressSyncEventCount -= 1\n this.suppressChangeEmissionCount -= 1\n }\n }\n\n private queueChangeEmission(emission: Promise<void>): void {\n void emission.catch((error: unknown) => {\n console.error(\"[ObservableInMemoryFs] Failed to emit change event\", error)\n })\n }\n\n private areConsoleLogsSuppressed(): boolean {\n return this.suppressConsoleLogCount > 0\n }\n\n private async runWithSuppressedConsoleLogs<T>(operation: () => Promise<T>): Promise<T> {\n this.suppressConsoleLogCount += 1\n\n try {\n return await operation()\n } finally {\n this.suppressConsoleLogCount -= 1\n }\n }\n\n private shouldConsoleLogChangeEvent(event: ObservableInMemoryFsChangeEvent): boolean {\n if (!this.isLoggableWorkspacePath(event.path)) {\n return false\n }\n\n if (event.previousPath && !this.isLoggableWorkspacePath(event.previousPath)) {\n return false\n }\n\n return true\n }\n\n private emit(\n event: ObservableInMemoryFsChangeEvent,\n options?: ObservableInMemoryFsEmitOptions,\n ): void {\n const shouldConsoleLog = options?.shouldConsoleLog ?? this.shouldConsoleLogChangeEvent(event)\n\n if (\n this.consoleLogChanges\n && shouldConsoleLog\n && !this.areConsoleLogsSuppressed()\n ) {\n console.log(`[ObservableInMemoryFs] ${event.event} ${event.entryType} ${event.path}${event.previousPath ? ` (from ${event.previousPath})` : \"\"}`)\n }\n\n if (!this.listeners) {\n return\n }\n\n for (const listener of this.listeners) {\n try {\n listener(event)\n } catch (error: unknown) {\n console.error(\"[ObservableInMemoryFs] Change listener failed\", error)\n }\n }\n }\n\n private areSyncEventsSuppressed(): boolean {\n return this.suppressSyncEventCount > 0\n }\n\n private async runWithSuppressedSyncEvents<T>(operation: () => Promise<T>): Promise<T> {\n this.suppressSyncEventCount += 1\n\n try {\n return await operation()\n } finally {\n this.suppressSyncEventCount -= 1\n }\n }\n\n override writeFileSync(\n path: string,\n content: FileContent,\n options?: ObservableInMemoryFsWriteFileSyncOptions,\n metadata?: ObservableInMemoryFsWriteFileSyncMetadata,\n ): void {\n const previous = this.areSyncEventsSuppressed() || !this.shouldEmitChanges()\n ? null\n : readPathState(this, path)\n\n super.writeFileSync(path, content, options, metadata)\n this.clearLazyPath(path)\n\n if (!previous) {\n return\n }\n\n this.queueChangeEmission(previous.then((state) => this.emitWriteEvent(path, state)))\n }\n\n override writeFileLazy(\n path: string,\n lazy: ObservableInMemoryFsWriteFileLazy,\n metadata?: ObservableInMemoryFsWriteFileLazyMetadata,\n ): void {\n const previous = this.areSyncEventsSuppressed() || !this.shouldEmitChanges()\n ? null\n : readPathState(this, path)\n\n super.writeFileLazy(path, lazy, metadata)\n this.lazyPaths.add(normalizeFsPathForLogScope(path))\n\n if (!previous) {\n return\n }\n\n this.queueChangeEmission(previous.then((state) => this.emitWriteEvent(path, state)))\n }\n\n private async emitWriteEvent(path: string, previous: ObservableInMemoryFsPathState): Promise<void> {\n const current = await readPathState(this, path)\n if (!current.exists || !current.entryType) {\n return\n }\n\n if (!previous.exists) {\n this.emit({\n event: mapAddEvent(current.entryType),\n path,\n entryType: current.entryType,\n })\n return\n }\n\n this.emit({\n event: \"change\",\n path,\n entryType: current.entryType,\n })\n }\n\n private async emitMkdirEvent(path: string, previous: ObservableInMemoryFsPathState): Promise<void> {\n const current = await readPathState(this, path)\n if (!current.exists || current.entryType !== \"directory\" || previous.exists) {\n return\n }\n\n this.emit({\n event: \"addDir\",\n path,\n entryType: \"directory\",\n })\n }\n\n private emitRemovalEvent(\n path: string,\n previous: ObservableInMemoryFsPathState,\n options?: ObservableInMemoryFsEmitOptions,\n ): void {\n if (!previous.exists || !previous.entryType) {\n return\n }\n\n this.emit({\n event: previous.entryType === \"directory\" ? \"unlinkDir\" : \"unlink\",\n path,\n entryType: previous.entryType,\n }, options)\n }\n\n override mkdirSync(path: string, options?: MkdirOptions): void {\n const previous = this.areSyncEventsSuppressed() || !this.shouldEmitChanges()\n ? null\n : readPathState(this, path)\n\n super.mkdirSync(path, options)\n\n if (!previous) {\n return\n }\n\n this.queueChangeEmission(previous.then((state) => this.emitMkdirEvent(path, state)))\n }\n\n override async readFileBuffer(path: string): Promise<Uint8Array> {\n const content = await super.readFileBuffer(path)\n this.clearLazyPath(path)\n return content\n }\n\n override async stat(path: string) {\n const stat = await super.stat(path)\n this.clearLazyPath(path)\n return stat\n }\n\n override async lstat(path: string) {\n const stat = await super.lstat(path)\n this.clearLazyPath(path)\n return stat\n }\n\n override async writeFile(\n path: string,\n content: FileContent,\n options?: ObservableInMemoryFsWriteOptions,\n ): Promise<void> {\n if (!this.shouldEmitChanges()) {\n await super.writeFile(path, content, options)\n return\n }\n\n const previous = await readPathState(this, path)\n await this.runWithSuppressedSyncEvents(() => super.writeFile(path, content, options))\n await this.emitWriteEvent(path, previous)\n }\n\n override async appendFile(\n path: string,\n content: FileContent,\n options?: ObservableInMemoryFsWriteOptions,\n ): Promise<void> {\n if (!this.shouldEmitChanges()) {\n await super.appendFile(path, content, options)\n return\n }\n\n const previous = await readPathState(this, path)\n await this.runWithSuppressedSyncEvents(() => super.appendFile(path, content, options))\n await this.emitWriteEvent(path, previous)\n }\n\n override async mkdir(path: string, options?: MkdirOptions): Promise<void> {\n if (!this.shouldEmitChanges()) {\n await super.mkdir(path, options)\n return\n }\n\n const previous = await readPathState(this, path)\n await this.runWithSuppressedSyncEvents(() => super.mkdir(path, options))\n await this.emitMkdirEvent(path, previous)\n }\n\n override async rm(path: string, options?: RmOptions): Promise<void> {\n if (!this.shouldEmitChanges()) {\n await super.rm(path, options)\n this.clearLazyPathsUnder(path)\n return\n }\n\n const previous = await readPathState(this, path)\n await super.rm(path, options)\n this.clearLazyPathsUnder(path)\n this.emitRemovalEvent(path, previous)\n }\n\n override async cp(src: string, dest: string, options?: CpOptions): Promise<void> {\n if (!this.shouldEmitChanges()) {\n await super.cp(src, dest, options)\n this.clearLazyPathsUnder(dest)\n return\n }\n\n const previous = await readPathState(this, dest)\n await super.cp(src, dest, options)\n this.clearLazyPathsUnder(dest)\n const current = await readPathState(this, dest)\n\n if (!current.exists || !current.entryType) {\n return\n }\n\n this.emit({\n event: previous.exists ? \"change\" : mapAddEvent(current.entryType),\n path: dest,\n entryType: current.entryType,\n })\n }\n\n override async mv(src: string, dest: string): Promise<void> {\n if (!this.shouldEmitChanges()) {\n await super.mv(src, dest)\n const normalizedSourcePath = normalizeFsPathForLogScope(src)\n const normalizedDestinationPath = normalizeFsPathForLogScope(dest)\n this.clearLazyPathsUnder(normalizedDestinationPath)\n\n for (const filePath of Array.from(this.lazyPaths)) {\n if (filePath === normalizedSourcePath || filePath.startsWith(`${normalizedSourcePath}/`)) {\n this.lazyPaths.delete(filePath)\n this.lazyPaths.add(`${normalizedDestinationPath}${filePath.slice(normalizedSourcePath.length)}`)\n }\n }\n return\n }\n\n const sourceState = await readPathState(this, src)\n const destinationState = await readPathState(this, dest)\n const shouldConsoleLogMove = this.shouldConsoleLogChangeEvent({\n event: destinationState.exists ? \"change\" : mapAddEvent(sourceState.entryType ?? \"file\"),\n path: dest,\n previousPath: src,\n entryType: sourceState.entryType ?? \"file\",\n })\n\n if (shouldConsoleLogMove) {\n await super.mv(src, dest)\n } else {\n await this.runWithSuppressedConsoleLogs(() => super.mv(src, dest))\n }\n\n const normalizedSourcePath = normalizeFsPathForLogScope(src)\n const normalizedDestinationPath = normalizeFsPathForLogScope(dest)\n this.clearLazyPathsUnder(normalizedDestinationPath)\n\n for (const filePath of Array.from(this.lazyPaths)) {\n if (filePath === normalizedSourcePath || filePath.startsWith(`${normalizedSourcePath}/`)) {\n this.lazyPaths.delete(filePath)\n this.lazyPaths.add(`${normalizedDestinationPath}${filePath.slice(normalizedSourcePath.length)}`)\n }\n }\n\n this.emitRemovalEvent(src, sourceState, {\n shouldConsoleLog: shouldConsoleLogMove,\n })\n\n const currentDestinationState = await readPathState(this, dest)\n if (!currentDestinationState.exists || !currentDestinationState.entryType) {\n return\n }\n\n this.emit({\n event: destinationState.exists ? \"change\" : mapAddEvent(currentDestinationState.entryType),\n path: dest,\n previousPath: src,\n entryType: currentDestinationState.entryType,\n }, {\n shouldConsoleLog: shouldConsoleLogMove,\n })\n }\n\n override async chmod(path: string, mode: number): Promise<void> {\n if (!this.shouldEmitChanges()) {\n await super.chmod(path, mode)\n return\n }\n\n await super.chmod(path, mode)\n\n const current = await readPathState(this, path)\n if (!current.exists || !current.entryType) {\n return\n }\n\n this.emit({\n event: \"change\",\n path,\n entryType: current.entryType,\n })\n }\n\n override async symlink(target: string, linkPath: string): Promise<void> {\n if (!this.shouldEmitChanges()) {\n await super.symlink(target, linkPath)\n return\n }\n\n const previous = await readPathState(this, linkPath)\n await super.symlink(target, linkPath)\n await this.emitWriteEvent(linkPath, previous)\n }\n\n override async link(existingPath: string, newPath: string): Promise<void> {\n if (!this.shouldEmitChanges()) {\n await super.link(existingPath, newPath)\n return\n }\n\n const previous = await readPathState(this, newPath)\n await super.link(existingPath, newPath)\n await this.emitWriteEvent(newPath, previous)\n }\n\n override async utimes(path: string, atime: Date, mtime: Date): Promise<void> {\n if (!this.shouldEmitChanges()) {\n await super.utimes(path, atime, mtime)\n return\n }\n\n await super.utimes(path, atime, mtime)\n\n const current = await readPathState(this, path)\n if (!current.exists || !current.entryType) {\n return\n }\n\n this.emit({\n event: \"change\",\n path,\n entryType: current.entryType,\n })\n }\n}\n","/**\r\n * `fd` command implementation for just-bash.\r\n *\r\n * A simplified browser-compatible implementation of https://github.com/sharkdp/fd\r\n * Supports the flags that pi-coding-agent's find tool uses:\r\n * fd [FLAGS] [pattern] [path...]\r\n *\r\n * Flags:\r\n * --glob / -g Treat pattern as glob (default: regex)\r\n * --fixed-strings / -F Treat pattern as literal string\r\n * --hidden / -H Include hidden files/directories\r\n * --no-ignore / -I Don't respect .gitignore\r\n * --type / -t f|d Filter by type (f=file, d=directory)\r\n * --extension / -e ext Filter by extension\r\n * --exclude PATTERN Exclude entries matching glob\r\n * --max-depth / -d N Maximum search depth\r\n * --max-results N Stop after N results\r\n * --color never (accepted, always off)\r\n * --ignore-file PATH Additional ignore file\r\n * --absolute-path / -a Print absolute paths\r\n * --full-path / -p Match pattern against full path\r\n * -1 Stop after first result\r\n */\r\n\r\nimport type { CommandContext, ExecResult } from \"just-bash/browser\"\r\n\r\ninterface FdOptions {\r\n glob: boolean\r\n fixedStrings: boolean\r\n hidden: boolean\r\n noIgnore: boolean\r\n typeFilter: \"f\" | \"d\" | null\r\n extensions: string[]\r\n excludes: string[]\r\n maxDepth: number\r\n maxResults: number\r\n ignoreFiles: string[]\r\n absolutePath: boolean\r\n fullPath: boolean\r\n pattern: string\r\n searchPaths: string[]\r\n}\r\n\r\nfunction parseFdArgs(args: string[]): { options: FdOptions } | { error: string } {\r\n const opts: FdOptions = {\r\n glob: false,\r\n fixedStrings: false,\r\n hidden: false,\r\n noIgnore: false,\r\n typeFilter: null,\r\n extensions: [],\r\n excludes: [],\r\n maxDepth: Infinity,\r\n maxResults: Infinity,\r\n ignoreFiles: [],\r\n absolutePath: false,\r\n fullPath: false,\r\n pattern: \"\",\r\n searchPaths: [],\r\n }\r\n\r\n const positional: string[] = []\r\n let i = 0\r\n\r\n while (i < args.length) {\r\n const arg = args[i]\r\n\r\n if (arg === \"--\") {\r\n positional.push(...args.slice(i + 1))\r\n break\r\n }\r\n\r\n if (arg === \"--glob\" || arg === \"-g\") { opts.glob = true; i++; continue }\r\n if (arg === \"--fixed-strings\" || arg === \"-F\") { opts.fixedStrings = true; i++; continue }\r\n if (arg === \"--hidden\" || arg === \"-H\") { opts.hidden = true; i++; continue }\r\n if (arg === \"--no-ignore\" || arg === \"-I\") { opts.noIgnore = true; i++; continue }\r\n if (arg === \"--absolute-path\" || arg === \"-a\") { opts.absolutePath = true; i++; continue }\r\n if (arg === \"--full-path\" || arg === \"-p\") { opts.fullPath = true; i++; continue }\r\n if (arg === \"-1\") { opts.maxResults = 1; i++; continue }\r\n\r\n if (arg === \"--type\" || arg === \"-t\") {\r\n const val = args[++i]\r\n if (val === \"f\" || val === \"file\") opts.typeFilter = \"f\"\r\n else if (val === \"d\" || val === \"dir\" || val === \"directory\") opts.typeFilter = \"d\"\r\n i++; continue\r\n }\r\n\r\n if (arg === \"--extension\" || arg === \"-e\") {\r\n const ext = args[++i]\r\n if (ext) opts.extensions.push(ext.startsWith(\".\") ? ext.slice(1) : ext)\r\n i++; continue\r\n }\r\n\r\n if (arg === \"--exclude\" || arg === \"-E\") {\r\n const pat = args[++i]\r\n if (pat) opts.excludes.push(pat)\r\n i++; continue\r\n }\r\n\r\n if (arg === \"--max-depth\" || arg === \"-d\") {\r\n const n = Number.parseInt(args[++i] ?? \"\", 10)\r\n if (!Number.isNaN(n)) opts.maxDepth = n\r\n i++; continue\r\n }\r\n\r\n if (arg === \"--max-results\") {\r\n const n = Number.parseInt(args[++i] ?? \"\", 10)\r\n if (!Number.isNaN(n)) opts.maxResults = n\r\n i++; continue\r\n }\r\n\r\n if (arg === \"--ignore-file\") {\r\n const p = args[++i]\r\n if (p) opts.ignoreFiles.push(p)\r\n i++; continue\r\n }\r\n\r\n // Accept and ignore color flags\r\n if (arg === \"--color\" || arg === \"--colour\") {\r\n i += 2; continue\r\n }\r\n if (arg.startsWith(\"--color=\") || arg.startsWith(\"--colour=\")) {\r\n i++; continue\r\n }\r\n\r\n // Accept and ignore some other common flags\r\n if (arg === \"-L\" || arg === \"--follow\") { i++; continue }\r\n if (arg === \"-s\" || arg === \"--case-sensitive\") { i++; continue }\r\n if (arg === \"-i\" || arg === \"--ignore-case\") { i++; continue }\r\n if (arg === \"-S\" || arg === \"--smart-case\") { i++; continue }\r\n\r\n // Version/help\r\n if (arg === \"--version\" || arg === \"-V\") {\r\n return { error: \"__version__\" }\r\n }\r\n if (arg === \"--help\" || arg === \"-h\") {\r\n return { error: \"__help__\" }\r\n }\r\n\r\n if (arg.startsWith(\"-\")) {\r\n return { error: `Unknown flag: ${arg}` }\r\n }\r\n\r\n positional.push(arg)\r\n i++\r\n }\r\n\r\n if (positional.length > 0) {\r\n opts.pattern = positional[0]\r\n opts.searchPaths = positional.slice(1)\r\n }\r\n\r\n return { options: opts }\r\n}\r\n\r\n/** Convert a glob pattern to a RegExp */\r\nfunction globToRegex(pattern: string): RegExp {\r\n let regex = \"\"\r\n let i = 0\r\n while (i < pattern.length) {\r\n const ch = pattern[i]\r\n if (ch === \"*\") {\r\n if (pattern[i + 1] === \"*\") {\r\n // ** matches everything including slashes\r\n regex += \".*\"\r\n i += 2\r\n if (pattern[i] === \"/\") i++ // skip trailing slash after **\r\n continue\r\n }\r\n regex += \"[^/]*\"\r\n } else if (ch === \"?\") {\r\n regex += \"[^/]\"\r\n } else if (ch === \"[\") {\r\n const close = pattern.indexOf(\"]\", i + 1)\r\n if (close !== -1) {\r\n regex += pattern.slice(i, close + 1)\r\n i = close + 1\r\n continue\r\n }\r\n regex += \"\\\\[\"\r\n } else if (ch === \"{\") {\r\n const close = pattern.indexOf(\"}\", i + 1)\r\n if (close !== -1) {\r\n const alternatives = pattern.slice(i + 1, close).split(\",\").map(a => a.trim())\r\n regex += `(?:${alternatives.map(escapeRegex).join(\"|\")})`\r\n i = close + 1\r\n continue\r\n }\r\n regex += \"\\\\{\"\r\n } else if (\".+^$|()\\\\\".includes(ch)) {\r\n regex += `\\\\${ch}`\r\n } else {\r\n regex += ch\r\n }\r\n i++\r\n }\r\n return new RegExp(`^${regex}$`, \"i\")\r\n}\r\n\r\nfunction escapeRegex(s: string): string {\r\n return s.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\")\r\n}\r\n\r\ntype IgnoreMatcher = (relPath: string, isDir: boolean) => boolean\r\n\r\nasync function loadIgnoreFile(\r\n fs: { readFile(path: string): Promise<string> },\r\n filePath: string,\r\n): Promise<IgnoreMatcher[]> {\r\n let content: string\r\n try {\r\n content = await fs.readFile(filePath)\r\n } catch {\r\n return []\r\n }\r\n\r\n const matchers: IgnoreMatcher[] = []\r\n for (const raw of content.split(\"\\n\")) {\r\n const line = raw.trim()\r\n if (!line || line.startsWith(\"#\")) continue\r\n if (line.startsWith(\"!\")) continue // negation not supported in this simple impl\r\n\r\n let pattern = line\r\n const dirOnly = pattern.endsWith(\"/\")\r\n if (dirOnly) pattern = pattern.slice(0, -1)\r\n\r\n const re = globToRegex(pattern)\r\n matchers.push((relPath, isDir) => {\r\n if (dirOnly && !isDir) return false\r\n // Match against the basename or full path\r\n const basename = relPath.split(\"/\").pop() ?? relPath\r\n return re.test(basename) || re.test(relPath)\r\n })\r\n }\r\n return matchers\r\n}\r\n\r\nfunction resolvePath(base: string, rel: string): string {\r\n const p = rel.startsWith(\"/\") ? rel : `${base}/${rel}`\r\n const parts = p.split(\"/\").filter(Boolean)\r\n const result: string[] = []\r\n for (const part of parts) {\r\n if (part === \"..\") result.pop()\r\n else if (part !== \".\") result.push(part)\r\n }\r\n return `/${result.join(\"/\")}`\r\n}\r\n\r\nexport async function executeFd(args: string[], ctx: CommandContext): Promise<ExecResult> {\r\n const parsed = parseFdArgs(args)\r\n\r\n if (\"error\" in parsed) {\r\n if (parsed.error === \"__version__\") {\r\n return { stdout: \"fd 10.2.0 (just-bash)\\n\", stderr: \"\", exitCode: 0 }\r\n }\r\n if (parsed.error === \"__help__\") {\r\n return {\r\n stdout: [\r\n \"Usage: fd [OPTIONS] [pattern] [path...]\",\r\n \"\",\r\n \"Options:\",\r\n \" -H, --hidden Include hidden files/directories\",\r\n \" -I, --no-ignore Don't respect .gitignore\",\r\n \" -g, --glob Glob-based search\",\r\n \" -F, --fixed-strings Literal string search\",\r\n \" -t, --type <type> Filter by type: f(ile), d(irectory)\",\r\n \" -e, --extension <ext> Filter by extension\",\r\n \" -E, --exclude <pat> Exclude pattern\",\r\n \" -d, --max-depth <n> Maximum search depth\",\r\n \" --max-results <n> Maximum number of results\",\r\n \" -a, --absolute-path Show absolute paths\",\r\n \" -p, --full-path Match against full path\",\r\n \" --ignore-file <f> Additional ignore file\",\r\n \" --color <when> (always off in browser)\",\r\n \" -1 Stop after first result\",\r\n \"\",\r\n ].join(\"\\n\"),\r\n stderr: \"\",\r\n exitCode: 0,\r\n }\r\n }\r\n return { stdout: \"\", stderr: `error: ${parsed.error}\\n`, exitCode: 1 }\r\n }\r\n\r\n const opts = parsed.options\r\n const fs = ctx.fs\r\n const cwd = ctx.cwd ?? \"/\"\r\n const searchRoots = opts.searchPaths.length > 0\r\n ? opts.searchPaths.map(p => resolvePath(cwd, p))\r\n : [cwd]\r\n\r\n // Build the match regex from the pattern\r\n let matchRegex: RegExp | null = null\r\n if (opts.pattern) {\r\n if (opts.fixedStrings) {\r\n matchRegex = new RegExp(escapeRegex(opts.pattern), \"i\")\r\n } else if (opts.glob) {\r\n matchRegex = globToRegex(opts.pattern)\r\n } else {\r\n try {\r\n matchRegex = new RegExp(opts.pattern, \"i\")\r\n } catch {\r\n return { stdout: \"\", stderr: `error: invalid regex: ${opts.pattern}\\n`, exitCode: 1 }\r\n }\r\n }\r\n }\r\n\r\n // Build exclude matchers\r\n const excludeMatchers = opts.excludes.map(p => globToRegex(p))\r\n\r\n // Load additional ignore files\r\n const ignoreMatchers: IgnoreMatcher[] = []\r\n for (const ignoreFile of opts.ignoreFiles) {\r\n const absPath = resolvePath(cwd, ignoreFile)\r\n const loaded = await loadIgnoreFile(fs, absPath)\r\n ignoreMatchers.push(...loaded)\r\n }\r\n\r\n const results: string[] = []\r\n let limitReached = false\r\n\r\n async function walk(dirPath: string, rootPath: string, depth: number): Promise<void> {\r\n if (limitReached) return\r\n if (depth > opts.maxDepth) return\r\n\r\n let entries: string[]\r\n try {\r\n entries = await fs.readdir(dirPath)\r\n } catch {\r\n return\r\n }\r\n\r\n for (const entry of entries) {\r\n if (limitReached) return\r\n\r\n // Skip hidden files unless --hidden\r\n if (!opts.hidden && entry.startsWith(\".\")) continue\r\n\r\n const fullPath = `${dirPath}/${entry}`\r\n let isDir = false\r\n let isFile = false\r\n try {\r\n const st = await fs.stat(fullPath)\r\n isDir = st.isDirectory\r\n isFile = st.isFile\r\n } catch {\r\n continue\r\n }\r\n\r\n const relPath = fullPath.slice(rootPath.length + 1) || entry\r\n\r\n // Check ignores\r\n if (!opts.noIgnore && ignoreMatchers.some(m => m(relPath, isDir))) continue\r\n\r\n // Check excludes\r\n const basename = entry\r\n if (excludeMatchers.some(re => re.test(basename) || re.test(relPath))) continue\r\n\r\n // Type filter\r\n if (opts.typeFilter === \"f\" && !isFile) {\r\n if (isDir) await walk(fullPath, rootPath, depth + 1)\r\n continue\r\n }\r\n if (opts.typeFilter === \"d\" && !isDir) continue\r\n\r\n // Extension filter\r\n if (opts.extensions.length > 0) {\r\n const dotIdx = entry.lastIndexOf(\".\")\r\n const ext = dotIdx >= 0 ? entry.slice(dotIdx + 1) : \"\"\r\n if (!opts.extensions.some(e => e.toLowerCase() === ext.toLowerCase())) {\r\n if (isDir) await walk(fullPath, rootPath, depth + 1)\r\n continue\r\n }\r\n }\r\n\r\n // Pattern matching\r\n if (matchRegex) {\r\n const target = opts.fullPath ? relPath : basename\r\n if (!matchRegex.test(target)) {\r\n if (isDir) await walk(fullPath, rootPath, depth + 1)\r\n continue\r\n }\r\n }\r\n\r\n // This entry matches\r\n const output = opts.absolutePath ? fullPath : relPath\r\n results.push(output)\r\n if (results.length >= opts.maxResults) {\r\n limitReached = true\r\n return\r\n }\r\n\r\n // Recurse into directories\r\n if (isDir) {\r\n await walk(fullPath, rootPath, depth + 1)\r\n }\r\n }\r\n }\r\n\r\n for (const root of searchRoots) {\r\n if (limitReached) break\r\n try {\r\n const st = await fs.stat(root)\r\n if (!st.isDirectory) {\r\n return { stdout: \"\", stderr: `error: '${root}' is not a directory\\n`, exitCode: 1 }\r\n }\r\n } catch {\r\n return { stdout: \"\", stderr: `error: '${root}': No such file or directory\\n`, exitCode: 1 }\r\n }\r\n\r\n // Load root-level gitignore for this search root\r\n if (!opts.noIgnore) {\r\n const rootGitignore = `${root}/.gitignore`\r\n const loaded = await loadIgnoreFile(fs, rootGitignore)\r\n ignoreMatchers.push(...loaded)\r\n }\r\n\r\n await walk(root, root, 1)\r\n }\r\n\r\n results.sort()\r\n\r\n if (results.length === 0) {\r\n return { stdout: \"\", stderr: \"\", exitCode: 1 }\r\n }\r\n\r\n return { stdout: results.join(\"\\n\") + \"\\n\", stderr: \"\", exitCode: 0 }\r\n}\r\n","import type { ToolResult } from \"./types\"\r\nimport { Bash, defineCommand, type CustomCommand } from \"just-bash/browser\"\r\n\r\nimport {\r\n ObservableInMemoryFs,\r\n type ObservableInMemoryFsOptions,\r\n} from \"./observable-in-memory-fs\"\r\nimport { executeFd } from \"./fd-command\"\r\n\r\nimport type { AlmostNodeSession } from \"./almostnode-session\"\r\nimport type { PyodideSession } from \"./pyodide-session\"\r\n\r\nexport const DEFAULT_BASH_SHELL_ENV = {\r\n LANG: \"C.UTF-8\",\r\n LC_ALL: \"C.UTF-8\",\r\n PYTHONIOENCODING: \"utf-8\",\r\n PYTHONUTF8: \"1\",\r\n PI_OFFLINE: \"1\",\r\n} as const\r\n\r\nconst DEFAULT_BASH_COMMAND_TIMEOUT_MS = 5 * 60 * 1000\r\nconst DEFAULT_BASH_OUTPUT_LIMIT = 10_000\r\n\r\nexport type BrowserBashSession = {\r\n fs: ObservableInMemoryFs\r\n bash: Bash\r\n rootPath: string\r\n cwd: string\r\n setStdoutWriter: (writer: ((data: string) => void) | undefined) => void\r\n writeStdin: (data: string) => void\r\n setTerminalSize: (columns: number, rows: number) => void\r\n dispose: () => void\r\n}\r\n\r\ntype BrowserBashSessionOptions = {\r\n /** Root path in the virtual filesystem (default: \"/workspace\") */\r\n rootPath?: string\r\n /** Shell environment variables */\r\n env?: Record<string, string>\r\n /** Options for the ObservableInMemoryFs */\r\n fsOptions?: ObservableInMemoryFsOptions\r\n /** Enable Node.js runtime (node, npm commands). Lazy-loaded on first use. (default: false) */\r\n node?: boolean\r\n /** Enable Python runtime via Pyodide (python, python3, pip commands). Lazy-loaded on first use. (default: false) */\r\n python?: boolean\r\n /** Additional custom commands to register alongside the built-in commands */\r\n customCommands?: CustomCommand[]\r\n}\r\n\r\ntype ExecuteBrowserBashOptions = {\r\n /** Whether to truncate command output (default: true) */\r\n truncateOutput?: boolean\r\n /** Abort signal for cancellation */\r\n signal?: AbortSignal\r\n /** Command timeout in ms (default: DEFAULT_BASH_COMMAND_TIMEOUT_MS) */\r\n commandTimeoutMs?: number\r\n /** Output truncation limit (default: DEFAULT_BASH_OUTPUT_LIMIT) */\r\n outputLimit?: number\r\n}\r\n\r\n/** Normalize a filesystem path to POSIX form */\r\nfunction normalizeBashPath(input: string): string {\r\n const posixPath = input.trim().replace(/\\\\/g, \"/\") || \"/\"\r\n const segments: string[] = []\r\n const isAbsolute = posixPath.startsWith(\"/\")\r\n for (const segment of posixPath.split(\"/\")) {\r\n if (segment === \"..\") {\r\n segments.pop()\r\n } else if (segment !== \".\" && segment !== \"\") {\r\n segments.push(segment)\r\n }\r\n }\r\n return (isAbsolute ? \"/\" : \"\") + segments.join(\"/\") || \"/\"\r\n}\r\n\r\n/** Truncate command output to a byte limit */\r\nfunction truncateBashOutput(output: string, limitBytes = DEFAULT_BASH_OUTPUT_LIMIT): string {\r\n if (!output || output.length <= limitBytes) {\r\n return output\r\n }\r\n\r\n const headBytes = Math.ceil(limitBytes * 0.3)\r\n const tailBytes = limitBytes - headBytes\r\n const omittedBytes = output.length - headBytes - tailBytes\r\n return `${output.slice(0, headBytes)}\\n\\n... [${omittedBytes} bytes truncated] ...\\n\\n${output.slice(-tailBytes)}`\r\n}\r\n\r\n/** Create a browser-based bash session with in-memory filesystem */\r\nexport function createBrowserBashSession(options: BrowserBashSessionOptions = {}): BrowserBashSession {\r\n const rootPath = normalizeBashPath(options.rootPath ?? \"/workspace\")\r\n const env = options.env ?? { ...DEFAULT_BASH_SHELL_ENV }\r\n\r\n const fs = new ObservableInMemoryFs(options.fsOptions)\r\n fs.mkdirSync(rootPath, { recursive: true })\r\n\r\n // Pre-create tool shim files at the paths pi-coding-agent expects\r\n // (almostnode's os.homedir() returns \"/home/user\")\r\n // This makes getToolPath() find the tools via existsSync() so no\r\n // download is attempted. The grep tool's spawn() then goes through\r\n // just-bash which has a built-in rg implementation.\r\n const piBinDir = \"/home/user/.pi/agent/bin\"\r\n fs.mkdirSync(piBinDir, { recursive: true })\r\n fs.writeFileSync(`${piBinDir}/rg`, \"#!/bin/sh\\nrg \\\"$@\\\"\\n\")\r\n fs.writeFileSync(`${piBinDir}/fd`, \"#!/bin/sh\\nfd \\\"$@\\\"\\n\")\r\n\r\n // Lazy-loaded runtime sessions\r\n let almostNodeSession: AlmostNodeSession | null = null\r\n let almostNodeSessionPromise: Promise<AlmostNodeSession> | null = null\r\n let pyodideSession: PyodideSession | null = null\r\n let pyodideSessionPromise: Promise<PyodideSession> | null = null\r\n\r\n async function getAlmostNodeSession(): Promise<AlmostNodeSession> {\r\n if (almostNodeSession) return almostNodeSession\r\n if (almostNodeSessionPromise) return almostNodeSessionPromise\r\n almostNodeSessionPromise = import(\"./almostnode-session\").then(({ createAlmostNodeSession }) => {\r\n almostNodeSession = createAlmostNodeSession(fs)\r\n almostNodeSession.setBinCommandRegistrar((name, handler) => {\r\n bash.registerCommand(defineCommand(name, handler))\r\n })\r\n if (currentStdoutWriter) almostNodeSession.setStdoutWriter(currentStdoutWriter)\r\n return almostNodeSession\r\n })\r\n return almostNodeSessionPromise\r\n }\r\n\r\n async function getPyodideSession(): Promise<PyodideSession> {\r\n if (pyodideSession) return pyodideSession\r\n if (pyodideSessionPromise) return pyodideSessionPromise\r\n pyodideSessionPromise = import(\"./pyodide-session\").then(({ createPyodideSession }) => {\r\n pyodideSession = createPyodideSession(fs)\r\n if (currentStdoutWriter) pyodideSession.setStdoutWriter(currentStdoutWriter)\r\n return pyodideSession\r\n })\r\n return pyodideSessionPromise\r\n }\r\n\r\n let currentStdoutWriter: ((data: string) => void) | undefined\r\n\r\n // Build custom commands based on enabled runtimes\r\n const runtimeCommands: CustomCommand[] = []\r\n\r\n if (options.node) {\r\n runtimeCommands.push(\r\n defineCommand(\"node\", async (args, ctx) => (await getAlmostNodeSession()).executeNode(args, ctx)),\r\n defineCommand(\"npm\", async (args, ctx) => (await getAlmostNodeSession()).executeNpm(args, ctx)),\r\n )\r\n }\r\n\r\n if (options.python) {\r\n runtimeCommands.push(\r\n defineCommand(\"python\", async (args, ctx) => (await getPyodideSession()).executePython(args, ctx)),\r\n defineCommand(\"python3\", async (args, ctx) => (await getPyodideSession()).executePython(args, ctx)),\r\n defineCommand(\"pip\", async (args, ctx) => (await getPyodideSession()).executePip(args, ctx)),\r\n )\r\n }\r\n\r\n const bash = new Bash({\r\n cwd: rootPath,\r\n env: { ...env },\r\n fs,\r\n customCommands: [\r\n ...runtimeCommands,\r\n defineCommand(\"fd\", async (args, ctx) => executeFd(args, ctx)),\r\n ...(options.customCommands ?? []),\r\n ],\r\n })\r\n\r\n return {\r\n fs,\r\n bash,\r\n rootPath,\r\n cwd: rootPath,\r\n setStdoutWriter: (writer) => {\r\n currentStdoutWriter = writer\r\n almostNodeSession?.setStdoutWriter(writer)\r\n pyodideSession?.setStdoutWriter(writer)\r\n },\r\n writeStdin: (data) => almostNodeSession?.writeStdin(data),\r\n setTerminalSize: (columns, rows) => almostNodeSession?.setTerminalSize(columns, rows),\r\n dispose: () => {\r\n almostNodeSession?.dispose()\r\n pyodideSession?.dispose()\r\n },\r\n }\r\n}\r\n\r\n/** Execute a bash command and return a ToolResult */\r\nexport async function executeBrowserBash(\r\n session: BrowserBashSession,\r\n command: string,\r\n options: ExecuteBrowserBashOptions = {},\r\n): Promise<ToolResult> {\r\n const trimmedCommand = command.trim()\r\n if (!trimmedCommand) {\r\n return { success: false, error: \"Command is required\", stderr: \"Command is required\", exit_code: 1, command: trimmedCommand, backend: \"just-bash\" }\r\n }\r\n\r\n const startedAt = Date.now()\r\n const outputLimit = options.outputLimit ?? DEFAULT_BASH_OUTPUT_LIMIT\r\n const timeoutMs = options.commandTimeoutMs ?? DEFAULT_BASH_COMMAND_TIMEOUT_MS\r\n\r\n const timeoutController = new AbortController()\r\n const combinedController = new AbortController()\r\n const abort = (reason?: unknown) => {\r\n combinedController.abort(reason instanceof Error ? reason : new Error(String(reason ?? \"Command aborted\")))\r\n }\r\n\r\n if (options.signal) {\r\n if (options.signal.aborted) {\r\n abort(options.signal.reason)\r\n } else {\r\n options.signal.addEventListener(\"abort\", () => abort(options.signal!.reason), { once: true })\r\n }\r\n }\r\n\r\n timeoutController.signal.addEventListener(\"abort\", () => abort(timeoutController.signal.reason), { once: true })\r\n const timeoutId = globalThis.setTimeout(() => {\r\n timeoutController.abort(new Error(`Command timed out after ${timeoutMs}ms`))\r\n }, timeoutMs)\r\n\r\n try {\r\n const result = await session.bash.exec(trimmedCommand, {\r\n cwd: session.cwd,\r\n env: {\r\n ...DEFAULT_BASH_SHELL_ENV,\r\n PWD: session.cwd,\r\n },\r\n signal: combinedController.signal,\r\n })\r\n\r\n const nextCwd = result.env?.PWD?.trim()\r\n if (nextCwd) {\r\n session.cwd = normalizeBashPath(nextCwd)\r\n }\r\n\r\n const stdout = options.truncateOutput === false ? result.stdout : truncateBashOutput(result.stdout, outputLimit)\r\n const stderr = options.truncateOutput === false ? result.stderr : truncateBashOutput(result.stderr, outputLimit)\r\n const error = result.exitCode === 0 ? undefined : stderr || undefined\r\n\r\n return {\r\n success: result.exitCode === 0,\r\n command: trimmedCommand,\r\n stdout,\r\n stderr,\r\n output: stdout,\r\n exit_code: result.exitCode,\r\n duration_ms: Date.now() - startedAt,\r\n backend: \"just-bash\",\r\n ...(error ? { error } : {}),\r\n }\r\n } catch (error) {\r\n const message = error instanceof Error ? error.message : String(error)\r\n return { success: false, command: trimmedCommand, error: message, stderr: message, exit_code: 1, duration_ms: Date.now() - startedAt, backend: \"just-bash\" }\r\n } finally {\r\n globalThis.clearTimeout(timeoutId)\r\n }\r\n}\r\n","export const AGENT_WEB_OS_VERSION = \"0.3.0-beta.0\"\r\nconsole.log(`[agent-web-os] v${AGENT_WEB_OS_VERSION}`)\r\n\r\nexport {\r\n ObservableInMemoryFs,\r\n assertObservableInMemoryFs,\r\n type ObservableInMemoryFsOptions,\r\n type ObservableInMemoryFsChangeEvent,\r\n type ObservableInMemoryFsChangeEventName,\r\n} from \"./observable-in-memory-fs\"\r\n\r\nexport {\r\n createBrowserBashSession,\r\n executeBrowserBash,\r\n DEFAULT_BASH_SHELL_ENV,\r\n type BrowserBashSession,\r\n} from \"./browser-bash-session\"\r\n\r\nexport { executeFd } from \"./fd-command\"\r\n\r\nexport type { ToolResult } from \"./types\"\r\n\r\n// Re-export just-bash/browser symbols so consumers don't need just-bash directly\r\nexport { Bash, defineCommand } from \"just-bash/browser\"\r\nexport type { CommandContext, ExecResult, CustomCommand } from \"just-bash/browser\"\r\n\r\n// Re-export almostnode server-bridge utilities\r\nimport { getServerBridge as _getServerBridge, resetServerBridge as _resetServerBridge } from \"almostnode\"\r\n\r\nexport type ServerBridge = {\r\n initServiceWorker(): Promise<void>\r\n registerServer(server: unknown, port: number): void\r\n unregisterServer(port: number): void\r\n getServerUrl(port: number): string\r\n}\r\n\r\nexport const getServerBridge: () => ServerBridge = _getServerBridge\r\nexport const resetServerBridge: () => void = _resetServerBridge\r\n"],"mappings":"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","names":["normalizedSourcePath","normalizedDestinationPath","posixPath","getServerBridge","resetServerBridge"]}
|
|
1
|
+
{"version":3,"sources":["../src/observable-in-memory-fs.ts","../src/fd-command.ts","../src/browser-bash-session.ts","../src/index.ts"],"sourcesContent":["import {\n InMemoryFs,\n type CpOptions,\n type FileContent,\n type MkdirOptions,\n type RmOptions,\n} from \"just-bash\"\nimport { posixPath as path } from \"./posix-path\"\n\ntype ObservableInMemoryFsWriteFileSyncOptions = Parameters<InMemoryFs[\"writeFileSync\"]>[2]\ntype ObservableInMemoryFsWriteFileSyncMetadata = Parameters<InMemoryFs[\"writeFileSync\"]>[3]\ntype ObservableInMemoryFsWriteFileLazy = Parameters<InMemoryFs[\"writeFileLazy\"]>[1]\ntype ObservableInMemoryFsWriteFileLazyMetadata = Parameters<InMemoryFs[\"writeFileLazy\"]>[2]\ntype ObservableInMemoryFsWriteOptions = Parameters<InMemoryFs[\"writeFile\"]>[2]\n\ntype ObservableInMemoryFsEntryType = \"file\" | \"directory\" | \"symlink\"\n\nexport type ObservableInMemoryFsChangeEventName =\n | \"add\"\n | \"addDir\"\n | \"change\"\n | \"unlink\"\n | \"unlinkDir\"\n\nexport type ObservableInMemoryFsChangeEvent = {\n event: ObservableInMemoryFsChangeEventName\n path: string\n entryType: ObservableInMemoryFsEntryType\n previousPath?: string\n}\n\nexport type ObservableInMemoryFsOptions = {\n /** Whether to console.log change events (default: false) */\n consoleLogChanges?: boolean\n /** Root path used to filter which changes are console-logged (default: \"/\") */\n workspaceRoot?: string\n}\n\nfunction isObservableInMemoryFsLike(value: unknown): value is ObservableInMemoryFs {\n if (!value || typeof value !== \"object\") {\n return false\n }\n\n const candidate = value as Partial<Record<keyof ObservableInMemoryFs, unknown>>\n\n return typeof candidate.subscribe === \"function\"\n && typeof candidate.exists === \"function\"\n && typeof candidate.readFile === \"function\"\n && typeof candidate.readdir === \"function\"\n && typeof candidate.stat === \"function\"\n}\n\nexport function assertObservableInMemoryFs(value: unknown): ObservableInMemoryFs {\n if (!isObservableInMemoryFsLike(value)) {\n throw new Error(\"Expected ObservableInMemoryFs-backed just-bash filesystem\")\n }\n\n return value\n}\n\ntype ObservableInMemoryFsListener = (event: ObservableInMemoryFsChangeEvent) => void\n\ntype ObservableInMemoryFsPathState = {\n exists: boolean\n entryType?: ObservableInMemoryFsEntryType\n}\n\ntype ObservableInMemoryFsEmitOptions = {\n shouldConsoleLog?: boolean\n}\n\nasync function readPathState(\n fs: InMemoryFs,\n path: string,\n): Promise<ObservableInMemoryFsPathState> {\n const exists = await fs.exists(path)\n if (!exists) {\n return { exists: false }\n }\n\n if (isObservableInMemoryFsLike(fs) && fs.isPathLazy(path)) {\n return {\n exists: true,\n entryType: \"file\",\n }\n }\n\n try {\n const stat = await fs.lstat(path)\n const entryType: ObservableInMemoryFsEntryType = stat.isDirectory\n ? \"directory\"\n : stat.isSymbolicLink\n ? \"symlink\"\n : \"file\"\n return {\n exists: true,\n entryType,\n }\n } catch {\n // Path may have been removed between exists() and lstat() (TOCTOU race)\n return { exists: false }\n }\n}\n\nfunction mapAddEvent(entryType: ObservableInMemoryFsEntryType): ObservableInMemoryFsChangeEventName {\n return entryType === \"directory\" ? \"addDir\" : \"add\"\n}\n\nfunction normalizeFsPathForLogScope(fsPath: string): string {\n const normalized = path.normalize(fsPath)\n return normalized === \".\" ? \"/\" : normalized\n}\n\nexport class ObservableInMemoryFs extends InMemoryFs {\n private listeners: Set<ObservableInMemoryFsListener> | undefined\n private lazyPaths = new Set<string>()\n private suppressSyncEventCount = 0\n private suppressConsoleLogCount = 0\n private suppressChangeEmissionCount = 0\n private readonly consoleLogChanges: boolean\n private readonly isLoggableWorkspacePath: (fsPath: string) => boolean\n\n constructor(options?: ObservableInMemoryFsOptions) {\n super()\n this.consoleLogChanges = options?.consoleLogChanges ?? false\n\n const normalizedWorkspaceRoot = normalizeFsPathForLogScope(options?.workspaceRoot ?? \"/\")\n this.isLoggableWorkspacePath = (fsPath: string) => {\n const normalizedPath = normalizeFsPathForLogScope(fsPath)\n\n if (normalizedPath !== normalizedWorkspaceRoot && !normalizedPath.startsWith(`${normalizedWorkspaceRoot}/`)) {\n return false\n }\n\n const relativePath = path.relative(normalizedWorkspaceRoot, normalizedPath)\n if (!relativePath || relativePath === \".\") {\n return true\n }\n\n return relativePath\n .split(\"/\")\n .every((segment) => segment.length > 0 && !segment.startsWith(\".\"))\n }\n }\n\n isPathLazy(filePath: string): boolean {\n return this.lazyPaths.has(normalizeFsPathForLogScope(filePath))\n }\n\n private clearLazyPath(filePath: string): void {\n this.lazyPaths.delete(normalizeFsPathForLogScope(filePath))\n }\n\n private clearLazyPathsUnder(rootPath: string): void {\n const normalizedRootPath = normalizeFsPathForLogScope(rootPath)\n\n for (const filePath of Array.from(this.lazyPaths)) {\n if (filePath === normalizedRootPath || filePath.startsWith(`${normalizedRootPath}/`)) {\n this.lazyPaths.delete(filePath)\n }\n }\n }\n\n subscribe(listener: ObservableInMemoryFsListener): () => void {\n const listeners = this.listeners ??= new Set<ObservableInMemoryFsListener>()\n listeners.add(listener)\n\n return () => {\n listeners.delete(listener)\n\n if (listeners.size === 0 && this.listeners === listeners) {\n this.listeners = undefined\n }\n }\n }\n\n private shouldEmitChanges(): boolean {\n if (this.suppressChangeEmissionCount > 0) {\n return false\n }\n\n return this.consoleLogChanges || (this.listeners?.size ?? 0) > 0\n }\n\n async suppressObservability<T>(operation: () => Promise<T>): Promise<T> {\n this.suppressChangeEmissionCount += 1\n this.suppressSyncEventCount += 1\n this.suppressConsoleLogCount += 1\n\n try {\n return await operation()\n } finally {\n this.suppressConsoleLogCount -= 1\n this.suppressSyncEventCount -= 1\n this.suppressChangeEmissionCount -= 1\n }\n }\n\n private queueChangeEmission(emission: Promise<void>): void {\n void emission.catch((error: unknown) => {\n console.error(\"[ObservableInMemoryFs] Failed to emit change event\", error)\n })\n }\n\n private areConsoleLogsSuppressed(): boolean {\n return this.suppressConsoleLogCount > 0\n }\n\n private async runWithSuppressedConsoleLogs<T>(operation: () => Promise<T>): Promise<T> {\n this.suppressConsoleLogCount += 1\n\n try {\n return await operation()\n } finally {\n this.suppressConsoleLogCount -= 1\n }\n }\n\n private shouldConsoleLogChangeEvent(event: ObservableInMemoryFsChangeEvent): boolean {\n if (!this.isLoggableWorkspacePath(event.path)) {\n return false\n }\n\n if (event.previousPath && !this.isLoggableWorkspacePath(event.previousPath)) {\n return false\n }\n\n return true\n }\n\n private emit(\n event: ObservableInMemoryFsChangeEvent,\n options?: ObservableInMemoryFsEmitOptions,\n ): void {\n const shouldConsoleLog = options?.shouldConsoleLog ?? this.shouldConsoleLogChangeEvent(event)\n\n if (\n this.consoleLogChanges\n && shouldConsoleLog\n && !this.areConsoleLogsSuppressed()\n ) {\n console.log(`[ObservableInMemoryFs] ${event.event} ${event.entryType} ${event.path}${event.previousPath ? ` (from ${event.previousPath})` : \"\"}`)\n }\n\n if (!this.listeners) {\n return\n }\n\n for (const listener of this.listeners) {\n try {\n listener(event)\n } catch (error: unknown) {\n console.error(\"[ObservableInMemoryFs] Change listener failed\", error)\n }\n }\n }\n\n private areSyncEventsSuppressed(): boolean {\n return this.suppressSyncEventCount > 0\n }\n\n private async runWithSuppressedSyncEvents<T>(operation: () => Promise<T>): Promise<T> {\n this.suppressSyncEventCount += 1\n\n try {\n return await operation()\n } finally {\n this.suppressSyncEventCount -= 1\n }\n }\n\n override writeFileSync(\n path: string,\n content: FileContent,\n options?: ObservableInMemoryFsWriteFileSyncOptions,\n metadata?: ObservableInMemoryFsWriteFileSyncMetadata,\n ): void {\n const previous = this.areSyncEventsSuppressed() || !this.shouldEmitChanges()\n ? null\n : readPathState(this, path)\n\n super.writeFileSync(path, content, options, metadata)\n this.clearLazyPath(path)\n\n if (!previous) {\n return\n }\n\n this.queueChangeEmission(previous.then((state) => this.emitWriteEvent(path, state)))\n }\n\n override writeFileLazy(\n path: string,\n lazy: ObservableInMemoryFsWriteFileLazy,\n metadata?: ObservableInMemoryFsWriteFileLazyMetadata,\n ): void {\n const previous = this.areSyncEventsSuppressed() || !this.shouldEmitChanges()\n ? null\n : readPathState(this, path)\n\n super.writeFileLazy(path, lazy, metadata)\n this.lazyPaths.add(normalizeFsPathForLogScope(path))\n\n if (!previous) {\n return\n }\n\n this.queueChangeEmission(previous.then((state) => this.emitWriteEvent(path, state)))\n }\n\n private async emitWriteEvent(path: string, previous: ObservableInMemoryFsPathState): Promise<void> {\n const current = await readPathState(this, path)\n if (!current.exists || !current.entryType) {\n return\n }\n\n if (!previous.exists) {\n this.emit({\n event: mapAddEvent(current.entryType),\n path,\n entryType: current.entryType,\n })\n return\n }\n\n this.emit({\n event: \"change\",\n path,\n entryType: current.entryType,\n })\n }\n\n private async emitMkdirEvent(path: string, previous: ObservableInMemoryFsPathState): Promise<void> {\n const current = await readPathState(this, path)\n if (!current.exists || current.entryType !== \"directory\" || previous.exists) {\n return\n }\n\n this.emit({\n event: \"addDir\",\n path,\n entryType: \"directory\",\n })\n }\n\n private emitRemovalEvent(\n path: string,\n previous: ObservableInMemoryFsPathState,\n options?: ObservableInMemoryFsEmitOptions,\n ): void {\n if (!previous.exists || !previous.entryType) {\n return\n }\n\n this.emit({\n event: previous.entryType === \"directory\" ? \"unlinkDir\" : \"unlink\",\n path,\n entryType: previous.entryType,\n }, options)\n }\n\n override mkdirSync(path: string, options?: MkdirOptions): void {\n const previous = this.areSyncEventsSuppressed() || !this.shouldEmitChanges()\n ? null\n : readPathState(this, path)\n\n super.mkdirSync(path, options)\n\n if (!previous) {\n return\n }\n\n this.queueChangeEmission(previous.then((state) => this.emitMkdirEvent(path, state)))\n }\n\n override async readFileBuffer(path: string): Promise<Uint8Array> {\n const content = await super.readFileBuffer(path)\n this.clearLazyPath(path)\n return content\n }\n\n override async stat(path: string) {\n const stat = await super.stat(path)\n this.clearLazyPath(path)\n return stat\n }\n\n override async lstat(path: string) {\n const stat = await super.lstat(path)\n this.clearLazyPath(path)\n return stat\n }\n\n override async writeFile(\n path: string,\n content: FileContent,\n options?: ObservableInMemoryFsWriteOptions,\n ): Promise<void> {\n if (!this.shouldEmitChanges()) {\n await super.writeFile(path, content, options)\n return\n }\n\n const previous = await readPathState(this, path)\n await this.runWithSuppressedSyncEvents(() => super.writeFile(path, content, options))\n await this.emitWriteEvent(path, previous)\n }\n\n override async appendFile(\n path: string,\n content: FileContent,\n options?: ObservableInMemoryFsWriteOptions,\n ): Promise<void> {\n if (!this.shouldEmitChanges()) {\n await super.appendFile(path, content, options)\n return\n }\n\n const previous = await readPathState(this, path)\n await this.runWithSuppressedSyncEvents(() => super.appendFile(path, content, options))\n await this.emitWriteEvent(path, previous)\n }\n\n override async mkdir(path: string, options?: MkdirOptions): Promise<void> {\n if (!this.shouldEmitChanges()) {\n await super.mkdir(path, options)\n return\n }\n\n const previous = await readPathState(this, path)\n await this.runWithSuppressedSyncEvents(() => super.mkdir(path, options))\n await this.emitMkdirEvent(path, previous)\n }\n\n override async rm(path: string, options?: RmOptions): Promise<void> {\n if (!this.shouldEmitChanges()) {\n await super.rm(path, options)\n this.clearLazyPathsUnder(path)\n return\n }\n\n const previous = await readPathState(this, path)\n await super.rm(path, options)\n this.clearLazyPathsUnder(path)\n this.emitRemovalEvent(path, previous)\n }\n\n override async cp(src: string, dest: string, options?: CpOptions): Promise<void> {\n if (!this.shouldEmitChanges()) {\n await super.cp(src, dest, options)\n this.clearLazyPathsUnder(dest)\n return\n }\n\n const previous = await readPathState(this, dest)\n await super.cp(src, dest, options)\n this.clearLazyPathsUnder(dest)\n const current = await readPathState(this, dest)\n\n if (!current.exists || !current.entryType) {\n return\n }\n\n this.emit({\n event: previous.exists ? \"change\" : mapAddEvent(current.entryType),\n path: dest,\n entryType: current.entryType,\n })\n }\n\n override async mv(src: string, dest: string): Promise<void> {\n if (!this.shouldEmitChanges()) {\n await super.mv(src, dest)\n const normalizedSourcePath = normalizeFsPathForLogScope(src)\n const normalizedDestinationPath = normalizeFsPathForLogScope(dest)\n this.clearLazyPathsUnder(normalizedDestinationPath)\n\n for (const filePath of Array.from(this.lazyPaths)) {\n if (filePath === normalizedSourcePath || filePath.startsWith(`${normalizedSourcePath}/`)) {\n this.lazyPaths.delete(filePath)\n this.lazyPaths.add(`${normalizedDestinationPath}${filePath.slice(normalizedSourcePath.length)}`)\n }\n }\n return\n }\n\n const sourceState = await readPathState(this, src)\n const destinationState = await readPathState(this, dest)\n const shouldConsoleLogMove = this.shouldConsoleLogChangeEvent({\n event: destinationState.exists ? \"change\" : mapAddEvent(sourceState.entryType ?? \"file\"),\n path: dest,\n previousPath: src,\n entryType: sourceState.entryType ?? \"file\",\n })\n\n if (shouldConsoleLogMove) {\n await super.mv(src, dest)\n } else {\n await this.runWithSuppressedConsoleLogs(() => super.mv(src, dest))\n }\n\n const normalizedSourcePath = normalizeFsPathForLogScope(src)\n const normalizedDestinationPath = normalizeFsPathForLogScope(dest)\n this.clearLazyPathsUnder(normalizedDestinationPath)\n\n for (const filePath of Array.from(this.lazyPaths)) {\n if (filePath === normalizedSourcePath || filePath.startsWith(`${normalizedSourcePath}/`)) {\n this.lazyPaths.delete(filePath)\n this.lazyPaths.add(`${normalizedDestinationPath}${filePath.slice(normalizedSourcePath.length)}`)\n }\n }\n\n this.emitRemovalEvent(src, sourceState, {\n shouldConsoleLog: shouldConsoleLogMove,\n })\n\n const currentDestinationState = await readPathState(this, dest)\n if (!currentDestinationState.exists || !currentDestinationState.entryType) {\n return\n }\n\n this.emit({\n event: destinationState.exists ? \"change\" : mapAddEvent(currentDestinationState.entryType),\n path: dest,\n previousPath: src,\n entryType: currentDestinationState.entryType,\n }, {\n shouldConsoleLog: shouldConsoleLogMove,\n })\n }\n\n override async chmod(path: string, mode: number): Promise<void> {\n if (!this.shouldEmitChanges()) {\n await super.chmod(path, mode)\n return\n }\n\n await super.chmod(path, mode)\n\n const current = await readPathState(this, path)\n if (!current.exists || !current.entryType) {\n return\n }\n\n this.emit({\n event: \"change\",\n path,\n entryType: current.entryType,\n })\n }\n\n override async symlink(target: string, linkPath: string): Promise<void> {\n if (!this.shouldEmitChanges()) {\n await super.symlink(target, linkPath)\n return\n }\n\n const previous = await readPathState(this, linkPath)\n await super.symlink(target, linkPath)\n await this.emitWriteEvent(linkPath, previous)\n }\n\n override async link(existingPath: string, newPath: string): Promise<void> {\n if (!this.shouldEmitChanges()) {\n await super.link(existingPath, newPath)\n return\n }\n\n const previous = await readPathState(this, newPath)\n await super.link(existingPath, newPath)\n await this.emitWriteEvent(newPath, previous)\n }\n\n override async utimes(path: string, atime: Date, mtime: Date): Promise<void> {\n if (!this.shouldEmitChanges()) {\n await super.utimes(path, atime, mtime)\n return\n }\n\n await super.utimes(path, atime, mtime)\n\n const current = await readPathState(this, path)\n if (!current.exists || !current.entryType) {\n return\n }\n\n this.emit({\n event: \"change\",\n path,\n entryType: current.entryType,\n })\n }\n}\n","/**\r\n * `fd` command implementation for just-bash.\r\n *\r\n * A simplified browser-compatible implementation of https://github.com/sharkdp/fd\r\n * Supports the flags that pi-coding-agent's find tool uses:\r\n * fd [FLAGS] [pattern] [path...]\r\n *\r\n * Flags:\r\n * --glob / -g Treat pattern as glob (default: regex)\r\n * --fixed-strings / -F Treat pattern as literal string\r\n * --hidden / -H Include hidden files/directories\r\n * --no-ignore / -I Don't respect .gitignore\r\n * --type / -t f|d Filter by type (f=file, d=directory)\r\n * --extension / -e ext Filter by extension\r\n * --exclude PATTERN Exclude entries matching glob\r\n * --max-depth / -d N Maximum search depth\r\n * --max-results N Stop after N results\r\n * --color never (accepted, always off)\r\n * --ignore-file PATH Additional ignore file\r\n * --absolute-path / -a Print absolute paths\r\n * --full-path / -p Match pattern against full path\r\n * -1 Stop after first result\r\n */\r\n\r\nimport type { CommandContext, ExecResult } from \"just-bash/browser\"\r\n\r\ninterface FdOptions {\r\n glob: boolean\r\n fixedStrings: boolean\r\n hidden: boolean\r\n noIgnore: boolean\r\n typeFilter: \"f\" | \"d\" | null\r\n extensions: string[]\r\n excludes: string[]\r\n maxDepth: number\r\n maxResults: number\r\n ignoreFiles: string[]\r\n absolutePath: boolean\r\n fullPath: boolean\r\n pattern: string\r\n searchPaths: string[]\r\n}\r\n\r\nfunction parseFdArgs(args: string[]): { options: FdOptions } | { error: string } {\r\n const opts: FdOptions = {\r\n glob: false,\r\n fixedStrings: false,\r\n hidden: false,\r\n noIgnore: false,\r\n typeFilter: null,\r\n extensions: [],\r\n excludes: [],\r\n maxDepth: Infinity,\r\n maxResults: Infinity,\r\n ignoreFiles: [],\r\n absolutePath: false,\r\n fullPath: false,\r\n pattern: \"\",\r\n searchPaths: [],\r\n }\r\n\r\n const positional: string[] = []\r\n let i = 0\r\n\r\n while (i < args.length) {\r\n const arg = args[i]\r\n\r\n if (arg === \"--\") {\r\n positional.push(...args.slice(i + 1))\r\n break\r\n }\r\n\r\n if (arg === \"--glob\" || arg === \"-g\") { opts.glob = true; i++; continue }\r\n if (arg === \"--fixed-strings\" || arg === \"-F\") { opts.fixedStrings = true; i++; continue }\r\n if (arg === \"--hidden\" || arg === \"-H\") { opts.hidden = true; i++; continue }\r\n if (arg === \"--no-ignore\" || arg === \"-I\") { opts.noIgnore = true; i++; continue }\r\n if (arg === \"--absolute-path\" || arg === \"-a\") { opts.absolutePath = true; i++; continue }\r\n if (arg === \"--full-path\" || arg === \"-p\") { opts.fullPath = true; i++; continue }\r\n if (arg === \"-1\") { opts.maxResults = 1; i++; continue }\r\n\r\n if (arg === \"--type\" || arg === \"-t\") {\r\n const val = args[++i]\r\n if (val === \"f\" || val === \"file\") opts.typeFilter = \"f\"\r\n else if (val === \"d\" || val === \"dir\" || val === \"directory\") opts.typeFilter = \"d\"\r\n i++; continue\r\n }\r\n\r\n if (arg === \"--extension\" || arg === \"-e\") {\r\n const ext = args[++i]\r\n if (ext) opts.extensions.push(ext.startsWith(\".\") ? ext.slice(1) : ext)\r\n i++; continue\r\n }\r\n\r\n if (arg === \"--exclude\" || arg === \"-E\") {\r\n const pat = args[++i]\r\n if (pat) opts.excludes.push(pat)\r\n i++; continue\r\n }\r\n\r\n if (arg === \"--max-depth\" || arg === \"-d\") {\r\n const n = Number.parseInt(args[++i] ?? \"\", 10)\r\n if (!Number.isNaN(n)) opts.maxDepth = n\r\n i++; continue\r\n }\r\n\r\n if (arg === \"--max-results\") {\r\n const n = Number.parseInt(args[++i] ?? \"\", 10)\r\n if (!Number.isNaN(n)) opts.maxResults = n\r\n i++; continue\r\n }\r\n\r\n if (arg === \"--ignore-file\") {\r\n const p = args[++i]\r\n if (p) opts.ignoreFiles.push(p)\r\n i++; continue\r\n }\r\n\r\n // Accept and ignore color flags\r\n if (arg === \"--color\" || arg === \"--colour\") {\r\n i += 2; continue\r\n }\r\n if (arg.startsWith(\"--color=\") || arg.startsWith(\"--colour=\")) {\r\n i++; continue\r\n }\r\n\r\n // Accept and ignore some other common flags\r\n if (arg === \"-L\" || arg === \"--follow\") { i++; continue }\r\n if (arg === \"-s\" || arg === \"--case-sensitive\") { i++; continue }\r\n if (arg === \"-i\" || arg === \"--ignore-case\") { i++; continue }\r\n if (arg === \"-S\" || arg === \"--smart-case\") { i++; continue }\r\n\r\n // Version/help\r\n if (arg === \"--version\" || arg === \"-V\") {\r\n return { error: \"__version__\" }\r\n }\r\n if (arg === \"--help\" || arg === \"-h\") {\r\n return { error: \"__help__\" }\r\n }\r\n\r\n if (arg.startsWith(\"-\")) {\r\n return { error: `Unknown flag: ${arg}` }\r\n }\r\n\r\n positional.push(arg)\r\n i++\r\n }\r\n\r\n if (positional.length > 0) {\r\n opts.pattern = positional[0]\r\n opts.searchPaths = positional.slice(1)\r\n }\r\n\r\n return { options: opts }\r\n}\r\n\r\n/** Convert a glob pattern to a RegExp */\r\nfunction globToRegex(pattern: string): RegExp {\r\n let regex = \"\"\r\n let i = 0\r\n while (i < pattern.length) {\r\n const ch = pattern[i]\r\n if (ch === \"*\") {\r\n if (pattern[i + 1] === \"*\") {\r\n // ** matches everything including slashes\r\n regex += \".*\"\r\n i += 2\r\n if (pattern[i] === \"/\") i++ // skip trailing slash after **\r\n continue\r\n }\r\n regex += \"[^/]*\"\r\n } else if (ch === \"?\") {\r\n regex += \"[^/]\"\r\n } else if (ch === \"[\") {\r\n const close = pattern.indexOf(\"]\", i + 1)\r\n if (close !== -1) {\r\n regex += pattern.slice(i, close + 1)\r\n i = close + 1\r\n continue\r\n }\r\n regex += \"\\\\[\"\r\n } else if (ch === \"{\") {\r\n const close = pattern.indexOf(\"}\", i + 1)\r\n if (close !== -1) {\r\n const alternatives = pattern.slice(i + 1, close).split(\",\").map(a => a.trim())\r\n regex += `(?:${alternatives.map(escapeRegex).join(\"|\")})`\r\n i = close + 1\r\n continue\r\n }\r\n regex += \"\\\\{\"\r\n } else if (\".+^$|()\\\\\".includes(ch)) {\r\n regex += `\\\\${ch}`\r\n } else {\r\n regex += ch\r\n }\r\n i++\r\n }\r\n return new RegExp(`^${regex}$`, \"i\")\r\n}\r\n\r\nfunction escapeRegex(s: string): string {\r\n return s.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\")\r\n}\r\n\r\ntype IgnoreMatcher = (relPath: string, isDir: boolean) => boolean\r\n\r\nasync function loadIgnoreFile(\r\n fs: { readFile(path: string): Promise<string> },\r\n filePath: string,\r\n): Promise<IgnoreMatcher[]> {\r\n let content: string\r\n try {\r\n content = await fs.readFile(filePath)\r\n } catch {\r\n return []\r\n }\r\n\r\n const matchers: IgnoreMatcher[] = []\r\n for (const raw of content.split(\"\\n\")) {\r\n const line = raw.trim()\r\n if (!line || line.startsWith(\"#\")) continue\r\n if (line.startsWith(\"!\")) continue // negation not supported in this simple impl\r\n\r\n let pattern = line\r\n const dirOnly = pattern.endsWith(\"/\")\r\n if (dirOnly) pattern = pattern.slice(0, -1)\r\n\r\n const re = globToRegex(pattern)\r\n matchers.push((relPath, isDir) => {\r\n if (dirOnly && !isDir) return false\r\n // Match against the basename or full path\r\n const basename = relPath.split(\"/\").pop() ?? relPath\r\n return re.test(basename) || re.test(relPath)\r\n })\r\n }\r\n return matchers\r\n}\r\n\r\nfunction resolvePath(base: string, rel: string): string {\r\n const p = rel.startsWith(\"/\") ? rel : `${base}/${rel}`\r\n const parts = p.split(\"/\").filter(Boolean)\r\n const result: string[] = []\r\n for (const part of parts) {\r\n if (part === \"..\") result.pop()\r\n else if (part !== \".\") result.push(part)\r\n }\r\n return `/${result.join(\"/\")}`\r\n}\r\n\r\nexport async function executeFd(args: string[], ctx: CommandContext): Promise<ExecResult> {\r\n const parsed = parseFdArgs(args)\r\n\r\n if (\"error\" in parsed) {\r\n if (parsed.error === \"__version__\") {\r\n return { stdout: \"fd 10.2.0 (just-bash)\\n\", stderr: \"\", exitCode: 0 }\r\n }\r\n if (parsed.error === \"__help__\") {\r\n return {\r\n stdout: [\r\n \"Usage: fd [OPTIONS] [pattern] [path...]\",\r\n \"\",\r\n \"Options:\",\r\n \" -H, --hidden Include hidden files/directories\",\r\n \" -I, --no-ignore Don't respect .gitignore\",\r\n \" -g, --glob Glob-based search\",\r\n \" -F, --fixed-strings Literal string search\",\r\n \" -t, --type <type> Filter by type: f(ile), d(irectory)\",\r\n \" -e, --extension <ext> Filter by extension\",\r\n \" -E, --exclude <pat> Exclude pattern\",\r\n \" -d, --max-depth <n> Maximum search depth\",\r\n \" --max-results <n> Maximum number of results\",\r\n \" -a, --absolute-path Show absolute paths\",\r\n \" -p, --full-path Match against full path\",\r\n \" --ignore-file <f> Additional ignore file\",\r\n \" --color <when> (always off in browser)\",\r\n \" -1 Stop after first result\",\r\n \"\",\r\n ].join(\"\\n\"),\r\n stderr: \"\",\r\n exitCode: 0,\r\n }\r\n }\r\n return { stdout: \"\", stderr: `error: ${parsed.error}\\n`, exitCode: 1 }\r\n }\r\n\r\n const opts = parsed.options\r\n const fs = ctx.fs\r\n const cwd = ctx.cwd ?? \"/\"\r\n const searchRoots = opts.searchPaths.length > 0\r\n ? opts.searchPaths.map(p => resolvePath(cwd, p))\r\n : [cwd]\r\n\r\n // Build the match regex from the pattern\r\n let matchRegex: RegExp | null = null\r\n if (opts.pattern) {\r\n if (opts.fixedStrings) {\r\n matchRegex = new RegExp(escapeRegex(opts.pattern), \"i\")\r\n } else if (opts.glob) {\r\n matchRegex = globToRegex(opts.pattern)\r\n } else {\r\n try {\r\n matchRegex = new RegExp(opts.pattern, \"i\")\r\n } catch {\r\n return { stdout: \"\", stderr: `error: invalid regex: ${opts.pattern}\\n`, exitCode: 1 }\r\n }\r\n }\r\n }\r\n\r\n // Build exclude matchers\r\n const excludeMatchers = opts.excludes.map(p => globToRegex(p))\r\n\r\n // Load additional ignore files\r\n const ignoreMatchers: IgnoreMatcher[] = []\r\n for (const ignoreFile of opts.ignoreFiles) {\r\n const absPath = resolvePath(cwd, ignoreFile)\r\n const loaded = await loadIgnoreFile(fs, absPath)\r\n ignoreMatchers.push(...loaded)\r\n }\r\n\r\n const results: string[] = []\r\n let limitReached = false\r\n\r\n async function walk(dirPath: string, rootPath: string, depth: number): Promise<void> {\r\n if (limitReached) return\r\n if (depth > opts.maxDepth) return\r\n\r\n let entries: string[]\r\n try {\r\n entries = await fs.readdir(dirPath)\r\n } catch {\r\n return\r\n }\r\n\r\n for (const entry of entries) {\r\n if (limitReached) return\r\n\r\n // Skip hidden files unless --hidden\r\n if (!opts.hidden && entry.startsWith(\".\")) continue\r\n\r\n const fullPath = `${dirPath}/${entry}`\r\n let isDir = false\r\n let isFile = false\r\n try {\r\n const st = await fs.stat(fullPath)\r\n isDir = st.isDirectory\r\n isFile = st.isFile\r\n } catch {\r\n continue\r\n }\r\n\r\n const relPath = fullPath.slice(rootPath.length + 1) || entry\r\n\r\n // Check ignores\r\n if (!opts.noIgnore && ignoreMatchers.some(m => m(relPath, isDir))) continue\r\n\r\n // Check excludes\r\n const basename = entry\r\n if (excludeMatchers.some(re => re.test(basename) || re.test(relPath))) continue\r\n\r\n // Type filter\r\n if (opts.typeFilter === \"f\" && !isFile) {\r\n if (isDir) await walk(fullPath, rootPath, depth + 1)\r\n continue\r\n }\r\n if (opts.typeFilter === \"d\" && !isDir) continue\r\n\r\n // Extension filter\r\n if (opts.extensions.length > 0) {\r\n const dotIdx = entry.lastIndexOf(\".\")\r\n const ext = dotIdx >= 0 ? entry.slice(dotIdx + 1) : \"\"\r\n if (!opts.extensions.some(e => e.toLowerCase() === ext.toLowerCase())) {\r\n if (isDir) await walk(fullPath, rootPath, depth + 1)\r\n continue\r\n }\r\n }\r\n\r\n // Pattern matching\r\n if (matchRegex) {\r\n const target = opts.fullPath ? relPath : basename\r\n if (!matchRegex.test(target)) {\r\n if (isDir) await walk(fullPath, rootPath, depth + 1)\r\n continue\r\n }\r\n }\r\n\r\n // This entry matches\r\n const output = opts.absolutePath ? fullPath : relPath\r\n results.push(output)\r\n if (results.length >= opts.maxResults) {\r\n limitReached = true\r\n return\r\n }\r\n\r\n // Recurse into directories\r\n if (isDir) {\r\n await walk(fullPath, rootPath, depth + 1)\r\n }\r\n }\r\n }\r\n\r\n for (const root of searchRoots) {\r\n if (limitReached) break\r\n try {\r\n const st = await fs.stat(root)\r\n if (!st.isDirectory) {\r\n return { stdout: \"\", stderr: `error: '${root}' is not a directory\\n`, exitCode: 1 }\r\n }\r\n } catch {\r\n return { stdout: \"\", stderr: `error: '${root}': No such file or directory\\n`, exitCode: 1 }\r\n }\r\n\r\n // Load root-level gitignore for this search root\r\n if (!opts.noIgnore) {\r\n const rootGitignore = `${root}/.gitignore`\r\n const loaded = await loadIgnoreFile(fs, rootGitignore)\r\n ignoreMatchers.push(...loaded)\r\n }\r\n\r\n await walk(root, root, 1)\r\n }\r\n\r\n results.sort()\r\n\r\n if (results.length === 0) {\r\n return { stdout: \"\", stderr: \"\", exitCode: 1 }\r\n }\r\n\r\n return { stdout: results.join(\"\\n\") + \"\\n\", stderr: \"\", exitCode: 0 }\r\n}\r\n","import type { ToolResult } from \"./types\"\r\nimport { Bash, defineCommand, type CustomCommand } from \"just-bash/browser\"\r\n\r\nimport {\r\n ObservableInMemoryFs,\r\n type ObservableInMemoryFsOptions,\r\n} from \"./observable-in-memory-fs\"\r\nimport { executeFd } from \"./fd-command\"\r\n\r\nimport type { AlmostNodeSession } from \"./almostnode-session\"\r\nimport type { PyodideSession } from \"./pyodide-session\"\r\n\r\nexport const DEFAULT_BASH_SHELL_ENV = {\r\n LANG: \"C.UTF-8\",\r\n LC_ALL: \"C.UTF-8\",\r\n PYTHONIOENCODING: \"utf-8\",\r\n PYTHONUTF8: \"1\",\r\n PI_OFFLINE: \"1\",\r\n} as const\r\n\r\nconst DEFAULT_BASH_COMMAND_TIMEOUT_MS = 5 * 60 * 1000\r\nconst DEFAULT_BASH_OUTPUT_LIMIT = 10_000\r\n\r\nexport type BrowserBashSession = {\r\n fs: ObservableInMemoryFs\r\n bash: Bash\r\n rootPath: string\r\n cwd: string\r\n setStdoutWriter: (writer: ((data: string) => void) | undefined) => void\r\n writeStdin: (data: string) => void\r\n setTerminalSize: (columns: number, rows: number) => void\r\n dispose: () => void\r\n}\r\n\r\ntype BrowserBashSessionOptions = {\r\n /** Root path in the virtual filesystem (default: \"/workspace\") */\r\n rootPath?: string\r\n /** Shell environment variables */\r\n env?: Record<string, string>\r\n /** Options for the ObservableInMemoryFs */\r\n fsOptions?: ObservableInMemoryFsOptions\r\n /** Enable Node.js runtime (node, npm commands). Lazy-loaded on first use. (default: false) */\r\n node?: boolean\r\n /** Enable Python runtime via Pyodide (python, python3, pip commands). Lazy-loaded on first use. (default: false) */\r\n python?: boolean\r\n /** Additional custom commands to register alongside the built-in commands */\r\n customCommands?: CustomCommand[]\r\n}\r\n\r\ntype ExecuteBrowserBashOptions = {\r\n /** Whether to truncate command output (default: true) */\r\n truncateOutput?: boolean\r\n /** Abort signal for cancellation */\r\n signal?: AbortSignal\r\n /** Command timeout in ms (default: DEFAULT_BASH_COMMAND_TIMEOUT_MS) */\r\n commandTimeoutMs?: number\r\n /** Output truncation limit (default: DEFAULT_BASH_OUTPUT_LIMIT) */\r\n outputLimit?: number\r\n}\r\n\r\n/** Normalize a filesystem path to POSIX form */\r\nfunction normalizeBashPath(input: string): string {\r\n const posixPath = input.trim().replace(/\\\\/g, \"/\") || \"/\"\r\n const segments: string[] = []\r\n const isAbsolute = posixPath.startsWith(\"/\")\r\n for (const segment of posixPath.split(\"/\")) {\r\n if (segment === \"..\") {\r\n segments.pop()\r\n } else if (segment !== \".\" && segment !== \"\") {\r\n segments.push(segment)\r\n }\r\n }\r\n return (isAbsolute ? \"/\" : \"\") + segments.join(\"/\") || \"/\"\r\n}\r\n\r\n/** Truncate command output to a byte limit */\r\nfunction truncateBashOutput(output: string, limitBytes = DEFAULT_BASH_OUTPUT_LIMIT): string {\r\n if (!output || output.length <= limitBytes) {\r\n return output\r\n }\r\n\r\n const headBytes = Math.ceil(limitBytes * 0.3)\r\n const tailBytes = limitBytes - headBytes\r\n const omittedBytes = output.length - headBytes - tailBytes\r\n return `${output.slice(0, headBytes)}\\n\\n... [${omittedBytes} bytes truncated] ...\\n\\n${output.slice(-tailBytes)}`\r\n}\r\n\r\n/** Create a browser-based bash session with in-memory filesystem */\r\nexport function createBrowserBashSession(options: BrowserBashSessionOptions = {}): BrowserBashSession {\r\n const rootPath = normalizeBashPath(options.rootPath ?? \"/workspace\")\r\n const env = options.env ?? { ...DEFAULT_BASH_SHELL_ENV }\r\n\r\n const fs = new ObservableInMemoryFs(options.fsOptions)\r\n fs.mkdirSync(rootPath, { recursive: true })\r\n\r\n // Pre-create tool shim files at the paths pi-coding-agent expects\r\n // (almostnode's os.homedir() returns \"/home/user\")\r\n // This makes getToolPath() find the tools via existsSync() so no\r\n // download is attempted. The grep tool's spawn() then goes through\r\n // just-bash which has a built-in rg implementation.\r\n const piBinDir = \"/home/user/.pi/agent/bin\"\r\n fs.mkdirSync(piBinDir, { recursive: true })\r\n fs.writeFileSync(`${piBinDir}/rg`, \"#!/bin/sh\\nrg \\\"$@\\\"\\n\")\r\n fs.writeFileSync(`${piBinDir}/fd`, \"#!/bin/sh\\nfd \\\"$@\\\"\\n\")\r\n\r\n // Lazy-loaded runtime sessions\r\n let almostNodeSession: AlmostNodeSession | null = null\r\n let almostNodeSessionPromise: Promise<AlmostNodeSession> | null = null\r\n let pyodideSession: PyodideSession | null = null\r\n let pyodideSessionPromise: Promise<PyodideSession> | null = null\r\n\r\n async function getAlmostNodeSession(): Promise<AlmostNodeSession> {\r\n if (almostNodeSession) return almostNodeSession\r\n if (almostNodeSessionPromise) return almostNodeSessionPromise\r\n almostNodeSessionPromise = import(\"./almostnode-session\").then((mod) => {\r\n almostNodeSession = new mod.AlmostNodeSession(fs)\r\n almostNodeSession.setBinCommandRegistrar((name, handler) => {\r\n bash.registerCommand(defineCommand(name, handler))\r\n })\r\n if (currentStdoutWriter) almostNodeSession.setStdoutWriter(currentStdoutWriter)\r\n return almostNodeSession\r\n })\r\n return almostNodeSessionPromise\r\n }\r\n\r\n async function getPyodideSession(): Promise<PyodideSession> {\r\n if (pyodideSession) return pyodideSession\r\n if (pyodideSessionPromise) return pyodideSessionPromise\r\n pyodideSessionPromise = import(\"./pyodide-session\").then((mod) => {\r\n pyodideSession = new mod.PyodideSession(fs)\r\n if (currentStdoutWriter) pyodideSession.setStdoutWriter(currentStdoutWriter)\r\n return pyodideSession\r\n })\r\n return pyodideSessionPromise\r\n }\r\n\r\n let currentStdoutWriter: ((data: string) => void) | undefined\r\n\r\n // Build custom commands based on enabled runtimes\r\n const runtimeCommands: CustomCommand[] = []\r\n\r\n if (options.node) {\r\n runtimeCommands.push(\r\n defineCommand(\"node\", async (args, ctx) => (await getAlmostNodeSession()).executeNode(args, ctx)),\r\n defineCommand(\"npm\", async (args, ctx) => (await getAlmostNodeSession()).executeNpm(args, ctx)),\r\n )\r\n }\r\n\r\n if (options.python) {\r\n runtimeCommands.push(\r\n defineCommand(\"python\", async (args, ctx) => (await getPyodideSession()).executePython(args, ctx)),\r\n defineCommand(\"python3\", async (args, ctx) => (await getPyodideSession()).executePython(args, ctx)),\r\n defineCommand(\"pip\", async (args, ctx) => (await getPyodideSession()).executePip(args, ctx)),\r\n )\r\n }\r\n\r\n const bash = new Bash({\r\n cwd: rootPath,\r\n env: { ...env },\r\n fs,\r\n customCommands: [\r\n ...runtimeCommands,\r\n defineCommand(\"fd\", async (args, ctx) => executeFd(args, ctx)),\r\n ...(options.customCommands ?? []),\r\n ],\r\n })\r\n\r\n return {\r\n fs,\r\n bash,\r\n rootPath,\r\n cwd: rootPath,\r\n setStdoutWriter: (writer) => {\r\n currentStdoutWriter = writer\r\n almostNodeSession?.setStdoutWriter(writer)\r\n pyodideSession?.setStdoutWriter(writer)\r\n },\r\n writeStdin: (data) => almostNodeSession?.writeStdin(data),\r\n setTerminalSize: (columns, rows) => almostNodeSession?.setTerminalSize(columns, rows),\r\n dispose: () => {\r\n almostNodeSession?.dispose()\r\n pyodideSession?.dispose()\r\n },\r\n }\r\n}\r\n\r\n/** Execute a bash command and return a ToolResult */\r\nexport async function executeBrowserBash(\r\n session: BrowserBashSession,\r\n command: string,\r\n options: ExecuteBrowserBashOptions = {},\r\n): Promise<ToolResult> {\r\n const trimmedCommand = command.trim()\r\n if (!trimmedCommand) {\r\n return { success: false, error: \"Command is required\", stderr: \"Command is required\", exit_code: 1, command: trimmedCommand, backend: \"just-bash\" }\r\n }\r\n\r\n const startedAt = Date.now()\r\n const outputLimit = options.outputLimit ?? DEFAULT_BASH_OUTPUT_LIMIT\r\n const timeoutMs = options.commandTimeoutMs ?? DEFAULT_BASH_COMMAND_TIMEOUT_MS\r\n\r\n const timeoutController = new AbortController()\r\n const combinedController = new AbortController()\r\n const abort = (reason?: unknown) => {\r\n combinedController.abort(reason instanceof Error ? reason : new Error(String(reason ?? \"Command aborted\")))\r\n }\r\n\r\n if (options.signal) {\r\n if (options.signal.aborted) {\r\n abort(options.signal.reason)\r\n } else {\r\n options.signal.addEventListener(\"abort\", () => abort(options.signal!.reason), { once: true })\r\n }\r\n }\r\n\r\n timeoutController.signal.addEventListener(\"abort\", () => abort(timeoutController.signal.reason), { once: true })\r\n const timeoutId = globalThis.setTimeout(() => {\r\n timeoutController.abort(new Error(`Command timed out after ${timeoutMs}ms`))\r\n }, timeoutMs)\r\n\r\n try {\r\n const result = await session.bash.exec(trimmedCommand, {\r\n cwd: session.cwd,\r\n env: {\r\n ...DEFAULT_BASH_SHELL_ENV,\r\n PWD: session.cwd,\r\n },\r\n signal: combinedController.signal,\r\n })\r\n\r\n const nextCwd = result.env?.PWD?.trim()\r\n if (nextCwd) {\r\n session.cwd = normalizeBashPath(nextCwd)\r\n }\r\n\r\n const stdout = options.truncateOutput === false ? result.stdout : truncateBashOutput(result.stdout, outputLimit)\r\n const stderr = options.truncateOutput === false ? result.stderr : truncateBashOutput(result.stderr, outputLimit)\r\n const error = result.exitCode === 0 ? undefined : stderr || undefined\r\n\r\n return {\r\n success: result.exitCode === 0,\r\n command: trimmedCommand,\r\n stdout,\r\n stderr,\r\n output: stdout,\r\n exit_code: result.exitCode,\r\n duration_ms: Date.now() - startedAt,\r\n backend: \"just-bash\",\r\n ...(error ? { error } : {}),\r\n }\r\n } catch (error) {\r\n const message = error instanceof Error ? error.message : String(error)\r\n return { success: false, command: trimmedCommand, error: message, stderr: message, exit_code: 1, duration_ms: Date.now() - startedAt, backend: \"just-bash\" }\r\n } finally {\r\n globalThis.clearTimeout(timeoutId)\r\n }\r\n}\r\n","export const AGENT_WEB_OS_VERSION = \"0.3.0\"\r\nconsole.log(`[agent-web-os] v${AGENT_WEB_OS_VERSION}`)\r\n\r\nexport {\r\n ObservableInMemoryFs,\r\n assertObservableInMemoryFs,\r\n type ObservableInMemoryFsOptions,\r\n type ObservableInMemoryFsChangeEvent,\r\n type ObservableInMemoryFsChangeEventName,\r\n} from \"./observable-in-memory-fs\"\r\n\r\nexport {\r\n createBrowserBashSession,\r\n executeBrowserBash,\r\n DEFAULT_BASH_SHELL_ENV,\r\n type BrowserBashSession,\r\n} from \"./browser-bash-session\"\r\n\r\nexport { executeFd } from \"./fd-command\"\r\n\r\nexport type { ToolResult } from \"./types\"\r\n\r\n// Re-export just-bash/browser symbols so consumers don't need just-bash directly\r\nexport { Bash, defineCommand } from \"just-bash/browser\"\r\nexport type { CommandContext, ExecResult, CustomCommand } from \"just-bash/browser\"\r\n\r\n// Re-export almostnode server-bridge utilities\r\nimport { getServerBridge as _getServerBridge, resetServerBridge as _resetServerBridge } from \"almostnode\"\r\n\r\nexport type ServerBridge = {\r\n initServiceWorker(): Promise<void>\r\n registerServer(server: unknown, port: number): void\r\n unregisterServer(port: number): void\r\n getServerUrl(port: number): string\r\n}\r\n\r\nexport const getServerBridge: () => ServerBridge = _getServerBridge\r\nexport const resetServerBridge: () => void = _resetServerBridge\r\n"],"mappings":"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","names":["normalizedSourcePath","normalizedDestinationPath","posixPath","getServerBridge","resetServerBridge"]}
|
|
@@ -94,16 +94,6 @@ var PyodideSession = class {
|
|
|
94
94
|
})();
|
|
95
95
|
await this.initPromise;
|
|
96
96
|
}
|
|
97
|
-
async syncWorkspaceToEmscriptenFS(cwd) {
|
|
98
|
-
if (!this.pyodide) return;
|
|
99
|
-
const workspaceRoot = this.getWorkspaceRoot(cwd);
|
|
100
|
-
await syncToEmscriptenFS(this.fs, this.pyodide.FS, workspaceRoot, workspaceRoot);
|
|
101
|
-
}
|
|
102
|
-
async syncWorkspaceFromEmscriptenFS(cwd) {
|
|
103
|
-
if (!this.pyodide) return;
|
|
104
|
-
const workspaceRoot = this.getWorkspaceRoot(cwd);
|
|
105
|
-
await syncFromEmscriptenFS(this.pyodide.FS, this.fs, workspaceRoot, workspaceRoot);
|
|
106
|
-
}
|
|
107
97
|
getWorkspaceRoot(cwd) {
|
|
108
98
|
const parts = cwd.split("/").filter(Boolean);
|
|
109
99
|
return parts.length > 0 ? `/${parts[0]}` : "/workspace";
|
|
@@ -130,7 +120,8 @@ var PyodideSession = class {
|
|
|
130
120
|
}
|
|
131
121
|
await this.ensureInitialized();
|
|
132
122
|
const pyodide = this.pyodide;
|
|
133
|
-
this.
|
|
123
|
+
const workspaceRoot = this.getWorkspaceRoot(cwd);
|
|
124
|
+
await syncToEmscriptenFS(this.fs, pyodide.FS, workspaceRoot, workspaceRoot);
|
|
134
125
|
let stdout = "";
|
|
135
126
|
let stderr = "";
|
|
136
127
|
pyodide.setStdout({
|
|
@@ -173,7 +164,7 @@ os.chdir(${JSON.stringify(cwd)})
|
|
|
173
164
|
}
|
|
174
165
|
});
|
|
175
166
|
await pyodide.runPythonAsync(code);
|
|
176
|
-
this.
|
|
167
|
+
await syncFromEmscriptenFS(pyodide.FS, this.fs, workspaceRoot, workspaceRoot);
|
|
177
168
|
return { stdout, stderr, exitCode: 0 };
|
|
178
169
|
} catch (error) {
|
|
179
170
|
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
@@ -338,11 +329,7 @@ function parsePythonArgs(args) {
|
|
|
338
329
|
}
|
|
339
330
|
return { kind: "run-file", filePath: first };
|
|
340
331
|
}
|
|
341
|
-
function createPyodideSession(fs) {
|
|
342
|
-
return new PyodideSession(fs);
|
|
343
|
-
}
|
|
344
332
|
export {
|
|
345
|
-
PyodideSession
|
|
346
|
-
createPyodideSession
|
|
333
|
+
PyodideSession
|
|
347
334
|
};
|
|
348
|
-
//# sourceMappingURL=pyodide-session-
|
|
335
|
+
//# sourceMappingURL=pyodide-session-OEKAVNSL.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/pyodide-session.ts"],"sourcesContent":["import type { CommandContext, ExecResult } from \"just-bash/browser\"\r\nimport { ObservableInMemoryFs } from \"./observable-in-memory-fs\"\r\n\r\n/**\r\n * Pyodide version loaded from CDN.\r\n * Update this when upgrading to a newer Pyodide release.\r\n */\r\nconst PYODIDE_VERSION = \"0.27.7\"\r\nconst PYODIDE_CDN_URL = `https://cdn.jsdelivr.net/pyodide/v${PYODIDE_VERSION}/full/`\r\n\r\nconst PYTHON_VERSION = \"3.13\"\r\n\r\nconst PIP_USAGE = [\r\n \"Usage: pip <command> [options]\",\r\n \"\",\r\n \"Commands:\",\r\n \" install <pkg> Install packages\",\r\n \" list List installed packages\",\r\n \" show <pkg> Show information about a package\",\r\n \" uninstall <pkg> Uninstall packages\",\r\n \" --version Show pip version\",\r\n].join(\"\\n\")\r\n\r\n/**\r\n * Minimal type for the Pyodide API surface we use.\r\n * We dynamically import pyodide from CDN so there's no compile-time package.\r\n */\r\ninterface PyodideAPI {\r\n version: string\r\n FS: EmscriptenFS\r\n runPython(code: string, options?: { globals?: unknown }): unknown\r\n runPythonAsync(code: string, options?: { globals?: unknown }): Promise<unknown>\r\n loadPackagesFromImports(code: string, options?: { messageCallback?: (msg: string) => void; errorCallback?: (msg: string) => void }): Promise<unknown>\r\n loadPackage(names: string | string[], options?: { messageCallback?: (msg: string) => void; errorCallback?: (msg: string) => void }): Promise<unknown>\r\n setStdout(options: { batched: (msg: string) => void }): void\r\n setStderr(options: { batched: (msg: string) => void }): void\r\n setStdin(options: { stdin: () => string | null }): void\r\n globals: { get(name: string): unknown }\r\n}\r\n\r\n/** Minimal Emscripten FS type surface */\r\ninterface EmscriptenFS {\r\n mkdir(path: string): void\r\n writeFile(path: string, data: string | Uint8Array, opts?: { encoding?: string }): void\r\n readFile(path: string, opts?: { encoding?: string }): string | Uint8Array\r\n readdir(path: string): string[]\r\n stat(path: string): { mode: number; size: number }\r\n unlink(path: string): void\r\n rmdir(path: string): void\r\n isDir(mode: number): boolean\r\n isFile(mode: number): boolean\r\n}\r\n\r\n/**\r\n * Recursively sync files from ObservableInMemoryFs → Pyodide's Emscripten FS.\r\n * Creates directories as needed and writes all files.\r\n */\r\nasync function syncToEmscriptenFS(\r\n srcFs: ObservableInMemoryFs,\r\n emFs: EmscriptenFS,\r\n srcPath: string,\r\n emPath: string,\r\n): Promise<void> {\r\n // Ensure target directory exists in Emscripten FS\r\n try {\r\n emFs.stat(emPath)\r\n } catch {\r\n emFs.mkdir(emPath)\r\n }\r\n\r\n let entries: string[]\r\n try {\r\n entries = await srcFs.readdir(srcPath)\r\n } catch {\r\n return\r\n }\r\n\r\n for (const entry of entries) {\r\n const srcChild = srcPath === \"/\" ? `/${entry}` : `${srcPath}/${entry}`\r\n const emChild = emPath === \"/\" ? `/${entry}` : `${emPath}/${entry}`\r\n\r\n try {\r\n const stat = await srcFs.stat(srcChild)\r\n if (stat.isDirectory) {\r\n await syncToEmscriptenFS(srcFs, emFs, srcChild, emChild)\r\n } else {\r\n const content = await srcFs.readFileBuffer(srcChild)\r\n emFs.writeFile(emChild, content)\r\n }\r\n } catch {\r\n // Skip files that can't be read\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Recursively sync files from Pyodide's Emscripten FS → ObservableInMemoryFs.\r\n * Only syncs files that differ or are new.\r\n */\r\nasync function syncFromEmscriptenFS(\r\n emFs: EmscriptenFS,\r\n dstFs: ObservableInMemoryFs,\r\n emPath: string,\r\n dstPath: string,\r\n): Promise<void> {\r\n let entries: string[]\r\n try {\r\n entries = emFs.readdir(emPath).filter((e: string) => e !== \".\" && e !== \"..\")\r\n } catch {\r\n return\r\n }\r\n\r\n for (const entry of entries) {\r\n const emChild = emPath === \"/\" ? `/${entry}` : `${emPath}/${entry}`\r\n const dstChild = dstPath === \"/\" ? `/${entry}` : `${dstPath}/${entry}`\r\n\r\n try {\r\n const stat = emFs.stat(emChild)\r\n if (emFs.isDir(stat.mode)) {\r\n dstFs.mkdirSync(dstChild, { recursive: true })\r\n await syncFromEmscriptenFS(emFs, dstFs, emChild, dstChild)\r\n } else if (emFs.isFile(stat.mode)) {\r\n const content = emFs.readFile(emChild) as Uint8Array\r\n dstFs.writeFileSync(dstChild, content)\r\n }\r\n } catch {\r\n // Skip entries we can't read\r\n }\r\n }\r\n}\r\n\r\nexport class PyodideSession {\r\n private pyodide: PyodideAPI | null = null\r\n private initPromise: Promise<void> | null = null\r\n private stdoutWriter?: (data: string) => void\r\n\r\n constructor(private readonly fs: ObservableInMemoryFs) {}\r\n\r\n private async ensureInitialized(): Promise<void> {\r\n if (this.pyodide) return\r\n if (this.initPromise) {\r\n await this.initPromise\r\n return\r\n }\r\n\r\n this.initPromise = (async () => {\r\n const { loadPyodide } = await import(\r\n /* webpackIgnore: true */\r\n `${PYODIDE_CDN_URL}pyodide.mjs`\r\n ) as { loadPyodide: (opts?: Record<string, unknown>) => Promise<PyodideAPI> }\r\n\r\n this.pyodide = await loadPyodide({\r\n indexURL: PYODIDE_CDN_URL,\r\n packages: [\"micropip\"],\r\n })\r\n\r\n // Set up the workspace directory in Pyodide FS\r\n try {\r\n this.pyodide.FS.mkdir(\"/workspace\")\r\n } catch {\r\n // May already exist\r\n }\r\n })()\r\n\r\n await this.initPromise\r\n }\r\n\r\n private getWorkspaceRoot(cwd: string): string {\r\n const parts = cwd.split(\"/\").filter(Boolean)\r\n return parts.length > 0 ? `/${parts[0]}` : \"/workspace\"\r\n }\r\n\r\n setStdoutWriter(writer: ((data: string) => void) | undefined): void {\r\n this.stdoutWriter = writer\r\n }\r\n\r\n async executePython(args: string[], ctx: CommandContext): Promise<ExecResult> {\r\n const cwd = ctx.cwd\r\n\r\n const invocation = parsePythonArgs(args)\r\n\r\n if (invocation.kind === \"version\") {\r\n return { stdout: `Python ${PYTHON_VERSION}\\n`, stderr: \"\", exitCode: 0 }\r\n }\r\n\r\n if (invocation.kind === \"help\") {\r\n return {\r\n stdout: \"usage: python3 [option] ... [-c cmd | -m mod | file | -] [arg] ...\\n\" +\r\n \"Supported modes: python3 <file>, python3 -c <code>, python3 --version\\n\",\r\n stderr: \"\",\r\n exitCode: 0,\r\n }\r\n }\r\n\r\n if (invocation.kind === \"error\") {\r\n return { stdout: \"\", stderr: invocation.message + \"\\n\", exitCode: 1 }\r\n }\r\n\r\n await this.ensureInitialized()\r\n const pyodide = this.pyodide!\r\n\r\n // Sync filesystem before execution\r\n const workspaceRoot = this.getWorkspaceRoot(cwd)\r\n await syncToEmscriptenFS(this.fs, pyodide.FS, workspaceRoot, workspaceRoot)\r\n\r\n let stdout = \"\"\r\n let stderr = \"\"\r\n\r\n pyodide.setStdout({\r\n batched: (msg: string) => {\r\n stdout += msg + \"\\n\"\r\n this.stdoutWriter?.(msg + \"\\n\")\r\n },\r\n })\r\n pyodide.setStderr({\r\n batched: (msg: string) => {\r\n stderr += msg + \"\\n\"\r\n this.stdoutWriter?.(msg + \"\\n\")\r\n },\r\n })\r\n\r\n // Set cwd in Python\r\n pyodide.runPython(`\r\nimport os\r\nos.chdir(${JSON.stringify(cwd)})\r\n`)\r\n\r\n let code: string\r\n if (invocation.kind === \"eval\") {\r\n code = invocation.code\r\n } else {\r\n // Run file\r\n const filePath = invocation.filePath.startsWith(\"/\")\r\n ? invocation.filePath\r\n : `${cwd}/${invocation.filePath}`\r\n try {\r\n const content = pyodide.FS.readFile(filePath, { encoding: \"utf8\" }) as string\r\n code = content\r\n } catch {\r\n return {\r\n stdout: \"\",\r\n stderr: `python3: can't open file '${invocation.filePath}': [Errno 2] No such file or directory\\n`,\r\n exitCode: 2,\r\n }\r\n }\r\n }\r\n\r\n try {\r\n // Auto-install any import-able packages\r\n await pyodide.loadPackagesFromImports(code, {\r\n messageCallback: (msg: string) => {\r\n this.stdoutWriter?.(msg + \"\\n\")\r\n },\r\n })\r\n\r\n await pyodide.runPythonAsync(code)\r\n\r\n // Sync filesystem after execution\r\n await syncFromEmscriptenFS(pyodide.FS, this.fs, workspaceRoot, workspaceRoot)\r\n\r\n return { stdout, stderr, exitCode: 0 }\r\n } catch (error) {\r\n const errorMsg = error instanceof Error ? error.message : String(error)\r\n stderr += errorMsg + \"\\n\"\r\n return { stdout, stderr, exitCode: 1 }\r\n }\r\n }\r\n\r\n async executePip(args: string[], ctx: CommandContext): Promise<ExecResult> {\r\n const subcommand = args[0]\r\n\r\n if (!subcommand || subcommand === \"help\" || subcommand === \"--help\" || subcommand === \"-h\") {\r\n return { stdout: PIP_USAGE + \"\\n\", stderr: \"\", exitCode: 0 }\r\n }\r\n\r\n if (subcommand === \"--version\" || subcommand === \"-V\") {\r\n await this.ensureInitialized()\r\n return {\r\n stdout: `pip (micropip) for Python ${PYTHON_VERSION} [Pyodide ${this.pyodide!.version}]\\n`,\r\n stderr: \"\",\r\n exitCode: 0,\r\n }\r\n }\r\n\r\n await this.ensureInitialized()\r\n const pyodide = this.pyodide!\r\n\r\n let stdout = \"\"\r\n let stderr = \"\"\r\n\r\n pyodide.setStdout({\r\n batched: (msg: string) => {\r\n stdout += msg + \"\\n\"\r\n this.stdoutWriter?.(msg + \"\\n\")\r\n },\r\n })\r\n pyodide.setStderr({\r\n batched: (msg: string) => {\r\n stderr += msg + \"\\n\"\r\n this.stdoutWriter?.(msg + \"\\n\")\r\n },\r\n })\r\n\r\n switch (subcommand) {\r\n case \"install\": {\r\n const packages = args.slice(1).filter((a) => !a.startsWith(\"-\"))\r\n if (packages.length === 0) {\r\n return { stdout: \"\", stderr: \"ERROR: You must give at least one requirement to install\\n\", exitCode: 1 }\r\n }\r\n\r\n try {\r\n const packageList = packages.map((p) => JSON.stringify(p)).join(\", \")\r\n await pyodide.runPythonAsync(`\r\nimport micropip\r\nawait micropip.install([${packageList}])\r\n`)\r\n const installedMsg = `Successfully installed ${packages.join(\" \")}\\n`\r\n stdout += installedMsg\r\n this.stdoutWriter?.(installedMsg)\r\n return { stdout, stderr, exitCode: 0 }\r\n } catch (error) {\r\n const errorMsg = error instanceof Error ? error.message : String(error)\r\n stderr += errorMsg + \"\\n\"\r\n return { stdout, stderr, exitCode: 1 }\r\n }\r\n }\r\n\r\n case \"list\": {\r\n try {\r\n await pyodide.runPythonAsync(`\r\nimport micropip\r\npkgs = micropip.list()\r\nprint(f\"{'Package':<30} {'Version':<15}\")\r\nprint(f\"{'-'*30} {'-'*15}\")\r\nfor name, pkg in sorted(pkgs.items()):\r\n print(f\"{name:<30} {pkg.version:<15}\")\r\n`)\r\n return { stdout, stderr, exitCode: 0 }\r\n } catch (error) {\r\n const errorMsg = error instanceof Error ? error.message : String(error)\r\n stderr += errorMsg + \"\\n\"\r\n return { stdout, stderr, exitCode: 1 }\r\n }\r\n }\r\n\r\n case \"show\": {\r\n const packageName = args[1]\r\n if (!packageName) {\r\n return { stdout: \"\", stderr: \"ERROR: Please provide a package name\\n\", exitCode: 1 }\r\n }\r\n\r\n try {\r\n await pyodide.runPythonAsync(`\r\nimport micropip\r\npkgs = micropip.list()\r\npkg_name = ${JSON.stringify(packageName)}\r\nif pkg_name in pkgs:\r\n pkg = pkgs[pkg_name]\r\n print(f\"Name: {pkg_name}\")\r\n print(f\"Version: {pkg.version}\")\r\nelse:\r\n print(f\"WARNING: Package(s) not found: {pkg_name}\")\r\n`)\r\n return { stdout, stderr, exitCode: 0 }\r\n } catch (error) {\r\n const errorMsg = error instanceof Error ? error.message : String(error)\r\n stderr += errorMsg + \"\\n\"\r\n return { stdout, stderr, exitCode: 1 }\r\n }\r\n }\r\n\r\n case \"uninstall\": {\r\n const packages = args.slice(1).filter((a) => !a.startsWith(\"-\"))\r\n if (packages.length === 0) {\r\n return { stdout: \"\", stderr: \"ERROR: You must give at least one requirement to uninstall\\n\", exitCode: 1 }\r\n }\r\n\r\n try {\r\n const packageList = packages.map((p) => JSON.stringify(p)).join(\", \")\r\n await pyodide.runPythonAsync(`\r\nimport micropip\r\nmicropip.uninstall([${packageList}])\r\n`)\r\n const uninstalledMsg = `Successfully uninstalled ${packages.join(\" \")}\\n`\r\n stdout += uninstalledMsg\r\n this.stdoutWriter?.(uninstalledMsg)\r\n return { stdout, stderr, exitCode: 0 }\r\n } catch (error) {\r\n const errorMsg = error instanceof Error ? error.message : String(error)\r\n stderr += errorMsg + \"\\n\"\r\n return { stdout, stderr, exitCode: 1 }\r\n }\r\n }\r\n\r\n default:\r\n return { stdout: \"\", stderr: `ERROR: unknown command \"${subcommand}\"\\n${PIP_USAGE}\\n`, exitCode: 1 }\r\n }\r\n }\r\n\r\n dispose(): void {\r\n this.pyodide = null\r\n this.initPromise = null\r\n }\r\n}\r\n\r\nfunction parsePythonArgs(args: string[]):\r\n | { kind: \"version\" }\r\n | { kind: \"help\" }\r\n | { kind: \"eval\"; code: string }\r\n | { kind: \"run-file\"; filePath: string }\r\n | { kind: \"error\"; message: string } {\r\n if (args.length === 0) {\r\n return { kind: \"error\", message: \"REPL mode is not supported. Use python3 -c <code> or python3 <file>.\" }\r\n }\r\n\r\n const [first, ...rest] = args\r\n\r\n if (first === \"-V\" || first === \"--version\") {\r\n return { kind: \"version\" }\r\n }\r\n\r\n if (first === \"-h\" || first === \"--help\") {\r\n return { kind: \"help\" }\r\n }\r\n\r\n if (first === \"-c\") {\r\n const code = rest[0]?.trim()\r\n if (!code) {\r\n return { kind: \"error\", message: \"python3 -c requires inline code\" }\r\n }\r\n return { kind: \"eval\", code }\r\n }\r\n\r\n if (first === \"-m\") {\r\n const moduleName = rest[0]?.trim()\r\n if (!moduleName) {\r\n return { kind: \"error\", message: \"python3 -m requires a module name\" }\r\n }\r\n // Run as `python -m module`\r\n return { kind: \"eval\", code: `import runpy; runpy.run_module(${JSON.stringify(moduleName)}, run_name='__main__')` }\r\n }\r\n\r\n if (first.startsWith(\"-\")) {\r\n return { kind: \"error\", message: `Unsupported option: ${first}` }\r\n }\r\n\r\n // It's a file path\r\n return { kind: \"run-file\", filePath: first }\r\n}\r\n\r\n\r\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/pyodide-session.ts"],"sourcesContent":["import type { CommandContext, ExecResult } from \"just-bash/browser\"\r\nimport { ObservableInMemoryFs } from \"./observable-in-memory-fs\"\r\n\r\n/**\r\n * Pyodide version loaded from CDN.\r\n * Update this when upgrading to a newer Pyodide release.\r\n */\r\nconst PYODIDE_VERSION = \"0.27.7\"\r\nconst PYODIDE_CDN_URL = `https://cdn.jsdelivr.net/pyodide/v${PYODIDE_VERSION}/full/`\r\n\r\nconst PYTHON_VERSION = \"3.13\"\r\n\r\nconst PIP_USAGE = [\r\n \"Usage: pip <command> [options]\",\r\n \"\",\r\n \"Commands:\",\r\n \" install <pkg> Install packages\",\r\n \" list List installed packages\",\r\n \" show <pkg> Show information about a package\",\r\n \" uninstall <pkg> Uninstall packages\",\r\n \" --version Show pip version\",\r\n].join(\"\\n\")\r\n\r\n/**\r\n * Minimal type for the Pyodide API surface we use.\r\n * We dynamically import pyodide from CDN so there's no compile-time package.\r\n */\r\ninterface PyodideAPI {\r\n version: string\r\n FS: EmscriptenFS\r\n runPython(code: string, options?: { globals?: unknown }): unknown\r\n runPythonAsync(code: string, options?: { globals?: unknown }): Promise<unknown>\r\n loadPackagesFromImports(code: string, options?: { messageCallback?: (msg: string) => void; errorCallback?: (msg: string) => void }): Promise<unknown>\r\n loadPackage(names: string | string[], options?: { messageCallback?: (msg: string) => void; errorCallback?: (msg: string) => void }): Promise<unknown>\r\n setStdout(options: { batched: (msg: string) => void }): void\r\n setStderr(options: { batched: (msg: string) => void }): void\r\n setStdin(options: { stdin: () => string | null }): void\r\n globals: { get(name: string): unknown }\r\n}\r\n\r\n/** Minimal Emscripten FS type surface */\r\ninterface EmscriptenFS {\r\n mkdir(path: string): void\r\n writeFile(path: string, data: string | Uint8Array, opts?: { encoding?: string }): void\r\n readFile(path: string, opts?: { encoding?: string }): string | Uint8Array\r\n readdir(path: string): string[]\r\n stat(path: string): { mode: number; size: number }\r\n unlink(path: string): void\r\n rmdir(path: string): void\r\n isDir(mode: number): boolean\r\n isFile(mode: number): boolean\r\n}\r\n\r\n/**\r\n * Recursively sync files from ObservableInMemoryFs → Pyodide's Emscripten FS.\r\n * Creates directories as needed and writes all files.\r\n */\r\nasync function syncToEmscriptenFS(\r\n srcFs: ObservableInMemoryFs,\r\n emFs: EmscriptenFS,\r\n srcPath: string,\r\n emPath: string,\r\n): Promise<void> {\r\n // Ensure target directory exists in Emscripten FS\r\n try {\r\n emFs.stat(emPath)\r\n } catch {\r\n emFs.mkdir(emPath)\r\n }\r\n\r\n let entries: string[]\r\n try {\r\n entries = await srcFs.readdir(srcPath)\r\n } catch {\r\n return\r\n }\r\n\r\n for (const entry of entries) {\r\n const srcChild = srcPath === \"/\" ? `/${entry}` : `${srcPath}/${entry}`\r\n const emChild = emPath === \"/\" ? `/${entry}` : `${emPath}/${entry}`\r\n\r\n try {\r\n const stat = await srcFs.stat(srcChild)\r\n if (stat.isDirectory) {\r\n await syncToEmscriptenFS(srcFs, emFs, srcChild, emChild)\r\n } else {\r\n const content = await srcFs.readFileBuffer(srcChild)\r\n emFs.writeFile(emChild, content)\r\n }\r\n } catch {\r\n // Skip files that can't be read\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Recursively sync files from Pyodide's Emscripten FS → ObservableInMemoryFs.\r\n * Only syncs files that differ or are new.\r\n */\r\nasync function syncFromEmscriptenFS(\r\n emFs: EmscriptenFS,\r\n dstFs: ObservableInMemoryFs,\r\n emPath: string,\r\n dstPath: string,\r\n): Promise<void> {\r\n let entries: string[]\r\n try {\r\n entries = emFs.readdir(emPath).filter((e: string) => e !== \".\" && e !== \"..\")\r\n } catch {\r\n return\r\n }\r\n\r\n for (const entry of entries) {\r\n const emChild = emPath === \"/\" ? `/${entry}` : `${emPath}/${entry}`\r\n const dstChild = dstPath === \"/\" ? `/${entry}` : `${dstPath}/${entry}`\r\n\r\n try {\r\n const stat = emFs.stat(emChild)\r\n if (emFs.isDir(stat.mode)) {\r\n dstFs.mkdirSync(dstChild, { recursive: true })\r\n await syncFromEmscriptenFS(emFs, dstFs, emChild, dstChild)\r\n } else if (emFs.isFile(stat.mode)) {\r\n const content = emFs.readFile(emChild) as Uint8Array\r\n dstFs.writeFileSync(dstChild, content)\r\n }\r\n } catch {\r\n // Skip entries we can't read\r\n }\r\n }\r\n}\r\n\r\nexport class PyodideSession {\r\n private pyodide: PyodideAPI | null = null\r\n private initPromise: Promise<void> | null = null\r\n private stdoutWriter?: (data: string) => void\r\n\r\n constructor(private readonly fs: ObservableInMemoryFs) {}\r\n\r\n private async ensureInitialized(): Promise<void> {\r\n if (this.pyodide) return\r\n if (this.initPromise) {\r\n await this.initPromise\r\n return\r\n }\r\n\r\n this.initPromise = (async () => {\r\n const { loadPyodide } = await import(\r\n /* webpackIgnore: true */\r\n `${PYODIDE_CDN_URL}pyodide.mjs`\r\n ) as { loadPyodide: (opts?: Record<string, unknown>) => Promise<PyodideAPI> }\r\n\r\n this.pyodide = await loadPyodide({\r\n indexURL: PYODIDE_CDN_URL,\r\n packages: [\"micropip\"],\r\n })\r\n\r\n // Set up the workspace directory in Pyodide FS\r\n try {\r\n this.pyodide.FS.mkdir(\"/workspace\")\r\n } catch {\r\n // May already exist\r\n }\r\n })()\r\n\r\n await this.initPromise\r\n }\r\n\r\n private async syncWorkspaceToEmscriptenFS(cwd: string): Promise<void> {\r\n if (!this.pyodide) return\r\n\r\n // Determine the workspace root to sync\r\n // Sync the root path that contains cwd\r\n const workspaceRoot = this.getWorkspaceRoot(cwd)\r\n await syncToEmscriptenFS(this.fs, this.pyodide.FS, workspaceRoot, workspaceRoot)\r\n }\r\n\r\n private async syncWorkspaceFromEmscriptenFS(cwd: string): Promise<void> {\r\n if (!this.pyodide) return\r\n\r\n const workspaceRoot = this.getWorkspaceRoot(cwd)\r\n await syncFromEmscriptenFS(this.pyodide.FS, this.fs, workspaceRoot, workspaceRoot)\r\n }\r\n\r\n private getWorkspaceRoot(cwd: string): string {\r\n // Use the first path component under root as workspace root\r\n // e.g. /workspace/project → /workspace\r\n const parts = cwd.split(\"/\").filter(Boolean)\r\n return parts.length > 0 ? `/${parts[0]}` : \"/workspace\"\r\n }\r\n\r\n setStdoutWriter(writer: ((data: string) => void) | undefined): void {\r\n this.stdoutWriter = writer\r\n }\r\n\r\n async executePython(args: string[], ctx: CommandContext): Promise<ExecResult> {\r\n const cwd = ctx.cwd\r\n\r\n const invocation = parsePythonArgs(args)\r\n\r\n if (invocation.kind === \"version\") {\r\n return { stdout: `Python ${PYTHON_VERSION}\\n`, stderr: \"\", exitCode: 0 }\r\n }\r\n\r\n if (invocation.kind === \"help\") {\r\n return {\r\n stdout: \"usage: python3 [option] ... [-c cmd | -m mod | file | -] [arg] ...\\n\" +\r\n \"Supported modes: python3 <file>, python3 -c <code>, python3 --version\\n\",\r\n stderr: \"\",\r\n exitCode: 0,\r\n }\r\n }\r\n\r\n if (invocation.kind === \"error\") {\r\n return { stdout: \"\", stderr: invocation.message + \"\\n\", exitCode: 1 }\r\n }\r\n\r\n await this.ensureInitialized()\r\n const pyodide = this.pyodide!\r\n\r\n // Sync filesystem before execution\r\n this.syncWorkspaceToEmscriptenFS(cwd)\r\n\r\n let stdout = \"\"\r\n let stderr = \"\"\r\n\r\n pyodide.setStdout({\r\n batched: (msg: string) => {\r\n stdout += msg + \"\\n\"\r\n this.stdoutWriter?.(msg + \"\\n\")\r\n },\r\n })\r\n pyodide.setStderr({\r\n batched: (msg: string) => {\r\n stderr += msg + \"\\n\"\r\n this.stdoutWriter?.(msg + \"\\n\")\r\n },\r\n })\r\n\r\n // Set cwd in Python\r\n pyodide.runPython(`\r\nimport os\r\nos.chdir(${JSON.stringify(cwd)})\r\n`)\r\n\r\n let code: string\r\n if (invocation.kind === \"eval\") {\r\n code = invocation.code\r\n } else {\r\n // Run file\r\n const filePath = invocation.filePath.startsWith(\"/\")\r\n ? invocation.filePath\r\n : `${cwd}/${invocation.filePath}`\r\n try {\r\n const content = pyodide.FS.readFile(filePath, { encoding: \"utf8\" }) as string\r\n code = content\r\n } catch {\r\n return {\r\n stdout: \"\",\r\n stderr: `python3: can't open file '${invocation.filePath}': [Errno 2] No such file or directory\\n`,\r\n exitCode: 2,\r\n }\r\n }\r\n }\r\n\r\n try {\r\n // Auto-install any import-able packages\r\n await pyodide.loadPackagesFromImports(code, {\r\n messageCallback: (msg: string) => {\r\n this.stdoutWriter?.(msg + \"\\n\")\r\n },\r\n })\r\n\r\n await pyodide.runPythonAsync(code)\r\n\r\n // Sync filesystem after execution\r\n this.syncWorkspaceFromEmscriptenFS(cwd)\r\n\r\n return { stdout, stderr, exitCode: 0 }\r\n } catch (error) {\r\n const errorMsg = error instanceof Error ? error.message : String(error)\r\n stderr += errorMsg + \"\\n\"\r\n return { stdout, stderr, exitCode: 1 }\r\n }\r\n }\r\n\r\n async executePip(args: string[], ctx: CommandContext): Promise<ExecResult> {\r\n const subcommand = args[0]\r\n\r\n if (!subcommand || subcommand === \"help\" || subcommand === \"--help\" || subcommand === \"-h\") {\r\n return { stdout: PIP_USAGE + \"\\n\", stderr: \"\", exitCode: 0 }\r\n }\r\n\r\n if (subcommand === \"--version\" || subcommand === \"-V\") {\r\n await this.ensureInitialized()\r\n return {\r\n stdout: `pip (micropip) for Python ${PYTHON_VERSION} [Pyodide ${this.pyodide!.version}]\\n`,\r\n stderr: \"\",\r\n exitCode: 0,\r\n }\r\n }\r\n\r\n await this.ensureInitialized()\r\n const pyodide = this.pyodide!\r\n\r\n let stdout = \"\"\r\n let stderr = \"\"\r\n\r\n pyodide.setStdout({\r\n batched: (msg: string) => {\r\n stdout += msg + \"\\n\"\r\n this.stdoutWriter?.(msg + \"\\n\")\r\n },\r\n })\r\n pyodide.setStderr({\r\n batched: (msg: string) => {\r\n stderr += msg + \"\\n\"\r\n this.stdoutWriter?.(msg + \"\\n\")\r\n },\r\n })\r\n\r\n switch (subcommand) {\r\n case \"install\": {\r\n const packages = args.slice(1).filter((a) => !a.startsWith(\"-\"))\r\n if (packages.length === 0) {\r\n return { stdout: \"\", stderr: \"ERROR: You must give at least one requirement to install\\n\", exitCode: 1 }\r\n }\r\n\r\n try {\r\n const packageList = packages.map((p) => JSON.stringify(p)).join(\", \")\r\n await pyodide.runPythonAsync(`\r\nimport micropip\r\nawait micropip.install([${packageList}])\r\n`)\r\n const installedMsg = `Successfully installed ${packages.join(\" \")}\\n`\r\n stdout += installedMsg\r\n this.stdoutWriter?.(installedMsg)\r\n return { stdout, stderr, exitCode: 0 }\r\n } catch (error) {\r\n const errorMsg = error instanceof Error ? error.message : String(error)\r\n stderr += errorMsg + \"\\n\"\r\n return { stdout, stderr, exitCode: 1 }\r\n }\r\n }\r\n\r\n case \"list\": {\r\n try {\r\n await pyodide.runPythonAsync(`\r\nimport micropip\r\npkgs = micropip.list()\r\nprint(f\"{'Package':<30} {'Version':<15}\")\r\nprint(f\"{'-'*30} {'-'*15}\")\r\nfor name, pkg in sorted(pkgs.items()):\r\n print(f\"{name:<30} {pkg.version:<15}\")\r\n`)\r\n return { stdout, stderr, exitCode: 0 }\r\n } catch (error) {\r\n const errorMsg = error instanceof Error ? error.message : String(error)\r\n stderr += errorMsg + \"\\n\"\r\n return { stdout, stderr, exitCode: 1 }\r\n }\r\n }\r\n\r\n case \"show\": {\r\n const packageName = args[1]\r\n if (!packageName) {\r\n return { stdout: \"\", stderr: \"ERROR: Please provide a package name\\n\", exitCode: 1 }\r\n }\r\n\r\n try {\r\n await pyodide.runPythonAsync(`\r\nimport micropip\r\npkgs = micropip.list()\r\npkg_name = ${JSON.stringify(packageName)}\r\nif pkg_name in pkgs:\r\n pkg = pkgs[pkg_name]\r\n print(f\"Name: {pkg_name}\")\r\n print(f\"Version: {pkg.version}\")\r\nelse:\r\n print(f\"WARNING: Package(s) not found: {pkg_name}\")\r\n`)\r\n return { stdout, stderr, exitCode: 0 }\r\n } catch (error) {\r\n const errorMsg = error instanceof Error ? error.message : String(error)\r\n stderr += errorMsg + \"\\n\"\r\n return { stdout, stderr, exitCode: 1 }\r\n }\r\n }\r\n\r\n case \"uninstall\": {\r\n const packages = args.slice(1).filter((a) => !a.startsWith(\"-\"))\r\n if (packages.length === 0) {\r\n return { stdout: \"\", stderr: \"ERROR: You must give at least one requirement to uninstall\\n\", exitCode: 1 }\r\n }\r\n\r\n try {\r\n const packageList = packages.map((p) => JSON.stringify(p)).join(\", \")\r\n await pyodide.runPythonAsync(`\r\nimport micropip\r\nmicropip.uninstall([${packageList}])\r\n`)\r\n const uninstalledMsg = `Successfully uninstalled ${packages.join(\" \")}\\n`\r\n stdout += uninstalledMsg\r\n this.stdoutWriter?.(uninstalledMsg)\r\n return { stdout, stderr, exitCode: 0 }\r\n } catch (error) {\r\n const errorMsg = error instanceof Error ? error.message : String(error)\r\n stderr += errorMsg + \"\\n\"\r\n return { stdout, stderr, exitCode: 1 }\r\n }\r\n }\r\n\r\n default:\r\n return { stdout: \"\", stderr: `ERROR: unknown command \"${subcommand}\"\\n${PIP_USAGE}\\n`, exitCode: 1 }\r\n }\r\n }\r\n\r\n dispose(): void {\r\n this.pyodide = null\r\n this.initPromise = null\r\n }\r\n}\r\n\r\nfunction parsePythonArgs(args: string[]): \r\n | { kind: \"version\" }\r\n | { kind: \"help\" }\r\n | { kind: \"eval\"; code: string }\r\n | { kind: \"run-file\"; filePath: string }\r\n | { kind: \"error\"; message: string } {\r\n if (args.length === 0) {\r\n return { kind: \"error\", message: \"REPL mode is not supported. Use python3 -c <code> or python3 <file>.\" }\r\n }\r\n\r\n const [first, ...rest] = args\r\n\r\n if (first === \"-V\" || first === \"--version\") {\r\n return { kind: \"version\" }\r\n }\r\n\r\n if (first === \"-h\" || first === \"--help\") {\r\n return { kind: \"help\" }\r\n }\r\n\r\n if (first === \"-c\") {\r\n const code = rest[0]?.trim()\r\n if (!code) {\r\n return { kind: \"error\", message: \"python3 -c requires inline code\" }\r\n }\r\n return { kind: \"eval\", code }\r\n }\r\n\r\n if (first === \"-m\") {\r\n const moduleName = rest[0]?.trim()\r\n if (!moduleName) {\r\n return { kind: \"error\", message: \"python3 -m requires a module name\" }\r\n }\r\n // Run as `python -m module`\r\n return { kind: \"eval\", code: `import runpy; runpy.run_module(${JSON.stringify(moduleName)}, run_name='__main__')` }\r\n }\r\n\r\n if (first.startsWith(\"-\")) {\r\n return { kind: \"error\", message: `Unsupported option: ${first}` }\r\n }\r\n\r\n // It's a file path\r\n return { kind: \"run-file\", filePath: first }\r\n}\r\n\r\nexport function createPyodideSession(fs: ObservableInMemoryFs): PyodideSession {\r\n return new PyodideSession(fs)\r\n}\r\n"],"mappings":"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","names":[]}
|