Install
Inside DeepSeek Harness, with dsh-market
dsh plugin --profile web add dshmarket
Or from the command line
dsh plugin --profile web add github:omdsh-dev/dsh-tool-encoding
Installing runs third-party code with your own permissions — it can read your files, use your credentials and reach the network. Review the source first, and pin a commit (github:owner/repo#sha) when you can.
README
DSH encoding/hash tool plugin — base64/base64url/url/hex encode/decode + hash + UUID for UTF-8 text. Zero dependencies, zero subprocesses, pure functions.
Package name:
@deepseek-ai/dsh-tool-encoding(standalone bundle, not a monorepo-integrated form); thelib/output is generated bynpm run build(tsc) inside the repo and committed with the repository.
Motivation
Encoding/hashing is a high-frequency daily operation for agents: inspecting base64 fields in API responses (JWT payload), building query parameters, verifying file integrity (sha256), generating UUIDs. Problems with the current approach bash -c "echo ... | base64": subprocess overhead, quote-escaping hell (a base64 string embedded in a bash command then in a JSON argument — the double-escaping error rate is extremely high), and inconsistent cross-platform tool names (md5 vs md5sum vs shasum -a 256).
Security model
No eval, no new Function. All operations are pure-function compositions of Buffer/node:crypto/TextDecoder/encodeURIComponent:
- UTF-8 integrity: decoding uses fatal mode (
TextDecoder('utf-8', { fatal: true })); illegal bytes throwencoding: invalid UTF-8 output; legal U+FFFD/control characters are not rejected (00NUL,0anewline,efbfbdU+FFFD are all legal,ffis illegal) - Strict base64 validation: no whitespace,
=only at the end and ≤2, length must be a multiple of 4, RFC 4648 canonical unused bits (non-canonical encodings such asZh==are rejected, preventing multiple strings from mapping to the same text) - Unified rejection of lone surrogates: all text inputs pass through
String.prototype.isWellFormed(), avoiding silent replacement and inconsistent URIError behavior - Byte limits: 1 MB input / 4 MB output (1,000,000 / 4,000,000 bytes each,
Buffer.byteLength; the output limit is a fuse of pre-allocation estimate + final check) - Hash algorithm whitelist:
Object.hasOwnlookup table (md5/sha1/sha256/sha512) - Errors uniformly use the
encoding:prefix and never pass through the underlyingURIError/TypeError
Architecture
DSH Agent
│ ctx.tools.register()
▼
src/index.ts(Cordis 插件入口 + action 分发 + 独立校验)
│
▼
src/encoding.ts
├── b64Encode/b64Decode — 标准 base64(严格校验)
├── b64UrlEncode/b64UrlDecode — base64url(canonical 无 padding,解码兼容)
├── urlEncode/urlDecode — component 语义(URIError 包装)
├── hexEncode/hexDecode — UTF-8 字节 hex(fatal 解码)
├── digest — 白名单哈希
├── newUuid — crypto.randomUUID()
└── validateUnicode/assertInputBytes/decodeUtf8Strict — 校验器
Tool declaration
ctx.tools.register(defineTool({
name: 'encoding',
parameters: {
action: {
type: 'string', required: true,
enum: ['base64_encode','base64_decode','base64url_encode','base64url_decode',
'url_encode','url_decode','hex_encode','hex_decode','hash','uuid'],
},
input: { type: 'string', description: 'Input string for encode/decode/hash' },
algorithm: { type: 'string', enum: ['md5','sha1','sha256','sha512'], description: 'For hash' },
},
output: { schema: { type: 'json' }, render: (_a, v) => [{ type: 'text', text: JSON.stringify(v) }] },
execute: (args) => Promise.resolve(executeAction(args.action, args) as JsonValue),
timeoutMs: 1000,
}))
Supported operations
| action | description | example |
|---|---|---|
base64_encode / base64_decode |
RFC 4648 standard base64 (strict validation) | "foobar" → "Zm9vYmFy" |
base64url_encode / base64url_decode |
JWT-style, unpadded output, decoding accepts +/ and optional padding |
"\uFEFF" → "77u_" |
url_encode / url_decode |
component semantics (not full query): space is %20 not +, !'()* not escaped, decode("+") → "+" |
"a b" → "a%20b" |
hex_encode / hex_decode |
UTF-8 byte hex; the decoded result must be valid UTF-8 | "AB" → "4142" |
hash |
md5/sha1/sha256/sha512 hex digest; non-security use only | sha256("") → e3b0c442... |
uuid |
UUID v4 string (crypto.randomUUID()) |
"550e8400-..." |
Semantic contract:
- v1 is a UTF-8 text tool: all inputs and outputs are strings; binary content is represented as hex; decoded results must be valid UTF-8
- All actions return strings (including
uuid) - Do not use this tool on confidential material: tool arguments are recorded in session logs
DSH 0.1.5-rc.1 compatibility (verified)
This plugin has been migrated to the DSH 0.1.5-rc.1 harness and fully verified in an isolated consumer of local harness 0.1.5-rc.1:
- Types/runtime:
@deepseek-ai/cordis@^4.0.1+@deepseek-ai/dsh-tools@>=0.0.1-rc.1 <0.2.0+@deepseek-ai/dsh-invariants@>=0.0.1-rc.1 <0.2.0(peer); no longer depends on unscopedcordis - Standalone build:
npm install(devDependencies are self-contained: typescript/vitest/@types/node) →npm run typecheck→npm test→npm run build→npm pack - Consumption verification: tarball installed into the 0.1.5-rc.1 consumer →
dsh --profile compat --dump-configshows this plugin's row → the tool actually registers and executes - Startup:
npx -p @deepseek-ai/dsh@next dsh web(lib production mode; do notinstall -gglobally)
Version adaptation
- DSH version adapted: DSH 0.1.5-rc.1
- Bundle declaration:
dsh.bundleinpackage.json(patch points tocordis.patch.yml) +exportsfields - Patch format:
cordis.patch.ymluses the- insert:list (patches are id-targeted; a bare- id:entry reportsentry not found) - files: the published tarball contains
lib/,src/,cordis.patch.yml
Installation
Plugin source repository: https://github.com/omdsh-dev/dsh-tool-encoding (public).
Profile Bundle (recommended)
Install this plugin as a standalone bundle into a profile (DSH 0.1.5-rc.1, npm):
# 交互式(web)profile
dsh plugin --profile web add github:omdsh-dev/dsh-tool-encoding
# 一次性任务(headless)profile —— dsh run 默认使用 headless
dsh plugin --profile headless add github:omdsh-dev/dsh-tool-encoding
The dsh.bundle.patch inside the package (pointing to cordis.patch.yml) automatically adds the plugin to the profile's layer stack after installation; the plugin's cordis.patch.yml inserts the tool-encoding entry via - insert:.
⚠️ web and headless are different profiles: installing into web does not automatically cover headless;
dsh runuses the headless profile by default.
Install via npm pack tarball
npm pack # generates dsh-tool-encoding-*.tgz
dsh plugin --profile web add ./dsh-tool-encoding-*.tgz
dsh plugin --profile headless add ./dsh-tool-encoding-*.tgz
Verify installation
dsh --profile web --dump-config | grep tool-encoding
Run verification
dsh run "使用 encoding 工具把 hello 做 base64 编码"
Manual installation and legacy compatibility
Only for legacy snapshots that do not support Profile Bundle, or plugin development/debugging environments:
- Place into the monorepo:
cp -r encoding ~/.dsh/source/master/packages/tools/encoding(development/debugging) - Add
"@deepseek-ai/dsh-tool-encoding": "workspace:^"toapps/cli/package.json; add{ "path": "./packages/tools/encoding" }to thereferencesoftsconfig.host.json pnpm install && pnpm run build- Insert the plugin in the profile's user-layer patch (
~/.dsh/profiles/<name>/cordis.patch.yml):
- insert:
- id: tool-encoding
name: '@deepseek-ai/dsh-tool-encoding'
- Verify:
dsh --profile <name> --dump-config | grep tool-encoding
Note: patches are id-targeted — a bare
- id:entry reportsentry "xxx" not found; it must be wrapped in an- insert:list.
Known limitations
- Arbitrary binary (non-printable bytes) encode/decode requires v2's
output: "utf8" | "hex"mode hashprovides digests only, no HMAC/salting/key derivation; MD5/SHA-1 are for compatibility/non-security integrity checks only- URL uses component semantics; form encoding (space →
+) needs a separate action (v2)
Testing
pnpm test
41 test cases covering functionality/errors/attack payloads (RFC 4648/1321/6234 known vectors, UTF-8 boundary distinctions, canonical padding boundaries, unified surrogate rejection, etc.). See the locally maintained design document for the full list.
License
MIT
Comments
Comments live in GitHub Discussions. Sign in with GitHub to post or react.