@fnndsc/brasa 0.31.4 → 0.32.0

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 (68) hide show
  1. package/dist/buildinfo.json +1 -1
  2. package/dist/builtins/fs/pull.js +16 -0
  3. package/dist/builtins/fs/pull.js.map +1 -1
  4. package/dist/builtins/games/bytes.d.ts +21 -0
  5. package/dist/builtins/games/bytes.js +224 -0
  6. package/dist/builtins/games/bytes.js.map +1 -0
  7. package/dist/builtins/games/chimes.d.ts +64 -0
  8. package/dist/builtins/games/chimes.js +223 -0
  9. package/dist/builtins/games/chimes.js.map +1 -0
  10. package/dist/builtins/games/cowsay.d.ts +36 -0
  11. package/dist/builtins/games/cowsay.js +127 -0
  12. package/dist/builtins/games/cowsay.js.map +1 -0
  13. package/dist/builtins/games/figlet.d.ts +25 -0
  14. package/dist/builtins/games/figlet.js +109 -0
  15. package/dist/builtins/games/figlet.js.map +1 -0
  16. package/dist/builtins/games/lab.d.ts +51 -0
  17. package/dist/builtins/games/lab.js +161 -0
  18. package/dist/builtins/games/lab.js.map +1 -0
  19. package/dist/builtins/games/lolcat.d.ts +26 -0
  20. package/dist/builtins/games/lolcat.js +71 -0
  21. package/dist/builtins/games/lolcat.js.map +1 -0
  22. package/dist/builtins/games/morse.d.ts +18 -0
  23. package/dist/builtins/games/morse.js +46 -0
  24. package/dist/builtins/games/morse.js.map +1 -0
  25. package/dist/builtins/games/numbers.d.ts +55 -0
  26. package/dist/builtins/games/numbers.js +270 -0
  27. package/dist/builtins/games/numbers.js.map +1 -0
  28. package/dist/builtins/games/play.d.ts +53 -0
  29. package/dist/builtins/games/play.js +228 -0
  30. package/dist/builtins/games/play.js.map +1 -0
  31. package/dist/builtins/games/qr.d.ts +40 -0
  32. package/dist/builtins/games/qr.js +336 -0
  33. package/dist/builtins/games/qr.js.map +1 -0
  34. package/dist/builtins/games/shelf.d.ts +27 -0
  35. package/dist/builtins/games/shelf.js +71 -0
  36. package/dist/builtins/games/shelf.js.map +1 -0
  37. package/dist/builtins/games/show.d.ts +32 -0
  38. package/dist/builtins/games/show.js +68 -0
  39. package/dist/builtins/games/show.js.map +1 -0
  40. package/dist/builtins/games/sky.d.ts +69 -0
  41. package/dist/builtins/games/sky.js +190 -0
  42. package/dist/builtins/games/sky.js.map +1 -0
  43. package/dist/builtins/games/stdin.d.ts +34 -0
  44. package/dist/builtins/games/stdin.js +48 -0
  45. package/dist/builtins/games/stdin.js.map +1 -0
  46. package/dist/builtins/games/text.d.ts +46 -0
  47. package/dist/builtins/games/text.js +133 -0
  48. package/dist/builtins/games/text.js.map +1 -0
  49. package/dist/builtins/games/wtf.d.ts +13 -0
  50. package/dist/builtins/games/wtf.data.d.ts +12 -0
  51. package/dist/builtins/games/wtf.data.js +70 -0
  52. package/dist/builtins/games/wtf.data.js.map +1 -0
  53. package/dist/builtins/games/wtf.js +45 -0
  54. package/dist/builtins/games/wtf.js.map +1 -0
  55. package/dist/builtins/help.d.ts +8 -0
  56. package/dist/builtins/help.js +296 -0
  57. package/dist/builtins/help.js.map +1 -1
  58. package/dist/core/dispatch.js +125 -9
  59. package/dist/core/dispatch.js.map +1 -1
  60. package/dist/core/engine.js +1 -0
  61. package/dist/core/engine.js.map +1 -1
  62. package/dist/core/surface.d.ts +14 -0
  63. package/dist/core/surface.js.map +1 -1
  64. package/dist/lib/vfs/providers/static.js +15 -1
  65. package/dist/lib/vfs/providers/static.js.map +1 -1
  66. package/dist/lib/vfs/providers/static_content.js +2 -2
  67. package/dist/lib/vfs/providers/static_content.js.map +1 -1
  68. package/package.json +4 -4
@@ -0,0 +1,161 @@
1
+ /**
2
+ * @file The lab's own toys: `who`, `uptime`, `ping`, `chrisfetch`, `say`.
3
+ *
4
+ * Small tools that happen to be fun. `who` names the surfaces on this
5
+ * session, `uptime` how long the process has been up, `ping` the round
6
+ * trip to CUBE, `chrisfetch` the brain beside the session's facts, and
7
+ * `say` hands words to a surface with a voice (the console prints them).
8
+ *
9
+ * @module
10
+ */
11
+ import { envelope_ok, envelope_error, chrisContext, requestLedger_snapshot } from '@fnndsc/cumin';
12
+ import chalk from 'chalk';
13
+ import { surface_get } from '../../core/surface.js';
14
+ import { motd_gather } from '../sys/motd.js';
15
+ import { BRAIN } from './cowsay.js';
16
+ import { text_input } from './stdin.js';
17
+ /** Round trips `ping` makes when not told. */
18
+ export const PING_COUNT = 3;
19
+ /** The most round trips `ping` makes however asked. */
20
+ export const PING_MAX = 20;
21
+ /** How long one round trip may take before it is called lost. */
22
+ const PING_TIMEOUT_MS = 8_000;
23
+ /** A span of seconds in words: `2d 3h 04m`, `17m 05s`. */
24
+ export function uptime_words(seconds) {
25
+ const s = Math.floor(seconds);
26
+ const days = Math.floor(s / 86400);
27
+ const hours = Math.floor((s % 86400) / 3600);
28
+ const minutes = Math.floor((s % 3600) / 60);
29
+ const secs = s % 60;
30
+ if (days > 0)
31
+ return `${days}d ${hours}h ${String(minutes).padStart(2, '0')}m`;
32
+ if (hours > 0)
33
+ return `${hours}h ${String(minutes).padStart(2, '0')}m`;
34
+ return `${minutes}m ${String(secs).padStart(2, '0')}s`;
35
+ }
36
+ /** `who`: the surfaces attached to this session. */
37
+ export async function builtin_who(_args) {
38
+ const peers = surface_get().peers?.() ?? null;
39
+ const user = (await chrisContext.ChRISuser_get()) ?? '?';
40
+ if (peers === null) {
41
+ return envelope_ok(`${user} this terminal\n`, { kind: 'games.who', data: { user, peers: [] } });
42
+ }
43
+ const lines = peers.map((p) => `${user.padEnd(16)} ${p.kind.padEnd(8)} ${p.id}${p.you ? chalk.gray(' (you)') : ''}`);
44
+ return envelope_ok(`${lines.join('\n')}\n`, { kind: 'games.who', data: { user, peers } });
45
+ }
46
+ /** `uptime`: how long this process has been up, and who is here. */
47
+ export async function builtin_uptime(_args) {
48
+ const seconds = process.uptime();
49
+ const peers = surface_get().peers?.() ?? null;
50
+ const since = new Date(Date.now() - seconds * 1000);
51
+ const now = new Date().toTimeString().slice(0, 8);
52
+ const who = peers === null ? '' : `, ${peers.length} surface${peers.length === 1 ? '' : 's'}`;
53
+ const line = ` ${now} up ${uptime_words(seconds)}${who} (since ${since.toISOString().replace('T', ' ').slice(0, 19)}Z, pid ${process.pid})`;
54
+ return envelope_ok(`${line}\n`, { kind: 'games.uptime', data: { seconds, since: since.toISOString(), pid: process.pid, surfaces: peers?.length ?? null } });
55
+ }
56
+ /**
57
+ * Round-trips to a URL `count` times.
58
+ *
59
+ * @param url - Where.
60
+ * @param count - How many.
61
+ * @param fetchFn - The fetch to use.
62
+ * @param onSample - Told each sample as it lands, for a surface that streams.
63
+ */
64
+ export async function ping_run(url, count, fetchFn, onSample) {
65
+ const samples = [];
66
+ for (let seq = 1; seq <= count; seq++) {
67
+ const started = performance.now();
68
+ const controller = new AbortController();
69
+ const timer = setTimeout(() => controller.abort(), PING_TIMEOUT_MS);
70
+ let sample;
71
+ try {
72
+ const response = await fetchFn(url, { method: 'GET', signal: controller.signal });
73
+ sample = { seq, ms: Math.round((performance.now() - started) * 10) / 10, status: response.status };
74
+ }
75
+ catch {
76
+ sample = { seq, ms: null, status: null };
77
+ }
78
+ finally {
79
+ clearTimeout(timer);
80
+ }
81
+ samples.push(sample);
82
+ onSample?.(sample);
83
+ }
84
+ return samples;
85
+ }
86
+ /** The summary line, as ping prints it. */
87
+ export function ping_summary(samples) {
88
+ const got = samples.map((s) => s.ms).filter((ms) => ms !== null);
89
+ const lost = samples.length - got.length;
90
+ const loss = samples.length === 0 ? '0' : String(Math.round((lost / samples.length) * 100));
91
+ let out = `${samples.length} sent, ${got.length} answered, ${loss}% lost`;
92
+ if (got.length > 0) {
93
+ const min = Math.min(...got);
94
+ const max = Math.max(...got);
95
+ const avg = got.reduce((a, b) => a + b, 0) / got.length;
96
+ out += `\nround-trip min/avg/max = ${min}/${avg.toFixed(1)}/${max} ms`;
97
+ }
98
+ return out;
99
+ }
100
+ /** `ping [-c N]`: round trips to CUBE. */
101
+ export async function builtin_ping(args, fetchFn = (url, init) => fetch(url, init)) {
102
+ let count = PING_COUNT;
103
+ for (let i = 0; i < args.length; i++) {
104
+ if (args[i] === '-c') {
105
+ const n = Number(args[i + 1]);
106
+ if (!Number.isInteger(n) || n < 1)
107
+ return envelope_error('', undefined, 'ping: -c wants a positive whole number\n');
108
+ count = Math.min(n, PING_MAX);
109
+ i++;
110
+ }
111
+ else if (args[i] !== 'cube') {
112
+ return envelope_error('', undefined, `ping: only CUBE is pinged from here (ping [-c N] [cube]); '${args[i]}' is not that\n`);
113
+ }
114
+ }
115
+ const url = await chrisContext.ChRISURL_get();
116
+ if (url === null)
117
+ return envelope_error('', undefined, 'ping: not connected to a CUBE\n');
118
+ const lines = [`PING cube (${url})`];
119
+ const samples = await ping_run(url, count, fetchFn, (s) => {
120
+ lines.push(s.ms === null ? `seq=${s.seq} lost (no answer in ${PING_TIMEOUT_MS / 1000}s)` : `seq=${s.seq} http=${s.status} time=${s.ms} ms`);
121
+ });
122
+ const ledger = requestLedger_snapshot({ last: 0 });
123
+ const recent = ledger.total > 0 ? `\nthis session's own calls: ${ledger.total} to CUBE, ${(ledger.ms / ledger.total).toFixed(0)} ms each on average` : '';
124
+ return envelope_ok(`${lines.join('\n')}\n--- cube ping statistics ---\n${ping_summary(samples)}${recent}\n`, { kind: 'games.ping', data: { url, samples } });
125
+ }
126
+ /** `chrisfetch`: the brain beside the session's facts, neofetch style. */
127
+ export async function builtin_chrisfetch(_args) {
128
+ const user = (await chrisContext.ChRISuser_get()) ?? '?';
129
+ const url = await chrisContext.ChRISURL_get();
130
+ const host = url === null ? '(not connected)' : url.replace(/^https?:\/\//, '').replace(/\/api\/v1\/?$/, '');
131
+ const motd = motd_gather(user, 'chrisfetch');
132
+ const peers = surface_get().peers?.() ?? null;
133
+ const facts = [
134
+ ['CUBE', host],
135
+ ['Feeds', `${motd.feeds.total} (${motd.feeds.own} own, ${motd.feeds.shared} shared, ${motd.feeds.public} public)`],
136
+ ['Jobs', `${motd.jobs.total.toLocaleString('en-US')} run · ${motd.jobs.running} running · ${motd.jobs.scheduled} scheduled`],
137
+ ['Failed', motd.failureRate === null ? 'none settled yet' : `${(motd.failureRate * 100).toFixed(1)} %`],
138
+ ['Index', motd.index.state === 'current' ? 'whole' : `${motd.index.state} (${motd.index.loaded}/${motd.index.total})`],
139
+ ['Surfaces', peers === null ? 'this terminal' : `${peers.length} attached (${peers.filter((p) => p.kind === 'browser').length} browser, ${peers.filter((p) => p.kind === 'chell').length} chell)`],
140
+ ['Uptime', uptime_words(process.uptime())],
141
+ ['Node', process.version],
142
+ ];
143
+ const title = `${chalk.bold.cyan(user)}@${chalk.bold.cyan(host.split(':')[0] ?? host)}`;
144
+ const right = [title, chalk.gray('─'.repeat(Math.min(40, user.length + host.length + 1))), ...facts.map(([k, v]) => `${chalk.cyan(k.padEnd(9))}${v}`)];
145
+ const rows = Math.max(BRAIN.length, right.length);
146
+ const lines = [];
147
+ for (let i = 0; i < rows; i++) {
148
+ const left = (BRAIN[i] ?? '').padEnd(27);
149
+ lines.push(`${chalk.cyan(left)} ${right[i] ?? ''}`.trimEnd());
150
+ }
151
+ return envelope_ok(`${lines.join('\n')}\n`, { kind: 'games.chrisfetch', data: { user, cube: url, feeds: motd.feeds, jobs: motd.jobs, failureRate: motd.failureRate, index: motd.index, surfaces: peers, uptimeSeconds: process.uptime() } });
152
+ }
153
+ /** `say [text]`: a surface with a voice speaks it; the console prints it. */
154
+ export async function builtin_say(args) {
155
+ const text = text_input(args);
156
+ if (text === null)
157
+ return envelope_error('', undefined, 'say: nothing to say (say hello, or fortune | say)\n');
158
+ const said = text.replace(/\n$/, '').replace(/\s+/g, ' ').trim();
159
+ return envelope_ok(`${chalk.gray('♪')} ${said}\n`, { kind: 'games.say', data: { text: said } });
160
+ }
161
+ //# sourceMappingURL=lab.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lab.js","sourceRoot":"","sources":["../../../src/builtins/games/lab.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * @file `lolcat`: text in a rainbow.
3
+ *
4
+ * Each character takes the next hue along a sine rainbow, the hue drifting
5
+ * down the lines, as the original does. The colour is 24-bit ANSI, which
6
+ * every surface here renders; `-p N` sets the spread (characters per cycle),
7
+ * `-S N` the starting phase.
8
+ *
9
+ * @module
10
+ */
11
+ import { CommandEnvelope } from '@fnndsc/cumin';
12
+ /** Characters per rainbow cycle when none is asked. */
13
+ export declare const LOLCAT_SPREAD: number;
14
+ /** The colour at a point along the rainbow. */
15
+ export declare function rainbow_rgb(position: number, spread: number): [number, number, number];
16
+ /**
17
+ * Paints a text.
18
+ *
19
+ * @param text - The lines.
20
+ * @param spread - Characters per cycle.
21
+ * @param phase - Where the first character starts.
22
+ * @returns The text with a colour per character; plain spaces stay plain.
23
+ */
24
+ export declare function lolcat_paint(text: string, spread?: number, phase?: number): string;
25
+ /** `lolcat [-p SPREAD] [-S PHASE] [text]` */
26
+ export declare function builtin_lolcat(args: string[]): Promise<CommandEnvelope>;
@@ -0,0 +1,71 @@
1
+ /**
2
+ * @file `lolcat`: text in a rainbow.
3
+ *
4
+ * Each character takes the next hue along a sine rainbow, the hue drifting
5
+ * down the lines, as the original does. The colour is 24-bit ANSI, which
6
+ * every surface here renders; `-p N` sets the spread (characters per cycle),
7
+ * `-S N` the starting phase.
8
+ *
9
+ * @module
10
+ */
11
+ import { envelope_ok, envelope_error } from '@fnndsc/cumin';
12
+ import chalk from 'chalk';
13
+ import { text_input } from './stdin.js';
14
+ /** 24-bit colour whatever the host thinks of its terminal: every surface here renders it. */
15
+ const paint = new chalk.Instance({ level: 3 });
16
+ /** Characters per rainbow cycle when none is asked. */
17
+ export const LOLCAT_SPREAD = 24;
18
+ /** The colour at a point along the rainbow. */
19
+ export function rainbow_rgb(position, spread) {
20
+ const t = (position / spread) * 2 * Math.PI;
21
+ const channel = (phase) => Math.round(Math.sin(t + phase) * 100 + 155);
22
+ return [channel(0), channel(2 * Math.PI / 3), channel(4 * Math.PI / 3)];
23
+ }
24
+ /**
25
+ * Paints a text.
26
+ *
27
+ * @param text - The lines.
28
+ * @param spread - Characters per cycle.
29
+ * @param phase - Where the first character starts.
30
+ * @returns The text with a colour per character; plain spaces stay plain.
31
+ */
32
+ export function lolcat_paint(text, spread = LOLCAT_SPREAD, phase = 0) {
33
+ const clean = text.replace(/\x1b\[[0-9;]*m/g, '');
34
+ return clean.split('\n').map((line, row) => [...line].map((c, col) => {
35
+ if (c === ' ')
36
+ return c;
37
+ const [r, g, b] = rainbow_rgb(phase + col + row * 3, spread);
38
+ return paint.rgb(r, g, b)(c);
39
+ }).join('')).join('\n');
40
+ }
41
+ /** `lolcat [-p SPREAD] [-S PHASE] [text]` */
42
+ export async function builtin_lolcat(args) {
43
+ let spread = LOLCAT_SPREAD;
44
+ let phase = Math.floor(Math.random() * 256);
45
+ const words = [];
46
+ for (let i = 0; i < args.length; i++) {
47
+ const flag = args[i];
48
+ if (flag === '-p' || flag === '-S') {
49
+ const n = Number(args[i + 1]);
50
+ if (!Number.isFinite(n) || (flag === '-p' && n < 1))
51
+ return envelope_error('', undefined, `lolcat: ${flag} wants a number${flag === '-p' ? ' of 1 or more' : ''}\n`);
52
+ if (flag === '-p')
53
+ spread = n;
54
+ else
55
+ phase = n;
56
+ i++;
57
+ }
58
+ else if (flag.startsWith('-') && flag.length > 1) {
59
+ return envelope_error('', undefined, `lolcat: unknown flag '${flag}' (only -p SPREAD and -S PHASE)\n`);
60
+ }
61
+ else {
62
+ words.push(flag);
63
+ }
64
+ }
65
+ const text = text_input(words);
66
+ if (text === null)
67
+ return envelope_error('', undefined, 'lolcat: nothing to paint (pipe text in: fortune | lolcat)\n');
68
+ const said = text.replace(/\n$/, '');
69
+ return envelope_ok(`${lolcat_paint(said, spread, phase)}\n`, { kind: 'games.lolcat', data: { text: said, spread, phase } });
70
+ }
71
+ //# sourceMappingURL=lolcat.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lolcat.js","sourceRoot":"","sources":["../../../src/builtins/games/lolcat.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * @file `morse`: text to code and back.
3
+ *
4
+ * `morse hello` taps it out; `morse -d .... . .-.. .-.. ---` reads it. One
5
+ * space between letters, a slash between words, as operators write it. The
6
+ * typed model carries the code so a surface with a speaker can sound it.
7
+ *
8
+ * @module
9
+ */
10
+ import { CommandEnvelope } from '@fnndsc/cumin';
11
+ /** The International code. */
12
+ export declare const MORSE: Readonly<Record<string, string>>;
13
+ /** Text to code: letters a space apart, words a slash apart; an unknown character is dropped. */
14
+ export declare function morse_encode(text: string): string;
15
+ /** Code to text: a group the code does not know becomes `?`. */
16
+ export declare function morse_decode(code: string): string;
17
+ /** `morse [-d] [text]` */
18
+ export declare function builtin_morse(args: string[]): Promise<CommandEnvelope>;
@@ -0,0 +1,46 @@
1
+ /**
2
+ * @file `morse`: text to code and back.
3
+ *
4
+ * `morse hello` taps it out; `morse -d .... . .-.. .-.. ---` reads it. One
5
+ * space between letters, a slash between words, as operators write it. The
6
+ * typed model carries the code so a surface with a speaker can sound it.
7
+ *
8
+ * @module
9
+ */
10
+ import { envelope_ok, envelope_error } from '@fnndsc/cumin';
11
+ import { text_input } from './stdin.js';
12
+ /** The International code. */
13
+ export const MORSE = {
14
+ A: '.-', B: '-...', C: '-.-.', D: '-..', E: '.', F: '..-.', G: '--.', H: '....', I: '..', J: '.---',
15
+ K: '-.-', L: '.-..', M: '--', N: '-.', O: '---', P: '.--.', Q: '--.-', R: '.-.', S: '...', T: '-',
16
+ U: '..-', V: '...-', W: '.--', X: '-..-', Y: '-.--', Z: '--..',
17
+ '0': '-----', '1': '.----', '2': '..---', '3': '...--', '4': '....-', '5': '.....', '6': '-....', '7': '--...', '8': '---..', '9': '----.',
18
+ '.': '.-.-.-', ',': '--..--', '?': '..--..', '!': '-.-.--', '/': '-..-.', '(': '-.--.', ')': '-.--.-', '&': '.-...', ':': '---...',
19
+ ';': '-.-.-.', '=': '-...-', '+': '.-.-.', '-': '-....-', '_': '..--.-', '"': '.-..-.', '$': '...-..-', '@': '.--.-.', '\'': '.----.',
20
+ };
21
+ const MORSE_BACK = Object.fromEntries(Object.entries(MORSE).map(([letter, code]) => [code, letter]));
22
+ /** Text to code: letters a space apart, words a slash apart; an unknown character is dropped. */
23
+ export function morse_encode(text) {
24
+ return text.toUpperCase().trim().split(/\s+/).map((word) => [...word].map((c) => MORSE[c] ?? '').filter((c) => c.length > 0).join(' ')).filter((w) => w.length > 0).join(' / ');
25
+ }
26
+ /** Code to text: a group the code does not know becomes `?`. */
27
+ export function morse_decode(code) {
28
+ return code.trim().split(/\s*\/\s*|\s{3,}/).map((word) => word.trim().split(/\s+/).filter((g) => g.length > 0).map((g) => MORSE_BACK[g] ?? '?').join('')).join(' ');
29
+ }
30
+ /** `morse [-d] [text]` */
31
+ export async function builtin_morse(args) {
32
+ const decode = args[0] === '-d' || args[0] === '--decode';
33
+ const text = text_input(decode ? args.slice(1) : args);
34
+ if (text === null)
35
+ return envelope_error('', undefined, 'morse: usage: morse <text> | morse -d <code>\n');
36
+ const said = text.replace(/\n$/, '');
37
+ if (decode) {
38
+ const plain = morse_decode(said);
39
+ return envelope_ok(`${plain}\n`, { kind: 'games.morse', data: { text: plain, code: said.trim(), direction: 'decode' } });
40
+ }
41
+ const code = morse_encode(said);
42
+ if (code === '')
43
+ return envelope_error('', undefined, 'morse: nothing in that the code can carry\n');
44
+ return envelope_ok(`${code}\n`, { kind: 'games.morse', data: { text: said, code, direction: 'encode' } });
45
+ }
46
+ //# sourceMappingURL=morse.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"morse.js","sourceRoot":"","sources":["../../../src/builtins/games/morse.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * @file Number toys from the shelf: `factor`, `primes`, `roll`, `calc`, `units`.
3
+ *
4
+ * `calc` is a small arithmetic reader of its own — no `eval` — with the
5
+ * usual operators, parentheses, a few functions and `pi` and `e`. `units`
6
+ * converts within a modest table: length, mass, time, data and temperature.
7
+ *
8
+ * @module
9
+ */
10
+ import { CommandEnvelope } from '@fnndsc/cumin';
11
+ /** The most primes `primes` lists in one call. */
12
+ export declare const PRIMES_MAX: number;
13
+ /** The prime factors of n, smallest first, with repeats. */
14
+ export declare function factors_of(n: number): number[];
15
+ /** The primes in [from, to], at most PRIMES_MAX of them. */
16
+ export declare function primes_between(from: number, to: number): number[];
17
+ /**
18
+ * Rolls dice written as `NdS[+M]`, e.g. `2d6+1`, `d20`.
19
+ *
20
+ * @returns Each die's face and the total, or a refusal.
21
+ */
22
+ export declare function dice_roll(spec: string, random?: () => number): {
23
+ rolls: number[];
24
+ modifier: number;
25
+ total: number;
26
+ } | {
27
+ refusal: string;
28
+ };
29
+ /**
30
+ * Evaluates an arithmetic expression: + - * / % ^, parentheses, unary minus,
31
+ * the functions above, pi and e. Throws with a reason on a malformed one.
32
+ */
33
+ export declare function calc_evaluate(expression: string): number;
34
+ /**
35
+ * Converts a quantity between two units of one kind.
36
+ *
37
+ * @returns The converted value, or a refusal naming what went wrong.
38
+ */
39
+ export declare function units_convert(value: number, from: string, to: string): {
40
+ value: number;
41
+ } | {
42
+ refusal: string;
43
+ };
44
+ /** The unit names `units` knows, for its help and its refusals. */
45
+ export declare function units_known(): string[];
46
+ /** `factor N...` */
47
+ export declare function builtin_factor(args: string[]): Promise<CommandEnvelope>;
48
+ /** `primes [FROM] TO` */
49
+ export declare function builtin_primes(args: string[]): Promise<CommandEnvelope>;
50
+ /** `roll [NdS[+M]]...` — 1d6 when bare. */
51
+ export declare function builtin_roll(args: string[]): Promise<CommandEnvelope>;
52
+ /** `calc EXPRESSION` */
53
+ export declare function builtin_calc(args: string[]): Promise<CommandEnvelope>;
54
+ /** `units VALUE FROM [to] TO` */
55
+ export declare function builtin_units(args: string[]): Promise<CommandEnvelope>;