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.
- package/LICENSE +92 -0
- package/NOTICES +72 -0
- package/README.md +124 -0
- package/bin/beatrina.mjs +223 -0
- package/bin/cli.mjs +80 -0
- package/bin/failsafe.mjs +74 -0
- package/bin/identity.mjs +45 -0
- package/bin/prova-post.mjs +51 -0
- package/bin/sessions.mjs +95 -0
- package/bin/shortcut.mjs +151 -0
- package/bin/update-check.mjs +55 -0
- package/bin/upgrade.mjs +76 -0
- package/build-info.json +1 -0
- package/carmar_V0.8.6.html +1310 -0
- package/check/acceptance.mjs +278 -0
- package/check/session.mjs +215 -0
- package/engines/js/document-exec.mjs +82 -0
- package/engines/js/persist.mjs +214 -0
- package/engines/js/worker.mjs +424 -0
- package/engines/python/adapter.py +577 -0
- package/engines/python/analyze.py +814 -0
- package/engines/python/bootstrap.py +309 -0
- package/engines/python/dataview.py +735 -0
- package/engines/python/debugger.py +346 -0
- package/engines/python/document_exec.py +158 -0
- package/engines/python/engine.json +28 -0
- package/engines/python/handoff.py +118 -0
- package/engines/python/worker.py +564 -0
- package/engines/r/engine.json +25 -0
- package/engines/r/handoff.R +92 -0
- package/failsafe/ai-policy.R +255 -0
- package/failsafe/ai-store.R +373 -0
- package/failsafe/cite.R +418 -0
- package/failsafe/journal.R +684 -0
- package/failsafe/plugins.R +809 -0
- package/failsafe/serve.R +5500 -0
- package/host/ai-policy.mjs +218 -0
- package/host/deployment.mjs +160 -0
- package/host/engine-js.mjs +98 -0
- package/host/engine-pool.mjs +383 -0
- package/host/engine-python.mjs +228 -0
- package/host/engine-r.mjs +206 -0
- package/host/engine-stdio.mjs +401 -0
- package/host/journal-store.mjs +749 -0
- package/host/main.mjs +503 -0
- package/host/planes/README.md +41 -0
- package/host/planes/ai-store.mjs +327 -0
- package/host/planes/ai.mjs +467 -0
- package/host/planes/analyze.mjs +397 -0
- package/host/planes/cite.mjs +517 -0
- package/host/planes/files.mjs +0 -0
- package/host/planes/jobs.mjs +704 -0
- package/host/planes/journal.mjs +53 -0
- package/host/planes/latex.mjs +201 -0
- package/host/planes/mcp.mjs +493 -0
- package/host/planes/pair.mjs +325 -0
- package/host/planes/pipe-term.mjs +122 -0
- package/host/planes/plugins.mjs +112 -0
- package/host/planes/proc-tree.mjs +76 -0
- package/host/planes/sessions.mjs +434 -0
- package/host/planes/settings.mjs +164 -0
- package/host/planes/terminal.mjs +286 -0
- package/host/planes/test-file.mjs +80 -0
- package/host/planes/update.mjs +214 -0
- package/host/plugin-store.mjs +838 -0
- package/host/server.mjs +441 -0
- package/host/settings.mjs +379 -0
- package/host/update-record.mjs +59 -0
- package/host/user-dirs.mjs +117 -0
- package/host/windows-runtime.mjs +145 -0
- package/host/worker-plane.mjs +713 -0
- package/host/ws.mjs +190 -0
- package/kernel/analyze.R +668 -0
- package/kernel/deployment.R +165 -0
- package/kernel/examples/NOTICE.md +38 -0
- package/kernel/examples/tna-complete-tutorial.Rmd +210 -0
- package/kernel/fileio.R +656 -0
- package/kernel/index.html +96 -0
- package/kernel/job-run.R +391 -0
- package/kernel/jobs.R +276 -0
- package/kernel/kernel-protocol +1 -0
- package/kernel/kernel-version +1 -0
- package/kernel/kernel.R +671 -0
- package/kernel/knitr-run.R +245 -0
- package/kernel/latex.R +609 -0
- package/kernel/mcp/carmar-mcp.mjs +516 -0
- package/kernel/notebook-page.R +67 -0
- package/kernel/plugins/csl/apa/apa.csl +2273 -0
- package/kernel/plugins/csl/apa/plugin.json +19 -0
- package/kernel/plugins/csl/chicago-author-date/chicago-author-date.csl +4216 -0
- package/kernel/plugins/csl/chicago-author-date/plugin.json +19 -0
- package/kernel/plugins/csl/harvard-cite-them-right/harvard-cite-them-right.csl +316 -0
- package/kernel/plugins/csl/harvard-cite-them-right/plugin.json +19 -0
- package/kernel/plugins/csl/ieee/ieee.csl +519 -0
- package/kernel/plugins/csl/ieee/plugin.json +19 -0
- package/kernel/plugins/csl/modern-language-association/modern-language-association.csl +1184 -0
- package/kernel/plugins/csl/modern-language-association/plugin.json +19 -0
- package/kernel/plugins/csl/nature/nature.csl +189 -0
- package/kernel/plugins/csl/nature/plugin.json +19 -0
- package/kernel/plugins/latex/apa7/apa7.json +14 -0
- package/kernel/plugins/latex/apa7/plugin.json +19 -0
- package/kernel/plugins/latex/elsarticle/elsarticle.json +14 -0
- package/kernel/plugins/latex/elsarticle/plugin.json +19 -0
- package/kernel/plugins/latex/ieeetran/ieeetran.json +10 -0
- package/kernel/plugins/latex/ieeetran/plugin.json +19 -0
- package/kernel/project.R +131 -0
- package/kernel/settings.R +410 -0
- package/kernel/sniff.R +769 -0
- package/kernel/worker-boot.R +22 -0
- package/kernel/worker.R +3496 -0
- package/lib/agent-authoring-contract.js +547 -0
- package/lib/cell-kinds.js +108 -0
- package/lib/engine-labels.js +324 -0
- package/package.json +32 -0
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
// engine-labels.js — the page's ONE answer to "what is this thing called?".
|
|
2
|
+
//
|
|
3
|
+
// For as long as there was one language the answer was a constant, so nothing
|
|
4
|
+
// had to ask: the editor's accessible name was the literal "R code editor",
|
|
5
|
+
// a figure's alt text was `R plot ${n}`, the AI chip said "⚡ R ready", and the
|
|
6
|
+
// footer said "local R kernel". Beatrix runs engines (R today, Python next),
|
|
7
|
+
// so every one of those became a question — and a question answered in a dozen
|
|
8
|
+
// places is a dozen answers that drift. This module is the one answer.
|
|
9
|
+
//
|
|
10
|
+
// TWO HALVES, ON PURPOSE.
|
|
11
|
+
//
|
|
12
|
+
// 1. The NAME of an engine (`engineKey`, `engineLabel`, and the phrasings
|
|
13
|
+
// built on them). Pure, no kernel, no DOM — a chunk header's `engine`
|
|
14
|
+
// string in, a word out.
|
|
15
|
+
// 2. What the ATTACHED KERNEL declared (`kernelLanguage`, `reportedEngines`,
|
|
16
|
+
// `kernelDisplay`). Also pure: it takes the ready frame's `info` object
|
|
17
|
+
// and returns a fact, so the page's language behaviour is testable
|
|
18
|
+
// without a socket.
|
|
19
|
+
//
|
|
20
|
+
// THE KERNEL DECLARES; THE PAGE NEVER GUESSES. `language` is a field on the
|
|
21
|
+
// ready frame and on /health. A kernel built before the field existed sends
|
|
22
|
+
// nothing, and an absent field means "r" — that is not a guess about an
|
|
23
|
+
// unknown kernel, it is the only kernel that can be speaking this protocol
|
|
24
|
+
// without saying so.
|
|
25
|
+
//
|
|
26
|
+
// R'S WORDING IS UNCHANGED FOR R, BYTE FOR BYTE. Every phrasing below produces
|
|
27
|
+
// exactly the string the page produced before it existed when the engine is R.
|
|
28
|
+
// That is the compatibility contract the existing suites assert, and it is
|
|
29
|
+
// what makes this a rename of the SOURCE of a word rather than of the word.
|
|
30
|
+
|
|
31
|
+
/** The engines the page knows how to name. Order is the options sheet's. */
|
|
32
|
+
export const KNOWN_ENGINES = Object.freeze([
|
|
33
|
+
Object.freeze({ key: "r", label: "R" }),
|
|
34
|
+
Object.freeze({ key: "python", label: "Python" }),
|
|
35
|
+
Object.freeze({ key: "js", label: "JavaScript" }),
|
|
36
|
+
Object.freeze({ key: "bash", label: "Bash" }),
|
|
37
|
+
Object.freeze({ key: "sql", label: "SQL" }),
|
|
38
|
+
]);
|
|
39
|
+
|
|
40
|
+
/** What a chunk with no `engine` at all is, and what a silent kernel runs. */
|
|
41
|
+
export const DEFAULT_ENGINE = "r";
|
|
42
|
+
|
|
43
|
+
const BY_KEY = new Map(KNOWN_ENGINES.map((e) => [e.key, e.label]));
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* An engine string, normalised to the key the page compares on.
|
|
47
|
+
*
|
|
48
|
+
* An ABSENT engine (null/undefined) is `r` — a hand-made cell with no header.
|
|
49
|
+
* An EMPTY engine is empty: ```{} names no engine and must never collapse into
|
|
50
|
+
* R, because "no engine" and "R" have opposite meanings at the run gate.
|
|
51
|
+
*
|
|
52
|
+
* @param {string|null|undefined} engine
|
|
53
|
+
* @returns {string}
|
|
54
|
+
*/
|
|
55
|
+
export function engineKey(engine) {
|
|
56
|
+
if (engine == null) return DEFAULT_ENGINE;
|
|
57
|
+
return String(engine).trim().toLowerCase();
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* `r` → "R", `python` → "Python"; an unknown engine keeps its own spelling,
|
|
62
|
+
* capitalised. The empty engine (```{}) has no name and returns "".
|
|
63
|
+
*
|
|
64
|
+
* @param {string|null|undefined} engine
|
|
65
|
+
* @returns {string}
|
|
66
|
+
*/
|
|
67
|
+
export function engineLabel(engine) {
|
|
68
|
+
const key = engineKey(engine);
|
|
69
|
+
if (!key) return "";
|
|
70
|
+
const known = BY_KEY.get(key);
|
|
71
|
+
if (known) return known;
|
|
72
|
+
return key.charAt(0).toUpperCase() + key.slice(1);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/** The word to put in a sentence for an engine that may be nameless. */
|
|
76
|
+
function word(engine) {
|
|
77
|
+
return engineLabel(engine) || engineLabel(DEFAULT_ENGINE);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// ── phrasings ───────────────────────────────────────────────────────────────
|
|
81
|
+
// One function per user-visible string that used to spell "R" inline. Each is
|
|
82
|
+
// the WHOLE string, not a fragment, so a translator or a reviewer can read the
|
|
83
|
+
// sentence here instead of reassembling it from a template at the call site.
|
|
84
|
+
|
|
85
|
+
/** The code surface's accessible name: "R code editor" / "Python code editor". */
|
|
86
|
+
export function codeEditorLabel(engine, profile = "cell") {
|
|
87
|
+
return `${word(engine)} ${profile === "script" ? "script" : "code"} editor`;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/** A figure's alt text: "R plot 1". `index` is 0-based, as the caller counts. */
|
|
91
|
+
export function plotAltText(engine, index) {
|
|
92
|
+
return `${word(engine)} plot ${Number(index) + 1}`;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/** The AI panel's session chip: "⚡ R ready" (the glyph is the caller's). */
|
|
96
|
+
export function readyLabel(engine) {
|
|
97
|
+
return `${word(engine)} ready`;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/** The footer's affiliation tail: "local R kernel". */
|
|
101
|
+
export function kernelFooterLabel(engine) {
|
|
102
|
+
return `local ${word(engine)} kernel`;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/** Session ▾'s runtime row: "R Version" / "Python Version". */
|
|
106
|
+
export function versionMenuLabel(engine) {
|
|
107
|
+
return `${word(engine)} Version`;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// ── what the attached kernel declared ───────────────────────────────────────
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* The language a kernel declared, from its ready frame (`kernel.info`) or a
|
|
114
|
+
* parsed /health body — the two carry the same field name on purpose.
|
|
115
|
+
*
|
|
116
|
+
* @param {object|null|undefined} info
|
|
117
|
+
* @returns {string} an engine key: "r", "python", …
|
|
118
|
+
*/
|
|
119
|
+
export function kernelLanguage(info) {
|
|
120
|
+
const declared = info && typeof info.language === "string" ? info.language.trim() : "";
|
|
121
|
+
return declared ? engineKey(declared) : DEFAULT_ENGINE;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* The language's version, as the kernel reported it.
|
|
126
|
+
*
|
|
127
|
+
* A kernel in any language other than R sends `language_version` ("3.14.4"),
|
|
128
|
+
* because a field called `r` holding a Python version would be a lie every
|
|
129
|
+
* existing reader would print.
|
|
130
|
+
*
|
|
131
|
+
* THE `r` FIELD HAS TWO SHAPES AND ONE NAME. The ready frame sends
|
|
132
|
+
* `R.version.string` — "R version 4.5.2 (2025-10-31)" — and /health sends
|
|
133
|
+
* "4.5.2". One reader has to handle both, so it strips what may be there and
|
|
134
|
+
* adds nothing. A patched build keeps its word ("4.5.2 Patched").
|
|
135
|
+
*
|
|
136
|
+
* @returns {string} e.g. "4.5.2", or "" when the kernel said nothing
|
|
137
|
+
*/
|
|
138
|
+
export function kernelVersion(info) {
|
|
139
|
+
if (!info) return "";
|
|
140
|
+
const declared = typeof info.language_version === "string" ? info.language_version.trim() : "";
|
|
141
|
+
if (declared) return declared;
|
|
142
|
+
if (typeof info.r === "string" && info.r.trim()) {
|
|
143
|
+
return info.r.replace(/^R version /, "").replace(/ \(.*\)$/, "").trim();
|
|
144
|
+
}
|
|
145
|
+
return "";
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* "R 4.5.2" / "Python 3.14.4" / "R session" — the short form for a badge, a
|
|
150
|
+
* chip or a chooser row. One function, so the badge, the status chip and the
|
|
151
|
+
* attach chooser cannot name one session three ways.
|
|
152
|
+
*
|
|
153
|
+
* With no version it is "<Language> session", which is what the attach chooser
|
|
154
|
+
* has always shown for a listener that named no version.
|
|
155
|
+
*/
|
|
156
|
+
export function kernelDisplay(info) {
|
|
157
|
+
const label = engineLabel(kernelLanguage(info));
|
|
158
|
+
const version = kernelVersion(info);
|
|
159
|
+
return version ? `${label} ${version}` : `${label} session`;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* One engine row, normalised. Two wire shapes are accepted on purpose.
|
|
164
|
+
*
|
|
165
|
+
* `ready.engines` may be
|
|
166
|
+
* - an array of STRINGS — `["python", "bash"]`, a bare declaration of what
|
|
167
|
+
* this kernel will also run. This is the shape the Python kernel
|
|
168
|
+
* (`carmapy`) already sends and the page-patch series already reads, so it
|
|
169
|
+
* must keep working.
|
|
170
|
+
* - an array of OBJECTS — `{name, label, version, path}`, which is what a
|
|
171
|
+
* host that DISCOVERED runtimes can say. The engine chooser and Doctor
|
|
172
|
+
* need the version and the path; a bare name cannot carry them.
|
|
173
|
+
*
|
|
174
|
+
* Accepting both is not indecision: they answer different questions ("may I
|
|
175
|
+
* send this chunk?" and "what did you find on this machine?"), and a kernel
|
|
176
|
+
* that can only answer the first must not be forced to invent the second.
|
|
177
|
+
*
|
|
178
|
+
* @returns {{name:string,label:string,version:string,path:string,current:boolean}|null}
|
|
179
|
+
*/
|
|
180
|
+
function engineRow(entry, language) {
|
|
181
|
+
if (typeof entry === "string") {
|
|
182
|
+
const name = engineKey(entry);
|
|
183
|
+
return name ? { name, label: engineLabel(name), version: "", path: "", current: name === language } : null;
|
|
184
|
+
}
|
|
185
|
+
if (!entry || typeof entry !== "object" || Array.isArray(entry)) return null;
|
|
186
|
+
const name = engineKey(entry.name ?? entry.engine ?? entry.key ?? entry.language);
|
|
187
|
+
if (!name) return null;
|
|
188
|
+
const text = (value) => (typeof value === "string" ? value.trim() : "");
|
|
189
|
+
return {
|
|
190
|
+
name,
|
|
191
|
+
label: text(entry.label) || engineLabel(name),
|
|
192
|
+
version: text(entry.version) || text(entry.language_version),
|
|
193
|
+
path: text(entry.path),
|
|
194
|
+
current: entry.current === true || name === language,
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* What the kernel SAID it found, normalised — or `[]` when it said nothing.
|
|
200
|
+
*
|
|
201
|
+
* An empty answer is the degradation signal, and it is deliberately NOT
|
|
202
|
+
* "assume R": a kernel that reports no engines is one built before the field
|
|
203
|
+
* existed, and the chooser that reads this must then show what it always
|
|
204
|
+
* showed rather than inventing a one-row table.
|
|
205
|
+
*
|
|
206
|
+
* @param {object|null|undefined} info
|
|
207
|
+
* @returns {Array<{name:string,label:string,version:string,path:string,current:boolean}>}
|
|
208
|
+
*/
|
|
209
|
+
export function reportedEngines(info) {
|
|
210
|
+
const declared = info && Array.isArray(info.engines) ? info.engines : null;
|
|
211
|
+
if (!declared || !declared.length) return [];
|
|
212
|
+
const language = kernelLanguage(info);
|
|
213
|
+
const rows = [];
|
|
214
|
+
declared.forEach((entry) => {
|
|
215
|
+
const row = engineRow(entry, language);
|
|
216
|
+
if (row && !rows.some((seen) => seen.name === row.name)) rows.push(row);
|
|
217
|
+
});
|
|
218
|
+
if (!rows.length) return [];
|
|
219
|
+
// The kernel's own language is always one of its engines — a session that
|
|
220
|
+
// would not run its own language is not a thing, and a list that omitted it
|
|
221
|
+
// would strand every chunk in the notebook.
|
|
222
|
+
if (!rows.some((row) => row.name === language)) {
|
|
223
|
+
rows.unshift({ name: language, label: engineLabel(language), version: kernelVersion(info), path: "", current: true });
|
|
224
|
+
} else {
|
|
225
|
+
const own = rows.find((row) => row.name === language);
|
|
226
|
+
if (!own.version) own.version = kernelVersion(info);
|
|
227
|
+
own.current = true;
|
|
228
|
+
}
|
|
229
|
+
return rows;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Every engine this kernel will execute, as keys — the language always first.
|
|
234
|
+
*
|
|
235
|
+
* This is the list a run gate compares against. It is never empty: with no
|
|
236
|
+
* declaration at all the answer is the kernel's language alone.
|
|
237
|
+
*
|
|
238
|
+
* @returns {string[]}
|
|
239
|
+
*/
|
|
240
|
+
export function declaredEngines(info) {
|
|
241
|
+
const language = kernelLanguage(info);
|
|
242
|
+
const out = [language];
|
|
243
|
+
reportedEngines(info).forEach((row) => { if (!out.includes(row.name)) out.push(row.name); });
|
|
244
|
+
return out;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// ── authoring: what an AI may say about a chunk's language ─────────────────
|
|
248
|
+
// The tool schemas (lib/ai-tools.js, lib/mcp-bridge.js, tools/mcp/carmar-mcp.mjs)
|
|
249
|
+
// all name engines from HERE, so the enum a model is shown, the refusal it gets
|
|
250
|
+
// and the header a chunk is written with cannot disagree. Pure and import-free:
|
|
251
|
+
// tools/mcp/carmar-mcp.mjs loads it in Node beside the authoring contract.
|
|
252
|
+
|
|
253
|
+
/** The engines a tool schema offers. The SESSION decides which of them run. */
|
|
254
|
+
export const AUTHORING_ENGINES = Object.freeze(KNOWN_ENGINES.map((e) => e.key));
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* A tool's `engine` argument, validated. Absent (undefined, null, "") is R, so
|
|
258
|
+
* a call that never heard of the parameter means exactly what it always meant.
|
|
259
|
+
*
|
|
260
|
+
* @returns {string} an engine key
|
|
261
|
+
* @throws {Error} naming the engines that exist, for anything else
|
|
262
|
+
*/
|
|
263
|
+
export function engineArg(value, name = "engine") {
|
|
264
|
+
if (value == null || value === "") return DEFAULT_ENGINE;
|
|
265
|
+
if (typeof value !== "string") {
|
|
266
|
+
throw new Error(`${name} must be a string: one of ${AUTHORING_ENGINES.join(", ")}.`);
|
|
267
|
+
}
|
|
268
|
+
const key = engineKey(value);
|
|
269
|
+
if (!AUTHORING_ENGINES.includes(key)) {
|
|
270
|
+
throw new Error(`${name} "${value}" is not an engine CarmaR knows. Use one of ${AUTHORING_ENGINES.join(", ")}.`);
|
|
271
|
+
}
|
|
272
|
+
return key;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* The chunk header a new code chunk carries for `engine` — the SAME shape the
|
|
277
|
+
* `carmar:insert-cell` door writes (src/notebook-entry.js). R gets none, so an
|
|
278
|
+
* R insert is byte-identical to one made before engines existed.
|
|
279
|
+
*
|
|
280
|
+
* @returns {object|null}
|
|
281
|
+
*/
|
|
282
|
+
export function engineChunkMeta(engine) {
|
|
283
|
+
const key = engineKey(engine);
|
|
284
|
+
if (!key || key === DEFAULT_ENGINE) return null;
|
|
285
|
+
return { engine: key, label: null, options: {}, rawOptions: null, hashPipeRaw: [] };
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* The engine of a notebook cell as a manifest or adapter describes it
|
|
290
|
+
* (`{kind, chunk}`): null for prose, the header's engine for code, R when the
|
|
291
|
+
* code cell has no header. An EMPTY engine (```{}) stays "" — it names none.
|
|
292
|
+
*/
|
|
293
|
+
export function cellEngine(cell) {
|
|
294
|
+
if (!cell) return null;
|
|
295
|
+
const kind = String(cell.kind || "");
|
|
296
|
+
if (kind === "md" || kind === "text") return null;
|
|
297
|
+
return engineKey(cell.chunk && cell.chunk.engine != null ? cell.chunk.engine : null);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* Why a chunk in `engine` cannot be authored or run here, in the sentence a
|
|
302
|
+
* model repeats to the user — or "" when the attached session runs it.
|
|
303
|
+
*
|
|
304
|
+
* @param {string} engine
|
|
305
|
+
* @param {string[]} declared what the host declared (lib/chunk-meta.js chunkEngines())
|
|
306
|
+
*/
|
|
307
|
+
export function engineRefusal(engine, declared = [DEFAULT_ENGINE]) {
|
|
308
|
+
const key = engineKey(engine);
|
|
309
|
+
const list = (Array.isArray(declared) && declared.length ? declared : [DEFAULT_ENGINE]).map(engineKey);
|
|
310
|
+
if (list.includes(key)) return "";
|
|
311
|
+
const runs = list.map(engineLabel);
|
|
312
|
+
const said = runs.length === 1 ? runs[0] : `${runs.slice(0, -1).join(", ")} and ${runs.at(-1)}`;
|
|
313
|
+
const name = key ? engineLabel(key) : "Engine-less";
|
|
314
|
+
return `This session does not run ${name} chunks — the attached session runs ${said} only. `
|
|
315
|
+
+ `Write the step in ${runs[0]}, or tell the user that ${name} needs a session with a `
|
|
316
|
+
+ `${name} engine (Session ▾ lists the engines this one found).`;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
export default {
|
|
320
|
+
AUTHORING_ENGINES, engineArg, engineChunkMeta, cellEngine, engineRefusal,
|
|
321
|
+
KNOWN_ENGINES, DEFAULT_ENGINE, engineKey, engineLabel,
|
|
322
|
+
codeEditorLabel, plotAltText, readyLabel, kernelFooterLabel, versionMenuLabel,
|
|
323
|
+
kernelLanguage, kernelVersion, kernelDisplay, reportedEngines, declaredEngines,
|
|
324
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "beatrina",
|
|
3
|
+
"version": "0.8.6",
|
|
4
|
+
"description": "Beatrina is a modern, powerful, feature-rich integrated development environment (IDE) for R, Python, and JavaScript.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"beatrina": "bin/beatrina.mjs"
|
|
8
|
+
},
|
|
9
|
+
"engines": {
|
|
10
|
+
"node": ">=22"
|
|
11
|
+
},
|
|
12
|
+
"optionalDependencies": {
|
|
13
|
+
"node-pty": "^1.1.0"
|
|
14
|
+
},
|
|
15
|
+
"license": "SEE LICENSE IN LICENSE",
|
|
16
|
+
"author": "Mohammed Saqr <saqr@saqr.me> (https://saqr.me)",
|
|
17
|
+
"homepage": "https://saqr.me",
|
|
18
|
+
"files": [
|
|
19
|
+
"bin",
|
|
20
|
+
"host",
|
|
21
|
+
"engines",
|
|
22
|
+
"kernel",
|
|
23
|
+
"failsafe",
|
|
24
|
+
"lib",
|
|
25
|
+
"check",
|
|
26
|
+
"build-info.json",
|
|
27
|
+
"carmar_V0.8.6.html",
|
|
28
|
+
"README.md",
|
|
29
|
+
"LICENSE",
|
|
30
|
+
"NOTICES"
|
|
31
|
+
]
|
|
32
|
+
}
|