@jidekaixin2dian/dsh-file-actions 0.1.12 → 0.1.14
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/CHANGELOG.md +5 -0
- package/README.en.md +4 -0
- package/README.md +6 -2
- package/assets/preview-link.png +0 -0
- package/lib/client.js +69 -41
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.1.13 — 2026-10-24
|
|
4
|
+
|
|
5
|
+
- 渠道对齐:0.1.12 的 GitHub Release 资产早于安全修复(tag 停在 `6aa0b38`),而 npm 0.1.12 已包含修复;自 0.1.13 起两个渠道从同一提交构建。代码与 0.1.12(npm)一致,仅升版本号。
|
|
6
|
+
- 发布链:npm 改用 Trusted Publishing(OIDC,无 token、无 OTP),`npm publish --provenance` 附带 SLSA 来源证明。
|
|
7
|
+
|
|
3
8
|
## 0.1.12 — 2026-10-24
|
|
4
9
|
|
|
5
10
|
- 「复制文件内容」作用于会话工作区之外的文件时先弹确认框,说明该文件不属于本对话;拒绝则不读取任何字节。工作区内的复制行为不变。缓解聊天文本被注入绝对路径后的诱导复制。
|
package/README.en.md
CHANGED
|
@@ -58,6 +58,10 @@ The rows follow the file type:
|
|
|
58
58
|
| Folders | open folder, reveal, copy path, copy relative path |
|
|
59
59
|
| Web links | open link, copy link, copy link text, copy as Markdown |
|
|
60
60
|
|
|
61
|
+
The link menu:
|
|
62
|
+
|
|
63
|
+

|
|
64
|
+
|
|
61
65
|
*Open with* keeps every registered application, ordered by preferred application, system default, editors, then other applications. A search box appears above seven entries.
|
|
62
66
|
|
|
63
67
|
Click ☆ beside an application to prefer it for that file type; click ★ to clear it. Keyboard users can select an application and press `Shift+Enter`. Preferences stay in this browser and do not change OS associations. An unavailable preferred application falls back to an available editor.
|
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
[English](README.en.md)
|
|
4
4
|
|
|
5
|
-
**0.1.
|
|
5
|
+
**0.1.13** 对齐 npm 与 GitHub Release 两个安装渠道(同源构建),npm 发布附带 provenance 来源证明;延续 0.1.12 的引用行号、复制动作与工作区外复制确认。安装包见 [npm](https://www.npmjs.com/package/@jidekaixin2dian/dsh-file-actions) 和 [Release](https://github.com/jidekaixin2dian/dsh-file-actions/releases/latest),修复记录见[变更记录](CHANGELOG.md)。
|
|
6
6
|
|
|
7
7
|
右键文件和链接,直接打开、定位、复制或另存。
|
|
8
8
|
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
dsh plugin --profile desktop add @jidekaixin2dian/dsh-file-actions --registry=https://registry.npmjs.org
|
|
17
17
|
```
|
|
18
18
|
|
|
19
|
-
装完重开 DSH 生效。指定官方 npm 源可以避开镜像同步延迟;安装固定版本时,在包名后加 `@0.1.
|
|
19
|
+
装完重开 DSH 生效。指定官方 npm 源可以避开镜像同步延迟;安装固定版本时,在包名后加 `@0.1.13`。
|
|
20
20
|
|
|
21
21
|
也可继续通过 GitHub Release 安装:
|
|
22
22
|
|
|
@@ -58,6 +58,10 @@ npm pack @jidekaixin2dian/dsh-file-actions --registry=https://registry.npmjs.org
|
|
|
58
58
|
| 文件夹 | 打开文件夹、在资源管理器中打开、复制路径、复制相对路径 |
|
|
59
59
|
| 网页链接 | 打开链接、复制链接、复制链接文字、复制为 Markdown |
|
|
60
60
|
|
|
61
|
+
网页链接的菜单:
|
|
62
|
+
|
|
63
|
+

|
|
64
|
+
|
|
61
65
|
「打开方式」完整保留系统关联应用,按首选、系统默认、编辑器、其他应用排序;超过 7 个会出现搜索框。
|
|
62
66
|
|
|
63
67
|
点击应用旁的 ☆,将它设为该文件类型的首选;再次点击 ★ 取消。键盘选中应用后也可用 `Shift+Enter` 设置或取消。首选仅保存在当前浏览器中,不修改系统文件关联;若应用不再可用,自动回落到可用编辑器。
|
|
Binary file
|
package/lib/client.js
CHANGED
|
@@ -94,7 +94,7 @@ const factory = () => {
|
|
|
94
94
|
denied: '没有权限访问该文件',
|
|
95
95
|
probeFailed: '无法确认文件,请检查连接或权限',
|
|
96
96
|
retry: '重试',
|
|
97
|
-
nativeHint: 'Shift+右键
|
|
97
|
+
nativeHint: 'Shift+右键 先交给页面处理',
|
|
98
98
|
kinds: {
|
|
99
99
|
text: '文本',
|
|
100
100
|
markdown: 'Markdown',
|
|
@@ -177,7 +177,7 @@ const factory = () => {
|
|
|
177
177
|
denied: 'Permission to access this file was denied',
|
|
178
178
|
probeFailed: 'Could not verify file; check connection or permissions',
|
|
179
179
|
retry: 'Retry',
|
|
180
|
-
nativeHint: 'Shift+right-click
|
|
180
|
+
nativeHint: 'Shift+right-click lets the page handle it first',
|
|
181
181
|
kinds: {
|
|
182
182
|
text: 'Text',
|
|
183
183
|
markdown: 'Markdown',
|
|
@@ -534,7 +534,7 @@ const factory = () => {
|
|
|
534
534
|
primary.push({
|
|
535
535
|
id: 'open',
|
|
536
536
|
label: isDir ? t.openFolder : t.open,
|
|
537
|
-
icon: isDir ? 'folder' : '
|
|
537
|
+
icon: isDir ? 'folder' : 'file',
|
|
538
538
|
action: 'open',
|
|
539
539
|
})
|
|
540
540
|
|
|
@@ -543,7 +543,7 @@ const factory = () => {
|
|
|
543
543
|
primary.push({
|
|
544
544
|
id: 'editor',
|
|
545
545
|
label: editor ? t.openIn(editor.name) : input.appsState === 'loading' ? t.appsLoading : t.noPreferred,
|
|
546
|
-
icon: '
|
|
546
|
+
icon: 'code',
|
|
547
547
|
action: 'open',
|
|
548
548
|
appId: editor?.id,
|
|
549
549
|
disabled: !editor,
|
|
@@ -584,7 +584,7 @@ const factory = () => {
|
|
|
584
584
|
navigate.push({
|
|
585
585
|
id: 'reveal',
|
|
586
586
|
label: isDir ? t.revealFolder : t.reveal,
|
|
587
|
-
icon: '
|
|
587
|
+
icon: 'folderOpen',
|
|
588
588
|
action: 'reveal',
|
|
589
589
|
})
|
|
590
590
|
sections.push(navigate)
|
|
@@ -596,11 +596,11 @@ const factory = () => {
|
|
|
596
596
|
transfer.push({ id: 'copyRelPath', label: t.copyRelPath, icon: 'copy', action: 'copyRelPath' })
|
|
597
597
|
}
|
|
598
598
|
if (!isDir) {
|
|
599
|
-
transfer.push({ id: 'copyFileName', label: t.copyFileName, icon: '
|
|
599
|
+
transfer.push({ id: 'copyFileName', label: t.copyFileName, icon: 'tag', action: 'copyFileName' })
|
|
600
600
|
}
|
|
601
601
|
// Copying the reference verbatim is only useful when it carries a location.
|
|
602
602
|
if (!isDir && input.location && Number(input.location.line) && input.reference) {
|
|
603
|
-
transfer.push({ id: 'copyReference', label: t.copyReference, icon: '
|
|
603
|
+
transfer.push({ id: 'copyReference', label: t.copyReference, icon: 'bookmark', action: 'copyReference' })
|
|
604
604
|
}
|
|
605
605
|
if (!isDir && file.canCopyText) {
|
|
606
606
|
transfer.push({ id: 'copyContents', label: t.copyContents, icon: 'clipboard', action: 'copyContents' })
|
|
@@ -654,8 +654,8 @@ const factory = () => {
|
|
|
654
654
|
pathLine = path === '' ? '/' : path
|
|
655
655
|
} catch { /* keep the raw URL */ }
|
|
656
656
|
const copy = [
|
|
657
|
-
{ id: 'copyLink', label: t.copyLink, icon: '
|
|
658
|
-
{ id: 'copyLinkText', label: t.copyLinkText, icon: '
|
|
657
|
+
{ id: 'copyLink', label: t.copyLink, icon: 'link', action: 'copyLink' },
|
|
658
|
+
{ id: 'copyLinkText', label: t.copyLinkText, icon: 'text', action: 'copyLinkText' },
|
|
659
659
|
]
|
|
660
660
|
// `[text](url)` only exists when the link has visible text to label it.
|
|
661
661
|
if (String(input.text || '').trim() !== '') {
|
|
@@ -671,7 +671,7 @@ const factory = () => {
|
|
|
671
671
|
kind: 'link',
|
|
672
672
|
outsideWorkspace: false,
|
|
673
673
|
sections: [
|
|
674
|
-
[{ id: 'openLink', label: t.openLink, icon: '
|
|
674
|
+
[{ id: 'openLink', label: t.openLink, icon: 'external', action: 'openLink' }],
|
|
675
675
|
copy,
|
|
676
676
|
],
|
|
677
677
|
}
|
|
@@ -680,27 +680,29 @@ const factory = () => {
|
|
|
680
680
|
/* ─────────────────────────────── icons ─────────────────────────────── */
|
|
681
681
|
|
|
682
682
|
const ICON_PATHS = {
|
|
683
|
-
|
|
684
|
-
folder: '<path d="
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
link: '<path d="
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
683
|
+
file: '<path d="M14 3H7a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V8z"/><path d="M14 3v5h5"/>',
|
|
684
|
+
folder: '<path d="M3 7a2 2 0 0 1 2-2h4l2 2.6h8a2 2 0 0 1 2 2V18a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/>',
|
|
685
|
+
folderOpen: '<path d="M3 18V7a2 2 0 0 1 2-2h4l2 2.6h8a2 2 0 0 1 2 2V11"/><path d="M3 18.5 5.7 12a2 2 0 0 1 1.9-1.3H22l-2.7 7.6a2 2 0 0 1-1.9 1.3H4.8a1.8 1.8 0 0 1-1.8-1.1z"/>',
|
|
686
|
+
code: '<path d="m9 8-4 4 4 4"/><path d="m15 8 4 4-4 4"/>',
|
|
687
|
+
chevron: '<path d="m10 7 5 5-5 5"/>',
|
|
688
|
+
globe: '<circle cx="12" cy="12" r="9"/><path d="M3 12h18"/><path d="M12 3a14 14 0 0 1 0 18a14 14 0 0 1 0-18"/>',
|
|
689
|
+
external: '<path d="M14 4h6v6"/><path d="M20 4l-9 9"/><path d="M18 14v4a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h4"/>',
|
|
690
|
+
copy: '<rect x="9" y="9" width="11" height="11" rx="2.4"/><path d="M6 15H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v1"/>',
|
|
691
|
+
clipboard: '<rect x="7" y="4.5" width="10" height="16" rx="2.2"/><path d="M10 4.5v-.7a.8.8 0 0 1 .8-.8h2.4a.8.8 0 0 1 .8.8v.7"/>',
|
|
692
|
+
download: '<path d="M12 4v10.5"/><path d="m7.6 11 4.4 4.4L16.4 11"/><path d="M4.8 19.4h14.4"/>',
|
|
693
|
+
link: '<path d="M10.4 13.6a4.3 4.3 0 0 0 6.1 0l2.3-2.3a4.3 4.3 0 0 0-6.1-6.1l-1.2 1.2"/><path d="M13.6 10.4a4.3 4.3 0 0 0-6.1 0l-2.3 2.3a4.3 4.3 0 0 0 6.1 6.1l1.2-1.2"/>',
|
|
694
|
+
text: '<path d="M4 6.5h16"/><path d="M4 12h10.5"/><path d="M4 17.5h13"/>',
|
|
695
|
+
markdown: '<path d="M3.5 17V7l4 5 4-5v10"/><path d="M16.5 7v10"/><path d="m13.8 14.2 2.7 2.8 2.7-2.8"/>',
|
|
696
|
+
image: '<rect x="3" y="4.5" width="18" height="15" rx="2.6"/><circle cx="8.6" cy="9.8" r="1.5"/><path d="m20.5 16-4.2-4.2a2 2 0 0 0-2.8 0L4.5 20"/>',
|
|
697
|
+
web: '<rect x="3" y="4.5" width="18" height="15" rx="2.6"/><path d="M3 9.4h18"/><circle cx="6.6" cy="6.9" r=".75" fill="currentColor" stroke="none"/><circle cx="9.3" cy="6.9" r=".75" fill="currentColor" stroke="none"/>',
|
|
698
|
+
doc: '<path d="M14 3H7a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V8z"/><path d="M14 3v5h5"/><path d="M8.5 13h7"/><path d="M8.5 17h4.5"/>',
|
|
699
|
+
office: '<path d="M14 3H7a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V8z"/><path d="M14 3v5h5"/><path d="M8.6 12.4h6.8"/><path d="M8.6 16.4h6.8"/><path d="M12 12.4v4"/>',
|
|
700
|
+
archive: '<rect x="3" y="4" width="18" height="4.6" rx="1.6"/><path d="M5 8.6V18a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V8.6"/><path d="M10 12.6h4"/>',
|
|
701
|
+
binary: '<rect x="4" y="4" width="6.2" height="7" rx="2"/><rect x="13.8" y="13" width="6.2" height="7" rx="2"/><path d="M5.4 20.2h3.4"/><path d="M15.2 10.8h3.4"/><path d="M6.8 7.6h1.1v3"/><path d="M16.6 16.6h1.1v3"/>',
|
|
702
|
+
bookmark: '<path d="M7 4.6h10a1.6 1.6 0 0 1 1.6 1.6V21L12 16.8 5.4 21V6.2A1.6 1.6 0 0 1 7 4.6z"/>',
|
|
703
|
+
tag: '<path d="M11.6 3.6H5.4A1.8 1.8 0 0 0 3.6 5.4v6.2a2 2 0 0 0 .6 1.4l7.4 7.4a2 2 0 0 0 2.8 0l5.6-5.6a2 2 0 0 0 0-2.8L12.9 4.2a2 2 0 0 0-1.3-.6z"/><circle cx="8.2" cy="8.2" r="1.2"/>',
|
|
704
|
+
refresh: '<path d="M20 11.5a8 8 0 1 0-2.4 6.4"/><path d="M20 5.5v6h-6"/>',
|
|
705
|
+
check: '<path d="m5 12.6 4.6 4.6L19 7"/>',
|
|
704
706
|
}
|
|
705
707
|
|
|
706
708
|
/** The header tile glyph for one file kind. */
|
|
@@ -718,8 +720,8 @@ const factory = () => {
|
|
|
718
720
|
}
|
|
719
721
|
|
|
720
722
|
function iconSvg(name) {
|
|
721
|
-
const body = ICON_PATHS[name] || ICON_PATHS.
|
|
722
|
-
return `<svg viewBox="0 0
|
|
723
|
+
const body = ICON_PATHS[name] || ICON_PATHS.file
|
|
724
|
+
return `<svg viewBox="0 0 24 24" width="16" height="16" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round">${body}</svg>`
|
|
723
725
|
}
|
|
724
726
|
|
|
725
727
|
/* ─────────────────────────────── styles ─────────────────────────────── */
|
|
@@ -762,11 +764,11 @@ const factory = () => {
|
|
|
762
764
|
.dfa-thumb img{max-width:100%;max-height:118px;display:block;object-fit:contain;border-radius:6px}
|
|
763
765
|
.dfa-head{display:flex;align-items:center;gap:9px;padding:6px 7px 8px;min-width:0;
|
|
764
766
|
border-bottom:1px solid var(--dsw-alias-border-l2,rgba(127,127,127,.28));margin-bottom:3px}
|
|
765
|
-
.dfa-tile{flex:none;width:
|
|
767
|
+
.dfa-tile{flex:none;width:30px;height:30px;border-radius:9px;display:grid;place-items:center;
|
|
766
768
|
color:var(--dfa-hue,#5b8cff);
|
|
767
|
-
background:color-mix(in srgb,var(--dfa-hue,#5b8cff)
|
|
768
|
-
box-shadow:inset 0 0 0
|
|
769
|
-
.dfa-tile svg{width:
|
|
769
|
+
background:linear-gradient(150deg,color-mix(in srgb,var(--dfa-hue,#5b8cff) 24%,transparent),color-mix(in srgb,var(--dfa-hue,#5b8cff) 9%,transparent));
|
|
770
|
+
box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--dfa-hue,#5b8cff) 30%,transparent),0 1px 2px rgba(0,0,0,.08)}
|
|
771
|
+
.dfa-tile svg{width:17px;height:17px}
|
|
770
772
|
.dfa-tile[data-kind="text"]{--dfa-hue:#5b8cff}
|
|
771
773
|
.dfa-tile[data-kind="markdown"]{--dfa-hue:#7b8cff}
|
|
772
774
|
.dfa-tile[data-kind="html"]{--dfa-hue:#e0714a}
|
|
@@ -1407,7 +1409,7 @@ const factory = () => {
|
|
|
1407
1409
|
})
|
|
1408
1410
|
const icon = makeNode('span', { class: 'dfa-ico' })
|
|
1409
1411
|
if (item.iconData) icon.appendChild(makeNode('img', { src: item.iconData, alt: '' }))
|
|
1410
|
-
else icon.innerHTML = iconSvg('
|
|
1412
|
+
else icon.innerHTML = iconSvg('file')
|
|
1411
1413
|
row.appendChild(icon)
|
|
1412
1414
|
row.appendChild(makeNode('span', { class: 'dfa-label', text: item.label }))
|
|
1413
1415
|
if (item.checked || item.preferred) {
|
|
@@ -2126,9 +2128,8 @@ const factory = () => {
|
|
|
2126
2128
|
}
|
|
2127
2129
|
}
|
|
2128
2130
|
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
if (event.shiftKey) { closeMenu(); return }
|
|
2131
|
+
/** Take the click and open our menu, unless the pointer sits on our own menu. */
|
|
2132
|
+
function openFromEvent(event) {
|
|
2132
2133
|
const target = event.target
|
|
2133
2134
|
// A right-click on the menu itself must not open a second menu over it.
|
|
2134
2135
|
if (target && target.closest && target.closest(`[${MENU_ATTR}]`)) {
|
|
@@ -2148,6 +2149,29 @@ const factory = () => {
|
|
|
2148
2149
|
void openAt(candidate, event.clientX, event.clientY, false)
|
|
2149
2150
|
}
|
|
2150
2151
|
|
|
2152
|
+
// The Electron shell ships no native context menu, so a Shift-click that only
|
|
2153
|
+
// stepped aside would be a dead end. Remember the event here, let the page and
|
|
2154
|
+
// any other plugin answer in the bubble phase, and fall back to our own menu
|
|
2155
|
+
// when nobody did.
|
|
2156
|
+
let shiftEvent = null
|
|
2157
|
+
|
|
2158
|
+
function onContextMenu(event) {
|
|
2159
|
+
if (event.defaultPrevented) return
|
|
2160
|
+
if (event.shiftKey) {
|
|
2161
|
+
shiftEvent = event
|
|
2162
|
+
closeMenu()
|
|
2163
|
+
return
|
|
2164
|
+
}
|
|
2165
|
+
openFromEvent(event)
|
|
2166
|
+
}
|
|
2167
|
+
|
|
2168
|
+
function onContextMenuFallback(event) {
|
|
2169
|
+
if (event !== shiftEvent) return
|
|
2170
|
+
shiftEvent = null
|
|
2171
|
+
if (event.defaultPrevented) return
|
|
2172
|
+
openFromEvent(event)
|
|
2173
|
+
}
|
|
2174
|
+
|
|
2151
2175
|
function onKeyDown(event) {
|
|
2152
2176
|
const wantsMenu = (event.key === 'F10' && event.shiftKey) || event.key === 'ContextMenu'
|
|
2153
2177
|
if (!wantsMenu) return
|
|
@@ -2197,6 +2221,7 @@ const factory = () => {
|
|
|
2197
2221
|
const install = () => {
|
|
2198
2222
|
if (activeCleanup) activeCleanup()
|
|
2199
2223
|
document.addEventListener('contextmenu', onContextMenu, true)
|
|
2224
|
+
window.addEventListener('contextmenu', onContextMenuFallback)
|
|
2200
2225
|
document.addEventListener('pointerover', onWarm, true)
|
|
2201
2226
|
document.addEventListener('focusin', onWarm, true)
|
|
2202
2227
|
document.addEventListener('keydown', onKeyDown, true)
|
|
@@ -2210,6 +2235,7 @@ const factory = () => {
|
|
|
2210
2235
|
disposed = true
|
|
2211
2236
|
document.documentElement.removeAttribute('data-dfa-ready')
|
|
2212
2237
|
document.removeEventListener('contextmenu', onContextMenu, true)
|
|
2238
|
+
window.removeEventListener('contextmenu', onContextMenuFallback)
|
|
2213
2239
|
document.removeEventListener('pointerover', onWarm, true)
|
|
2214
2240
|
document.removeEventListener('focusin', onWarm, true)
|
|
2215
2241
|
probeCache.clear()
|
|
@@ -2256,6 +2282,8 @@ const factory = () => {
|
|
|
2256
2282
|
// test harness evaluates it with a fake `window` and reads these directly.
|
|
2257
2283
|
__internals: {
|
|
2258
2284
|
messages,
|
|
2285
|
+
iconSvg,
|
|
2286
|
+
ICON_PATHS,
|
|
2259
2287
|
isAbsolutePath,
|
|
2260
2288
|
normalizeSlashes,
|
|
2261
2289
|
basename,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jidekaixin2dian/dsh-file-actions",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.14",
|
|
4
4
|
"description": "File and link actions for DeepSeek Harness: open, choose applications, reveal, copy paths or contents, and save files from the chat.",
|
|
5
5
|
"icon": "icon.svg",
|
|
6
6
|
"type": "module",
|