grain-tools 0.10.16 → 0.10.18

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/dist/web-app.html CHANGED
@@ -12553,13 +12553,16 @@ async function bootstrapLocalSession(location, history) {
12553
12553
  const params = new URLSearchParams(location.hash.replace(/^#/, ""));
12554
12554
  const capability = params.get("launch");
12555
12555
  const rawView = params.get("view");
12556
+ const sessionId = params.get("sessionId");
12557
+ const tabId = params.get("tabId");
12558
+ const result = sessionId && tabId ? { sessionId, tabId } : void 0;
12556
12559
  let view = void 0;
12557
12560
  if (rawView === "connections" || rawView === "connections-add") {
12558
12561
  view = rawView;
12559
12562
  }
12560
12563
  history.replaceState({}, "", `${location.pathname}${location.search}`);
12561
12564
  if (!capability) {
12562
- return { session: "no-capability", view };
12565
+ return { session: "no-capability", view, result };
12563
12566
  }
12564
12567
  try {
12565
12568
  const response = await fetch(LOCAL_EXCHANGE_PATH, {
@@ -12571,11 +12574,11 @@ async function bootstrapLocalSession(location, history) {
12571
12574
  body: JSON.stringify({ capability })
12572
12575
  });
12573
12576
  if (response.status === 204) {
12574
- return { session: "ok", view };
12577
+ return { session: "ok", view, result };
12575
12578
  }
12576
- return { session: "failed", view };
12579
+ return { session: "failed", view, result };
12577
12580
  } catch {
12578
- return { session: "failed", view };
12581
+ return { session: "failed", view, result };
12579
12582
  }
12580
12583
  }
12581
12584
  async function authorizedFetch(input, init2) {
@@ -13065,6 +13068,10 @@ function useWebBootstrap() {
13065
13068
  return unsubscribe;
13066
13069
  }, []);
13067
13070
  }
13071
+ const RESULT_ROUTING_SCHEMA = {
13072
+ events: ["mcp_result_routed", "mcp_result_view_opened"],
13073
+ flagKeys: ["results-card-routing"]
13074
+ };
13068
13075
  const ALL_TOOLS = [
13069
13076
  "list_connectors",
13070
13077
  "run_query",
@@ -13087,7 +13094,8 @@ const ALL_TOOLS = [
13087
13094
  "list_charts",
13088
13095
  "ledger_stats",
13089
13096
  "verify_ledger",
13090
- "record_ui_event"
13097
+ "record_ui_event",
13098
+ "open_result_view"
13091
13099
  ];
13092
13100
  const WEB_PROXIED_TOOLS = [
13093
13101
  "list_connectors",
@@ -13110,6 +13118,7 @@ const TELEMETRY_EVENTS = [
13110
13118
  "query_confirmation_shown",
13111
13119
  "mcp_tool_invoked",
13112
13120
  "mcp_resource_read",
13121
+ ...RESULT_ROUTING_SCHEMA.events,
13113
13122
  "daemon_crashed",
13114
13123
  "service_lifecycle",
13115
13124
  "mcp_http_error",
@@ -13584,6 +13593,7 @@ const TELEMETRY_FLAG_KEYS = [
13584
13593
  "sql_preview_credential_required_signal",
13585
13594
  "sql_preview_crash_diagnostics",
13586
13595
  "sql_preview_mcp_surface",
13596
+ ...RESULT_ROUTING_SCHEMA.flagKeys,
13587
13597
  "unknown"
13588
13598
  ];
13589
13599
  const TELEMETRY_ACQUISITION_CHANNELS = ["marketplace", "open_vsx", "cli"];
@@ -13780,21 +13790,15 @@ async function buildGuideHubState() {
13780
13790
  }
13781
13791
  const WEB_SESSION_KEY = "grain:web-session-id";
13782
13792
  function resolveWebSessionId() {
13783
- try {
13784
- const stored = window.sessionStorage.getItem(WEB_SESSION_KEY);
13785
- if (stored && /^web-[0-9a-f-]{36}$/.test(stored)) return stored;
13786
- } catch {
13787
- return `web-${crypto.randomUUID()}`;
13793
+ const stored = readStoredValue(WEB_SESSION_KEY);
13794
+ if (stored && /^web-[0-9a-f-]{36}$/.test(stored)) {
13795
+ return stored;
13788
13796
  }
13789
13797
  return `web-${crypto.randomUUID()}`;
13790
13798
  }
13791
13799
  const WEB_SESSION_ID = resolveWebSessionId();
13792
13800
  function rememberWebSessionId() {
13793
- try {
13794
- window.sessionStorage.setItem(WEB_SESSION_KEY, WEB_SESSION_ID);
13795
- } catch {
13796
- return;
13797
- }
13801
+ writeStoredValue(WEB_SESSION_KEY, WEB_SESSION_ID);
13798
13802
  }
13799
13803
  function resolveProjectedTarget(tabId, payload) {
13800
13804
  const parsed = tabId ? parseProjectedTabId(tabId) : void 0;
@@ -14051,6 +14055,8 @@ function useWebTabSync(options) {
14051
14055
  remoteId: tab.id,
14052
14056
  sessionDisplayName: session.displayName,
14053
14057
  clientType: session.clientType,
14058
+ connectionId: tab.connectionId,
14059
+ connectionName: tab.connectionName,
14054
14060
  isRemote: true,
14055
14061
  preserveFocus
14056
14062
  });
@@ -14068,6 +14074,8 @@ function useWebTabSync(options) {
14068
14074
  remoteId: tab.id,
14069
14075
  sessionDisplayName: session.displayName,
14070
14076
  clientType: session.clientType,
14077
+ connectionId: tab.connectionId,
14078
+ connectionName: tab.connectionName,
14071
14079
  isRemote: true,
14072
14080
  preserveFocus
14073
14081
  });
@@ -14088,6 +14096,8 @@ function useWebTabSync(options) {
14088
14096
  remoteId: tab.id,
14089
14097
  sessionDisplayName: session.displayName,
14090
14098
  clientType: session.clientType,
14099
+ connectionId: detail.connectionId ?? tab.connectionId,
14100
+ connectionName: detail.connectionName ?? tab.connectionName,
14091
14101
  isRemote: true
14092
14102
  };
14093
14103
  if (tab.status === "success") {
@@ -14164,7 +14174,7 @@ function useWebTabSync(options) {
14164
14174
  dispatchLoading(session, tab, true);
14165
14175
  }
14166
14176
  } else if (tab.status === "success" || tab.status === "error" || !cached || cached.status !== tab.status) {
14167
- const detailIsNeeded = tab.status === "success" && (!cached || !storeHasTab || cached.status !== tab.status || cached.rowCount !== tab.rowCount);
14177
+ const detailIsNeeded = tab.status === "success" && (!cached || !storeHasTab || cached.status !== tab.status || cached.rowCount !== tab.rowCount || cached.connectionId !== tab.connectionId);
14168
14178
  const errorIsNeeded = tab.status === "error" && (!cached || !storeHasTab || cached.status !== "error");
14169
14179
  if (detailIsNeeded || errorIsNeeded) {
14170
14180
  await dispatchTabDetail(session, tab);
@@ -14175,7 +14185,8 @@ function useWebTabSync(options) {
14175
14185
  remoteTabId: tab.id,
14176
14186
  status: tab.status,
14177
14187
  rowCount: tab.rowCount,
14178
- title: tab.title
14188
+ title: tab.title,
14189
+ connectionId: tab.connectionId
14179
14190
  });
14180
14191
  }
14181
14192
  })
@@ -14694,7 +14705,10 @@ function ConnectionSetupPage({
14694
14705
  /* @__PURE__ */ jsxRuntimeExports.jsx("strong", { children: "Connection failed" }),
14695
14706
  /* @__PURE__ */ jsxRuntimeExports.jsx("p", { children: error })
14696
14707
  ] }),
14697
- tested && !error && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "grain-connection-success", role: "status", children: "Connection test successful." }),
14708
+ tested && !error && /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "grain-connection-success", role: "status", children: [
14709
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { "aria-hidden": "true", children: "✓ " }),
14710
+ "Connection test successful."
14711
+ ] }),
14698
14712
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grain-connection-grid", children: [
14699
14713
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grain-connection-field", children: [
14700
14714
  /* @__PURE__ */ jsxRuntimeExports.jsx("label", { htmlFor: "grain-connection-type", children: "Database type" }),
@@ -14782,7 +14796,10 @@ function ConnectionSetupPage({
14782
14796
  ] })
14783
14797
  ] }),
14784
14798
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grain-connection-footer", children: [
14785
- /* @__PURE__ */ jsxRuntimeExports.jsx("p", { children: "Grain will test the connection before saving it." }),
14799
+ tested && !error ? /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "grain-connection-success", children: [
14800
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { "aria-hidden": "true", children: "✓ " }),
14801
+ "Connection test successful."
14802
+ ] }) : error ? /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "grain-connection-footer-error", children: error }) : /* @__PURE__ */ jsxRuntimeExports.jsx("p", { children: "Grain will test the connection before saving it." }),
14786
14803
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grain-connection-actions", children: [
14787
14804
  /* @__PURE__ */ jsxRuntimeExports.jsx(
14788
14805
  "button",
@@ -75125,7 +75142,6 @@ const DataGrid = reactExports.forwardRef(function DataGrid2({
75125
75142
  nativeTheme = false,
75126
75143
  disableFilters = false,
75127
75144
  autoSizeStrategy,
75128
- fillWidth = false,
75129
75145
  onCellDoubleClick
75130
75146
  }, ref) {
75131
75147
  const trackUi = useTrackUi();
@@ -75294,21 +75310,6 @@ const DataGrid = reactExports.forwardRef(function DataGrid2({
75294
75310
  }),
75295
75311
  [data, getNodeValue, copyIncludesHeaders]
75296
75312
  );
75297
- const userResizedRef = reactExports.useRef(false);
75298
- const fillSpareWidth = reactExports.useCallback((e2) => {
75299
- if (userResizedRef.current) return;
75300
- const body = e2.api.getHorizontalPixelRange?.();
75301
- const columns = (e2.api.getAllDisplayedColumns?.() ?? []).filter((c) => !c.getPinned());
75302
- if (!body || columns.length === 0) return;
75303
- const used = columns.reduce((sum2, c) => sum2 + c.getActualWidth(), 0);
75304
- if (used < body.right - body.left) e2.api.sizeColumnsToFit();
75305
- }, []);
75306
- const noteUserResize = reactExports.useCallback((e2) => {
75307
- if (e2.source === "uiColumnResized" && e2.finished) userResizedRef.current = true;
75308
- }, []);
75309
- reactExports.useEffect(() => {
75310
- userResizedRef.current = false;
75311
- }, [data?.columns]);
75312
75313
  const columnDefs = reactExports.useMemo(() => {
75313
75314
  if (!data?.columns) return [];
75314
75315
  const isInRange = (rowIndex, displayedColIndex) => {
@@ -75493,11 +75494,6 @@ const DataGrid = reactExports.forwardRef(function DataGrid2({
75493
75494
  onGridReady: (p) => {
75494
75495
  apiRef.current = p.api;
75495
75496
  },
75496
- ...fillWidth ? {
75497
- onFirstDataRendered: fillSpareWidth,
75498
- onGridSizeChanged: fillSpareWidth,
75499
- onColumnResized: noteUserResize
75500
- } : {},
75501
75497
  rowData: data.rows,
75502
75498
  columnDefs,
75503
75499
  defaultColDef: {
@@ -150368,7 +150364,8 @@ const TOOL_ENTRIES = {
150368
150364
  ledger_stats: ["ledger", "Show ledger health and counts."],
150369
150365
  verify_ledger: ["ledger", "Verify the ledger hash chain."],
150370
150366
  list_sessions: ["sessions", "Show active MCP sessions and their tabs."],
150371
- record_ui_event: null
150367
+ record_ui_event: null,
150368
+ open_result_view: null
150372
150369
  };
150373
150370
  const MCP_TOOL_GROUPS = GROUPS.map((group) => ({
150374
150371
  label: group.label,
@@ -152517,7 +152514,7 @@ function SidebarAddButton({ label, title, onClick }) {
152517
152514
  }
152518
152515
  );
152519
152516
  }
152520
- function SqlEditor({ value, onChange, onRun }) {
152517
+ function SqlEditor({ value, onChange, onRun, readOnly = false }) {
152521
152518
  const frameRef = reactExports.useRef(null);
152522
152519
  const gutterRef = reactExports.useRef(null);
152523
152520
  const lineCount = value.split("\n").length;
@@ -152544,12 +152541,13 @@ function SqlEditor({ value, onChange, onRun }) {
152544
152541
  spellCheck: false,
152545
152542
  wrap: "off",
152546
152543
  value,
152544
+ readOnly,
152547
152545
  onChange: (event) => onChange(event.target.value),
152548
152546
  onScroll: (event) => {
152549
152547
  if (gutterRef.current) gutterRef.current.scrollTop = event.currentTarget.scrollTop;
152550
152548
  },
152551
152549
  onKeyDown: (event) => {
152552
- if ((event.metaKey || event.ctrlKey) && event.key === "Enter") {
152550
+ if (!readOnly && (event.metaKey || event.ctrlKey) && event.key === "Enter") {
152553
152551
  event.preventDefault();
152554
152552
  onRun();
152555
152553
  }
@@ -152558,13 +152556,227 @@ function SqlEditor({ value, onChange, onRun }) {
152558
152556
  )
152559
152557
  ] });
152560
152558
  }
152559
+ function displayQueryTitle(title, sql) {
152560
+ if (title.trim() && !/^Result \d+$/.test(title.trim())) return title;
152561
+ const line = sql.replace(/\/\*[\s\S]*?\*\//g, "").split("\n").map((part) => part.trim()).find((part) => part && !part.startsWith("--"))?.replace(/\s+/g, " ");
152562
+ if (!line) return title.trim() || "Query";
152563
+ return line.length > 40 ? `${line.slice(0, 40).trimEnd()}…` : line;
152564
+ }
152565
+ function resultText(result, fallback) {
152566
+ return result.content?.find((item) => item.type === "text")?.text ?? fallback;
152567
+ }
152568
+ function failed(result) {
152569
+ return Boolean(result.isError) || result.structuredContent?.["success"] === false;
152570
+ }
152571
+ function ConnectionPage({
152572
+ connection,
152573
+ onNewQuery,
152574
+ onEdit,
152575
+ onDeleted
152576
+ }) {
152577
+ const { callServerTool } = useHostContext();
152578
+ const [test, setTest] = reactExports.useState(null);
152579
+ const [confirmingDelete, setConfirmingDelete] = reactExports.useState(false);
152580
+ const [deleteError, setDeleteError] = reactExports.useState("");
152581
+ const label = connection.name ?? connection.id;
152582
+ const runTest = async () => {
152583
+ setTest({ kind: "testing" });
152584
+ try {
152585
+ const result = await callServerTool("test_connection", { connectionId: connection.id });
152586
+ setTest(
152587
+ failed(result) ? { kind: "failed", message: resultText(result, "Connection test failed") } : { kind: "passed" }
152588
+ );
152589
+ } catch (error) {
152590
+ setTest({
152591
+ kind: "failed",
152592
+ message: error instanceof Error ? error.message : "Connection test failed"
152593
+ });
152594
+ }
152595
+ };
152596
+ const confirmDelete = async () => {
152597
+ setDeleteError("");
152598
+ try {
152599
+ const result = await callServerTool("delete_connection", { connectionId: connection.id });
152600
+ if (failed(result)) throw new Error(resultText(result, "Could not delete connection"));
152601
+ onDeleted();
152602
+ } catch (error) {
152603
+ setDeleteError(error instanceof Error ? error.message : "Could not delete connection");
152604
+ }
152605
+ };
152606
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "sp-web-connection-detail", children: [
152607
+ /* @__PURE__ */ jsxRuntimeExports.jsx("h1", { children: label }),
152608
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { children: [
152609
+ connection.type ?? "Database",
152610
+ " ·",
152611
+ " ",
152612
+ connection.engineState === "ready" ? "Ready" : "Saved connection"
152613
+ ] }),
152614
+ test?.kind === "testing" && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { role: "status", children: "Testing…" }),
152615
+ test?.kind === "passed" && /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "sp-web-connection-test-success", role: "status", children: [
152616
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { "aria-hidden": "true", children: "✓ " }),
152617
+ "Connection test successful."
152618
+ ] }),
152619
+ test?.kind === "failed" && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "sp-web-connection-test-error", role: "alert", children: test.message }),
152620
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "sp-web-connection-actions", children: [
152621
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
152622
+ "button",
152623
+ {
152624
+ type: "button",
152625
+ className: "sp-web-primary-button",
152626
+ "aria-label": `New query for ${label}`,
152627
+ onClick: onNewQuery,
152628
+ children: "New query"
152629
+ }
152630
+ ),
152631
+ !connection.builtIn && /* @__PURE__ */ jsxRuntimeExports.jsx("button", { type: "button", className: "sp-web-secondary-button", onClick: onEdit, children: "Edit" }),
152632
+ /* @__PURE__ */ jsxRuntimeExports.jsx("button", { type: "button", className: "sp-web-secondary-button", onClick: () => void runTest(), children: "Test" }),
152633
+ !connection.builtIn && /* @__PURE__ */ jsxRuntimeExports.jsx(
152634
+ "button",
152635
+ {
152636
+ type: "button",
152637
+ className: "sp-web-secondary-button",
152638
+ onClick: () => {
152639
+ setDeleteError("");
152640
+ setConfirmingDelete(true);
152641
+ },
152642
+ children: "Delete"
152643
+ }
152644
+ )
152645
+ ] }),
152646
+ confirmingDelete && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "sp-web-connection-delete-confirm", children: [
152647
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { children: [
152648
+ "Delete '",
152649
+ label,
152650
+ "'? Its stored password is removed too."
152651
+ ] }),
152652
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
152653
+ "button",
152654
+ {
152655
+ type: "button",
152656
+ className: "sp-web-secondary-button",
152657
+ onClick: () => void confirmDelete(),
152658
+ children: "Delete"
152659
+ }
152660
+ ),
152661
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
152662
+ "button",
152663
+ {
152664
+ type: "button",
152665
+ className: "sp-web-secondary-button",
152666
+ onClick: () => {
152667
+ setConfirmingDelete(false);
152668
+ setDeleteError("");
152669
+ },
152670
+ children: "Cancel"
152671
+ }
152672
+ )
152673
+ ] }),
152674
+ deleteError && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "sp-web-connection-test-error", role: "alert", children: deleteError })
152675
+ ] });
152676
+ }
152677
+ function AgentActivity({
152678
+ tabs,
152679
+ activeTabId,
152680
+ onSelect
152681
+ }) {
152682
+ const [collapsed, setCollapsed] = reactExports.useState([]);
152683
+ const sessions = Array.from(
152684
+ new Set(
152685
+ tabs.flatMap(
152686
+ (tab) => tab.sessionId && tab.sessionId !== WEB_SESSION_ID ? [tab.sessionId] : []
152687
+ )
152688
+ )
152689
+ );
152690
+ if (sessions.length === 0) return null;
152691
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
152692
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "sp-web-sidebar-section-title", children: "Agent activity" }),
152693
+ sessions.map((sessionId) => {
152694
+ const sessionTabs = tabs.filter((tab) => tab.sessionId === sessionId);
152695
+ const name = sessionTabs[0]?.sessionDisplayName || sessionTabs[0]?.clientType || "Agent";
152696
+ const isCollapsed = collapsed.includes(sessionId);
152697
+ const groupId = `sp-web-agent-${sessionId.replace(/[^a-zA-Z0-9_-]/g, "-")}`;
152698
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
152699
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
152700
+ "button",
152701
+ {
152702
+ type: "button",
152703
+ className: "sp-web-agent-session-toggle",
152704
+ "aria-expanded": !isCollapsed,
152705
+ "aria-controls": groupId,
152706
+ onClick: () => setCollapsed(
152707
+ (current2) => isCollapsed ? current2.filter((id) => id !== sessionId) : [...current2, sessionId]
152708
+ ),
152709
+ children: [
152710
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { "aria-hidden": "true", children: isCollapsed ? "▸" : "▾" }),
152711
+ " ",
152712
+ name
152713
+ ]
152714
+ }
152715
+ ),
152716
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { id: groupId, hidden: isCollapsed, children: sessionTabs.map((tab) => /* @__PURE__ */ jsxRuntimeExports.jsx(
152717
+ "button",
152718
+ {
152719
+ type: "button",
152720
+ className: `sp-web-session-item sp-web-session-button${activeTabId === tab.id ? " active" : ""}`,
152721
+ "aria-pressed": activeTabId === tab.id,
152722
+ onClick: () => onSelect(tab.id),
152723
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "sp-web-session-name", children: displayQueryTitle(tab.title, tab.sql) })
152724
+ },
152725
+ tab.id
152726
+ )) })
152727
+ ] }, sessionId);
152728
+ })
152729
+ ] });
152730
+ }
152731
+ function AgentQueryHeading({
152732
+ tab,
152733
+ connectionName
152734
+ }) {
152735
+ const ranAt = tab.result?.executedAt && new Date(tab.result.executedAt).toLocaleTimeString([], {
152736
+ hour: "2-digit",
152737
+ minute: "2-digit",
152738
+ hour12: false
152739
+ });
152740
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
152741
+ /* @__PURE__ */ jsxRuntimeExports.jsx("h1", { children: displayQueryTitle(tab.title, tab.sql) }),
152742
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "sp-web-query-provenance", children: [tab.sessionDisplayName || tab.clientType, connectionName, ranAt].filter(Boolean).join(" · ") })
152743
+ ] });
152744
+ }
152745
+ function useWebAppInitialTarget(isReady, viewHint, resultTarget, tabs, showQuery, openSettingsPanel) {
152746
+ const appliedHint = reactExports.useRef(false);
152747
+ const appliedTarget = reactExports.useRef(void 0);
152748
+ reactExports.useEffect(() => {
152749
+ if (appliedHint.current || !viewHint) {
152750
+ return;
152751
+ }
152752
+ appliedHint.current = true;
152753
+ openSettingsPanel("connections", viewHint === "connections-add");
152754
+ }, [viewHint, openSettingsPanel]);
152755
+ reactExports.useEffect(() => {
152756
+ if (!isReady || !resultTarget) {
152757
+ return;
152758
+ }
152759
+ const targetKey = `${resultTarget.sessionId}\0${resultTarget.tabId}`;
152760
+ if (appliedTarget.current === targetKey) {
152761
+ return;
152762
+ }
152763
+ const target = tabs.find(
152764
+ (tab) => tab.sessionId === resultTarget.sessionId && (tab.remoteId === resultTarget.tabId || tab.id === resultTarget.tabId)
152765
+ );
152766
+ if (target) {
152767
+ appliedTarget.current = targetKey;
152768
+ showQuery(target.id);
152769
+ }
152770
+ }, [isReady, resultTarget, tabs, showQuery]);
152771
+ }
152561
152772
  const THEME_KEY = "grain:web-theme";
152562
152773
  const SIDEBAR_DEFAULT_WIDTH = 220;
152563
152774
  const SIDEBAR_MIN_WIDTH = 160;
152564
152775
  const SIDEBAR_MAX_WIDTH = 400;
152565
152776
  const SIDEBAR_AUTO_COLLAPSE_QUERY = "(max-width: 640px)";
152566
152777
  const SIDEBAR_WIDTH_STORAGE_KEY = "sql-preview:web-sidebar-width";
152567
- function WebApp({ viewHint }) {
152778
+ const CONNECTIONS_COLLAPSED_KEY = "grain:web-connections-collapsed";
152779
+ function WebApp({ viewHint, resultTarget }) {
152568
152780
  const { onMessage, isReady, sendMessage, callServerTool, track } = useHostContext();
152569
152781
  const session = useWebSession();
152570
152782
  const {
@@ -152574,6 +152786,7 @@ function WebApp({ viewHint }) {
152574
152786
  setActiveTab,
152575
152787
  setTheme,
152576
152788
  openSettingsPanel,
152789
+ closeSettingsPanel,
152577
152790
  tabs,
152578
152791
  activeTabId,
152579
152792
  settingsPanelTab
@@ -152581,22 +152794,28 @@ function WebApp({ viewHint }) {
152581
152794
  const [connections, setConnections] = reactExports.useState([]);
152582
152795
  const [setupOpen, setSetupOpen] = reactExports.useState(false);
152583
152796
  const [editingConnection, setEditingConnection] = reactExports.useState(null);
152584
- const [openConnectionIds, setOpenConnectionIds] = reactExports.useState([]);
152797
+ const [connectionsCollapsed, setConnectionsCollapsed] = reactExports.useState(
152798
+ () => readStoredValue(CONNECTIONS_COLLAPSED_KEY) === "true"
152799
+ );
152585
152800
  const [activeConnectionId, setActiveConnectionId] = reactExports.useState(null);
152586
- const [connectionStatus, setConnectionStatus] = reactExports.useState({});
152587
152801
  const [descriptions, setDescriptions] = reactExports.useState({});
152588
152802
  const [queryConnections, setQueryConnections] = reactExports.useState({});
152589
152803
  const [closedQueries, setClosedQueries] = reactExports.useState([]);
152590
152804
  const activeTab = tabs.find((tab) => tab.id === activeTabId);
152591
152805
  const localConnection = connections.find((connection) => connection.id === "built-in-duckdb");
152592
- const selectedConnectionId = activeTab ? queryConnections[activeTab.id] ?? localConnection?.id ?? connections[0]?.id ?? "" : "";
152806
+ const isAgentTab = Boolean(activeTab?.sessionId && activeTab.sessionId !== WEB_SESSION_ID);
152807
+ const selectedConnectionId = activeTab ? isAgentTab ? activeTab.connectionId ?? "" : queryConnections[activeTab.id] ?? localConnection?.id ?? connections[0]?.id ?? "" : "";
152808
+ const activeConnectionName = activeTab ? activeTab.connectionName ?? connections.find((connection) => connection.id === activeTab.connectionId)?.name ?? (activeTab.connectionId === "unknown" ? void 0 : activeTab.connectionId) : void 0;
152593
152809
  reactExports.useEffect(() => {
152594
152810
  if (isReady) track?.("ui_state_shown", { state: "workspace_ready" });
152595
152811
  }, [isReady, track]);
152596
- const newQuery = (connectionId = "built-in-duckdb") => {
152812
+ const newQuery = (connectionId = "built-in-duckdb", sql = "SELECT 42;") => {
152813
+ setSetupOpen(false);
152814
+ setEditingConnection(null);
152815
+ closeSettingsPanel();
152597
152816
  const remoteId = crypto.randomUUID();
152598
152817
  const id = addTab(
152599
- "SELECT 42;",
152818
+ sql,
152600
152819
  createProjectedTabId(WEB_SESSION_ID, remoteId),
152601
152820
  tabs.some((tab) => tab.title === "Untitled query") ? `Untitled query ${tabs.filter((tab) => tab.title.startsWith("Untitled query")).length + 1}` : "Untitled query",
152602
152821
  void 0,
@@ -152605,26 +152824,14 @@ function WebApp({ viewHint }) {
152605
152824
  setQueryConnections((current2) => ({ ...current2, [id]: connectionId }));
152606
152825
  setActiveConnectionId(null);
152607
152826
  };
152608
- const openConnection = (id) => {
152609
- setOpenConnectionIds((current2) => current2.includes(id) ? current2 : [...current2, id]);
152610
- setActiveConnectionId(id);
152611
- };
152612
- const testConnection = async (id) => {
152613
- setConnectionStatus((current2) => ({ ...current2, [id]: "Testing…" }));
152614
- try {
152615
- const result = await callServerTool("test_connection", { connectionId: id });
152616
- const message = result.content?.find((item) => item.type === "text")?.text ?? "Connection test failed";
152617
- setConnectionStatus((current2) => ({
152618
- ...current2,
152619
- [id]: result.isError || result.structuredContent?.["success"] === false ? message : "Connected"
152620
- }));
152621
- } catch (error) {
152622
- setConnectionStatus((current2) => ({
152623
- ...current2,
152624
- [id]: error instanceof Error ? error.message : "Connection test failed"
152625
- }));
152626
- }
152827
+ const showQuery = (tabId) => {
152828
+ setSetupOpen(false);
152829
+ setEditingConnection(null);
152830
+ closeSettingsPanel();
152831
+ setActiveConnectionId(null);
152832
+ setActiveTab(tabId);
152627
152833
  };
152834
+ const openConnection = (id) => setActiveConnectionId(id);
152628
152835
  const closeQuery = (id) => {
152629
152836
  const tab = tabs.find((item) => item.id === id);
152630
152837
  if (tab) {
@@ -152634,7 +152841,7 @@ function WebApp({ viewHint }) {
152634
152841
  sql: tab.sql,
152635
152842
  title: tab.title,
152636
152843
  description: descriptions[id] ?? "",
152637
- connectionId: queryConnections[id] ?? "built-in-duckdb"
152844
+ connectionId: tab.sessionId && tab.sessionId !== WEB_SESSION_ID ? tab.connectionId ?? "" : queryConnections[id] ?? "built-in-duckdb"
152638
152845
  }
152639
152846
  ]);
152640
152847
  if (tab.result || tab.isLoading) {
@@ -152661,7 +152868,7 @@ function WebApp({ viewHint }) {
152661
152868
  const runQuery = async () => {
152662
152869
  if (!activeTab || !activeTab.sql.trim() || !selectedConnectionId || activeTab.isLoading) return;
152663
152870
  const { id, sql, title } = activeTab;
152664
- updateTab(id, { isLoading: true, error: null, cancelled: false });
152871
+ updateTab(id, { isLoading: true, error: null, result: null, cancelled: false });
152665
152872
  try {
152666
152873
  const result = await callServerTool("run_query", {
152667
152874
  sql,
@@ -152761,14 +152968,7 @@ function WebApp({ viewHint }) {
152761
152968
  reactExports.useEffect(() => {
152762
152969
  if (isReady) void fetchConnections();
152763
152970
  }, [isReady, fetchConnections]);
152764
- const hasAppliedHint = reactExports.useRef(false);
152765
- reactExports.useEffect(() => {
152766
- if (hasAppliedHint.current || !viewHint) {
152767
- return;
152768
- }
152769
- hasAppliedHint.current = true;
152770
- openSettingsPanel("connections", viewHint === "connections-add");
152771
- }, [viewHint, openSettingsPanel]);
152971
+ useWebAppInitialTarget(isReady, viewHint, resultTarget, tabs, showQuery, openSettingsPanel);
152772
152972
  reactExports.useEffect(() => {
152773
152973
  const mediaQuery = window.matchMedia(SIDEBAR_AUTO_COLLAPSE_QUERY);
152774
152974
  const handleChange = (e2) => {
@@ -152827,6 +153027,8 @@ function WebApp({ viewHint }) {
152827
153027
  remoteId: msg.remoteId,
152828
153028
  sessionDisplayName: msg.sessionDisplayName,
152829
153029
  clientType: msg.clientType,
153030
+ connectionId: msg.connectionId,
153031
+ connectionName: msg.connectionName,
152830
153032
  isRemote: msg.isRemote
152831
153033
  },
152832
153034
  !msg.preserveFocus
@@ -152848,6 +153050,8 @@ function WebApp({ viewHint }) {
152848
153050
  remoteId: msg.remoteId,
152849
153051
  sessionDisplayName: msg.sessionDisplayName,
152850
153052
  clientType: msg.clientType,
153053
+ connectionId: msg.connectionId,
153054
+ connectionName: msg.connectionName,
152851
153055
  isRemote: msg.isRemote
152852
153056
  },
152853
153057
  !msg.preserveFocus
@@ -152860,6 +153064,8 @@ function WebApp({ viewHint }) {
152860
153064
  remoteId: msg.remoteId,
152861
153065
  sessionDisplayName: msg.sessionDisplayName,
152862
153066
  clientType: msg.clientType,
153067
+ connectionId: msg.connectionId,
153068
+ connectionName: msg.connectionName,
152863
153069
  isRemote: msg.isRemote
152864
153070
  });
152865
153071
  if (!msg.preserveFocus || !currentActiveId) {
@@ -152878,6 +153084,8 @@ function WebApp({ viewHint }) {
152878
153084
  remoteId: msg.remoteId,
152879
153085
  sessionDisplayName: msg.sessionDisplayName,
152880
153086
  clientType: msg.clientType,
153087
+ connectionId: msg.connectionId,
153088
+ connectionName: msg.connectionName,
152881
153089
  isRemote: msg.isRemote
152882
153090
  },
152883
153091
  false
@@ -152890,6 +153098,8 @@ function WebApp({ viewHint }) {
152890
153098
  remoteId: msg.remoteId,
152891
153099
  sessionDisplayName: msg.sessionDisplayName,
152892
153100
  clientType: msg.clientType,
153101
+ connectionId: msg.connectionId,
153102
+ connectionName: msg.connectionName,
152893
153103
  isRemote: msg.isRemote,
152894
153104
  result: {
152895
153105
  query: msg.data.query,
@@ -152897,7 +153107,7 @@ function WebApp({ viewHint }) {
152897
153107
  rows: msg.data.rows,
152898
153108
  rowCount: msg.data.totalRowsInFirstBatch ?? msg.data.rows.length,
152899
153109
  executionTime: msg.data.executionTimeMs,
152900
- connection: "Web",
153110
+ connection: msg.connectionName ?? msg.connectionId ?? "Connection unknown",
152901
153111
  wasTruncated: msg.data.wasTruncated,
152902
153112
  executedAt: msg.data.executedAt
152903
153113
  }
@@ -152915,6 +153125,8 @@ function WebApp({ viewHint }) {
152915
153125
  remoteId: msg.remoteId,
152916
153126
  sessionDisplayName: msg.sessionDisplayName,
152917
153127
  clientType: msg.clientType,
153128
+ connectionId: msg.connectionId,
153129
+ connectionName: msg.connectionName,
152918
153130
  isRemote: msg.isRemote
152919
153131
  },
152920
153132
  false
@@ -152927,6 +153139,8 @@ function WebApp({ viewHint }) {
152927
153139
  remoteId: msg.remoteId,
152928
153140
  sessionDisplayName: msg.sessionDisplayName,
152929
153141
  clientType: msg.clientType,
153142
+ connectionId: msg.connectionId,
153143
+ connectionName: msg.connectionName,
152930
153144
  isRemote: msg.isRemote
152931
153145
  });
152932
153146
  break;
@@ -153034,7 +153248,25 @@ function WebApp({ viewHint }) {
153034
153248
  ] }),
153035
153249
  monitorOpen && /* @__PURE__ */ jsxRuntimeExports.jsxs("aside", { ref: sidebarRef, className: "sp-web-sidebar", "aria-label": "Workspace navigation", children: [
153036
153250
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "sp-web-sidebar-header", children: [
153037
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "sp-web-sidebar-title", children: "Connections" }),
153251
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
153252
+ "button",
153253
+ {
153254
+ type: "button",
153255
+ className: "sp-web-sidebar-title sp-web-section-toggle",
153256
+ "aria-expanded": !connectionsCollapsed,
153257
+ "aria-controls": "sp-web-connections",
153258
+ onClick: () => {
153259
+ setConnectionsCollapsed((current2) => {
153260
+ writeStoredValue(CONNECTIONS_COLLAPSED_KEY, String(!current2));
153261
+ return !current2;
153262
+ });
153263
+ },
153264
+ children: [
153265
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { "aria-hidden": "true", children: connectionsCollapsed ? "▸" : "▾" }),
153266
+ " Connections"
153267
+ ]
153268
+ }
153269
+ ),
153038
153270
  /* @__PURE__ */ jsxRuntimeExports.jsx(
153039
153271
  SidebarAddButton,
153040
153272
  {
@@ -153068,63 +153300,55 @@ function WebApp({ viewHint }) {
153068
153300
  "aria-valuemax": SIDEBAR_MAX_WIDTH
153069
153301
  }
153070
153302
  ),
153071
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "sp-web-connection-list", children: connections.length ? connections.map((connection) => /* @__PURE__ */ jsxRuntimeExports.jsxs(
153072
- "button",
153303
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
153304
+ "div",
153073
153305
  {
153074
- type: "button",
153075
- className: "sp-web-connection-item",
153076
- onClick: () => openConnection(connection.id),
153077
- children: [
153078
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "sp-web-connection-icon", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntimeExports.jsx(DatabaseIcon, { size: 15 }) }),
153079
- /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "sp-web-connection-label", children: [
153080
- connection.name ?? connection.id,
153081
- /* @__PURE__ */ jsxRuntimeExports.jsx("small", { children: connection.type })
153082
- ] }),
153083
- connection.engineState === "ready" && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
153084
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "sp-web-connection-dot", "aria-hidden": "true" }),
153085
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "sp-visually-hidden", children: "Ready" })
153086
- ] })
153087
- ]
153088
- },
153089
- connection.id
153090
- )) : /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "sp-web-sidebar-helper", children: "No connections yet." }) }),
153306
+ id: "sp-web-connections",
153307
+ className: "sp-web-connection-list",
153308
+ hidden: connectionsCollapsed,
153309
+ children: connections.length ? connections.map((connection) => /* @__PURE__ */ jsxRuntimeExports.jsxs(
153310
+ "button",
153311
+ {
153312
+ type: "button",
153313
+ className: "sp-web-connection-item",
153314
+ "aria-current": activeConnectionId === connection.id ? "page" : void 0,
153315
+ onClick: () => openConnection(connection.id),
153316
+ children: [
153317
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "sp-web-connection-icon", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntimeExports.jsx(DatabaseIcon, { size: 15 }) }),
153318
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "sp-web-connection-label", children: [
153319
+ connection.name ?? connection.id,
153320
+ /* @__PURE__ */ jsxRuntimeExports.jsx("small", { children: connection.type })
153321
+ ] }),
153322
+ connection.engineState === "ready" && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
153323
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "sp-web-connection-dot", "aria-hidden": "true" }),
153324
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "sp-visually-hidden", children: "Ready" })
153325
+ ] })
153326
+ ]
153327
+ },
153328
+ connection.id
153329
+ )) : /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "sp-web-sidebar-helper", children: "No connections yet." })
153330
+ }
153331
+ ),
153091
153332
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "sp-web-sidebar-section-title", children: [
153092
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Queries" }),
153333
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "My queries" }),
153093
153334
  /* @__PURE__ */ jsxRuntimeExports.jsx(SidebarAddButton, { label: "Add query", title: "New query", onClick: () => newQuery() })
153094
153335
  ] }),
153095
153336
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "sp-web-session-list", children: [
153096
153337
  closedQueries.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("button", { type: "button", className: "sp-web-add-connection", onClick: reopenQuery, children: "Reopen closed query" }),
153097
- tabs.filter((tab) => tab.sessionId === WEB_SESSION_ID).map((tab) => /* @__PURE__ */ jsxRuntimeExports.jsx(
153338
+ tabs.filter((tab) => !tab.sessionId || tab.sessionId === WEB_SESSION_ID).map((tab) => /* @__PURE__ */ jsxRuntimeExports.jsx(
153098
153339
  "button",
153099
153340
  {
153100
153341
  type: "button",
153101
153342
  className: `sp-web-session-item sp-web-session-button${activeTabId === tab.id ? " active" : ""}`,
153102
153343
  "aria-pressed": activeTabId === tab.id,
153103
- onClick: () => {
153104
- setActiveTab(tab.id);
153105
- setActiveConnectionId(null);
153106
- },
153107
- children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "sp-web-session-name", children: tab.title })
153108
- },
153109
- tab.id
153110
- )),
153111
- tabs.some((tab) => tab.sessionId !== WEB_SESSION_ID) && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "sp-web-session-meta sp-web-agent-heading", children: "Other sessions" }),
153112
- tabs.filter((tab) => tab.sessionId !== WEB_SESSION_ID).map((tab) => /* @__PURE__ */ jsxRuntimeExports.jsx(
153113
- "button",
153114
- {
153115
- type: "button",
153116
- className: `sp-web-session-item sp-web-session-button${activeTabId === tab.id ? " active" : ""}`,
153117
- "aria-pressed": activeTabId === tab.id,
153118
- onClick: () => {
153119
- setActiveTab(tab.id);
153120
- setActiveConnectionId(null);
153121
- },
153122
- children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "sp-web-session-name", children: tab.title })
153344
+ onClick: () => showQuery(tab.id),
153345
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "sp-web-session-name", children: displayQueryTitle(tab.title, tab.sql) })
153123
153346
  },
153124
153347
  tab.id
153125
153348
  )),
153126
153349
  tabs.length === 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "sp-web-empty-sessions", children: "No queries yet." })
153127
153350
  ] }),
153351
+ /* @__PURE__ */ jsxRuntimeExports.jsx(AgentActivity, { tabs, activeTabId, onSelect: showQuery }),
153128
153352
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "sp-web-sidebar-footer", children: "⌂   All work stays on this computer." })
153129
153353
  ] }),
153130
153354
  setupOpen ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "sp-web-main", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
@@ -153161,41 +153385,6 @@ function WebApp({ viewHint }) {
153161
153385
  ) }),
153162
153386
  !settingsPanelTab && (activeTab || activeConnectionId) && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "sp-web-query-workspace", children: [
153163
153387
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "sp-web-query-tabs", role: "tablist", "aria-label": "Open tabs", children: [
153164
- openConnectionIds.map((id) => {
153165
- const connection = connections.find((item) => item.id === id);
153166
- if (!connection) return null;
153167
- return /* @__PURE__ */ jsxRuntimeExports.jsxs(
153168
- "div",
153169
- {
153170
- className: `sp-web-query-tab${activeConnectionId === id ? " active" : ""}`,
153171
- children: [
153172
- /* @__PURE__ */ jsxRuntimeExports.jsx(
153173
- "button",
153174
- {
153175
- type: "button",
153176
- role: "tab",
153177
- "aria-selected": activeConnectionId === id,
153178
- onClick: () => setActiveConnectionId(id),
153179
- children: connection.name ?? id
153180
- }
153181
- ),
153182
- /* @__PURE__ */ jsxRuntimeExports.jsx(
153183
- "button",
153184
- {
153185
- type: "button",
153186
- "aria-label": `Close ${connection.name ?? id} tab`,
153187
- onClick: () => {
153188
- setOpenConnectionIds((current2) => current2.filter((item) => item !== id));
153189
- if (activeConnectionId === id) setActiveConnectionId(null);
153190
- },
153191
- children: "×"
153192
- }
153193
- )
153194
- ]
153195
- },
153196
- `connection-${id}`
153197
- );
153198
- }),
153199
153388
  tabs.map((tab) => /* @__PURE__ */ jsxRuntimeExports.jsxs(
153200
153389
  "div",
153201
153390
  {
@@ -153207,18 +153396,15 @@ function WebApp({ viewHint }) {
153207
153396
  type: "button",
153208
153397
  role: "tab",
153209
153398
  "aria-selected": tab.id === activeTabId && !activeConnectionId,
153210
- onClick: () => {
153211
- setActiveTab(tab.id);
153212
- setActiveConnectionId(null);
153213
- },
153214
- children: tab.title
153399
+ onClick: () => showQuery(tab.id),
153400
+ children: displayQueryTitle(tab.title, tab.sql)
153215
153401
  }
153216
153402
  ),
153217
153403
  /* @__PURE__ */ jsxRuntimeExports.jsx(
153218
153404
  "button",
153219
153405
  {
153220
153406
  type: "button",
153221
- "aria-label": `Close ${tab.title} tab`,
153407
+ "aria-label": `Close ${displayQueryTitle(tab.title, tab.sql)} tab`,
153222
153408
  onClick: () => closeQuery(tab.id),
153223
153409
  children: "×"
153224
153410
  }
@@ -153242,51 +153428,39 @@ function WebApp({ viewHint }) {
153242
153428
  activeConnectionId ? (() => {
153243
153429
  const connection = connections.find((item) => item.id === activeConnectionId);
153244
153430
  if (!connection) return null;
153245
- return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "sp-web-connection-detail", children: [
153246
- /* @__PURE__ */ jsxRuntimeExports.jsx("h1", { children: connection.name ?? connection.id }),
153247
- /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { children: [
153248
- connection.type ?? "Database",
153249
- " ·",
153250
- " ",
153251
- connectionStatus[connection.id] ?? (connection.engineState === "ready" ? "Ready" : "Saved connection")
153252
- ] }),
153253
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "sp-web-connection-actions", children: [
153254
- /* @__PURE__ */ jsxRuntimeExports.jsx(
153255
- "button",
153256
- {
153257
- type: "button",
153258
- className: "sp-web-primary-button",
153259
- "aria-label": `New query for ${connection.name ?? connection.id}`,
153260
- onClick: () => newQuery(connection.id),
153261
- children: "New query"
153262
- }
153263
- ),
153264
- !connection.builtIn && /* @__PURE__ */ jsxRuntimeExports.jsx(
153265
- "button",
153266
- {
153267
- type: "button",
153268
- className: "sp-web-secondary-button",
153269
- onClick: () => {
153270
- setEditingConnection(connection);
153271
- setSetupOpen(true);
153272
- },
153273
- children: "Edit"
153274
- }
153275
- ),
153276
- /* @__PURE__ */ jsxRuntimeExports.jsx(
153277
- "button",
153278
- {
153279
- type: "button",
153280
- className: "sp-web-secondary-button",
153281
- onClick: () => void testConnection(connection.id),
153282
- children: "Test"
153283
- }
153284
- )
153285
- ] })
153286
- ] });
153431
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
153432
+ ConnectionPage,
153433
+ {
153434
+ connection,
153435
+ onNewQuery: () => newQuery(connection.id),
153436
+ onEdit: () => {
153437
+ setEditingConnection(connection);
153438
+ setSetupOpen(true);
153439
+ },
153440
+ onDeleted: () => {
153441
+ setActiveConnectionId(null);
153442
+ setQueryConnections(
153443
+ (current2) => Object.fromEntries(
153444
+ Object.entries(current2).map(([tabId, id]) => [
153445
+ tabId,
153446
+ id === connection.id ? "built-in-duckdb" : id
153447
+ ])
153448
+ )
153449
+ );
153450
+ void fetchConnections();
153451
+ }
153452
+ },
153453
+ connection.id
153454
+ );
153287
153455
  })() : activeTab && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
153288
153456
  " ",
153289
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "sp-web-query-heading", children: [
153457
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "sp-web-query-heading", children: isAgentTab ? /* @__PURE__ */ jsxRuntimeExports.jsx(
153458
+ AgentQueryHeading,
153459
+ {
153460
+ tab: activeTab,
153461
+ connectionName: activeConnectionName
153462
+ }
153463
+ ) : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
153290
153464
  /* @__PURE__ */ jsxRuntimeExports.jsx(
153291
153465
  "input",
153292
153466
  {
@@ -153308,9 +153482,9 @@ function WebApp({ viewHint }) {
153308
153482
  rows: 1
153309
153483
  }
153310
153484
  )
153311
- ] }),
153485
+ ] }) }),
153312
153486
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "sp-web-query-toolbar", children: [
153313
- /* @__PURE__ */ jsxRuntimeExports.jsx("label", { children: /* @__PURE__ */ jsxRuntimeExports.jsx(
153487
+ isAgentTab ? /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "sp-web-readonly", children: activeConnectionName ?? "Connection unknown" }) : /* @__PURE__ */ jsxRuntimeExports.jsx("label", { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
153314
153488
  "select",
153315
153489
  {
153316
153490
  "aria-label": "Query connection",
@@ -153319,10 +153493,24 @@ function WebApp({ viewHint }) {
153319
153493
  ...current2,
153320
153494
  [activeTab.id]: event.target.value
153321
153495
  })),
153322
- children: connections.map((connection) => /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: connection.id, children: connection.name ?? connection.id }, connection.id))
153496
+ children: [
153497
+ !selectedConnectionId && /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "", children: "Choose connection" }),
153498
+ selectedConnectionId && !connections.some(
153499
+ (connection) => connection.id === selectedConnectionId
153500
+ ) && /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: selectedConnectionId, children: selectedConnectionId }),
153501
+ connections.map((connection) => /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: connection.id, children: connection.name ?? connection.id }, connection.id))
153502
+ ]
153323
153503
  }
153324
153504
  ) }),
153325
- activeTab.isLoading ? /* @__PURE__ */ jsxRuntimeExports.jsx(
153505
+ isAgentTab ? /* @__PURE__ */ jsxRuntimeExports.jsx(
153506
+ "button",
153507
+ {
153508
+ type: "button",
153509
+ className: "sp-web-secondary-button",
153510
+ onClick: () => newQuery(activeTab.connectionId ?? "", activeTab.sql),
153511
+ children: "Open as my query"
153512
+ }
153513
+ ) : activeTab.isLoading ? /* @__PURE__ */ jsxRuntimeExports.jsx(
153326
153514
  "button",
153327
153515
  {
153328
153516
  type: "button",
@@ -153350,7 +153538,8 @@ function WebApp({ viewHint }) {
153350
153538
  {
153351
153539
  value: activeTab.sql,
153352
153540
  onChange: (sql) => updateTab(activeTab.id, { sql }),
153353
- onRun: () => void runQuery()
153541
+ onRun: () => void runQuery(),
153542
+ readOnly: isAgentTab
153354
153543
  }
153355
153544
  )
153356
153545
  ] })
@@ -153369,7 +153558,13 @@ async function bootstrap() {
153369
153558
  return;
153370
153559
  }
153371
153560
  ReactDOM$1.createRoot(document.getElementById("root")).render(
153372
- /* @__PURE__ */ jsxRuntimeExports.jsx(React.StrictMode, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(WebHostProvider, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(WebApp, { viewHint: result.view }) }) })
153561
+ /* @__PURE__ */ jsxRuntimeExports.jsx(React.StrictMode, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(WebHostProvider, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(
153562
+ WebApp,
153563
+ {
153564
+ viewHint: result.view,
153565
+ ...result.result ? { resultTarget: result.result } : {}
153566
+ }
153567
+ ) }) })
153373
153568
  );
153374
153569
  }
153375
153570
  bootstrap();</script>
@@ -153528,11 +153723,18 @@ bootstrap();</script>
153528
153723
  margin: 5px 0 0;
153529
153724
  }
153530
153725
  .grain-connection-success {
153531
- color: var(--grain-ink);
153532
- background: var(--grain-surface);
153726
+ color: var(--vscode-testing-iconPassed, var(--sp-success));
153727
+ border: 1px solid var(--vscode-testing-iconPassed, var(--sp-success));
153728
+ background: color-mix(in srgb, var(--sp-success) 8%, var(--grain-surface));
153533
153729
  padding: 10px 14px;
153534
153730
  border-radius: var(--grain-radius-sm);
153535
153731
  }
153732
+ .grain-connection-footer .grain-connection-success {
153733
+ color: var(--vscode-testing-iconPassed, var(--sp-success));
153734
+ }
153735
+ .grain-connection-footer-error {
153736
+ color: var(--vscode-errorForeground, var(--sp-error));
153737
+ }
153536
153738
  .grain-connection-page :is(button, input, select, summary):focus-visible {
153537
153739
  outline: 2px solid var(--grain-accent);
153538
153740
  outline-offset: 2px;
@@ -166390,6 +166592,31 @@ body {
166390
166592
  .sp-web-sidebar-header .sp-web-sidebar-title {
166391
166593
  flex: 1;
166392
166594
  }
166595
+ .sp-web-section-toggle,
166596
+ .sp-web-agent-session-toggle {
166597
+ border: 0;
166598
+ background: transparent;
166599
+ color: var(--grain-ink);
166600
+ font: inherit;
166601
+ text-align: left;
166602
+ cursor: pointer;
166603
+ }
166604
+ .sp-web-section-toggle {
166605
+ padding: 0;
166606
+ }
166607
+ .sp-web-agent-session-toggle {
166608
+ width: 100%;
166609
+ padding: 7px 9px;
166610
+ color: var(--grain-ink-muted);
166611
+ font-size: 11px;
166612
+ }
166613
+ .sp-web-section-toggle:focus-visible,
166614
+ .sp-web-agent-session-toggle:focus-visible {
166615
+ outline: 1px solid var(--grain-accent);
166616
+ }
166617
+ [aria-current='page'].sp-web-connection-item {
166618
+ background: var(--grain-surface-raised);
166619
+ }
166393
166620
  .sp-web-section-add,
166394
166621
  .sp-web-sidebar-close {
166395
166622
  display: inline-flex;
@@ -166581,6 +166808,14 @@ body {
166581
166808
  gap: 4px;
166582
166809
  padding: 18px 24px 14px;
166583
166810
  }
166811
+ .sp-web-query-heading h1 {
166812
+ margin: 0;
166813
+ font-size: 22px;
166814
+ }
166815
+ .sp-web-query-provenance {
166816
+ color: var(--grain-ink-muted);
166817
+ font-size: 11px;
166818
+ }
166584
166819
  .sp-web-query-heading input,
166585
166820
  .sp-web-query-heading textarea {
166586
166821
  width: 100%;
@@ -166796,6 +167031,18 @@ body {
166796
167031
  .sp-web-connection-detail p {
166797
167032
  color: var(--grain-ink-muted);
166798
167033
  }
167034
+ .sp-web-connection-detail .sp-web-connection-test-success {
167035
+ color: var(--vscode-testing-iconPassed, var(--sp-success));
167036
+ }
167037
+ .sp-web-connection-detail .sp-web-connection-test-error {
167038
+ color: var(--vscode-errorForeground, var(--sp-error));
167039
+ }
167040
+ .sp-web-connection-delete-confirm {
167041
+ margin-top: 16px;
167042
+ }
167043
+ .sp-web-connection-delete-confirm p {
167044
+ color: var(--grain-ink);
167045
+ }
166799
167046
  .sp-web-connection-actions {
166800
167047
  display: flex;
166801
167048
  gap: 8px;