快捷指令 · Quick Prompts
A DeepSeek Harness (DSH) plugin that keeps a strip of reusable prompts directly above the conversation composer.
- The strip starts empty: a single dashed pill reading 快捷指令.
- Click a chip to insert its prompt at the draft caret.
- Click the pill (or the 管理 control once chips exist) to expand the management panel inline, between the strip and the composer — no dialog, no scrim.
- The panel holds the list (name + summary + insert / edit / move up / move down / delete) and the form. Both the name and the prompt body are required. A successful add or save always collapses the panel; a failed write keeps it open and shows the error, so the draft is not lost.
- The strip itself never edits: it only inserts and opens the manager.
Everything is stored per profile through the DSH storage domain, so the list survives restarts. Nothing is pre-seeded.
Layout
| File | Role |
|---|---|
lib/index.js |
Host activation: resolves the Harness bases, mounts the service, registers one agent tool |
lib/service.js |
Durable list + the five Remote methods (list / create / update / delete / move) |
lib/schema.js |
zod schemas for records and wire payloads |
client.js |
Browser bundle: the strip, the inline panel, the draft insertion |
cordis.patch.yml |
Inserts the Host row |
locale/{en,zh}.json |
Plugin inventory title/description |
icon.svg |
Inventory artwork |
The model sees the same data through the quick_prompts tool, which calls the
same service methods as the UI.
Install
From npm:
dsh plugin --profile <profile> add dsh-shortcuts-prompt
From this repository (source install; it is plain JavaScript, so no build step):
dsh plugin --profile <profile> add github:smithtomge-alt/dsh-shortcuts-prompt
In the desktop app, install it from Plugins (Plugin Manager) instead of the CLI: the desktop profile is managed by the application. Restart or reload the page after installing so the browser half joins the Client module graph.
Publish
The package is a bundle: dsh.bundle points at cordis.patch.yml, and
dsh.client declares the browser artifact. It ships no runtime npm
dependencies — the Host resolves the Harness packages it needs at activation.
First publish (once, by hand)
npm requires an interactive two-factor challenge for publishing, so the first version is released from a terminal:
npm adduser --auth-type=legacy --registry https://registry.npmjs.org
npm run check && npm test
npm publish --otp=<current 6-digit code> # publishConfig picks the registry
The OTP is required even when you are logged in: the token npm adduser writes
is a login token, and npm only accepts a bypass token (being retired) or an
interactive code for publish.
Automated releases (trusted publishing)
.github/workflows/publish.yml publishes on a GitHub Release (or a v* tag)
using npm trusted publishing: GitHub's OIDC identity is exchanged for a
short-lived registry token, so there is no NPM_TOKEN secret to leak or rotate.
Set it up once, after the first publish:
npmjs.com → the package → Settings → Trusted publishing.
Add a GitHub Actions publisher: repository
smithtomge-alt/dsh-shortcuts-prompt, workflowpublish.yml, environment left empty.Bump and tag:
npm version patch # or minor / major — updates package.json + tag git push --follow-tags gh release create "v$(node -p "require('./package.json').version")" --generate-notes
The workflow refuses to publish when the tag does not match the manifest
version, runs the same checks as CI, publishes with --provenance, and then
waits for the registry to serve the new version. A manual workflow_dispatch
run defaults to --dry-run.
Bypass-2FA granular tokens still work for direct publish today, but npm is retiring that path for publishing, which is why this workflow does not use a secret. See Restricting npm bypass-2FA granular access tokens.
Community listing: open a PR against
awesome-dsh-plugin
adding data/plugins/<owner>__<repo>.yml; the site, the market, and the
dsh-plugin-catalog index are generated from those files. Listing the plugin is
a one-time entry — later releases need no further PR.
Boot safety
Two guarantees keep this plugin from ever aborting the page load again:
- The Client entry never rejects.
apply()delegates toactivate()inside a try/catch and reports the failure, so a broken entry degrades to "strip unavailable" instead of failingweb boot(which shows up as a DSH crash). - The Remote contract is validated locally.
preview/harness.jsmounts the realclient.jsthrough a faithful subset of the API Gateway'svalidateContribution, so a malformed contribution fails in the preview instead of in the app.
The contribution must be { package, descriptors: [...] }; the Gateway iterates
contribution.descriptors, and an object shaped as { package, methods } throws
TypeError: contribution.descriptors is not iterable — which aborts web boot.
Design notes
- Placement. The entry registers in
conversation.input.dock, the slot for full-width rows directly above the composer card, atorder: 30so it sits closest to the card. Its width and centering mirror--dsh-composer-card-max-width, so its left and right edges line up with the input box. - Theming. Colors come only from
--dsw-alias-*tokens; the stylesheet is a single element inserted for the Client run and removed with it. - Dock placement. The strip registers at
order: 19— above the built-in queue dock (order: 20) and below the goal dock. That dock ends withmargin-bottom: calc(0px - var(--dsh-composer-stack-gap) - 3px)to tuck its panel under the composer card; registering above it keeps the strip out of that negative margin instead of being dragged under the card with it. - Wire method names. The Client Gateway's Remote namespace service reserves
ctx,empty,invokeRemote,methods,name,namespace, plus the prototype membersassertMethodAvailable,has,install,installDirect,installScoped, andremove. A Remote method with one of those names fails to mount withclient api: method ... conflicts with its namespace service, so deleting an instruction is exposed asquickPrompts/delete(the UI and the agent tool keep calling it "delete"/"remove" in prose). - Host dependencies. A profile install keeps DSH's own packages inside the
application, so the Host half resolves
TypertRemoteService, the storage domain helpers, andzodthroughcreateRequireagainst the running installation instead of importing them.
No comments yet. Be the first to write one.