@fonlan/dsh-quick-commands 0.1.6 → 0.1.8

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
@@ -4,10 +4,124 @@ window.__ModuleLoader__.load({
4
4
  var module = { exports: {} };
5
5
  var exports = module.exports;
6
6
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
7
+ //#region \0rolldown/runtime.js
8
+ var __create = Object.create;
9
+ var __defProp = Object.defineProperty;
10
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
11
+ var __getOwnPropNames = Object.getOwnPropertyNames;
12
+ var __getProtoOf = Object.getPrototypeOf;
13
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
14
+ var __copyProps = (to, from, except, desc) => {
15
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
16
+ key = keys[i];
17
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
18
+ get: ((k) => from[k]).bind(null, key),
19
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
20
+ });
21
+ }
22
+ return to;
23
+ };
24
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule || !__hasOwnProp.call(mod, "default") ? __defProp(target, "default", {
25
+ value: mod,
26
+ enumerable: true
27
+ }) : target, mod));
28
+ //#endregion
7
29
  let react = require("react");
8
30
  let react_dom = require("react-dom");
9
31
  let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
32
+ _deepseek_ai_dsh_client_ui_primitives = __toESM(_deepseek_ai_dsh_client_ui_primitives, 1);
10
33
  let react_jsx_runtime = require("react/jsx-runtime");
34
+ //#region src/client/icons.tsx
35
+ const ICON_EXPORTS = _deepseek_ai_dsh_client_ui_primitives;
36
+ /** First export name that exists on the running host, else the bundled artwork. */
37
+ function pickIcon(exportNames, fallback) {
38
+ for (const name of exportNames) {
39
+ const candidate = ICON_EXPORTS[name];
40
+ if (typeof candidate === "function") return candidate;
41
+ }
42
+ return fallback;
43
+ }
44
+ /** Wrap one locally drawn 16×16 artwork as an icon component. */
45
+ function localIcon(children) {
46
+ return function LocalIcon({ size = 16, className }) {
47
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
48
+ width: size,
49
+ height: size,
50
+ viewBox: "0 0 16 16",
51
+ fill: "none",
52
+ className,
53
+ "aria-hidden": "true",
54
+ children
55
+ });
56
+ };
57
+ }
58
+ /** Run/play glyph for the header quick-run button. */
59
+ const PlayIcon = pickIcon([
60
+ "IconPlayOutlineRegular",
61
+ "IconPlayOutlineMedium",
62
+ "IconPlayOutline16"
63
+ ], localIcon(/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
64
+ cx: "8",
65
+ cy: "8",
66
+ r: "6.5",
67
+ stroke: "currentColor"
68
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
69
+ d: "M6.6 5.9 10.4 8l-3.8 2.1Z",
70
+ fill: "currentColor"
71
+ })] })));
72
+ /** Dismiss glyph (menu header and popup close). */
73
+ const CloseIcon = pickIcon([
74
+ "IconCloseOutlineRegular",
75
+ "IconCloseOutlineMedium",
76
+ "IconCloseOutline16"
77
+ ], localIcon(/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
78
+ d: "M4.2 4.2 11.8 11.8M11.8 4.2 4.2 11.8",
79
+ stroke: "currentColor",
80
+ strokeWidth: "1.2",
81
+ strokeLinecap: "round"
82
+ })));
83
+ /** Stop/kill glyph for a running command. */
84
+ const StopIcon = pickIcon([
85
+ "IconStopFillRegular",
86
+ "IconStopFillMedium",
87
+ "IconStopFill16"
88
+ ], localIcon(/* @__PURE__ */ (0, react_jsx_runtime.jsx)("rect", {
89
+ x: "4.6",
90
+ y: "4.6",
91
+ width: "6.8",
92
+ height: "6.8",
93
+ rx: "1.6",
94
+ fill: "currentColor"
95
+ })));
96
+ /** Add-row glyph in the settings page. */
97
+ const PlusIcon = pickIcon([
98
+ "IconPlusOutlineRegular",
99
+ "IconPlusOutlineMedium",
100
+ "IconPlusOutline16"
101
+ ], localIcon(/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
102
+ d: "M8 3.4v9.2M3.4 8h9.2",
103
+ stroke: "currentColor",
104
+ strokeWidth: "1.2",
105
+ strokeLinecap: "round"
106
+ })));
107
+ /** Remove-command glyph in the settings page. */
108
+ const TrashIcon = pickIcon([
109
+ "IconTrashOutlineRegular",
110
+ "IconTrashOutlineMedium",
111
+ "IconTrashOutline16"
112
+ ], localIcon(/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
113
+ d: "M3.4 4.4h9.2",
114
+ stroke: "currentColor",
115
+ strokeWidth: "1.2",
116
+ strokeLinecap: "round"
117
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
118
+ d: "M6.4 4.4V3.1h3.2v1.3M4.9 4.4l.6 8.5h5l.6-8.5",
119
+ stroke: "currentColor",
120
+ strokeWidth: "1.2",
121
+ strokeLinecap: "round",
122
+ strokeLinejoin: "round"
123
+ })] })));
124
+ //#endregion
11
125
  //#region src/client/api.ts
12
126
  var QuickCommandsApiError = class extends Error {
13
127
  code;
@@ -161,6 +275,17 @@ window.__ModuleLoader__.load({
161
275
  });
162
276
  }
163
277
  //#endregion
278
+ //#region src/shared/contract.ts
279
+ /**
280
+ * The document's anchor as a usable literal. Wire data is defensive by
281
+ * contract: an older host can still answer with schemastery's empty-object
282
+ * resolution (`{}`) for this field, which must never reach a CSS class name or
283
+ * a radio `checked` comparison.
284
+ */
285
+ function anchorOf(value) {
286
+ return value === "button" ? "button" : "corner";
287
+ }
288
+ //#endregion
164
289
  //#region src/client/header.tsx
165
290
  /**
166
291
  * Session-header quick-command surface: the ▶ play icon button (left of the
@@ -206,9 +331,9 @@ window.__ModuleLoader__.load({
206
331
  /** Resolve the current session's workspace from the standard kits. */
207
332
  function useCurrentWorkspace(sessionId, useSessions, useWorkspaces) {
208
333
  const row = useSessions?.((s) => s.byId[sessionId]);
209
- const workspaces = useWorkspaces?.((s) => s.items);
334
+ const items = useWorkspaces?.((s) => s.items) ?? [];
210
335
  return {
211
- workspace: matchWorkspace(row?.cwd, workspaces ?? []),
336
+ workspace: items.find((ws) => ws.sessionIds?.includes(sessionId) === true) ?? matchWorkspace(row?.cwd, items),
212
337
  cwd: row?.cwd
213
338
  };
214
339
  }
@@ -270,7 +395,7 @@ window.__ModuleLoader__.load({
270
395
  const own = entries.find((e) => e.workspaceId === workspace?.workspaceId);
271
396
  setCommands(own === void 0 ? [] : own.commands);
272
397
  setMenuRemoteHost(own?.remoteHost ?? null);
273
- setAnchor(settings.popupAnchor);
398
+ setAnchor(anchorOf(settings.popupAnchor));
274
399
  setPopupSize(settings.popupSize);
275
400
  setMenuLoadError(null);
276
401
  } catch (e) {
@@ -312,7 +437,7 @@ window.__ModuleLoader__.load({
312
437
  onClick: () => {
313
438
  popover.menuOpen ? closeMenu() : openMenu();
314
439
  },
315
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPlayOutline16, { size: 15 })
440
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PlayIcon, { size: 15 })
316
441
  }),
317
442
  popover.menuOpen && workspace !== void 0 && menuPosition !== null && (0, react_dom.createPortal)(/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
318
443
  ref: menuRef,
@@ -345,7 +470,7 @@ window.__ModuleLoader__.load({
345
470
  className: "qc-menu-close",
346
471
  "aria-label": t("runClose"),
347
472
  onClick: closeMenu,
348
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconCloseOutline16, { size: 12 })
473
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CloseIcon, { size: 12 })
349
474
  })
350
475
  ]
351
476
  }),
@@ -582,7 +707,7 @@ window.__ModuleLoader__.load({
582
707
  title: t("runKill"),
583
708
  "aria-label": t("runKill"),
584
709
  onClick: () => void kill(),
585
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconStopFill16, { size: 14 })
710
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(StopIcon, { size: 14 })
586
711
  }),
587
712
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
588
713
  type: "button",
@@ -591,7 +716,7 @@ window.__ModuleLoader__.load({
591
716
  "aria-label": t("runClose"),
592
717
  onPointerUp: onClosePointerUp,
593
718
  onClick: closeOutput,
594
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconCloseOutline16, { size: 14 })
719
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CloseIcon, { size: 14 })
595
720
  })
596
721
  ]
597
722
  }),
@@ -700,7 +825,7 @@ window.__ModuleLoader__.load({
700
825
  });
701
826
  }
702
827
  //#endregion
703
- //#region \0dsh-css:/home/runner/work/dsh-quick-commands/dsh-quick-commands/src/client/settings-section.css.mjs
828
+ //#region \0dsh-css:/Users/fonlan/Repos/dsh-quick-commands/src/client/settings-section.css.mjs
704
829
  const css$1 = "/**\n * Styles for the quick-commands settings page.\n *\n * The page occupies the settings panel content column: a static header\n * (title plus a one-line summary) over the always-visible command editor.\n * Inner controls follow the built-in settings language.\n */\n\n/* page layout */\n\n.qc-page {\n display: flex;\n flex-direction: column;\n gap: 16px;\n max-width: 720px;\n}\n.qc-page-head {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n.qc-page-title {\n margin: 0;\n color: var(--dsw-alias-label-primary, #f2f2f2);\n font-size: 15px;\n font-weight: 600;\n line-height: 1.4;\n}\n.qc-page-sub {\n margin: 0;\n color: var(--dsw-alias-label-secondary, #cfd3d6);\n font-size: 13px;\n line-height: 1.5;\n}\n\n/* body: workspace / command-set editor */\n\n.qc-settings-body {\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n.qc-settings-intro {\n font-size: 12px;\n color: var(--dsw-alias-label-secondary, #cfd3d6);\n margin: 0;\n line-height: 1.5;\n}\n.qc-settings-anchor {\n display: flex;\n align-items: center;\n gap: 12px;\n font-size: 12px;\n}\n.qc-settings-anchor-label {\n color: var(--dsw-alias-label-primary, #f2f2f2);\n font-weight: 500;\n}\n.qc-settings-radio {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n color: var(--dsw-alias-label-secondary, #cfd3d6);\n cursor: pointer;\n}\n.qc-settings-error {\n font-size: 12px;\n color: var(--dsw-alias-state-error-primary, #e5484d);\n}\n.qc-settings-empty {\n font-size: 12px;\n color: var(--dsw-alias-label-secondary, #cfd3d6);\n margin: 0;\n}\n.qc-settings-workspace {\n border: 1px solid var(--dsw-alias-border-l2, rgba(128, 128, 128, 0.35));\n border-radius: 10px;\n padding: 10px;\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n.qc-settings-workspace-head {\n display: flex;\n align-items: baseline;\n gap: 8px;\n}\n.qc-settings-workspace-title {\n font-size: 13px;\n font-weight: 600;\n color: var(--dsw-alias-label-primary, #f2f2f2);\n}\n.qc-settings-workspace-path {\n font-size: 11px;\n font-family: var(--dsw-font-family-mono, monospace);\n color: var(--dsw-alias-label-tertiary, #adb2b8);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.qc-settings-no-commands {\n font-size: 12px;\n color: var(--dsw-alias-label-tertiary, #adb2b8);\n margin: 0;\n}\n.qc-settings-command {\n display: flex;\n gap: 6px;\n align-items: center;\n}\n.qc-settings-field {\n border: 1px solid var(--dsw-alias-border-l2, rgba(128, 128, 128, 0.35));\n border-radius: 8px;\n background: var(--dsw-alias-bg-layer-1, #2a2a2d);\n color: var(--dsw-alias-label-primary, #f2f2f2);\n font-size: 12px;\n padding: 6px 8px;\n outline: none;\n}\n.qc-settings-field::placeholder {\n color: var(--dsw-alias-label-tertiary, #adb2b8);\n}\n.qc-settings-field:focus {\n border-color: var(--dsw-alias-brand-primary, #4a9eff);\n}\n.qc-settings-field-name {\n width: 160px;\n flex: none;\n}\n.qc-settings-field-command {\n flex: 1;\n font-family: var(--dsw-font-family-mono, monospace);\n}\n.qc-settings-icon-btn {\n border: 0;\n background: transparent;\n color: var(--dsw-alias-label-tertiary, #adb2b8);\n cursor: pointer;\n padding: 4px;\n display: inline-flex;\n align-items: center;\n border-radius: 6px;\n}\n.qc-settings-icon-btn:hover {\n background: color-mix(in srgb, var(--dsw-alias-label-primary, #f2f2f2) 10%, transparent);\n color: var(--dsw-alias-state-error-primary, #e5484d);\n}\n.qc-settings-add-btn {\n align-self: flex-start;\n display: inline-flex;\n align-items: center;\n gap: 4px;\n border: 1px solid var(--dsw-alias-border-l2, rgba(128, 128, 128, 0.35));\n border-radius: 8px;\n background: transparent;\n color: var(--dsw-alias-label-primary, #f2f2f2);\n font-size: 12px;\n padding: 4px 10px;\n cursor: pointer;\n}\n.qc-settings-add-btn:hover {\n background: color-mix(in srgb, var(--dsw-alias-label-primary, #f2f2f2) 10%, transparent);\n}\n";
705
830
  const tagId$1 = "@fonlan/dsh-quick-commands/settings-section.css#d7004149";
706
831
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$1) + "]") === null) {
@@ -736,7 +861,7 @@ window.__ModuleLoader__.load({
736
861
  setState({
737
862
  loaded: true,
738
863
  entries,
739
- anchor: settings.popupAnchor
864
+ anchor: anchorOf(settings.popupAnchor)
740
865
  });
741
866
  setError(null);
742
867
  } catch (e) {
@@ -808,7 +933,7 @@ window.__ModuleLoader__.load({
808
933
  const next = await quickApi.settingsSetAnchor(anchor);
809
934
  setState((s) => ({
810
935
  ...s,
811
- anchor: next.popupAnchor
936
+ anchor: anchorOf(next.popupAnchor)
812
937
  }));
813
938
  } catch (e) {
814
939
  setError(e instanceof Error ? e.message : String(e));
@@ -914,7 +1039,7 @@ window.__ModuleLoader__.load({
914
1039
  "aria-label": t("cardRemove"),
915
1040
  title: t("cardRemove"),
916
1041
  onClick: () => removeCommand(entry.workspaceId, index),
917
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconTrashOutline16, { size: 14 })
1042
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TrashIcon, { size: 14 })
918
1043
  })
919
1044
  ]
920
1045
  }, `${entry.workspaceId}-${index}`)),
@@ -922,7 +1047,7 @@ window.__ModuleLoader__.load({
922
1047
  type: "button",
923
1048
  className: "qc-settings-add-btn",
924
1049
  onClick: () => addCommand(entry.workspaceId),
925
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPlusOutline16, { size: 14 }), t("cardAddCommand")]
1050
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(PlusIcon, { size: 14 }), t("cardAddCommand")]
926
1051
  })
927
1052
  ]
928
1053
  }, entry.workspaceId))
@@ -1027,7 +1152,7 @@ window.__ModuleLoader__.load({
1027
1152
  cardAnchorButton: "Anchored at button"
1028
1153
  };
1029
1154
  //#endregion
1030
- //#region \0dsh-css:/home/runner/work/dsh-quick-commands/dsh-quick-commands/src/client/quick-commands.css.mjs
1155
+ //#region \0dsh-css:/Users/fonlan/Repos/dsh-quick-commands/src/client/quick-commands.css.mjs
1031
1156
  const css = "/* @fonlan/dsh-quick-commands client styles.\n Uses theme CSS variables (--dsw-alias-*); falls back to neutral literals.\n Constraint: this deployment's theme defines only these text tokens —\n label-primary, label-secondary, label-tertiary, label-dimmed. READABLE\n description copy uses label-secondary / label-tertiary (never label-dimmed,\n which is intentionally near-invisible and reserved for disabled states). */\n\n/* ── header button (icon-only, left of Session log pill) ─────────────────── */\n.qc-head-wrap {\n position: relative;\n display: inline-flex;\n align-items: center;\n}\n/* Sized to DSH built-in header buttons (e.g. the open-in-app split button on\n the left): 26px tall pill, 13px radius, hairline border-l4, hover uses the\n shared --dsw-alias-interactive-bg-hover token. */\n.qc-head-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 26px;\n height: 26px;\n border: 0.5px solid var(--dsw-alias-border-l4, rgba(128, 128, 128, 0.35));\n border-radius: 13px;\n background: transparent;\n color: var(--dsw-alias-label-primary, #f2f2f2);\n cursor: pointer;\n padding: 0;\n}\n.qc-head-btn:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover, color-mix(in srgb, var(--dsw-alias-label-primary, #f2f2f2) 10%, transparent));\n}\n.qc-head-btn:disabled {\n color: var(--dsw-alias-label-dimmed, #666);\n cursor: not-allowed;\n}\n.qc-head-btn svg {\n flex: none;\n}\n\n/* ── command menu popover (anchored under the button) ────────────────────── */\n.qc-menu {\n position: absolute;\n top: calc(100% + 6px);\n right: 12px;\n min-width: 280px;\n max-height: 420px;\n overflow: auto;\n background: var(--dsw-alias-bg-overlay, #1b1b1c);\n border: 1px solid var(--dsw-alias-border-l2, rgba(128, 128, 128, 0.35));\n border-radius: 10px;\n box-shadow: 0 8px 24px rgba(0, 0, 0, 0.35);\n z-index: 50;\n padding: 6px;\n display: flex;\n flex-direction: column;\n}\n.qc-menu-head {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 4px 8px 6px;\n border-bottom: 1px solid var(--dsw-alias-border-l2, rgba(128, 128, 128, 0.25));\n}\n.qc-menu-title {\n font-size: 12px;\n font-weight: 600;\n color: var(--dsw-alias-label-primary, #f2f2f2);\n}\n.qc-menu-ws {\n flex: 1;\n font-size: 11px;\n color: var(--dsw-alias-label-tertiary, #adb2b8);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n text-align: right;\n margin-right: 2px;\n}\n.qc-menu-remote {\n flex: 0 0 auto;\n font-size: 10px;\n font-weight: 600;\n line-height: 1;\n padding: 2px 5px;\n border-radius: 5px;\n color: var(--dsw-alias-fg-on-accent, #fff);\n background: var(--dsw-alias-accent, #4a8dff);\n letter-spacing: 0.04em;\n}\n.qc-menu-close {\n border: 0;\n background: transparent;\n color: var(--dsw-alias-label-tertiary, #adb2b8);\n cursor: pointer;\n padding: 2px;\n display: inline-flex;\n align-items: center;\n}\n.qc-menu-empty {\n font-size: 12px;\n color: var(--dsw-alias-label-tertiary, #adb2b8);\n padding: 10px 8px;\n margin: 0;\n}\n.qc-menu-item {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: 2px;\n text-align: left;\n border: 0;\n background: transparent;\n border-radius: 8px;\n padding: 6px 8px;\n cursor: pointer;\n width: 100%;\n}\n.qc-menu-item:hover:not(:disabled) {\n background: color-mix(in srgb, var(--dsw-alias-label-primary, #f2f2f2) 10%, transparent);\n}\n.qc-menu-item:disabled {\n opacity: 0.6;\n cursor: wait;\n}\n.qc-menu-item-name {\n font-size: 13px;\n font-weight: 500;\n color: var(--dsw-alias-label-primary, #f2f2f2);\n}\n.qc-menu-item-cmd {\n font-family: var(--dsw-font-family-mono, monospace);\n font-size: 11px;\n color: var(--dsw-alias-label-secondary, #cfd3d6);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n max-width: 100%;\n}\n\n/* ── live output popup ───────────────────────────────────────────────────── */\n.qc-popup {\n position: relative; /* anchors the absolutely-positioned resize grip */\n display: flex;\n flex-direction: column;\n background: var(--dsw-alias-bg-overlay, #1b1b1c);\n border: 1px solid var(--dsw-alias-border-l2, rgba(128, 128, 128, 0.35));\n border-radius: 12px;\n box-shadow: 0 12px 36px rgba(0, 0, 0, 0.45);\n z-index: 60;\n overflow: hidden;\n}\n.qc-popup-corner {\n position: fixed;\n right: 20px;\n bottom: 20px;\n width: 520px;\n max-width: calc(100vw - 40px);\n height: 340px;\n max-height: calc(100vh - 120px);\n}\n.qc-popup-button {\n position: absolute;\n top: calc(100% + 6px);\n right: 12px;\n width: 440px;\n max-width: calc(100vw - 40px);\n height: 300px;\n max-height: calc(100vh - 120px);\n}\n.qc-popup-head {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 10px;\n border-bottom: 1px solid var(--dsw-alias-border-l2, rgba(128, 128, 128, 0.25));\n}\n.qc-popup-title {\n flex: 1;\n font-size: 12px;\n font-weight: 600;\n color: var(--dsw-alias-label-primary, #f2f2f2);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.qc-popup-cmd {\n font-family: var(--dsw-font-family-mono, monospace);\n font-size: 11px;\n color: var(--dsw-alias-label-secondary, #cfd3d6);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n max-width: 40%;\n}\n.qc-popup-remote {\n flex: 0 0 auto;\n font-size: 10px;\n font-weight: 600;\n line-height: 1;\n padding: 3px 6px;\n border-radius: 6px;\n color: var(--dsw-alias-fg-on-accent, #fff);\n background: var(--dsw-alias-accent, #4a8dff);\n letter-spacing: 0.04em;\n}\n.qc-popup-icon {\n border: 0;\n background: transparent;\n color: var(--dsw-alias-label-tertiary, #adb2b8);\n cursor: pointer;\n padding: 4px;\n display: inline-flex;\n align-items: center;\n border-radius: 6px;\n}\n.qc-popup-icon:hover:not(:disabled) {\n background: color-mix(in srgb, var(--dsw-alias-label-primary, #f2f2f2) 10%, transparent);\n}\n.qc-popup-icon:disabled {\n opacity: 0.4;\n cursor: not-allowed;\n}\n.qc-popup-kill {\n color: var(--dsw-alias-state-error-primary, #e5484d);\n}\n.qc-popup-confirm {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 12px;\n padding: 8px 10px;\n background: color-mix(in srgb, var(--dsw-alias-state-warn-primary, #f5a623) 12%, transparent);\n color: var(--dsw-alias-label-primary, #f2f2f2);\n border-bottom: 1px solid var(--dsw-alias-border-l2, rgba(128, 128, 128, 0.25));\n}\n.qc-popup-btn {\n border: 1px solid var(--dsw-alias-border-l2, rgba(128, 128, 128, 0.35));\n border-radius: 8px;\n background: transparent;\n color: var(--dsw-alias-label-primary, #f2f2f2);\n font-size: 12px;\n padding: 4px 10px;\n cursor: pointer;\n}\n.qc-popup-btn:hover {\n background: color-mix(in srgb, var(--dsw-alias-label-primary, #f2f2f2) 10%, transparent);\n}\n.qc-popup-btn-plain {\n color: var(--dsw-alias-label-secondary, #cfd3d6);\n}\n.qc-popup-tabs {\n display: flex;\n gap: 2px;\n padding: 6px 10px 0;\n border-bottom: 1px solid var(--dsw-alias-border-l2, rgba(128, 128, 128, 0.25));\n}\n.qc-popup-tab {\n border: 0;\n background: transparent;\n color: var(--dsw-alias-label-secondary, #cfd3d6);\n font-size: 12px;\n padding: 5px 10px;\n cursor: pointer;\n border-bottom: 2px solid transparent;\n}\n.qc-popup-tab-active {\n color: var(--dsw-alias-label-primary, #f2f2f2);\n border-bottom-color: var(--dsw-alias-brand-primary, #4a9eff);\n}\n.qc-popup-output {\n flex: 1;\n overflow: auto;\n padding: 8px 10px;\n font-family: var(--dsw-font-family-mono, monospace);\n font-size: 12px;\n line-height: 1.5;\n}\n.qc-popup-pre {\n margin: 0;\n white-space: pre-wrap;\n word-break: break-word;\n color: var(--dsw-alias-label-primary, #f2f2f2);\n}\n.qc-popup-empty {\n margin: 0;\n color: var(--dsw-alias-label-tertiary, #adb2b8);\n font-size: 12px;\n}\n.qc-popup-error {\n margin: 0 0 6px;\n color: var(--dsw-alias-state-error-primary, #e5484d);\n font-size: 12px;\n}\n.qc-popup-foot {\n display: flex;\n align-items: center;\n padding: 6px 10px;\n border-top: 1px solid var(--dsw-alias-border-l2, rgba(128, 128, 128, 0.25));\n font-size: 11px;\n}\n.qc-popup-state {\n color: var(--dsw-alias-label-secondary, #cfd3d6);\n}\n\n/* Resize handles. The popup pins its RIGHT edge (both anchors); width is\n always dragged from the LEFT border. Height is dragged from the TOP border\n (corner anchor, bottom pinned) or the BOTTOM border (button anchor, top\n pinned below the button). The free corner (top-left / bottom-left) carries\n the diagonal grip. Pointer capture lives in header.tsx; touch-action:none\n lets touch drags resize instead of scrolling. */\n.qc-popup-resize {\n position: absolute;\n z-index: 3;\n touch-action: none;\n user-select: none;\n}\n.qc-popup-resize-left {\n left: 0;\n top: 10px;\n bottom: 10px;\n width: 7px;\n cursor: ew-resize;\n}\n.qc-popup-resize-top {\n top: 0;\n left: 10px;\n right: 10px;\n height: 7px;\n cursor: ns-resize;\n}\n.qc-popup-resize-bottom {\n bottom: 0;\n left: 10px;\n right: 10px;\n height: 7px;\n cursor: ns-resize;\n}\n.qc-popup-resize-left:hover,\n.qc-popup-resize-top:hover,\n.qc-popup-resize-bottom:hover {\n background: color-mix(in srgb, var(--dsw-alias-label-primary, #f2f2f2) 14%, transparent);\n}\n.qc-popup-resize-corner {\n width: 22px;\n height: 22px;\n z-index: 4;\n display: flex;\n padding: 3px;\n color: var(--dsw-alias-label-tertiary, #adb2b8);\n opacity: 0.6;\n transition: opacity .15s ease;\n}\n.qc-popup-resize-corner-tl {\n top: 0;\n left: 0;\n cursor: nwse-resize;\n align-items: flex-start;\n justify-content: flex-start;\n}\n.qc-popup-resize-corner-bl {\n bottom: 0;\n left: 0;\n cursor: nesw-resize;\n align-items: flex-end;\n justify-content: flex-start;\n}\n.qc-popup-resize-corner:hover,\n.qc-popup-resize-corner:active {\n opacity: 1;\n}\n\n/* ── mobile fallback (dsh-mobile-nav) ──────────────────────────────────────\n The dsh-mobile-nav plugin (≤1023px) hides the ENTIRE header utilities seat\n with `[data-mobile-nav=\"frame\"] [data-phase] header > :first-child >\n :last-child { display: none !important; }`, because the seat used to hold\n only the session-log-export capsule (which it relocates to the drawer\n footer). Our quick-run ▶ button rides that same seat, so it vanished on\n phones.\n\n Re-show ONLY our button: restore the seat's flex layout (out-ranking the\n host rule via `:has(.qc-head-wrap)` specificity (0,5,1) > (0,4,1)) and keep\n every other seat occupant hidden (the session-log capsule stays relocated\n to the drawer footer). Desktop (no [data-mobile-nav]) is untouched. */\n[data-mobile-nav=\"frame\"] [data-phase] header > :first-child > :last-child:has(.qc-head-wrap) {\n display: flex !important;\n margin-left: 4px !important;\n gap: 0 !important;\n}\n[data-mobile-nav=\"frame\"] [data-phase] header > :first-child > :last-child:has(.qc-head-wrap)\n [data-slot=\"conversation.session.header.utilities\"] > :not(.qc-head-wrap) {\n display: none !important;\n}\n\n/* ── viewport-level command menu ─────────────────────────────────────────\n The phone shell's nav rail creates a sibling stacking context and its\n center column can clip header descendants. The React menu therefore mounts\n in document.body; these styles deliberately detach it from that header\n context. Pixel coordinates (including the 56px rail exclusion) are set by\n positionMenu() in header.tsx. */\n.qc-menu-portal {\n position: fixed;\n right: auto;\n z-index: 1100;\n box-sizing: border-box;\n max-height: min(420px, calc(100dvh - 72px));\n}\n\n@media (max-width: 767px) {\n /* A 44px target lets a fingertip reliably activate both the stop and close\n buttons without changing the desktop header density. */\n body[data-dsh-mobile] .qc-popup-icon,\n [data-mobile-nav=\"frame\"] .qc-popup-icon {\n min-width: 44px;\n min-height: 44px;\n justify-content: center;\n }\n}";
1032
1157
  const tagId = "@fonlan/dsh-quick-commands/quick-commands.css#b65a4ce4";
1033
1158
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {