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/connection-setup.html +79 -9
- package/dist/credential-page.html +54 -2
- package/dist/mcp-app-shell.html +31 -0
- package/dist/mcp-app.html +78 -32
- package/dist/web-app.html +460 -213
- package/out/server/standalone.js +2457 -1483
- package/package.json +2 -1
- package/server.json +2 -2
|
@@ -12745,7 +12745,10 @@ function ConnectionSetupPage({
|
|
|
12745
12745
|
/* @__PURE__ */ jsxRuntimeExports.jsx("strong", { children: "Connection failed" }),
|
|
12746
12746
|
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { children: error })
|
|
12747
12747
|
] }),
|
|
12748
|
-
tested && !error && /* @__PURE__ */ jsxRuntimeExports.
|
|
12748
|
+
tested && !error && /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "grain-connection-success", role: "status", children: [
|
|
12749
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { "aria-hidden": "true", children: "✓ " }),
|
|
12750
|
+
"Connection test successful."
|
|
12751
|
+
] }),
|
|
12749
12752
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grain-connection-grid", children: [
|
|
12750
12753
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grain-connection-field", children: [
|
|
12751
12754
|
/* @__PURE__ */ jsxRuntimeExports.jsx("label", { htmlFor: "grain-connection-type", children: "Database type" }),
|
|
@@ -12833,7 +12836,10 @@ function ConnectionSetupPage({
|
|
|
12833
12836
|
] })
|
|
12834
12837
|
] }),
|
|
12835
12838
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grain-connection-footer", children: [
|
|
12836
|
-
/* @__PURE__ */ jsxRuntimeExports.
|
|
12839
|
+
tested && !error ? /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "grain-connection-success", children: [
|
|
12840
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { "aria-hidden": "true", children: "✓ " }),
|
|
12841
|
+
"Connection test successful."
|
|
12842
|
+
] }) : 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." }),
|
|
12837
12843
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grain-connection-actions", children: [
|
|
12838
12844
|
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
12839
12845
|
"button",
|
|
@@ -12940,7 +12946,12 @@ function ConnectionSetupApp() {
|
|
|
12940
12946
|
if (saved)
|
|
12941
12947
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs("main", { className: "grain-setup-state", role: "status", children: [
|
|
12942
12948
|
/* @__PURE__ */ jsxRuntimeExports.jsx("h1", { children: "Saved." }),
|
|
12943
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { children: "Go back to your agent
|
|
12949
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { children: "Go back to your agent, and it will retry." }),
|
|
12950
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "grain-setup-workspace", children: [
|
|
12951
|
+
"To run queries yourself, run ",
|
|
12952
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("code", { children: "grain ui" }),
|
|
12953
|
+
" in a terminal to open the Grain workspace (Beta). The workspace is in beta and may be unstable."
|
|
12954
|
+
] })
|
|
12944
12955
|
] });
|
|
12945
12956
|
if (!state || !actions)
|
|
12946
12957
|
return /* @__PURE__ */ jsxRuntimeExports.jsx("main", { className: "grain-setup-state", role: "status", children: /* @__PURE__ */ jsxRuntimeExports.jsx("p", { children: message }) });
|
|
@@ -12949,13 +12960,11 @@ function ConnectionSetupApp() {
|
|
|
12949
12960
|
{
|
|
12950
12961
|
value: {
|
|
12951
12962
|
mode: "standalone",
|
|
12952
|
-
sendMessage: () =>
|
|
12953
|
-
},
|
|
12963
|
+
sendMessage: () => void 0,
|
|
12954
12964
|
callServerTool: async () => {
|
|
12955
12965
|
throw new Error("Unavailable");
|
|
12956
12966
|
},
|
|
12957
|
-
onMessage: () => () =>
|
|
12958
|
-
},
|
|
12967
|
+
onMessage: () => () => void 0,
|
|
12959
12968
|
isReady: true
|
|
12960
12969
|
},
|
|
12961
12970
|
children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
@@ -13129,11 +13138,18 @@ clientExports.createRoot(document.getElementById("root")).render(/* @__PURE__ */
|
|
|
13129
13138
|
margin: 5px 0 0;
|
|
13130
13139
|
}
|
|
13131
13140
|
.grain-connection-success {
|
|
13132
|
-
color: var(--
|
|
13133
|
-
|
|
13141
|
+
color: var(--vscode-testing-iconPassed, var(--sp-success));
|
|
13142
|
+
border: 1px solid var(--vscode-testing-iconPassed, var(--sp-success));
|
|
13143
|
+
background: color-mix(in srgb, var(--sp-success) 8%, var(--grain-surface));
|
|
13134
13144
|
padding: 10px 14px;
|
|
13135
13145
|
border-radius: var(--grain-radius-sm);
|
|
13136
13146
|
}
|
|
13147
|
+
.grain-connection-footer .grain-connection-success {
|
|
13148
|
+
color: var(--vscode-testing-iconPassed, var(--sp-success));
|
|
13149
|
+
}
|
|
13150
|
+
.grain-connection-footer-error {
|
|
13151
|
+
color: var(--vscode-errorForeground, var(--sp-error));
|
|
13152
|
+
}
|
|
13137
13153
|
.grain-connection-page :is(button, input, select, summary):focus-visible {
|
|
13138
13154
|
outline: 2px solid var(--grain-accent);
|
|
13139
13155
|
outline-offset: 2px;
|
|
@@ -17468,6 +17484,31 @@ body {
|
|
|
17468
17484
|
.sp-web-sidebar-header .sp-web-sidebar-title {
|
|
17469
17485
|
flex: 1;
|
|
17470
17486
|
}
|
|
17487
|
+
.sp-web-section-toggle,
|
|
17488
|
+
.sp-web-agent-session-toggle {
|
|
17489
|
+
border: 0;
|
|
17490
|
+
background: transparent;
|
|
17491
|
+
color: var(--grain-ink);
|
|
17492
|
+
font: inherit;
|
|
17493
|
+
text-align: left;
|
|
17494
|
+
cursor: pointer;
|
|
17495
|
+
}
|
|
17496
|
+
.sp-web-section-toggle {
|
|
17497
|
+
padding: 0;
|
|
17498
|
+
}
|
|
17499
|
+
.sp-web-agent-session-toggle {
|
|
17500
|
+
width: 100%;
|
|
17501
|
+
padding: 7px 9px;
|
|
17502
|
+
color: var(--grain-ink-muted);
|
|
17503
|
+
font-size: 11px;
|
|
17504
|
+
}
|
|
17505
|
+
.sp-web-section-toggle:focus-visible,
|
|
17506
|
+
.sp-web-agent-session-toggle:focus-visible {
|
|
17507
|
+
outline: 1px solid var(--grain-accent);
|
|
17508
|
+
}
|
|
17509
|
+
[aria-current='page'].sp-web-connection-item {
|
|
17510
|
+
background: var(--grain-surface-raised);
|
|
17511
|
+
}
|
|
17471
17512
|
.sp-web-section-add,
|
|
17472
17513
|
.sp-web-sidebar-close {
|
|
17473
17514
|
display: inline-flex;
|
|
@@ -17659,6 +17700,14 @@ body {
|
|
|
17659
17700
|
gap: 4px;
|
|
17660
17701
|
padding: 18px 24px 14px;
|
|
17661
17702
|
}
|
|
17703
|
+
.sp-web-query-heading h1 {
|
|
17704
|
+
margin: 0;
|
|
17705
|
+
font-size: 22px;
|
|
17706
|
+
}
|
|
17707
|
+
.sp-web-query-provenance {
|
|
17708
|
+
color: var(--grain-ink-muted);
|
|
17709
|
+
font-size: 11px;
|
|
17710
|
+
}
|
|
17662
17711
|
.sp-web-query-heading input,
|
|
17663
17712
|
.sp-web-query-heading textarea {
|
|
17664
17713
|
width: 100%;
|
|
@@ -17874,6 +17923,18 @@ body {
|
|
|
17874
17923
|
.sp-web-connection-detail p {
|
|
17875
17924
|
color: var(--grain-ink-muted);
|
|
17876
17925
|
}
|
|
17926
|
+
.sp-web-connection-detail .sp-web-connection-test-success {
|
|
17927
|
+
color: var(--vscode-testing-iconPassed, var(--sp-success));
|
|
17928
|
+
}
|
|
17929
|
+
.sp-web-connection-detail .sp-web-connection-test-error {
|
|
17930
|
+
color: var(--vscode-errorForeground, var(--sp-error));
|
|
17931
|
+
}
|
|
17932
|
+
.sp-web-connection-delete-confirm {
|
|
17933
|
+
margin-top: 16px;
|
|
17934
|
+
}
|
|
17935
|
+
.sp-web-connection-delete-confirm p {
|
|
17936
|
+
color: var(--grain-ink);
|
|
17937
|
+
}
|
|
17877
17938
|
.sp-web-connection-actions {
|
|
17878
17939
|
display: flex;
|
|
17879
17940
|
gap: 8px;
|
|
@@ -17913,6 +17974,15 @@ body {
|
|
|
17913
17974
|
.grain-connection-readonly {
|
|
17914
17975
|
grid-template-columns: 1fr;
|
|
17915
17976
|
}
|
|
17977
|
+
}
|
|
17978
|
+
|
|
17979
|
+
.grain-setup-workspace {
|
|
17980
|
+
color: var(--grain-ink-muted);
|
|
17981
|
+
font-size: 13px;
|
|
17982
|
+
}
|
|
17983
|
+
|
|
17984
|
+
.grain-setup-workspace code {
|
|
17985
|
+
font-family: var(--grain-font-mono);
|
|
17916
17986
|
}</style>
|
|
17917
17987
|
</head>
|
|
17918
17988
|
<body>
|
|
@@ -4351,6 +4351,31 @@ body {
|
|
|
4351
4351
|
.sp-web-sidebar-header .sp-web-sidebar-title {
|
|
4352
4352
|
flex: 1;
|
|
4353
4353
|
}
|
|
4354
|
+
.sp-web-section-toggle,
|
|
4355
|
+
.sp-web-agent-session-toggle {
|
|
4356
|
+
border: 0;
|
|
4357
|
+
background: transparent;
|
|
4358
|
+
color: var(--grain-ink);
|
|
4359
|
+
font: inherit;
|
|
4360
|
+
text-align: left;
|
|
4361
|
+
cursor: pointer;
|
|
4362
|
+
}
|
|
4363
|
+
.sp-web-section-toggle {
|
|
4364
|
+
padding: 0;
|
|
4365
|
+
}
|
|
4366
|
+
.sp-web-agent-session-toggle {
|
|
4367
|
+
width: 100%;
|
|
4368
|
+
padding: 7px 9px;
|
|
4369
|
+
color: var(--grain-ink-muted);
|
|
4370
|
+
font-size: 11px;
|
|
4371
|
+
}
|
|
4372
|
+
.sp-web-section-toggle:focus-visible,
|
|
4373
|
+
.sp-web-agent-session-toggle:focus-visible {
|
|
4374
|
+
outline: 1px solid var(--grain-accent);
|
|
4375
|
+
}
|
|
4376
|
+
[aria-current='page'].sp-web-connection-item {
|
|
4377
|
+
background: var(--grain-surface-raised);
|
|
4378
|
+
}
|
|
4354
4379
|
.sp-web-section-add,
|
|
4355
4380
|
.sp-web-sidebar-close {
|
|
4356
4381
|
display: inline-flex;
|
|
@@ -4542,6 +4567,14 @@ body {
|
|
|
4542
4567
|
gap: 4px;
|
|
4543
4568
|
padding: 18px 24px 14px;
|
|
4544
4569
|
}
|
|
4570
|
+
.sp-web-query-heading h1 {
|
|
4571
|
+
margin: 0;
|
|
4572
|
+
font-size: 22px;
|
|
4573
|
+
}
|
|
4574
|
+
.sp-web-query-provenance {
|
|
4575
|
+
color: var(--grain-ink-muted);
|
|
4576
|
+
font-size: 11px;
|
|
4577
|
+
}
|
|
4545
4578
|
.sp-web-query-heading input,
|
|
4546
4579
|
.sp-web-query-heading textarea {
|
|
4547
4580
|
width: 100%;
|
|
@@ -4757,6 +4790,18 @@ body {
|
|
|
4757
4790
|
.sp-web-connection-detail p {
|
|
4758
4791
|
color: var(--grain-ink-muted);
|
|
4759
4792
|
}
|
|
4793
|
+
.sp-web-connection-detail .sp-web-connection-test-success {
|
|
4794
|
+
color: var(--vscode-testing-iconPassed, var(--sp-success));
|
|
4795
|
+
}
|
|
4796
|
+
.sp-web-connection-detail .sp-web-connection-test-error {
|
|
4797
|
+
color: var(--vscode-errorForeground, var(--sp-error));
|
|
4798
|
+
}
|
|
4799
|
+
.sp-web-connection-delete-confirm {
|
|
4800
|
+
margin-top: 16px;
|
|
4801
|
+
}
|
|
4802
|
+
.sp-web-connection-delete-confirm p {
|
|
4803
|
+
color: var(--grain-ink);
|
|
4804
|
+
}
|
|
4760
4805
|
.sp-web-connection-actions {
|
|
4761
4806
|
display: flex;
|
|
4762
4807
|
gap: 8px;
|
|
@@ -4917,11 +4962,18 @@ body {
|
|
|
4917
4962
|
margin: 5px 0 0;
|
|
4918
4963
|
}
|
|
4919
4964
|
.grain-connection-success {
|
|
4920
|
-
color: var(--
|
|
4921
|
-
|
|
4965
|
+
color: var(--vscode-testing-iconPassed, var(--sp-success));
|
|
4966
|
+
border: 1px solid var(--vscode-testing-iconPassed, var(--sp-success));
|
|
4967
|
+
background: color-mix(in srgb, var(--sp-success) 8%, var(--grain-surface));
|
|
4922
4968
|
padding: 10px 14px;
|
|
4923
4969
|
border-radius: var(--grain-radius-sm);
|
|
4924
4970
|
}
|
|
4971
|
+
.grain-connection-footer .grain-connection-success {
|
|
4972
|
+
color: var(--vscode-testing-iconPassed, var(--sp-success));
|
|
4973
|
+
}
|
|
4974
|
+
.grain-connection-footer-error {
|
|
4975
|
+
color: var(--vscode-errorForeground, var(--sp-error));
|
|
4976
|
+
}
|
|
4925
4977
|
.grain-connection-page :is(button, input, select, summary):focus-visible {
|
|
4926
4978
|
outline: 2px solid var(--grain-accent);
|
|
4927
4979
|
outline-offset: 2px;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
6
|
+
<title>Grain Results</title>
|
|
7
|
+
<style>
|
|
8
|
+
body { margin: 0; padding: 12px; color: var(--vscode-foreground, #222); font: 13px var(--vscode-font-family, sans-serif); }
|
|
9
|
+
button { font: inherit; }
|
|
10
|
+
.row { margin: 0 0 8px; }
|
|
11
|
+
#columns { overflow-wrap: anywhere; }
|
|
12
|
+
#error { color: var(--vscode-errorForeground, #b00); }
|
|
13
|
+
#grid { width: 100%; height: 480px; border: 0; }
|
|
14
|
+
label { display: inline-flex; gap: 6px; align-items: center; }
|
|
15
|
+
</style>
|
|
16
|
+
<script type="module" crossorigin>(function(){const e=document.createElement("link").relList;if(e&&e.supports&&e.supports("modulepreload"))return;for(const t of document.querySelectorAll('link[rel="modulepreload"]'))s(t);new MutationObserver(t=>{for(const r of t)if(r.type==="childList")for(const u of r.addedNodes)u.tagName==="LINK"&&u.rel==="modulepreload"&&s(u)}).observe(document,{childList:!0,subtree:!0});function n(t){const r={};return t.integrity&&(r.integrity=t.integrity),t.referrerPolicy&&(r.referrerPolicy=t.referrerPolicy),t.crossOrigin==="use-credentials"?r.credentials="include":t.crossOrigin==="anonymous"?r.credentials="omit":r.credentials="same-origin",r}function s(t){if(t.ep)return;t.ep=!0;const r=n(t);fetch(t.href,r)}})();const l=new Map;let O=0,c,m=!1,i,f="",d=!1;function p(o,e={}){const n=++O;return new Promise(s=>{l.set(n,s),window.parent.postMessage({jsonrpc:"2.0",id:n,method:o,params:e},"*"),window.setTimeout(()=>{l.get(n)&&(l.delete(n),s({jsonrpc:"2.0",id:n,error:{message:"The host did not respond"}}))},1e4)})}function a(o){const e=document.querySelector("#error");e&&(e.textContent=o)}function y(o){const e=document.querySelector("#open");e&&(e.textContent=o)}function h(o){c?.contentWindow?.postMessage(o,"*")}function v(){!i||!m||h({jsonrpc:"2.0",method:"ui/notifications/tool-result",params:{structuredContent:i}})}window.addEventListener("message",o=>{const e=o.data;if(!(!e||e.jsonrpc!=="2.0")){if(o.source===c?.contentWindow){if(e.id!==void 0){const n=`frame-${String(e.id)}`;l.set(n,s=>{c?.contentWindow?.postMessage({...s,id:e.id},"*")}),window.parent.postMessage({...e,id:n},"*")}else window.parent.postMessage(e,"*"),e.method==="ui/notifications/initialized"&&(m=!0,v());return}if(e.id!==void 0&&l.has(e.id)){l.get(e.id)?.(e),l.delete(e.id);return}typeof e.method=="string"&&e.method.startsWith("ui/notifications/")&&(e.method==="ui/notifications/tool-result"?C(e.params):h(e))}});function C(o){if(!o||!o.structuredContent||typeof o.structuredContent!="object")return;i=o.structuredContent,v();const n=i.route==="editor",s=document.querySelector("#toggle-wrap");s&&(s.hidden=!n),y(n?"Open in Grain":"Open in workspace"),f=typeof i.cardPreferenceKey=="string"?i.cardPreferenceKey:"";const t=document.querySelector("#title"),r=document.querySelector("#count"),u=document.querySelector("#columns"),g=document.querySelector("#status");t&&(t.textContent=String(i.title||i.tabId||"Query result")),r&&(r.textContent=`${Number(i.rowCount??0).toLocaleString()} rows`),u&&(u.textContent=`Columns: ${(i.columns||[]).map(S=>S.name||"").join(", ")||"none"}`),g&&(g.textContent=`Status: ${i.status||"unknown"}`);try{d=f?window.localStorage.getItem(f)==="on":!1}catch{d=!1}const w=document.querySelector("#toggle");w&&(w.checked=d),(!n||d)&&b()}async function b(){if(c||!i)return;a("");const o=await p("resources/read",{uri:"ui://sql-preview/results-grid-full"}),n=o.result?.contents?.find(s=>typeof s.text=="string")?.text;if(o.error||!n){const s=i.route==="editor";a(s?"The full results view is unavailable. Open in Grain to see the result.":"The full results view is unavailable. Open in workspace to see the result."),y(s?"Open in Grain":"Open in workspace");return}c=document.createElement("iframe"),m=!1,c.id="grid",c.title="Full query results",c.srcdoc=n,document.body.append(c),document.querySelector("#card")?.classList.add("expanded")}document.querySelector("#open")?.addEventListener("click",async()=>{if(!i?.sessionId||!i.tabId){a("This result cannot be opened yet.");return}const o=i.route==="editor"?"open_in_grain":"open_in_workspace",e=await p("tools/call",{name:"open_result_view",arguments:{sessionId:i.sessionId,tabId:i.tabId,button:o}}),n=e.result,t=(n?.content||[]).map(u=>u.text).filter(Boolean).join(`
|
|
17
|
+
`),r=n?.structuredContent?.url||t.match(/https?:\/\/[^\s)]+/)?.[0];if(r){if(!(await p("ui/open-link",{url:r})).error){a(t&&t!==r?t:"Opened the result workspace.");return}p("tools/call",{name:"record_ui_event",arguments:{event:"mcp_result_view_opened",button:o}}).catch(()=>{}),a(`${t||"Open this result in your browser:"}
|
|
18
|
+
${r}`);return}t&&a(t),e.error&&a(`${o==="open_in_grain"?"Open in Grain":"Open in workspace"} is not available yet.`)});document.querySelector("#toggle")?.addEventListener("change",o=>{d=o.currentTarget.checked;try{f&&window.localStorage.setItem(f,d?"on":"off")}catch{d=o.currentTarget.checked}d?b():(c?.remove(),c=void 0,document.querySelector("#card")?.classList.remove("expanded"))});p("ui/initialize",{appInfo:{name:"Grain Results Card",version:"1.0.0"},appCapabilities:{},protocolVersion:"2025-11-25"}).then(()=>window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/initialized"},"*"));</script>
|
|
19
|
+
</head>
|
|
20
|
+
<body>
|
|
21
|
+
<main id="card">
|
|
22
|
+
<h2 id="title" class="row">Query result</h2>
|
|
23
|
+
<div id="count" class="row"></div>
|
|
24
|
+
<div id="columns" class="row"></div>
|
|
25
|
+
<div id="status" class="row"></div>
|
|
26
|
+
<div class="row"><button id="open">Open in Grain</button></div>
|
|
27
|
+
<label id="toggle-wrap"><input id="toggle" type="checkbox">Show in chat</label>
|
|
28
|
+
<div id="error" role="status" aria-live="polite"></div>
|
|
29
|
+
</main>
|
|
30
|
+
</body>
|
|
31
|
+
</html>
|
package/dist/mcp-app.html
CHANGED
|
@@ -12521,6 +12521,72 @@ function BaseHostProvider({
|
|
|
12521
12521
|
}) {
|
|
12522
12522
|
return /* @__PURE__ */ jsxRuntimeExports.jsx(HostContext.Provider, { value, children });
|
|
12523
12523
|
}
|
|
12524
|
+
function useWorkspaceResultTarget() {
|
|
12525
|
+
const [targets, setTargets] = reactExports.useState({});
|
|
12526
|
+
const [resetToken, setResetToken] = reactExports.useState(0);
|
|
12527
|
+
const remember = reactExports.useCallback((tabId, structured) => {
|
|
12528
|
+
setResetToken((current) => current + 1);
|
|
12529
|
+
const sessionId = structured?.["sessionId"];
|
|
12530
|
+
const resultTabId = structured?.["tabId"];
|
|
12531
|
+
if (structured?.["route"] === "chat" && typeof sessionId === "string" && typeof resultTabId === "string") {
|
|
12532
|
+
setTargets((current) => ({ ...current, [tabId]: { sessionId, tabId: resultTabId } }));
|
|
12533
|
+
}
|
|
12534
|
+
}, []);
|
|
12535
|
+
return { targetForTab: (tabId) => targets[tabId], remember, resetToken };
|
|
12536
|
+
}
|
|
12537
|
+
function WorkspaceResultAction({
|
|
12538
|
+
target,
|
|
12539
|
+
resetToken,
|
|
12540
|
+
callServerTool,
|
|
12541
|
+
sendMessage
|
|
12542
|
+
}) {
|
|
12543
|
+
const [linkError, setLinkError] = reactExports.useState("");
|
|
12544
|
+
reactExports.useEffect(() => setLinkError(""), [resetToken]);
|
|
12545
|
+
const openWorkspace = async () => {
|
|
12546
|
+
if (!target) {
|
|
12547
|
+
return;
|
|
12548
|
+
}
|
|
12549
|
+
setLinkError("");
|
|
12550
|
+
try {
|
|
12551
|
+
const response = await callServerTool("open_result_view", {
|
|
12552
|
+
...target,
|
|
12553
|
+
button: "open_in_workspace"
|
|
12554
|
+
});
|
|
12555
|
+
const structured = response.structuredContent;
|
|
12556
|
+
if (typeof structured?.url === "string") {
|
|
12557
|
+
try {
|
|
12558
|
+
await sendMessage("openLink", { url: structured.url });
|
|
12559
|
+
} catch {
|
|
12560
|
+
void callServerTool("record_ui_event", {
|
|
12561
|
+
event: "mcp_result_view_opened",
|
|
12562
|
+
button: "open_in_workspace"
|
|
12563
|
+
}).catch(() => void 0);
|
|
12564
|
+
setLinkError(structured.url);
|
|
12565
|
+
}
|
|
12566
|
+
} else if (structured?.openedInEditor === true) {
|
|
12567
|
+
setLinkError("Opened the result in Grain.");
|
|
12568
|
+
} else {
|
|
12569
|
+
throw new Error("The workspace link is unavailable");
|
|
12570
|
+
}
|
|
12571
|
+
} catch {
|
|
12572
|
+
setLinkError("Could not open this result in the workspace.");
|
|
12573
|
+
}
|
|
12574
|
+
};
|
|
12575
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
12576
|
+
target && /* @__PURE__ */ jsxRuntimeExports.jsx("button", { className: "sp-btn", onClick: () => void openWorkspace(), children: "Open in workspace" }),
|
|
12577
|
+
linkError && /* @__PURE__ */ jsxRuntimeExports.jsx("pre", { className: "sp-error-bar", role: "status", "aria-live": "polite", children: linkError })
|
|
12578
|
+
] });
|
|
12579
|
+
}
|
|
12580
|
+
function copyResultToClipboard(result, copyText) {
|
|
12581
|
+
if (!result || result.rows.length === 0) {
|
|
12582
|
+
return;
|
|
12583
|
+
}
|
|
12584
|
+
const header = result.columns.map((column) => column.name).join(" ");
|
|
12585
|
+
const rows = result.rows.map(
|
|
12586
|
+
(row) => result.columns.map((_, index) => String(row[index] ?? "")).join(" ")
|
|
12587
|
+
);
|
|
12588
|
+
copyText([header, ...rows].join("\n"));
|
|
12589
|
+
}
|
|
12524
12590
|
const createStoreImpl = (createState) => {
|
|
12525
12591
|
let state;
|
|
12526
12592
|
const listeners = /* @__PURE__ */ new Set();
|
|
@@ -73210,7 +73276,6 @@ const DataGrid = reactExports.forwardRef(function DataGrid2({
|
|
|
73210
73276
|
nativeTheme = false,
|
|
73211
73277
|
disableFilters = false,
|
|
73212
73278
|
autoSizeStrategy,
|
|
73213
|
-
fillWidth = false,
|
|
73214
73279
|
onCellDoubleClick
|
|
73215
73280
|
}, ref) {
|
|
73216
73281
|
const trackUi = useTrackUi();
|
|
@@ -73379,21 +73444,6 @@ const DataGrid = reactExports.forwardRef(function DataGrid2({
|
|
|
73379
73444
|
}),
|
|
73380
73445
|
[data, getNodeValue, copyIncludesHeaders]
|
|
73381
73446
|
);
|
|
73382
|
-
const userResizedRef = reactExports.useRef(false);
|
|
73383
|
-
const fillSpareWidth = reactExports.useCallback((e2) => {
|
|
73384
|
-
if (userResizedRef.current) return;
|
|
73385
|
-
const body = e2.api.getHorizontalPixelRange?.();
|
|
73386
|
-
const columns = (e2.api.getAllDisplayedColumns?.() ?? []).filter((c) => !c.getPinned());
|
|
73387
|
-
if (!body || columns.length === 0) return;
|
|
73388
|
-
const used = columns.reduce((sum2, c) => sum2 + c.getActualWidth(), 0);
|
|
73389
|
-
if (used < body.right - body.left) e2.api.sizeColumnsToFit();
|
|
73390
|
-
}, []);
|
|
73391
|
-
const noteUserResize = reactExports.useCallback((e2) => {
|
|
73392
|
-
if (e2.source === "uiColumnResized" && e2.finished) userResizedRef.current = true;
|
|
73393
|
-
}, []);
|
|
73394
|
-
reactExports.useEffect(() => {
|
|
73395
|
-
userResizedRef.current = false;
|
|
73396
|
-
}, [data?.columns]);
|
|
73397
73447
|
const columnDefs = reactExports.useMemo(() => {
|
|
73398
73448
|
if (!data?.columns) return [];
|
|
73399
73449
|
const isInRange = (rowIndex, displayedColIndex) => {
|
|
@@ -73578,11 +73628,6 @@ const DataGrid = reactExports.forwardRef(function DataGrid2({
|
|
|
73578
73628
|
onGridReady: (p2) => {
|
|
73579
73629
|
apiRef.current = p2.api;
|
|
73580
73630
|
},
|
|
73581
|
-
...fillWidth ? {
|
|
73582
|
-
onFirstDataRendered: fillSpareWidth,
|
|
73583
|
-
onGridSizeChanged: fillSpareWidth,
|
|
73584
|
-
onColumnResized: noteUserResize
|
|
73585
|
-
} : {},
|
|
73586
73631
|
rowData: data.rows,
|
|
73587
73632
|
columnDefs,
|
|
73588
73633
|
defaultColDef: {
|
|
@@ -147891,6 +147936,7 @@ function App() {
|
|
|
147891
147936
|
updateTab
|
|
147892
147937
|
} = useAppStore();
|
|
147893
147938
|
const [isAppMode, setIsAppMode] = reactExports.useState(true);
|
|
147939
|
+
const { targetForTab, remember, resetToken } = useWorkspaceResultTarget();
|
|
147894
147940
|
const hasReceivedToolCall = reactExports.useRef(false);
|
|
147895
147941
|
const hasFallbackFired = reactExports.useRef(false);
|
|
147896
147942
|
const gridRef = reactExports.useRef(null);
|
|
@@ -148005,6 +148051,7 @@ function App() {
|
|
|
148005
148051
|
const structured = params?.structuredContent && typeof params.structuredContent === "object" ? params.structuredContent : void 0;
|
|
148006
148052
|
const resultSql = entry?.sql ?? (typeof rawCallKey === "string" ? rawCallKey : typeof structured?.["query"] === "string" ? structured["query"] : "");
|
|
148007
148053
|
const tabId = entry?.tabId ?? createTab(resultSql, false);
|
|
148054
|
+
remember(tabId, structured);
|
|
148008
148055
|
setIsAppMode(true);
|
|
148009
148056
|
if (params?.isError) {
|
|
148010
148057
|
const text = params.content?.find((c) => c.type === "text")?.text;
|
|
@@ -148230,14 +148277,8 @@ function App() {
|
|
|
148230
148277
|
copyTextSafe(csvString);
|
|
148231
148278
|
}
|
|
148232
148279
|
};
|
|
148233
|
-
const
|
|
148234
|
-
|
|
148235
|
-
const header = result.columns.map((c) => c.name).join(" ");
|
|
148236
|
-
const tsvRows = result.rows.map(
|
|
148237
|
-
(row) => result.columns.map((_, i2) => String(row[i2] ?? "")).join(" ")
|
|
148238
|
-
);
|
|
148239
|
-
copyTextSafe([header, ...tsvRows].join("\n"));
|
|
148240
|
-
};
|
|
148280
|
+
const workspaceTarget = targetForTab(activeTab?.id ?? "");
|
|
148281
|
+
const handleCopy = () => copyResultToClipboard(result, copyTextSafe);
|
|
148241
148282
|
if (!isReady || !activeTab)
|
|
148242
148283
|
return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { style: { display: "flex", justifyContent: "center", padding: "40px" }, children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "spinner" }) });
|
|
148243
148284
|
const showTabs = tabs.length > 1 || !isAppMode;
|
|
@@ -148297,7 +148338,8 @@ function App() {
|
|
|
148297
148338
|
result && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "sp-row-count", children: [
|
|
148298
148339
|
/* @__PURE__ */ jsxRuntimeExports.jsx("strong", { children: result.rowCount ?? result.rows.length }),
|
|
148299
148340
|
" rows"
|
|
148300
|
-
] })
|
|
148341
|
+
] }),
|
|
148342
|
+
result && /* @__PURE__ */ jsxRuntimeExports.jsx(WorkspaceResultAction, { target: workspaceTarget, resetToken, callServerTool, sendMessage })
|
|
148301
148343
|
] }),
|
|
148302
148344
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "sp-result-header-right", children: result && result.rows.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
148303
148345
|
/* @__PURE__ */ jsxRuntimeExports.jsx("button", { className: "sp-btn", onClick: handleCopy, "aria-label": "Copy results", children: "Copy" }),
|
|
@@ -161960,11 +162002,15 @@ function MCPHostProvider({ children }) {
|
|
|
161960
162002
|
};
|
|
161961
162003
|
}
|
|
161962
162004
|
});
|
|
161963
|
-
const sendMessage = reactExports.useCallback((command, payload) => {
|
|
162005
|
+
const sendMessage = reactExports.useCallback(async (command, payload) => {
|
|
161964
162006
|
if (!appRef.current) return;
|
|
161965
162007
|
switch (command) {
|
|
161966
162008
|
case "openLink":
|
|
161967
|
-
if (appRef.current.openLink)
|
|
162009
|
+
if (appRef.current.openLink) {
|
|
162010
|
+
await appRef.current.openLink(payload);
|
|
162011
|
+
} else {
|
|
162012
|
+
throw new Error("The host cannot open links");
|
|
162013
|
+
}
|
|
161968
162014
|
break;
|
|
161969
162015
|
default:
|
|
161970
162016
|
console.warn("[MCPHost] Unknown command sent:", command);
|