@ggui-ai/dev-stack 0.25.0 → 0.27.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/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @ggui-ai/dev-stack
2
2
 
3
- > Shared local dev engine for the [ggui](https://github.com/ggui-ai/ggui) protocol.
3
+ > Shared local dev engine for the [GGUI](https://github.com/ggui-ai/ggui) protocol.
4
4
 
5
5
  [![npm version](https://img.shields.io/npm/v/@ggui-ai/dev-stack.svg)](https://www.npmjs.com/package/@ggui-ai/dev-stack)
6
6
  [![License: Apache 2.0](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](./LICENSE)
@@ -20910,6 +20910,7 @@ function buildWireConfig(opts) {
20910
20910
  const result = validateEnvelope(actionSpec, envelope);
20911
20911
  if (!result.valid) {
20912
20912
  opts.onViolation(new ClientContractViolationError("outbound-action", result.violations));
20913
+ opts.onDispatchRefused?.({ actionName, violations: result.violations });
20913
20914
  return;
20914
20915
  }
20915
20916
  if (isOneShot && !spentOneShots.has(actionName)) {
@@ -21209,7 +21210,7 @@ function resolveToneCss(tone) {
21209
21210
  case "muted":
21210
21211
  return "var(--ggui-color-onSunken, #52525b)";
21211
21212
  case "subtle":
21212
- return "var(--ggui-color-neutral-500, #71717a)";
21213
+ return "var(--ggui-color-onSunken, #52525b)";
21213
21214
  case "emphasized":
21214
21215
  return "var(--ggui-color-link, var(--ggui-color-primary-700, #0369a1))";
21215
21216
  case "loud":
@@ -21245,7 +21246,7 @@ function surfaceScopeCss(cls, name, bg, ink, accent, outlineOpen) {
21245
21246
  const inkAlias = "--ggui-surface-" + name + "-ink";
21246
21247
  const B = "var(" + bgAlias + ")";
21247
21248
  const I = "var(" + inkAlias + ")";
21248
- return `.${cls}{${bgAlias}:${bg};${inkAlias}:${ink};--ggui-color-onInverted:${ink}}.${cls}>*{--ggui-color-container:${B};--ggui-color-onContainer:${I};--ggui-color-elevated:${B};--ggui-color-onElevated:${I};--ggui-color-sunken:${B};--ggui-color-onSunken:${I};--ggui-color-neutral-500:${I};--ggui-color-ground:${B};--ggui-color-onGround:${I};--ggui-color-link:${accent}}@supports (color: color-mix(in srgb, red, blue)){.${cls}>*{--ggui-color-container:color-mix(in srgb, ${B} 94%, ${I});--ggui-color-elevated:color-mix(in srgb, ${B} 92%, ${I});--ggui-color-sunken:color-mix(in srgb, ${B} 88%, ${I});--ggui-color-onSunken:color-mix(in srgb, ${I} 76%, ${B});--ggui-color-neutral-500:color-mix(in srgb, ${I} 62%, ${B});--ggui-color-outline:${outlineOpen}color-mix(in srgb, ${I} 32%, ${B}));--ggui-color-outlineVariant:color-mix(in srgb, ${I} 18%, ${B})}}`;
21249
+ return `.${cls}{${bgAlias}:${bg};${inkAlias}:${ink};--ggui-color-onInverted:${ink}}.${cls}>*{--ggui-color-container:${B};--ggui-color-onContainer:${I};--ggui-color-elevated:${B};--ggui-color-onElevated:${I};--ggui-color-sunken:${B};--ggui-color-onSunken:${I};--ggui-color-neutral-500:${I};--ggui-color-ground:${B};--ggui-color-onGround:${I};--ggui-color-link:${accent};--ggui-color-controlAccentOutline:${accent}}@supports (color: color-mix(in srgb, red, blue)){.${cls}>*{--ggui-color-container:color-mix(in srgb, ${B} 94%, ${I});--ggui-color-elevated:color-mix(in srgb, ${B} 92%, ${I});--ggui-color-sunken:color-mix(in srgb, ${B} 88%, ${I});--ggui-color-onSunken:color-mix(in srgb, ${I} 76%, ${B});--ggui-color-neutral-500:color-mix(in srgb, ${I} 62%, ${B});--ggui-color-outline:${outlineOpen}color-mix(in srgb, ${I} 32%, ${B}));--ggui-color-controlOutline:${outlineOpen}color-mix(in srgb, ${I} 32%, ${B}));--ggui-color-outlineVariant:color-mix(in srgb, ${I} 18%, ${B})}}`;
21249
21250
  }
21250
21251
  var INVERTED_SCOPE_CSS = surfaceScopeCss(
21251
21252
  INVERTED_SCOPE_CLASS,
@@ -21744,7 +21745,8 @@ var variantStyles = {
21744
21745
  },
21745
21746
  secondary: {
21746
21747
  backgroundColor: "var(--ggui-color-sunken, #f4f4f5)",
21747
- color: "var(--ggui-color-onSunken, #52525b)",
21748
+ // The label reads at full strength; the chip marks the rank (ggui#1566).
21749
+ color: "var(--ggui-color-onContainer, #18181b)",
21748
21750
  border: "none"
21749
21751
  },
21750
21752
  outline: {
@@ -21753,13 +21755,15 @@ var variantStyles = {
21753
21755
  // label is the surface's own on-colour, never a brand-ladder stop
21754
21756
  // (ggui#1034): `primary-600` as the label read mid-grey on a monochrome
21755
21757
  // dark theme's ground — 2.41:1 / 3.5:1 on served reply chips. The brand
21756
- // stays on the border, where contrast is decorative.
21758
+ // stays on the border, and the border identifies the control, so it is the
21759
+ // first brand stop that clears 3:1 on the container (ggui#1494).
21757
21760
  color: "var(--ggui-color-onContainer, #18181b)",
21758
- border: "1px solid var(--ggui-color-primary-600, #0284c7)"
21761
+ border: "1px solid var(--ggui-color-controlAccentOutline, var(--ggui-color-primary-600, #0284c7))"
21759
21762
  },
21760
21763
  ghost: {
21761
21764
  backgroundColor: "transparent",
21762
- color: "var(--ggui-color-onSunken, #52525b)",
21765
+ // A dimmed label reads as disabled; ghost's rank is its missing chrome (ggui#1566).
21766
+ color: "var(--ggui-color-onContainer, #18181b)",
21763
21767
  border: "none"
21764
21768
  },
21765
21769
  danger: {
@@ -21821,7 +21825,7 @@ function Input({ label, placeholder, value, onChange, type = "text", error, help
21821
21825
  ...sizeStyles2[size],
21822
21826
  width: "100%",
21823
21827
  borderRadius: "var(--ggui-shape-radius-control, var(--ggui-shape-radius-md, 8px))",
21824
- border: `1px solid ${hasError ? "var(--ggui-color-error-500, #ef4444)" : "var(--ggui-color-outline, #d4d4d8)"}`,
21828
+ border: `1px solid ${hasError ? "var(--ggui-color-error-500, #ef4444)" : "var(--ggui-color-controlOutline, var(--ggui-color-outline, #d4d4d8))"}`,
21825
21829
  backgroundColor: disabled ? "var(--ggui-color-sunken, #fafafa)" : "var(--ggui-color-sunken, #ffffff)",
21826
21830
  color: "var(--ggui-color-onContainer, #18181b)",
21827
21831
  transition: `border-color ${motionVar.duration.base} ${motionVar.easing.standard}, box-shadow ${motionVar.duration.base} ${motionVar.easing.standard}`,
@@ -21851,7 +21855,7 @@ function TextArea({ label, placeholder, value, onChange, rows = 4, error, helper
21851
21855
  padding: "10px 12px",
21852
21856
  width: "100%",
21853
21857
  borderRadius: "var(--ggui-shape-radius-control, var(--ggui-shape-radius-md, 8px))",
21854
- border: `1px solid ${hasError ? "var(--ggui-color-error-500, #ef4444)" : "var(--ggui-color-outline, #d4d4d8)"}`,
21858
+ border: `1px solid ${hasError ? "var(--ggui-color-error-500, #ef4444)" : "var(--ggui-color-controlOutline, var(--ggui-color-outline, #d4d4d8))"}`,
21855
21859
  backgroundColor: disabled ? "var(--ggui-color-sunken, #fafafa)" : "var(--ggui-color-sunken, #ffffff)",
21856
21860
  color: "var(--ggui-color-onContainer, #18181b)",
21857
21861
  fontSize: "var(--ggui-font-size-sm, 14px)",
@@ -21879,17 +21883,25 @@ function Select({ label, value, onChange, options, placeholder, error, helperTex
21879
21883
  const messageId = `${uniqueId}-message`;
21880
21884
  const hasError = Boolean(error);
21881
21885
  const hasMessage = Boolean(error || helperText);
21886
+ const startsOnPlaceholder = Boolean(placeholder) && value === void 0 && rest.defaultValue === void 0;
21887
+ const [uncontrolledValue, setUncontrolledValue] = (0, import_react17.useState)(startsOnPlaceholder ? "" : typeof rest.defaultValue === "string" ? rest.defaultValue : void 0);
21888
+ const showingPlaceholder = Boolean(placeholder) && (value ?? uncontrolledValue) === "";
21882
21889
  return (0, import_jsx_runtime13.jsxs)("div", { className, style: { display: "flex", flexDirection: "column", gap: "var(--ggui-spacing-1, 4px)", ...style }, children: [label && (0, import_jsx_runtime13.jsxs)("label", { htmlFor: selectId, style: {
21883
21890
  fontSize: "var(--ggui-font-size-sm, 14px)",
21884
21891
  fontWeight: "var(--ggui-font-weight-medium, 500)",
21885
21892
  color: "var(--ggui-color-onSunken, #52525b)"
21886
- }, children: [label, required && (0, import_jsx_runtime13.jsx)("span", { "aria-hidden": "true", style: { color: "var(--ggui-color-error-500, #ef4444)", marginLeft: "2px" }, children: "*" })] }), (0, import_jsx_runtime13.jsxs)("select", { id: selectId, value, onChange: (e) => onChange?.(e.target.value), disabled, required, "aria-invalid": hasError || void 0, "aria-describedby": hasMessage ? messageId : void 0, style: {
21893
+ }, children: [label, required && (0, import_jsx_runtime13.jsx)("span", { "aria-hidden": "true", style: { color: "var(--ggui-color-error-500, #ef4444)", marginLeft: "2px" }, children: "*" })] }), (0, import_jsx_runtime13.jsxs)("select", { id: selectId, value, ...startsOnPlaceholder ? { defaultValue: "" } : {}, onChange: (e) => {
21894
+ if (value === void 0)
21895
+ setUncontrolledValue(e.target.value);
21896
+ onChange?.(e.target.value);
21897
+ }, disabled, required, "aria-invalid": hasError || void 0, "aria-describedby": hasMessage ? messageId : void 0, style: {
21887
21898
  ...sizeStyles3[size],
21888
21899
  width: "100%",
21889
21900
  borderRadius: "var(--ggui-shape-radius-control, var(--ggui-shape-radius-md, 8px))",
21890
- border: `1px solid ${hasError ? "var(--ggui-color-error-500, #ef4444)" : "var(--ggui-color-outline, #d4d4d8)"}`,
21901
+ border: `1px solid ${hasError ? "var(--ggui-color-error-500, #ef4444)" : "var(--ggui-color-controlOutline, var(--ggui-color-outline, #d4d4d8))"}`,
21891
21902
  backgroundColor: disabled ? "var(--ggui-color-sunken, #fafafa)" : "var(--ggui-color-sunken, #ffffff)",
21892
- color: value ? "var(--ggui-color-onContainer, #18181b)" : "var(--ggui-color-onSunken, #52525b)",
21903
+ // Muted only while the placeholder is what shows (ggui#1566, #1569).
21904
+ color: showingPlaceholder ? "var(--ggui-color-onSunken, #52525b)" : "var(--ggui-color-onContainer, #18181b)",
21893
21905
  cursor: disabled ? "not-allowed" : "pointer",
21894
21906
  appearance: "none",
21895
21907
  backgroundImage: `url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%236b7280' d='M3 4.5L6 7.5L9 4.5'/%3E%3C/svg%3E")`,
@@ -21931,7 +21943,7 @@ function Checkbox({ label, checked, onChange, disabled, description, indetermina
21931
21943
  width: "18px",
21932
21944
  height: "18px",
21933
21945
  borderRadius: "var(--ggui-shape-radius-sm, 4px)",
21934
- border: `2px solid ${checked || indeterminate ? "var(--ggui-color-primary-600, #0284c7)" : "var(--ggui-color-outline, #d4d4d8)"}`,
21946
+ border: `2px solid ${checked || indeterminate ? "var(--ggui-color-primary-600, #0284c7)" : "var(--ggui-color-controlOutline, var(--ggui-color-outline, #d4d4d8))"}`,
21935
21947
  backgroundColor: checked || indeterminate ? "var(--ggui-color-primary-600, #0284c7)" : "var(--ggui-color-sunken, #ffffff)",
21936
21948
  display: "flex",
21937
21949
  alignItems: "center",
@@ -21940,7 +21952,7 @@ function Checkbox({ label, checked, onChange, disabled, description, indetermina
21940
21952
  }, children: (checked || indeterminate) && (0, import_jsx_runtime14.jsx)("svg", { width: "12", height: "12", viewBox: "0 0 12 12", fill: "none", style: { color: "var(--ggui-color-onPrimary, #ffffff)" }, children: indeterminate ? (0, import_jsx_runtime14.jsx)("path", { d: "M2.5 6H9.5", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }) : (0, import_jsx_runtime14.jsx)("path", { d: "M2.5 6L5 8.5L9.5 3.5", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) }) })] }), (label || description) && (0, import_jsx_runtime14.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: "2px" }, children: [label && (0, import_jsx_runtime14.jsx)("span", { style: {
21941
21953
  fontSize: "var(--ggui-font-size-sm, 14px)",
21942
21954
  fontWeight: "var(--ggui-font-weight-medium, 500)",
21943
- color: "var(--ggui-color-onSunken, #52525b)"
21955
+ color: "var(--ggui-color-onContainer, #18181b)"
21944
21956
  }, children: label }), description && (0, import_jsx_runtime14.jsx)("span", { style: {
21945
21957
  fontSize: "var(--ggui-font-size-xs, 12px)",
21946
21958
  color: "var(--ggui-color-onSunken, #52525b)"
@@ -21972,7 +21984,7 @@ function Toggle({ label, checked, onChange, disabled, size = "md", style, classN
21972
21984
  width: config.width,
21973
21985
  height: config.height,
21974
21986
  borderRadius: "9999px",
21975
- backgroundColor: checked ? "var(--ggui-color-primary-600, #0284c7)" : "var(--ggui-color-outline, #d4d4d8)",
21987
+ backgroundColor: checked ? "var(--ggui-color-primary-600, #0284c7)" : "var(--ggui-color-controlOutline, var(--ggui-color-outline, #d4d4d8))",
21976
21988
  position: "relative",
21977
21989
  transition: `background-color ${motionVar.duration.base} ${motionVar.easing.standard}, box-shadow ${motionVar.duration.base} ${motionVar.easing.standard}`,
21978
21990
  flexShrink: 0,
@@ -21991,7 +22003,7 @@ function Toggle({ label, checked, onChange, disabled, size = "md", style, classN
21991
22003
  } }) }), label && (0, import_jsx_runtime15.jsx)("span", { style: {
21992
22004
  fontSize: "var(--ggui-font-size-sm, 14px)",
21993
22005
  fontWeight: "var(--ggui-font-weight-medium, 500)",
21994
- color: "var(--ggui-color-onSunken, #52525b)"
22006
+ color: "var(--ggui-color-onContainer, #18181b)"
21995
22007
  }, children: label })] });
21996
22008
  }
21997
22009
  function RadioGroup({ label, value, onChange, options, direction = "vertical", disabled, error, style, className }) {
@@ -22035,7 +22047,7 @@ function RadioGroup({ label, value, onChange, options, direction = "vertical", d
22035
22047
  width: "18px",
22036
22048
  height: "18px",
22037
22049
  borderRadius: "var(--ggui-shape-radius-full, 9999px)",
22038
- border: `2px solid ${isSelected ? "var(--ggui-color-primary-600, #0284c7)" : "var(--ggui-color-outline, #d4d4d8)"}`,
22050
+ border: `2px solid ${isSelected ? "var(--ggui-color-primary-600, #0284c7)" : "var(--ggui-color-controlOutline, var(--ggui-color-outline, #d4d4d8))"}`,
22039
22051
  backgroundColor: "var(--ggui-color-sunken, #ffffff)",
22040
22052
  display: "flex",
22041
22053
  alignItems: "center",
@@ -22049,7 +22061,7 @@ function RadioGroup({ label, value, onChange, options, direction = "vertical", d
22049
22061
  } }) })] }), (0, import_jsx_runtime16.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: "2px" }, children: [(0, import_jsx_runtime16.jsx)("span", { style: {
22050
22062
  fontSize: "var(--ggui-font-size-sm, 14px)",
22051
22063
  fontWeight: "var(--ggui-font-weight-medium, 500)",
22052
- color: "var(--ggui-color-onSunken, #52525b)"
22064
+ color: "var(--ggui-color-onContainer, #18181b)"
22053
22065
  }, children: option.label }), option.description && (0, import_jsx_runtime16.jsx)("span", { style: {
22054
22066
  fontSize: "var(--ggui-font-size-xs, 12px)",
22055
22067
  color: "var(--ggui-color-onSunken, #52525b)"
@@ -27064,7 +27076,9 @@ function Table({ columns, data, sortKey, sortDirection = "asc", onSort, striped
27064
27076
  width: "100%",
27065
27077
  borderCollapse: "collapse",
27066
27078
  fontSize: "var(--ggui-font-size-sm, 14px)",
27067
- color: "var(--ggui-color-onSunken, #52525b)"
27079
+ // Body cells are the data and inherit this (ggui#1566); the header and
27080
+ // caption set the muted tier themselves.
27081
+ color: "var(--ggui-color-onContainer, #18181b)"
27068
27082
  }, children: [caption && (0, import_jsx_runtime27.jsx)("caption", { style: {
27069
27083
  padding: cellPadding,
27070
27084
  fontSize: "var(--ggui-font-size-sm, 14px)",
@@ -27514,7 +27528,7 @@ function Accordion({ items, expandedKeys, onChange, multiple = false, variant =
27514
27528
  }, children: isExpanded && (0, import_jsx_runtime30.jsx)("div", { style: {
27515
27529
  padding: "0 var(--ggui-spacing-4, 16px) var(--ggui-spacing-4, 16px)",
27516
27530
  fontSize: "var(--ggui-font-size-sm, 14px)",
27517
- color: "var(--ggui-color-onSunken, #52525b)",
27531
+ color: "var(--ggui-color-onContainer, #18181b)",
27518
27532
  lineHeight: "var(--ggui-font-lineHeight-normal, 1.5)"
27519
27533
  }, children: item.content }) })] }, item.key);
27520
27534
  }) });
@@ -27622,7 +27636,7 @@ function SearchField({ value: controlledValue, onChange, onSearch, placeholder =
27622
27636
  paddingLeft: "36px",
27623
27637
  fontSize: size === "lg" ? "16px" : "14px",
27624
27638
  borderRadius: "6px",
27625
- border: `1px solid var(--ggui-color-outline, #d1d5db)`,
27639
+ border: `1px solid var(--ggui-color-controlOutline, var(--ggui-color-outline, #d1d5db))`,
27626
27640
  backgroundColor: disabled ? "var(--ggui-color-sunken, #f9fafb)" : "var(--ggui-color-container, #ffffff)",
27627
27641
  color: "var(--ggui-color-onContainer, #111827)",
27628
27642
  outline: "none",
@@ -27642,11 +27656,11 @@ function FormField({ label, children, error, helperText, required, description,
27642
27656
  color: "var(--ggui-color-onContainer, #374151)"
27643
27657
  }, children: [label, required && (0, import_jsx_runtime32.jsx)("span", { style: { color: "var(--ggui-color-error-500, #ef4444)", marginLeft: "2px" }, children: "*" })] }), description && (0, import_jsx_runtime32.jsx)("span", { style: {
27644
27658
  fontSize: fontSize.xs,
27645
- color: "var(--ggui-color-neutral-500, #6b7280)",
27659
+ color: resolveToneCss("subtle"),
27646
27660
  marginBottom: "4px"
27647
27661
  }, children: description }), children, (error || helperText) && (0, import_jsx_runtime32.jsx)("span", { style: {
27648
27662
  fontSize: fontSize.xs,
27649
- color: hasError ? "var(--ggui-color-error-500, #ef4444)" : "var(--ggui-color-neutral-500, #6b7280)"
27663
+ color: hasError ? "var(--ggui-color-error-500, #ef4444)" : resolveToneCss("subtle")
27650
27664
  }, children: error || helperText })] });
27651
27665
  }
27652
27666
  function MenuItem({ label, icon, rightElement, onClick, disabled, active, danger, style, className }) {
@@ -27878,7 +27892,7 @@ function Autocomplete({ value = "", onChange, onSelect, options, placeholder, la
27878
27892
  }, children: loading ? (0, import_jsx_runtime36.jsx)("div", { style: { padding: "12px", display: "flex", justifyContent: "center" }, children: (0, import_jsx_runtime36.jsx)(Spinner, { size: 20 }) }) : filteredOptions.length === 0 ? (0, import_jsx_runtime36.jsx)("div", { style: {
27879
27893
  padding: "12px",
27880
27894
  textAlign: "center",
27881
- color: "var(--ggui-color-neutral-500, #6b7280)",
27895
+ color: resolveToneCss("subtle"),
27882
27896
  fontSize: fontSize.sm
27883
27897
  }, children: noResultsText }) : filteredOptions.map((option, index) => (0, import_jsx_runtime36.jsxs)("div", { onClick: () => !option.disabled && handleSelect(option), style: {
27884
27898
  padding: "8px 12px",
@@ -27889,7 +27903,7 @@ function Autocomplete({ value = "", onChange, onSelect, options, placeholder, la
27889
27903
  display: "flex",
27890
27904
  alignItems: "center",
27891
27905
  gap: "8px"
27892
- }, onMouseEnter: () => setHighlightedIndex(index), children: [option.icon && (0, import_jsx_runtime36.jsx)("span", { style: { flexShrink: 0 }, children: option.icon }), (0, import_jsx_runtime36.jsxs)("div", { style: { flex: 1 }, children: [(0, import_jsx_runtime36.jsx)("div", { children: option.label }), option.description && (0, import_jsx_runtime36.jsx)("div", { style: { fontSize: fontSize.xs, color: "var(--ggui-color-neutral-500, #6b7280)" }, children: option.description })] })] }, option.value)) })] });
27906
+ }, onMouseEnter: () => setHighlightedIndex(index), children: [option.icon && (0, import_jsx_runtime36.jsx)("span", { style: { flexShrink: 0 }, children: option.icon }), (0, import_jsx_runtime36.jsxs)("div", { style: { flex: 1 }, children: [(0, import_jsx_runtime36.jsx)("div", { children: option.label }), option.description && (0, import_jsx_runtime36.jsx)("div", { style: { fontSize: fontSize.xs, color: resolveToneCss("subtle") }, children: option.description })] })] }, option.value)) })] });
27893
27907
  }
27894
27908
  function Breadcrumb({ items, separator = "/", onItemClick, style, className }) {
27895
27909
  return (0, import_jsx_runtime37.jsx)("nav", { "aria-label": "Breadcrumb", className, style: {
@@ -27903,7 +27917,7 @@ function Breadcrumb({ items, separator = "/", onItemClick, style, className }) {
27903
27917
  return (0, import_jsx_runtime37.jsxs)(import_react33.Fragment, { children: [index > 0 && (0, import_jsx_runtime37.jsx)("span", { style: { color: "var(--ggui-color-neutral-400, #9ca3af)" }, children: separator }), item.icon && (0, import_jsx_runtime37.jsx)("span", { style: {
27904
27918
  display: "flex",
27905
27919
  alignItems: "center",
27906
- color: isLast ? "var(--ggui-color-onContainer, #111827)" : "var(--ggui-color-neutral-500, #6b7280)"
27920
+ color: isLast ? "var(--ggui-color-onContainer, #111827)" : resolveToneCss("subtle")
27907
27921
  }, children: item.icon }), isLast ? (0, import_jsx_runtime37.jsx)("span", { style: {
27908
27922
  color: "var(--ggui-color-onContainer, #111827)",
27909
27923
  fontWeight: 500
@@ -27916,7 +27930,7 @@ function Breadcrumb({ items, separator = "/", onItemClick, style, className }) {
27916
27930
  background: "none",
27917
27931
  border: "none",
27918
27932
  padding: 0,
27919
- color: "var(--ggui-color-neutral-500, #6b7280)",
27933
+ color: resolveToneCss("subtle"),
27920
27934
  cursor: "pointer",
27921
27935
  fontSize: "inherit"
27922
27936
  }, children: item.label })] }, index);
@@ -28627,7 +28641,7 @@ function CommentItem({ comment, onReply, onReaction, depth = 0 }) {
28627
28641
  }
28628
28642
  };
28629
28643
  const timestamp = comment.timestamp instanceof Date ? comment.timestamp.toLocaleString() : comment.timestamp;
28630
- return (0, import_jsx_runtime46.jsxs)("div", { style: { marginLeft: depth > 0 ? "40px" : 0 }, children: [(0, import_jsx_runtime46.jsxs)("div", { style: { display: "flex", gap: "12px" }, children: [(0, import_jsx_runtime46.jsx)(Avatar, { name: comment.author.name, src: comment.author.avatar, size: "sm" }), (0, import_jsx_runtime46.jsxs)("div", { style: { flex: 1 }, children: [(0, import_jsx_runtime46.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: [(0, import_jsx_runtime46.jsx)("span", { style: { fontWeight: 500, fontSize: fontSize.sm }, children: comment.author.name }), (0, import_jsx_runtime46.jsx)("span", { style: { color: "var(--ggui-color-neutral-500, #6b7280)", fontSize: fontSize.xs }, children: timestamp })] }), (0, import_jsx_runtime46.jsx)("p", { style: { margin: "4px 0 8px", fontSize: fontSize.sm, color: "var(--ggui-color-onContainer, #374151)" }, children: comment.content }), (0, import_jsx_runtime46.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: "12px" }, children: [comment.reactions?.map((reaction) => (0, import_jsx_runtime46.jsxs)("button", { onClick: () => onReaction?.(comment.id, reaction.emoji), style: {
28644
+ return (0, import_jsx_runtime46.jsxs)("div", { style: { marginLeft: depth > 0 ? "40px" : 0 }, children: [(0, import_jsx_runtime46.jsxs)("div", { style: { display: "flex", gap: "12px" }, children: [(0, import_jsx_runtime46.jsx)(Avatar, { name: comment.author.name, src: comment.author.avatar, size: "sm" }), (0, import_jsx_runtime46.jsxs)("div", { style: { flex: 1 }, children: [(0, import_jsx_runtime46.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: [(0, import_jsx_runtime46.jsx)("span", { style: { fontWeight: 500, fontSize: fontSize.sm }, children: comment.author.name }), (0, import_jsx_runtime46.jsx)("span", { style: { color: resolveToneCss("subtle"), fontSize: fontSize.xs }, children: timestamp })] }), (0, import_jsx_runtime46.jsx)("p", { style: { margin: "4px 0 8px", fontSize: fontSize.sm, color: "var(--ggui-color-onContainer, #374151)" }, children: comment.content }), (0, import_jsx_runtime46.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: "12px" }, children: [comment.reactions?.map((reaction) => (0, import_jsx_runtime46.jsxs)("button", { onClick: () => onReaction?.(comment.id, reaction.emoji), style: {
28631
28645
  padding: "2px 8px",
28632
28646
  border: `1px solid var(--ggui-color-outlineVariant, #e5e7eb)`,
28633
28647
  borderRadius: "12px",
@@ -28637,7 +28651,7 @@ function CommentItem({ comment, onReply, onReaction, depth = 0 }) {
28637
28651
  }, children: [reaction.emoji, " ", reaction.count] }, reaction.emoji)), (0, import_jsx_runtime46.jsx)("button", { onClick: () => setShowReplyInput(!showReplyInput), style: {
28638
28652
  background: "none",
28639
28653
  border: "none",
28640
- color: "var(--ggui-color-neutral-500, #6b7280)",
28654
+ color: resolveToneCss("subtle"),
28641
28655
  fontSize: fontSize.xs,
28642
28656
  cursor: "pointer"
28643
28657
  }, children: "Reply" })] }), showReplyInput && (0, import_jsx_runtime46.jsxs)("div", { style: { marginTop: "12px" }, children: [(0, import_jsx_runtime46.jsx)(TextArea, { value: replyContent, onChange: setReplyContent, placeholder: "Write a reply...", rows: 2 }), (0, import_jsx_runtime46.jsxs)("div", { style: { display: "flex", gap: "8px", marginTop: "8px" }, children: [(0, import_jsx_runtime46.jsx)(Button, { size: "sm", onClick: handleSubmitReply, children: "Reply" }), (0, import_jsx_runtime46.jsx)(Button, { size: "sm", variant: "ghost", onClick: () => setShowReplyInput(false), children: "Cancel" })] })] })] })] }), comment.replies?.map((reply) => (0, import_jsx_runtime46.jsx)("div", { style: { marginTop: "16px" }, children: (0, import_jsx_runtime46.jsx)(CommentItem, { comment: reply, onReply, onReaction, depth: depth + 1 }) }, reply.id))] });
@@ -28692,7 +28706,7 @@ function DataTable({ columns, data, rowKey = "id", loading, emptyText = "No data
28692
28706
  borderBottom: "1px solid var(--ggui-color-outlineVariant, #e5e7eb)",
28693
28707
  cursor: col.sortable ? "pointer" : void 0,
28694
28708
  width: col.width
28695
- }, onClick: () => col.sortable && onSort?.(col.key, sortKey === col.key && sortDirection === "asc" ? "desc" : "asc"), children: (0, import_jsx_runtime47.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: "4px" }, children: [col.header, col.sortable && sortKey === col.key && (0, import_jsx_runtime47.jsx)(Icon, { name: sortDirection === "asc" ? "chevron-up" : "chevron-down", size: 14 })] }) }, col.key))] }) }), (0, import_jsx_runtime47.jsx)("tbody", { children: loading ? (0, import_jsx_runtime47.jsx)("tr", { children: (0, import_jsx_runtime47.jsx)("td", { colSpan: columns.length + (selectable ? 1 : 0), style: { padding: "48px", textAlign: "center" }, children: (0, import_jsx_runtime47.jsx)(Spinner, { size: 24 }) }) }) : data.length === 0 ? (0, import_jsx_runtime47.jsx)("tr", { children: (0, import_jsx_runtime47.jsx)("td", { colSpan: columns.length + (selectable ? 1 : 0), style: { padding: "48px", textAlign: "center", color: "var(--ggui-color-neutral-500, #6b7280)" }, children: emptyText }) }) : data.map((row, index) => {
28709
+ }, onClick: () => col.sortable && onSort?.(col.key, sortKey === col.key && sortDirection === "asc" ? "desc" : "asc"), children: (0, import_jsx_runtime47.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: "4px" }, children: [col.header, col.sortable && sortKey === col.key && (0, import_jsx_runtime47.jsx)(Icon, { name: sortDirection === "asc" ? "chevron-up" : "chevron-down", size: 14 })] }) }, col.key))] }) }), (0, import_jsx_runtime47.jsx)("tbody", { children: loading ? (0, import_jsx_runtime47.jsx)("tr", { children: (0, import_jsx_runtime47.jsx)("td", { colSpan: columns.length + (selectable ? 1 : 0), style: { padding: "48px", textAlign: "center" }, children: (0, import_jsx_runtime47.jsx)(Spinner, { size: 24 }) }) }) : data.length === 0 ? (0, import_jsx_runtime47.jsx)("tr", { children: (0, import_jsx_runtime47.jsx)("td", { colSpan: columns.length + (selectable ? 1 : 0), style: { padding: "48px", textAlign: "center", color: resolveToneCss("subtle") }, children: emptyText }) }) : data.map((row, index) => {
28696
28710
  const key = getRowKey(row, index);
28697
28711
  const isSelected = selectedKeys.includes(key);
28698
28712
  return (0, import_jsx_runtime47.jsxs)("tr", { onClick: () => onRowClick?.(row, index), style: {
@@ -28757,16 +28771,19 @@ function ChatWindow({ messages, currentUserId, onSendMessage, loading, typing, p
28757
28771
  padding: "10px 14px",
28758
28772
  borderRadius: radius.lg,
28759
28773
  backgroundColor: isOwn ? "var(--ggui-color-primary-600, #0284c7)" : "var(--ggui-color-sunken, #f3f4f6)",
28760
- color: isOwn ? "var(--ggui-color-onPrimary, #ffffff)" : "var(--ggui-color-onSunken, #111827)"
28774
+ color: isOwn ? "var(--ggui-color-onPrimary, #ffffff)" : "var(--ggui-color-onContainer, #111827)"
28761
28775
  }, children: [(0, import_jsx_runtime48.jsx)("p", { style: { margin: 0, fontSize: fontSize.sm }, children: message.content }), (0, import_jsx_runtime48.jsxs)("div", { style: {
28762
28776
  display: "flex",
28763
28777
  alignItems: "center",
28764
28778
  gap: "4px",
28765
28779
  marginTop: "4px",
28766
28780
  fontSize: fontSize.xs,
28767
- opacity: 0.7
28781
+ // Own messages derive the muted line from onPrimary; the other
28782
+ // party's message now reads at onContainer, so its timestamp
28783
+ // takes the muted tier itself (ggui#1566).
28784
+ ...isOwn ? { opacity: 0.7 } : { color: "var(--ggui-color-onSunken, #52525b)" }
28768
28785
  }, children: [(0, import_jsx_runtime48.jsx)("span", { children: timestamp }), isOwn && message.status && (0, import_jsx_runtime48.jsxs)("span", { children: [message.status === "sending" && "\u2022", message.status === "sent" && "\u2713", message.status === "delivered" && "\u2713\u2713", message.status === "read" && "\u2713\u2713", message.status === "error" && "!"] })] })] })] }, message.id);
28769
- }), typing && (0, import_jsx_runtime48.jsx)("div", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: (0, import_jsx_runtime48.jsxs)("span", { style: { fontSize: fontSize.xs, color: "var(--ggui-color-neutral-500, #6b7280)" }, children: [typing.name, " is typing..."] }) }), (0, import_jsx_runtime48.jsx)("div", { ref: messagesEndRef })] }), (0, import_jsx_runtime48.jsxs)("div", { style: {
28786
+ }), typing && (0, import_jsx_runtime48.jsx)("div", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: (0, import_jsx_runtime48.jsxs)("span", { style: { fontSize: fontSize.xs, color: resolveToneCss("subtle") }, children: [typing.name, " is typing..."] }) }), (0, import_jsx_runtime48.jsx)("div", { ref: messagesEndRef })] }), (0, import_jsx_runtime48.jsxs)("div", { style: {
28770
28787
  padding: "12px 16px",
28771
28788
  borderTop: `1px solid var(--ggui-color-outlineVariant, #e5e7eb)`,
28772
28789
  display: "flex",
@@ -28774,7 +28791,7 @@ function ChatWindow({ messages, currentUserId, onSendMessage, loading, typing, p
28774
28791
  }, children: [(0, import_jsx_runtime48.jsx)("input", { type: "text", value: inputValue, onChange: (e) => setInputValue(e.target.value), onKeyDown: handleKeyDown, placeholder, style: {
28775
28792
  flex: 1,
28776
28793
  padding: "10px 14px",
28777
- border: `1px solid var(--ggui-color-outline, #d1d5db)`,
28794
+ border: `1px solid var(--ggui-color-controlOutline, var(--ggui-color-outline, #d1d5db))`,
28778
28795
  borderRadius: radius.full,
28779
28796
  fontSize: fontSize.sm,
28780
28797
  outline: "none"
@@ -28879,7 +28896,7 @@ function FileUploader({ files = [], onFilesSelected, onFileRemove, accept, multi
28879
28896
  setIsDragOver(false);
28880
28897
  };
28881
28898
  return (0, import_jsx_runtime50.jsxs)("div", { className, style: { ...style }, children: [(0, import_jsx_runtime50.jsxs)("div", { onClick: () => !disabled && inputRef.current?.click(), onDrop: handleDrop, onDragOver: handleDragOver, onDragLeave: handleDragLeave, style: {
28882
- border: `2px dashed ${isDragOver ? "var(--ggui-color-primary-400, #38bdf8)" : "var(--ggui-color-outline, #d1d5db)"}`,
28899
+ border: `2px dashed ${isDragOver ? "var(--ggui-color-primary-400, #38bdf8)" : "var(--ggui-color-controlOutline, var(--ggui-color-outline, #d1d5db))"}`,
28883
28900
  borderRadius: radius.lg,
28884
28901
  padding: "32px",
28885
28902
  textAlign: "center",
@@ -28887,7 +28904,7 @@ function FileUploader({ files = [], onFilesSelected, onFileRemove, accept, multi
28887
28904
  cursor: disabled ? "not-allowed" : "pointer",
28888
28905
  transition: "all 0.2s",
28889
28906
  opacity: disabled ? 0.5 : 1
28890
- }, children: [(0, import_jsx_runtime50.jsx)("input", { ref: inputRef, type: "file", accept, multiple, onChange: (e) => handleFiles(e.target.files), disabled, style: { display: "none" } }), (0, import_jsx_runtime50.jsx)(Icon, { name: "plus", size: 32, tone: "subtle" }), (0, import_jsx_runtime50.jsx)("p", { style: { margin: "12px 0 4px", color: "var(--ggui-color-onContainer, #374151)", fontSize: fontSize.sm }, children: dragDrop ? "Drag and drop files here, or click to browse" : "Click to browse files" }), (0, import_jsx_runtime50.jsxs)("p", { style: { margin: 0, color: "var(--ggui-color-neutral-500, #6b7280)", fontSize: fontSize.xs }, children: [accept && `Accepted: ${accept}`, maxSize && ` \u2022 Max size: ${formatFileSize(maxSize)}`, maxFiles && ` \u2022 Max files: ${maxFiles}`] })] }), files.length > 0 && (0, import_jsx_runtime50.jsx)("div", { style: { marginTop: "16px", display: "flex", flexDirection: "column", gap: "8px" }, children: files.map((file) => (0, import_jsx_runtime50.jsxs)("div", { style: {
28907
+ }, children: [(0, import_jsx_runtime50.jsx)("input", { ref: inputRef, type: "file", accept, multiple, onChange: (e) => handleFiles(e.target.files), disabled, style: { display: "none" } }), (0, import_jsx_runtime50.jsx)(Icon, { name: "plus", size: 32, tone: "subtle" }), (0, import_jsx_runtime50.jsx)("p", { style: { margin: "12px 0 4px", color: "var(--ggui-color-onContainer, #374151)", fontSize: fontSize.sm }, children: dragDrop ? "Drag and drop files here, or click to browse" : "Click to browse files" }), (0, import_jsx_runtime50.jsxs)("p", { style: { margin: 0, color: resolveToneCss("subtle"), fontSize: fontSize.xs }, children: [accept && `Accepted: ${accept}`, maxSize && ` \u2022 Max size: ${formatFileSize(maxSize)}`, maxFiles && ` \u2022 Max files: ${maxFiles}`] })] }), files.length > 0 && (0, import_jsx_runtime50.jsx)("div", { style: { marginTop: "16px", display: "flex", flexDirection: "column", gap: "8px" }, children: files.map((file) => (0, import_jsx_runtime50.jsxs)("div", { style: {
28891
28908
  display: "flex",
28892
28909
  alignItems: "center",
28893
28910
  gap: "12px",
@@ -28902,7 +28919,7 @@ function FileUploader({ files = [], onFilesSelected, onFileRemove, accept, multi
28902
28919
  whiteSpace: "nowrap",
28903
28920
  overflow: "hidden",
28904
28921
  textOverflow: "ellipsis"
28905
- }, children: file.name }), (0, import_jsx_runtime50.jsxs)("p", { style: { margin: "2px 0 0", fontSize: fontSize.xs, color: "var(--ggui-color-neutral-500, #6b7280)" }, children: [formatFileSize(file.size), file.error && (0, import_jsx_runtime50.jsx)("span", { style: { color: "var(--ggui-color-error-500, #ef4444)", marginLeft: "8px" }, children: file.error })] }), file.status === "uploading" && file.progress !== void 0 && (0, import_jsx_runtime50.jsx)(Progress, { value: file.progress, size: "sm", style: { marginTop: "8px" } })] }), (0, import_jsx_runtime50.jsx)(Button, { variant: "ghost", size: "sm", onClick: () => onFileRemove?.(file.id), children: (0, import_jsx_runtime50.jsx)(Icon, { name: "x", size: 16 }) })] }, file.id)) })] });
28922
+ }, children: file.name }), (0, import_jsx_runtime50.jsxs)("p", { style: { margin: "2px 0 0", fontSize: fontSize.xs, color: resolveToneCss("subtle") }, children: [formatFileSize(file.size), file.error && (0, import_jsx_runtime50.jsx)("span", { style: { color: "var(--ggui-color-error-500, #ef4444)", marginLeft: "8px" }, children: file.error })] }), file.status === "uploading" && file.progress !== void 0 && (0, import_jsx_runtime50.jsx)(Progress, { value: file.progress, size: "sm", style: { marginTop: "8px" } })] }), (0, import_jsx_runtime50.jsx)(Button, { variant: "ghost", size: "sm", onClick: () => onFileRemove?.(file.id), children: (0, import_jsx_runtime50.jsx)(Icon, { name: "x", size: 16 }) })] }, file.id)) })] });
28906
28923
  }
28907
28924
  var variantColors2 = {
28908
28925
  info: "var(--ggui-color-info-500, #06b6d4)",
@@ -28917,7 +28934,10 @@ function NotificationItem({ notification, onMarkAsRead, onDismiss }) {
28917
28934
  display: "flex",
28918
28935
  gap: "12px",
28919
28936
  padding: "12px",
28920
- backgroundColor: notification.read ? "transparent" : "var(--ggui-color-primaryContainer, #f0f9ff)",
28937
+ // Unread is carried by the dot and the title's weight; the row takes the
28938
+ // ground its muted text is measured on (ggui#1567), not a raised accent
28939
+ // ground where that text falls under AA in dark themes.
28940
+ backgroundColor: notification.read ? "transparent" : "var(--ggui-color-sunken, #f4f4f5)",
28921
28941
  borderRadius: radius.md,
28922
28942
  transition: "background-color 0.15s"
28923
28943
  }, children: [(0, import_jsx_runtime51.jsx)("div", { style: {
@@ -28943,7 +28963,7 @@ function NotificationItem({ notification, onMarkAsRead, onDismiss }) {
28943
28963
  margin: "4px 0 0",
28944
28964
  color: "var(--ggui-color-onSunken, #4b5563)",
28945
28965
  fontSize: fontSize.xs
28946
- }, children: notification.message }), (0, import_jsx_runtime51.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: "12px", marginTop: "8px" }, children: [(0, import_jsx_runtime51.jsx)("span", { style: { color: "var(--ggui-color-neutral-400, #9ca3af)", fontSize: fontSize.xs }, children: timestamp }), !notification.read && (0, import_jsx_runtime51.jsx)("button", { onClick: () => onMarkAsRead?.(notification.id), style: {
28966
+ }, children: notification.message }), (0, import_jsx_runtime51.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: "12px", marginTop: "8px" }, children: [(0, import_jsx_runtime51.jsx)("span", { style: { color: resolveToneCss("subtle"), fontSize: fontSize.xs }, children: timestamp }), !notification.read && (0, import_jsx_runtime51.jsx)("button", { onClick: () => onMarkAsRead?.(notification.id), style: {
28947
28967
  background: "none",
28948
28968
  border: "none",
28949
28969
  padding: 0,
@@ -28978,7 +28998,7 @@ function NotificationCenter({ notifications, onMarkAsRead, onMarkAllAsRead, onDi
28978
28998
  color: "var(--ggui-color-onPrimaryContainer, #0369a1)",
28979
28999
  fontSize: fontSize.xs,
28980
29000
  fontWeight: fontWeight.medium
28981
- }, children: unreadCount })] }), (0, import_jsx_runtime51.jsxs)("div", { style: { display: "flex", gap: "8px" }, children: [unreadCount > 0 && (0, import_jsx_runtime51.jsx)(Button, { variant: "ghost", size: "sm", onClick: onMarkAllAsRead, children: "Mark all read" }), notifications.length > 0 && (0, import_jsx_runtime51.jsx)(Button, { variant: "ghost", size: "sm", onClick: onClearAll, children: "Clear all" })] })] }), (0, import_jsx_runtime51.jsx)("div", { style: { flex: 1, overflowY: "auto", padding: "8px" }, children: loading ? (0, import_jsx_runtime51.jsx)("div", { style: { display: "flex", justifyContent: "center", padding: "32px" }, children: (0, import_jsx_runtime51.jsx)(Spinner, { size: 24 }) }) : notifications.length === 0 ? (0, import_jsx_runtime51.jsx)("div", { style: { textAlign: "center", padding: "32px", color: "var(--ggui-color-neutral-500, #6b7280)" }, children: emptyText }) : (0, import_jsx_runtime51.jsx)("div", { style: { display: "flex", flexDirection: "column", gap: "4px" }, children: notifications.map((notification) => (0, import_jsx_runtime51.jsx)(NotificationItem, { notification, onMarkAsRead, onDismiss }, notification.id)) }) })] });
29001
+ }, children: unreadCount })] }), (0, import_jsx_runtime51.jsxs)("div", { style: { display: "flex", gap: "8px" }, children: [unreadCount > 0 && (0, import_jsx_runtime51.jsx)(Button, { variant: "ghost", size: "sm", onClick: onMarkAllAsRead, children: "Mark all read" }), notifications.length > 0 && (0, import_jsx_runtime51.jsx)(Button, { variant: "ghost", size: "sm", onClick: onClearAll, children: "Clear all" })] })] }), (0, import_jsx_runtime51.jsx)("div", { style: { flex: 1, overflowY: "auto", padding: "8px" }, children: loading ? (0, import_jsx_runtime51.jsx)("div", { style: { display: "flex", justifyContent: "center", padding: "32px" }, children: (0, import_jsx_runtime51.jsx)(Spinner, { size: 24 }) }) : notifications.length === 0 ? (0, import_jsx_runtime51.jsx)("div", { style: { textAlign: "center", padding: "32px", color: resolveToneCss("subtle") }, children: emptyText }) : (0, import_jsx_runtime51.jsx)("div", { style: { display: "flex", flexDirection: "column", gap: "4px" }, children: notifications.map((notification) => (0, import_jsx_runtime51.jsx)(NotificationItem, { notification, onMarkAsRead, onDismiss }, notification.id)) }) })] });
28982
29002
  }
28983
29003
  var sizeWidths = {
28984
29004
  sm: "400px",
@@ -29160,11 +29180,11 @@ function CommandPalette({ open, onClose, commands, onSelect, placeholder = "Sear
29160
29180
  fontSize: fontSize.base,
29161
29181
  outline: "none",
29162
29182
  backgroundColor: "transparent"
29163
- } })] }) }), (0, import_jsx_runtime53.jsx)("div", { style: { flex: 1, overflowY: "auto", padding: "8px" }, children: loading ? (0, import_jsx_runtime53.jsx)("div", { style: { display: "flex", justifyContent: "center", padding: "32px" }, children: (0, import_jsx_runtime53.jsx)(Spinner, { size: 24 }) }) : flatCommands.length === 0 ? (0, import_jsx_runtime53.jsx)("div", { style: { textAlign: "center", padding: "32px", color: "var(--ggui-color-neutral-500, #6b7280)" }, children: "No commands found" }) : Array.from(filteredCommands.entries()).map(([group, cmds]) => (0, import_jsx_runtime53.jsxs)("div", { style: { marginBottom: "8px" }, children: [(0, import_jsx_runtime53.jsx)("div", { style: {
29183
+ } })] }) }), (0, import_jsx_runtime53.jsx)("div", { style: { flex: 1, overflowY: "auto", padding: "8px" }, children: loading ? (0, import_jsx_runtime53.jsx)("div", { style: { display: "flex", justifyContent: "center", padding: "32px" }, children: (0, import_jsx_runtime53.jsx)(Spinner, { size: 24 }) }) : flatCommands.length === 0 ? (0, import_jsx_runtime53.jsx)("div", { style: { textAlign: "center", padding: "32px", color: resolveToneCss("subtle") }, children: "No commands found" }) : Array.from(filteredCommands.entries()).map(([group, cmds]) => (0, import_jsx_runtime53.jsxs)("div", { style: { marginBottom: "8px" }, children: [(0, import_jsx_runtime53.jsx)("div", { style: {
29164
29184
  padding: "8px 12px",
29165
29185
  fontSize: fontSize.xs,
29166
29186
  fontWeight: fontWeight.semibold,
29167
- color: "var(--ggui-color-neutral-500, #6b7280)",
29187
+ color: resolveToneCss("subtle"),
29168
29188
  textTransform: "uppercase",
29169
29189
  letterSpacing: "0.05em"
29170
29190
  }, children: group }), cmds.map((cmd) => {
@@ -29187,12 +29207,12 @@ function CommandPalette({ open, onClose, commands, onSelect, placeholder = "Sear
29187
29207
  color: cmd.disabled ? "var(--ggui-color-neutral-400, #9ca3af)" : "var(--ggui-color-onElevated, #111827)",
29188
29208
  textAlign: "left",
29189
29209
  cursor: cmd.disabled ? "not-allowed" : "pointer"
29190
- }, children: [cmd.icon && (0, import_jsx_runtime53.jsx)("span", { style: { display: "flex", color: "var(--ggui-color-neutral-500, #6b7280)" }, children: cmd.icon }), (0, import_jsx_runtime53.jsxs)("div", { style: { flex: 1 }, children: [(0, import_jsx_runtime53.jsx)("div", { style: { fontSize: fontSize.sm }, children: cmd.label }), cmd.description && (0, import_jsx_runtime53.jsx)("div", { style: { fontSize: fontSize.xs, color: "var(--ggui-color-neutral-500, #6b7280)" }, children: cmd.description })] }), cmd.shortcut && (0, import_jsx_runtime53.jsx)("kbd", { style: {
29210
+ }, children: [cmd.icon && (0, import_jsx_runtime53.jsx)("span", { style: { display: "flex", color: resolveToneCss("subtle") }, children: cmd.icon }), (0, import_jsx_runtime53.jsxs)("div", { style: { flex: 1 }, children: [(0, import_jsx_runtime53.jsx)("div", { style: { fontSize: fontSize.sm }, children: cmd.label }), cmd.description && (0, import_jsx_runtime53.jsx)("div", { style: { fontSize: fontSize.xs, color: resolveToneCss("subtle") }, children: cmd.description })] }), cmd.shortcut && (0, import_jsx_runtime53.jsx)("kbd", { style: {
29191
29211
  padding: "2px 6px",
29192
29212
  backgroundColor: "var(--ggui-color-sunken, #f3f4f6)",
29193
29213
  borderRadius: radius.sm,
29194
29214
  fontSize: fontSize.xs,
29195
- color: "var(--ggui-color-neutral-500, #6b7280)",
29215
+ color: resolveToneCss("subtle"),
29196
29216
  fontFamily: "inherit"
29197
29217
  }, children: cmd.shortcut })] }, cmd.id);
29198
29218
  })] }, group)) }), (0, import_jsx_runtime53.jsxs)("div", { style: {
@@ -29202,7 +29222,7 @@ function CommandPalette({ open, onClose, commands, onSelect, placeholder = "Sear
29202
29222
  alignItems: "center",
29203
29223
  gap: "16px",
29204
29224
  fontSize: fontSize.xs,
29205
- color: "var(--ggui-color-neutral-500, #6b7280)"
29225
+ color: resolveToneCss("subtle")
29206
29226
  }, children: [(0, import_jsx_runtime53.jsx)("span", { children: "\u2191\u2193 Navigate" }), (0, import_jsx_runtime53.jsx)("span", { children: "\u21B5 Select" }), (0, import_jsx_runtime53.jsx)("span", { children: "Esc Close" })] })] })] });
29207
29227
  }
29208
29228
  function Footer({ brand, columns, socialLinks, bottomText, bottomLinks, background, bordered = true, style, className }) {
@@ -29252,20 +29272,20 @@ function Footer({ brand, columns, socialLinks, bottomText, bottomLinks, backgrou
29252
29272
  borderTop: "1px solid var(--ggui-color-outlineVariant, #e5e7eb)"
29253
29273
  }, children: [bottomText && (0, import_jsx_runtime54.jsx)("span", { style: {
29254
29274
  fontSize: fontSize.sm,
29255
- color: "var(--ggui-color-neutral-500, #6b7280)",
29275
+ color: resolveToneCss("subtle"),
29256
29276
  lineHeight: lineHeight.normal
29257
29277
  }, children: bottomText }), (0, import_jsx_runtime54.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: "20px" }, children: [socialLinks?.map((social, idx) => (0, import_jsx_runtime54.jsx)("a", { href: social.href, "aria-label": social.label, style: {
29258
29278
  display: "flex",
29259
29279
  alignItems: "center",
29260
29280
  justifyContent: "center",
29261
- color: "var(--ggui-color-neutral-500, #6b7280)",
29281
+ color: resolveToneCss("subtle"),
29262
29282
  transition: "color 0.15s"
29263
29283
  }, children: social.icon }, idx)), bottomLinks?.map((link, idx) => (0, import_jsx_runtime54.jsx)("a", { href: link.href, onClick: link.onClick ? (e) => {
29264
29284
  e.preventDefault();
29265
29285
  link.onClick?.();
29266
29286
  } : void 0, style: {
29267
29287
  fontSize: fontSize.sm,
29268
- color: "var(--ggui-color-neutral-500, #6b7280)",
29288
+ color: resolveToneCss("subtle"),
29269
29289
  textDecoration: "none",
29270
29290
  transition: "color 0.15s"
29271
29291
  }, children: link.label }, idx))] })] })] });
@@ -29345,7 +29365,7 @@ function Hero({ heading, description, primaryAction, secondaryAction, media, ali
29345
29365
  fontWeight: fontWeight.semibold,
29346
29366
  color: showOverlay ? "#ffffff" : "var(--ggui-color-onContainer, #374151)",
29347
29367
  backgroundColor: "transparent",
29348
- border: `1px solid ${showOverlay ? "rgba(255,255,255,0.3)" : "var(--ggui-color-outline, #d1d5db)"}`,
29368
+ border: `1px solid ${showOverlay ? "rgba(255,255,255,0.3)" : "var(--ggui-color-controlOutline, var(--ggui-color-outline, #d1d5db))"}`,
29349
29369
  borderRadius: "8px",
29350
29370
  cursor: "pointer",
29351
29371
  transition: "all 0.15s",
@@ -29467,6 +29487,8 @@ var consumed_tokens_manifest_default = {
29467
29487
  version: 2,
29468
29488
  tokens: [
29469
29489
  "--ggui-color-container",
29490
+ "--ggui-color-controlAccentOutline",
29491
+ "--ggui-color-controlOutline",
29470
29492
  "--ggui-color-elevated",
29471
29493
  "--ggui-color-error",
29472
29494
  "--ggui-color-error-100",
@@ -29820,11 +29842,11 @@ function readableOutline(bg, ink) {
29820
29842
  }
29821
29843
  return ink;
29822
29844
  }
29823
- function readableAccent(V, surface, ink) {
29845
+ function readableAccent(V, surface, ink, floor = 4.5) {
29824
29846
  const light = contrastRatio("#000000", surface) >= contrastRatio("#ffffff", surface);
29825
29847
  for (const stop of light ? ACCENT_WALK.light : ACCENT_WALK.dark) {
29826
29848
  const hex = V[`--ggui-color-primary-${stop}`];
29827
- if (hex !== void 0 && contrastRatio(hex, surface) >= 4.5)
29849
+ if (hex !== void 0 && contrastRatio(hex, surface) >= floor)
29828
29850
  return hex;
29829
29851
  }
29830
29852
  return ink;
@@ -29906,6 +29928,8 @@ function deriveThemeVariables(doc, mode, options = {}) {
29906
29928
  V["--ggui-color-onInverted"] = container;
29907
29929
  V["--ggui-color-inverseOutline"] = readableOutline(onContainer, container);
29908
29930
  V["--ggui-color-heroOutline"] = readableOutline(V["--ggui-color-heroGround"], V["--ggui-color-onHeroGround"]);
29931
+ V["--ggui-color-controlOutline"] = readableOutline(container, onContainer);
29932
+ V["--ggui-color-controlAccentOutline"] = readableAccent(V, container, onContainer, 3);
29909
29933
  const family = doc.font.family;
29910
29934
  const sans = tokenValue(family.sans) ?? fontFamily.sans;
29911
29935
  V["--ggui-font-family-sans"] = sans;
@@ -30543,8 +30567,10 @@ var gguiDark = {
30543
30567
  // paper
30544
30568
  sunken: { $value: "#292929", $type: "color" },
30545
30569
  // ink
30546
- onSunken: { $value: "#d9d9d9", $type: "color" },
30547
- // chrome
30570
+ // Muted text, and text on sunken grounds (ggui#1566): the kit's dark muted
30571
+ // value, 6.57:1 on container and 5.80:1 on sunken. Light's onSunken is ink-3,
30572
+ // the same tier, so dark now reads as light already does.
30573
+ onSunken: { $value: "#a3a3a9", $type: "color" },
30548
30574
  container: { $value: "#1f1f1f", $type: "color" },
30549
30575
  // ink
30550
30576
  onContainer: { $value: "#f4f3ed", $type: "color" },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ggui-ai/dev-stack",
3
- "version": "0.25.0",
3
+ "version": "0.27.0",
4
4
  "description": "Shared local dev engine for the ggui protocol: local UI registry discovery, compile-on-demand, filesystem watcher with SSE, and a read-only HTTP surface for dev tooling. Framework-neutral — agent runtime supervision plugs in via an adapter seam, so no agent SDK is hardcoded.",
5
5
  "keywords": [
6
6
  "ggui",
@@ -28,9 +28,9 @@
28
28
  "dependencies": {
29
29
  "chokidar": "^4.0.3",
30
30
  "esbuild": "^0.28.2",
31
- "@ggui-ai/agent-runtime": "0.25.0",
32
- "@ggui-ai/project-config": "0.25.0",
33
- "@ggui-ai/ui-registry": "0.25.0"
31
+ "@ggui-ai/agent-runtime": "0.27.0",
32
+ "@ggui-ai/project-config": "0.27.0",
33
+ "@ggui-ai/ui-registry": "0.27.0"
34
34
  },
35
35
  "devDependencies": {
36
36
  "@types/node": "^24.0.0",
@@ -40,9 +40,9 @@
40
40
  "react-dom": "^19.0.0",
41
41
  "typescript": "^5.0.0",
42
42
  "vitest": "^3.2.6",
43
- "@ggui-ai/design": "0.25.0",
44
- "@ggui-ai/mcp-apps-react": "0.25.0",
45
- "@ggui-ai/wire": "0.25.0"
43
+ "@ggui-ai/design": "0.27.0",
44
+ "@ggui-ai/mcp-apps-react": "0.27.0",
45
+ "@ggui-ai/wire": "0.27.0"
46
46
  },
47
47
  "repository": {
48
48
  "type": "git",