@openspecui/web 2.0.1 → 2.1.1

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.
Files changed (60) hide show
  1. package/dist/assets/{BufferResource-Cipj3hQ5.js → BufferResource-CSbEbiLP.js} +1 -1
  2. package/dist/assets/{CanvasRenderer-C151fKcy.js → CanvasRenderer-CvpAMPzA.js} +1 -1
  3. package/dist/assets/{Filter-BpxymkGv.js → Filter-BqwVCa6B.js} +1 -1
  4. package/dist/assets/{RenderTargetSystem-C0zk81Mh.js → RenderTargetSystem-mD_Y2dUA.js} +1 -1
  5. package/dist/assets/{WebGLRenderer-De3GrxdN.js → WebGLRenderer-DsvDwXyL.js} +1 -1
  6. package/dist/assets/{WebGPURenderer-BkpejvST.js → WebGPURenderer-YcBYXAol.js} +1 -1
  7. package/dist/assets/{browserAll-B8KqF-Xa.js → browserAll-MbWxSnea.js} +1 -1
  8. package/dist/assets/{ghostty-web-BO5ww0eG.js → ghostty-web-cM8zjOdb.js} +1 -1
  9. package/dist/assets/{index-Cj_nv8ue.js → index-B0lABsCj.js} +1 -1
  10. package/dist/assets/{index-CwA_uPvf.js → index-B1J3yPM2.js} +1 -1
  11. package/dist/assets/{index-CDX9fioY.js → index-BCMJS8eq.js} +1 -1
  12. package/dist/assets/{index-CxDip8xJ.js → index-BMKX_bGe.js} +1 -1
  13. package/dist/assets/{index-a8osabOh.js → index-BY40EQxT.js} +1 -1
  14. package/dist/assets/{index-B-vvVL83.js → index-Cq4njHD4.js} +198 -193
  15. package/dist/assets/{index-Bxm-n0do.js → index-Cr4OFm9E.js} +1 -1
  16. package/dist/assets/{index-Cv-LON1K.js → index-CskIUxS-.js} +1 -1
  17. package/dist/assets/{index-Nl7iD8Yi.js → index-D0sXMPhu.js} +1 -1
  18. package/dist/assets/index-DHeR2UYq.css +1 -0
  19. package/dist/assets/{index-DtTSWBHJ.js → index-DijRYB99.js} +1 -1
  20. package/dist/assets/{index-DzK6gT7C.js → index-DuZDcW_P.js} +1 -1
  21. package/dist/assets/{index-iROJdLzk.js → index-DyZwNTgF.js} +1 -1
  22. package/dist/assets/{index-Bp2dpDFJ.js → index-JHrsE4PU.js} +1 -1
  23. package/dist/assets/{index-DL08rl2O.js → index-KaodXPu0.js} +1 -1
  24. package/dist/assets/{index-CFAzjIVm.js → index-TGQYcfbH.js} +1 -1
  25. package/dist/assets/{index-2DXouwnE.js → index-kjHuAdn9.js} +1 -1
  26. package/dist/assets/{webworkerAll-DPcI1cDK.js → webworkerAll-BE_Ec3Rk.js} +1 -1
  27. package/dist/index.html +2 -2
  28. package/dist-ssg/client/.vite/ssr-manifest.json +231 -225
  29. package/dist-ssg/client/assets/{BufferResource-Djy-vqXo.js → BufferResource-BXAwYrfZ.js} +1 -1
  30. package/dist-ssg/client/assets/{CanvasRenderer-KFsP4iAw.js → CanvasRenderer-C-_Ei4Lx.js} +1 -1
  31. package/dist-ssg/client/assets/{Filter-3xK-3KVh.js → Filter-ClWz3L4e.js} +1 -1
  32. package/dist-ssg/client/assets/{RenderTargetSystem-BAJ5M6Aj.js → RenderTargetSystem-mkoEDW34.js} +1 -1
  33. package/dist-ssg/client/assets/{WebGLRenderer-DezzkAy6.js → WebGLRenderer-D-p2Wvph.js} +1 -1
  34. package/dist-ssg/client/assets/{WebGPURenderer-ZzdUU8jb.js → WebGPURenderer-CnUVPIau.js} +1 -1
  35. package/dist-ssg/client/assets/{browserAll-CbpHY1zT.js → browserAll-DIrSCRrR.js} +1 -1
  36. package/dist-ssg/client/assets/{index-DY7da1s-.js → index-4SYwcH9o.js} +1 -1
  37. package/dist-ssg/client/assets/{index-yIXrbgDj.js → index-9dzaV4-3.js} +1 -1
  38. package/dist-ssg/client/assets/index-Brg9wIKi.css +1 -0
  39. package/dist-ssg/client/assets/{index-DEEhv4xj.js → index-BxqwPwCo.js} +1 -1
  40. package/dist-ssg/client/assets/{index-ChvVJs5U.js → index-C3Zu70mc.js} +1 -1
  41. package/dist-ssg/client/assets/{index-DHzU_xY8.js → index-CGYcF9cy.js} +1 -1
  42. package/dist-ssg/client/assets/{index-CckipaE4.js → index-D9vFOR1x.js} +1 -1
  43. package/dist-ssg/client/assets/{index-Z0tLCpB3.js → index-DGZY9q7K.js} +1 -1
  44. package/dist-ssg/client/assets/{index-YHr5vAyz.js → index-DH_3Uwqw.js} +1 -1
  45. package/dist-ssg/client/assets/{index-BwBOsQe8.js → index-DM-IE6Il.js} +1 -1
  46. package/dist-ssg/client/assets/{index-Cmce45ci.js → index-DMf28vE-.js} +1 -1
  47. package/dist-ssg/client/assets/{index-B5xZnlc2.js → index-I6EcgPnl.js} +1 -1
  48. package/dist-ssg/client/assets/{index-D5ENxVE5.js → index-R53t0sC8.js} +1 -1
  49. package/dist-ssg/client/assets/{index-Csq0Slx9.js → index-fIJERjSL.js} +1 -1
  50. package/dist-ssg/client/assets/{index-DaL9PO7O.js → index-geNCH0rZ.js} +1 -1
  51. package/dist-ssg/client/assets/{index-C23IRugh.js → index-zKBrZAkn.js} +1 -1
  52. package/dist-ssg/client/assets/{index.ssg-CYPPqc3Y.js → index.ssg-7hLvM_9r.js} +196 -191
  53. package/dist-ssg/client/assets/{webworkerAll-Ds7nVNhd.js → webworkerAll-CysFfo0u.js} +1 -1
  54. package/dist-ssg/client/index.ssg.html +2 -2
  55. package/dist-ssg/server/entry-server.js +521 -121
  56. package/dist-ssg/ssg-cli.mjs +0 -0
  57. package/package.json +25 -20
  58. package/LICENSE +0 -21
  59. package/dist/assets/index-aWxXp1oO.css +0 -1
  60. package/dist-ssg/client/assets/index-CR6zSaLm.css +0 -1
@@ -36081,6 +36081,43 @@ function requireServer_node() {
36081
36081
  return server_node;
36082
36082
  }
36083
36083
  var server_nodeExports = requireServer_node();
36084
+ const HOSTED_VERSION_PATH_RE = /^\/versions\/[^/]+(?:\/|$)/;
36085
+ function normalizeApiBaseUrl(input) {
36086
+ const trimmed = input.trim();
36087
+ if (!trimmed) return null;
36088
+ let url;
36089
+ try {
36090
+ url = new URL(trimmed);
36091
+ } catch {
36092
+ return null;
36093
+ }
36094
+ url.hash = "";
36095
+ url.search = "";
36096
+ const pathname = url.pathname.replace(/\/+$/, "");
36097
+ url.pathname = pathname.length > 0 ? pathname : "/";
36098
+ return url.toString().replace(/\/$/, url.pathname === "/" ? "" : "");
36099
+ }
36100
+ function getSearchParam(search2, key2) {
36101
+ const value = new URLSearchParams(search2).get(key2)?.trim();
36102
+ return value ? value : null;
36103
+ }
36104
+ function isHostedVersionEntryPath(pathname) {
36105
+ return HOSTED_VERSION_PATH_RE.test(pathname);
36106
+ }
36107
+ function getHostedApiBootstrapState(locationLike) {
36108
+ const hosted = isHostedVersionEntryPath(locationLike.pathname);
36109
+ const apiBaseUrl = normalizeApiBaseUrl(getSearchParam(locationLike.search, "api") ?? "");
36110
+ const sessionId = hosted ? getSearchParam(locationLike.search, "session") : null;
36111
+ return {
36112
+ hosted,
36113
+ apiBaseUrl,
36114
+ sessionId
36115
+ };
36116
+ }
36117
+ function getHostedScopedStorageKey(baseKey, locationLike) {
36118
+ const state = getHostedApiBootstrapState(locationLike);
36119
+ return state.hosted && state.sessionId ? `hosted-session:${state.sessionId}:${baseKey}` : baseKey;
36120
+ }
36084
36121
  let staticModeDetected = null;
36085
36122
  if (typeof window !== "undefined" && window.__OPENSPEC_STATIC_MODE__ === true && true) {
36086
36123
  staticModeDetected = true;
@@ -36136,8 +36173,12 @@ const POP_ROUTES = [
36136
36173
  "/opsx-verify",
36137
36174
  "/opsx-compose"
36138
36175
  ];
36139
- const KV_KEY = "nav-layout";
36140
- const LS_KEY = "nav-layout";
36176
+ function getRemoteStorageKey() {
36177
+ return getHostedScopedStorageKey("nav-layout", window.location);
36178
+ }
36179
+ function getLocalStorageKey() {
36180
+ return getHostedScopedStorageKey("nav-layout", window.location);
36181
+ }
36141
36182
  const PERSIST_DEBOUNCE = 300;
36142
36183
  function isTabId(value) {
36143
36184
  return ALL_TABS.includes(value);
@@ -36183,6 +36224,41 @@ function parseHref(href, state) {
36183
36224
  state: toParsedHistoryState(state, key2)
36184
36225
  };
36185
36226
  }
36227
+ function normalizeBasePath(basePath) {
36228
+ const trimmed = basePath.trim();
36229
+ if (!trimmed || trimmed === "./" || trimmed === ".") return "/";
36230
+ const withLeadingSlash = trimmed.startsWith("/") ? trimmed : `/${trimmed}`;
36231
+ const normalized = withLeadingSlash.endsWith("/") ? withLeadingSlash : `${withLeadingSlash}/`;
36232
+ return normalized.replace(/\/+/g, "/");
36233
+ }
36234
+ function stripBasePath(pathname, basePath) {
36235
+ if (basePath === "/") return pathname || "/";
36236
+ if (pathname === basePath.slice(0, -1)) return "/";
36237
+ if (!pathname.startsWith(basePath)) return pathname || "/";
36238
+ const stripped = pathname.slice(basePath.length - 1);
36239
+ return stripped || "/";
36240
+ }
36241
+ function applyBasePath(pathname, basePath) {
36242
+ if (basePath === "/") return pathname || "/";
36243
+ const normalizedPath = pathname.startsWith("/") ? pathname : `/${pathname}`;
36244
+ if (normalizedPath === "/") return basePath.slice(0, -1) || "/";
36245
+ return `${basePath.slice(0, -1)}${normalizedPath}`;
36246
+ }
36247
+ function normalizeNavigationHref(href) {
36248
+ if (typeof window === "undefined") return href;
36249
+ const url = new URL(href, window.location.origin);
36250
+ const basePath = normalizeBasePath(getBasePath());
36251
+ url.pathname = stripBasePath(url.pathname, basePath);
36252
+ return `${url.pathname}${url.search}${url.hash}`;
36253
+ }
36254
+ function preserveHostedSearchParams(target, source) {
36255
+ for (const key2 of ["api", "session"]) {
36256
+ const value = source.searchParams.get(key2);
36257
+ if (value && !target.searchParams.has(key2)) {
36258
+ target.searchParams.set(key2, value);
36259
+ }
36260
+ }
36261
+ }
36186
36262
  function pathToTabId(path2) {
36187
36263
  for (const tab2 of ALL_TABS) {
36188
36264
  if (path2 === tab2 || path2.startsWith(tab2 + "/")) {
@@ -36270,6 +36346,8 @@ function normalizeState(state) {
36270
36346
  }
36271
36347
  function parseBrowserLocation(loc, layout) {
36272
36348
  const url = new URL(loc.href);
36349
+ const basePath = normalizeBasePath(getBasePath());
36350
+ url.pathname = stripBasePath(url.pathname, basePath);
36273
36351
  const rawBottomHref = url.searchParams.get("_b");
36274
36352
  const rawPopHref = url.searchParams.get("_p");
36275
36353
  url.searchParams.delete("_b");
@@ -36285,7 +36363,11 @@ function parseBrowserLocation(loc, layout) {
36285
36363
  };
36286
36364
  }
36287
36365
  function buildCanonicalUrl(state) {
36366
+ const currentUrl = new URL(window.location.href);
36288
36367
  const url = new URL(state.mainLocation.href, window.location.origin);
36368
+ const basePath = normalizeBasePath(getBasePath());
36369
+ url.pathname = applyBasePath(url.pathname, basePath);
36370
+ preserveHostedSearchParams(url, currentUrl);
36289
36371
  url.searchParams.delete("_b");
36290
36372
  url.searchParams.delete("_p");
36291
36373
  if (state.bottomTabs.length > 0) {
@@ -36312,7 +36394,7 @@ function createInitialState() {
36312
36394
  }
36313
36395
  function readLocalStorage() {
36314
36396
  try {
36315
- const raw2 = localStorage.getItem(LS_KEY);
36397
+ const raw2 = localStorage.getItem(getLocalStorageKey());
36316
36398
  if (!raw2) return null;
36317
36399
  return parsePersistedLayout(JSON.parse(raw2));
36318
36400
  } catch {
@@ -36321,7 +36403,7 @@ function readLocalStorage() {
36321
36403
  }
36322
36404
  function writeLocalStorage(layout) {
36323
36405
  try {
36324
- localStorage.setItem(LS_KEY, JSON.stringify(layout));
36406
+ localStorage.setItem(getLocalStorageKey(), JSON.stringify(layout));
36325
36407
  } catch {
36326
36408
  }
36327
36409
  }
@@ -36615,7 +36697,7 @@ class NavController {
36615
36697
  type: "NAVIGATE",
36616
36698
  sourceArea: area2,
36617
36699
  action: "PUSH",
36618
- location: parseHref(path2, state)
36700
+ location: parseHref(normalizeNavigationHref(path2), state)
36619
36701
  });
36620
36702
  }
36621
36703
  replace(area2, path2, state) {
@@ -36623,9 +36705,19 @@ class NavController {
36623
36705
  type: "NAVIGATE",
36624
36706
  sourceArea: area2,
36625
36707
  action: "REPLACE",
36626
- location: parseHref(path2, state)
36708
+ location: parseHref(normalizeNavigationHref(path2), state)
36627
36709
  });
36628
36710
  }
36711
+ createHref(area2, path2, state) {
36712
+ if (typeof window === "undefined") return path2;
36713
+ const { nextState } = this.computeTransition({
36714
+ type: "NAVIGATE",
36715
+ sourceArea: area2,
36716
+ action: "PUSH",
36717
+ location: parseHref(normalizeNavigationHref(path2), state)
36718
+ });
36719
+ return buildCanonicalUrl(nextState);
36720
+ }
36629
36721
  get mainTabs() {
36630
36722
  return this.state.mainTabs;
36631
36723
  }
@@ -36681,13 +36773,15 @@ class NavController {
36681
36773
  this.initialized = true;
36682
36774
  try {
36683
36775
  const { trpcClient: trpcClient2 } = await Promise.resolve().then(() => trpc$1);
36684
- const remote = parsePersistedLayout(await trpcClient2.kv.get.query({ key: KV_KEY }));
36776
+ const remote = parsePersistedLayout(
36777
+ await trpcClient2.kv.get.query({ key: getRemoteStorageKey() })
36778
+ );
36685
36779
  if (remote) {
36686
36780
  if (remote.updatedAt > this.state.updatedAt) {
36687
36781
  this.dispatch({ type: "APPLY_LAYOUT", layout: remote });
36688
36782
  } else if (this.state.updatedAt > remote.updatedAt) {
36689
36783
  trpcClient2.kv.set.mutate({
36690
- key: KV_KEY,
36784
+ key: getRemoteStorageKey(),
36691
36785
  value: {
36692
36786
  mainTabs: this.state.mainTabs,
36693
36787
  bottomTabs: this.state.bottomTabs,
@@ -36698,7 +36792,7 @@ class NavController {
36698
36792
  }
36699
36793
  } else if (this.state.updatedAt > 0) {
36700
36794
  trpcClient2.kv.set.mutate({
36701
- key: KV_KEY,
36795
+ key: getRemoteStorageKey(),
36702
36796
  value: {
36703
36797
  mainTabs: this.state.mainTabs,
36704
36798
  bottomTabs: this.state.bottomTabs,
@@ -36708,7 +36802,7 @@ class NavController {
36708
36802
  });
36709
36803
  }
36710
36804
  const subscription = trpcClient2.kv.subscribe.subscribe(
36711
- { key: KV_KEY },
36805
+ { key: getRemoteStorageKey() },
36712
36806
  {
36713
36807
  onData: (data2) => {
36714
36808
  const incoming = parsePersistedLayout(data2);
@@ -36740,6 +36834,15 @@ class NavController {
36740
36834
  popLocation: parsed.pop
36741
36835
  });
36742
36836
  };
36837
+ computeTransition(event) {
36838
+ const transition = reduceKernel(this.state, event);
36839
+ if (!transition.changed) {
36840
+ return { transition, nextState: this.state };
36841
+ }
36842
+ let nextState = applyBehaviorPlugins(this.state, transition.nextState, event);
36843
+ nextState = normalizeState(nextState);
36844
+ return { transition, nextState };
36845
+ }
36743
36846
  dispatch(event) {
36744
36847
  if (typeof window !== "undefined" && event.type !== "POPSTATE" && this.mainHistory == null) {
36745
36848
  const parsed = parseBrowserLocation(window.location, this.state);
@@ -36830,7 +36933,7 @@ class NavController {
36830
36933
  this.persistTimer = null;
36831
36934
  Promise.resolve().then(() => trpc$1).then(
36832
36935
  ({ trpcClient: trpcClient2 }) => trpcClient2.kv.set.mutate({
36833
- key: KV_KEY,
36936
+ key: getRemoteStorageKey(),
36834
36937
  value: {
36835
36938
  mainTabs: this.state.mainTabs,
36836
36939
  bottomTabs: this.state.bottomTabs,
@@ -36930,23 +37033,23 @@ const createLucideIcon = (iconName, iconNode) => {
36930
37033
  Component.displayName = `${iconName}`;
36931
37034
  return Component;
36932
37035
  };
36933
- const __iconNode$R = [
37036
+ const __iconNode$S = [
36934
37037
  ["rect", { width: "20", height: "5", x: "2", y: "3", rx: "1", key: "1wp1u1" }],
36935
37038
  ["path", { d: "M4 8v11a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8", key: "1s80jp" }],
36936
37039
  ["path", { d: "M10 12h4", key: "a56b0p" }]
36937
37040
  ];
36938
- const Archive = createLucideIcon("Archive", __iconNode$R);
36939
- const __iconNode$Q = [
37041
+ const Archive = createLucideIcon("Archive", __iconNode$S);
37042
+ const __iconNode$R = [
36940
37043
  ["path", { d: "m12 19-7-7 7-7", key: "1l729n" }],
36941
37044
  ["path", { d: "M19 12H5", key: "x3x0zl" }]
36942
37045
  ];
36943
- const ArrowLeft = createLucideIcon("ArrowLeft", __iconNode$Q);
36944
- const __iconNode$P = [
37046
+ const ArrowLeft = createLucideIcon("ArrowLeft", __iconNode$R);
37047
+ const __iconNode$Q = [
36945
37048
  ["path", { d: "M5 12h14", key: "1ays0h" }],
36946
37049
  ["path", { d: "m12 5 7 7-7 7", key: "xquz4c" }]
36947
37050
  ];
36948
- const ArrowRight = createLucideIcon("ArrowRight", __iconNode$P);
36949
- const __iconNode$O = [
37051
+ const ArrowRight = createLucideIcon("ArrowRight", __iconNode$Q);
37052
+ const __iconNode$P = [
36950
37053
  [
36951
37054
  "path",
36952
37055
  {
@@ -36956,68 +37059,79 @@ const __iconNode$O = [
36956
37059
  ],
36957
37060
  ["circle", { cx: "12", cy: "13", r: "3", key: "1vg3eu" }]
36958
37061
  ];
36959
- const Camera = createLucideIcon("Camera", __iconNode$O);
36960
- const __iconNode$N = [["path", { d: "M20 6 9 17l-5-5", key: "1gmf2c" }]];
36961
- const Check = createLucideIcon("Check", __iconNode$N);
36962
- const __iconNode$M = [["path", { d: "m6 9 6 6 6-6", key: "qrunsl" }]];
36963
- const ChevronDown = createLucideIcon("ChevronDown", __iconNode$M);
36964
- const __iconNode$L = [["path", { d: "m9 18 6-6-6-6", key: "mthhwq" }]];
36965
- const ChevronRight = createLucideIcon("ChevronRight", __iconNode$L);
36966
- const __iconNode$K = [
37062
+ const Camera = createLucideIcon("Camera", __iconNode$P);
37063
+ const __iconNode$O = [["path", { d: "M20 6 9 17l-5-5", key: "1gmf2c" }]];
37064
+ const Check = createLucideIcon("Check", __iconNode$O);
37065
+ const __iconNode$N = [["path", { d: "m6 9 6 6 6-6", key: "qrunsl" }]];
37066
+ const ChevronDown = createLucideIcon("ChevronDown", __iconNode$N);
37067
+ const __iconNode$M = [["path", { d: "m9 18 6-6-6-6", key: "mthhwq" }]];
37068
+ const ChevronRight = createLucideIcon("ChevronRight", __iconNode$M);
37069
+ const __iconNode$L = [
36967
37070
  ["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
36968
37071
  ["line", { x1: "12", x2: "12", y1: "8", y2: "12", key: "1pkeuh" }],
36969
37072
  ["line", { x1: "12", x2: "12.01", y1: "16", y2: "16", key: "4dfq90" }]
36970
37073
  ];
36971
- const CircleAlert = createLucideIcon("CircleAlert", __iconNode$K);
36972
- const __iconNode$J = [
37074
+ const CircleAlert = createLucideIcon("CircleAlert", __iconNode$L);
37075
+ const __iconNode$K = [
36973
37076
  ["path", { d: "M21.801 10A10 10 0 1 1 17 3.335", key: "yps3ct" }],
36974
37077
  ["path", { d: "m9 11 3 3L22 4", key: "1pflzl" }]
36975
37078
  ];
36976
- const CircleCheckBig = createLucideIcon("CircleCheckBig", __iconNode$J);
36977
- const __iconNode$I = [
37079
+ const CircleCheckBig = createLucideIcon("CircleCheckBig", __iconNode$K);
37080
+ const __iconNode$J = [
36978
37081
  ["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
36979
37082
  ["path", { d: "m9 12 2 2 4-4", key: "dzmm74" }]
36980
37083
  ];
36981
- const CircleCheck = createLucideIcon("CircleCheck", __iconNode$I);
36982
- const __iconNode$H = [
37084
+ const CircleCheck = createLucideIcon("CircleCheck", __iconNode$J);
37085
+ const __iconNode$I = [
36983
37086
  ["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
36984
37087
  ["path", { d: "m15 9-6 6", key: "1uzhvr" }],
36985
37088
  ["path", { d: "m9 9 6 6", key: "z0biqf" }]
36986
37089
  ];
36987
- const CircleX = createLucideIcon("CircleX", __iconNode$H);
36988
- const __iconNode$G = [["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }]];
36989
- const Circle$1 = createLucideIcon("Circle", __iconNode$G);
36990
- const __iconNode$F = [
37090
+ const CircleX = createLucideIcon("CircleX", __iconNode$I);
37091
+ const __iconNode$H = [["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }]];
37092
+ const Circle$1 = createLucideIcon("Circle", __iconNode$H);
37093
+ const __iconNode$G = [
36991
37094
  ["rect", { width: "14", height: "14", x: "8", y: "8", rx: "2", ry: "2", key: "17jyea" }],
36992
37095
  ["path", { d: "M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2", key: "zix9uf" }]
36993
37096
  ];
36994
- const Copy = createLucideIcon("Copy", __iconNode$F);
36995
- const __iconNode$E = [
37097
+ const Copy = createLucideIcon("Copy", __iconNode$G);
37098
+ const __iconNode$F = [
36996
37099
  ["circle", { cx: "12", cy: "12", r: "1", key: "41hilf" }],
36997
37100
  ["circle", { cx: "12", cy: "5", r: "1", key: "gxeob9" }],
36998
37101
  ["circle", { cx: "12", cy: "19", r: "1", key: "lyex9k" }]
36999
37102
  ];
37000
- const EllipsisVertical = createLucideIcon("EllipsisVertical", __iconNode$E);
37001
- const __iconNode$D = [
37103
+ const EllipsisVertical = createLucideIcon("EllipsisVertical", __iconNode$F);
37104
+ const __iconNode$E = [
37002
37105
  ["path", { d: "M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z", key: "1rqfz7" }],
37003
37106
  ["path", { d: "M14 2v4a2 2 0 0 0 2 2h4", key: "tnqrlb" }],
37004
37107
  ["path", { d: "M9 15h6", key: "cctwl0" }],
37005
37108
  ["path", { d: "M12 18v-6", key: "17g6i2" }]
37006
37109
  ];
37007
- const FilePlus = createLucideIcon("FilePlus", __iconNode$D);
37008
- const __iconNode$C = [
37110
+ const FilePlus = createLucideIcon("FilePlus", __iconNode$E);
37111
+ const __iconNode$D = [
37009
37112
  ["path", { d: "M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z", key: "1rqfz7" }],
37010
37113
  ["path", { d: "M14 2v4a2 2 0 0 0 2 2h4", key: "tnqrlb" }],
37011
37114
  ["path", { d: "M10 9H8", key: "b1mrlr" }],
37012
37115
  ["path", { d: "M16 13H8", key: "t4e002" }],
37013
37116
  ["path", { d: "M16 17H8", key: "z1uh3a" }]
37014
37117
  ];
37015
- const FileText = createLucideIcon("FileText", __iconNode$C);
37016
- const __iconNode$B = [
37118
+ const FileText = createLucideIcon("FileText", __iconNode$D);
37119
+ const __iconNode$C = [
37017
37120
  ["path", { d: "M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z", key: "1rqfz7" }],
37018
37121
  ["path", { d: "M14 2v4a2 2 0 0 0 2 2h4", key: "tnqrlb" }]
37019
37122
  ];
37020
- const File = createLucideIcon("File", __iconNode$B);
37123
+ const File = createLucideIcon("File", __iconNode$C);
37124
+ const __iconNode$B = [
37125
+ [
37126
+ "path",
37127
+ {
37128
+ d: "m6 14 1.45-2.9A2 2 0 0 1 9.24 10H20a2 2 0 0 1 1.94 2.5l-1.55 6a2 2 0 0 1-1.94 1.5H4a2 2 0 0 1-2-2V5c0-1.1.9-2 2-2h3.93a2 2 0 0 1 1.66.9l.82 1.2a2 2 0 0 0 1.66.9H18a2 2 0 0 1 2 2v2",
37129
+ key: "1nmvlm"
37130
+ }
37131
+ ],
37132
+ ["circle", { cx: "14", cy: "15", r: "1", key: "1gm4qj" }]
37133
+ ];
37134
+ const FolderOpenDot = createLucideIcon("FolderOpenDot", __iconNode$B);
37021
37135
  const __iconNode$A = [
37022
37136
  [
37023
37137
  "path",
@@ -37356,7 +37470,7 @@ const navItems = allNavItems.filter(
37356
37470
  );
37357
37471
  const mobileNavItems = allNavItems.filter((i3) => i3.to !== "/settings");
37358
37472
  const settingsItem = allNavItems.find((i3) => i3.to === "/settings");
37359
- let _draggedTabId = null;
37473
+ let _draggedTabId$1 = null;
37360
37474
  function AreaNav({ area: area2, tabs, className, useLinks, onNavigate }) {
37361
37475
  const [dragOverArea, setDragOverArea] = reactExports.useState(false);
37362
37476
  const [dropIndicator, setDropIndicator] = reactExports.useState(null);
@@ -37374,12 +37488,12 @@ function AreaNav({ area: area2, tabs, className, useLinks, onNavigate }) {
37374
37488
  );
37375
37489
  const handleDragStart = reactExports.useCallback((e2, tabId) => {
37376
37490
  if (!e2.dataTransfer) return;
37377
- _draggedTabId = tabId;
37491
+ _draggedTabId$1 = tabId;
37378
37492
  e2.dataTransfer.setData("text/plain", tabId);
37379
37493
  e2.dataTransfer.effectAllowed = "move";
37380
37494
  }, []);
37381
37495
  const handleDragEnd = reactExports.useCallback(() => {
37382
- _draggedTabId = null;
37496
+ _draggedTabId$1 = null;
37383
37497
  }, []);
37384
37498
  const handleAreaDragOver = reactExports.useCallback((e2) => {
37385
37499
  e2.preventDefault();
@@ -37400,7 +37514,7 @@ function AreaNav({ area: area2, tabs, className, useLinks, onNavigate }) {
37400
37514
  e2.preventDefault();
37401
37515
  e2.stopPropagation();
37402
37516
  e2.dataTransfer.dropEffect = "move";
37403
- if (tabs[index2] === _draggedTabId) {
37517
+ if (tabs[index2] === _draggedTabId$1) {
37404
37518
  updateIndicator(null);
37405
37519
  return;
37406
37520
  }
@@ -37419,7 +37533,7 @@ function AreaNav({ area: area2, tabs, className, useLinks, onNavigate }) {
37419
37533
  const indicator = dropIndicatorRef.current;
37420
37534
  setDragOverArea(false);
37421
37535
  updateIndicator(null);
37422
- _draggedTabId = null;
37536
+ _draggedTabId$1 = null;
37423
37537
  if (!tabId) return;
37424
37538
  const isFromThisArea = tabs.includes(tabId);
37425
37539
  const targetTab = indicator != null ? tabs[indicator.index] : void 0;
@@ -39831,18 +39945,23 @@ function createTRPCOptionsProxy(opts) {
39831
39945
  function isBrowser$1() {
39832
39946
  return typeof window !== "undefined" && typeof window.location !== "undefined";
39833
39947
  }
39948
+ function getHostedApiState() {
39949
+ if (!isBrowser$1()) {
39950
+ return {
39951
+ hosted: false,
39952
+ apiBaseUrl: null,
39953
+ sessionId: null
39954
+ };
39955
+ }
39956
+ return getHostedApiBootstrapState(window.location);
39957
+ }
39834
39958
  function getApiBaseUrl() {
39835
39959
  if (!isBrowser$1()) {
39836
39960
  return "";
39837
39961
  }
39838
- const params = new URLSearchParams(window.location.search);
39839
- const apiUrl = params.get("api");
39840
- if (apiUrl) {
39841
- return apiUrl.replace(/\/$/, "");
39842
- }
39843
- return "";
39962
+ return getHostedApiState().apiBaseUrl ?? "";
39844
39963
  }
39845
- function getWsUrl() {
39964
+ function buildWebSocketUrl(pathname) {
39846
39965
  if (!isBrowser$1()) {
39847
39966
  return "";
39848
39967
  }
@@ -39850,10 +39969,13 @@ function getWsUrl() {
39850
39969
  if (baseUrl) {
39851
39970
  const url = new URL(baseUrl);
39852
39971
  const wsProtocol = url.protocol === "https:" ? "wss:" : "ws:";
39853
- return `${wsProtocol}//${url.host}/trpc`;
39972
+ return `${wsProtocol}//${url.host}${pathname}`;
39854
39973
  }
39855
39974
  const protocol = window.location.protocol === "https:" ? "wss:" : "ws:";
39856
- return `${protocol}//${window.location.host}/trpc`;
39975
+ return `${protocol}//${window.location.host}${pathname}`;
39976
+ }
39977
+ function getWsUrl() {
39978
+ return buildWebSocketUrl("/trpc");
39857
39979
  }
39858
39980
  function getTrpcUrl() {
39859
39981
  const baseUrl = getApiBaseUrl();
@@ -47850,6 +47972,7 @@ function buildStaticGitSnapshot(snapshot) {
47850
47972
  path: repositoryUrl ?? "Repository URL unavailable",
47851
47973
  relativePath: "repo",
47852
47974
  branchName: "(snapshot)",
47975
+ detached: false,
47853
47976
  isCurrent: true,
47854
47977
  ahead: 0,
47855
47978
  behind: 0,
@@ -48130,6 +48253,7 @@ async function getConfig$1() {
48130
48253
  codeEditor: {
48131
48254
  theme: "github"
48132
48255
  },
48256
+ appBaseUrl: "",
48133
48257
  dashboard: {
48134
48258
  trendPointLimit: 100
48135
48259
  },
@@ -72333,6 +72457,7 @@ const viewerStyles = css$2`
72333
72457
  }
72334
72458
  }
72335
72459
  `;
72460
+ let _draggedTabId = null;
72336
72461
  const tabsStyle = (id2) => {
72337
72462
  const css2 = String.raw;
72338
72463
  const anchorName = `--tabs-button-${id2}`;
@@ -72356,7 +72481,11 @@ const tabsStyle = (id2) => {
72356
72481
  & > button {
72357
72482
  scroll-snap-align: start;
72358
72483
  text-align: center;
72359
- &.tab-selected {
72484
+ }
72485
+ }
72486
+ &[data-tabs-variant='default'] {
72487
+ .tabs-button {
72488
+ & > button.tab-selected {
72360
72489
  background-image: linear-gradient(
72361
72490
  to bottom,
72362
72491
  transparent,
@@ -72402,79 +72531,236 @@ const tabsStyle = (id2) => {
72402
72531
  }
72403
72532
  ` });
72404
72533
  };
72534
+ function buildReorderedTabIds(currentTabIds, draggedTabId, targetTabId, position2) {
72535
+ if (draggedTabId === targetTabId) {
72536
+ return [...currentTabIds];
72537
+ }
72538
+ const remaining = currentTabIds.filter((tabId) => tabId !== draggedTabId);
72539
+ const targetIndex = remaining.indexOf(targetTabId);
72540
+ if (targetIndex < 0) {
72541
+ return [...currentTabIds];
72542
+ }
72543
+ const insertIndex = position2 === "before" ? targetIndex : targetIndex + 1;
72544
+ remaining.splice(insertIndex, 0, draggedTabId);
72545
+ return remaining;
72546
+ }
72547
+ function buildStableContentTabIds(previousTabIds, currentTabIds) {
72548
+ const currentTabIdSet = new Set(currentTabIds);
72549
+ const retained = previousTabIds.filter((tabId) => currentTabIdSet.has(tabId));
72550
+ const additions = currentTabIds.filter((tabId) => !retained.includes(tabId));
72551
+ return [...retained, ...additions];
72552
+ }
72405
72553
  function Tabs({
72406
72554
  tabs,
72407
72555
  selectedTab: controlled,
72408
72556
  onTabChange,
72409
72557
  onTabClose,
72558
+ onTabOrderChange,
72410
72559
  actions,
72411
72560
  onTabBarDoubleClick,
72412
- className = ""
72561
+ className = "",
72562
+ variant = "default"
72413
72563
  }) {
72414
72564
  const [uncontrolled, setUncontrolled] = reactExports.useState(tabs[0]?.id ?? "");
72565
+ const [dropIndicator, setDropIndicator] = reactExports.useState(null);
72566
+ const dropIndicatorRef = reactExports.useRef(null);
72567
+ const contentOrderRef = reactExports.useRef(tabs.map((tab2) => tab2.id));
72415
72568
  const activeTab = controlled ?? uncontrolled;
72569
+ const reorderable = typeof onTabOrderChange === "function" && tabs.length > 1;
72570
+ const tabIds = tabs.map((tab2) => tab2.id);
72571
+ const tabsById = reactExports.useMemo(() => new Map(tabs.map((tab2) => [tab2.id, tab2])), [tabs]);
72572
+ const contentTabIds = reactExports.useMemo(() => {
72573
+ const nextOrder = buildStableContentTabIds(contentOrderRef.current, tabIds);
72574
+ contentOrderRef.current = nextOrder;
72575
+ return nextOrder;
72576
+ }, [tabIds]);
72577
+ const contentTabs = contentTabIds.map((tabId) => tabsById.get(tabId)).filter((tab2) => tab2 !== void 0);
72578
+ const id2 = reactExports.useId();
72579
+ const style = reactExports.useMemo(() => tabsStyle(id2), [id2]);
72416
72580
  const handleChange = (id22) => {
72417
72581
  if (!controlled) {
72418
72582
  setUncontrolled(id22);
72419
72583
  }
72420
72584
  onTabChange?.(id22);
72421
72585
  };
72586
+ const updateIndicator = reactExports.useCallback((indicator) => {
72587
+ dropIndicatorRef.current = indicator;
72588
+ setDropIndicator(indicator);
72589
+ }, []);
72590
+ const resetDragState = reactExports.useCallback(() => {
72591
+ _draggedTabId = null;
72592
+ updateIndicator(null);
72593
+ }, [updateIndicator]);
72594
+ const commitReorder = reactExports.useCallback(
72595
+ (targetTabId, position2) => {
72596
+ if (!reorderable || !_draggedTabId) {
72597
+ return;
72598
+ }
72599
+ const nextTabIds = buildReorderedTabIds(tabIds, _draggedTabId, targetTabId, position2);
72600
+ const changed = nextTabIds.some((tabId, index2) => tabId !== tabIds[index2]);
72601
+ if (changed) {
72602
+ onTabOrderChange?.(nextTabIds);
72603
+ }
72604
+ },
72605
+ [onTabOrderChange, reorderable, tabIds]
72606
+ );
72607
+ const handleDragStart = reactExports.useCallback(
72608
+ (event, tabId) => {
72609
+ if (!reorderable || !event.dataTransfer) {
72610
+ return;
72611
+ }
72612
+ _draggedTabId = tabId;
72613
+ event.dataTransfer.setData("text/plain", tabId);
72614
+ event.dataTransfer.effectAllowed = "move";
72615
+ },
72616
+ [reorderable]
72617
+ );
72618
+ const handleDragEnd = reactExports.useCallback(() => {
72619
+ resetDragState();
72620
+ }, [resetDragState]);
72621
+ const handleItemDragOver = reactExports.useCallback(
72622
+ (event, tabId) => {
72623
+ if (!reorderable || !_draggedTabId) {
72624
+ return;
72625
+ }
72626
+ event.preventDefault();
72627
+ event.stopPropagation();
72628
+ event.dataTransfer.dropEffect = "move";
72629
+ if (tabId === _draggedTabId) {
72630
+ updateIndicator(null);
72631
+ return;
72632
+ }
72633
+ const rect = event.currentTarget.getBoundingClientRect();
72634
+ const midX = rect.left + rect.width / 2;
72635
+ const position2 = event.clientX < midX ? "before" : "after";
72636
+ updateIndicator({ tabId, position: position2 });
72637
+ },
72638
+ [reorderable, updateIndicator]
72639
+ );
72640
+ const handleItemDrop = reactExports.useCallback(
72641
+ (event, tabId) => {
72642
+ if (!reorderable) {
72643
+ return;
72644
+ }
72645
+ event.preventDefault();
72646
+ event.stopPropagation();
72647
+ const indicator = dropIndicatorRef.current;
72648
+ commitReorder(tabId, indicator?.tabId === tabId ? indicator.position : "after");
72649
+ resetDragState();
72650
+ },
72651
+ [commitReorder, reorderable, resetDragState]
72652
+ );
72653
+ const handleListDrop = reactExports.useCallback(
72654
+ (event) => {
72655
+ if (!reorderable) {
72656
+ return;
72657
+ }
72658
+ event.preventDefault();
72659
+ if (_draggedTabId && dropIndicatorRef.current === null) {
72660
+ const remaining = tabIds.filter((tabId) => tabId !== _draggedTabId);
72661
+ remaining.push(_draggedTabId);
72662
+ const changed = remaining.some((tabId, index2) => tabId !== tabIds[index2]);
72663
+ if (changed) {
72664
+ onTabOrderChange?.(remaining);
72665
+ }
72666
+ }
72667
+ resetDragState();
72668
+ },
72669
+ [onTabOrderChange, reorderable, resetDragState, tabIds]
72670
+ );
72671
+ const handleListDragOver = reactExports.useCallback(
72672
+ (event) => {
72673
+ if (!reorderable || !_draggedTabId) {
72674
+ return;
72675
+ }
72676
+ event.preventDefault();
72677
+ event.dataTransfer.dropEffect = "move";
72678
+ },
72679
+ [reorderable]
72680
+ );
72422
72681
  if (tabs.length === 0) return null;
72423
- const id2 = reactExports.useId();
72424
- const style = reactExports.useMemo(() => tabsStyle(id2), [id2]);
72425
- const handleTabBarDoubleClick = (e2) => {
72682
+ const headerClassName = variant === "terminal" ? "tabs-header z-2 bg-terminal text-terminal-foreground sticky top-0 flex min-w-0 items-stretch" : "tabs-header z-2 bg-background sticky top-0 flex min-w-0 items-stretch";
72683
+ const stripClassName = variant === "terminal" ? "tabs-strip min-w-0 flex-1 bg-terminal px-4" : "tabs-strip min-w-0 flex-1 px-4";
72684
+ const listClassName = variant === "terminal" ? "tabs-button scrollbar-none flex min-w-0 gap-1 overflow-x-auto pt-2" : "tabs-button scrollbar-none flex min-w-0 gap-1 overflow-x-auto";
72685
+ const buttonBaseClassName = `group relative m-0 flex h-full shrink-0 items-center gap-2 px-2 text-sm font-medium transition-colors ${variant === "terminal" ? "rounded-t-[8px] py-1" : "py-2"}`;
72686
+ const activeButtonClassName = variant === "terminal" ? "tab-selected bg-background text-foreground" : "tab-selected text-foreground";
72687
+ const inactiveButtonClassName = variant === "terminal" ? "bg-terminal text-terminal-foreground/80 hover:bg-terminal hover:text-terminal-foreground" : "text-muted-foreground hover:text-foreground";
72688
+ const actionsClassName = variant === "terminal" ? "tabs-actions border-border bg-terminal text-terminal-foreground flex shrink-0 items-center border-b px-1" : "tabs-actions border-border bg-background flex shrink-0 items-center border-b px-1";
72689
+ const handleTabBarDoubleClick = (event) => {
72426
72690
  if (!onTabBarDoubleClick) return;
72427
- if (e2.target.closest('[data-tab-item="true"]')) return;
72691
+ if (event.target.closest('[data-tab-item="true"]')) return;
72428
72692
  onTabBarDoubleClick();
72429
72693
  };
72430
- return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { id: id2, className: `flex min-h-0 min-w-0 flex-1 flex-col ${className}`, children: [
72431
- style,
72432
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "z-2 bg-background sticky top-0 flex min-w-0 items-stretch", children: [
72433
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "tabs-strip min-w-0 flex-1 px-4", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
72434
- "div",
72435
- {
72436
- className: "tabs-button scrollbar-none flex min-w-0 gap-1 overflow-x-auto",
72437
- onDoubleClick: handleTabBarDoubleClick,
72438
- children: tabs.map((tab2) => /* @__PURE__ */ jsxRuntimeExports.jsxs(
72439
- "button",
72694
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(
72695
+ "div",
72696
+ {
72697
+ id: id2,
72698
+ "data-tabs-variant": variant,
72699
+ className: `flex min-h-0 min-w-0 flex-1 flex-col ${className}`,
72700
+ children: [
72701
+ style,
72702
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: headerClassName, children: [
72703
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: stripClassName, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
72704
+ "div",
72440
72705
  {
72441
- "data-tab-item": "true",
72442
- onClick: () => handleChange(tab2.id),
72443
- className: `m-0 flex h-full shrink-0 items-center gap-2 px-2 py-2 text-sm font-medium transition-colors ${activeTab === tab2.id ? "tab-selected text-foreground" : "text-muted-foreground hover:text-foreground"}`,
72444
- children: [
72445
- tab2.icon,
72446
- tab2.label,
72447
- tab2.closable && onTabClose && /* @__PURE__ */ jsxRuntimeExports.jsx(
72448
- "span",
72706
+ className: listClassName,
72707
+ onDoubleClick: handleTabBarDoubleClick,
72708
+ onDragOver: handleListDragOver,
72709
+ onDrop: handleListDrop,
72710
+ children: tabs.map((tab2) => {
72711
+ const dragIndicatorStyle = dropIndicator?.tabId === tab2.id ? {
72712
+ boxShadow: dropIndicator.position === "before" ? "inset 2px 0 0 var(--border)" : "inset -2px 0 0 var(--border)"
72713
+ } : void 0;
72714
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(
72715
+ "button",
72449
72716
  {
72450
- role: "button",
72451
- tabIndex: 0,
72452
- onClick: (e2) => {
72453
- e2.stopPropagation();
72454
- onTabClose(tab2.id);
72455
- },
72456
- onKeyDown: (e2) => {
72457
- if (e2.key === "Enter" || e2.key === " ") {
72458
- e2.stopPropagation();
72459
- onTabClose(tab2.id);
72460
- }
72461
- },
72462
- className: `text-muted-foreground hover:text-foreground -mr-1 rounded p-0.5 transition ${tab2.closeButtonVisibility === "always" ? "opacity-100" : "opacity-0 group-hover:opacity-100 [button:hover>&]:opacity-100"}`,
72463
- children: /* @__PURE__ */ jsxRuntimeExports.jsx(X$2, { className: "h-3 w-3" })
72464
- }
72465
- )
72466
- ]
72467
- },
72468
- tab2.id
72469
- ))
72470
- }
72471
- ) }),
72472
- actions && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "border-border bg-background flex shrink-0 items-center border-b px-1", children: actions })
72473
- ] }),
72474
- tabs.map(
72475
- (tab2) => tab2.unmountOnHide ? activeTab === tab2.id && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex min-h-0 flex-1 flex-col", children: tab2.content }, tab2.id) : /* @__PURE__ */ jsxRuntimeExports.jsx(reactExports.Activity, { mode: activeTab === tab2.id ? "visible" : "hidden", children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex min-h-0 flex-1 flex-col", children: tab2.content }) }, tab2.id)
72476
- )
72477
- ] });
72717
+ "data-tab-item": "true",
72718
+ draggable: reorderable,
72719
+ onClick: () => handleChange(tab2.id),
72720
+ onDragStart: (event) => handleDragStart(event, tab2.id),
72721
+ onDragEnd: handleDragEnd,
72722
+ onDragOver: (event) => handleItemDragOver(event, tab2.id),
72723
+ onDrop: (event) => handleItemDrop(event, tab2.id),
72724
+ className: `${buttonBaseClassName} ${activeTab === tab2.id ? activeButtonClassName : inactiveButtonClassName} ${reorderable ? "cursor-grab active:cursor-grabbing" : ""}`,
72725
+ style: dragIndicatorStyle,
72726
+ children: [
72727
+ tab2.icon,
72728
+ tab2.label,
72729
+ tab2.closable && onTabClose && /* @__PURE__ */ jsxRuntimeExports.jsx(
72730
+ "span",
72731
+ {
72732
+ role: "button",
72733
+ tabIndex: 0,
72734
+ onClick: (event) => {
72735
+ event.stopPropagation();
72736
+ onTabClose(tab2.id);
72737
+ },
72738
+ onKeyDown: (event) => {
72739
+ if (event.key === "Enter" || event.key === " ") {
72740
+ event.stopPropagation();
72741
+ onTabClose(tab2.id);
72742
+ }
72743
+ },
72744
+ draggable: false,
72745
+ className: `hover:text-foreground -mr-1 rounded p-0.5 transition ${tab2.closeButtonVisibility === "always" ? "opacity-100" : "opacity-0 group-hover:opacity-100 [button:hover>&]:opacity-100"} ${activeTab === tab2.id ? "text-current/80" : "text-muted-foreground"}`,
72746
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(X$2, { className: "h-3 w-3" })
72747
+ }
72748
+ )
72749
+ ]
72750
+ },
72751
+ tab2.id
72752
+ );
72753
+ })
72754
+ }
72755
+ ) }),
72756
+ actions && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { "data-tabs-actions": "true", className: actionsClassName, children: actions })
72757
+ ] }),
72758
+ contentTabs.map(
72759
+ (tab2) => tab2.unmountOnHide ? activeTab === tab2.id && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex min-h-0 flex-1 flex-col", children: tab2.content }, tab2.id) : /* @__PURE__ */ jsxRuntimeExports.jsx(reactExports.Activity, { mode: activeTab === tab2.id ? "visible" : "hidden", children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex min-h-0 flex-1 flex-col", children: tab2.content }) }, tab2.id)
72760
+ )
72761
+ ]
72762
+ }
72763
+ );
72478
72764
  }
72479
72765
  function operationBadgeClass(operation) {
72480
72766
  switch (operation) {
@@ -111812,14 +112098,17 @@ function ButtonGroup({
111812
112098
  value,
111813
112099
  options,
111814
112100
  onChange,
111815
- className = ""
112101
+ className = "",
112102
+ tone = "default"
111816
112103
  }) {
112104
+ const containerClassName = tone === "terminal" ? "border-terminal-foreground/25 bg-terminal/70 text-terminal-foreground" : "border-border bg-card";
111817
112105
  return /* @__PURE__ */ jsxRuntimeExports.jsx(
111818
112106
  "div",
111819
112107
  {
111820
- className: `border-border bg-card inline-flex overflow-hidden rounded-md border ${className}`,
112108
+ className: `inline-flex overflow-hidden rounded-md border ${containerClassName} ${className}`,
111821
112109
  children: options.map((option2, index2) => {
111822
112110
  const active = option2.value === value;
112111
+ const stateClassName = active ? "bg-primary text-primary-foreground" : tone === "terminal" ? "text-terminal-foreground/72 hover:bg-terminal-foreground/10 hover:text-terminal-foreground" : "text-muted-foreground hover:bg-muted/60 hover:text-foreground";
111823
112112
  return /* @__PURE__ */ jsxRuntimeExports.jsx(
111824
112113
  "button",
111825
112114
  {
@@ -111827,7 +112116,7 @@ function ButtonGroup({
111827
112116
  disabled: option2.disabled,
111828
112117
  onClick: () => onChange(option2.value),
111829
112118
  "aria-pressed": active,
111830
- className: `px-3 py-1.5 text-xs font-medium transition-colors disabled:cursor-not-allowed disabled:opacity-50 ${index2 > 0 ? "border-border border-l" : ""} ${active ? "bg-primary text-primary-foreground" : "text-muted-foreground hover:bg-muted/60 hover:text-foreground"}`,
112119
+ className: `px-3 py-1.5 text-xs font-medium transition-colors disabled:cursor-not-allowed disabled:opacity-50 ${index2 > 0 ? tone === "terminal" ? "border-terminal-foreground/20 border-l" : "border-border border-l" : ""} ${stateClassName}`,
111831
112120
  children: option2.label
111832
112121
  },
111833
112122
  option2.value
@@ -152005,6 +152294,10 @@ async function refreshDashboardGitSnapshot(reason) {
152005
152294
  if (isStaticMode()) return;
152006
152295
  await trpcClient.dashboard.refreshGitSnapshot.mutate({ reason });
152007
152296
  }
152297
+ async function removeDetachedDashboardWorktree(path2) {
152298
+ if (isStaticMode()) return;
152299
+ await trpcClient.dashboard.removeDetachedWorktree.mutate({ path: path2 });
152300
+ }
152008
152301
  const SPEC_DRIVEN_ORDER = ["proposal", "design", "specs", "tasks"];
152009
152302
  const GIT_WORKTREE_BORDER_CLASS = "border-zinc-400/50";
152010
152303
  const GIT_WORKTREE_BG_CLASS = "bg-zinc-500/8";
@@ -152043,6 +152336,9 @@ function formatArtifactLabel(id2) {
152043
152336
  function isHttpUrl(value) {
152044
152337
  return /^https?:\/\//.test(value);
152045
152338
  }
152339
+ async function copyText(value) {
152340
+ await navigator.clipboard.writeText(value);
152341
+ }
152046
152342
  function sortArtifactIdsForSchema(schemaName, artifactIds) {
152047
152343
  if (schemaName !== "spec-driven") return artifactIds;
152048
152344
  const rank = /* @__PURE__ */ new Map();
@@ -152183,6 +152479,31 @@ function Dashboard() {
152183
152479
  }
152184
152480
  }, []);
152185
152481
  const focusRefreshAtRef = reactExports.useRef(0);
152482
+ const [removingWorktreePath, setRemovingWorktreePath] = reactExports.useState(null);
152483
+ const handleRemoveDetachedWorktree = reactExports.useCallback(async (worktree) => {
152484
+ if (isStaticMode() || worktree.isCurrent || !worktree.detached || isHttpUrl(worktree.path)) {
152485
+ return;
152486
+ }
152487
+ const confirmed = window.confirm(
152488
+ [
152489
+ "Remove detached worktree?",
152490
+ "",
152491
+ worktree.path,
152492
+ "",
152493
+ "This runs git worktree remove --force."
152494
+ ].join("\n")
152495
+ );
152496
+ if (!confirmed) return;
152497
+ setRemovingWorktreePath(worktree.path);
152498
+ try {
152499
+ await removeDetachedDashboardWorktree(worktree.path);
152500
+ } catch (error2) {
152501
+ console.error("[Dashboard] Failed to remove detached worktree:", error2);
152502
+ window.alert(error2 instanceof Error ? error2.message : "Failed to remove detached worktree.");
152503
+ } finally {
152504
+ setRemovingWorktreePath((current) => current === worktree.path ? null : current);
152505
+ }
152506
+ }, []);
152186
152507
  reactExports.useEffect(() => {
152187
152508
  if (isStaticMode()) return;
152188
152509
  const triggerOnce = (reason) => {
@@ -152407,7 +152728,15 @@ function Dashboard() {
152407
152728
  ] })
152408
152729
  ] }),
152409
152730
  currentWorktree ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-0", children: [
152410
- /* @__PURE__ */ jsxRuntimeExports.jsx(WorktreeRow, { worktree: currentWorktree, emphasize: true }),
152731
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
152732
+ WorktreeRow,
152733
+ {
152734
+ worktree: currentWorktree,
152735
+ emphasize: true,
152736
+ removing: removingWorktreePath === currentWorktree.path,
152737
+ onRemoveDetachedWorktree: handleRemoveDetachedWorktree
152738
+ }
152739
+ ),
152411
152740
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: `-mt-px space-y-1 border-l pl-3 pt-2 ${GIT_WORKTREE_LINE_CLASS}`, children: currentWorktree.entries.map((entry) => /* @__PURE__ */ jsxRuntimeExports.jsx(
152412
152741
  GitEntryRow,
152413
152742
  {
@@ -152418,7 +152747,16 @@ function Dashboard() {
152418
152747
  ] }) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-muted-foreground rounded-md border border-dashed px-2.5 py-2 text-xs", children: "No worktree snapshot available." }),
152419
152748
  otherWorktrees.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "border-border/70 mt-3 space-y-1 border-t pt-2", children: [
152420
152749
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-muted-foreground text-xs uppercase tracking-wide", children: "Other Worktrees" }),
152421
- otherWorktrees.map((worktree) => /* @__PURE__ */ jsxRuntimeExports.jsx(WorktreeRow, { worktree, emphasize: false }, worktree.path))
152750
+ otherWorktrees.map((worktree) => /* @__PURE__ */ jsxRuntimeExports.jsx(
152751
+ WorktreeRow,
152752
+ {
152753
+ worktree,
152754
+ emphasize: false,
152755
+ removing: removingWorktreePath === worktree.path,
152756
+ onRemoveDetachedWorktree: handleRemoveDetachedWorktree
152757
+ },
152758
+ worktree.path
152759
+ ))
152422
152760
  ] })
152423
152761
  ] })
152424
152762
  ] }) : null
@@ -152595,22 +152933,84 @@ function Dashboard() {
152595
152933
  }
152596
152934
  function WorktreeRow({
152597
152935
  worktree,
152598
- emphasize
152936
+ emphasize,
152937
+ removing = false,
152938
+ onRemoveDetachedWorktree
152599
152939
  }) {
152600
- const pathLabel = isHttpUrl(worktree.path) ? worktree.path : `${worktree.relativePath} | ${worktree.path}`;
152940
+ const isRemotePath = isHttpUrl(worktree.path);
152941
+ const canToggleRelativePath = !isRemotePath;
152942
+ const canRemoveDetached = !isRemotePath && worktree.detached && !worktree.isCurrent;
152943
+ const [showRelativePath, setShowRelativePath] = reactExports.useState(false);
152944
+ const [copied, setCopied] = reactExports.useState(false);
152945
+ const displayPath = isRemotePath ? worktree.path : showRelativePath ? worktree.relativePath : worktree.path;
152946
+ const handleCopyPath = reactExports.useCallback(async () => {
152947
+ try {
152948
+ await copyText(displayPath);
152949
+ setCopied(true);
152950
+ window.setTimeout(() => setCopied(false), 1200);
152951
+ } catch (error) {
152952
+ console.error("[Dashboard] Failed to copy worktree path:", error);
152953
+ }
152954
+ }, [displayPath]);
152601
152955
  return /* @__PURE__ */ jsxRuntimeExports.jsx(
152602
152956
  "div",
152603
152957
  {
152604
152958
  className: `min-w-0 rounded-e-md rounded-t-md border px-2.5 py-2 ${emphasize ? `${GIT_WORKTREE_BORDER_CLASS} ${GIT_WORKTREE_BG_CLASS}` : "border-border/70 bg-muted/15"}`,
152605
152959
  children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-start justify-between gap-2", children: [
152606
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "min-w-0", children: [
152960
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "min-w-0 flex-1", children: [
152607
152961
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1.5 text-sm font-medium", children: [
152608
- /* @__PURE__ */ jsxRuntimeExports.jsx(GitBranch, { className: "h-3.5 w-3.5" }),
152962
+ /* @__PURE__ */ jsxRuntimeExports.jsx(GitBranch, { className: "h-3.5 w-3.5 shrink-0" }),
152609
152963
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "truncate", children: worktree.branchName })
152610
152964
  ] }),
152611
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-muted-foreground truncate text-xs", children: pathLabel })
152965
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-0.5 flex min-w-0 items-center gap-1", children: [
152966
+ canToggleRelativePath ? /* @__PURE__ */ jsxRuntimeExports.jsx(
152967
+ "button",
152968
+ {
152969
+ type: "button",
152970
+ onClick: () => setShowRelativePath((current) => !current),
152971
+ className: "text-muted-foreground hover:text-foreground inline-flex h-5 w-5 shrink-0 items-center justify-center rounded border border-transparent",
152972
+ title: showRelativePath ? "Show absolute path" : "Show relative path",
152973
+ "aria-label": showRelativePath ? "Show absolute path" : "Show relative path",
152974
+ children: showRelativePath ? /* @__PURE__ */ jsxRuntimeExports.jsx(FolderOpenDot, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(FolderOpen, { className: "h-3.5 w-3.5" })
152975
+ }
152976
+ ) : null,
152977
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
152978
+ "button",
152979
+ {
152980
+ type: "button",
152981
+ onClick: () => {
152982
+ void handleCopyPath();
152983
+ },
152984
+ onDoubleClick: () => {
152985
+ if (!canToggleRelativePath) return;
152986
+ setShowRelativePath((current) => !current);
152987
+ },
152988
+ className: "text-muted-foreground hover:text-foreground inline-flex min-w-0 flex-1 items-center gap-1 truncate text-left text-xs",
152989
+ title: displayPath,
152990
+ "aria-label": `Copy ${showRelativePath && canToggleRelativePath ? "relative" : "absolute"} path for ${worktree.branchName}`,
152991
+ children: [
152992
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "truncate", children: displayPath }),
152993
+ copied ? /* @__PURE__ */ jsxRuntimeExports.jsx(Check, { className: "h-3 w-3 shrink-0" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Copy, { className: "h-3 w-3 shrink-0" })
152994
+ ]
152995
+ }
152996
+ )
152997
+ ] })
152612
152998
  ] }),
152613
152999
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "shrink-0 text-right", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-end gap-1", children: [
153000
+ canRemoveDetached ? /* @__PURE__ */ jsxRuntimeExports.jsx(
153001
+ "button",
153002
+ {
153003
+ type: "button",
153004
+ onClick: () => {
153005
+ void onRemoveDetachedWorktree?.(worktree);
153006
+ },
153007
+ disabled: removing,
153008
+ className: "text-muted-foreground hover:text-destructive inline-flex h-5 w-5 items-center justify-center rounded border border-transparent disabled:cursor-not-allowed disabled:opacity-60",
153009
+ title: "Remove detached worktree",
153010
+ "aria-label": "Remove detached worktree",
153011
+ children: removing ? /* @__PURE__ */ jsxRuntimeExports.jsx(LoaderCircle, { className: "h-3.5 w-3.5 animate-spin" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Trash2, { className: "h-3.5 w-3.5" })
153012
+ }
153013
+ ) : null,
152614
153014
  /* @__PURE__ */ jsxRuntimeExports.jsx(GitAheadBehindBadge, { ahead: worktree.ahead, behind: worktree.behind }),
152615
153015
  /* @__PURE__ */ jsxRuntimeExports.jsx(GitFilesBadge, { files: worktree.diff.files }),
152616
153016
  /* @__PURE__ */ jsxRuntimeExports.jsx(DiffStat, { diff: worktree.diff, className: "justify-end" })