@pellux/goodvibes-sdk 0.18.27 → 0.18.29
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_internal/platform/agents/orchestrator-runner.js +1 -1
- package/dist/_internal/platform/bookmarks/manager.d.ts +1 -1
- package/dist/_internal/platform/bookmarks/manager.d.ts.map +1 -1
- package/dist/_internal/platform/channels/surface-registry.js +3 -3
- package/dist/_internal/platform/config/api-keys.d.ts +29 -0
- package/dist/_internal/platform/config/api-keys.d.ts.map +1 -0
- package/dist/_internal/platform/config/api-keys.js +153 -0
- package/dist/_internal/platform/config/index.d.ts +1 -13
- package/dist/_internal/platform/config/index.d.ts.map +1 -1
- package/dist/_internal/platform/config/index.js +1 -138
- package/dist/_internal/platform/core/conversation-diff.d.ts +6 -2
- package/dist/_internal/platform/core/conversation-diff.d.ts.map +1 -1
- package/dist/_internal/platform/core/conversation.d.ts +13 -5
- package/dist/_internal/platform/core/conversation.d.ts.map +1 -1
- package/dist/_internal/platform/core/conversation.js +35 -1
- package/dist/_internal/platform/plugins/loader.d.ts +5 -1
- package/dist/_internal/platform/plugins/loader.d.ts.map +1 -1
- package/dist/_internal/platform/plugins/loader.js +7 -3
- package/dist/_internal/platform/runtime/bootstrap-hook-bridge.d.ts +10 -0
- package/dist/_internal/platform/runtime/bootstrap-hook-bridge.d.ts.map +1 -0
- package/dist/_internal/platform/runtime/bootstrap-hook-bridge.js +143 -0
- package/dist/_internal/platform/runtime/diagnostics/panels/panel-resources.d.ts +5 -5
- package/dist/_internal/platform/runtime/diagnostics/panels/panel-resources.d.ts.map +1 -1
- package/dist/_internal/platform/runtime/diagnostics/panels/panel-resources.js +3 -3
- package/dist/_internal/platform/runtime/diagnostics/types.d.ts +26 -13
- package/dist/_internal/platform/runtime/diagnostics/types.d.ts.map +1 -1
- package/dist/_internal/platform/runtime/diagnostics/types.js +4 -2
- package/dist/_internal/platform/runtime/mutable-runtime-state.d.ts +14 -0
- package/dist/_internal/platform/runtime/mutable-runtime-state.d.ts.map +1 -0
- package/dist/_internal/platform/runtime/mutable-runtime-state.js +1 -0
- package/dist/_internal/platform/runtime/ops/playbooks/permission-deadlock.js +2 -2
- package/dist/_internal/platform/runtime/perf/component-contracts.d.ts +114 -0
- package/dist/_internal/platform/runtime/perf/component-contracts.d.ts.map +1 -0
- package/dist/_internal/platform/runtime/perf/component-contracts.js +104 -0
- package/dist/_internal/platform/runtime/perf/component-health-monitor.d.ts +98 -0
- package/dist/_internal/platform/runtime/perf/component-health-monitor.d.ts.map +1 -0
- package/dist/_internal/platform/runtime/perf/component-health-monitor.js +248 -0
- package/dist/_internal/platform/runtime/perf/index.d.ts +6 -3
- package/dist/_internal/platform/runtime/perf/index.d.ts.map +1 -1
- package/dist/_internal/platform/runtime/perf/index.js +4 -2
- package/dist/_internal/platform/runtime/perf/panel-contracts.d.ts +6 -90
- package/dist/_internal/platform/runtime/perf/panel-contracts.d.ts.map +1 -1
- package/dist/_internal/platform/runtime/perf/panel-contracts.js +4 -83
- package/dist/_internal/platform/runtime/perf/panel-health-monitor.d.ts +4 -88
- package/dist/_internal/platform/runtime/perf/panel-health-monitor.d.ts.map +1 -1
- package/dist/_internal/platform/runtime/perf/panel-health-monitor.js +4 -236
- package/dist/_internal/platform/runtime/service-queries.d.ts +3 -0
- package/dist/_internal/platform/runtime/service-queries.d.ts.map +1 -0
- package/dist/_internal/platform/runtime/service-queries.js +1 -0
- package/dist/_internal/platform/runtime/services.d.ts +2 -2
- package/dist/_internal/platform/runtime/services.d.ts.map +1 -1
- package/dist/_internal/platform/runtime/services.js +3 -3
- package/dist/_internal/platform/runtime/session-persistence.d.ts +3 -3
- package/dist/_internal/platform/runtime/session-persistence.d.ts.map +1 -1
- package/dist/_internal/platform/runtime/session-persistence.js +13 -13
- package/dist/_internal/platform/runtime/session-return-context.js +1 -1
- package/dist/_internal/platform/runtime/shell-command-services.d.ts +2 -2
- package/dist/_internal/platform/runtime/shell-command-services.d.ts.map +1 -1
- package/dist/_internal/platform/runtime/shell-command-services.js +2 -2
- package/dist/_internal/platform/runtime/shell-command-workspace.d.ts +2 -2
- package/dist/_internal/platform/runtime/shell-command-workspace.d.ts.map +1 -1
- package/dist/_internal/platform/runtime/shell-command-workspace.js +2 -2
- package/dist/_internal/platform/runtime/store/domains/index.d.ts +2 -0
- package/dist/_internal/platform/runtime/store/domains/index.d.ts.map +1 -1
- package/dist/_internal/platform/runtime/store/domains/index.js +1 -0
- package/dist/_internal/platform/runtime/store/selectors/index.d.ts +27 -14
- package/dist/_internal/platform/runtime/store/selectors/index.d.ts.map +1 -1
- package/dist/_internal/platform/runtime/store/selectors/index.js +35 -25
- package/dist/_internal/platform/runtime/store/state.d.ts +3 -4
- package/dist/_internal/platform/runtime/store/state.d.ts.map +1 -1
- package/dist/_internal/platform/runtime/store/state.js +3 -4
- package/dist/_internal/platform/runtime/system-message-policy.d.ts +18 -0
- package/dist/_internal/platform/runtime/system-message-policy.d.ts.map +1 -0
- package/dist/_internal/platform/runtime/system-message-policy.js +35 -0
- package/dist/_internal/platform/utils/clipboard.d.ts +3 -2
- package/dist/_internal/platform/utils/clipboard.d.ts.map +1 -1
- package/dist/_internal/platform/utils/clipboard.js +0 -17
- package/dist/_internal/platform/utils/notify.d.ts.map +1 -1
- package/dist/_internal/platform/utils/notify.js +4 -1
- package/dist/_internal/platform/utils/terminal-width.d.ts +13 -0
- package/dist/_internal/platform/utils/terminal-width.d.ts.map +1 -1
- package/dist/_internal/platform/utils/terminal-width.js +13 -0
- package/dist/_internal/platform/version.js +1 -1
- package/package.json +1 -1
- package/dist/_internal/platform/core/history.d.ts +0 -22
- package/dist/_internal/platform/core/history.d.ts.map +0 -1
- package/dist/_internal/platform/core/history.js +0 -43
- package/dist/_internal/platform/types/grid.d.ts +0 -27
- package/dist/_internal/platform/types/grid.d.ts.map +0 -1
- package/dist/_internal/platform/types/grid.js +0 -26
- package/dist/_internal/platform/utils/splash-lines.d.ts +0 -8
- package/dist/_internal/platform/utils/splash-lines.d.ts.map +0 -1
- package/dist/_internal/platform/utils/splash-lines.js +0 -32
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ComponentHealthMonitor — enforces per-component resource contracts.
|
|
3
|
+
*
|
|
4
|
+
* Tracks update rate and render cost per component. Components that exceed their
|
|
5
|
+
* contracted budget are throttled (render gated to a minimum interval).
|
|
6
|
+
* Components with sustained violations are degraded (rendered at a fixed low rate).
|
|
7
|
+
*
|
|
8
|
+
* The monitor does NOT render components itself — callers ask canRender() before
|
|
9
|
+
* rendering and report the actual render cost via recordRender().
|
|
10
|
+
*
|
|
11
|
+
* This keeps the monitor policy-focused and the rendering path ignorant of
|
|
12
|
+
* throttling policy details.
|
|
13
|
+
*
|
|
14
|
+
* Surface-agnostic: a TUI panel, a web widget, or any other renderable unit
|
|
15
|
+
* can register with this monitor. The TUI uses componentId values that
|
|
16
|
+
* correspond to panel identifiers; other surfaces use their own naming.
|
|
17
|
+
*/
|
|
18
|
+
import type { ComponentResourceContract, ComponentHealthState } from './component-contracts.js';
|
|
19
|
+
/**
|
|
20
|
+
* ComponentHealthMonitor — tracks component resource usage and enforces budgets.
|
|
21
|
+
*
|
|
22
|
+
* Usage:
|
|
23
|
+
* 1. Register components with register(componentId, category).
|
|
24
|
+
* 2. Before rendering: if (!monitor.canRender(componentId, now)) skip the render.
|
|
25
|
+
* 3. After rendering: monitor.recordRender(componentId, durationMs, now).
|
|
26
|
+
* 4. Read health via getHealth(componentId) or getAllHealth().
|
|
27
|
+
*/
|
|
28
|
+
export declare class ComponentHealthMonitor {
|
|
29
|
+
private readonly _tracks;
|
|
30
|
+
/**
|
|
31
|
+
* Register a component with the monitor.
|
|
32
|
+
*
|
|
33
|
+
* If the component is already registered, this is a no-op.
|
|
34
|
+
*
|
|
35
|
+
* @param componentId - Unique component identifier.
|
|
36
|
+
* @param category - Component category (used to select the base contract).
|
|
37
|
+
* @param contractOverrides - Optional per-component contract overrides.
|
|
38
|
+
*/
|
|
39
|
+
register(componentId: string, category: string, contractOverrides?: Partial<Omit<ComponentResourceContract, 'componentId'>>): void;
|
|
40
|
+
/**
|
|
41
|
+
* Deregister a component, removing all tracking state.
|
|
42
|
+
*/
|
|
43
|
+
deregister(componentId: string): void;
|
|
44
|
+
/**
|
|
45
|
+
* Check whether a component is permitted to render at the given time.
|
|
46
|
+
*
|
|
47
|
+
* Records the render request for rate tracking regardless of the outcome.
|
|
48
|
+
* If the component is not registered, renders are always permitted.
|
|
49
|
+
*
|
|
50
|
+
* @param componentId - Component to check.
|
|
51
|
+
* @param now - Current epoch ms (defaults to Date.now()).
|
|
52
|
+
* @returns true if the render is permitted; false if it should be skipped.
|
|
53
|
+
*/
|
|
54
|
+
canRender(componentId: string, now?: number): boolean;
|
|
55
|
+
/**
|
|
56
|
+
* Record the actual render duration for a component.
|
|
57
|
+
*
|
|
58
|
+
* Should be called after every permitted render completes. Updates the
|
|
59
|
+
* p95 render cost and may escalate the component's throttle status if the
|
|
60
|
+
* render cost budget is violated.
|
|
61
|
+
*
|
|
62
|
+
* @param componentId - Component that rendered.
|
|
63
|
+
* @param durationMs - Actual render duration in milliseconds.
|
|
64
|
+
* @param now - Epoch ms at render completion (defaults to Date.now()).
|
|
65
|
+
*/
|
|
66
|
+
recordRender(componentId: string, durationMs: number, now?: number): void;
|
|
67
|
+
/**
|
|
68
|
+
* Return the current health state for a component, or undefined if not registered.
|
|
69
|
+
*/
|
|
70
|
+
getHealth(componentId: string): ComponentHealthState | undefined;
|
|
71
|
+
/**
|
|
72
|
+
* Return health states for all registered components.
|
|
73
|
+
*/
|
|
74
|
+
getAllHealth(): ComponentHealthState[];
|
|
75
|
+
/**
|
|
76
|
+
* Return the resource contract for a registered component, or undefined.
|
|
77
|
+
*/
|
|
78
|
+
getContract(componentId: string): ComponentResourceContract | undefined;
|
|
79
|
+
/**
|
|
80
|
+
* Forcibly reset a component's health state to normal.
|
|
81
|
+
* Useful for tests or manual operator intervention.
|
|
82
|
+
*/
|
|
83
|
+
resetHealth(componentId: string): void;
|
|
84
|
+
private _rotateWindow;
|
|
85
|
+
private _applyViolation;
|
|
86
|
+
/**
|
|
87
|
+
* Dual-path recovery: `_recordClean` handles render-cost-based recovery
|
|
88
|
+
* (triggered from `recordRender` after a cheap render), while `_rotateWindow`
|
|
89
|
+
* handles rate-based recovery (triggered at window boundaries). Both paths
|
|
90
|
+
* call `_recover` once the clean-window threshold is met, so either signal
|
|
91
|
+
* alone is sufficient to restore a component to normal status.
|
|
92
|
+
*/
|
|
93
|
+
private _recordClean;
|
|
94
|
+
private _recover;
|
|
95
|
+
}
|
|
96
|
+
/** @deprecated Use ComponentHealthMonitor */
|
|
97
|
+
export { ComponentHealthMonitor as PanelHealthMonitor };
|
|
98
|
+
//# sourceMappingURL=component-health-monitor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"component-health-monitor.d.ts","sourceRoot":"","sources":["../../../../../src/_internal/platform/runtime/perf/component-health-monitor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,yBAAyB,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAqChG;;;;;;;;GAQG;AACH,qBAAa,sBAAsB;IACjC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA0C;IAElE;;;;;;;;OAQG;IACH,QAAQ,CACN,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,EAChB,iBAAiB,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,yBAAyB,EAAE,aAAa,CAAC,CAAC,GAC1E,IAAI;IAgBP;;OAEG;IACH,UAAU,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI;IAIrC;;;;;;;;;OASG;IACH,SAAS,CAAC,WAAW,EAAE,MAAM,EAAE,GAAG,GAAE,MAAmB,GAAG,OAAO;IAmCjE;;;;;;;;;;OAUG;IACH,YAAY,CAAC,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,GAAE,MAAmB,GAAG,IAAI;IA2BrF;;OAEG;IACH,SAAS,CAAC,WAAW,EAAE,MAAM,GAAG,oBAAoB,GAAG,SAAS;IAIhE;;OAEG;IACH,YAAY,IAAI,oBAAoB,EAAE;IAItC;;OAEG;IACH,WAAW,CAAC,WAAW,EAAE,MAAM,GAAG,yBAAyB,GAAG,SAAS;IAIvE;;;OAGG;IACH,WAAW,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI;IAatC,OAAO,CAAC,aAAa;IA2BrB,OAAO,CAAC,eAAe;IAiBvB;;;;;;OAMG;IACH,OAAO,CAAC,YAAY;IASpB,OAAO,CAAC,QAAQ;CAOjB;AAMD,6CAA6C;AAC7C,OAAO,EAAE,sBAAsB,IAAI,kBAAkB,EAAE,CAAC"}
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ComponentHealthMonitor — enforces per-component resource contracts.
|
|
3
|
+
*
|
|
4
|
+
* Tracks update rate and render cost per component. Components that exceed their
|
|
5
|
+
* contracted budget are throttled (render gated to a minimum interval).
|
|
6
|
+
* Components with sustained violations are degraded (rendered at a fixed low rate).
|
|
7
|
+
*
|
|
8
|
+
* The monitor does NOT render components itself — callers ask canRender() before
|
|
9
|
+
* rendering and report the actual render cost via recordRender().
|
|
10
|
+
*
|
|
11
|
+
* This keeps the monitor policy-focused and the rendering path ignorant of
|
|
12
|
+
* throttling policy details.
|
|
13
|
+
*
|
|
14
|
+
* Surface-agnostic: a TUI panel, a web widget, or any other renderable unit
|
|
15
|
+
* can register with this monitor. The TUI uses componentId values that
|
|
16
|
+
* correspond to panel identifiers; other surfaces use their own naming.
|
|
17
|
+
*/
|
|
18
|
+
import { CATEGORY_CONTRACTS, buildContract, createInitialComponentHealthState, } from './component-contracts.js';
|
|
19
|
+
/** Measurement window for update-rate enforcement (ms). */
|
|
20
|
+
const RATE_WINDOW_MS = 1000;
|
|
21
|
+
/** Number of recent render durations to keep for p95 calculation. */
|
|
22
|
+
const RENDER_SAMPLE_CAPACITY = 20;
|
|
23
|
+
/** Recovery: violations reset to 0 after this many consecutive clean windows. */
|
|
24
|
+
const RECOVERY_CLEAN_WINDOWS = 3;
|
|
25
|
+
/**
|
|
26
|
+
* ComponentHealthMonitor — tracks component resource usage and enforces budgets.
|
|
27
|
+
*
|
|
28
|
+
* Usage:
|
|
29
|
+
* 1. Register components with register(componentId, category).
|
|
30
|
+
* 2. Before rendering: if (!monitor.canRender(componentId, now)) skip the render.
|
|
31
|
+
* 3. After rendering: monitor.recordRender(componentId, durationMs, now).
|
|
32
|
+
* 4. Read health via getHealth(componentId) or getAllHealth().
|
|
33
|
+
*/
|
|
34
|
+
export class ComponentHealthMonitor {
|
|
35
|
+
_tracks = new Map();
|
|
36
|
+
/**
|
|
37
|
+
* Register a component with the monitor.
|
|
38
|
+
*
|
|
39
|
+
* If the component is already registered, this is a no-op.
|
|
40
|
+
*
|
|
41
|
+
* @param componentId - Unique component identifier.
|
|
42
|
+
* @param category - Component category (used to select the base contract).
|
|
43
|
+
* @param contractOverrides - Optional per-component contract overrides.
|
|
44
|
+
*/
|
|
45
|
+
register(componentId, category, contractOverrides) {
|
|
46
|
+
if (this._tracks.has(componentId))
|
|
47
|
+
return;
|
|
48
|
+
const contract = buildContract(componentId, category, contractOverrides);
|
|
49
|
+
const health = createInitialComponentHealthState(componentId);
|
|
50
|
+
this._tracks.set(componentId, {
|
|
51
|
+
contract,
|
|
52
|
+
health,
|
|
53
|
+
renderSamples: { buf: new Array(RENDER_SAMPLE_CAPACITY), head: 0, size: 0 },
|
|
54
|
+
windowRequests: [],
|
|
55
|
+
cleanWindows: 0,
|
|
56
|
+
windowStart: 0,
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Deregister a component, removing all tracking state.
|
|
61
|
+
*/
|
|
62
|
+
deregister(componentId) {
|
|
63
|
+
this._tracks.delete(componentId);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Check whether a component is permitted to render at the given time.
|
|
67
|
+
*
|
|
68
|
+
* Records the render request for rate tracking regardless of the outcome.
|
|
69
|
+
* If the component is not registered, renders are always permitted.
|
|
70
|
+
*
|
|
71
|
+
* @param componentId - Component to check.
|
|
72
|
+
* @param now - Current epoch ms (defaults to Date.now()).
|
|
73
|
+
* @returns true if the render is permitted; false if it should be skipped.
|
|
74
|
+
*/
|
|
75
|
+
canRender(componentId, now = Date.now()) {
|
|
76
|
+
const track = this._tracks.get(componentId);
|
|
77
|
+
if (!track)
|
|
78
|
+
return true; // unregistered components are always permitted
|
|
79
|
+
// Rotate the measurement window if needed
|
|
80
|
+
this._rotateWindow(track, now);
|
|
81
|
+
// Gate on throttle/degrade interval
|
|
82
|
+
if (now < track.health.nextAllowedAt) {
|
|
83
|
+
track.health.totalSuppressed++;
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
// Record this request in the current window
|
|
87
|
+
track.windowRequests.push(now);
|
|
88
|
+
// Check update rate limit
|
|
89
|
+
let requestsInWindow = 0;
|
|
90
|
+
for (const t of track.windowRequests) {
|
|
91
|
+
if (now - t < RATE_WINDOW_MS)
|
|
92
|
+
requestsInWindow++;
|
|
93
|
+
}
|
|
94
|
+
// Note: stale entries older than RATE_WINDOW_MS are pruned at window rotation, not here
|
|
95
|
+
const maxPerWindow = track.contract.maxUpdatesPerSecond;
|
|
96
|
+
if (requestsInWindow > maxPerWindow) {
|
|
97
|
+
// Rate exceeded: throttle or degrade
|
|
98
|
+
this._applyViolation(track, now);
|
|
99
|
+
track.health.totalSuppressed++;
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
track.health.totalPermitted++;
|
|
103
|
+
return true;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Record the actual render duration for a component.
|
|
107
|
+
*
|
|
108
|
+
* Should be called after every permitted render completes. Updates the
|
|
109
|
+
* p95 render cost and may escalate the component's throttle status if the
|
|
110
|
+
* render cost budget is violated.
|
|
111
|
+
*
|
|
112
|
+
* @param componentId - Component that rendered.
|
|
113
|
+
* @param durationMs - Actual render duration in milliseconds.
|
|
114
|
+
* @param now - Epoch ms at render completion (defaults to Date.now()).
|
|
115
|
+
*/
|
|
116
|
+
recordRender(componentId, durationMs, now = Date.now()) {
|
|
117
|
+
const track = this._tracks.get(componentId);
|
|
118
|
+
if (!track)
|
|
119
|
+
return;
|
|
120
|
+
// Add sample to ring buffer (O(1) modular index — no shift/realloc)
|
|
121
|
+
const rb = track.renderSamples;
|
|
122
|
+
rb.buf[rb.head] = durationMs;
|
|
123
|
+
rb.head = (rb.head + 1) % RENDER_SAMPLE_CAPACITY;
|
|
124
|
+
if (rb.size < RENDER_SAMPLE_CAPACITY)
|
|
125
|
+
rb.size++;
|
|
126
|
+
// Update p95
|
|
127
|
+
const samples = rb.buf.slice(0, rb.size);
|
|
128
|
+
samples.sort((a, b) => a - b); // sort in-place, no second copy
|
|
129
|
+
const p95Val = samples[Math.ceil(samples.length * 0.95) - 1] ?? 0;
|
|
130
|
+
track.health.renderP95Ms = p95Val;
|
|
131
|
+
track.health.lastRenderAt = now;
|
|
132
|
+
track.health.rendersInWindow++;
|
|
133
|
+
// Check render cost budget
|
|
134
|
+
if (track.health.renderP95Ms > track.contract.maxRenderMs) {
|
|
135
|
+
this._applyViolation(track, now);
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
// Render cost within budget — count as a clean observation
|
|
139
|
+
this._recordClean(track);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Return the current health state for a component, or undefined if not registered.
|
|
144
|
+
*/
|
|
145
|
+
getHealth(componentId) {
|
|
146
|
+
return this._tracks.get(componentId)?.health;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Return health states for all registered components.
|
|
150
|
+
*/
|
|
151
|
+
getAllHealth() {
|
|
152
|
+
return Array.from(this._tracks.values()).map((t) => ({ ...t.health }));
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Return the resource contract for a registered component, or undefined.
|
|
156
|
+
*/
|
|
157
|
+
getContract(componentId) {
|
|
158
|
+
return this._tracks.get(componentId)?.contract;
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Forcibly reset a component's health state to normal.
|
|
162
|
+
* Useful for tests or manual operator intervention.
|
|
163
|
+
*/
|
|
164
|
+
resetHealth(componentId) {
|
|
165
|
+
const track = this._tracks.get(componentId);
|
|
166
|
+
if (!track)
|
|
167
|
+
return;
|
|
168
|
+
track.health = createInitialComponentHealthState(componentId);
|
|
169
|
+
track.renderSamples = { buf: new Array(RENDER_SAMPLE_CAPACITY), head: 0, size: 0 };
|
|
170
|
+
track.windowRequests = [];
|
|
171
|
+
track.cleanWindows = 0;
|
|
172
|
+
}
|
|
173
|
+
// ---------------------------------------------------------------------------
|
|
174
|
+
// Private helpers
|
|
175
|
+
// ---------------------------------------------------------------------------
|
|
176
|
+
_rotateWindow(track, now) {
|
|
177
|
+
if (track.windowStart === 0) {
|
|
178
|
+
track.windowStart = now;
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
if (now - track.windowStart >= RATE_WINDOW_MS) {
|
|
182
|
+
// Check for recovery
|
|
183
|
+
let requestsLastWindow = 0;
|
|
184
|
+
for (const t of track.windowRequests) {
|
|
185
|
+
if (t >= track.windowStart && t < track.windowStart + RATE_WINDOW_MS)
|
|
186
|
+
requestsLastWindow++;
|
|
187
|
+
}
|
|
188
|
+
const withinBudget = requestsLastWindow <= track.contract.maxUpdatesPerSecond;
|
|
189
|
+
if (withinBudget) {
|
|
190
|
+
track.cleanWindows++;
|
|
191
|
+
if (track.cleanWindows >= RECOVERY_CLEAN_WINDOWS) {
|
|
192
|
+
this._recover(track);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
else {
|
|
196
|
+
track.cleanWindows = 0;
|
|
197
|
+
}
|
|
198
|
+
// Discard old requests
|
|
199
|
+
track.windowRequests = track.windowRequests.filter((t) => now - t < RATE_WINDOW_MS);
|
|
200
|
+
track.windowStart = now;
|
|
201
|
+
track.health.rendersInWindow = 0;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
_applyViolation(track, now) {
|
|
205
|
+
track.health.consecutiveViolations++;
|
|
206
|
+
track.cleanWindows = 0;
|
|
207
|
+
if (track.health.consecutiveViolations >= track.contract.degradeAfterViolations) {
|
|
208
|
+
// Escalate to degraded
|
|
209
|
+
track.health.throttleStatus = 'degraded';
|
|
210
|
+
track.health.healthStatus = 'overloaded';
|
|
211
|
+
track.health.nextAllowedAt = now + track.contract.degradedIntervalMs;
|
|
212
|
+
}
|
|
213
|
+
else {
|
|
214
|
+
// Apply standard throttle
|
|
215
|
+
track.health.throttleStatus = 'throttled';
|
|
216
|
+
track.health.healthStatus = 'warning';
|
|
217
|
+
track.health.nextAllowedAt = now + track.contract.throttleIntervalMs;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Dual-path recovery: `_recordClean` handles render-cost-based recovery
|
|
222
|
+
* (triggered from `recordRender` after a cheap render), while `_rotateWindow`
|
|
223
|
+
* handles rate-based recovery (triggered at window boundaries). Both paths
|
|
224
|
+
* call `_recover` once the clean-window threshold is met, so either signal
|
|
225
|
+
* alone is sufficient to restore a component to normal status.
|
|
226
|
+
*/
|
|
227
|
+
_recordClean(track) {
|
|
228
|
+
// Only advance recovery if we're already throttled/degraded
|
|
229
|
+
if (track.health.throttleStatus === 'normal')
|
|
230
|
+
return;
|
|
231
|
+
track.cleanWindows++;
|
|
232
|
+
if (track.cleanWindows >= RECOVERY_CLEAN_WINDOWS) {
|
|
233
|
+
this._recover(track);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
_recover(track) {
|
|
237
|
+
track.health.throttleStatus = 'normal';
|
|
238
|
+
track.health.healthStatus = 'healthy';
|
|
239
|
+
track.health.consecutiveViolations = 0;
|
|
240
|
+
track.health.nextAllowedAt = 0;
|
|
241
|
+
track.cleanWindows = 0;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
// ---------------------------------------------------------------------------
|
|
245
|
+
// Backward-compatible alias
|
|
246
|
+
// ---------------------------------------------------------------------------
|
|
247
|
+
/** @deprecated Use ComponentHealthMonitor */
|
|
248
|
+
export { ComponentHealthMonitor as PanelHealthMonitor };
|
|
@@ -18,9 +18,12 @@ export { PerfMonitor } from '@pellux/goodvibes-sdk/platform/runtime/perf/monitor
|
|
|
18
18
|
export type { PerfSnapshot } from '@pellux/goodvibes-sdk/platform/runtime/perf/monitor';
|
|
19
19
|
export { formatReport, exitCode } from '@pellux/goodvibes-sdk/platform/runtime/perf/reporter';
|
|
20
20
|
export { SloCollector, SLO_METRICS } from './slo-collector.js';
|
|
21
|
-
export type {
|
|
22
|
-
export { CATEGORY_CONTRACTS, buildContract,
|
|
23
|
-
export {
|
|
21
|
+
export type { ComponentResourceContract, ComponentHealthState, ComponentThrottleStatus, ComponentHealthStatus, } from '@pellux/goodvibes-sdk/platform/runtime/perf/component-contracts';
|
|
22
|
+
export { CATEGORY_CONTRACTS, buildContract, createInitialComponentHealthState, } from '@pellux/goodvibes-sdk/platform/runtime/perf/component-contracts';
|
|
23
|
+
export { ComponentHealthMonitor } from '@pellux/goodvibes-sdk/platform/runtime/perf/component-health-monitor';
|
|
24
|
+
export type { PanelResourceContract, PanelHealthState, PanelThrottleStatus, PanelHealthStatus, } from '@pellux/goodvibes-sdk/platform/runtime/perf/component-contracts';
|
|
25
|
+
export { createInitialPanelHealthState, } from '@pellux/goodvibes-sdk/platform/runtime/perf/component-contracts';
|
|
26
|
+
export { PanelHealthMonitor, } from '@pellux/goodvibes-sdk/platform/runtime/perf/component-health-monitor';
|
|
24
27
|
import { PerfMonitor } from '@pellux/goodvibes-sdk/platform/runtime/perf/monitor';
|
|
25
28
|
import type { PerfBudget } from '@pellux/goodvibes-sdk/platform/runtime/perf/types';
|
|
26
29
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/_internal/platform/runtime/perf/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,YAAY,EACV,UAAU,EACV,UAAU,EACV,eAAe,EACf,UAAU,EACV,QAAQ,GACT,MAAM,mDAAmD,CAAC;AAE3D,OAAO,EAAE,eAAe,EAAE,MAAM,qDAAqD,CAAC;AACtF,OAAO,EAAE,WAAW,EAAE,MAAM,qDAAqD,CAAC;AAClF,YAAY,EAAE,YAAY,EAAE,MAAM,qDAAqD,CAAC;AACxF,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,sDAAsD,CAAC;AAC9F,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/_internal/platform/runtime/perf/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,YAAY,EACV,UAAU,EACV,UAAU,EACV,eAAe,EACf,UAAU,EACV,QAAQ,GACT,MAAM,mDAAmD,CAAC;AAE3D,OAAO,EAAE,eAAe,EAAE,MAAM,qDAAqD,CAAC;AACtF,OAAO,EAAE,WAAW,EAAE,MAAM,qDAAqD,CAAC;AAClF,YAAY,EAAE,YAAY,EAAE,MAAM,qDAAqD,CAAC;AACxF,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,sDAAsD,CAAC;AAC9F,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAE/D,YAAY,EACV,yBAAyB,EACzB,oBAAoB,EACpB,uBAAuB,EACvB,qBAAqB,GACtB,MAAM,iEAAiE,CAAC;AACzE,OAAO,EACL,kBAAkB,EAClB,aAAa,EACb,iCAAiC,GAClC,MAAM,iEAAiE,CAAC;AACzE,OAAO,EAAE,sBAAsB,EAAE,MAAM,sEAAsE,CAAC;AAG9G,YAAY,EACV,qBAAqB,EACrB,gBAAgB,EAChB,mBAAmB,EACnB,iBAAiB,GAClB,MAAM,iEAAiE,CAAC;AACzE,OAAO,EACL,6BAA6B,GAC9B,MAAM,iEAAiE,CAAC;AACzE,OAAO,EACL,kBAAkB,GACnB,MAAM,sEAAsE,CAAC;AAE9E,OAAO,EAAE,WAAW,EAAE,MAAM,qDAAqD,CAAC;AAClF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mDAAmD,CAAC;AAGpF;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,GAAE,UAAU,EAAoB,GAAG,WAAW,CAEtF"}
|
|
@@ -16,8 +16,10 @@ export { DEFAULT_BUDGETS } from '@pellux/goodvibes-sdk/platform/runtime/perf/bud
|
|
|
16
16
|
export { PerfMonitor } from '@pellux/goodvibes-sdk/platform/runtime/perf/monitor';
|
|
17
17
|
export { formatReport, exitCode } from '@pellux/goodvibes-sdk/platform/runtime/perf/reporter';
|
|
18
18
|
export { SloCollector, SLO_METRICS } from './slo-collector.js';
|
|
19
|
-
export { CATEGORY_CONTRACTS, buildContract,
|
|
20
|
-
export {
|
|
19
|
+
export { CATEGORY_CONTRACTS, buildContract, createInitialComponentHealthState, } from '@pellux/goodvibes-sdk/platform/runtime/perf/component-contracts';
|
|
20
|
+
export { ComponentHealthMonitor } from '@pellux/goodvibes-sdk/platform/runtime/perf/component-health-monitor';
|
|
21
|
+
export { createInitialPanelHealthState, } from '@pellux/goodvibes-sdk/platform/runtime/perf/component-contracts';
|
|
22
|
+
export { PanelHealthMonitor, } from '@pellux/goodvibes-sdk/platform/runtime/perf/component-health-monitor';
|
|
21
23
|
import { PerfMonitor } from '@pellux/goodvibes-sdk/platform/runtime/perf/monitor';
|
|
22
24
|
import { DEFAULT_BUDGETS } from '@pellux/goodvibes-sdk/platform/runtime/perf/budgets';
|
|
23
25
|
/**
|
|
@@ -1,94 +1,10 @@
|
|
|
1
|
-
/** SDK-owned platform module. This implementation is maintained in goodvibes-sdk. */
|
|
2
1
|
/**
|
|
3
|
-
*
|
|
2
|
+
* @deprecated This module has been renamed. Import from component-contracts.js instead.
|
|
4
3
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* runtime, throttling or degrading panels that exceed their budgets.
|
|
4
|
+
* This file is a backward-compatibility shim. All types and functions are
|
|
5
|
+
* re-exported from component-contracts.ts under their original Panel* names.
|
|
8
6
|
*/
|
|
9
|
-
|
|
10
|
-
export type PanelThrottleStatus
|
|
11
|
-
|
|
12
|
-
export type PanelHealthStatus = 'healthy' | 'warning' | 'overloaded';
|
|
13
|
-
/**
|
|
14
|
-
* Resource contract for a single panel.
|
|
15
|
-
*
|
|
16
|
-
* Defines the maximum acceptable update rate and render cost budget.
|
|
17
|
-
* Violations trigger throttling; sustained violations trigger degradation.
|
|
18
|
-
*/
|
|
19
|
-
export interface PanelResourceContract {
|
|
20
|
-
/** Panel id this contract applies to. */
|
|
21
|
-
panelId: string;
|
|
22
|
-
/**
|
|
23
|
-
* Maximum updates per second the panel is allowed to request.
|
|
24
|
-
* Panels that exceed this rate are throttled.
|
|
25
|
-
*/
|
|
26
|
-
maxUpdatesPerSecond: number;
|
|
27
|
-
/**
|
|
28
|
-
* Maximum acceptable render duration in milliseconds (p95).
|
|
29
|
-
* Panels that consistently exceed this are degraded.
|
|
30
|
-
*/
|
|
31
|
-
maxRenderMs: number;
|
|
32
|
-
/**
|
|
33
|
-
* Minimum interval in milliseconds between renders when throttled.
|
|
34
|
-
* The monitor enforces this floor when the panel exceeds its update rate.
|
|
35
|
-
*/
|
|
36
|
-
throttleIntervalMs: number;
|
|
37
|
-
/**
|
|
38
|
-
* Number of consecutive budget violations before moving to 'degraded' status.
|
|
39
|
-
* Degraded panels render at a fixed reduced rate regardless of update requests.
|
|
40
|
-
*/
|
|
41
|
-
degradeAfterViolations: number;
|
|
42
|
-
/**
|
|
43
|
-
* Fixed render interval in milliseconds when the panel is degraded.
|
|
44
|
-
* Replaces throttleIntervalMs for severely overloaded panels.
|
|
45
|
-
*/
|
|
46
|
-
degradedIntervalMs: number;
|
|
47
|
-
}
|
|
48
|
-
/**
|
|
49
|
-
* Live health state for a single panel, maintained by the PanelHealthMonitor.
|
|
50
|
-
*/
|
|
51
|
-
export interface PanelHealthState {
|
|
52
|
-
/** Panel id. */
|
|
53
|
-
panelId: string;
|
|
54
|
-
/** Current throttle status. */
|
|
55
|
-
throttleStatus: PanelThrottleStatus;
|
|
56
|
-
/** Current health status. */
|
|
57
|
-
healthStatus: PanelHealthStatus;
|
|
58
|
-
/** Observed render count over the last measurement window. */
|
|
59
|
-
rendersInWindow: number;
|
|
60
|
-
/** p95 render duration in ms over the last measurement window. */
|
|
61
|
-
renderP95Ms: number;
|
|
62
|
-
/** Number of consecutive contract violations (update rate or render cost). */
|
|
63
|
-
consecutiveViolations: number;
|
|
64
|
-
/** Epoch ms when the panel was last allowed to render. */
|
|
65
|
-
lastRenderAt: number;
|
|
66
|
-
/** Epoch ms of next allowed render (0 = no restriction). */
|
|
67
|
-
nextAllowedAt: number;
|
|
68
|
-
/** Total renders suppressed due to throttle or degradation since monitor start. */
|
|
69
|
-
totalSuppressed: number;
|
|
70
|
-
/** Total renders permitted since monitor start. */
|
|
71
|
-
totalPermitted: number;
|
|
72
|
-
}
|
|
73
|
-
/**
|
|
74
|
-
* Default resource contracts by panel category.
|
|
75
|
-
*
|
|
76
|
-
* Panels without an explicit contract inherit from their category default.
|
|
77
|
-
* Active/interactive panels get more generous budgets; monitoring panels
|
|
78
|
-
* are throttled aggressively to prevent render storms.
|
|
79
|
-
*/
|
|
80
|
-
export declare const CATEGORY_CONTRACTS: Record<string, Omit<PanelResourceContract, 'panelId'>>;
|
|
81
|
-
/**
|
|
82
|
-
* Build a PanelResourceContract for a panel, merging category defaults
|
|
83
|
-
* with any per-panel overrides.
|
|
84
|
-
*
|
|
85
|
-
* @param panelId - The panel's unique id.
|
|
86
|
-
* @param category - The panel's category (used to select the base contract).
|
|
87
|
-
* @param overrides - Optional per-panel overrides applied on top of the category contract.
|
|
88
|
-
*/
|
|
89
|
-
export declare function buildContract(panelId: string, category: string, overrides?: Partial<Omit<PanelResourceContract, 'panelId'>>): PanelResourceContract;
|
|
90
|
-
/**
|
|
91
|
-
* Create an initial (clean) PanelHealthState for a panel.
|
|
92
|
-
*/
|
|
93
|
-
export declare function createInitialPanelHealthState(panelId: string): PanelHealthState;
|
|
7
|
+
export type { ComponentThrottleStatus, ComponentHealthStatus, ComponentResourceContract, ComponentHealthState, } from './component-contracts.js';
|
|
8
|
+
export type { PanelThrottleStatus, PanelHealthStatus, PanelResourceContract, PanelHealthState, } from './component-contracts.js';
|
|
9
|
+
export { CATEGORY_CONTRACTS, buildContract, createInitialComponentHealthState, createInitialPanelHealthState, } from './component-contracts.js';
|
|
94
10
|
//# sourceMappingURL=panel-contracts.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"panel-contracts.d.ts","sourceRoot":"","sources":["../../../../../src/_internal/platform/runtime/perf/panel-contracts.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"panel-contracts.d.ts","sourceRoot":"","sources":["../../../../../src/_internal/platform/runtime/perf/panel-contracts.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,YAAY,EACV,uBAAuB,EACvB,qBAAqB,EACrB,yBAAyB,EACzB,oBAAoB,GACrB,MAAM,0BAA0B,CAAC;AAElC,YAAY,EACV,mBAAmB,EACnB,iBAAiB,EACjB,qBAAqB,EACrB,gBAAgB,GACjB,MAAM,0BAA0B,CAAC;AAElC,OAAO,EACL,kBAAkB,EAClB,aAAa,EACb,iCAAiC,EACjC,6BAA6B,GAC9B,MAAM,0BAA0B,CAAC"}
|
|
@@ -1,86 +1,7 @@
|
|
|
1
|
-
/** SDK-owned platform module. This implementation is maintained in goodvibes-sdk. */
|
|
2
1
|
/**
|
|
3
|
-
*
|
|
2
|
+
* @deprecated This module has been renamed. Import from component-contracts.js instead.
|
|
4
3
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* are throttled aggressively to prevent render storms.
|
|
4
|
+
* This file is a backward-compatibility shim. All types and functions are
|
|
5
|
+
* re-exported from component-contracts.ts under their original Panel* names.
|
|
8
6
|
*/
|
|
9
|
-
export
|
|
10
|
-
development: {
|
|
11
|
-
maxUpdatesPerSecond: 10,
|
|
12
|
-
maxRenderMs: 20,
|
|
13
|
-
throttleIntervalMs: 100,
|
|
14
|
-
degradeAfterViolations: 5,
|
|
15
|
-
degradedIntervalMs: 500,
|
|
16
|
-
},
|
|
17
|
-
agent: {
|
|
18
|
-
maxUpdatesPerSecond: 5,
|
|
19
|
-
maxRenderMs: 30,
|
|
20
|
-
throttleIntervalMs: 200,
|
|
21
|
-
degradeAfterViolations: 5,
|
|
22
|
-
degradedIntervalMs: 1000,
|
|
23
|
-
},
|
|
24
|
-
monitoring: {
|
|
25
|
-
maxUpdatesPerSecond: 2,
|
|
26
|
-
maxRenderMs: 50,
|
|
27
|
-
throttleIntervalMs: 500,
|
|
28
|
-
degradeAfterViolations: 3,
|
|
29
|
-
degradedIntervalMs: 2000,
|
|
30
|
-
},
|
|
31
|
-
session: {
|
|
32
|
-
maxUpdatesPerSecond: 4,
|
|
33
|
-
maxRenderMs: 25,
|
|
34
|
-
throttleIntervalMs: 250,
|
|
35
|
-
degradeAfterViolations: 5,
|
|
36
|
-
degradedIntervalMs: 1000,
|
|
37
|
-
},
|
|
38
|
-
ai: {
|
|
39
|
-
maxUpdatesPerSecond: 8,
|
|
40
|
-
maxRenderMs: 20,
|
|
41
|
-
throttleIntervalMs: 125,
|
|
42
|
-
degradeAfterViolations: 5,
|
|
43
|
-
degradedIntervalMs: 500,
|
|
44
|
-
},
|
|
45
|
-
/** Fallback for unrecognised categories. */
|
|
46
|
-
default: {
|
|
47
|
-
maxUpdatesPerSecond: 5,
|
|
48
|
-
maxRenderMs: 30,
|
|
49
|
-
throttleIntervalMs: 200,
|
|
50
|
-
degradeAfterViolations: 5,
|
|
51
|
-
degradedIntervalMs: 1000,
|
|
52
|
-
},
|
|
53
|
-
};
|
|
54
|
-
/**
|
|
55
|
-
* Build a PanelResourceContract for a panel, merging category defaults
|
|
56
|
-
* with any per-panel overrides.
|
|
57
|
-
*
|
|
58
|
-
* @param panelId - The panel's unique id.
|
|
59
|
-
* @param category - The panel's category (used to select the base contract).
|
|
60
|
-
* @param overrides - Optional per-panel overrides applied on top of the category contract.
|
|
61
|
-
*/
|
|
62
|
-
export function buildContract(panelId, category, overrides) {
|
|
63
|
-
const base = CATEGORY_CONTRACTS[category] ?? CATEGORY_CONTRACTS['default'];
|
|
64
|
-
return {
|
|
65
|
-
panelId,
|
|
66
|
-
...base,
|
|
67
|
-
...overrides,
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
/**
|
|
71
|
-
* Create an initial (clean) PanelHealthState for a panel.
|
|
72
|
-
*/
|
|
73
|
-
export function createInitialPanelHealthState(panelId) {
|
|
74
|
-
return {
|
|
75
|
-
panelId,
|
|
76
|
-
throttleStatus: 'normal',
|
|
77
|
-
healthStatus: 'healthy',
|
|
78
|
-
rendersInWindow: 0,
|
|
79
|
-
renderP95Ms: 0,
|
|
80
|
-
consecutiveViolations: 0,
|
|
81
|
-
lastRenderAt: 0,
|
|
82
|
-
nextAllowedAt: 0,
|
|
83
|
-
totalSuppressed: 0,
|
|
84
|
-
totalPermitted: 0,
|
|
85
|
-
};
|
|
86
|
-
}
|
|
7
|
+
export { CATEGORY_CONTRACTS, buildContract, createInitialComponentHealthState, createInitialPanelHealthState, } from './component-contracts.js';
|