beatrina 0.8.7 → 0.9.83
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/NOTICES +1 -1
- package/README.md +6 -0
- package/beatrina_V0.9.83.html +1903 -0
- package/beatrina_V0.9.83.html.inputs.json +1 -0
- package/bin/beatrina.mjs +152 -24
- package/bin/browser.mjs +31 -0
- package/bin/cli.mjs +64 -5
- package/bin/doctor-rows.mjs +31 -0
- package/bin/failsafe.mjs +8 -3
- package/bin/finder.mjs +74 -0
- package/bin/lsquery.swift +55 -0
- package/bin/pages.mjs +81 -0
- package/bin/python-setup.mjs +207 -0
- package/bin/runtime-dirs.mjs +27 -0
- package/bin/sessions.mjs +30 -10
- package/bin/shortcut.mjs +250 -42
- package/bin/update-check.mjs +2 -2
- package/build-info.json +1 -1
- package/engines/js/worker.mjs +6 -3
- package/engines/python/adapter.py +14 -13
- package/engines/python/analyze.py +4 -2
- package/engines/python/bootstrap.py +32 -31
- package/engines/python/debugger.py +10 -6
- package/engines/python/engine.json +1 -1
- package/engines/python/handoff.py +4 -2
- package/engines/python/worker.py +39 -10
- package/engines/r/engine.json +1 -1
- package/engines/r/handoff.R +4 -3
- package/failsafe/ai-policy.R +16 -16
- package/failsafe/ai-store.R +6 -6
- package/failsafe/cite.R +11 -11
- package/failsafe/journal.R +11 -11
- package/failsafe/plugins.R +27 -27
- package/failsafe/serve.R +241 -241
- package/host/ai-authority.mjs +55 -0
- package/host/ai-policy.mjs +48 -26
- package/host/bundle.mjs +194 -0
- package/host/deployment.mjs +25 -18
- package/host/engine-js.mjs +12 -17
- package/host/engine-pool.mjs +48 -6
- package/host/engine-python.mjs +80 -31
- package/host/engine-r.mjs +20 -21
- package/host/engine-stdio.mjs +35 -10
- package/host/env-names.mjs +148 -0
- package/host/gateway-token.mjs +51 -0
- package/host/journal-store.mjs +29 -12
- package/host/main.mjs +193 -77
- package/host/payload.mjs +131 -0
- package/host/planes/README.md +1 -1
- package/host/planes/ai-store.mjs +6 -5
- package/host/planes/ai.mjs +49 -29
- package/host/planes/analyze.mjs +6 -5
- package/host/planes/bundle.mjs +344 -0
- package/host/planes/choose.mjs +415 -0
- package/host/planes/cite.mjs +18 -17
- package/host/planes/expect-term.mjs +102 -0
- package/host/planes/files.mjs +0 -0
- package/host/planes/jobs.mjs +43 -20
- package/host/planes/latex.mjs +15 -5
- package/host/planes/mcp.mjs +80 -91
- package/host/planes/pair.mjs +24 -24
- package/host/planes/pipe-term.mjs +2 -2
- package/host/planes/plugins.mjs +1 -1
- package/host/planes/recent-documents.mjs +170 -0
- package/host/planes/sessions.mjs +226 -82
- package/host/planes/settings.mjs +4 -4
- package/host/planes/terminal.mjs +33 -17
- package/host/planes/test-file.mjs +2 -2
- package/host/planes/update.mjs +6 -13
- package/host/plugin-store.mjs +35 -52
- package/host/recent-documents.mjs +124 -0
- package/host/runtime-dir.mjs +47 -0
- package/host/server.mjs +75 -18
- package/host/session-keep.mjs +1 -1
- package/host/settings.mjs +85 -37
- package/host/update-record.mjs +3 -2
- package/host/user-dirs.mjs +60 -18
- package/host/which.mjs +39 -0
- package/host/windows-runtime.mjs +6 -3
- package/host/worker-plane.mjs +34 -6
- package/host/ws.mjs +9 -2
- package/host/zip.mjs +237 -0
- package/kernel/analyze.R +1 -1
- package/{check → kernel/check}/acceptance.mjs +1 -1
- package/kernel/check/knit-file.mjs +19855 -0
- package/{check → kernel/check}/session.mjs +49 -8
- package/kernel/deployment.R +20 -20
- package/kernel/examples/NOTICE.md +1 -1
- package/kernel/fileio.R +6 -6
- package/kernel/index.html +2 -2
- package/kernel/job-run.R +83 -22
- package/kernel/jobs.R +28 -12
- package/kernel/kernel-version +1 -1
- package/kernel/kernel.R +18 -18
- package/kernel/knitr-run.R +58 -10
- package/kernel/latex.R +128 -30
- package/kernel/mcp/{carmar-mcp.mjs → beatrina-mcp.mjs} +254 -63
- package/kernel/notebook-page.R +7 -7
- package/kernel/project.R +10 -10
- package/kernel/settings.R +105 -56
- package/kernel/sniff.R +4 -4
- package/kernel/typst.R +121 -0
- package/kernel/worker.R +542 -119
- package/kernel/workspace-keep.R +3 -3
- package/lib/agent-authoring-contract.js +28 -19
- package/lib/cell-kinds.js +3 -3
- package/lib/engine-labels.js +4 -4
- package/menu/Beatrina Menu.app/Contents/Info.plist +14 -0
- package/menu/Beatrina Menu.app/Contents/MacOS/Beatrina Menu +0 -0
- package/menu/Beatrina Menu.app/Contents/_CodeSignature/CodeResources +115 -0
- package/package.json +4 -3
- package/carmar_V0.8.7.html +0 -1522
package/host/journal-store.mjs
CHANGED
|
@@ -22,7 +22,8 @@
|
|
|
22
22
|
// the page's checkpoint codec wrote)
|
|
23
23
|
// checkpoint.rev the revision of that envelope
|
|
24
24
|
// pins/<rev>.json a named version, with its content
|
|
25
|
-
// meta.json display name, file binding, gaps, updated
|
|
25
|
+
// meta.json display name, file binding, gaps, updated,
|
|
26
|
+
// and `saved` — what the last Save wrote (N3)
|
|
26
27
|
// journal.corrupt-<time> bytes cut from a journal that did not end at
|
|
27
28
|
// a line boundary — kept as evidence
|
|
28
29
|
//
|
|
@@ -52,12 +53,13 @@ import crypto from "node:crypto";
|
|
|
52
53
|
import fs from "node:fs";
|
|
53
54
|
import path from "node:path";
|
|
54
55
|
import { privateModeHeld, stateDir } from "./user-dirs.mjs";
|
|
56
|
+
import { envReader } from "./env-names.mjs";
|
|
55
57
|
|
|
56
58
|
const TAB = 0x09;
|
|
57
59
|
const NL = 0x0a;
|
|
58
60
|
export const JOURNAL_KEY_RE = /^[a-z]+:[A-Za-z0-9._~-]{1,200}$/;
|
|
59
61
|
export const JOURNAL_MAX_REPLY_BYTES = 6e6; // under the 8 MB frame cap, with room
|
|
60
|
-
const envOf = (
|
|
62
|
+
const envOf = envReader(process.env); // dual-read (host/env-names.mjs)
|
|
61
63
|
|
|
62
64
|
/** A UTC stamp in the journal's evidence-filename shape: %Y%m%d-%H%M%S. */
|
|
63
65
|
const stamp = () => {
|
|
@@ -73,11 +75,11 @@ const bytesOf = (text) => Buffer.byteLength(text, "utf8");
|
|
|
73
75
|
* first's idea of where a tail is.
|
|
74
76
|
*/
|
|
75
77
|
export function createJournalStore() {
|
|
76
|
-
const enabled = envOf("
|
|
78
|
+
const enabled = envOf("BEATRINA_NO_JOURNAL") !== "1";
|
|
77
79
|
const cache = new Map();
|
|
78
80
|
|
|
79
81
|
const root = () => {
|
|
80
|
-
const explicit = envOf("
|
|
82
|
+
const explicit = envOf("BEATRINA_HISTORY_DIR");
|
|
81
83
|
if (explicit) return explicit;
|
|
82
84
|
return path.join(stateDir(), "history");
|
|
83
85
|
};
|
|
@@ -87,7 +89,7 @@ export function createJournalStore() {
|
|
|
87
89
|
* stacks; pins hold their own content), never the tail.
|
|
88
90
|
*/
|
|
89
91
|
const budget = () => {
|
|
90
|
-
const v = Number(envOf("
|
|
92
|
+
const v = Number(envOf("BEATRINA_HISTORY_BUDGET"));
|
|
91
93
|
return !Number.isFinite(v) || v < 65536 ? 64 * 1024 * 1024 : v;
|
|
92
94
|
};
|
|
93
95
|
const validKey = (key) => typeof key === "string" && JOURNAL_KEY_RE.test(key);
|
|
@@ -174,7 +176,7 @@ export function createJournalStore() {
|
|
|
174
176
|
|
|
175
177
|
/** Atomic replace within the same directory: write a sibling, rename over. */
|
|
176
178
|
const replace = (file, text) => {
|
|
177
|
-
const temp = path.join(path.dirname(file), `.
|
|
179
|
+
const temp = path.join(path.dirname(file), `.beatrina-journal-${crypto.randomBytes(8).toString("hex")}`);
|
|
178
180
|
writePrivate(temp, text);
|
|
179
181
|
try { fs.renameSync(temp, file); } catch (e) {
|
|
180
182
|
try { fs.unlinkSync(temp); } catch { /* gone */ }
|
|
@@ -263,7 +265,7 @@ export function createJournalStore() {
|
|
|
263
265
|
return { held: { pid: Math.trunc(prior.pid), port: prior.port, epoch: prior.epoch }, epoch: null };
|
|
264
266
|
}
|
|
265
267
|
const epoch = prior && typeof prior.epoch === "number" ? Math.trunc(prior.epoch) + 1 : 1;
|
|
266
|
-
const me = { pid: mePid, port: Number.parseInt(envOf("
|
|
268
|
+
const me = { pid: mePid, port: Number.parseInt(envOf("BEATRINA_PORT", "0"), 10) || 0, epoch, at: Date.now() };
|
|
267
269
|
try { replace(file, JSON.stringify(me)); } catch {
|
|
268
270
|
return { held: null, epoch: null, error: "The writer lease could not be written." };
|
|
269
271
|
}
|
|
@@ -294,8 +296,12 @@ export function createJournalStore() {
|
|
|
294
296
|
|
|
295
297
|
// ── the ops ───────────────────────────────────────────────────────────────
|
|
296
298
|
|
|
299
|
+
const HEX64 = /^[0-9a-f]{64}$/;
|
|
300
|
+
const validSaved = (v) => v != null && typeof v === "object" && !Array.isArray(v)
|
|
301
|
+
&& typeof v.model === "string" && HEX64.test(v.model) && typeof v.file === "string" && HEX64.test(v.file);
|
|
302
|
+
|
|
297
303
|
const open = (id, key, meta, takeover) => {
|
|
298
|
-
if (!enabled) return err("journal_open", id, "unavailable", "The document journal is disabled (
|
|
304
|
+
if (!enabled) return err("journal_open", id, "unavailable", "The document journal is disabled (BEATRINA_NO_JOURNAL=1).");
|
|
299
305
|
if (!validKey(key)) return err("journal_open", id, "invalid_key", "A journal needs a durable document key.");
|
|
300
306
|
let st;
|
|
301
307
|
try { st = stateOf(key); } catch (e) { return err("journal_open", id, "io", e.message); }
|
|
@@ -323,7 +329,7 @@ export function createJournalStore() {
|
|
|
323
329
|
* directory behind, so it never calls stateOf().
|
|
324
330
|
*/
|
|
325
331
|
const probe = (id, key) => {
|
|
326
|
-
if (!enabled) return err("journal_probe", id, "unavailable", "The document journal is disabled (
|
|
332
|
+
if (!enabled) return err("journal_probe", id, "unavailable", "The document journal is disabled (BEATRINA_NO_JOURNAL=1).");
|
|
327
333
|
if (!validKey(key)) return err("journal_probe", id, "invalid_key", "A journal needs a durable document key.");
|
|
328
334
|
const dir = dirOf(key);
|
|
329
335
|
if (!fs.existsSync(dir)) return { type: "journal_probe", id, key, exists: false, path: null, pathExists: false };
|
|
@@ -427,7 +433,7 @@ export function createJournalStore() {
|
|
|
427
433
|
return before - st.bytes;
|
|
428
434
|
};
|
|
429
435
|
|
|
430
|
-
const checkpoint = (id, key, revision, generation, envelope, meta, rebase, epoch) => {
|
|
436
|
+
const checkpoint = (id, key, revision, generation, envelope, meta, rebase, epoch, saved) => {
|
|
431
437
|
if (!enabled) return err("journal_checkpoint", id, "unavailable", "The document journal is disabled.");
|
|
432
438
|
if (!validKey(key)) return err("journal_checkpoint", id, "invalid_key", "A journal needs a durable document key.");
|
|
433
439
|
const refused = leaseRefusal("journal_checkpoint", id, dirOf(key), epoch);
|
|
@@ -436,6 +442,9 @@ export function createJournalStore() {
|
|
|
436
442
|
|| typeof envelope !== "string" || !envelope.length) {
|
|
437
443
|
return err("journal_checkpoint", id, "invalid_checkpoint", "A checkpoint needs a revision and its envelope.");
|
|
438
444
|
}
|
|
445
|
+
// Refused before anything is written, so a bad marker never leaves a
|
|
446
|
+
// checkpoint on disk that the store's state does not know about.
|
|
447
|
+
if (saved != null && !validSaved(saved)) return err("journal_checkpoint", id, "invalid_saved", "A save marker needs two SHA-256 digests.");
|
|
439
448
|
let st;
|
|
440
449
|
try { st = stateOf(key); } catch (e) { return err("journal_checkpoint", id, "io", e.message); }
|
|
441
450
|
const rev = Math.trunc(revision);
|
|
@@ -463,6 +472,13 @@ export function createJournalStore() {
|
|
|
463
472
|
stored.gaps = [...(stored.gaps ?? []), gap];
|
|
464
473
|
}
|
|
465
474
|
if (meta && typeof meta === "object" && Object.keys(meta).length) stored.display = meta;
|
|
475
|
+
// N3: a Save rides on a checkpoint and says what it wrote — two digests,
|
|
476
|
+
// the document's content and the file's bytes. It is kept apart from
|
|
477
|
+
// `display` because the next opening's journal_open replaces `display`
|
|
478
|
+
// before it loads, and this is exactly what that opening needs to read.
|
|
479
|
+
// Content-addressed, so it is never cleared: a later edit simply stops it
|
|
480
|
+
// matching. Anything malformed is refused rather than stored half-read.
|
|
481
|
+
if (saved != null) stored.saved = { model: saved.model, file: saved.file, at: Date.now() };
|
|
466
482
|
try { writeMeta(st.dir, stored); } catch { /* the checkpoint still stands */ }
|
|
467
483
|
st.checkpoint = rev;
|
|
468
484
|
st.last = rev;
|
|
@@ -500,6 +516,7 @@ export function createJournalStore() {
|
|
|
500
516
|
return { type: "journal_load", id, key, aliases: meta.aliases ?? [],
|
|
501
517
|
checkpointRevision: st.checkpoint, durableRevision: st.last,
|
|
502
518
|
more, repaired: st.repaired === true, gaps: meta.gaps ?? [], pins: pinsOf(st.dir),
|
|
519
|
+
saved: validSaved(meta.saved) ? meta.saved : null,
|
|
503
520
|
__raw: { records, checkpoint: envelope } };
|
|
504
521
|
};
|
|
505
522
|
|
|
@@ -674,7 +691,7 @@ export function createJournalStore() {
|
|
|
674
691
|
try { st = stateOf(key); } catch (e) { return err("journal_export", id, "io", e.message); }
|
|
675
692
|
const s = scan(st.path);
|
|
676
693
|
const envelope = readEnvelope(st.dir);
|
|
677
|
-
const head = JSON.stringify({ format: "
|
|
694
|
+
const head = JSON.stringify({ format: "beatrina-history-export", schema: 1, key,
|
|
678
695
|
exported: Date.now(), checkpointRevision: st.checkpoint, meta: readMeta(st.dir) });
|
|
679
696
|
const text = `${head.slice(0, head.length - 1)},"checkpoint":${envelope == null ? "null" : JSON.stringify(envelope)},"records":[${s.records.join(",")}]}`;
|
|
680
697
|
if (bytesOf(text) > JOURNAL_MAX_REPLY_BYTES) {
|
|
@@ -690,7 +707,7 @@ export function createJournalStore() {
|
|
|
690
707
|
case "journal_probe": return probe(cmd.id, cmd.key);
|
|
691
708
|
case "journal_append": return append(cmd.id, cmd.key, cmd.records, cmd.epoch);
|
|
692
709
|
case "journal_checkpoint": return checkpoint(cmd.id, cmd.key, cmd.revision, cmd.generation, cmd.envelope,
|
|
693
|
-
cmd.meta && typeof cmd.meta === "object" ? cmd.meta : null, cmd.rebase === true, cmd.epoch);
|
|
710
|
+
cmd.meta && typeof cmd.meta === "object" ? cmd.meta : null, cmd.rebase === true, cmd.epoch, cmd.saved ?? null);
|
|
694
711
|
case "journal_archive": return archive(cmd.id, cmd.key);
|
|
695
712
|
case "journal_rename": return rename(cmd.id, cmd.from, cmd.to);
|
|
696
713
|
case "journal_load": return load(cmd.id, cmd.key, cmd.afterRevision);
|