beatrina 0.8.6

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.
Files changed (114) hide show
  1. package/LICENSE +92 -0
  2. package/NOTICES +72 -0
  3. package/README.md +124 -0
  4. package/bin/beatrina.mjs +223 -0
  5. package/bin/cli.mjs +80 -0
  6. package/bin/failsafe.mjs +74 -0
  7. package/bin/identity.mjs +45 -0
  8. package/bin/prova-post.mjs +51 -0
  9. package/bin/sessions.mjs +95 -0
  10. package/bin/shortcut.mjs +151 -0
  11. package/bin/update-check.mjs +55 -0
  12. package/bin/upgrade.mjs +76 -0
  13. package/build-info.json +1 -0
  14. package/carmar_V0.8.6.html +1310 -0
  15. package/check/acceptance.mjs +278 -0
  16. package/check/session.mjs +215 -0
  17. package/engines/js/document-exec.mjs +82 -0
  18. package/engines/js/persist.mjs +214 -0
  19. package/engines/js/worker.mjs +424 -0
  20. package/engines/python/adapter.py +577 -0
  21. package/engines/python/analyze.py +814 -0
  22. package/engines/python/bootstrap.py +309 -0
  23. package/engines/python/dataview.py +735 -0
  24. package/engines/python/debugger.py +346 -0
  25. package/engines/python/document_exec.py +158 -0
  26. package/engines/python/engine.json +28 -0
  27. package/engines/python/handoff.py +118 -0
  28. package/engines/python/worker.py +564 -0
  29. package/engines/r/engine.json +25 -0
  30. package/engines/r/handoff.R +92 -0
  31. package/failsafe/ai-policy.R +255 -0
  32. package/failsafe/ai-store.R +373 -0
  33. package/failsafe/cite.R +418 -0
  34. package/failsafe/journal.R +684 -0
  35. package/failsafe/plugins.R +809 -0
  36. package/failsafe/serve.R +5500 -0
  37. package/host/ai-policy.mjs +218 -0
  38. package/host/deployment.mjs +160 -0
  39. package/host/engine-js.mjs +98 -0
  40. package/host/engine-pool.mjs +383 -0
  41. package/host/engine-python.mjs +228 -0
  42. package/host/engine-r.mjs +206 -0
  43. package/host/engine-stdio.mjs +401 -0
  44. package/host/journal-store.mjs +749 -0
  45. package/host/main.mjs +503 -0
  46. package/host/planes/README.md +41 -0
  47. package/host/planes/ai-store.mjs +327 -0
  48. package/host/planes/ai.mjs +467 -0
  49. package/host/planes/analyze.mjs +397 -0
  50. package/host/planes/cite.mjs +517 -0
  51. package/host/planes/files.mjs +0 -0
  52. package/host/planes/jobs.mjs +704 -0
  53. package/host/planes/journal.mjs +53 -0
  54. package/host/planes/latex.mjs +201 -0
  55. package/host/planes/mcp.mjs +493 -0
  56. package/host/planes/pair.mjs +325 -0
  57. package/host/planes/pipe-term.mjs +122 -0
  58. package/host/planes/plugins.mjs +112 -0
  59. package/host/planes/proc-tree.mjs +76 -0
  60. package/host/planes/sessions.mjs +434 -0
  61. package/host/planes/settings.mjs +164 -0
  62. package/host/planes/terminal.mjs +286 -0
  63. package/host/planes/test-file.mjs +80 -0
  64. package/host/planes/update.mjs +214 -0
  65. package/host/plugin-store.mjs +838 -0
  66. package/host/server.mjs +441 -0
  67. package/host/settings.mjs +379 -0
  68. package/host/update-record.mjs +59 -0
  69. package/host/user-dirs.mjs +117 -0
  70. package/host/windows-runtime.mjs +145 -0
  71. package/host/worker-plane.mjs +713 -0
  72. package/host/ws.mjs +190 -0
  73. package/kernel/analyze.R +668 -0
  74. package/kernel/deployment.R +165 -0
  75. package/kernel/examples/NOTICE.md +38 -0
  76. package/kernel/examples/tna-complete-tutorial.Rmd +210 -0
  77. package/kernel/fileio.R +656 -0
  78. package/kernel/index.html +96 -0
  79. package/kernel/job-run.R +391 -0
  80. package/kernel/jobs.R +276 -0
  81. package/kernel/kernel-protocol +1 -0
  82. package/kernel/kernel-version +1 -0
  83. package/kernel/kernel.R +671 -0
  84. package/kernel/knitr-run.R +245 -0
  85. package/kernel/latex.R +609 -0
  86. package/kernel/mcp/carmar-mcp.mjs +516 -0
  87. package/kernel/notebook-page.R +67 -0
  88. package/kernel/plugins/csl/apa/apa.csl +2273 -0
  89. package/kernel/plugins/csl/apa/plugin.json +19 -0
  90. package/kernel/plugins/csl/chicago-author-date/chicago-author-date.csl +4216 -0
  91. package/kernel/plugins/csl/chicago-author-date/plugin.json +19 -0
  92. package/kernel/plugins/csl/harvard-cite-them-right/harvard-cite-them-right.csl +316 -0
  93. package/kernel/plugins/csl/harvard-cite-them-right/plugin.json +19 -0
  94. package/kernel/plugins/csl/ieee/ieee.csl +519 -0
  95. package/kernel/plugins/csl/ieee/plugin.json +19 -0
  96. package/kernel/plugins/csl/modern-language-association/modern-language-association.csl +1184 -0
  97. package/kernel/plugins/csl/modern-language-association/plugin.json +19 -0
  98. package/kernel/plugins/csl/nature/nature.csl +189 -0
  99. package/kernel/plugins/csl/nature/plugin.json +19 -0
  100. package/kernel/plugins/latex/apa7/apa7.json +14 -0
  101. package/kernel/plugins/latex/apa7/plugin.json +19 -0
  102. package/kernel/plugins/latex/elsarticle/elsarticle.json +14 -0
  103. package/kernel/plugins/latex/elsarticle/plugin.json +19 -0
  104. package/kernel/plugins/latex/ieeetran/ieeetran.json +10 -0
  105. package/kernel/plugins/latex/ieeetran/plugin.json +19 -0
  106. package/kernel/project.R +131 -0
  107. package/kernel/settings.R +410 -0
  108. package/kernel/sniff.R +769 -0
  109. package/kernel/worker-boot.R +22 -0
  110. package/kernel/worker.R +3496 -0
  111. package/lib/agent-authoring-contract.js +547 -0
  112. package/lib/cell-kinds.js +108 -0
  113. package/lib/engine-labels.js +324 -0
  114. package/package.json +32 -0
package/host/ws.mjs ADDED
@@ -0,0 +1,190 @@
1
+ // ws.mjs — a WebSocket SERVER, RFC 6455, over Node's http upgrade event.
2
+ //
3
+ // Node ships a WebSocket client (>= 22) and no server, and the host has no
4
+ // dependencies by decision (tools/mcp/carmar-mcp.mjs and test/fixtures/
5
+ // ws-origin.mjs set the precedent: a few hundred lines of protocol beat a
6
+ // package the security review must then read). What this implements is the
7
+ // subset a notebook page uses: text frames, masked client → unmasked server,
8
+ // ping answered, close handshake, continuation reassembled. No extensions, no
9
+ // permessage-deflate (the client never negotiates one; a request for it is
10
+ // simply not granted).
11
+ //
12
+ // The gate is the caller's. `attachWebSocket` hands every upgrade request to
13
+ // `gate(req)` first and refuses with the returned status/text when it answers
14
+ // anything but null — that is where Origin and Host are decided, and it is
15
+ // deliberately outside this file so the protocol code never grows an opinion
16
+ // about trust.
17
+
18
+ import crypto from "node:crypto";
19
+
20
+ const GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
21
+ /** A single message larger than this closes the socket (1009). serve.R's
22
+ * 8 MB refusal is applied by the frame handler above; this is the ceiling
23
+ * under which a message is even assembled. */
24
+ const MAX_MESSAGE_BYTES = 16 * 1024 * 1024;
25
+
26
+ /**
27
+ * @typedef {Object} WsSocket
28
+ * @property {(text: string) => boolean} send false when the socket is gone
29
+ * @property {(code?: number, reason?: string) => void} close
30
+ * @property {(fn: (text: string) => void) => void} onMessage
31
+ * @property {(fn: () => void) => void} onClose
32
+ * @property {import("node:http").IncomingMessage} request the upgrade request, kept —
33
+ * the gate's reasoning is recomputed from it (socket_class in serve.R)
34
+ * @property {boolean} open
35
+ */
36
+
37
+ /**
38
+ * Listen for upgrades on an http.Server.
39
+ *
40
+ * @param {import("node:http").Server} server
41
+ * @param {Object} opts
42
+ * @param {(req: import("node:http").IncomingMessage) => (null | {status:number, body:string})} opts.gate
43
+ * @param {(socket: WsSocket) => void} opts.onOpen
44
+ */
45
+ export function attachWebSocket(server, { gate, onOpen }) {
46
+ server.on("upgrade", (req, raw, head) => {
47
+ const refusal = gate(req);
48
+ if (refusal) {
49
+ raw.write(`HTTP/1.1 ${refusal.status} ${statusText(refusal.status)}\r\n`
50
+ + "Content-Type: text/plain\r\nCache-Control: no-store\r\nConnection: close\r\n"
51
+ + `Content-Length: ${Buffer.byteLength(refusal.body)}\r\n\r\n${refusal.body}`);
52
+ raw.destroy();
53
+ return;
54
+ }
55
+ const key = req.headers["sec-websocket-key"];
56
+ const version = req.headers["sec-websocket-version"];
57
+ if (String(req.headers.upgrade || "").toLowerCase() !== "websocket" || !key || version !== "13") {
58
+ raw.write("HTTP/1.1 400 Bad Request\r\nConnection: close\r\nContent-Length: 0\r\n\r\n");
59
+ raw.destroy();
60
+ return;
61
+ }
62
+ const accept = crypto.createHash("sha1").update(key + GUID).digest("base64");
63
+ raw.write("HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\n"
64
+ + `Sec-WebSocket-Accept: ${accept}\r\n\r\n`);
65
+ raw.setNoDelay(true);
66
+ const socket = wrap(raw, req, head);
67
+ onOpen(socket);
68
+ });
69
+ }
70
+
71
+ function wrap(raw, request, head) {
72
+ let buf = head && head.length ? Buffer.from(head) : Buffer.alloc(0);
73
+ let partial = null; // continuation in progress: {opcode, chunks, bytes}
74
+ let open = true;
75
+ let closeSent = false;
76
+ const messageHandlers = [];
77
+ const closeHandlers = [];
78
+
79
+ const finish = () => {
80
+ if (!open) return;
81
+ open = false;
82
+ closeHandlers.forEach((fn) => { try { fn(); } catch { /* a listener must not break teardown */ } });
83
+ };
84
+ const sendFrame = (opcode, payload) => {
85
+ if (!open || raw.destroyed) return false;
86
+ try { raw.write(frame(opcode, payload)); return true; } catch { return false; }
87
+ };
88
+ const closeWith = (code, reason = "") => {
89
+ if (!closeSent) {
90
+ closeSent = true;
91
+ const body = Buffer.concat([Buffer.from([code >> 8, code & 0xff]), Buffer.from(reason, "utf8")]);
92
+ sendFrame(0x8, body);
93
+ }
94
+ // Give the peer's close frame a moment, then drop the transport either way.
95
+ setTimeout(() => { try { raw.destroy(); } catch { /* gone */ } }, 200).unref();
96
+ finish();
97
+ };
98
+
99
+ raw.on("data", (chunk) => {
100
+ buf = buf.length ? Buffer.concat([buf, chunk]) : chunk;
101
+ drain();
102
+ });
103
+ raw.on("close", finish);
104
+ raw.on("error", finish);
105
+ raw.on("end", () => { try { raw.end(); } catch { /* gone */ } finish(); });
106
+
107
+ function drain() {
108
+ for (;;) {
109
+ if (buf.length < 2) return;
110
+ const fin = (buf[0] & 0x80) !== 0;
111
+ const rsv = buf[0] & 0x70;
112
+ const opcode = buf[0] & 0x0f;
113
+ const masked = (buf[1] & 0x80) !== 0;
114
+ let len = buf[1] & 0x7f;
115
+ let off = 2;
116
+ if (len === 126) {
117
+ if (buf.length < 4) return;
118
+ len = buf.readUInt16BE(2); off = 4;
119
+ } else if (len === 127) {
120
+ if (buf.length < 10) return;
121
+ const big = buf.readBigUInt64BE(2);
122
+ if (big > BigInt(MAX_MESSAGE_BYTES)) return closeWith(1009, "message too big");
123
+ len = Number(big); off = 10;
124
+ }
125
+ // A client MUST mask (RFC 6455 §5.1) and no extension was negotiated, so
126
+ // a set RSV bit is a protocol error, not a feature.
127
+ if (!masked || rsv !== 0) return closeWith(1002, "protocol error");
128
+ if (buf.length < off + 4 + len) return;
129
+ const mask = buf.subarray(off, off + 4);
130
+ const payload = Buffer.from(buf.subarray(off + 4, off + 4 + len));
131
+ buf = buf.subarray(off + 4 + len);
132
+ for (let i = 0; i < payload.length; i += 1) payload[i] ^= mask[i & 3];
133
+
134
+ if (opcode === 0x8) { // close: echo, then drop
135
+ if (!closeSent) { closeSent = true; sendFrame(0x8, payload.subarray(0, 2)); }
136
+ try { raw.end(); } catch { /* gone */ }
137
+ finish();
138
+ return;
139
+ }
140
+ if (opcode === 0x9) { sendFrame(0xa, payload); continue; } // ping → pong
141
+ if (opcode === 0xa) continue; // pong: a reply to nothing we sent
142
+ if (opcode === 0x1 || opcode === 0x2) {
143
+ if (partial) return closeWith(1002, "interleaved message");
144
+ partial = { opcode, chunks: [payload], bytes: payload.length };
145
+ } else if (opcode === 0x0) {
146
+ if (!partial) return closeWith(1002, "continuation without a start");
147
+ partial.chunks.push(payload);
148
+ partial.bytes += payload.length;
149
+ } else {
150
+ return closeWith(1002, "unknown opcode");
151
+ }
152
+ if (partial.bytes > MAX_MESSAGE_BYTES) return closeWith(1009, "message too big");
153
+ if (!fin) continue;
154
+ const message = partial.chunks.length === 1 ? partial.chunks[0] : Buffer.concat(partial.chunks);
155
+ const isText = partial.opcode === 0x1;
156
+ partial = null;
157
+ // Binary is not the protocol (serve.R: `if (is.raw(message)) return`).
158
+ // Dropped without error, exactly as there.
159
+ if (!isText) continue;
160
+ const text = message.toString("utf8");
161
+ messageHandlers.forEach((fn) => { try { fn(text); } catch { /* a handler must not break the read loop */ } });
162
+ }
163
+ }
164
+
165
+ return {
166
+ request,
167
+ get open() { return open; },
168
+ send: (text) => sendFrame(0x1, Buffer.from(String(text), "utf8")),
169
+ close: (code = 1000, reason = "") => closeWith(code, reason),
170
+ onMessage: (fn) => { messageHandlers.push(fn); },
171
+ onClose: (fn) => { closeHandlers.push(fn); },
172
+ };
173
+ }
174
+
175
+ /** A server frame: never masked. */
176
+ function frame(opcode, payload) {
177
+ const body = Buffer.isBuffer(payload) ? payload : Buffer.from(String(payload), "utf8");
178
+ let head;
179
+ if (body.length < 126) head = Buffer.from([0x80 | opcode, body.length]);
180
+ else if (body.length < 65536) {
181
+ head = Buffer.alloc(4); head[0] = 0x80 | opcode; head[1] = 126; head.writeUInt16BE(body.length, 2);
182
+ } else {
183
+ head = Buffer.alloc(10); head[0] = 0x80 | opcode; head[1] = 127; head.writeBigUInt64BE(BigInt(body.length), 2);
184
+ }
185
+ return Buffer.concat([head, body]);
186
+ }
187
+
188
+ function statusText(status) {
189
+ return { 400: "Bad Request", 403: "Forbidden", 404: "Not Found", 429: "Too Many Requests" }[status] || "Error";
190
+ }