dsh-mask 0.1.1

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 ADDED
@@ -0,0 +1,188 @@
1
+ <div align="center">
2
+
3
+ # dsh-mask
4
+
5
+ **PII masking middleware for DeepSeek Harness — anonymize personal data before it reaches the model, restore it at the display layer.**
6
+
7
+ *Phones, emails, ID cards, bank cards, keys, and more become placeholders at the model boundary; the plaintext never enters your session log.*
8
+
9
+ [![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](LICENSE)
10
+ [![DSH plugin](https://img.shields.io/badge/dsh-plugin-✅-green)](https://github.com/topics/dsh-plugin)
11
+ [![Node](https://img.shields.io/badge/node-%5E22.19%20%7C%7C%20%3E%3D24-brightgreen.svg)](#)
12
+ [![CI](https://img.shields.io/github/actions/workflow/status/PerryLink/dsh-mask/ci.yml?branch=main&label=CI)](https://github.com/PerryLink/dsh-mask/actions)
13
+ [![Version](https://img.shields.io/github/v/tag/PerryLink/dsh-mask?label=version)](https://github.com/PerryLink/dsh-mask/releases)
14
+ [![npm version](https://img.shields.io/npm/v/dsh-mask)](https://www.npmjs.com/package/dsh-mask)
15
+ [![npm downloads](https://img.shields.io/npm/dm/dsh-mask)](https://www.npmjs.com/package/dsh-mask)
16
+
17
+ [English](README.md) · [简体中文](README.zh.md) · [Español](README.es.md) · [Português](README.pt.md) · [हिन्दी](README.hi.md)
18
+
19
+ </div>
20
+
21
+ ---
22
+
23
+ ## Compatibility
24
+
25
+ | Surface | Status |
26
+ |---|---|
27
+ | Harness | DeepSeek Harness `0.1.0-rc.6` |
28
+ | Node | `^22.19.0 \|\| >=24.0.0` |
29
+ | Platforms | Anywhere DSH runs (pure host, zero-dependency regex; no browser half) |
30
+ | Model | Text models fully supported; no extra model capability required |
31
+
32
+ ## What you get
33
+
34
+ `dsh-mask` anonymizes personal data **at the model boundary** — before a message reaches the model — and keeps a restore table so placeholders can be mapped back to the originals at the display layer:
35
+
36
+ - **Request-time masking** — `agent/pre-step` messages are rewritten so phones, emails, ID cards, bank cards, keys, and IPs (each opt-in) become `<PHONE_1>`-style placeholders. The masked text is what gets logged and sent to the model.
37
+ - **Restore table** — the `placeholder → original` map lives only in memory and a controlled storage domain (`dsh_mask`); the plaintext never enters the session log.
38
+ - **Audit, not plaintext** — the `mask/applied` session event records only "replaced N values + type distribution", never the original text or the mapping.
39
+ - **`/mask` command** — `status` (counts + distribution), `on`/`off` (runtime toggle), `restore <text>` (unmap placeholders), `help`.
40
+ - **`mask_test` tool** — run a snippet through the detector and see the placeholder result; it never reveals the original values.
41
+
42
+ ```text
43
+ user message ──agent/pre-step──▶ placeholders ──model──▶ placeholders ──restore──▶ display
44
+ ▲ │
45
+ └──────── restore table (memory + dsh_mask) ────────┘
46
+ ```
47
+
48
+ ## Quick start
49
+
50
+ ```sh
51
+ # 1. install the bundle into your profile
52
+ dsh plugin --profile web add "github:PerryLink/dsh-mask#main"
53
+
54
+ # or from npm (published releases)
55
+ dsh plugin --profile web add dsh-mask
56
+
57
+ # 2. verify the row mounts
58
+ dsh --profile web --dump-config | grep -A2 'id: mask'
59
+ ```
60
+
61
+ Then tailor the entity list in your profile patch:
62
+
63
+ ```yaml
64
+ - insert:
65
+ - id: mask
66
+ name: dsh-mask
67
+ config:
68
+ entities: [phone, email, id-card, bank-card, key]
69
+ ```
70
+
71
+ ```
72
+ > /mask status
73
+ > /mask restore <PHONE_1>
74
+ ```
75
+
76
+ ## Install & uninstall
77
+
78
+ - **git channel** (latest `main`): `dsh plugin --profile web add "github:PerryLink/dsh-mask#main"` (equivalent to installing from `git+https://github.com/PerryLink/dsh-mask.git`). No build step — `index.mjs` and `lib/` are the shipped artifacts.
79
+ - **npm channel** (published releases): `dsh plugin --profile web add dsh-mask`.
80
+ - **tarball channel**: `pnpm pack` in this repo, then `dsh plugin --profile web add ./dsh-mask-<version>.tgz`.
81
+ - **uninstall**: `dsh plugin --profile web remove dsh-mask` (or remove the row from the profile patch).
82
+
83
+ ## Configuration
84
+
85
+ All tunables are Schemastery `Config` fields (changeable from cordis.yml). An id-targeted override replaces the whole row — restate every key you need. `cordis.patch.yml` documents each key inline.
86
+
87
+ | Key | Default | Meaning |
88
+ |---|---|---|
89
+ | `enabled` | `true` | Master switch; `false` unregisters the listener, the `/mask` command, and the `mask_test` tool |
90
+ | `mode` | `regex` | Detection mode; only `regex` is implemented (`regex+ner` for name/address recognition is reserved and fails loud) |
91
+ | `entities` | `[phone, email, id-card, bank-card, key]` | Which PII types to mask; `ip` is also regex-capable (opt-in), `person`/`address` require NER |
92
+ | `scope` | `messages` | Masking surface; only `messages` (agent messages) is implemented (`tools` argument masking is reserved) |
93
+ | `registerCommand` | `true` | Register the `/mask` command |
94
+ | `registerTools` | `true` | Register the `mask_test` tool when the tools service is present |
95
+ | `persistRestoreTable` | `true` | Persist the restore table to the controlled `dsh_mask` storage domain (`false` = memory only) |
96
+ | `maxRestoreEntriesPerSession` | `500` | Per-session restore entry cap (oldest evicted first) |
97
+ | `maxSessions` | `1000` | In-memory session cap (least-recently-used evicted, mapping reloaded on demand) |
98
+
99
+ Example override in your profile patch:
100
+
101
+ ```yaml
102
+ - insert:
103
+ - id: mask
104
+ name: dsh-mask
105
+ config:
106
+ entities: [phone, email, id-card, bank-card, key, ip]
107
+ persistRestoreTable: false
108
+ registerCommand: true
109
+ ```
110
+
111
+ ## Tools & surfaces
112
+
113
+ | Surface | Reveals plaintext | Notes |
114
+ |---|---|---|
115
+ | `agent/pre-step` masking | never | Rewrites messages to placeholders before they are logged or sent to the model |
116
+ | `/mask status` | never | Enabled state, total replaced, type distribution |
117
+ | `/mask on` / `/mask off` | never | Runtime toggle (resets to `config.enabled` on restart) |
118
+ | `/mask restore <text>` | yes (explicit) | Unmaps placeholders back to the values stored for this session |
119
+ | `mask_test` | never | Masks a snippet and reports the placeholder result + counts |
120
+
121
+ ## Permissions & data
122
+
123
+ - **Permissions**: `dsh-mask` performs no network requests and stores no credentials; it only reads the session at the `agent/pre-step` boundary and writes its own `dsh_mask` storage domain. The `dshWorkshop` manifest declares `network:none` and `credentials:none`.
124
+ - **Data**: the `placeholder → original` restore table lives in memory and, when `persistRestoreTable: true`, in the controlled `dsh_mask` storage domain — this is the only place plaintext PII is stored, and it is never written to the session log.
125
+ - **Session log**: `mask/applied` is declared in `types.d.ts` and appended only when the host records the type (see Known limitations). Its payload is counts + type distribution only.
126
+
127
+ ## Security boundaries
128
+
129
+ - **Plaintext never enters the session log.** The masked (placeholder) form is what gets logged and sent to the model, so model-visible content is reconstructable from the log in placeholder form; the originals stay in the restore table.
130
+ - **Sanitize before display/log.** `lib/sanitize.mjs` redacts PII, secrets, and URL credentials before any text reaches the model or the log; `mask_test` and `/mask status` never echo originals.
131
+ - **Controlled restore.** `/mask restore` is the single explicit reveal surface, and it only reads the mapping for the active session.
132
+ - **Fail closed.** Unimplemented `mode` (`regex+ner`), `scope` (`tools`), NER-only entities, and out-of-bounds numbers all fail loudly at load.
133
+ - **Registrations are effects.** The listener, command, tool, and storage-domain close are all Cordis effects — stop/hot-reload removes them.
134
+
135
+ ## Known limitations
136
+
137
+ - **Regex only.** Name (`person`) and address (`address`) recognition needs an external NER recognizer, which the pure-host zero-dependency form does not bundle; `mode: regex+ner` and those entities fail loudly at load. The PII types covered out of the box are phone, email, ID card, bank card, key, and (opt-in) IP.
138
+ - **Display-layer restore needs a client half.** Masking is fully host-side, but transparently un-masking the assistant bubbles in the client UI is a browser-half feature this pure-host form does not ship; the restore table and `restore()` are the complete host-side seam a client plugin would consume, and `/mask restore` covers interactive needs today.
139
+ - **Session events on `0.1.0-rc.6`.** The harness does not yet record `mask/*` event types, so on rc.6 the session-log audit appends are skipped (sessions keep loading); the plugin enables them automatically once a host records the types or supports the `ignorable` envelope.
140
+
141
+ ## Development
142
+
143
+ ```sh
144
+ pnpm install # node ^22.19 || >=24
145
+ pnpm run typecheck && pnpm run typecheck:ci # tsc --checkJs against the published rc.6 peers
146
+ pnpm test # node --test
147
+ pnpm run verify:self-contained # dependency specs resolve from the registry
148
+ pnpm run verify:artifacts # shipped files present + index.mjs importable
149
+ pnpm run check:readmes # five-language README consistency
150
+ pnpm pack # the published tarball
151
+ ```
152
+
153
+ There is no build step: pure ESM, `index.mjs` and `lib/` are the shipped artifacts.
154
+
155
+ ## Topics
156
+
157
+ `dsh`, `dsh-plugin`, `deepseek-harness`, `deepseek`, `cordis`, `pii`, `mask`, `privacy`, `anonymization`, `security`
158
+
159
+ ## Contributors
160
+
161
+ - [@PerryLink](https://github.com/PerryLink) — creator and maintainer: the regex PII detector ported from Pii-Stripper-Middleware, the `agent/pre-step` masking seam, the restore table, the `/mask` command and `mask_test` tool, and the five-language docs.
162
+
163
+ ## PerryLink DSH Plugin Family
164
+
165
+ This project is one of the [DeepSeek Harness plugins](https://github.com/PerryLink) maintained by [PerryLink](https://github.com/PerryLink). If this one helps you, the others likely will too:
166
+
167
+ | Plugin | One-liner |
168
+ |---|---|
169
+ | **[dsh-mask](https://github.com/PerryLink/dsh-mask)** | PII masking middleware: anonymize at the model boundary, restore at the display layer |
170
+ | [dsh-mcp-panel](https://github.com/PerryLink/dsh-mcp-panel) | Read-only MCP runtime panel: /mcp command + Settings tab with status, tools and errors |
171
+ | [dsh-doublecheck](https://github.com/PerryLink/dsh-doublecheck) | Engineering-discipline guard: requirements grill, test gates, adversary review |
172
+ | [dsh-background-agents](https://github.com/PerryLink/dsh-background-agents) | Durable background child agents with a Web UI sidebar, messaging and interrupt |
173
+ | [dsh-lsp-actions](https://github.com/PerryLink/dsh-lsp-actions) | LSP diagnostics, formatting, completion, code actions and rename over language servers |
174
+ | [dsh-output-styles](https://github.com/PerryLink/dsh-output-styles) | Claude Code outputStyles-equivalent runtime style switching |
175
+ | [dsh-checkpoint-rewind](https://github.com/PerryLink/dsh-checkpoint-rewind) | Claude Code /rewind-equivalent: snapshots, session forks, one-shot restore |
176
+ | [dsh-permission-rules](https://github.com/PerryLink/dsh-permission-rules) | Claude Code-style declarative allow/deny/ask permission rules with audit |
177
+ | [dsh-auto-review](https://github.com/PerryLink/dsh-auto-review) | Second-model auto-review on the approval chain, fail-closed by default |
178
+ | [dsh-memento](https://github.com/PerryLink/dsh-memento) | Approval-gated cross-session memory: ctx.memory seam + SQLite + memory tool |
179
+ | [dsh-skill-pack-security](https://github.com/PerryLink/dsh-skill-pack-security) | Security-audit skill pack: secret scan, dependency and supply-chain review |
180
+ | [dsh-session-pin](https://github.com/PerryLink/dsh-session-pin) | Pin sessions in the Web sidebar with durable ordering |
181
+ | [dsh-composer-history](https://github.com/PerryLink/dsh-composer-history) | Terminal-style input history for the web composer: arrows, Ctrl+R search |
182
+ | [dsh-github](https://github.com/PerryLink/dsh-github) | GitHub PR/issues integration for DSH, every write gated by approval |
183
+ | [dsh-plugin-guide](https://github.com/PerryLink/dsh-plugin-guide) | Plugin-development knowledge base as an on-demand agent skill |
184
+ | [dsh-claude-move](https://github.com/PerryLink/dsh-claude-move) | Migrate Claude Code sessions, memory, skills and CLAUDE.md into DSH |
185
+
186
+ ## License
187
+
188
+ [LICENSE](LICENSE) (Apache License 2.0) © 2026 dsh-mask contributors
package/README.pt.md ADDED
@@ -0,0 +1,170 @@
1
+ <div align="center">
2
+
3
+ # dsh-mask
4
+
5
+ **Middleware de mascaramento de PII para o DeepSeek Harness: anonimize dados pessoais antes que cheguem ao modelo e restaure-os na camada de exibição.**
6
+
7
+ *Telefones, e-mails, documentos, cartões, chaves e mais viram marcadores no limite do modelo; o texto simples nunca entra no seu registro de sessão.*
8
+
9
+ [![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](LICENSE)
10
+ [![DSH plugin](https://img.shields.io/badge/dsh-plugin-✅-green)](https://github.com/topics/dsh-plugin)
11
+ [![Node](https://img.shields.io/badge/node-%5E22.19%20%7C%7C%20%3E%3D24-brightgreen.svg)](#)
12
+ [![CI](https://img.shields.io/github/actions/workflow/status/PerryLink/dsh-mask/ci.yml?branch=main&label=CI)](https://github.com/PerryLink/dsh-mask/actions)
13
+ [![Version](https://img.shields.io/github/v/tag/PerryLink/dsh-mask?label=version)](https://github.com/PerryLink/dsh-mask/releases)
14
+ [![npm version](https://img.shields.io/npm/v/dsh-mask)](https://www.npmjs.com/package/dsh-mask)
15
+ [![npm downloads](https://img.shields.io/npm/dm/dsh-mask)](https://www.npmjs.com/package/dsh-mask)
16
+
17
+ [English](README.md) · [简体中文](README.zh.md) · [Español](README.es.md) · [Português](README.pt.md) · [हिन्दी](README.hi.md)
18
+
19
+ </div>
20
+
21
+ ---
22
+
23
+ ## Compatibility
24
+
25
+ | Superfície | Estado |
26
+ |---|---|
27
+ | Harness | DeepSeek Harness `0.1.0-rc.6` |
28
+ | Node | `^22.19.0 \|\| >=24.0.0` |
29
+ | Plataformas | Onde o DSH rodar (host puro, regex sem dependências; sem metade de navegador) |
30
+ | Modelo | Modelos de texto totalmente suportados |
31
+
32
+ ## What you get
33
+
34
+ O `dsh-mask` anonimiza dados pessoais **no limite do modelo** e mantém uma tabela de restauração:
35
+
36
+ - **Mascaramento antes da requisição** — reescreve mensagens de `agent/pre-step` para que telefones, e-mails, documentos, cartões, chaves e IPs (opt-in) virem marcadores como `<PHONE_1>`. O texto mascarado é o que é registrado e enviado ao modelo.
37
+ - **Tabela de restauração** — o mapa `marcador → original` vive só em memória e num domínio de armazenamento controlado (`dsh_mask`); o texto simples nunca entra no registro de sessão.
38
+ - **Auditoria sem texto simples** — o evento `mask/applied` registra apenas «N valores substituídos + distribuição por tipo».
39
+ - **Comando `/mask`** — `status`, `on`/`off`, `restore <text>`, `help`.
40
+ - **Ferramenta `mask_test`** — teste um trecho e veja o resultado com marcadores; nunca revela os originais.
41
+
42
+ ```text
43
+ mensagem do usuário ──agent/pre-step──▶ marcadores ──modelo──▶ marcadores ──restore──▶ tela
44
+ ▲ │
45
+ └──── tabela de restauração (memória + dsh_mask) ─┘
46
+ ```
47
+
48
+ ## Quick start
49
+
50
+ ```sh
51
+ dsh plugin --profile web add "github:PerryLink/dsh-mask#main"
52
+ # ou via npm
53
+ dsh plugin --profile web add dsh-mask
54
+ dsh --profile web --dump-config | grep -A2 'id: mask'
55
+ ```
56
+
57
+ ```yaml
58
+ - insert:
59
+ - id: mask
60
+ name: dsh-mask
61
+ config:
62
+ entities: [phone, email, id-card, bank-card, key]
63
+ ```
64
+
65
+ ```
66
+ > /mask status
67
+ > /mask restore <PHONE_1>
68
+ ```
69
+
70
+ ## Install & uninstall
71
+
72
+ - **Canal git**: `dsh plugin --profile web add "github:PerryLink/dsh-mask#main"` (equivale a `git+https://github.com/PerryLink/dsh-mask.git`). Sem etapa de build.
73
+ - **Canal npm**: `dsh plugin --profile web add dsh-mask`.
74
+ - **Canal tarball**: `pnpm pack` e depois `dsh plugin --profile web add ./dsh-mask-<version>.tgz`.
75
+ - **Desinstalar**: `dsh plugin --profile web remove dsh-mask`.
76
+
77
+ ## Configuration
78
+
79
+ Todas as opções são campos Schemastery `Config` (alteráveis via cordis.yml). O `cordis.patch.yml` documenta cada chave.
80
+
81
+ | Chave | Padrão | Significado |
82
+ |---|---|---|
83
+ | `enabled` | `true` | Interruptor mestre |
84
+ | `mode` | `regex` | Só `regex` implementado (`regex+ner` reservado) |
85
+ | `entities` | `[phone, email, id-card, bank-card, key]` | Tipos de PII; `ip` opt-in, `person`/`address` exigem NER |
86
+ | `scope` | `messages` | Só `messages` implementado |
87
+ | `registerCommand` | `true` | Registra o comando `/mask` |
88
+ | `registerTools` | `true` | Registra a ferramenta `mask_test` |
89
+ | `persistRestoreTable` | `true` | Persiste a tabela no domínio `dsh_mask` |
90
+ | `maxRestoreEntriesPerSession` | `500` | Limite de entradas por sessão |
91
+ | `maxSessions` | `1000` | Limite de sessões em memória |
92
+
93
+ ## Tools & surfaces
94
+
95
+ | Superfície | Revela texto simples | Notas |
96
+ |---|---|---|
97
+ | Mascaramento `agent/pre-step` | nunca | Reescreve mensagens para marcadores |
98
+ | `/mask status` | nunca | Estado, total substituído, distribuição |
99
+ | `/mask on` / `/mask off` | nunca | Alternância em tempo de execução |
100
+ | `/mask restore <text>` | sim (explícito) | Desmapeia marcadores para os valores desta sessão |
101
+ | `mask_test` | nunca | Mascara um trecho e reporta o resultado |
102
+
103
+ ## Permissions & data
104
+
105
+ - **Permissões**: sem rede, sem credenciais (`network:none`, `credentials:none`).
106
+ - **Dados**: a tabela `marcador → original` vive em memória e, com `persistRestoreTable: true`, no domínio `dsh_mask`; nunca no registro de sessão.
107
+ - **Registro de sessão**: `mask/applied` é declarado em `types.d.ts` e anexado só quando o host registra o tipo.
108
+
109
+ ## Security boundaries
110
+
111
+ - **Texto simples nunca entra no registro de sessão.** O registrado e enviado é a forma mascarada; os originais ficam na tabela.
112
+ - **Sanitizar antes de exibir/registrar.** `lib/sanitize.mjs` redige PII, segredos e credenciais de URL.
113
+ - **Restauração controlada.** `/mask restore` é a única superfície de revelação explícita.
114
+ - **Falha fechada.** `mode`/`scope`/entidades não implementados e números fora de faixa falham ao carregar.
115
+ - **Registros como efeitos.** Listener, comando, ferramenta e fechamento de domínio são efeitos Cordis.
116
+
117
+ ## Known limitations
118
+
119
+ - **Somente regex.** `person` e `address` exigem um reconhecedor NER externo; falham ao carregar. Coberto de série: telefone, e-mail, documento, cartão, chave e IP (opt-in).
120
+ - **A restauração visual precisa de uma metade de cliente.** Mascarar é host-side; desmascarar bolhas na UI é uma função de navegador que esta forma host puro não inclui. A tabela e `restore()` são o seam host-side completo.
121
+ - **Eventos em `0.1.0-rc.6`.** O host ainda não registra `mask/*`, então os appends de auditoria são omitidos (sessões continuam carregando).
122
+
123
+ ## Development
124
+
125
+ ```sh
126
+ pnpm install
127
+ pnpm run typecheck && pnpm run typecheck:ci
128
+ pnpm test
129
+ pnpm run verify:self-contained
130
+ pnpm run verify:artifacts
131
+ pnpm run check:readmes
132
+ pnpm pack
133
+ ```
134
+
135
+ Sem etapa de build: ESM puro, `index.mjs` e `lib/` são os artefatos enviados.
136
+
137
+ ## Topics
138
+
139
+ `dsh`, `dsh-plugin`, `deepseek-harness`, `deepseek`, `cordis`, `pii`, `mask`, `privacy`, `anonymization`, `security`
140
+
141
+ ## Contributors
142
+
143
+ - [@PerryLink](https://github.com/PerryLink) — criador e mantenedor.
144
+
145
+ ## PerryLink DSH Plugin Family
146
+
147
+ Este projeto é um dos [plugins do DeepSeek Harness](https://github.com/PerryLink) mantidos por [PerryLink](https://github.com/PerryLink). Se este ajudar você, os outros provavelmente também ajudarão:
148
+
149
+ | Plugin | Em uma linha |
150
+ |---|---|
151
+ | **[dsh-mask](https://github.com/PerryLink/dsh-mask)** | Middleware de mascaramento de PII: anonimiza no limite do modelo, restaura na camada de exibição |
152
+ | [dsh-mcp-panel](https://github.com/PerryLink/dsh-mcp-panel) | Painel MCP somente leitura: comando /mcp + aba de configurações com status, ferramentas e erros |
153
+ | [dsh-doublecheck](https://github.com/PerryLink/dsh-doublecheck) | Guarda de disciplina de engenharia: interrogatório de requisitos, portões de teste, revisão adversária |
154
+ | [dsh-background-agents](https://github.com/PerryLink/dsh-background-agents) | Agentes filhos em segundo plano com barra lateral web, mensagens e interrupção |
155
+ | [dsh-lsp-actions](https://github.com/PerryLink/dsh-lsp-actions) | Diagnóstico, formatação, autocompletar, ações de código e renomear via LSP |
156
+ | [dsh-output-styles](https://github.com/PerryLink/dsh-output-styles) | Troca de estilo em runtime equivalente ao outputStyles do Claude Code |
157
+ | [dsh-checkpoint-rewind](https://github.com/PerryLink/dsh-checkpoint-rewind) | Equivalente ao /rewind do Claude Code: snapshots, forks de sessão, restauração em um clique |
158
+ | [dsh-permission-rules](https://github.com/PerryLink/dsh-permission-rules) | Regras de permissão declarativas allow/deny/ask estilo Claude Code, com auditoria |
159
+ | [dsh-auto-review](https://github.com/PerryLink/dsh-auto-review) | Revisão automática de segundo modelo na cadeia de aprovação, fail-closed por padrão |
160
+ | [dsh-memento](https://github.com/PerryLink/dsh-memento) | Memória entre sessões com aprovação: seam ctx.memory + SQLite + ferramenta memory |
161
+ | [dsh-skill-pack-security](https://github.com/PerryLink/dsh-skill-pack-security) | Pacote de skills de auditoria de segurança: varredura de segredos, revisão de dependências e cadeia de suprimentos |
162
+ | [dsh-session-pin](https://github.com/PerryLink/dsh-session-pin) | Fixa sessões na barra lateral web com ordenação durável |
163
+ | [dsh-composer-history](https://github.com/PerryLink/dsh-composer-history) | Histórico de entrada estilo terminal para o compositor web: setas, busca Ctrl+R |
164
+ | [dsh-github](https://github.com/PerryLink/dsh-github) | Integração de PR/issues do GitHub para DSH, toda escrita com aprovação |
165
+ | [dsh-plugin-guide](https://github.com/PerryLink/dsh-plugin-guide) | Base de conhecimento de desenvolvimento de plugins como skill de agente sob demanda |
166
+ | [dsh-claude-move](https://github.com/PerryLink/dsh-claude-move) | Migra sessões, memória, skills e CLAUDE.md do Claude Code para DSH |
167
+
168
+ ## License
169
+
170
+ [LICENSE](LICENSE) (Apache License 2.0) © 2026 dsh-mask contributors
package/README.zh.md ADDED
@@ -0,0 +1,188 @@
1
+ <div align="center">
2
+
3
+ # dsh-mask
4
+
5
+ **面向 DeepSeek Harness 的 PII 脱敏中间件——在个人数据进入模型前匿名化,在展示层还原。**
6
+
7
+ *电话、邮箱、身份证、银行卡、密钥等在模型边界变成占位符;原文绝不进入会话日志。*
8
+
9
+ [![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](LICENSE)
10
+ [![DSH plugin](https://img.shields.io/badge/dsh-plugin-✅-green)](https://github.com/topics/dsh-plugin)
11
+ [![Node](https://img.shields.io/badge/node-%5E22.19%20%7C%7C%20%3E%3D24-brightgreen.svg)](#)
12
+ [![CI](https://img.shields.io/github/actions/workflow/status/PerryLink/dsh-mask/ci.yml?branch=main&label=CI)](https://github.com/PerryLink/dsh-mask/actions)
13
+ [![Version](https://img.shields.io/github/v/tag/PerryLink/dsh-mask?label=version)](https://github.com/PerryLink/dsh-mask/releases)
14
+ [![npm version](https://img.shields.io/npm/v/dsh-mask)](https://www.npmjs.com/package/dsh-mask)
15
+ [![npm downloads](https://img.shields.io/npm/dm/dsh-mask)](https://www.npmjs.com/package/dsh-mask)
16
+
17
+ [English](README.md) · [简体中文](README.zh.md) · [Español](README.es.md) · [Português](README.pt.md) · [हिन्दी](README.hi.md)
18
+
19
+ </div>
20
+
21
+ ---
22
+
23
+ ## Compatibility
24
+
25
+ | 维度 | 状态 |
26
+ |---|---|
27
+ | Harness | DeepSeek Harness `0.1.0-rc.6` |
28
+ | Node | `^22.19.0 \|\| >=24.0.0` |
29
+ | 平台 | 任何 DSH 可运行处(纯 host、零依赖正则;无浏览器半) |
30
+ | 模型 | 文本模型完全支持;无需额外模型能力 |
31
+
32
+ ## What you get
33
+
34
+ `dsh-mask` 在**模型边界**匿名化个人数据——消息进入模型之前——并维护一张恢复表,以便在展示层把占位符映射回原文:
35
+
36
+ - **请求前遮罩** —— 重写 `agent/pre-step` 消息,使电话、邮箱、身份证、银行卡、密钥与 IP(均可按需开启)变成 `<PHONE_1>` 之类的占位符。被遮罩的文本才是落盘并发送给模型的内容。
37
+ - **恢复表** —— `占位符 → 原文` 映射只存内存与受控 storage domain(`dsh_mask`);原文绝不进会话日志。
38
+ - **审计不含明文** —— `mask/applied` 会话事件只记「替换了 N 处 + 类型分布」,不记原文与映射。
39
+ - **`/mask` 命令** —— `status`(计数 + 分布)、`on`/`off`(运行时开关)、`restore <text>`(还原占位符)、`help`。
40
+ - **`mask_test` 工具** —— 试跑一段文本看替换效果;绝不回显原文。
41
+
42
+ ```text
43
+ 用户消息 ──agent/pre-step──▶ 占位符 ──模型──▶ 占位符 ──restore──▶ 展示
44
+ ▲ │
45
+ └──── 恢复表(内存 + dsh_mask)──────────┘
46
+ ```
47
+
48
+ ## Quick start
49
+
50
+ ```sh
51
+ # 1. 把 bundle 安装进 profile
52
+ dsh plugin --profile web add "github:PerryLink/dsh-mask#main"
53
+
54
+ # 或从 npm(发布版本)
55
+ dsh plugin --profile web add dsh-mask
56
+
57
+ # 2. 校验行是否挂载
58
+ dsh --profile web --dump-config | grep -A2 'id: mask'
59
+ ```
60
+
61
+ 然后在 profile patch 里调整实体列表:
62
+
63
+ ```yaml
64
+ - insert:
65
+ - id: mask
66
+ name: dsh-mask
67
+ config:
68
+ entities: [phone, email, id-card, bank-card, key]
69
+ ```
70
+
71
+ ```
72
+ > /mask status
73
+ > /mask restore <PHONE_1>
74
+ ```
75
+
76
+ ## Install & uninstall
77
+
78
+ - **git 通道**(最新 `main`):`dsh plugin --profile web add "github:PerryLink/dsh-mask#main"`(等价于从 `git+https://github.com/PerryLink/dsh-mask.git` 安装)。无构建步骤——`index.mjs` 与 `lib/` 即发布产物。
79
+ - **npm 通道**(发布版本):`dsh plugin --profile web add dsh-mask`。
80
+ - **tarball 通道**:在本仓库 `pnpm pack`,再 `dsh plugin --profile web add ./dsh-mask-<version>.tgz`。
81
+ - **卸载**:`dsh plugin --profile web remove dsh-mask`(或从 profile patch 删掉该行)。
82
+
83
+ ## Configuration
84
+
85
+ 所有可调项都是 Schemastery `Config` 字段(可从 cordis.yml 覆盖)。按 id 覆盖会替换整行——请重述所有需要的键。`cordis.patch.yml` 逐键内联注释。
86
+
87
+ | 键 | 默认值 | 含义 |
88
+ |---|---|---|
89
+ | `enabled` | `true` | 总开关;`false` 卸载监听器、`/mask` 命令与 `mask_test` 工具 |
90
+ | `mode` | `regex` | 检测模式;只有 `regex` 实现(`regex+ner` 姓名/地址识别预留并响亮失败) |
91
+ | `entities` | `[phone, email, id-card, bank-card, key]` | 要遮罩的 PII 类型;`ip` 也支持正则(可选),`person`/`address` 需要 NER |
92
+ | `scope` | `messages` | 遮罩作用域;只有 `messages`(agent 消息)实现(`tools` 入参遮罩预留) |
93
+ | `registerCommand` | `true` | 注册 `/mask` 命令 |
94
+ | `registerTools` | `true` | tools 服务存在时注册 `mask_test` 工具 |
95
+ | `persistRestoreTable` | `true` | 把恢复表持久化到受控 `dsh_mask` 领域(`false` = 仅内存) |
96
+ | `maxRestoreEntriesPerSession` | `500` | 每会话恢复条目上限(最旧先逐出) |
97
+ | `maxSessions` | `1000` | 内存会话上限(LRU 逐出,映射按需回载) |
98
+
99
+ profile patch 覆盖示例:
100
+
101
+ ```yaml
102
+ - insert:
103
+ - id: mask
104
+ name: dsh-mask
105
+ config:
106
+ entities: [phone, email, id-card, bank-card, key, ip]
107
+ persistRestoreTable: false
108
+ registerCommand: true
109
+ ```
110
+
111
+ ## Tools & surfaces
112
+
113
+ | 表面 | 是否回显原文 | 说明 |
114
+ |---|---|---|
115
+ | `agent/pre-step` 遮罩 | 永不 | 把消息重写为占位符后再落盘/送模型 |
116
+ | `/mask status` | 永不 | 启用状态、替换总数、类型分布 |
117
+ | `/mask on` / `/mask off` | 永不 | 运行时开关(重启回到 `config.enabled`) |
118
+ | `/mask restore <text>` | 是(显式) | 把占位符还原为本会话存储的值 |
119
+ | `mask_test` | 永不 | 遮罩一段文本并报告占位符结果 + 计数 |
120
+
121
+ ## Permissions & data
122
+
123
+ - **权限**:`dsh-mask` 不做网络请求、不存凭据;只在 `agent/pre-step` 边界读取会话,并写入自己的 `dsh_mask` 领域。`dshWorkshop` manifest 声明 `network:none` 与 `credentials:none`。
124
+ - **数据**:`占位符 → 原文` 恢复表存内存;`persistRestoreTable: true` 时另存受控 `dsh_mask` 领域——这是 PII 原文唯一落点,绝不写会话日志。
125
+ - **会话日志**:`mask/applied` 在 `types.d.ts` 声明,仅在宿主收录该类型时 append(见 Known limitations)。载荷只有计数 + 类型分布。
126
+
127
+ ## Security boundaries
128
+
129
+ - **原文绝不进会话日志。** 落盘并送模型的是遮罩(占位符)形式,因此模型可见内容可自日志以占位符形式重建;原文留在恢复表。
130
+ - **展示/日志前脱敏。** `lib/sanitize.mjs` 在文本进入模型或日志前打码 PII、密钥与 URL 凭据;`mask_test` 与 `/mask status` 永不回显原文。
131
+ - **受控还原。** `/mask restore` 是唯一的显式还原面,且只读当前会话的映射。
132
+ - **失败关闭。** 未实现的 `mode`(`regex+ner`)、`scope`(`tools`)、NER 实体与越界数值均在加载期响亮失败。
133
+ - **注册即 effect。** 监听器、命令、工具与领域关闭都是 Cordis effect——停止/热重载即可撤销。
134
+
135
+ ## Known limitations
136
+
137
+ - **仅正则。** 姓名(`person`)与地址(`address`)识别需要外部 NER 识别器,纯 host 零依赖形态未捆绑;`mode: regex+ner` 与这些实体在加载期响亮失败。开箱即用覆盖电话、邮箱、身份证、银行卡、密钥与(可选)IP。
138
+ - **展示层还原需要浏览器半。** 遮罩完全在 host 侧,但客户端 UI 中透明还原助手气泡属于浏览器半功能,本纯 host 形态未交付;恢复表与 `restore()` 是供客户端插件消费的完整 host 侧 seam,交互需求现由 `/mask restore` 覆盖。
139
+ - **`0.1.0-rc.6` 会话事件。** 宿主尚未收录 `mask/*` 事件类型,因此 rc.6 上会话日志审计 append 被跳过(会话仍可加载);宿主收录类型或支持 `ignorable` 信封后自动开启。
140
+
141
+ ## Development
142
+
143
+ ```sh
144
+ pnpm install # node ^22.19 || >=24
145
+ pnpm run typecheck && pnpm run typecheck:ci # tsc --checkJs(对照 rc.6 peers)
146
+ pnpm test # node --test
147
+ pnpm run verify:self-contained # 依赖 spec 均来自 registry
148
+ pnpm run verify:artifacts # 发布文件齐全 + index.mjs 可 import
149
+ pnpm run check:readmes # 五语 README 一致性
150
+ pnpm pack # 发布 tarball
151
+ ```
152
+
153
+ 无构建步骤:纯 ESM,`index.mjs` 与 `lib/` 即发布产物。
154
+
155
+ ## Topics
156
+
157
+ `dsh`, `dsh-plugin`, `deepseek-harness`, `deepseek`, `cordis`, `pii`, `mask`, `privacy`, `anonymization`, `security`
158
+
159
+ ## Contributors
160
+
161
+ - [@PerryLink](https://github.com/PerryLink) —— 创建者与维护者:从 Pii-Stripper-Middleware 移植的正则 PII 检测器、`agent/pre-step` 遮罩 seam、恢复表、`/mask` 命令与 `mask_test` 工具、五语文档。
162
+
163
+ ## PerryLink DSH Plugin Family
164
+
165
+ 本项目是 [PerryLink](https://github.com/PerryLink) 维护的 [DeepSeek Harness 插件](https://github.com/PerryLink)之一。如果你觉得这个插件有用,其余的很可能同样有用:
166
+
167
+ | 插件 | 一句话说明 |
168
+ |---|---|
169
+ | **[dsh-mask](https://github.com/PerryLink/dsh-mask)** | PII 脱敏中间件:模型边界匿名化、展示层还原 |
170
+ | [dsh-mcp-panel](https://github.com/PerryLink/dsh-mcp-panel) | 只读 MCP 运行时面板:/mcp 命令 + 设置页,状态/工具/错误一览 |
171
+ | [dsh-doublecheck](https://github.com/PerryLink/dsh-doublecheck) | 工程纪律守门:需求审讯、测试证据门、对抗评审 |
172
+ | [dsh-background-agents](https://github.com/PerryLink/dsh-background-agents) | 持久化后台子代理:Web 侧边栏进度、随时留言与打断 |
173
+ | [dsh-lsp-actions](https://github.com/PerryLink/dsh-lsp-actions) | 基于语言服务器的诊断/格式化/补全/代码动作/重命名 |
174
+ | [dsh-output-styles](https://github.com/PerryLink/dsh-output-styles) | 对标 Claude Code outputStyles 的运行时风格切换 |
175
+ | [dsh-checkpoint-rewind](https://github.com/PerryLink/dsh-checkpoint-rewind) | 对标 Claude Code /rewind:快照、会话 fork、一键回退 |
176
+ | [dsh-permission-rules](https://github.com/PerryLink/dsh-permission-rules) | Claude Code 风格声明式 allow/deny/ask 权限规则,带审计 |
177
+ | [dsh-auto-review](https://github.com/PerryLink/dsh-auto-review) | 审批链上的第二模型自动审查,默认 fail-closed |
178
+ | [dsh-memento](https://github.com/PerryLink/dsh-memento) | 带审批门的跨会话记忆:ctx.memory + SQLite + memory 工具 |
179
+ | [dsh-skill-pack-security](https://github.com/PerryLink/dsh-skill-pack-security) | 安全审计技能包:密钥扫描、依赖与供应链审查 |
180
+ | [dsh-session-pin](https://github.com/PerryLink/dsh-session-pin) | 在 Web 侧边栏置顶会话,持久排序 |
181
+ | [dsh-composer-history](https://github.com/PerryLink/dsh-composer-history) | Web 作曲器终端式输入历史:方向键、Ctrl+R 搜索 |
182
+ | [dsh-github](https://github.com/PerryLink/dsh-github) | DSH 的 GitHub PR/issue 集成,所有写操作经审批门 |
183
+ | [dsh-plugin-guide](https://github.com/PerryLink/dsh-plugin-guide) | 插件开发知识库,随 bundle 安装的按需 agent 技能 |
184
+ | [dsh-claude-move](https://github.com/PerryLink/dsh-claude-move) | 把 Claude Code 会话、记忆、技能和 CLAUDE.md 迁入 DSH |
185
+
186
+ ## License
187
+
188
+ [LICENSE](LICENSE)(Apache License 2.0)© 2026 dsh-mask contributors
package/SECURITY.md ADDED
@@ -0,0 +1,45 @@
1
+ # Security policy
2
+
3
+ ## Reporting a vulnerability
4
+
5
+ Please **do not** open a public issue for security vulnerabilities.
6
+
7
+ Report privately through GitHub's private vulnerability reporting:
8
+
9
+ **https://github.com/PerryLink/dsh-mask/security/advisories/new**
10
+
11
+ That flow keeps the report confidential while we triage, and it is the channel we watch first.
12
+
13
+ ## Before you report
14
+
15
+ - **Redact sensitive data** from any logs or `/mask` output you attach: tokens, API keys, secrets, Authorization/request headers, personal paths, account identifiers, and — especially — real PII (phones, emails, ID cards, bank cards). Replace them with placeholders such as `<PHONE_1>` before pasting.
16
+ - Include, when possible: the plugin version, the harness (`dsh`) version, Node and OS versions, the `entities`/`mode` configuration, and the minimal steps to reproduce.
17
+
18
+ ## What to expect
19
+
20
+ - **Acknowledgment**: within 5 business days.
21
+ - **Triage**: within 10 business days we confirm the issue and assess severity, or ask for more details.
22
+ - **Fix**: security fixes are prepared in a private fork, released as a patch version, and announced in the release notes.
23
+
24
+ ## Disclosure and credit
25
+
26
+ - We follow coordinated disclosure: a public advisory (and CVE request where appropriate) is published once a fix ships.
27
+ - Reporters are credited in the advisory unless they ask to remain anonymous. There is no bug bounty program at this time.
28
+
29
+ ## Scope
30
+
31
+ This plugin anonymizes PII at the model boundary. Its own guarantees are:
32
+
33
+ - **Plaintext never enters the session log.** The masked (placeholder) form is what gets logged and sent to the model; the originals stay in the restore table (memory, and the controlled `dsh_mask` storage domain when `persistRestoreTable: true`).
34
+ - **Audit without plaintext.** The `mask/applied` session event records only counts and a type distribution, never the original text or the mapping.
35
+ - **Sanitized output.** `lib/sanitize.mjs` redacts PII, secrets, and URL credentials before any text reaches the model or the log; `mask_test` and `/mask status` never echo originals.
36
+ - **Controlled restore.** `/mask restore` is the single explicit reveal surface and reads only the active session's mapping.
37
+ - **No network, no credentials.** The plugin performs no network requests and stores no credentials.
38
+ - **Fail closed.** Unimplemented `mode` (`regex+ner`), `scope` (`tools`), NER-only entities, and out-of-bounds numbers fail loudly at load.
39
+
40
+ Two residual risks are the operator's to manage:
41
+
42
+ - When `persistRestoreTable: true`, the restore table holds plaintext PII on disk inside the `dsh_mask` storage domain. Protect that storage (file permissions, encrypted volume); set `persistRestoreTable: false` for memory-only operation.
43
+ - Masking is regex-based; it cannot catch every PII shape (names and addresses need an NER recognizer, which is not bundled). Treat it as a defense-in-depth boundary, not a completeness guarantee.
44
+
45
+ Vulnerabilities in the harness itself should be reported to the official harness maintainers instead.
@@ -0,0 +1,41 @@
1
+ # Third-party notices
2
+
3
+ ## Ported code
4
+
5
+ The regex PII detector in `lib/strip.mjs` (entity patterns, overlap resolution,
6
+ same-value-same-placeholder reuse, and the restore-by-descending-placeholder-length
7
+ logic) is ported from:
8
+
9
+ - **Pii-Stripper-Middleware** — https://github.com/PerryLink/Pii-Stripper-Middleware
10
+
11
+ License status of the source: the project's asset inventory recorded the upstream
12
+ as `NOASSERTION` at clone time; the upstream repository now carries the canonical
13
+ Apache-2.0 LICENSE (`Copyright 2026 PerryLink`), which is what this port follows.
14
+ The local `upstream/` reference clone may still hold the pre-fix file until refreshed.
15
+ The `upstream/` directory is a read-only reference clone kept only for the port and
16
+ is gitignored — it is not part of this repository and is not published.
17
+
18
+ This repository (`dsh-mask`) is licensed under Apache-2.0 (see `LICENSE`). The port
19
+ adapts the Python implementation to JavaScript and extends it with a `key` detector;
20
+ all other JavaScript here (`index.mjs`, `lib/`, `test/`, `scripts/`) is original work
21
+ by the dsh-mask contributors.
22
+
23
+ ## Install-time dependencies
24
+
25
+ `dsh-mask` bundles no third-party source code. The package depends on the following
26
+ software, none of which is bundled into the published tarball:
27
+
28
+ | Package | Version range | License | Purpose |
29
+ |---|---|---|---|
30
+ | [zod](https://github.com/colinhacks/zod) | `^4.4.3` | MIT | Runtime schema for the `dsh_mask` storage-domain record (persistence-boundary validator) |
31
+ | [typescript](https://github.com/microsoft/TypeScript) | `^5.9.0` | Apache-2.0 | `tsc --checkJs` typecheck gate (`tsconfig.check.json`) |
32
+ | [@deepseek-ai/cordis](https://www.npmjs.com/package/@deepseek-ai/cordis) | `^4.0.1` (peer) | See package | The plugin runtime |
33
+ | [@deepseek-ai/schemastery](https://www.npmjs.com/package/@deepseek-ai/schemastery) | `^3.18.0` (peer) | See package | Configuration schema |
34
+ | `@deepseek-ai/dsh-*` peers | `0.1.0-rc.6` (peer) | See packages | Official harness seams (`dsh-session`, `dsh-storage-domain`, `dsh-tools`) |
35
+
36
+ Development-only dependencies (not shipped, used by tests and the typecheck gate)
37
+ add `@deepseek-ai/dsh-agent` and `@deepseek-ai/dsh-commands` at `0.1.0-rc.6`, and
38
+ `@types/node`.
39
+
40
+ At runtime the plugin only talks to the harness services listed as peerDependencies;
41
+ it performs no network requests of its own.