@fnndsc/calypso 0.12.0 → 0.13.1

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/dist/calypso.js CHANGED
@@ -12,11 +12,11 @@
12
12
  */
13
13
  import { fileURLToPath } from 'node:url';
14
14
  import { realpathSync } from 'node:fs';
15
- import { engine_create, procIndex_snapshot, sessionConnect_fromSaved } from '@fnndsc/brasa';
15
+ import { engine_create, sessionConnect_fromSaved } from '@fnndsc/brasa';
16
16
  import chalk from 'chalk';
17
17
  import { daemon_launch } from './daemon/launch.js';
18
- import { hostControl_describe, hostControl_parseArgv } from './daemon/hostControl.js';
19
- import { face_start } from './daemon/face.js';
18
+ import { daemonConsole_run } from './daemon/consoleSession.js';
19
+ import { hostControl_parseArgv } from './daemon/hostControl.js';
20
20
  import { LocalBerthResolver, berthUrl_isAlive } from './daemon/berth.js';
21
21
  /**
22
22
  * Creates the engine, restores the saved session, and hosts the daemon.
@@ -40,30 +40,13 @@ async function calypso_start() {
40
40
  }
41
41
  const policy = parsedPolicy.policy;
42
42
  const info = await daemon_launch(engine, undefined, { hostControl: policy });
43
- // On a TTY, the terminal's resting state is the console face; off one
44
- // (systemd, nohup) face_start declines and logging stays sequential.
45
- face_start({
46
- ...(policy.tiers.size > 0
47
- ? { hostControl: { tiers: hostControl_describe(policy), ...(policy.exposed && info.bindHost !== '127.0.0.1' ? { exposedOn: info.bindHost } : {}) } }
48
- : {}),
49
- info: [
50
- { label: 'identity', value: info.identity },
51
- { label: 'wire', value: info.url },
52
- ...(info.argusUrl !== null ? [{ label: 'ARGUS', value: info.argusUrl }] : []),
53
- { label: 'token', value: info.token },
54
- { label: 'berth', value: info.berthPath },
55
- { label: 'attach', value: `chell --remote --attach ${info.url} --token ${info.token}` },
56
- ],
57
- telemetry_get: () => {
58
- const index = procIndex_snapshot();
59
- return {
60
- sessions: info.daemon.surfaces_count(),
61
- busy: info.daemon.busy_get(),
62
- jobs: index.jobs,
63
- feeds: index.feeds,
64
- };
65
- },
66
- });
43
+ // The boot ends at a login, the same as `chell --daemon`: on a TTY the
44
+ // daemon's own terminal becomes its first surface, an ordinary
45
+ // `chell --remote` spawned onto it. Off a TTY (systemd, nohup) there is
46
+ // no terminal to attach, so the daemon just keeps listening.
47
+ if (process.stdin.isTTY === true && process.stdout.isTTY === true) {
48
+ await daemonConsole_run({ identity: info.identity, url: info.url, token: info.token });
49
+ }
67
50
  }
68
51
  /**
69
52
  * Prints how to attach to each live daemon.
@@ -1 +1 @@
1
- {"version":3,"file":"calypso.js","sourceRoot":"","sources":["../src/calypso.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"calypso.js","sourceRoot":"","sources":["../src/calypso.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,110 @@
1
+ /**
2
+ * @file The daemon console: the terminal a daemon booted in becomes its
3
+ * first surface.
4
+ *
5
+ * A Linux boot ends at a login. A daemon boot ended at a resting face — a
6
+ * brain animation and a status line, with the boot log a keypress away —
7
+ * that was a screensaver where a session belonged. The identity is already
8
+ * resolved by the time the engine is ready, so the login is the attach: an
9
+ * ordinary `chell --remote` surface is put on the daemon's own terminal.
10
+ *
11
+ * It is a child process on the wire, not an in-process shortcut. The daemon
12
+ * process holds one output sink and one interaction surface for every
13
+ * attached session; a REPL started inside it would take those over and
14
+ * every other surface would go quiet. A child pays one loopback hop, which
15
+ * is what every surface pays, and shares nothing else.
16
+ *
17
+ * `exit` in the console detaches; the daemon stays up, its terminal idle.
18
+ * Enter attaches again. Ctrl-C at that idle terminal stops the daemon, as
19
+ * it always did. While the console holds the terminal, whatever the daemon
20
+ * itself writes — a roster row, a late warm-up settling — is held and
21
+ * handed back on detach, so it lands after the surface's last line and
22
+ * never across its prompt.
23
+ *
24
+ * The console lives here, in the daemon's own package, because both the
25
+ * chell `--daemon` host and the standalone `calypso` binary end their boot
26
+ * this way. What differs between them is only how the surface is launched —
27
+ * chell spawns itself, the calypso binary spawns `chell` from the path — so
28
+ * that is the one injected part.
29
+ *
30
+ * @module
31
+ */
32
+ import { type ChildProcess } from 'node:child_process';
33
+ import type { EventEmitter } from 'node:events';
34
+ /** What the console needs to know about the daemon it attaches to. */
35
+ export interface DaemonConsoleTarget {
36
+ identity: string;
37
+ url: string;
38
+ token: string;
39
+ }
40
+ /** How to launch the surface: the executable and the args before `--remote`. */
41
+ export interface SurfaceLaunch {
42
+ /** The program to run — `chell` on the path, or a node with an entry. */
43
+ exec: string;
44
+ /** Args that precede the surface flags (a script entry, or nothing). */
45
+ prefixArgs: string[];
46
+ }
47
+ /** The default: the `chell` a user would run, found on the path. */
48
+ export declare const CHELL_ON_PATH: SurfaceLaunch;
49
+ /** The running attached surface: settles with its exit code. */
50
+ export interface ConsoleChild {
51
+ exited: Promise<number>;
52
+ }
53
+ /** The seams the console loop runs on, replaceable under test. */
54
+ export interface DaemonConsoleDeps {
55
+ /** Starts a `chell --remote` surface on this terminal. */
56
+ attach: (target: DaemonConsoleTarget) => ConsoleChild;
57
+ /** Holds the daemon's own console writes. */
58
+ cage_start: () => void;
59
+ /** Hands back what was held. */
60
+ cage_stop: () => string[];
61
+ /** Resolves true on Enter, false when the terminal's input ends. */
62
+ enter_wait: () => Promise<boolean>;
63
+ /** The terminal's own line writer. */
64
+ log: (line: string) => void;
65
+ }
66
+ /** What the spawner needs of a child: its exit and error events. */
67
+ export type SpawnedChild = Pick<ChildProcess, 'once'>;
68
+ /** A process spawner with the shape of `child_process.spawn`. */
69
+ export type Spawn = (command: string, args: string[], options: {
70
+ stdio: 'inherit';
71
+ env: NodeJS.ProcessEnv;
72
+ }) => SpawnedChild;
73
+ /** What the Enter wait needs of the terminal's input. */
74
+ export type ConsoleInput = Pick<EventEmitter, 'on' | 'once' | 'off'> & {
75
+ resume(): unknown;
76
+ pause(): unknown;
77
+ };
78
+ /**
79
+ * Starts a remote surface on this terminal, attached by address.
80
+ *
81
+ * @param target - The daemon's wire address and token.
82
+ * @param launch - How to launch the surface; `chell` on the path by default.
83
+ * @param spawn - The process spawner; `child_process.spawn` by default.
84
+ * @returns The child, settling with its exit code when the operator detaches.
85
+ */
86
+ export declare function surface_spawn(target: DaemonConsoleTarget, launch?: SurfaceLaunch, spawn?: Spawn): ConsoleChild;
87
+ /**
88
+ * Waits for the operator to press Enter at the idle daemon terminal.
89
+ *
90
+ * @param input - The terminal's input; `process.stdin` by default.
91
+ * @returns True on a line of input; false when the input ends.
92
+ */
93
+ export declare function enter_await(input?: ConsoleInput): Promise<boolean>;
94
+ /**
95
+ * The live seams for a given surface launch: a real child on the wire, the
96
+ * real cage, the real terminal.
97
+ *
98
+ * @param launch - How to launch the surface.
99
+ * @returns The deps `daemonConsole_run` uses in production.
100
+ */
101
+ export declare function consoleDeps_live(launch?: SurfaceLaunch): DaemonConsoleDeps;
102
+ /**
103
+ * Runs the daemon console until the operator leaves the terminal idle for
104
+ * good: attach, detach on `exit`, attach again on Enter, until stdin ends.
105
+ *
106
+ * @param target - The daemon to attach to.
107
+ * @param deps - The seams; the live ones (chell on the path) by default.
108
+ * @returns Resolves when the operator will not attach again.
109
+ */
110
+ export declare function daemonConsole_run(target: DaemonConsoleTarget, deps?: DaemonConsoleDeps): Promise<void>;
@@ -0,0 +1,150 @@
1
+ /**
2
+ * @file The daemon console: the terminal a daemon booted in becomes its
3
+ * first surface.
4
+ *
5
+ * A Linux boot ends at a login. A daemon boot ended at a resting face — a
6
+ * brain animation and a status line, with the boot log a keypress away —
7
+ * that was a screensaver where a session belonged. The identity is already
8
+ * resolved by the time the engine is ready, so the login is the attach: an
9
+ * ordinary `chell --remote` surface is put on the daemon's own terminal.
10
+ *
11
+ * It is a child process on the wire, not an in-process shortcut. The daemon
12
+ * process holds one output sink and one interaction surface for every
13
+ * attached session; a REPL started inside it would take those over and
14
+ * every other surface would go quiet. A child pays one loopback hop, which
15
+ * is what every surface pays, and shares nothing else.
16
+ *
17
+ * `exit` in the console detaches; the daemon stays up, its terminal idle.
18
+ * Enter attaches again. Ctrl-C at that idle terminal stops the daemon, as
19
+ * it always did. While the console holds the terminal, whatever the daemon
20
+ * itself writes — a roster row, a late warm-up settling — is held and
21
+ * handed back on detach, so it lands after the surface's last line and
22
+ * never across its prompt.
23
+ *
24
+ * The console lives here, in the daemon's own package, because both the
25
+ * chell `--daemon` host and the standalone `calypso` binary end their boot
26
+ * this way. What differs between them is only how the surface is launched —
27
+ * chell spawns itself, the calypso binary spawns `chell` from the path — so
28
+ * that is the one injected part.
29
+ *
30
+ * @module
31
+ */
32
+ import { spawn as childSpawn } from 'node:child_process';
33
+ import chalk from 'chalk';
34
+ import { consoleCage_start, consoleCage_stop } from './console.js';
35
+ /** The default: the `chell` a user would run, found on the path. */
36
+ export const CHELL_ON_PATH = { exec: 'chell', prefixArgs: [] };
37
+ /**
38
+ * Starts a remote surface on this terminal, attached by address.
39
+ *
40
+ * @param target - The daemon's wire address and token.
41
+ * @param launch - How to launch the surface; `chell` on the path by default.
42
+ * @param spawn - The process spawner; `child_process.spawn` by default.
43
+ * @returns The child, settling with its exit code when the operator detaches.
44
+ */
45
+ export function surface_spawn(target, launch = CHELL_ON_PATH, spawn = childSpawn) {
46
+ // The identity rides along so the surface greets with it, not with the
47
+ // address twice; the environment mark tells it whose terminal it is on,
48
+ // so it skips the greeting the daemon's banner already gave.
49
+ const child = spawn(launch.exec, [...launch.prefixArgs, '--remote', target.identity, '--attach', target.url, '--token', target.token], { stdio: 'inherit', env: { ...process.env, CHELL_CONSOLE: '1' } });
50
+ const exited = new Promise((resolve) => {
51
+ child.once('exit', (code) => { resolve(code ?? 0); });
52
+ child.once('error', (error) => {
53
+ // A surface that cannot start at all (no `chell` on the path) must say
54
+ // so, or the loop would offer to attach again with nothing to show for
55
+ // it. Named so the operator knows what to install.
56
+ process.stderr.write(chalk.red(`[!] Could not start the console surface (${launch.exec}): ${error.message}\n`));
57
+ resolve(1);
58
+ });
59
+ });
60
+ return { exited };
61
+ }
62
+ /**
63
+ * Waits for the operator to press Enter at the idle daemon terminal.
64
+ *
65
+ * @param input - The terminal's input; `process.stdin` by default.
66
+ * @returns True on a line of input; false when the input ends.
67
+ */
68
+ export function enter_await(input = process.stdin) {
69
+ return new Promise((resolve) => {
70
+ const cleanup = () => {
71
+ input.off('data', onData);
72
+ input.off('end', onEnd);
73
+ input.pause();
74
+ };
75
+ const onData = () => { cleanup(); resolve(true); };
76
+ const onEnd = () => { cleanup(); resolve(false); };
77
+ input.on('data', onData);
78
+ input.once('end', onEnd);
79
+ input.resume();
80
+ });
81
+ }
82
+ /**
83
+ * The live seams for a given surface launch: a real child on the wire, the
84
+ * real cage, the real terminal.
85
+ *
86
+ * @param launch - How to launch the surface.
87
+ * @returns The deps `daemonConsole_run` uses in production.
88
+ */
89
+ export function consoleDeps_live(launch = CHELL_ON_PATH) {
90
+ return {
91
+ attach: (target) => surface_spawn(target, launch),
92
+ cage_start: consoleCage_start,
93
+ cage_stop: consoleCage_stop,
94
+ enter_wait: () => enter_await(),
95
+ log: (line) => { console.log(line); },
96
+ };
97
+ }
98
+ /**
99
+ * Holds the terminal's interrupt while a surface has it.
100
+ *
101
+ * The surface's readline owns Ctrl-C while attached (it clears the typed
102
+ * line, as chell always has); the daemon's own stop-on-interrupt is put
103
+ * back once the surface detaches, so Ctrl-C at the idle terminal stops
104
+ * the daemon as before.
105
+ *
106
+ * @returns A restore function.
107
+ */
108
+ function interrupt_hold() {
109
+ const held = process.listeners('SIGINT');
110
+ process.removeAllListeners('SIGINT');
111
+ const ignore = () => { };
112
+ process.on('SIGINT', ignore);
113
+ return () => {
114
+ process.off('SIGINT', ignore);
115
+ for (const listener of held)
116
+ process.on('SIGINT', listener);
117
+ };
118
+ }
119
+ /**
120
+ * Runs the daemon console until the operator leaves the terminal idle for
121
+ * good: attach, detach on `exit`, attach again on Enter, until stdin ends.
122
+ *
123
+ * @param target - The daemon to attach to.
124
+ * @param deps - The seams; the live ones (chell on the path) by default.
125
+ * @returns Resolves when the operator will not attach again.
126
+ */
127
+ export async function daemonConsole_run(target, deps = consoleDeps_live()) {
128
+ for (;;) {
129
+ deps.log(chalk.green(`[+] Console attached to ${target.identity} — 'exit' detaches, Enter attaches again, Ctrl-C then stops the daemon`));
130
+ deps.cage_start();
131
+ const restore = interrupt_hold();
132
+ let held;
133
+ try {
134
+ await deps.attach(target).exited;
135
+ }
136
+ finally {
137
+ restore();
138
+ held = deps.cage_stop();
139
+ }
140
+ if (held.length > 0) {
141
+ deps.log(chalk.gray('[+] While the console was attached:'));
142
+ for (const line of held)
143
+ deps.log(line);
144
+ }
145
+ deps.log(chalk.green('[+] Console detached; the daemon is still running. Enter attaches again, Ctrl-C stops the daemon.'));
146
+ if (!(await deps.enter_wait()))
147
+ return;
148
+ }
149
+ }
150
+ //# sourceMappingURL=consoleSession.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"consoleSession.js","sourceRoot":"","sources":["../../src/daemon/consoleSession.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -28,5 +28,6 @@ export { RequestBroker } from './daemon/broker.js';
28
28
  export { daemon_launch, daemonSurface_create, DaemonSink, type DaemonLaunchInfo } from './daemon/launch.js';
29
29
  export { face_start, face_boot, face_ready, face_suspend, face_resume, face_stop, face_isActive, face_frameCompose, uptime_format, FaceLogRing, type FaceInfo, type FaceTelemetry, type FaceOptions, type FaceFrame, } from './daemon/face.js';
30
30
  export { consoleCage_start, consoleCage_stop, consoleCage_isActive } from './daemon/console.js';
31
+ export { daemonConsole_run, surface_spawn, enter_await, consoleDeps_live, CHELL_ON_PATH, type DaemonConsoleTarget, type DaemonConsoleDeps, type ConsoleChild, type ConsoleInput, type Spawn, type SpawnedChild, type SurfaceLaunch, } from './daemon/consoleSession.js';
31
32
  export { discovery_read, discovery_write, discovery_path, type Discovery } from './daemon/discovery.js';
32
33
  export { identity_normalise, identity_forSession, DISCONNECTED_IDENTITY, berthKey_compute, berthDir_path, berth_path, berth_write, berth_read, berthAll_read, berth_remove, berthUrl_isAlive, LocalBerthResolver, type Berth, type BerthResolver, type BerthLivenessProbe, } from './daemon/berth.js';
package/dist/index.js CHANGED
@@ -27,6 +27,7 @@ export { RequestBroker } from './daemon/broker.js';
27
27
  export { daemon_launch, daemonSurface_create, DaemonSink } from './daemon/launch.js';
28
28
  export { face_start, face_boot, face_ready, face_suspend, face_resume, face_stop, face_isActive, face_frameCompose, uptime_format, FaceLogRing, } from './daemon/face.js';
29
29
  export { consoleCage_start, consoleCage_stop, consoleCage_isActive } from './daemon/console.js';
30
+ export { daemonConsole_run, surface_spawn, enter_await, consoleDeps_live, CHELL_ON_PATH, } from './daemon/consoleSession.js';
30
31
  export { discovery_read, discovery_write, discovery_path } from './daemon/discovery.js';
31
32
  export { identity_normalise, identity_forSession, DISCONNECTED_IDENTITY, berthKey_compute, berthDir_path, berth_path, berth_write, berth_read, berthAll_read, berth_remove, berthUrl_isAlive, LocalBerthResolver, } from './daemon/berth.js';
32
33
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACtE,OAAO,EACL,oBAAoB,EACpB,kBAAkB,EAClB,mBAAmB,EACnB,qBAAqB,EACrB,qBAAqB,GAEtB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,aAAa,EACb,mBAAmB,EACnB,oBAAoB,EACpB,qBAAqB,EACrB,uBAAuB,EACvB,sBAAsB,EACtB,mBAAmB,EACnB,qBAAqB,EACrB,mBAAmB,EACnB,mBAAmB,EACnB,mBAAmB,EACnB,uBAAuB,EACvB,kBAAkB,EAClB,mBAAmB,EACnB,kBAAkB,EAClB,oBAAoB,EACpB,qBAAqB,EACrB,oBAAoB,EACpB,kBAAkB,EAClB,mBAAmB,GAIpB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,mBAAmB,EACnB,mBAAmB,EACnB,sBAAsB,EACtB,YAAY,GAEb,MAAM,cAAc,CAAC;AAEtB,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AACnF,OAAO,EAAE,aAAa,EAAwC,MAAM,oBAAoB,CAAC;AACzF,OAAO,EACL,gBAAgB,EAChB,kBAAkB,EAClB,sBAAsB,EACtB,qBAAqB,EACrB,iBAAiB,EACjB,oBAAoB,EACpB,iBAAiB,GAIlB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,oBAAoB,EAAE,UAAU,EAAyB,MAAM,oBAAoB,CAAC;AAC5G,OAAO,EACL,UAAU,EACV,SAAS,EACT,UAAU,EACV,YAAY,EACZ,WAAW,EACX,SAAS,EACT,aAAa,EACb,iBAAiB,EACjB,aAAa,EACb,WAAW,GAKZ,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAChG,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,cAAc,EAAkB,MAAM,uBAAuB,CAAC;AACxG,OAAO,EACL,kBAAkB,EAClB,mBAAmB,EACnB,qBAAqB,EACrB,gBAAgB,EAChB,aAAa,EACb,UAAU,EACV,WAAW,EACX,UAAU,EACV,aAAa,EACb,YAAY,EACZ,gBAAgB,EAChB,kBAAkB,GAInB,MAAM,mBAAmB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACtE,OAAO,EACL,oBAAoB,EACpB,kBAAkB,EAClB,mBAAmB,EACnB,qBAAqB,EACrB,qBAAqB,GAEtB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,aAAa,EACb,mBAAmB,EACnB,oBAAoB,EACpB,qBAAqB,EACrB,uBAAuB,EACvB,sBAAsB,EACtB,mBAAmB,EACnB,qBAAqB,EACrB,mBAAmB,EACnB,mBAAmB,EACnB,mBAAmB,EACnB,uBAAuB,EACvB,kBAAkB,EAClB,mBAAmB,EACnB,kBAAkB,EAClB,oBAAoB,EACpB,qBAAqB,EACrB,oBAAoB,EACpB,kBAAkB,EAClB,mBAAmB,GAIpB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,mBAAmB,EACnB,mBAAmB,EACnB,sBAAsB,EACtB,YAAY,GAEb,MAAM,cAAc,CAAC;AAEtB,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AACnF,OAAO,EAAE,aAAa,EAAwC,MAAM,oBAAoB,CAAC;AACzF,OAAO,EACL,gBAAgB,EAChB,kBAAkB,EAClB,sBAAsB,EACtB,qBAAqB,EACrB,iBAAiB,EACjB,oBAAoB,EACpB,iBAAiB,GAIlB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,oBAAoB,EAAE,UAAU,EAAyB,MAAM,oBAAoB,CAAC;AAC5G,OAAO,EACL,UAAU,EACV,SAAS,EACT,UAAU,EACV,YAAY,EACZ,WAAW,EACX,SAAS,EACT,aAAa,EACb,iBAAiB,EACjB,aAAa,EACb,WAAW,GAKZ,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAChG,OAAO,EACL,iBAAiB,EACjB,aAAa,EACb,WAAW,EACX,gBAAgB,EAChB,aAAa,GAQd,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,cAAc,EAAkB,MAAM,uBAAuB,CAAC;AACxG,OAAO,EACL,kBAAkB,EAClB,mBAAmB,EACnB,qBAAqB,EACrB,gBAAgB,EAChB,aAAa,EACb,UAAU,EACV,WAAW,EACX,UAAU,EACV,aAAa,EACb,YAAY,EACZ,gBAAgB,EAChB,kBAAkB,GAInB,MAAM,mBAAmB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fnndsc/calypso",
3
- "version": "0.12.0",
3
+ "version": "0.13.1",
4
4
  "description": "CALYPSO: the ChRIS session daemon — hosts a brasa engine for attached surfaces over a WebSocket",
5
5
  "repository": {
6
6
  "type": "git",
@@ -51,11 +51,11 @@
51
51
  "typescript": "^5.0.0"
52
52
  },
53
53
  "dependencies": {
54
- "@fnndsc/brasa": "^0.20.0",
55
- "@fnndsc/cumin": "^3.21.0",
54
+ "@fnndsc/brasa": "^0.21.0",
55
+ "@fnndsc/cumin": "^3.21.1",
56
56
  "chalk": "^4.1.2",
57
57
  "ws": "^8.18.0",
58
58
  "zod": "^3.23.8",
59
- "@fnndsc/menu": "^0.7.0"
59
+ "@fnndsc/menu": "^0.8.0"
60
60
  }
61
61
  }