dsh-web
zhu1090093659/dsh-webDeepSeek Harness(DSH)Web 插件聚合生态包 · 一切皆插件,创意工坊分发(dsh-market.com)
dsh-dir-prep-organize
A dsh plugin: a split "Polish" button that hands your draft, the top level of the session directory and the recent real turns to the current default model for a rewrite, plus a "Template" dropdown of role templates. Zero model tools, zero HTTP routes of its own.
group field; an entry with an empty group lands in "General".scripts/gen-defaults.mjs from this package's agents/ role library - a vendored collection of several hundred role .md files across more than twenty department directories. The curated 85 is the number that matters to a user; the library size is not pinned here because it changes whenever the upstream project is refreshed.client.js to ~711 KB.defaults method once, lazily (first menu open or first settings-card visit) and reuses it in-process. Nothing is fetched at all when the user already has their own templates..md or directory by path, and registration of extra allowed import directories. That card is one list feeding two places: the input-box "Template" dropdown and the "Polish" ▾ role menu.dsh plugin --profile web add @jayyuen66/dsh-dir-prep-organizeRemove with dsh plugin --profile web remove @jayyuen66/dsh-dir-prep-organize. The package is on the public npm registry, so installation needs no credentials and no scoped-registry line.
import { apply } from "@jayyuen66/dsh-dir-prep-organize"); there is no default export, so import pkg from … fails with does not provide an export named 'default'. That Node floor is what makes require() of an ESM entry work at all, which is why engines.node is declared.engines.dsh (^0.2.1-rc.3), and it decides alone: evaluatePluginCompatibility returns on the engines.dsh branch before it ever looks at peerDependencies. Measured against the real host code: 0.2.0-rc.2 is refused, 0.2.1-rc.3 and 0.2.2 pass, 0.3.0 is refused. A refused host needs the explicit risk grant dsh plugin --profile allow-version @ --dsh-version --accept-risk.@deepseek-ai/dsh-* pins stay at 0.2.1-rc.3** - the version this package is built and tested against. The engines.dsh range is a claim about which *hosts* it runs on; the pin is a fact about which host version it was *compiled* against. Mixing the two is why the publish gate checks them separately.@deepseek-ai/* under dependencies, by contract (`test/publish-manifest.test.ts` enforces it). Consumer profiles install with `nodeLinker: hoisted` and `autoInstallPeers: false`, so a host package under `dependencies` is materialized as a real directory next to the copy the running host already loaded. `@deepseek-ai/dsh-tools` keys its tool-runtime scheduler with a plain `Symbol` (not `Symbol.for`), so symbol identity is per module instance: the host reads the scheduler off the profile copy, gets `undefined`, and every native tool call throws** - while this package's build, typecheck and coverage gates stay green right up to that moment.@deepseek-ai/schemastery (the host's fork - only it resolves the .volatile() fields) and @deepseek-ai/dsh-brand. build-host.mjs externalizes dependencies and peerDependencies, so the bare specifiers stay in the artifact; a devDependencies-only entry would let the bundler inline the official function body. test/build-host.test.ts pins both "specifier present" and "function body absent".@deepseek-ai/cordis, cosmokit, and the dsh-agent-default-model / client-ui / fs / llm / session family). Declaring them is not ceremony: under pnpm's strict layout a bare specifier in types/host.d.ts that no manifest table names is unresolvable on the consumer's side, while this repository's own typecheck stays green. The test reads that roster off types/**/*.d.ts rather than off this paragraph, so the two cannot drift apart.host.js, client.js, templates.data.mjs, types/, cordis.patch.yml, agents/ and THIRD_PARTY_NOTICES.md. package.json, README* and LICENSE are attached unconditionally by the registry client.host.js, so every user paid for the templates in memory even without opening the dropdown.agency-agents-zh (MIT). The copyright and licence notice ship in THIRD_PARTY_NOTICES.md, because MIT requires it in every distributed copy. Do not hand-edit files under agents/.If your profile pins @jayyuen66/dsh-plugin-shared with a pnpm overrides entry, that pin must be at least the version this package declares. A lower pin installs a copy without the names imported at runtime, and the host then reports N entries did not activate together with does not provide an export named ... at boot - the package installs fine and never loads, and no per-repository CI run can see it.
dsh --profile web --dump-config for the dir-prep-organize layer.--dump-config is the only accepted "it is in the layer stack" signal, and it is not read-only - it rewrites that profile's root assembly file. Read layer lines from stdout and check stderr separately: an unmatched patch target appears only on stderr, so the exit code alone proves nothing.# == or # == , patched by ; accept both forms.defaults method. A loading row means the call is in flight; a failure shows the host's reason plus Retry.Worth knowing before you look for them:
settings; it never touches the tool registry. There is no organize_text tool to call.dirPrepOrganize, registered through an injected child fiber, reached through the host /api gateway. Authentication, Host/DNS-rebinding/Origin checks, the signed browser-session cookie and body limits are all the gateway's - this package keeps no CSRF token and no route table.settings service (hard-injected), llm.stream, agentDefaultModel, and the session/filesystem services. Without settings the card is disabled with a warning and the dropdown falls back to the built-in curated set.dsh.bundle.patch → ./cordis.patch.yml), which inserts - id: dir-prep-organize with name set to the package name.conversation.input.right - the polish button (id dir-prep-organize, order 99) and the templates dropdown (id dir-prep-organize-templates, order 100).plugins.bundle.config - the settings card, keyed by the bundle package name @jayyuen66/dsh-dir-prep-organize. The host dispatches entryKey: pkg.name (source of truth: dsh.profile.bundles in the profile's package.json), so a bare entry id never matches and the card would render nowhere.configForms.get() stay the bare entry id dir-prep-organize - deliberately not the same identifier as that slot key.dsh.client.platform = web with immediately.Aspect · Fact Transport · Host llm.stream: one request-only user text message (no id, no source) plus a system rule block Model · agentDefaultModel.currentSelection() - provider / model / reasoningEffort. Its absence reports "No model selection is available" Role style · An optional roleText injected into the user message's ` fence (never into the system block - see the trust-order note above buildOrganizeSystem). It borrows terminology and tone only; it never executes the role's tasks Finish reason · Anything other than stop - including a missing finish chunk - **fails** and never writes back to the draft Timeout · organizeTimeoutMs, default 120000 ms, read per request via .get(). The client fetch timeout is that value + 5000 ms Input caps · maxSnippetBytes (262144 = 256 KiB) per key file, readConcurrency` (8) for reads. Directory, conversation and role text are never truncated No truncation, on purpose · A model context-overflow error is the feedback, and the user slims the input. A payload above the endpoint body cap gets a 413 instead
Aspect · Fact Entry shape · { id, name, description, text, group, emoji }, all strings. description / group / emoji default to empty strings Validation on save · Entries with an empty name or text are dropped; emoji is cut to 12 characters; a missing or colliding id is deterministically replaced by tpl- Built-in set · 85 curated templates generated from the agents/ role library. The dropdown falls back to them when templates is unset "Unset" is an empty array · Under implicit registration schemastery casts a missing array field to [], so an empty list always means "fall back to built-in". Only a non-empty array whose items are all invalid renders as an empty list Restore defaults · Unsets templates back to the curated set and leaves importAllowRoots untouched. Two-step confirm; the second click must come within 4 seconds Import · By path: a local .md file or a directory. path exactly empty imports the whole built-in library. A role file whose code fence never closes is rejected instead of silently importing half its body
Namespace dir-prep-organize equals the settings entry id. Fields projected into the settings form are the .volatile() ones.
Field · Type · Default · Card control · Notes templates · {id,name,description,text,group,emoji}[] · unset · yes · The user's own templates. Unset falls back to the 85 built-in entries importAllowRoots · string[] · [] · yes · Extra allowed roots for the import endpoint. Non-strings and whitespace-only items are dropped; duplicates removed. With nothing registered, only the session cwd and the built-in role library are allowed organizeTimeoutMs · natural, volatile · 120000 · no · The LLM abort deadline in ms. Positive values are truncated and clamped to [1, 2147483647]; non-finite or ≤0 values fall back to 120000 instead of becoming an instant timeout. Past 2^31-1 Node's setTimeout prints a TimeoutOverflowWarning and silently uses 1 ms, which turns "raise the timeout" into "fail instantly". The card has no control, so changing it means settings.yaml or the row's config: maxSnippetBytes · natural, non-volatile · 262144 · no · Per-file cap for key-file snippets; a larger file, or one whose size is unknown, is skipped whole and counted in skipped.tooLarge. Import candidates use the same cap. Non-volatile means no form projection, hence no card row - deployment value only readConcurrency · natural, non-volatile · 8 · no · Bounded read concurrency for snippets and directory imports. Clamped to [1, 64]: 0 or a negative value made the bounded map recurse forever until the host was killed by the OOM killer, and a huge value defeats the fd ceiling this field exists to hold
Settings are persisted in settings.yaml under the dsh data directory.
Official Typert Remote namespace `dirPrepOrganize`, registered through an injected child fiber. The descriptors are hand-written, parameters go through strict shape validation, results go through src-json.
Method · Input · Success payload defaults · - · ok / templates[…] (the curated set) context · { sessionId } · ok / cwd / truncated / skipped / entries[{name,isDir,sizeBytes,snippet}] model · { sessionId } · ok / provider / model / reasoningEffort organize · { sessionId, prompt, entriesSummary, roleText? } · ok / content importTemplates · { path, sessionId } (path exactly empty = whole built-in library) · ok / count / truncated / skipped / entries
ok:false with error. The import path-policy branches are the exception: an out-of-bounds path or a malformed path field also carries status 403 or 400.ok:true becomes a visible error, never an empty list.Aspect · Fact Network · No outbound requests of its own: the data plane is the host gateway's RPC channel. No environment variable is read On disk · The only data written is templates and importAllowRoots, in the host settings file What one polish call sends · The full draft, the session cwd path, top-level directory entries with the full text of key text files, the real user/assistant turns (framework-injected messages and tool results are filtered out), and the optional role body Which files get a snippet · Only 20 code/document extensions (ts/tsx/js/jsx/mjs/cjs/py/rs/go/java/rb/json/toml/md/sql/graphql/proto/css/scss/less). yaml / env are not whitelisted Sensitive file names · Any file whose name matches credentials / secret(s) / id_rsa / pem / p12 / pfx / keystore / env / key(s) / token(s) / auth / passwd / password / account(s) at a separator boundary never gets a snippet. The boundary is deliberate: a naive substring match would drop monkey.js and AUTHORS.md, while a miss would send credential text to a third-party model Caps and concurrency · A single file over maxSnippetBytes, or with unknown size, is skipped whole - never half-summarized. Reads run with readConcurrency Counters · Too-large / unreadable / deeper-level / non-role cases are counted in skipped, shown in the UI, and reflected honestly by truncated Import endpoint · Read-only: no model call, no disk writes. Absolute paths are refused by default; only paths inside the session cwd, the package's agents/ and importAllowRoots pass. . / .. / hidden segments (such as .ssh) are always rejected, and an out-of-bounds path answers 403 echoing the resolved path
Registered honestly, one entry per class.
sessionId as an empty string, so an import must live inside the built-in agents/ or a registered root, and must contain no . / .. / hidden segments. The rejection names the allowed zones and echoes the resolved path.deeper, never imported.agents/ role library and template bodies are user data; they are never translated, whichever interface language is active.stop finish reason fails the whole call; a model that returns prose instead of a rewrite replaces your draft with that prose.Symptom · What happens Nothing changed after pressing "Polish" · Failures never touch the draft; the button shows an error state for a few seconds with the reason in its tooltip. Usual causes: no session cwd (sessionId missing or session unknown), no model selection, a finish reason other than stop, or the organizeTimeoutMs deadline The model reports a context overflow · Working as designed: input is deliberately not truncated, so the model error is the feedback. A payload above the endpoint body cap gets 413 instead Importing local roles was refused · Absolute paths are refused by default and the card has no session context. The path must live inside the built-in agents/ or a registered directory and contain no . / .. / hidden segments | Fewer entries imported than expect