dsh-done-sound 0.1.7 → 0.1.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.
Files changed (2) hide show
  1. package/lib/client.js +90 -10
  2. package/package.json +1 -1
package/lib/client.js CHANGED
@@ -28,6 +28,7 @@ window.__ModuleLoader__.load({
28
28
  '.dtc-row{justify-content:space-between;align-items:center;gap:12px;display:flex}',
29
29
  '.dtc-muted{color:var(--dsw-alias-label-secondary);font-size:12px}',
30
30
  '.dtc-err{color:var(--dsw-alias-state-error-primary);white-space:pre-wrap;font-size:12px}',
31
+ '.dtc-ok{color:var(--dsw-alias-state-success-primary);white-space:pre-wrap;font-size:12px;word-break:break-all}',
31
32
  '.dtc-btn{border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border-radius:6px;padding:3px 12px;font-size:12px;white-space:nowrap}',
32
33
  '.dtc-btn:disabled{opacity:.5;cursor:default}',
33
34
  '.dtc-file{display:inline-flex;align-items:center}',
@@ -86,6 +87,11 @@ window.__ModuleLoader__.load({
86
87
  retryFailed: '自动发送「继续」失败',
87
88
  logPath: '日志文件',
88
89
  exportLog: '导出日志',
90
+ exportSaved: '日志已导出',
91
+ exportSavedFile: '保存文件名:{name}',
92
+ exportSavedFallbackHint: '未弹出保存窗口,文件已存到浏览器默认下载文件夹(通常 C:\\Users\\你的用户名\\Downloads)',
93
+ exportLogPath: '原始日志路径:{path}(复制到资源管理器地址栏可打开)',
94
+ exportLogPathUnknown: '原始日志路径未知(可在插件目录 logs 文件夹查看)',
89
95
  version: '当前版本',
90
96
  updateAvailable: '有新版本',
91
97
  upToDate: '已是最新',
@@ -134,6 +140,11 @@ window.__ModuleLoader__.load({
134
140
  retryFailed: 'failed to auto-send "continue"',
135
141
  logPath: 'Log file',
136
142
  exportLog: 'Export log',
143
+ exportSaved: 'Log exported',
144
+ exportSavedFile: 'Saved file name: {name}',
145
+ exportSavedFallbackHint: 'No save dialog shown; saved to the browser default Downloads folder (usually C:\\Users\\YourName\\Downloads)',
146
+ exportLogPath: 'Original log path: {path} (copy into File Explorer address bar to open)',
147
+ exportLogPathUnknown: 'Original log path unknown (check the plugin logs folder)',
137
148
  version: 'Version',
138
149
  updateAvailable: 'Update available',
139
150
  upToDate: 'Up to date',
@@ -418,11 +429,21 @@ window.__ModuleLoader__.load({
418
429
  loaded: true,
419
430
  });
420
431
  };
432
+ // 预热:模块一激活就拉取 Host 持久化配置(如自动重连秒数),
433
+ // 避免页面刷新后倒计时/自动重连先用初始默认值(60s),
434
+ // 而设置卡却显示已保存值(20s)——两者必须一致。
435
+ // 失败静默,卡片挂载和 detector 挂载时还会再次同步兜底。
436
+ api('/dsh-done-sound/api/status')
437
+ .then((payload) => {
438
+ if (payload && typeof payload === 'object') syncConfig(payload);
439
+ })
440
+ .catch(() => {});
421
441
 
422
442
  // ---- Settings card (global slot) ----
423
443
  const TurnChimeCard = (props) => {
424
444
  const cfg = useConfig();
425
445
  const [error, setError] = react.useState(null);
446
+ const [exportInfo, setExportInfo] = react.useState(null);
426
447
  const [busy, setBusy] = react.useState(false);
427
448
  const [lang] = react.useState(resolveLang());
428
449
  const L = (key) => t(lang, key);
@@ -471,8 +492,20 @@ window.__ModuleLoader__.load({
471
492
  );
472
493
  // Export today's log file: fetch it from the host, then hand the
473
494
  // browser a Blob download — the native save dialog lets the user pick
474
- // where to store it (filename is today's dated log name).
495
+ // where to store it (filename is today's dated log name). After a
496
+ // successful export, show a green banner with the saved file name and
497
+ // the original log path so the user can find the file on Windows even
498
+ // when the browser cannot show a save dialog.
475
499
  const exportLog = () => {
500
+ setExportInfo(null);
501
+ const showSaved = (savedName, fallbackHint) => {
502
+ const lines = [L('exportSaved') + ' ✓', L('exportSavedFile').replace('{name}', savedName)];
503
+ if (fallbackHint) lines.push(L('exportSavedFallbackHint'));
504
+ // 原始日志路径来自 Host,复制到资源管理器地址栏即可直接打开,
505
+ // 最方便排查「有概率无音效」类问题。
506
+ lines.push(cfg.logPath ? L('exportLogPath').replace('{path}', cfg.logPath) : L('exportLogPathUnknown'));
507
+ setExportInfo(lines.join('\n'));
508
+ };
476
509
  fetch('/dsh-done-sound/api/log/export')
477
510
  .then((res) => {
478
511
  if (!res.ok) {
@@ -483,15 +516,50 @@ window.__ModuleLoader__.load({
483
516
  return res.text();
484
517
  })
485
518
  .then((text) => {
486
- const blob = new Blob([text], { type: 'text/plain;charset=utf-8' });
487
- const url = URL.createObjectURL(blob);
488
- const a = document.createElement('a');
489
- a.href = url;
490
- a.download = cfg.logFileName || 'dsh-done-sound.log';
491
- document.body.appendChild(a);
492
- a.click();
493
- a.remove();
494
- setTimeout(() => URL.revokeObjectURL(url), 2000);
519
+ const fileName = cfg.logFileName || 'dsh-done-sound.log';
520
+ const fallbackDownload = () => {
521
+ const blob = new Blob([text], { type: 'text/plain;charset=utf-8' });
522
+ const url = URL.createObjectURL(blob);
523
+ const a = document.createElement('a');
524
+ a.href = url;
525
+ a.download = fileName;
526
+ document.body.appendChild(a);
527
+ a.click();
528
+ a.remove();
529
+ setTimeout(() => URL.revokeObjectURL(url), 2000);
530
+ showSaved(fileName, true);
531
+ };
532
+ // 优先用浏览器原生「另存为」对话框(File System Access API,
533
+ // Chrome/Edge 支持),让用户自己选择保存位置;
534
+ // 不支持或用户取消时回退为普通下载。
535
+ if (typeof window.showSaveFilePicker === 'function') {
536
+ window
537
+ .showSaveFilePicker({
538
+ suggestedName: fileName,
539
+ types: [{ description: '日志文件', accept: { 'text/plain': ['.log', '.txt'] } }],
540
+ })
541
+ .then((handle) => {
542
+ const savedName = handle && typeof handle.name === 'string' && handle.name ? handle.name : fileName;
543
+ return handle.createWritable().then(async (writable) => {
544
+ await writable.write(text);
545
+ await writable.close();
546
+ showSaved(savedName, false);
547
+ });
548
+ })
549
+ .catch((err) => {
550
+ // 用户点了「取消」关闭对话框 → 不算错误,直接结束。
551
+ if (err && err.name === 'AbortError') return;
552
+ // 其他失败(如手势过期、浏览器限制)→ 回退为普通下载。
553
+ try {
554
+ if (typeof console !== 'undefined') console.warn('[dsh-done-sound] save picker failed, falling back to download:', err);
555
+ } catch {
556
+ // ignore
557
+ }
558
+ fallbackDownload();
559
+ });
560
+ return;
561
+ }
562
+ fallbackDownload();
495
563
  })
496
564
  .catch((err) => {
497
565
  try {
@@ -658,6 +726,7 @@ window.__ModuleLoader__.load({
658
726
  L('exportLog'),
659
727
  ),
660
728
  ),
729
+ exportInfo !== null && react.createElement('div', { className: 'dtc-ok' }, exportInfo),
661
730
 
662
731
  react.createElement(
663
732
  'div',
@@ -874,6 +943,17 @@ window.__ModuleLoader__.load({
874
943
  const prevPendingKeysRef = react.useRef('');
875
944
  const seededRef = react.useRef(false);
876
945
 
946
+ // 兜底:挂载时若配置尚未从 Host 同步(如页面刚刷新、apply 预热未完成),
947
+ // 主动拉取一次,确保自动重连倒计时使用用户保存的秒数而非初始默认值。
948
+ react.useEffect(() => {
949
+ if (configStore.value.loaded) return;
950
+ api('/dsh-done-sound/api/status')
951
+ .then((payload) => {
952
+ if (payload && typeof payload === 'object') syncConfig(payload);
953
+ })
954
+ .catch(() => {});
955
+ }, []);
956
+
877
957
  const snap =
878
958
  typeof useSession === 'function'
879
959
  ? useSession((s) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-done-sound",
3
- "version": "0.1.7",
3
+ "version": "0.1.8",
4
4
  "description": "Play a user-chosen sound whenever a conversation finishes in the DeepSeek Harness web GUI",
5
5
  "license": "MIT",
6
6
  "type": "module",