Repository navigation
Releases
Releases · 0mao0/dsh-inline-figures
v0.1.0
Added
- Grouped bar and line charts.
charttakesseriesNamesplus onevaluesarray per item:{seriesNames: ["修前","修后"], data: [{label:"图边", values:[13,41]}]}draws one group of two bars per metric, with a legend. A before/after comparison had no way to be expressed, so it was flattened into one bar per metric-and-time with the time tag concatenated into the label — which stops being a comparison. - Closing-turn channel (the figure no longer depends on the model remembering).
agent/turn-stoppingnow runs the same structure check the nudge uses: when a drawing session tries to close on an answer that carries structure (a table, five-plus list items, or comparison/plan/flow prose) and no figure, the plugin steers the agent, which re-opens the inbox so the model owes another step and draws the figure. Capped at two steers per session with a two-turn gap, so it cannot loop. Measured cause: an AnGIneer session drew 12 figures over 29 turns while individual answers shipped tables, and the old rate-only rule stayed silent for all 29 turns — the model's own reasoning said "I already drew 9 figures, I'll use a table here". - Guidance runs as a procedure, not a preference: plan the structures first, make the
draw_figurecalls in the same batch, write the answer around the figures, then self-check the prepared answer for a table or long list that should have been a figure. raster-diagnostic.txtin the session workspace records every raster degradation where the user can read it, plus a session figure-coverage line in the tool result (figures embedded in replies versus figures drawn).
Fixed
- An asymmetric before/after chart is refused with the fix in the message. A chart whose label pairs a metric with 修后 but not 修前 (or the reverse) is not a comparison, and the missing half silently drops a number the answer's own table carries. The validator names the group, the missing side, and the grouped spec to send instead. Measured case: a chart shipped
进图轮次 修前/修后, 图节点 修前/修后, 图边 修后while the same answer's table read "图规模 5 节点/13 边 → 24 节点/41 边" — the 图边 修前 value 13 was lost. - The closing channel is gated on the session's own shape. It arms only in a session that has drawn at least once; the cheap reminder channel only in a session that has already produced a structured answer. Without that gate a working session (code, commits, verification logs) would be steered into drawing figures it does not need, at one extra model step each time.
- A raster failure no longer produces a broken image. The GUI serves figure files with
Content-Security-Policy: sandbox; default-src 'none', and Chromium refuses to rasterize an SVG loaded that way — so falling back to a relative.svglink (option A's documented fallback) rendered nothing at all. Measured live in the DSH Web GUI on 2026-10-05: the.svglink is a broken image while the PNG twin renders. The fallback order is now PNG → inline SVG data URI (32 KB budget) → relative path with a loud warning. - A failed
sharpload is cached per attempt instead of forever, and the diagnostic moved out of the plugin directory: under the shell sandbox an install below~/.dshcannot be written, so the old one-timeraster-diagnostic.txtwrite failed silently and the degradation stayed invisible for two days. - The nudge's per-session counters are keyed by session and dropped on
agent/disposed. Thesession/eventobserver cannot iterate aWeakMap, and reading the agent map threwusage.values is not a function— caught byscripts/_repro-nudge-channels.mjs. - Neither channel could read the answer, so both were silently dead. Two separate causes, both found by probing the live event path rather than reading the code: (1) the usage ledger is created lazily at the first
agent/pre-step, so a session's FIRST assistant message arrived before the ledger existed and was dropped; (2) the ledger clears its own text copy at every turn boundary, so atools/post-executeread always saw an empty string. The reply text now lives in a session-keyedlatestTextmap that onlyagent/disposedclears. A frame that was measured as "12 draws, 0 nudges" is what this looked like from outside. - The session key accepts
session.id,session.header.id,agent.sessionIdandagent.id. Reading onlysession.idworks on the realSession(a getter over its header) but degraded every equivalent object to'unknown', which is what the repro exposed. decideNudgereads the reply text fromusage, never fromopts: text passed in the wrong argument silently degraded every call to the counter fallback. The readable-text path also had no reminder exit at all — only the steer — so a session that stopped drawing went silent instead of reminding.
v0.0.3
Added
- Published to npm:
npm i dsh-inline-figures, ordsh plugin --profile <profile> add dsh-inline-figures.
Changed
- The Chinese README is
README-zh.md(wasREADME.zh.md). npm picks the README for a package page by globbing{README,README.*}in the package root and taking the first match, in directory order — with two matches the Chinese file won, so the package page showed Chinese for an English-default project. A hyphen keeps it out of that glob, which makes the English README the only candidate. - README install order is npm first again, now that the package is on npm.
- The
allow-versionexample no longer pins a stale version; it takes<version>.
v0.0.2
Added
- A "How it works" diagram in the README, one render per language, generated from a single layout by
scripts/make-readme-diagram.mjs.
Changed
- README head is a machine-readable
name/descriptiontable, so a reader — human or model — can tell what the plugin is before reading any prose. - README install order: the repository spec comes first, because the package is not on npm yet.
- README "What it writes to disk" spells out the persistence: the session workspace only, no network calls, no uploads, no telemetry, 200 figures per session, and a figure is a reference rather than a copy.
- README dropped its Releasing and Known issues sections. Release steps now live in
docs/MAINTAINER-NOTES.md, together with the open defects. - Line endings are LF everywhere, matching the
.gitattributesthe repository declares.
Fixed
- Figures are readable in a dark GUI. A rasterizer has no
prefers-color-scheme, so the PNG kept the stylesheet's light values on a transparent canvas and left titles, axis labels and timeline labels dark-on-dark. The PNG now gets an opaque canvas; the archived.svgstays transparent and theme-adaptive. - Concurrent draws no longer collide. Three or more same-slug
draw_figurecalls in one step could fail to allocate a file name. A retry now re-reads the directory instead of incrementing a number that was read before the first write. - The CHANGELOG carried two
## [Unreleased]headings, which madescripts/release.mjsread an empty section and refuse to release.
v0.0.1
First public release.
Added
draw_figurehost tool: a JSON figure spec (or a hand-authored SVG) goes in, a full-width figure file plus one inline Markdown line comes out.- Five spec kinds:
raw_svg(primary path, for free-form structures),architecture,compare,timeline,chart. - Deterministic layout engine in
lib/figures/— 680-unit logical canvas, 1600-wide intrinsic size, golden-snapshot tested, never draws outside the canvas. - SVG sanitizer for model-authored figures: rejects scripts, doctypes, entities, iframes, embeds and objects; strips event attributes, external references,
<image>,<foreignObject>and comments. - Portable
./engineentry with zero DSH or cordis dependencies, so the same renderer works in any Node or browser app. - System-prompt guidance section: when to draw, how to place the figure, and the ASD-STE100-style prose and label rules.
- Soft nudge: one self-contained reminder when a session draws far below the guidance rate.
- PNG raster twin for every figure, because the GUI serves files with a CSP
sandboxheader and Chromium refuses to rasterize an SVG served that way.sharpis a normal dependency and ships prebuilt binaries, so the install needs no build step. - Figure hygiene: per-session
.gitignore, monotonic file numbering, and a 200-file LRU prune that removes a PNG twin with its SVG. - Unit tests for the schema, the four presets, the sanitizer, the host file helpers, the nudge policy, the guidance text, the release gates and the official host-plugin contract, run with
node --test.
Changed
- Packaged for the official install path. The harness supplies the
@deepseek-ai/*runtime packages, so they are peer dependencies, not dependencies: nothing duplicates the runtime inside the profile, and the plugin manager refuses an incompatible runtime before it installs anything.dsh plugin addand the Web Plugins page are the supported ways in; the hand-rolled offline installer is kept only as a fallback for machines that cannot reach a registry. - Renamed from
@local/dsh-inline-figurestodsh-inline-figures; the bundle patch row now names the package, and the two are checked against each other. - Every contributed resource registers through
ctx.effect, so disabling the plugin row removes both the tool and the prompt section. - Added the display metadata the plugin manager reads without activating the plugin:
locale/en.json,locale/zh.json, and an exportedicon.svg. - README in two languages:
README.md(English, default) andREADME.zh.md, each with a switcher at the top and its own rendered hero image (docs/assets/before-after.png,docs/assets/before-after.zh.png). Both come from one script, so they cannot drift apart.scripts/release.mjskeeps the version badge of every variant in step, and the test suite fails if one drifts or if a variant points at the other language's picture.