@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.
@@ -1,4 +1,4 @@
1
- import { r as redactSecretText } from "./connections-WmjuUrDj.js";
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-LFgLb6el.js";
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
- if (connection.passwordRef === void 0) return {
1350
- ...connection,
1351
- tables: copyTables(connection.tables)
1352
- };
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}" 未配置`);
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
- if (connection.type === "sqlite") return void 0;
1404
- if (connection.password !== void 0) return {
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
- const summary = summarize(connection);
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-WmjuUrDj.js";
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-LFgLb6el.js";
4
- import { n as apply$2 } from "./tool-Dka6RyEp.js";
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 ? { connected: false } : {
94
- connected: true,
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-WmjuUrDj.js";
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-Dka6RyEp.js";
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. */
@@ -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.10",
4
+ "version": "0.0.11",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },