Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@
"url": "https://github.com/capsulerun/bash.git"
},
"dependencies": {
"@capsule-run/cli": "^0.8.9",
"@capsule-run/sdk": "^0.8.9"
"@capsule-run/cli": "^0.8.10",
"@capsule-run/sdk": "^0.8.10"
},
"devDependencies": {
"@types/node": "^25.6.0",
Expand Down
4 changes: 2 additions & 2 deletions packages/bash-wasm/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
},
"dependencies": {
"@capsule-run/bash-types": "workspace:*",
"@capsule-run/sdk": "^0.8.9",
"@capsule-run/cli": "^0.8.9"
"@capsule-run/sdk": "^0.8.10",
"@capsule-run/cli": "^0.8.10"
}
}
2 changes: 1 addition & 1 deletion packages/bash/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
".": "./src/index.ts"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
"test": "vitest run"
},
"license": "Apache-2.0",
"packageManager": "pnpm@10.21.0",
Expand Down
3 changes: 2 additions & 1 deletion packages/bash/src/commands/ls/ls.handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ export const handler: CommandHandler = async ({ opts, state, runtime }: CommandC
if (!a.startsWith(".") && b.startsWith(".")) return 1;
return a.localeCompare(b);
});

} catch (e) {
stderr.push(`bash: ls: cannot access '${arg}': No such file or directory`);
exitCode = 1;
Expand Down Expand Up @@ -86,7 +87,7 @@ export const handler: CommandHandler = async ({ opts, state, runtime }: CommandC
const time = `${months[date.getMonth()]} ${padDate} ${timeStr}`;

return `${permissions} ${hardlink} ${user} ${group} ${size} ${time} ${filename}`;
} catch (err) {
} catch {
return;
}
}))).filter((file): file is string => file !== undefined);
Expand Down
2 changes: 1 addition & 1 deletion packages/bash/src/commands/mv/mv.handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export const handler: CommandHandler = async ({ state, opts, runtime }: CommandC
(async () => {
${isSourceFolder ?
`await fs.cp('${sourceAbsolutePath}', '${destinationAbsolutePath}', {recursive: true });` :
`await fs.copyFile('${sourceAbsolutePath}', '${path.join(destinationAbsolutePath as string, sourceFileName)}');`
`await fs.cp('${sourceAbsolutePath}', '${path.join(destinationAbsolutePath as string, sourceFileName)}');`
}
fs.rmSync('${sourceAbsolutePath}', ${isSourceFolder ? '{ recursive: true }' : '{}'});
})()
Expand Down
2 changes: 1 addition & 1 deletion packages/bash/src/commands/mv/mv.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ describe('mv command', () => {
expect(result.stdout).toContain('File moved ✔');
expect(executeCodeMock).toHaveBeenCalledWith(
expect.anything(),
expect.stringContaining("fs.copyFile('/workspace/file1.txt'")
expect.stringContaining("fs.cp('/workspace/file1.txt'")
);
});

Expand Down
7 changes: 5 additions & 2 deletions packages/bash/src/commands/touch/touch.handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ export const handler: CommandHandler = async ({ state, opts, runtime }: CommandC

const segments = arg.split('/');
const parentFolder = segments.length > 1 ? segments.slice(0, -1).join('/') : '.';

const parentFolderAbsolutePath = (await runtime.resolvePath(state, parentFolder));

if (!parentFolderAbsolutePath) {
Expand All @@ -32,5 +31,9 @@ export const handler: CommandHandler = async ({ state, opts, runtime }: CommandC
}
}))

return { stdout: 'File created ✔', stderr: stderr.join('\n'), exitCode: stderr.length > 0 ? 1 : 0 };
if (stderr.length === 0) {
return { stdout: `${opts.args.length > 1 ? opts.args.length + ' Files' : 'File'} created ✔`, stderr: stderr.join('\n'), exitCode: 0 };
}

return { stdout: "", stderr: stderr.join('\n'), exitCode: 1 };
}
66 changes: 34 additions & 32 deletions packages/bash/src/core/executor.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import path from 'path';
import fs from 'fs';
import { fileURLToPath } from 'url';
import { createRequire } from 'module';

Expand All @@ -24,35 +23,38 @@ export class Executor {
private readonly state: State,
) {}

private snapshotFs(root: string): FsSnapshot {
const snapshot: FsSnapshot = {};

const walk = (dir: string) => {
try {
for (const entry of fs.readdirSync(dir)) {
const fullPath = path.join(dir, entry);
try {
const stat = fs.statSync(fullPath);
if (stat.isDirectory()) {
snapshot[fullPath.slice(root.length + 1) + '/'] = stat.mtimeMs;
walk(fullPath);
} else {
snapshot[fullPath.slice(root.length + 1)] = stat.mtimeMs;
}
} catch {}
}
} catch {}
};

walk(root);
return snapshot;
}
private async snapshotFs(root: string): Promise<FsSnapshot> {
const sandboxRoot = root;
const code = `
const fs = require('fs');
const path = require('path');
const root = ${JSON.stringify(sandboxRoot)};
const snapshot = {};
const walk = (dir) => {
try {
for (const entry of fs.readdirSync(dir)) {
const fullPath = path.join(dir, entry);
try {
const stat = fs.statSync(fullPath);
if (stat.isDirectory()) {
snapshot[fullPath.slice(root.length + 1) + '/'] = stat.mtimeMs;
walk(fullPath);
} else {
snapshot[fullPath.slice(root.length + 1)] = stat.mtimeMs;
}
} catch {}
}
} catch {}
};
walk(root);
return snapshot;
`;

private cwdRoot(): string {
const workspace = this.runtime.hostWorkspace;
if (!workspace) return '';
const relativeCwd = this.state.cwd.replace(/^\//, '');
return relativeCwd ? path.join(workspace, relativeCwd) : workspace;
try {
return await this.runtime.executeCode(this.state, code) as FsSnapshot;
} catch {
return {};
}
}

private diffSnapshots(before: FsSnapshot, after: FsSnapshot): { created: string[]; modified: string[]; deleted: string[] } {
Expand Down Expand Up @@ -170,8 +172,8 @@ export class Executor {
const opts = parsedCommandOptions(args);
const command = await this.searchCommandHandler(name);

const root = this.cwdRoot();
const before = this.snapshotFs(root);
const snapshotRoot = this.state.cwd || '/';
const before = await this.snapshotFs(snapshotRoot);

if (!command) {
result = { stdout: '', stderr: `bash: ${name}: command not found`, exitCode: 127, durationMs: Date.now() - start };
Expand Down Expand Up @@ -266,7 +268,7 @@ export class Executor {
}
}

const after = this.snapshotFs(root);
const after = await this.snapshotFs(snapshotRoot);
const diff = this.diffSnapshots(before, after);

const durationMs = Date.now() - start;
Expand Down
72 changes: 36 additions & 36 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading