- Remove the sync-manifest entry for shared/host/run-guarded.ts and the three
generated copies under packages/{dsh-usage,dsh-task-board,dsh-git-graph}/src/host/:
nothing in this repository imported the module (the satellite repositories
carry their own copies), so the entry only kept three unread files in sync.
The shared source and its spec stay.
- Delete the unused mobileBundle helper and its node:module createRequire import
from shared/tsdown.client.ts; the standalone mobile bundle has been gone since
0.4.0.
- Update the sync composition guard in scripts/sync-shared.test.mjs (99 -> 96
copies, 48 -> 45 host copies) and refresh scripts/lib-artifact-fingerprints.json.
- Re-point the notes, READMEs, CONTRIBUTING and docs that still linked the
skin-center contract files to the dsh-skins repository, and prune the stale
screenshots.
- Record the decision in
.agents/notes/implemented/simplification/2026-09-26-dead-shared-artifacts-removed.md
and correct the run-guarded facts in the aggregate fault-isolation note.
ssh is the last panel that took the center column over at the DOM level. It
now registers a row in the shell's own panel list (sidebar.panellist) and a
keyed page in the layout's main slot, like the task board and the skill
center, so the shell owns the row box, label, highlight, rail and switch.
That retires the whole takeover apparatus:
- shared/client/panel-mount-core.ts and shared/client/sidebar-entry-core.ts
are deleted along with every synced copy; ssh's mount.tsx, sidebar-entry.ts,
panel-mount-core.ts and sidebar-entry-core.ts go with them. The
body-mutations hub now serves only the aggregate shell and the usage card.
- The dsh-panel-activate handshake and PANEL_FAMILY occupancy table are gone:
the layout's keyed main slot is the single occupancy authority, so the board
and the skill center no longer coordinate with anyone.
- The terminal survives the move because the PTY session is host-owned (see
the previous commit): the layout unmounting a deselected page costs the view
its xterm instance, not the remote shell, and the terminal tab reattaches by
session id. The panel's tab, connect request and session id live in the
controller rather than in component state.
Tests move with the design: the takeover specs (center-panel-lifecycle,
center-column-css, sidebar-entry, the layout specs, board/ssh coexistence) are
replaced by native-panel-registry specs that drive the real SlotCore, plus a
controller-state spec for ssh's view state.
Validation: pnpm typecheck; pnpm test (ssh 202, task-board 561, skill-explorer
121, shared 107, all packages green); pnpm test:scripts 342/342;
pnpm test:standards; pnpm docs:check; pnpm i18n:check; pnpm aggregate:check;
pnpm libs:check; pnpm market:check.
The skill center stops taking the center column over at the DOM level. It
contributes a row into the shell's own panel list (sidebar.panellist) and a
keyed page into the layout's main slot, and drives ctx.layout.selectPanel —
the same shape the task board already uses, so the shell owns the row box,
the label, the active highlight and the collapsed rail. mount.tsx, the
hand-drawn sidebar row, and the package-local panel-mount-core /
sidebar-entry-core / body-mutations copies are gone.
The panel's tab and editor target move from SkillPanel component state into
PanelController. The layout mounts a keyed page only while its panel is
selected, so component-local state dropped the open tab and any in-progress
edit on every panel switch; SkillPanel now reads the controller snapshot
through useSyncExternalStore. panel-state.spec.ts locks that contract, and
native-panel-registry.spec.ts drives the registration against the real
SlotCore.
ssh still takes the column over at the DOM level, so native-panel.tsx keeps a
transitional dsh-panel-activate handshake with it (and the task board keeps
its side). Both go away when ssh moves to the native seats too.
sync-shared loses the skill center's three copies: the copy-count buckets are
102 total / 42 client, and ssh is now the only consumer of
sidebar-entry-core and panel-mount-core.
Validation: pnpm typecheck, pnpm test (skill-explorer 121, ssh 210,
task-board 565+1 skipped), pnpm test:scripts 342/342, pnpm test:standards,
pnpm docs:check, pnpm i18n:check, pnpm aggregate:check, pnpm libs:check and
pnpm market:check all pass.
Brings in the 11 upstream commits, chiefly 305a3863 (skill-explorer moves
into the center column). Both sides had reworked the same panel subsystem
from opposite directions, so the merge integrates rather than picks a side.
- shared/client/panel-mount-core.ts keeps the upstream PANEL_FAMILY table
(one occupancy row per panel instead of pairwise sibling options) and
documents that the task board left the core for the native layout seats.
- The board keeps its native panel registration and its dsh-panel-activate
handshake, widened from ssh alone to every DOM-takeover family panel:
coordinateWithFamilyPanels plus TAKEOVER_PANEL_NAMES now cover
skill-explorer too, so the new third panel can no longer paint over the
board while its row still looks selected. panel-coexistence.spec.ts
covers the new direction.
- sync-shared drops the board's body-mutations / sidebar-entry-core /
panel-mount-core copies and keeps ssh plus skill-explorer for the core;
copy-count buckets are 105 total / 45 client.
- The panel-mount-core extraction note records the merged design and
refreshed facts; both sides and the sidecar are re-recorded.
Merge conflicts: 14 files. Validation: pnpm typecheck, pnpm test
(ssh 210, task-board 565+1 skipped, skill-explorer 115), pnpm docs:check,
pnpm i18n:check, pnpm test:scripts 342/342, pnpm libs:check,
pnpm market:check, and the panel suites all pass.
pnpm test:standards reports 3 new violation groups, all in
dsh-plugin-manager gateway specs that another session has unstaged; they
are not part of this merge.
Move the task board off its DOM takeover: the board now registers a
sidebar.panellist row and a keyed main page through the official slots
system, and the package-local panel-mount-core, sidebar-entry-core and
body-mutations copies are retired. The shared panel-mount-core returns to
the single ssh consumer with sibling activation names.
Also folds in the plugin-manager update-patch rework (the settings tab is
replaced by a patch row on the official Plugins page, plus the desktop
launch-profile repair) and the matching Agent Notes.
Committed as a checkpoint before merging origin/dev.
A family settings card addresses its form by PROFILE ENTRY ID, but each card
knew only its own namespace. When the family binder is not loaded the cards
fell back to ctx.configForms.get(namespace) — an entry the Host does not serve
on an aggregate install. The write was rejected with "No configurable plugin
entry \"liangshen\"" while the card reported "the deployment did not accept
these values", which is what the LiangShen settings page showed for every edit.
The fallback now lives once in shared/client/settings/settings-entry-form.ts
(synced to the six packages whose card binds a family namespace) and binds the
entry id the shared describe mirror justifies, REBINDING when the mirror names
a different one of the package rows. A one-shot guess cannot be right for every
deployment: the mirror answers asynchronously — at plugin activation it usually
holds nothing yet, and the aggregate mounts its client children in order — the
bare namespace is no entry id on an aggregate install, and the aggregate row id
is wrong on a standalone one, whose row id is the namespace or the package own
ui-* row. An unanswered or EMPTY mirror counts as unanswered, not as absence;
only a mirror that answers with other packages rows falls back to the
namespace itself, which is the pre-0.1.7 keying shape.
Affected cards: dsh-liangshen, dsh-remote-web-ui, dsh-task-board, dsh-market,
dsh-usage and dsh-session-archive (the last three carried the same defect).
The aggregate and market specs now model a mirror that names the served row
instead of asserting the namespace.
Verified in the real Web GUI: the save now posts ns "web-ui-liangshen" and the
Host answers ok. The refreshed aggregate lib/ and the new fingerprints ship
with the change; the owning 0.1.7 cohort note records the binding rule.
pnpm typecheck, pnpm test, pnpm docs:check, pnpm i18n:check,
pnpm aggregate:check, pnpm libs:check, pnpm sync-shared:check,
pnpm test:standards, pnpm runtime-deps:check and pnpm emoji:check pass.
pnpm test:scripts fails only in the tar --force-local suites, which Windows
bsdtar rejects (GNU flag) and which this change does not touch.
The skill center's panel-mount-core.ts copy is a 102nd generated copy and the
42nd under src/client/, so the two bucket assertions in the sync-shared test
move with the manifest. Caught by CI: the assertion reported 102 against the
stale 101.
The self-update surface lived inside dsh-remote-web-ui, so disabling or removing the remote-access plugin also removed the update entry, and the desktop application - which owns its own updater - had no way to keep the seat off one page while keeping it elsewhere. It now ships as @linxin666/dsh-update with its own bundle row (update / web-ui-update) and its own host half behind the loopback fence.
The aggregate gains the child (aggregate.yml, cordis.patch.yml, children.*), the shared-file sync manifest carries the new consumer targets, the ru dictionary moves its update namespace to the new file, the three old note records are updated in place for the new owner of the surface, and the market's committed lib is rebuilt for the shared guard it carries.
The preset center now lives in its own repository (dsh-presets) and is consumed
here as the published npm package @linxin666/dsh-client-ui-preset-center, the
way the skin center, the pet plugin and the community plugin index already are.
- packages/dsh-preset-center leaves this tree (plugin sources, tests and the
presets/ catalog; history stays in this repository);
- the aggregate mounts it through an external rows: entry (web-ui-preset-center)
with a hand-written ^0.4.1 range, and ./preset-center stays in the exports map
as a tombstone so profiles written against the patchFrom era keep importing;
- market-inputs.lock.json gains a presets input pinned to the
satellites/dsh-presets gitlink, and scripts/market-build reads
.market-inputs/presets with the in-repo fallback kept for the fixture tests;
- scripts/sync-shared.mjs stops mirroring five host helpers into the package
(101 -> 96 copies); the lib fingerprints, coverage baseline, test-standards
baseline, runtime-deps scan and i18n audit each shrink by one package;
- the contribution gate has no exception left: reject-non-content-pr.yml
redirects a 新预设收录 declaration to dsh-presets, and the PR template,
CONTRIBUTING.md, PR_TRIAGE.md and ISSUE_TRIAGE.md now state that this
repository accepts no external contribution directly;
- docs, the family-satellite owning note and the two preset notes follow, and
the new Agent Note records the split.
Gated by: typecheck, aggregate:check, libs:check, sync-shared:check,
runtime-deps:check, i18n:check, emoji:check, docs:check, market:check,
test:standards, test:scripts (340 tests), test (every package) and build.
Not yet safe to merge on its own: the satellites/dsh-presets gitlink needs that
repository to exist on GitHub, so the satellite commits and this pin have to be
pushed together.
Node 25 defines localStorage on the global object, and without a usable
--localstorage-file its getter returns an empty object: getItem, setItem and
clear are all missing. Vitest's jsdom environment fills in globals only where
the name is still free, and under vitest window is globalThis, so that stub
survived into every DOM test: the packages whose code reads storage took their
degraded paths instead of the code under test, and dsh-task-board's specs failed
outright on window.localStorage.clear.
The shared setup now installs a Storage in a DOM environment and removes the
stub where there is no DOM, which is what Node 22 leaves behind. dsh-git-graph
and dsh-task-board join its copy manifest, and dsh-skill-explorer's own setup
imports the shared source.
Measured on Node 25 against Node 22, the repair is what moves the numbers back:
dsh-git-graph 79.53 -> 81.32 lines, dsh-remote-web-ui 69.66 -> 70.34,
dsh-skill-explorer 77.61 -> 80.22, dsh-web-settings 78.66 -> 82, with branches,
functions and statements following. Coverage no longer depends on the
interpreter that ran the suite, which is what makes one recorded baseline mean
the same thing in both.
The skin center, pet and community-index plugins now live in their own
repositories and are consumed as published npm packages, so this tree drops
them and everything that only existed to serve them in-repo.
Removed: packages/dsh-pet, packages/dsh-community-plugins and
packages/skins/skin-center (history stays in this repository), plus the root
scripts that moved with them (skin center catalog check, the reviewed-hooks
registry, the skin and pet authoring CLIs and their tests, community-index).
scripts/skins-montage.mjs stays: it renders the root README collage from
market/dist, which is this repository's tooling.
Decoupled:
- scripts/sync-shared.mjs no longer mirrors the settings trio, host helpers or
http/mount-once copies into the three packages (114 copies -> 99);
- lib-artifact-fingerprints.json tracks three committed lib/ packages now that
skin-center left;
- packages/dsh-usage drops an unused @linxin666/dsh-pet devDependency;
- the skin/pet/community gates leave ci.yml and the root scripts (they run in
the satellite repositories' own CI);
- scripts/i18n-audit.mjs no longer reads pet's client locale file, and the
test-standards and emoji audits skip .market-inputs (fetched content is not
ours to audit);
- the market build pins the community index in market-inputs.lock.json like the
skin and pet content, so the plugin list the site serves is reproducible from
a commit instead of following whatever npm resolves, and the catalog's skin
repo URLs point at dsh-skins;
- docs (root AGENTS.md, architecture, plugins, development, publish-prep) and
CONTRIBUTING point at the new repositories.
Gated by: aggregate:check, libs:check, runtime-deps:check, market:check,
sync-shared:check, test:standards, docs:check, i18n:check, emoji:check,
typecheck and 307/307 script tests.
Not yet safe to merge: the aggregate's three dependencies resolve from npm,
and the published 0.3.24 still injects the retired settingsScope service, so
the mount smoke stays red until the satellite repositories publish a build
containing the migration.
The 2026-09-18 removal left the usage overview reachable only from the
settings section. The user asked for the sidebar card back, redesigned at
the bottom-left below Settings. The new surface is a glance plus gateway,
not the retired panel: one card with a price-first headline (today's
estimated spend, falling back to today's tokens when nothing priced is
recorded), a tokens/calls line, and up to two configured-provider
balances. The card body opens the settings panel on the usage section;
a corner chevron folds it into a one-line strip persisted in localStorage
(dsh-usage.foot-card.collapsed).
- UsageFootCard.tsx + foot-card-mount.tsx: the mount appends the container
as the shell foot area's last child (no slot exists below
sidebar.settings) and self-heals through the shared body-mutation hub;
the card shares the section's store/poll and runs its own 30 s
visible-tab loop; it bows out while disabled or while the host answers
404, and hides in the 56 px rail.
- New zh/en keys usage.foot.* with ru mirrors; the body-mutations
sync-shared target returns for dsh-usage.
- The semantic-attrs contract gains the foot-card part rows and drops the
stale usage sidebar anchors; the README pair, the package description,
and the agent notes move with the change (the new foot-card note
partially supersedes the removal note, which keeps its decision with a
cross-link).
Live GUI evidence (Edge via Playwright against the running host at
127.0.0.1:3080): the card seats as the foot area's last child below the
settingsArea (256x96 expanded, 256x28 collapsed), the collapse choice
survives a reload, clicking the body opens the settings panel with the
usage section active, and the card hides in the collapsed rail; zero
console errors.
Both plugins are no longer useful and leave the family per owner direction.
The packages are deleted from the workspace; the aggregate drops their
patchFrom/deps rows and inactive entries, keeps one tombstone shell export
per removed id so old profiles degrade to an inert plugin instead of
ERR_PACKAGE_PATH_NOT_EXPORTED, and drops the stale retire block whose
target row the 0.1.7-alpha.2 host no longer mounts. The reference sweep
covers sync-shared targets and counts, the i18n audit, the ru dictionaries,
the web-settings allowlist, plugin-manager fixtures, the skin-center
semantic-attrs contract, the labeler, coverage baseline, lockfile, and
docs; desktop/runtime/profile-web stays pinned to the published 0.3.19
that still contains both packages.
The injected sidebar entry rows (task board / SSH / skill explorer) carried their
own box - 10px padding, 8px radius, 13px type - so their icons and labels sat on
different x positions than the shell panel rows next to them. They now reproduce
the shell panel-row geometry: 2px inset, 12px radius, 7px 8px padding, 36px row,
14/22 type, primary ink, and a 16px glyph box (18px on the 56px rail).
The usage sidebar entry and its collapsible panel are removed: the settings
section already renders the same overview, and the row duplicated it in a
permanent navigation slot. With its only consumer gone, the shared entry core
drops the trailing-actions API (SidebarEntryAction, the composite container, the
entryAction/entryMain CSS contract) it had grown for that row.
The pet bubble is untouched: dsh-pet has no changes here, and its announcement
API and bubble rendering are intact.
Adapt dsh-web to the experimental @deepseek-ai/dsh-* 0.1.6-alpha.2 cohort in the
same isolated alpha worktree and DSH home, so the accepted 0.1.5-rc.1 stable
environment, its profile tree and the global dsh CLI stay untouched.
Cohort: every consumed range, the plugin scaffold, the root README badges, the
CI and release mount-smoke pins, the desktop runtime pin and its lockfile, both
release-age exclusion lists and the desktop overrides block move to
0.1.6-alpha.2; the declared host floor becomes dsh.engines.dsh >=0.1.6-alpha.2.
cordis, cosmokit and schemastery keep their independent support pins.
@deepseek-ai/dsh-client-ui-workspace joins the repository exclusion list and the
packages that navigate gained it as a devDependency, because the family now
consumes it directly.
Adaptation of the SDK delta - the multi-instance Client Session model:
- SessionListState.current/currentAddress and SessionSummary.completed are gone,
and ISessions.open()/openSubagent()/clear() are removed. View selection now
belongs to the workspace UI, which owns the main-area reference and publishes
it as retainedBy.mainView; navigation is ctx.uiWorkspace.openSession(target).
- shared/client/main-session.ts adds mainViewSessionId(byId), the catalog-level
reading of that marker, and sync-shared copies it into the seven consumers.
Ten call sites across eight packages read the removed faces; two of them
(git-graph auto-isolation, session-archive) type-checked against local
structural doubles and never appeared in the compiler's error list, so the
inventory was built by searching for the removed names rather than by
trusting tsc.
- dsh-task-board's framework-free controller port changes from a list snapshot
to { current(), open(), subscribe() }; the wiring resolves current() from the
marker. dsh-git-graph navigates new worktree sessions through the workspace UI.
dsh-pet, dsh-plugin-manager, dsh-doctor, dsh-liangshen, dsh-session-id and
dsh-session-archive read the marker instead of the removed selection.
Upstream packaging defect: dsh-client-ui-primitives@0.1.6-alpha.2 imports
simple-icons from its emitted lib/index.js while the published manifest still
declares no runtime dependencies; packageExtensions restores it at the exact pin
the official source resolves (16.31.0), beside the existing diff/shiki/micromark
restorations. No installed file is patched.
Native-first: no family row registers the new sidebar panel slots, and the
alpha.1 to alpha.2 slot-key comparison is additive only. dsh-plugin-manager
already extends the official Plugins section through settings.plugins.tab rather
than mounting a parallel page, and that stays the right native extension. The
aggregate declares no external npm plugin, so the new runtime plugin dependency
resolution has no external hard-binding to unmask. The inject contract records
dsh-client-ui-workspace as an approved inject module with its rationale.
Testing: pnpm typecheck, sync-shared:check, skin-center:check, community:check,
libs:check, build, test, test:scripts, test:desktop, runtime-deps:check,
aggregate:check, emoji:check, test:standards, docs:check, i18n:check and
market:check pass, and pnpm install --frozen-lockfile --ignore-scripts resolves
the lockfile. The alpha host in ~/.dsh-alpha is upgraded to 0.1.6-alpha.2 and
every profile @deepseek-ai copy is a symlink into it (235 ok, 0 warn, 0 fail);
dsh --profile alpha-web --dump-config composes the family rows with the retired
ui-settings-unarchive-sessions row.
- task-board: pick the newest SETTLED execution for session reuse; the
launch path appends this run's open record before the rule reads it
(#1587)
- plugin-manager: resolve the packaged desktop runtime's own lib/bin.js
and run it through the host interpreter when no PATH entry or .bin shim
exists (#1588)
- plugin cards: contribute to whichever plugin-card seat the host
declares (family list seat, else the official keyed settings.plugin.item
seat) and log a refused registration instead of swallowing it (#1589)
- usage: sidebar entry + collapsible panel over the same overview
document, with the family pairing fence on the host routes (#1592)
- usage: serve the zai route, key plan windows by the provider unit,
use the exact credit ratio, and skip TIME_LIMIT/unknown units (#1597)
- plugin-manager + remote-web-ui: accumulate child output as bytes and
decode once, so a Windows CP936 console renders readable text (#1600)
Family plugins each installed their own document.body subtree MutationObserver,
so per-mutation cost grew with the number of installed plugins during chat
streaming. Add shared/client/body-mutations.ts: one page-wide observer
registered on globalThis under Symbol.for, delivering accumulated records to
subscribers at most once per animation frame. sidebar-entry-core,
panel-mount-core and the aggregate shim subscribe to it instead of observing
body themselves.
skin-center: cache the composer seat and skip the unchanged
--dsh-composer-height write, coalesce mutation-driven height and
conversation-content checks to one per frame, and write backdrop markers only
when they differ. The aggregate caches the [data-dsh-frame] lookup instead of
re-querying per mutation batch.
Controlled Chromium harness, 301 frames over 5 s, mean of 3 runs: body observer
callbacks 1503 -> 902, callback time 237 ms -> 2.9 ms, ScriptDuration
69.6 ms -> 13.6 ms, TaskDuration 984 ms -> 725 ms; LayoutCount unchanged
(natural per-frame paint layout). See
.agents/notes/implemented/bug-fix/2026-09-11-combined-plugin-mutation-cost.md.
New package @linxin666/dsh-client-ui-preset-center owns the community
preset domain: an inert library at $DSH_HOME/agent-presets/<id>/ (no
discovery root scans it), enable/disable by moving the directory into
$DSH_HOME/.agent-presets/<id>/, loopback-only /api/preset-center/* routes,
a composition profile (plugins, local code files, !!js expressions), the
reserved-id and default-preset guards, and the Presets panel the Workshop
card renders through its new dsh-workshop.panel child slot.
dsh-market gains the preset asset kind (downloads into the library, never
into a discovery root), the install-preset route, the fourth tab, and
records the manifest version in provenance. scripts/market-build publishes
packages/dsh-preset-center/presets/<id>/ as manifest/presets.json plus
assets/presets/<id>/; the worker asset allowlist and the market site gain
the preset kind. Only installed and enabled presets appear under
Settings - Agent presets.
Gates: typecheck, test, docs:check, i18n:check, market:check,
aggregate:check, test:scripts all pass.
- sync-shared copy counts follow the new mount-once consumer, so pnpm test:scripts is green again
- the archive footer lists only entries whose route is still down; a failed toggle re-reads instead of keeping a stale disabled view
- a route the composition layer also declares is refused with base-profile instead of reporting a disable that did not take effect
- refresh is scoped to llm-pi-ai and the archive namespace, concurrent describes coalesce onto one wire call, and an open draft survives a background refresh while staying fenced at its own revision
- the Agent Note ships as the standard English/Chinese/sidecar triplet with canonical Status and section names
- package AGENTS.md, cordis.patch.yml, and the semantic-attrs contract now state what shipped
BREAKING CHANGE: the dsh-perf package, its aggregate rows, ru dictionary
namespace, CI labeler rule, and issue-template option are removed. The
session-persistence-jsonl tuning patch goes with it; installs fall back
to the stock harness row. The npm badge allowlist keeps the published
name so download totals are unchanged.
The Electron desktop app (desktop/) takes over the desktop story, so the
plugin retires: package, aggregate rows and regenerated outputs (patch
block, family subpath export, workspace dependency, client-children
entry), settings-bridge allowlist rows, the remote-channel local-only
control plane (three remain), the central ru namespace, i18n-audit and
sync-shared rows, labeler path, publish-prep row, and README entries.
The npm name stays retired-but-published; the desktop runtime seed keeps
pinning the 0.3.13 aggregate until its next bump. Existing generated
desktop icons keep working (they shell out to dsh directly).
Gates: typecheck, test, test:scripts, docs:check, i18n:check,
aggregate:check all green; web-all lib rebuilt launcher-free.
Takes effect after a dsh web restart (bundle-layer change).
mount.tsx and board-mount.tsx carried ~100 identical lines of the
single-occupant takeover lifecycle (injection, sibling eviction,
remount resilience, sidebar click-out) that the fix history forced
through twice (#243/#107, c0a98c715, 170b3df31, d73bffc2a). The
lifecycle now lives once in shared/client/panel-mount-core.ts with
two sync-shared generated copies; both wrappers keep their public
exports and only wire the seven per-plugin parameters. Attribute
names stay wrapper-supplied: CSS, skins, and the semantic-attrs
contract pin them. Agent note included.
The aggregate client bundle keyed every injected stylesheet tag by
basename, so the eight same-named settings-card.module.css copies
suppressed each other and seven family packages rendered their settings
cards with UA defaults under every skin. Style tags now carry the full
repo-relative file id. The shared card chrome lifts 12-13px hint text
from label-tertiary to label-secondary (orca-link measures ~3.4:1 on
tertiary) and points the error roles at state-error-primary, which the
suite defines, instead of the nonexistent label-error token. sync-shared
gains dsh-perf for the card chrome pair only: its settings-form.ts still
runs the pre-0.1.2 per-field generation and must not be overwritten.
Live GUI verified on 127.0.0.1:3080 under the orca-link skin and the
default appearance.
The DSH loader mounts every patch row as one transactional group: a single
plugin that fails to import or start rolls back the whole family and aborts
'dsh web'. Redefine the fault unit to one plugin.
- scripts/aggregate.mjs emits each family insert row with the aggregate's own
never-failing shell module as the row name and the real plugin package in
the row config (config.plugin, original config under config.config);
dsh-i18n and all external npm rows keep mounting directly
- @linxin666/dsh-web-all main entry is the shell: it imports the real module
at start time, contains import/shape/activation failures to that entry
(logged + recorded), and mounts the real plugin as a nested plugin so
cordis service scoping, lifecycle, and retraction semantics stay intact
- loopback-only GET /api/dsh-web-all/degraded reports the degradation ledger
for doctor/monitoring consumption
- shared/host/run-guarded.ts (+ synced copies in the four packages with
in-process HTTP/poll faces) converts fire-and-forget rejections into logged
errors against the host's installFailLoud whole-process exit
- tests: shell-isolation.spec.ts runs the real installed host boot through
start-failure / import-failure / no-webServer scenarios plus the control
case proving today's direct-mount shape still kills the boot
Evidence: pnpm typecheck, pnpm test (22 packages), pnpm docs:check,
pnpm i18n:check, pnpm aggregate:check, pnpm test:scripts (234), and full
pnpm build all pass. Bundle-layer change: needs a dsh web restart.
New family plugin dsh-session-archive (@linxin666/dsh-session-archive):
complete session inventory (active, archived, blank, sub-agent,
workspace-less and metadata-incomplete rows), filter/search/sort,
full-result-set multi-select, batch archive/unarchive/physical delete
with family cascade and protected-session skipping, loopback-fenced
routes, and independent default-off auto-archive / auto-delete policies
(archive-time ledger, same-tick guard, catch-up scheduler).
Registered in the dsh-web-all aggregate; ru copy ships centrally in
dsh-i18n; sync-shared grows four copies; root/aggregate devDeps gain the
dsh-workspace and dsh-api-session-controller host-face closure; bilingual
README triplet and Agent Note included.
- new packages/dsh-usage: host service folds session usage into a persistent
per-day/per-provider ledger and probes every configured provider's balance
or coding-plan endpoint (DeepSeek, Moonshot, Kimi For Coding, GLM Coding
Plan, OpenCode Go, MiniMax, OpenRouter, SiliconFlow, ZenMux) through the
credential seam; keys stay host-side
- first-level settings section (id dsh-usage, order 151, below the Workshop):
usage tab (today totals, balances, 30-day trend) plus plans tab (quota
windows with percent and reset), served via loopback-fenced
/api/dsh-usage/overview|refresh
- dsh-pet grows the in-process pet.announce contract: bounded, validated
announcements render as a dedicated styled bubble on top of the session
bubble stack; dsh-usage announces the current provider's balance or
tightest plan window (bubbleMode: always/change/off)
- wire the family: aggregate membership, sync-shared copies with count gates,
publish-prep row, semantic-attrs entries, bilingual READMEs and Agent Notes
- the copy-count buckets lose the four dsh-aionui-panel entries removed
with the package (98/39/47)
- the not-exposed settings copy and the shared settings-form comment now
describe the 0.1.2 exposure model (owning plugin settings domain) instead
of the deleted host-apiproxy allowlist
Using better-session is itself session-performance governance, so its
management surface belongs in dsh-perf rather than a standalone family
package. The whole surface moves from the (short-lived) better-session-
manager package into packages/dsh-perf/src/bsm: core pipeline modules,
child-process service with atomic profile writes and store backup, plus
loopback-fenced /api/dsh-perf/better-session routes registered next to
the stats route. The browser half adds a Better Session card to the Web
Plugins group (slot id better-session, order 145) with its own locale
namespace; tsdown gains a companion entry emitting
lib/better-session-import.mjs, which scripts/dsh-better-session.mjs now
imports and which keeps semantic ownership single.
packages/better-session-manager is deleted again before any release;
aggregate reverts to 18 source blocks / 19 rows / 17 deps and publish-
prep inventory back to 18 packages. Tests move into dsh-perf (11 vitest,
node environment per file) and keep passing alongside the package's own
suite (51 total); CLI suite unchanged. Gates green: sync-shared/
aggregate/typecheck/test/test:scripts/docs. Composition verified via
dump-config: no manager row, integration rows still disabled. The host
picks up the moved routes only after the user restarts dsh web.
The inactive better-session integration was reachable only through a
repository checkout CLI and hand-edited profile YAML, with the storage-
switch warnings living far from the decision. A new public family package
(@linxin666/dsh-client-ui-better-session-manager) ships a Better Session
card under Settings -> Web Plugins: it declares the third-party origin on
the card, shows live posture plus both stores' counters, and gates
enable/disable behind confirm dialogs that carry the full trade-off list.
Enable runs the jsonl-to-sqlite migration first (child process; existing
store auto-backed-up; store bootstraps when absent) and only then writes
the managed override block into the boot profile's patch file - the hot-
reloaded user layer - so failures leave the profile untouched. The card
keeps no settings namespace: the patch layer is the single source of
truth shared by the card and the maintenance CLI, which now loads the
package-built lib/better-session-import.mjs instead of carrying its own
copy of the pipeline.
The importer core moved verbatim into src/core (drop/prune/dense-bridge/
head-cursor semantics mirrored from @morlay/session-rdb@0.0.11); package
vitest suite covers codec, projection, store writes, discovery across
naming eras, runImport e2e and block/posture logic (11 tests), while the
CLI node:test suite keeps argv/profile-write/status wiring coverage (3).
Aggregate grows to 20 rows / 18 deps with the active carrier row; all
better-session integration rows ship disabled as before. Gates: sync-
shared/typecheck/test/test:scripts/aggregate/docs all green; dump-config
confirms the new row activates while integration rows stay disabled.
Loading the new package requires one dsh web restart by the user.
Ingest @morlay/better-session@0.0.10 as a pinned external npm dependency following the better-sidebar/archive-manager pattern (upstream author approval); register its bundle row after the patchFrom blocks so session-persistence rewiring applies after the jsonl tuning row.
Remove packages/dsh-chat-recovery: capability overlap with better-session in-place edit/retry (fork-only approach superseded), including aggregate entries, telemetry sync target, publish-prep row, and test fixtures.
Docs: root README bilingual feature/table/licensing updates; agent note pair records the decision under implemented/architecture.
Gates: aggregate --check, docs:check, test:scripts, sync-shared:check, typecheck, full vitest all pass.
The test-harness ModuleLoader shim existed as four byte-identical copies
with no drift guard; it is now a sync-shared source with generated
package copies. The web-settings vitest.config duplicated shared's
byte-for-byte and now re-exports it, matching the tsdown preset pattern.
Git-graph, pet, and skill-explorer carried byte-identical fence logic.
The decision now lives in one shared source distributed as generated
sync-shared copies; each package keeps a self-describing thin wrapper.
Canonical tests added under shared/tests; wrapper specs stay as wiring
tests.
Four layers inside the plugin, zero DSH source changes:
- host: managed worktree verbs (worktrees/addWorktree/removeWorktree) over
the existing workspace gate; all managed worktrees live at
$DSH_HOME/worktrees/<repo-key>/<name>/ on a new wt/<name> branch; target
paths are host-constructed (clients never supply them); removal enforces
canonical-path containment on both sides, rejects dirty trees without
force, and deletes the wt/ branch only on request
- client: branch popover gains a create-worktree dialog (name + base
branch) and a worktree manager (dirty-guarded removal with inline force
confirm); created worktrees register as workspaces and open blank
sessions
- auto-isolation (settings-gated, default off): runtime-wrapped
WorkspacesService.startSession redirects a git workspace's New Session
into a fresh managed worktree (autoBaseline current|default); shape
probing degrades to official behavior, workspaces under the managed home
are never re-isolated
- agent tool (settings-gated, default off): opt-in git_worktree
create/list/remove via ctx.tools.register, scoped by the calling
session's cwd; create also registers the worktree as a workspace so it
stays useful under workspace-write sandboxing
Records the deliberate exception to the package's "git stays off the
model-visible surface" rule in the package AGENTS.md and the decision in
an Agent Note.
Follow-up to the package removal: regenerate the aggregate (18 rows, 17
workspace deps), refresh the pnpm lockfile, drop the miku mount-once and
loopback rows from sync-shared (96 entries / 44 host copies), document the
frames2d + gameplay contract in the dsh-pet README pair, and expect miku
in the repo-checkout registry scan.
Dual-publish the final @linxin666/dsh-web-ui-all for the two-release transition window, then stop automatically. Plugin-manager recognizes the legacy aggregate and performs a transactional CLI migration. Doctor introduces autoMigrate (default true) and migrates before DSH launch, preserving bundle order and verifying --dump-config before boot. Add compatibility audit gates, Agent Notes, and isolation evidence.
The seat machine was removed with the DSH Market hub; delete its shared test and drop the community-plugins consumer from the settings trio manifest (the package no longer ships a client half).
The four-tab market hub is gone: dsh-market registers only the store section; Skin Center and Pet register first-level sections (installed-only); the community plugin card is retired and its package becomes the community.json data source (inert cordis row keeps profiles and the aggregate resolving). The shared market tab seat machine and its sync copies are deleted; skin catalog now lists shipped builtins plus user dirs.
- READMEs for market, skin-center, pet and community-plugins describe the
single DSH Market section with category tabs and the standalone fallback;
skin-center documents the on-demand skin plan (package ships blue-fantasy
only, market installs into /Users/zcl/.dsh/skins, default activation and the
upgrade fallback)
- semantic-attrs contract: dsh-market row and updated anchors for the
category cards (hub tabs vs standalone sections)
- root AGENTS.md layout and docs/plugins|publish-prep updated to the same
facts
- rebuild market and skin-center lib bundles; shared market-tab seat gains
the slots/settings devDeps for its own typecheck; sync-shared test covers
the new copy