dsh-vault 1.5.0-rc.8 → 1.5.0

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-zh.md CHANGED
@@ -69,6 +69,9 @@ dsh-vault 是一个面向 DeepSeek Harness 的安全加密插件:把你在使
69
69
  | `vault_duplicates` | 查找重复分组:`mode` = `both`(默认)/ `title` / `content`(不含密钥) |
70
70
  | `vault_report` | 可打印清单,含到期/轮换列与统计页脚(不含密钥) |
71
71
  | `vault_export` / `vault_import` | 整库加密备份/迁移(独立导出密码) |
72
+ | `vault_backup` / `vault_backup_now` | 时间戳加密备份,文件名 `<库名>-backups-YYYY-MM-DD_HH-MM-SS-<hex>.json`(库名+日期一目了然);自动保留最近 N 份 |
73
+ | `vault_restore_backup` | 从备份还原:`mode: "merge"`(默认)把备份条目复制进当前库,出现在条目列表;`mode: "replace"` 整体覆盖(先写安全快照) |
74
+ | `vault_vault_rename` / `vault_vault_delete` | 重命名命名库(文件移动,当前会话跟随)或永久删除(default 库受保护) |
72
75
  | `vault_fill` | 按 host/URL/用户名/标题匹配条目并返回其凭据 |
73
76
  | `vault_env` | 把标记 env 的条目(tags 含 `env`)渲染为 `KEY=VALUE` 行 |
74
77
  | `vault_export_bitwarden` / `vault_import_bitwarden` | Bitwarden/Vaultwarden JSON 互通(完整字段映射,支持覆盖) |
package/README.md CHANGED
@@ -71,6 +71,9 @@ Each record has a `title`, an optional `kind`, and any combination of fields:
71
71
  | `vault_duplicates` | Find duplicate groups: `mode` = `both` (default) / `title` / `content` (no secrets) |
72
72
  | `vault_report` | Printable inventory with expiry/rotation columns and a stats footer (no secrets) |
73
73
  | `vault_export` / `vault_import` | Portable encrypted backup/migration of the whole vault (separate export password) |
74
+ | `vault_backup` / `vault_backup_now` | Timestamped encrypted backup named `<vault>-backups-YYYY-MM-DD_HH-MM-SS-<hex>.json` (owning vault + date visible); retention pruning keeps the newest N |
75
+ | `vault_restore_backup` | Restore from a backup: `mode: "merge"` (default) copies the backup entries INTO the current vault so they appear in the entries list; `mode: "replace"` overwrites the whole vault with a safety snapshot first |
76
+ | `vault_vault_rename` / `vault_vault_delete` | Rename a named vault (file moves, active session follows) or permanently delete one (default vault protected) |
74
77
  | `vault_fill` | Find the entry matching a host/URL/username/title and return its credentials |
75
78
  | `vault_env` | Render env-flagged entries (tags contain `env`) as `KEY=VALUE` lines |
76
79
  | `vault_export_bitwarden` / `vault_import_bitwarden` | Bitwarden/Vaultwarden JSON interop (full field mapping, overwrite support) |
package/lib/client.js CHANGED
@@ -7,7 +7,7 @@ window.__ModuleLoader__.load({
7
7
  let react = require("react");
8
8
  let react_jsx_runtime = require("react/jsx-runtime");
9
9
  //#region \0dsh-css:/Users/zhipeng/Desktop/work/dsh test/dsh-vault/src/client/VaultSection.module.css.mjs
10
- const css = ".t_j5va_section{flex-direction:column;gap:12px;padding:16px 0;display:flex}.t_j5va_intro{opacity:.75;margin:0;font-size:13px}.t_j5va_srOnly{clip-path:inset(50%);white-space:nowrap;width:1px;height:1px;position:absolute;overflow:hidden}.t_j5va_toolbar{flex-wrap:wrap;align-items:center;gap:8px;display:flex}.t_j5va_searchBox{flex:150px;min-width:150px;display:flex}.t_j5va_searchBox input{border:1px solid var(--color-border,#444);color:inherit;background:0 0;border-radius:6px;flex:1;padding:6px 10px;font-size:13px}.t_j5va_addButton,.t_j5va_saveButton{background:var(--color-accent,#4f8cff);color:#fff;cursor:pointer;border:1px solid #0000;border-radius:6px;padding:6px 12px;font-size:13px}.t_j5va_addButton:disabled,.t_j5va_saveButton:disabled,.t_j5va_rowActions button:disabled{opacity:.5;cursor:not-allowed}.t_j5va_list{flex-direction:column;gap:6px;margin:0;padding:0;list-style:none;display:flex}.t_j5va_row{border:1px solid var(--color-border,#333);border-radius:8px;justify-content:space-between;align-items:center;gap:12px;padding:8px 10px;display:flex}.t_j5va_rowMain{flex-direction:column;gap:2px;min-width:0;display:flex}.t_j5va_title{font-size:14px;font-weight:600}.t_j5va_identity{opacity:.7;text-overflow:ellipsis;white-space:nowrap;font-size:12px;overflow:hidden}.t_j5va_totp{font-family:var(--font-mono,monospace);color:var(--color-accent,#4f8cff);font-size:13px}.t_j5va_totpRing{vertical-align:-2px;margin-right:4px;display:inline-block}.t_j5va_rowActions{flex-shrink:0;align-items:center;gap:6px;display:flex}.t_j5va_rowActions button{border:1px solid var(--color-border,#444);color:inherit;cursor:pointer;background:0 0;border-radius:6px;padding:4px 8px;font-size:12px}.t_j5va_deleteButton{color:#e5484d}.t_j5va_copied{color:#30a46c;font-size:12px}.t_j5va_empty,.t_j5va_status,.t_j5va_error{opacity:.8;font-size:13px}.t_j5va_lockedBanner{color:#8a5a00;background:#fff4e5;border:1px solid #e0a83a;border-radius:6px;margin:0 0 10px;padding:8px 12px;font-size:13px}.t_j5va_modeReadonly,.t_j5va_modeAsk,.t_j5va_modeAuto{border-radius:999px;width:fit-content;margin:0;padding:4px 10px;font-size:12px;display:inline-block}.t_j5va_modeReadonly{color:#e5484d;border:1px solid #e5484d80}.t_j5va_modeAsk{color:#f5a524;border:1px solid #f5a52480}.t_j5va_modeAuto{color:#30a46c;border:1px solid #30a46c80}.t_j5va_policyBar{flex-direction:column;align-items:flex-start;gap:6px;display:flex}.t_j5va_policyField{align-items:center;gap:8px;font-size:13px;display:flex}.t_j5va_policyField select{border:1px solid var(--color-border,#444);color:inherit;background:0 0;border-radius:6px;padding:4px 8px;font-size:13px}.t_j5va_emptyBox{flex-direction:column;gap:4px;display:flex}.t_j5va_emptyHint{opacity:.65;margin:0;font-size:12px}.t_j5va_error{color:#e5484d}.t_j5va_editor{border:1px solid var(--color-border,#444);border-radius:8px;padding:12px}.t_j5va_editorBody{grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:8px 12px;display:grid}.t_j5va_checkField{align-items:center;gap:8px;font-size:13px;display:inline-flex}.t_j5va_field{flex-direction:column;gap:4px;font-size:12px;display:flex}.t_j5va_field input,.t_j5va_field select{border:1px solid var(--color-border,#444);color:inherit;background:0 0;border-radius:6px;padding:5px 8px;font-size:13px}.t_j5va_editorActions{justify-content:flex-end;gap:8px;margin-top:12px;display:flex}.t_j5va_editorActions button{border:1px solid var(--color-border,#444);color:inherit;cursor:pointer;background:0 0;border-radius:6px;padding:6px 12px;font-size:13px}.t_j5va_reportBox{border:1px solid #f5a52466;border-radius:8px;flex-direction:column;gap:2px;padding:8px 10px;font-size:12px;display:flex}.t_j5va_reportTitle{margin:0;font-weight:600}.t_j5va_reportLine{opacity:.8;margin:0}.t_j5va_reportSub{color:var(--dsh-color-text-2,#666);margin:2px 0 0 10px;font-size:12px}.t_j5va_trashButton{border:1px solid var(--color-border,#444);color:inherit;cursor:pointer;background:0 0;border-radius:6px;align-self:flex-start;padding:4px 8px;font-size:12px}.t_j5va_secretField{gap:4px;display:flex}.t_j5va_secretField input{flex:1;min-width:0}.t_j5va_revealButton{border:1px solid var(--color-border,#444);color:inherit;cursor:pointer;background:0 0;border-radius:6px;padding:0 8px;font-size:12px}.t_j5va_kindFilter{border:1px solid var(--color-border,#444);color:inherit;background:0 0;border-radius:6px;padding:6px 8px;font-size:13px}.t_j5va_highBadge{color:#e5484d;vertical-align:middle;background:#e5484d26;border-radius:4px;margin-left:6px;padding:1px 6px;font-size:10px;font-weight:600}.t_j5va_pinStar{color:#f5a524;margin-right:4px}.t_j5va_clearButton{color:inherit;cursor:pointer;opacity:.6;background:0 0;border:none;padding:0 8px;font-size:16px}.t_j5va_field textarea{border:1px solid var(--color-border,#444);color:inherit;resize:vertical;background:0 0;border-radius:6px;padding:5px 8px;font-family:inherit;font-size:13px}.t_j5va_row{transition:background .12s}.t_j5va_row:hover{background:var(--color-hover,#80808014)}.t_j5va_healthBar{flex-wrap:wrap;gap:6px;margin:0 0 10px;display:flex}.t_j5va_badge{border:1px solid var(--dsh-color-border,#ddd);background:var(--dsh-color-surface-2,#f7f7f8);color:var(--dsh-color-text-2,#555);border-radius:999px;padding:4px 10px;font-size:12px;line-height:1}.t_j5va_backupButton{border:1px solid var(--dsh-color-border,#ccc);background:var(--dsh-color-surface-2,#f7f7f8);cursor:pointer;border-radius:999px;padding:4px 10px;font-size:12px;line-height:1}.t_j5va_badgeOk{color:#2e9e5b;border-color:#2e9e5b}.t_j5va_badgeWarn{color:#b57f1a;border-color:#c98a1b}.t_j5va_rowDue{border-left:3px solid #c98a1b}.t_j5va_rowExpired{border-left:3px solid #cf3d3d}.t_j5va_dueBadge{border-radius:999px;margin-left:6px;padding:3px 8px;font-size:11px;font-weight:600;line-height:1}.t_j5va_badgeDanger{color:#c03a3a;border-color:#cf3d3d}.t_j5va_footer{opacity:.6;margin:0;font-size:12px}.t_j5va_kindIcon{margin-right:4px;font-size:12px}.t_j5va_dangerButton{color:#e5484d;cursor:pointer;background:0 0;border:1px solid #e5484d80;border-radius:6px;align-self:flex-start;padding:4px 8px;font-size:12px}.t_j5va_rowMain{cursor:pointer}.t_j5va_detailBox{background:var(--color-hover,#8080800f);border-radius:6px;flex-wrap:wrap;grid-column:1/-1;gap:4px 12px;padding:6px 8px;font-size:12px;display:flex}.t_j5va_detailItem{opacity:.85}.t_j5va_sortButton{border:1px solid var(--color-border,#444);color:inherit;cursor:pointer;background:0 0;border-radius:6px;padding:6px 10px;font-size:13px}.t_j5va_dupGroup{justify-content:space-between;align-items:center;gap:8px;margin:4px 0;display:flex}.t_j5va_dupNames{text-overflow:ellipsis;white-space:nowrap;font-size:12px;overflow:hidden}.t_j5va_dupMerge{border:1px solid var(--dsh-color-border,#ccc);cursor:pointer;border-radius:6px;flex-shrink:0;padding:2px 8px;font-size:12px}.t_j5va_auditRow{align-items:center;gap:8px;margin:4px 0;display:flex}.t_j5va_auditIssues{color:var(--dsh-color-text-2,#666);text-overflow:ellipsis;white-space:nowrap;flex:1;font-size:12px;overflow:hidden}.t_j5va_retryButton{border:1px solid var(--dsh-color-border,#ccc);cursor:pointer;border-radius:6px;margin-left:6px;padding:2px 8px;font-size:12px}.t_j5va_scoreRing{vertical-align:-2px;margin-right:4px;display:inline-block}.t_j5va_genOpts{border:1px solid var(--dsh-color-border,#ddd);border-radius:8px;flex-direction:column;gap:6px;padding:8px 10px;display:flex}.t_j5va_genOptRow{justify-content:space-between;align-items:center;gap:8px;font-size:13px;display:flex}.t_j5va_genOptRow input[type=number]{width:64px}.t_j5va_pwMeter{align-items:center;gap:8px;font-size:12px;display:flex}.t_j5va_pwBar{border-radius:999px;height:6px;transition:width .2s}.t_j5va_pwWeak{background:#cf3d3d}.t_j5va_pwFair{background:#c98a1b}.t_j5va_pwStrong{background:#2e9e5b}.t_j5va_pwLabel{color:var(--dsh-color-text-2,#666)}.t_j5va_resultCount{color:var(--dsh-color-text-2,#666);flex-wrap:wrap;align-items:center;gap:6px;margin:0 0 6px;font-size:12px;display:flex}.t_j5va_kindChip{border:1px solid var(--dsh-color-border,#ddd);border-radius:999px;padding:2px 8px;font-size:11px}.t_j5va_uriCode{overflow-wrap:anywhere;opacity:.85;font-size:10px}.t_j5va_genHist{flex-wrap:wrap;gap:4px;font-size:12px;display:flex}.t_j5va_genHist span{align-self:center}.t_j5va_lockedTag{color:#c98a1b;font-size:12px;font-weight:600}.t_j5va_tabs{flex-wrap:wrap;gap:6px;margin:0 0 12px;display:flex}.t_j5va_tab{border:1px solid var(--dsh-color-border,#ccc);color:inherit;cursor:pointer;background:0 0;border-radius:999px;padding:5px 14px;font-size:13px}.t_j5va_tabActive{background:var(--dsh-color-primary,#4a6cf7);color:#fff;border-color:#0000}.t_j5va_tabPane{margin-top:2px}";
10
+ const css = ".t_j5va_section{flex-direction:column;gap:12px;padding:16px 0;display:flex}.t_j5va_intro{opacity:.75;margin:0;font-size:13px}.t_j5va_srOnly{clip-path:inset(50%);white-space:nowrap;width:1px;height:1px;position:absolute;overflow:hidden}.t_j5va_toolbar{flex-wrap:wrap;align-items:center;gap:8px;display:flex}.t_j5va_searchBox{flex:150px;min-width:150px;display:flex}.t_j5va_searchBox input{border:1px solid var(--color-border,#444);color:inherit;background:0 0;border-radius:6px;flex:1;padding:6px 10px;font-size:13px}.t_j5va_addButton,.t_j5va_saveButton{background:var(--color-accent,#4f8cff);color:#fff;cursor:pointer;border:1px solid #0000;border-radius:6px;padding:6px 12px;font-size:13px}.t_j5va_addButton:disabled,.t_j5va_saveButton:disabled,.t_j5va_rowActions button:disabled{opacity:.5;cursor:not-allowed}.t_j5va_list{flex-direction:column;gap:6px;margin:0;padding:0;list-style:none;display:flex}.t_j5va_row{border:1px solid var(--color-border,#333);border-radius:8px;justify-content:space-between;align-items:center;gap:12px;padding:8px 10px;display:flex}.t_j5va_rowMain{flex-direction:column;gap:2px;min-width:0;display:flex}.t_j5va_title{font-size:14px;font-weight:600}.t_j5va_identity{opacity:.7;text-overflow:ellipsis;white-space:nowrap;font-size:12px;overflow:hidden}.t_j5va_totp{font-family:var(--font-mono,monospace);color:var(--color-accent,#4f8cff);font-size:13px}.t_j5va_totpRing{vertical-align:-2px;margin-right:4px;display:inline-block}.t_j5va_rowActions{flex-shrink:0;align-items:center;gap:6px;display:flex}.t_j5va_rowActions button{border:1px solid var(--color-border,#444);color:inherit;cursor:pointer;background:0 0;border-radius:6px;padding:4px 8px;font-size:12px}.t_j5va_deleteButton{color:#e5484d}.t_j5va_copied{color:#30a46c;font-size:12px}.t_j5va_empty,.t_j5va_status,.t_j5va_error{opacity:.8;font-size:13px}.t_j5va_lockedBanner{color:#8a5a00;background:#fff4e5;border:1px solid #e0a83a;border-radius:6px;margin:0 0 10px;padding:8px 12px;font-size:13px}.t_j5va_modeReadonly,.t_j5va_modeAsk,.t_j5va_modeAuto{border-radius:999px;width:fit-content;margin:0;padding:4px 10px;font-size:12px;display:inline-block}.t_j5va_modeReadonly{color:#e5484d;border:1px solid #e5484d80}.t_j5va_modeAsk{color:#f5a524;border:1px solid #f5a52480}.t_j5va_modeAuto{color:#30a46c;border:1px solid #30a46c80}.t_j5va_policyBar{flex-direction:column;align-items:flex-start;gap:6px;display:flex}.t_j5va_policyField{align-items:center;gap:8px;font-size:13px;display:flex}.t_j5va_policyField select{border:1px solid var(--color-border,#444);color:inherit;background:0 0;border-radius:6px;padding:4px 8px;font-size:13px}.t_j5va_emptyBox{flex-direction:column;gap:4px;display:flex}.t_j5va_emptyHint{opacity:.65;margin:0;font-size:12px}.t_j5va_error{color:#e5484d}.t_j5va_editor{border:1px solid var(--color-border,#444);border-radius:8px;padding:12px}.t_j5va_editorBody{grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:8px 12px;display:grid}.t_j5va_checkField{align-items:center;gap:8px;font-size:13px;display:inline-flex}.t_j5va_field{flex-direction:column;gap:4px;font-size:12px;display:flex}.t_j5va_field input,.t_j5va_field select{border:1px solid var(--color-border,#444);color:inherit;background:0 0;border-radius:6px;padding:5px 8px;font-size:13px}.t_j5va_editorActions{justify-content:flex-end;gap:8px;margin-top:12px;display:flex}.t_j5va_editorActions button{border:1px solid var(--color-border,#444);color:inherit;cursor:pointer;background:0 0;border-radius:6px;padding:6px 12px;font-size:13px}.t_j5va_reportBox{border:1px solid #f5a52466;border-radius:8px;flex-direction:column;gap:2px;padding:8px 10px;font-size:12px;display:flex}.t_j5va_reportTitle{margin:0;font-weight:600}.t_j5va_reportLine{opacity:.8;margin:0}.t_j5va_reportSub{color:var(--dsh-color-text-2,#666);margin:2px 0 0 10px;font-size:12px}.t_j5va_trashButton{border:1px solid var(--color-border,#444);color:inherit;cursor:pointer;background:0 0;border-radius:6px;align-self:flex-start;padding:4px 8px;font-size:12px}.t_j5va_secretField{gap:4px;display:flex}.t_j5va_secretField input{flex:1;min-width:0}.t_j5va_revealButton{border:1px solid var(--color-border,#444);color:inherit;cursor:pointer;background:0 0;border-radius:6px;padding:0 8px;font-size:12px}.t_j5va_kindFilter{border:1px solid var(--color-border,#444);color:inherit;background:0 0;border-radius:6px;padding:6px 8px;font-size:13px}.t_j5va_highBadge{color:#e5484d;vertical-align:middle;background:#e5484d26;border-radius:4px;margin-left:6px;padding:1px 6px;font-size:10px;font-weight:600}.t_j5va_pinStar{color:#f5a524;margin-right:4px}.t_j5va_clearButton{color:inherit;cursor:pointer;opacity:.6;background:0 0;border:none;padding:0 8px;font-size:16px}.t_j5va_field textarea{border:1px solid var(--color-border,#444);color:inherit;resize:vertical;background:0 0;border-radius:6px;padding:5px 8px;font-family:inherit;font-size:13px}.t_j5va_row{transition:background .12s}.t_j5va_row:hover{background:var(--color-hover,#80808014)}.t_j5va_healthBar{flex-wrap:wrap;gap:6px;margin:0 0 10px;display:flex}.t_j5va_badge{border:1px solid var(--dsh-color-border,#ddd);background:var(--dsh-color-surface-2,#f7f7f8);color:var(--dsh-color-text-2,#555);border-radius:999px;padding:4px 10px;font-size:12px;line-height:1}.t_j5va_backupButton{border:1px solid var(--dsh-color-border,#ccc);background:var(--dsh-color-surface-2,#f7f7f8);cursor:pointer;border-radius:999px;align-self:flex-start;padding:4px 10px;font-size:12px;line-height:1}.t_j5va_badgeOk{color:#2e9e5b;border-color:#2e9e5b}.t_j5va_badgeWarn{color:#b57f1a;border-color:#c98a1b}.t_j5va_rowDue{border-left:3px solid #c98a1b}.t_j5va_rowExpired{border-left:3px solid #cf3d3d}.t_j5va_dueBadge{border-radius:999px;margin-left:6px;padding:3px 8px;font-size:11px;font-weight:600;line-height:1}.t_j5va_badgeDanger{color:#c03a3a;border-color:#cf3d3d}.t_j5va_footer{opacity:.6;margin:0;font-size:12px}.t_j5va_kindIcon{margin-right:4px;font-size:12px}.t_j5va_dangerButton{color:#e5484d;cursor:pointer;background:0 0;border:1px solid #e5484d80;border-radius:6px;align-self:flex-start;padding:4px 8px;font-size:12px}.t_j5va_rowMain{cursor:pointer}.t_j5va_detailBox{background:var(--color-hover,#8080800f);border-radius:6px;flex-wrap:wrap;grid-column:1/-1;gap:4px 12px;padding:6px 8px;font-size:12px;display:flex}.t_j5va_detailItem{opacity:.85}.t_j5va_sortButton{border:1px solid var(--color-border,#444);color:inherit;cursor:pointer;background:0 0;border-radius:6px;padding:6px 10px;font-size:13px}.t_j5va_dupGroup{justify-content:space-between;align-items:center;gap:8px;margin:4px 0;display:flex}.t_j5va_dupNames{text-overflow:ellipsis;white-space:nowrap;font-size:12px;overflow:hidden}.t_j5va_dupMerge{border:1px solid var(--dsh-color-border,#ccc);cursor:pointer;border-radius:6px;flex-shrink:0;padding:2px 8px;font-size:12px}.t_j5va_auditRow{align-items:center;gap:8px;margin:4px 0;display:flex}.t_j5va_auditIssues{color:var(--dsh-color-text-2,#666);text-overflow:ellipsis;white-space:nowrap;flex:1;font-size:12px;overflow:hidden}.t_j5va_retryButton{border:1px solid var(--dsh-color-border,#ccc);cursor:pointer;border-radius:6px;margin-left:6px;padding:2px 8px;font-size:12px}.t_j5va_scoreRing{vertical-align:-2px;margin-right:4px;display:inline-block}.t_j5va_genOpts{border:1px solid var(--dsh-color-border,#ddd);border-radius:8px;flex-direction:column;gap:6px;padding:8px 10px;display:flex}.t_j5va_genOptRow{justify-content:space-between;align-items:center;gap:8px;font-size:13px;display:flex}.t_j5va_genOptRow input[type=number]{width:64px}.t_j5va_pwMeter{align-items:center;gap:8px;font-size:12px;display:flex}.t_j5va_pwBar{border-radius:999px;height:6px;transition:width .2s}.t_j5va_pwWeak{background:#cf3d3d}.t_j5va_pwFair{background:#c98a1b}.t_j5va_pwStrong{background:#2e9e5b}.t_j5va_pwLabel{color:var(--dsh-color-text-2,#666)}.t_j5va_resultCount{color:var(--dsh-color-text-2,#666);flex-wrap:wrap;align-items:center;gap:6px;margin:0 0 6px;font-size:12px;display:flex}.t_j5va_kindChip{border:1px solid var(--dsh-color-border,#ddd);border-radius:999px;padding:2px 8px;font-size:11px}.t_j5va_uriCode{overflow-wrap:anywhere;opacity:.85;font-size:10px}.t_j5va_genHist{flex-wrap:wrap;gap:4px;font-size:12px;display:flex}.t_j5va_genHist span{align-self:center}.t_j5va_lockedTag{color:#c98a1b;font-size:12px;font-weight:600}.t_j5va_tabs{flex-wrap:wrap;gap:6px;margin:0 0 12px;display:flex}.t_j5va_tab{border:1px solid var(--dsh-color-border,#ccc);color:inherit;cursor:pointer;background:0 0;border-radius:999px;padding:5px 14px;font-size:13px}.t_j5va_tabActive{background:var(--dsh-color-primary,#4a6cf7);color:#fff;border-color:#0000}.t_j5va_tabPane{margin-top:2px}";
11
11
  const tagId = "dsh-vault/VaultSection.module.css";
12
12
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
13
13
  const tag = document.createElement("style");
@@ -17,89 +17,89 @@ window.__ModuleLoader__.load({
17
17
  document.head.appendChild(tag);
18
18
  }
19
19
  var VaultSection_module_css_default = {
20
- "field": "t_j5va_field",
21
- "rowExpired": "t_j5va_rowExpired",
20
+ "lockedBanner": "t_j5va_lockedBanner",
22
21
  "dupGroup": "t_j5va_dupGroup",
23
- "reportLine": "t_j5va_reportLine",
24
- "modeAuto": "t_j5va_modeAuto",
22
+ "reportBox": "t_j5va_reportBox",
23
+ "dangerButton": "t_j5va_dangerButton",
24
+ "dupMerge": "t_j5va_dupMerge",
25
+ "field": "t_j5va_field",
26
+ "revealButton": "t_j5va_revealButton",
27
+ "badgeWarn": "t_j5va_badgeWarn",
28
+ "genOptRow": "t_j5va_genOptRow",
29
+ "tabPane": "t_j5va_tabPane",
30
+ "identity": "t_j5va_identity",
31
+ "dupNames": "t_j5va_dupNames",
32
+ "srOnly": "t_j5va_srOnly",
25
33
  "rowDue": "t_j5va_rowDue",
26
- "scoreRing": "t_j5va_scoreRing",
27
- "kindChip": "t_j5va_kindChip",
28
- "genHist": "t_j5va_genHist",
29
- "secretField": "t_j5va_secretField",
30
- "searchBox": "t_j5va_searchBox",
31
- "pwLabel": "t_j5va_pwLabel",
32
- "editorActions": "t_j5va_editorActions",
33
- "lockedTag": "t_j5va_lockedTag",
34
+ "toolbar": "t_j5va_toolbar",
35
+ "detailItem": "t_j5va_detailItem",
36
+ "pwWeak": "t_j5va_pwWeak",
34
37
  "tabActive": "t_j5va_tabActive",
35
- "kindIcon": "t_j5va_kindIcon",
38
+ "modeAsk": "t_j5va_modeAsk",
39
+ "policyField": "t_j5va_policyField",
40
+ "modeAuto": "t_j5va_modeAuto",
36
41
  "list": "t_j5va_list",
37
- "detailItem": "t_j5va_detailItem",
38
42
  "retryButton": "t_j5va_retryButton",
39
- "genOpts": "t_j5va_genOpts",
40
- "modeReadonly": "t_j5va_modeReadonly",
41
- "tabPane": "t_j5va_tabPane",
42
- "lockedBanner": "t_j5va_lockedBanner",
43
- "rowMain": "t_j5va_rowMain",
43
+ "tabs": "t_j5va_tabs",
44
+ "emptyBox": "t_j5va_emptyBox",
45
+ "detailBox": "t_j5va_detailBox",
46
+ "searchBox": "t_j5va_searchBox",
44
47
  "status": "t_j5va_status",
45
- "totpRing": "t_j5va_totpRing",
46
- "pinStar": "t_j5va_pinStar",
47
- "auditIssues": "t_j5va_auditIssues",
48
+ "reportSub": "t_j5va_reportSub",
49
+ "kindFilter": "t_j5va_kindFilter",
50
+ "backupButton": "t_j5va_backupButton",
51
+ "pwBar": "t_j5va_pwBar",
52
+ "pwFair": "t_j5va_pwFair",
53
+ "rowMain": "t_j5va_rowMain",
54
+ "kindChip": "t_j5va_kindChip",
48
55
  "error": "t_j5va_error",
49
- "genOptRow": "t_j5va_genOptRow",
50
- "auditRow": "t_j5va_auditRow",
56
+ "saveButton": "t_j5va_saveButton",
51
57
  "editor": "t_j5va_editor",
52
- "resultCount": "t_j5va_resultCount",
53
- "pwStrong": "t_j5va_pwStrong",
54
- "dupMerge": "t_j5va_dupMerge",
55
- "toolbar": "t_j5va_toolbar",
56
- "reportTitle": "t_j5va_reportTitle",
58
+ "policyBar": "t_j5va_policyBar",
59
+ "trashButton": "t_j5va_trashButton",
60
+ "scoreRing": "t_j5va_scoreRing",
61
+ "footer": "t_j5va_footer",
62
+ "reportLine": "t_j5va_reportLine",
57
63
  "copied": "t_j5va_copied",
58
- "intro": "t_j5va_intro",
59
- "uriCode": "t_j5va_uriCode",
60
- "checkField": "t_j5va_checkField",
61
- "reportSub": "t_j5va_reportSub",
62
- "revealButton": "t_j5va_revealButton",
63
- "pwMeter": "t_j5va_pwMeter",
64
- "reportBox": "t_j5va_reportBox",
64
+ "rowActions": "t_j5va_rowActions",
65
+ "deleteButton": "t_j5va_deleteButton",
66
+ "auditRow": "t_j5va_auditRow",
67
+ "genHist": "t_j5va_genHist",
68
+ "healthBar": "t_j5va_healthBar",
69
+ "genOpts": "t_j5va_genOpts",
70
+ "totpRing": "t_j5va_totpRing",
71
+ "clearButton": "t_j5va_clearButton",
65
72
  "badgeDanger": "t_j5va_badgeDanger",
73
+ "badge": "t_j5va_badge",
74
+ "pwStrong": "t_j5va_pwStrong",
66
75
  "row": "t_j5va_row",
67
- "kindFilter": "t_j5va_kindFilter",
68
- "pwWeak": "t_j5va_pwWeak",
69
- "highBadge": "t_j5va_highBadge",
70
- "srOnly": "t_j5va_srOnly",
71
- "modeAsk": "t_j5va_modeAsk",
72
- "backupButton": "t_j5va_backupButton",
73
- "clearButton": "t_j5va_clearButton",
74
- "badgeWarn": "t_j5va_badgeWarn",
75
- "healthBar": "t_j5va_healthBar",
76
- "policyBar": "t_j5va_policyBar",
77
- "tab": "t_j5va_tab",
78
76
  "title": "t_j5va_title",
79
- "policyField": "t_j5va_policyField",
77
+ "checkField": "t_j5va_checkField",
78
+ "pwMeter": "t_j5va_pwMeter",
79
+ "lockedTag": "t_j5va_lockedTag",
80
+ "auditIssues": "t_j5va_auditIssues",
80
81
  "badgeOk": "t_j5va_badgeOk",
81
- "totp": "t_j5va_totp",
82
- "sortButton": "t_j5va_sortButton",
83
- "section": "t_j5va_section",
84
- "badge": "t_j5va_badge",
85
- "saveButton": "t_j5va_saveButton",
86
- "empty": "t_j5va_empty",
87
- "pwFair": "t_j5va_pwFair",
88
- "rowActions": "t_j5va_rowActions",
89
- "pwBar": "t_j5va_pwBar",
90
- "dueBadge": "t_j5va_dueBadge",
91
- "detailBox": "t_j5va_detailBox",
92
- "trashButton": "t_j5va_trashButton",
93
- "footer": "t_j5va_footer",
94
- "emptyBox": "t_j5va_emptyBox",
95
- "dangerButton": "t_j5va_dangerButton",
82
+ "pinStar": "t_j5va_pinStar",
83
+ "resultCount": "t_j5va_resultCount",
84
+ "modeReadonly": "t_j5va_modeReadonly",
85
+ "intro": "t_j5va_intro",
86
+ "highBadge": "t_j5va_highBadge",
96
87
  "editorBody": "t_j5va_editorBody",
97
- "addButton": "t_j5va_addButton",
88
+ "empty": "t_j5va_empty",
89
+ "sortButton": "t_j5va_sortButton",
98
90
  "emptyHint": "t_j5va_emptyHint",
99
- "identity": "t_j5va_identity",
100
- "deleteButton": "t_j5va_deleteButton",
101
- "dupNames": "t_j5va_dupNames",
102
- "tabs": "t_j5va_tabs"
91
+ "editorActions": "t_j5va_editorActions",
92
+ "addButton": "t_j5va_addButton",
93
+ "totp": "t_j5va_totp",
94
+ "reportTitle": "t_j5va_reportTitle",
95
+ "secretField": "t_j5va_secretField",
96
+ "dueBadge": "t_j5va_dueBadge",
97
+ "kindIcon": "t_j5va_kindIcon",
98
+ "rowExpired": "t_j5va_rowExpired",
99
+ "section": "t_j5va_section",
100
+ "pwLabel": "t_j5va_pwLabel",
101
+ "uriCode": "t_j5va_uriCode",
102
+ "tab": "t_j5va_tab"
103
103
  };
104
104
  //#endregion
105
105
  //#region src/client/VaultSection.tsx
@@ -250,7 +250,7 @@ window.__ModuleLoader__.load({
250
250
  }
251
251
  /** Render the Vault settings section. */
252
252
  function VaultSection(props) {
253
- const { t, config, setAccessMode, setAutoCapture, list, search, get, add, update, remove, trash, rotation, health, duplicates, duplicateGroups, merge, history, stats, backupStatus, backup, recent, restore, undeleteAll, totp, status, switchVault, listVaults, touch, verifyAll, breachCheck, generatePassword, strength, generateUsername, templates, saveTemplate, lock, totpUri, tags, renameTag, generatorHistory, backups, restoreBackup, importChrome, importFirefox, import1password, importManagerCsv, importEnpass, importBitwarden, import1pif, importKeePassXml, importKdbx, importBitwardenEncrypted, keychainImport, searchSystem, sessionOpen, sessionCollect, sessionClose, sessionListOpen, sessionListSaved, sessionSave, sessionExport, sessionGet, sessionPrune } = props;
253
+ const { t, config, setAccessMode, setAutoCapture, list, search, get, add, update, remove, trash, rotation, health, duplicates, duplicateGroups, merge, history, stats, backupStatus, backup, recent, restore, undeleteAll, totp, status, switchVault, listVaults, touch, verifyAll, breachCheck, generatePassword, strength, generateUsername, templates, saveTemplate, lock, totpUri, tags, renameTag, generatorHistory, backups, deleteBackup, restoreBackup, importChrome, importFirefox, import1password, importManagerCsv, importEnpass, importBitwarden, import1pif, importKeePassXml, importKdbx, importBitwardenEncrypted, keychainImport, searchSystem, sessionOpen, sessionCollect, sessionClose, sessionListOpen, sessionListSaved, sessionSave, sessionExport, sessionGet, sessionPrune, vaultRename, vaultDelete } = props;
254
254
  const searchId = (0, react.useId)();
255
255
  const [query, setQuery] = (0, react.useState)("");
256
256
  const [state, setState] = (0, react.useState)({ status: "loading" });
@@ -416,6 +416,58 @@ window.__ModuleLoader__.load({
416
416
  setBusy(false);
417
417
  }
418
418
  }
419
+ /** Delete one backup file (confirms first). */
420
+ async function deleteBackupFile(b) {
421
+ if (!window.confirm(t("backupDeleteConfirm"))) return;
422
+ setBusy(true);
423
+ setMessage(null);
424
+ try {
425
+ await deleteBackup(b.path);
426
+ setMessage(t("backupDeleted"));
427
+ backups(20).then(setBackupList).catch(() => {});
428
+ } catch {
429
+ setMessage(t("error"));
430
+ } finally {
431
+ setBusy(false);
432
+ }
433
+ }
434
+ /** Rename the active (or picked) vault. */
435
+ async function runVaultRename() {
436
+ const current = vaults.find((v) => v.active)?.name ?? "default";
437
+ const target = window.prompt(`${t("vaultRenamePrompt")} (${current})`);
438
+ if (target === null || target.trim() === "" || target.trim() === current) return;
439
+ setBusy(true);
440
+ setMessage(null);
441
+ try {
442
+ setMessage((await vaultRename(current, target.trim())).note);
443
+ await listVaults().then(setVaults);
444
+ refresh();
445
+ } catch {
446
+ setMessage(t("error"));
447
+ } finally {
448
+ setBusy(false);
449
+ }
450
+ }
451
+ /** Delete a picked vault (confirms first; default vault cannot be deleted). */
452
+ async function runVaultDelete(name) {
453
+ if (name === "default") {
454
+ setMessage(t("vaultDeleteDefault"));
455
+ return;
456
+ }
457
+ if (!window.confirm(t("vaultDeleteConfirm").replace("{name}", name))) return;
458
+ setBusy(true);
459
+ setMessage(null);
460
+ try {
461
+ setMessage((await vaultDelete(name, true)).note);
462
+ await listVaults().then(setVaults);
463
+ backups(20).then(setBackupList).catch(() => {});
464
+ refresh();
465
+ } catch {
466
+ setMessage(t("error"));
467
+ } finally {
468
+ setBusy(false);
469
+ }
470
+ }
419
471
  /** Import from Firefox (prompts for the primary password when one is set). */
420
472
  async function runFirefoxImport() {
421
473
  const mp = window.prompt(t("firefoxMasterPw"));
@@ -689,11 +741,12 @@ window.__ModuleLoader__.load({
689
741
  }
690
742
  /** Restore the vault from a backup file (asks for confirmation first). */
691
743
  async function restoreBackupFrom(b) {
692
- if (!window.confirm(t("backupRestoreConfirm"))) return;
744
+ const mode = window.confirm(t("backupRestoreModeMerge")) ? "merge" : window.confirm(t("backupRestoreModeReplace")) ? "replace" : null;
745
+ if (mode === null) return;
693
746
  setBusy(true);
694
747
  setMessage(null);
695
748
  try {
696
- const result = await restoreBackup(b.path);
749
+ const result = await restoreBackup(b.path, mode);
697
750
  setMessage(result.note);
698
751
  setBackupInfo(null);
699
752
  backups(20).then(setBackupList).catch(() => {});
@@ -1323,6 +1376,26 @@ window.__ModuleLoader__.load({
1323
1376
  ]
1324
1377
  }, v.name))
1325
1378
  }),
1379
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1380
+ type: "button",
1381
+ className: VaultSection_module_css_default.dupMerge,
1382
+ onClick: () => void runVaultRename(),
1383
+ disabled: busy || locked,
1384
+ title: t("vaultRename"),
1385
+ children: t("vaultRename")
1386
+ }),
1387
+ vaults.filter((v) => v.name !== "default").map((v) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
1388
+ type: "button",
1389
+ className: VaultSection_module_css_default.dangerButton,
1390
+ onClick: () => void runVaultDelete(v.name),
1391
+ disabled: busy || locked,
1392
+ title: t("vaultDelete"),
1393
+ children: [
1394
+ t("vaultDelete"),
1395
+ " ",
1396
+ v.name
1397
+ ]
1398
+ }, v.name)),
1326
1399
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1327
1400
  className: VaultSection_module_css_default.searchBox,
1328
1401
  children: [
@@ -1890,17 +1963,28 @@ window.__ModuleLoader__.load({
1890
1963
  ]
1891
1964
  }), backupList.map((b) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1892
1965
  className: VaultSection_module_css_default.dupGroup,
1893
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1894
- className: VaultSection_module_css_default.dupNames,
1895
- children: new Date(b.at).toLocaleString()
1896
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1897
- type: "button",
1898
- className: VaultSection_module_css_default.dupMerge,
1899
- onClick: () => void restoreBackupFrom(b),
1900
- disabled: busy || readonly || locked,
1901
- title: t("backupRestoreHint"),
1902
- children: t("backupRestore")
1903
- })]
1966
+ children: [
1967
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1968
+ className: VaultSection_module_css_default.dupNames,
1969
+ children: [b.vaultName !== "" ? `${b.vaultName} · ` : "", new Date(b.at).toLocaleString()]
1970
+ }),
1971
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1972
+ type: "button",
1973
+ className: VaultSection_module_css_default.dupMerge,
1974
+ onClick: () => void restoreBackupFrom(b),
1975
+ disabled: busy || readonly || locked,
1976
+ title: t("backupRestoreHint"),
1977
+ children: t("backupRestore")
1978
+ }),
1979
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1980
+ type: "button",
1981
+ className: VaultSection_module_css_default.dangerButton,
1982
+ onClick: () => void deleteBackupFile(b),
1983
+ disabled: busy || readonly || locked,
1984
+ title: t("backupDelete"),
1985
+ children: t("backupDelete")
1986
+ })
1987
+ ]
1904
1988
  }, b.path))]
1905
1989
  }),
1906
1990
  backupList.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
@@ -3126,6 +3210,11 @@ window.__ModuleLoader__.load({
3126
3210
  backupDone: "Backup created",
3127
3211
  lockedBanner: "Vault is locked — unlock it with vault_unlock to read or write entries.",
3128
3212
  vaultSelect: "Active vault",
3213
+ vaultRename: "Rename vault",
3214
+ vaultRenamePrompt: "New name for the vault",
3215
+ vaultDelete: "Delete",
3216
+ vaultDeleteConfirm: "Permanently delete vault \"{name}\"? This cannot be undone.",
3217
+ vaultDeleteDefault: "The default vault cannot be deleted.",
3129
3218
  touch: "Used",
3130
3219
  touchHint: "Mark as recently used",
3131
3220
  auditTitle: "Needs attention",
@@ -3182,6 +3271,11 @@ window.__ModuleLoader__.load({
3182
3271
  backupRestore: "Restore",
3183
3272
  backupRestoreHint: "Restore the vault from this backup",
3184
3273
  backupRestoreConfirm: "Restore the vault from this backup? The current vault is snapshotted first, then replaced.",
3274
+ backupRestoreModeMerge: "Merge this backup into the current vault (entries are copied in, existing same-title entries are kept)? OK = merge. Cancel = replace the whole vault.",
3275
+ backupRestoreModeReplace: "Replace the WHOLE vault with this backup? A safety snapshot is written first.",
3276
+ backupDelete: "Delete",
3277
+ backupDeleteConfirm: "Delete this backup file permanently?",
3278
+ backupDeleted: "Backup deleted.",
3185
3279
  backupSafetyHint: "Pre-restore snapshot saved to",
3186
3280
  noBackups: "No backups yet — create one with \"Backup now\".",
3187
3281
  permTitle: "Access permissions & capture",
@@ -3384,6 +3478,11 @@ window.__ModuleLoader__.load({
3384
3478
  backupDone: "备份已创建",
3385
3479
  lockedBanner: "保险库已锁定 —— 请使用 vault_unlock 解锁后再读写条目。",
3386
3480
  vaultSelect: "当前保险库",
3481
+ vaultRename: "重命名保险库",
3482
+ vaultRenamePrompt: "保险库的新名称",
3483
+ vaultDelete: "删除",
3484
+ vaultDeleteConfirm: "永久删除保险库 \"{name}\"?此操作无法撤销。",
3485
+ vaultDeleteDefault: "默认保险库不能被删除。",
3387
3486
  touch: "标记已用",
3388
3487
  touchHint: "标记为最近使用",
3389
3488
  auditTitle: "需要处理",
@@ -3440,6 +3539,11 @@ window.__ModuleLoader__.load({
3440
3539
  backupRestore: "还原",
3441
3540
  backupRestoreHint: "用该备份还原密码库",
3442
3541
  backupRestoreConfirm: "确定用该备份还原密码库?当前状态会先快照,再被替换。",
3542
+ backupRestoreModeMerge: "将该备份合并进当前密码库(条目被复制进来,同标题条目保留)?确定=合并。取消=整体替换密码库。",
3543
+ backupRestoreModeReplace: "用该备份整体替换当前密码库?会先写一份安全快照。",
3544
+ backupDelete: "删除",
3545
+ backupDeleteConfirm: "永久删除这个备份文件?",
3546
+ backupDeleted: "备份已删除。",
3443
3547
  backupSafetyHint: "还原前快照已保存到",
3444
3548
  noBackups: "暂无备份 — 用“立即备份”创建。",
3445
3549
  permTitle: "访问权限与自动捕获",
@@ -3672,13 +3776,18 @@ window.__ModuleLoader__.load({
3672
3776
  }),
3673
3777
  generatorHistory: () => invoke("generatorHistory"),
3674
3778
  backups: (limit) => invoke("backups", { limit: limit ?? 5 }),
3675
- restoreBackup: (path) => invoke("restoreBackup", { path }),
3779
+ deleteBackup: (path) => invoke("deleteBackup", { path }),
3780
+ restoreBackup: (path, mode, overwrite) => invoke("restoreBackup", {
3781
+ path,
3782
+ mode: mode ?? "merge",
3783
+ overwrite: overwrite ?? false
3784
+ }),
3676
3785
  importChrome: (overwrite) => invoke("importChrome", { overwrite: overwrite ?? false }),
3677
3786
  importFirefox: (masterPassword, overwrite) => invoke("importFirefox", {
3678
3787
  masterPassword: masterPassword ?? "",
3679
3788
  overwrite: overwrite ?? false
3680
3789
  }),
3681
- keychainImport: (options) => invoke("keychainImport", { ...options ?? {} }),
3790
+ keychainImport: (options) => invoke("keychainImport", { options: options ?? {} }),
3682
3791
  import1password: (path, overwrite, dryRun) => invoke("import1password", {
3683
3792
  path,
3684
3793
  overwrite: overwrite ?? false,
@@ -3729,7 +3838,7 @@ window.__ModuleLoader__.load({
3729
3838
  }),
3730
3839
  verifyAll: () => invoke("verifyAll"),
3731
3840
  breachCheck: (online) => invoke("breachCheck", { online: online ?? true }),
3732
- generatePassword: (options) => invoke("generatePassword", { ...options ?? {} }),
3841
+ generatePassword: (options) => invoke("generatePassword", { options: options ?? {} }),
3733
3842
  strength: (password) => invoke("strength", { password }),
3734
3843
  templates: () => invoke("templates"),
3735
3844
  saveTemplate: (name, kind, fields) => invoke("saveTemplate", {
@@ -3755,7 +3864,7 @@ window.__ModuleLoader__.load({
3755
3864
  sessionClose: (sessionId) => invoke("sessionClose", { sessionId }),
3756
3865
  sessionListOpen: () => invoke("sessionListOpen"),
3757
3866
  sessionListSaved: () => invoke("sessionListSaved"),
3758
- sessionSave: (options) => invoke("sessionSave", { ...options ?? {} }),
3867
+ sessionSave: (options) => invoke("sessionSave", { options: options ?? {} }),
3759
3868
  sessionExport: (id, format) => invoke("sessionExport", {
3760
3869
  id,
3761
3870
  format: format ?? "header"
@@ -3764,6 +3873,14 @@ window.__ModuleLoader__.load({
3764
3873
  sessionPrune: (id, preview) => invoke("sessionPrune", {
3765
3874
  id,
3766
3875
  preview: preview ?? false
3876
+ }),
3877
+ vaultRename: (from, to) => invoke("vaultRename", {
3878
+ from,
3879
+ to
3880
+ }),
3881
+ vaultDelete: (name, confirm) => invoke("vaultDelete", {
3882
+ name,
3883
+ confirm
3767
3884
  })
3768
3885
  });
3769
3886
  ctx.slots.inject("settings.section", () => ctx.slots.register({