@agenthippo-ai/agenthippo 0.1.1 → 1.110.9
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/out/agentpack/index.js +2 -1
- package/out/agentpack/paths.js +23 -0
- package/out/analytics/dashboard/fleetDisplayUtils.js +3 -0
- package/out/analytics/dashboard/provider.js +13 -2
- package/out/analytics/dashboard/webview/panel.js +293 -82
- package/out/analytics/identity.js +0 -0
- package/out/analytics/service.js +23 -25
- package/out/analytics/sessionEvents.js +109 -22
- package/out/auth/authBaseUrl.js +59 -0
- package/out/auth/bootstrapApply.js +9 -10
- package/out/auth/brokerClient.js +49 -15
- package/out/auth/onboardingPrompt.js +112 -0
- package/out/auth/provider.js +9 -22
- package/out/auth/sessionStore.js +3 -40
- package/out/auth/signInFlow.js +2 -1
- package/out/auth-broker/config.js +54 -4
- package/out/auth-broker/server.js +152 -20
- package/out/auth-broker/store.js +25 -24
- package/out/authority/warrant.js +206 -0
- package/out/branding.js +27 -1
- package/out/cli/commands/ask.js +3 -0
- package/out/cli/commands/chat.js +3 -0
- package/out/cli/commands/conformance.js +249 -0
- package/out/cli/commands/data-plane.js +67 -0
- package/out/cli/commands/deploy.js +50 -10
- package/out/cli/commands/gateway.js +58 -0
- package/out/cli/commands/idp.js +85 -0
- package/out/cli/commands/pack.js +182 -3
- package/out/cli/commands/sandbox.js +332 -0
- package/out/cli/commands/serve.js +1165 -82
- package/out/cli/commands/store.js +12 -4
- package/out/cli/credential-context.js +42 -80
- package/out/cli/data-plane/broker.js +78 -0
- package/out/cli/data-plane/connector-host.js +121 -0
- package/out/cli/data-plane/egress.js +189 -0
- package/out/cli/data-plane/gateway.js +218 -0
- package/out/cli/data-plane/index.js +152 -0
- package/out/cli/data-plane/registry.js +89 -0
- package/out/cli/data-plane/remote.js +106 -0
- package/out/cli/data-plane/sidecar.js +161 -0
- package/out/cli/deploy/blueprints/registry.js +84 -0
- package/out/cli/deploy/layers/identity.js +172 -0
- package/out/cli/deploy-init.js +1182 -347
- package/out/cli/deps.js +106 -2
- package/out/cli/idp-init.js +338 -0
- package/out/cli/index.js +192 -23
- package/out/cli/pack-install-ref.js +15 -0
- package/out/cli/pack-loader.js +45 -3
- package/out/cli/pack-runtime.js +61 -0
- package/out/cli/runtime.js +44 -3
- package/out/cli/serve-hardening.js +139 -3
- package/out/cli/state-sync.js +16 -15
- package/out/cli/utils.js +12 -1
- package/out/engines/base.js +32 -3
- package/out/engines/claude.js +47 -8
- package/out/engines/codex.js +125 -22
- package/out/engines/custom.js +54 -12
- package/out/evidence/sessionShip.js +610 -0
- package/out/extension.js +13 -2
- package/out/gateway/bridge.js +40 -2
- package/out/gateway/client.js +34 -1
- package/out/gateway/installSource.js +68 -0
- package/out/gateway/lifecycle.js +185 -51
- package/out/gateway/outboundPaths.js +4 -1
- package/out/gateway/outboundSend.js +6 -6
- package/out/gateway/secretsPreflight.js +90 -0
- package/out/gateway/service.js +7 -2
- package/out/headless/index.js +40 -9
- package/out/live-e2e/mcp-demo/server.mjs +32 -0
- package/out/live-probe/connector.mjs +8 -0
- package/out/live-probe/env-report.mjs +8 -0
- package/out/mcp.js +115 -67
- package/out/pack/caps.js +271 -0
- package/out/pack/governor.js +309 -0
- package/out/pack/lease-schema.js +270 -0
- package/out/pack/lease.js +640 -0
- package/out/pack/reconcile.js +217 -0
- package/out/pack/signature.js +839 -0
- package/out/remote/handleRemoteChat.js +44 -3
- package/out/remote/remoteTrust.js +277 -0
- package/out/remote/serveClient.js +52 -5
- package/out/runner/host.js +131 -0
- package/out/runner/protocol.js +108 -0
- package/out/runner/remoteEngine.js +130 -0
- package/out/runtime/interfaces/edit-tracker.js +2 -0
- package/out/runtime/vscode/vscode-edit-tracker.js +2 -0
- package/out/sandbox/containerDriver.js +570 -0
- package/out/sandbox/processDriver.js +315 -0
- package/out/sandbox/sandboxRunner.js +191 -0
- package/out/sandbox/support.js +301 -0
- package/out/sandbox/types.js +55 -0
- package/out/scripts/agentide-litellm.sh +67 -5
- package/out/scripts/agentide_litellm_hooks_v1.py +182 -21
- package/out/scripts/analytics/agentide-litellm-otel.config.yaml +94 -118
- package/out/scripts/analytics/setup-analytics.ps1 +37 -13
- package/out/scripts/analytics/setup-analytics.sh +93 -13
- package/out/scripts/analytics/start-analytics.sh +86 -14
- package/out/scripts/gateway/setup-gateway.sh +72 -32
- package/out/shared/models.js +12 -111
- package/out/shared/providers.js +2 -2
- package/out/spotlight/install.js +7 -1
- package/out/store/index.js +41 -10
- package/out/sync.js +3 -1
- package/out/test/analytics.test.js +198 -34
- package/out/test/auth-baseurl.test.js +132 -0
- package/out/test/auth-bootstrapApply.test.js +27 -6
- package/out/test/auth-broker-hardening.test.js +227 -0
- package/out/test/auth-broker.test.js +112 -9
- package/out/test/blueprint-registry.test.js +105 -0
- package/out/test/branding.test.js +13 -0
- package/out/test/caps-governor.test.js +455 -0
- package/out/test/codex-new-file-survival.test.js +119 -0
- package/out/test/configuration-scopes.test.js +131 -0
- package/out/test/credential-context.test.js +23 -28
- package/out/test/custom-env-layering.test.js +151 -0
- package/out/test/data-plane-engine-wiring.test.js +250 -0
- package/out/test/data-plane.test.js +311 -0
- package/out/test/deploy-init.test.js +295 -4
- package/out/test/egress-broker.test.js +172 -0
- package/out/test/fleetDisplayUtils.test.js +4 -0
- package/out/test/gateway-client.test.js +28 -0
- package/out/test/gateway-install-source.test.js +111 -0
- package/out/test/gateway-lifecycle.test.js +1 -1
- package/out/test/gateway-outbound.test.js +7 -0
- package/out/test/gateway-secrets-preflight.test.js +127 -0
- package/out/test/gateway-session-routing.test.js +18 -0
- package/out/test/governor-hardening.test.js +217 -0
- package/out/test/headless-sync.test.js +22 -0
- package/out/test/idp-init.test.js +151 -0
- package/out/test/lease-signature.test.js +357 -0
- package/out/test/lease-trust-root.test.js +273 -0
- package/out/test/lease-validation.test.js +169 -0
- package/out/test/lease.test.js +114 -0
- package/out/test/mcp-obo.test.js +52 -27
- package/out/test/mcp.test.js +69 -3
- package/out/test/model-routing.test.js +133 -0
- package/out/test/pack-admission.test.js +216 -0
- package/out/test/pack-digest-parity.test.js +140 -0
- package/out/test/pack-reconcile.test.js +183 -0
- package/out/test/pack-signature-artifact.test.js +103 -0
- package/out/test/pack-signature.test.js +176 -0
- package/out/test/pack-trust-root.test.js +202 -0
- package/out/test/remote-trust.test.js +242 -0
- package/out/test/runner-protocol.test.js +249 -0
- package/out/test/sandbox-driver.test.js +553 -0
- package/out/test/sandbox-hardening.test.js +395 -0
- package/out/test/sandbox-runner.test.js +343 -0
- package/out/test/serve-gateway-turn.test.js +267 -0
- package/out/test/serve-hardening.test.js +125 -6
- package/out/test/serveClient.test.js +38 -5
- package/out/test/sessionShip.test.js +560 -0
- package/out/test/spotlightPublish.test.js +28 -0
- package/out/test/state-sync-peer.test.js +18 -5
- package/out/test/store-install-safe.test.js +69 -0
- package/out/test/tls-bypass.test.js +90 -0
- package/out/test/warrant.test.js +138 -0
- package/out/utils.js +73 -20
- package/package.json +1 -1
|
@@ -5,8 +5,9 @@
|
|
|
5
5
|
* Handles artifact display, rendering, and interactions.
|
|
6
6
|
* Uses panelApi (provided by runtime-bridge.js) instead of raw VS Code API.
|
|
7
7
|
*
|
|
8
|
-
* This file is
|
|
9
|
-
*
|
|
8
|
+
* This bundled file is the ONLY panel.js ever executed (see provider.getHtmlContent).
|
|
9
|
+
* It is not seeded to .agent-hippo/analytics/panel/ — a copy there would never run.
|
|
10
|
+
* Dashboard UI is customized via panel.html / panel.css, which ARE read from that directory.
|
|
10
11
|
* ----------------------------------------------------------------------------- */
|
|
11
12
|
|
|
12
13
|
// @ts-check
|
|
@@ -17,7 +18,7 @@ const panelApi = window.panelApi;
|
|
|
17
18
|
|
|
18
19
|
// Seed/version marker for deciding whether a user's locally seeded panel.js
|
|
19
20
|
// is compatible with the extension runtime (e.g. message forwarding fixes).
|
|
20
|
-
const AGENTIDE_PANEL_JS_VERSION = '2026.
|
|
21
|
+
const AGENTIDE_PANEL_JS_VERSION = '2026.07.21';
|
|
21
22
|
try { window.__AGENTIDE_PANEL_JS_VERSION__ = AGENTIDE_PANEL_JS_VERSION; } catch { /* no-op */ }
|
|
22
23
|
|
|
23
24
|
// -----------------------------------------------------------------------------
|
|
@@ -44,7 +45,7 @@ function createDefaultPanelState() {
|
|
|
44
45
|
return { version: 1, charts: {}, summaryHidden: false };
|
|
45
46
|
}
|
|
46
47
|
|
|
47
|
-
/** @type {{ artifacts: object[], galleryIgnorePatterns: string[], summaryCards: object[] | null, manifest: object | null, isRefreshing: boolean, scope: 'global'|'workspace', projectId: string, agentId: string, agentIds: string[], views: Array<{ id: string, name: string, scope: 'global'|'workspace', system: boolean, layout?: 'fleet-dashboard'|'gallery', refreshOnNavigate?: 'always'|'when-empty', preserveFleetIframe?: boolean }>, activeViewId: string, disabledCharts: Set<string>, panelState: PanelState, panelStateLoaded: boolean, lastArtifactCatalogSignature: string, fleetAutoRefreshIntervalSeconds: number, fleetRefreshVersion: number }} */
|
|
48
|
+
/** @type {{ artifacts: object[], galleryIgnorePatterns: string[], summaryCards: object[] | null, manifest: object | null, isRefreshing: boolean, scope: 'global'|'workspace', projectId: string, agentId: string, agentIds: string[], views: Array<{ id: string, name: string, scope: 'global'|'workspace', system: boolean, layout?: 'fleet-dashboard'|'gallery', refreshOnNavigate?: 'always'|'when-empty', preserveFleetIframe?: boolean }>, activeViewId: string, disabledCharts: Set<string>, panelState: PanelState, panelStateLoaded: boolean, lastArtifactCatalogSignature: string, fleetAutoRefreshIntervalSeconds: number, fleetRefreshVersion: number, needsGalleryRender: boolean, pendingForceFreshHtml: boolean, refreshingViewId: string | null }} */
|
|
48
49
|
const state = {
|
|
49
50
|
artifacts: [],
|
|
50
51
|
galleryIgnorePatterns: [],
|
|
@@ -64,8 +65,64 @@ const state = {
|
|
|
64
65
|
fleetAutoRefreshIntervalSeconds: 30,
|
|
65
66
|
fleetRefreshVersion: 0,
|
|
66
67
|
surfaceMode: 'spotlight',
|
|
68
|
+
// While a refresh is in flight, multiple artifactsUpdated bursts can arrive as scripts/
|
|
69
|
+
// watchers write files incrementally. Rendering on each one tears down and rebuilds the
|
|
70
|
+
// whole gallery (see renderGallery), which is visibly flickery. Defer to one render when
|
|
71
|
+
// the refresh actually ends (refreshFinished/refreshFailed/refreshNoData).
|
|
72
|
+
needsGalleryRender: false,
|
|
73
|
+
pendingForceFreshHtml: false,
|
|
74
|
+
// View id the in-flight refresh belongs to. Termination messages carry the viewId captured
|
|
75
|
+
// at refresh start, so after a mid-refresh view switch they no longer match activeViewId —
|
|
76
|
+
// match against this instead so isRefreshing cannot get stuck true.
|
|
77
|
+
refreshingViewId: null,
|
|
67
78
|
};
|
|
68
79
|
|
|
80
|
+
/** Render the gallery now if a render was deferred mid-refresh. */
|
|
81
|
+
function flushPendingGalleryRender() {
|
|
82
|
+
if (!state.needsGalleryRender) {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
state.needsGalleryRender = false;
|
|
86
|
+
const forceFreshHtml = state.pendingForceFreshHtml;
|
|
87
|
+
state.pendingForceFreshHtml = false;
|
|
88
|
+
renderGallery(state.artifacts, { forceFreshHtml });
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Single entry point for gallery renders triggered by host messages. While a refresh is in
|
|
93
|
+
* flight, defer to one render at refresh termination instead of tearing down and rebuilding
|
|
94
|
+
* the gallery on every artifactsUpdated/manifestUpdated/disabledChartsUpdated burst.
|
|
95
|
+
* @param {{ forceFreshHtml?: boolean }} [options]
|
|
96
|
+
*/
|
|
97
|
+
function requestGalleryRender(options) {
|
|
98
|
+
if (state.isRefreshing) {
|
|
99
|
+
state.needsGalleryRender = true;
|
|
100
|
+
if (options?.forceFreshHtml) {
|
|
101
|
+
state.pendingForceFreshHtml = true;
|
|
102
|
+
}
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
renderGallery(state.artifacts, { forceFreshHtml: Boolean(options?.forceFreshHtml) });
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* The active view changed while a refresh may be in flight: that refresh belongs to the view
|
|
110
|
+
* being left, so stop tracking it. The abandoned refresh's termination message is dropped by
|
|
111
|
+
* the viewId gates, and without this reset a deferred render would block the new view's first
|
|
112
|
+
* paint until that refresh ends (or forever, if no matching termination arrives).
|
|
113
|
+
*/
|
|
114
|
+
function resetRefreshTrackingForViewChange() {
|
|
115
|
+
if (!state.isRefreshing && !state.needsGalleryRender && !state.pendingForceFreshHtml) {
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
state.isRefreshing = false;
|
|
119
|
+
state.refreshingViewId = null;
|
|
120
|
+
state.needsGalleryRender = false;
|
|
121
|
+
state.pendingForceFreshHtml = false;
|
|
122
|
+
setRefreshButtonState(false);
|
|
123
|
+
setPerChartRefreshing(false);
|
|
124
|
+
}
|
|
125
|
+
|
|
69
126
|
function applySurfaceMode(mode) {
|
|
70
127
|
const team = mode === 'team';
|
|
71
128
|
state.surfaceMode = team ? 'team' : 'spotlight';
|
|
@@ -362,6 +419,7 @@ function switchToView(nextViewId) {
|
|
|
362
419
|
return;
|
|
363
420
|
}
|
|
364
421
|
state.activeViewId = nextViewId;
|
|
422
|
+
resetRefreshTrackingForViewChange();
|
|
365
423
|
state.panelStateLoaded = false;
|
|
366
424
|
state.panelState = createDefaultPanelState();
|
|
367
425
|
const viewSelect = /** @type {HTMLSelectElement | null} */ (document.getElementById('view-select'));
|
|
@@ -849,6 +907,9 @@ function toggleChartHiddenInPanelState(filename) {
|
|
|
849
907
|
// Summary Cards
|
|
850
908
|
// -----------------------------------------------------------------------------
|
|
851
909
|
|
|
910
|
+
/** Last rendered summary-cards payload, to skip no-op rebuilds of the summary strip. */
|
|
911
|
+
let lastSummaryCardsSignature = '';
|
|
912
|
+
|
|
852
913
|
/**
|
|
853
914
|
* Render summary cards in the header
|
|
854
915
|
* @param {Array<{label: string, value: string, icon: string}>} cards
|
|
@@ -859,10 +920,19 @@ function renderSummaryCards(cards) {
|
|
|
859
920
|
return;
|
|
860
921
|
}
|
|
861
922
|
if (!cards || cards.length === 0) {
|
|
923
|
+
lastSummaryCardsSignature = '';
|
|
862
924
|
renderSummaryPlaceholders();
|
|
863
925
|
return;
|
|
864
926
|
}
|
|
865
927
|
|
|
928
|
+
// The host posts summaryCards more than once per refresh; skip the rebuild (and its
|
|
929
|
+
// visible flash) when the payload is identical to what is already rendered.
|
|
930
|
+
const signature = JSON.stringify(cards);
|
|
931
|
+
if (signature === lastSummaryCardsSignature && !container.classList.contains('loading')) {
|
|
932
|
+
return;
|
|
933
|
+
}
|
|
934
|
+
lastSummaryCardsSignature = signature;
|
|
935
|
+
|
|
866
936
|
container.style.display = 'grid';
|
|
867
937
|
container.classList.remove('loading');
|
|
868
938
|
container.innerHTML = cards.map(card => `
|
|
@@ -987,7 +1057,6 @@ function renderGallery(artifacts, options) {
|
|
|
987
1057
|
}
|
|
988
1058
|
return new Date(b.modifiedAt).getTime() - new Date(a.modifiedAt).getTime();
|
|
989
1059
|
});
|
|
990
|
-
const interactiveChartKeys = chartArtifacts.map((artifact) => normalizeFilename(String(artifact.filename || '')));
|
|
991
1060
|
const nonChartArtifacts = visibleArtifacts
|
|
992
1061
|
.filter((artifact) => artifact.type !== 'chart')
|
|
993
1062
|
.sort((a, b) => new Date(b.modifiedAt).getTime() - new Date(a.modifiedAt).getTime());
|
|
@@ -1085,7 +1154,7 @@ function renderGallery(artifacts, options) {
|
|
|
1085
1154
|
|
|
1086
1155
|
showGalleryState('content');
|
|
1087
1156
|
|
|
1088
|
-
const
|
|
1157
|
+
const buildCardHtml = (artifact) => {
|
|
1089
1158
|
const timeAgo = formatTimeAgo(new Date(artifact.modifiedAt));
|
|
1090
1159
|
const sizeFormatted = formatSize(artifact.size);
|
|
1091
1160
|
const isChart = artifact.type === 'chart';
|
|
@@ -1175,101 +1244,214 @@ function renderGallery(artifacts, options) {
|
|
|
1175
1244
|
${resizeHandle}
|
|
1176
1245
|
</div>
|
|
1177
1246
|
`;
|
|
1178
|
-
}
|
|
1247
|
+
};
|
|
1248
|
+
// Keyed card reuse: diff incoming artifacts against existing cards by localPath and only
|
|
1249
|
+
// rebuild what changed. Rebuilding a card destroys its iframe/img and re-fetches content —
|
|
1250
|
+
// that teardown is the visible blink — so unchanged cards must not be touched at all.
|
|
1251
|
+
/** @type {Map<string, HTMLElement>} */
|
|
1252
|
+
const existingCards = new Map();
|
|
1253
|
+
Array.from(container.children).forEach((childEl) => {
|
|
1254
|
+
const child = /** @type {HTMLElement} */ (childEl);
|
|
1255
|
+
const childPath = child.dataset.path || '';
|
|
1256
|
+
const reusableAsCard =
|
|
1257
|
+
child.classList.contains('artifact-card')
|
|
1258
|
+
&& !child.classList.contains('fleet-dashboard-full') // fleet layout card: different structure
|
|
1259
|
+
&& !child.classList.contains('deleting')
|
|
1260
|
+
&& childPath
|
|
1261
|
+
&& !existingCards.has(childPath);
|
|
1262
|
+
if (!reusableAsCard) {
|
|
1263
|
+
child.remove();
|
|
1264
|
+
return;
|
|
1265
|
+
}
|
|
1266
|
+
existingCards.set(childPath, child);
|
|
1267
|
+
});
|
|
1179
1268
|
|
|
1180
|
-
container.innerHTML = html;
|
|
1181
1269
|
/** @type {Array<object>} */
|
|
1182
1270
|
const htmlArtifactsNeedingFetch = [];
|
|
1183
1271
|
/** @type {Array<object>} */
|
|
1184
1272
|
const markdownArtifactsNeedingFetch = [];
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
const
|
|
1273
|
+
/** @type {HTMLElement[]} */
|
|
1274
|
+
const orderedCards = [];
|
|
1275
|
+
for (const artifact of orderedArtifacts) {
|
|
1276
|
+
const path = String(artifact.localPath || '');
|
|
1277
|
+
const modifiedAt = String(artifact.modifiedAt || '');
|
|
1278
|
+
const isVisual = artifact.type === 'chart' || artifact.type === 'image';
|
|
1279
|
+
const chartState = isVisual ? artifact._panel : undefined;
|
|
1280
|
+
const signature = computeCardRenderSignature(artifact);
|
|
1281
|
+
const forceHtmlReload = forceFreshHtml && artifact.format === 'html';
|
|
1282
|
+
const existing = existingCards.get(path);
|
|
1283
|
+
existingCards.delete(path);
|
|
1284
|
+
|
|
1285
|
+
if (existing && existing.dataset.cardSignature === signature && !forceHtmlReload) {
|
|
1286
|
+
// Unchanged: leave the DOM (and any live iframe) alone. Expanded/height are kept
|
|
1287
|
+
// out of the signature and applied in place so toggling them never reloads content.
|
|
1288
|
+
if (isVisual) {
|
|
1289
|
+
existing.classList.toggle('expanded', chartState?.expanded === true);
|
|
1290
|
+
const contentEl = /** @type {HTMLElement | null} */ (existing.querySelector('.artifact-content'));
|
|
1291
|
+
if (contentEl && chartState?.height) {
|
|
1292
|
+
contentEl.style.height = `${chartState.height}px`;
|
|
1293
|
+
contentEl.style.minHeight = `${chartState.height}px`;
|
|
1294
|
+
contentEl.style.overflow = 'auto';
|
|
1295
|
+
}
|
|
1296
|
+
}
|
|
1297
|
+
const timeEl = existing.querySelector('.artifact-time');
|
|
1298
|
+
if (timeEl) {
|
|
1299
|
+
timeEl.textContent = formatTimeAgo(new Date(artifact.modifiedAt));
|
|
1300
|
+
}
|
|
1301
|
+
orderedCards.push(existing);
|
|
1302
|
+
continue;
|
|
1303
|
+
}
|
|
1304
|
+
|
|
1305
|
+
const template = document.createElement('template');
|
|
1306
|
+
template.innerHTML = buildCardHtml(artifact).trim();
|
|
1307
|
+
const card = /** @type {HTMLElement | null} */ (template.content.firstElementChild);
|
|
1308
|
+
if (!card) {
|
|
1309
|
+
continue;
|
|
1310
|
+
}
|
|
1311
|
+
card.dataset.cardSignature = signature;
|
|
1189
1312
|
const htmlHost = /** @type {HTMLElement | null} */ (card.querySelector('.html-preview'));
|
|
1190
|
-
if (htmlHost
|
|
1191
|
-
const reusable =
|
|
1313
|
+
if (htmlHost) {
|
|
1314
|
+
const reusable = forceHtmlReload ? undefined : reusableHtmlPreviews.get(`${path}::${modifiedAt}`);
|
|
1192
1315
|
if (reusable) {
|
|
1193
1316
|
htmlHost.classList.add('ready');
|
|
1194
1317
|
htmlHost.innerHTML = '';
|
|
1195
1318
|
htmlHost.appendChild(reusable);
|
|
1196
|
-
} else {
|
|
1197
|
-
|
|
1198
|
-
if (htmlArtifact) {
|
|
1199
|
-
htmlArtifactsNeedingFetch.push(htmlArtifact);
|
|
1200
|
-
}
|
|
1319
|
+
} else if (artifact.format === 'html') {
|
|
1320
|
+
htmlArtifactsNeedingFetch.push(artifact);
|
|
1201
1321
|
}
|
|
1202
1322
|
}
|
|
1323
|
+
if (card.querySelector('.markdown-preview')) {
|
|
1324
|
+
markdownArtifactsNeedingFetch.push(artifact);
|
|
1325
|
+
}
|
|
1326
|
+
attachArtifactCardHandlers(card);
|
|
1327
|
+
if (existing) {
|
|
1328
|
+
existing.replaceWith(card);
|
|
1329
|
+
}
|
|
1330
|
+
orderedCards.push(card);
|
|
1331
|
+
}
|
|
1203
1332
|
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1333
|
+
// Cards whose artifacts disappeared.
|
|
1334
|
+
existingCards.forEach((card) => card.remove());
|
|
1335
|
+
|
|
1336
|
+
// Minimal-move reorder: re-inserting a node reloads its iframe, so only move cards that
|
|
1337
|
+
// are actually out of position.
|
|
1338
|
+
let cursor = container.firstElementChild;
|
|
1339
|
+
for (const card of orderedCards) {
|
|
1340
|
+
if (card === cursor) {
|
|
1341
|
+
cursor = cursor.nextElementSibling;
|
|
1342
|
+
continue;
|
|
1210
1343
|
}
|
|
1211
|
-
|
|
1344
|
+
container.insertBefore(card, cursor);
|
|
1345
|
+
}
|
|
1346
|
+
|
|
1212
1347
|
requestHtmlPreviewContents(htmlArtifactsNeedingFetch);
|
|
1213
1348
|
requestMarkdownPreviewContents(markdownArtifactsNeedingFetch);
|
|
1214
1349
|
|
|
1215
|
-
//
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
const path = card.dataset.path;
|
|
1219
|
-
const filename = card.dataset.filename;
|
|
1220
|
-
const isChart = card.dataset.type === 'chart';
|
|
1221
|
-
const isVisual = card.dataset.type === 'chart' || card.dataset.type === 'image';
|
|
1350
|
+
// Markdown previews are loaded via host message passing (artifactContent)
|
|
1351
|
+
// to avoid fetch restrictions for local report files.
|
|
1352
|
+
}
|
|
1222
1353
|
|
|
1223
|
-
|
|
1354
|
+
/**
|
|
1355
|
+
* Per-card render signature: every input that affects a card's DOM except expanded/height,
|
|
1356
|
+
* which renderGallery applies in place so toggling them never rebuilds the card.
|
|
1357
|
+
* @param {object} artifact
|
|
1358
|
+
* @returns {string}
|
|
1359
|
+
*/
|
|
1360
|
+
function computeCardRenderSignature(artifact) {
|
|
1361
|
+
const isVisual = artifact.type === 'chart' || artifact.type === 'image';
|
|
1362
|
+
const chartState = isVisual ? artifact._panel : undefined;
|
|
1363
|
+
const manifestEntry = state.manifest?.artifacts?.find(e => e.filename === artifact.filename);
|
|
1364
|
+
return [
|
|
1365
|
+
String(artifact.localPath || ''),
|
|
1366
|
+
String(artifact.filename || ''),
|
|
1367
|
+
String(artifact.modifiedAt || ''),
|
|
1368
|
+
String(artifact.size || ''),
|
|
1369
|
+
String(artifact.type || ''),
|
|
1370
|
+
String(artifact.format || ''),
|
|
1371
|
+
String(artifact.generator || ''),
|
|
1372
|
+
String(manifestEntry?.title || ''),
|
|
1373
|
+
String(manifestEntry?.source || ''),
|
|
1374
|
+
chartState?.hidden === true ? '1' : '0',
|
|
1375
|
+
Number.isFinite(chartState?.order) ? String(chartState.order) : '',
|
|
1376
|
+
].join('|');
|
|
1377
|
+
}
|
|
1378
|
+
|
|
1379
|
+
/**
|
|
1380
|
+
* Chart/image ordering keys derived from current DOM order — computed at click time so
|
|
1381
|
+
* handlers on long-lived cards never act on a stale snapshot.
|
|
1382
|
+
* @returns {string[]}
|
|
1383
|
+
*/
|
|
1384
|
+
function getInteractiveChartKeysFromDom() {
|
|
1385
|
+
const container = document.getElementById('gallery-content');
|
|
1386
|
+
if (!container) {
|
|
1387
|
+
return [];
|
|
1388
|
+
}
|
|
1389
|
+
return Array.from(container.querySelectorAll('.artifact-card'))
|
|
1390
|
+
.filter((cardEl) => {
|
|
1391
|
+
const card = /** @type {HTMLElement} */ (cardEl);
|
|
1392
|
+
return card.dataset.type === 'chart' || card.dataset.type === 'image';
|
|
1393
|
+
})
|
|
1394
|
+
.map((cardEl) => normalizeFilename(String(/** @type {HTMLElement} */ (cardEl).dataset.filename || '')))
|
|
1395
|
+
.filter(Boolean);
|
|
1396
|
+
}
|
|
1397
|
+
|
|
1398
|
+
/**
|
|
1399
|
+
* Wire interactive behaviors for one gallery card (open/delete, layout buttons, expand on
|
|
1400
|
+
* click, resize handle). Called once per created card; reused cards keep their listeners.
|
|
1401
|
+
* @param {HTMLElement} card
|
|
1402
|
+
*/
|
|
1403
|
+
function attachArtifactCardHandlers(card) {
|
|
1404
|
+
const path = card.dataset.path;
|
|
1405
|
+
const filename = card.dataset.filename;
|
|
1406
|
+
const isChart = card.dataset.type === 'chart';
|
|
1407
|
+
const isVisual = card.dataset.type === 'chart' || card.dataset.type === 'image';
|
|
1408
|
+
|
|
1409
|
+
card.querySelector('.open-btn')?.addEventListener('click', (e) => {
|
|
1410
|
+
e.stopPropagation();
|
|
1411
|
+
panelApi.postMessage({ type: 'openArtifact', path });
|
|
1412
|
+
});
|
|
1413
|
+
|
|
1414
|
+
card.querySelector('.delete-btn')?.addEventListener('click', (e) => {
|
|
1415
|
+
e.stopPropagation();
|
|
1416
|
+
panelApi.postMessage({ type: 'deleteArtifact', path });
|
|
1417
|
+
});
|
|
1418
|
+
|
|
1419
|
+
if (isChart && filename) {
|
|
1420
|
+
card.querySelector('.move-up-btn')?.addEventListener('click', (e) => {
|
|
1224
1421
|
e.stopPropagation();
|
|
1225
|
-
|
|
1422
|
+
moveChartInPanelState(filename, 'up', getInteractiveChartKeysFromDom());
|
|
1423
|
+
renderGallery(state.artifacts);
|
|
1226
1424
|
});
|
|
1227
1425
|
|
|
1228
|
-
card.querySelector('.
|
|
1426
|
+
card.querySelector('.move-down-btn')?.addEventListener('click', (e) => {
|
|
1229
1427
|
e.stopPropagation();
|
|
1230
|
-
|
|
1428
|
+
moveChartInPanelState(filename, 'down', getInteractiveChartKeysFromDom());
|
|
1429
|
+
renderGallery(state.artifacts);
|
|
1231
1430
|
});
|
|
1232
1431
|
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
renderGallery(state.artifacts);
|
|
1238
|
-
});
|
|
1239
|
-
|
|
1240
|
-
card.querySelector('.move-down-btn')?.addEventListener('click', (e) => {
|
|
1241
|
-
e.stopPropagation();
|
|
1242
|
-
moveChartInPanelState(filename, 'down', interactiveChartKeys);
|
|
1243
|
-
renderGallery(state.artifacts);
|
|
1244
|
-
});
|
|
1245
|
-
|
|
1246
|
-
card.querySelector('.toggle-enabled-btn')?.addEventListener('click', (e) => {
|
|
1247
|
-
e.stopPropagation();
|
|
1248
|
-
toggleChartHiddenInPanelState(filename);
|
|
1249
|
-
renderGallery(state.artifacts);
|
|
1250
|
-
});
|
|
1251
|
-
}
|
|
1252
|
-
|
|
1253
|
-
// Click on card to expand/collapse
|
|
1254
|
-
card.addEventListener('click', (event) => {
|
|
1255
|
-
const target = /** @type {HTMLElement | null} */ (event.target instanceof HTMLElement ? event.target : null);
|
|
1256
|
-
if (target?.closest('button,.resize-handle')) {
|
|
1257
|
-
return;
|
|
1258
|
-
}
|
|
1259
|
-
const nextExpanded = !card.classList.contains('expanded');
|
|
1260
|
-
card.classList.toggle('expanded', nextExpanded);
|
|
1261
|
-
if (isVisual && filename) {
|
|
1262
|
-
setChartExpanded(filename, nextExpanded);
|
|
1263
|
-
}
|
|
1432
|
+
card.querySelector('.toggle-enabled-btn')?.addEventListener('click', (e) => {
|
|
1433
|
+
e.stopPropagation();
|
|
1434
|
+
toggleChartHiddenInPanelState(filename);
|
|
1435
|
+
renderGallery(state.artifacts);
|
|
1264
1436
|
});
|
|
1437
|
+
}
|
|
1265
1438
|
|
|
1266
|
-
|
|
1267
|
-
|
|
1439
|
+
// Click on card to expand/collapse
|
|
1440
|
+
card.addEventListener('click', (event) => {
|
|
1441
|
+
const target = /** @type {HTMLElement | null} */ (event.target instanceof HTMLElement ? event.target : null);
|
|
1442
|
+
if (target?.closest('button,.resize-handle')) {
|
|
1443
|
+
return;
|
|
1444
|
+
}
|
|
1445
|
+
const nextExpanded = !card.classList.contains('expanded');
|
|
1446
|
+
card.classList.toggle('expanded', nextExpanded);
|
|
1447
|
+
if (isVisual && filename) {
|
|
1448
|
+
setChartExpanded(filename, nextExpanded);
|
|
1268
1449
|
}
|
|
1269
1450
|
});
|
|
1270
1451
|
|
|
1271
|
-
|
|
1272
|
-
|
|
1452
|
+
if (filename) {
|
|
1453
|
+
attachResizeHandle(card, filename);
|
|
1454
|
+
}
|
|
1273
1455
|
}
|
|
1274
1456
|
|
|
1275
1457
|
/**
|
|
@@ -2044,12 +2226,18 @@ panelApi.onMessage(msg => {
|
|
|
2044
2226
|
state.artifacts = msg.artifacts;
|
|
2045
2227
|
state.galleryIgnorePatterns = nextGalleryIgnore;
|
|
2046
2228
|
// View selection is owned by viewsLoaded; do not let artifact batches revert the dropdown.
|
|
2229
|
+
const prevActiveViewId = state.activeViewId;
|
|
2047
2230
|
if (
|
|
2048
2231
|
nextActiveViewId === state.activeViewId
|
|
2049
2232
|
|| !state.views.some((view) => view.id === state.activeViewId)
|
|
2050
2233
|
) {
|
|
2051
2234
|
state.activeViewId = nextActiveViewId;
|
|
2052
2235
|
}
|
|
2236
|
+
if (state.activeViewId !== prevActiveViewId) {
|
|
2237
|
+
// Host-initiated view change (e.g. openWithView): any in-flight refresh belongs
|
|
2238
|
+
// to the previous view — render now instead of deferring behind it.
|
|
2239
|
+
resetRefreshTrackingForViewChange();
|
|
2240
|
+
}
|
|
2053
2241
|
state.fleetRefreshVersion = nextFleetRefreshVersion;
|
|
2054
2242
|
applyFleetAutoRefresh();
|
|
2055
2243
|
if (exportOnlyCatalogChange) {
|
|
@@ -2059,10 +2247,11 @@ panelApi.onMessage(msg => {
|
|
|
2059
2247
|
// Fleet JSON can change without agent-fleet.html mtime changing if the host
|
|
2060
2248
|
// did not re-run the widget script; bumping fleetRefreshVersion means data is
|
|
2061
2249
|
// fresher — force a preview reload so the iframe is not reused with stale HTML.
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2250
|
+
if (state.isRefreshing) {
|
|
2251
|
+
// Mid-refresh burst: keep spinners on; requestGalleryRender defers the rebuild.
|
|
2252
|
+
setPerChartRefreshing(true);
|
|
2253
|
+
}
|
|
2254
|
+
requestGalleryRender({ forceFreshHtml: hasFleetVersionUpdate });
|
|
2066
2255
|
break;
|
|
2067
2256
|
}
|
|
2068
2257
|
|
|
@@ -2093,7 +2282,7 @@ panelApi.onMessage(msg => {
|
|
|
2093
2282
|
state.manifest = msg.manifest;
|
|
2094
2283
|
// Re-render gallery with new manifest data
|
|
2095
2284
|
if (state.artifacts.length > 0) {
|
|
2096
|
-
|
|
2285
|
+
requestGalleryRender();
|
|
2097
2286
|
}
|
|
2098
2287
|
break;
|
|
2099
2288
|
|
|
@@ -2137,6 +2326,10 @@ panelApi.onMessage(msg => {
|
|
|
2137
2326
|
case 'generatingStarted':
|
|
2138
2327
|
setRefreshButtonState(true);
|
|
2139
2328
|
state.isRefreshing = false;
|
|
2329
|
+
state.refreshingViewId = null;
|
|
2330
|
+
// Drop any deferred render — a later flush would stomp the generating state.
|
|
2331
|
+
state.needsGalleryRender = false;
|
|
2332
|
+
state.pendingForceFreshHtml = false;
|
|
2140
2333
|
setPerChartRefreshing(false);
|
|
2141
2334
|
showGeneratingState();
|
|
2142
2335
|
break;
|
|
@@ -2144,6 +2337,9 @@ panelApi.onMessage(msg => {
|
|
|
2144
2337
|
case 'generatingCancelled':
|
|
2145
2338
|
setRefreshButtonState(false);
|
|
2146
2339
|
state.isRefreshing = false;
|
|
2340
|
+
state.refreshingViewId = null;
|
|
2341
|
+
state.needsGalleryRender = false;
|
|
2342
|
+
state.pendingForceFreshHtml = false;
|
|
2147
2343
|
setPerChartRefreshing(false);
|
|
2148
2344
|
// Go back to empty or content state
|
|
2149
2345
|
if (state.artifacts.length > 0) {
|
|
@@ -2156,6 +2352,9 @@ panelApi.onMessage(msg => {
|
|
|
2156
2352
|
case 'generatingFailed':
|
|
2157
2353
|
setRefreshButtonState(false);
|
|
2158
2354
|
state.isRefreshing = false;
|
|
2355
|
+
state.refreshingViewId = null;
|
|
2356
|
+
state.needsGalleryRender = false;
|
|
2357
|
+
state.pendingForceFreshHtml = false;
|
|
2159
2358
|
setPerChartRefreshing(false);
|
|
2160
2359
|
showFailedState(msg.error);
|
|
2161
2360
|
break;
|
|
@@ -2164,15 +2363,18 @@ panelApi.onMessage(msg => {
|
|
|
2164
2363
|
if (!msg.viewId || msg.viewId === state.activeViewId) {
|
|
2165
2364
|
setRefreshButtonState(true);
|
|
2166
2365
|
state.isRefreshing = true;
|
|
2366
|
+
state.refreshingViewId = typeof msg.viewId === 'string' && msg.viewId ? msg.viewId : null;
|
|
2167
2367
|
setPerChartRefreshing(true);
|
|
2168
2368
|
}
|
|
2169
2369
|
break;
|
|
2170
2370
|
|
|
2171
2371
|
case 'refreshFinished':
|
|
2172
|
-
if (!msg.viewId || msg.viewId === state.activeViewId) {
|
|
2372
|
+
if (!msg.viewId || msg.viewId === state.activeViewId || msg.viewId === state.refreshingViewId) {
|
|
2173
2373
|
setRefreshButtonState(false);
|
|
2174
2374
|
state.isRefreshing = false;
|
|
2375
|
+
state.refreshingViewId = null;
|
|
2175
2376
|
setPerChartRefreshing(false);
|
|
2377
|
+
flushPendingGalleryRender();
|
|
2176
2378
|
if (activeViewPreservesFleetIframe()) {
|
|
2177
2379
|
document.querySelectorAll('.html-preview iframe').forEach((frameEl) => {
|
|
2178
2380
|
const iframe = /** @type {HTMLIFrameElement} */ (frameEl);
|
|
@@ -2186,29 +2388,38 @@ panelApi.onMessage(msg => {
|
|
|
2186
2388
|
}
|
|
2187
2389
|
break;
|
|
2188
2390
|
|
|
2189
|
-
case 'viewsLoaded':
|
|
2391
|
+
case 'viewsLoaded': {
|
|
2190
2392
|
if (msg.surfaceMode === 'team' || msg.surfaceMode === 'spotlight') {
|
|
2191
2393
|
applySurfaceMode(msg.surfaceMode);
|
|
2192
2394
|
}
|
|
2395
|
+
const prevViewsLoadedViewId = state.activeViewId;
|
|
2193
2396
|
state.views = Array.isArray(msg.views) ? msg.views : [];
|
|
2194
2397
|
state.activeViewId = typeof msg.activeViewId === 'string' ? msg.activeViewId : state.activeViewId;
|
|
2398
|
+
if (state.activeViewId !== prevViewsLoadedViewId) {
|
|
2399
|
+
resetRefreshTrackingForViewChange();
|
|
2400
|
+
}
|
|
2195
2401
|
applyViewOptions();
|
|
2196
2402
|
applyFleetAutoRefresh();
|
|
2197
2403
|
break;
|
|
2404
|
+
}
|
|
2198
2405
|
|
|
2199
2406
|
case 'refreshNoData':
|
|
2200
|
-
if (!msg.viewId || msg.viewId === state.activeViewId) {
|
|
2407
|
+
if (!msg.viewId || msg.viewId === state.activeViewId || msg.viewId === state.refreshingViewId) {
|
|
2201
2408
|
setRefreshButtonState(false);
|
|
2202
2409
|
state.isRefreshing = false;
|
|
2410
|
+
state.refreshingViewId = null;
|
|
2203
2411
|
setPerChartRefreshing(false);
|
|
2412
|
+
flushPendingGalleryRender();
|
|
2204
2413
|
}
|
|
2205
2414
|
break;
|
|
2206
2415
|
|
|
2207
2416
|
case 'refreshFailed':
|
|
2208
|
-
if (!msg.viewId || msg.viewId === state.activeViewId) {
|
|
2417
|
+
if (!msg.viewId || msg.viewId === state.activeViewId || msg.viewId === state.refreshingViewId) {
|
|
2209
2418
|
setRefreshButtonState(false);
|
|
2210
2419
|
state.isRefreshing = false;
|
|
2420
|
+
state.refreshingViewId = null;
|
|
2211
2421
|
setPerChartRefreshing(false);
|
|
2422
|
+
flushPendingGalleryRender();
|
|
2212
2423
|
if (state.artifacts.length === 0) {
|
|
2213
2424
|
showFailedState(msg.error);
|
|
2214
2425
|
}
|
|
@@ -2256,7 +2467,7 @@ panelApi.onMessage(msg => {
|
|
|
2256
2467
|
.map((name) => String(name || '').trim().toLowerCase())
|
|
2257
2468
|
.filter(Boolean),
|
|
2258
2469
|
);
|
|
2259
|
-
|
|
2470
|
+
requestGalleryRender();
|
|
2260
2471
|
break;
|
|
2261
2472
|
|
|
2262
2473
|
case 'dataStale':
|
|
Binary file
|
package/out/analytics/service.js
CHANGED
|
@@ -800,21 +800,22 @@ class AnalyticsService {
|
|
|
800
800
|
'-ConfigPath',
|
|
801
801
|
options.configPath,
|
|
802
802
|
]);
|
|
803
|
+
// A missing config is not fatal: the launcher re-seeds the managed default
|
|
804
|
+
// (~/.agent-hippo/litellm-otel.yaml) from its bundled template before starting.
|
|
803
805
|
return [
|
|
804
806
|
'Write-Host "Starting LiteLLM proxy..."',
|
|
805
807
|
`if (-not (Test-Path ${q(options.configPath)})) {`,
|
|
806
|
-
` Write-Host ${q(`[
|
|
807
|
-
'}
|
|
808
|
-
|
|
809
|
-
'
|
|
810
|
-
`
|
|
811
|
-
'
|
|
812
|
-
`
|
|
813
|
-
`
|
|
814
|
-
'
|
|
815
|
-
'
|
|
816
|
-
'
|
|
817
|
-
' }',
|
|
808
|
+
` Write-Host ${q(`[INFO] LiteLLM config missing: ${options.configPath} — launcher will re-create it from the bundled template.`)}`,
|
|
809
|
+
'}',
|
|
810
|
+
`$env:LITELLM_CONFIG_PATH = ${q(options.configPath)}`,
|
|
811
|
+
'try {',
|
|
812
|
+
` $proc = Start-Process -FilePath ${q(getWindowsPwshOrPowerShell())} -WindowStyle Hidden -WorkingDirectory ${q(path.dirname(options.litellmScript))} -ArgumentList ${q(launcherArgumentLine)} -RedirectStandardOutput ${q(options.stdoutPath)} -RedirectStandardError ${q(options.stderrPath)} -PassThru -ErrorAction Stop`,
|
|
813
|
+
' Write-Host "[OK] LiteLLM launcher started (PID: $($proc.Id))"',
|
|
814
|
+
` Write-Host ${q(` Logs: ${options.stdoutPath}`)}`,
|
|
815
|
+
` Write-Host ${q(` Errors: ${options.stderrPath}`)}`,
|
|
816
|
+
'} catch {',
|
|
817
|
+
' Write-Host "[ERROR] Failed to start LiteLLM launcher." -ForegroundColor Red',
|
|
818
|
+
' Write-Host $_.Exception.Message -ForegroundColor Red',
|
|
818
819
|
'}',
|
|
819
820
|
];
|
|
820
821
|
}
|
|
@@ -854,17 +855,18 @@ class AnalyticsService {
|
|
|
854
855
|
if (!options.litellmScript) {
|
|
855
856
|
return ['echo "[WARN] LiteLLM launcher script not found. Skipping LiteLLM start." >&2'];
|
|
856
857
|
}
|
|
858
|
+
// A missing config is not fatal: the launcher re-seeds the managed default
|
|
859
|
+
// (~/.agent-hippo/litellm-otel.yaml) from its bundled template before starting.
|
|
857
860
|
return [
|
|
858
861
|
'echo "Starting LiteLLM proxy..."',
|
|
859
862
|
`if [ ! -f ${q(options.configPath)} ]; then`,
|
|
860
|
-
` echo ${q(`[
|
|
861
|
-
'else',
|
|
862
|
-
` export LITELLM_CONFIG_PATH=${q(options.configPath)}`,
|
|
863
|
-
` nohup ${q(options.litellmScript)} --config ${q(options.configPath)} >> ${q(options.stdoutPath)} 2>> ${q(options.stderrPath)} &`,
|
|
864
|
-
' echo "[OK] LiteLLM launcher started (PID: $!)"',
|
|
865
|
-
` echo ${q(` Logs: ${options.stdoutPath}`)}`,
|
|
866
|
-
` echo ${q(` Errors: ${options.stderrPath}`)}`,
|
|
863
|
+
` echo ${q(`[INFO] LiteLLM config missing: ${options.configPath} — launcher will re-create it from the bundled template.`)}`,
|
|
867
864
|
'fi',
|
|
865
|
+
`export LITELLM_CONFIG_PATH=${q(options.configPath)}`,
|
|
866
|
+
`nohup ${q(options.litellmScript)} --config ${q(options.configPath)} >> ${q(options.stdoutPath)} 2>> ${q(options.stderrPath)} &`,
|
|
867
|
+
'echo "[OK] LiteLLM launcher started (PID: $!)"',
|
|
868
|
+
`echo ${q(` Logs: ${options.stdoutPath}`)}`,
|
|
869
|
+
`echo ${q(` Errors: ${options.stderrPath}`)}`,
|
|
868
870
|
];
|
|
869
871
|
}
|
|
870
872
|
getLifecycleTerminalIntro(action) {
|
|
@@ -893,13 +895,9 @@ class AnalyticsService {
|
|
|
893
895
|
* Start LiteLLM in a detached background process. Logs go to .agent-hippo/analytics/litellm.{log,error.log}.
|
|
894
896
|
*/
|
|
895
897
|
async startLiteLLMDirectly() {
|
|
898
|
+
// No existence check: a missing managed config is re-seeded from the bundled
|
|
899
|
+
// template by the launcher itself (deleting it is a "reset to defaults" gesture).
|
|
896
900
|
const configPath = path.join((0, index_1.getAgentideHome)(), 'litellm-otel.yaml');
|
|
897
|
-
try {
|
|
898
|
-
await fs_1.promises.access(configPath);
|
|
899
|
-
}
|
|
900
|
-
catch {
|
|
901
|
-
return false;
|
|
902
|
-
}
|
|
903
901
|
const isWindows = process.platform === 'win32';
|
|
904
902
|
const args = isWindows
|
|
905
903
|
? ['-ConfigPath', configPath]
|