On branch persist-machine-session-id Your branch is up to date with 'origin/persist-machine-session-id'. Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git restore <file>..." to discard changes in working directory) modified: src/commands.ts modified: src/main.ts no changes added to commit (use "git add" and/or "git commit -a") src/commands.ts | 39 +++++++++++++++++ src/main.ts | 131 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 167 insertions(+), 3 deletions(-)
diff --git a/src/commands.ts b/src/commands.ts
index 3a3bb0d..fc1466a 100644
--- a/src/commands.ts
+++ b/src/commands.ts
@@ -108,6 +108,45 @@ else:
`,
};
+/**
+ * FS consistency test helper — writes or reads a test file from the Python side.
+ * Usage:
+ * fs-test write <path> <content> — write content to path via Python open()
+ * fs-test read <path> — read path via Python open() and print it
+ */
+export const FS_TEST: CommandDef = {
+ source: `\
+import sys
+import os
+
+args = sys.argv[1:]
+if len(args) < 2:
+ print("Usage: fs-test write <path> <content>", file=sys.stderr)
+ print(" fs-test read <path>", file=sys.stderr)
+ sys.exit(1)
+
+action = args[0]
+path = args[1]
+
+if action == "write":
+ if len(args) < 3:
+ print("Missing content argument", file=sys.stderr)
+ sys.exit(1)
+ content = args[2]
+ os.makedirs(os.path.dirname(path), exist_ok=True)
+ with open(path, 'w') as f:
+ f.write(content)
+ print(f"PY-WRITE: {content}")
+elif action == "read":
+ with open(path, 'r') as f:
+ content = f.read()
+ print(f"PY-READ: {content}")
+else:
+ print(f"Unknown action: {action}", file=sys.stderr)
+ sys.exit(1)
+`,
+};
+
export const FILES: CommandDef = {
source: `\
import os
diff --git a/src/main.ts b/src/main.ts
index 140bfa4..48f104b 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -1,5 +1,5 @@
import { BrowserRuntime } from "./runtime.js";
-import { HELLO, SYSINFO, FETCH, ENV, FILES } from "./commands.js";
+import { HELLO, SYSINFO, FETCH, ENV, FILES, FS_TEST } from "./commands.js";
import { SecretStore } from "./secrets.js";
import { MachineConfig } from "./machine-config.js";
@@ -305,11 +305,135 @@ async function main() {
const saved = localStorage.getItem(SESSION_ID_STORAGE_KEY) || "";
const match = saved.match(/id:\s*(.+)/);
if (match) {
- log(`Session ID: ${match[1].trim()}`);
+ log(`Session ID (localStorage): ${match[1].trim()}`);
+ } else {
+ log("Session ID (localStorage): not set");
+ }
+ // Also read the file via TS and Python for comparison
+ try {
+ const tsContent = await runtime.readFile(SESSION_ID_FS_PATH);
+ log(`Session ID (TS readFile): ${tsContent.trim()}`);
+ } catch {
+ log("Session ID (TS readFile): file not found");
+ }
+ try {
+ const pyResult = await runtime.exec("fs-test", ["read", SESSION_ID_FS_PATH]);
+ log(`Session ID (PY open): ${pyResult.stdout.trim().replace("PY-READ: ", "")}`);
+ } catch {
+ log("Session ID (PY open): file not found");
+ }
+ if (match) {
log("Paste this into another browser's config to share machine context.");
} else {
- log("No session ID yet. Run a machine command first to generate one.");
+ log("Run a machine command first to generate one.");
+ }
+ busy = false;
+ input.disabled = false;
+ input.focus();
+ return;
+ }
+
+ // Special built-in: fs-consistency-test
+ if (trimmed === "fs-consistency-test") {
+ const TEST_PATH = "/tmp/fs-test-file.txt";
+
+ async function tsWrite(content: string) {
+ await runtime.writeFile(TEST_PATH, content);
+ }
+ async function tsRead(): Promise<string> {
+ return await runtime.readFile(TEST_PATH);
+ }
+ async function pyWrite(content: string): Promise<string> {
+ const r = await runtime.exec("fs-test", ["write", TEST_PATH, content]);
+ return r.stdout.trim();
}
+ async function pyRead(): Promise<string> {
+ const r = await runtime.exec("fs-test", ["read", TEST_PATH]);
+ return r.stdout.trim();
+ }
+
+ let pass = 0;
+ let fail = 0;
+ async function check(label: string, reader: () => Promise<string>, expected: string) {
+ const got = await reader();
+ // For pyRead, output is "PY-READ: <content>"
+ const value = got.startsWith("PY-READ: ") ? got.slice(9) : got;
+ if (value === expected) {
+ log(` PASS ${label}`);
+ pass++;
+ } else {
+ logStderr(` FAIL ${label} — expected "${expected}", got "${value}"`);
+ fail++;
+ }
+ }
+
+ try {
+ // Clean slate — delete test file if it exists
+ try { await runtime.exec("fs-test", ["write", TEST_PATH, ""]); } catch {}
+
+ log("=== Test 1: TS creates file, both read ===");
+ await tsWrite("ts-created");
+ await check("TS write → TS read", tsRead, "ts-created");
+ await check("TS write → PY read", pyRead, "ts-created");
+
+ log("=== Test 2: PY creates file, both read ===");
+ // Use a fresh path so PY is the first writer
+ const TEST_PATH_2 = "/tmp/fs-test-file-2.txt";
+ const pyWrite2 = async (c: string) => { await runtime.exec("fs-test", ["write", TEST_PATH_2, c]); };
+ const tsRead2 = async () => runtime.readFile(TEST_PATH_2);
+ const pyRead2 = async () => {
+ const r = await runtime.exec("fs-test", ["read", TEST_PATH_2]);
+ return r.stdout.trim();
+ };
+ await pyWrite2("py-created");
+ await check("PY write → TS read", tsRead2, "py-created");
+ await check("PY write → PY read", pyRead2, "py-created");
+
+ log("=== Test 3: TS creates, PY overwrites, both read ===");
+ await tsWrite("ts-original");
+ await pyWrite("py-overwrite-1");
+ await check("TS create → PY overwrite → TS read", tsRead, "py-overwrite-1");
+ await check("TS create → PY overwrite → PY read", pyRead, "py-overwrite-1");
+
+ log("=== Test 4: PY creates, TS overwrites, both read ===");
+ await pyWrite2("py-original");
+ await runtime.writeFile(TEST_PATH_2, "ts-overwrite-1");
+ await check("PY create → TS overwrite → TS read", tsRead2, "ts-overwrite-1");
+ await check("PY create → TS overwrite → PY read", pyRead2, "ts-overwrite-1");
+
+ log("=== Test 5: PY creates, TS overwrites twice, both read ===");
+ const TEST_PATH_3 = "/tmp/fs-test-file-3.txt";
+ const pyWrite3 = async (c: string) => { await runtime.exec("fs-test", ["write", TEST_PATH_3, c]); };
+ const tsRead3 = async () => runtime.readFile(TEST_PATH_3);
+ const pyRead3 = async () => {
+ const r = await runtime.exec("fs-test", ["read", TEST_PATH_3]);
+ return r.stdout.trim();
+ };
+ await pyWrite3("py-first");
+ await runtime.writeFile(TEST_PATH_3, "ts-second");
+ await check("PY create → TS overwrite #1 → TS read", tsRead3, "ts-second");
+ await check("PY create → TS overwrite #1 → PY read", pyRead3, "ts-second");
+ await runtime.writeFile(TEST_PATH_3, "ts-third");
+ await check("PY create → TS overwrite #2 → TS read", tsRead3, "ts-third");
+ await check("PY create → TS overwrite #2 → PY read", pyRead3, "ts-third");
+
+ log("=== Test 6: Alternating writers ===");
+ await tsWrite("ts-v1");
+ await check("TS write v1 → PY read", pyRead, "ts-v1");
+ await pyWrite("py-v2");
+ await check("PY write v2 → TS read", tsRead, "py-v2");
+ await tsWrite("ts-v3");
+ await check("TS write v3 → PY read", pyRead, "ts-v3");
+ await pyWrite("py-v4");
+ await check("PY write v4 → TS read", tsRead, "py-v4");
+ await tsWrite("ts-v5");
+ await check("TS write v5 → PY read", pyRead, "ts-v5");
+
+ log(`\n=== Results: ${pass} passed, ${fail} failed ===`);
+ } catch (e: unknown) {
+ logStderr(`Test error: ${e instanceof Error ? e.message : e}`);
+ }
+
busy = false;
input.disabled = false;
input.focus();
@@ -426,6 +550,7 @@ async function main() {
runtime.registerCommand("fetch", FETCH),
runtime.registerCommand("env", ENV),
runtime.registerCommand("files", FILES),
+ runtime.registerCommand("fs-test", FS_TEST),
]);
// Register external packages from GitHubgit add src/commands.ts src/main.ts && git commit -m "$(cat <<'EOF' Add diagnostic tools for session ID and filesystem consistency - Extend session-id command to show value from all three sources (localStorage, TS readFile, Python open) for debugging - Add fs-test command for reading/writing files from the Python side - Add fs-consistency-test command that verifies TS/Python filesystem interop across all read/write permutations These tools helped confirm the session ID caching issue was in the machine tool (stirlingbridge/machine#75), not the Emscripten FS layer. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> EOF )"
2 files changed, 167 insertions(+), 3 deletions(-)
To github.com:stirlingbridge/local-orchestrator.git 0b72719..d3c40c1 persist-machine-session-id -> persist-machine-session-id
PR updated at https://github.com/stirlingbridge/local-orchestrator/pull/8 with the diagnostic tools. The two commits on the branch are now:
With stirlingbridge/machine#75 merged, the config editor session ID override should now work mid-session too.
Thanks. Can we move the fs-consistency-test code out of main.py and into its own file? It's a bit incongruous in main.
{
"file_path": "/home/david/projects/stirlingbridge/local-orchestrator/src/main.ts",
"offset": 319,
"limit": 100
}319 try {
320 const pyResult = await runtime.exec("fs-test", ["read", SESSION_ID_FS_PATH]);
321 log(`Session ID (PY open): ${pyResult.stdout.trim().replace("PY-READ: ", "")}`);
322 } catch {
323 log("Session ID (PY open): file not found");
324 }
325 if (match) {
326 log("Paste this into another browser's config to share machine context.");
327 } else {
328 log("Run a machine command first to generate one.");
329 }
330 busy = false;
331 input.disabled = false;
332 input.focus();
333 return;
334 }
335
336 // Special built-in: fs-consistency-test
337 if (trimmed === "fs-consistency-test") {
338 const TEST_PATH = "/tmp/fs-test-file.txt";
339
340 async function tsWrite(content: string) {
341 await runtime.writeFile(TEST_PATH, content);
342 }
343 async function tsRead(): Promise<string> {
344 return await runtime.readFile(TEST_PATH);
345 }
346 async function pyWrite(content: string): Promise<string> {
347 const r = await runtime.exec("fs-test", ["write", TEST_PATH, content]);
348 return r.stdout.trim();
349 }
350 async function pyRead(): Promise<string> {
351 const r = await runtime.exec("fs-test", ["read", TEST_PATH]);
352 return r.stdout.trim();
353 }
354
355 let pass = 0;
356 let fail = 0;
357 async function check(label: string, reader: () => Promise<string>, expected: string) {
358 const got = await reader();
359 // For pyRead, output is "PY-READ: <content>"
360 const value = got.startsWith("PY-READ: ") ? got.slice(9) : got;
361 if (value === expected) {
362 log(` PASS ${label}`);
363 pass++;
364 } else {
365 logStderr(` FAIL ${label} — expected "${expected}", got "${value}"`);
366 fail++;
367 }
368 }
369
370 try {
371 // Clean slate — delete test file if it exists
372 try { await runtime.exec("fs-test", ["write", TEST_PATH, ""]); } catch {}
373
374 log("=== Test 1: TS creates file, both read ===");
375 await tsWrite("ts-created");
376 await check("TS write → TS read", tsRead, "ts-created");
377 await check("TS write → PY read", pyRead, "ts-created");
378
379 log("=== Test 2: PY creates file, both read ===");
380 // Use a fresh path so PY is the first writer
381 const TEST_PATH_2 = "/tmp/fs-test-file-2.txt";
382 const pyWrite2 = async (c: string) => { await runtime.exec("fs-test", ["write", TEST_PATH_2, c]); };
383 const tsRead2 = async () => runtime.readFile(TEST_PATH_2);
384 const pyRead2 = async () => {
385 const r = await runtime.exec("fs-test", ["read", TEST_PATH_2]);
386 return r.stdout.trim();
387 };
388 await pyWrite2("py-created");
389 await check("PY write → TS read", tsRead2, "py-created");
390 await check("PY write → PY read", pyRead2, "py-created");
391
392 log("=== Test 3: TS creates, PY overwrites, both read ===");
393 await tsWrite("ts-original");
394 await pyWrite("py-overwrite-1");
395 await check("TS create → PY overwrite → TS read", tsRead, "py-overwrite-1");
396 await check("TS create → PY overwrite → PY read", pyRead, "py-overwrite-1");
397
398 log("=== Test 4: PY creates, TS overwrites, both read ===");
399 await pyWrite2("py-original");
400 await runtime.writeFile(TEST_PATH_2, "ts-overwrite-1");
401 await check("PY create → TS overwrite → TS read", tsRead2, "ts-overwrite-1");
402 await check("PY create → TS overwrite → PY read", pyRead2, "ts-overwrite-1");
403
404 log("=== Test 5: PY creates, TS overwrites twice, both read ===");
405 const TEST_PATH_3 = "/tmp/fs-test-file-3.txt";
406 const pyWrite3 = async (c: string) => { await runtime.exec("fs-test", ["write", TEST_PATH_3, c]); };
407 const tsRead3 = async () => runtime.readFile(TEST_PATH_3);
408 const pyRead3 = async () => {
409 const r = await runtime.exec("fs-test", ["read", TEST_PATH_3]);
410 return r.stdout.trim();
411 };
412 await pyWrite3("py-first");
413 await runtime.writeFile(TEST_PATH_3, "ts-second");
414 await check("PY create → TS overwrite #1 → TS read", tsRead3, "ts-second");
415 await check("PY create → TS overwrite #1 → PY read", pyRead3, "ts-second");
416 await runtime.writeFile(TEST_PATH_3, "ts-third");
417 await check("PY create → TS overwrite #2 → TS read", tsRead3, "ts-third");
418 await check("PY create → TS overwrite #2 → PY read", pyRead3, "ts-third");{
"file_path": "/home/david/projects/stirlingbridge/local-orchestrator/src/main.ts",
"offset": 418,
"limit": 25
}418 await check("PY create → TS overwrite #2 → PY read", pyRead3, "ts-third");
419
420 log("=== Test 6: Alternating writers ===");
421 await tsWrite("ts-v1");
422 await check("TS write v1 → PY read", pyRead, "ts-v1");
423 await pyWrite("py-v2");
424 await check("PY write v2 → TS read", tsRead, "py-v2");
425 await tsWrite("ts-v3");
426 await check("TS write v3 → PY read", pyRead, "ts-v3");
427 await pyWrite("py-v4");
428 await check("PY write v4 → TS read", tsRead, "py-v4");
429 await tsWrite("ts-v5");
430 await check("TS write v5 → PY read", pyRead, "ts-v5");
431
432 log(`\n=== Results: ${pass} passed, ${fail} failed ===`);
433 } catch (e: unknown) {
434 logStderr(`Test error: ${e instanceof Error ? e.message : e}`);
435 }
436
437 busy = false;
438 input.disabled = false;
439 input.focus();
440 return;
441 }
442 The test needs access to runtime, log, and logStderr from main. I'll extract it as a function that takes those as parameters.
import type { BrowserRuntime } from "./runtime.js";
interface TestLogger {
log: (text: string) => void;
logStderr: (text: string) => void;
}
/**
* Runs a filesystem consistency test that verifies TS (pyodide.FS) and
* Python (open()) can read/write files interchangeably across all
* permutations of who creates and who overwrites.
*
* Requires the "fs-test" command to be registered on the runtime.
*/
export async function runFsConsistencyTest(
runtime: BrowserRuntime,
{ log, logStderr }: TestLogger,
): Promise<void> {
const TEST_PATH = "/tmp/fs-test-file.txt";
async function tsWrite(content: string) {
await runtime.writeFile(TEST_PATH, content);
}
async function tsRead(): Promise<string> {
return await runtime.readFile(TEST_PATH);
}
async function pyWrite(content: string): Promise<string> {
const r = await runtime.exec("fs-test", ["write", TEST_PATH, content]);
return r.stdout.trim();
}
async function pyRead(): Promise<string> {
const r = await runtime.exec("fs-test", ["read", TEST_PATH]);
return r.stdout.trim();
}
let pass = 0;
let fail = 0;
async function check(label: string, reader: () => Promise<string>, expected: string) {
const got = await reader();
// For pyRead, output is "PY-READ: <content>"
const value = got.startsWith("PY-READ: ") ? got.slice(9) : got;
if (value === expected) {
log(` PASS ${label}`);
pass++;
} else {
logStderr(` FAIL ${label} — expected "${expected}", got "${value}"`);
fail++;
}
}
// Clean slate — delete test file if it exists
try { await runtime.exec("fs-test", ["write", TEST_PATH, ""]); } catch {}
log("=== Test 1: TS creates file, both read ===");
await tsWrite("ts-created");
await check("TS write → TS read", tsRead, "ts-created");
await check("TS write → PY read", pyRead, "ts-created");
log("=== Test 2: PY creates file, both read ===");
// Use a fresh path so PY is the first writer
const TEST_PATH_2 = "/tmp/fs-test-file-2.txt";
const pyWrite2 = async (c: string) => { await runtime.exec("fs-test", ["write", TEST_PATH_2, c]); };
const tsRead2 = async () => runtime.readFile(TEST_PATH_2);
const pyRead2 = async () => {
const r = await runtime.exec("fs-test", ["read", TEST_PATH_2]);
return r.stdout.trim();
};
await pyWrite2("py-created");
await check("PY write → TS read", tsRead2, "py-created");
await check("PY write → PY read", pyRead2, "py-created");
log("=== Test 3: TS creates, PY overwrites, both read ===");
await tsWrite("ts-original");
await pyWrite("py-overwrite-1");
await check("TS create → PY overwrite → TS read", tsRead, "py-overwrite-1");
await check("TS create → PY overwrite → PY read", pyRead, "py-overwrite-1");
log("=== Test 4: PY creates, TS overwrites, both read ===");
await pyWrite2("py-original");
await runtime.writeFile(TEST_PATH_2, "ts-overwrite-1");
await check("PY create → TS overwrite → TS read", tsRead2, "ts-overwrite-1");
await check("PY create → TS overwrite → PY read", pyRead2, "ts-overwrite-1");
log("=== Test 5: PY creates, TS overwrites twice, both read ===");
const TEST_PATH_3 = "/tmp/fs-test-file-3.txt";
const pyWrite3 = async (c: string) => { await runtime.exec("fs-test", ["write", TEST_PATH_3, c]); };
const tsRead3 = async () => runtime.readFile(TEST_PATH_3);
const pyRead3 = async () => {
const r = await runtime.exec("fs-test", ["read", TEST_PATH_3]);
return r.stdout.trim();
};
await pyWrite3("py-first");
await runtime.writeFile(TEST_PATH_3, "ts-second");
await check("PY create → TS overwrite #1 → TS read", tsRead3, "ts-second");
await check("PY create → TS overwrite #1 → PY read", pyRead3, "ts-second");
await runtime.writeFile(TEST_PATH_3, "ts-third");
await check("PY create → TS overwrite #2 → TS read", tsRead3, "ts-third");
await check("PY create → TS overwrite #2 → PY read", pyRead3, "ts-third");
log("=== Test 6: Alternating writers ===");
await tsWrite("ts-v1");
await check("TS write v1 → PY read", pyRead, "ts-v1");
await pyWrite("py-v2");
await check("PY write v2 → TS read", tsRead, "py-v2");
await tsWrite("ts-v3");
await check("TS write v3 → PY read", pyRead, "ts-v3");
await pyWrite("py-v4");
await check("PY write v4 → TS read", tsRead, "py-v4");
await tsWrite("ts-v5");
await check("TS write v5 → PY read", pyRead, "ts-v5");
log(`\n=== Results: ${pass} passed, ${fail} failed ===`);
}
File created successfully at: /home/david/projects/stirlingbridge/local-orchestrator/src/fs-consistency-test.ts
import { MachineConfig } from "./machine-config.js";import { MachineConfig } from "./machine-config.js";
import { runFsConsistencyTest } from "./fs-consistency-test.js";The file /home/david/projects/stirlingbridge/local-orchestrator/src/main.ts has been updated successfully.
// Special built-in: fs-consistency-test
if (trimmed === "fs-consistency-test") {
const TEST_PATH = "/tmp/fs-test-file.txt";
async function tsWrite(content: string) {
await runtime.writeFile(TEST_PATH, content);
}
async function tsRead(): Promise<string> {
return await runtime.readFile(TEST_PATH);
}
async function pyWrite(content: string): Promise<string> {
const r = await runtime.exec("fs-test", ["write", TEST_PATH, content]);
return r.stdout.trim();
}
async function pyRead(): Promise<string> {
const r = await runtime.exec("fs-test", ["read", TEST_PATH]);
return r.stdout.trim();
}
let pass = 0;
let fail = 0;
async function check(label: string, reader: () => Promise<string>, expected: string) {
const got = await reader();
// For pyRead, output is "PY-READ: <content>"
const value = got.startsWith("PY-READ: ") ? got.slice(9) : got;
if (value === expected) {
log(` PASS ${label}`);
pass++;
} else {
logStderr(` FAIL ${label} — expected "${expected}", got "${value}"`);
fail++;
}
}
try {
// Clean slate — delete test file if it exists
try { await runtime.exec("fs-test", ["write", TEST_PATH, ""]); } catch {}
log("=== Test 1: TS creates file, both read ===");
await tsWrite("ts-created");
await check("TS write → TS read", tsRead, "ts-created");
await check("TS write → PY read", pyRead, "ts-created");
log("=== Test 2: PY creates file, both read ===");
// Use a fresh path so PY is the first writer
const TEST_PATH_2 = "/tmp/fs-test-file-2.txt";
const pyWrite2 = async (c: string) => { await runtime.exec("fs-test", ["write", TEST_PATH_2, c]); };
const tsRead2 = async () => runtime.readFile(TEST_PATH_2);
const pyRead2 = async () => {
const r = await runtime.exec("fs-test", ["read", TEST_PATH_2]);
return r.stdout.trim();
};
await pyWrite2("py-created");
await check("PY write → TS read", tsRead2, "py-created");
await check("PY write → PY read", pyRead2, "py-created");
log("=== Test 3: TS creates, PY overwrites, both read ===");
await tsWrite("ts-original");
await pyWrite("py-overwrite-1");
await check("TS create → PY overwrite → TS read", tsRead, "py-overwrite-1");
await check("TS create → PY overwrite → PY read", pyRead, "py-overwrite-1");
log("=== Test 4: PY creates, TS overwrites, both read ===");
await pyWrite2("py-original");
await runtime.writeFile(TEST_PATH_2, "ts-overwrite-1");
await check("PY create → TS overwrite → TS read", tsRead2, "ts-overwrite-1");
await check("PY create → TS overwrite → PY read", pyRead2, "ts-overwrite-1");
log("=== Test 5: PY creates, TS overwrites twice, both read ===");
const TEST_PATH_3 = "/tmp/fs-test-file-3.txt";
const pyWrite3 = async (c: string) => { await runtime.exec("fs-test", ["write", TEST_PATH_3, c]); };
const tsRead3 = async () => runtime.readFile(TEST_PATH_3);
const pyRead3 = async () => {
const r = await runtime.exec("fs-test", ["read", TEST_PATH_3]);
return r.stdout.trim();
};
await pyWrite3("py-first");
await runtime.writeFile(TEST_PATH_3, "ts-second");
await check("PY create → TS overwrite #1 → TS read", tsRead3, "ts-second");
await check("PY create → TS overwrite #1 → PY read", pyRead3, "ts-second");
await runtime.writeFile(TEST_PATH_3, "ts-third");
await check("PY create → TS overwrite #2 → TS read", tsRead3, "ts-third");
await check("PY create → TS overwrite #2 → PY read", pyRead3, "ts-third");
log("=== Test 6: Alternating writers ===");
await tsWrite("ts-v1");
await check("TS write v1 → PY read", pyRead, "ts-v1");
await pyWrite("py-v2");
await check("PY write v2 → TS read", tsRead, "py-v2");
await tsWrite("ts-v3");
await check("TS write v3 → PY read", pyRead, "ts-v3");
await pyWrite("py-v4");
await check("PY write v4 → TS read", tsRead, "py-v4");
await tsWrite("ts-v5");
await check("TS write v5 → PY read", pyRead, "ts-v5");
log(`\n=== Results: ${pass} passed, ${fail} failed ===`);
} catch (e: unknown) {
logStderr(`Test error: ${e instanceof Error ? e.message : e}`);
}
busy = false;
input.disabled = false;
input.focus();
return;
} // Special built-in: fs-consistency-test
if (trimmed === "fs-consistency-test") {
try {
await runFsConsistencyTest(runtime, { log, logStderr });
} catch (e: unknown) {
logStderr(`Test error: ${e instanceof Error ? e.message : e}`);
}
busy = false;
input.disabled = false;
input.focus();
return;
}The file /home/david/projects/stirlingbridge/local-orchestrator/src/main.ts has been updated successfully.
> local-orchestrator@0.1.0 build > tsc && vite build vite v6.4.1 building for production... transforming... ✓ 9 modules transformed. rendering chunks... computing gzip size... dist/assets/worker-GLzDM1pK.js 9.10 kB dist/index.html 11.50 kB │ gzip: 2.44 kB dist/assets/index-9ROTy5Qb.js 23.12 kB │ gzip: 7.92 kB ✓ built in 212ms
Build is clean. The test code is now in src/fs-consistency-test.ts and main.ts just imports and calls it. Want me to push this to the PR?
git add src/fs-consistency-test.ts src/main.ts && git commit -m "$(cat <<'EOF' Extract fs-consistency-test into its own module Move the filesystem consistency test logic out of main.ts into src/fs-consistency-test.ts for better separation of concerns. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> EOF )"
2 files changed, 115 insertions(+), 95 deletions(-) create mode 100644 src/fs-consistency-test.ts
To github.com:stirlingbridge/local-orchestrator.git d3c40c1..6570838 persist-machine-session-id -> persist-machine-session-id