@linxin666/dsh-ssh 0.4.4 → 0.4.6
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.i18n.yaml +2 -2
- package/README.md +16 -2
- package/README.zh.md +16 -2
- package/lib/client.js +62 -14
- package/lib/client.js.map +1 -1
- package/lib/index.js +193 -41
- package/lib/types/client/api.d.ts +21 -10
- package/lib/types/client/locales.d.ts +1 -1
- package/lib/types/engine/cluster.d.ts +2 -0
- package/lib/types/engine/connection-pool.d.ts +2 -2
- package/lib/types/engine/tunnel.d.ts +2 -0
- package/lib/types/engine.d.ts +2 -1
- package/lib/types/tool-surface.d.ts +71 -0
- package/package.json +18 -22
- package/src/client/api.ts +72 -15
- package/src/client/locales.ts +2 -2
- package/src/engine/cluster.ts +3 -1
- package/src/engine/connection-pool.ts +47 -2
- package/src/engine/tunnel.ts +74 -19
- package/src/engine.ts +3 -2
- package/src/index.ts +11 -3
- package/src/tool-surface.ts +95 -0
- package/src/tools.ts +15 -16
- package/lib/invariant.js +0 -6
- package/lib/types/invariant.d.ts +0 -3
- package/src/invariant.ts +0 -4
package/src/tools.ts
CHANGED
|
@@ -91,8 +91,7 @@ function renderTunnel(tunnel: TunnelInfo): string {
|
|
|
91
91
|
export function sshListTool(engine: SshEngine) {
|
|
92
92
|
return defineTool({
|
|
93
93
|
name: 'ssh_list',
|
|
94
|
-
description: 'List configured SSH hosts (alias, host, user, auth, environment, tags, description). Use ssh_exec etc. with the alias.
|
|
95
|
-
'Triggers: SSH, remote server, server IP/hostname, connect/login, check server/status, deploy, upload/download, jump host, tunnel, port forward.',
|
|
94
|
+
description: 'List configured SSH hosts (alias, host, user, auth, environment, tags, description). Use ssh_exec etc. with the alias.',
|
|
96
95
|
parameters: {
|
|
97
96
|
query: { type: 'string', description: 'Optional fuzzy match against alias, description, host, and tags.' },
|
|
98
97
|
},
|
|
@@ -129,6 +128,8 @@ export function sshListTool(engine: SshEngine) {
|
|
|
129
128
|
},
|
|
130
129
|
render: (_args, value: { hosts?: AgentHostRow[] }) => text(renderHosts(value.hosts ?? [])),
|
|
131
130
|
},
|
|
131
|
+
// Reads the local host registry only: safe to overlap with sibling calls.
|
|
132
|
+
isConcurrencySafe: () => true,
|
|
132
133
|
async execute(args) {
|
|
133
134
|
return { hosts: engine.list(args.query).map(toAgentHostRow) }
|
|
134
135
|
},
|
|
@@ -139,8 +140,7 @@ export function sshListTool(engine: SshEngine) {
|
|
|
139
140
|
export function sshExecTool(engine: SshEngine) {
|
|
140
141
|
return defineTool({
|
|
141
142
|
name: 'ssh_exec',
|
|
142
|
-
description: 'Execute a shell command on a REMOTE SSH host by alias; the command runs on the remote host, never on this machine. For commands on this machine, use the local bash tool. Prefer combining independent read-only queries into one command.
|
|
143
|
-
'Triggers: run command on server, deploy, check server/status, service control, view logs, any remote operation.',
|
|
143
|
+
description: 'Execute a shell command on a REMOTE SSH host by alias; the command runs on the remote host, never on this machine. For commands on this machine, use the local bash tool. Prefer combining independent read-only queries into one command.',
|
|
144
144
|
parameters: {
|
|
145
145
|
alias: { type: 'string', required: true, description: 'Host alias from ssh_list.' },
|
|
146
146
|
command: { type: 'string', required: true, description: 'The shell command to run remotely.' },
|
|
@@ -162,9 +162,11 @@ export function sshExecTool(engine: SshEngine) {
|
|
|
162
162
|
},
|
|
163
163
|
render: (_args, value: ExecResult) => text(renderExec(value)),
|
|
164
164
|
},
|
|
165
|
-
async execute(args) {
|
|
165
|
+
async execute(args, exec) {
|
|
166
166
|
try {
|
|
167
|
-
|
|
167
|
+
// Forward the caller's cancellation: aborting closes the remote channel
|
|
168
|
+
// instead of leaving the command running on the host.
|
|
169
|
+
return await engine.exec(args.alias, args.command, args.timeoutMs, exec.signal)
|
|
168
170
|
} catch (error) {
|
|
169
171
|
return {
|
|
170
172
|
success: false,
|
|
@@ -184,8 +186,7 @@ export function sshExecTool(engine: SshEngine) {
|
|
|
184
186
|
export function sshUploadTool(engine: SshEngine) {
|
|
185
187
|
return defineTool({
|
|
186
188
|
name: 'ssh_upload',
|
|
187
|
-
description: 'Transfer a file FROM this machine (the dsh host) TO a remote SSH host. Use this only when the file must be copied to the remote host. Files that stay on this machine are handled with the local file tools (read / write / edit), not ssh_upload.
|
|
188
|
-
'Triggers: upload file to server, deploy artifact, copy config to server.',
|
|
189
|
+
description: 'Transfer a file FROM this machine (the dsh host) TO a remote SSH host. Use this only when the file must be copied to the remote host. Files that stay on this machine are handled with the local file tools (read / write / edit), not ssh_upload.',
|
|
189
190
|
parameters: {
|
|
190
191
|
alias: { type: 'string', required: true, description: 'Host alias from ssh_list.' },
|
|
191
192
|
localPath: { type: 'string', required: true, description: 'Absolute path of the source file on THIS machine (the dsh host) — not a path on the remote host.' },
|
|
@@ -221,8 +222,7 @@ export function sshUploadTool(engine: SshEngine) {
|
|
|
221
222
|
export function sshDownloadTool(engine: SshEngine) {
|
|
222
223
|
return defineTool({
|
|
223
224
|
name: 'ssh_download',
|
|
224
|
-
description: 'Copy a remote FILE from a configured SSH host to this machine (the dsh host). Use this only when the source is on the remote host; files already on this machine are read with the local file tools (read / write / edit), not ssh_download. Directory download is not supported — download files individually.
|
|
225
|
-
'Triggers: download file from server, fetch remote log/artifact.',
|
|
225
|
+
description: 'Copy a remote FILE from a configured SSH host to this machine (the dsh host). Use this only when the source is on the remote host; files already on this machine are read with the local file tools (read / write / edit), not ssh_download. Directory download is not supported — download files individually.',
|
|
226
226
|
parameters: {
|
|
227
227
|
alias: { type: 'string', required: true, description: 'Host alias from ssh_list.' },
|
|
228
228
|
remotePath: { type: 'string', required: true, description: 'Absolute path of the source file on the remote SSH host.' },
|
|
@@ -257,8 +257,7 @@ export function sshDownloadTool(engine: SshEngine) {
|
|
|
257
257
|
export function sshTunnelTool(engine: SshEngine) {
|
|
258
258
|
return defineTool({
|
|
259
259
|
name: 'ssh_tunnel',
|
|
260
|
-
description: 'Manage local port-forward tunnels to a configured SSH host. Start a tunnel to reach a remote internal service (database, web UI, API) through 127.0.0.1 on this machine.
|
|
261
|
-
'Triggers: tunnel, port forward, connect database, access internal service.',
|
|
260
|
+
description: 'Manage local port-forward tunnels to a configured SSH host. Start a tunnel to reach a remote internal service (database, web UI, API) through 127.0.0.1 on this machine.',
|
|
262
261
|
parameters: {
|
|
263
262
|
action: { type: 'string', required: true, enum: ['start', 'list', 'stop', 'stop-all'], description: 'start / list / stop / stop-all.' },
|
|
264
263
|
alias: { type: 'string', description: 'Host alias (required for start, optional for stop-all).' },
|
|
@@ -357,8 +356,7 @@ export function sshTunnelTool(engine: SshEngine) {
|
|
|
357
356
|
export function sshClusterTool(engine: SshEngine) {
|
|
358
357
|
return defineTool({
|
|
359
358
|
name: 'ssh_cluster',
|
|
360
|
-
description: 'Run one command concurrently across selected SSH hosts; at least one aliases, environment, or tags filter is required.
|
|
361
|
-
'Triggers: run on selected servers, batch operation, production servers, cluster command.',
|
|
359
|
+
description: 'Run one command concurrently across selected SSH hosts; at least one aliases, environment, or tags filter is required.',
|
|
362
360
|
parameters: {
|
|
363
361
|
command: { type: 'string', required: true, description: 'The shell command to run on every matched host.' },
|
|
364
362
|
aliases: { type: 'array', items: { type: 'string' }, description: 'Optional alias filter; at least one of aliases, environment, or tags is required.' },
|
|
@@ -394,12 +392,13 @@ export function sshClusterTool(engine: SshEngine) {
|
|
|
394
392
|
},
|
|
395
393
|
render: (_args, value: { results?: ClusterResult[] }) => text(renderCluster(value.results ?? [])),
|
|
396
394
|
},
|
|
397
|
-
async execute(args) {
|
|
395
|
+
async execute(args, exec) {
|
|
398
396
|
const hasSelector = (Array.isArray(args.aliases) && args.aliases.some((alias) => typeof alias === 'string' && alias.trim() !== '')) ||
|
|
399
397
|
(typeof args.environment === 'string' && args.environment.trim() !== '') ||
|
|
400
398
|
(Array.isArray(args.tags) && args.tags.some((tag) => typeof tag === 'string' && tag.trim() !== ''))
|
|
401
399
|
if (!hasSelector) throw new Error('ssh_cluster requires aliases, environment, or tags to limit the target set')
|
|
402
|
-
|
|
400
|
+
// Cancellation reaches every host's in-flight command.
|
|
401
|
+
return { results: await engine.cluster({ ...args, signal: exec.signal }) }
|
|
403
402
|
},
|
|
404
403
|
})
|
|
405
404
|
}
|
package/lib/invariant.js
DELETED
package/lib/types/invariant.d.ts
DELETED
package/src/invariant.ts
DELETED