@wszhoho/dsh-file-attachment 0.5.6 → 0.5.8

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.md CHANGED
@@ -23,7 +23,7 @@ DeepSeek Harness (dsh) web GUI 插件:在会话输入框中拖入或 Ctrl+V
23
23
  - **可上传类型**:按 文档 / 代码 / 配置文件 三类增删扩展名(小写、不带点),图片恒可发送;
24
24
  - **多模态识别参数(VLM)**:Base URL / API Key / 模型 / 思考模式开关(默认禁用)/ 超时时间(默认 60 秒),仅当前会话模型不支持多模态时调用,未填 API Key 时静默跳过。
25
25
 
26
- ![可上传类型设置](docs/settings-file-types.png)
26
+ ![可上传类型设置、多模态API设置](docs/settings-file-types.jpg)
27
27
 
28
28
  ## 行为一览
29
29
 
@@ -123,4 +123,4 @@ packages/dsh-file-attachment/
123
123
 
124
124
  ## License
125
125
 
126
- MIT
126
+ MIT
package/lib/client.js CHANGED
@@ -1091,6 +1091,7 @@ window.__ModuleLoader__.load({
1091
1091
 
1092
1092
  // 设置页扩展名分组:标题 + 可删 tag + 输入框 + 添加按钮
1093
1093
  function FaExtGroup(props) {
1094
+ const [hover, setHover] = react.useState(false)
1094
1095
  const list = props.list
1095
1096
  const setList = props.setList
1096
1097
  const input = props.input
@@ -1110,7 +1111,7 @@ window.__ModuleLoader__.load({
1110
1111
  style: { cursor: 'pointer', marginLeft: '4px', opacity: 0.55 },
1111
1112
  }, '×')
1112
1113
  ))
1113
- return react.createElement('div', { style: { marginBottom: '18px' } },
1114
+ return react.createElement('div', { onMouseEnter: () => setHover(true), onMouseLeave: () => setHover(false), style: { marginBottom: '18px', padding: '14px 16px', borderRadius: '12px', background: hover ? 'var(--dsw-alias-bg-layer-2, rgba(128,128,128,0.06))' : 'var(--dsw-alias-bg-layer-1, rgba(128,128,128,0.04))', border: `1px solid ${hover ? 'var(--dsw-alias-label-dimmed, var(--dsw-alias-border-l2, rgba(128,128,128,0.3)))' : 'var(--dsw-alias-border-l1, rgba(128,128,128,0.14))'}`, boxShadow: hover ? '0 2px 8px rgba(0,0,0,0.05)' : 'none', transition: 'border-color 0.16s, background 0.16s, box-shadow 0.16s' } },
1114
1115
  react.createElement('div', { style: { fontWeight: 600, marginBottom: '8px', fontSize: '13px' } }, props.title),
1115
1116
  react.createElement('div', { style: { marginBottom: '8px', minHeight: '22px' } }, tags),
1116
1117
  react.createElement('div', { style: { display: 'flex', gap: '8px' } },
@@ -1149,6 +1150,7 @@ window.__ModuleLoader__.load({
1149
1150
  const [cfgIn, setCfgIn] = react.useState('')
1150
1151
  const [saved, setSaved] = react.useState(false)
1151
1152
  const [saving, setSaving] = react.useState(false)
1153
+ const [vlmHover, setVlmHover] = react.useState(false)
1152
1154
  react.useEffect(() => {
1153
1155
  // 挂载时载入持久化配置到编辑副本(幂等,复用 loadConfig Promise)
1154
1156
  let live = true
@@ -1193,11 +1195,11 @@ window.__ModuleLoader__.load({
1193
1195
  } finally { setSaving(false) }
1194
1196
  }
1195
1197
  return react.createElement('div', { style: { padding: '16px', maxWidth: '680px' } },
1196
- react.createElement('div', { style: { marginBottom: '16px', fontSize: '13px', color: 'rgba(128,128,128,0.9)' } }, t('settings.hint')),
1198
+ react.createElement('div', { style: { marginBottom: '16px', fontSize: '13px', lineHeight: '1.5', color: 'var(--dsw-alias-label-secondary, rgba(128,128,128,0.95))' } }, t('settings.hint')),
1197
1199
  react.createElement(FaExtGroup, { title: t('doc.title'), list: doc, setList: setDoc, input: docIn, setInput: setDocIn }),
1198
1200
  react.createElement(FaExtGroup, { title: t('code.title'), list: code, setList: setCode, input: codeIn, setInput: setCodeIn }),
1199
1201
  react.createElement(FaExtGroup, { title: t('config.title'), list: config, setList: setConfig, input: cfgIn, setInput: setCfgIn }),
1200
- react.createElement('div', { style: { margin: '16px 0', padding: '12px', borderRadius: '8px', background: 'var(--dsw-alias-bg-layer-2, rgba(128,128,128,0.08))', border: '1px solid var(--dsw-alias-border-l2, rgba(128,128,128,0.15))' } },
1202
+ react.createElement('div', { onMouseEnter: () => setVlmHover(true), onMouseLeave: () => setVlmHover(false), style: { margin: '16px 0', padding: '14px 16px', borderRadius: '12px', background: vlmHover ? 'var(--dsw-alias-bg-layer-2, rgba(128,128,128,0.06))' : 'var(--dsw-alias-bg-layer-1, rgba(128,128,128,0.04))', border: `1px solid ${vlmHover ? 'var(--dsw-alias-label-dimmed, var(--dsw-alias-border-l2, rgba(128,128,128,0.3)))' : 'var(--dsw-alias-border-l1, rgba(128,128,128,0.14))'}`, boxShadow: vlmHover ? '0 2px 8px rgba(0,0,0,0.05)' : 'none', transition: 'border-color 0.16s, background 0.16s, box-shadow 0.16s' } },
1201
1203
  react.createElement('div', { style: { marginBottom: '8px', fontSize: '13px', fontWeight: '600', color: 'var(--dsw-alias-label-primary, inherit)' } }, t('vlm.title')),
1202
1204
  react.createElement('div', { style: { marginBottom: '10px', fontSize: '12px', color: 'var(--dsw-alias-label-tertiary, rgba(128,128,128,0.9))' } }, t('vlm.hint')),
1203
1205
  react.createElement('div', { style: { display: 'grid', gridTemplateColumns: '110px 1fr', gap: '8px 10px', alignItems: 'center' } },
@@ -1237,11 +1239,12 @@ window.__ModuleLoader__.load({
1237
1239
  const [open, setOpen] = react.useState(false)
1238
1240
  const [hover, setHover] = react.useState(false)
1239
1241
  const [version, setVersion] = react.useState(null)
1240
- react.useEffect(() => {
1241
- fetch('/dsh-file-attachment/version').then(r => r.json()).then(d => {
1242
- if (d.ok && d.version) setVersion(d.version)
1243
- }).catch(() => { /* ignore */ })
1244
- }, [])
1242
+ // 【已屏蔽 /version 拉取,保留代码以备后用】
1243
+ // react.useEffect(() => {
1244
+ // fetch('/dsh-file-attachment/version').then(r => r.json()).then(d => {
1245
+ // if (d.ok && d.version) setVersion(d.version)
1246
+ // }).catch(() => { /* ignore */ })
1247
+ // }, [])
1245
1248
  function t(key) {
1246
1249
  if (ctxRef !== null && ctxRef.locale !== void 0 && typeof ctxRef.locale.bind === 'function') {
1247
1250
  try { return ctxRef.locale.bind('dsh-file-attachment')(key) } catch (err) { /* 回退 key */ }
@@ -1383,17 +1386,15 @@ window.__ModuleLoader__.load({
1383
1386
  { name: 'shell.overlay', id: 'dsh-file-attachment-lightbox', order: 200 },
1384
1387
  FaLightbox
1385
1388
  ))
1386
- // 插件配置 tab 卡片:settings.plugin.itemkey = settings 命名空间 'dsh-file-attachment')。
1387
- // 卡片自渲染标题+描述+展开(见 FaSettingsCard),展开后承载原有设置表单。
1388
- // 嵌套 inject settingsScope:老版本 host(< 0.1.0-rc.7)无该服务时卡片不出现,
1389
- // 但不卸载整个插件(graceful degradation,与插件市场同形)。
1390
- ctx.inject(['settingsScope'], (scoped) => {
1391
- scoped.slots.inject('settings.plugin.item', () => scoped.slots.register({
1392
- name: 'settings.plugin.item',
1393
- key: 'dsh-file-attachment',
1394
- locale: 'dsh-file-attachment',
1395
- }, FaSettingsCard))
1396
- })
1389
+ // 设置左侧独立菜单:settings.sectionlabel 显示在左侧菜单,内容区渲染表单)
1390
+ slots.inject('settings.section', () => [
1391
+ slots.register({
1392
+ name: 'settings.section',
1393
+ id: 'dsh-file-attachment-settings',
1394
+ order: 120,
1395
+ label: () => ctx.locale.bind('dsh-file-attachment')('settings.title'),
1396
+ }, () => react.createElement(FaSettingsPage, {})),
1397
+ ])
1397
1398
  }
1398
1399
  bridge.conversation = ctx.get('conversation')
1399
1400
  // 劫持 dsh 原生📎:让上传入口位于与 dsh 本体一致的位置(hero/composer 两模式同一按钮),
package/lib/index.js CHANGED
@@ -9,7 +9,9 @@ import { homedir } from 'node:os'
9
9
  import { join, resolve } from 'node:path'
10
10
  import { fileURLToPath } from 'node:url'
11
11
  import { defineTool } from '@deepseek-ai/dsh-tools'
12
- import z from '@deepseek-ai/schemastery'
12
+ // schemastery peerDependency:link 插件目录内可能未安装,用顶层 await 安全加载
13
+ let z = null
14
+ try { z = (await import('@deepseek-ai/schemastery')).default } catch { /* 降级:跳过 settings 注册 */ }
13
15
 
14
16
  /** 本包声明依赖的 Host 服务。 */
15
17
  export const name = 'dsh-file-attachment'
@@ -161,7 +163,7 @@ const SETTINGS_NS = 'dsh-file-attachment'
161
163
  * 仅用于登记命名空间结构(与自动继续插件的 settings.register 同形);卡片内部表单
162
164
  * 继续走 /config 接口读写真实配置。
163
165
  */
164
- const FaAttachmentSchema = z.object({
166
+ const FaAttachmentSchema = z ? z.object({
165
167
  doc: z.array(z.string()).default(DEFAULT_TYPES.doc),
166
168
  code: z.array(z.string()).default(DEFAULT_TYPES.code),
167
169
  config: z.array(z.string()).default(DEFAULT_TYPES.config),
@@ -172,7 +174,7 @@ const FaAttachmentSchema = z.object({
172
174
  thinkingType: z.string().default(VLM_DEFAULTS.thinkingType),
173
175
  timeout: z.natural().default(VLM_DEFAULTS.timeout),
174
176
  }),
175
- })
177
+ }) : null
176
178
 
177
179
  /** 规范化多模态参数(缺省/空值回退默认,trim 去空白)。 */
178
180
  function normalizeVlm(raw) {
@@ -368,18 +370,19 @@ function registerRoutes(ctx) {
368
370
  return
369
371
  }
370
372
  }
371
- if (req.method === 'GET' && pathname === '/dsh-file-attachment/version') {
372
- try {
373
- const pkgPath = fileURLToPath(new URL('../package.json', import.meta.url))
374
- const raw = await readFile(pkgPath, 'utf8')
375
- const pkg = JSON.parse(raw)
376
- json(res, { ok: true, version: pkg.version || '0.0.0' })
377
- return
378
- } catch {
379
- json(res, { ok: false, version: 'unknown' }, 500)
380
- return
381
- }
382
- }
373
+ // 【已屏蔽 /version 路由,保留代码以备后用】
374
+ // if (req.method === 'GET' && pathname === '/dsh-file-attachment/version') {
375
+ // try {
376
+ // const pkgPath = fileURLToPath(new URL('../package.json', import.meta.url))
377
+ // const raw = await readFile(pkgPath, 'utf8')
378
+ // const pkg = JSON.parse(raw)
379
+ // json(res, { ok: true, version: pkg.version || '0.0.0' })
380
+ // return
381
+ // } catch {
382
+ // json(res, { ok: false, version: 'unknown' }, 500)
383
+ // return
384
+ // }
385
+ // }
383
386
  if (req.method === 'GET' && pathname === '/dsh-file-attachment/config') {
384
387
  json(res, { ok: true, value: await readConfig() })
385
388
  return
@@ -527,7 +530,9 @@ export function apply(ctx, config = {}) {
527
530
  // 老版本 host(无 settings 服务,< 0.1.0-rc.7)此回调不运行,命名空间不登记,
528
531
  // 卡片不出现但不卸载整个插件(graceful degradation,与自动继续/插件市场同形)。
529
532
  ctx.inject(['settings'], (scopedCtx) => {
530
- scopedCtx.settings.register(SETTINGS_NS, FaAttachmentSchema, {})
533
+ if (FaAttachmentSchema) {
534
+ scopedCtx.settings.register(SETTINGS_NS, FaAttachmentSchema, {})
535
+ }
531
536
  })
532
537
  console.log('[dsh-file-attachment] host loaded (webServer routes + describe_image tool)')
533
538
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wszhoho/dsh-file-attachment",
3
- "version": "0.5.6",
3
+ "version": "0.5.8",
4
4
  "description": "文件附件:拖拽/粘贴/上传文件(支持多文件);图片与文档统一落盘到 .dsh-file-attachment 并以 @绝对路径 引用发送(文本模型可正常使用);输入框内联显示图片缩略图预览与文件条目,聊天区图片同样渲染为可点击放大的缩略图、文件保持芯片样式;非多模态模型下图片自动调用可配置 VLM 识别生成中文描述回填草稿;文档/代码/配置文件可上传类型可在设置页配置;支持 PC 与移动端浏览器",
5
5
  "keywords": [
6
6
  "dsh",