@invinite-org/invinite-data-cli 0.1.22 → 0.2.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.
Files changed (51) hide show
  1. package/README.md +321 -6
  2. package/claude-plugin/.claude-plugin/plugin.json +2 -2
  3. package/claude-plugin/agents/invinite-data.md +5 -1
  4. package/claude-plugin/commands/analyze-earnings-call.md +24 -0
  5. package/claude-plugin/commands/financial-research.md +2 -1
  6. package/claude-plugin/skills/invinite-data-cli/SKILL.md +91 -1
  7. package/dist/src/cli.d.ts +2 -0
  8. package/dist/src/cli.js +22 -1
  9. package/dist/src/cli.js.map +1 -1
  10. package/dist/src/client/api-client.d.ts +13 -1
  11. package/dist/src/client/api-client.js +46 -13
  12. package/dist/src/client/api-client.js.map +1 -1
  13. package/dist/src/client/download.d.ts +23 -0
  14. package/dist/src/client/download.js +116 -0
  15. package/dist/src/client/download.js.map +1 -0
  16. package/dist/src/client/earnings-live.d.ts +156 -0
  17. package/dist/src/client/earnings-live.js +270 -0
  18. package/dist/src/client/earnings-live.js.map +1 -0
  19. package/dist/src/client/pagination.js +2 -1
  20. package/dist/src/client/pagination.js.map +1 -1
  21. package/dist/src/client/websocket-client.d.ts +14 -1
  22. package/dist/src/client/websocket-client.js +118 -37
  23. package/dist/src/client/websocket-client.js.map +1 -1
  24. package/dist/src/commands/earnings-selector.d.ts +15 -0
  25. package/dist/src/commands/earnings-selector.js +29 -0
  26. package/dist/src/commands/earnings-selector.js.map +1 -0
  27. package/dist/src/commands/earnings.d.ts +13 -0
  28. package/dist/src/commands/earnings.js +705 -0
  29. package/dist/src/commands/earnings.js.map +1 -0
  30. package/dist/src/commands/plugin.d.ts +11 -0
  31. package/dist/src/commands/plugin.js +23 -8
  32. package/dist/src/commands/plugin.js.map +1 -1
  33. package/dist/src/commands/webhooks.d.ts +16 -0
  34. package/dist/src/commands/webhooks.js +186 -0
  35. package/dist/src/commands/webhooks.js.map +1 -0
  36. package/dist/src/commands/ws.d.ts +18 -0
  37. package/dist/src/commands/ws.js +57 -3
  38. package/dist/src/commands/ws.js.map +1 -1
  39. package/dist/src/formatters/flatten.d.ts +4 -0
  40. package/dist/src/formatters/flatten.js +15 -0
  41. package/dist/src/formatters/flatten.js.map +1 -0
  42. package/dist/src/formatters/time.d.ts +2 -0
  43. package/dist/src/formatters/time.js +14 -0
  44. package/dist/src/formatters/time.js.map +1 -0
  45. package/dist/src/shared/errors.d.ts +2 -1
  46. package/dist/src/shared/errors.js +5 -1
  47. package/dist/src/shared/errors.js.map +1 -1
  48. package/dist/src/shared/options.d.ts +2 -0
  49. package/dist/src/shared/options.js +6 -0
  50. package/dist/src/shared/options.js.map +1 -1
  51. package/package.json +1 -1
@@ -1,6 +1,18 @@
1
1
  export interface RequestOptions {
2
2
  path: string;
3
- params?: Record<string, string | undefined>;
3
+ /** An array value is sent as a repeated parameter (`status=a&status=b`). */
4
+ params?: Record<string, string | string[] | undefined>;
4
5
  silent?: boolean;
5
6
  }
7
+ /** Same auth / URL building as `apiGet`, without the JSON parse; a non-2xx throws `ApiError`. */
8
+ export declare function apiGetRaw(opts: RequestOptions & {
9
+ accept?: string;
10
+ }): Promise<Response>;
6
11
  export declare function apiGet<T = unknown>(opts: RequestOptions): Promise<T>;
12
+ export interface ApiRequestOptions extends RequestOptions {
13
+ method: 'POST' | 'PUT' | 'PATCH' | 'DELETE';
14
+ /** Sent as JSON. */
15
+ body?: unknown;
16
+ }
17
+ /** A write with a JSON body; same auth / `ApiError` handling as `apiGet`. A 204 / empty body → `undefined`. */
18
+ export declare function apiRequest<T = unknown>(opts: ApiRequestOptions): Promise<T>;
@@ -7,28 +7,47 @@ function buildUrl(path, params) {
7
7
  const url = new URL(`${base}${path}`);
8
8
  if (params) {
9
9
  for (const [key, value] of Object.entries(params)) {
10
- if (value !== undefined && value !== '') {
11
- url.searchParams.set(key, value);
10
+ for (const item of Array.isArray(value) ? value : [value]) {
11
+ if (item !== undefined && item !== '') {
12
+ url.searchParams.append(key, item);
13
+ }
12
14
  }
13
15
  }
14
16
  }
15
17
  return url.toString();
16
18
  }
19
+ async function apiErrorFrom(response) {
20
+ const body = await response.json().catch(() => null);
21
+ return new ApiError(response.status, body?.error || response.statusText || 'Unknown Error', body?.message || `Request failed with status ${response.status}`);
22
+ }
23
+ async function request(opts, accept, init = {}) {
24
+ const apiKey = await getApiKey();
25
+ const url = buildUrl(opts.path, opts.params);
26
+ const headers = {
27
+ 'Authorization': `Bearer ${apiKey}`,
28
+ 'Accept': accept,
29
+ };
30
+ if (init.body !== undefined)
31
+ headers['Content-Type'] = 'application/json';
32
+ const response = await fetch(url, {
33
+ headers,
34
+ ...(init.method ? { method: init.method } : {}),
35
+ ...(init.body !== undefined ? { body: JSON.stringify(init.body) } : {}),
36
+ });
37
+ if (!response.ok) {
38
+ throw await apiErrorFrom(response);
39
+ }
40
+ return response;
41
+ }
42
+ /** Same auth / URL building as `apiGet`, without the JSON parse; a non-2xx throws `ApiError`. */
43
+ export async function apiGetRaw(opts) {
44
+ return request(opts, opts.accept ?? '*/*');
45
+ }
17
46
  export async function apiGet(opts) {
18
47
  const spinner = opts.silent ? null : createSpinner('Fetching data...');
19
48
  try {
20
- const apiKey = await getApiKey();
21
- const url = buildUrl(opts.path, opts.params);
22
- const response = await fetch(url, {
23
- headers: {
24
- 'Authorization': `Bearer ${apiKey}`,
25
- 'Accept': 'application/json',
26
- },
27
- });
49
+ const response = await request(opts, 'application/json');
28
50
  const body = await response.json();
29
- if (!response.ok) {
30
- throw new ApiError(response.status, body?.error || 'Unknown Error', body?.message || `Request failed with status ${response.status}`);
31
- }
32
51
  spinner?.succeed('Done');
33
52
  return body;
34
53
  }
@@ -37,4 +56,18 @@ export async function apiGet(opts) {
37
56
  throw error;
38
57
  }
39
58
  }
59
+ /** A write with a JSON body; same auth / `ApiError` handling as `apiGet`. A 204 / empty body → `undefined`. */
60
+ export async function apiRequest(opts) {
61
+ const spinner = opts.silent ? null : createSpinner('Sending request...');
62
+ try {
63
+ const response = await request(opts, 'application/json', { method: opts.method, body: opts.body });
64
+ const text = response.status === 204 ? '' : await response.text();
65
+ spinner?.succeed('Done');
66
+ return (text ? JSON.parse(text) : undefined);
67
+ }
68
+ catch (error) {
69
+ spinner?.fail('Failed');
70
+ throw error;
71
+ }
72
+ }
40
73
  //# sourceMappingURL=api-client.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"api-client.js","sourceRoot":"","sources":["../../../src/client/api-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AACzD,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAQrD,SAAS,QAAQ,CAAC,IAAY,EAAE,MAA2C;IACzE,MAAM,IAAI,GAAG,UAAU,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAC9C,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,IAAI,GAAG,IAAI,EAAE,CAAC,CAAC;IACtC,IAAI,MAAM,EAAE,CAAC;QACX,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;YAClD,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,EAAE,EAAE,CAAC;gBACxC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;YACnC,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC,QAAQ,EAAE,CAAC;AACxB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,MAAM,CAAc,IAAoB;IAC5D,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,aAAa,CAAC,kBAAkB,CAAC,CAAC;IACvE,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,SAAS,EAAE,CAAC;QACjC,MAAM,GAAG,GAAG,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;QAC7C,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;YAChC,OAAO,EAAE;gBACP,eAAe,EAAE,UAAU,MAAM,EAAE;gBACnC,QAAQ,EAAE,kBAAkB;aAC7B;SACF,CAAC,CAAC;QAEH,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAS,CAAC;QAE1C,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,IAAI,QAAQ,CAChB,QAAQ,CAAC,MAAM,EACf,IAAI,EAAE,KAAK,IAAI,eAAe,EAC9B,IAAI,EAAE,OAAO,IAAI,8BAA8B,QAAQ,CAAC,MAAM,EAAE,CACjE,CAAC;QACJ,CAAC;QAED,OAAO,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;QACzB,OAAO,IAAS,CAAC;IACnB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;QACxB,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"api-client.js","sourceRoot":"","sources":["../../../src/client/api-client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ export interface SaveOptions {
2
+ /** Replace an existing file. */
3
+ force?: boolean;
4
+ }
5
+ /**
6
+ * Streams a presigned URL to disk. Plain fetch: NO Authorization header — the URL is a
7
+ * bearer URL and R2 would reject the extra header. Written through `writeViaPart`.
8
+ */
9
+ export declare function downloadToFile(url: string, file: string, opts?: SaveOptions & {
10
+ spinnerText?: string;
11
+ }): Promise<{
12
+ path: string;
13
+ bytes: number;
14
+ }>;
15
+ /** Writes text (transcript, press release) to `file`; refuses an existing target unless `force`. */
16
+ export declare function writeTextFile(file: string, text: string, opts?: SaveOptions): Promise<{
17
+ path: string;
18
+ bytes: number;
19
+ }>;
20
+ /** `mkdir -p` of a directory target (`documents --output dir/`); returns its absolute path. */
21
+ export declare function ensureDir(dir: string): Promise<string>;
22
+ /** File extension for a `content_type` (parameters ignored); `bin` when unknown. */
23
+ export declare function extensionFor(contentType: string | null | undefined): string;
@@ -0,0 +1,116 @@
1
+ import { createWriteStream, rmSync } from 'node:fs';
2
+ import { access, mkdir, rename, rm, stat, writeFile } from 'node:fs/promises';
3
+ import { dirname, resolve } from 'node:path';
4
+ import { Readable } from 'node:stream';
5
+ import { pipeline } from 'node:stream/promises';
6
+ import { createSpinner } from '../shared/spinner.js';
7
+ async function exists(path) {
8
+ try {
9
+ await access(path);
10
+ return true;
11
+ }
12
+ catch {
13
+ return false;
14
+ }
15
+ }
16
+ /** Resolves `file` against cwd and refuses an existing target unless `force`. */
17
+ async function prepareTarget(file, opts) {
18
+ const path = resolve(file);
19
+ if (!opts.force && await exists(path)) {
20
+ throw new Error(`${path} already exists (use --force to overwrite)`);
21
+ }
22
+ await mkdir(dirname(path), { recursive: true });
23
+ return path;
24
+ }
25
+ /** Exit codes of the signals that abort a write (128 + signal number, as a shell reports them). */
26
+ const ABORT_SIGNALS = { SIGINT: 130, SIGTERM: 143 };
27
+ /**
28
+ * Runs `write(part, signal)` against `<path>.part` and renames it onto `path` on success, so a
29
+ * failed write never leaves a partial file or clobbers an existing one. While it runs, SIGINT /
30
+ * SIGTERM (Ctrl-C) abort `signal`, remove the `.part` file synchronously and exit with 130 / 143 —
31
+ * a listener replaces Node's default exit, which would skip the cleanup.
32
+ */
33
+ async function writeViaPart(path, write) {
34
+ const part = `${path}.part`;
35
+ const controller = new AbortController();
36
+ const onSignal = (signal) => {
37
+ controller.abort();
38
+ rmSync(part, { force: true });
39
+ process.exit(ABORT_SIGNALS[signal]);
40
+ };
41
+ for (const signal of Object.keys(ABORT_SIGNALS))
42
+ process.once(signal, onSignal);
43
+ try {
44
+ await write(part, controller.signal);
45
+ await rename(part, path);
46
+ }
47
+ catch (error) {
48
+ await rm(part, { force: true });
49
+ throw error;
50
+ }
51
+ finally {
52
+ for (const signal of Object.keys(ABORT_SIGNALS))
53
+ process.off(signal, onSignal);
54
+ }
55
+ }
56
+ /**
57
+ * Streams a presigned URL to disk. Plain fetch: NO Authorization header — the URL is a
58
+ * bearer URL and R2 would reject the extra header. Written through `writeViaPart`.
59
+ */
60
+ export async function downloadToFile(url, file, opts = {}) {
61
+ const path = await prepareTarget(file, opts);
62
+ const spinner = createSpinner(opts.spinnerText ?? 'Downloading...');
63
+ try {
64
+ await writeViaPart(path, async (part, signal) => {
65
+ const response = await fetch(url, { signal });
66
+ if (!response.ok || !response.body) {
67
+ throw new Error(`Download failed with status ${response.status}`);
68
+ }
69
+ await pipeline(Readable.fromWeb(response.body), createWriteStream(part), { signal });
70
+ });
71
+ const { size } = await stat(path);
72
+ spinner.succeed('Downloaded');
73
+ return { path, bytes: size };
74
+ }
75
+ catch (error) {
76
+ spinner.fail('Download failed');
77
+ throw error;
78
+ }
79
+ }
80
+ /** Writes text (transcript, press release) to `file`; refuses an existing target unless `force`. */
81
+ export async function writeTextFile(file, text, opts = {}) {
82
+ const path = await prepareTarget(file, opts);
83
+ await writeViaPart(path, (part, signal) => writeFile(part, text, { encoding: 'utf8', signal }));
84
+ return { path, bytes: Buffer.byteLength(text, 'utf8') };
85
+ }
86
+ /** `mkdir -p` of a directory target (`documents --output dir/`); returns its absolute path. */
87
+ export async function ensureDir(dir) {
88
+ const path = resolve(dir);
89
+ await mkdir(path, { recursive: true });
90
+ return path;
91
+ }
92
+ const EXTENSIONS = {
93
+ 'application/pdf': 'pdf',
94
+ 'text/html': 'html',
95
+ 'text/plain': 'txt',
96
+ 'text/csv': 'csv',
97
+ 'application/json': 'json',
98
+ 'application/xml': 'xml',
99
+ 'text/xml': 'xml',
100
+ 'application/vnd.openxmlformats-officedocument.wordprocessingml.document': 'docx',
101
+ 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': 'xlsx',
102
+ 'application/vnd.openxmlformats-officedocument.presentationml.presentation': 'pptx',
103
+ 'application/msword': 'doc',
104
+ 'application/vnd.ms-excel': 'xls',
105
+ 'application/vnd.ms-powerpoint': 'ppt',
106
+ 'image/png': 'png',
107
+ 'image/jpeg': 'jpg',
108
+ 'image/gif': 'gif',
109
+ 'audio/mpeg': 'mp3',
110
+ };
111
+ /** File extension for a `content_type` (parameters ignored); `bin` when unknown. */
112
+ export function extensionFor(contentType) {
113
+ const type = (contentType ?? '').split(';')[0].trim().toLowerCase();
114
+ return EXTENSIONS[type] ?? 'bin';
115
+ }
116
+ //# sourceMappingURL=download.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"download.js","sourceRoot":"","sources":["../../../src/client/download.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,156 @@
1
+ /**
2
+ * Pure pieces of `invd ws listen --earnings`: the subscribe frame and one step per server
3
+ * frame of IDA's `earnings-calls.live` channel (`src/routes/websocket/types/earningsMessages.ts`).
4
+ */
5
+ export declare const EARNINGS_LIVE_CHANNEL = "earnings-calls.live";
6
+ /** One call (event ID / CIK), or every live call at once (`scope: "all_live"`, keywords required). */
7
+ export type LiveTarget = {
8
+ event_id: string;
9
+ } | {
10
+ cik: string;
11
+ } | {
12
+ scope: 'all_live';
13
+ };
14
+ export declare const KEYWORD_MATCH_MODES: readonly ["exact", "stem"];
15
+ export type KeywordMatch = (typeof KEYWORD_MATCH_MODES)[number];
16
+ export declare const SPEAKER_ROLES: readonly ["executive", "ir_host", "analyst", "operator"];
17
+ export type SpeakerRole = (typeof SPEAKER_ROLES)[number];
18
+ /** Keyword alerts of the subscribe frame (`keywords` required for the global scope). */
19
+ export interface KeywordOptions {
20
+ keywords: string[];
21
+ keywordMatch?: KeywordMatch;
22
+ speakerRoles?: SpeakerRole[];
23
+ /** Global scope only: companies ranked ≤ N by market cap. */
24
+ minRank?: number;
25
+ }
26
+ export interface KeywordHit {
27
+ cik: string;
28
+ symbol: string;
29
+ conference_date: string;
30
+ keyword: string;
31
+ seq: number;
32
+ start_ms: number;
33
+ end_ms: number;
34
+ text: string;
35
+ context_before: string;
36
+ speaker_label: string | null;
37
+ speaker_name: string | null;
38
+ speaker_role: string | null;
39
+ layer: 'live' | 'final';
40
+ latency_ms: number;
41
+ }
42
+ export interface GuidanceFlash {
43
+ symbol: string;
44
+ conference_date: string;
45
+ seq: number;
46
+ revision: number;
47
+ metric: string;
48
+ metric_normalized: string | null;
49
+ period_label: string | null;
50
+ low: number | null;
51
+ high: number | null;
52
+ point: number | null;
53
+ unit: string | null;
54
+ currency: string | null;
55
+ source_sentence: string;
56
+ start_ms: number;
57
+ }
58
+ export interface SpeakerAssignment {
59
+ speaker_label: string;
60
+ from_seq: number;
61
+ to_seq: number | null;
62
+ name: string;
63
+ role?: string;
64
+ title?: string | null;
65
+ firm?: string | null;
66
+ }
67
+ export interface LiveSegment {
68
+ seq: number;
69
+ start_ms: number;
70
+ speaker_label: string | null;
71
+ text: string;
72
+ is_final: boolean;
73
+ }
74
+ export interface LiveState {
75
+ /** Highest final seq printed (or the `since_seq` asked for): a reconnect resumes after it. */
76
+ lastSeq: number;
77
+ eventId: string | null;
78
+ names: {
79
+ revision: number;
80
+ assignments: SpeakerAssignment[];
81
+ } | null;
82
+ }
83
+ export interface LiveOptions {
84
+ partials: boolean;
85
+ names: boolean;
86
+ /** Global scope: every hit line names its company. */
87
+ allLive?: boolean;
88
+ }
89
+ export interface LiveStep {
90
+ state: LiveState;
91
+ lines: string[];
92
+ /** A partial to show in place of the previous one (TTY only). */
93
+ partial?: string;
94
+ /** Stop: exit code + a closing line. */
95
+ end?: {
96
+ code: 0 | 1;
97
+ message: string;
98
+ };
99
+ /** Close the socket and resubscribe through the backoff. */
100
+ reconnect?: boolean;
101
+ }
102
+ /** `--earnings`: a UUID is an event_id, 1–10 digits a CIK. */
103
+ export declare function parseTarget(value: string): LiveTarget;
104
+ /** `--since-seq`: an integer ≥ -1; default -1 (the whole call from its first final). */
105
+ export declare function parseSinceSeq(value: string | undefined): number;
106
+ /** `--keywords`: 1–20 keywords of 2–64 characters (the API's limits), trimmed and de-duplicated. */
107
+ export declare function parseKeywords(value: string | undefined): string[];
108
+ /** `--keyword-match`: `exact` (default) or `stem`. */
109
+ export declare function parseKeywordMatch(value: string | undefined): KeywordMatch | undefined;
110
+ /** `--speaker-roles`: a comma-separated subset of executive, ir_host, analyst, operator. */
111
+ export declare function parseSpeakerRoles(value: string | undefined): SpeakerRole[] | undefined;
112
+ /** `--min-rank`: a positive integer (market-cap rank). */
113
+ export declare function parseMinRank(value: string | undefined): number | undefined;
114
+ export declare function isAllLive(target: LiveTarget): target is {
115
+ scope: 'all_live';
116
+ };
117
+ /** What a global subscription receives (the API defaults to keyword hits only; `ws listen` wants the flashes too). */
118
+ export declare const ALL_LIVE_EVENTS: readonly ["keyword_hit", "guidance_flash"];
119
+ /**
120
+ * The subscribe frame. One call: target + `since_seq` + `partials`. Global scope: `scope: "all_live"`
121
+ * carries no call target, no replay and no partials — only the keyword fields (the API refuses it
122
+ * without keywords, and so does `ws listen`) and `events` = keyword hits + guidance flashes.
123
+ */
124
+ export declare function subscribeFrame(target: LiveTarget, sinceSeq: number, partials: boolean, keywords?: KeywordOptions): {
125
+ min_rank?: number | undefined;
126
+ events: ("keyword_hit" | "guidance_flash")[];
127
+ type: string;
128
+ channel: string;
129
+ scope: string;
130
+ } | {
131
+ since_seq: number;
132
+ partials: boolean;
133
+ event_id: string;
134
+ type: string;
135
+ channel: string;
136
+ } | {
137
+ since_seq: number;
138
+ partials: boolean;
139
+ cik: string;
140
+ type: string;
141
+ channel: string;
142
+ };
143
+ export declare function initialLiveState(sinceSeq: number): LiveState;
144
+ /** The assignment of `label` covering `seq` (the latest-starting one wins), else null. */
145
+ export declare function nameFor(assignments: SpeakerAssignment[], label: string | null, seq: number): string | null;
146
+ /** `[m:ss] name: text`, the name from the snapshot, else `Speaker <label>`. */
147
+ export declare function formatSegment(segment: LiveSegment, assignments: SpeakerAssignment[]): string;
148
+ /** One highlighted line per keyword hit: `[m:ss] keyword "x" · speaker: text` (+ the company in the global scope). */
149
+ export declare function formatKeywordHit(hit: KeywordHit, allLive?: boolean): string;
150
+ /** One line per guidance flash: `[m:ss] guidance flash · metric period: value — "sentence"`. */
151
+ export declare function formatGuidanceFlash(flash: GuidanceFlash, allLive?: boolean): string;
152
+ export declare function finalTranscriptHint(eventId: string | null): string;
153
+ /** One server frame → the new state and what to print / do. Unknown frames are ignored. */
154
+ export declare function liveStep(state: LiveState, frame: Record<string, any>, opts: LiveOptions): LiveStep;
155
+ /** Frames of the earnings channel (the socket also carries `new_filing` broadcasts and pings). */
156
+ export declare function isEarningsFrame(frame: Record<string, any>): boolean;