dsh-ssh-manage 0.3.6 → 0.3.7

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 CHANGED
@@ -22,7 +22,7 @@
22
22
 
23
23
  `dsh-ssh-manage` is a Web plugin for [DeepSeek Harness (DSH)](https://github.com/deepseek-ai/deepseek-harness). It turns the hosts in `~/.ssh/config` into manageable objects in the DSH sidebar:
24
24
 
25
- - **Host management** — scan the config, groups, tags, favorites, notes, latency and host inspection;
25
+ - **Host management** — scan the config, groups, tags, favorites, notes, latency and host inspection; SSH aliases are globally unique, so use the repeatable Display name for same names across groups;
26
26
  - **Interactive terminal** — ssh2 allocates a PTY, xterm.js renders it, with colors, arrow keys, full-screen programs such as `vim`/`top`, and window resizing;
27
27
  - **Backup and migration** — export/import hosts, groups, tags, notes, favorites and passwords from Settings; exports are re-encrypted with a passphrase (scrypt + AES-256-GCM) and imports merge by alias;
28
28
  - **Day-to-day operations** — batch commands, SFTP browse/mkdir/rename/delete/upload/download, connection tests;
@@ -97,16 +97,16 @@ Creating a host requires alias, hostname and password. The password is not writt
97
97
 
98
98
  ### From npm (recommended)
99
99
 
100
- npm package: [`dsh-ssh-manage`](https://www.npmjs.com/package/dsh-ssh-manage) (current version `0.3.6`).
100
+ npm package: [`dsh-ssh-manage`](https://www.npmjs.com/package/dsh-ssh-manage) (current version `0.3.7`).
101
101
 
102
102
  ```text
103
- plugin_manager action=install_bundle target=dsh-ssh-manage@0.3.6
103
+ plugin_manager action=install_bundle target=dsh-ssh-manage@0.3.7
104
104
  ```
105
105
 
106
106
  Or with the DSH CLI:
107
107
 
108
108
  ```bash
109
- dsh plugin add dsh-ssh-manage@0.3.6
109
+ dsh plugin add dsh-ssh-manage@0.3.7
110
110
  ```
111
111
 
112
112
  After installation, refresh the Web page; the sidebar shows an "SSH Hosts" entry with id `dsh-ssh-manage`.
package/README.md CHANGED
@@ -22,7 +22,7 @@
22
22
 
23
23
  `dsh-ssh-manage` 是 [DeepSeek Harness (DSH)](https://github.com/deepseek-ai/deepseek-harness) 的 Web 插件。它把 `~/.ssh/config` 里的主机变成 DSH 侧边栏里可管理、可连接、可运维的对象:
24
24
 
25
- - **主机管理**:扫描配置、分组、标签、收藏、备注、连接延迟、主机巡检;
25
+ - **主机管理**:扫描配置、分组、标签、收藏、备注、连接延迟、主机巡检;SSH 别名全局唯一,不同分组如需同名请使用可重复的“显示名称”;
26
26
  - **交互式终端**:ssh2 分配 PTY,xterm.js 渲染,支持彩色输出、方向键、`vim`/`top` 等全屏程序和窗口自适应;
27
27
  - **备份迁移**:设置页可导出/导入主机、分组、标签、备注、收藏和密码;导出文件用自定义口令二次加密(scrypt + AES-256-GCM),导入按别名合并;
28
28
  - **日常运维**:批量命令、SFTP 目录浏览 / 新建 / 重命名 / 删除 / 上传 / 下载、测试连接;
@@ -99,16 +99,16 @@
99
99
 
100
100
  ### 从 npm 安装(推荐)
101
101
 
102
- npm 包:[`dsh-ssh-manage`](https://www.npmjs.com/package/dsh-ssh-manage)(当前版本 `0.3.6`)。
102
+ npm 包:[`dsh-ssh-manage`](https://www.npmjs.com/package/dsh-ssh-manage)(当前版本 `0.3.7`)。
103
103
 
104
104
  ```text
105
- plugin_manager action=install_bundle target=dsh-ssh-manage@0.3.6
105
+ plugin_manager action=install_bundle target=dsh-ssh-manage@0.3.7
106
106
  ```
107
107
 
108
108
  或使用 DSH CLI:
109
109
 
110
110
  ```bash
111
- dsh plugin add dsh-ssh-manage@0.3.6
111
+ dsh plugin add dsh-ssh-manage@0.3.7
112
112
  ```
113
113
 
114
114
  安装后刷新 Web 页面,左侧栏会出现「SSH 主机」入口,入口 id 为 `dsh-ssh-manage`。
package/client.js CHANGED
@@ -126,7 +126,7 @@ window.__ModuleLoader__.load({
126
126
  'editor.editTitle': ['编辑 SSH 主机', 'Edit SSH host'],
127
127
  'editor.alias': ['别名', 'Alias'],
128
128
  'editor.aliasPlaceholder': ['prod', 'prod'],
129
- 'editor.aliasHint': ['~/.ssh/config 中的 Host 名称,作为主机的唯一标识。', 'Host name in ~/.ssh/config; the unique identifier.'],
129
+ 'editor.aliasHint': ['~/.ssh/config 中的 Host 别名,必须全局唯一;不同分组要显示同名,请使用“显示名称”。', 'The Host alias in ~/.ssh/config must be globally unique. To show the same name in different groups, use Display name.'],
130
130
  'editor.hostname': ['服务器地址', 'Hostname'],
131
131
  'editor.hostnamePlaceholder': ['203.0.113.10 或 example.com', '203.0.113.10 or example.com'],
132
132
  'editor.user': ['用户', 'User'],
@@ -141,6 +141,9 @@ window.__ModuleLoader__.load({
141
141
  'editor.tagsPlaceholder': ['web, critical(逗号分隔)', 'web, critical (comma separated)'],
142
142
  'editor.label': ['显示名称', 'Display name'],
143
143
  'editor.labelPlaceholder': ['例如 生产 API', 'e.g. Production API'],
144
+ 'editor.labelHint': ['显示名称可以重复,列表和终端标签优先显示它;SSH 别名仍需唯一。', 'Display names may repeat; lists and terminal tabs prefer it. The SSH alias must still be unique.'],
145
+ 'editor.aliasExists': ['SSH 别名“{alias}”已被主机“{host}”使用(分组:{group})。SSH 要求别名全局唯一;如果只是想在另一个分组显示同名,请改用建议别名,并把“显示名称”设为 {alias}。', 'SSH alias "{alias}" is already used by "{host}" (group: {group}). SSH aliases must be globally unique. To show the same name in another group, use the suggested alias and set Display name to {alias}.'],
146
+ 'editor.useSuggestedAlias': ['使用建议别名 {alias}', 'Use suggested alias {alias}'],
144
147
  'editor.note': ['备注', 'Notes'],
145
148
  'editor.notePlaceholder': ['给这台主机的说明,会显示在列表里', 'A short note shown in the list'],
146
149
  'editor.passwordSection': ['服务器密码', 'Server password'],
@@ -4729,6 +4732,7 @@ window.__ModuleLoader__.load({
4729
4732
  const [password, setPassword] = React.useState('')
4730
4733
  const [passwordError, setPasswordError] = React.useState('')
4731
4734
  const [formError, setFormError] = React.useState('')
4735
+ const [aliasSuggestion, setAliasSuggestion] = React.useState('')
4732
4736
  const [groupMenuOpen, setGroupMenuOpen] = React.useState(false)
4733
4737
  const groupMenuRef = React.useRef(null)
4734
4738
  const groupOptions = (model.allGroups ?? []).filter((group) => group.key !== '').map((group) => group.key)
@@ -4798,6 +4802,28 @@ window.__ModuleLoader__.load({
4798
4802
  setFormError('')
4799
4803
  return
4800
4804
  }
4805
+ const collision = hosts.find((host) =>
4806
+ host.host !== state.original
4807
+ && (host.host === alias || (Array.isArray(host.aliases) && host.aliases.includes(alias))),
4808
+ )
4809
+ if (collision) {
4810
+ const groupPart = draft.group.trim().replace(/[^A-Za-z0-9_.@-]+/g, '-').replace(/^-+|-+$/g, '').slice(0, 20)
4811
+ let suggested = groupPart ? `${alias}-${groupPart}` : `${alias}-2`
4812
+ let counter = 2
4813
+ while (hosts.some((host) => host.host === suggested || (Array.isArray(host.aliases) && host.aliases.includes(suggested)))) {
4814
+ suggested = `${alias}-${counter}`
4815
+ counter += 1
4816
+ }
4817
+ suggested = suggested.slice(0, 64)
4818
+ setAliasSuggestion(suggested)
4819
+ setFormError(t('editor.aliasExists', {
4820
+ alias,
4821
+ host: hostName(collision),
4822
+ group: collision.group || t('tree.ungrouped'),
4823
+ }))
4824
+ return
4825
+ }
4826
+ setAliasSuggestion('')
4801
4827
  setPasswordError('')
4802
4828
  setFormError('')
4803
4829
  const saved = await saveEditor({
@@ -4860,13 +4886,36 @@ window.__ModuleLoader__.load({
4860
4886
  h(
4861
4887
  'div',
4862
4888
  { className: 'ssh-formSection' },
4863
- formError ? h('div', { className: 'ssh-formError' }, h(IconAlert, { size: 13 }), h('span', null, formError)) : null,
4889
+ formError
4890
+ ? h(
4891
+ 'div',
4892
+ { className: 'ssh-formError' },
4893
+ h(IconAlert, { size: 13 }),
4894
+ h('span', null, formError),
4895
+ aliasSuggestion
4896
+ ? h(
4897
+ Button,
4898
+ {
4899
+ size: 'sm',
4900
+ variant: 'ghost',
4901
+ onClick: () => {
4902
+ if (!draft.label.trim()) update('label', alias)
4903
+ update('host', aliasSuggestion)
4904
+ setAliasSuggestion('')
4905
+ setFormError('')
4906
+ },
4907
+ },
4908
+ t('editor.useSuggestedAlias', { alias: aliasSuggestion }),
4909
+ )
4910
+ : null,
4911
+ )
4912
+ : null,
4864
4913
  h(
4865
4914
  'div',
4866
4915
  { className: 'ssh-formGrid' },
4867
4916
  h(
4868
4917
  Field,
4869
- { label: t('editor.alias') },
4918
+ { label: t('editor.alias'), hint: t('editor.aliasHint') },
4870
4919
  h(TextInput, {
4871
4920
  value: draft.host,
4872
4921
  onChange: (value) => update('host', value),
@@ -4964,7 +5013,7 @@ window.__ModuleLoader__.load({
4964
5013
  ),
4965
5014
  h(
4966
5015
  Field,
4967
- { label: t('editor.label') },
5016
+ { label: t('editor.label'), hint: t('editor.labelHint') },
4968
5017
  h(TextInput, {
4969
5018
  value: draft.label,
4970
5019
  onChange: (value) => update('label', value),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-ssh-manage",
3
- "version": "0.3.6",
3
+ "version": "0.3.7",
4
4
  "description": "A DSH sidebar plugin for managing SSH host profiles with a real interactive PTY terminal.",
5
5
  "license": "MIT",
6
6
  "private": false,