2933 Commits
Author SHA1 Message Date
EDDYCRAZY-CC fb28142973 fix(web): resolve the open issue batch 1724, 1730, 1732, 1740 and 1742
/api/dsh-web-all/degraded answered an empty list while /rows still listed the
plugin, and the task board could only translate its absent routes into
"not mounted ... restart the DSH service" - advice that cannot work while
another process holds $DSH_HOME/task-board/ledger-v2.lock. A degraded record
now carries a bounded one-line reason and the task board reads it to report
the owning pid with actionable guidance; a bare 404 stays the only signal
that the routes are absent, and the one-owner-per-ledger contract is
unchanged (no lock change, no cross-process write).

The other four issues live in the skin center and are fixed in that
repository (satellites/dsh-skins, commit 82f42bd): the applied-skin contract
(#1740), the ORCA stage geometry and the semantic adapter's late anchors
(#1732), the maid-atelier trim over the plugin manager page head (#1742), and
the composer frost that made the card a containing block for the shell's
fixed tooltips (#1724). This commit moves the gitlink and rebuilds what the
market reads from it.

Also rebuilt: packages/dsh-web-all/lib (its sources moved), the market dist
for the four touched skins, and the recorded lib fingerprints.

Validation: pnpm typecheck, pnpm test, pnpm test:standards, pnpm docs:check,
pnpm i18n:check, pnpm emoji:check, pnpm aggregate:check, pnpm libs:check,
pnpm sync-shared:check, market-build --check, and the skins suite all pass.
2026-09-28 10:43:10 +08:00
zhu1090093659 30089082e1 feat(dsh-market): reuse the official plugin surfaces in the Workshop store
The store installed community plugins through its own writer chain (family
`pluginManager` service to the loopback gateway to the `dsh plugin`
CLI), which the packaged Desktop client refuses. Install through the
official in-process manager's remote face when the host publishes it, keep
the family face as the fallback, add a manage action that hands an
installed bundle to the official Plugins page via
`pluginNavigation.openBundle`, and bridge both faces with `ctx.inject`
as contract observations instead of cross-package imports.
2026-09-27 20:47:32 +08:00
zhu1090093659 eb8344c167 fix(plugin-manager): route app-owned profile installs and removals to the official manager
The packaged Desktop client's application-owned profile refuses the
`dsh plugin` CLI, so the Workshop store's one-click install failed with
the launcher refusal while `update()` already took the official
in-process manager. Give `install()` and `remove()` the same writer
selection, keep the CLI path untouched elsewhere, verify the profile
actually moved (an install must add a dependency, a removal must drop
one), and let the HTTP routes demand a `dsh` binary only when the CLI is
the writer that will run.
2026-09-27 20:47:14 +08:00
zhu1090093659 b424f237e3 feat(task-board): fold the task form into regions and surface the agent preset
The create/duplicate/subtask dialog stacked every field in one scrolling
column. It now groups its configuration into collapsible regions, task
content open by default, and every collapsed header keeps a one-line summary
of the values it holds, so the default layout needs no scrollbar; only the
modal body keeps an overflow fallback for short windows, and a region holding
a blocking error is forced open instead of reporting it out of sight.

The agent-preset pin is renamed from "Mode" to "Agent preset" in the create
dialog and the task detail. Its picker keeps the runtime roster as the
authority and groups it into built-in and user presets, shows the four
built-in rows under localized names, and defaults to an inherit choice that
names the preset a run without a pin actually uses. zh/en copy stays in the
package and ru mirrors it in dsh-i18n.
2026-09-27 20:47:14 +08:00
zhu1090093659 0a18cf62d4 feat(task-board): start task runs with dsh built-in /goal
A task row now carries an optional goalRun flag, on by default: the new-task
dialog starts checked and the task detail can turn it off. Only an explicit
false is stored, so a card that never touched the option - and every card
written before the field existed - keeps starting its runs as goal runs.

When it is on, HostExecutionRunner queues the task prompt first and then arms
dsh's built-in /goal with the same composed prompt as its objective, so the
session keeps working automatic continuation rounds until the agent marks the
goal complete. The inspection loop settles such a run from session/projections
(active stays pending, blocked fails with the goal's own reason, and
complete/paused/no goal keeps the turn verdict) instead of the first turn end,
which would have reported unfinished work as done and let a scheduled card
start a second concurrent session for the same objective.

A refused or unacknowledged /goal command is reported and the run continues as
a plain single turn; goalObjective prefixes an objective the command's own
parser would read as a goal operation.

Also updates the agent-tool surface, the zh/en locales, the dsh-i18n ru
dictionary, the package README pair and AGENTS.md, the rebuilt aggregate client
bundle with its fingerprint record, and adds the owning Agent Note plus the
goal-run test suite.
2026-09-27 20:47:14 +08:00
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
EDDYCRAZY-CC 97bcd4e610 fix(client): resolve layout injection in skill-explorer, 0.1.7 settings in usage, and fence error in task-board 2026-09-27 20:29:50 +08:00
zhu1090093659 c989e5a141 chore(release): bump to 0.4.3 v0.4.3 2026-09-26 22:22:42 +08:00
zhu1090093659 1898979187 chore(skins): pin the re-anchored skin rows and publish the market
Follows the dsh-skins fix (that repository's `a342b8e`) that re-anchors the
plugin sidebar rows on the shell's native `sidebar.panellist` rows. Moving the
gitlink is what the market build reads, so the four affected skins' assets and
their try-on transforms are regenerated here together with the aggregate
bundle (which inlines the child plugins' client sources and now carries the
`data-dsh-panel-entry` glyph anchor) and the recorded lib fingerprints.

pnpm market:check, pnpm libs:check, pnpm test:standards, pnpm i18n:check and
pnpm docs:check all pass at this revision.
2026-09-26 22:14:28 +08:00
zhu1090093659 cdb8b647e2 feat(panels): give the native panel rows a per-plugin identity anchor
The shell owns the `sidebar.panellist` row box and exposes no per-entry hook,
while the retired family row attributes were the only way a skin could tell
one plugin row from another. Each panel's own glyph now carries
`data-dsh-panel-entry` (the panel id, shared with its `main` slot key) — the
one piece of that shell-owned row the plugin itself renders.

The skin center's compat adapter keys on it to keep stamping
`data-dsh-part="sidebar-entry"` on these rows, which is what the eight
shipped skins and the L2 contract anchor on (dsh-skins `a342b8e`); without
this half the adapter rule never matches and every row rule stays dead.
2026-09-26 22:13:00 +08:00
zhu1090093659 17aec421da docs(notes): record the cross-repo re-anchoring of the panel rows
The dsh-skins repository re-anchored its skin hooks on the native panel rows
(that repository's `a342b8e`): the `sidebar-entry` part now means the
plugin-registered panel row, stamped by the skin center's compat adapter from
the css-module row class plus the glyph identity the registering plugin
outputs (`data-dsh-panel-entry`). The owning family notes record the shipped
mechanism and drop the stale `panel-mount-core.ts` consequence; both sidecars
are re-recorded.

The plugin-side half of the same contract (the three native-panel glyphs
emitting `data-dsh-panel-entry`) lands with the in-flight 0.4.3 release that
shares this checkout.
2026-09-26 22:12:00 +08:00
zhu1090093659 bc854536dd chore(market): track the skin-center picker fix in the dsh-skins pin
satellites/dsh-skins 05f5d512 -> a6278e43 (fix(skin-center): follow the
host's directory-picker capability).

The commit changes src/client, lib/client.js, tests and a note; the
market's content directory (skins/) is unchanged, so market/dist is
byte-identical: the rebuild reports "dist up to date (3325 files)" and
tryon/ still verifies against its hash manifest. The bump keeps the pin
on the satellite's integration branch, which is the commit the market
build reads.

The picker fix itself reaches users through the skin-center package, not
through market/dist; publishing it is a release, not this change.
2026-09-26 21:52:04 +08:00
zhu1090093659 1e8e68b039 docs(notes): follow the satellite pins in the workshop deploy note
The deploy note still listed the pre-split content paths (packages/skins/**,
packages/dsh-pet/**, packages/dsh-community-plugins/**). The workflow has
watched the satellite pins since the family split: market/**, satellites/**,
market-inputs.lock.json and the market scripts. The note now states that,
links the satellite-repositories note that owns the pin mechanics, and
records this round's bump -> rebuild -> deploy verification.

Both sides updated and the .i18n.yaml blob hashes re-recorded.
2026-09-26 21:27:16 +08:00
zhu1090093659 8b0f32f460 chore(market): publish the 2026-09-26 skin merges and dsh-model-priority
satellites/dsh-skins 0b0ea18 -> 05f5d512: verdandi and whale-fantasy are
new catalog skins, black-gold and cafe-roastery carry their 0.1.7
adaptations, and the round's notes are on top.

satellites/dsh-community-plugins 86303de -> 9cefdcc1: dsh-model-priority
enters the index. dsh-pet and dsh-presets already pointed at their
integration tips.

market/dist regenerated with node scripts/market-build after
scripts/market-fetch-inputs.mjs materialized the new pins from their
tarballs (47 skins, 8 pets, 125 plugins, 32 presets). tryon/ is the
committed build preserved and verified against its own hash manifest,
because market/shell/dist is not built in this worktree.

docs/architecture.md: the catalog count follows the new pin (42 -> 47).

Verified: market-build --check up to date (3325 files), tryon verified
(756 files), market-fetch-inputs --check OK, node --test scripts/*.test.mjs
349 pass, pnpm docs:check passed.
2026-09-26 21:21:34 +08:00
zhu1090093659 558702c4b2 Merge remote-tracking branch 'origin/dev' into dev 2026-09-26 18:19:51 +08:00
zhu1090093659 7370eaad1d fix(plugin-manager): update an application-owned profile through the official manager
Clicking Update on the packaged Desktop client failed with "env: node: No such
file or directory". The host is GUI-launched with PATH=/usr/bin:/bin:/usr/sbin:
/sbin, so findDshBinary() lands on the darwin fallback /opt/homebrew/bin/dsh, a
Node script whose shebang is #!/usr/bin/env node. dshSpawnCommand() returned that
path unchanged off Windows, so the kernel handed the shebang to env and the child
died before the CLI started (exit 127).

Two changes repair the flow:

- A Node-script CLI is never spawned through its shebang. isNodeScript()
  classifies the resolved path by extension or by a shebang probe, and the
  command then becomes an interpreter that exists without PATH: the node
  installed beside the CLI (npm-global and homebrew layouts), otherwise
  process.execPath, which the existing ELECTRON_RUN_AS_NODE branch covers for an
  Electron host. A native executable or a shell wrapper still spawns as-is, and
  an unreadable head falls back to the previous direct spawn. withPrependedPath()
  puts the CLI's own directory first on the child PATH, collapsing every case
  variant of the key into one PATH (the Windows hazard) because dsh plugin
  forwards to the pnpm installed beside it.
- An application-owned profile updates through the official in-process manager:
  the CLI refuses "dsh plugin --profile desktop ..." outright, while the running
  host mounts @deepseek-ai/dsh-plugin-manager as the pluginManager service with
  the launcher's bundled package-manager invocation. CliGateway reads it through
  a host-supplied seam and only when facts.desktop is true; the job table,
  /status polling, the mutation queue and the version verification are unchanged,
  so a green manager call that left the version in place is still a 更新未生效
  error. The manager is a contract observation, not an import, so the package
  keeps running on a host that mounts none.

Every other runtime keeps the CLI as the single writer. README pair, package
AGENTS.md and the owning Agent Note record the new path.

Validation: pnpm typecheck; pnpm test (plugin-manager 239/239, full suite green);
pnpm test:standards; pnpm docs:check; pnpm i18n:check; pnpm libs:check;
pnpm emoji:check; pnpm aggregate:check.
2026-09-26 18:14:47 +08:00
EDDYCRAZY-CC b2c71311cc chore: remove file 2026-09-26 17:45:27 +08:00
zhu1090093659 bc4c2d437e docs(notes): one owning note for the family's native seats
The panel-mount core and the PANEL_FAMILY occupancy table no longer exist, so
"One center-column panel family" becomes the single owning note for how family
panels occupy the center column: the shell's panellist row plus the layout's
keyed main slot are the occupancy authority, view state lives in a panel
controller, and a long-lived resource is never owned by the page.

The panel-mount-core extraction note is consolidated into it (its rationale,
alternatives and consequences are preserved) and deleted with its sidecar.
Inbound links from the plugin-mutation-cost and idle-resources notes are
repaired, the task-board note's cross-plugin-exclusivity bullet now records
the handshake as the transitional mechanism it was, the skill center's package
AGENTS drops the handshake too, and every touched pair is re-recorded.
2026-09-26 17:27:22 +08:00
zhu1090093659 dea76a8fdd fix(skins): move the dsh-skins gitlink to the hermetic legacy-bridge spec
The satellite suite now pins DSH_PROFILE/DSH_SKIN_PROFILE around its
issue #788 fixture, so the profile-probing cases stay on the fixture
path even when the invoking session runs under the desktop profile.
2026-09-26 17:26:11 +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 6965f49d95 fix(scripts): make the relink range guard real semver comparison
The guard rejected any satellite version above the range's base (for
example 0.4.3 under ^0.4.2) because the caret branch demanded component
equality with the base before its upper-bound check. Rewrite the
comparison as ordered lower/upper bounds: caret bumps the leftmost
non-zero component, tilde the minor, x-ranges their first hole, and
prerelease suffixes compare by release core. Covers the shapes the
aggregate declares (caret, tilde, OR alternations, x-ranges, exact
pins); regression tests pin 0.4.3-in-^0.4.2 accepted and 0.5.0
rejected.
2026-09-26 17:20:09 +08:00
zhu1090093659 546e727297 feat(ssh): let a terminal session outlive the view that opened it
The PTY shell is now owned by the host, not by the browser view: the upgrade
handler creates one session and any later socket attaches to it by id, so a
view can detach and come back without tearing the remote shell down. This is
the survival property the DOM takeover used to provide by keeping the visited
tree mounted, and it is the prerequisite for the panel moving to the native
layout seats (where the layout unmounts a deselected page).

- engine/terminal-sessions.ts owns the session table: a bounded scrollback
  replayed on attach, per-session backpressure across every attached socket,
  a grace window for an exited shell, and an idle reap so a detached session
  never leaks for the host's lifetime. Routes keeps loopback fencing and just
  wires sockets into the registry; the registry is disposed with the routes.
- protocol: the ready frame carries the session id; the client can send
  detach (keep the shell) and close (end it).
- client: openTerminal/attachTerminal plus detach()/close(); a deliberate
  detach no longer surfaces as a transport error.
- The panel controller owns the live session id and the active tab, and
  TerminalTab reattaches on mount and detaches on unmount, so a remount
  restores the terminal with its scrollback instead of a blank screen and a
  second shell.

Validation: pnpm typecheck; pnpm --filter @linxin666/dsh-ssh test (26 files,
215 tests) including the new terminal-sessions.spec (detach/reattach, expanded
scrollback, explicit close, idle reap, exit grace window).

Note: run this package's tests through pnpm (or its own .bin): the workspace
root .bin resolves vitest against jsdom 29, which serializes a CSS custom
property value without the space after the comma and fails an unrelated
terminal-font assertion.
2026-09-26 17:17:10 +08:00
zhu1090093659 b510711e80 fix(scripts): repoint the aggregate's satellite rows at local checkouts
The desktop host resolves the external rows the aggregate's patch
contributes from the aggregate package's own node_modules, where pnpm
links the satellite dependencies to published registry tarballs. A
satellite commit followed by a host restart therefore kept loading the
released copy: the reported skin-center picker error and the macOS
system-wallpaper list survived a restart even though the local checkout
carried the fix.

link-profile.mjs now repoints those four links at satellites/<repo> when
the checkout has a built lib/ whose version satisfies the declared
range, so the same script that already wins the profile layer for
family rows also wins the aggregate layer for satellite rows. pnpm
install reverts the links; rerunning the script repairs them. The flow
is documented beside the satellite commit rules it complements.
2026-09-26 17:15:47 +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
zhu1090093659 272a730709 chore(satellites): push the skin pin to the remote and move the four gitlinks
The dsh-skins gitlink recorded b6dea218, which existed only in this
checkout: the remote answered 422 for it and the codeload tarball URL
the market fetch falls back to answered 404, so every fresh clone and
CI would fail on `pnpm market:fetch` while the run that moved the pin
succeeded by copying the working tree. The two commits it carried are
now merged onto dsh-skins main (5217459) and pushed, which keeps both
of them reachable and makes the pin resolvable.

Move the remaining three gitlinks onto their remote mains, which are
strict descendants of the pins they replace:

- dsh-skins  b6dea218 -> 5217459 (blueprint #6, miku #8, claude #2,
  the frame-height and generated-artifact notes, the orca-link brand
  row fix and the skin-center folder picker fix)
- dsh-pet    855611d -> 9643959 (aggregate-shell pet toggle #1)
- dsh-community-plugins 54af365 -> 86303de (dsh-wx-bridge #2,
  agent-body #6, the three-axis assessment note)
- dsh-presets c94885b -> f3578f4 (README popularity showcase)

Regenerate market/dist from the new pins: the claude skin and the
miku READMEs enter the store, and blueprint / miku / orca-link
assets follow their sources. `pnpm market:check` reports the dist
up to date at 4080 files.

Record the push-before-pin rule in the note that owns the gitlink
pin, which is where the tarball fallback is described.
2026-09-26 15:56:48 +08:00
zhu1090093659 41e6c6f170 docs(contributing): require committing satellite submodule changes
A satellite under satellites/ is its own repository: edits written from
this checkout are not collected by this repository's git add, so a bare
commit here leaves them dirty (status shows m satellites/<name>) and a
later checkout or clean can drop them. Record the two-step rule - commit
inside the satellite, then commit the moved gitlink here - beside the
submodule flow CONTRIBUTING already owns.
2026-09-25 23:09:00 +08:00
zhu1090093659 629ec2a336 fix(skins): pin the skin-center picker fix and macOS wallpaper removal
Move the dsh-skins gitlink to the commit that repairs the wallpaper
folder picker (the missing remote.directoryPicker inject) and drops the
macOS built-in wallpaper scan, so the macOS library is the folders the
user adds and the feature starts disabled there.

The market lock records no content hash for this input — the gitlink on
this branch is the pin — and no skins/ asset changed, so there is no
market reproduction to redo.

Submodule commit: b6dea218c17d9718041ef080220b426527fceb86
2026-09-25 23:08:21 +08:00
EDDYCRAZY-CC 828bb6bdd4 fix(remote-web-ui): supervise a running tunnel by its public URL
A connector that loses its Cloudflare edge registration keeps its process and its metrics port alive while the minted hostname stops resolving. The lifecycle judgement covered only a URL timeout and a process exit, so the manager reported 'running' forever, the relay kept forwarding paired phones to the dead address, and the phone got Cloudflare 530 / Error 1016 instead of the relay's offline page - measured in issue #1723 for over four hours with no self-healing path.

TunnelManager now probes the public URL of a running tunnel every 60s and, after two consecutive failures (DNS failure, refused connection, timeout, or a Cloudflare 5xx such as 530/1033 - an unauthenticated 401/403 still counts as alive), calls the existing fail() path: the process is stopped, the phase goes to 'failed', and the ordinary backoff restart mints a new URL that re-registers the relay. The probe, its interval, its failure budget and its timeout are injectable seams.

The public URL is probed rather than cloudflared's local /ready endpoint: the package's Tunnel handle exposes no readiness face, and the public URL is the address the phone actually uses, so one measurement covers DNS, edge registration and origin reachability.
2026-09-25 22:41:43 +08:00
zhu1090093659 a00f7ebd6d fix(skins): move the orca-link pin to the desktop brand-row fix
The dsh-skins pin moves to cb1f8a9, which seats orca-link's wordmark,
link chip and pricing light in the macOS desktop shell's brand row
instead of the traffic-light caption strip, and market/dist is rebuilt
from the new pin.

Market gates: market:check (4063 files), market:verify (3103 asset
paths).
2026-09-25 21:10:29 +08:00
zhu1090093659 45fd26ab74 chore(satellites): bump the pins for the README popularity showcases
Record the satellite commits that showcase each Workshop category's three
most-liked items on dsh-market.com:

- dsh-skins 4bc73e1 (skins)
- dsh-pet ef70ab8 (pets)
- dsh-community-plugins 33cd5f1 (plugins)
- dsh-presets f3578f4 (presets)

No market input changed (skins/, assets/, presets/, community.json), so the
committed market/dist stays valid.
2026-09-25 20:49:38 +08:00
EDDYCRAZY-CC 767512ecfd feat(liangshen): measure V4.1 Flash evaluation honestly and settle the defaults
The LiangShen V4.1 Flash comparison needed evidence before any default could
move, and the tooling could not produce it: a run could not price itself, could
not tell a workspace that failed to reach a host apart from a model that
guessed, and recorded a Windows shim scripting error as the DSH version.

Runner and report:
- add tools/prices/deepseek-flash.json (CNY per million, published off-peak row)
  and price runs and the budget gate from it via --budget-cny; cost is no longer
  a conversion factor living in a reader's head;
- separate WEB_* transport failures from the tool errors the model caused, so an
  unreachable host never reads as a model mistake;
- record research calls and the inspections preceding the first write, the
  guardrail the external we-need experiments measured falling from 30 to 6;
- report a metric an older record does not carry as unmeasured rather than as a
  measured zero;
- derive the DSH version from a version token and fall back to the package the
  dsh shim resolves to.

Corpus and analysis:
- add three external-verification tasks whose facts are published outside the
  workspace, plus two workspace-local authority tasks that keep the same
  guardrail measurable without the network; every new check fails on its seed;
- state in analyze-session whether the log carried reasoning text, because a
  signed block with an empty string makes an empty counter look measured.

Decision record:
- move the improvement plan to implemented with the measured outcome: all five
  arms passed 15/15 and every paired comparison was 0.0pp, so the shipped
  persona and presentation 'both' stay the defaults; the candidate persona
  showed no advantage and the ptc presentation traded a cleaner tool surface for
  63 percent more output tokens;
- archive the evaluation snapshot and update the README pair.

Gates: pnpm typecheck, pnpm test (350 tests in the package, 8 focused additions),
pnpm test:standards, pnpm docs:check, pnpm i18n:check. pnpm test:scripts fails on
this host for a pre-existing unrelated reason: scripts/ pass GNU tar's
--force-local while the system tar is bsdtar 3.8.8.
2026-09-25 17:07:46 +08:00
zhu1090093659 6ca8b90d69 feat(pet)!: remove the pet directory diagnostics panel from settings
The pet settings page rendered every startup registry warning as a list of\nabsolute local paths above the display fields. Drop that presentation: the\nsatellite commit strips the controller fetch, the snapshot projection and the\ncard block, the zh/en dictionaries lose settings.diagnosticsTitle, and dsh-i18n\nloses the ru key so the i18n gate stays green. The README pair now points at\nnode scripts/dsh-pet validate <dir>. The host keeps the registry diagnostics,\nPetService.diagnostics() and the /api/pet/diagnostics route.
2026-09-25 16:07:04 +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 67f421a5cc test(sync-shared): move the copy-count buckets for the third panel core
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.
2026-09-25 15:00:18 +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
EDDYCRAZY-CC 607d207b5c fix(liangshen): declare the preset when the registry arrives late
The agent-preset registry's publication is decided by its own dependency chain
(the official registry injects loader and sessionProjections, and reaches
settings through ctx.inject), so a cold start can activate this row BEFORE the
service exists. The single declaration attempt then warned and gave up, and the
preset stayed missing until an unrelated settings write happened to re-arm the
row -- which is exactly the report: toggle any switch and it appears, and only
then (issue #1721).

The registry cannot simply be injected: a deployment may compose none at all,
and waiting on it would pend the row forever, which the host's boot gate turns
into a failed web boot rather than one dead plugin (issue #1712). So the row
keeps probing and degrading, and ctx.inject supplies only the late edge.

That recovery is gated on a registryMissing flag rather than re-arming
unconditionally: cordis runs the callback asynchronously even when the service
was already present at activation, so an ungated re-arm would release and
re-declare the declaration the activation had just registered. The child fiber
the callback runs under never makes this row pending, so the boot gate stays
out of it.

Also refresh the aggregate lib/ output and its fingerprints, and record the
decision in the 0.1.7 cohort note that owns the volatile settings model.
2026-09-25 13:58:06 +08:00
EDDYCRAZY-CC 67a720a4e6 chore(market): regenerate the dist for the moved skin pin
The dsh-skins pin now carries the upstream skin adaptations plus the
blue-fantasy and skin-center 0.1.7 fixes, and market/dist is derived from the
pinned content -- so the committed site was stale against the new pin
(ice-princess, mid-autumn, observatory, pixel-anime, shangmei-jinbi and
whale-maid all moved upstream, and blue-fantasy carries this branch's two
fixes). Regenerate it with scripts/market-build.

market/shell/dist is absent in this checkout, so tryon/ stayed at its
manifest-verified bytes; the check passes against that manifest.
2026-09-25 13:40:41 +08:00
EDDYCRAZY-CC 8c161ef398 docs(notes): keep the foot-row and cohort notes current with the 1710/1717 fixes
The foot-row note owns the wide-foot layout decision, so its decision list now
carries the #1710 finding: the action seat is a shared container, a box on it
scaled with third-party registrants and squeezed the shell's own Settings
trigger, and the seat is now display: contents with family triggers on the
bottom line and foreign registrants on a row above. Its rejected alternatives
gain the :has() guard the report proposed, its consequences and its testing
section state what the spec pins and what GUI evidence is still owed.

The 0.1.7 cohort note owns the volatile settings model, so its schemastery
bullet records that dsh-usage and dsh-remote-web-ui still imported the vanilla
package after the first migration pass, and states the rule that catches the
class of drift. Both notes' Chinese sides and sidecar hashes move with them.

Also bumps the dsh-skins pin to the commit carrying the two skin adaptations
and their note.
2026-09-25 13:40:41 +08:00
EDDYCRAZY-CC 3615f779d5 fix(remote-web-ui): stop the footer seat box from breaking the settings row
The wide-foot rules treated the sidebar.footer.action seat as this plugin's
own icon row and gave it a box (flex: none, order, align-items). The seat is
a shared container: as soon as any other plugin registered into it, the seat
became a tall column and the shell's own settings trigger -- an element this
plugin does not own -- was squeezed to 102px and vertically centred inside it,
with the whole footer growing to 515px over the session list (issue #1710).

Drop the seat's box (display: contents) so its occupants answer to the foot's
own wrapping layout, give a non-family registrant a full line of its own, and
keep the family trigger intrinsic-width on the settings line. The intended
result stands: settings on the left taking the remaining width, the family
trigger beside it, every other registrant on its own row above.

Also bump the dsh-skins pin to carry the skin-center and blue-fantasy 0.1.7
adaptations, and refresh the aggregate lib/ output and its fingerprints.
2026-09-25 13:40:41 +08:00
EDDYCRAZY-CC c815e299da fix(settings): make the usage and remote-web-ui settings pages writable
Under the 0.1.7 settings model the plugin's own Config schema is its
settings page: the Host serves a form only for a profile entry that declares
at least one volatile() field, and it refuses a write to a non-volatile path.
Both packages still imported vanilla schemastery, which has no volatile(), so
neither entry was served and neither card could save anything (issue #1717).

Migrate dsh-usage and dsh-remote-web-ui to @deepseek-ai/schemastery, mark the
card-edited fields volatile(), and read every field through its live reference
at use time instead of capturing it at activation. A save now commits into
those references and announces loader/volatile-update, which re-arms the
running instance in place -- so the usage probe cycle and ledger, and the
pairing service, its device sessions, the tunnel and the route registrations,
all survive an edit.

The deployment-level fields (trustedHosts, devicesFile, profile) stay
non-volatile: they belong in the profile patch, so the form offers no control
a live write could not honor. The remote card also stops masking an unserved
namespace with renderChildrenWhenNotExposed/hideNotExposedNotice, so a
deployment that composes no owner shows the reason instead of a doomed form.
2026-09-25 13:40:41 +08:00
zhu1090093659 35000705a1 chore(satellites): list the accepted skin and plugin content
Six skin pull requests and three plugin-index registrations were accepted in the
2026-09-25 maintenance round, so the gitlinks move to those repositories' main and
market/dist is rebuilt from the new pins.

New skins: mid-autumn, shangmei-jinbi, and the 0.1.7 adaptations of ice-princess,
observatory, whale-maid, pixel-anime and miku. verdandi and claude are not included:
their pull requests are held at intake. New store plugins: dsh-ltm,
dsh-session-suspend and dsh-attention-health; dsh-wx-bridge is held pending a
description correction.

market:check reports 4063 files, market:verify-assets validates 3103 asset paths,
and libs:check is unchanged.
2026-09-25 12:10:50 +08:00
EDDYCRAZY-CC e4fb5644fa docs(notes): record the 1716/1719 batch and the CI unblock
The round triaged ten open issues against the dev tip and landed three
changes: the legacy skin row is stripped as a whole block in dsh-skins
(#1719), the narrow-shell drawer no longer folds on a workspace group row or
its actions menu (#1716), and the dsh-update desktop-page spec installs its
scheme instead of pinning an opaque jsdom origin, which had been killing its
worker and failing CI on dev.

Seven issues resolved without a code change and are answered on the tracker:
#1713 and #1717 with their root causes, #1712 and #1692 as generation mismatch
and an out-of-process proposal, #1710/#1714/#1715 as visual decisions that
need a chosen direction before implementation, and #1701 against a desktop
surface this repository no longer ships.
2026-09-25 11:59:38 +08:00
EDDYCRAZY-CC 49a1af1b89 fix(dsh-update): stop the desktop page spec from killing its worker
`pnpm test` and CI were red on dev. `tests/client-entry-desktop.spec.ts`
pinned the jsdom origin at `dsh-app://app/`, which is an opaque origin:
jsdom's own `localStorage` getter throws `SecurityError: localStorage is not
available for opaque origins` there, and vitest reads that property while it
populates a jsdom environment's globals. The worker therefore died during
environment setup, so vitest reported the file as "failed to start" rather
than as a failing test, and the whole recursive `pnpm test` run aborted on
this package while all 86 remaining assertions passed.

The spec now installs the desktop scheme by replacing the ambient `location`
for the duration of one test and restoring it in a `finally`. The plugin reads
the scheme through `pageProtocolOf()`, which takes a window-like object, so the
same branch is exercised over a usable origin. The spec keeps asserting the
scheme it stands in for, the dictionary registration, and the absent seat.

The new mobile-drawer case in the aggregate's responsive contract also gains
the Given/When/Then marker its lane requires; no assertion changes.
2026-09-25 11:42:05 +08:00
EDDYCRAZY-CC 8225d9f2ce chore(libs): rebuild the aggregate for the mobile drawer fix 2026-09-25 11:25:34 +08:00
EDDYCRAZY-CC 4c39b90bae chore(satellites): pin dsh-skins to the legacy-row strip fix
The gitlink moves to the pushed fix for the half-removed legacy skin row
(issue #1719); no other satellite content changes.
2026-09-25 11:24:52 +08:00
EDDYCRAZY-CC d0b14a0231 fix(dsh-web-all): keep the mobile drawer open for group rows and row actions
On a <=768px shell the responsive compat layer folds the sidebar drawer on
every sidebar click it reads as a selection. Its selectors also matched a
workspace group row and the row's own actions, so two ordinary gestures were
mistaken for selections (issue #1716): tapping a group row toggled its
aria-expanded and folded the drawer in the same frame, so the sessions the tap
had just revealed were never seen, and tapping the row's ellipsis discarded
the menu before it could be used.

The group row stays open unless the tap is the row's trailing new-session
button, which navigates away and keeps the fold -- the same distinction the
remote package's mobile adaptation already draws for the same row. Session
rows, sidebar entries and other tree rows fold exactly as before, including a
session row nested inside an expanded group.

The regression test drives the four gestures against the stamped frame; the
group-row case fails against the previous source.
2026-09-25 11:24:35 +08:00
zhu1090093659 48dd55b5a4 chore(satellites): move the gitlinks to the pushed family content
All four satellites received the shared mount-once guard (dsh-skins and dsh-community-plugins one commit each; dsh-pet and dsh-presets also dropped the desktop-scheme Origin allowance, which the installed shell's forward does not exercise), dsh-skins registered the new update plugin and its two parts in the semantic-attrs contract, and every repository is pushed, so the recorded commits now exist upstream.

dsh-skins keeps two pre-existing failures in tests/legacy-bridge.spec.ts (home/profile patch probing) that reproduce at the previous commit and are unrelated to this move.
2026-09-25 10:24:31 +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