[Init] Initial commit - NetMesh terminal manager
Some checks failed
build-packages / resolve bundled mosh-client (push) Has been cancelled
build-packages / resolve bundled et-client (push) Has been cancelled
build-packages / build-macos (push) Has been cancelled
build-packages / build-windows (push) Has been cancelled
build-packages / build-linux-x64 (push) Has been cancelled
build-packages / build-linux-arm64 (push) Has been cancelled
build-packages / release (push) Has been cancelled
build-packages / update Nix release metadata (push) Has been cancelled
build-packages / bump homebrew tap (push) Has been cancelled
test / lint-and-test (push) Has been cancelled
AI automation / Route event (push) Has been cancelled
AI automation / Hand reopened issue to maintainers (push) Has been cancelled
AI automation / Clean source issue state (push) Has been cancelled
AI automation / Reconcile handoffs (push) Has been cancelled
AI automation / Classify issue (push) Has been cancelled
AI automation / Claude Code smoke (push) Has been cancelled
AI automation / Review issue follow-up (push) Has been cancelled
AI automation / Publish issue follow-up (push) Has been cancelled
AI automation / Implement with Claude Code (push) Has been cancelled
AI automation / Publish implement PR (push) Has been cancelled
AI automation / Continue queued issue comments (push) Has been cancelled
AI automation / Codex review loop (push) Has been cancelled
AI automation / Publish Codex fix (push) Has been cancelled
AI automation / Clear Codex dispatch marker (push) Has been cancelled
AI automation / Own PR re-request Codex (push) Has been cancelled
AI automation / External PR re-request Codex (push) Has been cancelled
AI automation / Poll Codex reaction / retry (push) Has been cancelled
build-et-binaries / build-linux-x64 (push) Has been cancelled
build-et-binaries / build-linux-arm64 (push) Has been cancelled
build-et-binaries / build-macos-universal (push) Has been cancelled
build-et-binaries / build-windows-x64 (push) Has been cancelled
build-et-binaries / release (push) Has been cancelled
Some checks failed
build-packages / resolve bundled mosh-client (push) Has been cancelled
build-packages / resolve bundled et-client (push) Has been cancelled
build-packages / build-macos (push) Has been cancelled
build-packages / build-windows (push) Has been cancelled
build-packages / build-linux-x64 (push) Has been cancelled
build-packages / build-linux-arm64 (push) Has been cancelled
build-packages / release (push) Has been cancelled
build-packages / update Nix release metadata (push) Has been cancelled
build-packages / bump homebrew tap (push) Has been cancelled
test / lint-and-test (push) Has been cancelled
AI automation / Route event (push) Has been cancelled
AI automation / Hand reopened issue to maintainers (push) Has been cancelled
AI automation / Clean source issue state (push) Has been cancelled
AI automation / Reconcile handoffs (push) Has been cancelled
AI automation / Classify issue (push) Has been cancelled
AI automation / Claude Code smoke (push) Has been cancelled
AI automation / Review issue follow-up (push) Has been cancelled
AI automation / Publish issue follow-up (push) Has been cancelled
AI automation / Implement with Claude Code (push) Has been cancelled
AI automation / Publish implement PR (push) Has been cancelled
AI automation / Continue queued issue comments (push) Has been cancelled
AI automation / Codex review loop (push) Has been cancelled
AI automation / Publish Codex fix (push) Has been cancelled
AI automation / Clear Codex dispatch marker (push) Has been cancelled
AI automation / Own PR re-request Codex (push) Has been cancelled
AI automation / External PR re-request Codex (push) Has been cancelled
AI automation / Poll Codex reaction / retry (push) Has been cancelled
build-et-binaries / build-linux-x64 (push) Has been cancelled
build-et-binaries / build-linux-arm64 (push) Has been cancelled
build-et-binaries / build-macos-universal (push) Has been cancelled
build-et-binaries / build-windows-x64 (push) Has been cancelled
build-et-binaries / release (push) Has been cancelled
This commit is contained in:
143
components/terminal/runtime/terminalPerformanceDiagnostics.ts
Normal file
143
components/terminal/runtime/terminalPerformanceDiagnostics.ts
Normal file
@@ -0,0 +1,143 @@
|
||||
import { netcattyBridge } from "../../../infrastructure/services/netcattyBridge";
|
||||
|
||||
export type TerminalOutputPerfMeta = {
|
||||
id: string;
|
||||
emittedAt: number;
|
||||
chars: number;
|
||||
lineFeeds: number;
|
||||
};
|
||||
|
||||
export type TerminalOutputPerfTrace = {
|
||||
id: string;
|
||||
sessionId?: string;
|
||||
startedAt: number;
|
||||
rendererReceivedAt: number;
|
||||
ingressBytes: number;
|
||||
inputChars: number;
|
||||
inputLineFeeds: number;
|
||||
backend?: TerminalOutputPerfMeta;
|
||||
};
|
||||
|
||||
type TerminalOutputPerfMetaCarrier = {
|
||||
terminalPerf?: TerminalOutputPerfMeta;
|
||||
};
|
||||
|
||||
const DEBUG_KEYS = [
|
||||
"NETCATTY_TERMINAL_PERF_DEBUG",
|
||||
"NETCATTY_TERMINAL_DEBUG",
|
||||
];
|
||||
const PERF_LOG_PREFIX = "[Netcatty Terminal Perf]";
|
||||
const LOCAL_STORAGE_DEBUG_CACHE_TTL_MS = 1000;
|
||||
|
||||
let localStorageDebugCache = false;
|
||||
let localStorageDebugCacheAt = 0;
|
||||
|
||||
const countLineFeeds = (data: string): number => {
|
||||
let count = 0;
|
||||
for (let index = 0; index < data.length; index += 1) {
|
||||
if (data[index] === "\n") count += 1;
|
||||
}
|
||||
return count;
|
||||
};
|
||||
|
||||
const safeJson = (value: unknown): string => JSON.stringify(value, (_key, nested) => {
|
||||
if (typeof nested === "bigint") return nested.toString();
|
||||
if (typeof nested === "function") return "[function]";
|
||||
return nested;
|
||||
});
|
||||
|
||||
const sendRendererDiagnostic = (
|
||||
message: string,
|
||||
payload: Record<string, unknown>,
|
||||
): void => {
|
||||
try {
|
||||
const logDiagnostic = netcattyBridge.get()?.logDiagnostic;
|
||||
if (typeof logDiagnostic !== "function") return;
|
||||
void logDiagnostic({
|
||||
source: "terminal-perf",
|
||||
message,
|
||||
extra: payload,
|
||||
}).catch(() => undefined);
|
||||
} catch {
|
||||
// Diagnostics must never affect terminal output.
|
||||
}
|
||||
};
|
||||
|
||||
const readLocalStorageDebugEnabled = (): boolean => {
|
||||
try {
|
||||
return DEBUG_KEYS.some((key) => window.localStorage?.getItem(key) === "1");
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
const isLocalStorageDebugEnabled = (): boolean => {
|
||||
const now = Date.now();
|
||||
if (now - localStorageDebugCacheAt > LOCAL_STORAGE_DEBUG_CACHE_TTL_MS) {
|
||||
localStorageDebugCache = readLocalStorageDebugEnabled();
|
||||
localStorageDebugCacheAt = now;
|
||||
}
|
||||
return localStorageDebugCache;
|
||||
};
|
||||
|
||||
export const isTerminalPerformanceDebugEnabled = (
|
||||
meta?: TerminalOutputPerfMetaCarrier,
|
||||
): boolean => Boolean(meta?.terminalPerf) || isLocalStorageDebugEnabled();
|
||||
|
||||
export const createTerminalOutputPerfTrace = ({
|
||||
sessionId,
|
||||
data,
|
||||
ingressBytes,
|
||||
meta,
|
||||
}: {
|
||||
sessionId?: string;
|
||||
data: string;
|
||||
ingressBytes: number;
|
||||
meta?: TerminalOutputPerfMetaCarrier;
|
||||
}): TerminalOutputPerfTrace | null => {
|
||||
if (!isTerminalPerformanceDebugEnabled(meta)) return null;
|
||||
const now = performance.now();
|
||||
return {
|
||||
id: meta?.terminalPerf?.id ?? `renderer-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`,
|
||||
sessionId,
|
||||
startedAt: now,
|
||||
rendererReceivedAt: Date.now(),
|
||||
ingressBytes,
|
||||
inputChars: data.length,
|
||||
inputLineFeeds: countLineFeeds(data),
|
||||
backend: meta?.terminalPerf,
|
||||
};
|
||||
};
|
||||
|
||||
export const logTerminalOutputPerf = (
|
||||
event: string,
|
||||
trace: TerminalOutputPerfTrace | null | undefined,
|
||||
details: Record<string, unknown> = {},
|
||||
): void => {
|
||||
if (!trace && !isLocalStorageDebugEnabled()) return;
|
||||
const now = performance.now();
|
||||
const backendToRendererMs = trace?.backend?.emittedAt
|
||||
? trace.rendererReceivedAt - trace.backend.emittedAt
|
||||
: undefined;
|
||||
const payload = {
|
||||
event,
|
||||
id: trace?.id,
|
||||
sessionId: trace?.sessionId,
|
||||
at: Date.now(),
|
||||
elapsedMs: trace ? Number((now - trace.startedAt).toFixed(1)) : undefined,
|
||||
backendToRendererMs,
|
||||
ingressBytes: trace?.ingressBytes,
|
||||
inputChars: trace?.inputChars,
|
||||
inputLineFeeds: trace?.inputLineFeeds,
|
||||
backendChars: trace?.backend?.chars,
|
||||
backendLineFeeds: trace?.backend?.lineFeeds,
|
||||
...details,
|
||||
};
|
||||
try {
|
||||
const message = `${PERF_LOG_PREFIX} ${safeJson(payload)}`;
|
||||
console.info(message);
|
||||
sendRendererDiagnostic(message, payload);
|
||||
} catch {
|
||||
// Diagnostics must never affect terminal output.
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user