78 Commits
Author SHA1 Message Date
zhu1090093659 dc7e26b9f0 refactor(shared): drop dead shared artifacts and realign references
- 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.
2026-09-27 20:47:07 +08:00
zhu1090093659 32e6a83a39 refactor(panels): render every family panel through the native layout seats
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.
2026-09-26 17:23:04 +08:00
zhu1090093659 208bb2c10e feat(skill-explorer): render the skill center through the native layout seats
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.
2026-09-26 17:10:00 +08:00
zhu1090093659 68b095272b Merge origin/dev into dev: one center-column panel family
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.
2026-09-26 16:37:10 +08:00
zhu1090093659 da32f628a5 feat(task-board): render the board through the native layout panel
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.
2026-09-26 16:14:14 +08:00
EDDYCRAZY-CC ad90e46b28 fix(settings): bind family cards to the profile entry the Host serves
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.
2026-09-25 15:39:12 +08:00
EDDYCRAZY-CC 305a38634c feat(skill-explorer): move the skill center into the center column
The skill center was a body-level overlay modal and the only family surface
that did not share the center column. It is now a center-column panel like ssh
and the task board: a header with the back-to-conversation control, a
skills/create tab bar, and the family's control vocabulary, still
theme-token-only.

Panels now share one occupancy table: shared/client/panel-mount-core.ts owns
PANEL_FAMILY (activation name and html attribute per panel) instead of the
pairwise sibling options. Opening a panel clears the other rows' attributes and
broadcasts its own name; an open panel closes when the broadcast name is not its
own. The pairwise shape could not express three panels, so a panel that did not
name the third one stayed logically open while invisible and its sidebar row
needed a second click to reopen.

The skills list adopts the family's row treatment, the refresh control hides
while a load is in flight, and the create tab resolves the workspace it needs
when it is the first tab opened. The semantic-attributes contract drops
card/head; the wallpaper-exclusive skin re-anchors its skill center rules on the
panel root plus skill-row (committed in the dsh-skins repository, pinned here).

Generated copies follow their sources: ssh and the task board mounts lose the
sibling options, the skill center gains a panel-mount-core copy, and the
aggregate artifact plus the market dist are rebuilt.

Authored by yupeng.jia <yupeng.jia@momenta.ai> as ad47d3a4 on the contribution
fork; re-applied here on the current dev (the original was based on 53ec2ed1,
108 commits behind) with the generated artifacts rebuilt rather than taken from
the stale base, and the skin-center content re-applied in its own repository.
2026-09-25 14:47:18 +08:00
zhu1090093659 e09bd211d3 feat(dsh-update): split the self-update surface into its own plugin row
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.
2026-09-25 10:22:27 +08:00
zhu1090093659 21f3b4d72a refactor(preset-center): consume the extracted preset center instead of carrying it
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.
2026-09-24 13:13:17 +08:00
zhu1090093659 57d1499ddf test(vitest): give the family test setups a usable localStorage
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.
2026-09-24 09:54:51 +08:00
zhu1090093659 9004d0ee7d refactor: consume the extracted plugins instead of carrying them
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.
2026-09-23 23:19:08 +08:00
EDDYCRAZY-CC 0da5046cd2 feat(usage): seat a collapsible price glance card below the sidebar Settings row
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.
2026-09-23 19:48:33 +08:00
zhu1090093659 ef637f657d feat(aggregate)!: remove dsh-doctor and dsh-tool-describe-image from the family
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.
2026-09-23 17:05:26 +08:00
EDDYCRAZY-CC 0520e8a479 fix(sidebar): align entry rows with the shell panel rows and drop the usage row
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.
2026-09-20 21:48:43 +08:00
zhu1090093659 40f5f2927d chore(sdk): move the family to the 0.1.6-alpha.2 cohort on the permanent alpha branch
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.
2026-09-20 21:48:39 +08:00
EDDYCRAZY-CC 8ad234c0dc fix(dsh-web): resolve issues #1587, #1588, #1589, #1592, #1597, #1600
- 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)
2026-09-17 00:58:01 +08:00
EDDYCRAZY-CC f489c925c8 feat(liangshen): add the plugin settings card
The six settings the Host plugin declares had no UI at all: they existed only
in the settings schema, so the operator had no way to reach them. The card now
renders every field into the Web UI plugin group beside the remote-access and
task-board cards.

- a card over the dsh-liangshen namespace with the presentation choice
  (ptc/native/both), the phase switch, and the three reasoning levels, each
  with the inherit option so a field can fall back to the composition layer.
- the shared card trio (PluginSettingsCard, settings-form, the module CSS) is
  synced in: dsh-liangshen joins SETTINGS_CONSUMERS, and the copies carry the
  generated header rather than being hand-written.
- the card shell reads a fixed set of framework keys (save, discard, expand,
  collapse, notExposed, ...) from the owning namespace, so those join the zh/en
  dictionaries and their ru mirror.
- zh/en/ru carry the field copy, the choice labels, and the framework keys;
  pnpm i18n:check stays green.
- a spec drives the card through the shared popup control (the custom trigger,
  not a native select, which only appears under an appearance skin).
2026-09-16 23:55:03 +08:00
zhu1090093659 7d236e315e perf(web-all,skin-center): share one body mutation observer and coalesce shell DOM syncs
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.
2026-09-11 11:56:12 +08:00
zhu1090093659 d6ad39cb91 feat(preset-center): community agent presets through the Workshop
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.
2026-09-09 19:07:01 +08:00
zhu1090093659 02c627969e feat(dsh-model-capabilities): disable and enable custom providers in place
Both model pickers (the composer's and the subagent selection) read the same
host-built model catalog, which is driven by the adapter route registry, and
the pi-ai config has no native disable field - so the sanctioned seam is the
official Remove-provider write: unset llm-pi-ai.providers.<route>.

Disable now stashes the user-layer profile in the plugin's own settings
namespace (registered by the host half, mount-once guarded) before unsetting
the route; enable restores the archived profile verbatim and clears the
archive. Orderings keep the worst case a duplicate archive, never a lost
profile; enable refuses when the route grew a newer profile; both namespaces
are revision-fenced. Disabled providers are listed in a settings.models.footer
archive area (a hand-declared route's card disappears from the Models page,
so the footer is the way back), and the settings/document-updated remote
event refreshes every open surface immediately.
2026-09-08 21:42:17 +08:00
zhu1090093659 7c497a135f refactor(perf)!: remove the built-in dsh-perf plugin
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.
2026-09-04 18:36:26 +08:00
zhu1090093659 55d5a1d387 chore(desktop-launcher): remove the desktop launcher plugin entirely
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).
2026-09-03 23:22:52 +08:00
zhu1090093659 5902cc4987 refactor(shared): extract the center-column panel-mount core
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.
2026-09-02 16:25:19 +08:00
zhu1090093659 eb2e135686 fix(shared): de-collide css module style tags and lift settings card contrast
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.
2026-09-02 13:06:53 +08:00
zhu1090093659 4b25dd7714 feat(aggregate): isolate per-plugin boot failures behind the dsh-web-all shell
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.
2026-09-01 20:34:14 +08:00
zhu1090093659 e1d650976d feat(session-archive): add built-in session archive manager plugin
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.
2026-08-31 19:45:10 +08:00
zhu1090093659 48637c9b6f feat(dsh-usage): add the usage statistics plugin with pet announcement linkage
- 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
2026-08-29 13:34:15 +08:00
zhu1090093659 24b71a4090 feat(simplification): remove the discontinued dsh-aionui-panel
The panel was discontinued (right panel owned by dsh-better-sidebar) and
its client cannot build against the 0.1.2-alpha.1 cohort now that
dsh-client-runtime is deleted upstream. Maintainer decision: remove it
with this migration instead of freezing it.

- drop the package directory and its aggregate membership
- drop its sync-shared consumer entries
- clean the bilingual README, publish-prep and packages/AGENTS.md rows
- record the decision in the preview-cohort Agent Note
2026-08-28 08:43:39 +08:00
zhu1090093659 22b55a8a90 refactor(dsh-perf): carry the better-session card in perf, not a new package
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.
2026-08-27 20:07:11 +08:00
zhu1090093659 d46fb792ba feat(better-session-manager): opt-in card with automatic legacy migration
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.
2026-08-27 20:07:11 +08:00
zhu1090093659 598fc333bb feat(web-ui-all): replace dsh-chat-recovery with external better-session
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.
2026-08-27 20:07:11 +08:00
zhu1090093659 73e456f536 refactor(shared): sync vitest.setup.ts to consumers; web-settings re-exports shared vitest config
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.
2026-08-27 01:24:34 +08:00
zhu1090093659 e7c74daefa refactor(shared): consolidate the pairing trust fence into shared/host/pair-access.ts
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.
2026-08-27 01:20:12 +08:00
zhu1090093659 60e6e75d06 feat(dsh-git-graph): git worktree parallel sessions
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.
2026-08-26 19:27:09 +08:00
zhu1090093659 ea49cead81 chore(dsh-web-all): drop dsh-miku-pet from the aggregate and sync tables
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.
2026-08-25 15:36:55 +08:00
涂山苏苏andzhu1090093659 ef0cbe88e4 feat(miku-pet): add Miku pet plugin package with work/shop/stats gameplay (#1031)
* feat(miku-pet): add Miku pet plugin package with work/shop/stats gameplay

* fix(miku-pet): address maintainer review (mount-once, path guards, config preservation, frame timers, compliance)

* chore(miku-pet): re-sync mount-once and aggregate after dev rebase

* test(sync-shared): bump copy counts after adding dsh-miku-pet mount-once

* feat(miku-pet): sleep/affection touch gameplay, lottery shop, menu revamp

- sleep animation (fall-asleep frames then resting loop) + energy restore
- affection stat (0-500): idle decay 300s -1, zone touch outcomes with 3s anims
- passive coin income +1/min, click mood +0~3
- shop: game coin exchange item + lucky lottery (10 game coins, all stats +10,
  instant prize draw with dedicated result popup)
- light anime hover menu + play-guide page (rules line-by-line, lottery odds/EV)
- robustness: frame-chain watchdog anti-hotloop, drag-end position corner fix
- new thumb assets: sleep/happy/shy/flirty/angry, shop4/6; README sync

* chore(miku-pet): refresh root lockfile for aggregate dependency

* feat(miku-pet): add host write fence, character notice, and GUI evidence (PR #1031)

---------

Co-authored-by: zhu1090093659 <1090093659@qq.com>
2026-08-25 13:39:18 +08:00
zhu1090093659 bfa4a6e788 feat(dsh-web): auto-migrate legacy aggregate during upgrade
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.
2026-08-24 15:24:43 +08:00
zhu1090093659 76e92e540c chore(repo): rename product from dsh-web-ui to dsh-web
Display and source layers rename to dsh-web: GitHub slug, docs and prose,
aggregate package dir packages/dsh-web-all with npm name
@linxin666/dsh-web-all, settings package dir packages/dsh-web-settings,
private shared package dsh-web-shared, repo-local skill dirs, and the
docs banner asset.

Runtime, wire, and storage identifiers are frozen byte-identical so
installed profiles keep resolving with zero migration: web-ui-* bundle
ids, the dsh-web-ui-market settings section id, /api/dsh-web-ui-settings
and its proxy-token header, and the dsh-web-ui-telemetry-* storage keys.
Frozen history (docs/archive, docs/release-notes, archived notes), the
JAVA-LW fork reference, and local filesystem paths keep the old name.

npm migration: the next tag release dual-publishes @linxin666/dsh-web-all
alongside the final @linxin666/dsh-web-ui-all version, then the old name
is deprecated with a pointer; dual-publish lasts two releases.

Decision record: .agents/notes/implemented/architecture/2026-08-24-product-rename-dsh-web.md
2026-08-24 14:22:14 +08:00
zhu1090093659 c055491cb3 feat(telemetry): version and channel dimensions, skin inventory, all-package wiring, bot filtering 2026-08-24 13:23:10 +08:00
zhu1090093659 2f56ff231f feat(telemetry): anonymous install heartbeats and market UV/PV summary 2026-08-24 13:23:10 +08:00
zhu1090093659 9c59e27600 refactor(task-board): migrate JSON responses onto shared writeJson 2026-08-23 20:07:30 +08:00
zhu1090093659 ef3deddc6d refactor(shared): add unified http json body/response helpers 2026-08-23 18:06:40 +08:00
zhu1090093659 626d1fac68 chore(shared): drop the retired market tab seat machine
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).
2026-08-23 13:27:53 +08:00
zhu1090093659 24c33b4c16 feat(market): reduce DSH Market to the store; category cards back to first-level sections
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.
2026-08-23 13:20:42 +08:00
zhu1090093659 e0180d4390 feat(market): merge skin center, pet and community plugins into one DSH Market menu
- dsh-market client becomes the DSH Market hub: one settings.section entry
  (id dsh-market) declaring the dsh-market.tab child slot; the Store card
  registers as the first tab panel
- skin-center / pet / community-plugins cards register into the hub tab via
  the shared two-seat machine (shared/client/settings/market-tab.ts + synced
  copies) and fall back to their own first-level section standalone; the
  seat logic is unit-tested with fake slots
- skin on-demand plan: the skin-center npm package ships only blue-fantasy
  (files whitelist narrowed); the other 17 skins stay in the repo as the
  market/gallery source and install on demand into /Users/zcl/.dsh/skins
- fresh installs seed blue-fantasy as the active skin (host seed in
  active-state); an update whose active skin vanished still falls back to
  the stock look browser-side (existing boot path)
- tests: shared market-tab seat spec, market client-apply + hub component
  specs, community client-apply dual-wiring spec, active-state seed specs,
  npm-files invariant in skin-asset-dirs
2026-08-23 13:03:35 +08:00
zhu1090093659 580f246bee feat(market): browser market card with one-click installs
- new @linxin666/dsh-client-ui-market package: settings Market section (order 150) + loopback install gateway /api/market/*

- installer core: manifest-driven downloads from dsh-market.com, conservative path allowlist, atomic replace, conflict confirm

- plugin installs through the optional pluginManager service with copy-command degradation; remote browsers read-only

- market-build: full per-asset file lists + complete asset trees for installability; CORS headers for manifest/*; aggregate + docs registration
2026-08-23 13:03:33 +08:00
EDDYCRAZY-CC b6fea32d4a refactor: remove retired dsh-skins package and dsh-aionui-panel host archive 2026-08-22 22:47:49 +08:00
zhu1090093659 4488a12c39 feat(doctor): move entry switch to the Web UI plugin group card with embedded recovery console 2026-08-22 07:13:01 +08:00
zhu1090093659 e5307c8876 feat(doctor): rescue mode foundation - supervisor, launcher, capsule, host API, console 2026-08-22 07:10:45 +08:00
Solitude 500e89a544 fix(ssh,desktop-launcher,settings): honor DSH_HOME for data paths (#802) (#894) 2026-08-21 18:50:36 +08:00