Replace per-plugin tapIndex regex edits with pure-data IndexInjection rows
collected fresh per render over one webserver/index-inject event. One table,
two renderers: the served form renders rows into index.html; a static worker
form ships the same rows over its boot payload. tapIndex survives as the
raw-HTML escape hatch, applied after row rendering; client-modules and
ui-theme move to the event, and the manifest global renders as
globalThis["__DSH_BOOT__"].
The client boot chain gains the seams a pre-injected transport needs: the
module loader takes loadBundle from the transport global by default, HTTP
prefetch stands down when a transport owns bundle bytes, the web-app bundle
can decline frontend serving, the gateway client installs a namespace's
whole method group inside its fiber apply so a parked dependent never
observes the service without its methods, and the dynamic-code precheck
gates through new Function so hosts without a real node:vm keep the
define-time parse gate.
The composition tests hardcoded shared /tmp/dsh-acp-demo-* persistence
roots. On the shared self-hosted CI VM, concurrent jobs running the same
master-level test file opened the same SQLite session-query.db and one
failed with "database is locked". Use mkdtemp-unique directories so each
run owns its SQLite index while still exercising explicit
persistenceRoot forwarding.
Address the latest review pass on PR #2798:
- client-build-environment.client.spec.ts: add release-publish.yml to
dshBuildWorkflows so the 'workflow env must not set DSH_CLIENT_*' gate covers
the new dsh publish path (it runs build:official and writes a dsh client
build record). vendor-publish runs only build:lib:host, so it is not added.
- 2026-08-10-npm-release-sequences note (en/zh/i18n): the Release-publish group
is carried by the publish job (job-level concurrency), not the whole
workflow; corrected the wording.
Address the fresh review pass on PR #2798:
- ci-workflow.spec.ts: restore the subscription-type assertions the rewrite had
dropped (issue-lifecycle pull_request types omit ready_for_review and include
review_requested; pull_request_review types == ['submitted']) alongside the
new step-level gate checks, so the 'tests pin the subscribed events' gate
holds.
- 2026-08-10-npm-release-sequences note (en/zh/i18n): the three-sequence table's
Workflow column now lists the pack and publish workflows for dsh/vendor, and
line 114 no longer claims release.yml publishes (the dsh pack job packs the
vendored family for verification; release-publish.yml repacks and publishes).
Follow-up for the pack-job copy drift is filed as #2816.
Ordinary typing supplied no edit range, so the machine recovered one by
scanning the two drafts for a common prefix and suffix. That reading is
ambiguous whenever the inserted text repeats what it lands against, and the
greedy scan always slides the edit as late as the characters allow. A
reference renders as '@' plus its label, so typing '@' immediately before one
reads as an insertion inside the reference; reconcile then applies its
intersect rule and drops the occurrence. Submission takes the occurrence-free
path and sends the human-facing label instead of the owner's model form, past
the serialization guard that only fires when an occurrence survives.
InputBar now records the textarea's selection during beforeinput and passes
the resulting range to setDraft, which the machine already prefers over its
own scan. A record that cannot describe the reported change yields no range
and the scan still runs.
The pending-question registry holds the awaiting tool call's own
resolve/reject, so it is host-process memory. events.mux replays every
still-pending question on reopen, which covers a browser reload or a
reconnect, but a host restart takes the awaiting turn with it and the
reopened Session offers no composer for that question.
A question that carried options collected its free-text answer in a
single-line input: a long sentence scrolled sideways inside one line and
Shift+Enter was inert, so an answer with structure could not be typed.
The optionless question already used a textarea, but a fixed 64-140px box
that never followed the draft.
Both shapes now answer into one AnswerField: a `textarea rows=1` sharing a
grid cell with a hidden mirror that renders the draft plus a trailing
newline and so owns the height. Soft wraps are invisible to a '\n' count,
so the mirror is what grows the box; growth stops at eight lines and the
textarea scrolls from there, keeping the choices the answer belongs to in
view. Enter still continues and submits, Shift+Enter breaks the line, and
the IME guard is unchanged.
Address ds-review-bot findings on PR #2798:
- release-publish.yml: use pnpm run build:official (not build) so the dsh
pack step's verifyBuildArtifacts (families.ts:327, readClientBuildRecord with
officialClientBuildEnvironment) finds the official client-build record; build
would fail Pack release tarballs on a clean runner.
- issue-lifecycle.yml: move the previous job-level if to step level on
Create project token and Handle repository event, so approved/commented
reviews pass (job reported success, no gray segment) without minting a
write-capable App token or touching the board — preserving the original
least-privilege property.
- ci-workflow.spec.ts: lock the step-level gate on the two lifecycle steps, and
add a release-workflow invariant test (release.yml/vendor are pack-only;
release-publish.yml/vendor-publish.yml are workflow_dispatch-only with the
npm-publish environment and Release-publish group) to prevent #2797 recurrence.
- Update 2026-08-10-event-directed-pr-review-status and 2026-08-10-npm-release-
sequences notes (en/zh/i18n) to the new split and step-level behavior.
Verification: ci-workflow.spec.ts 14/14, typecheck clean, all five workflows
YAML-parse, verify-translation-pairing consistent, note-format 582.
The themed WebKit scrollbar skin keeps a wide table's horizontal bar
permanently painted. Chromium never repaints state-conditioned scrollbar
styles (hover-conditioned ::-webkit-scrollbar* rules and :hover
scrollbar-color changes both compute but never reach the painted bar,
measured headed and headless), so the hover reveal toggles overflow-x
itself: hidden at rest with a padding-bottom matching the themed bar
height, auto on hover or keyboard focus with the padding released — the
appearing bar exactly replaces the padding and nothing below shifts.
Resting hidden overflow drops Chromium's implicit scroller focusability,
so wide wrappers carry an explicit tabindex for arrow-key scrolling.
Review follow-up on #2794: the pin was applied inside nextSessionOrderAccount,
whose output syncSessionOrderAccount persists into sessionOrderByAccount, so a
reused blank stayed first forever after turning non-blank (even across
reloads). Move the pin to the render-derived layer (orderedWorkspaces,
orderedUngroupedSessionIds, ungrouped order, flat rows) so the persisted
account order is never touched, and skip drags the pin would mask (dragging
the pinned blank, or parking another row into the pinned slot) entirely,
including the Host account write.
Adds regression tests for the masked-drag skip and for the pin releasing when
the blank turns real; updates the sidebar-order Agent Note (EN + ZH) and its
pairing hash.
Address ds-review-bot re-review: collect per-cleanup rejections and rethrow
as AggregateError so real flush failures surface instead of being swallowed;
register the cold-resume context's second persistence handle in cleanups so
it closes even on a failure path; drop the unverifiable flake-history aside.
Remove the three skipped (gray) checks from the PR check panel without changing
functional semantics:
- issue-lifecycle: remove the job-level 'if' that skipped the lifecycle job on
non-changes-requested pull_request_review events, so it now runs and reports
success (the lifecycle handler already no-ops for approved/commented reviews).
The changes-requested board transition is unchanged.
- release.yml / release-vendor.yml: drop the publish job (and its
workflow_dispatch 'publish' input + RELEASE_PUBLISH pass-through) so it no
longer appears as a skipped Publish-to-npm check on PRs; the files keep the
pack job that validates tarballs on PR/push.
- new release-publish.yml / release-vendor-publish.yml: manual workflow_dispatch
only, repack on the current tree then publish, so publication behaves exactly
as the old publish job (explicit dispatch, uses the packed bytes) but never
shows as a PR check.
Update the 2026-08-10 review-status note (en/zh/i18n) and the issue-lifecycle
spec assertion to match the unconditional lifecycle job.
Verification: ci-workflow.spec.ts 19/19, all five workflows YAML-parse, typecheck
clean, verify-translation-pairing consistent, note-format 582.
The backdrop keyed each plain-text reference mark by its draft offset, so
any character typed ahead of a reference changed the key and made React
unmount the mark with its nested spans and inline glyph. Every keystroke
before a reference rebuilt every reference after the caret.
A scan derives these ranges fresh on every render, so a range carries no
identity past the render slot it occupies. The mark now keys by its index
in the offset-sorted textRefs list. Structured chips keep occurrenceId,
the identity their occurrence table owns.
The New Session being created renders first in its account while selected,
in both order modes; opening or reusing a blank never advances its
updatedAt, so the pin keeps the reused row at the front.
Clicking New Session reuses the workspace's existing blank session when one
exists; reuse only opens it, so its updatedAt (host: max(createdAt,
lastPromptAt)) never advances and the row kept its old creation-time
position in the sidebar. nextSessionOrderAccount now pins the currently
selected blank session to the front of its account in both Manual and Last
updated modes; non-blank navigation stays untouched.
Fixes#2788
Trim knip.json to 655 lines by removing 15 stale or glob-duplicate workspace entries. Behavior-neutral under knip's specificity-based workspace config selection; CI green, issue policy green, review threads resolved.
ProjectionDefinition lost its persist?: boolean opt-in when every
projection unit became uniformly checkpointed, but the subsystem doc's
type-equiv paste still carried the field, so verify-type-equiv drifted
from packages/session/session-projection/src/index.ts. Remove the field
and its JSDoc from both language sides and re-record the bilingual
pairing record.