dsh-pentester 2.3.0 → 2.4.0

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/lib/client.js CHANGED
@@ -40,7 +40,7 @@ __export(plugin_exports, {
40
40
  setPentesterEndpointState: () => setPentesterEndpointState
41
41
  });
42
42
  module.exports = __toCommonJS(plugin_exports);
43
- var import_react19 = __toESM(require("react"), 1);
43
+ var import_react20 = __toESM(require("react"), 1);
44
44
 
45
45
  // node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/external.js
46
46
  var external_exports = {};
@@ -15397,7 +15397,7 @@ function isPentesterRootSession(snapshot, id) {
15397
15397
  }
15398
15398
 
15399
15399
  // src/ui/client/pentester-view.tsx
15400
- var import_react18 = __toESM(require("react"), 1);
15400
+ var import_react19 = __toESM(require("react"), 1);
15401
15401
 
15402
15402
  // src/ui/client/pentester/navigation.ts
15403
15403
  var PENTESTER_TABS = [
@@ -16100,8 +16100,71 @@ function LegendItem(props) {
16100
16100
  }
16101
16101
 
16102
16102
  // src/ui/client/pentester/FindingsView.tsx
16103
+ var import_react11 = __toESM(require("react"), 1);
16104
+ var import_dsh_client_ui_primitives4 = require("@deepseek-ai/dsh-client-ui-primitives");
16105
+
16106
+ // src/ui/client/pentester/CopyAction.tsx
16103
16107
  var import_react10 = __toESM(require("react"), 1);
16104
16108
  var import_dsh_client_ui_primitives3 = require("@deepseek-ai/dsh-client-ui-primitives");
16109
+ function CopyAction(props) {
16110
+ const { text } = props;
16111
+ const [copied, setCopied] = (0, import_react10.useState)(false);
16112
+ const timerRef = (0, import_react10.useRef)(null);
16113
+ const pendingRef = (0, import_react10.useRef)(false);
16114
+ const handleCopy = (0, import_react10.useCallback)(() => {
16115
+ if (copied || pendingRef.current) return;
16116
+ pendingRef.current = true;
16117
+ void (0, import_dsh_client_ui_primitives3.writeClipboard)(text).then((ok) => {
16118
+ pendingRef.current = false;
16119
+ if (!ok) return;
16120
+ setCopied(true);
16121
+ timerRef.current = setTimeout(() => {
16122
+ setCopied(false);
16123
+ timerRef.current = null;
16124
+ }, 1e3);
16125
+ });
16126
+ }, [text, copied]);
16127
+ (0, import_react10.useEffect)(() => {
16128
+ return () => {
16129
+ if (timerRef.current !== null) clearTimeout(timerRef.current);
16130
+ };
16131
+ }, []);
16132
+ return import_react10.default.createElement(
16133
+ "button",
16134
+ {
16135
+ type: "button",
16136
+ onClick: handleCopy,
16137
+ "aria-label": copied ? "Copied" : "Copy",
16138
+ style: {
16139
+ display: "inline-flex",
16140
+ alignItems: "center",
16141
+ gap: "6px",
16142
+ padding: "4px 8px",
16143
+ border: "none",
16144
+ borderRadius: "6px",
16145
+ background: "transparent",
16146
+ color: "var(--dsw-alias-label-secondary)",
16147
+ cursor: "pointer",
16148
+ fontSize: "13px",
16149
+ lineHeight: "16px",
16150
+ whiteSpace: "nowrap",
16151
+ flexShrink: 0
16152
+ },
16153
+ onMouseEnter: (e) => {
16154
+ e.currentTarget.style.background = "var(--dsw-alias-interactive-bg-hover)";
16155
+ e.currentTarget.style.color = "var(--dsw-alias-label-primary)";
16156
+ },
16157
+ onMouseLeave: (e) => {
16158
+ e.currentTarget.style.background = "transparent";
16159
+ e.currentTarget.style.color = "var(--dsw-alias-label-secondary)";
16160
+ }
16161
+ },
16162
+ copied ? import_react10.default.createElement(import_dsh_client_ui_primitives3.IconCheckOutline16, { size: 16 }) : import_react10.default.createElement(import_dsh_client_ui_primitives3.IconCopyOutline16, { size: 16 }),
16163
+ copied ? "Copied" : "Copy"
16164
+ );
16165
+ }
16166
+
16167
+ // src/ui/client/pentester/FindingsView.tsx
16105
16168
  var SEVERITY_ORDER = ["critical", "high", "medium", "low", "info"];
16106
16169
  var SEVERITY_LABELS = {
16107
16170
  critical: "Critical",
@@ -16124,20 +16187,20 @@ var FILTER_TABS = [
16124
16187
  function FindingsView(props) {
16125
16188
  const { snapshot, command, sessionId, onNavigate } = props;
16126
16189
  const findings = snapshot?.findings ?? [];
16127
- const [selectedId, setSelectedId] = (0, import_react10.useState)(null);
16128
- const [detailContent, setDetailContent] = (0, import_react10.useState)(null);
16129
- const [detailLoading, setDetailLoading] = (0, import_react10.useState)(false);
16130
- const [detailError, setDetailError] = (0, import_react10.useState)(false);
16131
- const [filter, setFilter] = (0, import_react10.useState)("all");
16132
- const [search, setSearch] = (0, import_react10.useState)("");
16133
- const [focusDone, setFocusDone] = (0, import_react10.useState)(false);
16134
- const loadSeqRef = (0, import_react10.useRef)(0);
16135
- const severityCounts = (0, import_react10.useMemo)(() => {
16190
+ const [selectedId, setSelectedId] = (0, import_react11.useState)(null);
16191
+ const [detailContent, setDetailContent] = (0, import_react11.useState)(null);
16192
+ const [detailLoading, setDetailLoading] = (0, import_react11.useState)(false);
16193
+ const [detailError, setDetailError] = (0, import_react11.useState)(false);
16194
+ const [filter, setFilter] = (0, import_react11.useState)("all");
16195
+ const [search, setSearch] = (0, import_react11.useState)("");
16196
+ const [focusDone, setFocusDone] = (0, import_react11.useState)(false);
16197
+ const loadSeqRef = (0, import_react11.useRef)(0);
16198
+ const severityCounts = (0, import_react11.useMemo)(() => {
16136
16199
  const counts = { critical: 0, high: 0, medium: 0, low: 0, info: 0 };
16137
16200
  for (const f of findings) counts[f.severity]++;
16138
16201
  return counts;
16139
16202
  }, [findings]);
16140
- const filtered = (0, import_react10.useMemo)(() => {
16203
+ const filtered = (0, import_react11.useMemo)(() => {
16141
16204
  let list = [...findings];
16142
16205
  if (filter !== "all") list = list.filter((f) => f.severity === filter);
16143
16206
  if (search.trim() !== "") {
@@ -16155,11 +16218,11 @@ function FindingsView(props) {
16155
16218
  });
16156
16219
  return list;
16157
16220
  }, [findings, filter, search]);
16158
- const selectedFinding = (0, import_react10.useMemo)(
16221
+ const selectedFinding = (0, import_react11.useMemo)(
16159
16222
  () => selectedId !== null ? findings.find((f) => f.id === selectedId) ?? null : null,
16160
16223
  [findings, selectedId]
16161
16224
  );
16162
- (0, import_react10.useEffect)(() => {
16225
+ (0, import_react11.useEffect)(() => {
16163
16226
  if (props.focusFinding !== void 0 && !focusDone) {
16164
16227
  const match = findings.find((f) => f.id === props.focusFinding);
16165
16228
  if (match !== void 0) {
@@ -16170,10 +16233,10 @@ function FindingsView(props) {
16170
16233
  }
16171
16234
  }
16172
16235
  }, [props.focusFinding, focusDone, findings]);
16173
- (0, import_react10.useEffect)(() => {
16236
+ (0, import_react11.useEffect)(() => {
16174
16237
  setFocusDone(false);
16175
16238
  }, [props.focusFinding]);
16176
- const loadDetail = (0, import_react10.useCallback)(async (finding) => {
16239
+ const loadDetail = (0, import_react11.useCallback)(async (finding) => {
16177
16240
  setSelectedId(finding.id);
16178
16241
  setDetailContent(null);
16179
16242
  setDetailLoading(true);
@@ -16202,7 +16265,7 @@ function FindingsView(props) {
16202
16265
  if (seq === loadSeqRef.current) setDetailLoading(false);
16203
16266
  }
16204
16267
  }, [command, sessionId]);
16205
- return import_react10.default.createElement(
16268
+ return import_react11.default.createElement(
16206
16269
  "div",
16207
16270
  {
16208
16271
  style: {
@@ -16214,14 +16277,14 @@ function FindingsView(props) {
16214
16277
  }
16215
16278
  },
16216
16279
  // ── Top: severity summary strip ──────────────────────────────────────
16217
- import_react10.default.createElement(SeveritySummary, {
16280
+ import_react11.default.createElement(SeveritySummary, {
16218
16281
  total: findings.length,
16219
16282
  counts: severityCounts,
16220
16283
  activeFilter: filter,
16221
16284
  onFilter: setFilter
16222
16285
  }),
16223
16286
  // ── Bottom: split view ───────────────────────────────────────────────
16224
- import_react10.default.createElement(
16287
+ import_react11.default.createElement(
16225
16288
  "div",
16226
16289
  {
16227
16290
  style: {
@@ -16232,7 +16295,7 @@ function FindingsView(props) {
16232
16295
  }
16233
16296
  },
16234
16297
  // ── Left: Navigator ───────────────────────────────────────────────
16235
- import_react10.default.createElement(
16298
+ import_react11.default.createElement(
16236
16299
  "div",
16237
16300
  {
16238
16301
  style: {
@@ -16247,7 +16310,7 @@ function FindingsView(props) {
16247
16310
  }
16248
16311
  },
16249
16312
  // Search + filter (fixed header)
16250
- import_react10.default.createElement(
16313
+ import_react11.default.createElement(
16251
16314
  "div",
16252
16315
  {
16253
16316
  style: {
@@ -16255,7 +16318,7 @@ function FindingsView(props) {
16255
16318
  padding: "8px 12px 4px"
16256
16319
  }
16257
16320
  },
16258
- import_react10.default.createElement("input", {
16321
+ import_react11.default.createElement("input", {
16259
16322
  type: "text",
16260
16323
  placeholder: "Search findings...",
16261
16324
  value: search,
@@ -16273,7 +16336,7 @@ function FindingsView(props) {
16273
16336
  marginBottom: "4px"
16274
16337
  }
16275
16338
  }),
16276
- import_react10.default.createElement(PentesterTabBar, {
16339
+ import_react11.default.createElement(PentesterTabBar, {
16277
16340
  items: FILTER_TABS,
16278
16341
  active: filter,
16279
16342
  onSelect: (id) => setFilter(id),
@@ -16281,7 +16344,7 @@ function FindingsView(props) {
16281
16344
  })
16282
16345
  ),
16283
16346
  // FindingList (scrollable)
16284
- import_react10.default.createElement(
16347
+ import_react11.default.createElement(
16285
16348
  "div",
16286
16349
  {
16287
16350
  style: {
@@ -16293,7 +16356,7 @@ function FindingsView(props) {
16293
16356
  scrollbarGutter: "stable"
16294
16357
  }
16295
16358
  },
16296
- filtered.length === 0 ? import_react10.default.createElement("div", {
16359
+ filtered.length === 0 ? import_react11.default.createElement("div", {
16297
16360
  style: {
16298
16361
  padding: "24px 12px",
16299
16362
  color: "var(--dsw-alias-label-tertiary)",
@@ -16301,7 +16364,7 @@ function FindingsView(props) {
16301
16364
  textAlign: "center"
16302
16365
  }
16303
16366
  }, findings.length === 0 ? "No findings yet" : "No matching findings") : filtered.map(
16304
- (finding) => import_react10.default.createElement(FindingRow, {
16367
+ (finding) => import_react11.default.createElement(FindingRow, {
16305
16368
  key: finding.id,
16306
16369
  finding,
16307
16370
  isSelected: finding.id === selectedId,
@@ -16311,7 +16374,7 @@ function FindingsView(props) {
16311
16374
  )
16312
16375
  ),
16313
16376
  // ── Right: Detail ──────────────────────────────────────────────────
16314
- import_react10.default.createElement(
16377
+ import_react11.default.createElement(
16315
16378
  "div",
16316
16379
  {
16317
16380
  style: {
@@ -16323,7 +16386,7 @@ function FindingsView(props) {
16323
16386
  overflow: "hidden"
16324
16387
  }
16325
16388
  },
16326
- selectedFinding === null ? import_react10.default.createElement(
16389
+ selectedFinding === null ? import_react11.default.createElement(
16327
16390
  "div",
16328
16391
  {
16329
16392
  style: {
@@ -16337,13 +16400,13 @@ function FindingsView(props) {
16337
16400
  fontSize: "13px"
16338
16401
  }
16339
16402
  },
16340
- findings.length === 0 ? import_react10.default.createElement(
16341
- import_react10.default.Fragment,
16403
+ findings.length === 0 ? import_react11.default.createElement(
16404
+ import_react11.default.Fragment,
16342
16405
  null,
16343
- import_react10.default.createElement("div", { style: { fontWeight: 500, color: "var(--dsw-alias-label-primary)" } }, "No findings yet"),
16344
- import_react10.default.createElement("div", null, "Validated findings will appear here as the assessment progresses.")
16406
+ import_react11.default.createElement("div", { style: { fontWeight: 500, color: "var(--dsw-alias-label-primary)" } }, "No findings yet"),
16407
+ import_react11.default.createElement("div", null, "Validated findings will appear here as the assessment progresses.")
16345
16408
  ) : "Select a finding to inspect"
16346
- ) : import_react10.default.createElement(FindingDetail, {
16409
+ ) : import_react11.default.createElement(FindingDetail, {
16347
16410
  finding: selectedFinding,
16348
16411
  content: detailContent,
16349
16412
  loading: detailLoading,
@@ -16365,7 +16428,7 @@ function SeveritySummary(props) {
16365
16428
  color: SEVERITY_COLORS[s]
16366
16429
  }))
16367
16430
  ];
16368
- return import_react10.default.createElement(
16431
+ return import_react11.default.createElement(
16369
16432
  "div",
16370
16433
  {
16371
16434
  style: {
@@ -16382,7 +16445,7 @@ function SeveritySummary(props) {
16382
16445
  },
16383
16446
  ...items.map((item) => {
16384
16447
  const isActive = activeFilter === item.key;
16385
- return import_react10.default.createElement(
16448
+ return import_react11.default.createElement(
16386
16449
  "button",
16387
16450
  {
16388
16451
  key: item.key,
@@ -16403,7 +16466,7 @@ function SeveritySummary(props) {
16403
16466
  whiteSpace: "nowrap"
16404
16467
  }
16405
16468
  },
16406
- item.color !== void 0 && import_react10.default.createElement("span", {
16469
+ item.color !== void 0 && import_react11.default.createElement("span", {
16407
16470
  style: {
16408
16471
  width: "8px",
16409
16472
  height: "8px",
@@ -16412,8 +16475,8 @@ function SeveritySummary(props) {
16412
16475
  flexShrink: 0
16413
16476
  }
16414
16477
  }),
16415
- import_react10.default.createElement("span", null, item.label),
16416
- import_react10.default.createElement("span", {
16478
+ import_react11.default.createElement("span", null, item.label),
16479
+ import_react11.default.createElement("span", {
16417
16480
  style: { fontWeight: 600, color: isActive ? "var(--dsw-alias-label-primary)" : "var(--dsw-alias-label-tertiary)" }
16418
16481
  }, String(item.count))
16419
16482
  );
@@ -16423,7 +16486,7 @@ function SeveritySummary(props) {
16423
16486
  function FindingRow(props) {
16424
16487
  const { finding, isSelected, onClick } = props;
16425
16488
  const color = SEVERITY_COLORS[finding.severity];
16426
- return import_react10.default.createElement(
16489
+ return import_react11.default.createElement(
16427
16490
  "div",
16428
16491
  {
16429
16492
  role: "button",
@@ -16457,7 +16520,7 @@ function FindingRow(props) {
16457
16520
  }
16458
16521
  },
16459
16522
  // Row 1: title + severity
16460
- import_react10.default.createElement(
16523
+ import_react11.default.createElement(
16461
16524
  "div",
16462
16525
  {
16463
16526
  style: {
@@ -16467,7 +16530,7 @@ function FindingRow(props) {
16467
16530
  minWidth: 0
16468
16531
  }
16469
16532
  },
16470
- import_react10.default.createElement("span", {
16533
+ import_react11.default.createElement("span", {
16471
16534
  style: {
16472
16535
  width: "7px",
16473
16536
  height: "7px",
@@ -16476,7 +16539,7 @@ function FindingRow(props) {
16476
16539
  flexShrink: 0
16477
16540
  }
16478
16541
  }),
16479
- import_react10.default.createElement("span", {
16542
+ import_react11.default.createElement("span", {
16480
16543
  style: {
16481
16544
  overflow: "hidden",
16482
16545
  textOverflow: "ellipsis",
@@ -16486,7 +16549,7 @@ function FindingRow(props) {
16486
16549
  minWidth: 0
16487
16550
  }
16488
16551
  }, finding.title),
16489
- import_react10.default.createElement("span", {
16552
+ import_react11.default.createElement("span", {
16490
16553
  style: {
16491
16554
  fontSize: "11px",
16492
16555
  fontWeight: 600,
@@ -16496,7 +16559,7 @@ function FindingRow(props) {
16496
16559
  }, SEVERITY_LABELS[finding.severity].toUpperCase())
16497
16560
  ),
16498
16561
  // Row 2: affected asset (if exists)
16499
- finding.affectedAsset !== void 0 && import_react10.default.createElement("div", {
16562
+ finding.affectedAsset !== void 0 && import_react11.default.createElement("div", {
16500
16563
  style: {
16501
16564
  fontSize: "12px",
16502
16565
  color: isSelected ? "rgba(255,255,255,0.6)" : "var(--dsw-alias-label-tertiary)",
@@ -16507,7 +16570,7 @@ function FindingRow(props) {
16507
16570
  }
16508
16571
  }, finding.affectedAsset),
16509
16572
  // Row 3: source stage + delegation
16510
- import_react10.default.createElement("div", {
16573
+ import_react11.default.createElement("div", {
16511
16574
  style: {
16512
16575
  fontSize: "11px",
16513
16576
  color: isSelected ? "rgba(255,255,255,0.5)" : "var(--dsw-alias-label-tertiary)",
@@ -16522,7 +16585,7 @@ function FindingRow(props) {
16522
16585
  function FindingDetail(props) {
16523
16586
  const { finding, content, loading, error: error51, onNavigate } = props;
16524
16587
  const color = SEVERITY_COLORS[finding.severity];
16525
- return import_react10.default.createElement(
16588
+ return import_react11.default.createElement(
16526
16589
  "div",
16527
16590
  {
16528
16591
  style: {
@@ -16534,7 +16597,7 @@ function FindingDetail(props) {
16534
16597
  }
16535
16598
  },
16536
16599
  // ── Metadata header (fixed) ─────────────────────────────────────────
16537
- import_react10.default.createElement(
16600
+ import_react11.default.createElement(
16538
16601
  "div",
16539
16602
  {
16540
16603
  style: {
@@ -16543,8 +16606,8 @@ function FindingDetail(props) {
16543
16606
  borderBottom: "1px solid var(--dsw-alias-border-l2)"
16544
16607
  }
16545
16608
  },
16546
- // Title + severity
16547
- import_react10.default.createElement(
16609
+ // Title + severity + copy
16610
+ import_react11.default.createElement(
16548
16611
  "div",
16549
16612
  {
16550
16613
  style: {
@@ -16554,7 +16617,7 @@ function FindingDetail(props) {
16554
16617
  marginBottom: "8px"
16555
16618
  }
16556
16619
  },
16557
- import_react10.default.createElement("span", {
16620
+ import_react11.default.createElement("span", {
16558
16621
  style: {
16559
16622
  fontSize: "15px",
16560
16623
  fontWeight: 600,
@@ -16566,7 +16629,8 @@ function FindingDetail(props) {
16566
16629
  minWidth: 0
16567
16630
  }
16568
16631
  }, finding.title),
16569
- import_react10.default.createElement("span", {
16632
+ content !== null && import_react11.default.createElement(CopyAction, { text: content }),
16633
+ import_react11.default.createElement("span", {
16570
16634
  style: {
16571
16635
  display: "inline-block",
16572
16636
  padding: "2px 8px",
@@ -16580,7 +16644,7 @@ function FindingDetail(props) {
16580
16644
  }, SEVERITY_LABELS[finding.severity].toUpperCase())
16581
16645
  ),
16582
16646
  // Affected asset
16583
- finding.affectedAsset !== void 0 && import_react10.default.createElement(
16647
+ finding.affectedAsset !== void 0 && import_react11.default.createElement(
16584
16648
  "div",
16585
16649
  {
16586
16650
  style: {
@@ -16591,8 +16655,8 @@ function FindingDetail(props) {
16591
16655
  gap: "6px"
16592
16656
  }
16593
16657
  },
16594
- import_react10.default.createElement("span", { style: { color: "var(--dsw-alias-label-tertiary)", flexShrink: 0 } }, "Affected asset"),
16595
- import_react10.default.createElement("code", {
16658
+ import_react11.default.createElement("span", { style: { color: "var(--dsw-alias-label-tertiary)", flexShrink: 0 } }, "Affected asset"),
16659
+ import_react11.default.createElement("code", {
16596
16660
  style: {
16597
16661
  fontSize: "12px",
16598
16662
  background: "var(--dsw-alias-bg-subtle)",
@@ -16602,7 +16666,7 @@ function FindingDetail(props) {
16602
16666
  }, finding.affectedAsset)
16603
16667
  ),
16604
16668
  // Stage + Delegation metadata
16605
- import_react10.default.createElement(
16669
+ import_react11.default.createElement(
16606
16670
  "div",
16607
16671
  {
16608
16672
  style: {
@@ -16612,24 +16676,24 @@ function FindingDetail(props) {
16612
16676
  color: "var(--dsw-alias-label-tertiary)"
16613
16677
  }
16614
16678
  },
16615
- import_react10.default.createElement(
16679
+ import_react11.default.createElement(
16616
16680
  "div",
16617
16681
  null,
16618
- import_react10.default.createElement("span", { style: { fontWeight: 500, color: "var(--dsw-alias-label-secondary)" } }, "Stage"),
16682
+ import_react11.default.createElement("span", { style: { fontWeight: 500, color: "var(--dsw-alias-label-secondary)" } }, "Stage"),
16619
16683
  " ",
16620
- import_react10.default.createElement("span", null, finding.sourceStage)
16684
+ import_react11.default.createElement("span", null, finding.sourceStage)
16621
16685
  ),
16622
- import_react10.default.createElement(
16686
+ import_react11.default.createElement(
16623
16687
  "div",
16624
16688
  null,
16625
- import_react10.default.createElement("span", { style: { fontWeight: 500, color: "var(--dsw-alias-label-secondary)" } }, "Delegation"),
16689
+ import_react11.default.createElement("span", { style: { fontWeight: 500, color: "var(--dsw-alias-label-secondary)" } }, "Delegation"),
16626
16690
  " ",
16627
- import_react10.default.createElement("span", null, finding.sourceDelegationId)
16691
+ import_react11.default.createElement("span", null, finding.sourceDelegationId)
16628
16692
  )
16629
16693
  )
16630
16694
  ),
16631
16695
  // ── DetailBody (scrollable) ────────────────────────────────────────
16632
- import_react10.default.createElement(
16696
+ import_react11.default.createElement(
16633
16697
  "div",
16634
16698
  {
16635
16699
  style: {
@@ -16645,16 +16709,16 @@ function FindingDetail(props) {
16645
16709
  color: "var(--dsw-alias-label-primary)"
16646
16710
  }
16647
16711
  },
16648
- loading && import_react10.default.createElement("div", {
16712
+ loading && import_react11.default.createElement("div", {
16649
16713
  style: { color: "var(--dsw-alias-label-tertiary)", padding: "16px 0" }
16650
16714
  }, "Loading finding..."),
16651
- error51 && import_react10.default.createElement("div", {
16715
+ error51 && import_react11.default.createElement("div", {
16652
16716
  style: { color: "var(--dsw-status-error)", padding: "16px 0" }
16653
16717
  }, "Unable to load finding detail"),
16654
- content !== null && import_react10.default.createElement(import_dsh_client_ui_primitives3.MarkdownText, { text: content })
16718
+ content !== null && import_react11.default.createElement(import_dsh_client_ui_primitives4.MarkdownText, { text: content })
16655
16719
  ),
16656
16720
  // ── Footer actions (fixed) ──────────────────────────────────────────
16657
- import_react10.default.createElement(
16721
+ import_react11.default.createElement(
16658
16722
  "div",
16659
16723
  {
16660
16724
  style: {
@@ -16665,11 +16729,11 @@ function FindingDetail(props) {
16665
16729
  gap: "8px"
16666
16730
  }
16667
16731
  },
16668
- import_react10.default.createElement(ActionButton, {
16732
+ import_react11.default.createElement(ActionButton, {
16669
16733
  label: "View Stage",
16670
16734
  onClick: () => onNavigate("stages", { stage: finding.sourceStage })
16671
16735
  }),
16672
- import_react10.default.createElement(ActionButton, {
16736
+ import_react11.default.createElement(ActionButton, {
16673
16737
  label: "View in Output",
16674
16738
  onClick: () => onNavigate("output", { output: `findings/${finding.detailFile}` })
16675
16739
  })
@@ -16677,7 +16741,7 @@ function FindingDetail(props) {
16677
16741
  );
16678
16742
  }
16679
16743
  function ActionButton(props) {
16680
- return import_react10.default.createElement("button", {
16744
+ return import_react11.default.createElement("button", {
16681
16745
  type: "button",
16682
16746
  onClick: props.onClick,
16683
16747
  style: {
@@ -16700,10 +16764,10 @@ function ActionButton(props) {
16700
16764
  }
16701
16765
 
16702
16766
  // src/ui/client/pentester/TraceView.tsx
16703
- var import_react15 = __toESM(require("react"), 1);
16767
+ var import_react16 = __toESM(require("react"), 1);
16704
16768
 
16705
16769
  // src/ui/client/pentester/trace/TraceTimeline.tsx
16706
- var import_react14 = __toESM(require("react"), 1);
16770
+ var import_react15 = __toESM(require("react"), 1);
16707
16771
 
16708
16772
  // src/ui/client/pentester/trace/types.ts
16709
16773
  var STAGE_NODE_H = 72;
@@ -17107,8 +17171,8 @@ function buildScaledTraceLayout(baseLayout, scale) {
17107
17171
  }
17108
17172
 
17109
17173
  // src/ui/client/pentester/trace/TraceNode.tsx
17110
- var import_react11 = __toESM(require("react"), 1);
17111
- var import_dsh_client_ui_primitives4 = require("@deepseek-ai/dsh-client-ui-primitives");
17174
+ var import_react12 = __toESM(require("react"), 1);
17175
+ var import_dsh_client_ui_primitives5 = require("@deepseek-ai/dsh-client-ui-primitives");
17112
17176
  var CARD = {
17113
17177
  position: "absolute",
17114
17178
  borderRadius: "7px",
@@ -17121,10 +17185,10 @@ var CARD = {
17121
17185
  cursor: "pointer",
17122
17186
  pointerEvents: "auto"
17123
17187
  };
17124
- var StartNode = (0, import_react11.forwardRef)(
17188
+ var StartNode = (0, import_react12.forwardRef)(
17125
17189
  function StartNode2(props, ref) {
17126
17190
  const { section, x } = props;
17127
- return import_react11.default.createElement(
17191
+ return import_react12.default.createElement(
17128
17192
  "div",
17129
17193
  {
17130
17194
  ref,
@@ -17152,7 +17216,7 @@ var StartNode = (0, import_react11.forwardRef)(
17152
17216
  pointerEvents: "auto"
17153
17217
  }
17154
17218
  },
17155
- import_react11.default.createElement("div", {
17219
+ import_react12.default.createElement("div", {
17156
17220
  style: {
17157
17221
  width: "6px",
17158
17222
  height: "6px",
@@ -17165,13 +17229,13 @@ var StartNode = (0, import_react11.forwardRef)(
17165
17229
  );
17166
17230
  }
17167
17231
  );
17168
- var StageNode = (0, import_react11.forwardRef)(
17232
+ var StageNode = (0, import_react12.forwardRef)(
17169
17233
  function StageNode2(props, ref) {
17170
17234
  const { section, x, onClick } = props;
17171
17235
  const status = section.status;
17172
17236
  const borderColor = status === "completed" ? "var(--dsw-status-done, #22c55e)" : status === "active" ? "var(--dsw-alias-state-business-primary)" : "var(--dsw-alias-border-l2)";
17173
17237
  const dotState = status === "completed" ? "done" : status === "active" ? "ongoing" : "ongoing";
17174
- return import_react11.default.createElement(
17238
+ return import_react12.default.createElement(
17175
17239
  "div",
17176
17240
  {
17177
17241
  ref,
@@ -17199,26 +17263,26 @@ var StageNode = (0, import_react11.forwardRef)(
17199
17263
  gap: "10px"
17200
17264
  }
17201
17265
  },
17202
- import_react11.default.createElement(import_dsh_client_ui_primitives4.StateDot, { state: dotState, size: 8 }),
17203
- import_react11.default.createElement(
17266
+ import_react12.default.createElement(import_dsh_client_ui_primitives5.StateDot, { state: dotState, size: 8 }),
17267
+ import_react12.default.createElement(
17204
17268
  "div",
17205
17269
  { style: { minWidth: 0 } },
17206
- import_react11.default.createElement("div", {
17270
+ import_react12.default.createElement("div", {
17207
17271
  style: { fontWeight: 600, color: "var(--dsw-alias-label-primary)", fontSize: "14px", lineHeight: "20px" }
17208
17272
  }, section.label),
17209
- import_react11.default.createElement("div", {
17273
+ import_react12.default.createElement("div", {
17210
17274
  style: { fontSize: "12px", color: "var(--dsw-alias-label-secondary)", marginTop: "2px" }
17211
17275
  }, section.sublabel)
17212
17276
  )
17213
17277
  );
17214
17278
  }
17215
17279
  );
17216
- var AgentNode = (0, import_react11.forwardRef)(
17280
+ var AgentNode = (0, import_react12.forwardRef)(
17217
17281
  function AgentNode2(props, ref) {
17218
17282
  const { branch, x, liveActivity, onClick } = props;
17219
17283
  const dotState = branch.status === "failed" ? "error" : branch.status === "closed" ? "done" : liveActivity === "running" ? "ongoing" : liveActivity === "inactive" ? "done" : branch.status === "starting" ? "ongoing" : "done";
17220
17284
  const borderColor = dotState === "error" ? "var(--dsw-status-error, #ef4444)" : dotState === "ongoing" ? "var(--dsw-alias-state-business-primary)" : "var(--dsw-alias-border-l2)";
17221
- return import_react11.default.createElement(
17285
+ return import_react12.default.createElement(
17222
17286
  "div",
17223
17287
  {
17224
17288
  ref,
@@ -17246,14 +17310,14 @@ var AgentNode = (0, import_react11.forwardRef)(
17246
17310
  gap: "8px"
17247
17311
  }
17248
17312
  },
17249
- import_react11.default.createElement(import_dsh_client_ui_primitives4.StateDot, { state: dotState, size: 8 }),
17250
- import_react11.default.createElement(
17313
+ import_react12.default.createElement(import_dsh_client_ui_primitives5.StateDot, { state: dotState, size: 8 }),
17314
+ import_react12.default.createElement(
17251
17315
  "div",
17252
17316
  { style: { minWidth: 0 } },
17253
- import_react11.default.createElement("div", {
17317
+ import_react12.default.createElement("div", {
17254
17318
  style: { fontWeight: 600, color: "var(--dsw-alias-label-primary)", fontSize: "13px", lineHeight: "18px" }
17255
17319
  }, branch.label),
17256
- import_react11.default.createElement("div", {
17320
+ import_react12.default.createElement("div", {
17257
17321
  style: { fontSize: "11px", color: "var(--dsw-alias-label-tertiary)", marginTop: "2px" }
17258
17322
  }, branch.status === "starting" ? "Agent starting" : branch.status === "active" ? "Agent active" : "Agent completed")
17259
17323
  )
@@ -17268,11 +17332,11 @@ var DELIVERY_ICON_COLORS = {
17268
17332
  finding: "var(--dsw-status-error, #ef4444)",
17269
17333
  asset: "#3b82f6"
17270
17334
  };
17271
- var DeliveryNode = (0, import_react11.forwardRef)(
17335
+ var DeliveryNode = (0, import_react12.forwardRef)(
17272
17336
  function DeliveryNode2(props, ref) {
17273
17337
  const { group, x, y, onClick } = props;
17274
17338
  const iconColor = DELIVERY_ICON_COLORS[group.kind] ?? "var(--dsw-alias-label-tertiary)";
17275
- return import_react11.default.createElement(
17339
+ return import_react12.default.createElement(
17276
17340
  "div",
17277
17341
  {
17278
17342
  ref,
@@ -17304,7 +17368,7 @@ var DeliveryNode = (0, import_react11.forwardRef)(
17304
17368
  textAlign: "center"
17305
17369
  }
17306
17370
  },
17307
- import_react11.default.createElement("div", {
17371
+ import_react12.default.createElement("div", {
17308
17372
  style: {
17309
17373
  width: "8px",
17310
17374
  height: "8px",
@@ -17313,10 +17377,10 @@ var DeliveryNode = (0, import_react11.forwardRef)(
17313
17377
  flexShrink: 0
17314
17378
  }
17315
17379
  }),
17316
- import_react11.default.createElement("div", {
17380
+ import_react12.default.createElement("div", {
17317
17381
  style: { fontWeight: 600, color: "var(--dsw-alias-label-primary)", fontSize: "12px", lineHeight: "16px" }
17318
17382
  }, group.label),
17319
- import_react11.default.createElement("div", {
17383
+ import_react12.default.createElement("div", {
17320
17384
  style: { fontSize: "10px", color: "var(--dsw-alias-label-tertiary)" }
17321
17385
  }, `${group.count} ${group.count === 1 ? "file" : "files"}`)
17322
17386
  );
@@ -17324,7 +17388,7 @@ var DeliveryNode = (0, import_react11.forwardRef)(
17324
17388
  );
17325
17389
 
17326
17390
  // src/ui/client/pentester/trace/TraceConnectors.tsx
17327
- var import_react12 = __toESM(require("react"), 1);
17391
+ var import_react13 = __toESM(require("react"), 1);
17328
17392
  function roundedOrthogonal(sx, sy, tx, ty, r = 6) {
17329
17393
  if (Math.abs(sx - tx) < 2) {
17330
17394
  return `M ${sx} ${sy} L ${tx} ${ty}`;
@@ -17349,7 +17413,7 @@ function branchJunction(cx, sy, targets) {
17349
17413
  }
17350
17414
  function TraceConnectors(props) {
17351
17415
  const { layout } = props;
17352
- const paths = (0, import_react12.useMemo)(() => {
17416
+ const paths = (0, import_react13.useMemo)(() => {
17353
17417
  const result = [];
17354
17418
  const cx = layout.spineX;
17355
17419
  const solid = { stroke: "var(--dsw-alias-border-l2)", strokeWidth: 1.25 };
@@ -17430,7 +17494,7 @@ function TraceConnectors(props) {
17430
17494
  }
17431
17495
  return result;
17432
17496
  }, [layout]);
17433
- return import_react12.default.createElement(
17497
+ return import_react13.default.createElement(
17434
17498
  "svg",
17435
17499
  {
17436
17500
  width: layout.worldHalfWidth * 2,
@@ -17443,7 +17507,7 @@ function TraceConnectors(props) {
17443
17507
  }
17444
17508
  },
17445
17509
  ...paths.map(
17446
- (p, i) => import_react12.default.createElement("path", {
17510
+ (p, i) => import_react13.default.createElement("path", {
17447
17511
  key: i,
17448
17512
  d: p.d,
17449
17513
  fill: "none",
@@ -17458,7 +17522,7 @@ function TraceConnectors(props) {
17458
17522
  }
17459
17523
 
17460
17524
  // src/ui/client/pentester/trace/TraceControls.tsx
17461
- var import_react13 = __toESM(require("react"), 1);
17525
+ var import_react14 = __toESM(require("react"), 1);
17462
17526
  var BTN = {
17463
17527
  height: "32px",
17464
17528
  display: "flex",
@@ -17477,33 +17541,33 @@ var BTN = {
17477
17541
  function TraceControls(props) {
17478
17542
  const { scale, onZoomIn, onZoomOut, onReset, onFit } = props;
17479
17543
  const pct = Math.round(scale * 100);
17480
- return import_react13.default.createElement(
17544
+ return import_react14.default.createElement(
17481
17545
  "div",
17482
17546
  {
17483
17547
  style: { display: "flex", alignItems: "center", gap: "4px" }
17484
17548
  },
17485
- import_react13.default.createElement("button", {
17549
+ import_react14.default.createElement("button", {
17486
17550
  type: "button",
17487
17551
  "aria-label": "Zoom out",
17488
17552
  title: "Zoom out",
17489
17553
  onClick: onZoomOut,
17490
17554
  style: { ...BTN, width: "32px", padding: 0 }
17491
17555
  }, "\u2212"),
17492
- import_react13.default.createElement("button", {
17556
+ import_react14.default.createElement("button", {
17493
17557
  type: "button",
17494
17558
  "aria-label": "Reset zoom",
17495
17559
  title: "Reset to 100%",
17496
17560
  onClick: onReset,
17497
17561
  style: { ...BTN, fontWeight: 500, fontSize: "11px", color: "var(--dsw-alias-label-primary)" }
17498
17562
  }, `${pct}%`),
17499
- import_react13.default.createElement("button", {
17563
+ import_react14.default.createElement("button", {
17500
17564
  type: "button",
17501
17565
  "aria-label": "Zoom in",
17502
17566
  title: "Zoom in",
17503
17567
  onClick: onZoomIn,
17504
17568
  style: { ...BTN, width: "32px", padding: 0 }
17505
17569
  }, "+"),
17506
- import_react13.default.createElement("button", {
17570
+ import_react14.default.createElement("button", {
17507
17571
  type: "button",
17508
17572
  "aria-label": "Fit to width",
17509
17573
  title: "Fit topology width",
@@ -17532,12 +17596,12 @@ function checkSpineInvariant(graphEl, scale) {
17532
17596
  }
17533
17597
  function TraceTimeline(props) {
17534
17598
  const { snapshot, liveActivity, onNavigate, onOpenSession } = props;
17535
- const baseLayout = (0, import_react14.useMemo)(() => buildTraceLayout(snapshot), [snapshot]);
17536
- const [scale, setScale] = (0, import_react14.useState)(DEFAULT_SCALE);
17537
- const graphRef = (0, import_react14.useRef)(null);
17538
- const graphVpRef = (0, import_react14.useRef)(null);
17539
- const autoFitDoneRef = (0, import_react14.useRef)(false);
17540
- const scaledLayout = (0, import_react14.useMemo)(
17599
+ const baseLayout = (0, import_react15.useMemo)(() => buildTraceLayout(snapshot), [snapshot]);
17600
+ const [scale, setScale] = (0, import_react15.useState)(DEFAULT_SCALE);
17601
+ const graphRef = (0, import_react15.useRef)(null);
17602
+ const graphVpRef = (0, import_react15.useRef)(null);
17603
+ const autoFitDoneRef = (0, import_react15.useRef)(false);
17604
+ const scaledLayout = (0, import_react15.useMemo)(
17541
17605
  () => buildScaledTraceLayout(baseLayout, scale),
17542
17606
  [baseLayout, scale]
17543
17607
  );
@@ -17547,7 +17611,7 @@ function TraceTimeline(props) {
17547
17611
  const spineX = scaledLayout.spineX;
17548
17612
  const worldW = worldHalfWidth * 2;
17549
17613
  const worldH = scaledLayout.totalHeight;
17550
- const doAutoFit = (0, import_react14.useCallback)(() => {
17614
+ const doAutoFit = (0, import_react15.useCallback)(() => {
17551
17615
  const vp = graphVpRef.current;
17552
17616
  if (vp === null) return DEFAULT_SCALE;
17553
17617
  const availableHalf = vp.clientWidth / 2 - GRAPH_PADDING;
@@ -17555,13 +17619,13 @@ function TraceTimeline(props) {
17555
17619
  const fitScale = availableHalf / requiredHalf;
17556
17620
  return Math.min(DEFAULT_SCALE, Math.max(MIN_SCALE, fitScale));
17557
17621
  }, [baseLayout.worldHalfWidth]);
17558
- (0, import_react14.useEffect)(() => {
17622
+ (0, import_react15.useEffect)(() => {
17559
17623
  if (autoFitDoneRef.current) return;
17560
17624
  const fitScale = doAutoFit();
17561
17625
  if (fitScale !== DEFAULT_SCALE) setScale(fitScale);
17562
17626
  autoFitDoneRef.current = true;
17563
17627
  }, [doAutoFit]);
17564
- const zoomTo = (0, import_react14.useCallback)((newScale) => {
17628
+ const zoomTo = (0, import_react15.useCallback)((newScale) => {
17565
17629
  const clamped = Math.min(MAX_SCALE, Math.max(MIN_SCALE, newScale));
17566
17630
  const owner = getScrollOwner();
17567
17631
  const oldScale = scale;
@@ -17574,26 +17638,26 @@ function TraceTimeline(props) {
17574
17638
  owner.scrollTop = Math.max(0, nextScrollTop);
17575
17639
  });
17576
17640
  }, [scale]);
17577
- const zoomIn = (0, import_react14.useCallback)(() => zoomTo(scale * 1.15), [zoomTo, scale]);
17578
- const zoomOut = (0, import_react14.useCallback)(() => zoomTo(scale / 1.15), [zoomTo, scale]);
17579
- const resetZoom = (0, import_react14.useCallback)(() => zoomTo(DEFAULT_SCALE), [zoomTo]);
17580
- const fitWidth = (0, import_react14.useCallback)(() => zoomTo(doAutoFit()), [zoomTo, doAutoFit]);
17581
- const handleWheel = (0, import_react14.useCallback)((e) => {
17641
+ const zoomIn = (0, import_react15.useCallback)(() => zoomTo(scale * 1.15), [zoomTo, scale]);
17642
+ const zoomOut = (0, import_react15.useCallback)(() => zoomTo(scale / 1.15), [zoomTo, scale]);
17643
+ const resetZoom = (0, import_react15.useCallback)(() => zoomTo(DEFAULT_SCALE), [zoomTo]);
17644
+ const fitWidth = (0, import_react15.useCallback)(() => zoomTo(doAutoFit()), [zoomTo, doAutoFit]);
17645
+ const handleWheel = (0, import_react15.useCallback)((e) => {
17582
17646
  if (!e.ctrlKey && !e.metaKey) return;
17583
17647
  e.preventDefault();
17584
17648
  const factor = e.deltaY < 0 ? 1.12 : 1 / 1.12;
17585
17649
  zoomTo(scale * factor);
17586
17650
  }, [zoomTo, scale]);
17587
- (0, import_react14.useEffect)(() => {
17651
+ (0, import_react15.useEffect)(() => {
17588
17652
  checkSpineInvariant(graphRef.current, scale);
17589
17653
  }, [scale, adjustedSections]);
17590
- const handleStageClick = (0, import_react14.useCallback)((stageId) => {
17654
+ const handleStageClick = (0, import_react15.useCallback)((stageId) => {
17591
17655
  onNavigate("stages", { stage: stageId });
17592
17656
  }, [onNavigate]);
17593
- const handleAgentClick = (0, import_react14.useCallback)((sessionId) => {
17657
+ const handleAgentClick = (0, import_react15.useCallback)((sessionId) => {
17594
17658
  if (sessionId !== void 0) onOpenSession(sessionId);
17595
17659
  }, [onOpenSession]);
17596
- const handleDeliveryClick = (0, import_react14.useCallback)((group) => {
17660
+ const handleDeliveryClick = (0, import_react15.useCallback)((group) => {
17597
17661
  if (group.navTab === "findings") {
17598
17662
  onNavigate("findings", { finding: group.navPath });
17599
17663
  } else {
@@ -17602,7 +17666,7 @@ function TraceTimeline(props) {
17602
17666
  }, [onNavigate]);
17603
17667
  const gridCols = `${TIME_PANEL_W}px minmax(0, 1fr)`;
17604
17668
  const timelineEventGrid = `${TIMELINE_DOT_W}px ${TIMELINE_TIME_W}px minmax(0, 1fr)`;
17605
- return import_react14.default.createElement(
17669
+ return import_react15.default.createElement(
17606
17670
  "div",
17607
17671
  {
17608
17672
  style: {
@@ -17615,7 +17679,7 @@ function TraceTimeline(props) {
17615
17679
  }
17616
17680
  },
17617
17681
  // ── TraceHeader ─────────────────────────────────────────────────────────
17618
- import_react14.default.createElement(
17682
+ import_react15.default.createElement(
17619
17683
  "div",
17620
17684
  {
17621
17685
  "data-testid": "trace-header",
@@ -17627,16 +17691,16 @@ function TraceTimeline(props) {
17627
17691
  background: "var(--dsw-alias-bg-base)"
17628
17692
  }
17629
17693
  },
17630
- import_react14.default.createElement(
17694
+ import_react15.default.createElement(
17631
17695
  "div",
17632
17696
  {
17633
17697
  style: { padding: "12px 18px", borderRight: "1px solid var(--dsw-alias-border-l1)" }
17634
17698
  },
17635
- import_react14.default.createElement("div", {
17699
+ import_react15.default.createElement("div", {
17636
17700
  style: { fontSize: "13px", fontWeight: 600, color: "var(--dsw-alias-label-primary)" }
17637
17701
  }, "Timeline")
17638
17702
  ),
17639
- import_react14.default.createElement(
17703
+ import_react15.default.createElement(
17640
17704
  "div",
17641
17705
  {
17642
17706
  style: {
@@ -17646,10 +17710,10 @@ function TraceTimeline(props) {
17646
17710
  justifyContent: "space-between"
17647
17711
  }
17648
17712
  },
17649
- import_react14.default.createElement("div", {
17713
+ import_react15.default.createElement("div", {
17650
17714
  style: { fontSize: "13px", fontWeight: 600, color: "var(--dsw-alias-label-primary)" }
17651
17715
  }, "Topology"),
17652
- import_react14.default.createElement(TraceControls, {
17716
+ import_react15.default.createElement(TraceControls, {
17653
17717
  scale,
17654
17718
  onZoomIn: zoomIn,
17655
17719
  onZoomOut: zoomOut,
@@ -17659,7 +17723,7 @@ function TraceTimeline(props) {
17659
17723
  )
17660
17724
  ),
17661
17725
  // ── Content (no scroll — flows into Harness scroll owner) ───────────────
17662
- import_react14.default.createElement(
17726
+ import_react15.default.createElement(
17663
17727
  "div",
17664
17728
  {
17665
17729
  onWheel: handleWheel,
@@ -17669,7 +17733,7 @@ function TraceTimeline(props) {
17669
17733
  }
17670
17734
  },
17671
17735
  // ── Timeline rail ────────────────────────────────────────────────────
17672
- import_react14.default.createElement(
17736
+ import_react15.default.createElement(
17673
17737
  "div",
17674
17738
  {
17675
17739
  style: {
@@ -17680,7 +17744,7 @@ function TraceTimeline(props) {
17680
17744
  }
17681
17745
  },
17682
17746
  // Vertical timeline spine line
17683
- import_react14.default.createElement("div", {
17747
+ import_react15.default.createElement("div", {
17684
17748
  "aria-hidden": true,
17685
17749
  style: {
17686
17750
  position: "absolute",
@@ -17695,7 +17759,7 @@ function TraceTimeline(props) {
17695
17759
  ...scaledBands.map((band) => {
17696
17760
  const isStart = band.bandId === "band:start";
17697
17761
  if (band.timelineItems.length === 0) return null;
17698
- return import_react14.default.createElement(
17762
+ return import_react15.default.createElement(
17699
17763
  "div",
17700
17764
  {
17701
17765
  key: band.bandId,
@@ -17712,7 +17776,7 @@ function TraceTimeline(props) {
17712
17776
  },
17713
17777
  // Start band
17714
17778
  isStart && band.timelineItems.map(
17715
- (item, ii) => import_react14.default.createElement(
17779
+ (item, ii) => import_react15.default.createElement(
17716
17780
  "div",
17717
17781
  {
17718
17782
  key: ii,
@@ -17724,12 +17788,12 @@ function TraceTimeline(props) {
17724
17788
  minHeight: `${TIMELINE_ROW_H}px`
17725
17789
  }
17726
17790
  },
17727
- import_react14.default.createElement(
17791
+ import_react15.default.createElement(
17728
17792
  "div",
17729
17793
  {
17730
17794
  style: { display: "flex", justifyContent: "center", paddingTop: "4px" }
17731
17795
  },
17732
- import_react14.default.createElement("div", {
17796
+ import_react15.default.createElement("div", {
17733
17797
  style: {
17734
17798
  width: "6px",
17735
17799
  height: "6px",
@@ -17738,7 +17802,7 @@ function TraceTimeline(props) {
17738
17802
  }
17739
17803
  })
17740
17804
  ),
17741
- import_react14.default.createElement("span", {
17805
+ import_react15.default.createElement("span", {
17742
17806
  style: {
17743
17807
  fontSize: "11px",
17744
17808
  fontFamily: "monospace",
@@ -17747,13 +17811,13 @@ function TraceTimeline(props) {
17747
17811
  paddingTop: "2px"
17748
17812
  }
17749
17813
  }, item.timeLabel),
17750
- import_react14.default.createElement(
17814
+ import_react15.default.createElement(
17751
17815
  "div",
17752
17816
  { style: { minWidth: 0, paddingTop: "2px" } },
17753
- import_react14.default.createElement("div", {
17817
+ import_react15.default.createElement("div", {
17754
17818
  style: { fontSize: "13px", fontWeight: 500, color: "var(--dsw-alias-label-primary)", lineHeight: "18px" }
17755
17819
  }, item.title),
17756
- item.subtitle !== "" && import_react14.default.createElement("div", {
17820
+ item.subtitle !== "" && import_react15.default.createElement("div", {
17757
17821
  style: { fontSize: "11px", color: "var(--dsw-alias-label-tertiary)", lineHeight: "16px" }
17758
17822
  }, item.subtitle)
17759
17823
  )
@@ -17761,7 +17825,7 @@ function TraceTimeline(props) {
17761
17825
  ),
17762
17826
  // Regular stage/agent items
17763
17827
  !isStart && band.timelineItems.map(
17764
- (item, ii) => import_react14.default.createElement(
17828
+ (item, ii) => import_react15.default.createElement(
17765
17829
  "div",
17766
17830
  {
17767
17831
  key: ii,
@@ -17773,12 +17837,12 @@ function TraceTimeline(props) {
17773
17837
  minHeight: `${TIMELINE_ROW_H}px`
17774
17838
  }
17775
17839
  },
17776
- import_react14.default.createElement(
17840
+ import_react15.default.createElement(
17777
17841
  "div",
17778
17842
  {
17779
17843
  style: { display: "flex", justifyContent: "center", paddingTop: "4px" }
17780
17844
  },
17781
- import_react14.default.createElement("div", {
17845
+ import_react15.default.createElement("div", {
17782
17846
  style: {
17783
17847
  width: "8px",
17784
17848
  height: "8px",
@@ -17787,7 +17851,7 @@ function TraceTimeline(props) {
17787
17851
  }
17788
17852
  })
17789
17853
  ),
17790
- import_react14.default.createElement("span", {
17854
+ import_react15.default.createElement("span", {
17791
17855
  style: {
17792
17856
  fontSize: "11px",
17793
17857
  fontFamily: "monospace",
@@ -17796,13 +17860,13 @@ function TraceTimeline(props) {
17796
17860
  paddingTop: "2px"
17797
17861
  }
17798
17862
  }, item.timeLabel),
17799
- import_react14.default.createElement(
17863
+ import_react15.default.createElement(
17800
17864
  "div",
17801
17865
  { style: { minWidth: 0, paddingTop: "2px" } },
17802
- import_react14.default.createElement("div", {
17866
+ import_react15.default.createElement("div", {
17803
17867
  style: { fontSize: "13px", fontWeight: 500, color: "var(--dsw-alias-label-primary)", lineHeight: "18px" }
17804
17868
  }, item.title),
17805
- item.subtitle !== "" && import_react14.default.createElement("div", {
17869
+ item.subtitle !== "" && import_react15.default.createElement("div", {
17806
17870
  style: { fontSize: "11px", color: "var(--dsw-alias-label-tertiary)", lineHeight: "16px" }
17807
17871
  }, item.subtitle)
17808
17872
  )
@@ -17812,7 +17876,7 @@ function TraceTimeline(props) {
17812
17876
  })
17813
17877
  ),
17814
17878
  // ── Graph viewport ────────────────────────────────────────────────────
17815
- import_react14.default.createElement(
17879
+ import_react15.default.createElement(
17816
17880
  "div",
17817
17881
  {
17818
17882
  ref: graphVpRef,
@@ -17824,7 +17888,7 @@ function TraceTimeline(props) {
17824
17888
  }
17825
17889
  },
17826
17890
  // SpineAnchor: CSS left:50%, always at viewport center
17827
- import_react14.default.createElement(
17891
+ import_react15.default.createElement(
17828
17892
  "div",
17829
17893
  {
17830
17894
  style: {
@@ -17837,7 +17901,7 @@ function TraceTimeline(props) {
17837
17901
  }
17838
17902
  },
17839
17903
  // TopologyWorld: symmetric around spine
17840
- import_react14.default.createElement(
17904
+ import_react15.default.createElement(
17841
17905
  "div",
17842
17906
  {
17843
17907
  ref: graphRef,
@@ -17851,24 +17915,24 @@ function TraceTimeline(props) {
17851
17915
  transformOrigin: `${spineX}px 0px`
17852
17916
  }
17853
17917
  },
17854
- import_react14.default.createElement(TraceConnectors, {
17918
+ import_react15.default.createElement(TraceConnectors, {
17855
17919
  layout: { ...baseLayout, sections: adjustedSections, worldHeight: worldH, spineX },
17856
17920
  rects: /* @__PURE__ */ new Map()
17857
17921
  }),
17858
- import_react14.default.createElement(
17922
+ import_react15.default.createElement(
17859
17923
  "div",
17860
17924
  {
17861
17925
  style: { position: "absolute", inset: 0, zIndex: 1 }
17862
17926
  },
17863
17927
  ...adjustedSections.filter((s) => s.stageId === "start").map(
17864
- (section) => import_react14.default.createElement(StartNode, {
17928
+ (section) => import_react15.default.createElement(StartNode, {
17865
17929
  key: "stage:start",
17866
17930
  section,
17867
17931
  x: spineX
17868
17932
  })
17869
17933
  ),
17870
17934
  ...adjustedSections.filter((s) => s.stageId !== "start").map(
17871
- (section) => import_react14.default.createElement(StageNode, {
17935
+ (section) => import_react15.default.createElement(StageNode, {
17872
17936
  key: `stage:${section.stageId}`,
17873
17937
  section,
17874
17938
  x: spineX,
@@ -17877,7 +17941,7 @@ function TraceTimeline(props) {
17877
17941
  ),
17878
17942
  ...adjustedSections.flatMap(
17879
17943
  (section) => section.agentBranches.map(
17880
- (branch) => import_react14.default.createElement(AgentNode, {
17944
+ (branch) => import_react15.default.createElement(AgentNode, {
17881
17945
  key: `agent:${branch.delegationId}`,
17882
17946
  branch,
17883
17947
  x: spineX + branch.x,
@@ -17892,7 +17956,7 @@ function TraceTimeline(props) {
17892
17956
  (row3, ri) => row3.map((dx, gi) => {
17893
17957
  const group = branch.deliveryGroups[ri * 3 + gi];
17894
17958
  if (group === void 0) return null;
17895
- return import_react14.default.createElement(DeliveryNode, {
17959
+ return import_react15.default.createElement(DeliveryNode, {
17896
17960
  key: `delivery:${branch.delegationId}:${group.kind}`,
17897
17961
  group,
17898
17962
  x: spineX + dx,
@@ -17915,11 +17979,11 @@ function TraceTimeline(props) {
17915
17979
  function TraceView(props) {
17916
17980
  const { snapshot, liveActivity, onNavigate, onOpenSession, activeTargetId } = props;
17917
17981
  if (snapshot === null || snapshot.run === null) {
17918
- return import_react15.default.createElement("div", {
17982
+ return import_react16.default.createElement("div", {
17919
17983
  style: { padding: "24px", color: "var(--dsw-alias-label-tertiary)", fontSize: "14px" }
17920
17984
  }, "No execution trace yet");
17921
17985
  }
17922
- return import_react15.default.createElement(TraceTimeline, {
17986
+ return import_react16.default.createElement(TraceTimeline, {
17923
17987
  snapshot,
17924
17988
  liveActivity,
17925
17989
  onNavigate,
@@ -17929,21 +17993,21 @@ function TraceView(props) {
17929
17993
  }
17930
17994
 
17931
17995
  // src/ui/client/pentester/OutputView.tsx
17932
- var import_react17 = __toESM(require("react"), 1);
17933
- var import_dsh_client_ui_primitives6 = require("@deepseek-ai/dsh-client-ui-primitives");
17996
+ var import_react18 = __toESM(require("react"), 1);
17997
+ var import_dsh_client_ui_primitives7 = require("@deepseek-ai/dsh-client-ui-primitives");
17934
17998
 
17935
17999
  // src/ui/client/pentester/FolderTreeRow.tsx
17936
- var import_react16 = __toESM(require("react"), 1);
17937
- var import_dsh_client_ui_primitives5 = require("@deepseek-ai/dsh-client-ui-primitives");
18000
+ var import_react17 = __toESM(require("react"), 1);
18001
+ var import_dsh_client_ui_primitives6 = require("@deepseek-ai/dsh-client-ui-primitives");
17938
18002
  function FolderTreeRow(props) {
17939
18003
  const { name, depth, defaultOpen = true, children, containsSelected = false } = props;
17940
- const [open, setOpen] = (0, import_react16.useState)(defaultOpen);
17941
- const hasChildren = children !== void 0 && import_react16.default.Children.count(children) > 0;
18004
+ const [open, setOpen] = (0, import_react17.useState)(defaultOpen);
18005
+ const hasChildren = children !== void 0 && import_react17.default.Children.count(children) > 0;
17942
18006
  const folderColor = containsSelected ? "var(--dsw-alias-state-business-primary)" : "var(--dsw-alias-label-secondary)";
17943
- return import_react16.default.createElement(
18007
+ return import_react17.default.createElement(
17944
18008
  "div",
17945
18009
  null,
17946
- import_react16.default.createElement(
18010
+ import_react17.default.createElement(
17947
18011
  "div",
17948
18012
  {
17949
18013
  role: "button",
@@ -17979,19 +18043,19 @@ function FolderTreeRow(props) {
17979
18043
  }
17980
18044
  },
17981
18045
  // Chevron
17982
- hasChildren ? import_react16.default.createElement(
18046
+ hasChildren ? import_react17.default.createElement(
17983
18047
  "span",
17984
18048
  { style: { flexShrink: 0, color: "var(--dsw-alias-label-tertiary)" } },
17985
- import_react16.default.createElement(open ? import_dsh_client_ui_primitives5.IconChevronDownOutline14 : import_dsh_client_ui_primitives5.IconChevronRightOutline14, { size: 14 })
17986
- ) : import_react16.default.createElement("span", { style: { width: "14px", flexShrink: 0 } }),
18049
+ import_react17.default.createElement(open ? import_dsh_client_ui_primitives6.IconChevronDownOutline14 : import_dsh_client_ui_primitives6.IconChevronRightOutline14, { size: 14 })
18050
+ ) : import_react17.default.createElement("span", { style: { width: "14px", flexShrink: 0 } }),
17987
18051
  // Folder icon — color reflects selected ancestry
17988
- import_react16.default.createElement(
18052
+ import_react17.default.createElement(
17989
18053
  "span",
17990
18054
  { style: { flexShrink: 0, color: folderColor } },
17991
- import_react16.default.createElement(open ? import_dsh_client_ui_primitives5.IconFolderOpen16 : import_dsh_client_ui_primitives5.IconFolderClose16, { size: 16 })
18055
+ import_react17.default.createElement(open ? import_dsh_client_ui_primitives6.IconFolderOpen16 : import_dsh_client_ui_primitives6.IconFolderClose16, { size: 16 })
17992
18056
  ),
17993
18057
  // Name
17994
- import_react16.default.createElement("span", {
18058
+ import_react17.default.createElement("span", {
17995
18059
  style: {
17996
18060
  overflow: "hidden",
17997
18061
  textOverflow: "ellipsis",
@@ -17999,12 +18063,12 @@ function FolderTreeRow(props) {
17999
18063
  }
18000
18064
  }, name)
18001
18065
  ),
18002
- open && hasChildren && import_react16.default.createElement("div", null, children)
18066
+ open && hasChildren && import_react17.default.createElement("div", null, children)
18003
18067
  );
18004
18068
  }
18005
18069
  function FileRow(props) {
18006
18070
  const { name, depth, size, isSelected = false, onClick } = props;
18007
- return import_react16.default.createElement(
18071
+ return import_react17.default.createElement(
18008
18072
  "div",
18009
18073
  {
18010
18074
  role: "button",
@@ -18039,10 +18103,10 @@ function FileRow(props) {
18039
18103
  }
18040
18104
  },
18041
18105
  // File icon placeholder (Harness doesn't have a specific file icon; use chevron space)
18042
- import_react16.default.createElement("span", {
18106
+ import_react17.default.createElement("span", {
18043
18107
  style: { width: "14px", flexShrink: 0 }
18044
18108
  }),
18045
- import_react16.default.createElement("span", {
18109
+ import_react17.default.createElement("span", {
18046
18110
  style: {
18047
18111
  overflow: "hidden",
18048
18112
  textOverflow: "ellipsis",
@@ -18051,7 +18115,7 @@ function FileRow(props) {
18051
18115
  minWidth: 0
18052
18116
  }
18053
18117
  }, name),
18054
- size !== void 0 && import_react16.default.createElement("span", {
18118
+ size !== void 0 && import_react17.default.createElement("span", {
18055
18119
  style: {
18056
18120
  fontSize: "11px",
18057
18121
  color: "var(--dsw-alias-label-tertiary)",
@@ -18070,7 +18134,7 @@ var OUTPUT_FILTER_TABS = [
18070
18134
  ];
18071
18135
  function TargetIcon(props) {
18072
18136
  const s = props.size ?? 16;
18073
- return import_react17.default.createElement(
18137
+ return import_react18.default.createElement(
18074
18138
  "svg",
18075
18139
  {
18076
18140
  width: s,
@@ -18084,13 +18148,13 @@ function TargetIcon(props) {
18084
18148
  "aria-hidden": true,
18085
18149
  style: { flexShrink: 0 }
18086
18150
  },
18087
- import_react17.default.createElement("circle", { cx: "8", cy: "8", r: "6.5" }),
18088
- import_react17.default.createElement("circle", { cx: "8", cy: "8", r: "3.5" }),
18089
- import_react17.default.createElement("circle", { cx: "8", cy: "8", r: "1", fill: "currentColor", stroke: "none" }),
18090
- import_react17.default.createElement("line", { x1: "8", y1: "1", x2: "8", y2: "3" }),
18091
- import_react17.default.createElement("line", { x1: "8", y1: "13", x2: "8", y2: "15" }),
18092
- import_react17.default.createElement("line", { x1: "1", y1: "8", x2: "3", y2: "8" }),
18093
- import_react17.default.createElement("line", { x1: "13", y1: "8", x2: "15", y2: "8" })
18151
+ import_react18.default.createElement("circle", { cx: "8", cy: "8", r: "6.5" }),
18152
+ import_react18.default.createElement("circle", { cx: "8", cy: "8", r: "3.5" }),
18153
+ import_react18.default.createElement("circle", { cx: "8", cy: "8", r: "1", fill: "currentColor", stroke: "none" }),
18154
+ import_react18.default.createElement("line", { x1: "8", y1: "1", x2: "8", y2: "3" }),
18155
+ import_react18.default.createElement("line", { x1: "8", y1: "13", x2: "8", y2: "15" }),
18156
+ import_react18.default.createElement("line", { x1: "1", y1: "8", x2: "3", y2: "8" }),
18157
+ import_react18.default.createElement("line", { x1: "13", y1: "8", x2: "15", y2: "8" })
18094
18158
  );
18095
18159
  }
18096
18160
  function entryContainsSelected(entry, selectedPath) {
@@ -18101,12 +18165,12 @@ function entryContainsSelected(entry, selectedPath) {
18101
18165
  }
18102
18166
  function TargetRow(props) {
18103
18167
  const { targetId, target, current, defaultOpen, containsSelected, children } = props;
18104
- const [open, setOpen] = (0, import_react17.useState)(defaultOpen);
18168
+ const [open, setOpen] = (0, import_react18.useState)(defaultOpen);
18105
18169
  const iconColor = containsSelected ? "var(--dsw-alias-state-business-primary)" : current ? "var(--dsw-alias-state-business-primary)" : "var(--dsw-alias-label-secondary)";
18106
- return import_react17.default.createElement(
18170
+ return import_react18.default.createElement(
18107
18171
  "div",
18108
18172
  null,
18109
- import_react17.default.createElement(
18173
+ import_react18.default.createElement(
18110
18174
  "div",
18111
18175
  {
18112
18176
  role: "button",
@@ -18142,7 +18206,7 @@ function TargetRow(props) {
18142
18206
  e.currentTarget.style.background = "transparent";
18143
18207
  }
18144
18208
  },
18145
- import_react17.default.createElement("span", {
18209
+ import_react18.default.createElement("span", {
18146
18210
  style: {
18147
18211
  color: "var(--dsw-alias-label-tertiary)",
18148
18212
  flexShrink: 0,
@@ -18152,22 +18216,22 @@ function TargetRow(props) {
18152
18216
  width: "12px"
18153
18217
  }
18154
18218
  }, open ? "\u25BE" : "\u25B8"),
18155
- import_react17.default.createElement("span", {
18219
+ import_react18.default.createElement("span", {
18156
18220
  style: {
18157
18221
  color: iconColor,
18158
18222
  flexShrink: 0,
18159
18223
  display: "flex",
18160
18224
  alignItems: "center"
18161
18225
  }
18162
- }, import_react17.default.createElement(TargetIcon, { size: 16 })),
18163
- import_react17.default.createElement("span", {
18226
+ }, import_react18.default.createElement(TargetIcon, { size: 16 })),
18227
+ import_react18.default.createElement("span", {
18164
18228
  style: {
18165
18229
  overflow: "hidden",
18166
18230
  textOverflow: "ellipsis",
18167
18231
  whiteSpace: "nowrap"
18168
18232
  }
18169
18233
  }, target),
18170
- current && import_react17.default.createElement("span", {
18234
+ current && import_react18.default.createElement("span", {
18171
18235
  style: {
18172
18236
  fontSize: "10px",
18173
18237
  color: "var(--dsw-alias-state-business-primary)",
@@ -18180,19 +18244,19 @@ function TargetRow(props) {
18180
18244
  }
18181
18245
  }, "active")
18182
18246
  ),
18183
- open && import_react17.default.createElement("div", { style: { marginLeft: "20px" } }, children)
18247
+ open && import_react18.default.createElement("div", { style: { marginLeft: "20px" } }, children)
18184
18248
  );
18185
18249
  }
18186
18250
  function OutputView(props) {
18187
18251
  const { snapshot, command, sessionId, focusOutput } = props;
18188
- const [filter, setFilter] = (0, import_react17.useState)("all");
18189
- const [preview, setPreview] = (0, import_react17.useState)(null);
18190
- const [previewContent, setPreviewContent] = (0, import_react17.useState)(null);
18191
- const [previewLoading, setPreviewLoading] = (0, import_react17.useState)(false);
18192
- const [outputTree, setOutputTree] = (0, import_react17.useState)(null);
18193
- const [outputLoading, setOutputLoading] = (0, import_react17.useState)(false);
18194
- const [outputError, setOutputError] = (0, import_react17.useState)(null);
18195
- (0, import_react17.useEffect)(() => {
18252
+ const [filter, setFilter] = (0, import_react18.useState)("all");
18253
+ const [preview, setPreview] = (0, import_react18.useState)(null);
18254
+ const [previewContent, setPreviewContent] = (0, import_react18.useState)(null);
18255
+ const [previewLoading, setPreviewLoading] = (0, import_react18.useState)(false);
18256
+ const [outputTree, setOutputTree] = (0, import_react18.useState)(null);
18257
+ const [outputLoading, setOutputLoading] = (0, import_react18.useState)(false);
18258
+ const [outputError, setOutputError] = (0, import_react18.useState)(null);
18259
+ (0, import_react18.useEffect)(() => {
18196
18260
  if (snapshot === null) return;
18197
18261
  let cancelled = false;
18198
18262
  setOutputLoading(true);
@@ -18218,7 +18282,7 @@ function OutputView(props) {
18218
18282
  const targetTrees = outputTree !== null ? [outputTree] : [];
18219
18283
  const selectedPath = preview?.entry.path ?? null;
18220
18284
  const selectedTargetId = preview?.targetId ?? null;
18221
- const filteredTargets = (0, import_react17.useMemo)(() => {
18285
+ const filteredTargets = (0, import_react18.useMemo)(() => {
18222
18286
  const base = filter === "all" ? targetTrees : (() => {
18223
18287
  const categoryMap = {
18224
18288
  all: [],
@@ -18239,7 +18303,7 @@ function OutputView(props) {
18239
18303
  )
18240
18304
  }));
18241
18305
  }, [targetTrees, filter, selectedPath, selectedTargetId]);
18242
- const openPreview = (0, import_react17.useCallback)(async (entry, targetId) => {
18306
+ const openPreview = (0, import_react18.useCallback)(async (entry, targetId) => {
18243
18307
  if (entry.kind === "directory") return;
18244
18308
  setPreview({ entry, targetId });
18245
18309
  setPreviewContent(null);
@@ -18262,12 +18326,12 @@ function OutputView(props) {
18262
18326
  setPreviewLoading(false);
18263
18327
  }
18264
18328
  }, [command, sessionId]);
18265
- const closePreview = (0, import_react17.useCallback)(() => {
18329
+ const closePreview = (0, import_react18.useCallback)(() => {
18266
18330
  setPreview(null);
18267
18331
  setPreviewContent(null);
18268
18332
  }, []);
18269
- const focusAppliedRef = (0, import_react17.useRef)(void 0);
18270
- (0, import_react17.useEffect)(() => {
18333
+ const focusAppliedRef = (0, import_react18.useRef)(void 0);
18334
+ (0, import_react18.useEffect)(() => {
18271
18335
  if (focusOutput === void 0 || focusOutput === focusAppliedRef.current) return;
18272
18336
  if (outputTree === null) return;
18273
18337
  focusAppliedRef.current = focusOutput;
@@ -18278,21 +18342,21 @@ function OutputView(props) {
18278
18342
  }, [focusOutput, outputTree, openPreview]);
18279
18343
  const initialLoading = outputTree === null && outputLoading;
18280
18344
  if (initialLoading) {
18281
- return import_react17.default.createElement("div", {
18345
+ return import_react18.default.createElement("div", {
18282
18346
  style: { padding: "24px", color: "var(--dsw-alias-label-tertiary)", fontSize: "14px" }
18283
18347
  }, "Loading output tree...");
18284
18348
  }
18285
18349
  if (outputError !== null) {
18286
- return import_react17.default.createElement(
18350
+ return import_react18.default.createElement(
18287
18351
  "div",
18288
18352
  { style: { padding: "24px" } },
18289
- import_react17.default.createElement("div", {
18353
+ import_react18.default.createElement("div", {
18290
18354
  style: { color: "var(--dsw-status-error)", marginBottom: "12px", fontSize: "14px" }
18291
18355
  }, "Unable to load output tree"),
18292
- import_react17.default.createElement("div", {
18356
+ import_react18.default.createElement("div", {
18293
18357
  style: { color: "var(--dsw-alias-label-tertiary)", fontSize: "12px", marginBottom: "12px" }
18294
18358
  }, outputError),
18295
- import_react17.default.createElement("button", {
18359
+ import_react18.default.createElement("button", {
18296
18360
  onClick: () => {
18297
18361
  setOutputError(null);
18298
18362
  setOutputTree(null);
@@ -18322,22 +18386,22 @@ function OutputView(props) {
18322
18386
  );
18323
18387
  }
18324
18388
  if (snapshot === null) {
18325
- return import_react17.default.createElement("div", {
18389
+ return import_react18.default.createElement("div", {
18326
18390
  style: { padding: "24px", color: "var(--dsw-alias-label-tertiary)", fontSize: "14px" }
18327
18391
  }, "No output data");
18328
18392
  }
18329
18393
  if (targetTrees.length === 0) {
18330
- return import_react17.default.createElement("div", {
18394
+ return import_react18.default.createElement("div", {
18331
18395
  style: { padding: "24px", color: "var(--dsw-alias-label-tertiary)", fontSize: "14px" }
18332
18396
  }, "No output files");
18333
18397
  }
18334
- return import_react17.default.createElement(
18398
+ return import_react18.default.createElement(
18335
18399
  "div",
18336
18400
  {
18337
18401
  style: { display: "flex", gap: "16px", flex: 1, height: "100%", minHeight: 0, minWidth: 0, overflow: "hidden" }
18338
18402
  },
18339
18403
  // Left: file tree
18340
- import_react17.default.createElement(
18404
+ import_react18.default.createElement(
18341
18405
  "div",
18342
18406
  {
18343
18407
  style: {
@@ -18351,7 +18415,7 @@ function OutputView(props) {
18351
18415
  }
18352
18416
  },
18353
18417
  // Filter tabs (fixed)
18354
- import_react17.default.createElement(
18418
+ import_react18.default.createElement(
18355
18419
  "div",
18356
18420
  {
18357
18421
  style: {
@@ -18360,7 +18424,7 @@ function OutputView(props) {
18360
18424
  paddingTop: "2px"
18361
18425
  }
18362
18426
  },
18363
- import_react17.default.createElement(PentesterTabBar, {
18427
+ import_react18.default.createElement(PentesterTabBar, {
18364
18428
  items: OUTPUT_FILTER_TABS,
18365
18429
  active: filter,
18366
18430
  onSelect: (id) => setFilter(id),
@@ -18368,7 +18432,7 @@ function OutputView(props) {
18368
18432
  })
18369
18433
  ),
18370
18434
  // ── TreeViewport (scrollable) ──────────────────────────────────
18371
- import_react17.default.createElement(
18435
+ import_react18.default.createElement(
18372
18436
  "div",
18373
18437
  {
18374
18438
  style: {
@@ -18381,7 +18445,7 @@ function OutputView(props) {
18381
18445
  scrollbarGutter: "stable"
18382
18446
  }
18383
18447
  },
18384
- import_react17.default.createElement("div", {
18448
+ import_react18.default.createElement("div", {
18385
18449
  style: {
18386
18450
  fontSize: "11px",
18387
18451
  fontWeight: 600,
@@ -18393,7 +18457,7 @@ function OutputView(props) {
18393
18457
  }
18394
18458
  }, "Targets"),
18395
18459
  ...filteredTargets.map(
18396
- (t) => import_react17.default.createElement(TargetRow, {
18460
+ (t) => import_react18.default.createElement(TargetRow, {
18397
18461
  key: t.targetId,
18398
18462
  targetId: t.targetId,
18399
18463
  target: t.target,
@@ -18408,7 +18472,7 @@ function OutputView(props) {
18408
18472
  )
18409
18473
  ),
18410
18474
  // Right: preview frame
18411
- import_react17.default.createElement(
18475
+ import_react18.default.createElement(
18412
18476
  "div",
18413
18477
  {
18414
18478
  style: {
@@ -18423,7 +18487,7 @@ function OutputView(props) {
18423
18487
  background: "var(--dsw-alias-bg-base)"
18424
18488
  }
18425
18489
  },
18426
- preview === null ? import_react17.default.createElement("div", {
18490
+ preview === null ? import_react18.default.createElement("div", {
18427
18491
  style: {
18428
18492
  flex: 1,
18429
18493
  display: "flex",
@@ -18432,40 +18496,63 @@ function OutputView(props) {
18432
18496
  color: "var(--dsw-alias-label-tertiary)",
18433
18497
  fontSize: "13px"
18434
18498
  }
18435
- }, "Select a file to preview") : import_react17.default.createElement(
18436
- import_react17.default.Fragment,
18499
+ }, "Select a file to preview") : import_react18.default.createElement(
18500
+ import_react18.default.Fragment,
18437
18501
  null,
18438
18502
  // PreviewHeader (fixed)
18439
- import_react17.default.createElement(
18503
+ import_react18.default.createElement(
18440
18504
  "div",
18441
18505
  {
18442
18506
  style: {
18443
18507
  flex: "none",
18444
18508
  display: "flex",
18445
18509
  alignItems: "center",
18446
- justifyContent: "space-between",
18447
18510
  padding: "8px 12px",
18448
18511
  borderBottom: "1px solid var(--dsw-alias-border-l2)"
18449
18512
  }
18450
18513
  },
18451
- import_react17.default.createElement("div", {
18452
- style: { fontSize: "13px", fontWeight: 600, color: "var(--dsw-alias-label-primary)" }
18453
- }, preview.entry.name),
18454
- import_react17.default.createElement("button", {
18455
- onClick: closePreview,
18514
+ // Filename
18515
+ import_react18.default.createElement("div", {
18456
18516
  style: {
18457
- background: "none",
18458
- border: "none",
18459
- color: "var(--dsw-alias-label-tertiary)",
18460
- cursor: "pointer",
18461
- fontSize: "18px",
18462
- padding: "0 4px"
18517
+ flex: 1,
18518
+ minWidth: 0,
18519
+ fontSize: "13px",
18520
+ fontWeight: 600,
18521
+ color: "var(--dsw-alias-label-primary)",
18522
+ overflow: "hidden",
18523
+ textOverflow: "ellipsis",
18524
+ whiteSpace: "nowrap"
18525
+ }
18526
+ }, preview.entry.name),
18527
+ // Actions
18528
+ import_react18.default.createElement(
18529
+ "div",
18530
+ {
18531
+ style: {
18532
+ flex: "none",
18533
+ display: "flex",
18534
+ alignItems: "center",
18535
+ gap: "4px",
18536
+ marginLeft: "8px"
18537
+ }
18463
18538
  },
18464
- "aria-label": "Close preview"
18465
- }, "\xD7")
18539
+ previewContent !== null && previewContent.content !== void 0 && previewContent.mime !== "binary" && import_react18.default.createElement(CopyAction, { text: previewContent.content }),
18540
+ import_react18.default.createElement("button", {
18541
+ onClick: closePreview,
18542
+ style: {
18543
+ background: "none",
18544
+ border: "none",
18545
+ color: "var(--dsw-alias-label-tertiary)",
18546
+ cursor: "pointer",
18547
+ fontSize: "18px",
18548
+ padding: "0 4px"
18549
+ },
18550
+ "aria-label": "Close preview"
18551
+ }, "\xD7")
18552
+ )
18466
18553
  ),
18467
18554
  // PreviewBody (scrollable)
18468
- import_react17.default.createElement(
18555
+ import_react18.default.createElement(
18469
18556
  "div",
18470
18557
  {
18471
18558
  style: {
@@ -18479,7 +18566,7 @@ function OutputView(props) {
18479
18566
  padding: "12px"
18480
18567
  }
18481
18568
  },
18482
- previewLoading && import_react17.default.createElement("div", {
18569
+ previewLoading && import_react18.default.createElement("div", {
18483
18570
  style: { color: "var(--dsw-alias-label-tertiary)", padding: "16px 0" }
18484
18571
  }, "Loading..."),
18485
18572
  previewContent !== null && renderPreview(previewContent)
@@ -18492,7 +18579,7 @@ function renderOutputTree(entry, depth, targetId, onSelect, selected, selectedPa
18492
18579
  if (entry.kind === "directory" && entry.children !== void 0 && entry.children.length > 0) {
18493
18580
  const isSelectedTarget = selectedTargetId === targetId;
18494
18581
  const containsSelected = isSelectedTarget && entryContainsSelected(entry, selectedPath);
18495
- return import_react17.default.createElement(FolderTreeRow, {
18582
+ return import_react18.default.createElement(FolderTreeRow, {
18496
18583
  key: `${targetId}:${entry.path}`,
18497
18584
  name: entry.name,
18498
18585
  depth,
@@ -18504,7 +18591,7 @@ function renderOutputTree(entry, depth, targetId, onSelect, selected, selectedPa
18504
18591
  });
18505
18592
  }
18506
18593
  const isSelected = selected?.entry.path === entry.path && selected?.targetId === targetId;
18507
- return import_react17.default.createElement(FileRow, {
18594
+ return import_react18.default.createElement(FileRow, {
18508
18595
  key: `${targetId}:${entry.path}`,
18509
18596
  name: entry.name,
18510
18597
  depth,
@@ -18515,33 +18602,33 @@ function renderOutputTree(entry, depth, targetId, onSelect, selected, selectedPa
18515
18602
  }
18516
18603
  function renderPreview(result) {
18517
18604
  if (result.mime === "binary") {
18518
- return import_react17.default.createElement(
18605
+ return import_react18.default.createElement(
18519
18606
  "div",
18520
18607
  {
18521
18608
  style: { color: "var(--dsw-alias-label-tertiary)", fontSize: "13px", padding: "16px" }
18522
18609
  },
18523
- import_react17.default.createElement("div", { style: { marginBottom: "8px" } }, "Preview unavailable"),
18524
- import_react17.default.createElement("div", { style: { fontSize: "12px" } }, `Binary file \xB7 ${formatSize(result.size)}`),
18525
- import_react17.default.createElement("div", { style: { fontSize: "12px" } }, result.path)
18610
+ import_react18.default.createElement("div", { style: { marginBottom: "8px" } }, "Preview unavailable"),
18611
+ import_react18.default.createElement("div", { style: { fontSize: "12px" } }, `Binary file \xB7 ${formatSize(result.size)}`),
18612
+ import_react18.default.createElement("div", { style: { fontSize: "12px" } }, result.path)
18526
18613
  );
18527
18614
  }
18528
18615
  if (result.content === void 0) {
18529
- return import_react17.default.createElement("div", {
18616
+ return import_react18.default.createElement("div", {
18530
18617
  style: { color: "var(--dsw-alias-label-tertiary)", fontSize: "13px" }
18531
18618
  }, "No content available");
18532
18619
  }
18533
18620
  if (result.mime === "markdown") {
18534
- return import_react17.default.createElement(import_dsh_client_ui_primitives6.MarkdownText, { text: result.content });
18621
+ return import_react18.default.createElement(import_dsh_client_ui_primitives7.MarkdownText, { text: result.content });
18535
18622
  }
18536
18623
  if (result.mime === "json") {
18537
18624
  try {
18538
18625
  const parsed = JSON.parse(result.content);
18539
- return import_react17.default.createElement(import_dsh_client_ui_primitives6.JsonTree, { data: parsed, label: result.name });
18626
+ return import_react18.default.createElement(import_dsh_client_ui_primitives7.JsonTree, { data: parsed, label: result.name });
18540
18627
  } catch {
18541
18628
  }
18542
18629
  }
18543
18630
  const lines = result.content.split("\n");
18544
- return import_react17.default.createElement(import_dsh_client_ui_primitives6.ReadBlock, {
18631
+ return import_react18.default.createElement(import_dsh_client_ui_primitives7.ReadBlock, {
18545
18632
  lines: lines.map((text, i) => ({ number: i + 1, text })),
18546
18633
  totalLines: lines.length,
18547
18634
  maxLines: 500
@@ -18616,13 +18703,13 @@ function resolveDelegationPresentationState(delegation, sessionList, rootSession
18616
18703
  return "unknown";
18617
18704
  }
18618
18705
  function useDelegationActivity(sessions, rootSessionId, delegations) {
18619
- const delegationSessionIds = (0, import_react18.useMemo)(
18706
+ const delegationSessionIds = (0, import_react19.useMemo)(
18620
18707
  () => new Set(delegations.filter((d) => d.sessionId !== void 0).map((d) => d.sessionId)),
18621
18708
  [delegations]
18622
18709
  );
18623
- const prevSigRef = (0, import_react18.useRef)("");
18624
- const cachedMapRef = (0, import_react18.useRef)(/* @__PURE__ */ new Map());
18625
- const getSnapshot = (0, import_react18.useCallback)(() => {
18710
+ const prevSigRef = (0, import_react19.useRef)("");
18711
+ const cachedMapRef = (0, import_react19.useRef)(/* @__PURE__ */ new Map());
18712
+ const getSnapshot = (0, import_react19.useCallback)(() => {
18626
18713
  const raw = sessions?.list.getSnapshot();
18627
18714
  if (raw === void 0) return cachedMapRef.current;
18628
18715
  const sig = computeActivitySignature(raw, rootSessionId, delegationSessionIds);
@@ -18636,7 +18723,7 @@ function useDelegationActivity(sessions, rootSessionId, delegations) {
18636
18723
  cachedMapRef.current = map2;
18637
18724
  return map2;
18638
18725
  }, [sessions, rootSessionId, delegationSessionIds, delegations]);
18639
- return (0, import_react18.useSyncExternalStore)(
18726
+ return (0, import_react19.useSyncExternalStore)(
18640
18727
  sessions?.list.subscribe ?? (() => () => {
18641
18728
  }),
18642
18729
  getSnapshot
@@ -18648,7 +18735,7 @@ var RPC_PREFIX = "[PENTESTER_RPC]";
18648
18735
  var isPerf = typeof window !== "undefined" && window.__DSH_PENTESTER_PERF === true;
18649
18736
  function PentesterView(props) {
18650
18737
  const { sessionId, reflect, sessions, useSession, sessionSwitchTimes: sessionSwitchTimes2, sessionPerf } = props;
18651
- const mountTime = (0, import_react18.useRef)(performance.now());
18738
+ const mountTime = (0, import_react19.useRef)(performance.now());
18652
18739
  const switchTime = sessionSwitchTimes2?.get(sessionId);
18653
18740
  if (isPerf) {
18654
18741
  console.log(`${PERF_PREFIX} mount=0ms`);
@@ -18657,8 +18744,8 @@ function PentesterView(props) {
18657
18744
  }
18658
18745
  }
18659
18746
  const openState = useSession?.((s) => s.openState);
18660
- const prevOpenState = (0, import_react18.useRef)(void 0);
18661
- (0, import_react18.useEffect)(() => {
18747
+ const prevOpenState = (0, import_react19.useRef)(void 0);
18748
+ (0, import_react19.useEffect)(() => {
18662
18749
  if (!sessionPerf || openState === void 0) return;
18663
18750
  if (openState !== prevOpenState.current) {
18664
18751
  const elapsed = (performance.now() - mountTime.current).toFixed(0);
@@ -18684,27 +18771,27 @@ function PentesterView(props) {
18684
18771
  prevOpenState.current = openState;
18685
18772
  }
18686
18773
  }, [openState, sessionPerf, switchTime]);
18687
- const [tab, setTab] = (0, import_react18.useState)("overview");
18688
- const [dataState, setDataState] = (0, import_react18.useState)({ kind: "initial" });
18689
- const [requestState, setRequestState] = (0, import_react18.useState)("idle");
18690
- const [navFocus, setNavFocus] = (0, import_react18.useState)({});
18691
- const [activeTargetId, setActiveTargetId] = (0, import_react18.useState)(null);
18692
- const requestSeqRef = (0, import_react18.useRef)(0);
18693
- const pendingRef = (0, import_react18.useRef)(null);
18694
- const mountedRef = (0, import_react18.useRef)(true);
18695
- const firstLoadDone = (0, import_react18.useRef)(false);
18696
- const pollingPausedRef = (0, import_react18.useRef)(false);
18697
- const backoffRef = (0, import_react18.useRef)(0);
18698
- const timerRef = (0, import_react18.useRef)(null);
18699
- const snapshotRef = (0, import_react18.useRef)(null);
18700
- const pentesterCommand = (0, import_react18.useCallback)((input2, timeoutMs) => {
18774
+ const [tab, setTab] = (0, import_react19.useState)("overview");
18775
+ const [dataState, setDataState] = (0, import_react19.useState)({ kind: "initial" });
18776
+ const [requestState, setRequestState] = (0, import_react19.useState)("idle");
18777
+ const [navFocus, setNavFocus] = (0, import_react19.useState)({});
18778
+ const [activeTargetId, setActiveTargetId] = (0, import_react19.useState)(null);
18779
+ const requestSeqRef = (0, import_react19.useRef)(0);
18780
+ const pendingRef = (0, import_react19.useRef)(null);
18781
+ const mountedRef = (0, import_react19.useRef)(true);
18782
+ const firstLoadDone = (0, import_react19.useRef)(false);
18783
+ const pollingPausedRef = (0, import_react19.useRef)(false);
18784
+ const backoffRef = (0, import_react19.useRef)(0);
18785
+ const timerRef = (0, import_react19.useRef)(null);
18786
+ const snapshotRef = (0, import_react19.useRef)(null);
18787
+ const pentesterCommand = (0, import_react19.useCallback)((input2, timeoutMs) => {
18701
18788
  const currentFace = reflect?.get("remote.pentesterView");
18702
18789
  return pentesterViewCommand(currentFace, input2, timeoutMs);
18703
18790
  }, [reflect]);
18704
18791
  const snapshot = dataState.kind === "bound" ? dataState.snapshot : null;
18705
18792
  const delegations = snapshot?.delegations ?? [];
18706
18793
  const liveActivity = useDelegationActivity(sessions, sessionId, delegations);
18707
- const loadSnapshot = (0, import_react18.useCallback)(async (reason) => {
18794
+ const loadSnapshot = (0, import_react19.useCallback)(async (reason) => {
18708
18795
  if (reason !== "retry" && reason !== "refresh" && getPentesterEndpointState() === "missing") {
18709
18796
  if (isPerf) console.log(`${RPC_PREFIX} circuit-open endpoint=missing reason=${reason}`);
18710
18797
  return;
@@ -18822,7 +18909,7 @@ Client: ${mismatch.client}`,
18822
18909
  }
18823
18910
  }
18824
18911
  }, [pentesterCommand, sessionId, switchTime]);
18825
- (0, import_react18.useEffect)(() => {
18912
+ (0, import_react19.useEffect)(() => {
18826
18913
  mountedRef.current = true;
18827
18914
  pollingPausedRef.current = false;
18828
18915
  backoffRef.current = 0;
@@ -18850,7 +18937,7 @@ Client: ${mismatch.client}`,
18850
18937
  if (timerRef.current !== null) clearTimeout(timerRef.current);
18851
18938
  };
18852
18939
  }, [loadSnapshot]);
18853
- (0, import_react18.useEffect)(() => {
18940
+ (0, import_react19.useEffect)(() => {
18854
18941
  const onVisible = () => {
18855
18942
  if (document.visibilityState === "visible" && mountedRef.current && firstLoadDone.current && !pollingPausedRef.current) {
18856
18943
  loadSnapshot("visible");
@@ -18859,11 +18946,11 @@ Client: ${mismatch.client}`,
18859
18946
  document.addEventListener("visibilitychange", onVisible);
18860
18947
  return () => document.removeEventListener("visibilitychange", onVisible);
18861
18948
  }, [loadSnapshot]);
18862
- const navigate = (0, import_react18.useCallback)((targetTab, focus) => {
18949
+ const navigate = (0, import_react19.useCallback)((targetTab, focus) => {
18863
18950
  setTab(targetTab);
18864
18951
  if (focus !== void 0) setNavFocus(focus);
18865
18952
  }, []);
18866
- const openSession = (0, import_react18.useCallback)((id) => {
18953
+ const openSession = (0, import_react19.useCallback)((id) => {
18867
18954
  sessions?.open(id);
18868
18955
  }, [sessions]);
18869
18956
  const isInitialLoading = dataState.kind === "initial" && requestState === "pending";
@@ -18871,7 +18958,7 @@ Client: ${mismatch.client}`,
18871
18958
  const errorMsg = dataState.kind === "error" ? dataState.error : null;
18872
18959
  const errorCode = dataState.kind === "error" ? dataState.code : null;
18873
18960
  const hasSnapshot = snapshot !== null;
18874
- return import_react18.default.createElement(
18961
+ return import_react19.default.createElement(
18875
18962
  "div",
18876
18963
  {
18877
18964
  "data-testid": "pentester-view",
@@ -18887,7 +18974,7 @@ Client: ${mismatch.client}`,
18887
18974
  }
18888
18975
  },
18889
18976
  // ── Layer 1: TabsBar (sticky) ────────────────────────────────────────
18890
- import_react18.default.createElement(
18977
+ import_react19.default.createElement(
18891
18978
  "div",
18892
18979
  {
18893
18980
  "data-testid": "pentester-tabs-bar",
@@ -18901,7 +18988,7 @@ Client: ${mismatch.client}`,
18901
18988
  boxSizing: "border-box"
18902
18989
  }
18903
18990
  },
18904
- import_react18.default.createElement(PentesterTabBar, {
18991
+ import_react19.default.createElement(PentesterTabBar, {
18905
18992
  items: PENTESTER_TABS.map((t) => ({
18906
18993
  id: t.id,
18907
18994
  label: t.id.charAt(0).toUpperCase() + t.id.slice(1)
@@ -18912,7 +18999,7 @@ Client: ${mismatch.client}`,
18912
18999
  ),
18913
19000
  // ── Refresh error banner ──────────────────────────────────────────────
18914
19001
  // Stale-while-revalidate: error + last good snapshot → show banner
18915
- errorMsg !== null && hasSnapshot && import_react18.default.createElement(
19002
+ errorMsg !== null && hasSnapshot && import_react19.default.createElement(
18916
19003
  "div",
18917
19004
  {
18918
19005
  style: {
@@ -18926,8 +19013,8 @@ Client: ${mismatch.client}`,
18926
19013
  alignItems: "center"
18927
19014
  }
18928
19015
  },
18929
- import_react18.default.createElement("span", null, errorMsg),
18930
- import_react18.default.createElement("button", {
19016
+ import_react19.default.createElement("span", null, errorMsg),
19017
+ import_react19.default.createElement("button", {
18931
19018
  onClick: () => {
18932
19019
  if (pendingRef.current === null) {
18933
19020
  void loadSnapshot("retry");
@@ -18948,7 +19035,7 @@ Client: ${mismatch.client}`,
18948
19035
  }, isRetrying ? "Retrying\u2026" : "Retry")
18949
19036
  ),
18950
19037
  // ── Body: bounded flex viewport ────────────────────────────────────
18951
- import_react18.default.createElement(
19038
+ import_react19.default.createElement(
18952
19039
  "div",
18953
19040
  {
18954
19041
  style: {
@@ -18962,17 +19049,17 @@ Client: ${mismatch.client}`,
18962
19049
  }
18963
19050
  },
18964
19051
  // Initial loading: shell is already visible, show skeleton
18965
- isInitialLoading && import_react18.default.createElement("div", {
19052
+ isInitialLoading && import_react19.default.createElement("div", {
18966
19053
  style: { padding: "24px", color: "var(--dsw-alias-label-tertiary)", fontSize: "14px" }
18967
19054
  }, "Loading..."),
18968
19055
  // Error state (no last good snapshot)
18969
- dataState.kind === "error" && !hasSnapshot && import_react18.default.createElement(
19056
+ dataState.kind === "error" && !hasSnapshot && import_react19.default.createElement(
18970
19057
  "div",
18971
19058
  { style: { padding: "24px" } },
18972
- import_react18.default.createElement("div", {
19059
+ import_react19.default.createElement("div", {
18973
19060
  style: { color: "var(--dsw-status-error)", marginBottom: "12px", fontSize: "14px" }
18974
19061
  }, errorMsg ?? "Unknown error"),
18975
- import_react18.default.createElement("button", {
19062
+ import_react19.default.createElement("button", {
18976
19063
  onClick: () => {
18977
19064
  if (pendingRef.current === null) {
18978
19065
  void loadSnapshot("retry");
@@ -18992,20 +19079,20 @@ Client: ${mismatch.client}`,
18992
19079
  }, isRetrying ? "Retrying\u2026" : "Retry")
18993
19080
  ),
18994
19081
  // Unbound state
18995
- dataState.kind === "unbound" && import_react18.default.createElement(
19082
+ dataState.kind === "unbound" && import_react19.default.createElement(
18996
19083
  "div",
18997
19084
  { style: { padding: "24px" } },
18998
- import_react18.default.createElement("div", {
19085
+ import_react19.default.createElement("div", {
18999
19086
  style: { fontSize: "14px", color: "var(--dsw-alias-label-tertiary)", marginBottom: "16px" }
19000
19087
  }, "This session is not bound to a pentest target."),
19001
- dataState.targets.length > 0 && import_react18.default.createElement(
19088
+ dataState.targets.length > 0 && import_react19.default.createElement(
19002
19089
  "div",
19003
19090
  { style: { marginBottom: "12px" } },
19004
- import_react18.default.createElement("div", {
19091
+ import_react19.default.createElement("div", {
19005
19092
  style: { fontSize: "13px", fontWeight: 600, marginBottom: "8px", color: "var(--dsw-alias-label-primary)" }
19006
19093
  }, "Existing targets"),
19007
19094
  ...dataState.targets.map(
19008
- (t) => import_react18.default.createElement(
19095
+ (t) => import_react19.default.createElement(
19009
19096
  "div",
19010
19097
  {
19011
19098
  key: t.id,
@@ -19020,17 +19107,17 @@ Client: ${mismatch.client}`,
19020
19107
  fontSize: "13px"
19021
19108
  }
19022
19109
  },
19023
- import_react18.default.createElement(
19110
+ import_react19.default.createElement(
19024
19111
  "div",
19025
19112
  null,
19026
- import_react18.default.createElement("div", { style: { fontWeight: 500 } }, t.target),
19027
- import_react18.default.createElement(
19113
+ import_react19.default.createElement("div", { style: { fontWeight: 500 } }, t.target),
19114
+ import_react19.default.createElement(
19028
19115
  "div",
19029
19116
  { style: { color: "var(--dsw-alias-label-tertiary)", fontSize: "12px" } },
19030
19117
  `${t.currentStage ?? "unknown"} \xB7 ${t.status}`
19031
19118
  )
19032
19119
  ),
19033
- t.rootSessionId !== null && import_react18.default.createElement("button", {
19120
+ t.rootSessionId !== null && import_react19.default.createElement("button", {
19034
19121
  onClick: () => sessions?.open(t.rootSessionId),
19035
19122
  style: {
19036
19123
  padding: "4px 12px",
@@ -19045,7 +19132,7 @@ Client: ${mismatch.client}`,
19045
19132
  )
19046
19133
  )
19047
19134
  ),
19048
- import_react18.default.createElement("button", {
19135
+ import_react19.default.createElement("button", {
19049
19136
  onClick: () => {
19050
19137
  if (pendingRef.current === null) {
19051
19138
  void loadSnapshot("refresh");
@@ -19066,7 +19153,7 @@ Client: ${mismatch.client}`,
19066
19153
  }, "Refresh")
19067
19154
  ),
19068
19155
  // Bound content — wrapped in a bounded viewport
19069
- dataState.kind === "bound" && import_react18.default.createElement(
19156
+ dataState.kind === "bound" && import_react19.default.createElement(
19070
19157
  "div",
19071
19158
  {
19072
19159
  style: {
@@ -19078,20 +19165,20 @@ Client: ${mismatch.client}`,
19078
19165
  flexDirection: "column"
19079
19166
  }
19080
19167
  },
19081
- tab === "overview" && import_react18.default.createElement(
19168
+ tab === "overview" && import_react19.default.createElement(
19082
19169
  ScrollablePage,
19083
19170
  null,
19084
- import_react18.default.createElement(OverviewView, {
19171
+ import_react19.default.createElement(OverviewView, {
19085
19172
  snapshot,
19086
19173
  liveActivity,
19087
19174
  onNavigate: navigate,
19088
19175
  onOpenSession: openSession
19089
19176
  })
19090
19177
  ),
19091
- tab === "stages" && import_react18.default.createElement(
19178
+ tab === "stages" && import_react19.default.createElement(
19092
19179
  ScrollablePage,
19093
19180
  null,
19094
- import_react18.default.createElement(StagesView, {
19181
+ import_react19.default.createElement(StagesView, {
19095
19182
  snapshot,
19096
19183
  liveActivity,
19097
19184
  onNavigate: navigate,
@@ -19099,17 +19186,17 @@ Client: ${mismatch.client}`,
19099
19186
  focusStage: navFocus.stage
19100
19187
  })
19101
19188
  ),
19102
- tab === "findings" && import_react18.default.createElement(FindingsView, {
19189
+ tab === "findings" && import_react19.default.createElement(FindingsView, {
19103
19190
  snapshot,
19104
19191
  command: pentesterCommand,
19105
19192
  sessionId,
19106
19193
  onNavigate: navigate,
19107
19194
  focusFinding: navFocus.finding
19108
19195
  }),
19109
- tab === "trace" && import_react18.default.createElement(
19196
+ tab === "trace" && import_react19.default.createElement(
19110
19197
  ScrollablePage,
19111
19198
  null,
19112
- import_react18.default.createElement(TraceView, {
19199
+ import_react19.default.createElement(TraceView, {
19113
19200
  snapshot,
19114
19201
  liveActivity,
19115
19202
  onNavigate: navigate,
@@ -19117,7 +19204,7 @@ Client: ${mismatch.client}`,
19117
19204
  activeTargetId
19118
19205
  })
19119
19206
  ),
19120
- tab === "output" && import_react18.default.createElement(OutputView, {
19207
+ tab === "output" && import_react19.default.createElement(OutputView, {
19121
19208
  snapshot,
19122
19209
  command: pentesterCommand,
19123
19210
  sessionId,
@@ -19128,7 +19215,7 @@ Client: ${mismatch.client}`,
19128
19215
  );
19129
19216
  }
19130
19217
  function ScrollablePage(props) {
19131
- return import_react18.default.createElement("div", {
19218
+ return import_react19.default.createElement("div", {
19132
19219
  style: {
19133
19220
  flex: 1,
19134
19221
  minHeight: 0,
@@ -19219,7 +19306,7 @@ var en = {
19219
19306
  };
19220
19307
 
19221
19308
  // src/build-id.ts
19222
- var BUILD_ID = "2.3.0+2a31301";
19309
+ var BUILD_ID = "2.4.0+3a85fc6";
19223
19310
 
19224
19311
  // src/ui/client/plugin.tsx
19225
19312
  var SESSION_SWITCH_PERF = "[SESSION_SWITCH_PERF]";
@@ -19319,7 +19406,7 @@ function apply(ctx) {
19319
19406
  return { command: (input2) => dockerCommand(face, input2) };
19320
19407
  }
19321
19408
  },
19322
- (props) => import_react19.default.createElement(PentesterConfigSection, { ...props })
19409
+ (props) => import_react20.default.createElement(PentesterConfigSection, { ...props })
19323
19410
  )
19324
19411
  );
19325
19412
  ctx.slots.inject("conversation.view", () => {
@@ -19366,7 +19453,7 @@ function apply(ctx) {
19366
19453
  }
19367
19454
  },
19368
19455
  (props) => {
19369
- return import_react19.default.createElement(PentesterView, {
19456
+ return import_react20.default.createElement(PentesterView, {
19370
19457
  sessionId: props.sessionId,
19371
19458
  reflect: props.reflect,
19372
19459
  sessions: props.sessions,