@wszhoho/dsh-file-attachment 0.5.7 → 0.5.9

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/lib/client.js CHANGED
@@ -118,6 +118,38 @@ window.__ModuleLoader__.load({
118
118
  hijackedInputs.add(el)
119
119
  el.addEventListener('change', onNativeFileChange)
120
120
  }
121
+ // ---- 移动端双📎兼容:dsh-web-mobile 向 conversation.input.left 注入 file-upload 回形针,
122
+ // 其设计前提是 host(0.1.6-alpha.2+)已删除 composer 原生📎;在 0.1.5-rc.x 上该前提不成立——
123
+ // 该代 host 仍渲染原生📎(即 hidden fileInput 的前邻 button),移动端窄屏下两枚并排出现
124
+ //(PC 宽屏被 dsh-web-mobile 的 pointer:fine 隐藏规则覆盖,故仅移动端可见)。
125
+ // 此处按 host 原生📎是否存在对调:原生📎在 → 内联 display:none!important 隐藏 mobile 注入的
126
+ //(压过其 display:grid!important);原生📎不在(0.1.6+)→ 移除内联声明交还 CSS,保留为唯一入口。
127
+ // 两枚按钮点击后都触发 host 的 hidden fileInput,change 已被本插件劫持走 runBatch,功能不受影响。
128
+ function cardHasNativeClip(card) {
129
+ let inputs
130
+ try { inputs = card.querySelectorAll('input[type="file"], input[type=file]') } catch (err) { return false }
131
+ for (let i = 0; i < inputs.length; i++) {
132
+ const inp = inputs[i]
133
+ if (typeof inp.hidden !== 'undefined' && !inp.hidden) continue // 只认 host 的 hidden fileInput
134
+ let prev = inp.previousElementSibling
135
+ while (prev !== null && prev.tagName !== 'BUTTON') prev = prev.previousElementSibling
136
+ if (prev !== null) return true
137
+ }
138
+ return false
139
+ }
140
+ function reconcileMobileFileUpload() {
141
+ let cards
142
+ try { cards = Array.from(document.querySelectorAll('[data-composer-card]')) } catch (err) { cards = [] }
143
+ for (let i = 0; i < cards.length; i++) {
144
+ const hideMobile = cardHasNativeClip(cards[i])
145
+ let btns
146
+ try { btns = cards[i].querySelectorAll('[data-mobile-nav="file-upload"]') } catch (err) { btns = [] }
147
+ for (let j = 0; j < btns.length; j++) {
148
+ const curHidden = btns[j].style.display === 'none'
149
+ if (hideMobile !== curHidden) btns[j].style.setProperty('display', hideMobile ? 'none' : '', 'important')
150
+ }
151
+ }
152
+ }
121
153
  function installNativeAttachHijack() {
122
154
  if (typeof document === 'undefined' || document.body === null || document.body === undefined) return
123
155
  let body
@@ -127,6 +159,7 @@ window.__ModuleLoader__.load({
127
159
  let all = []
128
160
  try { all = Array.from(body.querySelectorAll(nativeFileInputSelector)) } catch (err) { all = [] }
129
161
  for (let i = 0; i < all.length; i++) hijackFileInput(all[i])
162
+ reconcileMobileFileUpload() // 双📎对调:host 原生📎在则隐藏 dsh-web-mobile 注入的
130
163
  }
131
164
  scan()
132
165
  const mo = new MutationObserver(() => scan())
@@ -772,7 +805,6 @@ window.__ModuleLoader__.load({
772
805
  bridge.input = input
773
806
  bridge.sessionId = sessionId
774
807
  bridge.mounted = true
775
- if (typeof console !== 'undefined' && console.log) console.log('[dsh-file-attachment] FaBridge mounted', { sessionId, shell: shell === null ? 'null' : 'ok', addImages: typeof addImages })
776
808
  return () => {
777
809
  bridge.shell = null
778
810
  bridge.addImages = null
@@ -1091,6 +1123,7 @@ window.__ModuleLoader__.load({
1091
1123
 
1092
1124
  // 设置页扩展名分组:标题 + 可删 tag + 输入框 + 添加按钮
1093
1125
  function FaExtGroup(props) {
1126
+ const [hover, setHover] = react.useState(false)
1094
1127
  const list = props.list
1095
1128
  const setList = props.setList
1096
1129
  const input = props.input
@@ -1110,7 +1143,7 @@ window.__ModuleLoader__.load({
1110
1143
  style: { cursor: 'pointer', marginLeft: '4px', opacity: 0.55 },
1111
1144
  }, '×')
1112
1145
  ))
1113
- return react.createElement('div', { style: { marginBottom: '18px' } },
1146
+ 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
1147
  react.createElement('div', { style: { fontWeight: 600, marginBottom: '8px', fontSize: '13px' } }, props.title),
1115
1148
  react.createElement('div', { style: { marginBottom: '8px', minHeight: '22px' } }, tags),
1116
1149
  react.createElement('div', { style: { display: 'flex', gap: '8px' } },
@@ -1149,6 +1182,7 @@ window.__ModuleLoader__.load({
1149
1182
  const [cfgIn, setCfgIn] = react.useState('')
1150
1183
  const [saved, setSaved] = react.useState(false)
1151
1184
  const [saving, setSaving] = react.useState(false)
1185
+ const [vlmHover, setVlmHover] = react.useState(false)
1152
1186
  react.useEffect(() => {
1153
1187
  // 挂载时载入持久化配置到编辑副本(幂等,复用 loadConfig Promise)
1154
1188
  let live = true
@@ -1193,11 +1227,11 @@ window.__ModuleLoader__.load({
1193
1227
  } finally { setSaving(false) }
1194
1228
  }
1195
1229
  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')),
1230
+ 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
1231
  react.createElement(FaExtGroup, { title: t('doc.title'), list: doc, setList: setDoc, input: docIn, setInput: setDocIn }),
1198
1232
  react.createElement(FaExtGroup, { title: t('code.title'), list: code, setList: setCode, input: codeIn, setInput: setCodeIn }),
1199
1233
  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))' } },
1234
+ 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
1235
  react.createElement('div', { style: { marginBottom: '8px', fontSize: '13px', fontWeight: '600', color: 'var(--dsw-alias-label-primary, inherit)' } }, t('vlm.title')),
1202
1236
  react.createElement('div', { style: { marginBottom: '10px', fontSize: '12px', color: 'var(--dsw-alias-label-tertiary, rgba(128,128,128,0.9))' } }, t('vlm.hint')),
1203
1237
  react.createElement('div', { style: { display: 'grid', gridTemplateColumns: '110px 1fr', gap: '8px 10px', alignItems: 'center' } },
@@ -1237,11 +1271,12 @@ window.__ModuleLoader__.load({
1237
1271
  const [open, setOpen] = react.useState(false)
1238
1272
  const [hover, setHover] = react.useState(false)
1239
1273
  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
- }, [])
1274
+ // 【已屏蔽 /version 拉取,保留代码以备后用】
1275
+ // react.useEffect(() => {
1276
+ // fetch('/dsh-file-attachment/version').then(r => r.json()).then(d => {
1277
+ // if (d.ok && d.version) setVersion(d.version)
1278
+ // }).catch(() => { /* ignore */ })
1279
+ // }, [])
1245
1280
  function t(key) {
1246
1281
  if (ctxRef !== null && ctxRef.locale !== void 0 && typeof ctxRef.locale.bind === 'function') {
1247
1282
  try { return ctxRef.locale.bind('dsh-file-attachment')(key) } catch (err) { /* 回退 key */ }
package/lib/index.js CHANGED
@@ -370,18 +370,19 @@ function registerRoutes(ctx) {
370
370
  return
371
371
  }
372
372
  }
373
- if (req.method === 'GET' && pathname === '/dsh-file-attachment/version') {
374
- try {
375
- const pkgPath = fileURLToPath(new URL('../package.json', import.meta.url))
376
- const raw = await readFile(pkgPath, 'utf8')
377
- const pkg = JSON.parse(raw)
378
- json(res, { ok: true, version: pkg.version || '0.0.0' })
379
- return
380
- } catch {
381
- json(res, { ok: false, version: 'unknown' }, 500)
382
- return
383
- }
384
- }
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
+ // }
385
386
  if (req.method === 'GET' && pathname === '/dsh-file-attachment/config') {
386
387
  json(res, { ok: true, value: await readConfig() })
387
388
  return
@@ -488,9 +489,8 @@ function registerTools(ctx) {
488
489
  },
489
490
  },
490
491
  render: (_args, value) => {
491
- const thinkingText = (value && value.thinkingType === 'enabled') ? '开启' : '关闭'
492
492
  if (value && value.ok === true && typeof value.description === 'string' && value.description !== '') {
493
- return [{ type: 'text', text: '图片识别结果:' + value.description + '(思考模式:' + thinkingText + ')' }]
493
+ return [{ type: 'text', text: '图片识别结果:' + value.description }]
494
494
  }
495
495
  return [{ type: 'text', text: (value && value.ok === true) ? '(图片已识别)' : '(图片识别失败)' }]
496
496
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wszhoho/dsh-file-attachment",
3
- "version": "0.5.7",
3
+ "version": "0.5.9",
4
4
  "description": "文件附件:拖拽/粘贴/上传文件(支持多文件);图片与文档统一落盘到 .dsh-file-attachment 并以 @绝对路径 引用发送(文本模型可正常使用);输入框内联显示图片缩略图预览与文件条目,聊天区图片同样渲染为可点击放大的缩略图、文件保持芯片样式;非多模态模型下图片自动调用可配置 VLM 识别生成中文描述回填草稿;文档/代码/配置文件可上传类型可在设置页配置;支持 PC 与移动端浏览器",
5
5
  "keywords": [
6
6
  "dsh",