@yejiming/dsh-data-agent 0.0.10 → 0.0.11
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 +5 -11
- package/README.md +5 -11
- package/lib/client.js +130 -89
- package/lib/client.js.map +1 -1
- package/lib/{command-LFgLb6el.js → command-DuCpwVbl.js} +2 -2
- package/lib/command.js +1 -1
- package/lib/{connections-WmjuUrDj.js → connections-5sfdEDsG.js} +44 -23
- package/lib/index.js +8 -3
- package/lib/routes.js +6 -2
- package/lib/{tool-Dka6RyEp.js → tool-DVh61An-.js} +1 -1
- package/lib/tool.js +1 -1
- package/lib/types/client/locales.d.ts +6 -0
- package/lib/types/client/persistence.d.ts +1 -1
- package/lib/types/connections.d.ts +10 -0
- package/lib/types/storage.d.ts +5 -0
- package/package.json +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { r as redactSecretText } from "./connections-
|
|
1
|
+
import { r as redactSecretText } from "./connections-5sfdEDsG.js";
|
|
2
2
|
import { RUN_CODE_NAME } from "@deepseek-ai/dsh-tools";
|
|
3
3
|
//#region src/tui-connection-form.ts
|
|
4
4
|
const TUI_DATABASE_TYPES = [
|
|
@@ -691,7 +691,7 @@ function formatConnectionStatus(summary) {
|
|
|
691
691
|
if (summary === void 0) return "数据库状态:未连接。";
|
|
692
692
|
const endpoint = summary.type === "sqlite" ? summary.database : `${summary.host ?? "localhost"}${summary.port !== void 0 ? `:${summary.port}` : ""}`;
|
|
693
693
|
const lines = [
|
|
694
|
-
"数据库状态:已连接",
|
|
694
|
+
summary.reconnectRequired === true ? "数据库状态:需要重新认证" : "数据库状态:已连接",
|
|
695
695
|
`类型:${summary.type}`,
|
|
696
696
|
`地址:${endpoint}`,
|
|
697
697
|
`数据库:${summary.database}`,
|
package/lib/command.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as formatConnectionStatus, c as parseConnectArguments, i as executeDatabaseCommand, l as parseDatabaseAction, n as DATA_AGENT_TOOL_NAMES, o as inject, r as apply, s as name, t as DATABASE_COMMAND_USAGE } from "./command-
|
|
1
|
+
import { a as formatConnectionStatus, c as parseConnectArguments, i as executeDatabaseCommand, l as parseDatabaseAction, n as DATA_AGENT_TOOL_NAMES, o as inject, r as apply, s as name, t as DATABASE_COMMAND_USAGE } from "./command-DuCpwVbl.js";
|
|
2
2
|
export { DATABASE_COMMAND_USAGE, DATA_AGENT_TOOL_NAMES, apply, executeDatabaseCommand, formatConnectionStatus, inject, name, parseConnectArguments, parseDatabaseAction };
|
|
@@ -1305,7 +1305,8 @@ function normalizeConnectionInput(input, cwd = process.cwd()) {
|
|
|
1305
1305
|
if (input.name !== void 0 && input.name.trim().length === 0) throw new Error("name 不能为空");
|
|
1306
1306
|
const connection = {
|
|
1307
1307
|
type: input.type,
|
|
1308
|
-
database: input.type === "sqlite" ? resolve(cwd, input.database) : input.database
|
|
1308
|
+
database: input.type === "sqlite" ? resolve(cwd, input.database) : input.database,
|
|
1309
|
+
credentialMode: input.type === "sqlite" ? "none" : input.passwordRef !== void 0 ? "reference" : input.password !== void 0 && input.password.length > 0 ? "password" : "none"
|
|
1309
1310
|
};
|
|
1310
1311
|
if (input.type !== "sqlite") {
|
|
1311
1312
|
if (input.host !== void 0 && input.host.length > 0) connection.host = input.host;
|
|
@@ -1346,16 +1347,21 @@ function createConnectionService(ctx, options, persistence) {
|
|
|
1346
1347
|
return ctx;
|
|
1347
1348
|
};
|
|
1348
1349
|
const resolveCredential = async (connection) => {
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1350
|
+
const mode = credentialModeOf(connection);
|
|
1351
|
+
if (mode === "reference") {
|
|
1352
|
+
if (connection.passwordRef === void 0) throw new Error("数据库凭据引用缺失,请重新配置连接");
|
|
1353
|
+
const ref = validatedCredentialRef(connection.passwordRef);
|
|
1354
|
+
const hit = await requireContext().credentials.resolve(ref);
|
|
1355
|
+
if (hit === void 0 || hit.value.length === 0) throw new Error(`凭据引用 "${connection.passwordRef}" 未配置`);
|
|
1356
|
+
return {
|
|
1357
|
+
...connection,
|
|
1358
|
+
password: hit.value,
|
|
1359
|
+
tables: copyTables(connection.tables)
|
|
1360
|
+
};
|
|
1361
|
+
}
|
|
1362
|
+
if (mode === "password" && connection.password === void 0) throw new Error("数据库凭据需要重新输入;请打开数据库配置并重新连接");
|
|
1356
1363
|
return {
|
|
1357
1364
|
...connection,
|
|
1358
|
-
password: hit.value,
|
|
1359
1365
|
tables: copyTables(connection.tables)
|
|
1360
1366
|
};
|
|
1361
1367
|
};
|
|
@@ -1400,18 +1406,29 @@ function createConnectionService(ctx, options, persistence) {
|
|
|
1400
1406
|
}
|
|
1401
1407
|
};
|
|
1402
1408
|
const credentialSummary = async (connection) => {
|
|
1403
|
-
|
|
1404
|
-
if (connection.
|
|
1409
|
+
const mode = credentialModeOf(connection);
|
|
1410
|
+
if (connection.type === "sqlite" || mode === "none") return void 0;
|
|
1411
|
+
if (mode === "password") return connection.password === void 0 ? { configured: false } : {
|
|
1405
1412
|
configured: true,
|
|
1406
1413
|
source: "memory"
|
|
1407
1414
|
};
|
|
1408
|
-
if (connection.passwordRef === void 0) return { configured: false };
|
|
1415
|
+
if (mode !== "reference" || connection.passwordRef === void 0) return { configured: false };
|
|
1409
1416
|
const info = await requireContext().credentials.describe(validatedCredentialRef(connection.passwordRef));
|
|
1410
1417
|
return {
|
|
1411
1418
|
configured: info.configured,
|
|
1412
1419
|
...info.source !== void 0 ? { source: info.source } : {}
|
|
1413
1420
|
};
|
|
1414
1421
|
};
|
|
1422
|
+
const statusSummary = async (connection) => {
|
|
1423
|
+
const summary = summarize(connection);
|
|
1424
|
+
const mode = credentialModeOf(connection);
|
|
1425
|
+
summary.credentialMode = mode;
|
|
1426
|
+
summary.credential = await credentialSummary(connection);
|
|
1427
|
+
const ready = mode === "none" || summary.credential?.configured === true;
|
|
1428
|
+
summary.ready = ready;
|
|
1429
|
+
summary.reconnectRequired = !ready;
|
|
1430
|
+
return summary;
|
|
1431
|
+
};
|
|
1415
1432
|
const service = {
|
|
1416
1433
|
set(sessionId, connection) {
|
|
1417
1434
|
if (connection.password !== void 0 && connection.passwordRef !== void 0) throw new Error("password 与 passwordRef 不能同时提供");
|
|
@@ -1454,9 +1471,7 @@ function createConnectionService(ctx, options, persistence) {
|
|
|
1454
1471
|
async status(sessionId) {
|
|
1455
1472
|
const connection = rawConnection(sessionId);
|
|
1456
1473
|
if (connection === void 0) return void 0;
|
|
1457
|
-
|
|
1458
|
-
summary.credential = await credentialSummary(connection);
|
|
1459
|
-
return summary;
|
|
1474
|
+
return statusSummary(connection);
|
|
1460
1475
|
},
|
|
1461
1476
|
async connect(sessionId, input, signal) {
|
|
1462
1477
|
if (sessionId.length === 0) throw new Error("sessionId 必须是非空字符串");
|
|
@@ -1472,11 +1487,9 @@ function createConnectionService(ctx, options, persistence) {
|
|
|
1472
1487
|
tables
|
|
1473
1488
|
};
|
|
1474
1489
|
runtime.set(sessionId, published);
|
|
1475
|
-
const summary = summarize(published);
|
|
1476
|
-
summary.credential = await credentialSummary(published);
|
|
1477
1490
|
return {
|
|
1478
1491
|
tables,
|
|
1479
|
-
summary
|
|
1492
|
+
summary: await statusSummary(published)
|
|
1480
1493
|
};
|
|
1481
1494
|
},
|
|
1482
1495
|
async disconnect(sessionId) {
|
|
@@ -1491,11 +1504,9 @@ function createConnectionService(ctx, options, persistence) {
|
|
|
1491
1504
|
tables
|
|
1492
1505
|
};
|
|
1493
1506
|
runtime.set(sessionId, published);
|
|
1494
|
-
const summary = summarize(published);
|
|
1495
|
-
summary.credential = await credentialSummary(published);
|
|
1496
1507
|
return {
|
|
1497
1508
|
tables,
|
|
1498
|
-
summary
|
|
1509
|
+
summary: await statusSummary(published)
|
|
1499
1510
|
};
|
|
1500
1511
|
},
|
|
1501
1512
|
async resolveForExecution(sessionId) {
|
|
@@ -1583,7 +1594,8 @@ function connectionFromProfile(profileId, profile) {
|
|
|
1583
1594
|
...profile.port !== void 0 ? { port: profile.port } : {},
|
|
1584
1595
|
...profile.user !== void 0 ? { user: profile.user } : {},
|
|
1585
1596
|
...profile.readonly !== void 0 ? { readonly: profile.readonly } : {},
|
|
1586
|
-
...profile.passwordRef !== void 0 ? { passwordRef: profile.passwordRef } : {}
|
|
1597
|
+
...profile.passwordRef !== void 0 ? { passwordRef: profile.passwordRef } : {},
|
|
1598
|
+
credentialMode: profile.credentialMode ?? (profile.type === "sqlite" ? "none" : profile.passwordRef !== void 0 ? "reference" : "password")
|
|
1587
1599
|
};
|
|
1588
1600
|
}
|
|
1589
1601
|
function profileFromConnection(connection, updatedAt) {
|
|
@@ -1596,9 +1608,18 @@ function profileFromConnection(connection, updatedAt) {
|
|
|
1596
1608
|
...connection.port !== void 0 ? { port: connection.port } : {},
|
|
1597
1609
|
...connection.user !== void 0 ? { user: connection.user } : {},
|
|
1598
1610
|
...connection.readonly !== void 0 ? { readonly: connection.readonly } : {},
|
|
1599
|
-
...connection.passwordRef !== void 0 ? { passwordRef: connection.passwordRef } : {}
|
|
1611
|
+
...connection.passwordRef !== void 0 ? { passwordRef: connection.passwordRef } : {},
|
|
1612
|
+
...connection.credentialMode !== void 0 ? { credentialMode: connection.credentialMode } : {}
|
|
1600
1613
|
};
|
|
1601
1614
|
}
|
|
1615
|
+
/** Infer legacy records while leaving ambiguous secret-less SQL profiles conservative. */
|
|
1616
|
+
function credentialModeOf(connection) {
|
|
1617
|
+
if (connection.credentialMode !== void 0) return connection.credentialMode;
|
|
1618
|
+
if (connection.type === "sqlite") return "none";
|
|
1619
|
+
if (connection.passwordRef !== void 0) return "reference";
|
|
1620
|
+
if (connection.password !== void 0) return "password";
|
|
1621
|
+
return "none";
|
|
1622
|
+
}
|
|
1602
1623
|
function requireIdentifier(type, value, label) {
|
|
1603
1624
|
if (value === void 0 || value.length === 0) throw new Error(`${label} 不能为空`);
|
|
1604
1625
|
sanitizeIdentifier(type, value);
|
package/lib/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { o as clientsSchema, t as createConnectionService } from "./connections-
|
|
1
|
+
import { o as clientsSchema, t as createConnectionService } from "./connections-5sfdEDsG.js";
|
|
2
2
|
import { a as DEFAULT_PRESET_ID, i as DEFAULT_MAX_RESULT_CHARS, o as DEFAULT_QUERY_TIMEOUT_MS, r as DEFAULT_MAX_QUERY_CHARS, t as DEFAULT_CONNECT_TIMEOUT_MS } from "./defaults-DP4RyRh1.js";
|
|
3
|
-
import { r as apply$1 } from "./command-
|
|
4
|
-
import { n as apply$2 } from "./tool-
|
|
3
|
+
import { r as apply$1 } from "./command-DuCpwVbl.js";
|
|
4
|
+
import { n as apply$2 } from "./tool-DVh61An-.js";
|
|
5
5
|
import { createHash } from "node:crypto";
|
|
6
6
|
import { access, cp, mkdir, readFile, writeFile } from "node:fs/promises";
|
|
7
7
|
import { homedir } from "node:os";
|
|
@@ -43,6 +43,11 @@ const persistedConnectionProfileSchema = z$1.object({
|
|
|
43
43
|
database: z$1.string().min(1),
|
|
44
44
|
readonly: z$1.boolean().optional(),
|
|
45
45
|
passwordRef: z$1.string().regex(/^[A-Za-z_][A-Za-z0-9_]*$/).optional(),
|
|
46
|
+
credentialMode: z$1.enum([
|
|
47
|
+
"none",
|
|
48
|
+
"password",
|
|
49
|
+
"reference"
|
|
50
|
+
]).optional(),
|
|
46
51
|
updatedAt: z$1.string().min(1)
|
|
47
52
|
}).strict();
|
|
48
53
|
/** Durable session-to-profile binding schema. */
|
package/lib/routes.js
CHANGED
|
@@ -90,8 +90,12 @@ function apply(ctx, _config) {
|
|
|
90
90
|
if (req.method === "GET" && routeIs(segments, "status")) {
|
|
91
91
|
const sessionId = requireString(url.searchParams.get("sessionId"), "sessionId");
|
|
92
92
|
const summary = await scope.dataAgentConnections.status(sessionId);
|
|
93
|
-
writeJson(200, summary === void 0 ? {
|
|
94
|
-
connected:
|
|
93
|
+
writeJson(200, summary === void 0 ? {
|
|
94
|
+
connected: false,
|
|
95
|
+
reconnectRequired: false
|
|
96
|
+
} : {
|
|
97
|
+
connected: summary.ready === true,
|
|
98
|
+
reconnectRequired: summary.reconnectRequired === true,
|
|
95
99
|
summary
|
|
96
100
|
});
|
|
97
101
|
return;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as classifyStatement, c as assertSingleStatement, i as runClientQuery, n as redactQueryResult, o as clientsSchema, r as redactSecretText, s as enforceReadRowLimit } from "./connections-
|
|
1
|
+
import { a as classifyStatement, c as assertSingleStatement, i as runClientQuery, n as redactQueryResult, o as clientsSchema, r as redactSecretText, s as enforceReadRowLimit } from "./connections-5sfdEDsG.js";
|
|
2
2
|
import { i as DEFAULT_MAX_RESULT_CHARS, o as DEFAULT_QUERY_TIMEOUT_MS, r as DEFAULT_MAX_QUERY_CHARS } from "./defaults-DP4RyRh1.js";
|
|
3
3
|
import z from "schemastery";
|
|
4
4
|
import { defineTool } from "@deepseek-ai/dsh-tools";
|
package/lib/tool.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { i as name, n as apply, r as inject, t as Config } from "./tool-
|
|
1
|
+
import { i as name, n as apply, r as inject, t as Config } from "./tool-DVh61An-.js";
|
|
2
2
|
export { Config, apply, inject, name };
|
|
@@ -40,12 +40,15 @@ export declare const zh: {
|
|
|
40
40
|
'state.disconnected': string;
|
|
41
41
|
'state.checking': string;
|
|
42
42
|
'state.reconnecting': string;
|
|
43
|
+
'state.reconnectRequired': string;
|
|
43
44
|
'workbench.open.connected': string;
|
|
44
45
|
'workbench.open.disconnected': string;
|
|
45
46
|
'workbench.open.checking': string;
|
|
46
47
|
'workbench.open.error': string;
|
|
48
|
+
'workbench.open.reconnectRequired': string;
|
|
47
49
|
'composer.placeholder.disconnected': string;
|
|
48
50
|
'composer.placeholder.connected': string;
|
|
51
|
+
'composer.placeholder.reconnectRequired': string;
|
|
49
52
|
'wb.workbench.title': string;
|
|
50
53
|
'wb.workbench.description': string;
|
|
51
54
|
'wb.workbench.tabs': string;
|
|
@@ -125,12 +128,15 @@ export declare const en: {
|
|
|
125
128
|
'state.disconnected': string;
|
|
126
129
|
'state.checking': string;
|
|
127
130
|
'state.reconnecting': string;
|
|
131
|
+
'state.reconnectRequired': string;
|
|
128
132
|
'workbench.open.connected': string;
|
|
129
133
|
'workbench.open.disconnected': string;
|
|
130
134
|
'workbench.open.checking': string;
|
|
131
135
|
'workbench.open.error': string;
|
|
136
|
+
'workbench.open.reconnectRequired': string;
|
|
132
137
|
'composer.placeholder.disconnected': string;
|
|
133
138
|
'composer.placeholder.connected': string;
|
|
139
|
+
'composer.placeholder.reconnectRequired': string;
|
|
134
140
|
'wb.workbench.title': string;
|
|
135
141
|
'wb.workbench.description': string;
|
|
136
142
|
'wb.workbench.tabs': string;
|
|
@@ -24,7 +24,7 @@ export interface SavedConnection {
|
|
|
24
24
|
/** Non-secret credential reference; mutually exclusive with `password`. */
|
|
25
25
|
passwordRef?: string;
|
|
26
26
|
/** Explicit form mode; absent legacy records infer it from passwordRef. */
|
|
27
|
-
credentialMode?: 'password' | 'reference';
|
|
27
|
+
credentialMode?: 'none' | 'password' | 'reference';
|
|
28
28
|
/** Opt-in flag; when true, {@link saveConnection} may write `password`. */
|
|
29
29
|
persistPassword?: boolean;
|
|
30
30
|
readonly?: boolean;
|
|
@@ -14,6 +14,8 @@ import { type QueryResult } from './query.ts';
|
|
|
14
14
|
export declare const WILDCARD_SESSION = "*";
|
|
15
15
|
/** Supported database client kinds. */
|
|
16
16
|
export type DatabaseType = 'mysql' | 'postgres' | 'sqlite' | 'oracle' | 'hive' | 'impala';
|
|
17
|
+
/** How a non-SQLite profile authenticates without ever persisting a secret. */
|
|
18
|
+
export type CredentialMode = 'none' | 'password' | 'reference';
|
|
17
19
|
/** Safe credential facts returned to UI/command surfaces. */
|
|
18
20
|
export interface CredentialSummary {
|
|
19
21
|
configured: boolean;
|
|
@@ -38,6 +40,8 @@ export interface DatabaseConnectionInput {
|
|
|
38
40
|
}
|
|
39
41
|
/** Runtime connection. `tables` and temporary `password` are never durable. */
|
|
40
42
|
export interface DatabaseConnection extends DatabaseConnectionInput {
|
|
43
|
+
/** Internal authentication shape retained in the non-secret durable profile. */
|
|
44
|
+
credentialMode?: CredentialMode;
|
|
41
45
|
tables?: string[];
|
|
42
46
|
}
|
|
43
47
|
/** Password-free public connection view. */
|
|
@@ -53,6 +57,11 @@ export interface ConnectionSummary {
|
|
|
53
57
|
name?: string;
|
|
54
58
|
tables?: string[];
|
|
55
59
|
credential?: CredentialSummary;
|
|
60
|
+
credentialMode?: CredentialMode;
|
|
61
|
+
/** True only when the current process can execute a database operation now. */
|
|
62
|
+
ready?: boolean;
|
|
63
|
+
/** A saved profile exists, but its credential must be supplied/configured again. */
|
|
64
|
+
reconnectRequired?: boolean;
|
|
56
65
|
}
|
|
57
66
|
/** Value stored in the `profiles` domain table. Never add secrets here. */
|
|
58
67
|
export interface PersistedConnectionProfile {
|
|
@@ -64,6 +73,7 @@ export interface PersistedConnectionProfile {
|
|
|
64
73
|
database: string;
|
|
65
74
|
readonly?: boolean;
|
|
66
75
|
passwordRef?: string;
|
|
76
|
+
credentialMode?: CredentialMode;
|
|
67
77
|
updatedAt: string;
|
|
68
78
|
}
|
|
69
79
|
/** Value stored in the `bindings` domain table. */
|
package/lib/types/storage.d.ts
CHANGED
|
@@ -31,6 +31,11 @@ export declare const persistedConnectionProfileSchema: z.ZodObject<{
|
|
|
31
31
|
database: z.ZodString;
|
|
32
32
|
readonly: z.ZodOptional<z.ZodBoolean>;
|
|
33
33
|
passwordRef: z.ZodOptional<z.ZodString>;
|
|
34
|
+
credentialMode: z.ZodOptional<z.ZodEnum<{
|
|
35
|
+
none: "none";
|
|
36
|
+
password: "password";
|
|
37
|
+
reference: "reference";
|
|
38
|
+
}>>;
|
|
34
39
|
updatedAt: z.ZodString;
|
|
35
40
|
}, z.core.$strict>;
|
|
36
41
|
/** Durable session-to-profile binding schema. */
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yejiming/dsh-data-agent",
|
|
3
3
|
"description": "Data Agent for DSH Web and TUI: shared database connections, a masked TUI form, secure credential references, SQL tools, and the data-agent preset",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.11",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|