Install
Inside DeepSeek Harness, with dsh-market
dsh plugin --profile web add dshmarket
Or from the command line
dsh plugin --profile web add dsh-quick-actions
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
中文:README.md
Global Quick Actions next to every ordinary, session-backed Resident Composer in DSH. One press sends a piece of text you wrote in advance.
Preset Quick Actions ship with the package and are read-only — you can hide or clone them. Custom Quick Actions are entirely yours. Everything is persisted through DSH's local Settings and survives restarts.
What it does
- Send Actions: load a piece of static text into the draft and submit it through the official path. There is exactly one loading path,
setDraft(text)→submit(). - Three layouts: a ribbon above the input, a bar under it, or a single launcher opening a searchable panel. Switch at any time.
- Per-action send confirmation, on by default and yours to change.
- Text starting with
/is a valid Command Send Action, adjudicated by DSH itself. - Presets and customs are capped at 50 combined. At the cap, adding and cloning stop; if an upgrade or a config change pushes existing state past it, no data is lost — adding and cloning are simply refused until you are back under it.
This release has no insert action (insert at the selection, keep the editing context): DSH has not published insertText, and this release neither detects nor depends on it. Action text is static — no variables, templates or scripts. Every action is global, with no per-Agent or per-conversation visibility rules and no cross-device sync, import or export. Quick Actions never appear next to a no-session, hero or takeover composer.
Compatibility
| Item | Value |
|---|---|
| Verified baseline | DSH core packages at 0.1.7-rc.1. Note that dsh --version on the desktop build prints its dependency-set label, a different number from the core package version |
| DSH peers | >=0.1.7-alpha.2 |
| Cordis | ^4.0.4 |
| Schemastery | ^3.18.4 |
| React and React DOM (browser side) | ^18.3.1, supplied by the web shell's module table rather than installed into the profile |
| DSH UI primitives (browser side) | >=0.1.7-alpha.2, also supplied by the module table |
| Platform | web profile only |
The send and Settings contracts have no legacy compatibility layer. Unreleased source changes also support the optional conversation.composer.footer: a locally patched core places the bar below the statistics row, with the action group centered within the input's width; an unpatched core keeps the existing placement. Official 0.1.7-rc.2 does not include this slot, and installing the plugin alone does not add it.
The floor is the DSH release whose Settings form this plugin reads. Do not run it against anything older: 0.1.7-alpha.1 rewrote Settings — plugins no longer register namespaces of their own, and user data became the plugin's own Config, written into the profile. This release reads and writes the new model only, and on the 0.1.5 and 0.1.6 lines its Client never starts. For those lines, install this plugin's 0.1.0.
The verified baseline sits one release above the floor: this release is verified on 0.1.7-rc.1, and nothing this plugin consumes changed between 0.1.7-alpha.2 and 0.1.7-rc.1, so the floor stays at 0.1.7-alpha.2 and users still on the alpha channel can install it.
No upper bound is declared, but that is not a promise of forward compatibility. Two things to know:
- The prerelease lines do break published contracts. Between
0.1.2-rc.1and0.1.5-rc.1, the very field this plugin uses as its only send precondition was renamed;0.1.7-alpha.1then replaced the Settings interface wholesale, and an older release of this plugin fails to activate its Host on it (settings.register is not a function). Every DSH upgrade may need a follow-up release of this plugin; if the Quick Actions break after one, suspect another contract change and please open an issue. >=0.1.7-alpha.2does not match the next prerelease under semver. A prerelease version only satisfies a comparator with the same major.minor.patch, so0.1.8-rc.1does not satisfy>=0.1.7-alpha.2— and every DSH version published so far is a prerelease. The moment DSH ships a new prerelease, package managers report an unmet peer dependency even when the plugin is fine; conversely, semver does not stop you installing this release onto the0.1.5line either. That is semver's rule for prereleases rather than this plugin being picky: ifdsh plugin addinstalls it, keep using it, and judge breakage by the point above. (TheIssues with peer dependencies foundnote under "What a good install looks like" below has a different cause; the two show up together.)
Install
dsh plugin --profile web add dsh-quick-actions@next
Keep the @next. DSH's own npm latest still points at the 0.1.5 line, so this release is published under the next dist-tag. Without the tag you get 0.1.0 from latest, which supports only the 0.1.5 and 0.1.6 lines and fails to activate on 0.1.7. Once DSH moves 0.1.7 to latest, this plugin moves back to latest with it.
Then restart the web profile. One package is the whole thing: it carries dsh.bundle.patch, which inserts its Host half into the profile, while its dsh.client declaration makes the web app load the browser half.
Local / offline install
mkdir -p /tmp/quick-actions
pnpm --filter dsh-quick-actions pack --pack-destination /tmp/quick-actions
dsh plugin --profile web add /tmp/quick-actions/dsh-quick-actions-0.2.0-rc.2.tgz
The --filter form works from anywhere in the repository; from the package directory itself, pnpm pack --pack-destination /tmp/quick-actions is the same thing.
Use an absolute path for the tarball: dsh plugin is a pnpm forwarder and pnpm runs in the profile directory, so a relative path resolves under <DSH_HOME>/profiles/web/ and fails with ENOENT.
What a good install looks like
<DSH_HOME>/profiles/web/package.jsongainsdsh-quick-actionsboth underdependenciesand at the end ofdsh.profile.bundles. Both are maintained bydsh plugin— do not hand-edit them.You can check without starting a server:
dsh --profile web --dump-config | grep -A1 'id: composer-quick-actions'You should see
- id: composer-quick-actions/name: dsh-quick-actions. That row takes effect on the next profile boot.pnpm prints
Issues with peer dependencies found. That is expected: DSH's own packages live in DSH's install anchor, where the profile's pnpm cannot see them. Every other third-party DSH plugin in the same profile behaves the same way.
The install fails with ERR_PNPM_MINIMUM_RELEASE_AGE_VIOLATION
The install may end like this, with not one of the named packages being this plugin:
ERR_PNPM_MINIMUM_RELEASE_AGE_VIOLATION 4 lockfile entries failed verification:
some-other-plugin@1.2.3 was published at ..., within the minimumReleaseAge cutoff (...)
pnpm enforces a supply-chain policy that rejects dependencies published inside a cooling-off window (24 hours by default), and it checks the whole profile lockfile rather than only the package you are adding. So if any plugin already in the profile shipped a release in the last day without an exemption, adding anything at all is refused.
To confirm it has nothing to do with this plugin, run a bare pnpm install in the profile directory, adding nothing; the same error means exactly that. Three ways out:
Pass a flag for this one command, affecting nothing else:
dsh plugin --profile web add dsh-quick-actions --config.minimumReleaseAge=0Wait the window out. Each line of the error gives a publish time and the cutoff; once the newest is 24 hours old the install works unchanged.
Add each named
name@versiontominimumReleaseAgeExcludein<DSH_HOME>/profiles/web/pnpm-workspace.yaml, at the cost of giving up that protection for those packages.
Configuring Preset Quick Actions
The preset catalog is two parts in order: the list built into the package, then whatever the Host composition appends through Config.presets. That is the only channel for declaring presets — there is no runtime registration API.
Put config on the plugin's row:
# <DSH_HOME>/profiles/web/cordis.patch.yml
- id: composer-quick-actions
config:
presets:
- id: run-tests
label: Run tests
text: Run the test suite and paste the failures.
icon: ✅
- id: add-tests
label: Add tests
text: Add tests for that change, failing ones first.
confirm: false
Field rules:
idis required, unique across the catalog and permanent. Label, icon and text may change under the sameid;confirmis part of the safety signature, so changing it needs a newid— and so does making the text start with/, or stop starting with it.labelandtextare required;iconandconfirmare optional, andconfirmdefaults totrue.- An invalid preset (a missing field, a duplicate
id, a catalog over 50 entries) makes plugin loading fail loudly and lists every problem at once, rather than truncating silently. presetssits under the same row'sconfigas your action data (see "Settings paths" below), and this plugin never writes it. It is a DSH volatile field: editing it while the profile runs reaches the Quick Actions immediately; an invalid catalog written that way shows a catalog error in the Quick Actions area, and the next profile restart fails plugin loading with the list of problems.- Declare them in the active profile's own
cordis.patch.ymlonly. Do not put this plugin'sconfigin the home patch (<DSH_HOME>/cordis.patch.yml) or adsh --patchoverlay: DSH replaces a patch row'sconfigwhole, so that layer hides the action data stored on this row (the UI falls back to defaults; the data on disk is still there), and DSH refuses every save from then on — the UI reports the save as refused, and retrying never succeeds. Remove this plugin's row from that layer and restart the profile to recover.
Users can hide or clone a preset but never edit or delete it; a clone becomes an ordinary Custom Quick Action.
Three layouts
Layout is a global persisted setting, switched in the management panel:
| Value | Name | Where |
|---|---|---|
ribbon (default) |
Action ribbon | One row above the input, matching its width |
bar |
Action bar | With the footer core patch: a separate row below statistics, with controls centered within the input's width. Without it: the existing placement beside usage info. Actions that do not fit fold into "more" |
launcher |
Single launcher | One entry button opening a searchable panel |
bar and launcher share the same searchable panel, and the search matches labels and texts only. The management panel is where you reorder, hide, restore and clone presets, create, edit, enable and delete custom actions, and switch layout.
Command Send Action
Static text whose first non-whitespace character is / is marked as a command.
- It travels exactly the same path as any other Send Action, and the command is adjudicated by DSH itself; this plugin never parses or rewrites command semantics.
- Confirmation is on by default and can be turned off. The
confirmyou set is never rewritten. - With confirmation on, the panel shows precisely what will be submitted. The native candidate menu you get when typing
/in the composer does not appear here, so adjudication may differ from typing the same command by hand. - With confirmation off, the command is submitted in one press with no preview.
- The management form warns you when text becomes a command, but locks no control.
Settings paths
User data is the plugin's own Config, on its loader entry composer-quick-actions. DSH Settings writes it into the active profile's <DSH_HOME>/profiles/web/cordis.patch.yml (~/.dsh when DSH_HOME is unset), under that id's row config:
- id: composer-quick-actions
name: dsh-quick-actions
config:
schemaVersion: 1
layout: bar
userActionsById: { ... }
actionOrder: [ ... ]
presetStateById: { ... }
- Those five fields hold the layout, custom actions, the shared order and preset differences — the only persisted data. The same row's
config.presetsis the presets you declared, and this plugin never writes it. - Each profile keeps its own copy. The row may not exist at all until your first change in the management panel, and DSH removes it again once everything is back to its defaults.
- The plugin ships its own management panel, so it opts out of the Settings page DSH would otherwise generate for it.
The Host is the single validation authority and normalizes stored data idempotently at boot. Every change made in the UI carries an expected revision; on a conflict the panel refreshes to the latest state and asks you to confirm again, never silently overwriting someone else's write. Data written by a higher schemaVersion is kept as-is, so a downgrade round-trip loses nothing.
Migrating from DSH 0.1.5 / 0.1.6
Older releases kept the data in the composer-quick-actions section of <DSH_HOME>/settings.yaml. On its first boot, once every plugin has settled, DSH 0.1.7 renames the whole file to settings.yaml.imported and imports each section into the plugin entry of the same id — exactly once, and only for whichever profile boots first.
For that import to land, this release of the plugin must be the one running at that moment. Upgrade this plugin first, then DSH (or both within the same restart). If DSH was upgraded first, the old plugin fails to activate on it, the import fails with it, and the data stays untouched in settings.yaml.imported. Migrate by hand then: copy the five fields under that section verbatim under the row's config shown above, and restart the profile.
Upgrade, downgrade and uninstall
Upgrade / downgrade:
dsh plugin --profile web add dsh-quick-actions@<version>
With a local tarball, add the tarball of the version you want. Restart the profile afterwards. Re-adding the same version is idempotent.
Cross-version data compatibility is the Host's job: new presets are appended to the end of the existing order and nothing stored is rewritten.
Uninstall:
dsh plugin --profile web remove dsh-quick-actions
Both the dependency and the layer in dsh.profile.bundles go away. After a profile restart the actions are gone. The id: composer-quick-actions row in cordis.patch.yml stays as it is — your actions live in its config, and a reinstall picks the row back up by id, so they come back. If you uninstall without reinstalling, that row is left addressing nothing: it does not block startup, dsh --profile web --dump-config reports it as patch: entry "composer-quick-actions" not found, and step 1 below removes it.
Full manual cleanup (uninstalling does none of this, because a reinstall should restore your actions):
- Delete the
id: composer-quick-actionsrow from<DSH_HOME>/profiles/web/cordis.patch.yml— the only place user data (and the presets you declared) lives. - If a
composer-quick-actionssection is still left in<DSH_HOME>/settings.yaml.imported, delete it too. - Remove any entry you added for this plugin from
<DSH_HOME>/profiles/web/pnpm-workspace.yaml. - Restart the profile.
Development
pnpm install
pnpm build # Host ESM plus the single-file lazy-CJS Client
pnpm watch:client # rebuild the Client bundle only
pnpm test
pnpm typecheck
pnpm lint
Output: the Host is lib/index.js and lib/types.js (plain Node ESM); the Client is lib/client.js plus a sourcemap, a browser-only single-file lazy-CJS bundle; types are lib/types/**/*.d.ts, declarations only.
pnpm watch:client is not DSH GUI HMR. For a change to reach a running page, three things must hold: the profile is loading the checkout you are watching (an offline install loads a copy of the tarball), that checkout's watcher is running and has produced one complete build, and the page has refetched the new output. The Client artifact is published atomically, so a failed watch build keeps the last successful one and the page may still be running old code.
License
MIT
Comments
Comments live in GitHub Discussions. Sign in with GitHub to post or react.