sql-preview 0.6.1 → 0.6.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/Changelog.md CHANGED
@@ -2,6 +2,19 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [0.6.2] - 2026-06-03
6
+
7
+ ### Added
8
+
9
+ - Added a product strategy note on using SQL Preview's query wedge to accelerate toward a broader agentic query layer.
10
+ - Added the initial RFC-054 Zed MCP extension scaffold, local verification script, and setup guide.
11
+ - Added Zed marketplace readiness checks, CI, and publishing instructions for submitting the SQL Preview MCP extension to `zed-industries/extensions`.
12
+ - Added Snowflake Browser SSO profile support for VS Code by passing `EXTERNALBROWSER` auth options to the Snowflake driver without storing a Snowflake password.
13
+
14
+ ### Fixed
15
+
16
+ - Added Snowflake SDK optional-dependency handling so packaged VS Code installs surface guided installation advice instead of an unexplained missing-module failure.
17
+
5
18
  ## [0.6.1] - 2026-05-29
6
19
 
7
20
  ### Fixed
package/dist/mcp-app.html CHANGED
@@ -74186,6 +74186,29 @@ const DynamicForm = ({
74186
74186
  }),
74187
74187
  [initialData, schema.properties]
74188
74188
  );
74189
+ const isFieldVisible = (prop, data) => {
74190
+ var _a3;
74191
+ const visibleWhen = (_a3 = prop.ui) == null ? void 0 : _a3.visibleWhen;
74192
+ if (!visibleWhen) {
74193
+ return true;
74194
+ }
74195
+ const actual = data[visibleWhen.field];
74196
+ if ("equals" in visibleWhen) {
74197
+ return actual === visibleWhen.equals;
74198
+ }
74199
+ if ("notEquals" in visibleWhen) {
74200
+ return actual !== visibleWhen.notEquals;
74201
+ }
74202
+ if (Array.isArray(visibleWhen.in)) {
74203
+ return visibleWhen.in.includes(actual);
74204
+ }
74205
+ return true;
74206
+ };
74207
+ const visiblePropertyEntries = () => Object.entries(schema.properties || {}).filter(([, prop]) => isFieldVisible(prop, formData));
74208
+ const visibleFormData = () => {
74209
+ const visibleKeys = /* @__PURE__ */ new Set(["name", ...visiblePropertyEntries().map(([key]) => key)]);
74210
+ return Object.fromEntries(Object.entries(formData).filter(([key]) => visibleKeys.has(key)));
74211
+ };
74189
74212
  reactExports.useEffect(() => {
74190
74213
  if (lastResetKey.current === resetKey) {
74191
74214
  return;
@@ -74209,16 +74232,18 @@ const DynamicForm = ({
74209
74232
  };
74210
74233
  const handleSubmit = (e2) => {
74211
74234
  e2.preventDefault();
74212
- onSubmit(formData);
74235
+ onSubmit(visibleFormData());
74213
74236
  };
74214
74237
  const handleTest = () => {
74215
74238
  if (onTest) {
74216
- onTest(formData);
74239
+ onTest(visibleFormData());
74217
74240
  }
74218
74241
  };
74219
74242
  const fieldClass = (key, baseClass) => {
74243
+ var _a3, _b2;
74220
74244
  const normalizedKey = key.replace(/[^a-z0-9_-]/gi, "-").toLowerCase();
74221
- return `${baseClass} sp-conn-form-field sp-conn-form-field-${normalizedKey}`;
74245
+ const fullWidth = ((_b2 = (_a3 = schema.properties[key]) == null ? void 0 : _a3.ui) == null ? void 0 : _b2.fullWidth) ? " sp-conn-form-field-full" : "";
74246
+ return `${baseClass} sp-conn-form-field sp-conn-form-field-${normalizedKey}${fullWidth}`;
74222
74247
  };
74223
74248
  return /* @__PURE__ */ jsxRuntimeExports.jsxs("form", { onSubmit: handleSubmit, className: "sp-conn-form", role: "form", children: [
74224
74249
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "sp-conn-form-fields", children: [
@@ -74239,10 +74264,11 @@ const DynamicForm = ({
74239
74264
  }
74240
74265
  )
74241
74266
  ] }),
74242
- Object.entries(schema.properties || {}).map(([key, prop]) => {
74267
+ visiblePropertyEntries().map(([key, prop]) => {
74243
74268
  var _a3;
74244
74269
  const isRequired = (_a3 = schema.required) == null ? void 0 : _a3.includes(key);
74245
74270
  const value = formData[key];
74271
+ const fieldId = `form-${key}`;
74246
74272
  const field = (() => {
74247
74273
  var _a4;
74248
74274
  if (prop.type === "boolean") {
@@ -74251,7 +74277,7 @@ const DynamicForm = ({
74251
74277
  "input",
74252
74278
  {
74253
74279
  type: "checkbox",
74254
- id: `form-${key}`,
74280
+ id: fieldId,
74255
74281
  checked: !!value,
74256
74282
  onChange: (e2) => handleChange(key, e2.target.checked)
74257
74283
  }
@@ -74259,7 +74285,7 @@ const DynamicForm = ({
74259
74285
  /* @__PURE__ */ jsxRuntimeExports.jsx(
74260
74286
  "label",
74261
74287
  {
74262
- htmlFor: `form-${key}`,
74288
+ htmlFor: fieldId,
74263
74289
  className: "sp-conn-form-label",
74264
74290
  style: { marginBottom: 0 },
74265
74291
  children: prop.title || key
@@ -74269,14 +74295,28 @@ const DynamicForm = ({
74269
74295
  ] });
74270
74296
  }
74271
74297
  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: fieldClass(key, "sp-conn-form-group"), children: [
74272
- /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "sp-conn-form-label", children: [
74298
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { htmlFor: fieldId, className: "sp-conn-form-label", children: [
74273
74299
  prop.title || key,
74274
74300
  isRequired && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "required", children: "*" })
74275
74301
  ] }),
74276
74302
  prop.description && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "sp-conn-form-hint", children: prop.description }),
74277
- prop.type === "number" ? /* @__PURE__ */ jsxRuntimeExports.jsx(
74303
+ Array.isArray(prop.enum) ? /* @__PURE__ */ jsxRuntimeExports.jsx(
74304
+ "select",
74305
+ {
74306
+ id: fieldId,
74307
+ required: isRequired,
74308
+ className: "sp-conn-form-input",
74309
+ value: value || "",
74310
+ onChange: (e2) => handleChange(key, e2.target.value),
74311
+ children: prop.enum.map((option, index2) => {
74312
+ var _a5;
74313
+ return /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: option, children: ((_a5 = prop.enumNames) == null ? void 0 : _a5[index2]) ?? option }, option);
74314
+ })
74315
+ }
74316
+ ) : prop.type === "number" ? /* @__PURE__ */ jsxRuntimeExports.jsx(
74278
74317
  "input",
74279
74318
  {
74319
+ id: fieldId,
74280
74320
  type: "number",
74281
74321
  required: isRequired,
74282
74322
  className: "sp-conn-form-input",
@@ -74286,6 +74326,7 @@ const DynamicForm = ({
74286
74326
  ) : /* @__PURE__ */ jsxRuntimeExports.jsx(
74287
74327
  "input",
74288
74328
  {
74329
+ id: fieldId,
74289
74330
  type: ((_a4 = prop.ui) == null ? void 0 : _a4.widget) === "password" ? "password" : "text",
74290
74331
  required: isRequired,
74291
74332
  className: "sp-conn-form-input",
@@ -74340,12 +74381,20 @@ const DynamicForm = ({
74340
74381
  ] })
74341
74382
  ] });
74342
74383
  };
74343
- const DUCKDB_OPTIONAL_DEPENDENCY_ADVICE = {
74344
- dependency: "@duckdb/node-api",
74345
- installCommand: "npm install @duckdb/node-api",
74346
- title: "DUCKDB support is required",
74347
- guidance: "Local file queries require optional DuckDB support, but the DuckDB native module is not available in this extension runtime."
74348
- };
74384
+ const OPTIONAL_DEPENDENCY_ADVICE = [
74385
+ {
74386
+ dependency: "@duckdb/node-api",
74387
+ installCommand: "npm install @duckdb/node-api",
74388
+ title: "DUCKDB support is required",
74389
+ guidance: "Local file queries require optional DuckDB support, but the DuckDB native module is not available in this extension runtime."
74390
+ },
74391
+ {
74392
+ dependency: "snowflake-sdk",
74393
+ installCommand: "npm install snowflake-sdk",
74394
+ title: "Snowflake support is required",
74395
+ guidance: "Snowflake connections require optional Snowflake SDK support, but the SDK is not available in this extension runtime."
74396
+ }
74397
+ ];
74349
74398
  const CONNECTOR_ICONS = {
74350
74399
  duckdb: "🦆",
74351
74400
  trino: "⚡",
@@ -74358,10 +74407,18 @@ const CONNECTOR_ICONS = {
74358
74407
  };
74359
74408
  function getOptionalDependencyAdvice(message) {
74360
74409
  const lowerMessage = message.toLowerCase();
74361
- if (message.includes("@duckdb/node-api") || lowerMessage.includes("duckdb native module")) {
74362
- return DUCKDB_OPTIONAL_DEPENDENCY_ADVICE;
74363
- }
74364
- return null;
74410
+ return OPTIONAL_DEPENDENCY_ADVICE.find((advice) => {
74411
+ if (message.includes(advice.dependency)) {
74412
+ return true;
74413
+ }
74414
+ if (advice.dependency === "@duckdb/node-api") {
74415
+ return lowerMessage.includes("duckdb native module");
74416
+ }
74417
+ if (advice.dependency === "snowflake-sdk") {
74418
+ return lowerMessage.includes("snowflake sdk") || lowerMessage.includes("sdk is not available");
74419
+ }
74420
+ return false;
74421
+ }) ?? null;
74365
74422
  }
74366
74423
  function getOptionalDependencyDetails(message) {
74367
74424
  return message.replace(/^Connection Test Failed:\s*/i, "").replace(/^Error:\s*/i, "").trim();
@@ -74383,6 +74440,16 @@ function isErrorToolResult(result, text) {
74383
74440
  }
74384
74441
  return result.isError === true || text.toLowerCase().includes("failed") || text.toLowerCase().includes("error");
74385
74442
  }
74443
+ function buildConnectionTestToast(structuredContent, text) {
74444
+ const advice = (structuredContent == null ? void 0 : structuredContent.optionalDependencyAdvice) ?? getOptionalDependencyAdvice(text);
74445
+ const lowerText = text.toLowerCase();
74446
+ const isError = structuredContent ? !structuredContent.success : lowerText.includes("error") || lowerText.includes("failed");
74447
+ return {
74448
+ text: advice ? advice.guidance : text,
74449
+ severity: advice ? "warning" : isError ? "error" : "success",
74450
+ ...advice ? { advice } : {}
74451
+ };
74452
+ }
74386
74453
  function getFormInitialData(connection) {
74387
74454
  if (!connection) {
74388
74455
  return {};
@@ -74409,6 +74476,32 @@ function schemaWithoutPasswordField(schema) {
74409
74476
  ...required2 ? { required: required2 } : {}
74410
74477
  };
74411
74478
  }
74479
+ function schemaForConnectionMode(schema, connectorId, mode) {
74480
+ if (connectorId !== "snowflake" || mode === "vscode") {
74481
+ return schema;
74482
+ }
74483
+ const authModeProperty = schema.properties["authMode"];
74484
+ if (!Array.isArray(authModeProperty == null ? void 0 : authModeProperty.enum)) {
74485
+ return schema;
74486
+ }
74487
+ const allowedIndexes = authModeProperty.enum.map((option, index2) => ({ option, index: index2 })).filter(({ option }) => option !== "externalbrowser");
74488
+ const enumNames = Array.isArray(authModeProperty.enumNames) ? allowedIndexes.map(({ option, index: index2 }) => {
74489
+ var _a3;
74490
+ return ((_a3 = authModeProperty.enumNames) == null ? void 0 : _a3[index2]) ?? option;
74491
+ }) : void 0;
74492
+ return {
74493
+ ...schema,
74494
+ properties: {
74495
+ ...schema.properties,
74496
+ authMode: {
74497
+ ...authModeProperty,
74498
+ enum: allowedIndexes.map(({ option }) => option),
74499
+ ...enumNames ? { enumNames } : {},
74500
+ default: authModeProperty.default === "externalbrowser" ? "password" : authModeProperty.default
74501
+ }
74502
+ }
74503
+ };
74504
+ }
74412
74505
  const ConnectionsManager = () => {
74413
74506
  const { callServerTool, isReady, mode, sendMessage } = useHostContext();
74414
74507
  const supportsActiveConnection = mode === "vscode";
@@ -74421,6 +74514,7 @@ const ConnectionsManager = () => {
74421
74514
  const [statuses, setStatuses] = reactExports.useState({});
74422
74515
  const [statusMessages, setStatusMessages] = reactExports.useState({});
74423
74516
  const [toast, setToast] = reactExports.useState(null);
74517
+ const toastRef = reactExports.useRef(null);
74424
74518
  const [isFormOpen, setIsFormOpen] = reactExports.useState(false);
74425
74519
  const [selectedType, setSelectedType] = reactExports.useState("");
74426
74520
  const fetchData = reactExports.useCallback(async () => {
@@ -74485,6 +74579,16 @@ const ConnectionsManager = () => {
74485
74579
  });
74486
74580
  }
74487
74581
  }, [connections]);
74582
+ reactExports.useEffect(() => {
74583
+ if (!toast || toast.severity !== "warning") {
74584
+ return;
74585
+ }
74586
+ window.requestAnimationFrame(() => {
74587
+ var _a3, _b2;
74588
+ (_a3 = toastRef.current) == null ? void 0 : _a3.scrollIntoView({ behavior: "smooth", block: "center" });
74589
+ (_b2 = toastRef.current) == null ? void 0 : _b2.focus({ preventScroll: true });
74590
+ });
74591
+ }, [toast]);
74488
74592
  const handleTestConnection = async (connectionId) => {
74489
74593
  var _a3;
74490
74594
  if (!isReady) {
@@ -74511,7 +74615,7 @@ const ConnectionsManager = () => {
74511
74615
  }
74512
74616
  };
74513
74617
  const handleTestFormData = async (formData, connection) => {
74514
- var _a3, _b2;
74618
+ var _a3;
74515
74619
  const typeToTest = (connection == null ? void 0 : connection.type) ?? selectedType;
74516
74620
  if (!isReady || !typeToTest) {
74517
74621
  return;
@@ -74535,15 +74639,11 @@ const ConnectionsManager = () => {
74535
74639
  });
74536
74640
  const text = getToolText(result, ((_a3 = result.structuredContent) == null ? void 0 : _a3.message) ?? "No response");
74537
74641
  const isError = isErrorToolResult(result, text);
74538
- const advice = ((_b2 = result.structuredContent) == null ? void 0 : _b2.optionalDependencyAdvice) ?? getOptionalDependencyAdvice(text);
74539
74642
  if (connection) {
74540
74643
  setStatuses((prev) => ({ ...prev, [connection.id]: isError ? "error" : "ok" }));
74541
74644
  setStatusMessages((prev) => ({ ...prev, [connection.id]: text }));
74542
74645
  } else {
74543
- setToast({
74544
- text: advice ? advice.guidance : text,
74545
- severity: advice ? "warning" : isError ? "error" : "success"
74546
- });
74646
+ setToast(buildConnectionTestToast(result.structuredContent, text));
74547
74647
  }
74548
74648
  } catch (e2) {
74549
74649
  const message = `Error: ${e2}`;
@@ -74554,7 +74654,8 @@ const ConnectionsManager = () => {
74554
74654
  } else {
74555
74655
  setToast({
74556
74656
  text: advice ? advice.guidance : message,
74557
- severity: advice ? "warning" : "error"
74657
+ severity: advice ? "warning" : "error",
74658
+ ...advice ? { advice } : {}
74558
74659
  });
74559
74660
  }
74560
74661
  }
@@ -74686,6 +74787,7 @@ const ConnectionsManager = () => {
74686
74787
  };
74687
74788
  const activeSchemaDef = connectors.find((c) => c.id === selectedType);
74688
74789
  const selectedConnection = selectedConnectionId ? connections.find((c) => c.id === selectedConnectionId) : void 0;
74790
+ const activeFormSchema = (activeSchemaDef == null ? void 0 : activeSchemaDef.schema) ? schemaForConnectionMode(activeSchemaDef.schema, activeSchemaDef.id, mode) : void 0;
74689
74791
  const selectedFormInitialData = reactExports.useMemo(
74690
74792
  () => getFormInitialData(selectedConnection),
74691
74793
  [selectedConnection]
@@ -74693,18 +74795,40 @@ const ConnectionsManager = () => {
74693
74795
  const emptyFormInitialData = reactExports.useMemo(() => ({}), []);
74694
74796
  const renderToast = () => {
74695
74797
  if (!toast) return null;
74696
- return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: `sp-conn-toast sp-conn-toast-${toast.severity}`, children: [
74697
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "sp-conn-toast-text", children: toast.text }),
74698
- /* @__PURE__ */ jsxRuntimeExports.jsx(
74699
- "button",
74700
- {
74701
- className: "sp-conn-toast-close",
74702
- onClick: () => setToast(null),
74703
- "aria-label": "Close message",
74704
- children: "✕"
74705
- }
74706
- )
74707
- ] });
74798
+ const advice = toast.advice;
74799
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(
74800
+ "div",
74801
+ {
74802
+ ref: toastRef,
74803
+ className: `sp-conn-toast sp-conn-toast-${toast.severity}`,
74804
+ role: toast.severity === "warning" || toast.severity === "error" ? "alert" : "status",
74805
+ tabIndex: -1,
74806
+ children: [
74807
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "sp-conn-toast-text", children: toast.text }),
74808
+ advice && /* @__PURE__ */ jsxRuntimeExports.jsxs(
74809
+ "button",
74810
+ {
74811
+ type: "button",
74812
+ className: "sp-btn sp-btn-primary sp-conn-toast-action",
74813
+ onClick: () => handleInstallOptionalDependency(advice),
74814
+ children: [
74815
+ "Install ",
74816
+ advice.dependency
74817
+ ]
74818
+ }
74819
+ ),
74820
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
74821
+ "button",
74822
+ {
74823
+ className: "sp-conn-toast-close",
74824
+ onClick: () => setToast(null),
74825
+ "aria-label": "Close message",
74826
+ children: "✕"
74827
+ }
74828
+ )
74829
+ ]
74830
+ }
74831
+ );
74708
74832
  };
74709
74833
  const renderConnectionStatusMessage = (connection) => {
74710
74834
  const status = statuses[connection.id] || "unknown";
@@ -74772,10 +74896,10 @@ const ConnectionsManager = () => {
74772
74896
  },
74773
74897
  c.id
74774
74898
  )) }),
74775
- activeSchemaDef && activeSchemaDef.schema ? /* @__PURE__ */ jsxRuntimeExports.jsx(
74899
+ activeSchemaDef && activeFormSchema ? /* @__PURE__ */ jsxRuntimeExports.jsx(
74776
74900
  DynamicForm,
74777
74901
  {
74778
- schema: { ...activeSchemaDef.schema, type: "object" },
74902
+ schema: { ...activeFormSchema, type: "object" },
74779
74903
  initialData: emptyFormInitialData,
74780
74904
  onSubmit: (formData) => handleSaveConnection(formData),
74781
74905
  onTest: (formData) => handleTestFormData(formData),
@@ -74794,6 +74918,7 @@ const ConnectionsManager = () => {
74794
74918
  const schemaDef = connectors.find((c) => c.id === selectedConnection.type);
74795
74919
  const canManagePassword = supportsActiveConnection && !selectedConnection.builtIn && schemaHasPasswordField(schemaDef == null ? void 0 : schemaDef.schema);
74796
74920
  const editSchema = (schemaDef == null ? void 0 : schemaDef.schema) && canManagePassword ? schemaWithoutPasswordField(schemaDef.schema) : schemaDef == null ? void 0 : schemaDef.schema;
74921
+ const modeAwareEditSchema = editSchema ? schemaForConnectionMode(editSchema, selectedConnection.type, mode) : void 0;
74797
74922
  const passwordAnchorField = (editSchema == null ? void 0 : editSchema.properties["user"]) ? "user" : (editSchema == null ? void 0 : editSchema.properties["username"]) ? "username" : void 0;
74798
74923
  const renderPasswordManagementField = (key) => {
74799
74924
  if (!canManagePassword || key !== passwordAnchorField) {
@@ -74870,10 +74995,10 @@ const ConnectionsManager = () => {
74870
74995
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "sp-conn-detail-body", children: [
74871
74996
  renderToast(),
74872
74997
  isActive && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "sp-conn-active-callout", role: "status", children: "Queries from SQL Preview and MCP will use this connection unless a query overrides it." }),
74873
- editSchema ? /* @__PURE__ */ jsxRuntimeExports.jsx(
74998
+ modeAwareEditSchema ? /* @__PURE__ */ jsxRuntimeExports.jsx(
74874
74999
  DynamicForm,
74875
75000
  {
74876
- schema: { ...editSchema, type: "object" },
75001
+ schema: { ...modeAwareEditSchema, type: "object" },
74877
75002
  initialData: selectedFormInitialData,
74878
75003
  onSubmit: (formData) => handleSaveConnection(formData, selectedConnection),
74879
75004
  onTest: (formData) => handleTestFormData(formData, selectedConnection),
@@ -98712,7 +98837,8 @@ body.vscode-high-contrast .ag-theme-quartz {
98712
98837
  }
98713
98838
 
98714
98839
  .sp-conn-form-fields > .sp-conn-form-group:first-child,
98715
- .sp-conn-form-field-name {
98840
+ .sp-conn-form-field-name,
98841
+ .sp-conn-form-field-full {
98716
98842
  grid-column: 1 / -1;
98717
98843
  }
98718
98844
 
@@ -98883,6 +99009,10 @@ body.vscode-high-contrast .ag-theme-quartz {
98883
99009
  overflow-wrap: anywhere;
98884
99010
  word-break: break-word;
98885
99011
  }
99012
+ .sp-conn-toast-action {
99013
+ flex-shrink: 0;
99014
+ align-self: center;
99015
+ }
98886
99016
  .sp-conn-toast-close {
98887
99017
  background: none;
98888
99018
  border: none;