Commit Graph
396 Commits
Author SHA1 Message Date
bowenliang123 0c8312763e feat(client): jump from a chat reply to its turn in the Context tab
Add an icon to each finalized reply's assistant-actions row that opens
the Context tab pinned to that reply's turn: the click resolves the
reply's request seq off the served node seat, records it in a per-session
relay, and activates the tab; the view consumes the relay once its
projection data is in, flips the trend chart to turn bars, pins and
centers the turn's aggregate, and resets the shared scroller. Every hop
degrades quietly (unknown seat, unresolvable seq, missing tab, hostile
nodes, aged-out turn).
2026-08-29 01:44:51 +08:00
bowenliang123 84d4f57a6f docs(AGENTS): add instructions for exploring and syncing the code graph 2026-08-29 01:42:12 +08:00
bowenliang123 4a9a95e4f7 feat: add .gitignore to exclude CodeGraph data files 2026-08-29 01:33:23 +08:00
bowenliang123 86333a80d5 feat(client): link the trend card highlights to the shared category hover
Hovering a category in the Context browser (or the overview legend/bar)
now lights that category across the trend card: the matching segment in
EVERY chart bar (total and delta modes), the detail panel's composition
bar, and its per-category rows.

The chart highlight rides a plain container attribute (`data-catdim`) +
static per-segment `data-cat` keys, so the dim/brighten pairing is pure
CSS and the memoized bars never re-render on a cross-card hover. The
detail bar mirrors the key one-way with its tooltip off (a cross-card
hover must not float a second tip), and the detail rows reuse the
legend-chip idiom: tinted background, bold label, ring on the color dot.
The overview's 'free' key stays filtered, as in the browser's live link.
2026-08-29 00:53:48 +08:00
bowenliang123 de4d6f327a build: kill previous watch instance when starting pnpm watch
Track the tsdown watcher pid in .tmp/watch.pid; a new watch kills the
previous instance first and the pid file is cleaned up on exit.
2026-08-29 00:46:32 +08:00
bowenliang123 48e5efa7b3 docs(AGENTS): add instructions for updating dependencies after git pull 2026-08-28 23:18:15 +08:00
bowenliang123 73141fb53d docs(AGENTS): update compatibility section to include support for dsh 0.1.2-alpha1+ 2026-08-28 23:16:16 +08:00
bowenliang123 6d17588a56 release: v0.37.0 2026-08-28 22:32:46 +08:00
bowenliang123 1dab8dcdbf build: track the 0.1.2 client module graph
Drop the deleted `@deepseek-ai/dsh-client-runtime` from dsh.client.inject
and remove the preloaded-client-externals channel that died with it; mirror
0.1.2's platform module table (+ dsh-client-store) in the client bundle's
purity gate; widen the dsh peer ranges to >=0.1.0-rc.7 so 0.1.2 prereleases
resolve; pin the devDependency types to the newest published surface
(0.1.1-rc.2); the bundle smoke's fake ctx now honors inject callbacks.
2026-08-28 22:32:31 +08:00
bowenliang123 7b61d5ddc7 feat(browser): dual-face compatibility across the dsh 0.1.1/0.1.2 seams (#26)
0.1.2 rewrote the client composition and the history transport; every seam
this plugin touches now resolves by feature detection and degrades visibly
instead of erroring:

- history reads: `remote.session.page` (0.1.2; the inclusive cut
  `throughSeq` pinned to the target seq) over `connection.api.sessions.history`
  (0.1.1); both served envelopes unwrap ({ok,value} and {result:{ok,value}});
  packed chunk-row records skip (final events always ride verbatim); a
  malformed payload rejects into the retryable state instead of claiming
  absence.
- conversation join: `useChat` (ChatSnapshot.legacy.nodes) over the session
  snapshot's top-level `nodes`, both seats invoked in a stable hook order —
  fixes the empty File Activity card on 0.1.2 (#26).
- image loading: `uiConversation.imageUrl` (0.1.2) over
  `conversation.resolveImage` (0.1.1); absent faces degrade the cards to
  metadata-only.
- `/context` command: waits for the `inputTriggers` service (ctx.inject)
  instead of racing module arrival order, which 0.1.2's finer modules broke;
  the modal resolves `sessions` at close time for the same reason.

Absent faces drop features (static out-of-window hints, no command) — the
tab and the modal never render an error page.
2026-08-28 22:32:19 +08:00
bowenliang123 6e46d65d69 refactor(host): mirror both projection unit contracts across registry generations
The session-projection contract drifted again in 0.1.1/0.1.2: the unit-key
constraint moved from SessionProjectionMap to SessionProjectionStateMap, the
pre-0.1.1 `schema`/`view` fields left the published definition, the wired
register overload now demands `wire` PRESENT, and 0.1.2 widened `init` to
`init(header: SessionHeader)`. The dual-contract definition is therefore
mirrored locally in full (ProjectionDefinitionV1 + V2) instead of Pick-ing
from the installed dts, the plugin keys merge into BOTH type maps, and the
zero-argument init satisfies every supported registry — one definition
object still installs unchanged from 0.1.0-rc.7 through 0.1.2-alpha.1.
2026-08-28 22:32:19 +08:00
bowenliang123 d25d44aff1 fix(host): keep undefined-valued scalars off the wire view (#29, #30)
model/provider/contextWindow now join the served snapshot by conditional
spread: an unknown value leaves the key ABSENT instead of materializing an
`undefined`-valued property. The harness's lossless-JSON pipeline rejects
such a view whole — on 0.1.2 that fails every projection push for the
session (the fresh-blank-session breakage reported in #29/#30; the same
property discipline the persisted state has held since stateVersion 10).
Guarded by plain-JSON view assertions over both the unknown and the known
model shapes.
2026-08-28 22:32:01 +08:00
bowenliang123 201151793b docs: add note about gh cli installation and configuration 2026-08-28 20:35:03 +08:00
bowenliang123 83bc071338 feat(browser): number the lines of the raw text view
Each source line becomes a block span whose counter-fed ::before sits
in a narrow left gutter; pseudo content never reaches the clipboard and
user-select none keeps it that way, so copying the body still yields
the exact source. Interior empty lines keep their height, a trailing
newline adds no row, and soft-wrapped continuations align at the
content column.
2026-08-28 12:15:40 +08:00
bowenliang123 65db2a3b66 fix(browser): keep authored newlines breaking exactly once in markdown cards
e4eddbf dropped the card-level pre-line, which stopped the doubled
breaks but also collapsed bare soft newlines into spaces. The renderer
bakes soft breaks into paragraph text and pairs every hard break's <br>
with a '\n', so scoping pre-line to paragraphs and hiding those <br>s
makes every authored newline render exactly one line break while block
separators still collapse at the container's normal white-space.
2026-08-28 12:15:40 +08:00
bowenliang123 e4eddbf3f2 style(browser): stop markdown detail cards from doubling line breaks
The shared MarkdownText pipeline emits cosmetic newline text nodes
between blocks and after each <br>, designed to collapse under the
default white-space. The card's pre-line made every one of them
visible, so hard breaks rendered twice and block gaps stacked an
anonymous blank line on top of the paragraph margins.
2026-08-28 11:47:59 +08:00
bowenliang123 06d1a5df7c release: v0.36.0 2026-08-28 10:17:15 +08:00
bowenliang123 3862a48e47 docs: showcase the browser row filters and tool source chips
Two live screenshots: the tool-schema category with per-plugin source
chips and its filter/sort toolbar, and tool results narrowed by a
text filter — embedded next to the attribution and filter bullets.
2026-08-28 10:17:04 +08:00
bowenliang123 8a5f1e0b02 style(i18n): per-category placeholders for the row filter
Each category's filter box now names what it scans — message text
(user), injected context (inject), reply or calls (assistant), tool
or arguments (tool results) — instead of one generic "filter by
text". The tools category keeps its existing placeholder.
2026-08-28 10:08:56 +08:00
bowenliang123 093dd9f69e refactor(browser): a shared row filter across every category
The tools' text filter generalizes into the browser-wide row lens: a
shared RowToolbar (input plus an optional control group) now filters
the four message categories too — user, inject, assistant, and tool
results — matching each row's tag and preview text exactly as shown
(call breadcrumbs and call-args summaries included; full bodies stay
out of scope, they load on demand).

The node-list branch splits into a derive pass (each row's tag +
preview facts, computed once) and a filtered render pass, and the
query is a lens on the OPEN category: opening a different one resets
it while step picks keep it. System stays searchless (one row) and
sort stays tools-only (reading order is meaningful for messages).
2026-08-28 10:07:21 +08:00
bowenliang123 d6cd02acad feat(browser): filter and sort the tool-schema rows
The tools category gains a local view state: a text filter scanning
each row's name, producer description, plugin chip, and raw parameter
JSON (a hostile schema degrades to no matchable text), plus a
size/name sort toggle — size (token price, mirroring the overview's
Top chips) stays the default, name gives lookup. The toolbar stays
mounted on an empty match so the filter can always be cleared, and
both survive step picks so one lens compares epochs.

Reuse the FileCard's control idiom: the search input and toolbar
share the lc-fa-search/lc-fa-ctl rules under browser-scoped names.
2026-08-28 09:58:13 +08:00
3244ff29a9 feat: tool plugin source attribution in the Context browser (#25)
Tool-schema rows in the Context browser carry a best-effort source tag
for the registering plugin, recovered without a harness change:

- a harness-logged `plugin` field passes through verbatim (future-proof);
- MCP-proxied tools resolve `mcp:<server>` from their public names;
- shipped first-party tools resolve from a pinned package map;
- a live `tools.register()` hook (cordis `internal/get` reader slot,
  with a caller-package stack fallback for local-link installs) tags
  third-party, agent-scoped, and dynamic registrations, and peels a
  prior incarnation's wrapper on reload;
- tools already registered when the plugin mounts render a localized
  "unknown plugin" tag explaining the boot-order gap.

Priority: `mcp:<server>` > live record > pinned map > unknown. The
chip rides the shared tag frame tinted with the brand badge tokens.

Rebased onto v0.35.0 with maintainer review fixes; the attribution
priority and reload-safety rework and the chip theming are described
in the PR review comment.

Co-authored-by: Nwflower <1679659@qq.com>
Co-authored-by: bowenliang123 <liang.bowen.123@qq.com>
2026-08-28 09:50:10 +08:00
bowenliang123 ef97842129 release: v0.35.0 2026-08-28 03:11:27 +08:00
bowenliang123 15ae3b96c3 feat(files): open files on the system; display workspace paths relative
The File Activity card gains two affordances, both resolved from the
client ctx and degraded per-host:

- Workspace-relative display: paths inside the session's cwd (read off
  the session-list row) shorten to a './'-relative form; absolute paths
  outside the workspace, Windows drive paths, and already-'.'-relative
  paths keep their verbatim form. Path search matches the display form.
- System open: when the host description advertises canOpenPath and the
  connection api exposes host.openPath, a file name opens on the user's
  system (fire-and-forget, failures stay silent); otherwise it renders
  inert. A pathless search books its pattern as a display-only pattern
  row — never relativized, never openable — including nested Code-Mode
  searches, which previously leaked the pattern into a resolvable path.

workspaceOf and canOpenPathsOf re-prove every field and bound hostile
snapshots (a throw on call or property access degrades to undefined).
Component specs for the card are restored and extended for the new
props; the fold gains a pattern-row case for nested searches.
2026-08-28 03:11:23 +08:00
bowenliang123 059c85a54c feat(files): show each read's line footprint; op times on the right
Reads now carry their line footprint in the op log, in a third color
next to the +/- deltas: `>>30` for the exact window read off the
result's presentation meta (hover names the line range), degrading to
`≈80` estimated from the limit argument when no meta survived — and
staying silent for an unbounded read, which names no footprint. Nested
PTC reads estimate the same way.

The op timestamp moved from the leading column to the right edge,
mirroring the file row above it.
2026-08-28 01:27:42 +08:00
bowenliang123 2fa032d077 style(ui): draw the disclosure chevrons in CSS
The ▸ glyph sits off-center in its box, so the 90° rotation wobbled, and
at small sizes it read thin and cramped. The chevron is now a bordered
box rotated -45°↔45° — it spins about its true center, stays crisp at
any zoom, and takes the lighter tertiary label color with a little more
room before the icon.
2026-08-28 01:27:42 +08:00
bowenliang123 891c847f13 feat(files): render code files as language letter badges
Code files showed the same 🧩 puzzle piece. They now render as compact
letter badges over their language's GitHub-Linguist color — TS, TSX,
JS, PY, GO, RS, JAVA-equivalent short labels capped at three
characters — with the text color chosen per fill luminance (near-black
on the light shades, white elsewhere). Non-code files keep their emoji
glyphs (config, data, markdown, logs, sheets, documents, archives,
fonts, media), and each row's hover title names the resolved bucket in
both locales.

The icon column is a fixed-width flex cell so emoji rows and badge
rows align on the same path edge, with the chevron pulled in to keep
the left cluster tight. Test-file detection drops the .spec. form
(dot-delimited .test. and the underscore forms stay).
2026-08-28 01:03:28 +08:00
bowenliang123 0330a94ccd release: v0.34.1 2026-08-28 00:40:25 +08:00
bowenliang123 1f10674999 feat(files): type-aware row icons in File Activity
Every row showed the same 📄. The row glyph now comes from glyphOf, a
table-driven fold over the entry's form and name: image/dir forms keep
their icons, directories resolve by last segment (root, tests, docs,
deps, build output, scripts, config, assets, hidden metadata), files
match special names first (lockfiles, test files, Dockerfile,
Makefile, .gitignore, LICENSE, .env) and then extension buckets
(python, notebook, shell, web, styles, database, config, data,
markdown, log, sheets, documents, archives, fonts, media, and a code
catch-all), falling back to 📄. The row's hover title names the
resolved bucket via new files.glyph.* keys in both locales.
2026-08-28 00:33:49 +08:00
bowenliang123 3ac8689feb feat(plugin): make the info-card tagline link to the repo 2026-08-28 00:14:21 +08:00
bowenliang123 bee4b88509 fix(host): type the log-boundary block parsers as unknown
The content-block walkers declared ContentBlock[] parameters while the
arrays ride the untrusted session log — the type-aware lint rightly
rejected the null-element guards as "impossible", and an earlier
lint:fix run had silently flagged the committed state. The walkers now
take unknown and re-prove each element before the cast, and the
unpaired tool-result lookup uses Object.hasOwn instead of an
undefined comparison the Record index type claims cannot happen.
No behavior change: the runtime guards are the ones 6275ab0 shipped.
2026-08-28 00:14:21 +08:00
bowenliang123 f8c54a5feb docs: add the log-parsing resilience principles to AGENTS.md 2026-08-28 00:06:08 +08:00
bowenliang123 6275ab00d7 fix(host): keep the projection folds total over untrusted session-log events
The projection registry drives apply straight off the session/event bus
with no error boundary: one throwing fold stalls the unit's cells and
the contextTimeline push feed — the browser waits on "loading" forever.
Three real throw paths existed, and one of them also broke the
plain-JSON checkpoint precondition (one undefined-valued property fails
EVERY projection-cache write for the session):

- applyTimeline now isolates each event: a malformed one is dropped
  whole (all-or-nothing — the state reference is untouched), so no
  event shape, present or future, can take the fold down.
- A tool/result with no paired tool/call (aged-out call event, foreign
  producer, duplicate callId) no longer stamps an undefined-valued
  node.tool onto the surface node.
- pricing and header-epoch folds tolerate null or primitive elements
  inside content-block and tool arrays instead of throwing on them.

Hostile-fixture tests lock each path: a log missing data.message, null
blocks nesting inside tool-result content, unpaired results, and junk
tool entries — every fold state still losslessly JSON-serializable.
2026-08-28 00:06:02 +08:00
bowenliang123 b7741360ed fix(files): survive conversation join gaps in the file-activity fold
A file-kind tool node whose conversation join entry is gone entirely
(an aged window — exactly the sessions the card renders worst) crashed
the whole Context tab: the fold dereferenced the undefined node to read
its error flag. The optional chain restores the skip the args guard
used to provide, and the per-node fold is isolated in a catch so no
single join node — even a hostile one throwing on property access —
can take the walk or the card down.
2026-08-27 23:54:21 +08:00
bowenliang123 719d7b5364 docs: describe the widened File Activity coverage in the README 2026-08-27 23:48:35 +08:00
bowenliang123 cbbbfa5ff7 feat(files): count PTC nested calls, str_replace_editor, and real search targets
File Activity only folded top-level tool-result nodes, so PTC sessions
(run_code as the only tool) showed an empty card and the Minimal preset
went unseen. The fold now covers every surface that executes a file op:

- Nested Code-Mode calls: each settled sub-call in the conversation
  node's subCalls tree folds as one op, attributed to the nested tool
  and located on its parent run_code result (FileOp.parent; the op's
  own seq names the dispatch event, which has no surface row). The op
  log shows the program's description as the "why". Narrowing is fully
  defensive: malformed blocks drop out, and the walk is bounded by a
  depth cap plus a visited-set cycle guard.
- str_replace_editor (Minimal preset): view reads; create,
  str_replace, and insert write with their own line deltas.
- Searches resolve to real files when the result's presentation meta
  carries the complete matched-file list (FileOp.hits shows the count,
  include filters join the detail); a capped or malformed meta falls
  back to the searched path/pattern as before, and meta attribution
  survives an aged-out call head.

Closes #24
2026-08-27 23:48:32 +08:00
bowenliang123 e24dcdae87 docs: add workflow section with to-do list guidelines in AGENTS.md 2026-08-27 11:36:34 +08:00
bowenliang123 a20db6a781 docs: clarify usage of read and edit tools in AGENTS.md 2026-08-27 11:33:21 +08:00
bowenliang123 9ad168892e fix(trend): keep the chart scrollbar always visible
The scroller's scrollbar-width: thin made Chromium and Safari drop dsh's
global themed scrollbar skin (any non-auto scrollbar-width/-color silences
::-webkit-scrollbar* rules), falling back to the OS overlay bar that
auto-hides on macOS. Drop the property so the skin takes over; reserve the
bottom padding through its --dsh-scrollbar-width token.
2026-08-27 10:43:44 +08:00
Bowen Liang 201ac1879d fix(client): state each step-brief tooltip in its time window
The three rows draw from different slices of the log, and the tag bubbles only named the content, never the window — scrubbing read like the rows did not match up. Each bubble now opens with its window and closes with the one cross-bar fact that explains the half-step offset: inputs are what entered after the previous reply (nothing new on a turn opener), calls made here land in the NEXT bar's In row, and the opener recalls itself on every step of its turn.
2026-08-27 02:51:28 +08:00
Bowen Liang ce93eb755d fix(trend): hold the step brief at a constant height while scrubbing
Hovering around the trend chart used to change the detail panel's height: the brief section only rendered rows that resolved (the turn opener vanishes outside retention, usage-only replies carry no reply node), and collapsed entirely - margins included - when nothing did.

- the brief lane ALWAYS renders: a fixed three-row min-height, rows appear inside it, unknown steps leave blanks instead of collapsing
- the In row is one of those constants - an empty step shows a muted "(nothing new)" placeholder in place of its chips, and stays inert (a row with no node has nothing to locate)
2026-08-27 02:51:04 +08:00
Bowen Liang fb99ba983a fix(client): remove the trend chart scroll edge fades
The 26px gradient overlays at the chart's left/right edges (shown when the history overflows) read as washed-out white patches; drop the overlays, their edges state machine, and the .lc-chart-fade styles. Scroll anchoring, turn-label centering, and the hover tip are untouched.
2026-08-27 02:12:56 +08:00
Bowen Liang 8e0cc30cc7 fix: move the trend hover tip out of the chart scroller to stop hover layout jumps
The absolutely positioned tooltip contributed scrollable overflow inside
.lc-chart-scroll: a wide reply preview hovering a right-edge bar inflated
scrollWidth and toggled the horizontal scrollbar per hover, jumping the
whole trend card. A new positioned .lc-chart-wrap now anchors the edge
fades and the tip beside the scrollable content; syncTip glues the tip to
its bar visible slice via transform (edge-clamped, centered when wider
than the viewport), which also pins the left fade that used to drift
off-screen with the scrolled content.
2026-08-27 01:50:14 +08:00
Bowen Liang 8d6b2851f8 fix: wrap/shrink card internals instead of spilling past the card edge at narrow widths
Header rows (trend toggles, event kind chips, browser picker), the
file-activity filter/meta strips, and brief input chips now wrap under
width pressure; detail rows fall to one column; browser row tags and
tool-schema param columns shrink so long values ellipsize instead of
forcing their row past the card. Desktop-wide rendering is unchanged.
2026-08-27 01:03:07 +08:00
Bowen Liang 53209a14df release: v0.34.0 2026-08-26 23:28:18 +08:00
Bowen Liang 6735bf150d docs: condense the Agent Network section to its three key points 2026-08-26 23:16:40 +08:00
Bowen Liang 1a31b33191 feat: Agent Network card — live multi-agent context map in the Context tab (#21)
A new Agent Network card at the foot of the Context tab: the whole agent family (current agent, ancestors, subagents at any depth) as a live, fully responsive node map — fused context rings per session, family-colored lineage, halo status language, hover inspector, and click-to-jump into any agent's session. 693 tests, 100% coverage.
2026-08-26 23:09:19 +08:00
bowenliang123 f6564d6958 refactor: assemble registry URL inside readVersion
Drop the static REGISTRY_URLS array; readVersion(host) now concatenates
the plugin name and `/latest` path per call so the registry list holds
only the differing domain.
2026-08-26 17:19:00 +08:00
bowenliang123 3c7ca98d32 feat: fall back to npmmirror when official npm registry fails
Order registries as official npm then npmmirror; each source failure
(non-ok response, missing/non-string version, network error) advances to
the next source, and only an all-source failure resolves to null so the
plugin info card keeps its baked-in version. TTL cache and module-level
promise reuse are unchanged.
2026-08-26 17:16:09 +08:00
bowenliang123 114cd6490c docs: update language support guidelines for UI elements 2026-08-26 17:09:50 +08:00