dsh-recall-plugin 1.0.3 → 1.0.4

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
@@ -11,7 +11,6 @@
11
11
  ---
12
12
  **在任意一条你发过的消息下方**,**点「↶ 撤回」**,**工作区文件和对话历史一起回到那条消息发出之前的状态**。
13
13
 
14
-
15
14
  ## 界面预览
16
15
  - 撤回按钮位置
17
16
 
@@ -35,8 +34,9 @@
35
34
 
36
35
  - 快照在**消息发送时**创建,插件启用前的历史消息没有快照,不显示撤回按钮。
37
36
  - 会话第一条用户消息无法回退对话(仅文件回退),因为 fork 需要更早的 turn 边界。
38
- - 仅支持 Windows(脚本用 PowerShell + git CLI);Linux/macOS 下插件不报错,但快照不工作、不显示撤回按钮。
37
+ - 仅支持 Windows(脚本用 PowerShell + git CLI);Linux/macOS 下页面会弹一次性「仅支持 Windows」提示,快照不可用、不显示撤回按钮,也不会产生任何文件副作用。
39
38
  - 工作区内嵌套的其他 git 仓库(子目录自带 `.git`)不进快照,其内容不参与回退。
39
+ - MacOS和Linux环境未进行测试
40
40
 
41
41
  ## 安装
42
42
 
package/lib/client.js CHANGED
@@ -118,19 +118,29 @@ window.__ModuleLoader__.load({
118
118
  initedSessionId = sessionId
119
119
  initDone = api('init', { sessionId }).then((res) => {
120
120
  const notice = res && res.notice
121
+ if (notice && notice.unsupported) {
122
+ showNotice('unsupported', '撤回插件仅支持 Windows,当前平台的快照不可用。')
123
+ }
121
124
  if (notice && notice.gitMissing) {
122
125
  showNotice('git', '未检测到 git CLI,撤回功能不可用(快照引擎依赖 git)。安装 git 并重启 DSH 后即可使用。')
123
126
  }
124
127
  if (notice && notice.homeFallback) {
125
128
  showNotice('home', 'home 目录不可写,快照已降级存储到项目内 .dsh-recall-snapshots 目录。')
126
129
  }
127
- }).catch(() => {})
130
+ }).catch(() => {
131
+ // init 失败(如页面先于 Host API 就绪加载)时清掉标记:否则本会话
132
+ // 内被判定“已初始化”,撤回按钮永不出现;清掉后下一条消息挂载会重试
133
+ if (initedSessionId === sessionId) initedSessionId = null
134
+ })
128
135
  return initDone
129
136
  }
130
137
 
131
138
  // 消息时间:当天只显示时分,跨天显示月/日 时分
132
139
  function clockText(ms) {
133
140
  try {
141
+ // time 字段缺失或非法时返回空串:Invalid Date 不会 throw,
142
+ // 不拦会渲染出 "NaN/NaN NaN:NaN" 这样的坏时间戳
143
+ if (!ms || isNaN(new Date(ms).getTime())) return ''
134
144
  const d = new Date(ms)
135
145
  const now = new Date()
136
146
  const sameDay = d.getFullYear() === now.getFullYear() && d.getMonth() === now.getMonth() && d.getDate() === now.getDate()
package/lib/index.js CHANGED
@@ -19,6 +19,13 @@ export const inject = ['shell', 'sessions', 'webServer']
19
19
  const MAX_FILE_BYTES = 104857600
20
20
  const HOME_RETRY_MS = 300000
21
21
 
22
+ // 统一 UTF-8 输出前导:中文等非 ASCII 机器的默认代码页(如 GBK)下,
23
+ // PowerShell 重定向 stdout 按 [Console]::OutputEncoding 编码,而 DSH 按
24
+ // UTF-8 解码——不强制时 homeDirFor/resolveGit 输出里含中文的用户名/路径
25
+ // 会变乱码,store 会指向错误目录。diff/rollback 脚本里早有同款设置,
26
+ // 这里提到 runShell 全局注入一次,其余脚本不改自动受益(PS 5.1 / 7 均支持)。
27
+ const UTF8_PRELUDE = '$OutputEncoding = [Text.UTF8Encoding]::new($false)\ntry { [Console]::OutputEncoding = [Text.UTF8Encoding]::new($false) } catch {}'
28
+
22
29
  export function apply(ctx) {
23
30
  const shell = ctx.shell
24
31
  const sessions = ctx.sessions
@@ -36,6 +43,12 @@ export function apply(ctx) {
36
43
  gitExe: null
37
44
  }
38
45
 
46
+ // 非 Windows 平台干净降级:脚本体系(反斜杠路径、Windows git 安装候选、
47
+ // Expand-Archive)绑定 Windows,硬跑不报错但会在项目里创建名字带反斜杠的
48
+ // 垃圾目录。这里整体短路:init 返回 unsupported,Client 弹一次性提示;
49
+ // 其余端点因无快照自然返回「没有可用快照」,全程零文件副作用。
50
+ const supported = process.platform === 'win32'
51
+
39
52
  function psq(value) {
40
53
  return "'" + String(value).replace(/'/g, "''") + "'"
41
54
  }
@@ -52,7 +65,7 @@ export function apply(ctx) {
52
65
  async function runShell(command, opts) {
53
66
  const sp = ctx.get('sandboxPolicy')
54
67
  const spec = shell.resolve({
55
- command,
68
+ command: UTF8_PRELUDE + '\n' + command,
56
69
  timeoutMs: (opts && opts.timeoutMs) || 300000,
57
70
  stdoutMaxBytes: (opts && opts.stdoutMaxBytes) || 4194304,
58
71
  sandboxPolicy: { mode: 'danger-full-access', workspaceRoot: (sp && sp.workspaceRoot) || process.cwd() }
@@ -140,6 +153,9 @@ export function apply(ctx) {
140
153
  // PS 的 Join-Path 可能带出连续反斜杠(旧版脚本遗留 "…\\<hex>" 形态);
141
154
  // 折叠成单反斜杠。Windows 把中间的重复分隔符视为同一个目录,
142
155
  // 所以与既有快照数据(index.json、影子 git 仓库)路径完全兼容。
156
+ // 开头的双反斜杠是 UNC 前缀(DSH_HOME/用户主目录指到网络盘),
157
+ // 折叠掉会把 \\server\share 变成无效的 \server\share,必须原样保留。
158
+ if (/^\\\\/.test(text)) return '\\\\' + text.slice(2).replace(/\\{2,}/g, '\\')
143
159
  return text.replace(/\\{2,}/g, '\\')
144
160
  }
145
161
 
@@ -607,6 +623,10 @@ export function apply(ctx) {
607
623
  try {
608
624
  const args = await readJsonBody(req)
609
625
  if (name === 'init') {
626
+ if (!supported) {
627
+ sendJson(res, 200, { ok: false, root: null, notice: { unsupported: true } })
628
+ return
629
+ }
610
630
  const sessionId = args && args.sessionId ? String(args.sessionId) : null
611
631
  const root = await resolveRoot(sessionId)
612
632
  let notice = null
@@ -670,6 +690,9 @@ export function apply(ctx) {
670
690
  }
671
691
  }))
672
692
 
693
+ // 快照事件与启动预热仅在受支持平台注册(见上方 supported 短路说明)
694
+ if (!supported) return
695
+
673
696
  // 每条用户消息触发快照(子代理会话跳过)
674
697
  ctx.on('session/event', (session, event) => {
675
698
  if (!event || event.type !== 'user/message') return
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-recall-plugin",
3
- "version": "1.0.3",
3
+ "version": "1.0.4",
4
4
  "description": "DSH 消息撤回插件:在用户消息气泡旁加「撤回」按钮,把项目文件(独立影子 git 仓库快照)与对话历史(官方 fork)一并回退到该消息发送之前。",
5
5
  "type": "module",
6
6
  "repository": {