@yejiming/dsh-data-agent 0.0.1

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/lib/client.js ADDED
@@ -0,0 +1,1157 @@
1
+ window.__ModuleLoader__.load({
2
+ id: "@yejiming/dsh-data-agent",
3
+ factory: (require) => {
4
+ var module = { exports: {} };
5
+ var exports = module.exports;
6
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
7
+ let react = require("react");
8
+ let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
9
+ let react_jsx_runtime = require("react/jsx-runtime");
10
+ //#region src/client/persistence.ts
11
+ /** localStorage key holding the most recent connection configuration. */
12
+ const CONNECTION_STORAGE_KEY = "dsh-data-agent.connection.v1";
13
+ /** The default storage face (localStorage; unavailable → degraded no-op). */
14
+ function defaultStorage() {
15
+ try {
16
+ if (typeof localStorage !== "undefined") {
17
+ const probe = "__dsh_probe__";
18
+ localStorage.setItem(probe, "1");
19
+ localStorage.removeItem(probe);
20
+ return localStorage;
21
+ }
22
+ } catch {}
23
+ }
24
+ /** Validate one parsed storage value into a SavedConnection (or null). */
25
+ function parseSaved(value) {
26
+ if (value === null || typeof value !== "object" || Array.isArray(value)) return null;
27
+ const candidate = value;
28
+ const type = candidate.type;
29
+ if (type !== "mysql" && type !== "postgres" && type !== "sqlite" && type !== "oracle" && type !== "hive" && type !== "impala") return null;
30
+ const database = candidate.database;
31
+ if (typeof database !== "string") return null;
32
+ const saved = {
33
+ type,
34
+ database,
35
+ savedAt: typeof candidate.savedAt === "string" ? candidate.savedAt : ""
36
+ };
37
+ if (typeof candidate.host === "string") saved.host = candidate.host;
38
+ if (typeof candidate.port === "number" && Number.isInteger(candidate.port)) saved.port = candidate.port;
39
+ if (typeof candidate.user === "string") saved.user = candidate.user;
40
+ if (typeof candidate.password === "string") saved.password = candidate.password;
41
+ return saved;
42
+ }
43
+ /** Save one connection configuration (best-effort; storage failures degrade silently). */
44
+ function saveConnection(connection, storage = defaultStorage()) {
45
+ if (storage === void 0) return;
46
+ try {
47
+ storage.setItem(CONNECTION_STORAGE_KEY, JSON.stringify(connection));
48
+ } catch {}
49
+ }
50
+ /** Load the saved connection configuration; null when absent or malformed. */
51
+ function loadConnection(storage = defaultStorage()) {
52
+ if (storage === void 0) return null;
53
+ try {
54
+ const raw = storage.getItem(CONNECTION_STORAGE_KEY);
55
+ if (raw === null) return null;
56
+ return parseSaved(JSON.parse(raw));
57
+ } catch {
58
+ return null;
59
+ }
60
+ }
61
+ //#endregion
62
+ //#region \0dsh-css:/Users/yejiming/Desktop/OpenSource/dsh-data-agent/src/client/DataAgentWorkbench.module.css.mjs
63
+ const css = ".Sv3uVW_workbench{box-sizing:border-box;font-family:var(--dsw-font-family,-apple-system, BlinkMacSystemFont, \"Segoe UI\", \"PingFang SC\", \"Microsoft YaHei\", sans-serif);color:var(--dsw-alias-label-primary,inherit);flex-direction:column;gap:10px;font-size:13px;line-height:1.5;display:flex}.Sv3uVW_strip{width:100%}.Sv3uVW_docked{width:100%;max-height:55vh;overflow-y:auto}.Sv3uVW_rail{z-index:8;border-right:1px solid var(--dsw-alias-border-l2,#80808059);background:var(--dsw-specific-sidebar-fill,var(--dsw-alias-bg-layer-1,#ffffff08));padding:12px;overflow-y:auto}html.Sv3uVW_da-split [data-phase=active] [data-conversation-scroll]>:first-child{margin-left:380px}html.Sv3uVW_da-split [data-phase=active] [data-composer-seat]{padding-left:380px}.Sv3uVW_sections{flex-direction:column;gap:12px;display:flex}.Sv3uVW_card{border:1px solid var(--dsw-alias-border-l2,#80808059);border-radius:12px;flex-direction:column;gap:10px;padding:12px 14px;display:flex}.Sv3uVW_cardTitle{text-transform:uppercase;letter-spacing:.06em;color:var(--dsw-alias-label-tertiary,#808080b3);align-items:center;gap:6px;font-size:11px;font-weight:600;display:flex}.Sv3uVW_titleIcon{width:14px;height:14px;color:var(--dsw-alias-label-secondary,#808080cc);flex:none}.Sv3uVW_fieldGrid{flex-direction:column;gap:10px;display:flex}.Sv3uVW_fieldRow2{grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:10px;display:grid}.Sv3uVW_field{flex-direction:column;gap:4px;min-width:0;display:flex}.Sv3uVW_label{color:var(--dsw-alias-label-secondary,#808080b3);font-size:11px;font-weight:500}.Sv3uVW_input{box-sizing:border-box;border:1px solid var(--dsw-alias-border-l2,#80808059);background:var(--dsw-alias-bg-layer-2,#ffffff0a);width:100%;height:32px;color:var(--dsw-alias-label-primary,inherit);font:inherit;border-radius:8px;padding:0 10px;font-size:13px;transition:border-color .15s ease-out,box-shadow .15s ease-out}.Sv3uVW_input::placeholder{color:var(--dsw-alias-label-caption,#80808080)}.Sv3uVW_input:focus-visible,.Sv3uVW_input:focus{border-color:var(--dsw-alias-button-info-fill,#3b82f6);box-shadow:0 0 0 3px color-mix(in srgb, var(--dsw-alias-button-info-fill,#3b82f6) 18%, transparent);outline:none}.Sv3uVW_input:disabled{opacity:.55}select.Sv3uVW_input{-webkit-appearance:none;appearance:none;cursor:pointer;background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath d='M3 4.5L6 7.5L9 4.5' fill='none' stroke='%23777' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E\");background-position:right 10px center;background-repeat:no-repeat;padding-right:28px}.Sv3uVW_actions{align-items:center;gap:8px;margin-top:2px;display:flex}.Sv3uVW_actions>.Sv3uVW_primary,.Sv3uVW_actions>.Sv3uVW_ghost{flex:1}.Sv3uVW_primary,.Sv3uVW_ghost{height:32px;font:inherit;cursor:pointer;border:1px solid #0000;border-radius:8px;justify-content:center;align-items:center;gap:6px;padding:0 14px;font-size:13px;font-weight:500;transition:background-color .15s ease-out,border-color .15s ease-out,opacity .15s ease-out;display:inline-flex}.Sv3uVW_primary{background:var(--dsw-alias-button-info-fill,#3b82f6);color:#fff}.Sv3uVW_primary:hover:not(:disabled){background:var(--dsw-alias-button-info-hover,#3573e0)}.Sv3uVW_primary:active:not(:disabled){background:var(--dsw-static-deepseek-600,#2f5fc0)}.Sv3uVW_ghost{border-color:var(--dsw-alias-border-l2,#80808059);color:var(--dsw-alias-label-primary,inherit);background:0 0}.Sv3uVW_ghost:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover,#80808014)}.Sv3uVW_ghost:active:not(:disabled){background:var(--dsw-alias-interactive-bg-active,#80808024)}.Sv3uVW_primary:focus-visible,.Sv3uVW_ghost:focus-visible{box-shadow:0 0 0 3px color-mix(in srgb, var(--dsw-alias-button-info-fill,#3b82f6) 25%, transparent);outline:none}.Sv3uVW_primary:disabled,.Sv3uVW_ghost:disabled{opacity:.45;cursor:default}.Sv3uVW_small{border-radius:6px;height:24px;padding:0 10px;font-size:12px}.Sv3uVW_hint{color:var(--dsw-alias-label-tertiary,#80808099);font-size:12px}.Sv3uVW_summaryRow{align-items:center;gap:8px;min-height:28px;display:flex}.Sv3uVW_statusOk{color:var(--dsw-alias-state-success-primary,#22c55e);flex:none;align-items:center;gap:5px;font-size:12px;font-weight:500;display:inline-flex}.Sv3uVW_summaryType{border:1px solid var(--dsw-alias-border-l2,#80808059);background:var(--dsw-alias-bg-layer-2,#ffffff0a);font-family:var(--ds-font-family-code,ui-monospace, SFMono-Regular, Menlo, Consolas, monospace);color:var(--dsw-alias-label-secondary,#808080cc);border-radius:999px;flex:none;padding:2px 8px;font-size:11px}.Sv3uVW_summaryDb{text-overflow:ellipsis;white-space:nowrap;min-width:0;font-family:var(--ds-font-family-code,ui-monospace, SFMono-Regular, Menlo, Consolas, monospace);flex:1;font-size:12px;overflow:hidden}.Sv3uVW_summaryActions{flex:none;gap:6px;display:flex}.Sv3uVW_browseRow{border:1px solid var(--dsw-alias-border-l2,#80808059);background:var(--dsw-alias-bg-layer-2,#ffffff0a);width:100%;height:36px;color:var(--dsw-alias-label-primary,inherit);font:inherit;text-align:left;cursor:pointer;border-radius:8px;align-items:center;gap:8px;padding:0 12px;font-size:13px;font-weight:500;transition:background-color .15s ease-out,border-color .15s ease-out;display:flex}.Sv3uVW_browseRow:hover{background:var(--dsw-alias-interactive-bg-hover,#80808014);border-color:var(--dsw-alias-border-l3,#80808080)}.Sv3uVW_browseRow:focus-visible{border-color:var(--dsw-alias-button-info-fill,#3b82f6);box-shadow:0 0 0 3px color-mix(in srgb, var(--dsw-alias-button-info-fill,#3b82f6) 18%, transparent);outline:none}.Sv3uVW_browseIcon{width:14px;height:14px;color:var(--dsw-alias-button-info-fill,#3b82f6);flex:none}.Sv3uVW_browseChevron{width:12px;height:12px;color:var(--dsw-alias-label-tertiary,#80808099);flex:none;margin-left:auto}.Sv3uVW_sqlInput{box-sizing:border-box;border:1px solid var(--dsw-alias-border-l2,#80808059);background:var(--dsw-alias-bg-layer-2,#ffffff0a);width:100%;min-height:190px;color:var(--dsw-alias-label-primary,inherit);font-family:var(--ds-font-family-code,ui-monospace, SFMono-Regular, Menlo, Consolas, monospace);resize:vertical;border-radius:10px;padding:10px 12px;font-size:12.5px;line-height:1.6;transition:border-color .15s ease-out,box-shadow .15s ease-out}.Sv3uVW_sqlInput::placeholder{color:var(--dsw-alias-label-caption,#80808080)}.Sv3uVW_sqlInput:focus-visible,.Sv3uVW_sqlInput:focus{border-color:var(--dsw-alias-button-info-fill,#3b82f6);box-shadow:0 0 0 3px color-mix(in srgb, var(--dsw-alias-button-info-fill,#3b82f6) 18%, transparent);outline:none}.Sv3uVW_sqlInput:disabled{opacity:.55}.Sv3uVW_sqlActions{justify-content:flex-end;align-items:center;gap:10px;display:flex}.Sv3uVW_sqlActions .Sv3uVW_primary{flex:none;min-width:92px}.Sv3uVW_shortcutHint{color:var(--dsw-alias-label-caption,#80808080);font-size:11.5px}.Sv3uVW_sqlResult{border:1px solid var(--dsw-alias-border-l1,#80808033);background:var(--dsw-alias-markdown-code-block,#ffffff0a);font-family:var(--ds-font-family-code,ui-monospace, SFMono-Regular, Menlo, Consolas, monospace);white-space:pre-wrap;word-break:break-word;border-radius:8px;max-height:200px;margin:0;padding:10px 12px;font-size:11.5px;line-height:1.55;overflow-y:auto}.Sv3uVW_errorBar{border:1px solid var(--dsw-alias-state-error-secondary,#ef444480);background:var(--dsw-alias-interactive-bg-hover-danger,#ef444414);border-radius:10px;flex-direction:column;gap:3px;padding:10px 12px;display:flex}.Sv3uVW_errorHead{color:var(--dsw-alias-state-error-primary,#ef4444);align-items:center;gap:6px;font-size:12px;font-weight:600;display:flex}.Sv3uVW_errorIcon{flex:none;width:14px;height:14px}.Sv3uVW_errorText{white-space:pre-wrap;word-break:break-word;font-size:12px}.Sv3uVW_schemaModal{width:min(900px,94vw)}.Sv3uVW_modalBody{align-items:stretch;gap:20px;height:min(540px,58vh);display:flex}.Sv3uVW_modalCol{flex-direction:column;flex:1;gap:8px;min-width:0;min-height:0;display:flex}.Sv3uVW_modalColTitle{text-transform:uppercase;letter-spacing:.06em;color:var(--dsw-alias-label-tertiary,#808080b3);flex:none;align-items:center;gap:6px;font-size:11px;font-weight:600;display:flex}.Sv3uVW_colCount{border:1px solid var(--dsw-alias-border-l1,#80808033);background:var(--dsw-alias-bg-layer-2,#ffffff0a);color:var(--dsw-alias-label-secondary,#808080cc);border-radius:999px;flex:none;padding:1px 7px;font-size:10px;font-weight:500}.Sv3uVW_treeScroll{flex:1;min-height:0;padding-right:4px;overflow-y:auto}.Sv3uVW_tree{flex-direction:column;gap:1px;margin:0;padding:0;list-style:none;display:flex}.Sv3uVW_treeNode{flex-direction:column;display:flex}.Sv3uVW_treeItem{width:100%;min-height:28px;color:var(--dsw-alias-label-primary,inherit);font:inherit;text-align:left;cursor:pointer;background:0 0;border:none;border-radius:7px;align-items:center;gap:6px;padding:0 8px;font-size:12.5px;display:flex}.Sv3uVW_treeItem:hover{background:var(--dsw-alias-interactive-bg-hover,#80808014)}.Sv3uVW_treeItem.Sv3uVW_active,.Sv3uVW_treeItem.Sv3uVW_active:hover{background:var(--dsw-alias-interactive-bg-active,#3b82f62e)}.Sv3uVW_treeChevron{width:12px;height:12px;color:var(--dsw-alias-label-tertiary,#80808099);flex:none;transition:transform .15s ease-out}.Sv3uVW_treeChevron.Sv3uVW_open{transform:rotate(90deg)}.Sv3uVW_treeIcon{width:14px;height:14px;color:var(--dsw-alias-label-secondary,#808080cc);flex:none}.Sv3uVW_treeItem.Sv3uVW_active .Sv3uVW_treeIcon{color:var(--dsw-alias-button-info-fill,#3b82f6)}.Sv3uVW_treeName{text-overflow:ellipsis;white-space:nowrap;min-width:0;font-family:var(--ds-font-family-code,ui-monospace, SFMono-Regular, Menlo, Consolas, monospace);flex:1;font-size:12px;overflow:hidden}.Sv3uVW_treeCount{border:1px solid var(--dsw-alias-border-l1,#80808033);background:var(--dsw-alias-bg-layer-2,#ffffff0a);color:var(--dsw-alias-label-secondary,#808080cc);border-radius:999px;flex:none;padding:0 6px;font-size:10px}.Sv3uVW_treeChildren{border-left:1px solid var(--dsw-alias-border-l2,#80808059);flex-direction:column;gap:1px;margin-left:12px;padding-left:10px;display:flex}.Sv3uVW_colScroll{border:1px solid var(--dsw-alias-border-l1,#80808033);border-radius:8px;flex:1;min-height:0;overflow:auto}.Sv3uVW_columnsTable{border-collapse:collapse;width:100%;font-family:var(--ds-font-family-code,ui-monospace, SFMono-Regular, Menlo, Consolas, monospace);font-size:12px}.Sv3uVW_columnsTable th{z-index:1;text-align:left;text-transform:uppercase;letter-spacing:.05em;color:var(--dsw-alias-label-tertiary,#808080b3);background:var(--dsw-alias-bg-layer-2,#ffffff0a);border-bottom:1px solid var(--dsw-alias-border-l2,#80808059);padding:7px 10px;font-size:10.5px;font-weight:600;position:sticky;top:0}.Sv3uVW_columnsTable td{border-bottom:1px solid var(--dsw-alias-border-l1,#80808033);color:var(--dsw-alias-label-primary,inherit);padding:5px 10px}.Sv3uVW_columnsTable tbody tr:hover td{background:var(--dsw-alias-interactive-bg-hover,#80808014)}.Sv3uVW_typeCell{color:var(--dsw-alias-label-secondary,#808080cc)}.Sv3uVW_nullCell{color:var(--dsw-alias-label-caption,#80808080);font-size:11px}.Sv3uVW_emptyState{border:1px dashed var(--dsw-alias-border-l2,#80808059);min-height:0;color:var(--dsw-alias-label-tertiary,#808080b3);border-radius:8px;flex-direction:column;flex:1;justify-content:center;align-items:center;gap:8px;display:flex}.Sv3uVW_emptyStateIcon{width:20px;height:20px;color:var(--dsw-alias-label-dimmed,#80808066)}.Sv3uVW_emptyStateText{font-size:12px}.Sv3uVW_modalHint{color:var(--dsw-alias-label-caption,#80808080);flex:none;align-items:center;gap:6px;margin-top:2px;font-size:11.5px;display:flex}@media (width<=640px){.Sv3uVW_modalBody{flex-direction:column;height:auto}.Sv3uVW_treeScroll{flex:none;height:300px}.Sv3uVW_colScroll{flex:none;height:240px}.Sv3uVW_emptyState{flex:none;height:120px}}";
64
+ const tagId = "@yejiming/dsh-data-agent/DataAgentWorkbench.module.css";
65
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
66
+ const tag = document.createElement("style");
67
+ tag.dataset.plugin = "@yejiming/dsh-data-agent";
68
+ tag.dataset.pluginCss = tagId;
69
+ tag.textContent = css;
70
+ document.head.appendChild(tag);
71
+ }
72
+ var DataAgentWorkbench_module_css_default = {
73
+ "small": "Sv3uVW_small",
74
+ "treeCount": "Sv3uVW_treeCount",
75
+ "sqlActions": "Sv3uVW_sqlActions",
76
+ "statusOk": "Sv3uVW_statusOk",
77
+ "colScroll": "Sv3uVW_colScroll",
78
+ "ghost": "Sv3uVW_ghost",
79
+ "summaryType": "Sv3uVW_summaryType",
80
+ "summaryActions": "Sv3uVW_summaryActions",
81
+ "browseRow": "Sv3uVW_browseRow",
82
+ "errorIcon": "Sv3uVW_errorIcon",
83
+ "schemaModal": "Sv3uVW_schemaModal",
84
+ "primary": "Sv3uVW_primary",
85
+ "errorBar": "Sv3uVW_errorBar",
86
+ "tree": "Sv3uVW_tree",
87
+ "active": "Sv3uVW_active",
88
+ "modalHint": "Sv3uVW_modalHint",
89
+ "treeScroll": "Sv3uVW_treeScroll",
90
+ "browseChevron": "Sv3uVW_browseChevron",
91
+ "errorText": "Sv3uVW_errorText",
92
+ "strip": "Sv3uVW_strip",
93
+ "docked": "Sv3uVW_docked",
94
+ "typeCell": "Sv3uVW_typeCell",
95
+ "summaryDb": "Sv3uVW_summaryDb",
96
+ "label": "Sv3uVW_label",
97
+ "emptyStateText": "Sv3uVW_emptyStateText",
98
+ "shortcutHint": "Sv3uVW_shortcutHint",
99
+ "rail": "Sv3uVW_rail",
100
+ "card": "Sv3uVW_card",
101
+ "modalBody": "Sv3uVW_modalBody",
102
+ "treeChevron": "Sv3uVW_treeChevron",
103
+ "emptyState": "Sv3uVW_emptyState",
104
+ "treeNode": "Sv3uVW_treeNode",
105
+ "modalCol": "Sv3uVW_modalCol",
106
+ "treeChildren": "Sv3uVW_treeChildren",
107
+ "actions": "Sv3uVW_actions",
108
+ "hint": "Sv3uVW_hint",
109
+ "field": "Sv3uVW_field",
110
+ "columnsTable": "Sv3uVW_columnsTable",
111
+ "nullCell": "Sv3uVW_nullCell",
112
+ "workbench": "Sv3uVW_workbench",
113
+ "cardTitle": "Sv3uVW_cardTitle",
114
+ "sqlInput": "Sv3uVW_sqlInput",
115
+ "open": "Sv3uVW_open",
116
+ "summaryRow": "Sv3uVW_summaryRow",
117
+ "sqlResult": "Sv3uVW_sqlResult",
118
+ "input": "Sv3uVW_input",
119
+ "treeItem": "Sv3uVW_treeItem",
120
+ "fieldGrid": "Sv3uVW_fieldGrid",
121
+ "errorHead": "Sv3uVW_errorHead",
122
+ "da-split": "Sv3uVW_da-split",
123
+ "sections": "Sv3uVW_sections",
124
+ "treeIcon": "Sv3uVW_treeIcon",
125
+ "browseIcon": "Sv3uVW_browseIcon",
126
+ "emptyStateIcon": "Sv3uVW_emptyStateIcon",
127
+ "fieldRow2": "Sv3uVW_fieldRow2",
128
+ "titleIcon": "Sv3uVW_titleIcon",
129
+ "colCount": "Sv3uVW_colCount",
130
+ "treeName": "Sv3uVW_treeName",
131
+ "modalColTitle": "Sv3uVW_modalColTitle"
132
+ };
133
+ //#endregion
134
+ //#region src/client/DataAgentWorkbench.tsx
135
+ /**
136
+ * The database workbench: connection config (collapsible after connect),
137
+ * a browse button that opens the schema explorer Modal, and the SQL command
138
+ * box, rendered into the composer input dock (the strip ABOVE the input bar)
139
+ * for data-agent sessions.
140
+ *
141
+ * Layout is phase-driven by the conversation root's `data-phase` attribute:
142
+ * - hero (blank session): the workbench is a full-width stacked strip above
143
+ * the input bar (which stays at the bottom);
144
+ * - active (conversation started): the workbench becomes a fixed left rail
145
+ * (measured from the conversation column), the chat records and the input
146
+ * bar shift right via the `da-split` CSS rules; if measurement is
147
+ * unavailable the workbench falls back to a docked bottom panel.
148
+ *
149
+ * Interaction model:
150
+ * - after a successful connect the connection form collapses into a summary
151
+ * row (click 连接配置 to expand the readonly form again);
152
+ * - the schema explorer lives in a Modal (ui-primitives) opened by the
153
+ * 库表 button; a single click on a database toggles its table list in a
154
+ * file-explorer style tree (folder rows with chevrons, indented table rows
155
+ * with guide lines, the whole tree scrolls inside the column);
156
+ * - clicking a table loads its columns into the Modal's structure panel.
157
+ *
158
+ * Non-data-agent sessions render null — zero impact on ordinary sessions.
159
+ * Connection state lives on the server (the dataAgentConnections store), so
160
+ * remounts never lose it — this component mirrors `/status` on mount.
161
+ */
162
+ /** The plugin's preset id, matching the installed agent preset directory. */
163
+ const DATA_AGENT_PRESET = "data-agent";
164
+ /** 16×16 stroke icons drawn inline (the primitives package does not export icon atoms). */
165
+ function Icon({ className, children, size = 14 }) {
166
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
167
+ className,
168
+ width: size,
169
+ height: size,
170
+ viewBox: "0 0 16 16",
171
+ fill: "none",
172
+ "aria-hidden": "true",
173
+ children
174
+ });
175
+ }
176
+ /** Database cylinder: section header of the connection form. */
177
+ function DatabaseIcon({ className }) {
178
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Icon, {
179
+ className,
180
+ children: [
181
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ellipse", {
182
+ cx: "8",
183
+ cy: "4",
184
+ rx: "5.5",
185
+ ry: "2.1",
186
+ stroke: "currentColor",
187
+ strokeWidth: "1.2"
188
+ }),
189
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
190
+ d: "M2.5 4V12C2.5 13.16 4.96 14.1 8 14.1C11.04 14.1 13.5 13.16 13.5 12V4",
191
+ stroke: "currentColor",
192
+ strokeWidth: "1.2"
193
+ }),
194
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
195
+ d: "M2.5 8C2.5 9.16 4.96 10.1 8 10.1C11.04 10.1 13.5 9.16 13.5 8",
196
+ stroke: "currentColor",
197
+ strokeWidth: "1.2"
198
+ })
199
+ ]
200
+ });
201
+ }
202
+ /** Table grid: browse row + table rows in the tree. */
203
+ function TableIcon({ className }) {
204
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Icon, {
205
+ className,
206
+ children: [
207
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("rect", {
208
+ x: "2",
209
+ y: "3",
210
+ width: "12",
211
+ height: "10",
212
+ rx: "1.5",
213
+ stroke: "currentColor",
214
+ strokeWidth: "1.2"
215
+ }),
216
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
217
+ d: "M2 6.5H14",
218
+ stroke: "currentColor",
219
+ strokeWidth: "1.2"
220
+ }),
221
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
222
+ d: "M6.5 6.5V13",
223
+ stroke: "currentColor",
224
+ strokeWidth: "1.2"
225
+ })
226
+ ]
227
+ });
228
+ }
229
+ /** Folder: schema rows in the tree. */
230
+ function FolderIcon({ className }) {
231
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, {
232
+ className,
233
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
234
+ d: "M1.8 4.6C1.8 4.05 2.25 3.6 2.8 3.6H5.9L7.1 5.1H13.2C13.75 5.1 14.2 5.55 14.2 6.1V11.4C14.2 11.95 13.75 12.4 13.2 12.4H2.8C2.25 12.4 1.8 11.95 1.8 11.4V4.6Z",
235
+ stroke: "currentColor",
236
+ strokeWidth: "1.2",
237
+ strokeLinejoin: "round"
238
+ })
239
+ });
240
+ }
241
+ /** Terminal prompt: section header of the SQL box. */
242
+ function TerminalIcon({ className }) {
243
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Icon, {
244
+ className,
245
+ children: [
246
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("rect", {
247
+ x: "1.5",
248
+ y: "2.5",
249
+ width: "13",
250
+ height: "11",
251
+ rx: "2",
252
+ stroke: "currentColor",
253
+ strokeWidth: "1.2"
254
+ }),
255
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
256
+ d: "M4.5 6L6.5 8L4.5 10",
257
+ stroke: "currentColor",
258
+ strokeWidth: "1.2",
259
+ strokeLinecap: "round",
260
+ strokeLinejoin: "round"
261
+ }),
262
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
263
+ d: "M8 10.5H11.2",
264
+ stroke: "currentColor",
265
+ strokeWidth: "1.2",
266
+ strokeLinecap: "round"
267
+ })
268
+ ]
269
+ });
270
+ }
271
+ /** Chevron: tree expand indicator (rotates 90° when open). */
272
+ function ChevronIcon({ className }) {
273
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
274
+ className,
275
+ width: "12",
276
+ height: "12",
277
+ viewBox: "0 0 12 12",
278
+ fill: "none",
279
+ "aria-hidden": "true",
280
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
281
+ d: "M4.5 2.5L8 6L4.5 9.5",
282
+ stroke: "currentColor",
283
+ strokeWidth: "1.5",
284
+ strokeLinecap: "round",
285
+ strokeLinejoin: "round"
286
+ })
287
+ });
288
+ }
289
+ /** Alert triangle: error bar heading. */
290
+ function AlertIcon({ className }) {
291
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Icon, {
292
+ className,
293
+ children: [
294
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
295
+ d: "M8 2.2L14.2 13H1.8L8 2.2Z",
296
+ stroke: "currentColor",
297
+ strokeWidth: "1.2",
298
+ strokeLinejoin: "round"
299
+ }),
300
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
301
+ d: "M8 6.4V9.2",
302
+ stroke: "currentColor",
303
+ strokeWidth: "1.2",
304
+ strokeLinecap: "round"
305
+ }),
306
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
307
+ cx: "8",
308
+ cy: "11",
309
+ r: "0.9",
310
+ fill: "currentColor"
311
+ })
312
+ ]
313
+ });
314
+ }
315
+ /** Play triangle: SQL run button. */
316
+ function PlayIcon({ className }) {
317
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
318
+ className,
319
+ width: "12",
320
+ height: "12",
321
+ viewBox: "0 0 12 12",
322
+ fill: "currentColor",
323
+ "aria-hidden": "true",
324
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M3.4 2.1C3.4 1.66 3.88 1.4 4.26 1.62L9.9 5.02C10.26 5.23 10.26 5.77 9.9 5.98L4.26 9.38C3.88 9.6 3.4 9.34 3.4 8.9V2.1Z" })
325
+ });
326
+ }
327
+ /** The conversation column's phase attribute value while the session is blank. */
328
+ function isHeroPhase(element) {
329
+ return element?.getAttribute("data-phase") === "hero";
330
+ }
331
+ /**
332
+ * 开始对话后(active 布局)左栏工作台相对会话列顶部的下移偏移(px):
333
+ * 让工作台避开会话头部区域、整体往下沉一些,顶部露出对话记录。
334
+ */
335
+ const RAIL_TOP_OFFSET = 96;
336
+ /** Default port per type (used to fill the form from a saved connection). */
337
+ function defaultPortOf(type) {
338
+ switch (type) {
339
+ case "postgres": return "5432";
340
+ case "oracle": return "1521";
341
+ case "hive": return "10000";
342
+ case "impala": return "21050";
343
+ case "sqlite": return "";
344
+ case "mysql": return "3306";
345
+ }
346
+ }
347
+ /** Run one /connect request (shared by the form connect and mount auto-reconnect). */
348
+ async function performConnect(sessionId, body) {
349
+ return (await fetch("/plugins/data-agent/connect", {
350
+ method: "POST",
351
+ headers: { "content-type": "application/json" },
352
+ body: JSON.stringify({
353
+ sessionId,
354
+ ...body
355
+ })
356
+ })).json();
357
+ }
358
+ /** Build the /connect payload from a saved connection. */
359
+ function payloadFromSaved(saved) {
360
+ if (saved.type === "sqlite") return {
361
+ type: saved.type,
362
+ database: saved.database
363
+ };
364
+ const body = {
365
+ type: saved.type,
366
+ host: saved.host ?? "127.0.0.1",
367
+ user: saved.user ?? "",
368
+ database: saved.database
369
+ };
370
+ if (saved.port !== void 0) body.port = saved.port;
371
+ if (saved.password !== void 0 && saved.password !== "") body.password = saved.password;
372
+ return body;
373
+ }
374
+ /** The database workbench body. */
375
+ function DataAgentWorkbench({ sessionId, useSessions, t }) {
376
+ const isDataAgent = useSessions((snapshot) => snapshot).byId[sessionId]?.agentPreset === DATA_AGENT_PRESET;
377
+ const rootRef = (0, react.useRef)(null);
378
+ const [phase, setPhase] = (0, react.useState)("hero");
379
+ const [railRect, setRailRect] = (0, react.useState)(null);
380
+ const [initialSaved] = (0, react.useState)(loadConnection);
381
+ const [type, setType] = (0, react.useState)(initialSaved?.type ?? "mysql");
382
+ const [host, setHost] = (0, react.useState)(initialSaved?.host ?? "127.0.0.1");
383
+ const [port, setPort] = (0, react.useState)(initialSaved?.port !== void 0 ? String(initialSaved.port) : defaultPortOf(initialSaved?.type ?? "mysql"));
384
+ const [user, setUser] = (0, react.useState)(initialSaved?.user ?? "");
385
+ const [password, setPassword] = (0, react.useState)(initialSaved?.password ?? "");
386
+ const [database, setDatabase] = (0, react.useState)(initialSaved?.database ?? "");
387
+ const [busy, setBusy] = (0, react.useState)(false);
388
+ const [error, setError] = (0, react.useState)(null);
389
+ const [connected, setConnected] = (0, react.useState)(false);
390
+ const [configOpen, setConfigOpen] = (0, react.useState)(false);
391
+ const [restoring, setRestoring] = (0, react.useState)(false);
392
+ const [schemaModalOpen, setSchemaModalOpen] = (0, react.useState)(false);
393
+ const [schemas, setSchemas] = (0, react.useState)([]);
394
+ const [activeSchema, setActiveSchema] = (0, react.useState)(null);
395
+ const [tables, setTables] = (0, react.useState)([]);
396
+ const [activeTable, setActiveTable] = (0, react.useState)(null);
397
+ const [columns, setColumns] = (0, react.useState)(null);
398
+ const [sql, setSql] = (0, react.useState)("");
399
+ const [sqlBusy, setSqlBusy] = (0, react.useState)(false);
400
+ const [sqlResult, setSqlResult] = (0, react.useState)(null);
401
+ (0, react.useEffect)(() => {
402
+ const column = rootRef.current?.closest("[data-phase]") ?? null;
403
+ if (column === null) return;
404
+ const measure = () => {
405
+ const rect = column.getBoundingClientRect();
406
+ setRailRect({
407
+ left: rect.left,
408
+ top: rect.top,
409
+ bottom: window.innerHeight - rect.bottom
410
+ });
411
+ };
412
+ const refreshPhase = () => {
413
+ setPhase(isHeroPhase(column) ? "hero" : "active");
414
+ };
415
+ refreshPhase();
416
+ measure();
417
+ const observer = new MutationObserver(refreshPhase);
418
+ observer.observe(column, {
419
+ attributes: true,
420
+ attributeFilter: ["data-phase"]
421
+ });
422
+ const resizer = new ResizeObserver(measure);
423
+ resizer.observe(column);
424
+ window.addEventListener("resize", measure);
425
+ return () => {
426
+ observer.disconnect();
427
+ resizer.disconnect();
428
+ window.removeEventListener("resize", measure);
429
+ };
430
+ }, []);
431
+ const split = phase === "active" && railRect !== null;
432
+ (0, react.useEffect)(() => {
433
+ const root = document.documentElement;
434
+ const splitClass = DataAgentWorkbench_module_css_default["da-split"];
435
+ if (split && splitClass !== void 0) root.classList.add(splitClass);
436
+ else if (splitClass !== void 0) root.classList.remove(splitClass);
437
+ return () => {
438
+ if (splitClass !== void 0) root.classList.remove(splitClass);
439
+ };
440
+ }, [split]);
441
+ const firstDraftRun = (0, react.useRef)(true);
442
+ (0, react.useEffect)(() => {
443
+ if (firstDraftRun.current) {
444
+ firstDraftRun.current = false;
445
+ return;
446
+ }
447
+ saveConnection({
448
+ type,
449
+ database,
450
+ ...type !== "sqlite" ? {
451
+ host,
452
+ user
453
+ } : {},
454
+ ...type !== "sqlite" && port !== "" ? { port: Number(port) } : {},
455
+ ...password !== "" ? { password } : {},
456
+ savedAt: (/* @__PURE__ */ new Date()).toISOString()
457
+ });
458
+ }, [
459
+ type,
460
+ host,
461
+ port,
462
+ user,
463
+ database,
464
+ password
465
+ ]);
466
+ (0, react.useEffect)(() => {
467
+ let cancelled = false;
468
+ const saved = initialSaved;
469
+ setBusy(true);
470
+ fetch(`/plugins/data-agent/status?sessionId=${encodeURIComponent(sessionId)}`).then((response) => response.json()).then(async (body) => {
471
+ if (cancelled) return;
472
+ if (body.connected) {
473
+ setConnected(true);
474
+ if (body.summary !== void 0) {
475
+ setType(body.summary.type);
476
+ setHost(body.summary.host ?? "");
477
+ setPort(body.summary.port !== void 0 ? String(body.summary.port) : "");
478
+ setUser(body.summary.user ?? "");
479
+ setDatabase(body.summary.database);
480
+ }
481
+ const schemasBody = await (await fetch(`/plugins/data-agent/schemas?sessionId=${encodeURIComponent(sessionId)}`)).json();
482
+ if (!cancelled && schemasBody.ok) setSchemas(schemasBody.schemas ?? []);
483
+ return;
484
+ }
485
+ if (saved !== null && saved.database !== "") {
486
+ setRestoring(true);
487
+ try {
488
+ const result = await performConnect(sessionId, payloadFromSaved(saved));
489
+ if (cancelled) return;
490
+ if (result.ok) {
491
+ setConnected(true);
492
+ setConfigOpen(false);
493
+ const schemasBody = await (await fetch(`/plugins/data-agent/schemas?sessionId=${encodeURIComponent(sessionId)}`)).json();
494
+ if (!cancelled && schemasBody.ok) setSchemas(schemasBody.schemas ?? []);
495
+ } else setError(`连接恢复失败:${result.error ?? "unknown error"}`);
496
+ } catch (cause) {
497
+ if (!cancelled) setError(`连接恢复失败:${cause instanceof Error ? cause.message : String(cause)}`);
498
+ } finally {
499
+ if (!cancelled) setRestoring(false);
500
+ }
501
+ }
502
+ }).catch(() => {}).finally(() => {
503
+ if (!cancelled) setBusy(false);
504
+ });
505
+ return () => {
506
+ cancelled = true;
507
+ };
508
+ }, [sessionId]);
509
+ const sqlite = type === "sqlite";
510
+ const connect = async () => {
511
+ setBusy(true);
512
+ setError(null);
513
+ const body = {
514
+ sessionId,
515
+ type
516
+ };
517
+ if (sqlite) body.database = database;
518
+ else {
519
+ body.host = host;
520
+ if (port !== "") body.port = Number(port);
521
+ body.user = user;
522
+ body.database = database;
523
+ if (password !== "") body.password = password;
524
+ }
525
+ try {
526
+ const result = await performConnect(sessionId, body);
527
+ if (result.ok) {
528
+ setConnected(true);
529
+ setConfigOpen(false);
530
+ const schemasBody = await (await fetch(`/plugins/data-agent/schemas?sessionId=${encodeURIComponent(sessionId)}`)).json();
531
+ if (schemasBody.ok) setSchemas(schemasBody.schemas ?? []);
532
+ } else setError(result.error ?? "unknown error");
533
+ } catch (cause) {
534
+ setError(cause instanceof Error ? cause.message : String(cause));
535
+ } finally {
536
+ setBusy(false);
537
+ }
538
+ };
539
+ const disconnect = async () => {
540
+ setBusy(true);
541
+ setError(null);
542
+ try {
543
+ await fetch("/plugins/data-agent/disconnect", {
544
+ method: "POST",
545
+ headers: { "content-type": "application/json" },
546
+ body: JSON.stringify({ sessionId })
547
+ });
548
+ setConnected(false);
549
+ setConfigOpen(false);
550
+ setSchemaModalOpen(false);
551
+ setSchemas([]);
552
+ setActiveSchema(null);
553
+ setTables([]);
554
+ setActiveTable(null);
555
+ setColumns(null);
556
+ setSqlResult(null);
557
+ } catch (cause) {
558
+ setError(cause instanceof Error ? cause.message : String(cause));
559
+ } finally {
560
+ setBusy(false);
561
+ }
562
+ };
563
+ /** Toggle one schema's table list (single click; only one open at a time). */
564
+ const toggleSchema = async (schema) => {
565
+ if (activeSchema === schema) {
566
+ setActiveSchema(null);
567
+ setTables([]);
568
+ setActiveTable(null);
569
+ setColumns(null);
570
+ return;
571
+ }
572
+ setActiveSchema(schema);
573
+ setActiveTable(null);
574
+ setColumns(null);
575
+ setTables([]);
576
+ try {
577
+ const result = await (await fetch(`/plugins/data-agent/tables?sessionId=${encodeURIComponent(sessionId)}&schema=${encodeURIComponent(schema)}`)).json();
578
+ if (result.ok) setTables(result.tables ?? []);
579
+ else setError(result.error ?? "unknown error");
580
+ } catch (cause) {
581
+ setError(cause instanceof Error ? cause.message : String(cause));
582
+ }
583
+ };
584
+ const selectTable = async (table) => {
585
+ setActiveTable(table);
586
+ setColumns(null);
587
+ const params = new URLSearchParams({
588
+ sessionId,
589
+ table
590
+ });
591
+ if (activeSchema !== null) params.set("schema", activeSchema);
592
+ try {
593
+ const result = await (await fetch(`/plugins/data-agent/describe?${params.toString()}`)).json();
594
+ if (result.ok) setColumns(result.columns ?? []);
595
+ else setError(result.error ?? "unknown error");
596
+ } catch (cause) {
597
+ setError(cause instanceof Error ? cause.message : String(cause));
598
+ }
599
+ };
600
+ const runSql = async () => {
601
+ if (sql.trim() === "") return;
602
+ setSqlBusy(true);
603
+ setSqlResult(null);
604
+ try {
605
+ const result = await (await fetch("/plugins/data-agent/query", {
606
+ method: "POST",
607
+ headers: { "content-type": "application/json" },
608
+ body: JSON.stringify({
609
+ sessionId,
610
+ sql
611
+ })
612
+ })).json();
613
+ if (result.ok && result.result !== void 0) {
614
+ const parts = [];
615
+ if (result.result.stdout !== "") parts.push(result.result.stdout);
616
+ if (result.result.stderr !== "") parts.push(`[stderr]\n${result.result.stderr}`);
617
+ if (result.result.truncated) parts.push("… 输出超过上限,已截断");
618
+ if (result.result.exitCode !== 0) parts.push(`[exit code: ${result.result.exitCode ?? "signal"}]`);
619
+ setSqlResult(parts.join("\n"));
620
+ } else setSqlResult(`Error: ${result.error ?? "unknown error"}`);
621
+ } catch (cause) {
622
+ setSqlResult(`Error: ${cause instanceof Error ? cause.message : String(cause)}`);
623
+ } finally {
624
+ setSqlBusy(false);
625
+ }
626
+ };
627
+ if (!isDataAgent) return null;
628
+ const databaseLabel = sqlite ? t("form.database.sqlite") : type === "oracle" ? t("form.database.oracle") : type === "hive" || type === "impala" ? t("form.database.hive") : t("form.database");
629
+ const railStyle = split ? {
630
+ position: "fixed",
631
+ left: railRect.left,
632
+ top: railRect.top + RAIL_TOP_OFFSET,
633
+ bottom: railRect.bottom,
634
+ width: 380
635
+ } : void 0;
636
+ const formDisabled = busy || connected;
637
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
638
+ ref: rootRef,
639
+ className: `${DataAgentWorkbench_module_css_default.workbench} ${split ? DataAgentWorkbench_module_css_default.rail : phase === "active" ? DataAgentWorkbench_module_css_default.docked : DataAgentWorkbench_module_css_default.strip}`,
640
+ style: railStyle,
641
+ children: [
642
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
643
+ className: DataAgentWorkbench_module_css_default.sections,
644
+ children: [
645
+ connected && !configOpen ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("section", {
646
+ className: DataAgentWorkbench_module_css_default.card,
647
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
648
+ className: DataAgentWorkbench_module_css_default.summaryRow,
649
+ children: [
650
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.StateDot, {
651
+ state: "done",
652
+ size: 8,
653
+ className: DataAgentWorkbench_module_css_default.dot
654
+ }),
655
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
656
+ className: DataAgentWorkbench_module_css_default.statusOk,
657
+ children: t("state.connected")
658
+ }),
659
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
660
+ className: DataAgentWorkbench_module_css_default.summaryType,
661
+ children: t(`type.${type}`)
662
+ }),
663
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
664
+ className: DataAgentWorkbench_module_css_default.summaryDb,
665
+ title: database,
666
+ children: database
667
+ }),
668
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
669
+ className: DataAgentWorkbench_module_css_default.summaryActions,
670
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
671
+ type: "button",
672
+ className: `${DataAgentWorkbench_module_css_default.ghost} ${DataAgentWorkbench_module_css_default.small}`,
673
+ onClick: () => setConfigOpen(true),
674
+ children: t("action.config")
675
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
676
+ type: "button",
677
+ className: `${DataAgentWorkbench_module_css_default.ghost} ${DataAgentWorkbench_module_css_default.small}`,
678
+ disabled: busy,
679
+ onClick: () => {
680
+ disconnect();
681
+ },
682
+ children: t("action.disconnect")
683
+ })]
684
+ })
685
+ ]
686
+ })
687
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
688
+ className: DataAgentWorkbench_module_css_default.card,
689
+ children: [
690
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
691
+ className: DataAgentWorkbench_module_css_default.cardTitle,
692
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(DatabaseIcon, { className: DataAgentWorkbench_module_css_default.titleIcon }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("form.title") })]
693
+ }),
694
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
695
+ className: DataAgentWorkbench_module_css_default.fieldGrid,
696
+ children: [
697
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
698
+ className: DataAgentWorkbench_module_css_default.field,
699
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
700
+ className: DataAgentWorkbench_module_css_default.label,
701
+ children: t("form.type")
702
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
703
+ className: DataAgentWorkbench_module_css_default.input,
704
+ value: type,
705
+ disabled: formDisabled,
706
+ onChange: (event) => {
707
+ const next = event.target.value;
708
+ setType(next);
709
+ setPort(next === "postgres" ? "5432" : next === "mysql" ? "3306" : next === "oracle" ? "1521" : next === "hive" ? "10000" : next === "impala" ? "21050" : "");
710
+ },
711
+ children: [
712
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
713
+ value: "mysql",
714
+ children: t("type.mysql")
715
+ }),
716
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
717
+ value: "postgres",
718
+ children: t("type.postgres")
719
+ }),
720
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
721
+ value: "sqlite",
722
+ children: t("type.sqlite")
723
+ }),
724
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
725
+ value: "oracle",
726
+ children: t("type.oracle")
727
+ }),
728
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
729
+ value: "hive",
730
+ children: t("type.hive")
731
+ }),
732
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
733
+ value: "impala",
734
+ children: t("type.impala")
735
+ })
736
+ ]
737
+ })]
738
+ }),
739
+ !sqlite && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
740
+ className: DataAgentWorkbench_module_css_default.fieldRow2,
741
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
742
+ className: DataAgentWorkbench_module_css_default.field,
743
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
744
+ className: DataAgentWorkbench_module_css_default.label,
745
+ children: t("form.host")
746
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
747
+ className: DataAgentWorkbench_module_css_default.input,
748
+ type: "text",
749
+ value: host,
750
+ disabled: formDisabled,
751
+ onChange: (event) => setHost(event.target.value)
752
+ })]
753
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
754
+ className: DataAgentWorkbench_module_css_default.field,
755
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
756
+ className: DataAgentWorkbench_module_css_default.label,
757
+ children: t("form.port")
758
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
759
+ className: DataAgentWorkbench_module_css_default.input,
760
+ type: "number",
761
+ min: 1,
762
+ max: 65535,
763
+ value: port,
764
+ disabled: formDisabled,
765
+ onChange: (event) => setPort(event.target.value)
766
+ })]
767
+ })]
768
+ }),
769
+ !sqlite && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
770
+ className: DataAgentWorkbench_module_css_default.fieldRow2,
771
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
772
+ className: DataAgentWorkbench_module_css_default.field,
773
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
774
+ className: DataAgentWorkbench_module_css_default.label,
775
+ children: t("form.user")
776
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
777
+ className: DataAgentWorkbench_module_css_default.input,
778
+ type: "text",
779
+ value: user,
780
+ disabled: formDisabled,
781
+ onChange: (event) => setUser(event.target.value)
782
+ })]
783
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
784
+ className: DataAgentWorkbench_module_css_default.field,
785
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
786
+ className: DataAgentWorkbench_module_css_default.label,
787
+ children: t("form.password")
788
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
789
+ className: DataAgentWorkbench_module_css_default.input,
790
+ type: "password",
791
+ value: password,
792
+ autoComplete: "new-password",
793
+ disabled: formDisabled,
794
+ onChange: (event) => setPassword(event.target.value)
795
+ })]
796
+ })]
797
+ }),
798
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
799
+ className: DataAgentWorkbench_module_css_default.field,
800
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
801
+ className: DataAgentWorkbench_module_css_default.label,
802
+ children: databaseLabel
803
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
804
+ className: DataAgentWorkbench_module_css_default.input,
805
+ type: "text",
806
+ value: database,
807
+ placeholder: sqlite ? t("form.database.sqlite.placeholder") : void 0,
808
+ disabled: formDisabled,
809
+ onChange: (event) => setDatabase(event.target.value)
810
+ })]
811
+ })
812
+ ]
813
+ }),
814
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
815
+ className: DataAgentWorkbench_module_css_default.actions,
816
+ children: !connected ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
817
+ type: "button",
818
+ className: DataAgentWorkbench_module_css_default.primary,
819
+ disabled: busy || database === "" || !sqlite && host === "",
820
+ onClick: () => {
821
+ connect();
822
+ },
823
+ children: restoring ? t("state.reconnecting") : busy ? t("state.checking") : t("action.connect")
824
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
825
+ type: "button",
826
+ className: DataAgentWorkbench_module_css_default.ghost,
827
+ onClick: () => setConfigOpen(false),
828
+ children: t("action.collapse")
829
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
830
+ type: "button",
831
+ className: DataAgentWorkbench_module_css_default.ghost,
832
+ disabled: busy,
833
+ onClick: () => {
834
+ disconnect();
835
+ },
836
+ children: t("action.disconnect")
837
+ })] })
838
+ })
839
+ ]
840
+ }),
841
+ connected && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("section", {
842
+ className: DataAgentWorkbench_module_css_default.card,
843
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
844
+ type: "button",
845
+ className: DataAgentWorkbench_module_css_default.browseRow,
846
+ onClick: () => setSchemaModalOpen(true),
847
+ children: [
848
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TableIcon, { className: DataAgentWorkbench_module_css_default.browseIcon }),
849
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("action.browse") }),
850
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChevronIcon, { className: DataAgentWorkbench_module_css_default.browseChevron })
851
+ ]
852
+ })
853
+ }),
854
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
855
+ className: DataAgentWorkbench_module_css_default.card,
856
+ children: [
857
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
858
+ className: DataAgentWorkbench_module_css_default.cardTitle,
859
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(TerminalIcon, { className: DataAgentWorkbench_module_css_default.titleIcon }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("wb.sql") })]
860
+ }),
861
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
862
+ className: DataAgentWorkbench_module_css_default.sqlInput,
863
+ value: sql,
864
+ rows: 8,
865
+ spellCheck: false,
866
+ placeholder: t("wb.sql.placeholder"),
867
+ onChange: (event) => setSql(event.target.value),
868
+ onKeyDown: (event) => {
869
+ if ((event.metaKey || event.ctrlKey) && event.key === "Enter") {
870
+ event.preventDefault();
871
+ runSql();
872
+ }
873
+ }
874
+ }),
875
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
876
+ className: DataAgentWorkbench_module_css_default.sqlActions,
877
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
878
+ className: DataAgentWorkbench_module_css_default.shortcutHint,
879
+ children: t("wb.sql.shortcut")
880
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
881
+ type: "button",
882
+ className: DataAgentWorkbench_module_css_default.primary,
883
+ disabled: sqlBusy || !connected || sql.trim() === "",
884
+ onClick: () => {
885
+ runSql();
886
+ },
887
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(PlayIcon, {}), sqlBusy ? t("wb.sql.running") : t("wb.sql.run")]
888
+ })]
889
+ }),
890
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("pre", {
891
+ className: DataAgentWorkbench_module_css_default.sqlResult,
892
+ children: sqlResult ?? t("wb.sql.empty")
893
+ })
894
+ ]
895
+ })
896
+ ]
897
+ }),
898
+ error !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
899
+ className: DataAgentWorkbench_module_css_default.errorBar,
900
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
901
+ className: DataAgentWorkbench_module_css_default.errorHead,
902
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(AlertIcon, { className: DataAgentWorkbench_module_css_default.errorIcon }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("error.title") })]
903
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
904
+ className: DataAgentWorkbench_module_css_default.errorText,
905
+ children: error
906
+ })]
907
+ }),
908
+ schemaModalOpen && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
909
+ open: schemaModalOpen,
910
+ onClose: () => setSchemaModalOpen(false),
911
+ title: t("wb.modal.title"),
912
+ closeLabel: t("action.close"),
913
+ className: DataAgentWorkbench_module_css_default.schemaModal,
914
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
915
+ className: DataAgentWorkbench_module_css_default.modalBody,
916
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
917
+ className: DataAgentWorkbench_module_css_default.modalCol,
918
+ children: [
919
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
920
+ className: DataAgentWorkbench_module_css_default.modalColTitle,
921
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("wb.schemas") }), schemas.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
922
+ className: DataAgentWorkbench_module_css_default.colCount,
923
+ children: schemas.length
924
+ })]
925
+ }),
926
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
927
+ className: DataAgentWorkbench_module_css_default.treeScroll,
928
+ children: [schemas.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
929
+ className: DataAgentWorkbench_module_css_default.hint,
930
+ children: t("wb.loading")
931
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
932
+ className: DataAgentWorkbench_module_css_default.tree,
933
+ children: schemas.map((schema) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", {
934
+ className: DataAgentWorkbench_module_css_default.treeNode,
935
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
936
+ type: "button",
937
+ className: `${DataAgentWorkbench_module_css_default.treeItem}${activeSchema === schema ? ` ${DataAgentWorkbench_module_css_default.active}` : ""}`,
938
+ onClick: () => {
939
+ toggleSchema(schema);
940
+ },
941
+ children: [
942
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChevronIcon, { className: `${DataAgentWorkbench_module_css_default.treeChevron}${activeSchema === schema ? ` ${DataAgentWorkbench_module_css_default.open}` : ""}` }),
943
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(FolderIcon, { className: DataAgentWorkbench_module_css_default.treeIcon }),
944
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
945
+ className: DataAgentWorkbench_module_css_default.treeName,
946
+ children: schema
947
+ }),
948
+ activeSchema === schema && tables.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
949
+ className: DataAgentWorkbench_module_css_default.treeCount,
950
+ children: tables.length
951
+ })
952
+ ]
953
+ }), activeSchema === schema && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
954
+ className: DataAgentWorkbench_module_css_default.treeChildren,
955
+ children: [tables.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
956
+ className: DataAgentWorkbench_module_css_default.hint,
957
+ children: t("wb.empty")
958
+ }), tables.map((table) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
959
+ type: "button",
960
+ className: `${DataAgentWorkbench_module_css_default.treeItem}${activeTable === table ? ` ${DataAgentWorkbench_module_css_default.active}` : ""}`,
961
+ onClick: () => {
962
+ selectTable(table);
963
+ },
964
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(TableIcon, { className: DataAgentWorkbench_module_css_default.treeIcon }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
965
+ className: DataAgentWorkbench_module_css_default.treeName,
966
+ children: table
967
+ })]
968
+ }, table))]
969
+ })]
970
+ }, schema))
971
+ })]
972
+ }),
973
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
974
+ className: DataAgentWorkbench_module_css_default.modalHint,
975
+ children: t("wb.hint.click")
976
+ })
977
+ ]
978
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
979
+ className: DataAgentWorkbench_module_css_default.modalCol,
980
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
981
+ className: DataAgentWorkbench_module_css_default.modalColTitle,
982
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [t("wb.columns"), activeTable !== null && ` · ${activeTable}`] })
983
+ }), columns === null ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
984
+ className: DataAgentWorkbench_module_css_default.emptyState,
985
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(TableIcon, { className: DataAgentWorkbench_module_css_default.emptyStateIcon }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
986
+ className: DataAgentWorkbench_module_css_default.emptyStateText,
987
+ children: t("wb.hint.click")
988
+ })]
989
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
990
+ className: DataAgentWorkbench_module_css_default.colScroll,
991
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("table", {
992
+ className: DataAgentWorkbench_module_css_default.columnsTable,
993
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("thead", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("tr", { children: [
994
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("th", { children: "name" }),
995
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("th", { children: "type" }),
996
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("th", { children: "null" })
997
+ ] }) }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("tbody", { children: columns.map((column) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("tr", { children: [
998
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", { children: column.name }),
999
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", {
1000
+ className: DataAgentWorkbench_module_css_default.typeCell,
1001
+ children: column.type
1002
+ }),
1003
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", {
1004
+ className: DataAgentWorkbench_module_css_default.nullCell,
1005
+ children: column.nullable === void 0 ? "" : column.nullable ? "YES" : "NO"
1006
+ })
1007
+ ] }, column.name)) })]
1008
+ })
1009
+ })]
1010
+ })]
1011
+ })
1012
+ })
1013
+ ]
1014
+ });
1015
+ }
1016
+ //#endregion
1017
+ //#region src/client/locales.ts
1018
+ /** `data-agent` namespace dictionaries for the database workbench. */
1019
+ /** Dictionary namespace owned by this plugin. */
1020
+ const NS = "data-agent";
1021
+ /** Simplified Chinese dictionary (the key-set source of truth). */
1022
+ const zh = {
1023
+ "form.title": "数据库连接",
1024
+ "form.type": "数据库类型",
1025
+ "type.mysql": "MySQL",
1026
+ "type.postgres": "PostgreSQL",
1027
+ "type.sqlite": "SQLite",
1028
+ "type.oracle": "Oracle",
1029
+ "type.hive": "Hive",
1030
+ "type.impala": "Impala",
1031
+ "form.host": "主机",
1032
+ "form.port": "端口",
1033
+ "form.user": "用户名",
1034
+ "form.password": "密码",
1035
+ "form.database": "数据库名",
1036
+ "form.database.oracle": "服务名 / SID",
1037
+ "form.database.hive": "默认库",
1038
+ "form.database.impala": "默认库",
1039
+ "form.database.sqlite": "数据库文件路径",
1040
+ "form.database.sqlite.placeholder": "/path/to/orders.db",
1041
+ "action.connect": "连接",
1042
+ "action.disconnect": "断开",
1043
+ "state.connected": "已连接",
1044
+ "state.disconnected": "未连接",
1045
+ "state.checking": "正在检查连接…",
1046
+ "state.reconnecting": "正在恢复连接…",
1047
+ "wb.schemas": "库",
1048
+ "wb.tables": "表",
1049
+ "wb.columns": "表结构",
1050
+ "wb.sql": "SQL 命令",
1051
+ "wb.sql.placeholder": "在此输入 SQL,例如 SELECT * FROM orders LIMIT 10;",
1052
+ "wb.sql.run": "运行",
1053
+ "wb.sql.running": "运行中…",
1054
+ "wb.sql.shortcut": "Ctrl / ⌘ + Enter 运行",
1055
+ "wb.sql.empty": "-- 尚无输出 --",
1056
+ "wb.loading": "加载中…",
1057
+ "wb.empty": "(空)",
1058
+ "wb.modal.title": "库表浏览",
1059
+ "wb.hint.click": "单击库展开表 · 点击表查看结构",
1060
+ "action.config": "连接配置",
1061
+ "action.browse": "库表",
1062
+ "action.close": "关闭",
1063
+ "action.collapse": "收起",
1064
+ "error.title": "操作失败"
1065
+ };
1066
+ /** English dictionary, checked complete against the zh key set. */
1067
+ const en = {
1068
+ "form.title": "Database connection",
1069
+ "form.type": "Database type",
1070
+ "type.mysql": "MySQL",
1071
+ "type.postgres": "PostgreSQL",
1072
+ "type.sqlite": "SQLite",
1073
+ "type.oracle": "Oracle",
1074
+ "type.hive": "Hive",
1075
+ "type.impala": "Impala",
1076
+ "form.host": "Host",
1077
+ "form.port": "Port",
1078
+ "form.user": "User",
1079
+ "form.password": "Password",
1080
+ "form.database": "Database",
1081
+ "form.database.oracle": "Service name / SID",
1082
+ "form.database.hive": "Default database",
1083
+ "form.database.impala": "Default database",
1084
+ "form.database.sqlite": "Database file path",
1085
+ "form.database.sqlite.placeholder": "/path/to/orders.db",
1086
+ "action.connect": "Connect",
1087
+ "action.disconnect": "Disconnect",
1088
+ "state.connected": "Connected",
1089
+ "state.disconnected": "Not connected",
1090
+ "state.checking": "Checking connection…",
1091
+ "state.reconnecting": "Restoring connection…",
1092
+ "wb.schemas": "Databases",
1093
+ "wb.tables": "Tables",
1094
+ "wb.columns": "Columns",
1095
+ "wb.sql": "SQL",
1096
+ "wb.sql.placeholder": "Write SQL here, e.g. SELECT * FROM orders LIMIT 10;",
1097
+ "wb.sql.run": "Run",
1098
+ "wb.sql.running": "Running…",
1099
+ "wb.sql.shortcut": "Ctrl / ⌘ + Enter to run",
1100
+ "wb.sql.empty": "-- no output --",
1101
+ "wb.loading": "Loading…",
1102
+ "wb.empty": "(empty)",
1103
+ "wb.modal.title": "Database explorer",
1104
+ "wb.hint.click": "Click a database to expand tables · click a table for columns",
1105
+ "action.config": "Connection settings",
1106
+ "action.browse": "Tables",
1107
+ "action.close": "Close",
1108
+ "action.collapse": "Collapse",
1109
+ "error.title": "Operation failed"
1110
+ };
1111
+ //#endregion
1112
+ //#region src/client/index.ts
1113
+ /** Required services: the locale service, the slot registry, and the sessions list. */
1114
+ const inject = [
1115
+ "slots",
1116
+ "locale",
1117
+ "sessions"
1118
+ ];
1119
+ /**
1120
+ * Client plugin body: register the data-agent dictionaries and the database
1121
+ * workbench into the composer input dock. The registration rides the slot
1122
+ * service's effect wrapper, so plugin unload removes it.
1123
+ * @param ctx - client root context.
1124
+ */
1125
+ function apply(ctx) {
1126
+ ctx.effect(() => ctx.locale.register(NS, {
1127
+ zh,
1128
+ en
1129
+ }), "data-agent: dictionaries");
1130
+ ctx.locale.bind(NS);
1131
+ ctx.inject([
1132
+ "slots",
1133
+ "locale",
1134
+ "sessions"
1135
+ ], (scope) => {
1136
+ const list = scope.sessions.list;
1137
+ const sessionsSource = {
1138
+ getSnapshot: () => list.getSnapshot(),
1139
+ subscribe: (fn) => list.subscribe(fn)
1140
+ };
1141
+ scope.slots.inject("conversation.input.dock", () => scope.slots.register({
1142
+ name: "conversation.input.dock",
1143
+ id: "data-agent",
1144
+ order: 0,
1145
+ locale: NS,
1146
+ inject: () => ({ hooks: { sessions: sessionsSource } })
1147
+ }, DataAgentWorkbench));
1148
+ });
1149
+ }
1150
+ //#endregion
1151
+ exports.apply = apply;
1152
+ exports.inject = inject;
1153
+ return module.exports;
1154
+ }
1155
+ });
1156
+
1157
+ //# sourceMappingURL=client.js.map