Starlit-Sky-code/dsh-prompt-starlight

dsh-prompt-starlight

Prompt optimizer for the DSH composer: one star button, two sliders, model switching, 11 toggleable rules. 星芒 · DSH 提示词一键优化插件。

미분류composerdeepseek-harnessdsh

Starlight · one-click prompt optimizer

A circular four-pointed-star button on the left of the DSH composer, wearing a hairline ring and soft glow so it lifts off the toolbar. One click turns your draft into a clearer, more complete, more executable prompt.

Model, strength, detail, language and rules are all editable, each in its own place: the model comes first, strength and detail are two sliders, and the 11 built-in rules toggle individually — custom rules on top. All of it lives on a dedicated settings page (Settings → Starlight), while the popover keeps only the four controls you reach for.

A standalone plugin. No DSH source edits, no index.html injection, two official slot seats.
┌───────────────────────────────────────────────┐
│  Draft text…                                  │
│                                               │
│  (✦) [+] [permissions]       [model] [send]  │
│   └ star button (left, ringed)                │
└───────────────────────────────────────────────┘

Features

· ✦ One click · Read the draft → rewrite with the rule set → atomic write-back, caret returned to the editor ✦ Editable rules · 11 built-in rules grouped as *structure / expression quality / fidelity guards*, each toggleable, with per-group counters and all-on / all-off ✦ Custom rules · One per line; they outrank the built-in rules 🎚 Slider-first · Strength (5 stops: minimal → light → balanced → strong → rebuild) and Detail (3 stops) are sliders with real stops, not three values padded into five ✦ Scenario · General / engineering / writing / analysis, folded under “More” ✦ Output language · Follow the draft / force Chinese / force English 🎛 Model switching · Pick any model the host advertises (provider · friendly name), or keep the default "follow the session model". Affects only Starlight's side call, never your session model ⚙ Settings page · Settings → Starlight: switch, shape, all 11 rules, custom rules, model, temperature / token cap / timeout — in one place ↩ Undo · A toast after each run restores the previous draft in one click ⌨ Shortcut · Ctrl/⌘ + Shift + O inside the composer 🛟 Local fallback · No model, timeout or offline → mechanical tidy-up plus a stated reason, never a silent failure 🖱 Right-click / long-press · Opens the compact rules popover (520 ms for touch); the settings page has everything else

It never sends messages, creates turns, writes to the session log, or touches other plugins' settings.

What it looks like

Popover (right-click / long-press) — four controls by default, everything else folded into “More”:

Model list expanded (the same row + chevron as DSH's native picker, no OS dropdown):

"More" expanded — rule titles only, two columns, custom rules folded one level deeper:

The gear in the popover opens a standalone settings window — the same config as Settings → Starlight, 760px wide, rules in two columns:

The "Plugin market" tab (browsing a format 1 index, read-only, install specs one click away):

Settings page (Settings → Starlight) — model first, then the two sliders, the rest collapsed:

Both are rendered from the real components by node tools/make-shots.mjs (jsdom + React + headless Edge), not hand-drawn mockups — they cannot drift from the shipped UI.

Interface details

  • The settings page leads with a star badge plus status pills (On/Off, current model) and a footer that always says Unsaved changes / Saved / In sync with disk; Save is disabled while clean.
  • Rules lay out in two columns above 560 px, with an enabled/total counter per group. Loading shows a skeleton instead of a bare "loading…" line.
  • The popover header shows an *Unsaved* pill; the undo toast carries a star and the model's friendly name.
  • prefers-reduced-motion is respected: no spin, no pulse, no slide-in.

Install

One npm package = one host half + one browser half.

A. Install from a plugin market (recommended)

DSH ships no official market — a "market" is a `format: 1` JSON index hosted at any https URL. This repository carries one, so you can treat it as a market listing just this plugin:

  1. Sidebar Plugins → More next to Experimental plugins → enable Custom plugin markets
  2. Open Discover and add the index URL (prefer the fastly host):
https://fastly.jsdelivr.net/gh/Starlit-Sky-code/dsh-prompt-starlight@main/market/index.json

jsDelivr's edge hosts differ a lot in reachability, especially on mainland China networks. Measured here:

Index URL · Measured https://fastly.jsdelivr.net/gh/Starlit-Sky-code/dsh-prompt-starlight@main/market/index.json · 本次实测可达(1.4s) https://gcore.jsdelivr.net/gh/Starlit-Sky-code/dsh-prompt-starlight@main/market/index.json · 本次实测可达(0.9s) https://testingcf.jsdelivr.net/gh/Starlit-Sky-code/dsh-prompt-starlight@main/market/index.json · 本次实测可达(1.1s) https://cdn.jsdelivr.net/gh/Starlit-Sky-code/dsh-prompt-starlight@main/market/index.json · 官方 CDN 域名,本网络下 SSL 失败 https://raw.githubusercontent.com/Starlit-Sky-code/dsh-prompt-starlight/main/market/index.json · unreachable on this network

Switching hosts is just a domain swap — the path is identical. Avoid github.com/.../raw/...: the host refuses redirects and that URL 302s to raw.githubusercontent.
  1. Install from the list. DSH installs it into the current profile pinned to the exact 40-character commit in the index, so the result is reproducible.
The index is validated with the official @deepseek-ai/dsh-plugin-market-index (npm run market:validate). The host caches a successful read for ten minutes, so a release is not visible instantly.

B. Install a pinned commit directly

dsh plugin add "git+https://github.com/Starlit-Sky-code/dsh-prompt-starlight.git#<40-char-commit>"

C. Install the prebuilt tarball from a GitHub Release

Every version ships a packed tgz, so installing needs neither a local pnpm build nor a build-authorisation prompt:

dsh plugin add "https://github.com/Starlit-Sky-code/dsh-prompt-starlight/releases/download/v0.4.1/dsh-prompt-starlight-0.4.1.tgz"
The asset name carries the version, so the URL pins the v0.4.0 tag; bump both when you upgrade.
Caveat: the download 302s to GitHub's release CDN (objects.githubusercontent.com and friends), which is frequently unreachable on mainland China networks — use option A (the jsDelivr index) or D in that case.

D. Link this directory into the current profile (local development)

$profile = "$env:DSH_HOME\profiles\desktop"
$pkg = Get-Content "$profile\package.json" -Raw | ConvertFrom-Json
$pkg.dependencies | Add-Member -NotePropertyName 'dsh-prompt-starlight' -NotePropertyValue 'link:D:\plugins\dsh-prompt-starlight' -Force
$pkg.dsh.profile.bundles += 'dsh-prompt-starlight'
$pkg | ConvertTo-Json -Depth 20 | Set-Content "$profile\package.json" -Encoding utf8

& "$env:DSH_HOME\resources\runtime\pnpm\bin\pnpm.cmd" install --dir $profile

Then restart DSH — the host half has to reload before the HTTP routes exist.

The desktop profile is named desktop, and the CLI's dsh plugin --profile refuses it. Use the GUI or the manual link above; don't copy --profile web instructions from web-edition tutorials.

Verify

http://127.0.0.1:19387/dsh-starlight/health
http://127.0.0.1:19387/plugins/dsh-prompt-starlight/client.js

JSON with providers = host half alive. JavaScript = the browser half made it into the boot graph. Both fine but no star? Hard-refresh (Ctrl+Shift+R).

Where it is listed

Channel · Mechanism · Status Index in this repository · market/index.json (format 1, official validator passes) · ✅ live, URL above awesome-dsh-plugin · one PR adding data/plugins/__.yml · 📝 entry ready in market/awesome-entry.yml, pending the "repo at least 1 day old" gate dshbase.com · per their docs, adding the dsh-plugin GitHub topic is what makes a repo discoverable · ⏳ topic still to add npm · npm publish, then dsh plugin add dsh-prompt-starlight · ⚠️ package is ready, but the starlit_sky npm account is temporarily suspended (recent security-sensitive action); publishing is refused with 403 until it lifts Personal indexes (e.g. Silentforfar's market) · each author's private index · — not something to push an entry into

Publishing to npm (optional)

npm login            # once; the publish target is already pinned to the official registry
npm publish

Then the shortest install form works:

dsh plugin add dsh-prompt-starlight
package.json pins publishConfig.registry = https://registry.npmjs.org/ on purpose. If any global .npmrc points the registry at npm.pkg.github.com, publishing fails with `ENEEDAUTH` even when you are logged in, and the error only says "you need to log in" — a genuinely hard bug to trace. Pinning the target rules that failure mode out.

Releasing: push a tag

# 1) bump the version (package.json + the two version strings in lib/index.js
#    + the watermark and About line in lib/client.js)
# 2) commit, then tag
git tag v0.4.2
git push origin main --tags

.github/workflows/release.yml then:

  1. Checks the tag matches package.json (mismatch fails, so a wrong version can never reach the market index)
  2. Runs every check: signature headers, all three test suites, plugin-card metadata, market-index format
  3. npm pack, then creates or updates the Release and uploads the tgz
  4. Re-pins the market index to the tagged commit and commits it back to main — without this, users installing from the index get the previous commit
  5. Publishes to npm when NPM_TOKEN is configured
Every push and PR also runs .github/workflows/ci.yml — the same checks plus a 2 MB unpacked-size guard.

Locally, the equivalent is two commands:

npm run market           # pin index.json to HEAD + the package.json version
npm run market:validate  # run the official validator

Optional: let CI publish to npm (Trusted Publishing, no token at all)

npm's recommended path is OIDC trusted publishing, not a long-lived "Bypass 2FA" token — that token is a key that skips the one-time code entirely, so leaking it is far worse than a leaked OTP.

Bootstrap order matters: trusted publishing is configured on an *existing* package's settings page, and there is no such entry until the package exists. So the first version has to go out with a token, and the token gets revoked right after:

Step · Action 1 · Create a Granular Access Token: 7-day expiry, this package only, "Bypass 2FA" checked 2 · Publish the first version with it: npm publish --//registry.npmjs.org/:_authToken=npm_xxx 3 · The package now exists → its Trusted publishing settings appear; configure the fields below 4 · Revoke the token (Access Tokens → Delete) 5 · Package settings → Publishing access → *Require two-factor authentication and disallow tokens*

Every later version then goes through OIDC, with no long-lived credential anywhere.

One-time setup:

  1. npmjs.com → Packages → dsh-prompt-starlight → Settings → Trusted publishing → Add trusted publisher

Field · Value Provider · GitHub Actions Organization / user · Starlit-Sky-code Repository · dsh-prompt-starlight Workflow filename · release.yml Environment · leave empty Allowed actions · npm publish

A new configuration expires in 2 days: the first successful publish must happen inside that window, otherwise it dies and has to be recreated.
  1. Repo Settings → Secrets and variables → Actions → Variables → new NPM_PUBLISH = true

From then on every tag push exchanges the workflow's OIDC token for a short-lived publish token, and public repositories get provenance for free. The workflow only needs:

permissions:
  contents: write
  id-token: write     # ← that is all

After the first successful publish, harden it: package settings → Settings → Publishing access → *Require two-factor authentication and disallow tokens*. No long-lived token can publish the package again; OIDC is the only way in.

Skipping all of this is fine too: the publish step skips itself and the rest of the release (Release asset + index re-pin) still runs.

Usage

Action · Effect Left click · Optimize the current draft (greyed out when empty) Right click / long-press · Open the compact rules popover Settings → Starlight · Open the dedicated settings page (everything, plus advanced fields) Ctrl/⌘ + Shift + O · Optimize while the editor is focused

Popover and settings-page edits both apply on Save and share one config document. Restore defaults resets every rule, slider and model override.

What the settings page holds

Navigation id: starlight.

Section · Contents Switch · Master switch; off ⇒ the button only tidies formatting and never calls a model Rewrite force · Strength (5-stop slider) + Detail (3-stop slider) + language (3 segments); the current stop's explanation sits under each slider Rules · Folded by default: scenario chips, 11 grouped checkboxes with per-group counters, all-on / all-off, master switch Custom rules · Folded: multi-line textarea, one rule per line Model (first) · Dropdown to switch models (Follow the session model or any advertised model), with ⟳ to re-read the catalog Advanced · Folded: maxTokens / temperature / timeoutMs as sliders, plus the config-file path Config file · Absolute path of the config document; a clear reason plus Retry when the host is unreachable

The footer shows Unsaved changes (amber) / Saved / In sync with disk, with Restore defaults and Save (disabled while clean).

How model switching behaves

  • Follow the session model (recommended) writes no provider/model: every click uses whatever model your session is on.
  • Picking a concrete model pins it in the config — handy when you want a strong model for chat and a cheap fast one for rewriting.
  • Host-side route order: pinned config route → the session route reported by the browser → the host default model. A failing candidate (NO_ADAPTER, missing credential, auth) falls through to the next.
  • The catalog comes from GET /dsh-starlight/models (60 s cache, ?refresh=1 forces, 4 s timeout per provider, and a failing provider only becomes one entry in errors).