libfx 0.0.1 → 0.0.3

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/README.md CHANGED
@@ -73,6 +73,6 @@ The staging script includes `zig-out/lib/libfx.node` by default for local testin
73
73
 
74
74
  The npm `latest` dist-tag is the stable channel. The `dev` dist-tag tracks successful builds from `main` and uses immutable prerelease versions. Publishing runs through `.github/workflows/publish-libfx.yml` with npm trusted publishing and provenance. Configure the npm trusted publisher for the `vercel-labs/fx` repository, workflow filename `publish-libfx.yml`, and GitHub environment `npm`. Because npm requires a package to exist before trusted publishing can be configured, the first `libfx` version must be published once by a maintainer before enabling that relationship.
75
75
 
76
- JavaScript hosts may also provide configuration, prompt history, session persistence, device login, URL opening, and a foreground workspace. The optional workspace adapter exposes only `run_command`, delegated to the host.
76
+ JavaScript hosts can provide configuration, prompt history, session persistence, device login, URL opening, and a foreground workspace. The optional workspace adapter exposes only `terminal` with `{ action: "exec", command }`; command execution is delegated to the host in a clean, root-fixed environment.
77
77
 
78
78
  WebAssembly builds do not include native processes, OS sandboxing, native MCP, subagents, skills, auto-upgrade, clipboard integration, arbitrary WASI filesystem access, or web search.
package/fx-core.wasm CHANGED
Binary file
package/fx-sdk.js CHANGED
@@ -4,6 +4,7 @@ const strictDecoder = new TextDecoder("utf-8", { fatal: true });
4
4
  const workspaceInfoLimit = 4 * 1024;
5
5
  const workspaceCommandLimit = 64 * 1024;
6
6
  const workspaceOutputLimit = 64 * 1024;
7
+ const streamReadsPerTaskYield = 32;
7
8
 
8
9
  function validWorkspacePath(path) {
9
10
  if (typeof path !== "string" || !path.startsWith("/") || path.includes("\0")) return false;
@@ -205,6 +206,13 @@ function raceWithTimeout(promise, timeoutMs, timeoutValue) {
205
206
  });
206
207
  }
207
208
 
209
+ function yieldToHostTask() {
210
+ if (typeof globalThis.setImmediate === "function") {
211
+ return new Promise((resolve) => globalThis.setImmediate(resolve));
212
+ }
213
+ return new Promise((resolve) => setTimeout(resolve, 0));
214
+ }
215
+
208
216
  function createRuntime(options) {
209
217
  const stdin = new ByteQueue();
210
218
  const streams = new Map();
@@ -332,6 +340,7 @@ function createRuntime(options) {
332
340
  options.onTerminalPoll?.();
333
341
  if (stdin.chunks.length) return 1;
334
342
  if (stdin.closed) return -1;
343
+ if (timeoutMs === 0) return 0;
335
344
  return stdin.wait(timeoutMs >= 0 ? timeoutMs : undefined).then(() =>
336
345
  stdin.chunks.length ? 1 : (stdin.closed ? -1 : 0));
337
346
  }
@@ -355,6 +364,7 @@ function createRuntime(options) {
355
364
  pendingRead: null,
356
365
  readResult: null,
357
366
  readError: null,
367
+ readsSinceTaskYield: 0,
358
368
  };
359
369
  streams.set(handle, state);
360
370
  state.responseSettled = Promise.resolve().then(() => options.fetch(text(urlPtr, urlLen), {
@@ -389,6 +399,13 @@ function createRuntime(options) {
389
399
  function streamNext(handle, outPtr, outCap) {
390
400
  const state = streams.get(handle);
391
401
  if (!state) return -1;
402
+ const yieldAfterReadyResult = (result) => {
403
+ if (result <= 0) return result;
404
+ state.readsSinceTaskYield += 1;
405
+ if (state.readsSinceTaskYield < streamReadsPerTaskYield) return result;
406
+ state.readsSinceTaskYield = 0;
407
+ return yieldToHostTask().then(() => result);
408
+ };
392
409
  const copy = (chunk) => {
393
410
  const written = chunk.subarray(0, outCap);
394
411
  bytes(outPtr, written.length).set(written);
@@ -406,7 +423,7 @@ function createRuntime(options) {
406
423
  return copy(value);
407
424
  };
408
425
  const immediate = consume();
409
- if (immediate !== null) return immediate;
426
+ if (immediate !== null) return yieldAfterReadyResult(immediate);
410
427
  if (!state.reader) return 0;
411
428
  if (!state.pendingRead) {
412
429
  state.pendingRead = state.reader.read().then((result) => {
@@ -420,7 +437,7 @@ function createRuntime(options) {
420
437
  return raceWithTimeout(state.pendingRead.then(() => true), 50, false).then((ready) => {
421
438
  if (!ready) return -3;
422
439
  const result = consume();
423
- return result === null ? -3 : result;
440
+ return result === null ? -3 : yieldAfterReadyResult(result);
424
441
  });
425
442
  }
426
443
 
package/fx-term.wasm CHANGED
Binary file
Binary file
Binary file
Binary file
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "libfx",
3
- "version": "0.0.1",
3
+ "version": "0.0.3",
4
4
  "description": "Embed fx agents and terminals in JavaScript hosts",
5
5
  "type": "module",
6
6
  "repository": {