@fnndsc/calypso 0.6.1 → 0.7.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.
package/dist/calypso.js CHANGED
@@ -12,8 +12,11 @@
12
12
  */
13
13
  import { fileURLToPath } from 'node:url';
14
14
  import { realpathSync } from 'node:fs';
15
- import { engine_create, sessionConnect_fromSaved } from '@fnndsc/brasa';
15
+ import { engine_create, procIndex_snapshot, sessionConnect_fromSaved } from '@fnndsc/brasa';
16
+ import chalk from 'chalk';
16
17
  import { daemon_launch } from './daemon/launch.js';
18
+ import { face_start } from './daemon/face.js';
19
+ import { LocalBerthResolver, berthUrl_isAlive } from './daemon/berth.js';
17
20
  /**
18
21
  * Creates the engine, restores the saved session, and hosts the daemon.
19
22
  *
@@ -29,7 +32,52 @@ async function calypso_start() {
29
32
  else {
30
33
  console.error(`[!] No active session (${result.status}). Log in with 'chell' first; hosting offline.`);
31
34
  }
32
- await daemon_launch(engine);
35
+ const info = await daemon_launch(engine);
36
+ // On a TTY, the terminal's resting state is the console face; off one
37
+ // (systemd, nohup) face_start declines and logging stays sequential.
38
+ face_start({
39
+ info: [
40
+ { label: 'identity', value: info.identity },
41
+ { label: 'wire', value: info.url },
42
+ ...(info.argusUrl !== null ? [{ label: 'ARGUS', value: info.argusUrl }] : []),
43
+ { label: 'token', value: info.token },
44
+ { label: 'berth', value: info.berthPath },
45
+ { label: 'attach', value: `chell --remote --attach ${info.url} --token ${info.token}` },
46
+ ],
47
+ telemetry_get: () => {
48
+ const index = procIndex_snapshot();
49
+ return {
50
+ sessions: info.daemon.surfaces_count(),
51
+ busy: info.daemon.busy_get(),
52
+ jobs: index.jobs,
53
+ feeds: index.feeds,
54
+ };
55
+ },
56
+ });
57
+ }
58
+ /**
59
+ * Prints how to attach to each live daemon.
60
+ *
61
+ * A daemon prints its addresses once, at launch, into a terminal it then
62
+ * occupies. The facts survive in the berth — url and token, mode 0600 in the
63
+ * user's runtime directory — so they are reprinted from there rather than
64
+ * copied somewhere more convenient and less private. `/tmp` would be more
65
+ * convenient; it is also world-readable, and the token is a credential.
66
+ */
67
+ async function berths_print() {
68
+ const resolver = new LocalBerthResolver((berth) => berthUrl_isAlive(berth.url));
69
+ const berths = await resolver.list();
70
+ if (berths.length === 0) {
71
+ console.error(chalk.yellow('No CALYPSO daemon is running.'));
72
+ console.error(chalk.gray("Start one with: chell --daemon <user>@<url>"));
73
+ return;
74
+ }
75
+ for (const berth of berths) {
76
+ const web = berth.url.replace(/^ws/, 'http');
77
+ console.log(chalk.bold.cyan(berth.identity));
78
+ console.log(chalk.green(` ARGUS: ${web}/?token=${berth.token}`));
79
+ console.log(chalk.gray(` attach: chell --remote --attach ${berth.url} --token ${berth.token}`));
80
+ }
33
81
  }
34
82
  const currentFile = fileURLToPath(import.meta.url);
35
83
  let isMain = false;
@@ -40,6 +88,8 @@ catch {
40
88
  // Not invoked as a script.
41
89
  }
42
90
  if (isMain) {
43
- void calypso_start();
91
+ // One flag, not a subcommand grammar: this binary hosts a daemon, and the
92
+ // only other thing anyone needs from it is where the running ones are.
93
+ void (process.argv.includes('--berths') ? berths_print() : calypso_start());
44
94
  }
45
95
  //# sourceMappingURL=calypso.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"calypso.js","sourceRoot":"","sources":["../src/calypso.ts"],"names":[],"mappings":";AACA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,wBAAwB,EAA6C,MAAM,eAAe,CAAC;AACnH,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAEnD;;;;;GAKG;AACH,KAAK,UAAU,aAAa;IAC1B,MAAM,MAAM,GAAgB,MAAM,aAAa,EAAE,CAAC;IAElD,MAAM,MAAM,GAAuB,MAAM,wBAAwB,EAAE,CAAC;IACpE,IAAI,MAAM,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;QACjC,OAAO,CAAC,KAAK,CAAC,yBAAyB,MAAM,CAAC,OAAO,CAAC,IAAI,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IACtF,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,KAAK,CAAC,0BAA0B,MAAM,CAAC,MAAM,gDAAgD,CAAC,CAAC;IACzG,CAAC;IAED,MAAM,aAAa,CAAC,MAAM,CAAC,CAAC;AAC9B,CAAC;AAED,MAAM,WAAW,GAAW,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC3D,IAAI,MAAM,GAAY,KAAK,CAAC;AAC5B,IAAI,CAAC;IACH,MAAM,GAAG,YAAY,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,YAAY,CAAC,WAAW,CAAC,CAAC;AACvE,CAAC;AAAC,MAAM,CAAC;IACP,2BAA2B;AAC7B,CAAC;AAED,IAAI,MAAM,EAAE,CAAC;IACX,KAAK,aAAa,EAAE,CAAC;AACvB,CAAC"}
1
+ {"version":3,"file":"calypso.js","sourceRoot":"","sources":["../src/calypso.ts"],"names":[],"mappings":";AACA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,wBAAwB,EAA6C,MAAM,eAAe,CAAC;AACvI,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,aAAa,EAAyB,MAAM,oBAAoB,CAAC;AAC1E,OAAO,EAAE,UAAU,EAAsB,MAAM,kBAAkB,CAAC;AAClE,OAAO,EAAE,kBAAkB,EAAE,gBAAgB,EAAc,MAAM,mBAAmB,CAAC;AAErF;;;;;GAKG;AACH,KAAK,UAAU,aAAa;IAC1B,MAAM,MAAM,GAAgB,MAAM,aAAa,EAAE,CAAC;IAElD,MAAM,MAAM,GAAuB,MAAM,wBAAwB,EAAE,CAAC;IACpE,IAAI,MAAM,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;QACjC,OAAO,CAAC,KAAK,CAAC,yBAAyB,MAAM,CAAC,OAAO,CAAC,IAAI,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IACtF,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,KAAK,CAAC,0BAA0B,MAAM,CAAC,MAAM,gDAAgD,CAAC,CAAC;IACzG,CAAC;IAED,MAAM,IAAI,GAAqB,MAAM,aAAa,CAAC,MAAM,CAAC,CAAC;IAC3D,sEAAsE;IACtE,qEAAqE;IACrE,UAAU,CAAC;QACT,IAAI,EAAE;YACJ,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,IAAI,CAAC,QAAQ,EAAE;YAC3C,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,CAAC,GAAG,EAAE;YAClC,GAAG,CAAC,IAAI,CAAC,QAAQ,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YAC7E,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE;YACrC,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,SAAS,EAAE;YACzC,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,2BAA2B,IAAI,CAAC,GAAG,YAAY,IAAI,CAAC,KAAK,EAAE,EAAE;SACxF;QACD,aAAa,EAAE,GAAkB,EAAE;YACjC,MAAM,KAAK,GAAoC,kBAAkB,EAAE,CAAC;YACpE,OAAO;gBACL,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,cAAc,EAAE;gBACtC,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE;gBAC5B,IAAI,EAAE,KAAK,CAAC,IAAI;gBAChB,KAAK,EAAE,KAAK,CAAC,KAAK;aACnB,CAAC;QACJ,CAAC;KACF,CAAC,CAAC;AACL,CAAC;AAED;;;;;;;;GAQG;AACH,KAAK,UAAU,YAAY;IACzB,MAAM,QAAQ,GAAuB,IAAI,kBAAkB,CACzD,CAAC,KAAY,EAAoB,EAAE,CAAC,gBAAgB,CAAC,KAAK,CAAC,GAAG,CAAC,CAChE,CAAC;IACF,MAAM,MAAM,GAAY,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;IAC9C,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,+BAA+B,CAAC,CAAC,CAAC;QAC7D,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,8CAA8C,CAAC,CAAC,CAAC;QAC1E,OAAO;IACT,CAAC;IACD,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,GAAG,GAAW,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;QACrD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC;QAC7C,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,cAAc,GAAG,WAAW,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;QACpE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,sCAAsC,KAAK,CAAC,GAAG,YAAY,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;IACpG,CAAC;AACH,CAAC;AAED,MAAM,WAAW,GAAW,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC3D,IAAI,MAAM,GAAY,KAAK,CAAC;AAC5B,IAAI,CAAC;IACH,MAAM,GAAG,YAAY,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,YAAY,CAAC,WAAW,CAAC,CAAC;AACvE,CAAC;AAAC,MAAM,CAAC;IACP,2BAA2B;AAC7B,CAAC;AAED,IAAI,MAAM,EAAE,CAAC;IACX,0EAA0E;IAC1E,uEAAuE;IACvE,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,aAAa,EAAE,CAAC,CAAC;AAC9E,CAAC"}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * @file The attach note: a daemon's addresses, written where they can be read.
3
+ *
4
+ * A daemon prints its ARGUS link and attach command once, into a terminal it
5
+ * then occupies with a live boot animation. Selecting text out from under a
6
+ * repainting screen is awkward, and scrollback is lost the moment anyone
7
+ * clears it — so the same lines are also written to a file.
8
+ *
9
+ * The file carries the attach token, which is a credential, and `/tmp` is
10
+ * world-readable. Three things follow, and none is optional:
11
+ *
12
+ * * it is created `0600`, so the mode rather than the directory protects it;
13
+ * * it is created exclusively (`wx`), so a symlink planted at the path by
14
+ * another user makes the write fail rather than land somewhere chosen by
15
+ * them; and
16
+ * * it is removed when the daemon exits, so a dead session's token does not
17
+ * linger.
18
+ *
19
+ * `calypso --berths` reads the same facts from the berth, which is `0600` in
20
+ * the user's own runtime directory. That remains the safer route; this one is
21
+ * the convenient one.
22
+ *
23
+ * @module
24
+ */
25
+ /**
26
+ * The path this daemon's attach note occupies.
27
+ *
28
+ * Per OS user rather than per session, so it can be named in a message and
29
+ * found again without reading one. A second daemon for a second CUBE identity
30
+ * overwrites it; `calypso --berths` lists them all.
31
+ *
32
+ * @returns An absolute path in the system temporary directory.
33
+ */
34
+ export declare function attachFile_path(): string;
35
+ /**
36
+ * Writes the attach note, replacing any note this user left before.
37
+ *
38
+ * @param lines - The addresses to record, one per line.
39
+ * @returns The path written, or null when it could not be written safely.
40
+ */
41
+ export declare function attachFile_write(lines: string[]): string | null;
42
+ /** Removes the attach note, so a dead session's token does not linger. */
43
+ export declare function attachFile_remove(): void;
@@ -0,0 +1,80 @@
1
+ /**
2
+ * @file The attach note: a daemon's addresses, written where they can be read.
3
+ *
4
+ * A daemon prints its ARGUS link and attach command once, into a terminal it
5
+ * then occupies with a live boot animation. Selecting text out from under a
6
+ * repainting screen is awkward, and scrollback is lost the moment anyone
7
+ * clears it — so the same lines are also written to a file.
8
+ *
9
+ * The file carries the attach token, which is a credential, and `/tmp` is
10
+ * world-readable. Three things follow, and none is optional:
11
+ *
12
+ * * it is created `0600`, so the mode rather than the directory protects it;
13
+ * * it is created exclusively (`wx`), so a symlink planted at the path by
14
+ * another user makes the write fail rather than land somewhere chosen by
15
+ * them; and
16
+ * * it is removed when the daemon exits, so a dead session's token does not
17
+ * linger.
18
+ *
19
+ * `calypso --berths` reads the same facts from the berth, which is `0600` in
20
+ * the user's own runtime directory. That remains the safer route; this one is
21
+ * the convenient one.
22
+ *
23
+ * @module
24
+ */
25
+ import { chmodSync, openSync, writeSync, closeSync, rmSync } from 'node:fs';
26
+ import { tmpdir } from 'node:os';
27
+ import { join } from 'node:path';
28
+ import { userInfo } from 'node:os';
29
+ /**
30
+ * The path this daemon's attach note occupies.
31
+ *
32
+ * Per OS user rather than per session, so it can be named in a message and
33
+ * found again without reading one. A second daemon for a second CUBE identity
34
+ * overwrites it; `calypso --berths` lists them all.
35
+ *
36
+ * @returns An absolute path in the system temporary directory.
37
+ */
38
+ export function attachFile_path() {
39
+ return join(tmpdir(), `calypso-${userInfo().username}.attach`);
40
+ }
41
+ /**
42
+ * Writes the attach note, replacing any note this user left before.
43
+ *
44
+ * @param lines - The addresses to record, one per line.
45
+ * @returns The path written, or null when it could not be written safely.
46
+ */
47
+ export function attachFile_write(lines) {
48
+ const path = attachFile_path();
49
+ try {
50
+ // Remove our own stale note first, then create exclusively: if anything
51
+ // reappears at the path in between, the create fails rather than writing
52
+ // through whatever is there.
53
+ rmSync(path, { force: true });
54
+ const handle = openSync(path, 'wx', 0o600);
55
+ try {
56
+ writeSync(handle, `${lines.join('\n')}\n`);
57
+ }
58
+ finally {
59
+ closeSync(handle);
60
+ }
61
+ // openSync's mode is subject to umask; set it outright.
62
+ chmodSync(path, 0o600);
63
+ return path;
64
+ }
65
+ catch {
66
+ // A note is a convenience. Failing to write one must never stop a daemon
67
+ // from starting, and the addresses were printed regardless.
68
+ return null;
69
+ }
70
+ }
71
+ /** Removes the attach note, so a dead session's token does not linger. */
72
+ export function attachFile_remove() {
73
+ try {
74
+ rmSync(attachFile_path(), { force: true });
75
+ }
76
+ catch {
77
+ // Nothing useful to say at exit about a file that may already be gone.
78
+ }
79
+ }
80
+ //# sourceMappingURL=attachFile.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attachFile.js","sourceRoot":"","sources":["../../src/daemon/attachFile.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAC5E,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC;;;;;;;;GAQG;AACH,MAAM,UAAU,eAAe;IAC7B,OAAO,IAAI,CAAC,MAAM,EAAE,EAAE,WAAW,QAAQ,EAAE,CAAC,QAAQ,SAAS,CAAC,CAAC;AACjE,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAe;IAC9C,MAAM,IAAI,GAAW,eAAe,EAAE,CAAC;IACvC,IAAI,CAAC;QACH,wEAAwE;QACxE,yEAAyE;QACzE,6BAA6B;QAC7B,MAAM,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QAC9B,MAAM,MAAM,GAAW,QAAQ,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;QACnD,IAAI,CAAC;YACH,SAAS,CAAC,MAAM,EAAE,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC7C,CAAC;gBAAS,CAAC;YACT,SAAS,CAAC,MAAM,CAAC,CAAC;QACpB,CAAC;QACD,wDAAwD;QACxD,SAAS,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QACvB,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,yEAAyE;QACzE,4DAA4D;QAC5D,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,0EAA0E;AAC1E,MAAM,UAAU,iBAAiB;IAC/B,IAAI,CAAC;QACH,MAAM,CAAC,eAAe,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAC7C,CAAC;IAAC,MAAM,CAAC;QACP,uEAAuE;IACzE,CAAC;AACH,CAAC"}
@@ -11,6 +11,7 @@
11
11
  * @module
12
12
  */
13
13
  import type { CommandEnvelope } from '@fnndsc/cumin';
14
+ import type { Regard } from '@fnndsc/menu';
14
15
  /**
15
16
  * A completion answer: the candidates and the prefix they complete.
16
17
  *
@@ -58,4 +59,19 @@ export interface HostedEngine {
58
59
  * @returns The file's bytes.
59
60
  */
60
61
  file_read?(filePath: string): Promise<Buffer>;
62
+ /**
63
+ * Notes a regard write relayed from a surface, retaining it as session
64
+ * truth engine-side. Optional: a daemon still retains and rebroadcasts
65
+ * regard on the wire without it.
66
+ *
67
+ * @param regard - The indicated address with its provenance.
68
+ */
69
+ regard_note?(regard: Regard): void;
70
+ /**
71
+ * Returns the engine's retained regard, or null before the first
72
+ * indication.
73
+ *
74
+ * @returns The retained regard, or null.
75
+ */
76
+ regard_get?(): Regard | null;
61
77
  }
@@ -0,0 +1,127 @@
1
+ /** One labeled fact shown on the face's identity panel. */
2
+ export interface FaceInfo {
3
+ label: string;
4
+ value: string;
5
+ }
6
+ /** Live daemon readings the face polls once per frame. */
7
+ export interface FaceTelemetry {
8
+ /** Attached surfaces right now. */
9
+ sessions: number;
10
+ /** Whether a foreground command is executing. */
11
+ busy: boolean;
12
+ /** Jobs the proc index holds. */
13
+ jobs: number;
14
+ /** Feeds the proc index holds. */
15
+ feeds: number;
16
+ }
17
+ /** What the face needs from its host. */
18
+ export interface FaceOptions {
19
+ /** Identity panel rows: identity, wire, web surface, token, berth. */
20
+ info: FaceInfo[];
21
+ /** Live readings; omitted readings render as an idle daemon. */
22
+ telemetry_get?: () => FaceTelemetry;
23
+ }
24
+ /**
25
+ * A bounded line buffer for output arriving while the face owns the screen.
26
+ *
27
+ * Everything a stray `console.log` (a retry warning, a background sweep
28
+ * report) writes is caged here: the newest lines feed the face's strip, and
29
+ * the whole run since the last flush is replayed into the normal buffer when
30
+ * the operator drops to text — so nothing is ever lost, only re-homed.
31
+ */
32
+ export declare class FaceLogRing {
33
+ private lines;
34
+ private pending;
35
+ private unflushed;
36
+ /**
37
+ * Absorbs one raw write, splitting it into stripped, stored lines.
38
+ *
39
+ * A carriage return without a newline is a redraw (a spinner frame): it
40
+ * discards what preceded it on the line rather than appending, so a
41
+ * thousand frames stay one line, not one enormous one.
42
+ *
43
+ * @param chunk - The text a hijacked stdout/stderr write carried.
44
+ */
45
+ push(chunk: string): void;
46
+ /**
47
+ * The newest lines, for the face's log strip.
48
+ *
49
+ * @param count - How many lines the strip shows.
50
+ * @returns Up to `count` lines, oldest first.
51
+ */
52
+ tail(count: number): string[];
53
+ /**
54
+ * Returns and forgets the lines not yet replayed into the normal buffer.
55
+ *
56
+ * @returns The unflushed lines, oldest first.
57
+ */
58
+ drain(): string[];
59
+ }
60
+ /** Everything the pure composer needs to draw one frame. */
61
+ export interface FaceFrame {
62
+ rows: number;
63
+ columns: number;
64
+ frameIndex: number;
65
+ /** 'boot': frenetic pulse over the streaming boot log; 'ready': the steady instrument. */
66
+ phase: 'boot' | 'ready';
67
+ info: FaceInfo[];
68
+ telemetry: FaceTelemetry | null;
69
+ logTail: string[];
70
+ uptimeSeconds: number;
71
+ }
72
+ /**
73
+ * Formats an uptime as `2d 03:14:07` / `03:14:07`.
74
+ *
75
+ * @param seconds - Whole seconds since the daemon came up.
76
+ * @returns The formatted uptime.
77
+ */
78
+ export declare function uptime_format(seconds: number): string;
79
+ /**
80
+ * Composes one face frame as screen lines, top to bottom. Pure: no terminal
81
+ * control, no timers — the runtime places these under the alternate buffer
82
+ * and the tests read them directly.
83
+ *
84
+ * @param frame - The readings and geometry for this frame.
85
+ * @returns The lines to paint, at most `frame.rows - 1` of them.
86
+ */
87
+ export declare function face_frameCompose(frame: FaceFrame): string[];
88
+ /** Whether the console face currently owns the terminal. */
89
+ export declare function face_isActive(): boolean;
90
+ /**
91
+ * Takes the daemon terminal over as the console face.
92
+ *
93
+ * A no-op off a TTY (systemd, nohup, a pipe): the daemon then logs
94
+ * sequentially exactly as before.
95
+ *
96
+ * @param options - Identity rows and live-telemetry hook.
97
+ * @returns True when the face took the screen.
98
+ */
99
+ export declare function face_start(options: FaceOptions, phase?: 'boot' | 'ready'): boolean;
100
+ /**
101
+ * Takes the terminal over for the boot phase: the brain in its frenetic
102
+ * boot pulse over a tall strip of the streaming boot log — no identity
103
+ * panel yet, because there is nothing to identify. A no-op off a TTY.
104
+ *
105
+ * @returns True when the boot face took the screen.
106
+ */
107
+ export declare function face_boot(): boolean;
108
+ /**
109
+ * Settles the face into its steady state: the calm ambient pulse, the
110
+ * identity panel, live telemetry, and the toggle hint. Called on a face
111
+ * already up (the boot phase) it repaints in place; called with no face
112
+ * (a host that skipped the boot phase) it starts one. Off a TTY, nothing.
113
+ *
114
+ * @param options - Identity rows and live-telemetry hook.
115
+ * @returns True when a face is showing the steady state.
116
+ */
117
+ export declare function face_ready(options: FaceOptions): boolean;
118
+ /**
119
+ * Steps aside for an interactive prompt: the terminal returns to the
120
+ * normal buffer with cooked stdin, and the face's key handler stops
121
+ * listening so the prompt's readline owns every keystroke.
122
+ */
123
+ export declare function face_suspend(): void;
124
+ /** Returns from a prompt: raw keys again, and back onto the face. */
125
+ export declare function face_resume(): void;
126
+ /** Releases the terminal entirely: buffers, writes, raw mode, listeners. */
127
+ export declare function face_stop(): void;