@comecaramelos/dsh-chrome-mcp 1.0.0 → 2.0.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.
Files changed (172) hide show
  1. package/README.md +44 -39
  2. package/lib/client.js +2186 -614
  3. package/lib/client.js.map +4 -4
  4. package/lib/host/apply.d.ts +38 -1
  5. package/lib/host/apply.d.ts.map +1 -1
  6. package/lib/host/apply.js +43 -17
  7. package/lib/host/apply.js.map +1 -1
  8. package/lib/host/bridge.d.ts +28 -19
  9. package/lib/host/bridge.d.ts.map +1 -1
  10. package/lib/host/bridge.js +71 -79
  11. package/lib/host/bridge.js.map +1 -1
  12. package/lib/host/catalog.d.ts +2 -2
  13. package/lib/host/catalog.js +2 -2
  14. package/lib/host/commands/chrome-path.d.ts +4 -0
  15. package/lib/host/commands/chrome-path.d.ts.map +1 -0
  16. package/lib/host/commands/chrome-path.js +65 -0
  17. package/lib/host/commands/chrome-path.js.map +1 -0
  18. package/lib/host/commands/chrome-refresh.d.ts +17 -0
  19. package/lib/host/commands/chrome-refresh.d.ts.map +1 -0
  20. package/lib/host/commands/chrome-refresh.js +37 -0
  21. package/lib/host/commands/chrome-refresh.js.map +1 -0
  22. package/lib/host/commands/index.d.ts +26 -0
  23. package/lib/host/commands/index.d.ts.map +1 -0
  24. package/lib/host/commands/index.js +41 -0
  25. package/lib/host/commands/index.js.map +1 -0
  26. package/lib/host/constants.d.ts +107 -30
  27. package/lib/host/constants.d.ts.map +1 -1
  28. package/lib/host/constants.js +107 -30
  29. package/lib/host/constants.js.map +1 -1
  30. package/lib/host/controller/_trace.d.ts +3 -0
  31. package/lib/host/controller/_trace.d.ts.map +1 -0
  32. package/lib/host/controller/_trace.js +14 -0
  33. package/lib/host/controller/_trace.js.map +1 -0
  34. package/lib/host/controller/bridge-run.d.ts +4 -2
  35. package/lib/host/controller/bridge-run.d.ts.map +1 -1
  36. package/lib/host/controller/bridge-run.js +24 -8
  37. package/lib/host/controller/bridge-run.js.map +1 -1
  38. package/lib/host/controller/captures.d.ts +9 -16
  39. package/lib/host/controller/captures.d.ts.map +1 -1
  40. package/lib/host/controller/captures.js +73 -48
  41. package/lib/host/controller/captures.js.map +1 -1
  42. package/lib/host/controller/commits.d.ts +2 -2
  43. package/lib/host/controller/commits.d.ts.map +1 -1
  44. package/lib/host/controller/commits.js +97 -41
  45. package/lib/host/controller/commits.js.map +1 -1
  46. package/lib/host/controller/connections.d.ts +38 -0
  47. package/lib/host/controller/connections.d.ts.map +1 -0
  48. package/lib/host/controller/connections.js +71 -0
  49. package/lib/host/controller/connections.js.map +1 -0
  50. package/lib/host/controller/controller.d.ts +19 -24
  51. package/lib/host/controller/controller.d.ts.map +1 -1
  52. package/lib/host/controller/controller.js +181 -114
  53. package/lib/host/controller/controller.js.map +1 -1
  54. package/lib/host/controller/index.d.ts +18 -14
  55. package/lib/host/controller/index.d.ts.map +1 -1
  56. package/lib/host/controller/index.js +16 -14
  57. package/lib/host/controller/index.js.map +1 -1
  58. package/lib/host/controller/notes.d.ts +9 -9
  59. package/lib/host/controller/notes.d.ts.map +1 -1
  60. package/lib/host/controller/notes.js +16 -21
  61. package/lib/host/controller/notes.js.map +1 -1
  62. package/lib/host/controller/persist.d.ts +10 -3
  63. package/lib/host/controller/persist.d.ts.map +1 -1
  64. package/lib/host/controller/persist.js +89 -42
  65. package/lib/host/controller/persist.js.map +1 -1
  66. package/lib/host/controller/publish.d.ts +4 -0
  67. package/lib/host/controller/publish.d.ts.map +1 -0
  68. package/lib/host/controller/publish.js +56 -0
  69. package/lib/host/controller/publish.js.map +1 -0
  70. package/lib/host/controller/runs.d.ts +34 -10
  71. package/lib/host/controller/runs.d.ts.map +1 -1
  72. package/lib/host/controller/runs.js +241 -58
  73. package/lib/host/controller/runs.js.map +1 -1
  74. package/lib/host/controller/state.d.ts +122 -20
  75. package/lib/host/controller/state.d.ts.map +1 -1
  76. package/lib/host/controller/windows-run.d.ts +10 -2
  77. package/lib/host/controller/windows-run.d.ts.map +1 -1
  78. package/lib/host/controller/windows-run.js +66 -35
  79. package/lib/host/controller/windows-run.js.map +1 -1
  80. package/lib/host/discovery/candidates.d.ts +23 -13
  81. package/lib/host/discovery/candidates.d.ts.map +1 -1
  82. package/lib/host/discovery/candidates.js +20 -8
  83. package/lib/host/discovery/candidates.js.map +1 -1
  84. package/lib/host/discovery/index.d.ts +1 -0
  85. package/lib/host/discovery/index.d.ts.map +1 -1
  86. package/lib/host/discovery/index.js +1 -0
  87. package/lib/host/discovery/index.js.map +1 -1
  88. package/lib/host/discovery/probe.d.ts +16 -5
  89. package/lib/host/discovery/probe.d.ts.map +1 -1
  90. package/lib/host/discovery/probe.js +68 -10
  91. package/lib/host/discovery/probe.js.map +1 -1
  92. package/lib/host/discovery/scan.d.ts +14 -9
  93. package/lib/host/discovery/scan.d.ts.map +1 -1
  94. package/lib/host/discovery/scan.js +56 -30
  95. package/lib/host/discovery/scan.js.map +1 -1
  96. package/lib/host/flags.d.ts +28 -5
  97. package/lib/host/flags.d.ts.map +1 -1
  98. package/lib/host/flags.js +75 -7
  99. package/lib/host/flags.js.map +1 -1
  100. package/lib/host/kind.d.ts +45 -0
  101. package/lib/host/kind.d.ts.map +1 -0
  102. package/lib/host/kind.js +251 -0
  103. package/lib/host/kind.js.map +1 -0
  104. package/lib/host/manager.d.ts +21 -0
  105. package/lib/host/manager.d.ts.map +1 -0
  106. package/lib/host/manager.js +113 -0
  107. package/lib/host/manager.js.map +1 -0
  108. package/lib/host/migration.d.ts +26 -0
  109. package/lib/host/migration.d.ts.map +1 -0
  110. package/lib/host/migration.js +127 -0
  111. package/lib/host/migration.js.map +1 -0
  112. package/lib/host/plugin-meta.d.ts +12 -3
  113. package/lib/host/plugin-meta.d.ts.map +1 -1
  114. package/lib/host/plugin-meta.js +13 -4
  115. package/lib/host/plugin-meta.js.map +1 -1
  116. package/lib/host/schema.d.ts +301 -247
  117. package/lib/host/schema.d.ts.map +1 -1
  118. package/lib/host/schema.js +145 -120
  119. package/lib/host/schema.js.map +1 -1
  120. package/lib/host/settings.d.ts +22 -3
  121. package/lib/host/settings.d.ts.map +1 -1
  122. package/lib/host/settings.js +81 -60
  123. package/lib/host/settings.js.map +1 -1
  124. package/lib/host/status.d.ts +7 -10
  125. package/lib/host/status.d.ts.map +1 -1
  126. package/lib/host/status.js +8 -23
  127. package/lib/host/status.js.map +1 -1
  128. package/lib/host/tool.d.ts +13 -7
  129. package/lib/host/tool.d.ts.map +1 -1
  130. package/lib/host/tool.js +4 -3
  131. package/lib/host/tool.js.map +1 -1
  132. package/lib/host/types/config.d.ts +66 -12
  133. package/lib/host/types/config.d.ts.map +1 -1
  134. package/lib/host/types/executable.d.ts +8 -3
  135. package/lib/host/types/executable.d.ts.map +1 -1
  136. package/lib/host/types/index.d.ts +5 -4
  137. package/lib/host/types/index.d.ts.map +1 -1
  138. package/lib/host/types/services.d.ts +26 -0
  139. package/lib/host/types/services.d.ts.map +1 -0
  140. package/lib/host/types/services.js +9 -0
  141. package/lib/host/types/services.js.map +1 -0
  142. package/lib/host/types/settings.d.ts +118 -65
  143. package/lib/host/types/settings.d.ts.map +1 -1
  144. package/lib/host/types/stderr.d.ts +3 -5
  145. package/lib/host/types/stderr.d.ts.map +1 -1
  146. package/lib/host/values.d.ts +152 -37
  147. package/lib/host/values.d.ts.map +1 -1
  148. package/lib/host/values.js +304 -112
  149. package/lib/host/values.js.map +1 -1
  150. package/lib/host/windows/connect-flags.d.ts +19 -8
  151. package/lib/host/windows/connect-flags.d.ts.map +1 -1
  152. package/lib/host/windows/connect-flags.js +50 -20
  153. package/lib/host/windows/connect-flags.js.map +1 -1
  154. package/lib/host/windows/index.d.ts +1 -1
  155. package/lib/host/windows/index.d.ts.map +1 -1
  156. package/lib/host/windows/index.js +1 -1
  157. package/lib/host/windows/index.js.map +1 -1
  158. package/lib/host/windows/paths.d.ts +27 -6
  159. package/lib/host/windows/paths.d.ts.map +1 -1
  160. package/lib/host/windows/paths.js +40 -13
  161. package/lib/host/windows/paths.js.map +1 -1
  162. package/lib/host/windows/run.d.ts.map +1 -1
  163. package/lib/host/windows/run.js +3 -2
  164. package/lib/host/windows/run.js.map +1 -1
  165. package/lib/index.d.ts +72 -56
  166. package/lib/index.d.ts.map +1 -1
  167. package/lib/index.js +74 -55
  168. package/lib/index.js.map +1 -1
  169. package/locale/en.json +6 -0
  170. package/locale/zh.json +6 -0
  171. package/package.json +35 -14
  172. package/cordis.patch.yml +0 -5
package/lib/client.js CHANGED
@@ -36,47 +36,1777 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
36
36
  // src/client/index.ts
37
37
  var index_exports = {};
38
38
  __export(index_exports, {
39
- CHECK_POLL_TICK_MS: () => CHECK_POLL_TICK_MS,
40
- CHECK_POLL_TIMEOUT_MS: () => CHECK_POLL_TIMEOUT_MS,
39
+ LIVE_KEYS: () => LIVE_KEYS,
40
+ RUN_SETTLE_TIMEOUT_MS: () => RUN_SETTLE_TIMEOUT_MS2,
41
41
  apply: () => apply,
42
+ card: () => card,
43
+ cardActions: () => cardActions,
44
+ cardState: () => cardState,
42
45
  inject: () => inject
43
46
  });
44
47
  module.exports = __toCommonJS(index_exports);
45
48
 
49
+ // node_modules/@comecaramelos/dsh-ancesters/lib/client.esm.js
50
+ var react4 = __toESM(require("react"), 1);
51
+ var import_jsx_runtime = require("react/jsx-runtime");
52
+ var react = __toESM(require("react"), 1);
53
+ var import_jsx_runtime2 = require("react/jsx-runtime");
54
+ var react2 = __toESM(require("react"), 1);
55
+ var import_jsx_runtime3 = require("react/jsx-runtime");
56
+ var import_jsx_runtime4 = require("react/jsx-runtime");
57
+ var import_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
58
+ var import_jsx_runtime5 = require("react/jsx-runtime");
59
+ var import_jsx_runtime6 = require("react/jsx-runtime");
60
+ var import_dsh_client_ui_primitives2 = require("@deepseek-ai/dsh-client-ui-primitives");
61
+ var import_jsx_runtime7 = require("react/jsx-runtime");
62
+ var react3 = __toESM(require("react"), 1);
63
+ var import_jsx_runtime8 = require("react/jsx-runtime");
64
+ var import_dsh_client_ui_primitives3 = require("@deepseek-ai/dsh-client-ui-primitives");
65
+ var import_jsx_runtime9 = require("react/jsx-runtime");
66
+ var import_dsh_client_ui_primitives4 = require("@deepseek-ai/dsh-client-ui-primitives");
67
+ var import_dsh_client_store = require("@deepseek-ai/dsh-client-store");
68
+ function rowConfigKey(pkgName, entryId) {
69
+ if (typeof pkgName !== "string" || pkgName === "") {
70
+ throw new Error("dsh-ancesters: rowConfigKey(pkg, entryId) requires a non-empty package name");
71
+ }
72
+ if (typeof entryId !== "string" || entryId === "") {
73
+ throw new Error("dsh-ancesters: rowConfigKey(pkg, entryId) requires a non-empty entry id");
74
+ }
75
+ return `${pkgName}#${entryId}`;
76
+ }
77
+ var cssText = '.qox3mn_body{flex-direction:column;gap:10px;display:flex}.qox3mn_field{align-items:flex-start;gap:4px;display:flex;flex-direction:column;width:100%}.qox3mn_fieldRow{align-items:center;gap:8px;display:flex;width:100%}.qox3mn_fieldTitle{color:var(--dsw-alias-label-primary);font-size:14px;font-weight:400;line-height:22px;flex:1;min-width:0}.qox3mn_fieldDesc{color:var(--dsw-alias-label-tertiary);font-size:12px;font-weight:400;line-height:18px;width:100%}.qox3mn_selector{background:var(--dsw-alias-bg-module-platform);height:36px;font:inherit;color:var(--dsw-alias-label-primary);cursor:pointer;border:none;border-radius:18px;align-items:center;gap:12px;padding:0 14px;font-size:14px;line-height:22px;display:inline-flex}.qox3mn_selector:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.qox3mn_selector:disabled{cursor:default}.qox3mn_selectorWrap{display:flex}.qox3mn_pillChevron{flex:none}.qox3mn_row{display:flex;gap:10px;align-items:center}.qox3mn_button{display:inline-flex;align-items:center;justify-content:center;gap:4px;border:.5px solid var(--dsw-alias-border-l3);border-radius:14px;cursor:pointer;font-size:12px;line-height:18px;color:var(--dsw-alias-label-primary);background:transparent;padding:0 10px;height:28px}.qox3mn_button:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.qox3mn_button:disabled{cursor:not-allowed;opacity:.4}.qox3mn_button:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}.qox3mn_readOnly{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px}.qox3mn_error{color:var(--dsw-alias-state-error-primary);margin:0;font-size:12px;line-height:1.5}.qox3mn_dot{box-sizing:border-box;corner-shape:round;border-radius:50%;flex:none;width:8px;height:8px;display:inline-block}.qox3mn_dotError{background:var(--dsw-alias-state-error-primary)}.qox3mn_badge{color:var(--dsw-alias-label-tertiary);background:var(--dsw-alias-bg-layer-1);border-radius:10px;padding:1px 8px;font-size:11px;line-height:16px;display:inline-flex;align-items:center;flex:none}.qox3mn_empty{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px}.qox3mn_catalog{flex-direction:column;align-items:stretch;gap:10px;display:flex}.qox3mn_catalog+.qox3mn_catalog{border-top:.5px solid var(--dsw-alias-border-l2);padding-top:12px}.qox3mn_catalog>.qox3mn_linkButton{align-self:flex-start}.qox3mn_catalog>.qox3mn_linkButtonRow{align-self:flex-start;display:flex;gap:8px;align-items:center}.qox3mn_linkButton{box-sizing:border-box;border:none;background:0 0;color:var(--dsw-alias-label-tertiary);cursor:pointer;border-radius:14px;align-items:center;height:28px;padding:0 10px;font:inherit;font-size:12px;line-height:18px;display:inline-flex}.qox3mn_linkButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-secondary)}.qox3mn_linkButton:disabled{opacity:.4;cursor:default}.qox3mn_linkButton:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}.qox3mn_rowList{flex-direction:column;align-items:stretch;gap:6px;display:flex}.qox3mn_rowList>button{align-self:flex-start}.qox3mn_catalogEntry{border:.5px solid var(--dsw-alias-border-l4);background:var(--dsw-alias-bg-module-platform);border-radius:10px;padding:6px}.qox3mn_catalogRow{grid-template-columns:minmax(0,1.4fr) minmax(0,1fr) auto;align-items:center;gap:6px;display:grid}.qox3mn_catalogInput{box-sizing:border-box;border:.5px solid var(--dsw-alias-border-l4);background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);border-radius:8px;height:28px;padding:0 10px;font:inherit;font-size:14px;line-height:22px;min-width:0;width:100%}.qox3mn_catalogInput::placeholder{color:var(--dsw-alias-label-dimmed)}.qox3mn_catalogInput:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:-1px}.qox3mn_catalogInput:disabled{opacity:.6;cursor:default}.qox3mn_iconButton{box-sizing:border-box;width:28px;height:28px;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:none;border-radius:6px;justify-content:center;align-items:center;display:inline-flex}.qox3mn_iconButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.qox3mn_iconButton:disabled{opacity:.4;cursor:default}.qox3mn_iconButton:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}.qox3mn_iconButtonDanger:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-danger);color:var(--dsw-alias-state-error-primary)}.qox3mn_addButton{box-sizing:border-box;border:.5px solid var(--dsw-alias-border-l3);color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border-radius:14px;align-self:flex-start;align-items:center;gap:4px;height:28px;padding:0 10px;font:inherit;font-size:12px;line-height:18px;display:inline-flex}.qox3mn_addButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.qox3mn_addButton:disabled{opacity:.4;cursor:default}.qox3mn_disclosure{flex-direction:column;gap:10px;display:flex}.qox3mn_disclosureSummary{color:var(--dsw-alias-label-secondary);cursor:pointer;list-style:none;align-items:center;gap:6px;font-size:12px;line-height:18px;user-select:none;display:flex}.qox3mn_disclosureSummary::-webkit-details-marker{display:none}.qox3mn_disclosureSummary:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px;border-radius:6px}.qox3mn_disclosureLabel:before{content:"\\25b8";display:inline-block;margin-right:6px;transition:transform .16s}.qox3mn_disclosure[open] .qox3mn_disclosureLabel:before{transform:rotate(90deg)}.qox3mn_disclosureCount{color:var(--dsw-alias-label-tertiary)}.qox3mn_disclosureBody{flex-direction:column;gap:10px;display:flex}.qox3mn_disclosureBody>.qox3mn_linkButton{align-self:flex-start}.qox3mn_disclosureBody>.qox3mn_linkButtonRow{align-self:flex-start;display:flex;gap:8px;align-items:center}.qox3mn_toggleLabel{align-items:center;display:inline-flex;flex:none}.qox3mn_fetchDialog{background:color-mix(in srgb,var(--dsw-alias-label-primary) 28%,transparent);align-items:center;justify-content:center;display:flex;position:fixed;inset:0;z-index:90}.qox3mn_dialogContent{background:var(--dsw-alias-bg-layer-3);border:.5px solid var(--dsw-alias-border-l3);border-radius:16px;flex-direction:column;gap:10px;width:min(520px,calc(100vw - 32px));max-height:min(620px,calc(100vh - 48px));display:flex;overflow:hidden}.qox3mn_dialogHeader{align-items:center;gap:8px;padding:14px 16px 0;display:flex}.qox3mn_dialogTitle{color:var(--dsw-alias-label-primary);font-size:15px;font-weight:600;line-height:22px;flex:1;min-width:0;margin:0}.qox3mn_dialogClose{box-sizing:border-box;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:none;border-radius:6px;justify-content:center;align-items:center;flex:none;width:28px;height:28px;display:inline-flex}.qox3mn_dialogClose:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.qox3mn_dialogClose:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}.qox3mn_dialogDescription{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px;margin:0;padding:0 16px}.qox3mn_dialogBody{flex-direction:column;flex:1;gap:8px;min-height:0;padding:0 16px;display:flex}.qox3mn_candidateToolbar{align-items:center;gap:8px;display:flex}.qox3mn_candidateSearch{box-sizing:border-box;border:.5px solid var(--dsw-alias-border-l4);background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);border-radius:8px;height:32px;padding:0 10px;font:inherit;font-size:12px;line-height:20px;flex:1;min-width:0}.qox3mn_candidateSearch::placeholder{color:var(--dsw-alias-label-dimmed)}.qox3mn_candidateSearch:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:-1px}.qox3mn_candidateList{flex-direction:column;gap:2px;margin:0;padding:0 0 10px;list-style:none;overflow-y:auto;display:flex}.qox3mn_candidate{border-radius:8px;padding:4px 6px}.qox3mn_candidate:hover{background:var(--dsw-alias-interactive-bg-hover)}.qox3mn_candidateLabel{align-items:center;gap:8px;min-width:0;display:flex}.qox3mn_candidateLabel input[type=checkbox]{accent-color:var(--dsw-alias-brand-primary);flex:none;margin:0}.qox3mn_candidateId{color:var(--dsw-alias-label-primary);font-size:12px;line-height:18px;text-overflow:ellipsis;white-space:nowrap;flex:1;min-width:0;overflow:hidden}.qox3mn_candidateNote{color:var(--dsw-alias-label-tertiary);flex:0 1 auto;min-width:0;overflow-wrap:anywhere;font-size:11px;line-height:16px}.qox3mn_dialogFooter{border-top:.5px solid var(--dsw-alias-border-l2);align-items:center;justify-content:flex-end;gap:8px;padding:12px 16px;display:flex}.qox3mn_dialogButton{display:inline-flex;align-items:center;justify-content:center;gap:4px;border:.5px solid var(--dsw-alias-border-l3);border-radius:16px;cursor:pointer;font-size:13px;line-height:20px;color:var(--dsw-alias-label-primary);background:transparent;padding:0 12px;height:32px}.qox3mn_dialogButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.qox3mn_dialogButton:disabled{cursor:not-allowed;opacity:.4}.qox3mn_dialogButton:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}.qox3mn_dialogButtonPrimary{color:var(--dsw-alias-label-primary);font-weight:600}.qox3mn_selectorLabel{text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}.qox3mn_result{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:18px}.qox3mn_resultValue{color:var(--dsw-alias-label-secondary);margin-left:4px}.qox3mn_resultAge{color:var(--dsw-alias-label-dimmed);margin-left:4px}.qox3mn_notice{flex-direction:column;gap:4px;display:flex;border:.5px solid var(--dsw-alias-border-l3);border-radius:10px;background:var(--dsw-alias-bg-layer-1);padding:8px 10px}.qox3mn_noticeTitle{color:var(--dsw-alias-label-primary);font-size:12px;font-weight:600;line-height:18px}.qox3mn_noticeBody{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px}.qox3mn_docsLink{color:var(--dsw-alias-label-tertiary);align-items:center;gap:4px;display:inline-flex;text-decoration:none;font-size:12px;line-height:1.5}.qox3mn_docsLinkLabel{text-decoration:none}.qox3mn_docsLink:hover{color:var(--dsw-alias-brand-primary)}.qox3mn_docsLink:hover .qox3mn_docsLinkLabel{text-decoration:underline}.qox3mn_docsLink:hover .qox3mn_docsIcon{color:var(--dsw-alias-brand-primary)}.qox3mn_docsIcon{color:var(--dsw-alias-label-tertiary);flex:none}.qox3mn_docsLink:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px;border-radius:4px}.qox3mn_catalogRowSingle{grid-template-columns:minmax(0,1fr) auto}.qox3mn_catalogInputMono{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px}.qox3mn_footer{border-top:.5px solid var(--dsw-alias-border-l2);align-items:center;justify-content:flex-end;gap:8px;padding:12px 0 0;display:flex}.qox3mn_footerError{color:var(--dsw-alias-label-error);text-align:right;min-width:0;flex:1;margin:0;font-size:12px;line-height:1.5}.qox3mn_footerButton{border:.5px solid var(--dsw-alias-border-l3);border-radius:8px;cursor:pointer;color:var(--dsw-alias-label-secondary);background:transparent;padding:5px 14px;font-size:13px;line-height:1.5}.qox3mn_footerButton:hover:not(:disabled){color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-label-dimmed)}.qox3mn_footerButton:disabled{cursor:default;opacity:.4}.qox3mn_footerButton:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}.qox3mn_footerButtonPrimary{color:var(--dsw-alias-bg-layer-3);font-weight:600;background:var(--dsw-alias-label-primary);border-color:transparent}.qox3mn_footerButtonPrimary:hover:not(:disabled){color:var(--dsw-alias-bg-layer-3);background:var(--dsw-alias-label-secondary);border-color:transparent}.qox3mn_liveLine{align-items:center;gap:8px;display:flex;padding:6px 10px;border:.5px solid var(--dsw-alias-border-l3);border-radius:8px;background:var(--dsw-alias-bg-layer-1)}.qox3mn_liveLine:hover{border-color:var(--dsw-alias-border-l4)}.qox3mn_liveText{flex:1;min-width:0;display:flex;align-items:center;gap:8px}.qox3mn_liveName{color:var(--dsw-alias-label-primary);font-size:14px;line-height:20px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.qox3mn_liveState{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.qox3mn_tools{flex:1 1 auto;min-width:0;display:flex;flex-wrap:wrap;gap:4px;color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:16px}.qox3mn_tools span{padding:0 6px;border:.5px solid var(--dsw-alias-border-l3);border-radius:6px;background:var(--dsw-alias-bg-module-platform)}.qox3mn_control{box-sizing:border-box;width:100%;min-width:0;height:28px;padding:0 10px;border:.5px solid var(--dsw-alias-border-l4);border-radius:8px;background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);font:inherit;font-size:14px;line-height:22px}.qox3mn_control::placeholder{color:var(--dsw-alias-label-dimmed)}.qox3mn_control:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:-1px}.qox3mn_control:disabled{opacity:.6;cursor:default}.qox3mn_textarea{box-sizing:border-box;width:100%;min-width:0;min-height:64px;padding:6px 10px;border:.5px solid var(--dsw-alias-border-l4);border-radius:8px;background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px;line-height:18px;resize:vertical}.qox3mn_textarea:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:-1px}.qox3mn_textarea:disabled{opacity:.6;cursor:default}.qox3mn_select{box-sizing:border-box;height:28px;min-width:0;padding:0 8px;border:.5px solid var(--dsw-alias-border-l4);border-radius:8px;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-primary);font:inherit;font-size:13px;line-height:22px}.qox3mn_select:disabled{opacity:.6;cursor:default}.qox3mn_checkbox{margin:0;accent-color:var(--dsw-alias-brand-primary)}.qox3mn_controlField{align-items:flex-start;gap:4px;display:flex;flex-direction:column;width:100%}.qox3mn_controlTitle{color:var(--dsw-alias-label-primary);font-size:12px;line-height:18px}.qox3mn_controlField .qox3mn_control,.qox3mn_controlField .qox3mn_textarea{margin-top:2px}.qox3mn_grid{display:grid;grid-template-columns:minmax(96px,20%) minmax(0,1fr);gap:6px 10px;align-items:center;width:100%}.qox3mn_grid>label{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px}.qox3mn_editor{gap:10px;display:flex;flex-direction:column;padding:10px;border:.5px solid var(--dsw-alias-border-l3);border-radius:10px;background:var(--dsw-alias-bg-layer-1)}.qox3mn_editorTitle{color:var(--dsw-alias-label-primary);font-size:14px;line-height:20px}.qox3mn_editorHint{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px}.qox3mn_editorActions{align-items:center;gap:8px;display:flex;justify-content:flex-end}.qox3mn_transport{color:var(--dsw-alias-label-tertiary);font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px;line-height:18px;word-break:break-all}.qox3mn_summary{color:var(--dsw-alias-label-secondary);font-size:13px;line-height:20px;display:flex;align-items:center;gap:6px}.qox3mn_summaryItem{color:var(--dsw-alias-label-primary);font-size:13px;line-height:20px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.qox3mn_summaryNone{color:var(--dsw-alias-label-tertiary);font-size:13px;line-height:20px}.qox3mn_summaryBroken{color:var(--dsw-alias-state-error-primary);font-size:13px;line-height:20px}.qox3mn_toastRoot{z-index:2147483000;flex-direction:column;gap:8px;display:flex;position:fixed;right:16px;bottom:16px;max-width:min(360px,50vw)}.qox3mn_toast{border:.5px solid var(--dsw-alias-border-l3);border-radius:10px;background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-secondary);padding:8px 10px;font-size:12px;line-height:18px;box-shadow:0 4px 12px #0000001f;overflow-wrap:anywhere}.qox3mn_toast[data-notice-kind=error]{border-color:var(--dsw-alias-state-error-primary);color:var(--dsw-alias-label-primary)}.qox3mn_toast[data-notice-kind=stall]{border-color:var(--dsw-alias-border-l4);color:var(--dsw-alias-label-tertiary)}.qox3mn_composerPills{display:inline-flex;gap:4px}.qox3mn_composerPillRoot{display:flex}.qox3mn_composerPill{min-width:0;max-width:220px;height:28px;font:inherit;font-size:13px;font-weight:500;line-height:20px;color:var(--dsw-alias-label-secondary);cursor:pointer;background:transparent;border:none;border-radius:24px;outline:none;align-items:center;gap:4px;padding:0 4px 0 8px;display:inline-flex}.qox3mn_composerPill:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.qox3mn_composerPill:disabled{cursor:default}.qox3mn_composerPillIcon{flex:none;display:inline-flex;color:var(--dsw-alias-label-secondary)}.qox3mn_composerPillLabel{text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}.qox3mn_composerPillChevron{color:var(--dsw-alias-label-caption);flex:none;transition:transform .12s;display:inline-flex}.qox3mn_composerPillChevronOpen{transform:rotate(180deg)}\n';
78
+ var shared_default = { "body": "qox3mn_body", "field": "qox3mn_field", "fieldRow": "qox3mn_fieldRow", "fieldTitle": "qox3mn_fieldTitle", "fieldDesc": "qox3mn_fieldDesc", "selector": "qox3mn_selector", "selectorWrap": "qox3mn_selectorWrap", "pillChevron": "qox3mn_pillChevron", "row": "qox3mn_row", "button": "qox3mn_button", "readOnly": "qox3mn_readOnly", "error": "qox3mn_error", "dot": "qox3mn_dot", "dotError": "qox3mn_dotError", "badge": "qox3mn_badge", "empty": "qox3mn_empty", "catalog": "qox3mn_catalog", "linkButton": "qox3mn_linkButton", "linkButtonRow": "qox3mn_linkButtonRow", "rowList": "qox3mn_rowList", "catalogEntry": "qox3mn_catalogEntry", "catalogRow": "qox3mn_catalogRow", "catalogInput": "qox3mn_catalogInput", "iconButton": "qox3mn_iconButton", "iconButtonDanger": "qox3mn_iconButtonDanger", "addButton": "qox3mn_addButton", "disclosure": "qox3mn_disclosure", "disclosureSummary": "qox3mn_disclosureSummary", "disclosureLabel": "qox3mn_disclosureLabel", "disclosureCount": "qox3mn_disclosureCount", "disclosureBody": "qox3mn_disclosureBody", "toggleLabel": "qox3mn_toggleLabel", "fetchDialog": "qox3mn_fetchDialog", "dialogContent": "qox3mn_dialogContent", "dialogHeader": "qox3mn_dialogHeader", "dialogTitle": "qox3mn_dialogTitle", "dialogClose": "qox3mn_dialogClose", "dialogDescription": "qox3mn_dialogDescription", "dialogBody": "qox3mn_dialogBody", "candidateToolbar": "qox3mn_candidateToolbar", "candidateSearch": "qox3mn_candidateSearch", "candidateList": "qox3mn_candidateList", "candidate": "qox3mn_candidate", "candidateLabel": "qox3mn_candidateLabel", "candidateId": "qox3mn_candidateId", "candidateNote": "qox3mn_candidateNote", "dialogFooter": "qox3mn_dialogFooter", "dialogButton": "qox3mn_dialogButton", "dialogButtonPrimary": "qox3mn_dialogButtonPrimary", "selectorLabel": "qox3mn_selectorLabel", "result": "qox3mn_result", "resultValue": "qox3mn_resultValue", "resultAge": "qox3mn_resultAge", "notice": "qox3mn_notice", "noticeTitle": "qox3mn_noticeTitle", "noticeBody": "qox3mn_noticeBody", "docsLink": "qox3mn_docsLink", "docsLinkLabel": "qox3mn_docsLinkLabel", "docsIcon": "qox3mn_docsIcon", "catalogRowSingle": "qox3mn_catalogRowSingle", "catalogInputMono": "qox3mn_catalogInputMono", "footer": "qox3mn_footer", "footerError": "qox3mn_footerError", "footerButton": "qox3mn_footerButton", "footerButtonPrimary": "qox3mn_footerButtonPrimary", "liveLine": "qox3mn_liveLine", "liveText": "qox3mn_liveText", "liveName": "qox3mn_liveName", "liveState": "qox3mn_liveState", "tools": "qox3mn_tools", "control": "qox3mn_control", "textarea": "qox3mn_textarea", "select": "qox3mn_select", "checkbox": "qox3mn_checkbox", "controlField": "qox3mn_controlField", "controlTitle": "qox3mn_controlTitle", "grid": "qox3mn_grid", "editor": "qox3mn_editor", "editorTitle": "qox3mn_editorTitle", "editorHint": "qox3mn_editorHint", "editorActions": "qox3mn_editorActions", "transport": "qox3mn_transport", "summary": "qox3mn_summary", "summaryItem": "qox3mn_summaryItem", "summaryNone": "qox3mn_summaryNone", "summaryBroken": "qox3mn_summaryBroken", "toastRoot": "qox3mn_toastRoot", "toast": "qox3mn_toast", "composerPills": "qox3mn_composerPills", "composerPillRoot": "qox3mn_composerPillRoot", "composerPill": "qox3mn_composerPill", "composerPillIcon": "qox3mn_composerPillIcon", "composerPillLabel": "qox3mn_composerPillLabel", "composerPillChevron": "qox3mn_composerPillChevron", "composerPillChevronOpen": "qox3mn_composerPillChevronOpen" };
79
+ var CHEVRON_PATH = "M11.8486 5.5L11.4238 5.92383L8.69727 8.65137C8.44157 8.90706 8.21562 9.13382 8.01172 9.29785C7.79912 9.46883 7.55595 9.61756 7.25 9.66602C7.08435 9.69222 6.91565 9.69222 6.75 9.66602C6.44405 9.61756 6.20088 9.46883 5.98828 9.29785C5.78438 9.13382 5.55843 8.90706 5.30273 8.65137L2.57617 5.92383L2.15137 5.5L3 4.65137L3.42383 5.07617L6.15137 7.80273C6.42595 8.07732 6.59876 8.24849 6.74023 8.3623C6.87291 8.46904 6.92272 8.47813 6.9375 8.48047C6.97895 8.48703 7.02105 8.48703 7.0625 8.48047C7.07728 8.47813 7.12709 8.46904 7.25977 8.3623C7.40124 8.24849 7.57405 8.07732 7.84863 7.80273L10.5762 5.07617L11 4.65137L11.8486 5.5Z";
80
+ var TRASH_PATH = "M2.5 4h11M6.5 4V2.5h3V4M4 4l.7 9a1 1 0 001 .9h4.6a1 1 0 001-.9L12 4M6.5 6.8v4.4M9.5 6.8v4.4";
81
+ var CLOSE_PATHS = [
82
+ "M14.1168 13.197L13.197 14.1167L1.8833 2.80303L2.80309 1.88324L14.1168 13.197Z",
83
+ "M13.197 1.88326L14.1168 2.80305L2.80309 14.1168L1.8833 13.197L13.197 1.88326Z"
84
+ ];
85
+ var DOCS_PATHS = [
86
+ "M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6",
87
+ "M15 3h6v6",
88
+ "M10 14 21 3"
89
+ ];
90
+ function RowsBlock(props) {
91
+ const served = Array.isArray(props.values) ? props.values : [];
92
+ const writable = props.writable === true;
93
+ const busy = props.busy === true;
94
+ const labels = Array.isArray(props.labels) ? props.labels : [];
95
+ const placeholders = Array.isArray(props.placeholders) ? props.placeholders : [];
96
+ const columns = Math.max(1, labels.length);
97
+ const blankRow = [];
98
+ for (let blank = 0; blank < columns; blank++) blankRow.push("");
99
+ const servedKey = JSON.stringify(served);
100
+ const draftState = react.useState({ key: "", rows: [] });
101
+ const draft = draftState[0];
102
+ const setDraft = draftState[1];
103
+ const rows = draft.key === servedKey ? draft.rows : served.map((row) => Array.from(row));
104
+ const write = (next) => {
105
+ const saved = props.save === void 0 ? void 0 : props.save(next);
106
+ return Promise.resolve(saved === void 0 ? void 0 : saved).then(
107
+ () => {
108
+ setDraft({ key: "", rows: [] });
109
+ },
110
+ (failure) => {
111
+ throw failure;
112
+ }
113
+ );
114
+ };
115
+ const setCell = (at, column, value) => {
116
+ const next = rows.map((row, index) => index === at ? row.map((cell, cellIndex) => cellIndex === column ? value : cell) : row.slice());
117
+ setDraft({ key: servedKey, rows: next });
118
+ };
119
+ const commit = () => {
120
+ const cleaned = [];
121
+ for (const row of rows) {
122
+ const cells = row.map((cell) => String(cell ?? "").trim());
123
+ if (cells.some((cell) => cell !== "")) cleaned.push(cells);
124
+ }
125
+ return write(cleaned);
126
+ };
127
+ const remove = (at) => {
128
+ return write(rows.filter((_row, index) => index !== at));
129
+ };
130
+ const add = () => {
131
+ setDraft({ key: servedKey, rows: rows.concat([blankRow.slice()]) });
132
+ };
133
+ const rowClass = props.rowClassName === void 0 || props.rowClassName === shared_default.catalogRow ? shared_default.catalogRow : shared_default.catalogRow + " " + props.rowClassName;
134
+ const inputClass = props.inputClassName === void 0 ? shared_default.catalogInput : props.inputClassName;
135
+ const list = (0, import_jsx_runtime2.jsxs)("div", {
136
+ className: shared_default.rowList,
137
+ children: [
138
+ served.length === 0 && props.emptyLabel !== void 0 ? (0, import_jsx_runtime2.jsx)("div", { className: shared_default.empty, children: props.emptyLabel }, "empty") : null,
139
+ rows.map(
140
+ (row, at) => (0, import_jsx_runtime2.jsx)("div", {
141
+ className: shared_default.catalogEntry,
142
+ children: (0, import_jsx_runtime2.jsxs)("div", {
143
+ className: rowClass,
144
+ children: [
145
+ row.map(
146
+ (cell, column) => (0, import_jsx_runtime2.jsx)("input", {
147
+ className: inputClass,
148
+ type: "text",
149
+ value: cell === void 0 ? "" : cell,
150
+ placeholder: placeholders[column] === void 0 ? "" : placeholders[column],
151
+ disabled: !writable || busy,
152
+ onChange: (event) => {
153
+ setCell(at, column, typeof event?.target?.value === "string" ? event.target.value : "");
154
+ },
155
+ onBlur: () => {
156
+ if (writable && !busy) void commit();
157
+ },
158
+ onKeyDown: (event) => {
159
+ if (event.key === "Enter") {
160
+ if (typeof event.preventDefault === "function") event.preventDefault();
161
+ if (writable && !busy) void commit();
162
+ }
163
+ }
164
+ }, column)
165
+ ),
166
+ (0, import_jsx_runtime2.jsx)("button", {
167
+ type: "button",
168
+ className: shared_default.iconButton + " " + shared_default.iconButtonDanger,
169
+ disabled: !writable || busy,
170
+ title: props.removeLabel === void 0 ? "" : props.removeLabel,
171
+ onClick: () => {
172
+ if (writable && !busy) void remove(at);
173
+ },
174
+ children: (0, import_jsx_runtime2.jsx)("svg", {
175
+ width: 14,
176
+ height: 14,
177
+ viewBox: "0 0 16 16",
178
+ fill: "none",
179
+ stroke: "currentColor",
180
+ children: (0, import_jsx_runtime2.jsx)("path", { d: TRASH_PATH })
181
+ })
182
+ }, "remove")
183
+ ]
184
+ })
185
+ }, at)
186
+ ),
187
+ (0, import_jsx_runtime2.jsx)("button", {
188
+ type: "button",
189
+ className: shared_default.linkButton,
190
+ disabled: !writable || busy,
191
+ title: props.addTitle === void 0 ? "" : props.addTitle,
192
+ onClick: () => {
193
+ if (!writable || busy) return;
194
+ add();
195
+ },
196
+ children: props.addLabel === void 0 ? "" : props.addLabel
197
+ }, "add"),
198
+ props.renderAction === void 0 ? null : props.renderAction(rows)
199
+ ]
200
+ });
201
+ if (props.disclosure !== true) return list;
202
+ return (0, import_jsx_runtime2.jsxs)("details", {
203
+ className: shared_default.disclosure,
204
+ children: [
205
+ (0, import_jsx_runtime2.jsxs)("summary", {
206
+ className: shared_default.disclosureSummary,
207
+ children: [
208
+ (0, import_jsx_runtime2.jsx)("span", { className: shared_default.disclosureLabel, children: props.disclosureLabel === void 0 ? "" : props.disclosureLabel }),
209
+ (0, import_jsx_runtime2.jsx)("span", {
210
+ className: shared_default.disclosureCount,
211
+ children: (props.disclosureCountLabel === void 0 ? String(rows.length) : props.disclosureCountLabel).replace("{count}", String(rows.length))
212
+ })
213
+ ]
214
+ }),
215
+ (0, import_jsx_runtime2.jsx)("div", { className: shared_default.disclosureBody, children: list })
216
+ ]
217
+ });
218
+ }
219
+ function DialogBlock(props) {
220
+ var t = props.t;
221
+ var candidates = Array.from(props.candidates);
222
+ var savedIds = Array.from(props.savedIds);
223
+ var savedSet = new Set(savedIds);
224
+ var initialChecked = candidates.filter((candidate) => savedSet.has(candidate.id)).map((candidate) => candidate.id);
225
+ var servedKey = JSON.stringify(candidates) + "|" + JSON.stringify(savedIds);
226
+ var draftState = react2.useState({ key: "", query: "", checked: [] });
227
+ var draft = draftState[0];
228
+ var setDraft = draftState[1];
229
+ var dirty = draft.key !== servedKey;
230
+ var query = dirty ? "" : draft.query;
231
+ var checked = dirty ? initialChecked : draft.checked;
232
+ var checkedSet = new Set(checked);
233
+ var setQuery = (value) => {
234
+ setDraft({ key: servedKey, query: value, checked: Array.from(checkedSet) });
235
+ };
236
+ var setChecked = (make) => {
237
+ setDraft({ key: servedKey, query, checked: make(checked) });
238
+ };
239
+ var needle = query.trim().toLowerCase();
240
+ var shown = needle === "" ? candidates : candidates.filter((candidate) => candidate.id.toLowerCase().indexOf(needle) !== -1);
241
+ var addable = shown.filter((candidate) => !savedSet.has(candidate.id)).map((candidate) => candidate.id);
242
+ var allChecked = addable.length > 0 && addable.every((id) => checkedSet.has(id));
243
+ var toggle = (id, value) => {
244
+ setChecked((current) => value ? current.concat([id]) : current.filter((entry) => entry !== id));
245
+ };
246
+ return (0, import_jsx_runtime3.jsxs)("div", {
247
+ className: shared_default.fetchDialog,
248
+ role: "dialog",
249
+ "aria-modal": "true",
250
+ "aria-label": props.title,
251
+ children: [
252
+ (0, import_jsx_runtime3.jsxs)("div", {
253
+ className: shared_default.dialogContent,
254
+ children: [
255
+ (0, import_jsx_runtime3.jsxs)("div", {
256
+ className: shared_default.dialogHeader,
257
+ children: [
258
+ (0, import_jsx_runtime3.jsx)("h2", { className: shared_default.dialogTitle, children: props.title }),
259
+ (0, import_jsx_runtime3.jsx)("button", {
260
+ type: "button",
261
+ className: shared_default.dialogClose,
262
+ "aria-label": t("close"),
263
+ onClick: () => props.onClose(),
264
+ children: (0, import_jsx_runtime3.jsx)("svg", {
265
+ width: 14,
266
+ height: 14,
267
+ viewBox: "0 0 16 16",
268
+ fill: "none",
269
+ xmlns: "http://www.w3.org/2000/svg",
270
+ "aria-hidden": "true",
271
+ children: CLOSE_PATHS.map((d, at) => (0, import_jsx_runtime3.jsx)("path", { d, fill: "currentColor" }, at))
272
+ })
273
+ })
274
+ ]
275
+ }),
276
+ (0, import_jsx_runtime3.jsx)("p", { className: shared_default.dialogDescription, children: props.description }),
277
+ (0, import_jsx_runtime3.jsxs)("div", {
278
+ className: shared_default.dialogBody,
279
+ children: [
280
+ (0, import_jsx_runtime3.jsxs)("div", {
281
+ className: shared_default.candidateToolbar,
282
+ children: [
283
+ (0, import_jsx_runtime3.jsx)("input", {
284
+ className: shared_default.candidateSearch,
285
+ type: "search",
286
+ placeholder: props.searchPlaceholder,
287
+ "aria-label": props.searchPlaceholder,
288
+ value: query,
289
+ onChange: (event) => {
290
+ setQuery(event && event.target ? String(event.target.value ?? "") : "");
291
+ }
292
+ }),
293
+ (0, import_jsx_runtime3.jsx)("button", {
294
+ type: "button",
295
+ className: shared_default.linkButton,
296
+ onClick: () => {
297
+ if (allChecked) setChecked(() => []);
298
+ else setChecked((current) => Array.from(new Set(current.concat(addable))));
299
+ },
300
+ children: t("selectAll")
301
+ })
302
+ ]
303
+ }),
304
+ shown.length === 0 ? (0, import_jsx_runtime3.jsx)("p", { className: shared_default.empty, children: t("dialogEmpty") }) : (0, import_jsx_runtime3.jsx)("ul", {
305
+ className: shared_default.candidateList,
306
+ children: shown.map((candidate) => {
307
+ var isSaved = savedSet.has(candidate.id);
308
+ var note = candidate.note !== "" ? candidate.note : isSaved ? t("candidateSaved") : "";
309
+ return (0, import_jsx_runtime3.jsx)("li", {
310
+ className: shared_default.candidate,
311
+ children: (0, import_jsx_runtime3.jsxs)("label", {
312
+ className: shared_default.candidateLabel,
313
+ children: [
314
+ (0, import_jsx_runtime3.jsx)("input", {
315
+ type: "checkbox",
316
+ checked: isSaved ? true : checkedSet.has(candidate.id),
317
+ disabled: isSaved,
318
+ onChange: (event) => {
319
+ toggle(candidate.id, !!(event && event.target && event.target.checked));
320
+ }
321
+ }),
322
+ (0, import_jsx_runtime3.jsx)("span", { className: shared_default.candidateId, children: candidate.id }),
323
+ note === "" ? null : (0, import_jsx_runtime3.jsx)("span", { className: shared_default.candidateNote, children: note })
324
+ ]
325
+ })
326
+ }, candidate.id);
327
+ })
328
+ })
329
+ ]
330
+ }),
331
+ (0, import_jsx_runtime3.jsxs)("div", {
332
+ className: shared_default.dialogFooter,
333
+ children: [
334
+ (0, import_jsx_runtime3.jsx)("button", {
335
+ type: "button",
336
+ className: shared_default.dialogButton,
337
+ onClick: () => props.onClose(),
338
+ children: t("cancel")
339
+ }),
340
+ (0, import_jsx_runtime3.jsx)("button", {
341
+ type: "button",
342
+ className: shared_default.dialogButton + " " + shared_default.dialogButtonPrimary,
343
+ onClick: () => props.onAdd(Array.from(checkedSet)),
344
+ children: t("addSelected")
345
+ })
346
+ ]
347
+ })
348
+ ]
349
+ })
350
+ ]
351
+ });
352
+ }
353
+ function PickerBlock(props) {
354
+ const entries = Array.isArray(props.entries) ? props.entries : [];
355
+ const options = Array.isArray(props.options) ? props.options : [];
356
+ const selectedId = props.selectedId === void 0 ? "" : props.selectedId;
357
+ const writable = props.writable === true;
358
+ const busy = props.busy === true;
359
+ const rows = entries.map((entry) => [entry.id, entry.name]);
360
+ const saveEntries = (next) => {
361
+ if (props.save === void 0) return Promise.resolve();
362
+ return Promise.resolve(props.save(next.map((row) => ({ id: row[0] ?? "", name: row[1] ?? "" }))));
363
+ };
364
+ const refreshAction = () => (0, import_jsx_runtime4.jsx)("button", {
365
+ type: "button",
366
+ className: shared_default.linkButton,
367
+ disabled: !writable || busy,
368
+ onClick: () => {
369
+ props.refresh();
370
+ },
371
+ children: busy && props.busyLabel !== void 0 ? props.busyLabel : props.refreshLabel
372
+ });
373
+ const extras = props.actions === void 0 ? [] : props.actions;
374
+ const renderActions = () => (0, import_jsx_runtime4.jsxs)("div", {
375
+ className: shared_default.linkButtonRow,
376
+ children: [
377
+ refreshAction(),
378
+ ...extras.map(
379
+ (action, index) => (0, import_jsx_runtime4.jsx)("button", {
380
+ type: "button",
381
+ className: shared_default.linkButton,
382
+ disabled: !writable || busy || action.disabled === true,
383
+ title: action.title === void 0 ? "" : action.title,
384
+ onClick: () => {
385
+ action.onClick();
386
+ },
387
+ children: action.label
388
+ }, index)
389
+ )
390
+ ]
391
+ });
392
+ return (0, import_jsx_runtime4.jsxs)("div", {
393
+ className: shared_default.catalog,
394
+ children: [
395
+ (0, import_jsx_runtime4.jsxs)("div", {
396
+ className: shared_default.field,
397
+ children: [
398
+ (0, import_jsx_runtime4.jsxs)("div", {
399
+ className: shared_default.fieldRow,
400
+ children: [
401
+ props.selectorLabel === void 0 || props.selectorLabel === "" ? null : (0, import_jsx_runtime4.jsx)("span", { className: shared_default.fieldTitle, children: props.selectorLabel }),
402
+ (0, import_jsx_runtime4.jsx)("span", {
403
+ className: shared_default.selectorWrap,
404
+ children: (0, import_jsx_runtime4.jsx)(import_dsh_client_ui_primitives.Menu, {
405
+ open: props.menuOpen === true,
406
+ onClose: () => {
407
+ props.setMenuOpen(false);
408
+ },
409
+ items: options.map((option) => ({ id: option.id, label: option.label })),
410
+ selectedId: options.some((option) => option.id === selectedId) ? selectedId : "",
411
+ onSelect: (id) => {
412
+ props.setMenuOpen(false);
413
+ props.select(id);
414
+ },
415
+ align: "end",
416
+ portal: true,
417
+ anchor: (0, import_jsx_runtime4.jsxs)("button", {
418
+ type: "button",
419
+ className: shared_default.selector,
420
+ "aria-haspopup": "menu",
421
+ "aria-expanded": props.menuOpen === true,
422
+ disabled: !writable || busy,
423
+ title: props.selectedTitle === void 0 ? "" : props.selectedTitle,
424
+ onClick: () => {
425
+ props.setMenuOpen(!(props.menuOpen === true));
426
+ },
427
+ children: [
428
+ // A bare label; a path needs its own
429
+ // truncating span.
430
+ (0, import_jsx_runtime4.jsx)("span", { className: shared_default.selectorLabel, children: props.selectedLabel }),
431
+ (0, import_jsx_runtime4.jsx)("svg", {
432
+ width: 14,
433
+ height: 14,
434
+ className: shared_default.pillChevron,
435
+ viewBox: "0 0 14 14",
436
+ fill: "none",
437
+ "aria-hidden": "true",
438
+ children: (0, import_jsx_runtime4.jsx)("path", { d: CHEVRON_PATH, fill: "currentColor" })
439
+ })
440
+ ]
441
+ })
442
+ })
443
+ })
444
+ ]
445
+ }),
446
+ props.hint === void 0 ? null : (0, import_jsx_runtime4.jsx)("div", { className: shared_default.fieldDesc, children: props.hint })
447
+ ]
448
+ }),
449
+ RowsBlock({
450
+ values: rows,
451
+ save: saveEntries,
452
+ labels: [props.idLabel === void 0 ? "" : props.idLabel, props.nameLabel === void 0 ? "" : props.nameLabel],
453
+ placeholders: [props.idPlaceholder === void 0 ? "" : props.idPlaceholder, props.namePlaceholder === void 0 ? "" : props.namePlaceholder],
454
+ writable: props.writable,
455
+ busy,
456
+ emptyLabel: props.emptyText,
457
+ addLabel: props.addLabel,
458
+ removeLabel: props.removeLabel,
459
+ disclosureLabel: props.rowsLabel,
460
+ disclosure: true,
461
+ rowClassName: shared_default.catalogRow,
462
+ renderAction: renderActions
463
+ }),
464
+ props.statusLine === void 0 || props.statusLine === null ? null : props.statusLine
465
+ ]
466
+ });
467
+ }
468
+ function FlagsBlock(props) {
469
+ const writable = props.writable === true;
470
+ const busy = props.busy === true;
471
+ const flags = Array.isArray(props.flags) ? props.flags : [];
472
+ const saveValues = (next) => {
473
+ const cleaned = next.map((row) => String(row === void 0 || row === null ? "" : row[0] ?? "").trim()).filter((flag) => flag !== "").filter((flag, index, all) => all.indexOf(flag) === index);
474
+ if (typeof props.save !== "function") return Promise.resolve();
475
+ return Promise.resolve(props.save(cleaned));
476
+ };
477
+ const actions = props.actions === void 0 ? [] : props.actions;
478
+ const renderAction = (visible) => (0, import_jsx_runtime5.jsxs)("div", {
479
+ className: shared_default.linkButtonRow,
480
+ children: actions.map(
481
+ (action, index) => (0, import_jsx_runtime5.jsx)(
482
+ "button",
483
+ {
484
+ type: "button",
485
+ className: shared_default.linkButton,
486
+ disabled: !writable || busy || action.disabled === true,
487
+ title: action.title === void 0 ? action.label : action.title,
488
+ onClick: () => {
489
+ if (!writable || busy) return;
490
+ const current = visible.map((row) => String(row[0] ?? "").trim()).filter((flag) => flag !== "");
491
+ const merged = Array.from(/* @__PURE__ */ new Set([...current, ...action.merged(current)]));
492
+ void saveValues(merged.map((flag) => [flag]));
493
+ },
494
+ children: action.label
495
+ },
496
+ index
497
+ )
498
+ )
499
+ }, "actions");
500
+ return (0, import_jsx_runtime5.jsxs)("div", {
501
+ className: shared_default.catalog,
502
+ children: [
503
+ (0, import_jsx_runtime5.jsxs)("div", {
504
+ className: shared_default.field,
505
+ children: [
506
+ (0, import_jsx_runtime5.jsxs)("div", {
507
+ className: shared_default.fieldRow,
508
+ children: [
509
+ (0, import_jsx_runtime5.jsx)("span", { className: shared_default.fieldTitle, children: props.title }),
510
+ props.link === void 0 || props.link.href === "" ? null : (0, import_jsx_runtime5.jsxs)("a", {
511
+ className: shared_default.docsLink,
512
+ href: props.link.href,
513
+ target: "_blank",
514
+ rel: "noopener noreferrer",
515
+ title: props.link.title === void 0 ? props.link.label : props.link.title,
516
+ children: [
517
+ (0, import_jsx_runtime5.jsx)("svg", {
518
+ className: shared_default.docsIcon,
519
+ width: 14,
520
+ height: 14,
521
+ viewBox: "0 0 24 24",
522
+ fill: "none",
523
+ stroke: "currentColor",
524
+ strokeWidth: 2,
525
+ strokeLinecap: "round",
526
+ strokeLinejoin: "round",
527
+ "aria-hidden": "true",
528
+ children: DOCS_PATHS.map((d, at) => (0, import_jsx_runtime5.jsx)("path", { d }, at))
529
+ }),
530
+ (0, import_jsx_runtime5.jsx)("span", { className: shared_default.docsLinkLabel, children: props.link.label })
531
+ ]
532
+ })
533
+ ]
534
+ }),
535
+ props.hint === void 0 ? null : (0, import_jsx_runtime5.jsx)("div", { className: shared_default.fieldDesc, children: props.hint })
536
+ ]
537
+ }),
538
+ RowsBlock({
539
+ values: flags.map((flag) => [flag]),
540
+ save: saveValues,
541
+ labels: [props.rowLabel === void 0 ? "" : props.rowLabel],
542
+ placeholders: [props.rowPlaceholder === void 0 ? "" : props.rowPlaceholder],
543
+ writable: props.writable,
544
+ busy,
545
+ emptyLabel: props.emptyText,
546
+ addLabel: props.addLabel,
547
+ removeLabel: props.removeLabel,
548
+ disclosureLabel: props.disclosureLabel,
549
+ disclosure: props.disclosure === true,
550
+ rowClassName: shared_default.catalogRowSingle,
551
+ inputClassName: shared_default.catalogInput,
552
+ renderAction
553
+ })
554
+ ]
555
+ });
556
+ }
557
+ function SwitchField(props) {
558
+ const control = (0, import_jsx_runtime6.jsx)(import_dsh_client_ui_primitives2.Switch, {
559
+ checked: props.checked === true,
560
+ label: props.label,
561
+ disabled: props.disabled === true || props.busy === true,
562
+ onChange: () => {
563
+ if (typeof props.onToggle === "function") props.onToggle();
564
+ }
565
+ });
566
+ if (props.variant === "row") {
567
+ return (0, import_jsx_runtime6.jsx)("span", {
568
+ className: shared_default.toggleLabel,
569
+ title: props.title === void 0 ? props.label : props.title,
570
+ "aria-label": props.label,
571
+ children: control
572
+ });
573
+ }
574
+ return (0, import_jsx_runtime6.jsxs)("div", {
575
+ className: shared_default.catalog,
576
+ children: [
577
+ (0, import_jsx_runtime6.jsxs)("div", {
578
+ className: shared_default.field,
579
+ children: [
580
+ (0, import_jsx_runtime6.jsxs)("div", {
581
+ className: shared_default.fieldRow,
582
+ children: [
583
+ (0, import_jsx_runtime6.jsx)("span", { className: shared_default.fieldTitle, children: props.label }),
584
+ (0, import_jsx_runtime6.jsx)("span", {
585
+ className: shared_default.toggleLabel,
586
+ title: props.title === void 0 ? props.label : props.title,
587
+ children: control
588
+ })
589
+ ]
590
+ }),
591
+ props.hint === void 0 ? null : (0, import_jsx_runtime6.jsx)("div", { className: shared_default.fieldDesc, children: props.hint })
592
+ ]
593
+ })
594
+ ]
595
+ });
596
+ }
597
+ function LinkButtonRow(props) {
598
+ return (0, import_jsx_runtime7.jsxs)("div", { className: shared_default.linkButtonRow, children: props.children === void 0 ? [] : [props.children] });
599
+ }
600
+ function ErrorLine(props) {
601
+ const text2 = String(props.text ?? "");
602
+ if (text2 === "") return null;
603
+ return (0, import_jsx_runtime7.jsxs)("p", {
604
+ className: shared_default.error,
605
+ role: "status",
606
+ children: [
607
+ (0, import_jsx_runtime7.jsx)("span", { className: shared_default.dot + " " + shared_default.dotError, "aria-hidden": "true" }),
608
+ (0, import_jsx_runtime7.jsx)("span", { children: text2 })
609
+ ]
610
+ });
611
+ }
612
+ function TextField(props) {
613
+ return field(props, (0, import_jsx_runtime8.jsx)("input", {
614
+ type: "text",
615
+ className: shared_default.control,
616
+ value: text(props.value),
617
+ placeholder: props.placeholder ?? "",
618
+ disabled: props.disabled === true,
619
+ "aria-label": props.label,
620
+ onChange: (event) => props.onChange(event.target.value)
621
+ }));
622
+ }
623
+ function LinesField(props) {
624
+ const box = useTypedBox(linesOf(props.value).join("\n"));
625
+ return field(props, (0, import_jsx_runtime8.jsx)("textarea", {
626
+ className: shared_default.textarea,
627
+ value: box.text,
628
+ placeholder: props.placeholder ?? "",
629
+ disabled: props.disabled === true,
630
+ "aria-label": props.label,
631
+ onChange: (event) => {
632
+ const typed = event.target.value;
633
+ box.stage(typed);
634
+ props.onChange(parseLines(typed));
635
+ }
636
+ }));
637
+ }
638
+ function MapField(props) {
639
+ const box = useTypedBox(serializeMap(props.value));
640
+ return field(props, (0, import_jsx_runtime8.jsx)("textarea", {
641
+ className: shared_default.textarea,
642
+ value: box.text,
643
+ placeholder: props.placeholder ?? "",
644
+ disabled: props.disabled === true,
645
+ "aria-label": props.label,
646
+ onChange: (event) => {
647
+ const typed = event.target.value;
648
+ box.stage(typed);
649
+ props.onChange(parseMap(typed));
650
+ }
651
+ }));
652
+ }
653
+ function SelectField(props) {
654
+ const options = selectOptions(props.value, props.options ?? [], props.placeholder);
655
+ return field(
656
+ props,
657
+ (0, import_jsx_runtime8.jsx)("select", {
658
+ className: shared_default.select,
659
+ value: text(props.value),
660
+ disabled: props.disabled === true,
661
+ "aria-label": props.label,
662
+ onChange: (event) => {
663
+ const picked = options.find((option) => text(option.value) === event.target.value);
664
+ props.onChange(picked === void 0 ? event.target.value : picked.value);
665
+ },
666
+ children: options.map(
667
+ (option) => (0, import_jsx_runtime8.jsx)("option", { value: text(option.value), children: option.label }, text(option.value))
668
+ )
669
+ })
670
+ );
671
+ }
672
+ function DropdownField(props) {
673
+ const openState = react3.useState(false);
674
+ const open = openState[0];
675
+ const setOpen = openState[1];
676
+ const disabled = props.disabled === true;
677
+ const options = selectOptions(props.value, props.options ?? [], props.placeholder);
678
+ const held = text(props.value);
679
+ const current = options.find((option) => text(option.value) === held);
680
+ return field(
681
+ props,
682
+ (0, import_jsx_runtime8.jsx)("span", {
683
+ className: shared_default.selectorWrap,
684
+ children: (0, import_jsx_runtime8.jsx)(import_dsh_client_ui_primitives3.Menu, {
685
+ open: open && !disabled,
686
+ onClose: () => setOpen(false),
687
+ items: options.map((option) => ({ id: text(option.value), label: option.label })),
688
+ selectedId: current === void 0 ? "" : held,
689
+ onSelect: (id) => {
690
+ setOpen(false);
691
+ if (id === held) return;
692
+ const picked = options.find((option) => text(option.value) === id);
693
+ props.onChange(picked === void 0 ? id : picked.value);
694
+ },
695
+ align: "start",
696
+ portal: true,
697
+ anchor: (0, import_jsx_runtime8.jsxs)("button", {
698
+ type: "button",
699
+ className: shared_default.selector,
700
+ "aria-haspopup": "menu",
701
+ "aria-expanded": open && !disabled,
702
+ "aria-label": props.label,
703
+ disabled,
704
+ onClick: () => setOpen(!open),
705
+ children: [
706
+ (0, import_jsx_runtime8.jsx)("span", { className: shared_default.selectorLabel, children: current === void 0 ? props.placeholder ?? "" : current.label }),
707
+ (0, import_jsx_runtime8.jsx)("svg", {
708
+ width: 14,
709
+ height: 14,
710
+ className: shared_default.pillChevron,
711
+ viewBox: "0 0 14 14",
712
+ fill: "none",
713
+ "aria-hidden": "true",
714
+ children: (0, import_jsx_runtime8.jsx)("path", { d: CHEVRON_PATH, fill: "currentColor" })
715
+ })
716
+ ]
717
+ })
718
+ })
719
+ })
720
+ );
721
+ }
722
+ function ExtraField(props) {
723
+ const type = props.type === void 0 ? "string" : props.type;
724
+ if (type === "boolean") {
725
+ return field(
726
+ props,
727
+ (0, import_jsx_runtime8.jsx)("input", {
728
+ type: "checkbox",
729
+ className: shared_default.checkbox,
730
+ checked: props.value === true,
731
+ disabled: props.disabled === true,
732
+ "aria-label": props.label,
733
+ onChange: (event) => props.onChange(event.target.checked)
734
+ })
735
+ );
736
+ }
737
+ if (type === "lines") return (0, import_jsx_runtime8.jsx)(LinesField, props);
738
+ if (type === "select") return SelectField(props);
739
+ if (type === "secret") {
740
+ return field(
741
+ props,
742
+ (0, import_jsx_runtime8.jsx)("input", {
743
+ type: "password",
744
+ className: shared_default.control,
745
+ value: text(props.value),
746
+ placeholder: props.placeholder ?? "",
747
+ disabled: props.disabled === true,
748
+ "aria-label": props.label,
749
+ onChange: (event) => props.onChange(event.target.value)
750
+ })
751
+ );
752
+ }
753
+ if ((props.options ?? []).length > 0) return SelectField(props);
754
+ return TextField(props);
755
+ }
756
+ function selectOptions(value, served, placeholder) {
757
+ const out = [];
758
+ const seen = /* @__PURE__ */ new Set();
759
+ const held = text(value);
760
+ if (held === "" && placeholder !== void 0 && placeholder !== "" && !served.some((option) => text(option.value) === "")) {
761
+ out.push({ value: "", label: placeholder });
762
+ seen.add("");
763
+ }
764
+ for (const option of served) {
765
+ const key = text(option.value);
766
+ if (seen.has(key)) continue;
767
+ seen.add(key);
768
+ out.push(option);
769
+ }
770
+ if (held !== "" && !seen.has(held)) out.push({ value, label: held });
771
+ return out;
772
+ }
773
+ function linesOf(value) {
774
+ if (Array.isArray(value)) return value.map((item) => text(item)).filter((item) => item.trim() !== "");
775
+ if (typeof value === "string") return parseLines(value);
776
+ return [];
777
+ }
778
+ function useTypedBox(served) {
779
+ const typedState = react3.useState({ key: "", text: "" });
780
+ const typed = typedState[0];
781
+ const setTyped = typedState[1];
782
+ return {
783
+ text: typed.key === served ? typed.text : served,
784
+ stage: (text2) => setTyped({ key: served, text: text2 })
785
+ };
786
+ }
787
+ function text(value) {
788
+ if (value === void 0 || value === null) return "";
789
+ return typeof value === "string" ? value : String(value);
790
+ }
791
+ function parseLines(text2) {
792
+ return String(text2).split("\n").filter((line) => line.trim() !== "");
793
+ }
794
+ function parseMap(text2) {
795
+ const out = {};
796
+ for (const line of String(text2).split("\n")) {
797
+ if (line.trim() === "") continue;
798
+ const split = line.indexOf("=");
799
+ if (split <= 0) continue;
800
+ const key = line.slice(0, split);
801
+ if (key.trim() === "") continue;
802
+ out[key] = line.slice(split + 1);
803
+ }
804
+ return out;
805
+ }
806
+ function mapText(value) {
807
+ if (value === void 0 || value === null) return "";
808
+ if (typeof value === "string") return value;
809
+ if (Array.isArray(value)) return value.map((item) => text(item)).join(",");
810
+ if (typeof value === "object") return JSON.stringify(value);
811
+ return String(value);
812
+ }
813
+ function serializeMap(value) {
814
+ if (typeof value === "string") return value;
815
+ if (value === null || typeof value !== "object" || Array.isArray(value)) return "";
816
+ return Object.entries(value).map(([key, item]) => `${key}=${mapText(item)}`).join("\n");
817
+ }
818
+ function field(props, control) {
819
+ return (0, import_jsx_runtime8.jsxs)("div", {
820
+ className: shared_default.controlField,
821
+ children: [
822
+ (0, import_jsx_runtime8.jsx)("div", { className: shared_default.controlTitle, children: props.label }),
823
+ control,
824
+ props.help === void 0 || props.help === "" ? null : (0, import_jsx_runtime8.jsx)("div", { className: shared_default.fieldDesc, children: props.help })
825
+ ]
826
+ });
827
+ }
828
+ function ComposerPill(props) {
829
+ const disabled = props.disabled === true;
830
+ return (0, import_jsx_runtime9.jsx)("span", {
831
+ className: shared_default.composerPillRoot,
832
+ "data-pill": props.key,
833
+ children: (0, import_jsx_runtime9.jsx)(import_dsh_client_ui_primitives4.Menu, {
834
+ open: props.open && !disabled,
835
+ onClose: () => props.setOpen(false),
836
+ items: props.options,
837
+ selectedId: props.selectedId,
838
+ onSelect: (id) => {
839
+ props.setOpen(false);
840
+ if (id === props.selectedId) return;
841
+ Promise.resolve(props.onSelect(id)).catch(() => void 0);
842
+ },
843
+ align: "start",
844
+ side: "top",
845
+ portal: true,
846
+ anchor: (0, import_jsx_runtime9.jsxs)("button", {
847
+ type: "button",
848
+ className: shared_default.composerPill,
849
+ "aria-label": props.ariaLabel ?? (props.title === void 0 ? props.label : `${props.title}: ${props.label}`),
850
+ title: props.title ?? props.label,
851
+ "aria-haspopup": "menu",
852
+ "aria-expanded": props.open && !disabled,
853
+ disabled,
854
+ onClick: () => props.setOpen(!props.open),
855
+ children: [
856
+ props.icon === void 0 || props.icon.length === 0 ? null : (0, import_jsx_runtime9.jsx)("span", {
857
+ className: shared_default.composerPillIcon,
858
+ "aria-hidden": true,
859
+ children: (0, import_jsx_runtime9.jsx)("svg", {
860
+ width: 14,
861
+ height: 14,
862
+ viewBox: "0 0 24 24",
863
+ fill: "none",
864
+ xmlns: "http://www.w3.org/2000/svg",
865
+ children: props.icon.map(
866
+ (d, at) => (0, import_jsx_runtime9.jsx)("path", { d, stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round" }, at)
867
+ )
868
+ })
869
+ }),
870
+ (0, import_jsx_runtime9.jsx)("span", { className: shared_default.composerPillLabel, children: props.label }),
871
+ (0, import_jsx_runtime9.jsx)("span", {
872
+ className: shared_default.composerPillChevron + (props.open && !disabled ? " " + shared_default.composerPillChevronOpen : ""),
873
+ "aria-hidden": true,
874
+ children: (0, import_jsx_runtime9.jsx)("svg", {
875
+ width: 14,
876
+ height: 14,
877
+ viewBox: "0 0 14 14",
878
+ fill: "none",
879
+ xmlns: "http://www.w3.org/2000/svg",
880
+ children: (0, import_jsx_runtime9.jsx)("path", { d: CHEVRON_PATH, fill: "currentColor" })
881
+ })
882
+ })
883
+ ]
884
+ })
885
+ })
886
+ });
887
+ }
888
+ var Blocks = {
889
+ RowsBlock,
890
+ DialogBlock,
891
+ PickerBlock,
892
+ FlagsBlock,
893
+ SwitchField,
894
+ LinkButtonRow,
895
+ ErrorLine,
896
+ TextField,
897
+ LinesField,
898
+ MapField,
899
+ SelectField,
900
+ DropdownField,
901
+ ExtraField,
902
+ ComposerPill
903
+ };
904
+ function tag(value) {
905
+ return Object.prototype.toString.call(value).slice(8, -1);
906
+ }
907
+ function isPlainObject(value) {
908
+ const prototype = Object.getPrototypeOf(value);
909
+ if (prototype === null) return true;
910
+ if (prototype === Object.prototype) return true;
911
+ return Object.getPrototypeOf(prototype) === null && tag(value) === "Object";
912
+ }
913
+ function canonicalCollection(value, kind) {
914
+ if (kind === "Set") {
915
+ return [...value].map(canonical).sort((left, right) => stableKey(left) < stableKey(right) ? -1 : 1);
916
+ }
917
+ return [...value].map(([key, item]) => [canonical(key), canonical(item)]).sort((left, right) => stableKey(left[0]) < stableKey(right[0]) ? -1 : 1);
918
+ }
919
+ function answersNothing(value) {
920
+ return value === void 0 || value === null;
921
+ }
922
+ function meaningfulKeys(value) {
923
+ return Object.keys(value).filter((key) => !answersNothing(value[key]));
924
+ }
925
+ function canonical(value) {
926
+ const kind = tag(value);
927
+ if (kind === "Set" || kind === "Map") return canonicalCollection(value, kind);
928
+ return value;
929
+ }
930
+ function stableKey(value) {
931
+ const text2 = JSON.stringify(value, (_key, item) => {
932
+ if (item !== null && typeof item === "object") {
933
+ const kind = tag(item);
934
+ if (kind === "Set" || kind === "Map") return canonicalCollection(item, kind);
935
+ }
936
+ if (item !== null && typeof item === "object" && !Array.isArray(item)) {
937
+ const sorted = {};
938
+ for (const name of Object.keys(item).sort()) {
939
+ const child = item[name];
940
+ if (!answersNothing(child)) sorted[name] = child;
941
+ }
942
+ return sorted;
943
+ }
944
+ return item === void 0 ? null : item;
945
+ });
946
+ return text2 === void 0 ? "null" : text2;
947
+ }
948
+ function sameValue(a, b) {
949
+ if (a === b) return true;
950
+ if (typeof a === "number" && typeof b === "number") return Number.isNaN(a) && Number.isNaN(b);
951
+ const leftMissing = answersNothing(a);
952
+ const rightMissing = answersNothing(b);
953
+ if (leftMissing || rightMissing) return leftMissing && rightMissing;
954
+ if (typeof a !== "object" || typeof b !== "object") return false;
955
+ if (Array.isArray(a) !== Array.isArray(b)) return false;
956
+ if (Array.isArray(a) && Array.isArray(b)) {
957
+ if (a.length !== b.length) return false;
958
+ return a.every((item, index) => sameValue(item, b[index]));
959
+ }
960
+ if (!isPlainObject(a) || !isPlainObject(b)) return sameOpaqueValue(a, b);
961
+ const left = meaningfulKeys(a);
962
+ const right = meaningfulKeys(b);
963
+ if (left.length !== right.length) return false;
964
+ return left.every(
965
+ (key) => Object.prototype.hasOwnProperty.call(b, key) && sameValue(a[key], b[key])
966
+ );
967
+ }
968
+ function sameOpaqueValue(a, b) {
969
+ const kind = tag(a);
970
+ if (kind !== tag(b)) return false;
971
+ if (kind === "Date") return sameValue(a.getTime(), b.getTime());
972
+ if (kind === "RegExp") {
973
+ return sameValue(a.source, b.source) && sameValue(a.flags, b.flags);
974
+ }
975
+ if (kind === "Map" || kind === "Set") {
976
+ return sameValue(canonical(a), canonical(b));
977
+ }
978
+ if (kind === "String" || kind === "Number" || kind === "Boolean") {
979
+ return sameValue(a.valueOf(), b.valueOf());
980
+ }
981
+ return false;
982
+ }
983
+ function nothingCardSnapshot() {
984
+ return {
985
+ available: false,
986
+ writable: false,
987
+ values: {},
988
+ overridden: [],
989
+ lastError: "",
990
+ dirty: false,
991
+ saving: false,
992
+ failed: false,
993
+ actionError: "",
994
+ notice: null
995
+ };
996
+ }
997
+ var RUN_SETTLE_TIMEOUT_MS = 9e4;
998
+ function settleOnRevision(host, settled, write, deadline = RUN_SETTLE_TIMEOUT_MS) {
999
+ if (host.disposed) return Promise.resolve();
1000
+ let satisfied = false;
1001
+ const armed = host.settleOn((snapshot) => {
1002
+ if (settled(snapshot) !== true) return false;
1003
+ satisfied = true;
1004
+ return true;
1005
+ });
1006
+ return new Promise((resolve) => {
1007
+ let done = false;
1008
+ const timer = setTimeout(() => finish(), deadline);
1009
+ host.settleTimer = timer;
1010
+ const finish = (refused = false) => {
1011
+ if (done) return;
1012
+ done = true;
1013
+ clearTimeout(timer);
1014
+ if (host.settleTimer === timer) host.settleTimer = null;
1015
+ armed.cancel();
1016
+ resolve();
1017
+ if (refused || satisfied || host.disposed) return;
1018
+ const state = host.getSnapshot();
1019
+ if (state.lastError !== "") host.noteNotice("error", state.lastError);
1020
+ else host.noteNotice("stall", "");
1021
+ };
1022
+ void armed.settle.then(() => finish());
1023
+ void Promise.resolve(write()).then(
1024
+ (accepted) => {
1025
+ if (accepted === false) {
1026
+ host.noteError("configuration write refused");
1027
+ finish(true);
1028
+ }
1029
+ },
1030
+ (error) => {
1031
+ host.noteError(error);
1032
+ finish(true);
1033
+ }
1034
+ );
1035
+ });
1036
+ }
1037
+ var MAX_WRITE_PASSES = 4;
1038
+ var CardController = class {
1039
+ /** Disposed — every late answer and timer bails on this flag first. */
1040
+ disposed = false;
1041
+ /** The armed stall-deadline timer (owned by ./wait.ts). */
1042
+ settleTimer = null;
1043
+ store;
1044
+ fields;
1045
+ errorField;
1046
+ settleDeadlineMs;
1047
+ settleField;
1048
+ /** The last pass of the write door, when the mount can issue it unfenced. */
1049
+ unfencedMutate;
1050
+ /** The form the entry's row page handed (`view: "page"`), if any. */
1051
+ pageForm;
1052
+ formRef;
1053
+ unsubscribe;
1054
+ /** Staged drafts: only fields that differ from what is served. */
1055
+ draft = {};
1056
+ /** The last served (undrafted) answers, recomputed on every push. */
1057
+ served = {};
1058
+ saving = false;
1059
+ failed = false;
1060
+ actionError = "";
1061
+ noticeQueue = null;
1062
+ noticeSeq = 0;
1063
+ /** Every armed settle; keyed against a published snapshot. */
1064
+ waits = [];
1065
+ constructor(form, spec = {}) {
1066
+ this.fields = spec.fields ?? {};
1067
+ this.errorField = spec.errorField ?? "lastError";
1068
+ this.settleDeadlineMs = spec.settleDeadlineMs;
1069
+ this.settleField = spec.settleField === void 0 || spec.settleField === "" ? void 0 : spec.settleField;
1070
+ this.unfencedMutate = spec.unfencedMutate;
1071
+ this.formRef = form;
1072
+ this.store = (0, import_dsh_client_store.createSnapshotStore)(nothingCardSnapshot());
1073
+ this.unsubscribe = form === void 0 ? void 0 : form.subscribe(() => {
1074
+ this.actionError = "";
1075
+ this.publish();
1076
+ });
1077
+ this.publish();
1078
+ }
1079
+ /** Adopt the form the row page hands with `view: "page"` (identity guarded:
1080
+ * an unchanged adopt is a no-op, keeping its publish out of the render). */
1081
+ adoptForm(form) {
1082
+ if (this.disposed) return;
1083
+ const next = form === void 0 ? void 0 : form;
1084
+ if (this.pageForm === next) return;
1085
+ this.pageForm = next;
1086
+ this.publish();
1087
+ }
1088
+ /** The card's store is what the card body renders. */
1089
+ getSnapshot() {
1090
+ return this.store.getSnapshot();
1091
+ }
1092
+ /** Whether anything serves this entry. */
1093
+ available() {
1094
+ return this.store.getSnapshot().available === true;
1095
+ }
1096
+ /** Read one field off the current snapshot (drafts overlaid). */
1097
+ value(field2) {
1098
+ return this.store.getSnapshot().values[field2];
1099
+ }
1100
+ /** One field as the Host serves it, drafts left out — what a staged edit
1101
+ * that lands back on it is compared against. */
1102
+ servedValue(field2) {
1103
+ return this.documentValue(field2);
1104
+ }
1105
+ /** One field as the served document answers it (what a wait arms against). */
1106
+ documentValue(field2) {
1107
+ const snapshot = this.readSnapshot();
1108
+ if (snapshot === void 0 || snapshot.status !== "ready" || snapshot.value === void 0) return void 0;
1109
+ return snapshot.value[field2];
1110
+ }
1111
+ /**
1112
+ * Staged edit: save one value as a draft. A draft equal to what is served
1113
+ * is not dirty — it stages nothing and dirties nothing.
1114
+ */
1115
+ stage(field2, value) {
1116
+ if (this.disposed) return;
1117
+ const servedValue = this.served[field2];
1118
+ if (valuesEqual(servedValue, value)) {
1119
+ delete this.draft[field2];
1120
+ } else {
1121
+ this.draft[field2] = value;
1122
+ }
1123
+ this.publish();
1124
+ }
1125
+ /** Drop every staged draft: the card answers with what is served. */
1126
+ discard() {
1127
+ if (this.disposed) return;
1128
+ for (const key of Object.keys(this.draft)) delete this.draft[key];
1129
+ this.failed = false;
1130
+ this.publish();
1131
+ }
1132
+ /** Apply exactly the staged fields. Accepted: the drafts clear with the
1133
+ * Host's answers. Refused: the drafts stand, `failed` says so. */
1134
+ async applyStaged() {
1135
+ if (this.disposed) return false;
1136
+ const staged = Object.entries(this.draft);
1137
+ if (staged.length === 0) return true;
1138
+ this.saving = true;
1139
+ this.publish();
1140
+ const ops = staged.map(([field2, value]) => ({ op: "set", path: [field2], value }));
1141
+ const accepted = await this.writeDoor(() => ops);
1142
+ if (accepted) {
1143
+ for (const field2 of Object.keys(this.draft)) delete this.draft[field2];
1144
+ this.failed = false;
1145
+ } else {
1146
+ this.failed = true;
1147
+ this.actionError = "configuration write refused";
1148
+ }
1149
+ this.saving = false;
1150
+ this.publish();
1151
+ return accepted;
1152
+ }
1153
+ /** Immediate write of one field — rows, selections: written on the spot. */
1154
+ async writeField(field2, value) {
1155
+ if (this.disposed) return false;
1156
+ const accepted = await this.writeDoor(() => [{ op: "set", path: [field2], value }]);
1157
+ this.publish();
1158
+ return accepted;
1159
+ }
1160
+ /** Return one field to what the row's own configuration answers: the field
1161
+ * leaves the user layer (an `unset`), and any draft standing over it goes. */
1162
+ async resetField(field2) {
1163
+ if (this.disposed) return false;
1164
+ const accepted = await this.writeDoor(() => [{ op: "unset", path: [field2] }]);
1165
+ if (accepted) delete this.draft[field2];
1166
+ this.publish();
1167
+ return accepted;
1168
+ }
1169
+ /**
1170
+ * Trigger write — a nonce: the value is always a stamp that moved off what
1171
+ * stood before it (`nextStamp`), so a later commit always reads as a diff.
1172
+ * Returns as soon as the write lands; waiting for the Host *run* is the job
1173
+ * of `settle` — armed before this crosses the wire, so nothing can slip
1174
+ * between. A stamp that stands where it stood answers no run at all: two
1175
+ * actions inside one millisecond must not read as nothing happened.
1176
+ */
1177
+ async writeTrigger(field2) {
1178
+ return this.writeDoor((document2) => [{ op: "set", path: [field2], value: nextStamp(document2[field2]) }]);
1179
+ }
1180
+ /** Write a trigger and wait for the mirror to satisfy `settled`. */
1181
+ settleAndTrigger(settled, field2) {
1182
+ return settleOnRevision(this, settled, () => this.writeTrigger(field2), this.settleDeadlineMs);
1183
+ }
1184
+ /** The immediate-write shape of `settleAndTrigger`: write one field on the
1185
+ * spot (a selection, a saved list) and wait for the Host run behind it to
1186
+ * satisfy `settled` — the wait armed before the write crosses the wire. */
1187
+ settleAndWrite(settled, field2, value) {
1188
+ return settleOnRevision(this, settled, () => this.writeField(field2, value), this.settleDeadlineMs);
1189
+ }
1190
+ /**
1191
+ * Entry trigger — the keyed nonce (`entryActions` hole): stamps a moved
1192
+ * value **under `key`** inside the field's map, keeping every other row's
1193
+ * stamp, and writes the whole map through the door. The Host's trigger diff
1194
+ * answers per key (`host/adapter/form.ts`), so exactly the row that stamped
1195
+ * fires its run. The merge is composed inside the door (what the document
1196
+ * stands on now), never from what this half last rendered.
1197
+ */
1198
+ async writeEntryTrigger(field2, key) {
1199
+ const wanted = String(key);
1200
+ return this.writeDoor((document2) => {
1201
+ const current = document2[field2];
1202
+ const stamps = current !== null && typeof current === "object" && !Array.isArray(current) ? { ...current } : {};
1203
+ stamps[wanted] = nextStamp(stamps[wanted]);
1204
+ return [{ op: "set", path: [field2], value: stamps }];
1205
+ });
1206
+ }
1207
+ /** The keyed shape of `settleAndTrigger`: arm the wait, write the entry
1208
+ * nonce, settle when `settled` stands. */
1209
+ settleAndTriggerEntry(settled, field2, key) {
1210
+ return settleOnRevision(this, settled, () => this.writeEntryTrigger(field2, key), this.settleDeadlineMs);
1211
+ }
1212
+ /** Host-run settle on the `settleField` hole: write the trigger for
1213
+ * `triggerField`, settle once what `watchField` answers moves off the value
1214
+ * it stood at when the wait was armed — the diff is the answer, the wall
1215
+ * clock only the backstop. With no `watchField` declared anywhere, the
1216
+ * trigger field itself is what must move.
1217
+ *
1218
+ * Both sides read the **served document**: the store is what the body
1219
+ * renders, and at arm time it may not have answered the field at all (nothing
1220
+ * published yet) — armed against that, every answer reads as a move. */
1221
+ settleTrigger(triggerField, watchField) {
1222
+ const watched = watchField ?? this.settleField ?? triggerField;
1223
+ const armed = this.documentValue(watched);
1224
+ return settleOnRevision(
1225
+ this,
1226
+ () => !sameValue(this.documentValue(watched), armed),
1227
+ () => this.writeTrigger(triggerField),
1228
+ this.settleDeadlineMs
1229
+ );
1230
+ }
1231
+ /** The keyed shape of `settleTrigger`: the wait answers **per entry** — what
1232
+ * `watchField` answers for `key` moves off what it answered when armed. A
1233
+ * mirror shaped as a list of lines answers it by the line's own `id`/`key`,
1234
+ * which is the shape a live mirror really carries. */
1235
+ settleEntryTrigger(triggerField, key, watchField) {
1236
+ const watched = watchField ?? this.settleField ?? triggerField;
1237
+ const wanted = String(key);
1238
+ const armed = keyedAnswer(this.documentValue(watched), wanted);
1239
+ return settleOnRevision(
1240
+ this,
1241
+ () => !sameValue(keyedAnswer(this.documentValue(watched), wanted), armed),
1242
+ () => this.writeEntryTrigger(triggerField, key),
1243
+ this.settleDeadlineMs
1244
+ );
1245
+ }
1246
+ /** Arm one predicate against the next publish (the wait surface). */
1247
+ settleOn(settled) {
1248
+ let resolve = () => void 0;
1249
+ const settle = new Promise((done) => {
1250
+ resolve = done;
1251
+ });
1252
+ const wait = { settled, resolve };
1253
+ this.waits.push(wait);
1254
+ return {
1255
+ settle,
1256
+ cancel: () => {
1257
+ const index = this.waits.indexOf(wait);
1258
+ if (index >= 0) this.waits.splice(index, 1);
1259
+ resolve();
1260
+ }
1261
+ };
1262
+ }
1263
+ /** Stage one failure notice for the body's toast host. */
1264
+ noteNotice(kind, text2) {
1265
+ this.noticeSeq += 1;
1266
+ this.noticeQueue = { seq: this.noticeSeq, kind, text: String(text2 ?? "") };
1267
+ this.publish();
1268
+ }
1269
+ /** Drop one announced notice (by `seq`). */
1270
+ clearNotice(seq) {
1271
+ if (this.noticeQueue !== null && this.noticeQueue.seq === seq) this.noticeQueue = null;
1272
+ this.publish();
1273
+ }
1274
+ /** Surface a refused or failed write as the card's own error line. */
1275
+ noteError(error) {
1276
+ this.actionError = String(error instanceof Error ? error.message : error);
1277
+ this.publish();
1278
+ }
1279
+ /** Release everything: subscriptions, settle, timers. */
1280
+ dispose() {
1281
+ this.disposed = true;
1282
+ this.unsubscribe?.();
1283
+ this.unsubscribe = void 0;
1284
+ this.pageForm = void 0;
1285
+ for (const wait of [...this.waits]) wait.resolve();
1286
+ this.waits.length = 0;
1287
+ if (this.settleTimer !== null && this.settleTimer !== void 0) {
1288
+ clearTimeout(this.settleTimer);
1289
+ this.settleTimer = null;
1290
+ }
1291
+ }
1292
+ /** Everything a registered card body receives — the same object for every
1293
+ * render (identity stable), so a re-render cannot disturb the store. */
1294
+ inject() {
1295
+ return {
1296
+ store: this.store,
1297
+ controller: this,
1298
+ fields: this.fields
1299
+ };
1300
+ }
1301
+ /** Push the served answers, overlaid by drafts, into the store. */
1302
+ publish() {
1303
+ if (this.disposed) return;
1304
+ const previous = this.store.getSnapshot();
1305
+ const snapshot = this.readSnapshot();
1306
+ let values = {};
1307
+ let overridden = [];
1308
+ let available = false;
1309
+ let writable = false;
1310
+ if (snapshot !== void 0 && snapshot.status === "ready" && snapshot.value !== void 0) {
1311
+ available = true;
1312
+ writable = snapshot.writable !== false;
1313
+ values = { ...snapshot.value };
1314
+ const user = snapshot.user;
1315
+ if (user !== null && typeof user === "object") overridden = Object.keys(user);
1316
+ for (const [field2, value] of Object.entries(this.draft)) values[field2] = value;
1317
+ } else {
1318
+ for (const key of Object.keys(this.draft)) delete this.draft[key];
1319
+ this.releaseWaits();
1320
+ }
1321
+ this.served = snapshot !== void 0 && snapshot.status === "ready" && snapshot.value !== void 0 ? { ...snapshot.value } : {};
1322
+ this.store.set({
1323
+ available,
1324
+ writable,
1325
+ values,
1326
+ overridden,
1327
+ lastError: typeof values[this.errorField] === "string" ? String(values[this.errorField]) : "",
1328
+ dirty: Object.keys(this.draft).length > 0,
1329
+ saving: this.saving,
1330
+ failed: this.failed,
1331
+ actionError: this.actionError,
1332
+ notice: this.noticeQueue
1333
+ });
1334
+ const state = this.store.getSnapshot();
1335
+ for (const wait of [...this.waits]) {
1336
+ if (wait.settled(state) === true) {
1337
+ this.waits.splice(this.waits.indexOf(wait), 1);
1338
+ wait.resolve();
1339
+ }
1340
+ }
1341
+ }
1342
+ /** What every read stands on: the shared form's mirror, which subscribes
1343
+ * and so moves with every Host answer. The page's handed `state` is a
1344
+ * snapshot taken when the page rendered — only the fallback when no shared
1345
+ * form stands; the page form is adopted as the write **door**, not as the
1346
+ * source. */
1347
+ readSnapshot() {
1348
+ if (this.formRef !== void 0) {
1349
+ try {
1350
+ return this.formRef.getSnapshot();
1351
+ } catch {
1352
+ }
1353
+ }
1354
+ return this.pageForm?.state;
1355
+ }
1356
+ /**
1357
+ * The write door — a refused pass is re-issued against the re-read document
1358
+ * until the budget runs out, then the refusal is *reported*.
1359
+ *
1360
+ * The door takes what the ops are **made of**, not the ops themselves, for
1361
+ * one reason: anything that has to carry what the document already says (a
1362
+ * keyed trigger's stamp map, a stamp that must move) is composed against
1363
+ * what the document says *now*, on every pass. Composing it once from what
1364
+ * this half last rendered would re-issue a merge made against a document
1365
+ * that already moved — and drop the other row's stamp on the floor.
1366
+ */
1367
+ async writeDoor(compose) {
1368
+ for (let pass = 0; pass < MAX_WRITE_PASSES; pass++) {
1369
+ const snapshot = this.readSnapshot();
1370
+ if (snapshot === void 0 || snapshot.status !== "ready") return false;
1371
+ const document2 = snapshot.value ?? {};
1372
+ const ops = withLiveCleared(compose(document2), this.fields.liveKeys);
1373
+ const pageForm = this.pageForm;
1374
+ const formRef = this.formRef;
1375
+ const door = pageForm !== void 0 ? (next) => pageForm.mutate(next) : formRef !== void 0 ? (next) => formRef.mutate(next) : void 0;
1376
+ if (door === void 0) return false;
1377
+ const last = pass === MAX_WRITE_PASSES - 1 && this.unfencedMutate !== void 0;
1378
+ try {
1379
+ const accepted = last ? await this.unfencedMutate(ops) : await door(ops);
1380
+ if (accepted === true) return true;
1381
+ } catch {
1382
+ }
1383
+ }
1384
+ return false;
1385
+ }
1386
+ /** Nothing serves: no wait can settle. */
1387
+ releaseWaits() {
1388
+ for (const wait of [...this.waits]) {
1389
+ this.waits.splice(this.waits.indexOf(wait), 1);
1390
+ wait.resolve();
1391
+ }
1392
+ }
1393
+ };
1394
+ function withLiveCleared(ops, liveKeys) {
1395
+ if (liveKeys === void 0 || liveKeys.length === 0) return ops;
1396
+ const written = new Set(ops.map((op) => op.path[0]));
1397
+ const clears = liveKeys.filter((key) => !written.has(key)).map((key) => ({ op: "unset", path: [key] }));
1398
+ return clears.length === 0 ? ops : [...ops, ...clears];
1399
+ }
1400
+ function valuesEqual(a, b) {
1401
+ return sameValue(a, b);
1402
+ }
1403
+ function keyedAnswer(value, key) {
1404
+ if (value === null || typeof value !== "object") return value;
1405
+ if (Array.isArray(value)) {
1406
+ const rows = value;
1407
+ const row = rows.find((item) => identityOf(item) === key);
1408
+ if (rows.some((item) => identityOf(item) !== void 0)) return row;
1409
+ return value;
1410
+ }
1411
+ if (Object.prototype.hasOwnProperty.call(value, key)) return value[key];
1412
+ return value;
1413
+ }
1414
+ function identityOf(row) {
1415
+ if (row === null || typeof row !== "object") return void 0;
1416
+ const claimed = row.id ?? row.key;
1417
+ if (typeof claimed === "string") return claimed;
1418
+ if (typeof claimed === "number") return String(claimed);
1419
+ return void 0;
1420
+ }
1421
+ function nextStamp(previous) {
1422
+ const standing = typeof previous === "number" && Number.isFinite(previous) ? previous : 0;
1423
+ return Math.max(Date.now(), standing + 1);
1424
+ }
1425
+ var LOCALE_NAMESPACE = "dshAncesters";
1426
+ var DICTIONARIES = {
1427
+ en: {
1428
+ apply: "Apply",
1429
+ discard: "Discard",
1430
+ saving: "Saving\u2026",
1431
+ unsaved: "Unsaved changes",
1432
+ saveFailed: "Save failed",
1433
+ cancel: "Cancel",
1434
+ close: "Close",
1435
+ search: "Search",
1436
+ searchNoResults: "No matches",
1437
+ searchPlaceholder: "Search\u2026",
1438
+ addSelected: "Add selected",
1439
+ // The page-wide notices (`toasts`): a wait that ended with nothing
1440
+ // answered, and a failure the Host answered without a line of its own.
1441
+ toastStall: "The host did not answer the action \u2014 try it again.",
1442
+ toastError: "The host reported a failure."
1443
+ }
1444
+ };
1445
+ function mergeDictionaries(base = DICTIONARIES, override = {}) {
1446
+ const merged = {};
1447
+ for (const locale of [...Object.keys(base), ...Object.keys(override)]) {
1448
+ merged[locale] = { ...base[locale] === void 0 ? {} : base[locale], ...override[locale] === void 0 ? {} : override[locale] };
1449
+ }
1450
+ return merged;
1451
+ }
1452
+ var TOAST_ROOT_SELECTOR = "div[data-dsh-ancesters-toasts]";
1453
+ var TOAST_DISMISS_MS = 8e3;
1454
+ function noticeText(notice, t) {
1455
+ if (notice.kind === "stall") return t("toastStall");
1456
+ return notice.text !== "" ? notice.text : t("toastError");
1457
+ }
1458
+ function mountToastMirror(source, host, options = {}) {
1459
+ const doc = documentOf(host);
1460
+ if (doc === void 0) return () => void 0;
1461
+ const root = host === void 0 || host === null ? toastRoot(doc) : host;
1462
+ if (root === void 0 || typeof root.appendChild !== "function") return () => void 0;
1463
+ const t = typeof options.t === "function" ? options.t : (key) => key;
1464
+ const dismissMs = typeof options.dismissMs === "number" && options.dismissMs >= 0 ? options.dismissMs : TOAST_DISMISS_MS;
1465
+ let node = void 0;
1466
+ let shownSeq = -1;
1467
+ let timer = void 0;
1468
+ const dismiss = (seq) => {
1469
+ if (typeof source.clearNotice === "function") source.clearNotice(seq);
1470
+ };
1471
+ const stopTimer = () => {
1472
+ if (timer !== void 0) clearTimeout(timer);
1473
+ timer = void 0;
1474
+ };
1475
+ const paint = () => {
1476
+ const snapshot = source.store.getSnapshot();
1477
+ const notice = snapshot.notice ?? null;
1478
+ if (notice === null) {
1479
+ stopTimer();
1480
+ shownSeq = -1;
1481
+ if (node !== void 0) {
1482
+ root.removeChild(node);
1483
+ node = void 0;
1484
+ }
1485
+ return;
1486
+ }
1487
+ if (node === void 0) {
1488
+ node = doc.createElement("div");
1489
+ node.className = shared_default.toast;
1490
+ root.appendChild(node);
1491
+ }
1492
+ node.dataset.dshAncestersToast = String(notice.seq);
1493
+ node.dataset.noticeKind = notice.kind;
1494
+ node.textContent = typeof options.text === "function" ? options.text(notice, snapshot, t) : noticeText(notice, t);
1495
+ const seq = notice.seq;
1496
+ node.onclick = () => dismiss(seq);
1497
+ if (seq !== shownSeq) {
1498
+ shownSeq = seq;
1499
+ stopTimer();
1500
+ if (dismissMs > 0 && typeof setTimeout === "function") timer = setTimeout(() => dismiss(seq), dismissMs);
1501
+ }
1502
+ };
1503
+ const unsubscribe = source.store.subscribe(() => paint());
1504
+ paint();
1505
+ return () => {
1506
+ unsubscribe();
1507
+ stopTimer();
1508
+ if (node !== void 0) {
1509
+ root.removeChild(node);
1510
+ node = void 0;
1511
+ }
1512
+ };
1513
+ }
1514
+ function documentOf(host) {
1515
+ const own = host !== void 0 && host !== null ? host.ownerDocument : void 0;
1516
+ if (own !== void 0 && own !== null) return own;
1517
+ return typeof document === "undefined" ? void 0 : document;
1518
+ }
1519
+ function toastRoot(doc) {
1520
+ const standing = doc.querySelectorAll(TOAST_ROOT_SELECTOR);
1521
+ if (standing.length > 0) return standing[0];
1522
+ const root = doc.createElement("div");
1523
+ root.className = shared_default.toastRoot;
1524
+ root.dataset.dshAncestersToasts = "1";
1525
+ const container = doc.body ?? doc.head;
1526
+ if (container === void 0) return void 0;
1527
+ container.appendChild(root);
1528
+ return root;
1529
+ }
1530
+ var SHEET_ID = "dsh-ancesters-" + hash(cssText);
1531
+ function sheetId(css) {
1532
+ return "dsh-ancesters-" + hash(css);
1533
+ }
1534
+ function injected(id) {
1535
+ return document.querySelectorAll('style[data-dsh-ancesters-css="' + id + '"]').length > 0;
1536
+ }
1537
+ function injectCardStyles(sheets) {
1538
+ if (typeof document === "undefined") return;
1539
+ const wanted = [cssText, ...sheets ?? []].filter((sheet) => typeof sheet === "string" && sheet !== "");
1540
+ for (const sheet of wanted) {
1541
+ const id = sheetId(sheet);
1542
+ if (injected(id)) continue;
1543
+ const styleTag = document.createElement("style");
1544
+ styleTag.dataset.dshAncestersCss = id;
1545
+ styleTag.textContent = sheet;
1546
+ document.head.appendChild(styleTag);
1547
+ }
1548
+ }
1549
+ function hash(text2) {
1550
+ let value = 2166136261 >>> 0;
1551
+ for (let index = 0; index < text2.length; index++) {
1552
+ value ^= text2.charCodeAt(index);
1553
+ value = Math.imul(value, 16777619) >>> 0;
1554
+ }
1555
+ return value.toString(36).padStart(6, "0").slice(0, 6) + "-" + text2.length.toString(36);
1556
+ }
1557
+ function unfencedSettingsWrite(ctx, ns) {
1558
+ const settings = ctx.remote?.settings;
1559
+ const mutate = settings?.mutate;
1560
+ if (settings === void 0 || typeof mutate !== "function") return void 0;
1561
+ return async (ops) => {
1562
+ try {
1563
+ const response = await mutate.call(settings, ns, ops, void 0);
1564
+ return response?.ok === true;
1565
+ } catch {
1566
+ return false;
1567
+ }
1568
+ };
1569
+ }
1570
+ function mountSettingsCard(spec) {
1571
+ if (spec === void 0 || typeof spec !== "object" || Array.isArray(spec)) {
1572
+ throw new TypeError("mountSettingsCard: requires a descriptor object ({ entryId, fields, blocks \u2026 })");
1573
+ }
1574
+ if (typeof spec.entryId !== "string" || spec.entryId === "") {
1575
+ throw new TypeError("mountSettingsCard: the descriptor requires a non-empty `entryId`");
1576
+ }
1577
+ if (spec.pluginId !== void 0 && (typeof spec.pluginId !== "string" || spec.pluginId === "")) {
1578
+ throw new TypeError("mountSettingsCard: the descriptor's `pluginId` must be a non-empty string (the row key needs the package identity)");
1579
+ }
1580
+ if (spec.bundleId !== void 0 && (typeof spec.bundleId !== "string" || spec.bundleId === "")) {
1581
+ throw new TypeError("mountSettingsCard: the descriptor's `bundleId` must be a non-empty string (it is the bundle package the row key is built from)");
1582
+ }
1583
+ if (spec.placement !== void 0 && spec.placement !== "row" && spec.placement !== "bundle") {
1584
+ throw new TypeError('mountSettingsCard: the descriptor\'s `placement` is "row" or "bundle"');
1585
+ }
1586
+ const namespace = spec.localeNamespace === void 0 || spec.localeNamespace === "" ? LOCALE_NAMESPACE : spec.localeNamespace;
1587
+ const bundle = spec.placement === "bundle";
1588
+ const slotName = bundle ? "plugins.bundle.config" : "plugins.row.config";
1589
+ return {
1590
+ inject: ["configForms", "slots", "locale", "remote", "remote.settings"],
1591
+ apply(ctx) {
1592
+ if (ctx === void 0 || typeof ctx !== "object" || ctx.slots === void 0 || typeof ctx.slots.inject !== "function") {
1593
+ throw new TypeError("mountSettingsCard.apply: needs the browser plugin context (the shell's `slots` service)");
1594
+ }
1595
+ injectCardStyles();
1596
+ const dicts = mergeDictionaries(DICTIONARIES, spec.locale ?? {});
1597
+ if (ctx.locale !== void 0 && typeof ctx.locale.register === "function") {
1598
+ ctx.effect(() => ctx.locale.register(namespace, dicts), `${spec.entryId}: dictionaries`);
1599
+ }
1600
+ const form = ctx.configForms === void 0 ? void 0 : ctx.configForms.get(spec.entryId);
1601
+ const controller = new CardController(form, {
1602
+ fields: spec.fields,
1603
+ errorField: spec.errorField,
1604
+ settleDeadlineMs: spec.settleDeadlineMs,
1605
+ settleField: spec.settleField,
1606
+ unfencedMutate: unfencedSettingsWrite(ctx, spec.entryId)
1607
+ });
1608
+ ctx.effect(() => () => controller.dispose(), `${spec.entryId}: card controller`);
1609
+ const translate = ctx.locale !== void 0 && typeof ctx.locale.bind === "function" ? ctx.locale.bind(namespace) : (key) => key;
1610
+ if (spec.toasts === true || spec.toasts !== void 0 && typeof spec.toasts === "object") {
1611
+ const toastHost = typeof spec.toasts === "object" ? spec.toasts.host : void 0;
1612
+ const dismissMs = typeof spec.toasts === "object" ? spec.toasts.dismissMs : void 0;
1613
+ const text2 = typeof spec.toasts === "object" ? spec.toasts.text : void 0;
1614
+ ctx.effect(
1615
+ () => mountToastMirror(controller, toastHost, { t: translate, dismissMs, text: text2 }),
1616
+ `${spec.entryId}: toast host`
1617
+ );
1618
+ }
1619
+ const body = (props) => {
1620
+ const view = String(props?.view) === "page" ? "page" : "summary";
1621
+ controller.adoptForm(props?.form === void 0 ? void 0 : props.form);
1622
+ const snapshot = controller.getSnapshot();
1623
+ if (view === "summary") {
1624
+ if (typeof spec.renderSummary !== "function") return null;
1625
+ return spec.renderSummary(snapshot, translate);
1626
+ }
1627
+ if (!snapshot.available && (spec.blocks ?? []).length === 0) return null;
1628
+ const renders = (spec.blocks ?? []).map(
1629
+ (block, index) => renderBlock(block, { snapshot, controller, view, t: translate })
1630
+ );
1631
+ const composed = renders.filter((rendered) => rendered !== null && rendered !== void 0);
1632
+ if (spec.errorLine === false) return composed;
1633
+ const error = snapshot.actionError !== "" ? snapshot.actionError : snapshot.lastError;
1634
+ const line = ErrorLine({ text: error === "" ? "" : error });
1635
+ return line === null ? composed : [...composed, line];
1636
+ };
1637
+ const pageKey = bundle ? bundleConfigKey(spec.bundleId ?? spec.pluginId) : rowConfigKey(spec.bundleId ?? spec.pluginId ?? "", spec.entryId);
1638
+ ctx.slots.inject(slotName, () => {
1639
+ ctx.slots.register(
1640
+ {
1641
+ name: slotName,
1642
+ key: pageKey,
1643
+ locale: namespace,
1644
+ inject: () => controller.inject()
1645
+ },
1646
+ body
1647
+ );
1648
+ });
1649
+ const composer = spec.composer;
1650
+ if (composer !== void 0) {
1651
+ if (typeof composer.id !== "string" || composer.id === "" || typeof composer.bind !== "function") {
1652
+ throw new TypeError("mountSettingsCard: `composer` needs a non-empty `id` and a `bind` function");
1653
+ }
1654
+ const pills = (props) => {
1655
+ const subscribe = props?.useAncestersComposer;
1656
+ const snapshot = typeof subscribe === "function" ? subscribe((state) => state) : controller.getSnapshot();
1657
+ const openState = react4.useState("");
1658
+ const open = openState[0];
1659
+ const setOpen = openState[1];
1660
+ if (snapshot?.available !== true) return null;
1661
+ const t = typeof props?.t === "function" ? props.t : translate;
1662
+ const declared = composer.bind(snapshot, controller, t) ?? [];
1663
+ if (declared.length === 0) return null;
1664
+ return (0, import_jsx_runtime.jsx)("span", {
1665
+ className: shared_default.composerPills,
1666
+ children: declared.map(
1667
+ (pill) => (0, import_jsx_runtime.jsx)(
1668
+ ComposerPill,
1669
+ { ...pill, open: open === pill.key, setOpen: (next) => setOpen(next ? pill.key : "") },
1670
+ pill.key
1671
+ )
1672
+ )
1673
+ });
1674
+ };
1675
+ ctx.slots.inject("conversation.input.left", () => {
1676
+ ctx.slots.register(
1677
+ {
1678
+ name: "conversation.input.left",
1679
+ // The slot is kind `list`: entries are deduped and
1680
+ // placed by a stable `id`, not a keyed `key`.
1681
+ id: composer.id,
1682
+ locale: namespace,
1683
+ inject: () => ({ hooks: { ancestersComposer: controller.store }, controller })
1684
+ },
1685
+ pills
1686
+ );
1687
+ });
1688
+ }
1689
+ }
1690
+ };
1691
+ }
1692
+ function bundleConfigKey(pkgName) {
1693
+ if (typeof pkgName !== "string" || pkgName === "") {
1694
+ throw new TypeError('mountSettingsCard: `placement: "bundle"` needs `pluginId` or `bundleId` (the bundle page is keyed by its package name)');
1695
+ }
1696
+ return pkgName;
1697
+ }
1698
+ function renderBlock(block, props) {
1699
+ if (block.hideWhenUnavailable === true && props.snapshot.available !== true) return null;
1700
+ const compose = { ...block.props ?? {} };
1701
+ if (block.field !== void 0) {
1702
+ compose.value = props.snapshot.values[block.field];
1703
+ compose.field = block.field;
1704
+ }
1705
+ if (block.liveKeys !== void 0) {
1706
+ for (const liveKey of block.liveKeys) compose[liveKey] = props.snapshot.values[liveKey];
1707
+ }
1708
+ if (typeof block.bind === "function") Object.assign(compose, block.bind(props.snapshot, props.controller, props.t));
1709
+ if (block.action !== void 0) compose.action = composeAction(block.action, props.controller, block.field);
1710
+ const component = typeof block.block === "string" ? BlocksByName[block.block] : block.block;
1711
+ if (typeof component !== "function") return null;
1712
+ return component({ ...compose, t: props.t });
1713
+ }
1714
+ function composeAction(action, controller, field2) {
1715
+ if (typeof action === "function") return action(controller);
1716
+ if (action === "stage") return (value) => controller.stage(String(field2 ?? ""), value);
1717
+ if (action === "apply") return () => controller.applyStaged();
1718
+ if (action === "discard") return () => controller.discard();
1719
+ if (action === "write") return (value) => controller.writeField(String(field2 ?? ""), value);
1720
+ return (value) => value === void 0 ? controller.writeTrigger(String(field2 ?? "")) : controller.writeEntryTrigger(String(field2 ?? ""), value);
1721
+ }
1722
+ var BlocksByName = Blocks;
1723
+ function mountSettingsCard2(spec) {
1724
+ return mountSettingsCard(spec);
1725
+ }
1726
+
1727
+ // src/client/catalog.ts
1728
+ var ID_MAX_LENGTH = 1024;
1729
+ var PATH_PATTERN = /^[^\x00-\x1f\x7f]{1,1024}$/u;
1730
+ var NAME_MAX_LENGTH = 200;
1731
+ var ENTRY_CAP = 50;
1732
+ function isValidEntryId(id) {
1733
+ if (id === "" || id.length > ID_MAX_LENGTH) return false;
1734
+ return PATH_PATTERN.test(id);
1735
+ }
1736
+ function entryLabel(entry) {
1737
+ const name = entry.name.trim();
1738
+ return name === "" ? entry.id : name;
1739
+ }
1740
+ function normalizeEntries(value) {
1741
+ if (!Array.isArray(value)) return [];
1742
+ const out = [];
1743
+ const seen = /* @__PURE__ */ new Set();
1744
+ for (const item of value) {
1745
+ if (out.length === ENTRY_CAP) break;
1746
+ if (item === null || typeof item !== "object" || Array.isArray(item)) continue;
1747
+ const raw = item;
1748
+ const id = typeof raw.id === "string" ? raw.id.trim() : "";
1749
+ if (!isValidEntryId(id) || seen.has(id)) continue;
1750
+ seen.add(id);
1751
+ const name = typeof raw.name === "string" ? raw.name.trim() : "";
1752
+ out.push({ id, name: name.slice(0, NAME_MAX_LENGTH) });
1753
+ }
1754
+ return out;
1755
+ }
1756
+
46
1757
  // src/client/card/index.ts
47
- var react4 = __toESM(require("react"), 1);
48
- var import_jsx_runtime6 = require("react/jsx-runtime");
1758
+ var react8 = __toESM(require("react"), 1);
1759
+ var import_jsx_runtime15 = require("react/jsx-runtime");
49
1760
 
50
1761
  // dsh-css:/home/roberto/dev/dsh/dsh-chrome-mcp/src/client/styles/ChromeMcpCard.module.css
51
- var cssText = '.e5pfpa_card{border:.5px solid var(--dsw-alias-border-l4);background:var(--dsw-alias-bg-layer-3);border-radius:16px;list-style:none;transition:border-color .16s,background .16s}.e5pfpa_card:hover{border-color:var(--dsw-alias-label-dimmed)}.e5pfpa_cardOpen{background:var(--dsw-alias-bg-layer-2);border-color:var(--dsw-alias-label-dimmed)}.e5pfpa_header{appearance:none;width:100%;font:inherit;color:inherit;text-align:left;cursor:pointer;background:0 0;border:0;border-radius:12px;align-items:center;gap:12px;padding:14px 16px;display:flex}.e5pfpa_header:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:-2px}.e5pfpa_headText{flex-direction:column;flex:1;gap:4px;min-width:0;display:flex}.e5pfpa_nameRow{align-items:center;gap:8px;min-width:0;display:flex}.e5pfpa_name{color:var(--dsw-alias-label-primary);font-size:15px;font-weight:600;line-height:1.4}.e5pfpa_desc{color:var(--dsw-alias-label-tertiary);font-size:13px;line-height:1.5}.e5pfpa_chevron{color:var(--dsw-alias-label-tertiary);flex:none;transition:transform .16s}.e5pfpa_chevronOpen{transform:rotate(180deg)}.e5pfpa_body{border-top:.5px solid var(--dsw-alias-border-l2);display:flex;flex-direction:column;gap:10px;margin:0 16px;padding:12px 0}.e5pfpa_field{align-items:flex-start;gap:4px;display:flex;flex-direction:column;width:100%}.e5pfpa_fieldRow{align-items:center;gap:8px;display:flex;width:100%}.e5pfpa_fieldTitle{color:var(--dsw-alias-label-primary);font-size:14px;font-weight:400;line-height:22px;flex:1;min-width:0}.e5pfpa_fieldDesc{color:var(--dsw-alias-label-tertiary);font-size:12px;font-weight:400;line-height:18px;width:100%}.e5pfpa_selector{background:var(--dsw-alias-bg-module-platform);height:36px;font:inherit;color:var(--dsw-alias-label-primary);cursor:pointer;border:none;border-radius:18px;align-items:center;gap:12px;padding:0 14px;font-size:14px;line-height:22px;display:inline-flex}.e5pfpa_selector:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.e5pfpa_selector:disabled{cursor:default}.e5pfpa_selectorWrap{display:flex}.e5pfpa_pillChevron{flex:none}.e5pfpa_row{display:flex;gap:10px;align-items:center}.e5pfpa_button{display:inline-flex;align-items:center;justify-content:center;gap:4px;border:.5px solid var(--dsw-alias-border-l3);border-radius:14px;cursor:pointer;font-size:12px;line-height:18px;color:var(--dsw-alias-label-primary);background:transparent;padding:0 10px;height:28px}.e5pfpa_button:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.e5pfpa_button:disabled{cursor:not-allowed;opacity:.4}.e5pfpa_button:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}.e5pfpa_readOnly{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px}.e5pfpa_error{color:var(--dsw-alias-state-error-primary);margin:0;font-size:12px;line-height:1.5}.e5pfpa_dot{box-sizing:border-box;corner-shape:round;border-radius:50%;flex:none;width:8px;height:8px;display:inline-block}.e5pfpa_dotError{background:var(--dsw-alias-state-error-primary)}.e5pfpa_empty{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px}.e5pfpa_catalog{flex-direction:column;align-items:stretch;gap:10px;display:flex}.e5pfpa_catalog+.e5pfpa_catalog{border-top:.5px solid var(--dsw-alias-border-l2);padding-top:12px}.e5pfpa_catalog>.e5pfpa_linkButton{align-self:flex-start}.e5pfpa_catalog>.e5pfpa_linkButtonRow{align-self:flex-start;display:flex;gap:8px;align-items:center}.e5pfpa_linkButton{box-sizing:border-box;border:none;background:0 0;color:var(--dsw-alias-label-tertiary);cursor:pointer;border-radius:14px;align-items:center;height:28px;padding:0 10px;font:inherit;font-size:12px;line-height:18px;display:inline-flex}.e5pfpa_linkButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-secondary)}.e5pfpa_linkButton:disabled{opacity:.4;cursor:default}.e5pfpa_linkButton:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}.e5pfpa_catalogEntry{border:.5px solid var(--dsw-alias-border-l4);background:var(--dsw-alias-bg-module-platform);border-radius:10px;padding:6px}.e5pfpa_catalogRow{grid-template-columns:minmax(0,1.4fr) minmax(0,1fr) auto;align-items:center;gap:6px;display:grid}.e5pfpa_catalogInput{box-sizing:border-box;border:.5px solid var(--dsw-alias-border-l4);background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);border-radius:8px;height:28px;padding:0 10px;font:inherit;font-size:14px;line-height:22px;min-width:0;width:100%}.e5pfpa_catalogInput::placeholder{color:var(--dsw-alias-label-dimmed)}.e5pfpa_catalogInput:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:-1px}.e5pfpa_catalogInput:disabled{opacity:.6;cursor:default}.e5pfpa_iconButton{box-sizing:border-box;width:28px;height:28px;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:none;border-radius:6px;justify-content:center;align-items:center;display:inline-flex}.e5pfpa_iconButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.e5pfpa_iconButton:disabled{opacity:.4;cursor:default}.e5pfpa_iconButton:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}.e5pfpa_iconButtonDanger:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-danger);color:var(--dsw-alias-state-error-primary)}.e5pfpa_addButton{box-sizing:border-box;border:.5px solid var(--dsw-alias-border-l3);color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border-radius:14px;align-self:flex-start;align-items:center;gap:4px;height:28px;padding:0 10px;font:inherit;font-size:12px;line-height:18px;display:inline-flex}.e5pfpa_addButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.e5pfpa_addButton:disabled{opacity:.4;cursor:default}.e5pfpa_disclosure{flex-direction:column;gap:10px;display:flex}.e5pfpa_disclosureSummary{color:var(--dsw-alias-label-secondary);cursor:pointer;list-style:none;align-items:center;gap:6px;font-size:12px;line-height:18px;user-select:none;display:flex}.e5pfpa_disclosureSummary::-webkit-details-marker{display:none}.e5pfpa_disclosureSummary:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px;border-radius:6px}.e5pfpa_disclosureLabel:before{content:"\\25b8";display:inline-block;margin-right:6px;transition:transform .16s}.e5pfpa_disclosure[open] .e5pfpa_disclosureLabel:before{transform:rotate(90deg)}.e5pfpa_disclosureCount{color:var(--dsw-alias-label-tertiary)}.e5pfpa_disclosureBody{flex-direction:column;gap:10px;display:flex}.e5pfpa_disclosureBody>.e5pfpa_linkButton{align-self:flex-start}.e5pfpa_disclosureBody>.e5pfpa_linkButtonRow{align-self:flex-start;display:flex;gap:8px;align-items:center}.e5pfpa_toggleLabel{align-items:center;display:inline-flex;flex:none}.e5pfpa_fetchDialog{background:color-mix(in srgb,var(--dsw-alias-label-primary) 28%,transparent);align-items:center;justify-content:center;display:flex;position:fixed;inset:0;z-index:90}.e5pfpa_dialogContent{background:var(--dsw-alias-bg-layer-3);border:.5px solid var(--dsw-alias-border-l3);border-radius:16px;flex-direction:column;gap:10px;width:min(520px,calc(100vw - 32px));max-height:min(620px,calc(100vh - 48px));display:flex;overflow:hidden}.e5pfpa_dialogHeader{align-items:center;gap:8px;padding:14px 16px 0;display:flex}.e5pfpa_dialogTitle{color:var(--dsw-alias-label-primary);font-size:15px;font-weight:600;line-height:22px;flex:1;min-width:0;margin:0}.e5pfpa_dialogClose{box-sizing:border-box;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:none;border-radius:6px;justify-content:center;align-items:center;flex:none;width:28px;height:28px;display:inline-flex}.e5pfpa_dialogClose:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.e5pfpa_dialogClose:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}.e5pfpa_dialogDescription{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px;margin:0;padding:0 16px}.e5pfpa_dialogBody{flex-direction:column;flex:1;gap:8px;min-height:0;padding:0 16px;display:flex}.e5pfpa_candidateToolbar{align-items:center;gap:8px;display:flex}.e5pfpa_candidateSearch{box-sizing:border-box;border:.5px solid var(--dsw-alias-border-l4);background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);border-radius:8px;height:32px;padding:0 10px;font:inherit;font-size:12px;line-height:20px;flex:1;min-width:0}.e5pfpa_candidateSearch::placeholder{color:var(--dsw-alias-label-dimmed)}.e5pfpa_candidateSearch:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:-1px}.e5pfpa_candidateList{flex-direction:column;gap:2px;margin:0;padding:0 0 10px;list-style:none;overflow-y:auto;display:flex}.e5pfpa_candidate{border-radius:8px;padding:4px 6px}.e5pfpa_candidate:hover{background:var(--dsw-alias-interactive-bg-hover)}.e5pfpa_candidateLabel{align-items:center;gap:8px;min-width:0;display:flex}.e5pfpa_candidateLabel input[type=checkbox]{accent-color:var(--dsw-alias-brand-primary);flex:none;margin:0}.e5pfpa_candidateId{color:var(--dsw-alias-label-primary);font-size:12px;line-height:18px;text-overflow:ellipsis;white-space:nowrap;flex:1;min-width:0;overflow:hidden}.e5pfpa_candidateNote{color:var(--dsw-alias-label-tertiary);flex:none;font-size:11px;line-height:16px}.e5pfpa_dialogFooter{border-top:.5px solid var(--dsw-alias-border-l2);align-items:center;justify-content:flex-end;gap:8px;padding:12px 16px;display:flex}.e5pfpa_dialogButton{display:inline-flex;align-items:center;justify-content:center;gap:4px;border:.5px solid var(--dsw-alias-border-l3);border-radius:16px;cursor:pointer;font-size:13px;line-height:20px;color:var(--dsw-alias-label-primary);background:transparent;padding:0 12px;height:32px}.e5pfpa_dialogButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.e5pfpa_dialogButton:disabled{cursor:not-allowed;opacity:.4}.e5pfpa_dialogButton:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}.e5pfpa_dialogButtonPrimary{color:var(--dsw-alias-label-primary);font-weight:600}.e5pfpa_selectorLabel{text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}.e5pfpa_result{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:18px}.e5pfpa_resultValue{color:var(--dsw-alias-label-secondary);margin-left:4px}.e5pfpa_resultAge{color:var(--dsw-alias-label-dimmed);margin-left:4px}.e5pfpa_notice{flex-direction:column;gap:4px;display:flex;border:.5px solid var(--dsw-alias-border-l3);border-radius:10px;background:var(--dsw-alias-bg-layer-1);padding:8px 10px}.e5pfpa_noticeTitle{color:var(--dsw-alias-label-primary);font-size:12px;font-weight:600;line-height:18px}.e5pfpa_noticeBody{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px}.e5pfpa_docsLink{color:var(--dsw-alias-label-tertiary);align-items:center;gap:4px;display:inline-flex;text-decoration:none;font-size:12px;line-height:1.5}.e5pfpa_docsLinkLabel{text-decoration:none}.e5pfpa_docsLink:hover{color:var(--dsw-alias-brand-primary)}.e5pfpa_docsLink:hover .e5pfpa_docsLinkLabel{text-decoration:underline}.e5pfpa_docsLink:hover .e5pfpa_docsIcon{color:var(--dsw-alias-brand-primary)}.e5pfpa_docsIcon{color:var(--dsw-alias-label-tertiary);flex:none}.e5pfpa_docsLink:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px;border-radius:4px}.e5pfpa_catalogRowSingle{grid-template-columns:minmax(0,1fr) auto}.e5pfpa_catalogInputMono{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px}\n';
52
- var ChromeMcpCard_default = { "card": "e5pfpa_card", "cardOpen": "e5pfpa_cardOpen", "header": "e5pfpa_header", "headText": "e5pfpa_headText", "nameRow": "e5pfpa_nameRow", "name": "e5pfpa_name", "desc": "e5pfpa_desc", "chevron": "e5pfpa_chevron", "chevronOpen": "e5pfpa_chevronOpen", "body": "e5pfpa_body", "field": "e5pfpa_field", "fieldRow": "e5pfpa_fieldRow", "fieldTitle": "e5pfpa_fieldTitle", "fieldDesc": "e5pfpa_fieldDesc", "selector": "e5pfpa_selector", "selectorWrap": "e5pfpa_selectorWrap", "pillChevron": "e5pfpa_pillChevron", "row": "e5pfpa_row", "button": "e5pfpa_button", "readOnly": "e5pfpa_readOnly", "error": "e5pfpa_error", "dot": "e5pfpa_dot", "dotError": "e5pfpa_dotError", "empty": "e5pfpa_empty", "catalog": "e5pfpa_catalog", "linkButton": "e5pfpa_linkButton", "linkButtonRow": "e5pfpa_linkButtonRow", "catalogEntry": "e5pfpa_catalogEntry", "catalogRow": "e5pfpa_catalogRow", "catalogInput": "e5pfpa_catalogInput", "iconButton": "e5pfpa_iconButton", "iconButtonDanger": "e5pfpa_iconButtonDanger", "addButton": "e5pfpa_addButton", "disclosure": "e5pfpa_disclosure", "disclosureSummary": "e5pfpa_disclosureSummary", "disclosureLabel": "e5pfpa_disclosureLabel", "disclosureCount": "e5pfpa_disclosureCount", "disclosureBody": "e5pfpa_disclosureBody", "toggleLabel": "e5pfpa_toggleLabel", "fetchDialog": "e5pfpa_fetchDialog", "dialogContent": "e5pfpa_dialogContent", "dialogHeader": "e5pfpa_dialogHeader", "dialogTitle": "e5pfpa_dialogTitle", "dialogClose": "e5pfpa_dialogClose", "dialogDescription": "e5pfpa_dialogDescription", "dialogBody": "e5pfpa_dialogBody", "candidateToolbar": "e5pfpa_candidateToolbar", "candidateSearch": "e5pfpa_candidateSearch", "candidateList": "e5pfpa_candidateList", "candidate": "e5pfpa_candidate", "candidateLabel": "e5pfpa_candidateLabel", "candidateId": "e5pfpa_candidateId", "candidateNote": "e5pfpa_candidateNote", "dialogFooter": "e5pfpa_dialogFooter", "dialogButton": "e5pfpa_dialogButton", "dialogButtonPrimary": "e5pfpa_dialogButtonPrimary", "selectorLabel": "e5pfpa_selectorLabel", "result": "e5pfpa_result", "resultValue": "e5pfpa_resultValue", "resultAge": "e5pfpa_resultAge", "notice": "e5pfpa_notice", "noticeTitle": "e5pfpa_noticeTitle", "noticeBody": "e5pfpa_noticeBody", "docsLink": "e5pfpa_docsLink", "docsLinkLabel": "e5pfpa_docsLinkLabel", "docsIcon": "e5pfpa_docsIcon", "catalogRowSingle": "e5pfpa_catalogRowSingle", "catalogInputMono": "e5pfpa_catalogInputMono" };
1762
+ var cssText2 = '.e5pfpa_body{flex-direction:column;gap:10px;display:flex}.e5pfpa_field{align-items:flex-start;gap:4px;display:flex;flex-direction:column;width:100%}.e5pfpa_fieldRow{align-items:center;gap:8px;display:flex;width:100%}.e5pfpa_fieldTitle{color:var(--dsw-alias-label-primary);font-size:14px;font-weight:400;line-height:22px;flex:1;min-width:0}.e5pfpa_fieldDesc{color:var(--dsw-alias-label-tertiary);font-size:12px;font-weight:400;line-height:18px;width:100%}.e5pfpa_selector{background:var(--dsw-alias-bg-module-platform);height:36px;font:inherit;color:var(--dsw-alias-label-primary);cursor:pointer;border:none;border-radius:18px;align-items:center;gap:12px;padding:0 14px;font-size:14px;line-height:22px;display:inline-flex}.e5pfpa_selector:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.e5pfpa_selector:disabled{cursor:default}.e5pfpa_selectorWrap{display:flex}.e5pfpa_pillChevron{flex:none}.e5pfpa_row{display:flex;gap:10px;align-items:center}.e5pfpa_button{display:inline-flex;align-items:center;justify-content:center;gap:4px;border:.5px solid var(--dsw-alias-border-l3);border-radius:14px;cursor:pointer;font-size:12px;line-height:18px;color:var(--dsw-alias-label-primary);background:transparent;padding:0 10px;height:28px}.e5pfpa_button:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.e5pfpa_button:disabled{cursor:not-allowed;opacity:.4}.e5pfpa_button:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}.e5pfpa_readOnly{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px}.e5pfpa_error{color:var(--dsw-alias-state-error-primary);margin:0;font-size:12px;line-height:1.5}.e5pfpa_dot{box-sizing:border-box;corner-shape:round;border-radius:50%;flex:none;width:8px;height:8px;display:inline-block}.e5pfpa_dotError{background:var(--dsw-alias-state-error-primary)}.e5pfpa_badge{color:var(--dsw-alias-label-tertiary);background:var(--dsw-alias-bg-layer-1);border-radius:10px;padding:1px 8px;font-size:11px;line-height:16px;display:inline-flex;align-items:center;flex:none}.e5pfpa_empty{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px}.e5pfpa_catalog{flex-direction:column;align-items:stretch;gap:10px;display:flex}.e5pfpa_catalog+.e5pfpa_catalog{border-top:.5px solid var(--dsw-alias-border-l2);padding-top:12px}.e5pfpa_catalog>.e5pfpa_linkButton{align-self:flex-start}.e5pfpa_catalog>.e5pfpa_linkButtonRow{align-self:flex-start;display:flex;gap:8px;align-items:center}.e5pfpa_linkButton{box-sizing:border-box;border:none;background:0 0;color:var(--dsw-alias-label-tertiary);cursor:pointer;border-radius:14px;align-items:center;height:28px;padding:0 10px;font:inherit;font-size:12px;line-height:18px;display:inline-flex}.e5pfpa_linkButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-secondary)}.e5pfpa_linkButton:disabled{opacity:.4;cursor:default}.e5pfpa_linkButton:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}.e5pfpa_catalogEntry{border:.5px solid var(--dsw-alias-border-l4);background:var(--dsw-alias-bg-module-platform);border-radius:10px;padding:6px}.e5pfpa_catalogRow{grid-template-columns:minmax(0,1.4fr) minmax(0,1fr) auto;align-items:center;gap:6px;display:grid}.e5pfpa_catalogInput{box-sizing:border-box;border:.5px solid var(--dsw-alias-border-l4);background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);border-radius:8px;height:28px;padding:0 10px;font:inherit;font-size:14px;line-height:22px;min-width:0;width:100%}.e5pfpa_catalogInput::placeholder{color:var(--dsw-alias-label-dimmed)}.e5pfpa_catalogInput:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:-1px}.e5pfpa_catalogInput:disabled{opacity:.6;cursor:default}.e5pfpa_iconButton{box-sizing:border-box;width:28px;height:28px;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:none;border-radius:6px;justify-content:center;align-items:center;display:inline-flex}.e5pfpa_iconButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.e5pfpa_iconButton:disabled{opacity:.4;cursor:default}.e5pfpa_iconButton:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}.e5pfpa_iconButtonDanger:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-danger);color:var(--dsw-alias-state-error-primary)}.e5pfpa_addButton{box-sizing:border-box;border:.5px solid var(--dsw-alias-border-l3);color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border-radius:14px;align-self:flex-start;align-items:center;gap:4px;height:28px;padding:0 10px;font:inherit;font-size:12px;line-height:18px;display:inline-flex}.e5pfpa_addButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.e5pfpa_addButton:disabled{opacity:.4;cursor:default}.e5pfpa_disclosure{flex-direction:column;gap:10px;display:flex}.e5pfpa_disclosureSummary{color:var(--dsw-alias-label-secondary);cursor:pointer;list-style:none;align-items:center;gap:6px;font-size:12px;line-height:18px;user-select:none;display:flex}.e5pfpa_disclosureSummary::-webkit-details-marker{display:none}.e5pfpa_disclosureSummary:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px;border-radius:6px}.e5pfpa_disclosureLabel:before{content:"\\25b8";display:inline-block;margin-right:6px;transition:transform .16s}.e5pfpa_disclosure[open] .e5pfpa_disclosureLabel:before{transform:rotate(90deg)}.e5pfpa_disclosureCount{color:var(--dsw-alias-label-tertiary)}.e5pfpa_disclosureBody{flex-direction:column;gap:10px;display:flex}.e5pfpa_disclosureBody>.e5pfpa_linkButton{align-self:flex-start}.e5pfpa_disclosureBody>.e5pfpa_linkButtonRow{align-self:flex-start;display:flex;gap:8px;align-items:center}.e5pfpa_toggleLabel{align-items:center;display:inline-flex;flex:none}.e5pfpa_fetchDialog{background:color-mix(in srgb,var(--dsw-alias-label-primary) 28%,transparent);align-items:center;justify-content:center;display:flex;position:fixed;inset:0;z-index:90}.e5pfpa_dialogContent{background:var(--dsw-alias-bg-layer-3);border:.5px solid var(--dsw-alias-border-l3);border-radius:16px;flex-direction:column;gap:10px;width:min(520px,calc(100vw - 32px));max-height:min(620px,calc(100vh - 48px));display:flex;overflow:hidden}.e5pfpa_dialogHeader{align-items:center;gap:8px;padding:14px 16px 0;display:flex}.e5pfpa_dialogTitle{color:var(--dsw-alias-label-primary);font-size:15px;font-weight:600;line-height:22px;flex:1;min-width:0;margin:0}.e5pfpa_dialogClose{box-sizing:border-box;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:none;border-radius:6px;justify-content:center;align-items:center;flex:none;width:28px;height:28px;display:inline-flex}.e5pfpa_dialogClose:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.e5pfpa_dialogClose:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}.e5pfpa_dialogDescription{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px;margin:0;padding:0 16px}.e5pfpa_dialogBody{flex-direction:column;flex:1;gap:8px;min-height:0;padding:0 16px;display:flex}.e5pfpa_candidateToolbar{align-items:center;gap:8px;display:flex}.e5pfpa_candidateSearch{box-sizing:border-box;border:.5px solid var(--dsw-alias-border-l4);background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);border-radius:8px;height:32px;padding:0 10px;font:inherit;font-size:12px;line-height:20px;flex:1;min-width:0}.e5pfpa_candidateSearch::placeholder{color:var(--dsw-alias-label-dimmed)}.e5pfpa_candidateSearch:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:-1px}.e5pfpa_candidateList{flex-direction:column;gap:2px;margin:0;padding:0 0 10px;list-style:none;overflow-y:auto;display:flex}.e5pfpa_candidate{border-radius:8px;padding:4px 6px}.e5pfpa_candidate:hover{background:var(--dsw-alias-interactive-bg-hover)}.e5pfpa_candidateLabel{align-items:center;gap:8px;min-width:0;display:flex}.e5pfpa_candidateLabel input[type=checkbox]{accent-color:var(--dsw-alias-brand-primary);flex:none;margin:0}.e5pfpa_candidateId{color:var(--dsw-alias-label-primary);font-size:12px;line-height:18px;text-overflow:ellipsis;white-space:nowrap;flex:1;min-width:0;overflow:hidden}.e5pfpa_candidateNote{color:var(--dsw-alias-label-tertiary);flex:0 1 auto;min-width:0;overflow-wrap:anywhere;font-size:11px;line-height:16px}.e5pfpa_dialogFooter{border-top:.5px solid var(--dsw-alias-border-l2);align-items:center;justify-content:flex-end;gap:8px;padding:12px 16px;display:flex}.e5pfpa_dialogButton{display:inline-flex;align-items:center;justify-content:center;gap:4px;border:.5px solid var(--dsw-alias-border-l3);border-radius:16px;cursor:pointer;font-size:13px;line-height:20px;color:var(--dsw-alias-label-primary);background:transparent;padding:0 12px;height:32px}.e5pfpa_dialogButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.e5pfpa_dialogButton:disabled{cursor:not-allowed;opacity:.4}.e5pfpa_dialogButton:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}.e5pfpa_dialogButtonPrimary{color:var(--dsw-alias-label-primary);font-weight:600}.e5pfpa_selectorLabel{text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}.e5pfpa_result{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:18px}.e5pfpa_resultValue{color:var(--dsw-alias-label-secondary);margin-left:4px}.e5pfpa_resultAge{color:var(--dsw-alias-label-dimmed);margin-left:4px}.e5pfpa_notice{flex-direction:column;gap:4px;display:flex;border:.5px solid var(--dsw-alias-border-l3);border-radius:10px;background:var(--dsw-alias-bg-layer-1);padding:8px 10px}.e5pfpa_noticeTitle{color:var(--dsw-alias-label-primary);font-size:12px;font-weight:600;line-height:18px}.e5pfpa_noticeBody{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px}.e5pfpa_docsLink{color:var(--dsw-alias-label-tertiary);align-items:center;gap:4px;display:inline-flex;text-decoration:none;font-size:12px;line-height:1.5}.e5pfpa_docsLinkLabel{text-decoration:none}.e5pfpa_docsLink:hover{color:var(--dsw-alias-brand-primary)}.e5pfpa_docsLink:hover .e5pfpa_docsLinkLabel{text-decoration:underline}.e5pfpa_docsLink:hover .e5pfpa_docsIcon{color:var(--dsw-alias-brand-primary)}.e5pfpa_docsIcon{color:var(--dsw-alias-label-tertiary);flex:none}.e5pfpa_docsLink:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px;border-radius:4px}.e5pfpa_catalogRowSingle{grid-template-columns:minmax(0,1fr) auto}.e5pfpa_catalogInputMono{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px}.e5pfpa_footer{border-top:.5px solid var(--dsw-alias-border-l2);align-items:center;justify-content:flex-end;gap:8px;padding:12px 0 0;display:flex}.e5pfpa_footerError{color:var(--dsw-alias-label-error);text-align:right;min-width:0;flex:1;margin:0;font-size:12px;line-height:1.5}.e5pfpa_footerButton{border:.5px solid var(--dsw-alias-border-l3);border-radius:8px;cursor:pointer;color:var(--dsw-alias-label-secondary);background:transparent;padding:5px 14px;font-size:13px;line-height:1.5}.e5pfpa_footerButton:hover:not(:disabled){color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-label-dimmed)}.e5pfpa_footerButton:disabled{cursor:default;opacity:.4}.e5pfpa_footerButton:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}.e5pfpa_footerButtonPrimary{color:var(--dsw-alias-bg-layer-3);font-weight:600;background:var(--dsw-alias-label-primary);border-color:transparent}.e5pfpa_footerButtonPrimary:hover:not(:disabled){color:var(--dsw-alias-bg-layer-3);background:var(--dsw-alias-label-secondary);border-color:transparent}\n';
1763
+ var ChromeMcpCard_default = { "body": "e5pfpa_body", "field": "e5pfpa_field", "fieldRow": "e5pfpa_fieldRow", "fieldTitle": "e5pfpa_fieldTitle", "fieldDesc": "e5pfpa_fieldDesc", "selector": "e5pfpa_selector", "selectorWrap": "e5pfpa_selectorWrap", "pillChevron": "e5pfpa_pillChevron", "row": "e5pfpa_row", "button": "e5pfpa_button", "readOnly": "e5pfpa_readOnly", "error": "e5pfpa_error", "dot": "e5pfpa_dot", "dotError": "e5pfpa_dotError", "badge": "e5pfpa_badge", "empty": "e5pfpa_empty", "catalog": "e5pfpa_catalog", "linkButton": "e5pfpa_linkButton", "linkButtonRow": "e5pfpa_linkButtonRow", "catalogEntry": "e5pfpa_catalogEntry", "catalogRow": "e5pfpa_catalogRow", "catalogInput": "e5pfpa_catalogInput", "iconButton": "e5pfpa_iconButton", "iconButtonDanger": "e5pfpa_iconButtonDanger", "addButton": "e5pfpa_addButton", "disclosure": "e5pfpa_disclosure", "disclosureSummary": "e5pfpa_disclosureSummary", "disclosureLabel": "e5pfpa_disclosureLabel", "disclosureCount": "e5pfpa_disclosureCount", "disclosureBody": "e5pfpa_disclosureBody", "toggleLabel": "e5pfpa_toggleLabel", "fetchDialog": "e5pfpa_fetchDialog", "dialogContent": "e5pfpa_dialogContent", "dialogHeader": "e5pfpa_dialogHeader", "dialogTitle": "e5pfpa_dialogTitle", "dialogClose": "e5pfpa_dialogClose", "dialogDescription": "e5pfpa_dialogDescription", "dialogBody": "e5pfpa_dialogBody", "candidateToolbar": "e5pfpa_candidateToolbar", "candidateSearch": "e5pfpa_candidateSearch", "candidateList": "e5pfpa_candidateList", "candidate": "e5pfpa_candidate", "candidateLabel": "e5pfpa_candidateLabel", "candidateId": "e5pfpa_candidateId", "candidateNote": "e5pfpa_candidateNote", "dialogFooter": "e5pfpa_dialogFooter", "dialogButton": "e5pfpa_dialogButton", "dialogButtonPrimary": "e5pfpa_dialogButtonPrimary", "selectorLabel": "e5pfpa_selectorLabel", "result": "e5pfpa_result", "resultValue": "e5pfpa_resultValue", "resultAge": "e5pfpa_resultAge", "notice": "e5pfpa_notice", "noticeTitle": "e5pfpa_noticeTitle", "noticeBody": "e5pfpa_noticeBody", "docsLink": "e5pfpa_docsLink", "docsLinkLabel": "e5pfpa_docsLinkLabel", "docsIcon": "e5pfpa_docsIcon", "catalogRowSingle": "e5pfpa_catalogRowSingle", "catalogInputMono": "e5pfpa_catalogInputMono", "footer": "e5pfpa_footer", "footerError": "e5pfpa_footerError", "footerButton": "e5pfpa_footerButton", "footerButtonPrimary": "e5pfpa_footerButtonPrimary" };
53
1764
 
54
1765
  // src/client/card/flags.ts
55
- var import_jsx_runtime2 = require("react/jsx-runtime");
1766
+ var import_jsx_runtime11 = require("react/jsx-runtime");
56
1767
 
57
1768
  // src/client/plugin-meta.ts
58
- var SETTINGS_NAMESPACE = "chrome-mcp";
59
- var LOCALE_NAMESPACE = "chromeMcp";
1769
+ var ENTRY_ID = "mcp-chrome";
60
1770
  var PLUGIN_ID = "@comecaramelos/dsh-chrome-mcp";
1771
+ var BUNDLE_ID = "@comecaramelos/dsh-mcp-manager-bundle";
1772
+ var ROW_CONFIG_KEY = `${BUNDLE_ID}#${ENTRY_ID}`;
1773
+ var LOCALE_NAMESPACE2 = "chromeMcp";
61
1774
  var CONFIGURATION_URL = "https://github.com/ChromeDevTools/chrome-devtools-mcp/blob/main/docs/configuration.md";
62
- var inject = ["slots", "locale", "settingsScope"];
1775
+ var RUN_SETTLE_TIMEOUT_MS2 = 9e4;
1776
+ var LIVE_KEYS = [
1777
+ "lastError",
1778
+ "chromeMissing",
1779
+ "executableDiscoveryRevision",
1780
+ "chromeVersion",
1781
+ "executableStatus",
1782
+ "effectiveChromePath",
1783
+ "effectiveSource",
1784
+ "stderrEffective",
1785
+ "defaultExtraFlags",
1786
+ "wslExtraFlags",
1787
+ "wslWindowsExecutable",
1788
+ "windowsChromeStatus",
1789
+ "carriesConnectionMode",
1790
+ "runningFlags",
1791
+ "runningNote"
1792
+ ];
63
1793
 
64
1794
  // src/client/card/icons.ts
65
- var CHEVRON_PATH = "M11.8486 5.5L11.4238 5.92383L8.69727 8.65137C8.44157 8.90706 8.21562 9.13382 8.01172 9.29785C7.79912 9.46883 7.55595 9.61756 7.25 9.66602C7.08435 9.69222 6.91565 9.69222 6.75 9.66602C6.44405 9.61756 6.20088 9.46883 5.98828 9.29785C5.78438 9.13382 5.55843 8.90706 5.30273 8.65137L2.57617 5.92383L2.15137 5.5L3 4.65137L3.42383 5.07617L6.15137 7.80273C6.42595 8.07732 6.59876 8.24849 6.74023 8.3623C6.87291 8.46904 6.92272 8.47813 6.9375 8.48047C6.97895 8.48703 7.02105 8.48703 7.0625 8.48047C7.07728 8.47813 7.12709 8.46904 7.25977 8.3623C7.40124 8.24849 7.57405 8.07732 7.84863 7.80273L10.5762 5.07617L11 4.65137L11.8486 5.5Z";
66
- var TRASH_PATH = "M2.5 4h11M6.5 4V2.5h3V4M4 4l.7 9a1 1 0 001 .9h4.6a1 1 0 001-.9L12 4M6.5 6.8v4.4M9.5 6.8v4.4";
67
- var CLOSE_PATHS = [
1795
+ var CHEVRON_PATH2 = "M11.8486 5.5L11.4238 5.92383L8.69727 8.65137C8.44157 8.90706 8.21562 9.13382 8.01172 9.29785C7.79912 9.46883 7.55595 9.61756 7.25 9.66602C7.08435 9.69222 6.91565 9.69222 6.75 9.66602C6.44405 9.61756 6.20088 9.46883 5.98828 9.29785C5.78438 9.13382 5.55843 8.90706 5.30273 8.65137L2.57617 5.92383L2.15137 5.5L3 4.65137L3.42383 5.07617L6.15137 7.80273C6.42595 8.07732 6.59876 8.24849 6.74023 8.3623C6.87291 8.46904 6.92272 8.47813 6.9375 8.48047C6.97895 8.48703 7.02105 8.48703 7.0625 8.48047C7.07728 8.47813 7.12709 8.46904 7.25977 8.3623C7.40124 8.24849 7.57405 8.07732 7.84863 7.80273L10.5762 5.07617L11 4.65137L11.8486 5.5Z";
1796
+ var TRASH_PATH2 = "M2.5 4h11M6.5 4V2.5h3V4M4 4l.7 9a1 1 0 001 .9h4.6a1 1 0 001-.9L12 4M6.5 6.8v4.4M9.5 6.8v4.4";
1797
+ var CLOSE_PATHS2 = [
68
1798
  "M14.1168 13.197L13.197 14.1167L1.8833 2.80303L2.80309 1.88324L14.1168 13.197Z",
69
1799
  "M13.197 1.88326L14.1168 2.80305L2.80309 14.1168L1.8833 13.197L13.197 1.88326Z"
70
1800
  ];
71
- var DOCS_PATHS = [
1801
+ var DOCS_PATHS2 = [
72
1802
  "M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6",
73
1803
  "M15 3h6v6",
74
1804
  "M10 14 21 3"
75
1805
  ];
76
1806
 
77
1807
  // src/client/card/rows.ts
78
- var react = __toESM(require("react"), 1);
79
- var import_jsx_runtime = require("react/jsx-runtime");
1808
+ var react5 = __toESM(require("react"), 1);
1809
+ var import_jsx_runtime10 = require("react/jsx-runtime");
80
1810
  function RowList(props) {
81
1811
  var served = Array.isArray(props.values) ? props.values : [];
82
1812
  var writable = props.writable === true;
@@ -86,14 +1816,14 @@ function RowList(props) {
86
1816
  var columns = Math.max(1, labels.length);
87
1817
  var blankRow = [];
88
1818
  for (var blank = 0; blank < columns; blank++) blankRow.push("");
89
- var draftState = react.useState(null);
1819
+ var draftState = react5.useState(null);
90
1820
  var draft = draftState[0];
91
1821
  var setDraft = draftState[1];
92
- var focusedState = react.useState(false);
1822
+ var focusedState = react5.useState(false);
93
1823
  var focused = focusedState[0];
94
1824
  var setFocused = focusedState[1];
95
1825
  var servedKey = JSON.stringify(served);
96
- var syncState = react.useState("");
1826
+ var syncState = react5.useState("");
97
1827
  var servedSync = syncState[0];
98
1828
  var setServedSync = syncState[1];
99
1829
  if (servedKey !== servedSync) {
@@ -113,7 +1843,7 @@ function RowList(props) {
113
1843
  setDraft(
114
1844
  withDraft(
115
1845
  (current) => current.map(
116
- (row, at) => at === index2 ? row.map((cell, field) => field === column ? value : cell) : row
1846
+ (row, at) => at === index2 ? row.map((cell, field2) => field2 === column ? value : cell) : row
117
1847
  )
118
1848
  )
119
1849
  );
@@ -130,7 +1860,7 @@ function RowList(props) {
130
1860
  if (draft === null) return;
131
1861
  save(rows);
132
1862
  };
133
- var fieldNode = (row, index2, column) => (0, import_jsx_runtime.jsx)("input", {
1863
+ var fieldNode = (row, index2, column) => (0, import_jsx_runtime10.jsx)("input", {
134
1864
  className: props.inputClassName ? ChromeMcpCard_default.catalogInput + " " + props.inputClassName : ChromeMcpCard_default.catalogInput,
135
1865
  type: "text",
136
1866
  value: row[column] === void 0 ? "" : row[column],
@@ -161,7 +1891,7 @@ function RowList(props) {
161
1891
  var width = row.length === 0 ? columns : row.length;
162
1892
  for (var column = 0; column < width; column++) cells.push(fieldNode(row, index2, column));
163
1893
  cells.push(
164
- (0, import_jsx_runtime.jsx)("button", {
1894
+ (0, import_jsx_runtime10.jsx)("button", {
165
1895
  type: "button",
166
1896
  className: ChromeMcpCard_default.iconButton + " " + ChromeMcpCard_default.iconButtonDanger,
167
1897
  "aria-label": props.removeLabel + " " + (index2 + 1),
@@ -170,14 +1900,14 @@ function RowList(props) {
170
1900
  onClick: () => {
171
1901
  removeRow(index2);
172
1902
  },
173
- children: (0, import_jsx_runtime.jsx)("svg", {
1903
+ children: (0, import_jsx_runtime10.jsx)("svg", {
174
1904
  width: 14,
175
1905
  height: 14,
176
1906
  viewBox: "0 0 16 16",
177
1907
  fill: "none",
178
1908
  "aria-hidden": "true",
179
- children: (0, import_jsx_runtime.jsx)("path", {
180
- d: TRASH_PATH,
1909
+ children: (0, import_jsx_runtime10.jsx)("path", {
1910
+ d: TRASH_PATH2,
181
1911
  stroke: "currentColor",
182
1912
  strokeWidth: 1.3,
183
1913
  strokeLinecap: "round",
@@ -186,9 +1916,9 @@ function RowList(props) {
186
1916
  })
187
1917
  })
188
1918
  );
189
- return (0, import_jsx_runtime.jsx)("div", {
1919
+ return (0, import_jsx_runtime10.jsx)("div", {
190
1920
  className: ChromeMcpCard_default.catalogEntry,
191
- children: (0, import_jsx_runtime.jsxs)("div", {
1921
+ children: (0, import_jsx_runtime10.jsxs)("div", {
192
1922
  className: props.rowClassName ? ChromeMcpCard_default.catalogRow + " " + props.rowClassName : ChromeMcpCard_default.catalogRow,
193
1923
  children: cells
194
1924
  })
@@ -200,7 +1930,7 @@ function RowList(props) {
200
1930
  for (var index = 0; index < rows.length; index++) visible.push(entryNode(rows[index], index));
201
1931
  body = body.concat(visible);
202
1932
  body.push(
203
- (0, import_jsx_runtime.jsx)("button", {
1933
+ (0, import_jsx_runtime10.jsx)("button", {
204
1934
  type: "button",
205
1935
  className: ChromeMcpCard_default.addButton,
206
1936
  disabled: !writable || busy,
@@ -208,23 +1938,23 @@ function RowList(props) {
208
1938
  children: props.addLabel
209
1939
  })
210
1940
  );
211
- var emptyLine = rows.length === 0 ? (0, import_jsx_runtime.jsx)("p", { className: ChromeMcpCard_default.empty, children: props.emptyText }) : null;
1941
+ var emptyLine = rows.length === 0 ? (0, import_jsx_runtime10.jsx)("p", { className: ChromeMcpCard_default.empty, children: props.emptyText }) : null;
212
1942
  if (props.disclosure !== true) {
213
1943
  return [emptyLine].concat(body);
214
1944
  }
215
1945
  return [
216
1946
  emptyLine,
217
- (0, import_jsx_runtime.jsxs)("details", {
1947
+ (0, import_jsx_runtime10.jsxs)("details", {
218
1948
  className: ChromeMcpCard_default.disclosure,
219
1949
  children: [
220
- (0, import_jsx_runtime.jsxs)("summary", {
1950
+ (0, import_jsx_runtime10.jsxs)("summary", {
221
1951
  className: ChromeMcpCard_default.disclosureSummary,
222
1952
  children: [
223
- (0, import_jsx_runtime.jsx)("span", { className: ChromeMcpCard_default.disclosureLabel, children: props.rowsLabel }),
224
- (0, import_jsx_runtime.jsx)("span", { className: ChromeMcpCard_default.disclosureCount, children: String(rows.length) })
1953
+ (0, import_jsx_runtime10.jsx)("span", { className: ChromeMcpCard_default.disclosureLabel, children: props.rowsLabel }),
1954
+ (0, import_jsx_runtime10.jsx)("span", { className: ChromeMcpCard_default.disclosureCount, children: String(rows.length) })
225
1955
  ]
226
1956
  }),
227
- (0, import_jsx_runtime.jsx)("div", { className: ChromeMcpCard_default.disclosureBody, children: body })
1957
+ (0, import_jsx_runtime10.jsx)("div", { className: ChromeMcpCard_default.disclosureBody, children: body })
228
1958
  ]
229
1959
  })
230
1960
  ];
@@ -257,7 +1987,7 @@ function ExtraFlagsEditor(props) {
257
1987
  var restoreAction = (visible) => {
258
1988
  var current = flagsOf(visible);
259
1989
  var merged = current.concat(defaults.filter((flag) => current.indexOf(flag) === -1));
260
- return (0, import_jsx_runtime2.jsx)("button", {
1990
+ return (0, import_jsx_runtime11.jsx)("button", {
261
1991
  type: "button",
262
1992
  className: ChromeMcpCard_default.linkButton,
263
1993
  // The defaults list is host-served — with nothing to recover there
@@ -274,7 +2004,7 @@ function ExtraFlagsEditor(props) {
274
2004
  var wslAction = (visible) => {
275
2005
  var current = flagsOf(visible);
276
2006
  var merged = current.concat(wsl.filter((flag) => current.indexOf(flag) === -1));
277
- return (0, import_jsx_runtime2.jsx)("button", {
2007
+ return (0, import_jsx_runtime11.jsx)("button", {
278
2008
  type: "button",
279
2009
  className: ChromeMcpCard_default.linkButton,
280
2010
  // The recommended list is host-served — with every one of them
@@ -288,30 +2018,30 @@ function ExtraFlagsEditor(props) {
288
2018
  children: t("flagsWsl")
289
2019
  });
290
2020
  };
291
- var renderActions = (visible) => (0, import_jsx_runtime2.jsxs)("div", {
2021
+ var renderActions = (visible) => (0, import_jsx_runtime11.jsxs)("div", {
292
2022
  className: ChromeMcpCard_default.linkButtonRow,
293
2023
  children: [restoreAction(visible), wslAction(visible)]
294
2024
  });
295
- return (0, import_jsx_runtime2.jsxs)("div", {
2025
+ return (0, import_jsx_runtime11.jsxs)("div", {
296
2026
  className: ChromeMcpCard_default.catalog,
297
2027
  children: [
298
- (0, import_jsx_runtime2.jsxs)("div", {
2028
+ (0, import_jsx_runtime11.jsxs)("div", {
299
2029
  className: ChromeMcpCard_default.field,
300
2030
  children: [
301
- (0, import_jsx_runtime2.jsxs)("div", {
2031
+ (0, import_jsx_runtime11.jsxs)("div", {
302
2032
  className: ChromeMcpCard_default.fieldRow,
303
2033
  children: [
304
- (0, import_jsx_runtime2.jsx)("span", { className: ChromeMcpCard_default.fieldTitle, children: t("flagsTitle") }),
2034
+ (0, import_jsx_runtime11.jsx)("span", { className: ChromeMcpCard_default.fieldTitle, children: t("flagsTitle") }),
305
2035
  // The guide link rides the same field row the picker's
306
2036
  // pill occupies.
307
- (0, import_jsx_runtime2.jsxs)("a", {
2037
+ (0, import_jsx_runtime11.jsxs)("a", {
308
2038
  className: ChromeMcpCard_default.docsLink,
309
2039
  href: CONFIGURATION_URL,
310
2040
  target: "_blank",
311
2041
  rel: "noopener noreferrer",
312
2042
  title: t("docsMessage"),
313
2043
  children: [
314
- (0, import_jsx_runtime2.jsx)("svg", {
2044
+ (0, import_jsx_runtime11.jsx)("svg", {
315
2045
  className: ChromeMcpCard_default.docsIcon,
316
2046
  width: 14,
317
2047
  height: 14,
@@ -322,20 +2052,20 @@ function ExtraFlagsEditor(props) {
322
2052
  strokeLinecap: "round",
323
2053
  strokeLinejoin: "round",
324
2054
  "aria-hidden": "true",
325
- children: DOCS_PATHS.map((d, at) => (0, import_jsx_runtime2.jsx)("path", { d }, at))
2055
+ children: DOCS_PATHS2.map((d, at) => (0, import_jsx_runtime11.jsx)("path", { d }, at))
326
2056
  }),
327
- (0, import_jsx_runtime2.jsx)("span", { className: ChromeMcpCard_default.docsLinkLabel, children: t("docsLinkLabel") })
2057
+ (0, import_jsx_runtime11.jsx)("span", { className: ChromeMcpCard_default.docsLinkLabel, children: t("docsLinkLabel") })
328
2058
  ]
329
2059
  })
330
2060
  ]
331
2061
  }),
332
- (0, import_jsx_runtime2.jsx)("div", { className: ChromeMcpCard_default.fieldDesc, children: t("flagsHint") })
2062
+ (0, import_jsx_runtime11.jsx)("div", { className: ChromeMcpCard_default.fieldDesc, children: t("flagsHint") })
333
2063
  ]
334
2064
  }),
335
2065
  // One row per saved flag: the single field is the flag itself, and
336
2066
  // the two append controls — Restore defaults and Flags WSL — ride
337
2067
  // the list's action line.
338
- (0, import_jsx_runtime2.jsx)(RowList, {
2068
+ (0, import_jsx_runtime11.jsx)(RowList, {
339
2069
  values: rowsOf(flags),
340
2070
  labels: [t("flagsValueLabel")],
341
2071
  placeholders: [t("flagsValuePlaceholder")],
@@ -355,8 +2085,8 @@ function ExtraFlagsEditor(props) {
355
2085
  }
356
2086
 
357
2087
  // src/client/card/picker.ts
358
- var import_jsx_runtime3 = require("react/jsx-runtime");
359
- var import_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
2088
+ var import_jsx_runtime12 = require("react/jsx-runtime");
2089
+ var import_dsh_client_ui_primitives5 = require("@deepseek-ai/dsh-client-ui-primitives");
360
2090
  function CatalogPicker(props) {
361
2091
  var entries = props.entries;
362
2092
  var options = props.options;
@@ -368,7 +2098,7 @@ function CatalogPicker(props) {
368
2098
  if (typeof props.saveEntries !== "function") return Promise.resolve();
369
2099
  return Promise.resolve(props.saveEntries(next.map((row) => ({ id: row[0] ?? "", name: row[1] ?? "" }))));
370
2100
  };
371
- var fetchAction = () => (0, import_jsx_runtime3.jsx)("button", {
2101
+ var fetchAction = () => (0, import_jsx_runtime12.jsx)("button", {
372
2102
  type: "button",
373
2103
  className: ChromeMcpCard_default.linkButton,
374
2104
  disabled: !writable || busy,
@@ -377,7 +2107,7 @@ function CatalogPicker(props) {
377
2107
  },
378
2108
  children: busy ? props.busyLabel : props.refreshLabel
379
2109
  });
380
- var windowsAction = () => (0, import_jsx_runtime3.jsx)("button", {
2110
+ var windowsAction = () => (0, import_jsx_runtime12.jsx)("button", {
381
2111
  type: "button",
382
2112
  className: ChromeMcpCard_default.linkButton,
383
2113
  disabled: props.windowsDisabled === true,
@@ -387,23 +2117,23 @@ function CatalogPicker(props) {
387
2117
  },
388
2118
  children: props.windowsLabel
389
2119
  });
390
- var renderActions = () => (0, import_jsx_runtime3.jsxs)("div", {
2120
+ var renderActions = () => (0, import_jsx_runtime12.jsxs)("div", {
391
2121
  className: ChromeMcpCard_default.linkButtonRow,
392
2122
  children: [fetchAction(), windowsAction()]
393
2123
  });
394
- return (0, import_jsx_runtime3.jsxs)("div", {
2124
+ return (0, import_jsx_runtime12.jsxs)("div", {
395
2125
  className: ChromeMcpCard_default.catalog,
396
2126
  children: [
397
- (0, import_jsx_runtime3.jsxs)("div", {
2127
+ (0, import_jsx_runtime12.jsxs)("div", {
398
2128
  className: ChromeMcpCard_default.field,
399
2129
  children: [
400
- (0, import_jsx_runtime3.jsxs)("div", {
2130
+ (0, import_jsx_runtime12.jsxs)("div", {
401
2131
  className: ChromeMcpCard_default.fieldRow,
402
2132
  children: [
403
- (0, import_jsx_runtime3.jsx)("span", { className: ChromeMcpCard_default.fieldTitle, children: props.selectorLabel }),
404
- (0, import_jsx_runtime3.jsx)("span", {
2133
+ (0, import_jsx_runtime12.jsx)("span", { className: ChromeMcpCard_default.fieldTitle, children: props.selectorLabel }),
2134
+ (0, import_jsx_runtime12.jsx)("span", {
405
2135
  className: ChromeMcpCard_default.selectorWrap,
406
- children: (0, import_jsx_runtime3.jsx)(import_dsh_client_ui_primitives.Menu, {
2136
+ children: (0, import_jsx_runtime12.jsx)(import_dsh_client_ui_primitives5.Menu, {
407
2137
  open: props.menuOpen,
408
2138
  onClose: () => {
409
2139
  props.setMenuOpen(false);
@@ -416,7 +2146,7 @@ function CatalogPicker(props) {
416
2146
  },
417
2147
  align: "end",
418
2148
  portal: true,
419
- anchor: (0, import_jsx_runtime3.jsxs)("button", {
2149
+ anchor: (0, import_jsx_runtime12.jsxs)("button", {
420
2150
  type: "button",
421
2151
  className: ChromeMcpCard_default.selector,
422
2152
  "aria-haspopup": "menu",
@@ -429,15 +2159,15 @@ function CatalogPicker(props) {
429
2159
  children: [
430
2160
  // The reference card hands the pill a bare label;
431
2161
  // the path needs its own truncating span.
432
- (0, import_jsx_runtime3.jsx)("span", { className: ChromeMcpCard_default.selectorLabel, children: props.selectedLabel }),
433
- (0, import_jsx_runtime3.jsx)("svg", {
2162
+ (0, import_jsx_runtime12.jsx)("span", { className: ChromeMcpCard_default.selectorLabel, children: props.selectedLabel }),
2163
+ (0, import_jsx_runtime12.jsx)("svg", {
434
2164
  width: 14,
435
2165
  height: 14,
436
2166
  className: ChromeMcpCard_default.pillChevron,
437
2167
  viewBox: "0 0 14 14",
438
2168
  fill: "none",
439
2169
  xmlns: "http://www.w3.org/2000/svg",
440
- children: (0, import_jsx_runtime3.jsx)("path", { d: CHEVRON_PATH, fill: "currentColor" })
2170
+ children: (0, import_jsx_runtime12.jsx)("path", { d: CHEVRON_PATH2, fill: "currentColor" })
441
2171
  })
442
2172
  ]
443
2173
  })
@@ -445,12 +2175,12 @@ function CatalogPicker(props) {
445
2175
  })
446
2176
  ]
447
2177
  }),
448
- (0, import_jsx_runtime3.jsx)("div", { className: ChromeMcpCard_default.fieldDesc, children: props.hint })
2178
+ (0, import_jsx_runtime12.jsx)("div", { className: ChromeMcpCard_default.fieldDesc, children: props.hint })
449
2179
  ]
450
2180
  }),
451
2181
  // The saved rows: two fields per row, folded behind the disclosure,
452
2182
  // with the fetch action sitting inside the body.
453
- (0, import_jsx_runtime3.jsx)(RowList, {
2183
+ (0, import_jsx_runtime12.jsx)(RowList, {
454
2184
  values: rows,
455
2185
  labels: [props.idLabel, props.nameLabel],
456
2186
  placeholders: [props.idPlaceholder, props.namePlaceholder],
@@ -470,8 +2200,8 @@ function CatalogPicker(props) {
470
2200
  }
471
2201
 
472
2202
  // src/client/card/dialog.ts
473
- var react2 = __toESM(require("react"), 1);
474
- var import_jsx_runtime4 = require("react/jsx-runtime");
2203
+ var react6 = __toESM(require("react"), 1);
2204
+ var import_jsx_runtime13 = require("react/jsx-runtime");
475
2205
  function CandidateDialog(props) {
476
2206
  var t = props.t;
477
2207
  var candidates = props.candidates;
@@ -479,7 +2209,7 @@ function CandidateDialog(props) {
479
2209
  var savedSet = new Set(savedIds);
480
2210
  var initialChecked = candidates.filter((candidate) => savedSet.has(candidate.id)).map((candidate) => candidate.id);
481
2211
  var servedKey = JSON.stringify(candidates) + "|" + JSON.stringify(savedIds);
482
- var draftState = react2.useState({ key: "", query: "", checked: [] });
2212
+ var draftState = react6.useState({ key: "", query: "", checked: [] });
483
2213
  var draft = draftState[0];
484
2214
  var setDraft = draftState[1];
485
2215
  var dirty = draft.key !== servedKey;
@@ -499,44 +2229,44 @@ function CandidateDialog(props) {
499
2229
  var toggle = (id, value) => {
500
2230
  setChecked((current) => value ? current.concat([id]) : current.filter((entry) => entry !== id));
501
2231
  };
502
- return (0, import_jsx_runtime4.jsxs)("div", {
2232
+ return (0, import_jsx_runtime13.jsxs)("div", {
503
2233
  className: ChromeMcpCard_default.fetchDialog,
504
2234
  role: "dialog",
505
2235
  "aria-modal": "true",
506
2236
  "aria-label": props.title,
507
2237
  children: [
508
- (0, import_jsx_runtime4.jsxs)("div", {
2238
+ (0, import_jsx_runtime13.jsxs)("div", {
509
2239
  className: ChromeMcpCard_default.dialogContent,
510
2240
  children: [
511
- (0, import_jsx_runtime4.jsxs)("div", {
2241
+ (0, import_jsx_runtime13.jsxs)("div", {
512
2242
  className: ChromeMcpCard_default.dialogHeader,
513
2243
  children: [
514
- (0, import_jsx_runtime4.jsx)("h2", { className: ChromeMcpCard_default.dialogTitle, children: props.title }),
515
- (0, import_jsx_runtime4.jsx)("button", {
2244
+ (0, import_jsx_runtime13.jsx)("h2", { className: ChromeMcpCard_default.dialogTitle, children: props.title }),
2245
+ (0, import_jsx_runtime13.jsx)("button", {
516
2246
  type: "button",
517
2247
  className: ChromeMcpCard_default.dialogClose,
518
2248
  "aria-label": t("close"),
519
2249
  onClick: () => props.onClose(),
520
- children: (0, import_jsx_runtime4.jsx)("svg", {
2250
+ children: (0, import_jsx_runtime13.jsx)("svg", {
521
2251
  width: 14,
522
2252
  height: 14,
523
2253
  viewBox: "0 0 16 16",
524
2254
  fill: "none",
525
2255
  xmlns: "http://www.w3.org/2000/svg",
526
2256
  "aria-hidden": "true",
527
- children: CLOSE_PATHS.map((d, at) => (0, import_jsx_runtime4.jsx)("path", { d, fill: "currentColor" }, at))
2257
+ children: CLOSE_PATHS2.map((d, at) => (0, import_jsx_runtime13.jsx)("path", { d, fill: "currentColor" }, at))
528
2258
  })
529
2259
  })
530
2260
  ]
531
2261
  }),
532
- (0, import_jsx_runtime4.jsx)("p", { className: ChromeMcpCard_default.dialogDescription, children: props.description }),
533
- (0, import_jsx_runtime4.jsxs)("div", {
2262
+ (0, import_jsx_runtime13.jsx)("p", { className: ChromeMcpCard_default.dialogDescription, children: props.description }),
2263
+ (0, import_jsx_runtime13.jsxs)("div", {
534
2264
  className: ChromeMcpCard_default.dialogBody,
535
2265
  children: [
536
- (0, import_jsx_runtime4.jsxs)("div", {
2266
+ (0, import_jsx_runtime13.jsxs)("div", {
537
2267
  className: ChromeMcpCard_default.candidateToolbar,
538
2268
  children: [
539
- (0, import_jsx_runtime4.jsx)("input", {
2269
+ (0, import_jsx_runtime13.jsx)("input", {
540
2270
  className: ChromeMcpCard_default.candidateSearch,
541
2271
  type: "search",
542
2272
  placeholder: props.searchPlaceholder,
@@ -546,7 +2276,7 @@ function CandidateDialog(props) {
546
2276
  setQuery(event && event.target ? String(event.target.value ?? "") : "");
547
2277
  }
548
2278
  }),
549
- (0, import_jsx_runtime4.jsx)("button", {
2279
+ (0, import_jsx_runtime13.jsx)("button", {
550
2280
  type: "button",
551
2281
  className: ChromeMcpCard_default.linkButton,
552
2282
  onClick: () => {
@@ -557,17 +2287,17 @@ function CandidateDialog(props) {
557
2287
  })
558
2288
  ]
559
2289
  }),
560
- shown.length === 0 ? (0, import_jsx_runtime4.jsx)("p", { className: ChromeMcpCard_default.empty, children: t("dialogEmpty") }) : (0, import_jsx_runtime4.jsx)("ul", {
2290
+ shown.length === 0 ? (0, import_jsx_runtime13.jsx)("p", { className: ChromeMcpCard_default.empty, children: t("dialogEmpty") }) : (0, import_jsx_runtime13.jsx)("ul", {
561
2291
  className: ChromeMcpCard_default.candidateList,
562
2292
  children: shown.map((candidate) => {
563
2293
  var isSaved = savedSet.has(candidate.id);
564
2294
  var note = candidate.note !== "" ? candidate.note : isSaved ? t("candidateSaved") : "";
565
- return (0, import_jsx_runtime4.jsx)("li", {
2295
+ return (0, import_jsx_runtime13.jsx)("li", {
566
2296
  className: ChromeMcpCard_default.candidate,
567
- children: (0, import_jsx_runtime4.jsxs)("label", {
2297
+ children: (0, import_jsx_runtime13.jsxs)("label", {
568
2298
  className: ChromeMcpCard_default.candidateLabel,
569
2299
  children: [
570
- (0, import_jsx_runtime4.jsx)("input", {
2300
+ (0, import_jsx_runtime13.jsx)("input", {
571
2301
  type: "checkbox",
572
2302
  checked: isSaved ? true : checkedSet.has(candidate.id),
573
2303
  disabled: isSaved,
@@ -575,8 +2305,8 @@ function CandidateDialog(props) {
575
2305
  toggle(candidate.id, !!(event && event.target && event.target.checked));
576
2306
  }
577
2307
  }),
578
- (0, import_jsx_runtime4.jsx)("span", { className: ChromeMcpCard_default.candidateId, children: candidate.id }),
579
- note === "" ? null : (0, import_jsx_runtime4.jsx)("span", { className: ChromeMcpCard_default.candidateNote, children: note })
2308
+ (0, import_jsx_runtime13.jsx)("span", { className: ChromeMcpCard_default.candidateId, children: candidate.id }),
2309
+ note === "" ? null : (0, import_jsx_runtime13.jsx)("span", { className: ChromeMcpCard_default.candidateNote, children: note })
580
2310
  ]
581
2311
  })
582
2312
  }, candidate.id);
@@ -584,16 +2314,16 @@ function CandidateDialog(props) {
584
2314
  })
585
2315
  ]
586
2316
  }),
587
- (0, import_jsx_runtime4.jsxs)("div", {
2317
+ (0, import_jsx_runtime13.jsxs)("div", {
588
2318
  className: ChromeMcpCard_default.dialogFooter,
589
2319
  children: [
590
- (0, import_jsx_runtime4.jsx)("button", {
2320
+ (0, import_jsx_runtime13.jsx)("button", {
591
2321
  type: "button",
592
2322
  className: ChromeMcpCard_default.dialogButton,
593
2323
  onClick: () => props.onClose(),
594
2324
  children: t("cancel")
595
2325
  }),
596
- (0, import_jsx_runtime4.jsx)("button", {
2326
+ (0, import_jsx_runtime13.jsx)("button", {
597
2327
  type: "button",
598
2328
  className: ChromeMcpCard_default.dialogButton + " " + ChromeMcpCard_default.dialogButtonPrimary,
599
2329
  onClick: () => props.onAdd(Array.from(checkedSet)),
@@ -608,25 +2338,25 @@ function CandidateDialog(props) {
608
2338
  }
609
2339
 
610
2340
  // src/client/card/run-actions.ts
611
- var react3 = __toESM(require("react"), 1);
2341
+ var react7 = __toESM(require("react"), 1);
612
2342
  var PROBED_AGE_TICK_MS = 1e4;
613
2343
  function useRunActions(deps) {
614
- const runningState = react3.useState(false);
2344
+ const runningState = react7.useState(false);
615
2345
  const isRunning = runningState[0];
616
2346
  const setRunning = runningState[1];
617
- const windowsRunningState = react3.useState(false);
2347
+ const windowsRunningState = react7.useState(false);
618
2348
  const isWindowsRunning = windowsRunningState[0];
619
2349
  const setWindowsRunning = windowsRunningState[1];
620
- const dialogRef = react3.useState(null);
2350
+ const dialogRef = react7.useState(null);
621
2351
  const dialog = dialogRef[0];
622
2352
  const setDialog = dialogRef[1];
623
- const probedState = react3.useState(0);
2353
+ const probedState = react7.useState(0);
624
2354
  const lastProbedAt = probedState[0];
625
2355
  const setLastProbedAt = probedState[1];
626
- const clockState = react3.useState(() => Date.now());
2356
+ const clockState = react7.useState(() => Date.now());
627
2357
  const clock = clockState[0];
628
2358
  const setClock = clockState[1];
629
- react3.useEffect(() => {
2359
+ react7.useEffect(() => {
630
2360
  const tick = setInterval(() => setClock(Date.now()), PROBED_AGE_TICK_MS);
631
2361
  return () => clearInterval(tick);
632
2362
  }, []);
@@ -647,7 +2377,7 @@ function useRunActions(deps) {
647
2377
  if (!Array.isArray(statuses) || statuses.length === 0) return;
648
2378
  const candidates = statuses.map((status) => ({
649
2379
  id: status.path,
650
- note: status.version !== "" ? status.version : status.error,
2380
+ note: status.version !== "" ? status.version : status.error !== "" ? status.error : status.note,
651
2381
  broken: status.version === "" && status.error !== ""
652
2382
  }));
653
2383
  setDialog({ candidates });
@@ -693,24 +2423,24 @@ function useRunActions(deps) {
693
2423
  }
694
2424
 
695
2425
  // src/client/card/toggle.ts
696
- var import_jsx_runtime5 = require("react/jsx-runtime");
697
- var import_dsh_client_ui_primitives2 = require("@deepseek-ai/dsh-client-ui-primitives");
2426
+ var import_jsx_runtime14 = require("react/jsx-runtime");
2427
+ var import_dsh_client_ui_primitives6 = require("@deepseek-ai/dsh-client-ui-primitives");
698
2428
  function LogOutputToggle(props) {
699
2429
  var t = props.t;
700
- return (0, import_jsx_runtime5.jsxs)("div", {
2430
+ return (0, import_jsx_runtime14.jsxs)("div", {
701
2431
  className: ChromeMcpCard_default.catalog,
702
2432
  children: [
703
- (0, import_jsx_runtime5.jsxs)("div", {
2433
+ (0, import_jsx_runtime14.jsxs)("div", {
704
2434
  className: ChromeMcpCard_default.field,
705
2435
  children: [
706
- (0, import_jsx_runtime5.jsxs)("div", {
2436
+ (0, import_jsx_runtime14.jsxs)("div", {
707
2437
  className: ChromeMcpCard_default.fieldRow,
708
2438
  children: [
709
- (0, import_jsx_runtime5.jsx)("span", { className: ChromeMcpCard_default.fieldTitle, children: t("reduceLabel") }),
710
- (0, import_jsx_runtime5.jsx)("span", {
2439
+ (0, import_jsx_runtime14.jsx)("span", { className: ChromeMcpCard_default.fieldTitle, children: t("reduceLabel") }),
2440
+ (0, import_jsx_runtime14.jsx)("span", {
711
2441
  className: ChromeMcpCard_default.toggleLabel,
712
2442
  title: t("reduceTitle"),
713
- children: (0, import_jsx_runtime5.jsx)(import_dsh_client_ui_primitives2.Switch, {
2443
+ children: (0, import_jsx_runtime14.jsx)(import_dsh_client_ui_primitives6.Switch, {
714
2444
  checked: props.checked,
715
2445
  label: t("reduceLabel"),
716
2446
  disabled: props.disabled,
@@ -721,43 +2451,13 @@ function LogOutputToggle(props) {
721
2451
  })
722
2452
  ]
723
2453
  }),
724
- (0, import_jsx_runtime5.jsx)("div", { className: ChromeMcpCard_default.fieldDesc, children: t("reduceHint") })
2454
+ (0, import_jsx_runtime14.jsx)("div", { className: ChromeMcpCard_default.fieldDesc, children: t("reduceHint") })
725
2455
  ]
726
2456
  })
727
2457
  ]
728
2458
  });
729
2459
  }
730
2460
 
731
- // src/client/catalog.ts
732
- var ID_MAX_LENGTH = 1024;
733
- var PATH_PATTERN = /^[^\x00-\x1f\x7f]{1,1024}$/u;
734
- var NAME_MAX_LENGTH = 200;
735
- var ENTRY_CAP = 50;
736
- function isValidEntryId(id) {
737
- if (id === "" || id.length > ID_MAX_LENGTH) return false;
738
- return PATH_PATTERN.test(id);
739
- }
740
- function entryLabel(entry) {
741
- const name = entry.name.trim();
742
- return name === "" ? entry.id : name;
743
- }
744
- function normalizeEntries(value) {
745
- if (!Array.isArray(value)) return [];
746
- const out = [];
747
- const seen = /* @__PURE__ */ new Set();
748
- for (const item of value) {
749
- if (out.length === ENTRY_CAP) break;
750
- if (item === null || typeof item !== "object" || Array.isArray(item)) continue;
751
- const raw = item;
752
- const id = typeof raw.id === "string" ? raw.id.trim() : "";
753
- if (!isValidEntryId(id) || seen.has(id)) continue;
754
- seen.add(id);
755
- const name = typeof raw.name === "string" ? raw.name.trim() : "";
756
- out.push({ id, name: name.slice(0, NAME_MAX_LENGTH) });
757
- }
758
- return out;
759
- }
760
-
761
2461
  // src/client/card/view.ts
762
2462
  function labelOf(entries, id) {
763
2463
  const row = entries.find((entry) => entry.id === id);
@@ -786,9 +2486,22 @@ function describeCard(state) {
786
2486
  dotIsError: error !== "",
787
2487
  wslWindowsExecutable: state.wslWindowsExecutable === true,
788
2488
  windowsChrome: readWindowsChrome(state.windowsChromeStatus),
789
- connectMode: state.carriesConnectionMode === true
2489
+ // Connect mode reads two ways. The mirror's answer is what the Host says
2490
+ // the bridge launches with — authoritative when it has been answered. And
2491
+ // the same question answered off the **saved flags**, which is what the
2492
+ // bridge launches with by the same precedence the flags rows edit: a flag
2493
+ // entry is a real config field a write-back never clears, so it keeps the
2494
+ // answer standing through the reset window every write pass leaves behind
2495
+ // (the same rule the pill's saved-path fallback follows). Either half
2496
+ // answering is enough; neither can contradict what the other states,
2497
+ // because both are asked of the same launch.
2498
+ connectMode: state.carriesConnectionMode === true || flagsCarryConnectionMode(state.extraFlags)
790
2499
  };
791
2500
  }
2501
+ var CONNECT_FLAG_PATTERN = /^--(?:browserUrl|wsEndpoint)(?:=|(?=\s)|$)/iu;
2502
+ function flagsCarryConnectionMode(flags) {
2503
+ return Array.isArray(flags) && flags.some((flag) => typeof flag === "string" && CONNECT_FLAG_PATTERN.test(flag));
2504
+ }
792
2505
  function executableLabel(view, id) {
793
2506
  return labelOf(view.executableEntries, id);
794
2507
  }
@@ -805,8 +2518,8 @@ function windowsChromeButton(view) {
805
2518
  const status = view.windowsChrome;
806
2519
  if (status.state === "launching") return { labelKey: "openWindowsChromeBusy", titleKey: "openWindowsChromeTitle", disabled: true, busy: true };
807
2520
  if (status.state === "not-applicable") return { labelKey: "openWindowsChrome", titleKey: "windowsChromeNotWsl", disabled: true, busy: false };
808
- if (status.state === "not-found") return { labelKey: "openWindowsChrome", titleKey: "windowsChromeNotFound", disabled: true, busy: false };
809
- if (status.state === "unreachable") return { labelKey: "openWindowsChrome", titleKey: "windowsChromeUnreachable", disabled: true, busy: false };
2521
+ if (status.state === "not-found") return { labelKey: "openWindowsChrome", titleKey: "windowsChromeNotFound", disabled: false, busy: false };
2522
+ if (status.state === "unreachable") return { labelKey: "openWindowsChrome", titleKey: "windowsChromeUnreachable", disabled: false, busy: false };
810
2523
  return { labelKey: "openWindowsChrome", titleKey: "openWindowsChromeTitle", disabled: false, busy: false };
811
2524
  }
812
2525
  function isBroken(view, id) {
@@ -829,18 +2542,15 @@ function optionLabel(view, id, t) {
829
2542
  function ChromeMcpCard(props) {
830
2543
  const t = props.t;
831
2544
  const state = props.useChromeMcpCard((snapshot) => snapshot);
832
- const openState = react4.useState(false);
833
- const open = openState[0];
834
- const setOpen = openState[1];
835
- const menuState = react4.useState(false);
2545
+ const menuState = react8.useState(false);
836
2546
  const menuOpen = menuState[0];
837
2547
  const setMenuOpen = menuState[1];
838
- const bodyId = react4.useId();
839
2548
  const runs = useRunActions({
840
2549
  refreshExecutables: props.refreshExecutables,
841
2550
  openWindowsChrome: props.openWindowsChrome,
842
2551
  addExecutables: props.addExecutables
843
2552
  });
2553
+ if (props.view !== "page") return null;
844
2554
  if (!state.available) return null;
845
2555
  const view = describeCard(state);
846
2556
  const rows = view.executableEntries;
@@ -848,158 +2558,153 @@ function ChromeMcpCard(props) {
848
2558
  const options = view.executableOptions.map((option) => ({ id: option.id, label: optionLabel(view, option.id, t) }));
849
2559
  const dotLabel = view.error !== "" ? view.error : t("chromeMissing");
850
2560
  const dotAria = view.dotIsError || view.missing ? t("statusError") : t("statusOk");
2561
+ const statusDot = (0, import_jsx_runtime15.jsx)("span", {
2562
+ className: ChromeMcpCard_default.dot + " " + ChromeMcpCard_default.dotError,
2563
+ role: "img",
2564
+ "aria-label": dotAria,
2565
+ title: dotLabel
2566
+ });
851
2567
  const windowsButton = windowsChromeButton(view);
852
2568
  const windowsDisabled = windowsButton.disabled || runs.windowsRunning || !state.writable;
853
2569
  const windowsBusy = windowsButton.busy || runs.windowsRunning;
854
2570
  const connectLabel = view.windowsChrome.port > 0 ? t("connectModeLabel") + " (http://127.0.0.1:" + String(view.windowsChrome.port) + ")" : t("connectModeLabel");
855
2571
  const selectedLabel = view.connectMode ? connectLabel : view.effectivePath === "" ? t("executableNone") : executableLabel(view, view.effectivePath);
856
- const statusLine = runs.running ? (0, import_jsx_runtime6.jsx)("p", { className: ChromeMcpCard_default.result, role: "status", children: t("probing") }) : view.version === "" ? null : (0, import_jsx_runtime6.jsxs)("p", {
2572
+ const statusLine = runs.running ? (0, import_jsx_runtime15.jsx)("p", { className: ChromeMcpCard_default.result, role: "status", children: t("probing") }) : view.version === "" ? null : (0, import_jsx_runtime15.jsxs)("p", {
857
2573
  className: ChromeMcpCard_default.result,
858
2574
  role: "status",
859
2575
  children: [
860
2576
  t("versionLabel"),
861
- (0, import_jsx_runtime6.jsx)("span", { className: ChromeMcpCard_default.resultValue, children: view.version }),
862
- runs.lastProbedAt === 0 ? null : (0, import_jsx_runtime6.jsx)("span", { className: ChromeMcpCard_default.resultAge, children: probeAge(runs.lastProbedAt, runs.clock, t) })
2577
+ (0, import_jsx_runtime15.jsx)("span", { className: ChromeMcpCard_default.resultValue, children: view.version }),
2578
+ runs.lastProbedAt === 0 ? null : (0, import_jsx_runtime15.jsx)("span", { className: ChromeMcpCard_default.resultAge, children: probeAge(runs.lastProbedAt, runs.clock, t) })
863
2579
  ]
864
2580
  });
865
- return (0, import_jsx_runtime6.jsx)("li", {
866
- className: ChromeMcpCard_default.card + (open ? " " + ChromeMcpCard_default.cardOpen : ""),
2581
+ const errorLine = view.error !== "" ? (0, import_jsx_runtime15.jsxs)("p", { className: ChromeMcpCard_default.error, role: "status", children: [statusDot, view.error] }) : view.missing ? (0, import_jsx_runtime15.jsxs)("p", { className: ChromeMcpCard_default.error, role: "status", children: [statusDot, t("chromeMissing")] }) : null;
2582
+ return (0, import_jsx_runtime15.jsxs)("div", {
2583
+ className: ChromeMcpCard_default.body,
867
2584
  children: [
868
- (0, import_jsx_runtime6.jsxs)("button", {
869
- type: "button",
870
- className: ChromeMcpCard_default.header,
871
- "aria-expanded": open,
872
- "aria-label": t(open ? "collapse" : "expand") + ": " + t("title"),
873
- "aria-controls": bodyId,
874
- onClick: () => {
875
- setOpen(!open);
876
- if (!open && typeof props.refresh === "function") void props.refresh();
2585
+ // Nothing the page can write from here is writable: the row's
2586
+ // configuration is owned elsewhere (a home patch or the page's own
2587
+ // read-only state).
2588
+ !state.writable ? (0, import_jsx_runtime15.jsx)("p", { className: ChromeMcpCard_default.readOnly, role: "status", children: t("readOnly") }) : null,
2589
+ (0, import_jsx_runtime15.jsx)(CatalogPicker, {
2590
+ t,
2591
+ entries: rows,
2592
+ options,
2593
+ idPlaceholder: t("executableIdPlaceholder"),
2594
+ namePlaceholder: t("namePlaceholder"),
2595
+ selectedId: view.effectivePath,
2596
+ selectedLabel,
2597
+ selectedTitle: view.connectMode ? connectLabel : view.effectivePath !== "" ? view.effectivePath : selectedLabel,
2598
+ writable: state.writable,
2599
+ busy: runs.running,
2600
+ menuOpen,
2601
+ setMenuOpen,
2602
+ connectMode: view.connectMode,
2603
+ selectorLabel: t("executableLabel"),
2604
+ hint: view.connectMode ? t("connectModeHint") : t("executableHint"),
2605
+ windowsLabel: windowsBusy ? t("openWindowsChromeBusy") : t(windowsButton.labelKey),
2606
+ windowsTitle: t(windowsButton.titleKey),
2607
+ windowsDisabled,
2608
+ windowsOnOpen: runs.runWindowsChrome,
2609
+ rowsLabel: t("executableRows"),
2610
+ emptyText: t("executableEmpty"),
2611
+ idLabel: t("executableIdLabel"),
2612
+ nameLabel: t("executableNameLabel"),
2613
+ removeLabel: t("removeExecutable"),
2614
+ addLabel: t("addExecutable"),
2615
+ refreshLabel: t("fetchExecutables"),
2616
+ busyLabel: t("fetching"),
2617
+ select: (id) => {
2618
+ if (typeof props.selectExecutable === "function") void props.selectExecutable(id);
877
2619
  },
2620
+ saveEntries: (entries) => props.saveExecutables(entries),
2621
+ refresh: runs.runFetch,
2622
+ statusLine
2623
+ }),
2624
+ // The one state no control of this form can express: the host runs
2625
+ // under WSL and what is selected is a Windows executable — which the
2626
+ // bridge cannot launch, however healthy its `--version` answer looks.
2627
+ // Nothing has failed yet, so this is a notice (static copy, shown only
2628
+ // while the host reports the state), not a third error surface: the
2629
+ // required configuration differs.
2630
+ view.wslWindowsExecutable ? (0, import_jsx_runtime15.jsxs)("div", {
2631
+ className: ChromeMcpCard_default.notice,
2632
+ role: "note",
878
2633
  children: [
879
- (0, import_jsx_runtime6.jsxs)("span", {
880
- className: ChromeMcpCard_default.headText,
881
- children: [
882
- (0, import_jsx_runtime6.jsxs)("div", {
883
- className: ChromeMcpCard_default.nameRow,
884
- children: [
885
- (0, import_jsx_runtime6.jsx)("span", { className: ChromeMcpCard_default.name, children: t("title") }),
886
- view.dotIsError || view.missing ? (0, import_jsx_runtime6.jsx)("span", {
887
- className: ChromeMcpCard_default.dot + " " + ChromeMcpCard_default.dotError,
888
- role: "img",
889
- "aria-label": dotAria,
890
- title: dotLabel
891
- }) : null
892
- ]
893
- }),
894
- (0, import_jsx_runtime6.jsx)("span", { className: ChromeMcpCard_default.desc, children: t("description") })
895
- ]
896
- }),
897
- (0, import_jsx_runtime6.jsx)("svg", {
898
- width: 14,
899
- height: 14,
900
- className: ChromeMcpCard_default.chevron + (open ? " " + ChromeMcpCard_default.chevronOpen : ""),
901
- viewBox: "0 0 14 14",
902
- fill: "none",
903
- xmlns: "http://www.w3.org/2000/svg",
904
- children: (0, import_jsx_runtime6.jsx)("path", { d: CHEVRON_PATH, fill: "currentColor" })
905
- })
2634
+ (0, import_jsx_runtime15.jsx)("div", { className: ChromeMcpCard_default.noticeTitle, children: t("wslWindowsTitle") }),
2635
+ (0, import_jsx_runtime15.jsx)("div", { className: ChromeMcpCard_default.noticeBody, children: t("wslWindowsNote") })
906
2636
  ]
2637
+ }) : null,
2638
+ (0, import_jsx_runtime15.jsx)(ExtraFlagsEditor, {
2639
+ t,
2640
+ flags: Array.isArray(state.extraFlags) ? state.extraFlags : [],
2641
+ defaultFlags: Array.isArray(state.defaultExtraFlags) ? state.defaultExtraFlags : [],
2642
+ wslFlags: Array.isArray(state.wslExtraFlags) ? state.wslExtraFlags : [],
2643
+ writable: state.writable,
2644
+ saveFlags: props.saveFlags
907
2645
  }),
908
- open ? (0, import_jsx_runtime6.jsxs)("div", {
909
- id: bodyId,
910
- className: ChromeMcpCard_default.body,
2646
+ (0, import_jsx_runtime15.jsx)(LogOutputToggle, {
2647
+ t,
2648
+ checked: view.reduceChecked,
2649
+ disabled: !state.writable,
2650
+ onToggle: props.toggleStderr
2651
+ }),
2652
+ errorLine,
2653
+ runs.dialog !== null ? (0, import_jsx_runtime15.jsx)(CandidateDialog, {
2654
+ t,
2655
+ candidates: runs.dialog.candidates,
2656
+ savedIds,
2657
+ title: t("dialogExecutablesTitle"),
2658
+ description: t("dialogExecutablesDescription"),
2659
+ searchPlaceholder: t("searchExecutables"),
2660
+ onAdd: runs.addFromDialog,
2661
+ onClose: runs.closeDialog
2662
+ }) : null,
2663
+ // The form writes nothing as it is edited: every staged edit is
2664
+ // persisted only when **Apply** lands them, and **Discard** drops the
2665
+ // whole draft — reverting every staged value to what the host already
2666
+ // serves.
2667
+ (0, import_jsx_runtime15.jsxs)("div", {
2668
+ className: ChromeMcpCard_default.footer,
911
2669
  children: [
912
- !state.writable ? (0, import_jsx_runtime6.jsx)("p", { className: ChromeMcpCard_default.readOnly, role: "status", children: t("readOnly") }) : null,
913
- (0, import_jsx_runtime6.jsx)(CatalogPicker, {
914
- t,
915
- entries: rows,
916
- options,
917
- idPlaceholder: t("executableIdPlaceholder"),
918
- namePlaceholder: t("namePlaceholder"),
919
- selectedId: view.effectivePath,
920
- selectedLabel,
921
- selectedTitle: view.connectMode ? connectLabel : view.effectivePath !== "" ? view.effectivePath : selectedLabel,
922
- writable: state.writable,
923
- busy: runs.running,
924
- menuOpen,
925
- setMenuOpen,
926
- connectMode: view.connectMode,
927
- selectorLabel: t("executableLabel"),
928
- hint: view.connectMode ? t("connectModeHint") : t("executableHint"),
929
- windowsLabel: windowsBusy ? t("openWindowsChromeBusy") : t(windowsButton.labelKey),
930
- windowsTitle: t(windowsButton.titleKey),
931
- windowsDisabled,
932
- windowsOnOpen: runs.runWindowsChrome,
933
- rowsLabel: t("executableRows"),
934
- emptyText: t("executableEmpty"),
935
- idLabel: t("executableIdLabel"),
936
- nameLabel: t("executableNameLabel"),
937
- removeLabel: t("removeExecutable"),
938
- addLabel: t("addExecutable"),
939
- refreshLabel: t("fetchExecutables"),
940
- busyLabel: t("fetching"),
941
- select: (id) => {
942
- if (typeof props.selectExecutable === "function") void props.selectExecutable(id);
2670
+ // A staged edit announces itself on the save line, since the
2671
+ // identity line the page draws says nothing about it.
2672
+ state.dirty ? (0, import_jsx_runtime15.jsx)("span", { className: ChromeMcpCard_default.badge, children: t("unsaved") }) : null,
2673
+ state.failed ? (0, import_jsx_runtime15.jsx)("p", { className: ChromeMcpCard_default.footerError, role: "status", children: t("saveFailed") }) : null,
2674
+ (0, import_jsx_runtime15.jsx)("button", {
2675
+ type: "button",
2676
+ className: ChromeMcpCard_default.footerButton,
2677
+ onClick: () => {
2678
+ if (typeof props.discard === "function") props.discard();
943
2679
  },
944
- saveEntries: (entries) => props.saveExecutables(entries),
945
- refresh: runs.runFetch,
946
- statusLine
947
- }),
948
- // The one state no control of this card can express: the
949
- // host runs under WSL and what is selected is a Windows
950
- // executable — which the bridge cannot launch, however
951
- // healthy its `--version` answer looks. Nothing has failed
952
- // yet, so this is a notice (static copy, shown only while
953
- // the host reports the state), not a third error surface:
954
- // the required configuration differs.
955
- view.wslWindowsExecutable ? (0, import_jsx_runtime6.jsxs)("div", {
956
- className: ChromeMcpCard_default.notice,
957
- role: "note",
958
- children: [
959
- (0, import_jsx_runtime6.jsx)("div", { className: ChromeMcpCard_default.noticeTitle, children: t("wslWindowsTitle") }),
960
- (0, import_jsx_runtime6.jsx)("div", { className: ChromeMcpCard_default.noticeBody, children: t("wslWindowsNote") })
961
- ]
962
- }) : null,
963
- (0, import_jsx_runtime6.jsx)(ExtraFlagsEditor, {
964
- t,
965
- flags: Array.isArray(state.extraFlags) ? state.extraFlags : [],
966
- defaultFlags: Array.isArray(state.defaultExtraFlags) ? state.defaultExtraFlags : [],
967
- wslFlags: Array.isArray(state.wslExtraFlags) ? state.wslExtraFlags : [],
968
- writable: state.writable,
969
- saveFlags: props.saveFlags
2680
+ children: t("discard")
970
2681
  }),
971
- (0, import_jsx_runtime6.jsx)(LogOutputToggle, {
972
- t,
973
- checked: view.reduceChecked,
974
- disabled: !state.writable,
975
- onToggle: props.toggleStderr
976
- }),
977
- state.lastError ? (0, import_jsx_runtime6.jsx)("p", { className: ChromeMcpCard_default.error, role: "status", children: state.lastError }) : null,
978
- state.actionError ? (0, import_jsx_runtime6.jsx)("p", { className: ChromeMcpCard_default.error, role: "status", children: state.actionError }) : null,
979
- runs.dialog !== null ? (0, import_jsx_runtime6.jsx)(CandidateDialog, {
980
- t,
981
- candidates: runs.dialog.candidates,
982
- savedIds,
983
- title: t("dialogExecutablesTitle"),
984
- description: t("dialogExecutablesDescription"),
985
- searchPlaceholder: t("searchExecutables"),
986
- onAdd: runs.addFromDialog,
987
- onClose: runs.closeDialog
988
- }) : null
2682
+ (0, import_jsx_runtime15.jsx)("button", {
2683
+ type: "button",
2684
+ className: ChromeMcpCard_default.footerButton + " " + ChromeMcpCard_default.footerButtonPrimary,
2685
+ disabled: !state.dirty || state.saving || !state.writable,
2686
+ onClick: () => {
2687
+ if (typeof props.apply === "function") void props.apply();
2688
+ },
2689
+ children: state.saving ? t("saving") : t("apply")
2690
+ })
989
2691
  ]
990
- }) : null
2692
+ })
991
2693
  ]
992
2694
  });
993
2695
  }
994
2696
 
995
- // src/client/controller/budget.ts
996
- var CHECK_POLL_TICK_MS = 700;
997
- var CHECK_POLL_TIMEOUT_MS = 2e4;
998
-
999
- // src/client/controller/controller.ts
1000
- var import_dsh_client_store = require("@deepseek-ai/dsh-client-store");
1001
-
1002
- // src/client/controller/read.ts
2697
+ // src/client/read.ts
2698
+ function sameEntries(a, b) {
2699
+ if (a === b) return true;
2700
+ if (a.length !== b.length) return false;
2701
+ for (let i = 0; i < a.length; i++) if (a[i].id !== b[i].id || a[i].name !== b[i].name) return false;
2702
+ return true;
2703
+ }
2704
+ function readFlags(value) {
2705
+ if (!Array.isArray(value)) return [];
2706
+ return value.filter((flag) => typeof flag === "string" && flag !== "");
2707
+ }
1003
2708
  function readNumber(value, fallback) {
1004
2709
  return typeof value === "number" ? value : fallback;
1005
2710
  }
@@ -1029,323 +2734,163 @@ function readStatus(value) {
1029
2734
  statuses.push({
1030
2735
  path,
1031
2736
  version: readString(item.version, ""),
1032
- error: readString(item.error, "")
2737
+ error: readString(item.error, ""),
2738
+ note: readString(item.note, "")
1033
2739
  });
1034
2740
  }
1035
2741
  return statuses;
1036
2742
  }
1037
2743
 
1038
- // src/client/controller/controller.ts
1039
- var ChromeMcpCardController = class {
1040
- scope;
1041
- mirror;
1042
- disposed = false;
1043
- pollTimer = null;
1044
- pollGeneration = 0;
1045
- waitStarted = false;
1046
- store;
1047
- unsubscribe;
1048
- constructor(scope, mirror) {
1049
- this.scope = scope;
1050
- this.mirror = mirror;
1051
- this.store = (0, import_dsh_client_store.createSnapshotStore)({
1052
- available: false,
1053
- writable: false,
1054
- extraFlags: [],
1055
- lastError: "",
1056
- chromeMissing: false,
1057
- executableDiscoveryRevision: 0,
1058
- chromeVersion: "",
1059
- executables: [],
1060
- executableStatus: [],
1061
- chromePath: "",
1062
- effectiveChromePath: "",
1063
- effectiveSource: "",
1064
- stderrMode: "",
1065
- rowStderr: "log",
1066
- defaultExtraFlags: [],
1067
- wslExtraFlags: [],
1068
- wslWindowsExecutable: false,
1069
- windowsChromeStatus: { state: "off", port: 0, error: "" },
1070
- carriesConnectionMode: false,
1071
- actionError: ""
1072
- });
1073
- this.unsubscribe = scope.subscribe(() => this.publish());
1074
- this.publish();
1075
- }
1076
- /** Republish the latest scope snapshot into the card store. */
1077
- publish() {
1078
- if (this.disposed) return;
1079
- const previous = this.store.getSnapshot();
1080
- const snapshot = this.scope.getSnapshot();
1081
- if (snapshot.status !== "ready" || snapshot.value === void 0) {
1082
- this.store.set({
1083
- available: false,
1084
- writable: false,
1085
- extraFlags: [],
1086
- lastError: "",
1087
- chromeMissing: false,
1088
- executableDiscoveryRevision: 0,
1089
- chromeVersion: "",
1090
- executables: [],
1091
- executableStatus: [],
1092
- chromePath: "",
1093
- effectiveChromePath: "",
1094
- effectiveSource: "",
1095
- stderrMode: "",
1096
- rowStderr: "log",
1097
- defaultExtraFlags: [],
1098
- wslExtraFlags: [],
1099
- wslWindowsExecutable: false,
1100
- windowsChromeStatus: { state: "off", port: 0, error: "" },
1101
- carriesConnectionMode: false,
1102
- actionError: previous.actionError
1103
- });
1104
- return;
1105
- }
1106
- const value = snapshot.value;
1107
- const base = snapshot.base ?? {};
1108
- const servedRevision = readNumber(base.executableDiscoveryRevision, readNumber(value.executableDiscoveryRevision, 0));
1109
- const servedVersion = readString(base.chromeVersion, readString(value.chromeVersion, ""));
1110
- const servedExecutables = normalizeEntries(value.executables);
1111
- const servedStatus = readStatus(base.executableStatus);
1112
- const servedEffectivePath = readString(
1113
- base.effectiveChromePath,
1114
- readString(value.effectiveChromePath, readString(value.chromePath, ""))
1115
- );
1116
- const servedSource = base.effectiveSource === "selected" || base.effectiveSource === "row-config" ? base.effectiveSource : value.effectiveSource === "selected" || value.effectiveSource === "row-config" ? value.effectiveSource : "";
1117
- const servedStderrMode = typeof value.stderrMode === "string" ? value.stderrMode : "";
1118
- const servedRowStderr = typeof base.rowStderr === "string" ? base.rowStderr : typeof value.rowStderr === "string" ? value.rowStderr : "log";
1119
- const servedDefaults = Array.isArray(base.defaultExtraFlags) ? base.defaultExtraFlags.filter((flag) => typeof flag === "string" && flag !== "") : Array.isArray(value.defaultExtraFlags) ? value.defaultExtraFlags.filter((flag) => typeof flag === "string" && flag !== "") : [];
1120
- const servedWslFlags = Array.isArray(base.wslExtraFlags) ? base.wslExtraFlags.filter((flag) => typeof flag === "string" && flag !== "") : Array.isArray(value.wslExtraFlags) ? value.wslExtraFlags.filter((flag) => typeof flag === "string" && flag !== "") : [];
1121
- const servedWslWindows = base.wslWindowsExecutable === void 0 ? value.wslWindowsExecutable === true : base.wslWindowsExecutable === true;
1122
- const servedWindowsChrome = readWindowsChromeStatus(base.windowsChromeStatus !== void 0 ? base.windowsChromeStatus : value.windowsChromeStatus);
1123
- const servedConnectMode = base.carriesConnectionMode === void 0 ? value.carriesConnectionMode === true : base.carriesConnectionMode === true;
1124
- this.store.set({
1125
- available: true,
1126
- writable: snapshot.writable === true,
1127
- extraFlags: Array.isArray(value.extraFlags) ? value.extraFlags : [],
1128
- lastError: typeof base.lastError === "string" ? base.lastError : value.lastError ?? "",
1129
- chromeMissing: base.chromeMissing === void 0 ? value.chromeMissing === true : base.chromeMissing === true,
1130
- executableDiscoveryRevision: servedRevision,
1131
- chromeVersion: servedVersion,
1132
- executables: servedExecutables,
1133
- executableStatus: servedStatus,
1134
- chromePath: readString(value.chromePath, ""),
1135
- effectiveChromePath: servedEffectivePath,
1136
- effectiveSource: servedSource,
1137
- stderrMode: servedStderrMode === "log" || servedStderrMode === "console" ? servedStderrMode : "",
1138
- rowStderr: servedRowStderr === "console" ? "console" : "log",
1139
- defaultExtraFlags: servedDefaults,
1140
- wslExtraFlags: servedWslFlags,
1141
- wslWindowsExecutable: servedWslWindows,
1142
- windowsChromeStatus: servedWindowsChrome,
1143
- carriesConnectionMode: servedConnectMode,
1144
- actionError: ""
1145
- });
1146
- if (!this.waitStarted) {
1147
- this.waitStarted = true;
1148
- if (servedRevision === 0) void this.waitFor("executableDiscoveryRevision", 0, Date.now() + CHECK_POLL_TIMEOUT_MS);
1149
- }
1150
- }
1151
- /**
1152
- * Immediate write of the user's extra flags (persisted; the host's
1153
- * validate hook rejects invalid lists here, and the next bridge
1154
- * launch starts with them).
1155
- */
1156
- saveFlags(flags) {
1157
- return this.scope.set("extraFlags", flags).catch((error) => this.noteError(error));
1158
- }
1159
- /**
1160
- * Pick one saved executable. Writes the persisted `chromePath` (the host
1161
- * restarts the bridge connection carrying it and re-runs the discovery), then
1162
- * waits until the served revision advances past the click-time value.
1163
- */
1164
- selectExecutable(id) {
1165
- if (this.disposed) return Promise.resolve();
1166
- const target = typeof id === "string" ? id.trim() : "";
1167
- if (target === "") return Promise.resolve();
1168
- const baseline = this.store.getSnapshot().executableDiscoveryRevision;
1169
- const wait = this.waitFor("executableDiscoveryRevision", baseline, Date.now() + CHECK_POLL_TIMEOUT_MS);
1170
- return this.scope.set("chromePath", target).catch((error) => this.noteError(error)).then(() => wait);
1171
- }
1172
- /**
1173
- * Save the whole rows list: the card owns the draft, the host re-normalizes
1174
- * on the way in and re-runs the scan the new ids imply.
1175
- */
1176
- saveExecutables(entries) {
1177
- if (this.disposed) return Promise.resolve();
1178
- const rows = normalizeEntries(entries);
1179
- const snapshot = this.store.getSnapshot();
1180
- const unchanged = JSON.stringify(rows) === JSON.stringify(snapshot.executables);
1181
- if (unchanged) return Promise.resolve();
1182
- const baseline = snapshot.executableDiscoveryRevision;
1183
- const wait = this.waitFor("executableDiscoveryRevision", baseline, Date.now() + CHECK_POLL_TIMEOUT_MS);
1184
- return this.scope.set("executables", rows).catch((error) => this.noteError(error)).then(() => wait);
1185
- }
1186
- /**
1187
- * Ask the host to re-probe the saved rows and fold what it finds into them,
1188
- * then wait for the served revision to advance: write the trigger, then poll
1189
- * the shared describe mirror until it moves — or the budget elapses. Resolves
1190
- * with every candidate the run answered for and what it said about each, so
1191
- * the dialog opens over the run's own answer list.
1192
- */
1193
- refreshExecutables() {
1194
- if (this.disposed) return Promise.resolve([]);
1195
- const baseline = this.store.getSnapshot().executableDiscoveryRevision;
1196
- const wait = this.waitFor("executableDiscoveryRevision", baseline, Date.now() + CHECK_POLL_TIMEOUT_MS);
1197
- return this.scope.set("refreshExecutablesNonce", Date.now()).catch((error) => this.noteError(error)).then(() => wait).then(() => {
1198
- const served = this.store.getSnapshot();
1199
- return Array.isArray(served.executableStatus) ? served.executableStatus : [];
1200
- });
1201
- }
1202
- /**
1203
- * Merge the ids picked in the dialog into the saved rows: every id already
1204
- * there keeps its place (and its name), the missing ones append nameless.
1205
- * The host re-normalizes on the way in and re-runs the scan the new ids
1206
- * imply, so the same revision counter carries the wait.
1207
- */
1208
- addExecutables(ids) {
1209
- if (this.disposed) return Promise.resolve();
1210
- const served = this.store.getSnapshot();
1211
- const rows = normalizeEntries(served.executables);
1212
- const merged = rows.concat(
2744
+ // src/client/project.ts
2745
+ function nothingProjected() {
2746
+ return {
2747
+ available: false,
2748
+ writable: false,
2749
+ extraFlags: [],
2750
+ lastError: "",
2751
+ chromeMissing: false,
2752
+ executableDiscoveryRevision: 0,
2753
+ chromeVersion: "",
2754
+ executables: [],
2755
+ executableStatus: [],
2756
+ chromePath: "",
2757
+ effectiveChromePath: "",
2758
+ effectiveSource: "",
2759
+ stderrMode: "",
2760
+ rowStderr: "log",
2761
+ defaultExtraFlags: [],
2762
+ wslExtraFlags: [],
2763
+ wslWindowsExecutable: false,
2764
+ windowsChromeStatus: { state: "off", port: 0, error: "" },
2765
+ carriesConnectionMode: false,
2766
+ actionError: "",
2767
+ dirty: false,
2768
+ saving: false,
2769
+ failed: false
2770
+ };
2771
+ }
2772
+ function projectCard(snapshot, heldWslNotice2) {
2773
+ if (snapshot.available !== true) return nothingProjected();
2774
+ const value = snapshot.values ?? {};
2775
+ const chromePath = readString(value.chromePath, "");
2776
+ const answeredEffective = readString(value.effectiveChromePath, "");
2777
+ const wslNotice = value.wslWindowsExecutable === true ? true : answeredEffective === "" && chromePath !== "" ? heldWslNotice2 : false;
2778
+ const effectiveChromePath = answeredEffective !== "" ? answeredEffective : value.wslWindowsExecutable === true ? "" : chromePath;
2779
+ const effectiveSource = value.effectiveSource === "selected" || value.effectiveSource === "row-config" ? value.effectiveSource : "";
2780
+ const stderrMode = value.stderrMode === "log" || value.stderrMode === "console" ? value.stderrMode : "";
2781
+ return {
2782
+ available: true,
2783
+ writable: snapshot.writable === true,
2784
+ extraFlags: readFlags(value.extraFlags),
2785
+ lastError: readString(value.lastError, ""),
2786
+ chromeMissing: value.chromeMissing === true,
2787
+ executableDiscoveryRevision: readNumber(value.executableDiscoveryRevision, 0),
2788
+ chromeVersion: readString(value.chromeVersion, ""),
2789
+ executables: normalizeEntries(value.executables),
2790
+ executableStatus: readStatus(value.executableStatus),
2791
+ chromePath,
2792
+ effectiveChromePath,
2793
+ effectiveSource,
2794
+ stderrMode,
2795
+ // The mode the bridge actually routes console output through, as the
2796
+ // Host resolves it — what the field states wins, the live answer fills
2797
+ // the gap.
2798
+ rowStderr: value.stderrEffective === "console" ? "console" : "log",
2799
+ defaultExtraFlags: readFlags(value.defaultExtraFlags),
2800
+ wslExtraFlags: readFlags(value.wslExtraFlags),
2801
+ wslWindowsExecutable: wslNotice,
2802
+ windowsChromeStatus: readWindowsChromeStatus(value.windowsChromeStatus),
2803
+ carriesConnectionMode: value.carriesConnectionMode === true,
2804
+ actionError: snapshot.actionError ?? "",
2805
+ dirty: snapshot.dirty === true,
2806
+ saving: snapshot.saving === true,
2807
+ failed: snapshot.failed === true
2808
+ };
2809
+ }
2810
+
2811
+ // src/client/block.ts
2812
+ var RUN_COUNTER = "executableDiscoveryRevision";
2813
+ var heldWslNotice = /* @__PURE__ */ new WeakMap();
2814
+ function runCounter(snapshot) {
2815
+ const value = snapshot.values?.[RUN_COUNTER];
2816
+ return typeof value === "number" ? value : 0;
2817
+ }
2818
+ function cardState(controller) {
2819
+ const state = projectCard(controller.getSnapshot(), heldWslNotice.get(controller) === true);
2820
+ heldWslNotice.set(controller, state.wslWindowsExecutable);
2821
+ return state;
2822
+ }
2823
+ function cardActions(controller) {
2824
+ const current = () => cardState(controller);
2825
+ const saveExecutables = (entries) => {
2826
+ const next = normalizeEntries(entries);
2827
+ if (sameEntries(next, current().executables)) return Promise.resolve();
2828
+ const baseline = runCounter(controller.getSnapshot());
2829
+ return controller.settleAndWrite((snapshot) => runCounter(snapshot) > baseline, "executables", next);
2830
+ };
2831
+ return {
2832
+ /** Stage the extra-flags list; a list equal to what is served is not
2833
+ * dirty (the controller drops that draft). */
2834
+ saveFlags: (flags) => {
2835
+ controller.stage("extraFlags", Array.isArray(flags) ? flags : []);
2836
+ return Promise.resolve();
2837
+ },
2838
+ /** Stage the flipped "Reduce log output" mode. A flip that lands back on
2839
+ * what is already effective drops the draft instead of staging a no-op:
2840
+ * it stages the served value itself, which the controller reads as clean. */
2841
+ toggleStderr: () => {
2842
+ const state = current();
2843
+ const held = state.stderrMode;
2844
+ const effective = held === "" ? state.rowStderr : held;
2845
+ const next = effective === "log" ? "console" : "log";
2846
+ const servedRaw = controller.servedValue("stderrMode");
2847
+ const served = servedRaw === "log" || servedRaw === "console" ? servedRaw : "";
2848
+ const servedEffective = served === "" ? state.rowStderr : served;
2849
+ controller.stage("stderrMode", next === servedEffective ? served : next);
2850
+ return Promise.resolve();
2851
+ },
2852
+ /** Select the executable the bridge launches with: written on the spot,
2853
+ * settled by the Host's own re-run. Picking what already runs writes
2854
+ * nothing. */
2855
+ selectExecutable: (id) => {
2856
+ const target = typeof id === "string" ? id.trim() : "";
2857
+ if (target === "" || target === current().effectiveChromePath) return Promise.resolve();
2858
+ const baseline = runCounter(controller.getSnapshot());
2859
+ return controller.settleAndWrite((snapshot) => runCounter(snapshot) > baseline, "chromePath", target);
2860
+ },
2861
+ saveExecutables,
2862
+ /** Merge the ids picked in the dialog into the saved rows. */
2863
+ addExecutables: (ids) => saveExecutables(current().executables.concat(
1213
2864
  (Array.isArray(ids) ? ids : []).filter((id) => typeof id === "string" && id.trim() !== "").map((id) => ({ id: id.trim(), name: "" }))
1214
- );
1215
- const next = normalizeEntries(merged);
1216
- if (JSON.stringify(next) === JSON.stringify(rows)) return Promise.resolve();
1217
- const baseline = served.executableDiscoveryRevision;
1218
- const wait = this.waitFor("executableDiscoveryRevision", baseline, Date.now() + CHECK_POLL_TIMEOUT_MS);
1219
- return this.scope.set("executables", next).catch((error) => this.noteError(error)).then(() => wait);
1220
- }
1221
- /**
1222
- * Ask the host to drive a Windows-side Chrome in connect mode: write the
1223
- * trigger, then wait for the run to settle (same revision counter every
1224
- * executable run advances). What the button ends up reporting — launched,
1225
- * already connected, prereq missing — is served through
1226
- * `windowsChromeStatus`, not through the promise.
1227
- */
1228
- openWindowsChrome() {
1229
- if (this.disposed) return Promise.resolve();
1230
- const baseline = this.store.getSnapshot().executableDiscoveryRevision;
1231
- const wait = this.waitFor("executableDiscoveryRevision", baseline, Date.now() + CHECK_POLL_TIMEOUT_MS);
1232
- return this.scope.set("openWindowsChromeNonce", Date.now()).catch((error) => this.noteError(error)).then(() => wait);
1233
- }
1234
- /**
1235
- * Flip the "Reduce log output" toggle: persists `stderrMode` as "log"
1236
- * (capture stderr into the bridge log file) or "console" (echo it for
1237
- * debugging), starting from what the host currently resolves — the served
1238
- * `stderrMode` when set, else the row-config `rowStderr` fallback. The host
1239
- * restarts the bridge connection on the change.
1240
- */
1241
- toggleStderr() {
1242
- if (this.disposed) return Promise.resolve();
1243
- const snapshot = this.store.getSnapshot();
1244
- const effective = snapshot.stderrMode === "log" || snapshot.stderrMode === "console" ? snapshot.stderrMode : snapshot.rowStderr === "console" ? "console" : "log";
1245
- const next = effective === "log" ? "console" : "log";
1246
- return this.scope.set("stderrMode", next).catch((error) => this.noteError(error));
1247
- }
1248
- /** The face the card's slot registration injects. */
1249
- inject() {
1250
- return {
1251
- hooks: { chromeMcpCard: this.store },
1252
- saveFlags: (flags) => this.saveFlags(flags),
1253
- toggleStderr: () => this.toggleStderr(),
1254
- selectExecutable: (id) => this.selectExecutable(id),
1255
- saveExecutables: (entries) => this.saveExecutables(entries),
1256
- refreshExecutables: () => this.refreshExecutables(),
1257
- addExecutables: (ids) => this.addExecutables(ids),
1258
- openWindowsChrome: () => this.openWindowsChrome(),
1259
- /** One mirror re-read (used when the card opens). */
1260
- refresh: () => this.refresh()
1261
- };
1262
- }
1263
- /**
1264
- * Re-read the shared describe mirror once so base-layer status
1265
- * captured asynchronously by the host (bridge connection errors)
1266
- * reaches an opened card without waiting for a write or a run.
1267
- */
1268
- refresh() {
1269
- if (this.disposed) return Promise.resolve();
1270
- let load;
1271
- try {
1272
- load = this.mirror.load();
1273
- } catch {
1274
- load = void 0;
1275
- }
1276
- return Promise.resolve(load).catch(() => {
1277
- });
1278
- }
1279
- dispose() {
1280
- this.disposed = true;
1281
- if (this.pollTimer !== null) {
1282
- clearTimeout(this.pollTimer);
1283
- this.pollTimer = null;
1284
- }
1285
- this.unsubscribe();
1286
- }
1287
- /**
1288
- * Re-describe the settings mirror every tick until the given revision field
1289
- * advances past `baseline`, or the deadline passes.
1290
- */
1291
- waitFor(field, baseline, deadline) {
1292
- const generation = ++this.pollGeneration;
1293
- const controller = this;
1294
- return new Promise((resolve) => {
1295
- let timer;
1296
- let settled = false;
1297
- const arm = (delay) => {
1298
- timer = setTimeout(tick, delay);
1299
- controller.pollTimer = timer ?? null;
1300
- };
1301
- const finish = () => {
1302
- if (settled) return;
1303
- settled = true;
1304
- clearTimeout(timer);
1305
- if (controller.pollTimer === (timer ?? null)) controller.pollTimer = null;
1306
- resolve();
1307
- };
1308
- const satisfied = () => readNumber(controller.store.getSnapshot()[field], baseline) > baseline || Date.now() >= deadline;
1309
- const stale = () => controller.disposed || generation !== controller.pollGeneration;
1310
- const tick = () => {
1311
- if (stale() || satisfied()) {
1312
- finish();
1313
- return;
1314
- }
1315
- let loaded;
1316
- try {
1317
- loaded = controller.mirror.load();
1318
- } catch {
1319
- loaded = void 0;
1320
- }
1321
- Promise.resolve(loaded).catch(() => ({})).then(() => {
1322
- if (stale() || satisfied()) {
1323
- finish();
1324
- return;
1325
- }
1326
- arm(CHECK_POLL_TICK_MS);
1327
- });
1328
- };
1329
- arm(CHECK_POLL_TICK_MS);
1330
- });
1331
- }
1332
- /** Surface a rejected action on the card (store-only; never host state). */
1333
- noteError(error) {
1334
- if (this.disposed) return;
1335
- const previous = this.store.getSnapshot();
1336
- this.store.set({
1337
- ...previous,
1338
- actionError: error != null && typeof error.message === "string" ? error.message : String(error)
1339
- });
1340
- }
1341
- };
2865
+ )),
2866
+ /** Ask the Host to re-probe the saved rows; answers every path the run
2867
+ * answered for, read off the served mirror once it settles. */
2868
+ refreshExecutables: () => controller.settleTrigger("refreshExecutablesNonce", RUN_COUNTER).then(() => readStatus(controller.value("executableStatus"))),
2869
+ /** Ask the Host to drive a Windows-side Chrome in connect mode; what the
2870
+ * button reports is served through `windowsChromeStatus`. */
2871
+ openWindowsChrome: () => controller.settleTrigger("openWindowsChromeNonce", RUN_COUNTER),
2872
+ /** Persist every staged edit in one pass. */
2873
+ apply: async () => {
2874
+ await controller.applyStaged();
2875
+ },
2876
+ /** Drop every staged edit. */
2877
+ discard: () => controller.discard()
2878
+ };
2879
+ }
2880
+ function ChromeCardBlock(props) {
2881
+ const state = cardState(props.controller);
2882
+ return ChromeMcpCard({
2883
+ t: props.t,
2884
+ view: "page",
2885
+ useChromeMcpCard: (selector) => selector(state),
2886
+ ...cardActions(props.controller)
2887
+ });
2888
+ }
1342
2889
 
1343
2890
  // src/client/locales/en-US.ts
1344
2891
  var en = {
1345
- title: "DSH Chrome MCP",
1346
- description: "DSH Chrome MCP server (chrome-devtools-mcp) settings and status",
1347
2892
  executableLabel: "Chrome executable",
1348
- executableHint: "The saved executable the bridge launches with. Selecting one restarts the connection.",
2893
+ executableHint: "The executable every connection launched from this row launches with, unless the connection picked its own. Changing it answers the live connections again.",
1349
2894
  executableNone: "No Chrome executable detected",
1350
2895
  executableRows: "Saved executables",
1351
2896
  executableIdLabel: "Executable path",
@@ -1368,7 +2913,7 @@ var en = {
1368
2913
  cancel: "Cancel",
1369
2914
  unavailableSuffix: "not runnable",
1370
2915
  wslWindowsTitle: "Windows executable under WSL",
1371
- wslWindowsNote: "This host runs inside Windows Subsystem for Linux and the selected executable is the Windows Chrome, which the bridge cannot launch: the debug pipes it opens do not survive the WSL interop boundary, and its debugging port stays bound to the Windows loopback, unreachable over the WSL2 NAT bridge. It answers --version correctly, so the pill looks healthy until the first tool call fails. To drive the Windows browser, start Chrome yourself with --remote-debugging-port=9222 --user-data-dir=C:\\chrome-debug, add --browserUrl=http://127.0.0.1:9222 to the extra flags, and make Windows loopback reachable from WSL by setting networkingMode=mirrored in %USERPROFILE%\\.wslconfig followed by wsl --shutdown. Chrome installed inside the Linux distro needs none of this.",
2916
+ wslWindowsNote: "This host runs inside Windows Subsystem for Linux and the selected executable is the Windows Chrome, which no connection here can launch: the debug pipes it opens do not survive the WSL interop boundary, and its debugging port stays bound to the Windows loopback. It answers --version correctly, so the pill looks healthy until the first tool call fails. Drive it instead with the \u201CWindows Chrome (WSL debug port)\u201D connection, or with its run \u2014 Prelaunch Windows Chrome, the action the executable block carries next to Fetch executables, or the prelaunch_windows_chrome tool \u2014 which starts the Windows browser on a free debugging port. The run only reads whether Windows loopback reaches this WSL host (networkingMode=mirrored in %USERPROFILE%\\.wslconfig, then wsl --shutdown \u2014 a manual Windows-side setting it never edits). Chrome installed inside the Linux distro needs none of this.",
1372
2917
  probing: "Checking the executables\u2026",
1373
2918
  versionLabel: "Probed version:",
1374
2919
  probeJustNow: "just now",
@@ -1376,7 +2921,7 @@ var en = {
1376
2921
  probeMinutesAgo: "minutes ago",
1377
2922
  probeHoursAgo: "hours ago",
1378
2923
  flagsTitle: "Extra flags",
1379
- flagsHint: "The extra flags the bridge launches with. One flag per row \u2014 saving restarts the connection.",
2924
+ flagsHint: "The extra flags every connection launched from this row launches with, unless the connection carries its own. One flag per row \u2014 applying them answers the live connections again.",
1380
2925
  flagsEmpty: "No extra flags saved. Add one by hand, or use \u201CRestore defaults\u201D.",
1381
2926
  flagsRows: "Saved flags",
1382
2927
  flagsValueLabel: "Extra flag",
@@ -1386,63 +2931,90 @@ var en = {
1386
2931
  flagsRestore: "Restore defaults",
1387
2932
  flagsRestoreTitle: "Keep every flag the rows carry and append the defaults that are still missing",
1388
2933
  flagsWsl: "Flags WSL",
1389
- flagsWslTitle: "A\xF1adir flags recomendados para WSL<->Windows",
2934
+ flagsWslTitle: "Append the recommended WSL<->Windows flags",
1390
2935
  openWindowsChrome: "Prelaunch Windows Chrome",
1391
- openWindowsChromeTitle: "Lanza el Chrome del lado Windows con --remote-debugging-port y deja el bridge en modo conexi\xF3n",
1392
- openWindowsChromeBusy: "Iniciando Chrome de Windows\u2026",
1393
- windowsChromeNotWsl: "Windows Chrome no aplica fuera de WSL.",
1394
- windowsChromeNotFound: "No se encontr\xF3 Chrome en el lado Windows (Program Files / Program Files (x86)).",
1395
- windowsChromeUnreachable: "Requiere networkingMode=mirrored en %USERPROFILE%\\.wslconfig, con wsl --shutdown: hoy el loopback de Windows no es alcanzable desde este host WSL.",
2936
+ openWindowsChromeTitle: "Start the Windows-side Chrome with --remote-debugging-port and refresh whatever Windows Chrome connections stand live",
2937
+ openWindowsChromeBusy: "Starting Windows Chrome\u2026",
2938
+ windowsChromeNotWsl: "Windows Chrome does not apply outside WSL.",
2939
+ windowsChromeNotFound: "No Windows Chrome was found (Program Files / Program Files (x86)) \u2014 run it again once one is installed.",
2940
+ windowsChromeUnreachable: "Needs networkingMode=mirrored in %USERPROFILE%\\.wslconfig, with wsl --shutdown: right now this WSL host cannot reach the Windows loopback.",
1396
2941
  connectModeLabel: "Connect mode",
1397
- connectModeHint: "Modo conexi\xF3n: el bridge no lanza un Chrome local (conecta con --browserUrl / --wsEndpoint); la selecci\xF3n local queda a la espera.",
2942
+ connectModeHint: "Connect mode: the connection launches no local Chrome (it connects with --browserUrl / --wsEndpoint); the local selection stays put.",
1398
2943
  reduceLabel: "Reduce log output",
1399
- reduceTitle: "Capture the bridge's stderr into the plugin's log file",
1400
- reduceHint: "Captures stderr into the plugin's log file. Turn it off to debug the raw bridge output; switching restarts the bridge connection.",
2944
+ reduceTitle: "Capture the connection's stderr into the plugin's log file",
2945
+ reduceHint: "Captures stderr into the plugin's log file. Turn it off to debug the raw output; switching answers the live connections again.",
2946
+ // The staged form's own copy: nothing is written until **Apply** lands every
2947
+ // staged edit, so the card announces what a save would store and what it
2948
+ // could not land.
2949
+ apply: "Apply",
2950
+ discard: "Discard",
2951
+ saving: "Applying\u2026",
2952
+ unsaved: "Unsaved",
2953
+ saveFailed: "The last save was not accepted.",
1401
2954
  docsMessage: "Find the complete list of server parameters (e.g., --headless, --isolated, --slim) and how to configure WebSocket connections in the Configuration Guide.",
1402
2955
  docsLinkLabel: "Configuration Guide",
1403
2956
  statusError: "Error",
1404
2957
  statusOk: "OK",
1405
2958
  chromeMissing: "Chrome executable not found",
1406
- readOnly: "Settings are read-only in this deployment.",
1407
- expand: "Expand",
1408
- collapse: "Collapse"
2959
+ // The body-mounted toast host's copy: it announces what the card's own error
2960
+ // line can only show while the row page is open. An error notice carries the
2961
+ // Host's captured line, so `toastError` only stands behind an empty one.
2962
+ toastStall: "The Chrome host did not answer the action \u2014 try it again.",
2963
+ toastError: "The Chrome host reported a failure.",
2964
+ readOnly: "Settings are read-only in this deployment."
1409
2965
  };
1410
2966
 
1411
2967
  // src/client/locales/index.ts
1412
- var DICTIONARIES = { en };
2968
+ var DICTIONARIES2 = { en };
1413
2969
 
1414
2970
  // src/client/styles/index.ts
1415
2971
  var CARD_CSS_ID = PLUGIN_ID + "/ChromeMcpCard.module.css";
1416
- function injectCardStyles() {
2972
+ function injectCardStyles2() {
1417
2973
  if (typeof document === "undefined") return;
1418
2974
  if (document.querySelector('style[data-plugin-css="' + CARD_CSS_ID + '"]') !== null) return;
1419
2975
  const styleTag = document.createElement("style");
1420
2976
  styleTag.dataset.plugin = PLUGIN_ID;
1421
2977
  styleTag.dataset.pluginCss = CARD_CSS_ID;
1422
- styleTag.textContent = cssText;
2978
+ styleTag.textContent = cssText2;
1423
2979
  document.head.appendChild(styleTag);
1424
2980
  }
1425
2981
 
1426
- // src/client/apply.ts
2982
+ // src/client/index.ts
2983
+ var card = mountSettingsCard2({
2984
+ entryId: ENTRY_ID,
2985
+ pluginId: PLUGIN_ID,
2986
+ bundleId: BUNDLE_ID,
2987
+ localeNamespace: LOCALE_NAMESPACE2,
2988
+ locale: DICTIONARIES2,
2989
+ fields: {
2990
+ // The flags and the "Reduce log output" mode are edited as a draft:
2991
+ // nothing reaches the Host until Apply.
2992
+ staged: ["extraFlags", "stderrMode"],
2993
+ // The saved rows and the selection drive a Host run, so they land on
2994
+ // the click that asked for them.
2995
+ immediate: ["executables", "chromePath"],
2996
+ triggers: ["refreshExecutablesNonce", "openWindowsChromeNonce"],
2997
+ liveKeys: [...LIVE_KEYS]
2998
+ },
2999
+ blocks: [{ block: ChromeCardBlock, bind: (_snapshot, controller) => ({ controller }) }],
3000
+ // The body states the error itself (the dot and the line under the
3001
+ // toggle), so the shared second line stays off.
3002
+ errorLine: false,
3003
+ // A failure that lands while the person is elsewhere in the app is still
3004
+ // announced: the row page is closed most of the time a run is happening.
3005
+ // An error carries the Host's own line; a stall has no text of its own and
3006
+ // reads from the mirror — the known missing-executable answer when it
3007
+ // stands, the "the host did not answer" line otherwise.
3008
+ toasts: {
3009
+ text: (notice, snapshot, t) => notice.kind === "error" ? notice.text !== "" ? notice.text : t("toastError") : snapshot.values?.chromeMissing === true ? t("chromeMissing") : t("toastStall")
3010
+ },
3011
+ settleField: "executableDiscoveryRevision",
3012
+ settleDeadlineMs: RUN_SETTLE_TIMEOUT_MS2
3013
+ });
3014
+ var inject = card.inject;
1427
3015
  function apply(ctx) {
1428
- injectCardStyles();
1429
- ctx.effect(() => ctx.locale.register(LOCALE_NAMESPACE, DICTIONARIES), `${SETTINGS_NAMESPACE}: dictionaries`);
1430
- const binder = ctx.settingsScope;
1431
- const scope = binder.bind({ namespace: SETTINGS_NAMESPACE });
1432
- const controller = new ChromeMcpCardController(scope, binder.describe());
1433
- ctx.effect(
1434
- () => () => controller.dispose(),
1435
- `${SETTINGS_NAMESPACE}: card controller`
1436
- );
1437
- ctx.slots.inject("settings.plugin.item", () => ctx.slots.register(
1438
- {
1439
- name: "settings.plugin.item",
1440
- key: SETTINGS_NAMESPACE,
1441
- locale: LOCALE_NAMESPACE,
1442
- inject: () => controller.inject()
1443
- },
1444
- ChromeMcpCard
1445
- ));
3016
+ injectCardStyles2();
3017
+ card.apply(ctx);
1446
3018
  }
1447
3019
  return module.exports;
1448
3020
  }