tmux-ide 2.9.0-beta.20 → 2.9.0-beta.21
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/bin/cli.js +100 -8
- package/package.json +3 -2
- package/packages/daemon/dist/command-center/diagnostics.js +65 -0
- package/packages/daemon/dist/command-center/log-stream.js +9 -0
- package/packages/daemon/dist/command-center/server.js +7 -0
- package/packages/daemon/dist/lib/app-config.js +4 -2
- package/packages/daemon/dist/lib/soak-diagnostics.js +124 -0
- package/packages/daemon/dist/lib/soak-verdict.js +185 -35
- package/packages/daemon/dist/lib/terminal-host-color.js +33 -0
- package/packages/daemon/dist/tui/mirror/automatic-contrast.js +161 -0
- package/packages/daemon/dist/tui/mirror/open-tui-workspace-runtime-port.js +9 -3
- package/packages/daemon/dist/tui/mirror/pane-surface.jsx +7 -5
- package/packages/daemon/dist/tui/mirror/resize-transaction.js +48 -20
- package/packages/daemon/dist/tui/mirror/runtime/application-appearance-owner.js +40 -6
- package/packages/daemon/dist/tui/mirror/runtime/application-machine-sidebar.jsx +63 -42
- package/packages/daemon/dist/tui/mirror/runtime/application-terminal-interaction-controller.js +138 -67
- package/packages/daemon/dist/tui/mirror/runtime/application-terminal-palette-owner.js +44 -28
- package/packages/daemon/dist/tui/mirror/runtime/application-terminal-workspace.jsx +49 -11
- package/packages/daemon/dist/tui/mirror/runtime/semantic-shell-viewport-resize.js +140 -2
- package/packages/daemon/dist/tui/mirror/runtime/workspace-terminal-fast-lane.js +3 -1
- package/packages/daemon/dist/tui/mirror/semantic-pane-render-source.js +2 -1
- package/packages/daemon/dist/tui/mirror/theme.js +4 -31
- package/packages/daemon/dist/tui/mirror/workspace/terminal-pane-header.jsx +15 -8
- package/packages/daemon/src/command-center/diagnostics.ts +75 -0
- package/packages/daemon/src/command-center/log-stream.ts +8 -0
- package/packages/daemon/src/command-center/server.ts +8 -0
- package/packages/daemon/src/lib/app-config.ts +11 -3
- package/packages/daemon/src/lib/soak-diagnostics.ts +183 -0
- package/packages/daemon/src/lib/soak-verdict.ts +314 -23
- package/packages/daemon/src/lib/terminal-host-color.ts +43 -0
- package/packages/daemon/src/tui/mirror/automatic-contrast.ts +180 -0
- package/packages/daemon/src/tui/mirror/open-tui-workspace-runtime-port.ts +26 -5
- package/packages/daemon/src/tui/mirror/pane-surface.tsx +9 -8
- package/packages/daemon/src/tui/mirror/resize-transaction.ts +46 -22
- package/packages/daemon/src/tui/mirror/runtime/application-appearance-owner.ts +45 -6
- package/packages/daemon/src/tui/mirror/runtime/application-machine-sidebar.tsx +99 -75
- package/packages/daemon/src/tui/mirror/runtime/application-root-v2.tsx +1 -0
- package/packages/daemon/src/tui/mirror/runtime/application-shell-overlays.tsx +9 -2
- package/packages/daemon/src/tui/mirror/runtime/application-shell-view.tsx +2 -0
- package/packages/daemon/src/tui/mirror/runtime/application-terminal-interaction-controller.ts +148 -69
- package/packages/daemon/src/tui/mirror/runtime/application-terminal-palette-owner.ts +55 -28
- package/packages/daemon/src/tui/mirror/runtime/application-terminal-workspace.tsx +59 -17
- package/packages/daemon/src/tui/mirror/runtime/semantic-shell-viewport-resize.ts +151 -3
- package/packages/daemon/src/tui/mirror/runtime/workspace-terminal-fast-lane.ts +3 -1
- package/packages/daemon/src/tui/mirror/semantic-pane-render-source.ts +2 -1
- package/packages/daemon/src/tui/mirror/theme.ts +4 -39
- package/packages/daemon/src/tui/mirror/workspace/terminal-pane-header.tsx +21 -8
- package/packages/daemon-client/src/terminal-fast-lane.test.ts +18 -0
- package/packages/daemon-client/src/terminal-fast-lane.ts +7 -2
package/bin/cli.js
CHANGED
|
@@ -9273,7 +9273,12 @@ function parseAppConfig(input) {
|
|
|
9273
9273
|
}
|
|
9274
9274
|
},
|
|
9275
9275
|
theme: {
|
|
9276
|
-
|
|
9276
|
+
automaticContrast: pickBool(theme.automaticContrast, D.theme.automaticContrast),
|
|
9277
|
+
mode: pickChoice(
|
|
9278
|
+
theme.mode,
|
|
9279
|
+
["dark", "light", "system"],
|
|
9280
|
+
findVisualThemePreset(theme.preset)?.appearance ?? D.theme.mode
|
|
9281
|
+
),
|
|
9277
9282
|
...findVisualThemePreset(theme.preset) ? { preset: String(theme.preset) } : {},
|
|
9278
9283
|
accent: pickString(theme.accent, D.theme.accent),
|
|
9279
9284
|
muted: pickString(theme.muted, D.theme.muted),
|
|
@@ -9399,7 +9404,8 @@ var init_app_config = __esm({
|
|
|
9399
9404
|
panels: { explorer: "M-e", changes: "M-g", config: "M-," }
|
|
9400
9405
|
},
|
|
9401
9406
|
theme: {
|
|
9402
|
-
|
|
9407
|
+
automaticContrast: true,
|
|
9408
|
+
mode: "system",
|
|
9403
9409
|
accent: "colour75",
|
|
9404
9410
|
muted: "colour240",
|
|
9405
9411
|
fg: "colour250",
|
|
@@ -10969,7 +10975,7 @@ var require_package = __commonJS({
|
|
|
10969
10975
|
"package.json"(exports, module) {
|
|
10970
10976
|
module.exports = {
|
|
10971
10977
|
name: "tmux-ide",
|
|
10972
|
-
version: "2.9.0-beta.
|
|
10978
|
+
version: "2.9.0-beta.21",
|
|
10973
10979
|
description: "A visual, agent-aware IDE for any tmux session, with optional workspace presets",
|
|
10974
10980
|
type: "module",
|
|
10975
10981
|
bin: {
|
|
@@ -11008,6 +11014,7 @@ var require_package = __commonJS({
|
|
|
11008
11014
|
typecheck: 'echo "root typecheck deferred to per-package turbo run"',
|
|
11009
11015
|
dev: "node bin/cli.js",
|
|
11010
11016
|
"dev:instance": "node scripts/development-instance.mjs",
|
|
11017
|
+
"dev:pilotty": "node scripts/pilotty-dev.mjs",
|
|
11011
11018
|
"dev:web": "node scripts/dev-web.mjs",
|
|
11012
11019
|
test: "pnpm -r --workspace-concurrency=1 --filter @tmux-ide/daemon --filter @tmux-ide/contracts --filter @tmux-ide/core --filter @tmux-ide/daemon-client --filter @tmux-ide/sdk --filter @tmux-ide/desktop-renderer --filter @tmux-ide/web-workspace --filter @tmux-ide/electron-shell run test",
|
|
11013
11020
|
"test:unit": "pnpm -r --workspace-concurrency=1 --filter @tmux-ide/daemon --filter @tmux-ide/contracts --filter @tmux-ide/core --filter @tmux-ide/daemon-client --filter @tmux-ide/sdk --filter @tmux-ide/desktop-renderer --filter @tmux-ide/web-workspace --filter @tmux-ide/electron-shell run test",
|
|
@@ -11032,7 +11039,7 @@ var require_package = __commonJS({
|
|
|
11032
11039
|
postinstall: "node scripts/postinstall.js",
|
|
11033
11040
|
docs: "turbo run dev --filter=@tmux-ide/docs",
|
|
11034
11041
|
"demo:tui": "bun --preload @opentui/solid/preload docs/scripts/render-tui-demo.tsx",
|
|
11035
|
-
"test:tui-renderer": "bun test --preload @opentui/solid/preload --preload ./packages/daemon/test-support/opentui-renderer-preload.ts ./packages/daemon/src/tui/mirror/pane-surface-renderer.test.tsx ./packages/daemon/src/tui/mirror/native-grid-projection-renderer.test.tsx ./packages/daemon/src/tui/mirror/widget-surface-renderer.test.tsx ./packages/daemon/src/tui/mirror/missions-surface-renderer.test.tsx ./packages/daemon/src/tui/mirror/recipes-gallery-renderer.test.tsx ./packages/daemon/src/tui/mirror/shell-chrome-renderer.test.tsx ./packages/daemon/src/tui/mirror/sidebar-renderer.test.tsx ./packages/daemon/src/tui/mirror/home-files-surface-renderer.test.tsx ./packages/daemon/src/tui/mirror/changes-terminal-surface-renderer.test.tsx ./packages/daemon/src/tui/mirror/activity-surface-renderer.test.tsx ./packages/daemon/src/tui/mirror/features/files/session-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-terminal-workspace-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-shell-view-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-root-error-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-backpressure-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-demand-cadence-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/files-optional-feature-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/changes-optional-feature-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/missions-activity-optional-feature-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/dialogs-optional-feature-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/optional-feature-registry-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/palette-optional-feature-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/pane-scoped-terminal-surface-renderer.test.tsx ./packages/daemon/src/tui/mirror/features/rich-preview/feature.test.ts ./packages/daemon/src/tui/mirror/runtime/rich-preview-optional-feature-renderer.test.tsx ./packages/daemon/src/tui/mirror/workspace/application-shell-renderer.test.tsx ./packages/daemon/src/tui/mirror/workspace/pane-frame-renderer.test.tsx ./packages/daemon/src/tui/mirror/workspace/terminal-pane-chrome-view.test.tsx ./packages/daemon/src/tui/mirror/workspace/terminal-window-strip-renderer.test.tsx ./packages/daemon/src/tui/mirror/workspace/workbench-shell-renderer.test.tsx ./packages/daemon/src/tui/mirror/workspace/workbench-dock-dual-host-renderer.test.tsx ./packages/daemon/src/tui/mirror/workspace/agent-terminal-canvas-renderer.test.tsx ./packages/daemon/src/tui/mirror/workspace/command-palette-surface-renderer.test.tsx ./packages/daemon/src/tui/mirror/workspace/opentui-insertion-stability-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-shell-home-renderer.test.tsx ./packages/daemon/src/tui/mirror/workspace/terminal-pane-header-polish-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-home-agent-roster-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-home-agent-flow-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-shell-sidebar-catalog-renderer.test.tsx ./packages/daemon/src/tui/mirror/ui/ui-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-machine-sidebar-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-add-machine-dialog-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-fleet-switcher-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-palette-preview-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-fleet-palette-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-fleet-session-actions-renderer.test.tsx",
|
|
11042
|
+
"test:tui-renderer": "bun test --preload @opentui/solid/preload --preload ./packages/daemon/test-support/opentui-renderer-preload.ts ./packages/daemon/src/tui/mirror/automatic-contrast-renderer.test.tsx ./packages/daemon/src/tui/mirror/pane-surface-renderer.test.tsx ./packages/daemon/src/tui/mirror/native-grid-projection-renderer.test.tsx ./packages/daemon/src/tui/mirror/widget-surface-renderer.test.tsx ./packages/daemon/src/tui/mirror/missions-surface-renderer.test.tsx ./packages/daemon/src/tui/mirror/recipes-gallery-renderer.test.tsx ./packages/daemon/src/tui/mirror/shell-chrome-renderer.test.tsx ./packages/daemon/src/tui/mirror/sidebar-renderer.test.tsx ./packages/daemon/src/tui/mirror/home-files-surface-renderer.test.tsx ./packages/daemon/src/tui/mirror/changes-terminal-surface-renderer.test.tsx ./packages/daemon/src/tui/mirror/activity-surface-renderer.test.tsx ./packages/daemon/src/tui/mirror/features/files/session-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-terminal-workspace-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-shell-view-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-root-error-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-backpressure-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-demand-cadence-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/files-optional-feature-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/changes-optional-feature-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/missions-activity-optional-feature-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/dialogs-optional-feature-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/optional-feature-registry-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/palette-optional-feature-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/pane-scoped-terminal-surface-renderer.test.tsx ./packages/daemon/src/tui/mirror/features/rich-preview/feature.test.ts ./packages/daemon/src/tui/mirror/runtime/rich-preview-optional-feature-renderer.test.tsx ./packages/daemon/src/tui/mirror/workspace/application-shell-renderer.test.tsx ./packages/daemon/src/tui/mirror/workspace/pane-frame-renderer.test.tsx ./packages/daemon/src/tui/mirror/workspace/terminal-pane-chrome-view.test.tsx ./packages/daemon/src/tui/mirror/workspace/terminal-window-strip-renderer.test.tsx ./packages/daemon/src/tui/mirror/workspace/workbench-shell-renderer.test.tsx ./packages/daemon/src/tui/mirror/workspace/workbench-dock-dual-host-renderer.test.tsx ./packages/daemon/src/tui/mirror/workspace/agent-terminal-canvas-renderer.test.tsx ./packages/daemon/src/tui/mirror/workspace/command-palette-surface-renderer.test.tsx ./packages/daemon/src/tui/mirror/workspace/opentui-insertion-stability-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-shell-home-renderer.test.tsx ./packages/daemon/src/tui/mirror/workspace/terminal-pane-header-polish-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-home-agent-roster-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-home-agent-flow-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-shell-sidebar-catalog-renderer.test.tsx ./packages/daemon/src/tui/mirror/ui/ui-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-machine-sidebar-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-add-machine-dialog-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-fleet-switcher-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-palette-preview-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-fleet-palette-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-fleet-session-actions-renderer.test.tsx",
|
|
11036
11043
|
"test:tui-smoke": "bun scripts/smoke-tui-missions.mjs",
|
|
11037
11044
|
"test:tui-live": "node scripts/tui-testdrive.mjs smoke",
|
|
11038
11045
|
"test:tui-testdrive": "node --test scripts/lib/tui-testdrive-clipboard-hook.test.mjs scripts/lib/tui-testdrive-input.test.mjs",
|
|
@@ -68929,6 +68936,7 @@ async function streamBoundedLogs(stream, options) {
|
|
|
68929
68936
|
let unsubscribe = () => {
|
|
68930
68937
|
};
|
|
68931
68938
|
let timer = null;
|
|
68939
|
+
let heartbeatTimer = null;
|
|
68932
68940
|
let cancelWrite = null;
|
|
68933
68941
|
const cleanup = () => {
|
|
68934
68942
|
if (closed) return;
|
|
@@ -68938,6 +68946,8 @@ async function streamBoundedLogs(stream, options) {
|
|
|
68938
68946
|
bytes = 0;
|
|
68939
68947
|
if (timer) clearTimeout(timer);
|
|
68940
68948
|
timer = null;
|
|
68949
|
+
if (heartbeatTimer) clearInterval(heartbeatTimer);
|
|
68950
|
+
heartbeatTimer = null;
|
|
68941
68951
|
wake?.();
|
|
68942
68952
|
wake = null;
|
|
68943
68953
|
cancelWrite?.();
|
|
@@ -68967,6 +68977,10 @@ async function streamBoundedLogs(stream, options) {
|
|
|
68967
68977
|
unsubscribe();
|
|
68968
68978
|
return;
|
|
68969
68979
|
}
|
|
68980
|
+
heartbeatTimer = setInterval(() => {
|
|
68981
|
+
if (!closed && queue.length === 0 && !push({ event: "heartbeat", data: "keep-alive" })) abort();
|
|
68982
|
+
}, options.heartbeatIntervalMs ?? 15e3);
|
|
68983
|
+
heartbeatTimer.unref?.();
|
|
68970
68984
|
try {
|
|
68971
68985
|
const retained = [];
|
|
68972
68986
|
let retainedBytes = 0;
|
|
@@ -75929,6 +75943,79 @@ var init_workspace_missions_route = __esm({
|
|
|
75929
75943
|
}
|
|
75930
75944
|
});
|
|
75931
75945
|
|
|
75946
|
+
// packages/daemon/src/command-center/diagnostics.ts
|
|
75947
|
+
import { performance as performance2 } from "node:perf_hooks";
|
|
75948
|
+
function sampleDaemonDiagnostics(daemon) {
|
|
75949
|
+
const sampledAtMs = Date.now();
|
|
75950
|
+
const memory = process.memoryUsage();
|
|
75951
|
+
const cpu = process.cpuUsage();
|
|
75952
|
+
const eventLoop = performance2.eventLoopUtilization();
|
|
75953
|
+
const activeResources = {
|
|
75954
|
+
Timeout: 0,
|
|
75955
|
+
Immediate: 0,
|
|
75956
|
+
TCPServerWrap: 0,
|
|
75957
|
+
TCPSocketWrap: 0,
|
|
75958
|
+
PipeWrap: 0,
|
|
75959
|
+
ProcessWrap: 0,
|
|
75960
|
+
FSEventWrap: 0,
|
|
75961
|
+
other: 0
|
|
75962
|
+
};
|
|
75963
|
+
const resourceNames = process.getActiveResourcesInfo?.();
|
|
75964
|
+
for (const resource3 of resourceNames ?? []) {
|
|
75965
|
+
if (Object.hasOwn(activeResources, resource3) && resource3 !== "other") {
|
|
75966
|
+
activeResources[resource3]++;
|
|
75967
|
+
} else {
|
|
75968
|
+
activeResources.other++;
|
|
75969
|
+
}
|
|
75970
|
+
}
|
|
75971
|
+
return {
|
|
75972
|
+
daemon: {
|
|
75973
|
+
protocolVersion: daemon.protocolVersion,
|
|
75974
|
+
productVersion: daemon.productVersion,
|
|
75975
|
+
instanceId: daemon.instanceId,
|
|
75976
|
+
startedAt: daemon.startedAt,
|
|
75977
|
+
...daemon.environmentId !== void 0 ? { environmentId: daemon.environmentId } : {}
|
|
75978
|
+
},
|
|
75979
|
+
pid: process.pid,
|
|
75980
|
+
uptimeMs: process.uptime() * 1e3,
|
|
75981
|
+
sampledAtMs,
|
|
75982
|
+
memory: {
|
|
75983
|
+
rss: memory.rss,
|
|
75984
|
+
heapTotal: memory.heapTotal,
|
|
75985
|
+
heapUsed: memory.heapUsed,
|
|
75986
|
+
external: memory.external,
|
|
75987
|
+
arrayBuffers: memory.arrayBuffers
|
|
75988
|
+
},
|
|
75989
|
+
cpu: { user: cpu.user, system: cpu.system },
|
|
75990
|
+
eventLoop: {
|
|
75991
|
+
idle: eventLoop.idle,
|
|
75992
|
+
active: eventLoop.active,
|
|
75993
|
+
utilization: eventLoop.utilization
|
|
75994
|
+
},
|
|
75995
|
+
activeResources: resourceNames === void 0 ? null : activeResources
|
|
75996
|
+
};
|
|
75997
|
+
}
|
|
75998
|
+
function mountDiagnosticsRoute(app, options) {
|
|
75999
|
+
app.get(
|
|
76000
|
+
"/api/diagnostics",
|
|
76001
|
+
requireOwnerAuthority(options.ownerToken, {
|
|
76002
|
+
whenOwnerless: "unavailable",
|
|
76003
|
+
unavailableMessage: "Diagnostics unavailable",
|
|
76004
|
+
mismatchMessage: "Diagnostics require owner authority"
|
|
76005
|
+
}),
|
|
76006
|
+
(c) => {
|
|
76007
|
+
c.header("Cache-Control", "no-store");
|
|
76008
|
+
return c.json(sampleDaemonDiagnostics(options.daemon));
|
|
76009
|
+
}
|
|
76010
|
+
);
|
|
76011
|
+
}
|
|
76012
|
+
var init_diagnostics = __esm({
|
|
76013
|
+
"packages/daemon/src/command-center/diagnostics.ts"() {
|
|
76014
|
+
"use strict";
|
|
76015
|
+
init_owner_authority();
|
|
76016
|
+
}
|
|
76017
|
+
});
|
|
76018
|
+
|
|
75932
76019
|
// packages/daemon/src/canonical.ts
|
|
75933
76020
|
var init_canonical = __esm({
|
|
75934
76021
|
"packages/daemon/src/canonical.ts"() {
|
|
@@ -76535,6 +76622,10 @@ function createApp(options = {}) {
|
|
|
76535
76622
|
const healthBootedAt = Date.now();
|
|
76536
76623
|
const app = new Hono();
|
|
76537
76624
|
app.use("/*", cors());
|
|
76625
|
+
mountDiagnosticsRoute(app, {
|
|
76626
|
+
daemon: daemonInstanceIdentity,
|
|
76627
|
+
ownerToken: options.remoteAccess?.ownerToken ?? null
|
|
76628
|
+
});
|
|
76538
76629
|
mountTerminalAttachmentIssueRoute(app, {
|
|
76539
76630
|
daemonInstanceId: daemonIdentity.instanceId,
|
|
76540
76631
|
ownerToken: options.remoteAccess?.ownerToken ?? null,
|
|
@@ -77716,6 +77807,7 @@ var init_server2 = __esm({
|
|
|
77716
77807
|
init_fleet_resource_route();
|
|
77717
77808
|
init_workspace_missions_route();
|
|
77718
77809
|
init_owner_authority();
|
|
77810
|
+
init_diagnostics();
|
|
77719
77811
|
init_startup_readiness_route();
|
|
77720
77812
|
init_widget_asset_store();
|
|
77721
77813
|
defaultApplicationShellAppWindowBackend = {
|
|
@@ -77796,7 +77888,7 @@ import { randomBytes as randomBytes8, randomUUID as randomUUID23 } from "node:cr
|
|
|
77796
77888
|
import { createWriteStream } from "node:fs";
|
|
77797
77889
|
import { createServer as createServer2 } from "node:http";
|
|
77798
77890
|
import { createRequire as createRequire3 } from "node:module";
|
|
77799
|
-
import { performance as
|
|
77891
|
+
import { performance as performance3 } from "node:perf_hooks";
|
|
77800
77892
|
import { WebSocket, WebSocketServer as WebSocketServer4 } from "ws";
|
|
77801
77893
|
function loadBundledPackage() {
|
|
77802
77894
|
return requireFromHere2("../../package.json");
|
|
@@ -78005,13 +78097,13 @@ function createTakeoverDeadline(timeoutMs) {
|
|
|
78005
78097
|
throw new TypeError("Takeover deadline must be a positive finite duration.");
|
|
78006
78098
|
}
|
|
78007
78099
|
const controller = new AbortController();
|
|
78008
|
-
const expiresAt =
|
|
78100
|
+
const expiresAt = performance3.now() + timeoutMs;
|
|
78009
78101
|
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
78010
78102
|
timer.unref?.();
|
|
78011
78103
|
return {
|
|
78012
78104
|
signal: controller.signal,
|
|
78013
78105
|
expiresAt,
|
|
78014
|
-
remainingMs: () => Math.max(0, expiresAt -
|
|
78106
|
+
remainingMs: () => Math.max(0, expiresAt - performance3.now()),
|
|
78015
78107
|
dispose: () => clearTimeout(timer)
|
|
78016
78108
|
};
|
|
78017
78109
|
}
|
|
@@ -78637,7 +78729,7 @@ async function startEmbeddedDaemonGeneration(opts) {
|
|
|
78637
78729
|
}
|
|
78638
78730
|
};
|
|
78639
78731
|
const diagnostics = {
|
|
78640
|
-
nowMicros: () => Math.floor(
|
|
78732
|
+
nowMicros: () => Math.floor(performance3.now() * 1e3),
|
|
78641
78733
|
createTraceId: randomUUID23,
|
|
78642
78734
|
publish: publishObserverDiagnostic
|
|
78643
78735
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tmux-ide",
|
|
3
|
-
"version": "2.9.0-beta.
|
|
3
|
+
"version": "2.9.0-beta.21",
|
|
4
4
|
"description": "A visual, agent-aware IDE for any tmux session, with optional workspace presets",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -39,6 +39,7 @@
|
|
|
39
39
|
"typecheck": "echo \"root typecheck deferred to per-package turbo run\"",
|
|
40
40
|
"dev": "node bin/cli.js",
|
|
41
41
|
"dev:instance": "node scripts/development-instance.mjs",
|
|
42
|
+
"dev:pilotty": "node scripts/pilotty-dev.mjs",
|
|
42
43
|
"dev:web": "node scripts/dev-web.mjs",
|
|
43
44
|
"test": "pnpm -r --workspace-concurrency=1 --filter @tmux-ide/daemon --filter @tmux-ide/contracts --filter @tmux-ide/core --filter @tmux-ide/daemon-client --filter @tmux-ide/sdk --filter @tmux-ide/desktop-renderer --filter @tmux-ide/web-workspace --filter @tmux-ide/electron-shell run test",
|
|
44
45
|
"test:unit": "pnpm -r --workspace-concurrency=1 --filter @tmux-ide/daemon --filter @tmux-ide/contracts --filter @tmux-ide/core --filter @tmux-ide/daemon-client --filter @tmux-ide/sdk --filter @tmux-ide/desktop-renderer --filter @tmux-ide/web-workspace --filter @tmux-ide/electron-shell run test",
|
|
@@ -63,7 +64,7 @@
|
|
|
63
64
|
"postinstall": "node scripts/postinstall.js",
|
|
64
65
|
"docs": "turbo run dev --filter=@tmux-ide/docs",
|
|
65
66
|
"demo:tui": "bun --preload @opentui/solid/preload docs/scripts/render-tui-demo.tsx",
|
|
66
|
-
"test:tui-renderer": "bun test --preload @opentui/solid/preload --preload ./packages/daemon/test-support/opentui-renderer-preload.ts ./packages/daemon/src/tui/mirror/pane-surface-renderer.test.tsx ./packages/daemon/src/tui/mirror/native-grid-projection-renderer.test.tsx ./packages/daemon/src/tui/mirror/widget-surface-renderer.test.tsx ./packages/daemon/src/tui/mirror/missions-surface-renderer.test.tsx ./packages/daemon/src/tui/mirror/recipes-gallery-renderer.test.tsx ./packages/daemon/src/tui/mirror/shell-chrome-renderer.test.tsx ./packages/daemon/src/tui/mirror/sidebar-renderer.test.tsx ./packages/daemon/src/tui/mirror/home-files-surface-renderer.test.tsx ./packages/daemon/src/tui/mirror/changes-terminal-surface-renderer.test.tsx ./packages/daemon/src/tui/mirror/activity-surface-renderer.test.tsx ./packages/daemon/src/tui/mirror/features/files/session-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-terminal-workspace-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-shell-view-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-root-error-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-backpressure-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-demand-cadence-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/files-optional-feature-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/changes-optional-feature-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/missions-activity-optional-feature-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/dialogs-optional-feature-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/optional-feature-registry-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/palette-optional-feature-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/pane-scoped-terminal-surface-renderer.test.tsx ./packages/daemon/src/tui/mirror/features/rich-preview/feature.test.ts ./packages/daemon/src/tui/mirror/runtime/rich-preview-optional-feature-renderer.test.tsx ./packages/daemon/src/tui/mirror/workspace/application-shell-renderer.test.tsx ./packages/daemon/src/tui/mirror/workspace/pane-frame-renderer.test.tsx ./packages/daemon/src/tui/mirror/workspace/terminal-pane-chrome-view.test.tsx ./packages/daemon/src/tui/mirror/workspace/terminal-window-strip-renderer.test.tsx ./packages/daemon/src/tui/mirror/workspace/workbench-shell-renderer.test.tsx ./packages/daemon/src/tui/mirror/workspace/workbench-dock-dual-host-renderer.test.tsx ./packages/daemon/src/tui/mirror/workspace/agent-terminal-canvas-renderer.test.tsx ./packages/daemon/src/tui/mirror/workspace/command-palette-surface-renderer.test.tsx ./packages/daemon/src/tui/mirror/workspace/opentui-insertion-stability-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-shell-home-renderer.test.tsx ./packages/daemon/src/tui/mirror/workspace/terminal-pane-header-polish-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-home-agent-roster-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-home-agent-flow-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-shell-sidebar-catalog-renderer.test.tsx ./packages/daemon/src/tui/mirror/ui/ui-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-machine-sidebar-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-add-machine-dialog-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-fleet-switcher-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-palette-preview-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-fleet-palette-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-fleet-session-actions-renderer.test.tsx",
|
|
67
|
+
"test:tui-renderer": "bun test --preload @opentui/solid/preload --preload ./packages/daemon/test-support/opentui-renderer-preload.ts ./packages/daemon/src/tui/mirror/automatic-contrast-renderer.test.tsx ./packages/daemon/src/tui/mirror/pane-surface-renderer.test.tsx ./packages/daemon/src/tui/mirror/native-grid-projection-renderer.test.tsx ./packages/daemon/src/tui/mirror/widget-surface-renderer.test.tsx ./packages/daemon/src/tui/mirror/missions-surface-renderer.test.tsx ./packages/daemon/src/tui/mirror/recipes-gallery-renderer.test.tsx ./packages/daemon/src/tui/mirror/shell-chrome-renderer.test.tsx ./packages/daemon/src/tui/mirror/sidebar-renderer.test.tsx ./packages/daemon/src/tui/mirror/home-files-surface-renderer.test.tsx ./packages/daemon/src/tui/mirror/changes-terminal-surface-renderer.test.tsx ./packages/daemon/src/tui/mirror/activity-surface-renderer.test.tsx ./packages/daemon/src/tui/mirror/features/files/session-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-terminal-workspace-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-shell-view-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-root-error-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-backpressure-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-demand-cadence-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/files-optional-feature-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/changes-optional-feature-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/missions-activity-optional-feature-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/dialogs-optional-feature-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/optional-feature-registry-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/palette-optional-feature-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/pane-scoped-terminal-surface-renderer.test.tsx ./packages/daemon/src/tui/mirror/features/rich-preview/feature.test.ts ./packages/daemon/src/tui/mirror/runtime/rich-preview-optional-feature-renderer.test.tsx ./packages/daemon/src/tui/mirror/workspace/application-shell-renderer.test.tsx ./packages/daemon/src/tui/mirror/workspace/pane-frame-renderer.test.tsx ./packages/daemon/src/tui/mirror/workspace/terminal-pane-chrome-view.test.tsx ./packages/daemon/src/tui/mirror/workspace/terminal-window-strip-renderer.test.tsx ./packages/daemon/src/tui/mirror/workspace/workbench-shell-renderer.test.tsx ./packages/daemon/src/tui/mirror/workspace/workbench-dock-dual-host-renderer.test.tsx ./packages/daemon/src/tui/mirror/workspace/agent-terminal-canvas-renderer.test.tsx ./packages/daemon/src/tui/mirror/workspace/command-palette-surface-renderer.test.tsx ./packages/daemon/src/tui/mirror/workspace/opentui-insertion-stability-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-shell-home-renderer.test.tsx ./packages/daemon/src/tui/mirror/workspace/terminal-pane-header-polish-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-home-agent-roster-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-home-agent-flow-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-shell-sidebar-catalog-renderer.test.tsx ./packages/daemon/src/tui/mirror/ui/ui-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-machine-sidebar-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-add-machine-dialog-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-fleet-switcher-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-palette-preview-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-fleet-palette-renderer.test.tsx ./packages/daemon/src/tui/mirror/runtime/application-fleet-session-actions-renderer.test.tsx",
|
|
67
68
|
"test:tui-smoke": "bun scripts/smoke-tui-missions.mjs",
|
|
68
69
|
"test:tui-live": "node scripts/tui-testdrive.mjs smoke",
|
|
69
70
|
"test:tui-testdrive": "node --test scripts/lib/tui-testdrive-clipboard-hook.test.mjs scripts/lib/tui-testdrive-input.test.mjs",
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { performance } from "node:perf_hooks";
|
|
2
|
+
import { requireOwnerAuthority } from "./owner-authority.js";
|
|
3
|
+
/** One synchronous, demand-only sample. No observers, discovery, or retained baseline. */
|
|
4
|
+
export function sampleDaemonDiagnostics(daemon) {
|
|
5
|
+
const sampledAtMs = Date.now();
|
|
6
|
+
const memory = process.memoryUsage();
|
|
7
|
+
const cpu = process.cpuUsage();
|
|
8
|
+
const eventLoop = performance.eventLoopUtilization();
|
|
9
|
+
// Fixed output cardinality. Unknown runtime resource labels are never echoed.
|
|
10
|
+
const activeResources = {
|
|
11
|
+
Timeout: 0,
|
|
12
|
+
Immediate: 0,
|
|
13
|
+
TCPServerWrap: 0,
|
|
14
|
+
TCPSocketWrap: 0,
|
|
15
|
+
PipeWrap: 0,
|
|
16
|
+
ProcessWrap: 0,
|
|
17
|
+
FSEventWrap: 0,
|
|
18
|
+
other: 0,
|
|
19
|
+
};
|
|
20
|
+
const resourceNames = process.getActiveResourcesInfo?.();
|
|
21
|
+
for (const resource of resourceNames ?? []) {
|
|
22
|
+
if (Object.hasOwn(activeResources, resource) && resource !== "other") {
|
|
23
|
+
activeResources[resource]++;
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
activeResources.other++;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return {
|
|
30
|
+
daemon: {
|
|
31
|
+
protocolVersion: daemon.protocolVersion,
|
|
32
|
+
productVersion: daemon.productVersion,
|
|
33
|
+
instanceId: daemon.instanceId,
|
|
34
|
+
startedAt: daemon.startedAt,
|
|
35
|
+
...(daemon.environmentId !== undefined ? { environmentId: daemon.environmentId } : {}),
|
|
36
|
+
},
|
|
37
|
+
pid: process.pid,
|
|
38
|
+
uptimeMs: process.uptime() * 1000,
|
|
39
|
+
sampledAtMs,
|
|
40
|
+
memory: {
|
|
41
|
+
rss: memory.rss,
|
|
42
|
+
heapTotal: memory.heapTotal,
|
|
43
|
+
heapUsed: memory.heapUsed,
|
|
44
|
+
external: memory.external,
|
|
45
|
+
arrayBuffers: memory.arrayBuffers,
|
|
46
|
+
},
|
|
47
|
+
cpu: { user: cpu.user, system: cpu.system },
|
|
48
|
+
eventLoop: {
|
|
49
|
+
idle: eventLoop.idle,
|
|
50
|
+
active: eventLoop.active,
|
|
51
|
+
utilization: eventLoop.utilization,
|
|
52
|
+
},
|
|
53
|
+
activeResources: resourceNames === undefined ? null : activeResources,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
export function mountDiagnosticsRoute(app, options) {
|
|
57
|
+
app.get("/api/diagnostics", requireOwnerAuthority(options.ownerToken, {
|
|
58
|
+
whenOwnerless: "unavailable",
|
|
59
|
+
unavailableMessage: "Diagnostics unavailable",
|
|
60
|
+
mismatchMessage: "Diagnostics require owner authority",
|
|
61
|
+
}), (c) => {
|
|
62
|
+
c.header("Cache-Control", "no-store");
|
|
63
|
+
return c.json(sampleDaemonDiagnostics(options.daemon));
|
|
64
|
+
});
|
|
65
|
+
}
|
|
@@ -8,6 +8,7 @@ export async function streamBoundedLogs(stream, options) {
|
|
|
8
8
|
let wake = null;
|
|
9
9
|
let unsubscribe = () => { };
|
|
10
10
|
let timer = null;
|
|
11
|
+
let heartbeatTimer = null;
|
|
11
12
|
let cancelWrite = null;
|
|
12
13
|
const cleanup = () => {
|
|
13
14
|
if (closed)
|
|
@@ -19,6 +20,9 @@ export async function streamBoundedLogs(stream, options) {
|
|
|
19
20
|
if (timer)
|
|
20
21
|
clearTimeout(timer);
|
|
21
22
|
timer = null;
|
|
23
|
+
if (heartbeatTimer)
|
|
24
|
+
clearInterval(heartbeatTimer);
|
|
25
|
+
heartbeatTimer = null;
|
|
22
26
|
wake?.();
|
|
23
27
|
wake = null;
|
|
24
28
|
cancelWrite?.();
|
|
@@ -51,6 +55,11 @@ export async function streamBoundedLogs(stream, options) {
|
|
|
51
55
|
unsubscribe();
|
|
52
56
|
return;
|
|
53
57
|
}
|
|
58
|
+
heartbeatTimer = setInterval(() => {
|
|
59
|
+
if (!closed && queue.length === 0 && !push({ event: "heartbeat", data: "keep-alive" }))
|
|
60
|
+
abort();
|
|
61
|
+
}, options.heartbeatIntervalMs ?? 15_000);
|
|
62
|
+
heartbeatTimer.unref?.();
|
|
54
63
|
try {
|
|
55
64
|
// Keep newest bounded history, reserving room for gap/bookmark metadata.
|
|
56
65
|
const retained = [];
|
|
@@ -63,6 +63,7 @@ import { mountWorkspaceResourceRoutes } from "./resources/workspace-resource-rou
|
|
|
63
63
|
import { mountFleetResourceRoute } from "./resources/fleet-resource-route.js";
|
|
64
64
|
import { mountWorkspaceMissionsRoute } from "./resources/workspace-missions-route.js";
|
|
65
65
|
import { ownerAuthorityGate, requireOwnerAuthority } from "./owner-authority.js";
|
|
66
|
+
import { mountDiagnosticsRoute } from "./diagnostics.js";
|
|
66
67
|
import { mountStartupReadinessRoute, } from "./resources/startup-readiness-route.js";
|
|
67
68
|
import { readWidgetAsset } from "../lib/widget-asset-store.js";
|
|
68
69
|
const defaultApplicationShellAppWindowBackend = {
|
|
@@ -316,6 +317,12 @@ export function createApp(options = {}) {
|
|
|
316
317
|
const app = new Hono();
|
|
317
318
|
// Allow cross-origin (Next.js dashboard, Tailscale, etc.)
|
|
318
319
|
app.use("/*", cors());
|
|
320
|
+
// Owner-only reads use the same early routing boundary as issuance below:
|
|
321
|
+
// remote/project credentials neither authorize nor block the owner bearer.
|
|
322
|
+
mountDiagnosticsRoute(app, {
|
|
323
|
+
daemon: daemonInstanceIdentity,
|
|
324
|
+
ownerToken: options.remoteAccess?.ownerToken ?? null,
|
|
325
|
+
});
|
|
319
326
|
// This exact route carries its own owner-only bearer and correlation gate.
|
|
320
327
|
// Mount it before remote and project auth so a valid host capability is
|
|
321
328
|
// neither rejected nor confused with any remotely shared user credential.
|
|
@@ -39,7 +39,8 @@ export const DEFAULT_APP_CONFIG = {
|
|
|
39
39
|
panels: { explorer: "M-e", changes: "M-g", config: "M-," },
|
|
40
40
|
},
|
|
41
41
|
theme: {
|
|
42
|
-
|
|
42
|
+
automaticContrast: true,
|
|
43
|
+
mode: "system",
|
|
43
44
|
accent: "colour75",
|
|
44
45
|
muted: "colour240",
|
|
45
46
|
fg: "colour250",
|
|
@@ -160,7 +161,8 @@ export function parseAppConfig(input) {
|
|
|
160
161
|
},
|
|
161
162
|
},
|
|
162
163
|
theme: {
|
|
163
|
-
|
|
164
|
+
automaticContrast: pickBool(theme.automaticContrast, D.theme.automaticContrast),
|
|
165
|
+
mode: pickChoice(theme.mode, ["dark", "light", "system"], findVisualThemePreset(theme.preset)?.appearance ?? D.theme.mode),
|
|
164
166
|
...(findVisualThemePreset(theme.preset) ? { preset: String(theme.preset) } : {}),
|
|
165
167
|
accent: pickString(theme.accent, D.theme.accent),
|
|
166
168
|
muted: pickString(theme.muted, D.theme.muted),
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/** Pure, allowlisted evidence projection. Never retain response bodies or errors. */
|
|
2
|
+
export const DIAGNOSTICS_MAX_BYTES = 16_384;
|
|
3
|
+
export const RESOURCE_KEYS = [
|
|
4
|
+
"Timeout",
|
|
5
|
+
"Immediate",
|
|
6
|
+
"TCPServerWrap",
|
|
7
|
+
"TCPSocketWrap",
|
|
8
|
+
"PipeWrap",
|
|
9
|
+
"ProcessWrap",
|
|
10
|
+
"FSEventWrap",
|
|
11
|
+
"other",
|
|
12
|
+
];
|
|
13
|
+
export const MEMORY_KEYS = ["rss", "heapTotal", "heapUsed", "external", "arrayBuffers"];
|
|
14
|
+
const object = (v) => !!v && typeof v === "object" && !Array.isArray(v);
|
|
15
|
+
const number = (v) => typeof v === "number" && Number.isFinite(v) && v >= 0;
|
|
16
|
+
const text = (v) => typeof v === "string" && v.length > 0 && v.length <= 256;
|
|
17
|
+
function numeric(v, keys, integer = false) {
|
|
18
|
+
if (!object(v) || !keys.every((k) => number(v[k]) && (!integer || Number.isSafeInteger(v[k]))))
|
|
19
|
+
return null;
|
|
20
|
+
return Object.fromEntries(keys.map((k) => [k, v[k]]));
|
|
21
|
+
}
|
|
22
|
+
export function parseSoakDiagnostics(body, status, expected) {
|
|
23
|
+
const fail = (status) => ({
|
|
24
|
+
status,
|
|
25
|
+
sample: null,
|
|
26
|
+
});
|
|
27
|
+
if (status === 404)
|
|
28
|
+
return fail("unsupported-endpoint");
|
|
29
|
+
if (status !== 200)
|
|
30
|
+
return fail("http-error");
|
|
31
|
+
if (body === null || body === "")
|
|
32
|
+
return fail("missing");
|
|
33
|
+
if (new TextEncoder().encode(body).length > DIAGNOSTICS_MAX_BYTES)
|
|
34
|
+
return fail("malformed");
|
|
35
|
+
let raw;
|
|
36
|
+
try {
|
|
37
|
+
raw = JSON.parse(body);
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
return fail("malformed");
|
|
41
|
+
}
|
|
42
|
+
if (!object(raw) || !object(raw.daemon))
|
|
43
|
+
return fail("malformed");
|
|
44
|
+
const d = raw.daemon;
|
|
45
|
+
if (!Number.isSafeInteger(d.protocolVersion) ||
|
|
46
|
+
!number(d.protocolVersion) ||
|
|
47
|
+
!text(d.productVersion) ||
|
|
48
|
+
!text(d.instanceId) ||
|
|
49
|
+
!text(d.startedAt) ||
|
|
50
|
+
!Number.isFinite(Date.parse(d.startedAt)) ||
|
|
51
|
+
(d.environmentId !== undefined && !text(d.environmentId)) ||
|
|
52
|
+
!Number.isSafeInteger(raw.pid) ||
|
|
53
|
+
!number(raw.pid) ||
|
|
54
|
+
raw.pid === 0)
|
|
55
|
+
return fail("malformed");
|
|
56
|
+
if (["protocolVersion", "productVersion", "instanceId", "startedAt", "environmentId"].some((k) => d[k] !== expected[k]) ||
|
|
57
|
+
raw.pid !== expected.pid)
|
|
58
|
+
return fail("identity-mismatch");
|
|
59
|
+
const memory = numeric(raw.memory, MEMORY_KEYS, true);
|
|
60
|
+
const cpu = numeric(raw.cpu, ["user", "system"], true);
|
|
61
|
+
const eventLoop = numeric(raw.eventLoop, ["idle", "active", "utilization"]);
|
|
62
|
+
const activeResources = raw.activeResources === null ? null : numeric(raw.activeResources, RESOURCE_KEYS, true);
|
|
63
|
+
if (!memory ||
|
|
64
|
+
!cpu ||
|
|
65
|
+
!eventLoop ||
|
|
66
|
+
eventLoop.utilization > 1 ||
|
|
67
|
+
!number(raw.uptimeMs) ||
|
|
68
|
+
!number(raw.sampledAtMs) ||
|
|
69
|
+
(raw.activeResources !== null && !activeResources))
|
|
70
|
+
return fail("malformed");
|
|
71
|
+
return {
|
|
72
|
+
status: "ok",
|
|
73
|
+
sample: {
|
|
74
|
+
daemon: {
|
|
75
|
+
protocolVersion: d.protocolVersion,
|
|
76
|
+
productVersion: d.productVersion,
|
|
77
|
+
instanceId: d.instanceId,
|
|
78
|
+
startedAt: d.startedAt,
|
|
79
|
+
...(d.environmentId !== undefined ? { environmentId: d.environmentId } : {}),
|
|
80
|
+
},
|
|
81
|
+
pid: raw.pid,
|
|
82
|
+
uptimeMs: raw.uptimeMs,
|
|
83
|
+
sampledAtMs: raw.sampledAtMs,
|
|
84
|
+
memory,
|
|
85
|
+
cpu,
|
|
86
|
+
eventLoop,
|
|
87
|
+
activeResources,
|
|
88
|
+
},
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
/** Uptime is monotonic; wall-clock jumps do not change interval rates. */
|
|
92
|
+
export function diagnosticsDelta(previous, current) {
|
|
93
|
+
if (!previous)
|
|
94
|
+
return { status: "missing-baseline" };
|
|
95
|
+
if (previous.pid !== current.pid ||
|
|
96
|
+
["protocolVersion", "productVersion", "instanceId", "startedAt", "environmentId"].some((key) => previous.daemon[key] !==
|
|
97
|
+
current.daemon[key]))
|
|
98
|
+
return { status: "identity-mismatch" };
|
|
99
|
+
const intervalMs = current.uptimeMs - previous.uptimeMs;
|
|
100
|
+
if (!Number.isFinite(intervalMs) || intervalMs <= 0)
|
|
101
|
+
return { status: "invalid-interval" };
|
|
102
|
+
const cpuUserMicros = current.cpu.user - previous.cpu.user;
|
|
103
|
+
const cpuSystemMicros = current.cpu.system - previous.cpu.system;
|
|
104
|
+
const eventLoopIdleMs = current.eventLoop.idle - previous.eventLoop.idle;
|
|
105
|
+
const eventLoopActiveMs = current.eventLoop.active - previous.eventLoop.active;
|
|
106
|
+
if (![cpuUserMicros, cpuSystemMicros, eventLoopIdleMs, eventLoopActiveMs].every(number))
|
|
107
|
+
return { status: "counter-regression" };
|
|
108
|
+
const cpuPercent = (cpuUserMicros + cpuSystemMicros) / (intervalMs * 10);
|
|
109
|
+
if (!Number.isFinite(cpuPercent))
|
|
110
|
+
return { status: "invalid-interval" };
|
|
111
|
+
const eventTotal = eventLoopIdleMs + eventLoopActiveMs;
|
|
112
|
+
if (!Number.isFinite(eventTotal))
|
|
113
|
+
return { status: "invalid-interval" };
|
|
114
|
+
return {
|
|
115
|
+
status: "ok",
|
|
116
|
+
intervalMs,
|
|
117
|
+
cpuUserMicros,
|
|
118
|
+
cpuSystemMicros,
|
|
119
|
+
cpuPercent,
|
|
120
|
+
eventLoopIdleMs,
|
|
121
|
+
eventLoopActiveMs,
|
|
122
|
+
eventLoopUtilization: eventTotal === 0 ? null : eventLoopActiveMs / eventTotal,
|
|
123
|
+
};
|
|
124
|
+
}
|