DeepSeek Harness Plugin

omdsh-dev/dsh-tool-csv

Stars ★ 3 Category Tools & Capabilities Added 2026-08-13

Parse/query/aggregate/convert CSV (RFC 4180) with a zero-dependency state-machine parser.

Install

# from GitHub (first run asks for allowBuilds approval — follow the hint, retry)

dsh plugin --profile web add github:omdsh-dev/dsh-tool-csv

GitHub-sourced plugins run build scripts on your machine at install time. Only install sources you trust, and pin a commit (github:owner/repo#sha).

README

中文

DSH CSV data tool plugin — parse, query, filter, aggregate, and transform CSV text. Zero dependencies, pure functions, RFC 4180 state-machine parser.

License

Motivation

Tabular data (export files, API responses, report snippets) appears frequently in agent sessions. The existing path is to spawn a bash process and have the model write a parsing script on the fly:

  1. Every call spawns a process — especially expensive on Windows
  2. Model-written CSV parsers have a high error rate — hand-written code easily trips over edge cases like commas inside quotes, "" escapes, BOM, multi-line fields, and CRLF, and the result can't be verified

This plugin provides deterministic, zero-dependency, pure-function CSV processing: a single function call returns structured JSON in milliseconds.

Together with dsh-tool-json it forms a "structured data processing" pair: JSON handles objects, CSV handles tables.

Security Model

  • Zero dependencies: no CSV parsing library; a hand-written state machine (single pass, O(n))
  • Pure functions: no file reads, no file writes, no network, no eval
  • No injection surface: query filtering only does literal exact matching (===), no expression evaluation
  • Budgets: input capped at 256,000 bytes (errors directly beyond the limit, no truncation); timeoutMs: 2000; limit defaults to 100 rows to prevent output bloat
  • Tool arguments are recorded in the session log; don't pass sensitive data

Tool Declaration

Registers the csv tool (@deepseek-ai/dsh-tool-csv, row id tool-csv), uniformly outputting JSON text strings.

Parameter Type Required Description
action string parse / query / stats / to_json
csv string CSV text (RFC 4180; quoted fields may contain commas/newlines; "" escapes; BOM ignored)
column string Query column: column name (when there's a header) or a 1-based index such as "2"
value string Exact-match value for query (strict equality, not substring)
delimiter string Delimiter, default ","; a single character or "tab"
header boolean Whether the first row is a header, default true; when false, rows are parsed as arrays
limit integer Max number of returned rows (query/parse), default 100

Actions

action Function Example output
parse Parse into a JSON array (one object per row when there's a header) [{"name":"Alice","city":"NYC"}]
query Exactly filter rows by column name/index (result includes the header and can be read back) [["name","city"],["Alice","NYC"]]
stats Row count / column count / column names / empty-row count / warnings (including duplicate column names, inconsistent field counts) {"rows":2,"columns":2,...}
to_json Alias of parse (model-friendly) Same as parse

Examples

csv { action: "parse", csv: "name,city\nalice,nyc\nbob,la" }
  → [{"name":"alice","city":"nyc"},{"name":"bob","city":"la"}]

csv { action: "query", csv: "name,city\nalice,nyc\nbob,la", column: "city", value: "la" }
  → [["name","city"],["bob","la"]]

csv { action: "stats", csv: "name,city\nalice,nyc" }
  → {"rows":1,"columns":2,"columnNames":["name","city"],"emptyRows":0,"warnings":[]}

Edge-Case Behavior

Situation Handling
Comma/newline/CRLF inside quotes Treated as field content (multi-line fields)
"" escape Decoded to a single "
Unclosed quote Error: csv: unterminated quoted field (strict mode, no silent tolerance)
Invalid character after closing quote Error: csv: invalid character "x" after closing quote (RFC 4180: only a delimiter/newline/EOF is allowed after the closing quote)
BOM in the first row Stripped before parsing
Empty rows Skipped (stats reports the empty-row count)
Inconsistent field counts No error: missing fields are padded with null, extras are merged into the last field (stats records a warning)
Duplicate column names The later column overrides the earlier one (stats records a warning)
__proto__/constructor/prototype headers Written into a null-prototype object, lossless serialization ({"__proto__":"value"})
delimiter Only a single UTF-16 code unit or "tab"; surrogate pairs (e.g. 😀) and control characters (except \t) are rejected
No header header: false, rows are parsed as arrays, column uses 1-based indexes
Input over 256KB Errors directly (no truncation)
Hundred-thousand-row input Single-pass aggregation computes column widths (no spread), no RangeError

npm 0.1.0-rc.6 Compatibility (Verified)

This plugin has been migrated to the npm 0.1.0-rc.6 dependency line and fully verified end-to-end in an isolated consumer of @deepseek-ai/dsh@0.1.0-rc.6:

  • 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 unscoped cordis
  • Standalone build: npm install (devDependencies self-contained: typescript/vitest/@types/node) → npm run typechecknpm testnpm run buildnpm pack
  • Consumption verification: tarball loaded into a 0.1.0-rc.6 consumer → dsh --profile compat --dump-config shows this plugin's row → the tool genuinely registers and executes
  • Launch method: npx -p @deepseek-ai/dsh@0.1.0-rc.6 dsh web (lib production mode; don't install -g globally)

Installation

Profile Bundle (Recommended)

As of DSH 0.1.0-rc.6 (npm), this plugin can be installed into any profile as a standalone bundle in one step (repositories live at https://github.com/omdsh-dev, public):

# 交互式(web)profile
dsh plugin --profile web add github:omdsh-dev/dsh-tool-csv
# 一次性任务(headless)profile —— dsh run 默认使用 headless
dsh plugin --profile headless add github:omdsh-dev/dsh-tool-csv

You can also pack a tarball with npm pack first and install that:

git clone https://github.com/omdsh-dev/dsh-tool-csv
cd dsh-tool-csv
npm install && npm pack
dsh plugin --profile web add ./deepseek-ai-dsh-tool-csv-*.tgz
dsh plugin --profile headless add ./deepseek-ai-dsh-tool-csv-*.tgz

The in-package dsh.bundle.patch automatically adds the plugin to the profile's layer stack after installation (row id: tool-csv). The plugin's missing peer dependencies (@deepseek-ai/cordis, @deepseek-ai/dsh-tools, @deepseek-ai/dsh-invariants) are provided by the profile's healed profiles/node_modules fallback installation.

⚠️ web and headless are different profiles: installing for web doesn't automatically cover headless; dsh run uses the headless profile by default. Use forward slashes for Windows paths (C:/...).

Verify Installation

dsh --profile web --dump-config | grep tool-csv

Runtime Verification

dsh run "使用 csv 工具解析 'a,b
1,2'"

Manual Installation (Source Contribution / Legacy Snapshot Scenarios)

Only for source contribution (developing/debugging this plugin in the monorepo) or scenarios still using old snapshots (local junction/symlink, manual profile-layer editing).

Testing

node <monorepo>/node_modules/vitest/vitest.mjs run tests
  • parse.spec.ts: RFC 4180 edge cases (quotes/escapes/BOM/CRLF/empty rows/tab/size caps/strict quote errors/delimiter validation)
  • query.spec.ts: column name/index filtering, exact matching, limit, error paths, stats warnings, JSON mapping, dangerous headers, 125k-row stress
  • register.spec.ts: registration contract (AUDIT-CROSS-02 style)

License

MIT

Content from the project README on GitHub ↗

Links

More in this category

View the whole category →