Skip to content
Closed
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
12 changes: 8 additions & 4 deletions docs-internal/registry-parity-worklist.md
Original file line number Diff line number Diff line change
Expand Up @@ -168,14 +168,18 @@ so a reader sees the whole board at a glance.
`2026-07-07T23-11-21-0700-item3-dispose-behavior-final-pass.txt`.
- **rev:** `zkywnwup` — `fix(runtime): unblock WasmVM signal waits and dispose`

### 4. VFS missing `pwrite` — sqlite3 file-backed DBs don't persist
### 4. VFS missing `pwrite` — sqlite3 file-backed DBs don't persist — DONE
- **Broken:** `filesystem method pwrite is unavailable` — sqlite3 file-backed DB
can't persist across exec calls.
- **Objective:** the VFS implements positioned writes (`pwrite`/`pwritev`) so any
command doing positioned I/O (sqlite3, and others) behaves like Linux.
- **Proof:** sqlite3 "file-based DB persists across separate exec calls" passes;
add a direct VFS pwrite test.
- **rev:** `fix(vfs): implement pwrite for positioned writes`
- **Proof:** sqlite3 "file-based DB persists across separate exec calls" passes
in `2026-07-07T23-18-45-0700-item4-sqlite3-file-db-pwrite-pass.txt`; direct
mounted JS VFS `pwrite` test passes in
`2026-07-07T23-18-45-0700-item4-runtime-core-custom-vfs-pwrite-pass.txt`.
Type/build checks pass in `2026-07-07T23-19-11-0700-item4-runtime-core-build.txt`
and `2026-07-07T23-19-11-0700-item4-sqlite3-check-types.txt`.
- **rev:** `klrzzkro` — `fix(vfs): expose positioned writes in test kernel`

### 5. Socket-layer failures (net-server/udp/unix, signal_handler)
- **Broken:** in the audit run, `st.create is not a function` + a `LinkError` in
Expand Down
10 changes: 10 additions & 0 deletions packages/runtime-core/src/test-runtime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -475,6 +475,7 @@ export interface Kernel extends KernelInterface {
removeFile(path: string): Promise<void>;
removeDir(path: string): Promise<void>;
rename(oldPath: string, newPath: string): Promise<void>;
pwrite(path: string, offset: number, data: Uint8Array): Promise<void>;
vmFetch(request: {
port: number;
method: string;
Expand Down Expand Up @@ -2985,6 +2986,15 @@ class NativeKernel implements Kernel {
return this.proxy!.rename(oldPath, newPath);
}

async pwrite(
targetPath: string,
offset: number,
data: Uint8Array,
): Promise<void> {
await this.ensureReady();
return this.proxy!.vfs.pwrite(targetPath, offset, data);
}

private tryResolveMountedCommand(command: string): boolean {
const normalized = normalizeCommandLookup(command);
for (const driver of this.mountedRuntimeDrivers) {
Expand Down
18 changes: 18 additions & 0 deletions packages/runtime-core/tests/mount-fs-custom-vfs.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,4 +83,22 @@ describe("Kernel.mountFs custom JS VFS", () => {
},
120_000,
);

test("routes positioned writes through a mounted JS VFS", async () => {
const mounted = createRecordingFilesystem();
kernel = createKernel({ filesystem: createInMemoryFileSystem() });

kernel.mountFs("/mnt/custom", mounted.fs);
await kernel.writeFile("/mnt/custom/db.bin", "abcde");
await kernel.pwrite(
"/mnt/custom/db.bin",
2,
new TextEncoder().encode("XYZ"),
);

expect(
new TextDecoder().decode(await kernel.readFile("/mnt/custom/db.bin")),
).toBe("abXYZ");
expect(mounted.calls).toContain("pwrite:/db.bin");
});
});
77 changes: 38 additions & 39 deletions software/sqlite3/test/sqlite3.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,24 @@
*/

import { describe, it, expect, afterEach } from 'vitest';
import { existsSync } from 'node:fs';
import { resolve } from 'node:path';
import { createWasmVmRuntime } from '@agentos/test-harness';
import {
C_BUILD_DIR,
COMMANDS_DIR,
createKernel,
describeIf,
hasCWasmBinaries,
} from '@agentos/test-harness';
import type { Kernel } from '@agentos/test-harness';

const SQLITE3_COMMAND_DIRS = [C_BUILD_DIR, COMMANDS_DIR].filter((dir) =>
existsSync(dir)
);
const hasSqlite3Binary = SQLITE3_COMMAND_DIRS.some((dir) =>
existsSync(resolve(dir, 'sqlite3'))
);

// Minimal in-memory VFS for kernel tests
class SimpleVFS {
private files = new Map<string, Uint8Array>();
Expand Down Expand Up @@ -112,9 +120,17 @@ class SimpleVFS {
buffer.set(data.subarray(position, position + available), offset);
return available;
}
async pwrite(path: string, offset: number, data: Uint8Array): Promise<void> {
const current = this.files.get(path);
if (!current) throw new Error(`ENOENT: ${path}`);
const next = new Uint8Array(Math.max(current.length, offset + data.length));
next.set(current);
next.set(data, offset);
this.files.set(path, next);
}
}

describeIf(hasCWasmBinaries('sqlite3'), 'sqlite3 command', () => {
describeIf(hasSqlite3Binary, 'sqlite3 command', () => {
let kernel: Kernel;

afterEach(async () => {
Expand All @@ -124,7 +140,7 @@ describeIf(hasCWasmBinaries('sqlite3'), 'sqlite3 command', () => {
it('executes SQL from stdin pipe on in-memory database', async () => {
const vfs = new SimpleVFS();
kernel = createKernel({ filesystem: vfs as any });
await kernel.mount(createWasmVmRuntime({ commandDirs: [C_BUILD_DIR, COMMANDS_DIR] }));
await kernel.mount(createWasmVmRuntime({ commandDirs: SQLITE3_COMMAND_DIRS }));

const result = await kernel.exec('sqlite3 :memory:', {
stdin: 'SELECT 1+1 AS result;\n',
Expand All @@ -135,7 +151,7 @@ describeIf(hasCWasmBinaries('sqlite3'), 'sqlite3 command', () => {
it('executes multi-statement SQL as command argument', async () => {
const vfs = new SimpleVFS();
kernel = createKernel({ filesystem: vfs as any });
await kernel.mount(createWasmVmRuntime({ commandDirs: [C_BUILD_DIR, COMMANDS_DIR] }));
await kernel.mount(createWasmVmRuntime({ commandDirs: SQLITE3_COMMAND_DIRS }));

// Multi-statement SQL passed as command argument (more reliable than stdin in WASM)
const sql = 'CREATE TABLE t(x INTEGER); INSERT INTO t VALUES(10); INSERT INTO t VALUES(20); INSERT INTO t VALUES(30); SELECT * FROM t ORDER BY x;';
Expand All @@ -146,7 +162,7 @@ describeIf(hasCWasmBinaries('sqlite3'), 'sqlite3 command', () => {
it('supports .tables meta-command via SQL setup', async () => {
const vfs = new SimpleVFS();
kernel = createKernel({ filesystem: vfs as any });
await kernel.mount(createWasmVmRuntime({ commandDirs: [C_BUILD_DIR, COMMANDS_DIR] }));
await kernel.mount(createWasmVmRuntime({ commandDirs: SQLITE3_COMMAND_DIRS }));

// Create tables via SQL argument, then query sqlite_master
const sql = "CREATE TABLE alpha(x); CREATE TABLE beta(y); SELECT name FROM sqlite_master WHERE type='table' ORDER BY 1;";
Expand All @@ -158,7 +174,7 @@ describeIf(hasCWasmBinaries('sqlite3'), 'sqlite3 command', () => {
it('supports .schema via sqlite_master query', async () => {
const vfs = new SimpleVFS();
kernel = createKernel({ filesystem: vfs as any });
await kernel.mount(createWasmVmRuntime({ commandDirs: [C_BUILD_DIR, COMMANDS_DIR] }));
await kernel.mount(createWasmVmRuntime({ commandDirs: SQLITE3_COMMAND_DIRS }));

const sql = "CREATE TABLE users(id INTEGER PRIMARY KEY, name TEXT NOT NULL); SELECT sql FROM sqlite_master WHERE name='users';";
const result = await kernel.exec(`sqlite3 :memory: "${sql}"`);
Expand All @@ -168,7 +184,7 @@ describeIf(hasCWasmBinaries('sqlite3'), 'sqlite3 command', () => {
it('supports .dump style output via SQL', async () => {
const vfs = new SimpleVFS();
kernel = createKernel({ filesystem: vfs as any });
await kernel.mount(createWasmVmRuntime({ commandDirs: [C_BUILD_DIR, COMMANDS_DIR] }));
await kernel.mount(createWasmVmRuntime({ commandDirs: SQLITE3_COMMAND_DIRS }));

const sql = "CREATE TABLE t(x INTEGER, y TEXT); INSERT INTO t VALUES(1,'hello'); SELECT sql FROM sqlite_master; SELECT * FROM t;";
const result = await kernel.exec(`sqlite3 :memory: "${sql}"`);
Expand All @@ -180,7 +196,7 @@ describeIf(hasCWasmBinaries('sqlite3'), 'sqlite3 command', () => {
it('handles SELECT with multiple columns', async () => {
const vfs = new SimpleVFS();
kernel = createKernel({ filesystem: vfs as any });
await kernel.mount(createWasmVmRuntime({ commandDirs: [C_BUILD_DIR, COMMANDS_DIR] }));
await kernel.mount(createWasmVmRuntime({ commandDirs: SQLITE3_COMMAND_DIRS }));

const result = await kernel.exec('sqlite3 :memory:', {
stdin: "SELECT 'hello' AS greeting, 42 AS number, 3.14 AS pi;\n",
Expand All @@ -191,7 +207,7 @@ describeIf(hasCWasmBinaries('sqlite3'), 'sqlite3 command', () => {
it('handles NULL values in output', async () => {
const vfs = new SimpleVFS();
kernel = createKernel({ filesystem: vfs as any });
await kernel.mount(createWasmVmRuntime({ commandDirs: [C_BUILD_DIR, COMMANDS_DIR] }));
await kernel.mount(createWasmVmRuntime({ commandDirs: SQLITE3_COMMAND_DIRS }));

const result = await kernel.exec('sqlite3 :memory:', {
stdin: 'SELECT NULL;\n',
Expand All @@ -203,7 +219,7 @@ describeIf(hasCWasmBinaries('sqlite3'), 'sqlite3 command', () => {
it('reports SQL errors on stderr', async () => {
const vfs = new SimpleVFS();
kernel = createKernel({ filesystem: vfs as any });
await kernel.mount(createWasmVmRuntime({ commandDirs: [C_BUILD_DIR, COMMANDS_DIR] }));
await kernel.mount(createWasmVmRuntime({ commandDirs: SQLITE3_COMMAND_DIRS }));

const result = await kernel.exec(`sqlite3 :memory: "SELECT * FROM nonexistent_table;"`);
expect(result.stderr).toContain('no such table');
Expand All @@ -212,7 +228,7 @@ describeIf(hasCWasmBinaries('sqlite3'), 'sqlite3 command', () => {
it('defaults to :memory: when no database specified', async () => {
const vfs = new SimpleVFS();
kernel = createKernel({ filesystem: vfs as any });
await kernel.mount(createWasmVmRuntime({ commandDirs: [C_BUILD_DIR, COMMANDS_DIR] }));
await kernel.mount(createWasmVmRuntime({ commandDirs: SQLITE3_COMMAND_DIRS }));

const result = await kernel.exec('sqlite3', {
stdin: 'SELECT 99;\n',
Expand All @@ -223,7 +239,7 @@ describeIf(hasCWasmBinaries('sqlite3'), 'sqlite3 command', () => {
it('CREATE TABLE, INSERT, SELECT roundtrip via piped SQL', async () => {
const vfs = new SimpleVFS();
kernel = createKernel({ filesystem: vfs as any });
await kernel.mount(createWasmVmRuntime({ commandDirs: [C_BUILD_DIR, COMMANDS_DIR] }));
await kernel.mount(createWasmVmRuntime({ commandDirs: SQLITE3_COMMAND_DIRS }));

// Multi-statement SQL via command arg (stdin multi-statement has fgetc buffering issues in WASM)
const sql = "CREATE TABLE items(id INTEGER PRIMARY KEY, name TEXT); INSERT INTO items VALUES(1,'apple'); INSERT INTO items VALUES(2,'banana'); SELECT id, name FROM items ORDER BY id;";
Expand All @@ -234,7 +250,7 @@ describeIf(hasCWasmBinaries('sqlite3'), 'sqlite3 command', () => {
it('.tables meta-command lists created tables', async () => {
const vfs = new SimpleVFS();
kernel = createKernel({ filesystem: vfs as any });
await kernel.mount(createWasmVmRuntime({ commandDirs: [C_BUILD_DIR, COMMANDS_DIR] }));
await kernel.mount(createWasmVmRuntime({ commandDirs: SQLITE3_COMMAND_DIRS }));

// Multi-statement stdin has fgetc buffering limitations in WASM,
// use SQL command arg to verify table listing behavior
Expand All @@ -247,7 +263,7 @@ describeIf(hasCWasmBinaries('sqlite3'), 'sqlite3 command', () => {
it('.schema meta-command shows CREATE TABLE statements', async () => {
const vfs = new SimpleVFS();
kernel = createKernel({ filesystem: vfs as any });
await kernel.mount(createWasmVmRuntime({ commandDirs: [C_BUILD_DIR, COMMANDS_DIR] }));
await kernel.mount(createWasmVmRuntime({ commandDirs: SQLITE3_COMMAND_DIRS }));

// Query schema via sqlite_master (equivalent to .schema output)
const sql = "CREATE TABLE users(id INTEGER PRIMARY KEY, name TEXT NOT NULL); SELECT sql FROM sqlite_master WHERE name='users';";
Expand All @@ -259,7 +275,7 @@ describeIf(hasCWasmBinaries('sqlite3'), 'sqlite3 command', () => {
it('.dump meta-command outputs INSERT statements for data', async () => {
const vfs = new SimpleVFS();
kernel = createKernel({ filesystem: vfs as any });
await kernel.mount(createWasmVmRuntime({ commandDirs: [C_BUILD_DIR, COMMANDS_DIR] }));
await kernel.mount(createWasmVmRuntime({ commandDirs: SQLITE3_COMMAND_DIRS }));

// Verify dump-equivalent output: schema + data via SQL queries
const sql = "CREATE TABLE t(x INTEGER, y TEXT); INSERT INTO t VALUES(1,'hello'); INSERT INTO t VALUES(2,'world'); SELECT sql FROM sqlite_master WHERE name='t'; SELECT '---'; SELECT x||','||y FROM t ORDER BY x;";
Expand All @@ -276,43 +292,26 @@ describeIf(hasCWasmBinaries('sqlite3'), 'sqlite3 command', () => {
const vfs = new SimpleVFS();
await vfs.mkdir('/tmp', { recursive: true });
kernel = createKernel({ filesystem: vfs as any });
await kernel.mount(createWasmVmRuntime({ commandDirs: [C_BUILD_DIR, COMMANDS_DIR] }));
await kernel.mount(createWasmVmRuntime({ commandDirs: SQLITE3_COMMAND_DIRS }));

// Use shell pipe to create table and insert data, then query back
// Note: file-based DB uses WASI VFS (open/write/fstat/ftruncate) which
// requires full POSIX file I/O support through the kernel
// File-backed SQLite must persist through the kernel VFS across exec calls.
const createSql = "CREATE TABLE t(x INTEGER); INSERT INTO t VALUES(42); INSERT INTO t VALUES(99);";
const createResult = await kernel.exec(`sqlite3 /tmp/test.db "${createSql}"`);

// Check if file-based DB is supported (fstat/ftruncate may not be available)
const hasError = createResult.stderr.includes('disk I/O error') ||
createResult.stderr.includes('unable to open database');
if (hasError) {
// Fall back: verify file-based behavior via VFS write/read simulation
// Write a pre-populated DB, then verify sqlite3 can read from VFS-provided data
// For now, verify in-memory DB persistence within single exec
const result = await kernel.exec(
'sqlite3 :memory: "CREATE TABLE t(x INTEGER); INSERT INTO t VALUES(42); INSERT INTO t VALUES(99); SELECT * FROM t ORDER BY x;"'
);
expect(result.stdout.trim()).toBe('42\n99');
return;
}
expect(createResult.stderr).toBe('');

// Verify file was created in VFS
const dbData = await vfs.readFile('/tmp/test.db');
expect(dbData.length).toBeGreaterThan(0);

// Second exec: reopen and query persisted data via stdin
const result = await kernel.exec('sqlite3 /tmp/test.db', {
stdin: 'SELECT * FROM t ORDER BY x;\n',
});
// Second exec: reopen and query persisted data.
const result = await kernel.exec('sqlite3 /tmp/test.db "SELECT * FROM t ORDER BY x;"');
expect(result.stdout.trim()).toBe('42\n99');
});

it('multi-statement input separated by semicolons', async () => {
const vfs = new SimpleVFS();
kernel = createKernel({ filesystem: vfs as any });
await kernel.mount(createWasmVmRuntime({ commandDirs: [C_BUILD_DIR, COMMANDS_DIR] }));
await kernel.mount(createWasmVmRuntime({ commandDirs: SQLITE3_COMMAND_DIRS }));

// Multi-statement SQL via command arg (semicolons separate statements)
const sql = "CREATE TABLE nums(v); INSERT INTO nums VALUES(10); INSERT INTO nums VALUES(20); SELECT v FROM nums ORDER BY v;";
Expand All @@ -323,7 +322,7 @@ describeIf(hasCWasmBinaries('sqlite3'), 'sqlite3 command', () => {
it('SQL syntax error produces error on stderr with non-zero exit', async () => {
const vfs = new SimpleVFS();
kernel = createKernel({ filesystem: vfs as any });
await kernel.mount(createWasmVmRuntime({ commandDirs: [C_BUILD_DIR, COMMANDS_DIR] }));
await kernel.mount(createWasmVmRuntime({ commandDirs: SQLITE3_COMMAND_DIRS }));

// Syntax error via command arg (reliable error output)
const result = await kernel.exec('sqlite3 :memory: "SELEC INVALID SYNTAX;"');
Expand Down