Commit Graph
1011 Commits
Author SHA1 Message Date
bowenliang123 a03e606f08 fix(client): paint the DNA trend bars on the shared token scale
DnaBar's gradient stops were percentages of each bar's own total, so the
browser rasterized common strands differently per bar (sub-pixel bands
flipping visible/merged between steps) and inherited bands read thicker
and thinner across the chart. Stops now ride the shared per-token pixel
scale (CHART_H/maxTotal) and are byte-identical in every bar; the bar
height reuses the same scale. Live-measured on a 99-bar session with the
duration curve off: adjacent-bar common-row pixel diffs dropped 589 -> 11,
the remainder being genuinely new top-of-bar strands.
2026-10-17 09:35:33 +08:00
bowenliang123 a4bec7d544 refactor(client): split the browser card into a fixed head and a scrolling rows region 2026-10-17 07:08:04 +08:00
bowenliang123 feacf5d906 feat(client): stripe the context browser's rows with a faint even-row wash
Row lists (the DNA flat feed, category bodies, tool schemas) previously read
as one undifferentiated white field. One rule keyed on the shared .lc-br-elem
row factory stripes every list: `nth-child(even of .lc-br-elem)` keeps the
phase stable across toolbars, notes and filtered-out rows, the tint is 60% of
the theme's interactive hover wash so it sits under hover and open states,
and an open row keeps its active highlight alone.
2026-10-17 02:49:33 +08:00
bowenliang123 9c55959456 fix(client): exempt the DNA faces from the browser's category focus
Opening a browser row/category persists focusCat with no visible UI; with DNA
on, TrendChart then scaled bar heights to the focused category's share
(focusOf) while the band data and the lifetime slices stayed in full-context
offsets — dark slices floating above half-height bars. The DNA faces now pass
no focus into preprocessTrend (the stacked faces keep it), and the previously
false-positive 'focus is ignored' test now discriminates: with the axis driven
by a second bar, focused heights (22px) diverge from the full-context share
(56px).
2026-10-17 01:25:01 +08:00
bowenliang123 f4db11776f fix(client): ride the fetch routes as browser-relative spellings
The client POSTed every plugin route as a root-absolute /api/dsh-context/*
path, which stripped a reverse proxy's /app/dsh prefix at the gateway —
every poll 404ed at it, the panel retried on an aggressive backoff, and
the deployment fell into the issue #159 reconnect loop. The six route
constants now live in one module as their browser-relative spellings:
fetch resolves them against the page's document base, the same idiom
dsh's own stream/socket clients ride, so a prefixed proxy keeps its
prefix and a direct deployment resolves to the exact same URLs before
and after. A host/client pairing spec pins each spelling to its route
registration, and docs/compatibility.md gains the §5.8 client-seam rule.

Fixes #159
2026-10-16 23:50:58 +08:00
bowenliang123 8331602b0b docs(vitest): state the pool rationale as measured runtime
Review follow-up to 2ce42f6: "~30% off the coverage gate" reads as a
pass/fail claim, and the file count next to it rots as specs are added. The
comment now names the measured runtime and keeps only the two facts that
cannot be read off the config: the per-worker environment an amortized ~30%
buys, and why the pool stays client-only.
2026-10-16 23:22:08 +08:00
bowenliang123 2ce42f6e7a perf(client): run the client suite in the vmThreads pool
Vitest 5's duration diagnostics flagged that the jsdom environment was created
once per client file — 111 times, 36% of tracked time. vmThreads creates it
once per worker while keeping per-file isolation, so the same 153 files /
2429 tests and the same 100%-per-file coverage scope (131 instrumented files)
now finish in ~16.7s instead of ~24.0s: paired interleaved medians of five
gate runs, and ~46% faster at the CI runner's four workers.

Client-only: the host project fails under vmThreads (10 files), and the
`isolate: false` shortcut the same hint offers fails two client files.
Peak process-tree memory rises ~0.9 GB (3.0 -> 3.9 GB).
2026-10-16 23:18:16 +08:00
bowenliang123 e620e4fbf6 chore(deps): update vitest to 5.0.5
Vitest 5 needs Node >=22.12 and Vite >=6.4 — already satisfied (node 24, vite
8.3.1 auto-installed as its peer) — and needs no config or test change here:
`clearMocks` now defaults on, inline projects inherit the root config, and `-t`
joins suites with ">", none of which this repo relies on.

Paired interleaved runs against v4.1.12, on two warm checkouts and alternating
the version per pair to cancel machine drift: `vitest run` 22.40s -> 20.95s and
`vitest run --coverage` 26.09s -> 25.65s (median per-pair delta -5.8%), with the
same 153 files / 2429 tests and the same 131-file coverage scope at 100% per
file.
2026-10-16 23:06:48 +08:00
bowenliang123 9217fca879 feat(client): echo a DNA band hover onto its feed row
Hovering a band on the DNA bar now lights the row it names below — a message
band its exact feed row, a tool-schema band the tools group row, the system
band the system row — the reverse of the row-hover-to-band link, so the two
surfaces read as one surface. The echoed row also scrolls into view, confined
to the nearest scrollable ancestor's own scrollport (the capped column): the
row only has to reach the scrollport's visible slice, since a capped column
usually extends below the page fold and a page scroll would drag the pointer
off the pinned band mid-scrub. Clicking a band still lands on the row and
expands it.
2026-10-16 22:33:19 +08:00
bowenliang123 ef478dee24 feat(client): cap the context browser at 3x the composition + trend cards' height
The DNA flat feed lays every message out at once, and an uncapped card would
outgrow the page. The browser column now measures the composition and trend
cards stacked beside it — per render, followed by a ResizeObserver for pane
drags and card reflows — and tops out at three times their sum, scrolling
taller content inside; the card head (title, composition bar, notices, and the
DNA feed's lens) stays pinned above the scrolling list. The /context modal
keeps its own single-card scroll and stays uncapped.
2026-10-16 22:10:46 +08:00
bowenliang123 26cfc8052e feat(client): lay the DNA context feed out flat in reading order, newest on top
In DNA mode the category accordion yields to one flat list of every assembled
item: the model reads the prompt oldest-first, so the list presents that order
bottom-up — the newest message is row one, and the tool schemas (one group row
opening into the category body) plus the system prompt close the list. Each row
carries its #prompt position, a category chip tinted with the category's own
palette color, its introducing-step stamp and token price, and expands into the
same full content.

A text lens pinned in the card head filters the feed's rows and the open tools
group's schemas alike (the served system prompt text included); hovering a row
lights its exact band — or its band group for the header rows — on the DNA bar
without reporting upward; a category jump (catFocus) drops back to the
accordion, which has no row landing in the feed.
2026-10-16 22:09:48 +08:00
bowenliang123 781c81e216 fix(client): shrink the /context modal's side margins to two thirds
The card was pinned by the fixed 720px cap, so wide panes left large
proportional blank space on both sides. Width is now
min(calc(33.333% + 480px), calc(100% - 32px)): each side margin is
exactly 2/3 of the old layout's at every pane width, and the narrow
gutter floor drops from 24px to 16px.
2026-10-16 20:54:03 +08:00
bowenliang123 aca1574c25 feat(client): render JSON-detected section bodies as the harness JsonTree
Whole-text JSON payloads (a leading { or [ that parses) open on the shell's
JsonTree inspector instead of markdown: the switch offers Raw|JSON there
(markdown is meaningless on structured payloads), the tree opens two levels
deep via the expanders' own click path (focus restored, capped at 100), and
an expanded row drops its inline preview Chrome-DevTools style. The JsonTree
faces are pinned per baseline and probed by the compat matrix.
2026-10-16 18:45:26 +08:00
bowenliang123 dd690e0599 fix(client): give the native selects dsh's form-field border
The 1px border-l2 hairline on a white layer-2 background reads as
borderless. Adopt dsh's own form-field recipe (0.5px solid border-l4,
the settings inputs/selects idiom) for all four native selects: the
overview coverage picker, the fleet sort/filter, and the context
browser step picker.
2026-10-16 16:37:35 +08:00
bowenliang123 7ae8de869d feat(client): add a session coverage picker to Context Insights, defaulting to all
Archived sessions fold back into every figure the page derives off the
session list: rowsOfSnapshot now tags archived rows instead of dropping
them, and one coveredRowsOf pass scopes the KPI band, charts, heatmap,
skills, and the session grid together. A "Filter sessions" select next to
the list's search box offers dsh's own archived-filter set — All (show
archived) by default, Hide archived, Archived only. The Active Sessions
card follows the picked coverage (Sessions incl. the window's archived
count under All; Active/Archived Sessions over the full-list total under
the narrow scopes), archived cards wear an Archived tag and refuse to
open like dsh does, and kpisOf drops its now-unused listed param.
2026-10-16 15:58:28 +08:00
Copilot ca5a3e8d3d chore: declare supported DSH engine range via engines.dsh in package.json (#155)
Authored-by: bowenliang123 <liang.bowen.123@qq.com>
2026-10-15 21:59:03 +08:00
Copilot ba65d6ea96 doc(readme): Add Chinese README translation (#154)
Authored-by: bowenliang123 <liang.bowen.123@qq.com>
2026-10-15 21:36:40 +08:00
bowenliang123 ca89acfd93 chore(release): 0.72.0 2026-10-15 15:47:04 +08:00
bowenliang123 8d634dc719 fix(client): make the block-map toggle span the browser bar block
Wrap the meta row and the composition bar into one main column with the
enlarged map toggle as a right column stretching across both rows, so the
figures shift left of the card edge instead of crowding the button.
2026-10-15 15:26:02 +08:00
bowenliang123 9dc2253653 feat(client): add a token block map under the context browser's composition bar
A bar-right toggle reveals a squarified treemap of the shown step's
context: category regions sized by tokens, with same-kind items folded
into one weighted block (every bash result together, skill loads by
skill, injections by form) and an 'others' tail past the fold cap.
Clicking a singleton block lands on its exact row (the DNA band pick's
path), a folded block filters the category's rows to the group's tag,
and a region header toggles the category like its row does. Block and
region hovers float a figure bubble and, outside DNA mode, report the
category to the shared composition hover; the open category keeps its
region framed.
2026-10-15 15:02:44 +08:00
bowenliang123 6581685fea fix(docs): clarify regex usage in test command for iteration 2026-10-15 14:23:49 +08:00
bowenliang123 9462598b5c fix(docs): update test command to include test case name for iteration 2026-10-15 14:19:26 +08:00
bowenliang123 023edb15ab fix(client): show the file activity card's relative paths without a ./ prefix 2026-10-15 03:26:34 +08:00
bowenliang123 cc0babaf02 feat(client): lead the trend detail panel with the composition card's chips
The pinned step's per-category rows were a second rendering of the same
categories, drifted from the one above: their own grid, dimmed regular-weight
labels, a fixed figure column. The panel now renders the composition card's
own chip legend — same dot, 600-weight label, right-aligned figures with the
secondary share, same hover highlight and 160px grid reflow — in the shared
CATS order, so a category reads identically in both cards.

Delta mode has no counterpart above, so makeLegend gains a delta variant: the
chips print the signed change colored by sign, and both the share and its
"of used" hint drop out. The panel's chips report hovers back exactly as the
composition legend's do, and the reserved lane mirrors the chip grid so the
pending and loaded panels still measure alike.
2026-10-15 03:06:24 +08:00
bowenliang123 408bbc1a29 test(client): pin the trend detail row anatomy instead of the deleted bar class
Code review flagged the two "no mini bar" assertions as a duplicated absent-class
check. One anatomy pin per mode now asserts the child sequence a row is made of —
dot, label, figure, share — and a mutation test confirmed reintroducing
.lc-bar-track anywhere in the row fails both modes.
2026-10-15 02:51:51 +08:00
bowenliang123 4891a7a978 fix(client): drop the trend detail rows' mini composition bars
The pinned step's per-category rows carried a mini bar beside the figures
— the share track in Total mode, a diverging zero-line bar in Delta. Both
go: a row now reads dot, label, figure, share, with the figures pinned to
the row's right edge, and the trend card's reserved lane mirrors that same
anatomy so the pending and loaded panels still measure alike.
2026-10-15 02:48:20 +08:00
bowenliang123 afd94fec7b chore(release): 0.71.0 2026-10-15 02:31:07 +08:00
bowenliang123 72d1464f18 feat(fleet): fetch the task card's unclipped report-back on unfold
The Fleet task board's opened card boards its owner's report-back from a
wire excerpt the route clips at 300 chars, so expansion could never show
the whole text even though DSH itself hands the fold the whole log. The
fleet route now reads a `full: true` body whose prompt/reply skip the
excerpt caps (only a hostile-payload bound stands), and the task board's
unfold asks for it once per session per mount: the excerpt renders
first and swaps in place on landing, the section meta carries
loading/excerpt-only states, and the scan never pays for the full read.
2026-10-15 01:37:20 +08:00
bowenliang123 99cb1f3706 fix(client): drop the task board's header completion bar and the rows' occupancy pct 2026-10-15 00:19:39 +08:00
bowenliang123 adac598ed3 feat(client): gray the unhovered cards on hover, sparing the hovered lineage 2026-10-15 00:12:39 +08:00
bowenliang123 e67fd3e9a6 feat(client): lead the team-member graph cards with the roster name and a 2-line duty
The head keeps a teammate's roster name in bold with their duty in the light
secondary tone (the member cards' desc idiom); the self and lead cards keep
their title. The label box grows to a fixed 3 lines so the duty wraps to 2 —
the card grows uniformly with AGENT_CARD_H, keeping every card's metric row
aligned and the link anchors on the card's edges. The geometry pins derive
from literals so a layout bug cannot mirror its own arithmetic.
2026-10-14 23:31:04 +08:00
bowenliang123 da78faf4ca feat(client): open a member card's subagent in the right Sidebar's chat
The aside rides the shipped catalog's own address and options, addressed by the
node's direct parent; a face that cannot take the resource keeps the whole-view
jump on every supported line. The openers' test suites move to their own file
to hold the 1000-line cap.
2026-10-14 22:57:37 +08:00
bowenliang123 05501e45b5 feat(client): interlock the boards' and the graph cards' hover lift 2026-10-14 22:57:26 +08:00
bowenliang123 84d55fe15b fix(client): drop the occupancy figure from the member cards' activity line 2026-10-14 22:56:56 +08:00
bowenliang123 13783634d5 fix(client): reweight the Fleet agent card title and usage line
Bold the card title at the weight the figures previously carried (650),
and drop the figures line's bold both in markup (<b> to <span>) and in
the CSS so the tokens/cost figures read regular.
2026-10-14 21:38:02 +08:00
bowenliang123 13cef4215a feat(config): enable source maps in tsdown configuration for local diagnosis 2026-10-14 21:26:31 +08:00
bowenliang123 bd3fce8409 feat(config): enable minification in tsdown configuration 2026-10-14 21:11:50 +08:00
bowenliang123 e1c0d4539a feat(overview): flag the full span at the pane's right edge
The overview's quartile poles and the turn strip's width-quartile labels also mark the
full-span position (the last record / last turn), so the log's end carries its figure like the
quartiles do. The full-span pole insets by its own 1px width (calc(100% - 1px)): at exactly
left 100% the pole falls wholly past the scroller's clip, while the number label keeps reading
leftward inside the pane. The collapsed-at-start pole still drops — at the left edge its
label would clip and the pane edge already answers. Chip tips and the README now say quartiles
and the full span.
2026-10-14 19:58:06 +08:00
bowenliang123 e88a0a4bdc docs: describe the trend Overview toggle in the README 2026-10-14 17:48:23 +08:00
bowenliang123 db5a25acd4 feat(client): add the trend Overview face squeezing the whole log into the pane width
One toggle next to Duration flattens every retained step (or turn) into a continuous stacked
ribbon across the visible width — no horizontal scrolling, nothing computed while it is off:
the drawing geometry memoizes on [requests, mode, duration] so hover re-renders never rebuild
the polygons. Flags mark the record quartiles only (interior-only: short logs' collapsed edge
quartiles drop), and the turn strip stays proportional with its labels on the width quartiles.

Interaction keeps the bars': nearest-record hover with the shared tip, click to pin, scissors
markers, the duration-curve overlay on the same svg with its right-hand axis, Total/Delta
(signed up/down bands around the proportional zero line) and category focus. Exclusive with
DNA mode and Adaptive: activating one clears the others.

trendChart.tsx lifts focusOf/deltaOf/trendTipRows and the whole-log maxima to module scope
(preprocessTrend/trendMaxima) so both faces share one preprocessing path and one tip shape.
2026-10-14 17:48:23 +08:00
bowenliang123 854ce14aad chore: release v0.70.0 2026-10-14 07:45:49 +08:00
bowenliang123 6184f0fbc0 test(compat): pin the sliced cold fold's faces in the baseline matrix (issue #145)
The backfill's sliced path is optional-by-contract: restore/hydrate/prepare/
write exist on both supported baselines, and any absence falls the session
back to the single-shot coldSnapshot. Pin all four needles (plus coldSnapshot)
per baseline tag so a removal names the seam instead of silently degrading
the pass to whole-log blocks, and record the rule in docs/compatibility.md
§6.
2026-10-14 02:50:46 +08:00
bowenliang123 5f20076f3e fix(host): yield during the cold detail fold and cache payloads by durable revision (issue #145)
A cold /detail request folded the whole log synchronously inside the request
(~0.35s per 30k events on a fast host) and re-folded on every view. The fold
now yields to the event loop every 1,000 events (the result is asserted
byte-identical against a buildTimelineDetail reference), and the folded
payload is cached keyed on the observation's (persistence instance, session
id, durable revision) tuple — the same trust tuple dsh's own observation
reader uses — so an unchanged cold session re-serves in ~1ms while a changed
log, a swapped backend, an observation without a revision (a live-race cut),
or a config remount always refolds. The cache is bounded at four payloads
(each bounded by the fold bounds) and lives in the watch closure.

The observation lease now disposes on every path including the early returns
(a latent pin on hostile faces is gone with the restructure).
2026-10-14 02:46:02 +08:00
bowenliang123 f5ef57d56f feat(host): pace the projection backfill proportionally with a logged work budget (issue #145)
The pass used to hold the host at ~60% duty for the whole corpus window (a
fixed 100ms sleep between full-log folds). Rests are now proportional to the
measured work (at least a 25ms floor) at both granularities — between slices
and between sessions — capping the pass near 50% duty, and every 8s of
cumulative fold work the pass takes a logged 2s recovery pause and resumes on
its own (the issue's 'bounded, background, visibly paused' ask). Slice work is
billed exactly once across the two granularities, and every sleep wakes early
on abort so dispose never waits out a pause.

Pacing is injectable (BackfillPacing) for deterministic tests, mirroring the
cold-read gate's injectable reading; the sliced-fold suite moves to its own
spec file with the shared rig extracted to tests/host/helpers/backfill.ts.
What gets folded and the final cache rows are unchanged — only when the loop
breathes.
2026-10-14 02:32:28 +08:00
bowenliang123 8d74f6e548 fix(host): fold monster sessions in slices during projection backfill (issue #145)
A whole-log cold restore lands on the host event loop as one uninterruptible
synchronous block (~1s per 30k events on a fast host, more on a Windows
desktop), and a 100+ session backfill strings those into a window the desktop
renderer watchdog cannot survive (issue #145: 118 sessions, 47s, renderer
killed).

Sessions over 2,000 events now fold in 2,000-event in-memory slices through
the public registry.restore, yielding between slices, with exactly one durable
write-back at the end (sessions.prepare + registry.hydrate with the rows
already at the log end, then sessionProjectionCache.write). The composed rows
are byte-identical to one single-shot coldSnapshot (asserted with the real
registry + the plugin's real units), no intermediate durable rows land, and a
crash mid-fold keeps the single-shot failure semantics. A session going live
mid-fold skips silently; a write-back failure stays fail-soft.

Faces are re-proved per deployment and any absence (older/unknown harness)
keeps the single-shot coldSnapshot path; all four faces exist on both
supported baselines (0.1.7-rc.2, 0.2.0-rc.2), verified against the tags.
2026-10-14 02:03:22 +08:00
bowenliang123 b6037a6523 docs(compatibility): rewrite as a staged, evidence-anchored rule set
Compress the compatibility page from narrative prose to a uniform
grammar — numbered rules with bold-lead invariants, Limitations, Checks
and Procedures, each carrying evidence pointers into the dsh source
tree — staged by lifecycle: supported set, admission, fold, metering
parity, client surface, projection cache, packaging, verification.

Drop what code, tests or git history already carry: the per-bump
stateVersion narratives, the V4 shape table, per-route architecture
stories and retired-version deltas. AGENTS.md gains the conciseness
mandate for the page: less is always better.
2026-10-14 00:11:53 +08:00
bowenliang123 bb29bcad59 fix(client): report a file attachment's token estimate as ≈ instead of ≥
The file card priced only the pathless branch of the harness handle — the one
dsh emits when the stored copy cannot be read — and disclosed that shortfall
with a `≥` lower-bound marker, which read as a bug beside the image rows' `≈`.
Every other token row reports a heuristic estimate, so this one now does too.

The tooltip claimed the handle named "where the stored copy can be read": the
path-bearing branch, which costs roughly 1.7x more and is never priced. Under
`≥` the marker covered that gap; under `≈` the explanation described a branch
the number does not come from, so the clause is gone from both locales. The
estimate itself is unchanged.
2026-10-13 23:39:09 +08:00
bowenliang123 3f67d625b4 chore(typecheck): include tsdown.config.ts in the test project
The build config was neither linted (.oxlintrc.json ignores *.config.ts) nor type-checked, so only running a build could catch a mistake in it.
2026-10-13 23:30:07 +08:00
bowenliang123 e0b42ee6a7 chore(pre-commit): run lint, typecheck and coverage as one parallel gate
The hook ran `pnpm test`, the whole coverage suite, and the agent flow in AGENTS.md ran that same suite again before committing: one commit verified identical content twice, about 45s of it.

`pnpm run check` (scripts/check.sh) runs lint, typecheck and coverage concurrently, prints each tool's complete output (also kept in .tmp/check-logs) and fails when any of them does. A green run fingerprints the worktree into .tmp/check.stamp, so the hook skips the suite for content that just passed; any tracked or untracked edit, or a stamp older than an hour (gitignored inputs like lib/ and node_modules can drift unseen), re-runs it, and `--full` always does. The hook gains lint and typecheck at no extra wall time: 3.2s and 1.4s hide inside the 23s test run.

.gitignore now lists the local tool state (.codegraph, .idea, .zcode): it is not a gate input, and its churn would otherwise invalidate every stamp.

Verified: green gate on 146 files / 2305 tests, hook skip in 0.1s, full re-run after any edit, and a stubbed failing tool exits 1 without stamping.
2026-10-13 23:30:07 +08:00
bowenliang123 d9d3868dc4 ci: restore the typecheck gate in both workflows
`pnpm test` is the vitest run only since the local pre-commit flow took typecheck over, so neither PR checks nor release builds type-checked anything, and the pr-checks comment still claimed the single test run covered it. Both workflows now run `pnpm run typecheck` beside lint, and the comment says what the vitest run actually covers.
2026-10-13 23:30:03 +08:00