@noodleseed/one 0.144.2 → 0.145.1

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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@noodle-borg/agent-kit",
3
- "version": "0.87.0",
3
+ "version": "0.87.1",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "engines": {
@@ -0,0 +1,87 @@
1
+ import { parentPort, workerData } from 'node:worker_threads';
2
+ import { getQuickJS, newQuickJSAsyncWASMModule, } from 'quickjs-emscripten';
3
+ import { ComputeError } from './engine.js';
4
+ import { runHosted, runPure } from './sandbox-eval.js';
5
+ if (parentPort !== null && workerData?.noodleComputeWorker === true) {
6
+ startWorker(parentPort);
7
+ }
8
+ function startWorker(port) {
9
+ let syncModule;
10
+ let asyncModule;
11
+ const pendingHostReplies = new Map();
12
+ const pendingLogAcks = new Map();
13
+ let nextCallId = 0;
14
+ const post = (message) => port.postMessage(message);
15
+ port.on('message', (message) => {
16
+ if (message.t === 'run') {
17
+ void handleRun(message);
18
+ return;
19
+ }
20
+ if (message.t === 'host_result') {
21
+ const resolve = pendingHostReplies.get(message.callId);
22
+ pendingHostReplies.delete(message.callId);
23
+ resolve?.(message.envelopeJson);
24
+ return;
25
+ }
26
+ const ack = pendingLogAcks.get(message.callId);
27
+ pendingLogAcks.delete(message.callId);
28
+ ack?.();
29
+ });
30
+ function bridgeFor(run) {
31
+ return {
32
+ callOperation: (name, argsJson) => new Promise((resolve) => {
33
+ const callId = nextCallId;
34
+ nextCallId += 1;
35
+ pendingHostReplies.set(callId, resolve);
36
+ post({ t: 'host_call', id: run.id, callId, name, argsJson });
37
+ }),
38
+ ...(run.consoleEnabled
39
+ ? {
40
+ log: (entry) => new Promise((resolve) => {
41
+ const callId = nextCallId;
42
+ nextCallId += 1;
43
+ pendingLogAcks.set(callId, resolve);
44
+ post({ t: 'log', id: run.id, callId, entry });
45
+ }),
46
+ }
47
+ : {}),
48
+ };
49
+ }
50
+ function loadSyncModule() {
51
+ syncModule ??= getQuickJS();
52
+ return syncModule;
53
+ }
54
+ function loadAsyncModule() {
55
+ asyncModule ??= newQuickJSAsyncWASMModule();
56
+ return asyncModule;
57
+ }
58
+ async function handleRun(run) {
59
+ let outcome;
60
+ try {
61
+ const input = JSON.parse(run.inputJson);
62
+ const outputJson = run.hostEnabled
63
+ ? await runHosted(await loadAsyncModule(), run.source, input, run.limits, bridgeFor(run))
64
+ : runPure(await loadSyncModule(), run.source, input, run.limits);
65
+ outcome = { ok: true, outputJson };
66
+ }
67
+ catch (error) {
68
+ const compute = error instanceof ComputeError
69
+ ? error
70
+ : new ComputeError('runtime_error', 'sandbox execution failed');
71
+ outcome = {
72
+ ok: false,
73
+ error: {
74
+ code: compute.code,
75
+ message: compute.message,
76
+ ...(compute.path === undefined ? {} : { path: compute.path }),
77
+ },
78
+ };
79
+ }
80
+ finally {
81
+ pendingHostReplies.clear();
82
+ pendingLogAcks.clear();
83
+ }
84
+ post({ t: 'result', id: run.id, outcome });
85
+ }
86
+ }
87
+ //# sourceMappingURL=worker-entry.js.map
@@ -73,10 +73,12 @@ export class ComputeWorkerPool {
73
73
  workerData: { noodleComputeWorker: true },
74
74
  });
75
75
  const slot = { worker, runs: 0, active: null, dropped: false };
76
- worker.unref();
77
76
  worker.on('message', (message) => this.#onMessage(slot, message));
78
77
  worker.on('error', () => this.#onWorkerLost(slot));
79
78
  worker.on('exit', () => this.#onWorkerLost(slot));
79
+ // Registering a message listener references the Worker again, so unref must happen last. This
80
+ // lets one-shot CLI processes exit after their compute result without closing the shared pool.
81
+ worker.unref();
80
82
  this.#slots.push(slot);
81
83
  return slot;
82
84
  }
@@ -355,6 +355,20 @@ h2{
355
355
  }
356
356
  .pane--stage>div{padding:16px 18px 18px}
357
357
  #preview-view,#chat-view{display:flex;flex:1;min-height:0;flex-direction:column}
358
+ #preview-view{
359
+ overflow-x:hidden;
360
+ overflow-y:auto;
361
+ scrollbar-width:thin;
362
+ scrollbar-color:rgba(255,255,255,.13) transparent;
363
+ }
364
+ #preview-view>.controls{
365
+ position:sticky;
366
+ top:0;
367
+ z-index:4;
368
+ flex:none;
369
+ background:rgba(18,18,20,.96);
370
+ box-shadow:0 10px 24px rgba(0,0,0,.24);
371
+ }
358
372
  .hidden{display:none}
359
373
  #frame.hidden,#chat-view.hidden,#chat-body.hidden,#design-view.hidden{display:none}
360
374
  #frame{
@@ -39,7 +39,7 @@
39
39
  "dependencies": {
40
40
  "@modelcontextprotocol/sdk": "^1.29.0",
41
41
  "@noodle-borg/admission-limits": "0.0.0",
42
- "@noodle-borg/agent-kit": "0.87.0",
42
+ "@noodle-borg/agent-kit": "0.87.1",
43
43
  "@noodle-borg/app-package": "0.0.0",
44
44
  "@noodle-borg/assistant-gateway": "0.0.0",
45
45
  "@noodle-borg/auth": "0.0.0",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@noodleseed/one",
3
- "version": "0.144.2",
3
+ "version": "0.145.1",
4
4
  "private": false,
5
5
  "description": "Noodle CLI by Noodle Seed — author, run, and deploy declarative MCP servers. Embedding the assistant in your own web app is @noodleseed/assistant.",
6
6
  "license": "Apache-2.0",
@@ -236,7 +236,7 @@
236
236
  "@modelcontextprotocol/client": "2.0.0",
237
237
  "@modelcontextprotocol/server": "2.0.0",
238
238
  "@noodle-borg/admission-limits": "0.0.0",
239
- "@noodle-borg/agent-kit": "0.87.0",
239
+ "@noodle-borg/agent-kit": "0.87.1",
240
240
  "@noodle-borg/app-audit": "0.0.0",
241
241
  "@noodle-borg/app-package": "0.0.0",
242
242
  "@noodle-borg/assistant-gateway": "0.0.0",