@noodleseed/one 0.89.0 → 0.90.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 (180) hide show
  1. package/README.md +193 -0
  2. package/dist/commands/billing-enforcement-activation-ops.js +1 -11
  3. package/dist/commands/billing-enforcement-activation-ops.js.map +1 -1
  4. package/dist/commands/billing-enforcement-ops.js +1 -11
  5. package/dist/commands/billing-enforcement-ops.js.map +1 -1
  6. package/dist/commands/billing-metering-ops.js +1 -11
  7. package/dist/commands/billing-metering-ops.js.map +1 -1
  8. package/dist/commands/billing-metering-validation-ops.js +1 -11
  9. package/dist/commands/billing-metering-validation-ops.js.map +1 -1
  10. package/dist/commands/billing-read-ops.js +1 -11
  11. package/dist/commands/billing-read-ops.js.map +1 -1
  12. package/dist/commands/billing-stripe-ops.js +1 -11
  13. package/dist/commands/billing-stripe-ops.js.map +1 -1
  14. package/dist/commands/org-admin.d.ts +6 -0
  15. package/dist/commands/org-admin.d.ts.map +1 -1
  16. package/dist/commands/org-admin.js +1 -29
  17. package/dist/commands/org-admin.js.map +1 -1
  18. package/dist/commands/org-domains.js +1 -22
  19. package/dist/commands/org-domains.js.map +1 -1
  20. package/dist/commands/org-member-args.d.ts +1 -1
  21. package/dist/commands/org-member-args.d.ts.map +1 -1
  22. package/dist/commands/org-member-args.js +1 -10
  23. package/dist/commands/org-member-args.js.map +1 -1
  24. package/dist/commands/org-openai-challenge.js +1 -22
  25. package/dist/commands/org-openai-challenge.js.map +1 -1
  26. package/dist/commands/platform-account-reset-args.d.ts.map +1 -1
  27. package/dist/commands/platform-account-reset-args.js +1 -6
  28. package/dist/commands/platform-account-reset-args.js.map +1 -1
  29. package/dist/commands/platform-account-reset-ops.js +1 -11
  30. package/dist/commands/platform-account-reset-ops.js.map +1 -1
  31. package/dist/commands/platform-auth-migration-args.d.ts +2 -0
  32. package/dist/commands/platform-auth-migration-args.d.ts.map +1 -1
  33. package/dist/commands/platform-auth-migration-args.js +2 -1
  34. package/dist/commands/platform-auth-migration-args.js.map +1 -1
  35. package/dist/commands/platform-auth-migration-ops.js +1 -11
  36. package/dist/commands/platform-auth-migration-ops.js.map +1 -1
  37. package/dist/commands/shared.d.ts +6 -0
  38. package/dist/commands/shared.d.ts.map +1 -1
  39. package/dist/commands/shared.js +34 -0
  40. package/dist/commands/shared.js.map +1 -1
  41. package/dist/deploy.d.ts +2 -0
  42. package/dist/deploy.d.ts.map +1 -1
  43. package/dist/deploy.js +4 -4
  44. package/dist/deploy.js.map +1 -1
  45. package/dist/dev.d.ts.map +1 -1
  46. package/dist/dev.js +1 -7
  47. package/dist/dev.js.map +1 -1
  48. package/dist/devtools-brand.d.ts +14 -0
  49. package/dist/devtools-brand.d.ts.map +1 -0
  50. package/dist/devtools-brand.js +98 -0
  51. package/dist/devtools-brand.js.map +1 -0
  52. package/dist/devtools-chat-anthropic.d.ts +3 -0
  53. package/dist/devtools-chat-anthropic.d.ts.map +1 -0
  54. package/dist/devtools-chat-anthropic.js +75 -0
  55. package/dist/devtools-chat-anthropic.js.map +1 -0
  56. package/dist/devtools-chat-gemini.d.ts +3 -0
  57. package/dist/devtools-chat-gemini.d.ts.map +1 -0
  58. package/dist/devtools-chat-gemini.js +82 -0
  59. package/dist/devtools-chat-gemini.js.map +1 -0
  60. package/dist/devtools-chat-types.d.ts +64 -0
  61. package/dist/devtools-chat-types.d.ts.map +1 -0
  62. package/dist/devtools-chat-types.js +64 -0
  63. package/dist/devtools-chat-types.js.map +1 -0
  64. package/dist/devtools-chat.d.ts +7 -39
  65. package/dist/devtools-chat.d.ts.map +1 -1
  66. package/dist/devtools-chat.js +33 -48
  67. package/dist/devtools-chat.js.map +1 -1
  68. package/dist/devtools-copy-styles.d.ts +3 -0
  69. package/dist/devtools-copy-styles.d.ts.map +1 -0
  70. package/dist/devtools-copy-styles.js +54 -0
  71. package/dist/devtools-copy-styles.js.map +1 -0
  72. package/dist/devtools-design.d.ts +5 -0
  73. package/dist/devtools-design.d.ts.map +1 -0
  74. package/dist/devtools-design.js +62 -0
  75. package/dist/devtools-design.js.map +1 -0
  76. package/dist/devtools-harness.d.ts +2 -2
  77. package/dist/devtools-harness.d.ts.map +1 -1
  78. package/dist/devtools-harness.js +130 -216
  79. package/dist/devtools-harness.js.map +1 -1
  80. package/dist/devtools-json.d.ts +10 -0
  81. package/dist/devtools-json.d.ts.map +1 -0
  82. package/dist/devtools-json.js +23 -0
  83. package/dist/devtools-json.js.map +1 -0
  84. package/dist/devtools-preview-control-styles.d.ts +3 -0
  85. package/dist/devtools-preview-control-styles.d.ts.map +1 -0
  86. package/dist/devtools-preview-control-styles.js +207 -0
  87. package/dist/devtools-preview-control-styles.js.map +1 -0
  88. package/dist/devtools-preview.d.ts +7 -3
  89. package/dist/devtools-preview.d.ts.map +1 -1
  90. package/dist/devtools-preview.js +189 -43
  91. package/dist/devtools-preview.js.map +1 -1
  92. package/dist/devtools-provider-logos.d.ts +5 -0
  93. package/dist/devtools-provider-logos.d.ts.map +1 -0
  94. package/dist/devtools-provider-logos.js +5 -0
  95. package/dist/devtools-provider-logos.js.map +1 -0
  96. package/dist/devtools-responsive-styles.d.ts +3 -0
  97. package/dist/devtools-responsive-styles.d.ts.map +1 -0
  98. package/dist/devtools-responsive-styles.js +75 -0
  99. package/dist/devtools-responsive-styles.js.map +1 -0
  100. package/dist/devtools-styles.d.ts +3 -0
  101. package/dist/devtools-styles.d.ts.map +1 -0
  102. package/dist/devtools-styles.js +694 -0
  103. package/dist/devtools-styles.js.map +1 -0
  104. package/dist/local-target.d.ts.map +1 -1
  105. package/dist/local-target.js +1 -6
  106. package/dist/local-target.js.map +1 -1
  107. package/dist/plugin-mode/build-readiness-server.d.ts +4 -10
  108. package/dist/plugin-mode/build-readiness-server.d.ts.map +1 -1
  109. package/dist/plugin-mode/build-readiness-server.js +68 -67
  110. package/dist/plugin-mode/build-readiness-server.js.map +1 -1
  111. package/dist/plugin-mode/plugin-command-runner.d.ts +41 -0
  112. package/dist/plugin-mode/plugin-command-runner.d.ts.map +1 -0
  113. package/dist/plugin-mode/plugin-command-runner.js +122 -0
  114. package/dist/plugin-mode/plugin-command-runner.js.map +1 -0
  115. package/dist/plugin-mode/plugin-operation-contract.d.ts +237 -0
  116. package/dist/plugin-mode/plugin-operation-contract.d.ts.map +1 -0
  117. package/dist/plugin-mode/plugin-operation-contract.js +164 -0
  118. package/dist/plugin-mode/plugin-operation-contract.js.map +1 -0
  119. package/dist/plugin-mode/plugin-operation-tools.d.ts +20 -0
  120. package/dist/plugin-mode/plugin-operation-tools.d.ts.map +1 -0
  121. package/dist/plugin-mode/plugin-operation-tools.js +289 -0
  122. package/dist/plugin-mode/plugin-operation-tools.js.map +1 -0
  123. package/dist/preview-session.d.ts.map +1 -1
  124. package/dist/preview-session.js +22 -5
  125. package/dist/preview-session.js.map +1 -1
  126. package/dist/project.d.ts.map +1 -1
  127. package/dist/project.js +1 -7
  128. package/dist/project.js.map +1 -1
  129. package/node_modules/@noodle-borg/agent-kit/dist/generated/example-files.js +1 -1
  130. package/node_modules/@noodle-borg/agent-kit/dist/generated/example-files.js.map +1 -1
  131. package/node_modules/@noodle-borg/agent-kit/dist/plugin-bundle.d.ts.map +1 -1
  132. package/node_modules/@noodle-borg/agent-kit/dist/plugin-bundle.js +16 -12
  133. package/node_modules/@noodle-borg/agent-kit/dist/plugin-bundle.js.map +1 -1
  134. package/node_modules/@noodle-borg/agent-kit/dist/plugin-marketplace-docs.js +9 -9
  135. package/node_modules/@noodle-borg/agent-kit/dist/skill-feedback-ref.js +4 -4
  136. package/node_modules/@noodle-borg/agent-kit/dist/skill-feedback-ref.js.map +1 -1
  137. package/node_modules/@noodle-borg/agent-kit/dist/skill-router.d.ts.map +1 -1
  138. package/node_modules/@noodle-borg/agent-kit/dist/skill-router.js +6 -3
  139. package/node_modules/@noodle-borg/agent-kit/dist/skill-router.js.map +1 -1
  140. package/node_modules/@noodle-borg/agent-kit/package.json +1 -1
  141. package/node_modules/@noodle-borg/connector-defs/dist/index.d.ts +1 -1
  142. package/node_modules/@noodle-borg/connector-defs/dist/index.d.ts.map +1 -1
  143. package/node_modules/@noodle-borg/connector-defs/dist/index.js.map +1 -1
  144. package/node_modules/@noodle-borg/module-audit/dist/route.d.ts +0 -2
  145. package/node_modules/@noodle-borg/module-audit/dist/route.d.ts.map +1 -1
  146. package/node_modules/@noodle-borg/module-audit/dist/route.js +0 -4
  147. package/node_modules/@noodle-borg/module-audit/dist/route.js.map +1 -1
  148. package/node_modules/@noodle-borg/protocol/dist/input-validation.d.ts +0 -2
  149. package/node_modules/@noodle-borg/protocol/dist/input-validation.d.ts.map +1 -1
  150. package/node_modules/@noodle-borg/protocol/dist/input-validation.js +1 -5
  151. package/node_modules/@noodle-borg/protocol/dist/input-validation.js.map +1 -1
  152. package/node_modules/@noodle-borg/service/dist/auth/deploy-gate.d.ts +0 -2
  153. package/node_modules/@noodle-borg/service/dist/auth/deploy-gate.d.ts.map +1 -1
  154. package/node_modules/@noodle-borg/service/dist/auth/deploy-gate.js +0 -7
  155. package/node_modules/@noodle-borg/service/dist/auth/deploy-gate.js.map +1 -1
  156. package/node_modules/@noodle-borg/service/dist/credential-binding-index.d.ts +1 -3
  157. package/node_modules/@noodle-borg/service/dist/credential-binding-index.d.ts.map +1 -1
  158. package/node_modules/@noodle-borg/service/dist/credential-binding-index.js +1 -14
  159. package/node_modules/@noodle-borg/service/dist/credential-binding-index.js.map +1 -1
  160. package/node_modules/@noodle-borg/service/dist/index.d.ts +5 -5
  161. package/node_modules/@noodle-borg/service/dist/index.d.ts.map +1 -1
  162. package/node_modules/@noodle-borg/service/dist/index.js +1 -1
  163. package/node_modules/@noodle-borg/service/dist/index.js.map +1 -1
  164. package/node_modules/@noodle-borg/service/dist/mcp-public-routing.d.ts +0 -2
  165. package/node_modules/@noodle-borg/service/dist/mcp-public-routing.d.ts.map +1 -1
  166. package/node_modules/@noodle-borg/service/dist/mcp-public-routing.js +0 -6
  167. package/node_modules/@noodle-borg/service/dist/mcp-public-routing.js.map +1 -1
  168. package/node_modules/@noodle-borg/service/dist/oauth/console-url.d.ts +2 -0
  169. package/node_modules/@noodle-borg/service/dist/oauth/console-url.d.ts.map +1 -0
  170. package/node_modules/@noodle-borg/service/dist/oauth/console-url.js +4 -0
  171. package/node_modules/@noodle-borg/service/dist/oauth/console-url.js.map +1 -0
  172. package/node_modules/@noodle-borg/service/dist/oauth/service-bootstrap.d.ts.map +1 -1
  173. package/node_modules/@noodle-borg/service/dist/oauth/service-bootstrap.js +2 -1
  174. package/node_modules/@noodle-borg/service/dist/oauth/service-bootstrap.js.map +1 -1
  175. package/node_modules/@noodle-borg/service/dist/registry-targets.d.ts +1 -3
  176. package/node_modules/@noodle-borg/service/dist/registry-targets.d.ts.map +1 -1
  177. package/node_modules/@noodle-borg/service/dist/registry-targets.js +0 -17
  178. package/node_modules/@noodle-borg/service/dist/registry-targets.js.map +1 -1
  179. package/node_modules/@noodle-borg/service/package.json +0 -1
  180. package/package.json +23 -1
@@ -6,6 +6,17 @@
6
6
  * The client script is plain (no template literals / no `${...}`) so it splices safely into the shell
7
7
  * and so the shim's classic script runs before the widget's deferred bridge module.
8
8
  */
9
+ import { DEVTOOLS_FAVICON_DATA_URI, DEVTOOLS_SHADER_SCRIPT, DEVTOOLS_WORDMARK, } from './devtools-brand.js';
10
+ import { DEVTOOLS_DESIGN_HTML } from './devtools-design.js';
11
+ import { DEVTOOLS_JSON_CLIENT_JS, DEVTOOLS_JSON_STYLES } from './devtools-json.js';
12
+ import { CLAUDE_MARK, GEMINI_MARK, OPENAI_MARK } from './devtools-provider-logos.js';
13
+ import { DEVTOOLS_STYLES } from './devtools-styles.js';
14
+ /** Convert a native range value to a clamped percentage using its actual, non-zero bounds. */
15
+ export function calculateRangeProgress(value, min, max) {
16
+ if (![value, min, max].every(Number.isFinite) || max <= min)
17
+ return 0;
18
+ return Math.max(0, Math.min(100, ((value - min) / (max - min)) * 100));
19
+ }
9
20
  /**
10
21
  * Serialize a value for safe inlining inside a `<script>` block. Tool output/metadata can contain
11
22
  * `</script>` (and can come from an untrusted upstream API), which would otherwise close the inline script
@@ -54,7 +65,7 @@ export function openAiShimScript(init) {
54
65
  * preview instead of showing a white default canvas. Iframes do not render reliably transparent across
55
66
  * browser color-scheme handling, so an explicit opaque colour is used rather than `transparent`.
56
67
  */
57
- const STAGE_BG = '#0c0a09';
68
+ const STAGE_BG = '#000000';
58
69
  const PREVIEW_RESET_STYLE = `<style>html,body{background:${STAGE_BG}!important;margin:0;padding:0}</style>`;
59
70
  /** Insert the reset + shim into the widget document so they run before the (deferred) bridge module script. */
60
71
  export function wrapWidgetHtml(html, shimScript) {
@@ -76,40 +87,51 @@ export function wrapWidgetHtml(html, shimScript) {
76
87
  function escapeHtml(value) {
77
88
  return value.replaceAll('&', '&amp;').replaceAll('<', '&lt;').replaceAll('>', '&gt;');
78
89
  }
79
- /** Official Noodle Seed brand mark (from apps/website/public/favicon.svg), sized via CSS. */
80
- const NOODLE_MARK = '<svg class="brand__mark" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">' +
81
- '<rect width="16" height="16" rx="8" fill="white"/>' +
82
- '<path d="M8.58023 12.8485C6.27833 12.8463 4.41315 11.0141 4.42117 8.75681L4.43588 4.61714L8.66254 4.62118C10.9644 4.62339 12.8296 6.45561 12.8216 8.71287C12.8135 10.9975 10.9128 12.8507 8.58023 12.8485Z" fill="black"/>' +
83
- '<path d="M8.82627 4.76869C11.1282 4.7709 12.9933 6.60312 12.9853 8.86038L12.9706 13L8.74395 12.996C6.44206 12.9938 4.57687 11.1616 4.5849 8.90432C4.59302 6.6197 6.49364 4.76646 8.82627 4.76869Z" fill="black"/>' +
84
- '<ellipse cx="3.69536" cy="3.68106" rx="0.695363" ry="0.681056" fill="black"/></svg>';
85
90
  /** The three-pane harness shell. */
86
91
  export function harnessHtml(options) {
87
- const client = HARNESS_CLIENT_JS.replace('__INITIAL_THEME__', options.theme === 'dark' ? 'dark' : 'light')
88
- .replace('__INITIAL_DEVICE__', options.device === 'mobile' ? 'mobile' : 'desktop')
89
- // replaceAll: the placeholder appears more than once in the client — a single replace would leave a
90
- // literal `__CHAT_HAS_KEY__` that throws a ReferenceError and aborts the script (breaking the key gate).
91
- .replaceAll('__CHAT_HAS_KEY__', options.hasServerKey ? 'true' : 'false');
92
+ const client = HARNESS_CLIENT_JS.replace('__INITIAL_THEME__', options.theme === 'dark' ? 'dark' : 'light').replace('__INITIAL_DEVICE__', options.device === 'mobile' ? 'mobile' : 'desktop');
92
93
  return ('<!doctype html><html lang="en"><head><meta charset="utf-8">' +
93
94
  '<meta name="viewport" content="width=device-width, initial-scale=1">' +
95
+ `<link rel="icon" type="image/svg+xml" href="${DEVTOOLS_FAVICON_DATA_URI}">` +
94
96
  '<title>Noodle Seed Devtools</title><style>' +
95
- HARNESS_CSS +
97
+ DEVTOOLS_STYLES +
98
+ DEVTOOLS_JSON_STYLES +
96
99
  '</style></head><body>' +
97
- '<header class="bar"><span class="brand">' +
98
- NOODLE_MARK +
99
- '<span class="brand__name">Noodle Seed</span><span class="brand__label">Devtools</span></span>' +
100
- '<div class="modes" role="tablist">' +
100
+ '<canvas id="ns-canvas" aria-hidden="true"></canvas>' +
101
+ '<div class="ambient-fallback" aria-hidden="true"></div>' +
102
+ '<div class="ambient-scrim" aria-hidden="true"></div>' +
103
+ '<div id="rail-scrim" class="rail-scrim" aria-hidden="true"></div>' +
104
+ '<div class="workspace">' +
105
+ '<aside id="tools" class="pane pane--tools" aria-label="Tools">' +
106
+ '<div class="brand"><span class="brand__logo">' +
107
+ DEVTOOLS_WORDMARK +
108
+ '</span>' +
109
+ '<button id="close-tools" class="rail-close" type="button" aria-label="Close tools">×</button></div>' +
110
+ '<div class="rail-heading"><h2>Tools</h2><span class="rail-heading__hint">Server surface</span></div>' +
111
+ '<ul id="tool-list"></ul></aside>' +
112
+ '<main id="stage" class="pane pane--stage">' +
113
+ '<header class="bar">' +
114
+ '<button id="toggle-tools" class="rail-toggle rail-toggle--tools" type="button" aria-label="Open tools" aria-controls="tools" aria-expanded="false">' +
115
+ '<span aria-hidden="true">☰</span><span>Tools</span></button>' +
116
+ '<div class="modes" role="tablist" aria-label="Devtools mode">' +
101
117
  '<button id="mode-preview" class="mode is-active" type="button" role="tab">Preview</button>' +
102
118
  '<button id="mode-chat" class="mode" type="button" role="tab">Chat</button>' +
119
+ '<button id="mode-design" class="mode mode--design" type="button" role="tab" aria-controls="design-view" aria-selected="false"><span>Design</span><span class="mode__soon">Soon</span></button>' +
103
120
  '</div>' +
104
- `<span class="muted brand__url">${escapeHtml(options.mcpUrl)}</span></header>` +
105
- '<div class="cols">' +
106
- '<aside id="tools" class="pane pane--tools"><h2>Tools</h2><ul id="tool-list"></ul></aside>' +
107
- '<main id="stage" class="pane pane--stage">' +
121
+ `<span class="muted brand__url" title="${escapeHtml(options.mcpUrl)}">${escapeHtml(options.mcpUrl)}</span>` +
122
+ '<button id="toggle-activity" class="rail-toggle rail-toggle--activity" type="button" aria-label="Open MCP calls" aria-controls="log" aria-expanded="false">' +
123
+ '<span class="status-dot" aria-hidden="true"></span><span>Activity</span></button></header>' +
108
124
  '<div id="preview-view">' +
109
125
  '<div id="controls" class="controls">' +
110
- '<span class="ctl"><span class="ctl__lbl">Theme</span><select id="theme"><option value="light">Light</option><option value="dark">Dark</option></select></span>' +
111
- '<span class="ctl"><span class="ctl__lbl">Device</span><select id="device"><option value="desktop">Desktop</option><option value="mobile">Mobile</option></select></span>' +
112
- '<span class="ctl ctl--width"><span class="ctl__lbl">Width</span><input id="width" type="range" min="320" max="1200" value="820"><span id="width-val" class="ctl__val">820px</span></span>' +
126
+ '<span class="ctl"><span class="ctl__lbl">Theme</span><button id="theme-toggle" class="theme-switch" type="button" aria-label="Switch to dark theme" aria-pressed="false">' +
127
+ '<span class="theme-switch__icon" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"><circle cx="12" cy="12" r="3.5"/><path d="M12 2v2M12 20v2M4.93 4.93l1.42 1.42M17.66 17.66l1.41 1.41M2 12h2M20 12h2M4.93 19.07l1.42-1.42M17.66 6.34l1.41-1.41"/></svg></span>' +
128
+ '<span class="theme-switch__track" aria-hidden="true"><span class="theme-switch__thumb"></span></span>' +
129
+ '<span class="theme-switch__icon" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12.8A8.5 8.5 0 1 1 11.2 3 6.7 6.7 0 0 0 21 12.8Z"/></svg></span></button></span>' +
130
+ '<span class="ctl"><span class="ctl__lbl">Device</span><span class="device-switch" role="group" aria-label="Preview device">' +
131
+ '<button type="button" data-device="desktop" aria-label="Desktop preview" title="Desktop preview" aria-pressed="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="4" width="18" height="13" rx="2"/><path d="M8 21h8M12 17v4"/></svg></button>' +
132
+ '<button type="button" data-device="mobile" aria-label="Mobile preview" title="Mobile preview" aria-pressed="false"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><rect x="7" y="2" width="10" height="20" rx="2"/><path d="M11 18h2"/></svg></button>' +
133
+ '</span></span>' +
134
+ '<span class="ctl ctl--width"><span class="ctl__lbl">Width</span><input id="width" type="range" min="320" max="1200" value="820" aria-label="Preview width"><output id="width-val" for="width" class="ctl__val">820 px</output></span>' +
113
135
  '<span class="ctl__spacer"></span>' +
114
136
  '<button id="fullscreen" class="ctl-btn" type="button" title="Toggle fullscreen preview">' +
115
137
  '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M8 3H5a2 2 0 0 0-2 2v3m13-5h3a2 2 0 0 1 2 2v3M8 21H5a2 2 0 0 1-2-2v-3m13 5h3a2 2 0 0 0 2-2v-3"/></svg>Fullscreen</button>' +
@@ -120,24 +142,34 @@ export function harnessHtml(options) {
120
142
  '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">' +
121
143
  '<rect x="3" y="4" width="18" height="16" rx="2"/><path d="M3 9h18"/><path d="M7.5 4v5"/></svg>' +
122
144
  '<p>Nothing selected</p>' +
123
- '<span>Pick a tool on the left preview a widget, or run a tool to see its JSON response here.</span>' +
145
+ '<span>Pick a tool on the left to preview a widget or inspect its JSON response here.</span>' +
124
146
  '</div>' +
125
147
  '<iframe id="frame" class="hidden" title="widget preview"></iframe>' +
126
- '<div id="result" class="hidden"><div class="result__label">response</div><pre id="result-pre"></pre></div>' +
148
+ '<div id="result" class="hidden"><div class="result__bar"><div class="result__label">response</div>' +
149
+ '<button id="copy-result" class="copy-action" type="button" aria-label="Copy response">' +
150
+ '<span class="copy-action__icons" aria-hidden="true">' +
151
+ '<svg class="copy-action__copy" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="11" height="11" rx="2"/><path d="M15 9V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7a2 2 0 0 0 2 2h3"/></svg>' +
152
+ '<svg class="copy-action__check" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m5 12 4 4L19 6"/></svg>' +
153
+ '</span><span class="copy-action__label">Copy</span></button>' +
154
+ '<span id="copy-status" class="sr-only" aria-live="polite"></span></div><pre id="result-pre"></pre></div>' +
127
155
  '</div>' +
128
156
  '<div id="chat-view" class="hidden">' +
129
- // Key-entry gate shown when the server has no key; the key is sent to the loopback /chat only.
157
+ // Key gate. The key prefix identifies the provider on the loopback server and is never retained by the page.
130
158
  '<div id="chat-gate" class="chat-gate"><div class="chat-gate__card">' +
131
- '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">' +
132
- '<circle cx="7.5" cy="15.5" r="4.5"/><path d="M10.7 12.3 19 4"/><path d="m16 6 2 2"/><path d="m14 8 2 2"/></svg>' +
133
- '<h3>Connect a model</h3>' +
134
- '<p>Enter an OpenAI API key to start the chat playground. It is kept only on this local devtools server to call OpenAI — never stored in the browser.</p>' +
135
- '<form id="chat-key-form"><input id="chat-key-input" type="password" placeholder="sk-…" autocomplete="off" spellcheck="false">' +
136
- '<button class="btn btn--run" type="submit">Start chatting</button></form>' +
137
- '<span id="chat-gate-hint" class="chat-gate__hint">Prefer a file? Set <code>OPENAI_API_KEY</code> in your shell or a <code>.env.local</code>.</span>' +
159
+ '<h3>Use your favourite model</h3>' +
160
+ '<p class="model-compatibility"><span>Test your local MCP server with</span>' +
161
+ '<span class="compatibility-logos">' +
162
+ `<span class="compatibility-logo compatibility-logo--openai" data-provider-logo="openai">${OPENAI_MARK}</span>` +
163
+ `<span class="compatibility-logo compatibility-logo--anthropic" data-provider-logo="anthropic">${CLAUDE_MARK}</span>` +
164
+ `<span class="compatibility-logo compatibility-logo--gemini" data-provider-logo="gemini">${GEMINI_MARK}</span>` +
165
+ '</span></p>' +
166
+ '<form id="chat-key-form">' +
167
+ '<label class="chat-config-field"><span>API key</span><input id="chat-key-input" type="password" aria-label="Provider API key" autocomplete="off" spellcheck="false"></label>' +
168
+ '<button id="chat-connect" class="btn primary-action" type="submit">Start chatting</button></form>' +
169
+ '<span id="chat-gate-hint" class="chat-gate__hint" aria-live="polite">Your key stays in this local process.</span>' +
138
170
  '</div></div>' +
139
171
  '<div id="chat-body" class="hidden">' +
140
- '<div id="chat-keybar"><button id="chat-reset" type="button">Change key</button></div>' +
172
+ '<div id="chat-keybar"><span id="chat-model-label"></span><button id="chat-reset" type="button">Change key</button></div>' +
141
173
  '<div id="chat-log"><div id="chat-empty" class="empty-state">' +
142
174
  '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">' +
143
175
  '<path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>' +
@@ -146,186 +178,66 @@ export function harnessHtml(options) {
146
178
  '</div></div>' +
147
179
  '<form id="chat-form" class="chat-form">' +
148
180
  '<textarea id="chat-input" rows="1" placeholder="Ask the agent to run a tool…"></textarea>' +
149
- '<button id="chat-send" class="btn btn--run" type="submit">Send</button>' +
181
+ '<button id="chat-send" class="btn primary-action" type="submit">Send</button>' +
150
182
  '</form>' +
151
183
  '</div>' +
152
184
  '</div>' +
185
+ DEVTOOLS_DESIGN_HTML +
153
186
  '</main>' +
154
- '<aside id="log" class="pane pane--log"><h2>MCP calls</h2><ol id="log-list"></ol></aside>' +
187
+ '<aside id="log" class="pane pane--log" aria-label="MCP calls">' +
188
+ '<div class="rail-heading rail-heading--activity"><div><span class="rail-eyebrow">Activity</span><h2>MCP calls</h2></div>' +
189
+ '<span class="activity-state" aria-label="Listening for MCP calls"><span class="status-dot" aria-hidden="true"></span></span>' +
190
+ '<button id="close-activity" class="rail-close" type="button" aria-label="Close MCP calls">×</button></div>' +
191
+ '<ol id="log-list"></ol></aside>' +
155
192
  '</div>' +
156
193
  '<script>' +
194
+ DEVTOOLS_JSON_CLIENT_JS +
195
+ '\n' +
157
196
  client +
197
+ '</script><script>' +
198
+ DEVTOOLS_SHADER_SCRIPT +
158
199
  '</script></body></html>');
159
200
  }
160
- const HARNESS_CSS =
161
- // Warm-on-stone brand palette ported from apps/website (stone-950 base + warm CTA ramp).
162
- ':root{color-scheme:dark;' +
163
- '--nd-bg:#0c0a09;--nd-panel:#1c1917;--nd-raised:#292524;' +
164
- '--nd-border:rgba(250,250,249,.09);--nd-border-strong:rgba(250,250,249,.16);' +
165
- '--nd-text:#fafaf9;--nd-muted:#a8a29e;--nd-faint:#78716c;' +
166
- '--nd-accent:#f97316;--nd-amber:#f59e0b;--nd-rose:#f43f5e;--nd-ok:#4ade80;' +
167
- '--nd-r:10px;--nd-r-sm:7px;' +
168
- '--nd-font:"Geist",ui-sans-serif,system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;' +
169
- '--nd-mono:"Geist Mono",ui-monospace,SFMono-Regular,Menlo,monospace}' +
170
- '*{box-sizing:border-box}' +
171
- // Full-height flex column (header + cols) instead of a magic `100vh - 49px`, so a taller header (mode
172
- // toggle) never pushes the grid past the viewport and makes the body scroll.
173
- 'body{margin:0;height:100vh;display:flex;flex-direction:column;overflow:hidden;font-family:var(--nd-font);background:var(--nd-bg);color:var(--nd-text);-webkit-font-smoothing:antialiased}' +
174
- '.bar{flex:none;display:flex;gap:12px;align-items:center;padding:12px 16px;border-bottom:1px solid var(--nd-border)}' +
175
- '.brand{display:flex;align-items:center;gap:9px}' +
176
- '.brand__mark{width:22px;height:22px;display:block;flex:none}' +
177
- '.brand__name{font-weight:650;font-size:14px;color:var(--nd-text);letter-spacing:-.01em}' +
178
- '.brand__label{font-size:10px;font-weight:600;text-transform:uppercase;letter-spacing:.08em;color:var(--nd-accent);background:color-mix(in oklab,var(--nd-accent) 14%,transparent);padding:2px 7px;border-radius:999px}' +
179
- '.brand__url{margin-left:auto;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:38%}' +
180
- '.muted{color:var(--nd-muted);font-size:12px}' +
181
- // Segmented Preview|Chat toggle in the header.
182
- '.modes{display:flex;gap:2px;background:var(--nd-panel);border:1px solid var(--nd-border-strong);border-radius:999px;padding:3px}' +
183
- '.mode{background:transparent;color:var(--nd-muted);border:0;border-radius:999px;padding:5px 16px;font-size:12.5px;font-weight:600;cursor:pointer;font-family:inherit}' +
184
- '.mode.is-active{background:var(--nd-accent);color:#1c0a00}' +
185
- '.cols{flex:1;min-height:0;display:grid;grid-template-columns:288px 1fr 372px;grid-template-rows:minmax(0,1fr)}' +
186
- '.pane{padding:14px;overflow:auto}.pane--tools{border-right:1px solid var(--nd-border)}' +
187
- '.pane--log{border-left:1px solid var(--nd-border)}' +
188
- 'h2{font-size:11px;text-transform:uppercase;letter-spacing:.08em;color:var(--nd-faint);margin:0 0 12px;font-weight:600}' +
189
- '#tool-list{list-style:none;margin:0;padding:0}' +
190
- '.tool{border:1px solid var(--nd-border);border-radius:var(--nd-r);margin-bottom:8px;overflow:hidden;background:var(--nd-panel)}' +
191
- '.tool__head{display:flex;align-items:center;gap:8px;padding:10px 12px;cursor:pointer;font-size:13.5px}' +
192
- '.tool__head:hover{background:var(--nd-raised)}.tool.open .tool__head{background:var(--nd-raised)}' +
193
- '.tool__name{font-weight:600;font-family:var(--nd-mono);font-size:13px}' +
194
- '.tag{font-size:10px;font-weight:600;color:var(--nd-accent);background:color-mix(in oklab,var(--nd-accent) 16%,transparent);padding:1px 7px;border-radius:999px}' +
195
- '.chev{color:var(--nd-faint);font-size:11px}.tool__head .chev{margin-left:auto}' +
196
- '.tool__detail{display:none;padding:2px 12px 12px}.tool.open .tool__detail{display:block}' +
197
- '.tool__desc{color:var(--nd-muted);font-size:12.5px;margin:6px 0 12px;line-height:1.5}' +
198
- '.field{margin-bottom:10px}.field label{display:block;font-size:12px;color:var(--nd-text);margin-bottom:4px}' +
199
- '.field__hint{font-size:11px;color:var(--nd-muted);margin-top:4px;line-height:1.4}' +
200
- '.field input[type=text],.field input[type=number],.field select{width:100%;background:var(--nd-bg);color:var(--nd-text);border:1px solid var(--nd-border-strong);border-radius:var(--nd-r-sm);padding:7px 9px;font-size:13px;font-family:var(--nd-mono)}' +
201
- '.field input:focus-visible,.field select:focus-visible{outline:2px solid var(--nd-accent);outline-offset:1px}' +
202
- '.tool__actions{display:flex;gap:8px;margin-top:12px;justify-content:flex-end}' +
203
- '.btn{background:var(--nd-raised);color:var(--nd-text);border:1px solid var(--nd-border-strong);border-radius:var(--nd-r-sm);padding:7px 14px;font-size:13px;font-weight:500;cursor:pointer;transition:filter .15s ease}' +
204
- '.btn:hover{filter:brightness(1.15)}' +
205
- '.btn--run{background:var(--nd-accent);border-color:transparent;color:#1c0a00;font-weight:600;box-shadow:0 6px 18px color-mix(in oklab,var(--nd-accent) 35%,transparent)}' +
206
- '.btn:disabled{opacity:.55;cursor:default;box-shadow:none;filter:none}' +
207
- // Polished preview toolbar: one rounded bar, micro-labels, custom-caret selects, icon buttons.
208
- '.controls{display:flex;gap:10px;align-items:center;flex-wrap:wrap;margin-bottom:14px;padding:7px 9px;background:var(--nd-panel);border:1px solid var(--nd-border);border-radius:12px}' +
209
- '.ctl{display:flex;align-items:center;gap:8px}' +
210
- '.ctl__lbl{font-size:10px;text-transform:uppercase;letter-spacing:.07em;color:var(--nd-faint);font-weight:600}' +
211
- '.ctl select{appearance:none;-webkit-appearance:none;background-color:var(--nd-bg);color:var(--nd-text);border:1px solid var(--nd-border-strong);' +
212
- 'border-radius:8px;padding:6px 26px 6px 10px;font-size:12.5px;font-family:inherit;cursor:pointer;background-repeat:no-repeat;background-position:right 8px center;background-size:11px;' +
213
- 'background-image:url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2012%2012%22%20fill%3D%22none%22%20stroke%3D%22%23a8a29e%22%20stroke-width%3D%221.6%22%20stroke-linecap%3D%22round%22%3E%3Cpath%20d%3D%22M3%204.5%206%207.5%209%204.5%22%2F%3E%3C%2Fsvg%3E")}' +
214
- '.ctl select:hover{border-color:var(--nd-faint)}.ctl select:focus-visible{outline:2px solid var(--nd-accent);outline-offset:1px}' +
215
- '.ctl--width{gap:10px}.ctl input[type=range]{accent-color:var(--nd-accent);width:118px;height:4px;cursor:pointer}' +
216
- '.ctl__val{font-family:var(--nd-mono);font-size:11.5px;color:var(--nd-muted);min-width:46px}' +
217
- '.ctl__spacer{margin-left:auto}' +
218
- '.ctl-btn{display:inline-flex;align-items:center;gap:6px;background:var(--nd-bg);color:var(--nd-text);border:1px solid var(--nd-border-strong);' +
219
- 'border-radius:8px;padding:6px 12px;font-size:12.5px;font-weight:500;cursor:pointer;font-family:inherit;transition:filter .15s ease,border-color .15s ease}' +
220
- '.ctl-btn:hover{border-color:var(--nd-faint);filter:brightness(1.12)}.ctl-btn svg{width:14px;height:14px}' +
221
- // min-height:0 + overflow:hidden so the stage stays bounded and its inner scroller (chat log / result) scrolls
222
- // instead of the whole grid growing as tool cards accumulate.
223
- '.pane--stage{display:flex;flex-direction:column;padding:0;min-height:0;overflow:hidden}.pane--stage>div{padding:14px}' +
224
- '#preview-view{flex:1;min-height:0;flex-direction:column}' +
225
- '.hidden{display:none}' +
226
- '#frame{width:820px;max-width:100%;height:300px;border:0;background:var(--nd-bg);display:block;margin:0 auto;flex:none}' +
227
- // Fullscreen: the widget iframe fills the viewport; a floating exit control + Esc leave it.
228
- '.nd-frame-full{display:block!important;position:fixed!important;inset:0!important;width:100vw!important;height:100dvh!important;max-width:none!important;margin:0!important;z-index:60!important;background:var(--nd-bg)!important}' +
229
- '#fs-exit{position:fixed;top:16px;right:16px;z-index:61;display:inline-flex;align-items:center;gap:6px;background:var(--nd-panel);color:var(--nd-text);' +
230
- 'border:1px solid var(--nd-border-strong);border-radius:8px;padding:8px 13px;font-size:12.5px;font-weight:500;cursor:pointer;font-family:var(--nd-font);box-shadow:0 10px 30px rgba(0,0,0,.45)}' +
231
- '#fs-exit:hover{filter:brightness(1.12)}' +
232
- '.empty-state{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12px;color:var(--nd-muted);text-align:center;padding:24px}' +
233
- '.empty-state svg{width:48px;height:48px;color:var(--nd-accent);opacity:.55}' +
234
- '.empty-state p{margin:0;font-size:15px;font-weight:600;color:var(--nd-text)}' +
235
- '.empty-state span{font-size:12.5px;max-width:300px;line-height:1.5}' +
236
- '#result{flex:1;min-height:0;overflow:auto}' +
237
- '.result__label{font-size:10px;text-transform:uppercase;letter-spacing:.08em;color:var(--nd-faint);margin:0 0 6px}' +
238
- '#result pre{margin:0;background:var(--nd-panel);border:1px solid var(--nd-border);border-radius:var(--nd-r);padding:12px;' +
239
- 'font-family:var(--nd-mono);font-size:12.5px;white-space:pre-wrap;word-break:break-word;color:var(--nd-text)}' +
240
- '#log-list{list-style:none;margin:0;padding:0;font-size:12px}' +
241
- '.log{border-bottom:1px solid var(--nd-border)}' +
242
- '.log__head{display:flex;gap:8px;align-items:baseline;padding:7px 4px;cursor:pointer}' +
243
- '.log__head:hover{background:var(--nd-panel)}' +
244
- '.log .m{font-weight:600;font-family:var(--nd-mono);font-size:11.5px}.log .ok{color:var(--nd-ok)}.log .error{color:var(--nd-rose)}' +
245
- '.log__sum{color:var(--nd-muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}' +
246
- '.log .d{margin-left:auto;color:var(--nd-faint)}' +
247
- '.log__detail{display:none;padding:4px 6px 10px}.log.open .log__detail{display:block}' +
248
- '.log__label{font-size:10px;text-transform:uppercase;letter-spacing:.08em;color:var(--nd-faint);margin:6px 0 3px}' +
249
- '.log__detail pre{margin:0;background:var(--nd-bg);border:1px solid var(--nd-border);border-radius:var(--nd-r-sm);padding:8px;' +
250
- 'font-family:var(--nd-mono);font-size:11.5px;white-space:pre-wrap;word-break:break-word;max-height:280px;overflow:auto;color:var(--nd-text)}' +
251
- // Chat playground.
252
- '#chat-view{flex:1;min-height:0;flex-direction:column}' +
253
- '#chat-body{flex:1;min-height:0;flex-direction:column;gap:12px}' +
254
- '.chat-gate{flex:1;min-height:0;display:flex;align-items:center;justify-content:center;padding:24px}' +
255
- '.chat-gate__card{max-width:390px;width:100%;text-align:center;display:flex;flex-direction:column;align-items:center;gap:10px}' +
256
- '.chat-gate__card svg{width:38px;height:38px;color:var(--nd-accent);opacity:.75}' +
257
- '.chat-gate__card h3{margin:0;font-size:16px;font-weight:650;letter-spacing:-.01em}' +
258
- '.chat-gate__card p{margin:0;font-size:12.5px;color:var(--nd-muted);line-height:1.55}' +
259
- '#chat-key-form{display:flex;gap:8px;width:100%;margin-top:6px}' +
260
- '#chat-key-input{flex:1;background:var(--nd-bg);color:var(--nd-text);border:1px solid var(--nd-border-strong);' +
261
- 'border-radius:var(--nd-r-sm);padding:9px 11px;font-size:13px;font-family:var(--nd-mono)}' +
262
- '#chat-key-input:focus-visible{outline:2px solid var(--nd-accent);outline-offset:1px}' +
263
- '.chat-gate__hint{font-size:11.5px;color:var(--nd-faint);line-height:1.5}' +
264
- '.chat-gate__hint code{font-family:var(--nd-mono);color:var(--nd-muted)}' +
265
- '.chat-gate__hint.err{color:var(--nd-rose)}' +
266
- '#chat-keybar{display:none;justify-content:flex-end;flex:none}#chat-keybar.on{display:flex}' +
267
- '#chat-reset{background:transparent;border:0;color:var(--nd-muted);font-size:11.5px;cursor:pointer;text-decoration:underline;font-family:inherit;padding:0}' +
268
- '#chat-reset:hover{color:var(--nd-text)}' +
269
- '#chat-log{flex:1;min-height:0;overflow-y:auto;display:flex;flex-direction:column;gap:14px}' +
270
- // Critical: children must not flex-shrink, else they compress to fit (no scroll, squished/cut-off cards)
271
- // instead of overflowing the log. flex:none = keep natural height; the log scrolls.
272
- '#chat-log>*{flex:0 0 auto}' +
273
- // User message: a rounded bubble. Assistant: plain text + inline widget, no bubble.
274
- '.msg{max-width:84%;line-height:1.55;white-space:pre-wrap;word-break:break-word}' +
275
- '.msg--user{align-self:flex-end;background:var(--nd-accent);color:#1c0a00;font-weight:500;padding:10px 15px;border-radius:18px;font-size:13.5px}' +
276
- '.msg--assistant{align-self:stretch;max-width:100%;color:var(--nd-text);font-size:14px;padding:2px 1px}' +
277
- '.msg--error{align-self:flex-start;background:color-mix(in oklab,var(--nd-rose) 14%,transparent);border:1px solid color-mix(in oklab,var(--nd-rose) 40%,transparent);color:var(--nd-text);padding:10px 14px;border-radius:14px;font-size:13.5px}' +
278
- '.msg--pending{align-self:flex-start;color:var(--nd-muted);font-style:italic;font-size:13.5px;padding:2px 1px}' +
279
- // Tool call: a minimal, collapsed-by-default card, separate from the widget.
280
- '.toolcall{align-self:stretch;border:1px solid var(--nd-border);border-radius:12px;background:color-mix(in oklab,var(--nd-panel) 55%,transparent);overflow:hidden}' +
281
- '.toolcall__head{display:flex;align-items:center;gap:8px;padding:9px 12px;cursor:pointer;font-size:12.5px}' +
282
- '.toolcall__head:hover{background:color-mix(in oklab,var(--nd-panel) 80%,transparent)}' +
283
- '.toolcall__ico{color:var(--nd-faint);display:flex;align-items:center}.toolcall__ico svg{width:14px;height:14px}' +
284
- '.toolcall__name{font-family:var(--nd-mono);font-weight:600;font-size:12.5px;color:var(--nd-text)}' +
285
- '.toolcall__name.error{color:var(--nd-rose)}' +
286
- '.toolcall__chev{margin-left:auto;color:var(--nd-faint);font-size:11px}' +
287
- '.toolcall__detail{display:none;padding:0 12px 12px}.toolcall.open .toolcall__detail{display:block}' +
288
- '.toolcall__detail .log__label{margin:10px 0 4px}.toolcall__detail .log__label:first-child{margin-top:2px}' +
289
- // No inner scroll: the JSON renders full-height and the chat log is the single scroll surface.
290
- '.toolcall__detail pre{margin:0;background:var(--nd-bg);border:1px solid var(--nd-border);border-radius:8px;padding:8px;' +
291
- 'font-family:var(--nd-mono);font-size:11.5px;white-space:pre-wrap;word-break:break-word;overflow-x:auto;color:var(--nd-text)}' +
292
- // Widget: inline in the conversation, no wrapping container. A shimmer skeleton covers it while it mounts.
293
- '.chat-widget{align-self:stretch;margin:2px 0;position:relative;min-height:160px}' +
294
- '.chat-widget iframe{width:100%;border:0;background:var(--nd-bg);display:block;min-height:120px}' +
295
- '.chat-skeleton{position:absolute;inset:0;border-radius:12px;background:var(--nd-panel);border:1px solid var(--nd-border);overflow:hidden}' +
296
- '.chat-skeleton::after{content:"";position:absolute;inset:0;transform:translateX(-100%);animation:nd-shimmer 1.4s ease-in-out infinite;' +
297
- 'background:linear-gradient(90deg,transparent,color-mix(in oklab,var(--nd-raised) 70%,transparent),transparent)}' +
298
- '@keyframes nd-shimmer{100%{transform:translateX(100%)}}' +
299
- '@media (prefers-reduced-motion: reduce){.chat-skeleton::after{animation:none}}' +
300
- '.chat-form{display:flex;gap:8px;align-items:flex-end;border-top:1px solid var(--nd-border);padding-top:12px;flex:none}' +
301
- '#chat-input{flex:1;resize:none;max-height:160px;background:var(--nd-bg);color:var(--nd-text);border:1px solid var(--nd-border-strong);' +
302
- 'border-radius:var(--nd-r-sm);padding:9px 11px;font-size:13.5px;font-family:var(--nd-font);line-height:1.5}' +
303
- '#chat-input:focus-visible{outline:2px solid var(--nd-accent);outline-offset:1px}' +
304
- '#chat-send:disabled{opacity:.55;cursor:default;box-shadow:none;filter:none}';
305
201
  // Plain ES5-ish client (no template literals / no ${...}) — spliced into the harness verbatim.
306
202
  const HARNESS_CLIENT_JS = [
203
+ calculateRangeProgress.toString(),
307
204
  'var frame=document.getElementById("frame");',
308
205
  'var empty=document.getElementById("empty");',
309
- 'var themeSel=document.getElementById("theme");',
310
- 'var deviceSel=document.getElementById("device");',
206
+ 'var themeToggle=document.getElementById("theme-toggle");',
207
+ 'var deviceButtons=document.querySelectorAll("[data-device]");',
311
208
  'var widthInput=document.getElementById("width");',
312
209
  'var widthVal=document.getElementById("width-val");',
313
210
  'var current=null; var currentArgs={};',
314
- 'var resultBox=document.getElementById("result"); var resultPre=document.getElementById("result-pre"); var controlsBar=document.getElementById("controls");',
315
- 'themeSel.value="__INITIAL_THEME__"; deviceSel.value="__INITIAL_DEVICE__";',
211
+ 'var resultBox=document.getElementById("result"); var resultPre=document.getElementById("result-pre"); var copyResult=document.getElementById("copy-result"); var copyStatus=document.getElementById("copy-status"); var controlsBar=document.getElementById("controls"); var currentResultSource="";',
212
+ 'var toolsToggle=document.getElementById("toggle-tools"); var activityToggle=document.getElementById("toggle-activity"); var railScrim=document.getElementById("rail-scrim");',
213
+ 'function setRail(name,open){ var isTools=name==="tools"; document.body.classList.toggle(isTools?"tools-open":"activity-open",open); (isTools?toolsToggle:activityToggle).setAttribute("aria-expanded",open?"true":"false"); }',
214
+ 'function closeRails(){ setRail("tools",false); setRail("activity",false); }',
215
+ 'toolsToggle.addEventListener("click",function(){ var open=!document.body.classList.contains("tools-open"); closeRails(); setRail("tools",open); });',
216
+ 'activityToggle.addEventListener("click",function(){ var open=!document.body.classList.contains("activity-open"); closeRails(); setRail("activity",open); });',
217
+ 'document.getElementById("close-tools").addEventListener("click",function(){ setRail("tools",false); });',
218
+ 'document.getElementById("close-activity").addEventListener("click",function(){ setRail("activity",false); });',
219
+ 'railScrim.addEventListener("click",closeRails);',
220
+ 'window.addEventListener("resize",function(){ if(window.innerWidth>=1180) closeRails(); });',
221
+ 'document.addEventListener("keydown",function(e){ if(e.key==="Escape") closeRails(); });',
222
+ 'var currentTheme="__INITIAL_THEME__"; var currentDevice="__INITIAL_DEVICE__";',
316
223
  'function rpc(method,params){ return fetch("/rpc",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({jsonrpc:"2.0",id:Date.now(),method:method,params:params||{}})}).then(function(r){return r.json();}); }',
317
- 'function applyTheme(){ try{ var w=frame.contentWindow; if(w&&w.openai){ w.openai.theme=themeSel.value; w.dispatchEvent(new Event("openai:set_globals")); } }catch(e){} }',
224
+ 'function syncThemeControl(){ var dark=currentTheme==="dark"; themeToggle.setAttribute("aria-pressed",dark?"true":"false"); themeToggle.setAttribute("aria-label",dark?"Switch to light theme":"Switch to dark theme"); themeToggle.dataset.theme=currentTheme; }',
225
+ 'function applyTheme(){ syncThemeControl(); try{ var w=frame.contentWindow; if(w&&w.openai){ w.openai.theme=currentTheme; w.dispatchEvent(new Event("openai:set_globals")); } }catch(e){} }',
318
226
  'function fitFrame(){ if(frame.classList.contains("nd-frame-full")) return; try{ var d=frame.contentDocument; if(d&&d.documentElement){ frame.style.height=Math.max(120, d.documentElement.scrollHeight)+"px"; } }catch(e){} }',
319
- 'function clearBg(){ try{ var d=frame.contentDocument; if(d){ if(d.documentElement) d.documentElement.style.setProperty("background","#0c0a09","important"); if(d.body) d.body.style.setProperty("background","#0c0a09","important"); } }catch(e){} }',
320
- 'function applyDevice(){ widthInput.value = deviceSel.value==="mobile"?390:820; syncWidth(); }',
321
- 'function syncWidth(){ frame.style.width=widthInput.value+"px"; widthVal.textContent=widthInput.value+"px"; }',
227
+ 'function clearBg(){ try{ var d=frame.contentDocument; if(d){ if(d.documentElement) d.documentElement.style.setProperty("background","#000000","important"); if(d.body) d.body.style.setProperty("background","#000000","important"); } }catch(e){} }',
228
+ 'function syncDeviceControl(){ for(var i=0;i<deviceButtons.length;i++){ var active=deviceButtons[i].dataset.device===currentDevice; deviceButtons[i].classList.toggle("is-active",active); deviceButtons[i].setAttribute("aria-pressed",active?"true":"false"); } }',
229
+ 'function setDevice(device){ currentDevice=device; widthInput.value=device==="mobile"?390:820; syncDeviceControl(); syncWidth(); }',
230
+ 'function syncWidth(){ var progress=calculateRangeProgress(Number(widthInput.value),Number(widthInput.min),Number(widthInput.max)); widthInput.style.setProperty("--width-progress",progress+"%"); frame.style.width=widthInput.value+"px"; widthVal.textContent=widthInput.value+" px"; }',
322
231
  'function setState(s){ empty.style.display=s==="empty"?"flex":"none"; frame.style.display=s==="widget"?"block":"none"; resultBox.style.display=s==="result"?"block":"none"; controlsBar.style.display=s==="widget"?"flex":"none"; }',
323
232
  'function loadWidget(name,args){ current=name; currentArgs=args||{}; setState("widget"); var q="/widget?name="+encodeURIComponent(name); if(Object.keys(currentArgs).length) q+="&args="+encodeURIComponent(JSON.stringify(currentArgs)); frame.src=q; }',
324
- 'function showResult(v){ current=null; resultPre.textContent=(typeof v==="string")?v:JSON.stringify(v,null,2); setState("result"); }',
233
+ 'function legacyCopy(value){ var textarea=document.createElement("textarea"); textarea.value=value; textarea.setAttribute("readonly",""); textarea.style.position="fixed"; textarea.style.left="-9999px"; document.body.appendChild(textarea); textarea.select(); var copied=false; try{ copied=document.execCommand("copy"); }catch(e){} textarea.remove(); return copied?Promise.resolve():Promise.reject(new Error("copy failed")); }',
234
+ 'function copyText(value,trigger,label){ var operation=navigator.clipboard&&navigator.clipboard.writeText?navigator.clipboard.writeText(value).catch(function(){return legacyCopy(value);}):legacyCopy(value); return operation.then(function(){ var text=trigger.querySelector(".copy-action__label"); trigger.classList.add("is-copied"); if(text) text.textContent="Copied"; copyStatus.textContent="Copied "+label; setTimeout(function(){ trigger.classList.remove("is-copied"); if(text) text.textContent="Copy"; },1600); }).catch(function(){ copyStatus.textContent="Could not copy "+label; }); }',
235
+ 'copyResult.addEventListener("click",function(){ copyText(currentResultSource,copyResult,"response"); });',
236
+ 'function showResult(v){ current=null; currentResultSource=jsonSource(v); renderJson(resultPre,v); setState("result"); }',
325
237
  'frame.addEventListener("load", function(){ applyTheme(); clearBg(); fitFrame(); try{ var b=frame.contentDocument&&frame.contentDocument.body; if(b&&window.ResizeObserver){ new ResizeObserver(function(){ clearBg(); fitFrame(); }).observe(b); } }catch(e){} setTimeout(function(){ clearBg(); fitFrame(); },150); setTimeout(function(){ clearBg(); fitFrame(); },600); });',
326
- 'themeSel.addEventListener("change", applyTheme);',
327
- 'deviceSel.addEventListener("change", applyDevice);',
328
- 'widthInput.addEventListener("input", syncWidth);',
238
+ 'themeToggle.addEventListener("click", function(){ currentTheme=currentTheme==="dark"?"light":"dark"; applyTheme(); });',
239
+ 'for(var deviceIndex=0;deviceIndex<deviceButtons.length;deviceIndex++){ deviceButtons[deviceIndex].addEventListener("click",function(){ setDevice(this.dataset.device); }); }',
240
+ 'widthInput.addEventListener("input", function(){ currentDevice="custom"; syncDeviceControl(); syncWidth(); });',
329
241
  'document.getElementById("reload").addEventListener("click", function(){ if(current) loadWidget(current, currentArgs); });',
330
242
  // Fullscreen: works for the preview frame (toolbar button) and any chat widget (its requestDisplayMode).
331
243
  'var fsFrame=null; var fsExitBtn=null;',
@@ -340,50 +252,52 @@ const HARNESS_CLIENT_JS = [
340
252
  // Tool cards (expandable: description + schema fields + a single Run; widget tools render in the preview).
341
253
  'function makeControl(p){ if(Array.isArray(p.enum)){ var s=document.createElement("select"); p.enum.forEach(function(v){ var o=document.createElement("option"); o.value=String(v); o.textContent=String(v); s.appendChild(o); }); return s; } if(p.type==="boolean"){ var c=document.createElement("input"); c.type="checkbox"; return c; } var i=document.createElement("input"); i.type=(p.type==="number"||p.type==="integer")?"number":"text"; if(p.default!==undefined&&p.type!=="object"&&p.type!=="array") i.value=String(p.default); return i; }',
342
254
  'function collect(props,controls){ var args={}; Object.keys(controls).forEach(function(k){ var p=props[k]||{}; var el=controls[k]; if(el.type==="checkbox"){ args[k]=el.checked; return; } var v=el.value; if(v==="") return; if(p.type==="number"||p.type==="integer"){ args[k]=Number(v); return; } if(p.type==="object"||p.type==="array"){ try{ args[k]=JSON.parse(v); }catch(e){ args[k]=v; } return; } args[k]=v; }); return args; }',
343
- 'function buildDetail(detail,t,hasWidget){ if(t.description){ var d=document.createElement("p"); d.className="tool__desc"; d.textContent=t.description; detail.appendChild(d); } var schema=t.inputSchema||{}; var props=schema.properties||{}; var req=schema.required||[]; var controls={}; Object.keys(props).forEach(function(k){ var p=props[k]||{}; var f=document.createElement("div"); f.className="field"; var lab=document.createElement("label"); lab.textContent=k+(req.indexOf(k)>=0?" *":"")+(p.type?" ("+p.type+")":""); var ctrl=makeControl(p); f.appendChild(lab); f.appendChild(ctrl); if(p.description){ var h=document.createElement("div"); h.className="field__hint"; h.textContent=p.description; f.appendChild(h); } controls[k]=ctrl; detail.appendChild(f); }); var actions=document.createElement("div"); actions.className="tool__actions"; var run=document.createElement("button"); run.className="btn btn--run"; run.textContent="Run"; run.addEventListener("click", function(){ if(hasWidget){ loadWidget(t.name, collect(props,controls)); return; } var args=collect(props,controls); run.disabled=true; var o=run.textContent; run.textContent="Running…"; rpc("tools/call",{name:t.name,arguments:args}).then(function(j){ showResult(j&&j.result!==undefined?j.result:(j&&j.error!==undefined?j.error:j)); }).catch(function(){}).then(function(){ run.disabled=false; run.textContent=o; }); }); actions.appendChild(run); detail.appendChild(actions); }',
344
- 'function renderTools(tools){ var ul=document.getElementById("tool-list"); ul.innerHTML=""; tools.forEach(function(t){ var li=document.createElement("li"); li.className="tool"; var head=document.createElement("div"); head.className="tool__head"; var nm=document.createElement("span"); nm.className="tool__name"; nm.textContent=t.name; head.appendChild(nm); var hasWidget=t._meta&&t._meta.ui&&t._meta.ui.resourceUri; if(hasWidget){ var b=document.createElement("span"); b.className="tag"; b.textContent="widget"; head.appendChild(b); } var chev=document.createElement("span"); chev.className="chev"; chev.textContent="▸"; head.appendChild(chev); var detail=document.createElement("div"); detail.className="tool__detail"; head.addEventListener("click", function(){ var open=li.classList.toggle("open"); chev.textContent=open?"▾":"▸"; if(open&&!detail.dataset.built){ buildDetail(detail,t,hasWidget); detail.dataset.built="1"; } }); li.appendChild(head); li.appendChild(detail); ul.appendChild(li); }); }',
255
+ 'function buildDetail(detail,t,hasWidget){ if(t.description){ var d=document.createElement("p"); d.className="tool__desc"; d.textContent=t.description; detail.appendChild(d); } var schema=t.inputSchema||{}; var props=schema.properties||{}; var req=schema.required||[]; var controls={}; Object.keys(props).forEach(function(k){ var p=props[k]||{}; var f=document.createElement("div"); f.className="field"; var lab=document.createElement("label"); lab.textContent=k+(req.indexOf(k)>=0?" *":"")+(p.type?" ("+p.type+")":""); var ctrl=makeControl(p); f.appendChild(lab); f.appendChild(ctrl); if(p.description){ var h=document.createElement("div"); h.className="field__hint"; h.textContent=p.description; f.appendChild(h); } controls[k]=ctrl; detail.appendChild(f); }); var actions=document.createElement("div"); actions.className="tool__actions"; var run=document.createElement("button"); run.className="btn primary-action"; run.textContent="Run"; run.addEventListener("click", function(){ if(hasWidget){ loadWidget(t.name, collect(props,controls)); return; } var args=collect(props,controls); run.disabled=true; var o=run.textContent; run.textContent="Running…"; rpc("tools/call",{name:t.name,arguments:args}).then(function(j){ showResult(j&&j.result!==undefined?j.result:(j&&j.error!==undefined?j.error:j)); }).catch(function(){}).then(function(){ run.disabled=false; run.textContent=o; }); }); actions.appendChild(run); detail.appendChild(actions); }',
256
+ 'function renderTools(tools){ var ul=document.getElementById("tool-list"); ul.innerHTML=""; tools.forEach(function(t){ var li=document.createElement("li"); li.className="tool"; var head=document.createElement("button"); head.type="button"; head.className="tool__head"; head.setAttribute("aria-expanded","false"); var nm=document.createElement("span"); nm.className="tool__name"; nm.textContent=t.name; head.appendChild(nm); var hasWidget=t._meta&&t._meta.ui&&t._meta.ui.resourceUri; if(hasWidget){ var b=document.createElement("span"); b.className="tag"; b.textContent="widget"; head.appendChild(b); } var chev=document.createElement("span"); chev.className="chev"; chev.textContent="▸"; head.appendChild(chev); var detail=document.createElement("div"); detail.className="tool__detail"; head.addEventListener("click", function(){ var open=li.classList.toggle("open"); head.setAttribute("aria-expanded",open?"true":"false"); chev.textContent=open?"▾":"▸"; if(open&&!detail.dataset.built){ buildDetail(detail,t,hasWidget); detail.dataset.built="1"; } }); li.appendChild(head); li.appendChild(detail); ul.appendChild(li); }); }',
345
257
  'function refreshTools(){ return rpc("tools/list",{}).then(function(j){ renderTools((j.result&&j.result.tools)||[]); }); }',
346
258
  'refreshTools();',
347
259
  // MCP call log (expandable: input + output JSON).
348
- 'function section(label,value){ var w=document.createElement("div"); var h=document.createElement("div"); h.className="log__label"; h.textContent=label; var pre=document.createElement("pre"); pre.textContent=(typeof value==="string")?value:JSON.stringify(value,null,2); w.appendChild(h); w.appendChild(pre); return w; }',
349
- 'function addLog(e){ var ol=document.getElementById("log-list"); var li=document.createElement("li"); li.className="log"; var head=document.createElement("div"); head.className="log__head"; var has=(e.request!==undefined||e.response!==undefined); var chev=document.createElement("span"); chev.className="chev"; chev.textContent=has?"▸":""; var m=document.createElement("span"); m.className="m "+e.status; m.textContent=e.method; var n=document.createElement("span"); n.className="log__sum"; n.textContent=(e.name?e.name+" ":"")+e.summary; var d=document.createElement("span"); d.className="d"; d.textContent=e.durationMs+"ms"; head.appendChild(chev); head.appendChild(m); head.appendChild(n); head.appendChild(d); var detail=document.createElement("div"); detail.className="log__detail"; if(has){ head.addEventListener("click", function(){ var open=li.classList.toggle("open"); chev.textContent=open?"▾":"▸"; if(open&&!detail.dataset.built){ if(e.request!==undefined) detail.appendChild(section("input",e.request)); if(e.response!==undefined) detail.appendChild(section("output",e.response)); detail.dataset.built="1"; } }); } li.appendChild(head); li.appendChild(detail); ol.insertBefore(li, ol.firstChild); }',
260
+ 'function section(label,value){ var w=document.createElement("div"); var h=document.createElement("div"); h.className="log__label"; h.textContent=label; var pre=document.createElement("pre"); renderJson(pre,value); w.appendChild(h); w.appendChild(pre); return w; }',
261
+ 'function addLog(e){ var ol=document.getElementById("log-list"); var li=document.createElement("li"); li.className="log log--"+(e.status==="error"?"error":"ok"); var has=(e.request!==undefined||e.response!==undefined); var head=document.createElement(has?"button":"div"); if(has){ head.type="button"; head.setAttribute("aria-expanded","false"); } head.className="log__head"; var chev=document.createElement("span"); chev.className="chev"; chev.textContent=has?"▸":""; var m=document.createElement("span"); m.className="m "+e.status; m.textContent=e.method; var n=document.createElement("span"); n.className="log__sum"; n.textContent=(e.name?e.name+" ":"")+e.summary; var d=document.createElement("span"); d.className="d"; d.textContent=e.durationMs+"ms"; head.appendChild(chev); head.appendChild(m); head.appendChild(n); head.appendChild(d); var detail=document.createElement("div"); detail.className="log__detail"; if(has){ head.addEventListener("click", function(){ var open=li.classList.toggle("open"); head.setAttribute("aria-expanded",open?"true":"false"); chev.textContent=open?"▾":"▸"; if(open&&!detail.dataset.built){ if(e.request!==undefined) detail.appendChild(section("input",e.request)); if(e.response!==undefined) detail.appendChild(section("output",e.response)); detail.dataset.built="1"; } }); } li.appendChild(head); li.appendChild(detail); ol.insertBefore(li, ol.firstChild); }',
350
262
  'try{ var es=new EventSource("/rpc/log"); es.onmessage=function(ev){ try{ addLog(JSON.parse(ev.data)); }catch(e){} }; }catch(e){}',
351
263
  'try{ var rs=new EventSource("/reload"); rs.onmessage=function(){ refreshTools(); if(current) loadWidget(current, currentArgs); }; }catch(e){}',
352
- // Preview | Chat mode toggle.
353
- 'var previewView=document.getElementById("preview-view"); var chatView=document.getElementById("chat-view");',
354
- 'var modePreview=document.getElementById("mode-preview"); var modeChat=document.getElementById("mode-chat");',
355
- 'function setMode(m){ var p=m!=="chat"; modePreview.classList.toggle("is-active",p); modeChat.classList.toggle("is-active",!p); previewView.style.display=p?"flex":"none"; chatView.style.display=p?"none":"flex"; if(!p) enterChat(); }',
264
+ // Preview | Chat | Design mode toggle.
265
+ 'var previewView=document.getElementById("preview-view"); var chatView=document.getElementById("chat-view"); var designView=document.getElementById("design-view");',
266
+ 'var modePreview=document.getElementById("mode-preview"); var modeChat=document.getElementById("mode-chat"); var modeDesign=document.getElementById("mode-design");',
267
+ 'function setMode(m){ var p=m==="preview"; var c=m==="chat"; var d=m==="design"; modePreview.classList.toggle("is-active",p); modeChat.classList.toggle("is-active",c); modeDesign.classList.toggle("is-active",d); modePreview.setAttribute("aria-selected",p?"true":"false"); modeChat.setAttribute("aria-selected",c?"true":"false"); modeDesign.setAttribute("aria-selected",d?"true":"false"); previewView.style.display=p?"flex":"none"; chatView.style.display=c?"flex":"none"; designView.style.display=d?"flex":"none"; if(c) enterChat(); }',
356
268
  'modePreview.addEventListener("click", function(){ setMode("preview"); });',
357
269
  'modeChat.addEventListener("click", function(){ setMode("chat"); });',
270
+ 'modeDesign.addEventListener("click", function(){ setMode("design"); });',
358
271
  // Chat playground: an agent turn posts the running message history to /chat and renders tool calls inline.
359
272
  'var chatMessages=[]; var chatBusy=false;',
360
273
  'var chatLog=document.getElementById("chat-log"); var chatForm=document.getElementById("chat-form"); var chatInput=document.getElementById("chat-input"); var chatSend=document.getElementById("chat-send"); var chatEmpty=document.getElementById("chat-empty");',
361
- // Key gate: the key lives ONLY in the loopback server (POST /chat/key), never in the browser same-origin
362
- // widget iframes could otherwise read it from localStorage/globals and exfiltrate it. The gate state comes
363
- // from GET /chat/status (a boolean + source), and the key is never sent back to the page.
364
- 'var chatGate=document.getElementById("chat-gate"); var chatBody=document.getElementById("chat-body"); var chatKeyForm=document.getElementById("chat-key-form"); var chatKeyInput=document.getElementById("chat-key-input"); var chatGateHint=document.getElementById("chat-gate-hint"); var chatKeybar=document.getElementById("chat-keybar"); var chatReset=document.getElementById("chat-reset");',
365
- 'var chatHasKey=__CHAT_HAS_KEY__; var chatKeySource=__CHAT_HAS_KEY__?"env":"none";',
366
- 'function refreshChatReady(cb){ fetch("/chat/status").then(function(r){return r.json();}).then(function(j){ chatHasKey=!!(j&&j.hasKey); chatKeySource=(j&&j.source)||"none"; if(cb) cb(); }).catch(function(){ if(cb) cb(); }); }',
367
- 'function renderGate(){ if(chatHasKey){ chatGate.style.display="none"; chatBody.style.display="flex"; chatKeybar.className=(chatKeySource==="session")?"on":""; chatInput.focus(); } else { chatBody.style.display="none"; chatGate.style.display="flex"; chatKeyInput.focus(); } }',
368
- 'function enterChat(){ renderGate(); refreshChatReady(renderGate); }',
274
+ // Key gate: credentials stay in the loopback server. The browser retains only the inferred provider id.
275
+ 'var chatGate=document.getElementById("chat-gate"); var chatBody=document.getElementById("chat-body"); var chatKeyForm=document.getElementById("chat-key-form"); var chatKeyInput=document.getElementById("chat-key-input"); var chatGateHint=document.getElementById("chat-gate-hint"); var chatKeybar=document.getElementById("chat-keybar"); var chatReset=document.getElementById("chat-reset"); var chatConnect=document.getElementById("chat-connect"); var chatModelLabel=document.getElementById("chat-model-label");',
276
+ 'var chatProvider="openai"; var chatProviders={}; var chatRequiresKey=false; var chatStatusMessage="";',
277
+ 'var providerInfo={openai:{label:"OpenAI"},anthropic:{label:"Claude"},gemini:{label:"Gemini"}};',
278
+ 'function activeProvider(){ if(chatRequiresKey) return {hasKey:false,source:"none",model:""}; return chatProviders[chatProvider]||{hasKey:false,source:"none",model:""}; }',
279
+ 'function paintKeyGate(){ var s=activeProvider(); chatKeyInput.placeholder=s.hasKey?"Paste a different API key":"Paste your API key"; chatConnect.textContent=s.hasKey?"Use connected key":"Start chatting"; chatGateHint.className="chat-gate__hint"+(chatRequiresKey?" err":""); chatGateHint.textContent=chatRequiresKey?chatStatusMessage:(s.hasKey?"A "+providerInfo[chatProvider].label+" key is connected. Paste another key to switch models.":"Your key stays in this local process."); }',
280
+ 'function refreshChatReady(cb){ fetch("/chat/status").then(function(r){return r.json();}).then(function(j){ chatProviders=(j&&j.providers)||{}; chatRequiresKey=Boolean(j&&j.requiresKey); chatStatusMessage=(j&&j.error&&j.error.message)||""; if(j&&j.activeProvider) chatProvider=j.activeProvider; paintKeyGate(); if(cb) cb(); }).catch(function(){ if(cb) cb(); }); }',
281
+ 'function renderGate(){ var s=activeProvider(); if(s.hasKey){ chatGate.style.display="none"; chatBody.style.display="flex"; chatKeybar.className="on"; chatModelLabel.textContent=providerInfo[chatProvider].label; chatInput.focus(); } else { chatBody.style.display="none"; chatGate.style.display="flex"; paintKeyGate(); chatKeyInput.focus(); } }',
282
+ 'function enterChat(){ refreshChatReady(renderGate); }',
369
283
  'function showKeyError(msg){ chatGateHint.textContent=msg; chatGateHint.className="chat-gate__hint err"; chatBody.style.display="none"; chatGate.style.display="flex"; chatKeyInput.focus(); }',
370
- 'chatKeyForm.addEventListener("submit", function(e){ e.preventDefault(); var v=chatKeyInput.value.trim(); if(!v) return; fetch("/chat/key",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({key:v})}).then(function(r){return r.json();}).then(function(j){ chatKeyInput.value=""; if(j&&j.ok){ chatHasKey=!!j.hasKey; chatKeySource=j.source||"session"; chatGateHint.className="chat-gate__hint"; chatGateHint.innerHTML="Prefer a file? Set <code>OPENAI_API_KEY</code> in your shell or a <code>.env.local</code>."; renderGate(); } else { showKeyError("Could not set the key. Try again."); } }).catch(function(){ showKeyError("Could not reach the devtools server."); }); });',
371
- 'chatReset.addEventListener("click", function(){ fetch("/chat/key",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({key:""})}).then(function(r){return r.json();}).then(function(j){ chatHasKey=!!(j&&j.hasKey); chatKeySource=(j&&j.source)||"none"; renderGate(); }).catch(function(){ enterChat(); }); });',
284
+ 'chatKeyForm.addEventListener("submit", function(e){ e.preventDefault(); var key=chatKeyInput.value.trim(); var s=activeProvider(); if(!key&&!s.hasKey) return; var payload=key?{key:key}:{provider:chatProvider}; fetch("/chat/key",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(payload)}).then(function(r){return r.json();}).then(function(j){ chatKeyInput.value=""; if(j&&j.ok){ var nextProvider=j.provider||chatProvider; if(nextProvider!==chatProvider) chatMessages=[]; chatProvider=nextProvider; chatRequiresKey=false; chatStatusMessage=""; chatProviders[chatProvider]=j; renderGate(); } else { showKeyError((j&&j.error&&j.error.message)||"Could not connect this key. Check it and try again."); } }).catch(function(){ showKeyError("Could not reach the devtools server."); }); });',
285
+ 'chatReset.addEventListener("click", function(){ chatBody.style.display="none"; chatGate.style.display="flex"; paintKeyGate(); chatKeyInput.focus(); });',
372
286
  'function scrollChat(){ chatLog.scrollTop=chatLog.scrollHeight; }',
373
287
  'function clearChatEmpty(){ if(chatEmpty){ chatEmpty.remove(); chatEmpty=null; } }',
374
288
  'function chatBubble(cls,text){ clearChatEmpty(); var d=document.createElement("div"); d.className="msg "+cls; d.textContent=text; chatLog.appendChild(d); scrollChat(); return d; }',
375
289
  'function fitChatFrame(f){ if(f.classList.contains("nd-frame-full")) return; try{ var d=f.contentDocument; if(d&&d.documentElement){ var h=Math.max(d.documentElement.scrollHeight, d.body?d.body.scrollHeight:0); f.style.height=Math.max(120,h)+"px"; } }catch(e){} }',
376
290
  // The widget mounts async, so fit on load, keep fitting via ResizeObserver, and retry a couple of times.
377
- 'function wireChatFrame(f, onReady){ f.addEventListener("load", function(){ try{ var d=f.contentDocument; if(d){ if(d.documentElement) d.documentElement.style.setProperty("background","#0c0a09","important"); if(d.body) d.body.style.setProperty("background","#0c0a09","important"); } }catch(e){} fitChatFrame(f); try{ var b=f.contentDocument&&f.contentDocument.body; if(b&&window.ResizeObserver){ new ResizeObserver(function(){ fitChatFrame(f); scrollChat(); }).observe(b); } }catch(e){} setTimeout(function(){ fitChatFrame(f); },150); setTimeout(function(){ fitChatFrame(f); if(onReady) onReady(); scrollChat(); },500); }); }',
291
+ 'function wireChatFrame(f, onReady){ f.addEventListener("load", function(){ try{ var d=f.contentDocument; if(d){ if(d.documentElement) d.documentElement.style.setProperty("background","#000000","important"); if(d.body) d.body.style.setProperty("background","#000000","important"); } }catch(e){} fitChatFrame(f); try{ var b=f.contentDocument&&f.contentDocument.body; if(b&&window.ResizeObserver){ new ResizeObserver(function(){ fitChatFrame(f); scrollChat(); }).observe(b); } }catch(e){} setTimeout(function(){ fitChatFrame(f); },150); setTimeout(function(){ fitChatFrame(f); if(onReady) onReady(); scrollChat(); },500); }); }',
378
292
  'var TOOL_ICO=\'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><circle cx="6" cy="6" r="2.3"/><circle cx="18" cy="6" r="2.3"/><circle cx="6" cy="18" r="2.3"/><circle cx="18" cy="18" r="2.3"/><path d="M8.3 6h7.4M6 8.3v7.4M18 8.3v7.4M8.3 18h7.4"/></svg>\';',
379
293
  // Tool call: a minimal card, collapsed by default; its I/O is separate from the widget below it.
380
- 'function renderToolCall(tc){ clearChatEmpty(); var card=document.createElement("div"); card.className="toolcall"; var head=document.createElement("div"); head.className="toolcall__head"; var ico=document.createElement("span"); ico.className="toolcall__ico"; ico.innerHTML=TOOL_ICO; var nm=document.createElement("span"); nm.className="toolcall__name"+(tc.isError?" error":""); nm.textContent=tc.name; head.appendChild(ico); head.appendChild(nm); if(tc.resourceUri){ var tag=document.createElement("span"); tag.className="tag"; tag.textContent="widget"; head.appendChild(tag); } var chev=document.createElement("span"); chev.className="toolcall__chev"; chev.textContent="▸"; head.appendChild(chev); var detail=document.createElement("div"); detail.className="toolcall__detail"; detail.appendChild(section("input",tc.arguments)); detail.appendChild(section("output",tc.result)); head.addEventListener("click", function(){ var open=card.classList.toggle("open"); chev.textContent=open?"▾":"▸"; if(open) setTimeout(function(){ try{ card.scrollIntoView({block:"nearest"}); }catch(e){} },0); }); card.appendChild(head); card.appendChild(detail); chatLog.appendChild(card); scrollChat(); }',
294
+ 'function renderToolCall(tc){ clearChatEmpty(); var card=document.createElement("div"); card.className="toolcall"; var head=document.createElement("button"); head.type="button"; head.className="toolcall__head"; head.setAttribute("aria-expanded","false"); var ico=document.createElement("span"); ico.className="toolcall__ico"; ico.innerHTML=TOOL_ICO; var nm=document.createElement("span"); nm.className="toolcall__name"+(tc.isError?" error":""); nm.textContent=tc.name; head.appendChild(ico); head.appendChild(nm); if(tc.resourceUri){ var tag=document.createElement("span"); tag.className="tag"; tag.textContent="widget"; head.appendChild(tag); } var chev=document.createElement("span"); chev.className="toolcall__chev"; chev.textContent="▸"; head.appendChild(chev); var detail=document.createElement("div"); detail.className="toolcall__detail"; detail.appendChild(section("input",tc.arguments)); detail.appendChild(section("output",tc.result)); head.addEventListener("click", function(){ var open=card.classList.toggle("open"); head.setAttribute("aria-expanded",open?"true":"false"); chev.textContent=open?"▾":"▸"; if(open) setTimeout(function(){ try{ card.scrollIntoView({block:"nearest"}); }catch(e){} },0); }); card.appendChild(head); card.appendChild(detail); chatLog.appendChild(card); scrollChat(); }',
381
295
  // Widget: rendered inline in the conversation, unboxed.
382
296
  'function renderWidget(tc){ if(!tc.resourceUri) return; clearChatEmpty(); var wrap=document.createElement("div"); wrap.className="chat-widget"; var sk=document.createElement("div"); sk.className="chat-skeleton"; wrap.appendChild(sk); var f=document.createElement("iframe"); f.title="widget"; wireChatFrame(f, function(){ if(sk&&sk.parentNode) sk.remove(); }); var q="/widget?name="+encodeURIComponent(tc.name); if(tc.arguments&&Object.keys(tc.arguments).length) q+="&args="+encodeURIComponent(JSON.stringify(tc.arguments)); f.src=q; wrap.appendChild(f); chatLog.appendChild(wrap); scrollChat(); }',
383
- 'function sendChat(){ var text=chatInput.value.trim(); if(!text||chatBusy) return; chatBubble("msg--user",text); chatInput.value=""; chatInput.style.height="auto"; chatBusy=true; chatSend.disabled=true; var pending=chatBubble("msg--pending","Thinking"); var outgoing=chatMessages.concat([{role:"user",content:text}]); fetch("/chat",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({messages:outgoing})}).then(function(r){return r.json();}).then(function(j){ pending.remove(); if(j&&j.error){ if(j.error.code==="no_api_key"){ showKeyError("Add an OpenAI key to start chatting."); return; } chatBubble("msg--error","Chat failed: "+(j.error.message||"unknown error")); return; } chatMessages=(j&&j.messages)||outgoing; (j&&j.toolCalls||[]).forEach(function(tc){ renderToolCall(tc); renderWidget(tc); }); if(j&&j.text) chatBubble("msg--assistant",j.text); }).catch(function(e){ pending.remove(); chatBubble("msg--error","Chat failed: "+(e&&e.message||e)); }).then(function(){ chatBusy=false; chatSend.disabled=false; scrollChat(); }); }',
297
+ 'function sendChat(){ var text=chatInput.value.trim(); if(!text||chatBusy) return; chatBubble("msg--user",text); chatInput.value=""; chatInput.style.height="auto"; chatBusy=true; chatSend.disabled=true; var pending=chatBubble("msg--pending","Thinking..."); var outgoing=chatMessages.concat([{role:"user",content:text}]); fetch("/chat",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({provider:chatProvider,messages:outgoing})}).then(function(r){return r.json();}).then(function(j){ pending.remove(); if(j&&j.error){ if(j.error.code==="no_api_key"||j.error.code==="ambiguous_provider"){ showKeyError(j.error.message||"Connect an API key to start chatting."); return; } chatBubble("msg--error","Chat failed: "+(j.error.message||"unknown error")); return; } chatMessages=(j&&j.messages)||outgoing; (j&&j.toolCalls||[]).forEach(function(tc){ renderToolCall(tc); renderWidget(tc); }); if(j&&j.text) chatBubble("msg--assistant",j.text); }).catch(function(e){ pending.remove(); chatBubble("msg--error","Chat failed: "+(e&&e.message||e)); }).then(function(){ chatBusy=false; chatSend.disabled=false; scrollChat(); }); }',
384
298
  'chatForm.addEventListener("submit", function(e){ e.preventDefault(); sendChat(); });',
385
299
  'chatInput.addEventListener("keydown", function(e){ if(e.key==="Enter"&&!e.shiftKey){ e.preventDefault(); sendChat(); } });',
386
300
  'chatInput.addEventListener("input", function(){ chatInput.style.height="auto"; chatInput.style.height=Math.min(160, chatInput.scrollHeight)+"px"; });',
387
- 'setState("empty"); syncWidth(); setMode("preview");',
301
+ 'setState("empty"); applyTheme(); setDevice(currentDevice); setMode("preview");',
388
302
  ].join('\n');
389
303
  //# sourceMappingURL=devtools-harness.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"devtools-harness.js","sourceRoot":"","sources":["../src/devtools-harness.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"devtools-harness.js","sourceRoot":"","sources":["../src/devtools-harness.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EACL,yBAAyB,EACzB,sBAAsB,EACtB,iBAAiB,GAClB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAAE,uBAAuB,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AACnF,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AACrF,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAKvD,8FAA8F;AAC9F,MAAM,UAAU,sBAAsB,CAAC,KAAa,EAAE,GAAW,EAAE,GAAW;IAC5E,IAAI,CAAC,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,GAAG,IAAI,GAAG;QAAE,OAAO,CAAC,CAAC;IACtE,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,KAAK,GAAG,GAAG,CAAC,GAAG,CAAC,GAAG,GAAG,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;AACzE,CAAC;AAED;;;;GAIG;AACH,SAAS,aAAa,CAAC,KAAc;IACnC,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC;SACzB,UAAU,CAAC,GAAG,EAAE,SAAS,CAAC;SAC1B,UAAU,CAAC,GAAG,EAAE,SAAS,CAAC;SAC1B,UAAU,CAAC,GAAG,EAAE,SAAS,CAAC;SAC1B,UAAU,CAAC,QAAQ,EAAE,SAAS,CAAC;SAC/B,UAAU,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;AACrC,CAAC;AAED,wGAAwG;AACxG,MAAM,UAAU,gBAAgB,CAAC,IAMhC;IACC,MAAM,IAAI,GAAG;QACX,gBAAgB,EAAE,IAAI;QACtB,kBAAkB,EAAE,IAAI,CAAC,UAAU,IAAI,IAAI;QAC3C,SAAS,EAAE,IAAI,CAAC,SAAS,IAAI,EAAE;QAC/B,UAAU,EAAE,IAAI,CAAC,UAAU,IAAI,IAAI;QACnC,oBAAoB,EAAE,IAAI,CAAC,oBAAoB,IAAI,IAAI;QACvD,KAAK,EAAE,IAAI,CAAC,KAAK,IAAI,OAAO;KAC7B,CAAC;IACF,OAAO,CACL,UAAU;QACV,gCAAgC;QAChC,aAAa,CAAC,IAAI,CAAC;QACnB,KAAK;QACL,0DAA0D;QAC1D,oCAAoC;QACpC,2FAA2F;QAC3F,iFAAiF;QACjF,yDAAyD;QACzD,6CAA6C;QAC7C,mIAAmI;QACnI,KAAK;QACL,6FAA6F;QAC7F,4GAA4G;QAC5G,8OAA8O;QAC9O,gHAAgH;QAChH,iEAAiE;QACjE,KAAK;QACL,WAAW,CACZ,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,QAAQ,GAAG,SAAS,CAAC;AAC3B,MAAM,mBAAmB,GAAG,+BAA+B,QAAQ,wCAAwC,CAAC;AAE5G,+GAA+G;AAC/G,MAAM,UAAU,cAAc,CAAC,IAAY,EAAE,UAAkB;IAC7D,MAAM,MAAM,GAAG,mBAAmB,GAAG,UAAU,CAAC;IAChD,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;IACjC,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACxC,IAAI,OAAO,KAAK,CAAC,CAAC,EAAE,CAAC;QACnB,MAAM,EAAE,GAAG,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC;QACrC,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IACrD,CAAC;IACD,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IACvC,IAAI,OAAO,KAAK,CAAC,CAAC,EAAE,CAAC;QACnB,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;QACzC,IAAI,KAAK,KAAK,CAAC,CAAC;YAAE,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,GAAG,CAAC,CAAC,GAAG,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;IACrF,CAAC;IACD,OAAO,MAAM,GAAG,IAAI,CAAC;AACvB,CAAC;AAED,SAAS,UAAU,CAAC,KAAa;IAC/B,OAAO,KAAK,CAAC,UAAU,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC,UAAU,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,UAAU,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;AACxF,CAAC;AAED,oCAAoC;AACpC,MAAM,UAAU,WAAW,CAAC,OAI3B;IACC,MAAM,MAAM,GAAG,iBAAiB,CAAC,OAAO,CACtC,mBAAmB,EACnB,OAAO,CAAC,KAAK,KAAK,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAC5C,CAAC,OAAO,CAAC,oBAAoB,EAAE,OAAO,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IACpF,OAAO,CACL,6DAA6D;QAC7D,sEAAsE;QACtE,+CAA+C,yBAAyB,IAAI;QAC5E,4CAA4C;QAC5C,eAAe;QACf,oBAAoB;QACpB,uBAAuB;QACvB,qDAAqD;QACrD,yDAAyD;QACzD,sDAAsD;QACtD,mEAAmE;QACnE,yBAAyB;QACzB,gEAAgE;QAChE,+CAA+C;QAC/C,iBAAiB;QACjB,SAAS;QACT,qGAAqG;QACrG,sGAAsG;QACtG,kCAAkC;QAClC,4CAA4C;QAC5C,sBAAsB;QACtB,qJAAqJ;QACrJ,8DAA8D;QAC9D,+DAA+D;QAC/D,4FAA4F;QAC5F,4EAA4E;QAC5E,gMAAgM;QAChM,QAAQ;QACR,yCAAyC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC,SAAS;QAC3G,6JAA6J;QAC7J,4FAA4F;QAC5F,yBAAyB;QACzB,sCAAsC;QACtC,2KAA2K;QAC3K,uUAAuU;QACvU,uGAAuG;QACvG,gRAAgR;QAChR,6HAA6H;QAC7H,+UAA+U;QAC/U,sUAAsU;QACtU,gBAAgB;QAChB,uOAAuO;QACvO,mCAAmC;QACnC,0FAA0F;QAC1F,iQAAiQ;QACjQ,0EAA0E;QAC1E,oMAAoM;QACpM,QAAQ;QACR,sCAAsC;QACtC,+HAA+H;QAC/H,gGAAgG;QAChG,yBAAyB;QACzB,6FAA6F;QAC7F,QAAQ;QACR,oEAAoE;QACpE,oGAAoG;QACpG,wFAAwF;QACxF,sDAAsD;QACtD,mRAAmR;QACnR,wLAAwL;QACxL,8DAA8D;QAC9D,0GAA0G;QAC1G,QAAQ;QACR,qCAAqC;QACrC,6GAA6G;QAC7G,qEAAqE;QACrE,mCAAmC;QACnC,6EAA6E;QAC7E,oCAAoC;QACpC,2FAA2F,WAAW,SAAS;QAC/G,iGAAiG,WAAW,SAAS;QACrH,2FAA2F,WAAW,SAAS;QAC/G,aAAa;QACb,2BAA2B;QAC3B,8KAA8K;QAC9K,mGAAmG;QACnG,mHAAmH;QACnH,cAAc;QACd,qCAAqC;QACrC,0HAA0H;QAC1H,8DAA8D;QAC9D,+HAA+H;QAC/H,iFAAiF;QACjF,wBAAwB;QACxB,sGAAsG;QACtG,cAAc;QACd,yCAAyC;QACzC,2FAA2F;QAC3F,+EAA+E;QAC/E,SAAS;QACT,QAAQ;QACR,QAAQ;QACR,oBAAoB;QACpB,SAAS;QACT,gEAAgE;QAChE,0HAA0H;QAC1H,8HAA8H;QAC9H,4GAA4G;QAC5G,iCAAiC;QACjC,QAAQ;QACR,UAAU;QACV,uBAAuB;QACvB,IAAI;QACJ,MAAM;QACN,mBAAmB;QACnB,sBAAsB;QACtB,yBAAyB,CAC1B,CAAC;AACJ,CAAC;AAED,+FAA+F;AAC/F,MAAM,iBAAiB,GAAG;IACxB,sBAAsB,CAAC,QAAQ,EAAE;IACjC,6CAA6C;IAC7C,6CAA6C;IAC7C,0DAA0D;IAC1D,+DAA+D;IAC/D,kDAAkD;IAClD,oDAAoD;IACpD,uCAAuC;IACvC,sSAAsS;IACtS,8KAA8K;IAC9K,+NAA+N;IAC/N,6EAA6E;IAC7E,qJAAqJ;IACrJ,8JAA8J;IAC9J,yGAAyG;IACzG,+GAA+G;IAC/G,iDAAiD;IACjD,4FAA4F;IAC5F,yFAAyF;IACzF,+EAA+E;IAC/E,yOAAyO;IACzO,kQAAkQ;IAClQ,4LAA4L;IAC5L,+NAA+N;IAC/N,sPAAsP;IACtP,oQAAoQ;IACpQ,mIAAmI;IACnI,2RAA2R;IAC3R,oOAAoO;IACpO,yPAAyP;IACzP,yaAAya;IACza,4kBAA4kB;IAC5kB,0GAA0G;IAC1G,yHAAyH;IACzH,gXAAgX;IAChX,wHAAwH;IACxH,8KAA8K;IAC9K,gHAAgH;IAChH,2HAA2H;IAC3H,yGAAyG;IACzG,uCAAuC;IACvC,sEAAsE;IACtE,+KAA+K;IAC/K,sZAAsZ;IACtZ,0OAA0O;IAC1O,uGAAuG;IACvG,wJAAwJ;IACxJ,8OAA8O;IAC9O,4PAA4P;IAC5P,2GAA2G;IAC3G,0hBAA0hB;IAC1hB,2aAA2a;IAC3a,y6CAAy6C;IACz6C,qmCAAqmC;IACrmC,2HAA2H;IAC3H,iBAAiB;IACjB,kDAAkD;IAClD,yQAAyQ;IACzQ,m3CAAm3C;IACn3C,kIAAkI;IAClI,+IAA+I;IAC/I,uCAAuC;IACvC,oKAAoK;IACpK,oKAAoK;IACpK,shBAAshB;IACthB,2EAA2E;IAC3E,qEAAqE;IACrE,yEAAyE;IACzE,2GAA2G;IAC3G,0CAA0C;IAC1C,kQAAkQ;IAClQ,wGAAwG;IACxG,8fAA8f;IAC9f,uGAAuG;IACvG,gGAAgG;IAChG,2KAA2K;IAC3K,meAAme;IACne,4WAA4W;IAC5W,wVAAwV;IACxV,uDAAuD;IACvD,+LAA+L;IAC/L,4yBAA4yB;IAC5yB,yJAAyJ;IACzJ,kEAAkE;IAClE,mFAAmF;IACnF,qLAAqL;IACrL,wQAAwQ;IACxQ,yGAAyG;IACzG,knBAAknB;IAClnB,6UAA6U;IAC7U,iGAAiG;IACjG,2xCAA2xC;IAC3xC,wDAAwD;IACxD,qlBAAqlB;IACrlB,unCAAunC;IACvnC,sFAAsF;IACtF,4HAA4H;IAC5H,uJAAuJ;IACvJ,gFAAgF;CACjF,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC"}