@industry-theme/principal-view-panels 0.1.46 → 0.1.47

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.
@@ -51917,6 +51917,833 @@ const TraceViewerPanel = ({
51917
51917
  }
51918
51918
  );
51919
51919
  };
51920
+ const EXECUTION_FILE_PATTERNS = [
51921
+ // Packages monorepo pattern: packages/core/__executions__/api-tests.spans.json
51922
+ /^packages\/([^/]+)\/__executions__\/(.+)\.(?:spans|execution|events)\.json$/,
51923
+ // Inside .principal-views: .principal-views/__executions__/graph-converter.spans.json
51924
+ /^\.principal-views\/__executions__\/(.+)\.(?:spans|execution|events)\.json$/,
51925
+ // Direct __executions__ folder: __executions__/test-run.spans.json
51926
+ /^__executions__\/(.+)\.(?:spans|execution|events)\.json$/
51927
+ ];
51928
+ function getExecutionNameFromFilename(filename) {
51929
+ return filename.replace(/\.(?:spans|execution|events)\.json$/, "").split("-").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
51930
+ }
51931
+ function getCanvasBasename(filename) {
51932
+ return filename.replace(/\.(?:spans|execution|events)\.json$/, "");
51933
+ }
51934
+ class ExecutionLoader {
51935
+ /**
51936
+ * Parse JSON execution artifact content
51937
+ */
51938
+ static parseExecutionArtifact(content) {
51939
+ try {
51940
+ const parsed = JSON.parse(content);
51941
+ if (Array.isArray(parsed)) {
51942
+ return { spans: parsed };
51943
+ }
51944
+ return parsed;
51945
+ } catch (error) {
51946
+ throw new Error(`Failed to parse execution artifact JSON: ${error.message}`);
51947
+ }
51948
+ }
51949
+ /**
51950
+ * Get spans array from artifact (handles both formats)
51951
+ */
51952
+ static getSpans(artifact) {
51953
+ if (artifact.spans) {
51954
+ return artifact.spans;
51955
+ }
51956
+ if (Array.isArray(artifact)) {
51957
+ return artifact;
51958
+ }
51959
+ const spans = [];
51960
+ for (const key in artifact) {
51961
+ if (!isNaN(Number(key))) {
51962
+ spans.push(artifact[key]);
51963
+ }
51964
+ }
51965
+ return spans;
51966
+ }
51967
+ /**
51968
+ * Extract metadata from an execution artifact
51969
+ */
51970
+ static getExecutionMetadata(artifact) {
51971
+ const spans = ExecutionLoader.getSpans(artifact);
51972
+ const spanCount = spans.length;
51973
+ const eventCount = spans.reduce((total, span) => {
51974
+ var _a;
51975
+ return total + (((_a = span.events) == null ? void 0 : _a.length) || 0);
51976
+ }, 0);
51977
+ const metadata = artifact.metadata;
51978
+ let status = "success";
51979
+ if (metadata == null ? void 0 : metadata.status) {
51980
+ status = metadata.status;
51981
+ } else if (spans.length > 0) {
51982
+ const hasError = spans.some(
51983
+ (s) => s.status === "ERROR" || s.status === "error" || s.status === "FAILED"
51984
+ );
51985
+ status = hasError ? "error" : "OK";
51986
+ }
51987
+ return {
51988
+ name: (metadata == null ? void 0 : metadata.canvasName) || "Untitled Execution",
51989
+ canvasName: metadata == null ? void 0 : metadata.canvasName,
51990
+ exportedAt: metadata == null ? void 0 : metadata.exportedAt,
51991
+ source: metadata == null ? void 0 : metadata.source,
51992
+ framework: metadata == null ? void 0 : metadata.framework,
51993
+ status,
51994
+ spanCount,
51995
+ eventCount
51996
+ };
51997
+ }
51998
+ /**
51999
+ * Find all execution artifact files in the file tree
52000
+ */
52001
+ static findExecutionFiles(files) {
52002
+ const executionFiles = [];
52003
+ for (const file of files) {
52004
+ const filePath = file.relativePath || file.path || "";
52005
+ const fileName = file.name || filePath.split("/").pop() || "";
52006
+ for (const pattern of EXECUTION_FILE_PATTERNS) {
52007
+ const match = filePath.match(pattern);
52008
+ if (match) {
52009
+ let id;
52010
+ let packageName;
52011
+ let baseName;
52012
+ if (pattern === EXECUTION_FILE_PATTERNS[0]) {
52013
+ packageName = match[1];
52014
+ baseName = match[2];
52015
+ id = `${packageName}-${baseName}`;
52016
+ } else if (pattern === EXECUTION_FILE_PATTERNS[1]) {
52017
+ baseName = match[1];
52018
+ id = `pv-${baseName}`;
52019
+ } else {
52020
+ baseName = match[1];
52021
+ id = baseName;
52022
+ }
52023
+ executionFiles.push({
52024
+ id,
52025
+ name: getExecutionNameFromFilename(fileName),
52026
+ path: filePath,
52027
+ canvasBasename: getCanvasBasename(fileName),
52028
+ packageName
52029
+ });
52030
+ break;
52031
+ }
52032
+ }
52033
+ }
52034
+ return executionFiles.sort((a, b) => {
52035
+ if (a.packageName && b.packageName) {
52036
+ const pkgCompare = a.packageName.localeCompare(b.packageName);
52037
+ if (pkgCompare !== 0) return pkgCompare;
52038
+ } else if (a.packageName) {
52039
+ return -1;
52040
+ } else if (b.packageName) {
52041
+ return 1;
52042
+ }
52043
+ return a.name.localeCompare(b.name);
52044
+ });
52045
+ }
52046
+ /**
52047
+ * Find execution artifact for a given canvas file path
52048
+ */
52049
+ static findExecutionForCanvas(canvasPath, files) {
52050
+ const canvasFilename = canvasPath.split("/").pop() || "";
52051
+ const canvasBasename = canvasFilename.replace(/\.otel\.canvas$/, "");
52052
+ const executions = ExecutionLoader.findExecutionFiles(files);
52053
+ return executions.find((exec) => exec.canvasBasename === canvasBasename) || null;
52054
+ }
52055
+ /**
52056
+ * Find canvas file for a given execution artifact path
52057
+ */
52058
+ static findCanvasForExecution(executionPath, files) {
52059
+ const executionFilename = executionPath.split("/").pop() || "";
52060
+ const canvasBasename = getCanvasBasename(executionFilename);
52061
+ for (const file of files) {
52062
+ const filePath = file.relativePath || file.path || "";
52063
+ const fileName = file.name || filePath.split("/").pop() || "";
52064
+ if (fileName === `${canvasBasename}.otel.canvas` || fileName === `${canvasBasename}.canvas`) {
52065
+ return filePath;
52066
+ }
52067
+ }
52068
+ return null;
52069
+ }
52070
+ }
52071
+ const ExecutionStats = ({ metadata }) => {
52072
+ const formatDate = (isoString) => {
52073
+ if (!isoString) return "Unknown";
52074
+ try {
52075
+ const date = new Date(isoString);
52076
+ return date.toLocaleString();
52077
+ } catch {
52078
+ return isoString;
52079
+ }
52080
+ };
52081
+ const getStatusColor = (status) => {
52082
+ switch (status) {
52083
+ case "success":
52084
+ case "OK":
52085
+ return "#10b981";
52086
+ // green
52087
+ case "error":
52088
+ case "ERROR":
52089
+ case "FAILED":
52090
+ return "#ef4444";
52091
+ // red
52092
+ default:
52093
+ return "#6b7280";
52094
+ }
52095
+ };
52096
+ const getStatusIcon = (status) => {
52097
+ switch (status) {
52098
+ case "success":
52099
+ case "OK":
52100
+ return "✓";
52101
+ case "error":
52102
+ case "ERROR":
52103
+ case "FAILED":
52104
+ return "✗";
52105
+ default:
52106
+ return "○";
52107
+ }
52108
+ };
52109
+ return /* @__PURE__ */ jsxs(
52110
+ "div",
52111
+ {
52112
+ style: {
52113
+ padding: "12px 16px",
52114
+ borderTop: "1px solid #333",
52115
+ background: "#1a1a1a",
52116
+ display: "flex",
52117
+ gap: "24px",
52118
+ fontSize: "12px",
52119
+ color: "#999",
52120
+ fontFamily: "monospace"
52121
+ },
52122
+ children: [
52123
+ metadata.status && /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "6px" }, children: [
52124
+ /* @__PURE__ */ jsx(
52125
+ "span",
52126
+ {
52127
+ style: {
52128
+ color: getStatusColor(metadata.status),
52129
+ fontSize: "14px",
52130
+ fontWeight: "bold"
52131
+ },
52132
+ children: getStatusIcon(metadata.status)
52133
+ }
52134
+ ),
52135
+ /* @__PURE__ */ jsx("span", { style: { color: "#ccc" }, children: "Status:" }),
52136
+ /* @__PURE__ */ jsx("span", { style: { color: getStatusColor(metadata.status) }, children: metadata.status.toUpperCase() })
52137
+ ] }),
52138
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "6px" }, children: [
52139
+ /* @__PURE__ */ jsx("span", { style: { color: "#ccc" }, children: "Spans:" }),
52140
+ /* @__PURE__ */ jsx("span", { style: { color: "#3b82f6" }, children: metadata.spanCount })
52141
+ ] }),
52142
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "6px" }, children: [
52143
+ /* @__PURE__ */ jsx("span", { style: { color: "#ccc" }, children: "Events:" }),
52144
+ /* @__PURE__ */ jsx("span", { style: { color: "#8b5cf6" }, children: metadata.eventCount })
52145
+ ] }),
52146
+ metadata.framework && /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "6px" }, children: [
52147
+ /* @__PURE__ */ jsx("span", { style: { color: "#ccc" }, children: "Framework:" }),
52148
+ /* @__PURE__ */ jsx("span", { style: { color: "#f59e0b" }, children: metadata.framework })
52149
+ ] }),
52150
+ metadata.source && /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "6px" }, children: [
52151
+ /* @__PURE__ */ jsx("span", { style: { color: "#ccc" }, children: "Source:" }),
52152
+ /* @__PURE__ */ jsx("span", { style: { color: "#10b981" }, children: metadata.source })
52153
+ ] }),
52154
+ metadata.exportedAt && /* @__PURE__ */ jsxs(
52155
+ "div",
52156
+ {
52157
+ style: {
52158
+ display: "flex",
52159
+ alignItems: "center",
52160
+ gap: "6px",
52161
+ marginLeft: "auto"
52162
+ },
52163
+ children: [
52164
+ /* @__PURE__ */ jsx("span", { style: { color: "#ccc" }, children: "Exported:" }),
52165
+ /* @__PURE__ */ jsx("span", { style: { color: "#6b7280" }, children: formatDate(metadata.exportedAt) })
52166
+ ]
52167
+ }
52168
+ )
52169
+ ]
52170
+ }
52171
+ );
52172
+ };
52173
+ const ExecutionViewerPanel = ({
52174
+ context,
52175
+ actions,
52176
+ events
52177
+ }) => {
52178
+ var _a;
52179
+ const { theme } = useTheme();
52180
+ const [state, setState] = useState({
52181
+ canvas: null,
52182
+ execution: null,
52183
+ metadata: null,
52184
+ loading: true,
52185
+ error: null,
52186
+ availableExecutions: [],
52187
+ selectedExecutionId: null,
52188
+ showExecutionSelector: false,
52189
+ isPlaying: false,
52190
+ currentSpanIndex: 0,
52191
+ currentEventIndex: 0
52192
+ });
52193
+ const contextRef = useRef(context);
52194
+ const actionsRef = useRef(actions);
52195
+ const eventsRef = useRef(events);
52196
+ contextRef.current = context;
52197
+ actionsRef.current = actions;
52198
+ eventsRef.current = events;
52199
+ const selectedExecutionIdRef = useRef(null);
52200
+ selectedExecutionIdRef.current = state.selectedExecutionId;
52201
+ const playbackTimerRef = useRef(null);
52202
+ const loadExecution = useCallback(async (executionId) => {
52203
+ setState((prev) => ({ ...prev, loading: prev.canvas === null, error: null }));
52204
+ try {
52205
+ const ctx = contextRef.current;
52206
+ const acts = actionsRef.current;
52207
+ if (!ctx.hasSlice("fileTree")) {
52208
+ throw new Error("File tree data not available");
52209
+ }
52210
+ if (ctx.isSliceLoading("fileTree")) {
52211
+ return;
52212
+ }
52213
+ const fileTreeSlice = ctx.getSlice("fileTree");
52214
+ const fileTreeData = fileTreeSlice == null ? void 0 : fileTreeSlice.data;
52215
+ if (!(fileTreeData == null ? void 0 : fileTreeData.allFiles)) {
52216
+ setState((prev) => ({
52217
+ ...prev,
52218
+ canvas: null,
52219
+ execution: null,
52220
+ metadata: null,
52221
+ loading: false,
52222
+ error: null,
52223
+ availableExecutions: [],
52224
+ selectedExecutionId: null
52225
+ }));
52226
+ return;
52227
+ }
52228
+ const availableExecutions = ExecutionLoader.findExecutionFiles(fileTreeData.allFiles);
52229
+ if (availableExecutions.length === 0) {
52230
+ setState((prev) => ({
52231
+ ...prev,
52232
+ canvas: null,
52233
+ execution: null,
52234
+ metadata: null,
52235
+ loading: false,
52236
+ error: null,
52237
+ availableExecutions: [],
52238
+ selectedExecutionId: null
52239
+ }));
52240
+ return;
52241
+ }
52242
+ let selectedExecution2;
52243
+ if (executionId) {
52244
+ const found = availableExecutions.find((e) => e.id === executionId);
52245
+ if (!found) {
52246
+ throw new Error(`Execution with ID '${executionId}' not found`);
52247
+ }
52248
+ selectedExecution2 = found;
52249
+ } else if (selectedExecutionIdRef.current) {
52250
+ const found = availableExecutions.find((e) => e.id === selectedExecutionIdRef.current);
52251
+ selectedExecution2 = found || availableExecutions[0];
52252
+ } else {
52253
+ selectedExecution2 = availableExecutions[0];
52254
+ }
52255
+ const readFile = acts.readFile;
52256
+ if (!readFile) {
52257
+ throw new Error("readFile action not available");
52258
+ }
52259
+ const repositoryPath = ctx.repositoryPath;
52260
+ if (!repositoryPath) {
52261
+ throw new Error("Repository path not available");
52262
+ }
52263
+ const fullExecutionPath = `${repositoryPath}/${selectedExecution2.path}`;
52264
+ const executionContent = await readFile(fullExecutionPath);
52265
+ if (!executionContent || typeof executionContent !== "string") {
52266
+ throw new Error("Failed to read execution file");
52267
+ }
52268
+ const execution = ExecutionLoader.parseExecutionArtifact(executionContent);
52269
+ const metadata = ExecutionLoader.getExecutionMetadata(execution);
52270
+ const canvasPath = ExecutionLoader.findCanvasForExecution(
52271
+ selectedExecution2.path,
52272
+ fileTreeData.allFiles
52273
+ );
52274
+ let canvas = null;
52275
+ if (canvasPath) {
52276
+ try {
52277
+ const fullCanvasPath = `${repositoryPath}/${canvasPath}`;
52278
+ const canvasContent = await readFile(fullCanvasPath);
52279
+ if (canvasContent && typeof canvasContent === "string") {
52280
+ canvas = JSON.parse(canvasContent);
52281
+ }
52282
+ } catch (error) {
52283
+ console.warn("[ExecutionViewer] Failed to load canvas:", error);
52284
+ }
52285
+ }
52286
+ setState((prev) => ({
52287
+ ...prev,
52288
+ canvas,
52289
+ execution,
52290
+ metadata,
52291
+ loading: false,
52292
+ error: null,
52293
+ availableExecutions,
52294
+ selectedExecutionId: selectedExecution2.id,
52295
+ currentSpanIndex: 0,
52296
+ currentEventIndex: 0
52297
+ }));
52298
+ } catch (error) {
52299
+ console.error("[ExecutionViewer] Error loading execution:", error);
52300
+ setState((prev) => ({
52301
+ ...prev,
52302
+ loading: false,
52303
+ error: error.message
52304
+ }));
52305
+ }
52306
+ }, []);
52307
+ useEffect(() => {
52308
+ loadExecution();
52309
+ }, [loadExecution]);
52310
+ useEffect(() => {
52311
+ if (!events) return;
52312
+ const handleEvent = (event) => {
52313
+ var _a2;
52314
+ if (event.type === "custom" && event.action === "selectExecution") {
52315
+ const executionId = (_a2 = event.payload) == null ? void 0 : _a2.executionId;
52316
+ if (executionId) {
52317
+ loadExecution(executionId);
52318
+ }
52319
+ }
52320
+ };
52321
+ events.on("custom", handleEvent);
52322
+ return () => {
52323
+ events.off("custom", handleEvent);
52324
+ };
52325
+ }, [events, loadExecution]);
52326
+ const handlePlayPause = useCallback(() => {
52327
+ setState((prev) => ({ ...prev, isPlaying: !prev.isPlaying }));
52328
+ }, []);
52329
+ const handleReset = useCallback(() => {
52330
+ setState((prev) => ({
52331
+ ...prev,
52332
+ isPlaying: false,
52333
+ currentSpanIndex: 0,
52334
+ currentEventIndex: 0
52335
+ }));
52336
+ }, []);
52337
+ useEffect(() => {
52338
+ if (!state.isPlaying || !state.execution) {
52339
+ if (playbackTimerRef.current) {
52340
+ clearInterval(playbackTimerRef.current);
52341
+ playbackTimerRef.current = null;
52342
+ }
52343
+ return;
52344
+ }
52345
+ const spans = ExecutionLoader.getSpans(state.execution);
52346
+ spans.reduce((sum, span) => {
52347
+ var _a2;
52348
+ return sum + (((_a2 = span.events) == null ? void 0 : _a2.length) || 0);
52349
+ }, 0);
52350
+ playbackTimerRef.current = setInterval(() => {
52351
+ setState((prev) => {
52352
+ var _a2;
52353
+ const spans2 = prev.execution ? ExecutionLoader.getSpans(prev.execution) : [];
52354
+ if (spans2.length === 0) return { ...prev, isPlaying: false };
52355
+ const currentSpan = spans2[prev.currentSpanIndex];
52356
+ const spanEventCount = ((_a2 = currentSpan == null ? void 0 : currentSpan.events) == null ? void 0 : _a2.length) || 0;
52357
+ if (prev.currentEventIndex < spanEventCount - 1) {
52358
+ return { ...prev, currentEventIndex: prev.currentEventIndex + 1 };
52359
+ }
52360
+ if (prev.currentSpanIndex < spans2.length - 1) {
52361
+ return {
52362
+ ...prev,
52363
+ currentSpanIndex: prev.currentSpanIndex + 1,
52364
+ currentEventIndex: 0
52365
+ };
52366
+ }
52367
+ return { ...prev, isPlaying: false };
52368
+ });
52369
+ }, 800);
52370
+ return () => {
52371
+ if (playbackTimerRef.current) {
52372
+ clearInterval(playbackTimerRef.current);
52373
+ playbackTimerRef.current = null;
52374
+ }
52375
+ };
52376
+ }, [state.isPlaying, state.execution]);
52377
+ if (!state.loading && state.availableExecutions.length === 0) {
52378
+ return /* @__PURE__ */ jsx(
52379
+ "div",
52380
+ {
52381
+ style: {
52382
+ display: "flex",
52383
+ alignItems: "center",
52384
+ justifyContent: "center",
52385
+ height: "100%",
52386
+ background: theme.colors.background,
52387
+ color: theme.colors.text
52388
+ },
52389
+ children: /* @__PURE__ */ jsxs("div", { style: { textAlign: "center", maxWidth: "600px", padding: "20px" }, children: [
52390
+ /* @__PURE__ */ jsx(Activity, { size: 48, style: { margin: "0 auto 20px", opacity: 0.3 } }),
52391
+ /* @__PURE__ */ jsx("h2", { style: { margin: "0 0 10px 0", fontSize: "18px", fontWeight: 600 }, children: "No Execution Artifacts Found" }),
52392
+ /* @__PURE__ */ jsxs("p", { style: { margin: "0 0 20px 0", color: theme.colors.textSecondary, lineHeight: 1.5 }, children: [
52393
+ "Execution artifacts should be saved to ",
52394
+ /* @__PURE__ */ jsx("code", { children: "__executions__/*.spans.json" }),
52395
+ " or",
52396
+ " ",
52397
+ /* @__PURE__ */ jsx("code", { children: "packages/*/__executions__/*.spans.json" })
52398
+ ] }),
52399
+ /* @__PURE__ */ jsxs(
52400
+ "div",
52401
+ {
52402
+ style: {
52403
+ background: "#1e1e1e",
52404
+ padding: "12px",
52405
+ borderRadius: "4px",
52406
+ fontFamily: "monospace",
52407
+ fontSize: "12px",
52408
+ textAlign: "left",
52409
+ color: "#d4d4d4"
52410
+ },
52411
+ children: [
52412
+ /* @__PURE__ */ jsx("div", { children: "# Export execution data from tests" }),
52413
+ /* @__PURE__ */ jsxs("div", { children: [
52414
+ "exportExecutionArtifact(canvas, spans, ",
52415
+ "{"
52416
+ ] }),
52417
+ /* @__PURE__ */ jsx("div", { children: "  outputPath: '__executions__/my-test.spans.json'" }),
52418
+ /* @__PURE__ */ jsxs("div", { children: [
52419
+ "}",
52420
+ ");"
52421
+ ] })
52422
+ ]
52423
+ }
52424
+ )
52425
+ ] })
52426
+ }
52427
+ );
52428
+ }
52429
+ if (state.error) {
52430
+ return /* @__PURE__ */ jsx(
52431
+ "div",
52432
+ {
52433
+ style: {
52434
+ display: "flex",
52435
+ alignItems: "center",
52436
+ justifyContent: "center",
52437
+ height: "100%",
52438
+ background: theme.colors.background,
52439
+ color: theme.colors.error
52440
+ },
52441
+ children: /* @__PURE__ */ jsxs("div", { style: { textAlign: "center", padding: "20px" }, children: [
52442
+ /* @__PURE__ */ jsx("h2", { style: { margin: "0 0 10px 0", fontSize: "18px" }, children: "Error Loading Execution" }),
52443
+ /* @__PURE__ */ jsx("p", { style: { margin: 0, fontSize: "14px" }, children: state.error })
52444
+ ] })
52445
+ }
52446
+ );
52447
+ }
52448
+ if (state.loading) {
52449
+ return /* @__PURE__ */ jsx(
52450
+ "div",
52451
+ {
52452
+ style: {
52453
+ display: "flex",
52454
+ alignItems: "center",
52455
+ justifyContent: "center",
52456
+ height: "100%",
52457
+ background: theme.colors.background,
52458
+ color: theme.colors.text
52459
+ },
52460
+ children: /* @__PURE__ */ jsx(Loader, { className: "animate-spin", size: 32 })
52461
+ }
52462
+ );
52463
+ }
52464
+ const selectedExecution = state.availableExecutions.find(
52465
+ (e) => e.id === state.selectedExecutionId
52466
+ );
52467
+ return /* @__PURE__ */ jsxs(
52468
+ "div",
52469
+ {
52470
+ style: {
52471
+ display: "flex",
52472
+ flexDirection: "column",
52473
+ height: "100%",
52474
+ background: theme.colors.background,
52475
+ color: theme.colors.text
52476
+ },
52477
+ children: [
52478
+ /* @__PURE__ */ jsxs(
52479
+ "div",
52480
+ {
52481
+ style: {
52482
+ display: "flex",
52483
+ alignItems: "center",
52484
+ padding: "12px 16px",
52485
+ borderBottom: `1px solid ${theme.colors.border}`,
52486
+ background: "#1a1a1a",
52487
+ gap: "12px"
52488
+ },
52489
+ children: [
52490
+ /* @__PURE__ */ jsxs("div", { style: { position: "relative" }, children: [
52491
+ /* @__PURE__ */ jsxs(
52492
+ "button",
52493
+ {
52494
+ onClick: () => setState((prev) => ({ ...prev, showExecutionSelector: !prev.showExecutionSelector })),
52495
+ style: {
52496
+ display: "flex",
52497
+ alignItems: "center",
52498
+ gap: "8px",
52499
+ padding: "6px 12px",
52500
+ background: "#2a2a2a",
52501
+ border: "1px solid #3a3a3a",
52502
+ borderRadius: "4px",
52503
+ color: "#fff",
52504
+ cursor: "pointer",
52505
+ fontSize: "13px"
52506
+ },
52507
+ children: [
52508
+ /* @__PURE__ */ jsx(Activity, { size: 16 }),
52509
+ /* @__PURE__ */ jsx("span", { children: (selectedExecution == null ? void 0 : selectedExecution.name) || "Select Execution" }),
52510
+ (selectedExecution == null ? void 0 : selectedExecution.packageName) && /* @__PURE__ */ jsx(
52511
+ "span",
52512
+ {
52513
+ style: {
52514
+ padding: "2px 6px",
52515
+ background: "#3b82f6",
52516
+ borderRadius: "3px",
52517
+ fontSize: "11px",
52518
+ fontWeight: 600
52519
+ },
52520
+ children: selectedExecution.packageName
52521
+ }
52522
+ ),
52523
+ /* @__PURE__ */ jsx(ChevronDown, { size: 16 })
52524
+ ]
52525
+ }
52526
+ ),
52527
+ state.showExecutionSelector && /* @__PURE__ */ jsxs(Fragment, { children: [
52528
+ /* @__PURE__ */ jsx(
52529
+ "div",
52530
+ {
52531
+ style: {
52532
+ position: "fixed",
52533
+ inset: 0,
52534
+ zIndex: 999
52535
+ },
52536
+ onClick: () => setState((prev) => ({ ...prev, showExecutionSelector: false }))
52537
+ }
52538
+ ),
52539
+ /* @__PURE__ */ jsx(
52540
+ "div",
52541
+ {
52542
+ style: {
52543
+ position: "absolute",
52544
+ top: "100%",
52545
+ left: 0,
52546
+ marginTop: "4px",
52547
+ minWidth: "300px",
52548
+ maxHeight: "400px",
52549
+ overflowY: "auto",
52550
+ background: "#2a2a2a",
52551
+ border: "1px solid #3a3a3a",
52552
+ borderRadius: "4px",
52553
+ boxShadow: "0 4px 12px rgba(0,0,0,0.3)",
52554
+ zIndex: 1e3
52555
+ },
52556
+ children: state.availableExecutions.map((execution) => /* @__PURE__ */ jsxs(
52557
+ "button",
52558
+ {
52559
+ onClick: () => {
52560
+ loadExecution(execution.id);
52561
+ setState((prev) => ({ ...prev, showExecutionSelector: false }));
52562
+ },
52563
+ style: {
52564
+ width: "100%",
52565
+ padding: "10px 16px",
52566
+ background: execution.id === state.selectedExecutionId ? "#3b82f6" : "transparent",
52567
+ border: "none",
52568
+ borderBottom: "1px solid #3a3a3a",
52569
+ color: "#fff",
52570
+ textAlign: "left",
52571
+ cursor: "pointer",
52572
+ fontSize: "13px",
52573
+ display: "flex",
52574
+ alignItems: "center",
52575
+ gap: "8px"
52576
+ },
52577
+ children: [
52578
+ /* @__PURE__ */ jsx(Activity, { size: 14 }),
52579
+ /* @__PURE__ */ jsx("span", { style: { flex: 1 }, children: execution.name }),
52580
+ execution.packageName && /* @__PURE__ */ jsx(
52581
+ "span",
52582
+ {
52583
+ style: {
52584
+ padding: "2px 6px",
52585
+ background: execution.id === state.selectedExecutionId ? "#2563eb" : "#3b82f6",
52586
+ borderRadius: "3px",
52587
+ fontSize: "11px",
52588
+ fontWeight: 600
52589
+ },
52590
+ children: execution.packageName
52591
+ }
52592
+ )
52593
+ ]
52594
+ },
52595
+ execution.id
52596
+ ))
52597
+ }
52598
+ )
52599
+ ] })
52600
+ ] }),
52601
+ /* @__PURE__ */ jsxs("div", { style: { flex: 1 }, children: [
52602
+ /* @__PURE__ */ jsx("div", { style: { fontSize: "14px", fontWeight: 600 }, children: ((_a = state.metadata) == null ? void 0 : _a.name) || "Execution Viewer" }),
52603
+ selectedExecution && /* @__PURE__ */ jsx("div", { style: { fontSize: "11px", color: "#999", marginTop: "2px" }, children: selectedExecution.path })
52604
+ ] }),
52605
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: "8px" }, children: [
52606
+ /* @__PURE__ */ jsx(
52607
+ "button",
52608
+ {
52609
+ onClick: handleReset,
52610
+ style: {
52611
+ padding: "6px 10px",
52612
+ background: "#2a2a2a",
52613
+ border: "1px solid #3a3a3a",
52614
+ borderRadius: "4px",
52615
+ color: "#fff",
52616
+ cursor: "pointer",
52617
+ display: "flex",
52618
+ alignItems: "center",
52619
+ gap: "4px"
52620
+ },
52621
+ title: "Reset",
52622
+ children: /* @__PURE__ */ jsx(RotateCcw, { size: 14 })
52623
+ }
52624
+ ),
52625
+ /* @__PURE__ */ jsxs(
52626
+ "button",
52627
+ {
52628
+ onClick: handlePlayPause,
52629
+ style: {
52630
+ padding: "6px 10px",
52631
+ background: state.isPlaying ? "#ef4444" : "#10b981",
52632
+ border: "none",
52633
+ borderRadius: "4px",
52634
+ color: "#fff",
52635
+ cursor: "pointer",
52636
+ display: "flex",
52637
+ alignItems: "center",
52638
+ gap: "4px",
52639
+ fontWeight: 600
52640
+ },
52641
+ children: [
52642
+ state.isPlaying ? /* @__PURE__ */ jsx(Pause, { size: 14 }) : /* @__PURE__ */ jsx(Play, { size: 14 }),
52643
+ state.isPlaying ? "Pause" : "Play"
52644
+ ]
52645
+ }
52646
+ )
52647
+ ] })
52648
+ ]
52649
+ }
52650
+ ),
52651
+ /* @__PURE__ */ jsxs("div", { style: { flex: 1, display: "flex", overflow: "hidden" }, children: [
52652
+ state.canvas ? /* @__PURE__ */ jsx("div", { style: { flex: "0 0 60%", position: "relative" }, children: /* @__PURE__ */ jsx(
52653
+ distExports.GraphRenderer,
52654
+ {
52655
+ canvas: state.canvas,
52656
+ showMinimap: true,
52657
+ showControls: true,
52658
+ showBackground: true,
52659
+ backgroundVariant: "lines",
52660
+ showTooltips: true
52661
+ }
52662
+ ) }) : /* @__PURE__ */ jsx(
52663
+ "div",
52664
+ {
52665
+ style: {
52666
+ flex: "0 0 60%",
52667
+ display: "flex",
52668
+ alignItems: "center",
52669
+ justifyContent: "center",
52670
+ background: "#0a0a0a",
52671
+ color: "#666"
52672
+ },
52673
+ children: /* @__PURE__ */ jsxs("div", { style: { textAlign: "center" }, children: [
52674
+ /* @__PURE__ */ jsx("p", { children: "No matching canvas found" }),
52675
+ /* @__PURE__ */ jsxs("p", { style: { fontSize: "12px", marginTop: "8px" }, children: [
52676
+ "Expected: ",
52677
+ selectedExecution == null ? void 0 : selectedExecution.canvasBasename,
52678
+ ".otel.canvas"
52679
+ ] })
52680
+ ] })
52681
+ }
52682
+ ),
52683
+ /* @__PURE__ */ jsxs("div", { style: { flex: "0 0 40%", borderLeft: "1px solid #333", display: "flex", flexDirection: "column" }, children: [
52684
+ /* @__PURE__ */ jsxs("div", { style: { padding: "16px", borderBottom: "1px solid #333" }, children: [
52685
+ /* @__PURE__ */ jsx("h3", { style: { margin: "0 0 8px 0", fontSize: "14px", fontWeight: 600 }, children: "Execution Events" }),
52686
+ /* @__PURE__ */ jsxs("div", { style: { fontSize: "12px", color: "#999" }, children: [
52687
+ "Span ",
52688
+ state.currentSpanIndex + 1,
52689
+ " of ",
52690
+ ExecutionLoader.getSpans(state.execution || {}).length,
52691
+ " • ",
52692
+ "Event ",
52693
+ state.currentEventIndex + 1
52694
+ ] })
52695
+ ] }),
52696
+ /* @__PURE__ */ jsx("div", { style: { flex: 1, overflowY: "auto", padding: "16px" }, children: ExecutionLoader.getSpans(state.execution || {}).map((span, spanIdx) => {
52697
+ var _a2;
52698
+ return /* @__PURE__ */ jsxs("div", { style: { marginBottom: "24px" }, children: [
52699
+ /* @__PURE__ */ jsx(
52700
+ "div",
52701
+ {
52702
+ style: {
52703
+ fontSize: "13px",
52704
+ fontWeight: 600,
52705
+ marginBottom: "8px",
52706
+ color: spanIdx === state.currentSpanIndex ? "#3b82f6" : "#ccc"
52707
+ },
52708
+ children: span.name
52709
+ }
52710
+ ),
52711
+ (_a2 = span.events) == null ? void 0 : _a2.map((event, eventIdx) => {
52712
+ const isActive = spanIdx === state.currentSpanIndex && eventIdx === state.currentEventIndex;
52713
+ const isPast = spanIdx < state.currentSpanIndex || spanIdx === state.currentSpanIndex && eventIdx < state.currentEventIndex;
52714
+ return /* @__PURE__ */ jsxs(
52715
+ "div",
52716
+ {
52717
+ style: {
52718
+ padding: "8px",
52719
+ marginBottom: "4px",
52720
+ background: isActive ? "#3b82f610" : "transparent",
52721
+ border: `1px solid ${isActive ? "#3b82f6" : "#333"}`,
52722
+ borderRadius: "4px",
52723
+ fontSize: "12px",
52724
+ opacity: isPast ? 0.5 : 1
52725
+ },
52726
+ children: [
52727
+ /* @__PURE__ */ jsx("div", { style: { fontWeight: 600, color: "#fff", marginBottom: "4px" }, children: event.name }),
52728
+ event.attributes && Object.keys(event.attributes).length > 0 && /* @__PURE__ */ jsx("div", { style: { color: "#999", fontFamily: "monospace", fontSize: "11px" }, children: Object.entries(event.attributes).map(([key, value]) => /* @__PURE__ */ jsxs("div", { children: [
52729
+ key,
52730
+ ": ",
52731
+ JSON.stringify(value)
52732
+ ] }, key)) })
52733
+ ]
52734
+ },
52735
+ eventIdx
52736
+ );
52737
+ })
52738
+ ] }, span.id);
52739
+ }) })
52740
+ ] })
52741
+ ] }),
52742
+ state.metadata && /* @__PURE__ */ jsx(ExecutionStats, { metadata: state.metadata })
52743
+ ]
52744
+ }
52745
+ );
52746
+ };
51920
52747
  const focusNodeTool = {
51921
52748
  name: "focus_node",
51922
52749
  description: "Focuses the graph view on a specific node",
@@ -52717,6 +53544,31 @@ const panels = [
52717
53544
  onUnmount: async (_context) => {
52718
53545
  console.log("Trace Viewer Panel unmounting");
52719
53546
  }
53547
+ },
53548
+ {
53549
+ metadata: {
53550
+ id: "principal-ai.execution-viewer",
53551
+ name: "Execution Viewer",
53552
+ icon: "⚡",
53553
+ version: "0.1.0",
53554
+ author: "Principal AI",
53555
+ description: "Visualizes execution artifacts (test runs) overlaid on canvas diagrams with playback controls",
53556
+ slices: ["fileTree"]
53557
+ },
53558
+ component: ExecutionViewerPanel,
53559
+ onMount: async (context) => {
53560
+ var _a;
53561
+ console.log(
53562
+ "Execution Viewer Panel mounted",
53563
+ (_a = context.currentScope.repository) == null ? void 0 : _a.path
53564
+ );
53565
+ if (context.hasSlice("fileTree") && !context.isSliceLoading("fileTree")) {
53566
+ await context.refresh("repository", "fileTree");
53567
+ }
53568
+ },
53569
+ onUnmount: async (_context) => {
53570
+ console.log("Execution Viewer Panel unmounting");
53571
+ }
52720
53572
  }
52721
53573
  ];
52722
53574
  const onPackageLoad = async () => {
@@ -52727,6 +53579,7 @@ const onPackageUnload = async () => {
52727
53579
  };
52728
53580
  export {
52729
53581
  EventControllerPanel,
53582
+ ExecutionViewerPanel,
52730
53583
  PanelFileSystemAdapter,
52731
53584
  TraceViewerPanel,
52732
53585
  focusNodeTool,