instar 0.24.16 → 0.24.17
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/dashboard/index.html +385 -145
- package/dist/commands/server.d.ts.map +1 -1
- package/dist/commands/server.js +165 -19
- package/dist/commands/server.js.map +1 -1
- package/dist/lifeline/TelegramLifeline.d.ts +5 -0
- package/dist/lifeline/TelegramLifeline.d.ts.map +1 -1
- package/dist/lifeline/TelegramLifeline.js +57 -3
- package/dist/lifeline/TelegramLifeline.js.map +1 -1
- package/dist/messaging/TelegramAdapter.d.ts +6 -0
- package/dist/messaging/TelegramAdapter.d.ts.map +1 -1
- package/dist/messaging/TelegramAdapter.js +21 -10
- package/dist/messaging/TelegramAdapter.js.map +1 -1
- package/dist/messaging/slack/SlackAdapter.d.ts +42 -0
- package/dist/messaging/slack/SlackAdapter.d.ts.map +1 -1
- package/dist/messaging/slack/SlackAdapter.js +220 -5
- package/dist/messaging/slack/SlackAdapter.js.map +1 -1
- package/dist/monitoring/PromptGate.d.ts +17 -0
- package/dist/monitoring/PromptGate.d.ts.map +1 -1
- package/dist/monitoring/PromptGate.js +166 -49
- package/dist/monitoring/PromptGate.js.map +1 -1
- package/dist/server/routes.d.ts.map +1 -1
- package/dist/server/routes.js +533 -86
- package/dist/server/routes.js.map +1 -1
- package/package.json +1 -1
- package/src/data/builtin-manifest.json +47 -47
- package/upgrades/0.24.17.md +40 -0
package/dashboard/index.html
CHANGED
|
@@ -205,6 +205,11 @@
|
|
|
205
205
|
.type-badge.job { background: #1b2e1b; color: #86efac; }
|
|
206
206
|
.type-badge.interactive { background: #2e2e1b; color: #fde047; }
|
|
207
207
|
|
|
208
|
+
.platform-badge {
|
|
209
|
+
font-size: 12px;
|
|
210
|
+
cursor: default;
|
|
211
|
+
}
|
|
212
|
+
|
|
208
213
|
.session-telemetry {
|
|
209
214
|
display: flex;
|
|
210
215
|
align-items: center;
|
|
@@ -1957,139 +1962,269 @@
|
|
|
1957
1962
|
color: var(--text);
|
|
1958
1963
|
}
|
|
1959
1964
|
|
|
1960
|
-
|
|
1965
|
+
/* Health Banner */
|
|
1966
|
+
.health-banner {
|
|
1961
1967
|
display: flex;
|
|
1968
|
+
align-items: center;
|
|
1962
1969
|
gap: 16px;
|
|
1970
|
+
padding: 20px 24px;
|
|
1971
|
+
border-radius: 10px;
|
|
1963
1972
|
margin-bottom: 24px;
|
|
1964
|
-
|
|
1973
|
+
border: 1px solid var(--border);
|
|
1974
|
+
}
|
|
1975
|
+
|
|
1976
|
+
.health-banner.healthy {
|
|
1977
|
+
background: rgba(76, 175, 80, 0.08);
|
|
1978
|
+
border-color: rgba(76, 175, 80, 0.25);
|
|
1965
1979
|
}
|
|
1966
1980
|
|
|
1967
|
-
.
|
|
1981
|
+
.health-banner.error {
|
|
1982
|
+
background: rgba(244, 67, 54, 0.08);
|
|
1983
|
+
border-color: rgba(244, 67, 54, 0.25);
|
|
1984
|
+
}
|
|
1985
|
+
|
|
1986
|
+
.health-banner.degraded {
|
|
1987
|
+
background: rgba(255, 152, 0, 0.08);
|
|
1988
|
+
border-color: rgba(255, 152, 0, 0.25);
|
|
1989
|
+
}
|
|
1990
|
+
|
|
1991
|
+
.health-icon {
|
|
1992
|
+
font-size: 28px;
|
|
1993
|
+
line-height: 1;
|
|
1994
|
+
flex-shrink: 0;
|
|
1995
|
+
}
|
|
1996
|
+
|
|
1997
|
+
.health-banner.healthy .health-icon { color: var(--accent); }
|
|
1998
|
+
.health-banner.error .health-icon { color: var(--red); }
|
|
1999
|
+
.health-banner.degraded .health-icon { color: var(--orange); }
|
|
2000
|
+
|
|
2001
|
+
.health-text {
|
|
1968
2002
|
flex: 1;
|
|
1969
|
-
|
|
1970
|
-
|
|
2003
|
+
}
|
|
2004
|
+
|
|
2005
|
+
.health-title {
|
|
2006
|
+
font-size: 16px;
|
|
2007
|
+
font-weight: 600;
|
|
2008
|
+
color: var(--text-bright);
|
|
2009
|
+
margin-bottom: 4px;
|
|
2010
|
+
}
|
|
2011
|
+
|
|
2012
|
+
.health-meta {
|
|
2013
|
+
font-size: 12px;
|
|
2014
|
+
color: var(--text-dim);
|
|
2015
|
+
}
|
|
2016
|
+
|
|
2017
|
+
/* Issues Panel */
|
|
2018
|
+
.issues-panel {
|
|
2019
|
+
margin-bottom: 24px;
|
|
2020
|
+
}
|
|
2021
|
+
|
|
2022
|
+
.issue-card {
|
|
2023
|
+
display: flex;
|
|
2024
|
+
align-items: flex-start;
|
|
2025
|
+
gap: 12px;
|
|
2026
|
+
padding: 12px 16px;
|
|
1971
2027
|
background: var(--bg-panel);
|
|
1972
2028
|
border: 1px solid var(--border);
|
|
1973
|
-
border-
|
|
1974
|
-
|
|
2029
|
+
border-left: 3px solid var(--red);
|
|
2030
|
+
border-radius: 6px;
|
|
2031
|
+
margin-bottom: 8px;
|
|
1975
2032
|
}
|
|
1976
2033
|
|
|
1977
|
-
.
|
|
1978
|
-
|
|
1979
|
-
|
|
2034
|
+
.issue-card.warning {
|
|
2035
|
+
border-left-color: var(--orange);
|
|
2036
|
+
}
|
|
2037
|
+
|
|
2038
|
+
.issue-card-icon {
|
|
2039
|
+
font-size: 14px;
|
|
2040
|
+
margin-top: 1px;
|
|
2041
|
+
flex-shrink: 0;
|
|
2042
|
+
}
|
|
2043
|
+
|
|
2044
|
+
.issue-card-content {
|
|
2045
|
+
flex: 1;
|
|
2046
|
+
}
|
|
2047
|
+
|
|
2048
|
+
.issue-card-label {
|
|
2049
|
+
font-size: 13px;
|
|
2050
|
+
font-weight: 500;
|
|
1980
2051
|
color: var(--text-bright);
|
|
2052
|
+
margin-bottom: 2px;
|
|
1981
2053
|
}
|
|
1982
2054
|
|
|
1983
|
-
.
|
|
1984
|
-
font-size:
|
|
2055
|
+
.issue-card-desc {
|
|
2056
|
+
font-size: 12px;
|
|
1985
2057
|
color: var(--text-dim);
|
|
1986
|
-
margin-top: 4px;
|
|
1987
2058
|
}
|
|
1988
2059
|
|
|
1989
|
-
|
|
2060
|
+
/* Capabilities Grid */
|
|
2061
|
+
.capabilities-section {
|
|
1990
2062
|
margin-bottom: 24px;
|
|
1991
2063
|
}
|
|
1992
2064
|
|
|
1993
|
-
.
|
|
1994
|
-
font-size:
|
|
2065
|
+
.capabilities-section-title {
|
|
2066
|
+
font-size: 12px;
|
|
1995
2067
|
font-weight: 600;
|
|
1996
|
-
color: var(--text-
|
|
2068
|
+
color: var(--text-dim);
|
|
2069
|
+
text-transform: uppercase;
|
|
2070
|
+
letter-spacing: 0.5px;
|
|
1997
2071
|
margin-bottom: 12px;
|
|
1998
2072
|
}
|
|
1999
2073
|
|
|
2000
|
-
|
|
2074
|
+
/* Capability Cards */
|
|
2075
|
+
.capability-card {
|
|
2001
2076
|
background: var(--bg-panel);
|
|
2002
2077
|
border: 1px solid var(--border);
|
|
2003
2078
|
border-radius: 8px;
|
|
2004
|
-
margin-bottom:
|
|
2079
|
+
margin-bottom: 6px;
|
|
2005
2080
|
overflow: hidden;
|
|
2081
|
+
transition: border-color 0.15s;
|
|
2082
|
+
}
|
|
2083
|
+
|
|
2084
|
+
.capability-card:hover {
|
|
2085
|
+
border-color: rgba(255,255,255,0.12);
|
|
2006
2086
|
}
|
|
2007
2087
|
|
|
2008
|
-
.
|
|
2088
|
+
.capability-card.expanded {
|
|
2089
|
+
border-color: var(--accent);
|
|
2090
|
+
}
|
|
2091
|
+
|
|
2092
|
+
.capability-card-header {
|
|
2009
2093
|
display: flex;
|
|
2010
2094
|
align-items: center;
|
|
2011
|
-
gap:
|
|
2012
|
-
padding:
|
|
2095
|
+
gap: 12px;
|
|
2096
|
+
padding: 14px 16px;
|
|
2013
2097
|
cursor: pointer;
|
|
2014
2098
|
user-select: none;
|
|
2015
|
-
transition: background 0.15s;
|
|
2016
2099
|
}
|
|
2017
2100
|
|
|
2018
|
-
.
|
|
2019
|
-
|
|
2101
|
+
.cap-dot {
|
|
2102
|
+
width: 8px;
|
|
2103
|
+
height: 8px;
|
|
2104
|
+
border-radius: 50%;
|
|
2105
|
+
flex-shrink: 0;
|
|
2106
|
+
}
|
|
2107
|
+
|
|
2108
|
+
.cap-dot.active { background: var(--accent); }
|
|
2109
|
+
.cap-dot.error { background: var(--red); }
|
|
2110
|
+
|
|
2111
|
+
.cap-info {
|
|
2112
|
+
flex: 1;
|
|
2113
|
+
min-width: 0;
|
|
2114
|
+
}
|
|
2115
|
+
|
|
2116
|
+
.cap-label {
|
|
2117
|
+
font-size: 13px;
|
|
2118
|
+
color: var(--text-bright);
|
|
2119
|
+
font-weight: 500;
|
|
2120
|
+
margin-bottom: 2px;
|
|
2020
2121
|
}
|
|
2021
2122
|
|
|
2022
|
-
.
|
|
2123
|
+
.cap-metric {
|
|
2124
|
+
font-size: 11px;
|
|
2125
|
+
color: var(--text-dim);
|
|
2126
|
+
white-space: nowrap;
|
|
2127
|
+
overflow: hidden;
|
|
2128
|
+
text-overflow: ellipsis;
|
|
2129
|
+
}
|
|
2130
|
+
|
|
2131
|
+
.cap-arrow {
|
|
2023
2132
|
font-size: 10px;
|
|
2024
2133
|
color: var(--text-dim);
|
|
2025
2134
|
transition: transform 0.2s;
|
|
2026
|
-
|
|
2135
|
+
flex-shrink: 0;
|
|
2027
2136
|
}
|
|
2028
2137
|
|
|
2029
|
-
.
|
|
2138
|
+
.capability-card.expanded .cap-arrow {
|
|
2030
2139
|
transform: rotate(90deg);
|
|
2031
2140
|
}
|
|
2032
2141
|
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2142
|
+
/* Capability Detail (expandable) */
|
|
2143
|
+
.cap-detail {
|
|
2144
|
+
display: none;
|
|
2145
|
+
padding: 0 16px 14px;
|
|
2146
|
+
border-top: 1px solid var(--border);
|
|
2038
2147
|
}
|
|
2039
2148
|
|
|
2040
|
-
.
|
|
2041
|
-
|
|
2042
|
-
font-weight: 500;
|
|
2043
|
-
color: var(--text-bright);
|
|
2044
|
-
flex: 1;
|
|
2149
|
+
.capability-card.expanded .cap-detail {
|
|
2150
|
+
display: block;
|
|
2045
2151
|
}
|
|
2046
2152
|
|
|
2047
|
-
.
|
|
2048
|
-
font-size:
|
|
2153
|
+
.cap-detail-desc {
|
|
2154
|
+
font-size: 12px;
|
|
2049
2155
|
color: var(--text-dim);
|
|
2156
|
+
margin: 12px 0 10px;
|
|
2157
|
+
line-height: 1.5;
|
|
2050
2158
|
}
|
|
2051
2159
|
|
|
2052
|
-
.
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2160
|
+
.cap-detail-label {
|
|
2161
|
+
font-size: 10px;
|
|
2162
|
+
font-weight: 600;
|
|
2163
|
+
color: var(--text-dim);
|
|
2164
|
+
text-transform: uppercase;
|
|
2165
|
+
letter-spacing: 0.5px;
|
|
2166
|
+
margin-bottom: 6px;
|
|
2056
2167
|
}
|
|
2057
2168
|
|
|
2058
|
-
.
|
|
2169
|
+
.cap-detail-processes {
|
|
2059
2170
|
display: flex;
|
|
2060
2171
|
flex-wrap: wrap;
|
|
2172
|
+
gap: 6px;
|
|
2061
2173
|
}
|
|
2062
2174
|
|
|
2063
|
-
.
|
|
2175
|
+
.cap-detail-proc {
|
|
2064
2176
|
display: flex;
|
|
2065
2177
|
align-items: center;
|
|
2066
|
-
gap:
|
|
2067
|
-
padding:
|
|
2178
|
+
gap: 6px;
|
|
2179
|
+
padding: 4px 10px;
|
|
2068
2180
|
background: var(--bg);
|
|
2069
2181
|
border: 1px solid var(--border);
|
|
2070
|
-
border-radius:
|
|
2071
|
-
|
|
2182
|
+
border-radius: 4px;
|
|
2183
|
+
font-size: 11px;
|
|
2184
|
+
color: var(--text);
|
|
2072
2185
|
}
|
|
2073
2186
|
|
|
2074
|
-
.
|
|
2075
|
-
width:
|
|
2076
|
-
height:
|
|
2187
|
+
.cap-detail-proc-dot {
|
|
2188
|
+
width: 5px;
|
|
2189
|
+
height: 5px;
|
|
2077
2190
|
border-radius: 50%;
|
|
2078
|
-
flex-shrink: 0;
|
|
2079
2191
|
}
|
|
2080
2192
|
|
|
2081
|
-
|
|
2193
|
+
/* Events Disclosure */
|
|
2194
|
+
.events-disclosure {
|
|
2195
|
+
margin-top: 8px;
|
|
2196
|
+
}
|
|
2197
|
+
|
|
2198
|
+
.events-disclosure-toggle {
|
|
2199
|
+
display: flex;
|
|
2200
|
+
align-items: center;
|
|
2201
|
+
gap: 8px;
|
|
2202
|
+
padding: 10px 0;
|
|
2203
|
+
cursor: pointer;
|
|
2204
|
+
user-select: none;
|
|
2082
2205
|
font-size: 12px;
|
|
2206
|
+
color: var(--text-dim);
|
|
2207
|
+
border: none;
|
|
2208
|
+
background: none;
|
|
2209
|
+
width: 100%;
|
|
2210
|
+
text-align: left;
|
|
2211
|
+
}
|
|
2212
|
+
|
|
2213
|
+
.events-disclosure-toggle:hover {
|
|
2083
2214
|
color: var(--text);
|
|
2084
2215
|
}
|
|
2085
2216
|
|
|
2086
|
-
.
|
|
2217
|
+
.events-disclosure-arrow {
|
|
2087
2218
|
font-size: 10px;
|
|
2088
|
-
|
|
2089
|
-
|
|
2219
|
+
transition: transform 0.2s;
|
|
2220
|
+
}
|
|
2221
|
+
|
|
2222
|
+
.events-disclosure.expanded .events-disclosure-arrow {
|
|
2223
|
+
transform: rotate(90deg);
|
|
2090
2224
|
}
|
|
2091
2225
|
|
|
2092
|
-
.
|
|
2226
|
+
.events-disclosure-body {
|
|
2227
|
+
display: none;
|
|
2093
2228
|
background: var(--bg-panel);
|
|
2094
2229
|
border: 1px solid var(--border);
|
|
2095
2230
|
border-radius: 8px;
|
|
@@ -2097,6 +2232,10 @@
|
|
|
2097
2232
|
overflow-y: auto;
|
|
2098
2233
|
}
|
|
2099
2234
|
|
|
2235
|
+
.events-disclosure.expanded .events-disclosure-body {
|
|
2236
|
+
display: block;
|
|
2237
|
+
}
|
|
2238
|
+
|
|
2100
2239
|
.systems-event-row {
|
|
2101
2240
|
display: flex;
|
|
2102
2241
|
align-items: center;
|
|
@@ -2776,12 +2915,17 @@
|
|
|
2776
2915
|
onkeydown="if(event.key==='Enter')createNewSession()" autofocus>
|
|
2777
2916
|
</div>
|
|
2778
2917
|
<div class="modal-field">
|
|
2779
|
-
<label
|
|
2780
|
-
|
|
2781
|
-
<
|
|
2782
|
-
|
|
2783
|
-
|
|
2918
|
+
<label for="newSessionPlatform">Platform</label>
|
|
2919
|
+
<select id="newSessionPlatform" style="width:100%;padding:8px 12px;background:var(--bg-panel);color:var(--text-bright);border:1px solid var(--border);border-radius:6px;font-size:14px;">
|
|
2920
|
+
<option value="auto">Auto (best available)</option>
|
|
2921
|
+
<option value="telegram">✈️ Telegram</option>
|
|
2922
|
+
<option value="slack">💬 Slack</option>
|
|
2923
|
+
<option value="headless">🖥️ Headless (no messaging)</option>
|
|
2924
|
+
</select>
|
|
2925
|
+
<div class="modal-hint">Choose which messaging platform to link this session to.</div>
|
|
2784
2926
|
</div>
|
|
2927
|
+
<!-- Keep hidden checkbox for backward compat -->
|
|
2928
|
+
<input type="hidden" id="newSessionHeadless">
|
|
2785
2929
|
<div class="modal-actions">
|
|
2786
2930
|
<button class="modal-btn-cancel" onclick="closeNewSessionModal()">Cancel</button>
|
|
2787
2931
|
<button class="modal-btn-create" id="createSessionBtn" onclick="createNewSession()">Create Session</button>
|
|
@@ -2864,19 +3008,15 @@
|
|
|
2864
3008
|
<div class="systems-container" id="systemsTab" style="display:none">
|
|
2865
3009
|
<div class="systems-main">
|
|
2866
3010
|
<div class="systems-header">
|
|
2867
|
-
<h2>Systems
|
|
3011
|
+
<h2>Systems</h2>
|
|
2868
3012
|
<button class="systems-refresh" onclick="loadSystems()">Refresh</button>
|
|
2869
3013
|
</div>
|
|
2870
|
-
<div
|
|
3014
|
+
<div id="systemsBanner">
|
|
2871
3015
|
<div style="padding:20px;color:var(--text-dim);text-align:center">Loading...</div>
|
|
2872
3016
|
</div>
|
|
2873
|
-
<div
|
|
2874
|
-
<div
|
|
2875
|
-
|
|
2876
|
-
<div class="systems-events" id="systemsEvents">
|
|
2877
|
-
<div style="padding:12px;color:var(--text-dim);text-align:center">No events</div>
|
|
2878
|
-
</div>
|
|
2879
|
-
</div>
|
|
3017
|
+
<div id="systemsIssues"></div>
|
|
3018
|
+
<div id="systemsCapabilities"></div>
|
|
3019
|
+
<div id="systemsEvents"></div>
|
|
2880
3020
|
</div>
|
|
2881
3021
|
</div>
|
|
2882
3022
|
|
|
@@ -3236,6 +3376,10 @@
|
|
|
3236
3376
|
}
|
|
3237
3377
|
}
|
|
3238
3378
|
|
|
3379
|
+
const platform = session.platform || 'headless';
|
|
3380
|
+
const platformIcon = platform === 'telegram' ? '✈️' : platform === 'slack' ? '💬' : platform === 'whatsapp' ? '📱' : '🖥️';
|
|
3381
|
+
const platformLabel = platform.charAt(0).toUpperCase() + platform.slice(1);
|
|
3382
|
+
|
|
3239
3383
|
el.innerHTML = `
|
|
3240
3384
|
<div class="session-name-row">
|
|
3241
3385
|
<div class="session-name">${escapeHtml(session.name)}</div>
|
|
@@ -3244,6 +3388,7 @@
|
|
|
3244
3388
|
<div class="session-meta">
|
|
3245
3389
|
<span class="type-badge ${sType}">${sType}</span>
|
|
3246
3390
|
<span class="model-badge ${model}">${model}</span>
|
|
3391
|
+
<span class="platform-badge ${platform}" title="${platformLabel}">${platformIcon}</span>
|
|
3247
3392
|
<span>${elapsed}</span>
|
|
3248
3393
|
</div>
|
|
3249
3394
|
${telemetryHtml}
|
|
@@ -3556,7 +3701,9 @@
|
|
|
3556
3701
|
|
|
3557
3702
|
async function createNewSession() {
|
|
3558
3703
|
const nameInput = document.getElementById('newSessionName');
|
|
3559
|
-
const
|
|
3704
|
+
const platformSelect = document.getElementById('newSessionPlatform');
|
|
3705
|
+
const platform = platformSelect ? platformSelect.value : 'auto';
|
|
3706
|
+
const headless = platform === 'headless';
|
|
3560
3707
|
const name = nameInput.value.trim();
|
|
3561
3708
|
const btn = document.getElementById('createSessionBtn');
|
|
3562
3709
|
|
|
@@ -3577,7 +3724,7 @@
|
|
|
3577
3724
|
'Authorization': `Bearer ${token}`,
|
|
3578
3725
|
'Content-Type': 'application/json',
|
|
3579
3726
|
},
|
|
3580
|
-
body: JSON.stringify({ name, headless }),
|
|
3727
|
+
body: JSON.stringify({ name, headless, platform: platform === 'auto' ? undefined : platform }),
|
|
3581
3728
|
});
|
|
3582
3729
|
const data = await resp.json();
|
|
3583
3730
|
|
|
@@ -5474,96 +5621,189 @@
|
|
|
5474
5621
|
async function loadSystems() {
|
|
5475
5622
|
try {
|
|
5476
5623
|
systemsData = await apiFetch('/systems/status');
|
|
5477
|
-
|
|
5624
|
+
showSystemsOverview();
|
|
5625
|
+
renderSystemsOverview();
|
|
5478
5626
|
} catch (e) {
|
|
5479
|
-
document.getElementById('
|
|
5627
|
+
document.getElementById('systemsBanner').innerHTML =
|
|
5480
5628
|
'<div style="padding:20px;color:var(--red);text-align:center">Failed to load systems status</div>';
|
|
5481
5629
|
}
|
|
5482
5630
|
}
|
|
5483
5631
|
|
|
5484
|
-
function
|
|
5632
|
+
function renderSystemsOverview() {
|
|
5485
5633
|
if (!systemsData) return;
|
|
5486
|
-
const { uptime,
|
|
5487
|
-
|
|
5488
|
-
// Summary
|
|
5489
|
-
let totalProcesses = 0;
|
|
5490
|
-
let healthyProcesses = 0;
|
|
5491
|
-
let errorProcesses = 0;
|
|
5492
|
-
for (const cat of categories) {
|
|
5493
|
-
for (const p of cat.processes) {
|
|
5494
|
-
totalProcesses++;
|
|
5495
|
-
if (p.status === 'running') healthyProcesses++;
|
|
5496
|
-
if (p.status === 'error') errorProcesses++;
|
|
5497
|
-
}
|
|
5498
|
-
}
|
|
5634
|
+
const { uptime, health, healthSummary, activeCapabilities, issues, recentEvents } = systemsData;
|
|
5499
5635
|
const uptimeStr = formatUptimeClient(uptime);
|
|
5500
5636
|
|
|
5501
|
-
|
|
5502
|
-
|
|
5503
|
-
|
|
5504
|
-
|
|
5505
|
-
|
|
5506
|
-
|
|
5507
|
-
<div class="
|
|
5508
|
-
|
|
5509
|
-
|
|
5510
|
-
|
|
5511
|
-
<div class="summary-value">${esc(uptimeStr)}</div>
|
|
5512
|
-
<div class="summary-label">Uptime</div>
|
|
5513
|
-
</div>
|
|
5514
|
-
<div class="systems-summary-card">
|
|
5515
|
-
<div class="summary-value">${recentEvents.length}</div>
|
|
5516
|
-
<div class="summary-label">Recent Events</div>
|
|
5637
|
+
// Health Banner
|
|
5638
|
+
const bannerClass = health === 'healthy' ? 'healthy' : health === 'error' ? 'error' : 'degraded';
|
|
5639
|
+
const bannerIcon = health === 'healthy' ? '✓' : '⚠';
|
|
5640
|
+
document.getElementById('systemsBanner').innerHTML = `
|
|
5641
|
+
<div class="health-banner ${bannerClass}">
|
|
5642
|
+
<span class="health-icon">${bannerIcon}</span>
|
|
5643
|
+
<div class="health-text">
|
|
5644
|
+
<div class="health-title">${esc(healthSummary)}</div>
|
|
5645
|
+
<div class="health-meta">Uptime: ${esc(uptimeStr)} · ${activeCapabilities.length} capabilities active${issues.length > 0 ? ' · ' + issues.length + ' issue' + (issues.length > 1 ? 's' : '') : ''}</div>
|
|
5646
|
+
</div>
|
|
5517
5647
|
</div>`;
|
|
5518
5648
|
|
|
5519
|
-
//
|
|
5520
|
-
const
|
|
5521
|
-
|
|
5522
|
-
|
|
5523
|
-
|
|
5524
|
-
|
|
5525
|
-
|
|
5526
|
-
|
|
5527
|
-
|
|
5528
|
-
|
|
5529
|
-
|
|
5530
|
-
|
|
5531
|
-
|
|
5532
|
-
|
|
5533
|
-
|
|
5534
|
-
|
|
5649
|
+
// Issues (only if any)
|
|
5650
|
+
const issuesEl = document.getElementById('systemsIssues');
|
|
5651
|
+
if (issues.length > 0) {
|
|
5652
|
+
issuesEl.innerHTML = '<div class="issues-panel">' + issues.map(iss => {
|
|
5653
|
+
const cls = iss.severity === 'warning' ? ' warning' : '';
|
|
5654
|
+
const ic = iss.severity === 'warning' ? '⚠' : '❌';
|
|
5655
|
+
return `<div class="issue-card${cls}">
|
|
5656
|
+
<span class="issue-card-icon">${ic}</span>
|
|
5657
|
+
<div class="issue-card-content">
|
|
5658
|
+
<div class="issue-card-label">${esc(iss.label)}</div>
|
|
5659
|
+
<div class="issue-card-desc">${esc(iss.description)}</div>
|
|
5660
|
+
</div>
|
|
5661
|
+
</div>`;
|
|
5662
|
+
}).join('') + '</div>';
|
|
5663
|
+
} else {
|
|
5664
|
+
issuesEl.innerHTML = '';
|
|
5665
|
+
}
|
|
5666
|
+
|
|
5667
|
+
// Card Grid
|
|
5668
|
+
const capsEl = document.getElementById('systemsCapabilities');
|
|
5669
|
+
if (activeCapabilities.length > 0) {
|
|
5670
|
+
const cards = activeCapabilities.map(cap => {
|
|
5671
|
+
const dotClass = cap.status === 'error' ? 'error' : 'active';
|
|
5672
|
+
const statusClass = cap.status === 'error' ? ' error' : '';
|
|
5673
|
+
const previewStats = buildPreviewStats(cap.stats || {});
|
|
5674
|
+
return `<div class="cap-card${statusClass}" onclick="showCapabilityDetail('${esc(cap.id)}')">
|
|
5675
|
+
<div class="cap-card-top">
|
|
5676
|
+
<span class="cap-dot ${dotClass}"></span>
|
|
5677
|
+
<span class="cap-card-name">${esc(cap.label)}</span>
|
|
5678
|
+
<span class="cap-card-arrow">▶</span>
|
|
5679
|
+
</div>
|
|
5680
|
+
<div class="cap-card-desc">${esc(cap.description)}</div>
|
|
5681
|
+
${previewStats ? '<div class="cap-card-stats">' + previewStats + '</div>' : ''}
|
|
5682
|
+
<div class="cap-card-metric">${esc(cap.metric)}</div>
|
|
5535
5683
|
</div>`;
|
|
5536
5684
|
}).join('');
|
|
5537
|
-
|
|
5538
|
-
|
|
5539
|
-
|
|
5540
|
-
|
|
5541
|
-
<span class="systems-category-dot" style="background:${dotColor}"></span>
|
|
5542
|
-
<span class="systems-category-name">${esc(cat.name)}</span>
|
|
5543
|
-
<span class="systems-category-count">${running}/${cat.processes.length} active</span>
|
|
5544
|
-
</div>
|
|
5545
|
-
<div class="systems-category-body">${processCards}</div>
|
|
5546
|
-
</div>`;
|
|
5547
|
-
}).join('');
|
|
5685
|
+
capsEl.innerHTML = `<div class="cap-section-title">Active Capabilities</div><div class="cap-grid">${cards}</div>`;
|
|
5686
|
+
} else {
|
|
5687
|
+
capsEl.innerHTML = '';
|
|
5688
|
+
}
|
|
5548
5689
|
|
|
5549
5690
|
// Events
|
|
5550
5691
|
const eventsEl = document.getElementById('systemsEvents');
|
|
5551
|
-
if (recentEvents.length
|
|
5552
|
-
|
|
5553
|
-
} else {
|
|
5554
|
-
eventsEl.innerHTML = recentEvents.map(e => {
|
|
5692
|
+
if (recentEvents.length > 0) {
|
|
5693
|
+
const rows = recentEvents.map(e => {
|
|
5555
5694
|
const time = e.timestamp ? new Date(e.timestamp).toLocaleString([], { month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit' }) : '';
|
|
5556
|
-
return `<div class="systems-event-row"
|
|
5557
|
-
<span class="systems-event-time">${esc(time)}</span>
|
|
5558
|
-
<span class="systems-event-text">${esc(e.narrative || e.subsystem || 'Unknown event')}</span>
|
|
5559
|
-
</div>`;
|
|
5695
|
+
return `<div class="systems-event-row"><span class="systems-event-time">${esc(time)}</span><span class="systems-event-text">${esc(e.narrative || e.subsystem || '')}</span></div>`;
|
|
5560
5696
|
}).join('');
|
|
5697
|
+
eventsEl.innerHTML = `<div class="events-disclosure" id="eventsDisclosure">
|
|
5698
|
+
<button class="events-disclosure-toggle" onclick="document.getElementById('eventsDisclosure').classList.toggle('expanded')">
|
|
5699
|
+
<span class="events-disclosure-arrow">▶</span> Recent Events (${recentEvents.length})
|
|
5700
|
+
</button>
|
|
5701
|
+
<div class="events-disclosure-body">${rows}</div></div>`;
|
|
5702
|
+
} else {
|
|
5703
|
+
eventsEl.innerHTML = '';
|
|
5704
|
+
}
|
|
5705
|
+
}
|
|
5706
|
+
|
|
5707
|
+
function buildPreviewStats(stats) {
|
|
5708
|
+
if (!stats || typeof stats !== 'object') return '';
|
|
5709
|
+
const map = {
|
|
5710
|
+
recoveries: 'Recoveries', interventions: 'Interventions', activeCases: 'Active',
|
|
5711
|
+
coherencePassed: 'Passed', coherenceFailed: 'Failed', memoryPercent: 'Memory',
|
|
5712
|
+
enabledJobs: 'Jobs', activeJobSessions: 'Running', queueLength: 'Queued',
|
|
5713
|
+
weeklyUsage: 'Weekly', fiveHourRate: '5h Rate',
|
|
5714
|
+
topicMappings: 'Topics', totalMessages: 'Messages',
|
|
5715
|
+
proposals: 'Proposals', gaps: 'Gaps', learningsApplied: 'Applied',
|
|
5716
|
+
};
|
|
5717
|
+
const chips = [];
|
|
5718
|
+
for (const [key, label] of Object.entries(map)) {
|
|
5719
|
+
if (stats[key] != null && stats[key] !== 0 && stats[key] !== false) {
|
|
5720
|
+
const suf = ['weeklyUsage','fiveHourRate','memoryPercent'].includes(key) ? '%' : '';
|
|
5721
|
+
chips.push(`<span class="cap-stat"><span class="cap-stat-value">${esc(String(stats[key]))}${suf}</span>${esc(label)}</span>`);
|
|
5722
|
+
}
|
|
5723
|
+
if (chips.length >= 3) break;
|
|
5724
|
+
}
|
|
5725
|
+
return chips.join('');
|
|
5726
|
+
}
|
|
5727
|
+
|
|
5728
|
+
function showCapabilityDetail(capId) {
|
|
5729
|
+
if (!systemsData) return;
|
|
5730
|
+
const cap = systemsData.activeCapabilities.find(c => c.id === capId);
|
|
5731
|
+
if (!cap) return;
|
|
5732
|
+
document.getElementById('systemsOverview').style.display = 'none';
|
|
5733
|
+
document.getElementById('systemsDetailView').classList.add('active');
|
|
5734
|
+
const content = document.getElementById('systemsDetailContent');
|
|
5735
|
+
|
|
5736
|
+
const statCards = buildStatCards(cap.stats || {});
|
|
5737
|
+
const processRows = (cap.processes || []).map(p => {
|
|
5738
|
+
const dotColor = p.status === 'running' ? 'var(--accent)' : 'var(--red)';
|
|
5739
|
+
return `<div class="cap-process-row">
|
|
5740
|
+
<span class="cap-process-dot" style="background:${dotColor}"></span>
|
|
5741
|
+
<span class="cap-process-name">${esc(p.name)}</span>
|
|
5742
|
+
<span class="cap-process-status">${esc(p.status === 'running' ? 'Running' : 'Error')}</span>
|
|
5743
|
+
</div>`;
|
|
5744
|
+
}).join('');
|
|
5745
|
+
|
|
5746
|
+
const lastAct = cap.lastActivity
|
|
5747
|
+
? '<div class="cap-last-activity">Last activity: ' + esc(timeAgo(cap.lastActivity)) + '</div>' : '';
|
|
5748
|
+
|
|
5749
|
+
content.innerHTML = `
|
|
5750
|
+
<div class="cap-detail-header">
|
|
5751
|
+
<div class="cap-detail-title">
|
|
5752
|
+
<span class="cap-dot ${cap.status === 'error' ? 'error' : 'active'}"></span>
|
|
5753
|
+
<h3>${esc(cap.label)}</h3>
|
|
5754
|
+
</div>
|
|
5755
|
+
<div class="cap-detail-description">${esc(cap.description)}</div>
|
|
5756
|
+
${lastAct}
|
|
5757
|
+
</div>
|
|
5758
|
+
${statCards ? '<div class="cap-detail-section"><div class="cap-detail-section-title">Metrics</div><div class="cap-stats-grid">' + statCards + '</div></div>' : ''}
|
|
5759
|
+
<div class="cap-detail-section">
|
|
5760
|
+
<div class="cap-detail-section-title">Components (${(cap.processes || []).length})</div>
|
|
5761
|
+
<div class="cap-process-list">${processRows}</div>
|
|
5762
|
+
</div>
|
|
5763
|
+
<div class="cap-detail-section">
|
|
5764
|
+
<div class="cap-detail-section-title">Status</div>
|
|
5765
|
+
<div style="font-size:13px;color:var(--accent);font-weight:500;padding:8px 0">${esc(cap.metric)}</div>
|
|
5766
|
+
</div>`;
|
|
5767
|
+
}
|
|
5768
|
+
|
|
5769
|
+
function buildStatCards(stats) {
|
|
5770
|
+
if (!stats || typeof stats !== 'object') return '';
|
|
5771
|
+
const map = {
|
|
5772
|
+
interventions: 'Interventions', recoveries: 'Recoveries', sessionDeaths: 'Deaths',
|
|
5773
|
+
llmOverrides: 'LLM Overrides', activeCases: 'Active Cases', totalTriages: 'Triages',
|
|
5774
|
+
cooldowns: 'Cooldowns',
|
|
5775
|
+
coherenceChecks: 'Checks', coherencePassed: 'Passed', coherenceFailed: 'Failed', coherenceCorrected: 'Corrected',
|
|
5776
|
+
memoryPercent: 'Memory %', memoryFreeGB: 'Free GB', memoryTotalGB: 'Total GB',
|
|
5777
|
+
trackedProcesses: 'Tracked', orphanProcesses: 'Orphans', totalMemoryMB: 'Memory MB',
|
|
5778
|
+
totalJobs: 'Total Jobs', enabledJobs: 'Enabled', queueLength: 'Queued', activeJobSessions: 'Running',
|
|
5779
|
+
weeklyUsage: 'Weekly %', fiveHourRate: '5h Rate %',
|
|
5780
|
+
topicMappings: 'Topics', pendingStalls: 'Pending', totalMessages: 'Messages',
|
|
5781
|
+
proposals: 'Proposals', learnings: 'Learnings', learningsApplied: 'Applied',
|
|
5782
|
+
gaps: 'Gaps', actions: 'Actions', overdueActions: 'Overdue',
|
|
5783
|
+
};
|
|
5784
|
+
const cards = [];
|
|
5785
|
+
for (const [key, label] of Object.entries(map)) {
|
|
5786
|
+
if (stats[key] != null && typeof stats[key] === 'number') {
|
|
5787
|
+
cards.push(`<div class="cap-stat-card"><div class="cap-stat-card-value">${stats[key]}</div><div class="cap-stat-card-label">${esc(label)}</div></div>`);
|
|
5788
|
+
}
|
|
5561
5789
|
}
|
|
5790
|
+
return cards.join('');
|
|
5791
|
+
}
|
|
5792
|
+
|
|
5793
|
+
function showSystemsOverview() {
|
|
5794
|
+
document.getElementById('systemsOverview').style.display = '';
|
|
5795
|
+
document.getElementById('systemsDetailView').classList.remove('active');
|
|
5562
5796
|
}
|
|
5563
5797
|
|
|
5564
|
-
function
|
|
5565
|
-
const
|
|
5566
|
-
|
|
5798
|
+
function timeAgo(isoStr) {
|
|
5799
|
+
const ms = Date.now() - new Date(isoStr).getTime();
|
|
5800
|
+
const s = Math.floor(ms / 1000);
|
|
5801
|
+
if (s < 60) return 'just now';
|
|
5802
|
+
const m = Math.floor(s / 60);
|
|
5803
|
+
if (m < 60) return m + 'm ago';
|
|
5804
|
+
const h = Math.floor(m / 60);
|
|
5805
|
+
if (h < 24) return h + 'h ago';
|
|
5806
|
+
return Math.floor(h / 24) + 'd ago';
|
|
5567
5807
|
}
|
|
5568
5808
|
|
|
5569
5809
|
function formatUptimeClient(ms) {
|