@gloom-sh/terminal 0.19.1 → 0.19.2
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/package.json +2 -1
- package/src/api-client/errors.ts +38 -0
- package/src/app/runtime/startup.ts +3 -1
- package/src/capabilities/chart-series.ts +2 -1
- package/src/cli/commands/market.ts +9 -4
- package/src/cli/commands/overview.ts +5 -6
- package/src/cli/commands/search.ts +13 -13
- package/src/cli/context.ts +1 -0
- package/src/cli/glossary.ts +2 -1
- package/src/cli/history-rows.ts +35 -7
- package/src/cli/known-gaps.ts +11 -0
- package/src/cli/listing-arg.ts +17 -1
- package/src/cli/quote-answer.ts +29 -6
- package/src/components/command-bar/routes/root/runtime.ts +27 -5
- package/src/components/command-bar/selection-runtime.ts +12 -29
- package/src/components/layout/detached-pane-shell.tsx +2 -2
- package/src/components/layout/header.tsx +2 -2
- package/src/components/layout/pane/footer/index.tsx +1 -0
- package/src/components/layout/pane/footer/model.ts +33 -1
- package/src/components/layout/pane/header.tsx +2 -2
- package/src/components/layout/pane/status-footer.ts +2 -1
- package/src/components/onboarding/onboarding-frame.tsx +2 -1
- package/src/components/onboarding/onboarding-wizard.tsx +6 -3
- package/src/components/ui/display.tsx +16 -5
- package/src/components/ui/icon.tsx +8 -2
- package/src/core/app-services.ts +11 -2
- package/src/data/app-persistence.ts +9 -7
- package/src/data/plugin-cache.ts +15 -0
- package/src/data/plugin-state-store.ts +81 -24
- package/src/data/resource-store.ts +130 -58
- package/src/data/session-store.ts +31 -8
- package/src/data/sqlite/access.ts +313 -0
- package/src/data/sqlite/checkpointer.ts +198 -0
- package/src/data/sqlite/database.ts +47 -4
- package/src/data/sqlite/retry.ts +50 -9
- package/src/data/ticker-store.ts +57 -23
- package/src/market-data/realized-volatility.ts +4 -2
- package/src/plugins/auto-update-node.ts +10 -6
- package/src/plugins/builtin/central-bank-rates/series.ts +2 -3
- package/src/plugins/builtin/chart-composer/cli-options.ts +16 -0
- package/src/plugins/builtin/chart-composer/headless-schema.ts +5 -0
- package/src/plugins/builtin/chart-composer/pane.tsx +5 -1
- package/src/plugins/builtin/chart-composer/session-range.ts +5 -2
- package/src/plugins/builtin/commodity-balances/client.ts +4 -1
- package/src/plugins/builtin/cot/client.ts +28 -2
- package/src/plugins/builtin/cot/headless.ts +4 -1
- package/src/plugins/builtin/cot/index.tsx +4 -2
- package/src/plugins/builtin/cot/model.ts +58 -7
- package/src/plugins/builtin/cot/pane.tsx +6 -2
- package/src/plugins/builtin/cpi/client.ts +6 -5
- package/src/plugins/builtin/credit-boards/series.ts +3 -4
- package/src/plugins/builtin/credit-conditions/client.ts +22 -14
- package/src/plugins/builtin/crypto-board/client.ts +5 -5
- package/src/plugins/builtin/crypto-board/series.ts +4 -4
- package/src/plugins/builtin/debt-maturities/series.ts +3 -3
- package/src/plugins/builtin/doe/client.ts +6 -5
- package/src/plugins/builtin/doe/prices.ts +2 -3
- package/src/plugins/builtin/doe/series.ts +4 -4
- package/src/plugins/builtin/earnings-calls/calendar.tsx +10 -2
- package/src/plugins/builtin/earnings-calls/data.ts +19 -11
- package/src/plugins/builtin/earnings-calls/pane.tsx +27 -14
- package/src/plugins/builtin/econ/detail-view.tsx +16 -2
- package/src/plugins/builtin/executives/data.ts +6 -1
- package/src/plugins/builtin/executives/pane.tsx +9 -21
- package/src/plugins/builtin/fear-greed/cache.ts +4 -0
- package/src/plugins/builtin/fear-greed/series.ts +6 -4
- package/src/plugins/builtin/gpu/client.ts +4 -1
- package/src/plugins/builtin/gpu/series.ts +2 -3
- package/src/plugins/builtin/holders/beneficial-view.tsx +1 -2
- package/src/plugins/builtin/jodi/client.ts +4 -1
- package/src/plugins/builtin/market-movers/client.ts +1 -0
- package/src/plugins/builtin/market-movers/index.tsx +10 -5
- package/src/plugins/builtin/market-movers/screener.ts +23 -6
- package/src/plugins/builtin/market-movers/session-body.tsx +2 -1
- package/src/plugins/builtin/money-markets/series.ts +3 -5
- package/src/plugins/builtin/power/gas-client.ts +2 -1
- package/src/plugins/builtin/power/prices-client.ts +3 -2
- package/src/plugins/builtin/risk-factors/data.ts +8 -4
- package/src/plugins/builtin/risk-factors/index.tsx +3 -1
- package/src/plugins/builtin/risk-factors/pane.tsx +5 -8
- package/src/plugins/builtin/scanner/lock-note.ts +26 -3
- package/src/plugins/builtin/shared/cloud-resource.ts +13 -8
- package/src/plugins/builtin/shared/fred-points.ts +6 -1
- package/src/plugins/builtin/shared/pro-lock-note.ts +23 -8
- package/src/plugins/builtin/shared/series-warning.ts +13 -4
- package/src/plugins/builtin/short-volume/series.ts +2 -3
- package/src/plugins/builtin/social-mentions/client.ts +15 -10
- package/src/plugins/builtin/social-mentions/series.ts +2 -3
- package/src/plugins/builtin/thirteenf/api.ts +11 -16
- package/src/plugins/builtin/thirteenf/data.ts +34 -6
- package/src/plugins/builtin/thirteenf/overlap-pane.tsx +5 -1
- package/src/plugins/builtin/thirteenf/pane.tsx +21 -5
- package/src/plugins/builtin/thirteenf/types.ts +2 -0
- package/src/plugins/builtin/ticker-detail/data-panes/historical-prices.tsx +5 -2
- package/src/plugins/builtin/ticker-detail/financials/model.ts +35 -2
- package/src/plugins/builtin/ticker-detail/financials/ratios.ts +53 -18
- package/src/plugins/builtin/ticker-detail/headless.ts +59 -8
- package/src/plugins/builtin/treasury-auctions/cache.ts +20 -8
- package/src/plugins/builtin/treasury-auctions/client.ts +3 -3
- package/src/plugins/builtin/treasury-auctions/headless.ts +3 -1
- package/src/plugins/builtin/treasury-auctions/pane.tsx +9 -3
- package/src/plugins/builtin/volatility/client.ts +43 -16
- package/src/plugins/builtin/volatility/headless.ts +5 -2
- package/src/plugins/builtin/volatility/model.ts +17 -6
- package/src/plugins/builtin/volatility/pane.tsx +6 -2
- package/src/plugins/builtin/volatility/series.ts +2 -1
- package/src/plugins/builtin/yield-curve/client.ts +4 -6
- package/src/plugins/installer.ts +50 -39
- package/src/renderers/dom/desktop/icons.tsx +3 -2
- package/src/renderers/electrobun/bun/desktop/detached-windows.ts +23 -1
- package/src/renderers/electrobun/bun/desktop/initialization.ts +9 -1
- package/src/renderers/electrobun/bun/window/attention.ts +54 -0
- package/src/renderers/electrobun/bun/window/create.ts +2 -0
- package/src/renderers/electrobun/launcher/preload.ts +13 -0
- package/src/renderers/electrobun/launcher/windows-emulation.ts +50 -0
- package/src/renderers/electrobun/view/ui-host.tsx +9 -2
- package/src/series/resolve.ts +2 -1
- package/src/series/types.ts +5 -0
- package/src/sources/gloomberb-cloud/fred-series.ts +5 -3
- package/src/telemetry/stall-reports-node.ts +13 -2
- package/src/telemetry/stall-reports.ts +189 -13
- package/src/test-support/outage.ts +8 -0
- package/src/tickers/company-name-listing.ts +59 -29
- package/src/tickers/company-name.ts +65 -1
- package/src/tickers/search/home-listing.ts +93 -8
- package/src/tickers/search/index.ts +1 -1
- package/src/time-series/market.ts +5 -3
- package/src/time-series/price-comparison.ts +20 -2
- package/src/time-series/resolve.ts +20 -1
- package/src/time-series/types.ts +7 -0
- package/src/types/financials.ts +18 -3
- package/src/ui/host.tsx +6 -1
- package/src/utils/financial-statements.ts +73 -16
- package/src/utils/fundamentals.ts +17 -5
- package/src/utils/lease-liabilities.ts +54 -0
- package/src/utils/main-thread-stall.ts +47 -2
- package/src/utils/perf-marks.ts +23 -11
- package/src/utils/price-history-integrity.ts +47 -1
|
@@ -9,15 +9,31 @@ const SAMPLE_INTERVAL_MS = 250;
|
|
|
9
9
|
*/
|
|
10
10
|
const STALL_THRESHOLD_MS = 400;
|
|
11
11
|
|
|
12
|
+
/** The facts a `sqlite.blocked` step was measured with (data/sqlite/retry.ts). */
|
|
13
|
+
interface StallSqliteDetail {
|
|
14
|
+
/** The statement's fixed name, such as "touch cached resource". */
|
|
15
|
+
operation: string;
|
|
16
|
+
attempts: number;
|
|
17
|
+
/** Whether it waited on another connection's lock, rather than being slow on its own. */
|
|
18
|
+
lockWait: boolean;
|
|
19
|
+
}
|
|
20
|
+
|
|
12
21
|
export interface StallEvent {
|
|
13
22
|
blockedMs: number;
|
|
14
23
|
/** The last measured section before the stall (perf-marks), if any. */
|
|
15
24
|
lastMeasured?: string;
|
|
16
25
|
/** How long before the stall was noticed that section ended. */
|
|
17
26
|
lastMeasuredEndedMsAgo?: number;
|
|
27
|
+
/** When that section was a SQLite statement that held the thread. */
|
|
28
|
+
sqlite?: StallSqliteDetail;
|
|
29
|
+
/** How long the process had been running when the stall was noticed. */
|
|
30
|
+
uptimeMs?: number;
|
|
31
|
+
/** Whether the process had finished starting (`markStartupComplete`). */
|
|
32
|
+
phase?: "startup" | "steady";
|
|
18
33
|
}
|
|
19
34
|
|
|
20
35
|
let stallSink: ((event: StallEvent) => void) | null = null;
|
|
36
|
+
let startupComplete = false;
|
|
21
37
|
|
|
22
38
|
/**
|
|
23
39
|
* Where this process's stalls go besides the Debug Log: the stall log and its
|
|
@@ -31,6 +47,20 @@ export function setStallSink(next: ((event: StallEvent) => void) | null): () =>
|
|
|
31
47
|
};
|
|
32
48
|
}
|
|
33
49
|
|
|
50
|
+
/**
|
|
51
|
+
* The process is up: its first screen has its data, or (the desktop app's
|
|
52
|
+
* Bun process) the main window has what it asked for. Stalls before this are
|
|
53
|
+
* reported as startup ones.
|
|
54
|
+
*/
|
|
55
|
+
export function markStartupComplete(): void {
|
|
56
|
+
startupComplete = true;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** Test seam. */
|
|
60
|
+
export function resetStartupCompleteForTests(): void {
|
|
61
|
+
startupComplete = false;
|
|
62
|
+
}
|
|
63
|
+
|
|
34
64
|
function noteStall(event: StallEvent): void {
|
|
35
65
|
try {
|
|
36
66
|
stallSink?.(event);
|
|
@@ -39,6 +69,14 @@ function noteStall(event: StallEvent): void {
|
|
|
39
69
|
}
|
|
40
70
|
}
|
|
41
71
|
|
|
72
|
+
/** The facts of a `sqlite.blocked` sample, when they have the shape retry.ts gives them. */
|
|
73
|
+
function sqliteDetail(metadata: Record<string, unknown> | undefined): StallSqliteDetail | undefined {
|
|
74
|
+
if (!metadata) return undefined;
|
|
75
|
+
const { operation, attempts, lockWait } = metadata;
|
|
76
|
+
if (typeof operation !== "string" || typeof attempts !== "number") return undefined;
|
|
77
|
+
return { operation, attempts, lockWait: lockWait === true };
|
|
78
|
+
}
|
|
79
|
+
|
|
42
80
|
export interface MainThreadStallMonitorOptions {
|
|
43
81
|
intervalMs?: number;
|
|
44
82
|
thresholdMs?: number;
|
|
@@ -60,7 +98,9 @@ function defaultNow(): number {
|
|
|
60
98
|
* comes back late, the app was unresponsive for exactly that long. The report
|
|
61
99
|
* carries the last measured section and how long before the stall it ended,
|
|
62
100
|
* which is usually enough to tell "the cache read did it" from "the render
|
|
63
|
-
* did it" in a report that only says the app hung for a few seconds
|
|
101
|
+
* did it" in a report that only says the app hung for a few seconds, and how
|
|
102
|
+
* long the process had been up, so a slow start reads apart from a hang
|
|
103
|
+
* hours in.
|
|
64
104
|
*/
|
|
65
105
|
export function startMainThreadStallMonitor(
|
|
66
106
|
options: MainThreadStallMonitorOptions = {},
|
|
@@ -72,7 +112,8 @@ export function startMainThreadStallMonitor(
|
|
|
72
112
|
const cancel = options.cancel ?? ((handle) => clearInterval(handle as ReturnType<typeof setInterval>));
|
|
73
113
|
const report = options.report
|
|
74
114
|
?? ((blockedMs, context) => {
|
|
75
|
-
|
|
115
|
+
// Logged, but not a step: the next stall still names the work before it.
|
|
116
|
+
recordPerfSample("runtime.stall", blockedMs, context, { lastStep: false });
|
|
76
117
|
noteStall({ blockedMs, ...context });
|
|
77
118
|
});
|
|
78
119
|
|
|
@@ -83,10 +124,14 @@ export function startMainThreadStallMonitor(
|
|
|
83
124
|
previous = current;
|
|
84
125
|
if (blockedMs < thresholdMs) return;
|
|
85
126
|
const sample = lastPerfSample();
|
|
127
|
+
const sqlite = sample?.name === "sqlite.blocked" ? sqliteDetail(sample.metadata) : undefined;
|
|
86
128
|
report(blockedMs, {
|
|
87
129
|
...(sample
|
|
88
130
|
? { lastMeasured: sample.name, lastMeasuredEndedMsAgo: Math.round(current - sample.endedAt) }
|
|
89
131
|
: {}),
|
|
132
|
+
...(sqlite ? { sqlite } : {}),
|
|
133
|
+
uptimeMs: Math.round(current),
|
|
134
|
+
phase: startupComplete ? "steady" : "startup",
|
|
90
135
|
});
|
|
91
136
|
}, intervalMs);
|
|
92
137
|
if (handle && typeof (handle as { unref?: () => void }).unref === "function") {
|
package/src/utils/perf-marks.ts
CHANGED
|
@@ -20,27 +20,34 @@ function now(): number {
|
|
|
20
20
|
: Date.now();
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
//
|
|
24
|
-
// only the stall monitor ever reads them.
|
|
23
|
+
// Scalars rather than an object: every measured section writes them, and
|
|
24
|
+
// only the stall monitor ever reads them. The metadata is the caller's own
|
|
25
|
+
// object, kept by reference.
|
|
25
26
|
let lastSampleName: string | null = null;
|
|
26
27
|
let lastSampleEndedAt = 0;
|
|
28
|
+
let lastSampleMetadata: Record<string, unknown> | undefined;
|
|
27
29
|
|
|
28
30
|
/**
|
|
29
|
-
* The most recent measured section
|
|
30
|
-
* it so a report of "the app froze" carries the
|
|
31
|
-
* have been doing.
|
|
31
|
+
* The most recent measured section, when it ended and what it was measured
|
|
32
|
+
* with. The stall monitor reads it so a report of "the app froze" carries the
|
|
33
|
+
* last thing the app is known to have been doing.
|
|
32
34
|
*/
|
|
33
|
-
export function lastPerfSample(): { name: string; endedAt: number } | null {
|
|
34
|
-
|
|
35
|
+
export function lastPerfSample(): { name: string; endedAt: number; metadata?: Record<string, unknown> } | null {
|
|
36
|
+
if (lastSampleName == null) return null;
|
|
37
|
+
return { name: lastSampleName, endedAt: lastSampleEndedAt, ...(lastSampleMetadata ? { metadata: lastSampleMetadata } : {}) };
|
|
35
38
|
}
|
|
36
39
|
|
|
37
40
|
function logSlowPerfSample(
|
|
38
41
|
name: string,
|
|
39
42
|
durationMs: number,
|
|
40
43
|
metadata?: Record<string, unknown>,
|
|
44
|
+
lastStep = true,
|
|
41
45
|
): void {
|
|
42
|
-
|
|
43
|
-
|
|
46
|
+
if (lastStep) {
|
|
47
|
+
lastSampleName = name;
|
|
48
|
+
lastSampleEndedAt = now();
|
|
49
|
+
lastSampleMetadata = metadata;
|
|
50
|
+
}
|
|
44
51
|
const payload = {
|
|
45
52
|
durationMs: Math.round(durationMs * 10) / 10,
|
|
46
53
|
...(metadata ?? {}),
|
|
@@ -60,13 +67,18 @@ export function isPerfTraceEnabled(): boolean {
|
|
|
60
67
|
return traceToStderr;
|
|
61
68
|
}
|
|
62
69
|
|
|
63
|
-
/**
|
|
70
|
+
/**
|
|
71
|
+
* A sample measured elsewhere (a React Profiler callback, for instance).
|
|
72
|
+
* `lastStep: false` logs it without making it the step a later stall names:
|
|
73
|
+
* the stall monitor's own samples, which measure no work.
|
|
74
|
+
*/
|
|
64
75
|
export function recordPerfSample(
|
|
65
76
|
name: string,
|
|
66
77
|
durationMs: number,
|
|
67
78
|
metadata?: Record<string, unknown>,
|
|
79
|
+
options?: { lastStep?: boolean },
|
|
68
80
|
): void {
|
|
69
|
-
logSlowPerfSample(name, durationMs, metadata);
|
|
81
|
+
logSlowPerfSample(name, durationMs, metadata, options?.lastStep !== false);
|
|
70
82
|
}
|
|
71
83
|
|
|
72
84
|
export function measurePerf<T>(
|
|
@@ -46,6 +46,50 @@ export function pricePointIntegrityFlags(point: PricePoint): string[] {
|
|
|
46
46
|
return flags;
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
+
/**
|
|
50
|
+
* A wick too far from its bar's body to have traded: a low under half the lower
|
|
51
|
+
* of open and close, or a high over twice the higher, as `low<close/2` or
|
|
52
|
+
* `high>2*open` (IAG on LSE, 2021-11-29: a low of 0.0155 under a close of
|
|
53
|
+
* 1.316). Only that wick is withheld: the open and close stand, so closes,
|
|
54
|
+
* returns and drawdowns read the bar while lows, highs and ranges do not.
|
|
55
|
+
* Empty when the wicks are plausible, or when the bar's prices contradict
|
|
56
|
+
* each other, which blanks it whole (pricePointIntegrityFlags).
|
|
57
|
+
*/
|
|
58
|
+
export function pricePointWickFlags(point: PricePoint): string[] {
|
|
59
|
+
const { open, high, low, close } = point;
|
|
60
|
+
if (pricePointIntegrityFlags(point).length > 0) return [];
|
|
61
|
+
const body = [["open", open], ["close", close]].filter((entry): entry is [string, number] => isFiniteNumber(entry[1]));
|
|
62
|
+
if (body.length === 0) return [];
|
|
63
|
+
// On a tie the close names the side, as the price the bar is read by.
|
|
64
|
+
const [bottomName, bottom] = body.reduce((least, entry) => entry[1] <= least[1] ? entry : least);
|
|
65
|
+
const [topName, top] = body.reduce((most, entry) => entry[1] >= most[1] ? entry : most);
|
|
66
|
+
const flags: string[] = [];
|
|
67
|
+
if (isFiniteNumber(low) && bottom > 0 && low < bottom / 2) flags.push(`low<${bottomName}/2`);
|
|
68
|
+
if (isFiniteNumber(high) && top > 0 && high > top * 2) flags.push(`high>2*${topName}`);
|
|
69
|
+
return flags;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/** Whether a flag code is a withheld wick (pricePointWickFlags), whose bar keeps its open and close. */
|
|
73
|
+
export function isWickFlag(code: string): boolean {
|
|
74
|
+
return /^(low<(open|close)\/2|high>2\*(open|close))$/.test(code);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** A bar's high and low with a wick too far from its body to have traded (pricePointWickFlags) left out. */
|
|
78
|
+
export function pricePointWicks(point: PricePoint): { high: number | undefined; low: number | undefined } {
|
|
79
|
+
const flags = pricePointWickFlags(point);
|
|
80
|
+
return {
|
|
81
|
+
high: flags.some((flag) => flag.startsWith("high")) ? undefined : point.high,
|
|
82
|
+
low: flags.some((flag) => flag.startsWith("low")) ? undefined : point.low,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** "1 bar has a low or high too far from its open and close to have traded; left out of ranges.", or undefined for none. */
|
|
87
|
+
export function priceHistoryWickNotice(count: number): string | undefined {
|
|
88
|
+
return count > 0
|
|
89
|
+
? `${count === 1 ? "1 bar has a low or high" : `${count} bars have lows or highs`} too far from ${count === 1 ? "its" : "their"} open and close to have traded; left out of ranges.`
|
|
90
|
+
: undefined;
|
|
91
|
+
}
|
|
92
|
+
|
|
49
93
|
export function pricePointIntegrity(point: PricePoint): PriceHistoryIntegrity | undefined {
|
|
50
94
|
if (pricePointIntegrityFlags(point).length === 0) return undefined;
|
|
51
95
|
const date = new Date(point.date);
|
|
@@ -58,8 +102,10 @@ export function pricePointIntegrity(point: PricePoint): PriceHistoryIntegrity |
|
|
|
58
102
|
/** Calculation/display fields deliberately exclude the contradictory source row. */
|
|
59
103
|
export function pricePointValues(point: PricePoint, integrity = pricePointIntegrity(point)) {
|
|
60
104
|
const value = (number: number | undefined) => !integrity && isFiniteNumber(number) ? number : null;
|
|
105
|
+
// A wick too far from the body to have traded is left out; the rest of the bar stands.
|
|
106
|
+
const wicks = pricePointWicks(point);
|
|
61
107
|
return {
|
|
62
|
-
open: value(point.open), high: value(
|
|
108
|
+
open: value(point.open), high: value(wicks.high), low: value(wicks.low),
|
|
63
109
|
close: value(point.close), volume: value(point.volume),
|
|
64
110
|
...(integrity ? { integrity } : {}),
|
|
65
111
|
};
|