@yejiming/dsh-data-agent 0.0.6 → 0.0.10
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 +142 -119
- package/README.md +138 -118
- package/cordis.patch.yml +8 -9
- package/lib/client.js +42423 -524
- package/lib/client.js.map +1 -1
- package/lib/command-LFgLb6el.js +875 -0
- package/lib/command.js +2 -0
- package/lib/connections-WmjuUrDj.js +1608 -0
- package/lib/defaults-DP4RyRh1.js +21 -0
- package/lib/index.js +265 -68
- package/lib/routes.js +94 -170
- package/lib/tool-Dka6RyEp.js +1128 -0
- package/lib/tool.js +1 -426
- package/lib/types/analysis.d.ts +1071 -0
- package/lib/types/client/AnalysisChart.d.ts +26 -0
- package/lib/types/client/AnalysisDashboard.d.ts +30 -0
- package/lib/types/client/DataAgentWorkbench.d.ts +2 -2
- package/lib/types/client/analysis-charts.d.ts +40 -0
- package/lib/types/client/analysis-view-model.d.ts +44 -0
- package/lib/types/client/index.d.ts +3 -4
- package/lib/types/client/locales.d.ts +66 -0
- package/lib/types/client/persistence.d.ts +6 -1
- package/lib/types/client-discovery.d.ts +45 -0
- package/lib/types/clients.d.ts +17 -10
- package/lib/types/command.d.ts +41 -0
- package/lib/types/connections.d.ts +115 -40
- package/lib/types/defaults.d.ts +2 -0
- package/lib/types/index.d.ts +109 -63
- package/lib/types/routes.d.ts +25 -91
- package/lib/types/sql.d.ts +1 -1
- package/lib/types/storage.d.ts +70 -0
- package/lib/types/structured-read.d.ts +50 -0
- package/lib/types/tool.d.ts +29 -20
- package/lib/types/tui-connection-form.d.ts +98 -0
- package/package.json +65 -4
- package/preset/data-agent/agent.cordis.yml +22 -25
- package/preset/data-agent/preset.yml +1 -1
- package/lib/defaults-Bac6QvNt.js +0 -911
- package/lib/query-CmhTFklw.js +0 -86
package/lib/types/index.d.ts
CHANGED
|
@@ -1,37 +1,38 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Data Agent
|
|
3
|
-
* `dataAgentConnections` service (
|
|
4
|
-
*
|
|
5
|
-
* wildcard default),
|
|
6
|
-
* `$DSH_HOME/.agent-presets
|
|
7
|
-
*
|
|
2
|
+
* Data Agent profile entry. The host row provides the
|
|
3
|
+
* `dataAgentConnections` service (shared non-secret profile/binding storage;
|
|
4
|
+
* temporary passwords stay process-local), seeds config connections (`connections`, `'*'` =
|
|
5
|
+
* wildcard default), installs the `data-agent` agent preset into
|
|
6
|
+
* `$DSH_HOME/.agent-presets/`, and preloads the preset-scoped database tools
|
|
7
|
+
* and command through this profile bundle entry.
|
|
8
8
|
*
|
|
9
9
|
* The HTTP routes live in the separate `./routes` entry
|
|
10
10
|
* (`@yejiming/dsh-data-agent/routes`, cordis row `data-agent-routes`) so
|
|
11
|
-
* this row keeps working in headless profiles without a webserver
|
|
12
|
-
* database
|
|
13
|
-
*
|
|
11
|
+
* this row keeps working in headless profiles without a webserver. The
|
|
12
|
+
* database implementations still have public `./tool` and `./command`
|
|
13
|
+
* exports, but the shipped preset does not dynamically import those package
|
|
14
|
+
* subpaths. Loading them here keeps Desktop on the same profile-startup path
|
|
15
|
+
* as other UI bundles and avoids Electron ASAR package-resolution drift.
|
|
14
16
|
* @module @yejiming/dsh-data-agent
|
|
15
17
|
*/
|
|
16
18
|
import type { Context } from '@deepseek-ai/cordis';
|
|
19
|
+
import type { ScopeKey } from '@deepseek-ai/dsh-scope';
|
|
17
20
|
/** The `dataAgentConnections` service face on the cordis context. */
|
|
18
21
|
declare module '@deepseek-ai/cordis' {
|
|
19
22
|
interface Context {
|
|
20
23
|
dataAgentConnections: DataAgentConnections;
|
|
21
24
|
}
|
|
22
25
|
}
|
|
26
|
+
import z from 'schemastery';
|
|
23
27
|
import { type DataAgentConnections, type DatabaseType } from './connections.ts';
|
|
24
28
|
import { type ClientConfig } from './clients.ts';
|
|
29
|
+
import { type Config as ToolConfig } from './tool.ts';
|
|
25
30
|
/** Cordis plugin name (diagnostics only). */
|
|
26
31
|
export declare const name = "data-agent";
|
|
27
|
-
/** Services required before the
|
|
32
|
+
/** Services required before the profile entry can mount its preset layer. */
|
|
28
33
|
export declare const inject: string[];
|
|
29
34
|
/** Deployment overrides for one database type's CLI client. */
|
|
30
|
-
export
|
|
31
|
-
mysql?: ClientConfig;
|
|
32
|
-
postgres?: ClientConfig;
|
|
33
|
-
sqlite?: ClientConfig;
|
|
34
|
-
}
|
|
35
|
+
export type ClientsConfig = Partial<Record<DatabaseType, ClientConfig>>;
|
|
35
36
|
/**
|
|
36
37
|
* One config-seeded connection. Deliberately password-free: passwords are a
|
|
37
38
|
* memory-only / connect-time value, so only the /connect route may carry one.
|
|
@@ -46,6 +47,9 @@ export interface SeededConnectionConfig {
|
|
|
46
47
|
database: string;
|
|
47
48
|
/** Optional per-seed read-only guard. */
|
|
48
49
|
readonly?: boolean;
|
|
50
|
+
/** Safe credential reference. Real passwords are rejected by the schema. */
|
|
51
|
+
passwordRef?: string;
|
|
52
|
+
password?: never;
|
|
49
53
|
}
|
|
50
54
|
/** Required plugin configuration (loader schema with deployment defaults). */
|
|
51
55
|
export interface Config {
|
|
@@ -61,73 +65,97 @@ export interface Config {
|
|
|
61
65
|
queryTimeoutMs: number;
|
|
62
66
|
/** In-memory cap on database-tool captured output. */
|
|
63
67
|
maxResultChars: number;
|
|
68
|
+
/** Maximum structured rows returned by one database read tool call. */
|
|
69
|
+
maxRows: number;
|
|
70
|
+
/** Maximum SQL text accepted by the shared Web query adapter. */
|
|
71
|
+
maxQueryChars: number;
|
|
64
72
|
/** Default read-only guard: true rejects write statements in database tools and /query. */
|
|
65
73
|
readonly: boolean;
|
|
74
|
+
/** Persist non-secret profiles/bindings through DSH storage-domain. */
|
|
75
|
+
persistConnections: boolean;
|
|
66
76
|
/** CLI client overrides keyed by database type. */
|
|
67
77
|
clients: ClientsConfig;
|
|
68
78
|
/** Config-seeded connections keyed by session id (`'*'` = wildcard default). */
|
|
69
79
|
connections: Record<string, SeededConnectionConfig>;
|
|
70
80
|
}
|
|
71
81
|
/** Loader schema with deployment defaults (no library defaults). */
|
|
72
|
-
export declare const Config:
|
|
73
|
-
presetId:
|
|
74
|
-
installPreset:
|
|
75
|
-
connectTimeoutMs:
|
|
76
|
-
introspectMaxTables:
|
|
77
|
-
queryTimeoutMs:
|
|
78
|
-
maxResultChars:
|
|
79
|
-
|
|
80
|
-
|
|
82
|
+
export declare const Config: z<Schemastery.ObjectS<{
|
|
83
|
+
presetId: z<string, string>;
|
|
84
|
+
installPreset: z<boolean, boolean>;
|
|
85
|
+
connectTimeoutMs: z<number, number>;
|
|
86
|
+
introspectMaxTables: z<number, number>;
|
|
87
|
+
queryTimeoutMs: z<number, number>;
|
|
88
|
+
maxResultChars: z<number, number>;
|
|
89
|
+
maxRows: z<number, number>;
|
|
90
|
+
maxQueryChars: z<number, number>;
|
|
91
|
+
readonly: z<boolean, boolean>;
|
|
92
|
+
persistConnections: z<boolean, boolean>;
|
|
93
|
+
clients: z<import("cosmokit").Dict<{
|
|
81
94
|
command?: string | null | undefined;
|
|
82
95
|
args?: string[] | null | undefined;
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
96
|
+
searchPaths?: string[] | null | undefined;
|
|
97
|
+
} & import("@deepseek-ai/cosmokit").Dict, string>, import("cosmokit").Dict<Schemastery.ObjectT<{
|
|
98
|
+
command: z<string, string>;
|
|
99
|
+
args: z<string[], string[]>;
|
|
100
|
+
searchPaths: z<string[], string[]>;
|
|
86
101
|
}>, string>>;
|
|
87
|
-
connections:
|
|
102
|
+
connections: z<import("cosmokit").Dict<{
|
|
88
103
|
type?: "mysql" | "postgres" | "sqlite" | "oracle" | "hive" | "impala" | null | undefined;
|
|
89
104
|
host?: string | null | undefined;
|
|
90
105
|
port?: number | null | undefined;
|
|
91
106
|
user?: string | null | undefined;
|
|
92
107
|
database?: string | null | undefined;
|
|
93
108
|
readonly?: boolean | null | undefined;
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
109
|
+
passwordRef?: string | null | undefined;
|
|
110
|
+
password?: null | undefined;
|
|
111
|
+
} & import("@deepseek-ai/cosmokit").Dict, string>, import("cosmokit").Dict<Schemastery.ObjectT<{
|
|
112
|
+
type: z<"mysql" | "postgres" | "sqlite" | "oracle" | "hive" | "impala", "mysql" | "postgres" | "sqlite" | "oracle" | "hive" | "impala">;
|
|
113
|
+
host: z<string, string>;
|
|
114
|
+
port: z<number, number>;
|
|
115
|
+
user: z<string, string>;
|
|
116
|
+
database: z<string, string>;
|
|
117
|
+
readonly: z<boolean, boolean>;
|
|
118
|
+
passwordRef: z<string, string>;
|
|
119
|
+
password: z<never, never>;
|
|
101
120
|
}>, string>>;
|
|
102
121
|
}>, Schemastery.ObjectT<{
|
|
103
|
-
presetId:
|
|
104
|
-
installPreset:
|
|
105
|
-
connectTimeoutMs:
|
|
106
|
-
introspectMaxTables:
|
|
107
|
-
queryTimeoutMs:
|
|
108
|
-
maxResultChars:
|
|
109
|
-
|
|
110
|
-
|
|
122
|
+
presetId: z<string, string>;
|
|
123
|
+
installPreset: z<boolean, boolean>;
|
|
124
|
+
connectTimeoutMs: z<number, number>;
|
|
125
|
+
introspectMaxTables: z<number, number>;
|
|
126
|
+
queryTimeoutMs: z<number, number>;
|
|
127
|
+
maxResultChars: z<number, number>;
|
|
128
|
+
maxRows: z<number, number>;
|
|
129
|
+
maxQueryChars: z<number, number>;
|
|
130
|
+
readonly: z<boolean, boolean>;
|
|
131
|
+
persistConnections: z<boolean, boolean>;
|
|
132
|
+
clients: z<import("cosmokit").Dict<{
|
|
111
133
|
command?: string | null | undefined;
|
|
112
134
|
args?: string[] | null | undefined;
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
135
|
+
searchPaths?: string[] | null | undefined;
|
|
136
|
+
} & import("@deepseek-ai/cosmokit").Dict, string>, import("cosmokit").Dict<Schemastery.ObjectT<{
|
|
137
|
+
command: z<string, string>;
|
|
138
|
+
args: z<string[], string[]>;
|
|
139
|
+
searchPaths: z<string[], string[]>;
|
|
116
140
|
}>, string>>;
|
|
117
|
-
connections:
|
|
141
|
+
connections: z<import("cosmokit").Dict<{
|
|
118
142
|
type?: "mysql" | "postgres" | "sqlite" | "oracle" | "hive" | "impala" | null | undefined;
|
|
119
143
|
host?: string | null | undefined;
|
|
120
144
|
port?: number | null | undefined;
|
|
121
145
|
user?: string | null | undefined;
|
|
122
146
|
database?: string | null | undefined;
|
|
123
147
|
readonly?: boolean | null | undefined;
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
148
|
+
passwordRef?: string | null | undefined;
|
|
149
|
+
password?: null | undefined;
|
|
150
|
+
} & import("@deepseek-ai/cosmokit").Dict, string>, import("cosmokit").Dict<Schemastery.ObjectT<{
|
|
151
|
+
type: z<"mysql" | "postgres" | "sqlite" | "oracle" | "hive" | "impala", "mysql" | "postgres" | "sqlite" | "oracle" | "hive" | "impala">;
|
|
152
|
+
host: z<string, string>;
|
|
153
|
+
port: z<number, number>;
|
|
154
|
+
user: z<string, string>;
|
|
155
|
+
database: z<string, string>;
|
|
156
|
+
readonly: z<boolean, boolean>;
|
|
157
|
+
passwordRef: z<string, string>;
|
|
158
|
+
password: z<never, never>;
|
|
131
159
|
}>, string>>;
|
|
132
160
|
}>>;
|
|
133
161
|
/**
|
|
@@ -137,17 +165,35 @@ export declare const Config: import("@deepseek-ai/schemastery").default<Schemast
|
|
|
137
165
|
export declare function resolveDshHome(env?: Record<string, string | undefined>): string;
|
|
138
166
|
/**
|
|
139
167
|
* Install the packaged `preset/data-agent/` directory into
|
|
140
|
-
* `$DSH_HOME/.agent-presets/<presetId>/`. Idempotent: an existing target
|
|
141
|
-
*
|
|
142
|
-
*
|
|
143
|
-
*
|
|
168
|
+
* `$DSH_HOME/.agent-presets/<presetId>/`. Idempotent: an existing target is
|
|
169
|
+
* normally left untouched. The exact package-owned 0.0.9 composition is
|
|
170
|
+
* migrated once because its two dynamic package rows are incompatible with
|
|
171
|
+
* DSH Desktop's unpacked-ASAR loader; user-edited compositions are never
|
|
172
|
+
* overwritten. `installPreset: false` never calls this. Best-effort — a
|
|
173
|
+
* failure logs a warning with manual install instructions instead of failing
|
|
174
|
+
* the boot.
|
|
175
|
+
*/
|
|
176
|
+
export declare function installPreset(ctx: Context, presetId: string): Promise<boolean>;
|
|
177
|
+
/** Public for regression tests of the non-destructive preset migration gate. */
|
|
178
|
+
export declare function isLegacyManagedPreset(source: string): boolean;
|
|
179
|
+
/** Exact profile-local package installation command used by diagnostics/docs. */
|
|
180
|
+
export declare function profileInstallCommand(profile: string): string;
|
|
181
|
+
/** Actionable diagnostic for a roster-visible preset whose profile lacks this package. */
|
|
182
|
+
export declare function missingProfileDependencyMessage(profile: string): string;
|
|
183
|
+
/** Tool configuration inherited by the profile-preloaded preset capabilities. */
|
|
184
|
+
type PresetCapabilitiesConfig = Pick<ToolConfig, 'queryTimeoutMs' | 'maxResultChars' | 'maxRows' | 'maxQueryChars' | 'readonly' | 'clients'>;
|
|
185
|
+
/**
|
|
186
|
+
* Register the statically imported database tools and command under the exact
|
|
187
|
+
* standing key owned by the data-agent preset. Selecting the preset performs
|
|
188
|
+
* no package import and only links the agent scope to this key.
|
|
144
189
|
*/
|
|
145
|
-
export declare function
|
|
190
|
+
export declare function mountPresetCapabilities(ctx: Context, key: ScopeKey, scopeTag: symbol, config: PresetCapabilitiesConfig): Promise<void>;
|
|
146
191
|
/**
|
|
147
|
-
* Mount the data-agent
|
|
148
|
-
* connections,
|
|
149
|
-
* `data-agent-routes` row (`./routes`).
|
|
192
|
+
* Mount the data-agent profile row: connection store, config-seeded
|
|
193
|
+
* connections, preset installation, and profile-preloaded preset capabilities.
|
|
194
|
+
* HTTP routes are the sibling `data-agent-routes` row (`./routes`).
|
|
150
195
|
* @param ctx - host cordis context.
|
|
151
196
|
* @param config - validated loader configuration.
|
|
152
197
|
*/
|
|
153
|
-
export declare function apply(ctx: Context, config: Config): void
|
|
198
|
+
export declare function apply(ctx: Context, config: Config): Promise<void>;
|
|
199
|
+
export {};
|
package/lib/types/routes.d.ts
CHANGED
|
@@ -1,112 +1,46 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
* `/plugins/data-agent` HTTP surface. A separate row from the main `data-agent`
|
|
4
|
-
* row so the plugin keeps working in headless profiles (no webserver): the
|
|
5
|
-
* connection store, preset self-install, and config-seeded connections all
|
|
6
|
-
* live on the main row, and this row simply never activates where
|
|
7
|
-
* `webServer` is absent.
|
|
2
|
+
* Web adapter for the shared data-agent connection service.
|
|
8
3
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* return `{ ok, tables }` (or `{ ok: false, error }` without saving).
|
|
13
|
-
* - `POST /plugins/data-agent/disconnect` — drop one session's connection.
|
|
14
|
-
* - `GET /plugins/data-agent/status` — the current connection's
|
|
15
|
-
* password-stripped summary plus the table list.
|
|
16
|
-
* - `GET /plugins/data-agent/schemas` — schema/database list.
|
|
17
|
-
* - `GET /plugins/data-agent/tables` — table list of one schema.
|
|
18
|
-
* - `GET /plugins/data-agent/describe` — column structure of one table.
|
|
19
|
-
* - `POST /plugins/data-agent/query` — run one SQL text (the workbench
|
|
20
|
-
* command box; non-agent channel, same trust as sqlcmd).
|
|
4
|
+
* This entry owns only HTTP parsing/serialization. Connection validation,
|
|
5
|
+
* credentials, persistence, metadata, query safety, and error semantics live
|
|
6
|
+
* in `DataAgentConnections`, which is also consumed by TUI commands/tools.
|
|
21
7
|
* @module @yejiming/dsh-data-agent/routes
|
|
22
8
|
*/
|
|
23
|
-
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
24
9
|
import type { Context } from '@deepseek-ai/cordis';
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
* The service was renamed from `httpServer` to `webServer` in
|
|
28
|
-
* dsh 0.1.0-rc.6; the nested inject below waits on `webServer`.
|
|
29
|
-
*/
|
|
30
|
-
interface WebServerLike {
|
|
31
|
-
register(route: {
|
|
32
|
-
kind: 'exact' | 'prefix';
|
|
33
|
-
path: string;
|
|
34
|
-
handler: (req: IncomingMessage, res: ServerResponse) => void | Promise<void>;
|
|
35
|
-
}): () => void;
|
|
36
|
-
}
|
|
37
|
-
declare module '@deepseek-ai/cordis' {
|
|
38
|
-
interface Context {
|
|
39
|
-
webServer: WebServerLike;
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
import type { DatabaseType } from './connections.ts';
|
|
43
|
-
/** Cordis plugin name (diagnostics only). */
|
|
10
|
+
import z from 'schemastery';
|
|
11
|
+
import type { DatabaseConnectionInput } from './connections.ts';
|
|
44
12
|
export declare const name = "data-agent-routes";
|
|
45
|
-
/**
|
|
46
|
-
* No top-level `inject` export: the row must ACTIVATE even in headless
|
|
47
|
-
* profiles where `webServer` never exists (a permanently pending entry
|
|
48
|
-
* breaks one-shot runs). The routes register through a nested inject fiber
|
|
49
|
-
* the moment the webserver and the connection store are both available.
|
|
50
|
-
*/
|
|
13
|
+
/** Headless profiles activate this row without waiting forever for webServer. */
|
|
51
14
|
export declare const inject: string[];
|
|
52
|
-
/** Route prefix owned by this plugin (the browser half calls under it). */
|
|
53
15
|
export declare const DATA_AGENT_PATH = "/plugins/data-agent";
|
|
54
|
-
/**
|
|
16
|
+
/** Retained loader surface for backward compatibility; domain options live on the host row. */
|
|
55
17
|
export interface Config {
|
|
56
|
-
/** Deadline for one /connect connectivity check, milliseconds. */
|
|
57
18
|
connectTimeoutMs: number;
|
|
58
|
-
/** Cap on metadata lists returned by /connect /status /schemas /tables. */
|
|
59
19
|
introspectMaxTables: number;
|
|
60
|
-
/** In-memory cap on captured output. */
|
|
61
20
|
maxResultChars: number;
|
|
62
|
-
/** Deadline for one /query or metadata query, milliseconds. */
|
|
63
21
|
queryTimeoutMs: number;
|
|
64
|
-
/** Cap on one /query SQL text length. */
|
|
65
22
|
maxQueryChars: number;
|
|
66
|
-
/** Read-only guard: true rejects write statements in /query. */
|
|
67
23
|
readonly: boolean;
|
|
68
24
|
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
readonly: import("@deepseek-ai/schemastery").default<boolean, boolean>;
|
|
25
|
+
export declare const Config: z<Schemastery.ObjectS<{
|
|
26
|
+
connectTimeoutMs: z<number, number>;
|
|
27
|
+
introspectMaxTables: z<number, number>;
|
|
28
|
+
maxResultChars: z<number, number>;
|
|
29
|
+
queryTimeoutMs: z<number, number>;
|
|
30
|
+
maxQueryChars: z<number, number>;
|
|
31
|
+
readonly: z<boolean, boolean>;
|
|
77
32
|
}>, Schemastery.ObjectT<{
|
|
78
|
-
connectTimeoutMs:
|
|
79
|
-
introspectMaxTables:
|
|
80
|
-
maxResultChars:
|
|
81
|
-
queryTimeoutMs:
|
|
82
|
-
maxQueryChars:
|
|
83
|
-
readonly:
|
|
33
|
+
connectTimeoutMs: z<number, number>;
|
|
34
|
+
introspectMaxTables: z<number, number>;
|
|
35
|
+
maxResultChars: z<number, number>;
|
|
36
|
+
queryTimeoutMs: z<number, number>;
|
|
37
|
+
maxQueryChars: z<number, number>;
|
|
38
|
+
readonly: z<boolean, boolean>;
|
|
84
39
|
}>>;
|
|
85
|
-
|
|
86
|
-
export interface ConnectRequestBody {
|
|
40
|
+
export interface ConnectRequestBody extends DatabaseConnectionInput {
|
|
87
41
|
sessionId: string;
|
|
88
|
-
type: DatabaseType;
|
|
89
|
-
host?: string;
|
|
90
|
-
port?: number;
|
|
91
|
-
user?: string;
|
|
92
|
-
database: string;
|
|
93
|
-
password?: string;
|
|
94
|
-
readonly?: boolean;
|
|
95
42
|
}
|
|
96
|
-
/**
|
|
97
|
-
* Validate an untrusted /connect body; sqlite paths resolve to absolute
|
|
98
|
-
* (the client resolves the path relative to its own cwd, so the server pins
|
|
99
|
-
* it at connect time). Oracle/Hive/Impala follow the mysql/postgres shape:
|
|
100
|
-
* host/port/user/database (Oracle database = service name/SID, Hive/Impala
|
|
101
|
-
* database = default schema).
|
|
102
|
-
*/
|
|
43
|
+
/** Validate the Web wire shape while retaining temporary-password compatibility. */
|
|
103
44
|
export declare function validateConnectBody(value: unknown, cwd?: string): ConnectRequestBody;
|
|
104
|
-
/**
|
|
105
|
-
|
|
106
|
-
* The registration rides a nested inject fiber so this row activates in every
|
|
107
|
-
* profile; headless profiles simply never get routes.
|
|
108
|
-
* @param ctx - host cordis context.
|
|
109
|
-
* @param config - validated loader configuration.
|
|
110
|
-
*/
|
|
111
|
-
export declare function apply(ctx: Context, config: Config): void;
|
|
112
|
-
export {};
|
|
45
|
+
/** Register Web routes only when both the webserver and shared service exist. */
|
|
46
|
+
export declare function apply(ctx: Context, _config: Config): void;
|
package/lib/types/sql.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Lightweight SQL-text scanning helpers shared by the
|
|
2
|
+
* Lightweight SQL-text scanning helpers shared by the sql-cmd tool half and
|
|
3
3
|
* the /query route. This is intentionally NOT a SQL parser: the scanner only
|
|
4
4
|
* understands lexical boundaries (strings, quoted identifiers, comments and
|
|
5
5
|
* parenthesis depth) well enough to make the two agent-loop guarantees from
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Durable, non-secret connection profiles, session bindings, and form drafts.
|
|
3
|
+
*
|
|
4
|
+
* The domain intentionally excludes passwords, resolved credentials, SQL,
|
|
5
|
+
* table metadata, and client output. Form drafts likewise accept no secret
|
|
6
|
+
* fields. Runtime secrets stay in
|
|
7
|
+
* {@link DataAgentConnectionService}; durable records only retain enough
|
|
8
|
+
* information to rebuild a connection description in another DSH surface.
|
|
9
|
+
* @module @yejiming/dsh-data-agent/storage
|
|
10
|
+
*/
|
|
11
|
+
import { type Domain } from '@deepseek-ai/dsh-storage-domain';
|
|
12
|
+
import { z } from 'zod';
|
|
13
|
+
import type { ConnectionPersistence, PersistedConnectionFormDraft, PersistedConnectionProfile, SessionConnectionBinding } from './connections.ts';
|
|
14
|
+
/** Storage-domain identity. Bump the version only with an explicit migration. */
|
|
15
|
+
export declare const CONNECTION_STORAGE_DOMAIN = "data_agent_connections";
|
|
16
|
+
export declare const CONNECTION_STORAGE_VERSION = 1;
|
|
17
|
+
/** Durable profile schema. There is deliberately no `password` field. */
|
|
18
|
+
export declare const persistedConnectionProfileSchema: z.ZodObject<{
|
|
19
|
+
name: z.ZodOptional<z.ZodString>;
|
|
20
|
+
type: z.ZodEnum<{
|
|
21
|
+
mysql: "mysql";
|
|
22
|
+
postgres: "postgres";
|
|
23
|
+
sqlite: "sqlite";
|
|
24
|
+
oracle: "oracle";
|
|
25
|
+
hive: "hive";
|
|
26
|
+
impala: "impala";
|
|
27
|
+
}>;
|
|
28
|
+
host: z.ZodOptional<z.ZodString>;
|
|
29
|
+
port: z.ZodOptional<z.ZodNumber>;
|
|
30
|
+
user: z.ZodOptional<z.ZodString>;
|
|
31
|
+
database: z.ZodString;
|
|
32
|
+
readonly: z.ZodOptional<z.ZodBoolean>;
|
|
33
|
+
passwordRef: z.ZodOptional<z.ZodString>;
|
|
34
|
+
updatedAt: z.ZodString;
|
|
35
|
+
}, z.core.$strict>;
|
|
36
|
+
/** Durable session-to-profile binding schema. */
|
|
37
|
+
export declare const sessionConnectionBindingSchema: z.ZodObject<{
|
|
38
|
+
profileId: z.ZodString;
|
|
39
|
+
updatedAt: z.ZodString;
|
|
40
|
+
}, z.core.$strict>;
|
|
41
|
+
/** Session form draft schema. Secret-shaped fields are rejected by strict mode. */
|
|
42
|
+
export declare const persistedConnectionFormDraftSchema: z.ZodObject<{
|
|
43
|
+
type: z.ZodEnum<{
|
|
44
|
+
mysql: "mysql";
|
|
45
|
+
postgres: "postgres";
|
|
46
|
+
sqlite: "sqlite";
|
|
47
|
+
oracle: "oracle";
|
|
48
|
+
hive: "hive";
|
|
49
|
+
impala: "impala";
|
|
50
|
+
}>;
|
|
51
|
+
host: z.ZodString;
|
|
52
|
+
port: z.ZodString;
|
|
53
|
+
user: z.ZodString;
|
|
54
|
+
database: z.ZodString;
|
|
55
|
+
readonly: z.ZodBoolean;
|
|
56
|
+
updatedAt: z.ZodString;
|
|
57
|
+
}, z.core.$strict>;
|
|
58
|
+
/** Single source of truth for the storage layout and durable validation. */
|
|
59
|
+
export declare const connectionStorageSpec: {
|
|
60
|
+
name: string;
|
|
61
|
+
version: number;
|
|
62
|
+
tables: {
|
|
63
|
+
profiles: import("@deepseek-ai/dsh-storage-domain").DomainTableSpec<string, PersistedConnectionProfile>;
|
|
64
|
+
bindings: import("@deepseek-ai/dsh-storage-domain").DomainTableSpec<string, SessionConnectionBinding>;
|
|
65
|
+
drafts: import("@deepseek-ai/dsh-storage-domain").DomainTableSpec<string, PersistedConnectionFormDraft>;
|
|
66
|
+
};
|
|
67
|
+
};
|
|
68
|
+
export type ConnectionStorageDomain = Domain<typeof connectionStorageSpec>;
|
|
69
|
+
/** Project a typed DSH domain handle onto the service's persistence seam. */
|
|
70
|
+
export declare function createDomainConnectionPersistence(domain: ConnectionStorageDomain): ConnectionPersistence;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared structured read-query execution extracted from the sql-query tool
|
|
3
|
+
* (task 2.1). Both sql-query and render-analysis run every read dataset
|
|
4
|
+
* through this helper, so connection resolution, single-statement assertion,
|
|
5
|
+
* read classification, LIMIT/maxRows enforcement, client execution, secret
|
|
6
|
+
* redaction, timeout/cancellation, non-zero-exit surfacing and structured
|
|
7
|
+
* parsing share one code path. Existing sql-query behavior and messages stay
|
|
8
|
+
* unchanged.
|
|
9
|
+
* @module @yejiming/dsh-data-agent/structured-read
|
|
10
|
+
*/
|
|
11
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
12
|
+
import { type ClientConfig } from './clients.ts';
|
|
13
|
+
import { type DatabaseConnection } from './connections.ts';
|
|
14
|
+
import { type QueryOptions, type QueryResult } from './query.ts';
|
|
15
|
+
/** Tool-run context face used by the helpers. */
|
|
16
|
+
export interface ToolExecLike {
|
|
17
|
+
agent?: {
|
|
18
|
+
id: string;
|
|
19
|
+
};
|
|
20
|
+
signal: AbortSignal;
|
|
21
|
+
}
|
|
22
|
+
/** Resolved runner options shared by the database tools. */
|
|
23
|
+
export interface ResolvedRunnerConfig {
|
|
24
|
+
queryTimeoutMs: number;
|
|
25
|
+
maxResultChars: number;
|
|
26
|
+
maxRows: number;
|
|
27
|
+
maxQueryChars: number;
|
|
28
|
+
/** Read-only guard: true rejects write statements. */
|
|
29
|
+
readonly: boolean;
|
|
30
|
+
clients: Readonly<Partial<Record<string, ClientConfig>>>;
|
|
31
|
+
}
|
|
32
|
+
/** Canonical structured read result (elapsed/truncation metadata included). */
|
|
33
|
+
export interface StructuredReadResult {
|
|
34
|
+
columns: string[];
|
|
35
|
+
rows: Record<string, string | null>[];
|
|
36
|
+
elapsedMs: number;
|
|
37
|
+
truncated: boolean;
|
|
38
|
+
}
|
|
39
|
+
/** Look up the session connection, failing with the same message for every tool. */
|
|
40
|
+
export declare function requireToolConnection(ctx: Context, exec: ToolExecLike, toolName: string): Promise<DatabaseConnection>;
|
|
41
|
+
/** Run and redact a client result/error before it reaches tool/session output. */
|
|
42
|
+
export declare function runRedactedClientQuery(ctx: Context, connection: DatabaseConnection, sql: string, options: QueryOptions, signal: AbortSignal): Promise<QueryResult>;
|
|
43
|
+
/** Query runner options with the deployment overrides applied. */
|
|
44
|
+
export declare function runnerOptions(resolved: Pick<ResolvedRunnerConfig, 'queryTimeoutMs' | 'maxResultChars' | 'clients'>, mode?: QueryOptions['mode']): QueryOptions;
|
|
45
|
+
/**
|
|
46
|
+
* Execute one read-only SQL through the structured client template and parse
|
|
47
|
+
* it into the canonical { columns, rows } shape, with maxRows enforced at both
|
|
48
|
+
* the SQL level (LIMIT injection) and the parse level.
|
|
49
|
+
*/
|
|
50
|
+
export declare function runStructuredReadQuery(ctx: Context, connection: DatabaseConnection, sql: string, resolved: ResolvedRunnerConfig, toolName: string, signal: AbortSignal): Promise<StructuredReadResult>;
|
package/lib/types/tool.d.ts
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* Tool surface:
|
|
9
9
|
* - `sql-query`: read-only statements, structured `{ columns, rows, ... }`;
|
|
10
10
|
* - `sql-write`: one write/management statement per call, explicit autocommit;
|
|
11
|
-
* - `
|
|
11
|
+
* - `sql-cmd`: the raw-terminal compatibility tool.
|
|
12
12
|
*
|
|
13
13
|
* Execution model (see `src/query.ts`): the SQL text travels on the client's
|
|
14
14
|
* stdin, argv carries flags only, credentials go through environment entries
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
* @module @yejiming/dsh-data-agent/tool
|
|
19
19
|
*/
|
|
20
20
|
import type { Context } from '@deepseek-ai/cordis';
|
|
21
|
+
import z from 'schemastery';
|
|
21
22
|
import { type ClientConfig } from './clients.ts';
|
|
22
23
|
/** Cordis plugin name (diagnostics only). */
|
|
23
24
|
export declare const name = "data-agent-tool";
|
|
@@ -25,46 +26,54 @@ export declare const name = "data-agent-tool";
|
|
|
25
26
|
export declare const inject: string[];
|
|
26
27
|
/** Tool-half configuration (loader schema with the same defaults as the host). */
|
|
27
28
|
export interface Config {
|
|
28
|
-
/** Deadline for one
|
|
29
|
+
/** Deadline for one sql-cmd / sql-query / sql-write query, milliseconds. */
|
|
29
30
|
queryTimeoutMs: number;
|
|
30
31
|
/** In-memory cap on captured output. */
|
|
31
32
|
maxResultChars: number;
|
|
32
33
|
/** Enforced read-query row cap (LIMIT injection + structured truncation). */
|
|
33
34
|
maxRows: number;
|
|
35
|
+
/** Maximum SQL text length accepted per dataset statement. */
|
|
36
|
+
maxQueryChars: number;
|
|
34
37
|
/** Read-only guard: true rejects write statements. */
|
|
35
38
|
readonly: boolean;
|
|
36
39
|
/** CLI client overrides keyed by database type. */
|
|
37
40
|
clients: Partial<Record<string, ClientConfig>>;
|
|
38
41
|
}
|
|
39
42
|
/** Loader schema with deployment defaults (no library defaults). */
|
|
40
|
-
export declare const Config:
|
|
41
|
-
queryTimeoutMs:
|
|
42
|
-
maxResultChars:
|
|
43
|
-
maxRows:
|
|
44
|
-
|
|
45
|
-
|
|
43
|
+
export declare const Config: z<Schemastery.ObjectS<{
|
|
44
|
+
queryTimeoutMs: z<number, number>;
|
|
45
|
+
maxResultChars: z<number, number>;
|
|
46
|
+
maxRows: z<number, number>;
|
|
47
|
+
maxQueryChars: z<number, number>;
|
|
48
|
+
readonly: z<boolean, boolean>;
|
|
49
|
+
clients: z<import("cosmokit").Dict<{
|
|
46
50
|
command?: string | null | undefined;
|
|
47
51
|
args?: string[] | null | undefined;
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
52
|
+
searchPaths?: string[] | null | undefined;
|
|
53
|
+
} & import("@deepseek-ai/cosmokit").Dict, string>, import("cosmokit").Dict<Schemastery.ObjectT<{
|
|
54
|
+
command: z<string, string>;
|
|
55
|
+
args: z<string[], string[]>;
|
|
56
|
+
searchPaths: z<string[], string[]>;
|
|
51
57
|
}>, string>>;
|
|
52
58
|
}>, Schemastery.ObjectT<{
|
|
53
|
-
queryTimeoutMs:
|
|
54
|
-
maxResultChars:
|
|
55
|
-
maxRows:
|
|
56
|
-
|
|
57
|
-
|
|
59
|
+
queryTimeoutMs: z<number, number>;
|
|
60
|
+
maxResultChars: z<number, number>;
|
|
61
|
+
maxRows: z<number, number>;
|
|
62
|
+
maxQueryChars: z<number, number>;
|
|
63
|
+
readonly: z<boolean, boolean>;
|
|
64
|
+
clients: z<import("cosmokit").Dict<{
|
|
58
65
|
command?: string | null | undefined;
|
|
59
66
|
args?: string[] | null | undefined;
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
67
|
+
searchPaths?: string[] | null | undefined;
|
|
68
|
+
} & import("@deepseek-ai/cosmokit").Dict, string>, import("cosmokit").Dict<Schemastery.ObjectT<{
|
|
69
|
+
command: z<string, string>;
|
|
70
|
+
args: z<string[], string[]>;
|
|
71
|
+
searchPaths: z<string[], string[]>;
|
|
63
72
|
}>, string>>;
|
|
64
73
|
}>>;
|
|
65
74
|
/**
|
|
66
75
|
* Mount the data-agent database tools: `sql-query` (structured read-only),
|
|
67
|
-
* `sql-write` (explicit write semantics), and `
|
|
76
|
+
* `sql-write` (explicit write semantics), and `sql-cmd` (raw compatibility).
|
|
68
77
|
* @param ctx - the preset-scoped agent context.
|
|
69
78
|
* @param config - validated loader configuration.
|
|
70
79
|
*/
|