@yejiming/dsh-data-agent 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.en.md +25 -14
- package/README.md +36 -23
- package/lib/client.js +104 -51
- package/lib/client.js.map +1 -1
- package/lib/{defaults-D__D30ED.js → defaults-Dgu2B2Yq.js} +176 -10
- package/lib/index.js +8 -3
- package/lib/{query-DAjhNTo8.js → query-vK9dr7Z6.js} +1 -1
- package/lib/routes.js +18 -13
- package/lib/tool.js +5 -2
- package/lib/types/client/locales.d.ts +8 -0
- package/lib/types/client/persistence.d.ts +4 -1
- package/lib/types/clients.d.ts +15 -0
- package/lib/types/connections.d.ts +4 -0
- package/lib/types/index.d.ts +10 -0
- package/lib/types/routes.d.ts +5 -0
- package/lib/types/tool.d.ts +4 -0
- package/package.json +4 -1
package/lib/routes.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { d as
|
|
2
|
-
import { t as runClientQuery } from "./query-
|
|
1
|
+
import { d as metadataQuery, f as parseColumns, g as tableListingSql, h as sanitizeIdentifier, i as DEFAULT_MAX_RESULT_CHARS, l as classifyStatement, m as parseTableListing, o as DEFAULT_QUERY_TIMEOUT_MS, p as parseListing, r as DEFAULT_MAX_QUERY_CHARS, t as DEFAULT_CONNECT_TIMEOUT_MS } from "./defaults-Dgu2B2Yq.js";
|
|
2
|
+
import { t as runClientQuery } from "./query-vK9dr7Z6.js";
|
|
3
3
|
import { resolve } from "node:path";
|
|
4
4
|
import z from "schemastery";
|
|
5
5
|
//#region src/routes.ts
|
|
@@ -20,7 +20,8 @@ const Config = z.object({
|
|
|
20
20
|
introspectMaxTables: z.number().step(1).min(1).default(500),
|
|
21
21
|
maxResultChars: z.number().step(1).min(1024).default(DEFAULT_MAX_RESULT_CHARS),
|
|
22
22
|
queryTimeoutMs: z.number().step(1).min(1e3).default(DEFAULT_QUERY_TIMEOUT_MS),
|
|
23
|
-
maxQueryChars: z.number().step(1).min(1024).default(DEFAULT_MAX_QUERY_CHARS)
|
|
23
|
+
maxQueryChars: z.number().step(1).min(1024).default(DEFAULT_MAX_QUERY_CHARS),
|
|
24
|
+
readonly: z.boolean().default(false)
|
|
24
25
|
});
|
|
25
26
|
/**
|
|
26
27
|
* Validate an untrusted /connect body; sqlite paths resolve to absolute
|
|
@@ -51,6 +52,8 @@ function validateConnectBody(value, cwd = process.cwd()) {
|
|
|
51
52
|
if (user !== void 0 && typeof user !== "string") throw new Error("user 必须是字符串");
|
|
52
53
|
const password = candidate.password;
|
|
53
54
|
if (password !== void 0 && typeof password !== "string") throw new Error("password 必须是字符串");
|
|
55
|
+
const readonly = candidate.readonly;
|
|
56
|
+
if (readonly !== void 0 && typeof readonly !== "boolean") throw new Error("readonly 必须是布尔值");
|
|
54
57
|
const connection = {
|
|
55
58
|
type,
|
|
56
59
|
database
|
|
@@ -59,6 +62,7 @@ function validateConnectBody(value, cwd = process.cwd()) {
|
|
|
59
62
|
if (port !== void 0) connection.port = port;
|
|
60
63
|
if (typeof user === "string" && user.length > 0) connection.user = user;
|
|
61
64
|
if (typeof password === "string" && password.length > 0) connection.password = password;
|
|
65
|
+
if (readonly !== void 0) connection.readonly = readonly;
|
|
62
66
|
return {
|
|
63
67
|
sessionId,
|
|
64
68
|
type,
|
|
@@ -66,15 +70,14 @@ function validateConnectBody(value, cwd = process.cwd()) {
|
|
|
66
70
|
...connection.host !== void 0 ? { host: connection.host } : {},
|
|
67
71
|
...connection.port !== void 0 ? { port: connection.port } : {},
|
|
68
72
|
...connection.user !== void 0 ? { user: connection.user } : {},
|
|
69
|
-
...connection.password !== void 0 ? { password: connection.password } : {}
|
|
73
|
+
...connection.password !== void 0 ? { password: connection.password } : {},
|
|
74
|
+
...connection.readonly !== void 0 ? { readonly: connection.readonly } : {}
|
|
70
75
|
};
|
|
71
76
|
}
|
|
72
|
-
/**
|
|
73
|
-
|
|
74
|
-
/** Validate one schema/table identifier (rejects any injection-shaped input). */
|
|
75
|
-
function requireIdentifier(value, label) {
|
|
77
|
+
/** Validate one schema/table identifier: reuse the clients' sanitizer (validation + quoting). */
|
|
78
|
+
function requireIdentifier(type, value, label) {
|
|
76
79
|
if (value === null || value.length === 0) throw new Error(`${label} 不能为空`);
|
|
77
|
-
|
|
80
|
+
sanitizeIdentifier(type, value);
|
|
78
81
|
return value;
|
|
79
82
|
}
|
|
80
83
|
/**
|
|
@@ -148,7 +151,8 @@ function apply(ctx, config) {
|
|
|
148
151
|
...request.host !== void 0 ? { host: request.host } : {},
|
|
149
152
|
...request.port !== void 0 ? { port: request.port } : {},
|
|
150
153
|
...request.user !== void 0 ? { user: request.user } : {},
|
|
151
|
-
...request.password !== void 0 ? { password: request.password } : {}
|
|
154
|
+
...request.password !== void 0 ? { password: request.password } : {},
|
|
155
|
+
...request.readonly !== void 0 ? { readonly: request.readonly } : {}
|
|
152
156
|
};
|
|
153
157
|
const listing = await runClientQuery(scope, connection, tableListingSql(connection.type, connection), connectOptions, new AbortController().signal, true);
|
|
154
158
|
if (listing.exitCode !== 0) {
|
|
@@ -199,7 +203,7 @@ function apply(ctx, config) {
|
|
|
199
203
|
const sessionId = url.searchParams.get("sessionId") ?? "";
|
|
200
204
|
if (sessionId.length === 0) throw new Error("sessionId 不能为空");
|
|
201
205
|
const connection = requireConnection(sessionId);
|
|
202
|
-
const schema = connection.type === "sqlite" ? void 0 : requireIdentifier(url.searchParams.get("schema"), "schema");
|
|
206
|
+
const schema = connection.type === "sqlite" ? void 0 : requireIdentifier(connection.type, url.searchParams.get("schema"), "schema");
|
|
203
207
|
const stdout = await runMetadata(connection, "tables", schema);
|
|
204
208
|
writeJson(200, {
|
|
205
209
|
ok: true,
|
|
@@ -211,8 +215,8 @@ function apply(ctx, config) {
|
|
|
211
215
|
const sessionId = url.searchParams.get("sessionId") ?? "";
|
|
212
216
|
if (sessionId.length === 0) throw new Error("sessionId 不能为空");
|
|
213
217
|
const connection = requireConnection(sessionId);
|
|
214
|
-
const schema = connection.type === "sqlite" ? void 0 : requireIdentifier(url.searchParams.get("schema"), "schema");
|
|
215
|
-
const table = requireIdentifier(url.searchParams.get("table"), "table");
|
|
218
|
+
const schema = connection.type === "sqlite" ? void 0 : requireIdentifier(connection.type, url.searchParams.get("schema"), "schema");
|
|
219
|
+
const table = requireIdentifier(connection.type, url.searchParams.get("table"), "table");
|
|
216
220
|
const stdout = await runMetadata(connection, "describe", schema, table);
|
|
217
221
|
writeJson(200, {
|
|
218
222
|
ok: true,
|
|
@@ -228,6 +232,7 @@ function apply(ctx, config) {
|
|
|
228
232
|
if (typeof sql !== "string" || sql.trim().length === 0) throw new Error("sql 必须是非空字符串");
|
|
229
233
|
if (sql.length > config.maxQueryChars) throw new Error(`sql 超过长度上限(${config.maxQueryChars} 字符)`);
|
|
230
234
|
const connection = requireConnection(sessionId);
|
|
235
|
+
if ((connection.readonly ?? config.readonly) && classifyStatement(sql, connection.type) === "write") throw new Error("当前连接为只读模式,拒绝执行非读语句(仅放行 SELECT/SHOW/DESCRIBE/EXPLAIN/PRAGMA 等)");
|
|
231
236
|
writeJson(200, {
|
|
232
237
|
ok: true,
|
|
233
238
|
result: await runClientQuery(scope, connection, sql, queryOptions, new AbortController().signal)
|
package/lib/tool.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { i as DEFAULT_MAX_RESULT_CHARS, l as
|
|
2
|
-
import { t as runClientQuery } from "./query-
|
|
1
|
+
import { i as DEFAULT_MAX_RESULT_CHARS, l as classifyStatement, o as DEFAULT_QUERY_TIMEOUT_MS, u as clientsSchema } from "./defaults-Dgu2B2Yq.js";
|
|
2
|
+
import { t as runClientQuery } from "./query-vK9dr7Z6.js";
|
|
3
3
|
import z from "schemastery";
|
|
4
4
|
import { defineTool } from "@deepseek-ai/dsh-tools";
|
|
5
5
|
//#region src/tool.ts
|
|
@@ -16,6 +16,7 @@ const Config = z.object({
|
|
|
16
16
|
queryTimeoutMs: z.number().step(1).min(1e3).default(DEFAULT_QUERY_TIMEOUT_MS),
|
|
17
17
|
maxResultChars: z.number().step(1).min(1024).default(DEFAULT_MAX_RESULT_CHARS),
|
|
18
18
|
maxRows: z.number().step(1).min(1).default(100),
|
|
19
|
+
readonly: z.boolean().default(false),
|
|
19
20
|
clients: clientsSchema
|
|
20
21
|
});
|
|
21
22
|
/** One-line sqlcmd label for the terminal card (newlines collapsed). */
|
|
@@ -42,6 +43,7 @@ function apply(ctx, config) {
|
|
|
42
43
|
queryTimeoutMs: config.queryTimeoutMs,
|
|
43
44
|
maxResultChars: config.maxResultChars,
|
|
44
45
|
maxRows: config.maxRows,
|
|
46
|
+
readonly: config.readonly,
|
|
45
47
|
clients: config.clients
|
|
46
48
|
};
|
|
47
49
|
ctx.tools.register(defineTool({
|
|
@@ -95,6 +97,7 @@ function apply(ctx, config) {
|
|
|
95
97
|
if (sessionId === void 0) throw new Error("sqlcmd: 缺少会话上下文(agent loop 未注入)");
|
|
96
98
|
const connection = ctx.dataAgentConnections.getWithSecret(sessionId);
|
|
97
99
|
if (connection === void 0) throw new Error("请先在「数据库」标签页连接数据库,再使用 sqlcmd(未找到当前会话的连接)");
|
|
100
|
+
if ((connection.readonly ?? resolved.readonly) && classifyStatement(args.sql, connection.type) === "write") throw new Error("当前连接为只读模式,sqlcmd 拒绝执行非读语句(仅放行 SELECT/SHOW/DESCRIBE/EXPLAIN/PRAGMA 等)");
|
|
98
101
|
return runClientQuery(ctx, connection, args.sql, {
|
|
99
102
|
clients: resolved.clients,
|
|
100
103
|
timeoutMs: resolved.queryTimeoutMs,
|
|
@@ -15,6 +15,10 @@ export declare const zh: {
|
|
|
15
15
|
'form.port': string;
|
|
16
16
|
'form.user': string;
|
|
17
17
|
'form.password': string;
|
|
18
|
+
'form.rememberPassword': string;
|
|
19
|
+
'form.rememberPassword.hint': string;
|
|
20
|
+
'form.readonly': string;
|
|
21
|
+
'form.readonly.hint': string;
|
|
18
22
|
'form.database': string;
|
|
19
23
|
'form.database.oracle': string;
|
|
20
24
|
'form.database.hive': string;
|
|
@@ -62,6 +66,10 @@ export declare const en: {
|
|
|
62
66
|
'form.port': string;
|
|
63
67
|
'form.user': string;
|
|
64
68
|
'form.password': string;
|
|
69
|
+
'form.rememberPassword': string;
|
|
70
|
+
'form.rememberPassword.hint': string;
|
|
71
|
+
'form.readonly': string;
|
|
72
|
+
'form.readonly.hint': string;
|
|
65
73
|
'form.database': string;
|
|
66
74
|
'form.database.oracle': string;
|
|
67
75
|
'form.database.hive': string;
|
|
@@ -12,14 +12,17 @@
|
|
|
12
12
|
import type { DatabaseType } from './DataAgentWorkbench.tsx';
|
|
13
13
|
/** localStorage key holding the most recent connection configuration. */
|
|
14
14
|
export declare const CONNECTION_STORAGE_KEY = "dsh-data-agent.connection.v1";
|
|
15
|
-
/** The persisted connection configuration
|
|
15
|
+
/** The persisted connection configuration. */
|
|
16
16
|
export interface SavedConnection {
|
|
17
17
|
type: DatabaseType;
|
|
18
18
|
host?: string;
|
|
19
19
|
port?: number;
|
|
20
20
|
user?: string;
|
|
21
21
|
database: string;
|
|
22
|
+
/** Present only when the user explicitly opted in to persist the password. */
|
|
22
23
|
password?: string;
|
|
24
|
+
/** Opt-in flag; when true, {@link saveConnection} may write `password`. */
|
|
25
|
+
persistPassword?: boolean;
|
|
23
26
|
/** Diagnostic timestamp of the save. */
|
|
24
27
|
savedAt: string;
|
|
25
28
|
}
|
package/lib/types/clients.d.ts
CHANGED
|
@@ -12,6 +12,21 @@
|
|
|
12
12
|
* @module @yejiming/dsh-data-agent/clients
|
|
13
13
|
*/
|
|
14
14
|
import type { DatabaseConnection, DatabaseType } from './connections.ts';
|
|
15
|
+
/**
|
|
16
|
+
* Classify a SQL text as a read or write statement by its FIRST effective
|
|
17
|
+
* token (a conservative read whitelist, not a parser). `with` is read only
|
|
18
|
+
* when its body's first token is `select`. `pragma` is read-only for SQLite.
|
|
19
|
+
*/
|
|
20
|
+
export declare function classifyStatement(sql: string, type: DatabaseType): 'read' | 'write';
|
|
21
|
+
/**
|
|
22
|
+
* Validate and quote one schema/table identifier for a safe metadata query.
|
|
23
|
+
* Identifiers are restricted to `[A-Za-z0-9_$]+` and then wrapped per type:
|
|
24
|
+
* backticks (mysql/hive/impala) or double quotes (postgres/oracle/sqlite),
|
|
25
|
+
* with the wrapping quote doubled for any interior occurrence. Rejects any
|
|
26
|
+
* input that could cross the identifier boundary (`#`, `--`, `;`, `'`, `` ` ``,
|
|
27
|
+
* `"`, `.`, `-` are all refused).
|
|
28
|
+
*/
|
|
29
|
+
export declare function sanitizeIdentifier(type: DatabaseType, identifier: string): string;
|
|
15
30
|
/** One deployment override for a database type's CLI client. */
|
|
16
31
|
export interface ClientConfig {
|
|
17
32
|
/** Executable name (resolved through PATH) or absolute path. */
|
|
@@ -37,6 +37,8 @@ export interface DatabaseConnection {
|
|
|
37
37
|
database: string;
|
|
38
38
|
/** In-memory only; never exposed through {@link DataAgentConnections.get}. */
|
|
39
39
|
password?: string;
|
|
40
|
+
/** Optional per-session read-only guard (defaults to the plugin's `readonly`). */
|
|
41
|
+
readonly?: boolean;
|
|
40
42
|
tables?: string[];
|
|
41
43
|
}
|
|
42
44
|
/** Password-free view of one connection (the wire/UI face). */
|
|
@@ -46,6 +48,8 @@ export interface ConnectionSummary {
|
|
|
46
48
|
port?: number;
|
|
47
49
|
user?: string;
|
|
48
50
|
database: string;
|
|
51
|
+
/** Present only when the connection explicitly set it. */
|
|
52
|
+
readonly?: boolean;
|
|
49
53
|
tables?: string[];
|
|
50
54
|
}
|
|
51
55
|
/** The host-plane connection store service (`ctx.dataAgentConnections`). */
|
package/lib/types/index.d.ts
CHANGED
|
@@ -44,6 +44,8 @@ export interface SeededConnectionConfig {
|
|
|
44
44
|
port?: number;
|
|
45
45
|
user?: string;
|
|
46
46
|
database: string;
|
|
47
|
+
/** Optional per-seed read-only guard. */
|
|
48
|
+
readonly?: boolean;
|
|
47
49
|
}
|
|
48
50
|
/** Required plugin configuration (loader schema with deployment defaults). */
|
|
49
51
|
export interface Config {
|
|
@@ -59,6 +61,8 @@ export interface Config {
|
|
|
59
61
|
queryTimeoutMs: number;
|
|
60
62
|
/** In-memory cap on sqlcmd captured output. */
|
|
61
63
|
maxResultChars: number;
|
|
64
|
+
/** Default read-only guard: true rejects write statements in sqlcmd//query. */
|
|
65
|
+
readonly: boolean;
|
|
62
66
|
/** CLI client overrides keyed by database type. */
|
|
63
67
|
clients: ClientsConfig;
|
|
64
68
|
/** Config-seeded connections keyed by session id (`'*'` = wildcard default). */
|
|
@@ -72,6 +76,7 @@ export declare const Config: import("@deepseek-ai/schemastery").default<Schemast
|
|
|
72
76
|
introspectMaxTables: import("@deepseek-ai/schemastery").default<number, number>;
|
|
73
77
|
queryTimeoutMs: import("@deepseek-ai/schemastery").default<number, number>;
|
|
74
78
|
maxResultChars: import("@deepseek-ai/schemastery").default<number, number>;
|
|
79
|
+
readonly: import("@deepseek-ai/schemastery").default<boolean, boolean>;
|
|
75
80
|
clients: import("@deepseek-ai/schemastery").default<import("@deepseek-ai/cosmokit").Dict<{
|
|
76
81
|
command?: string | null | undefined;
|
|
77
82
|
args?: string[] | null | undefined;
|
|
@@ -85,12 +90,14 @@ export declare const Config: import("@deepseek-ai/schemastery").default<Schemast
|
|
|
85
90
|
port?: number | null | undefined;
|
|
86
91
|
user?: string | null | undefined;
|
|
87
92
|
database?: string | null | undefined;
|
|
93
|
+
readonly?: boolean | null | undefined;
|
|
88
94
|
} & import("cosmokit").Dict, string>, import("@deepseek-ai/cosmokit").Dict<Schemastery.ObjectT<{
|
|
89
95
|
type: import("@deepseek-ai/schemastery").default<"mysql" | "postgres" | "sqlite" | "oracle" | "hive" | "impala", "mysql" | "postgres" | "sqlite" | "oracle" | "hive" | "impala">;
|
|
90
96
|
host: import("@deepseek-ai/schemastery").default<string, string>;
|
|
91
97
|
port: import("@deepseek-ai/schemastery").default<number, number>;
|
|
92
98
|
user: import("@deepseek-ai/schemastery").default<string, string>;
|
|
93
99
|
database: import("@deepseek-ai/schemastery").default<string, string>;
|
|
100
|
+
readonly: import("@deepseek-ai/schemastery").default<boolean, boolean>;
|
|
94
101
|
}>, string>>;
|
|
95
102
|
}>, Schemastery.ObjectT<{
|
|
96
103
|
presetId: import("@deepseek-ai/schemastery").default<string, string>;
|
|
@@ -99,6 +106,7 @@ export declare const Config: import("@deepseek-ai/schemastery").default<Schemast
|
|
|
99
106
|
introspectMaxTables: import("@deepseek-ai/schemastery").default<number, number>;
|
|
100
107
|
queryTimeoutMs: import("@deepseek-ai/schemastery").default<number, number>;
|
|
101
108
|
maxResultChars: import("@deepseek-ai/schemastery").default<number, number>;
|
|
109
|
+
readonly: import("@deepseek-ai/schemastery").default<boolean, boolean>;
|
|
102
110
|
clients: import("@deepseek-ai/schemastery").default<import("@deepseek-ai/cosmokit").Dict<{
|
|
103
111
|
command?: string | null | undefined;
|
|
104
112
|
args?: string[] | null | undefined;
|
|
@@ -112,12 +120,14 @@ export declare const Config: import("@deepseek-ai/schemastery").default<Schemast
|
|
|
112
120
|
port?: number | null | undefined;
|
|
113
121
|
user?: string | null | undefined;
|
|
114
122
|
database?: string | null | undefined;
|
|
123
|
+
readonly?: boolean | null | undefined;
|
|
115
124
|
} & import("cosmokit").Dict, string>, import("@deepseek-ai/cosmokit").Dict<Schemastery.ObjectT<{
|
|
116
125
|
type: import("@deepseek-ai/schemastery").default<"mysql" | "postgres" | "sqlite" | "oracle" | "hive" | "impala", "mysql" | "postgres" | "sqlite" | "oracle" | "hive" | "impala">;
|
|
117
126
|
host: import("@deepseek-ai/schemastery").default<string, string>;
|
|
118
127
|
port: import("@deepseek-ai/schemastery").default<number, number>;
|
|
119
128
|
user: import("@deepseek-ai/schemastery").default<string, string>;
|
|
120
129
|
database: import("@deepseek-ai/schemastery").default<string, string>;
|
|
130
|
+
readonly: import("@deepseek-ai/schemastery").default<boolean, boolean>;
|
|
121
131
|
}>, string>>;
|
|
122
132
|
}>>;
|
|
123
133
|
/**
|
package/lib/types/routes.d.ts
CHANGED
|
@@ -63,6 +63,8 @@ export interface Config {
|
|
|
63
63
|
queryTimeoutMs: number;
|
|
64
64
|
/** Cap on one /query SQL text length. */
|
|
65
65
|
maxQueryChars: number;
|
|
66
|
+
/** Read-only guard: true rejects write statements in /query. */
|
|
67
|
+
readonly: boolean;
|
|
66
68
|
}
|
|
67
69
|
/** Loader schema with deployment defaults (no library defaults). */
|
|
68
70
|
export declare const Config: import("@deepseek-ai/schemastery").default<Schemastery.ObjectS<{
|
|
@@ -71,12 +73,14 @@ export declare const Config: import("@deepseek-ai/schemastery").default<Schemast
|
|
|
71
73
|
maxResultChars: import("@deepseek-ai/schemastery").default<number, number>;
|
|
72
74
|
queryTimeoutMs: import("@deepseek-ai/schemastery").default<number, number>;
|
|
73
75
|
maxQueryChars: import("@deepseek-ai/schemastery").default<number, number>;
|
|
76
|
+
readonly: import("@deepseek-ai/schemastery").default<boolean, boolean>;
|
|
74
77
|
}>, Schemastery.ObjectT<{
|
|
75
78
|
connectTimeoutMs: import("@deepseek-ai/schemastery").default<number, number>;
|
|
76
79
|
introspectMaxTables: import("@deepseek-ai/schemastery").default<number, number>;
|
|
77
80
|
maxResultChars: import("@deepseek-ai/schemastery").default<number, number>;
|
|
78
81
|
queryTimeoutMs: import("@deepseek-ai/schemastery").default<number, number>;
|
|
79
82
|
maxQueryChars: import("@deepseek-ai/schemastery").default<number, number>;
|
|
83
|
+
readonly: import("@deepseek-ai/schemastery").default<boolean, boolean>;
|
|
80
84
|
}>>;
|
|
81
85
|
/** The connection request wire body (validated in the /connect handler). */
|
|
82
86
|
export interface ConnectRequestBody {
|
|
@@ -87,6 +91,7 @@ export interface ConnectRequestBody {
|
|
|
87
91
|
user?: string;
|
|
88
92
|
database: string;
|
|
89
93
|
password?: string;
|
|
94
|
+
readonly?: boolean;
|
|
90
95
|
}
|
|
91
96
|
/**
|
|
92
97
|
* Validate an untrusted /connect body; sqlite paths resolve to absolute
|
package/lib/types/tool.d.ts
CHANGED
|
@@ -26,6 +26,8 @@ export interface Config {
|
|
|
26
26
|
maxResultChars: number;
|
|
27
27
|
/** Row-count guidance injected into the tool description. */
|
|
28
28
|
maxRows: number;
|
|
29
|
+
/** Read-only guard: true rejects write statements. */
|
|
30
|
+
readonly: boolean;
|
|
29
31
|
/** CLI client overrides keyed by database type. */
|
|
30
32
|
clients: Partial<Record<string, ClientConfig>>;
|
|
31
33
|
}
|
|
@@ -34,6 +36,7 @@ export declare const Config: import("@deepseek-ai/schemastery").default<Schemast
|
|
|
34
36
|
queryTimeoutMs: import("@deepseek-ai/schemastery").default<number, number>;
|
|
35
37
|
maxResultChars: import("@deepseek-ai/schemastery").default<number, number>;
|
|
36
38
|
maxRows: import("@deepseek-ai/schemastery").default<number, number>;
|
|
39
|
+
readonly: import("@deepseek-ai/schemastery").default<boolean, boolean>;
|
|
37
40
|
clients: import("@deepseek-ai/schemastery").default<import("@deepseek-ai/cosmokit").Dict<{
|
|
38
41
|
command?: string | null | undefined;
|
|
39
42
|
args?: string[] | null | undefined;
|
|
@@ -45,6 +48,7 @@ export declare const Config: import("@deepseek-ai/schemastery").default<Schemast
|
|
|
45
48
|
queryTimeoutMs: import("@deepseek-ai/schemastery").default<number, number>;
|
|
46
49
|
maxResultChars: import("@deepseek-ai/schemastery").default<number, number>;
|
|
47
50
|
maxRows: import("@deepseek-ai/schemastery").default<number, number>;
|
|
51
|
+
readonly: import("@deepseek-ai/schemastery").default<boolean, boolean>;
|
|
48
52
|
clients: import("@deepseek-ai/schemastery").default<import("@deepseek-ai/cosmokit").Dict<{
|
|
49
53
|
command?: string | null | undefined;
|
|
50
54
|
args?: string[] | null | undefined;
|
package/package.json
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yejiming/dsh-data-agent",
|
|
3
3
|
"description": "Data Agent for the dsh web GUI: session-scoped database connections (MySQL/PostgreSQL/SQLite), the sqlcmd tool, the data-agent agent preset, and the database conversation-view tab",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.2",
|
|
5
|
+
"publishConfig": {
|
|
6
|
+
"access": "public"
|
|
7
|
+
},
|
|
5
8
|
"type": "module",
|
|
6
9
|
"main": "lib/index.js",
|
|
7
10
|
"types": "lib/types/index.d.ts",
|