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.
Files changed (112) hide show
  1. package/NOTICES +1 -1
  2. package/README.md +6 -0
  3. package/beatrina_V0.9.83.html +1903 -0
  4. package/beatrina_V0.9.83.html.inputs.json +1 -0
  5. package/bin/beatrina.mjs +152 -24
  6. package/bin/browser.mjs +31 -0
  7. package/bin/cli.mjs +64 -5
  8. package/bin/doctor-rows.mjs +31 -0
  9. package/bin/failsafe.mjs +8 -3
  10. package/bin/finder.mjs +74 -0
  11. package/bin/lsquery.swift +55 -0
  12. package/bin/pages.mjs +81 -0
  13. package/bin/python-setup.mjs +207 -0
  14. package/bin/runtime-dirs.mjs +27 -0
  15. package/bin/sessions.mjs +30 -10
  16. package/bin/shortcut.mjs +250 -42
  17. package/bin/update-check.mjs +2 -2
  18. package/build-info.json +1 -1
  19. package/engines/js/worker.mjs +6 -3
  20. package/engines/python/adapter.py +14 -13
  21. package/engines/python/analyze.py +4 -2
  22. package/engines/python/bootstrap.py +32 -31
  23. package/engines/python/debugger.py +10 -6
  24. package/engines/python/engine.json +1 -1
  25. package/engines/python/handoff.py +4 -2
  26. package/engines/python/worker.py +39 -10
  27. package/engines/r/engine.json +1 -1
  28. package/engines/r/handoff.R +4 -3
  29. package/failsafe/ai-policy.R +16 -16
  30. package/failsafe/ai-store.R +6 -6
  31. package/failsafe/cite.R +11 -11
  32. package/failsafe/journal.R +11 -11
  33. package/failsafe/plugins.R +27 -27
  34. package/failsafe/serve.R +241 -241
  35. package/host/ai-authority.mjs +55 -0
  36. package/host/ai-policy.mjs +48 -26
  37. package/host/bundle.mjs +194 -0
  38. package/host/deployment.mjs +25 -18
  39. package/host/engine-js.mjs +12 -17
  40. package/host/engine-pool.mjs +48 -6
  41. package/host/engine-python.mjs +80 -31
  42. package/host/engine-r.mjs +20 -21
  43. package/host/engine-stdio.mjs +35 -10
  44. package/host/env-names.mjs +148 -0
  45. package/host/gateway-token.mjs +51 -0
  46. package/host/journal-store.mjs +29 -12
  47. package/host/main.mjs +193 -77
  48. package/host/payload.mjs +131 -0
  49. package/host/planes/README.md +1 -1
  50. package/host/planes/ai-store.mjs +6 -5
  51. package/host/planes/ai.mjs +49 -29
  52. package/host/planes/analyze.mjs +6 -5
  53. package/host/planes/bundle.mjs +344 -0
  54. package/host/planes/choose.mjs +415 -0
  55. package/host/planes/cite.mjs +18 -17
  56. package/host/planes/expect-term.mjs +102 -0
  57. package/host/planes/files.mjs +0 -0
  58. package/host/planes/jobs.mjs +43 -20
  59. package/host/planes/latex.mjs +15 -5
  60. package/host/planes/mcp.mjs +80 -91
  61. package/host/planes/pair.mjs +24 -24
  62. package/host/planes/pipe-term.mjs +2 -2
  63. package/host/planes/plugins.mjs +1 -1
  64. package/host/planes/recent-documents.mjs +170 -0
  65. package/host/planes/sessions.mjs +226 -82
  66. package/host/planes/settings.mjs +4 -4
  67. package/host/planes/terminal.mjs +33 -17
  68. package/host/planes/test-file.mjs +2 -2
  69. package/host/planes/update.mjs +6 -13
  70. package/host/plugin-store.mjs +35 -52
  71. package/host/recent-documents.mjs +124 -0
  72. package/host/runtime-dir.mjs +47 -0
  73. package/host/server.mjs +75 -18
  74. package/host/session-keep.mjs +1 -1
  75. package/host/settings.mjs +85 -37
  76. package/host/update-record.mjs +3 -2
  77. package/host/user-dirs.mjs +60 -18
  78. package/host/which.mjs +39 -0
  79. package/host/windows-runtime.mjs +6 -3
  80. package/host/worker-plane.mjs +34 -6
  81. package/host/ws.mjs +9 -2
  82. package/host/zip.mjs +237 -0
  83. package/kernel/analyze.R +1 -1
  84. package/{check → kernel/check}/acceptance.mjs +1 -1
  85. package/kernel/check/knit-file.mjs +19855 -0
  86. package/{check → kernel/check}/session.mjs +49 -8
  87. package/kernel/deployment.R +20 -20
  88. package/kernel/examples/NOTICE.md +1 -1
  89. package/kernel/fileio.R +6 -6
  90. package/kernel/index.html +2 -2
  91. package/kernel/job-run.R +83 -22
  92. package/kernel/jobs.R +28 -12
  93. package/kernel/kernel-version +1 -1
  94. package/kernel/kernel.R +18 -18
  95. package/kernel/knitr-run.R +58 -10
  96. package/kernel/latex.R +128 -30
  97. package/kernel/mcp/{carmar-mcp.mjs → beatrina-mcp.mjs} +254 -63
  98. package/kernel/notebook-page.R +7 -7
  99. package/kernel/project.R +10 -10
  100. package/kernel/settings.R +105 -56
  101. package/kernel/sniff.R +4 -4
  102. package/kernel/typst.R +121 -0
  103. package/kernel/worker.R +542 -119
  104. package/kernel/workspace-keep.R +3 -3
  105. package/lib/agent-authoring-contract.js +28 -19
  106. package/lib/cell-kinds.js +3 -3
  107. package/lib/engine-labels.js +4 -4
  108. package/menu/Beatrina Menu.app/Contents/Info.plist +14 -0
  109. package/menu/Beatrina Menu.app/Contents/MacOS/Beatrina Menu +0 -0
  110. package/menu/Beatrina Menu.app/Contents/_CodeSignature/CodeResources +115 -0
  111. package/package.json +4 -3
  112. package/carmar_V0.8.7.html +0 -1522
@@ -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 = (name, unset = "") => (process.env[name] == null ? unset : String(process.env[name]));
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("CARMAR_NO_JOURNAL") !== "1";
78
+ const enabled = envOf("BEATRINA_NO_JOURNAL") !== "1";
77
79
  const cache = new Map();
78
80
 
79
81
  const root = () => {
80
- const explicit = envOf("CARMAR_HISTORY_DIR");
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("CARMAR_HISTORY_BUDGET"));
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), `.carmar-journal-${crypto.randomBytes(8).toString("hex")}`);
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("CARMAR_PORT", "0"), 10) || 0, epoch, at: Date.now() };
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 (CARMAR_NO_JOURNAL=1).");
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 (CARMAR_NO_JOURNAL=1).");
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: "carmar-history-export", schema: 1, key,
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);