* feat(liveshare): add the owner host, viewer host, and share runtime
The owner-side half of the bundle: the share host that publishes a Session to a Relay and answers one viewer per share, the owner credential/authorization records, the fork registry and its enforcement, the read-only viewer access policy and read budgets, the turn-requester fold, and the Relay gateway worker. The viewer host renders the served page's assets and declarations; no browser code is included in this layer.
* test(liveshare): cover the owner host, viewer host, and gateway
Keyless host-side coverage: share publication and restore, owner login/authority, fork registry and enforcement, viewer read policy and budgets, the turn-requester fold, the Relay tunnel worker and gateway commands, and the served viewer page. The browser surfaces are covered by the client layer's own suite.
* chore(build): register the host bundle in the compiler, dependency policy, and CI
The package manifest, Host compiler face, and tsdown host entries the bundle needs; the workspace constraints the built gateway/declaration artifacts require; the release-family and README model-experience rows; the coverage-lane exemption; and the keyless CI job that runs the share cases on Linux. The dependency-policy classifications wait for the client layer, which is where the package's client face (and its imports) first appears.
* docs(liveshare): record the bundle's subsystem, projection, and decision rationale
The package README for the host layer, the subsystem page, the persistence record that declares the viewer principal projection, and the note that keeps the protocol and owner-surface decisions with their evidence.
* feat(boot): offer the Liveshare host bundle in the CLI profile and plugin manager
The bundle joins the optional bundles the CLI installation carries and the Official group the plugin manager lists, so an owner can switch it on without editing a profile by hand. The plugin-manager and plugin-config expectations follow in the client layer that renders the card's browser half.
* chore(docs): regenerate the graphs, catalogs, and persistence records for the host
Run the generators over the host layer: the event producer/consumer graphs, the persistence catalog and schema inventory, the config catalog, the module graph, and the Cordis API catalog. The persisted viewer-principal event appears in the catalog and the historical format index counts it.
* fix(liveshare): keep the bundle's locale display metadata in this layer
The CLI profile registers the bundle as optional, so the plugin manager reads title and description from ./locale/*.json. Ship the two locale files and their export here; the browser half is not needed for display metadata.
* refactor(liveshare): read the turn boundary through the typed Agents service
The retained projection-handle migration left two assertions converted through unknown; ctx.get('agents') already exposes turnBoundaryOf, so the host and the cancel-admission case call it directly and the unknown-cast baseline stays untouched.
* test(liveshare): expect the canonical viewer tier from the three-mode harness
The Relay reports a share published with the withdrawn fork-readonly tier as view and carries the fork grant separately, so the harness compares the canonical tier and forwards an explicit allowsFork when the case names one.
* refactor(liveshare): share the reader-facing record and body readers
The fork decision and the access snapshot built the same share facts twice, and the two share-writing routes read the same share-naming JSON body twice; both pairs are now one helper each, so jscpd no longer reports them. Behavior is unchanged.
* test(web): record the host layer's optional-bundle expectations
Registering the LiveShare bundle in the Official group adds its card and description to the plugin manager and plugin-config pages, and the packed preview must state that its host plugin needs LIVESHARE_RELAY_URL instead of a generic applied toggle. Refresh the affected goldens locally (keyless web snapshot refresh) and keep the card badge at this layer: the client list that labels it experimental arrives with the client layer.
* docs(liveshare): mark the shipping owner policy note implemented
The protocol-and-owner-surfaces decision shipped with this bundle, so the note moves from proposed/ to implemented/ in both languages, its proposal-era headings become Decision/Verification/Consequences, and the subsystem page plus package README link to the new path. The pairing record moves with the triplet.
* fix(liveshare): judge tool turns from the open Session turn and recheck the narrowed write
The master baseline has no ToolExecutionInput.turn, so the host derives the turn a tool execution serves from the Agent's Session: the latest turn/start with no turn/end after it. A missing Agent, Session, or open turn yields no turn and the fork guard refuses the execution (fail-closed) instead of reading it as the owner's. Also refuse a fork that names a child without a bound rpcId/operationId, classify forwarded paths by their normalized pathname so /api/session/./fork or a query suffix cannot skip the fork decision, and ask the write gate again after the final authorization refresh so a share narrowed to view during fs/write-intent cannot write. The subsystem page, package README, and model-experience census follow the two-tier model and the bounded-write child ceiling.
* refactor(liveshare): read the open turn beside the requester fold
The derivation reads the same Session log the requester fold decides, so it
lives with that fold and the host imports it instead of keeping a private copy.
* test(liveshare): cover the derived turn and the refusal paths
Drive the host's real derivation from Session events: the open turn of the
Agent's Session decides a viewer turn is confined and an owner turn is not,
while a missing Agent, an absent open turn, and a requester the host no longer
drives all refuse instead of being read as the owner's. Cover the three safety
behaviours the host commit added: fork child naming without a bound request
identity, dot-segment/query fork paths that must still reach the fork decision,
and a share narrowed to view while fs/write-intent awaits.
* fix(liveshare): avoid the deprecated snapshot reader and the extra casts
The host derived the open turn by scanning the Session event log, which the
deprecation note forbids for new production calls. Read the same state from the
turnBoundary projection the Agents service maintains instead, and let a spec
supply a fixture boundary reader where production supplies turnBoundaryOf.
The live attribution of an execution is unchanged: an absent boundary or one
between turns still yields no turn and the guard refuses it fail-closed.
* docs(liveshare): describe the bundle's indirect model experience
The bundle's Model Experience moved to the audited indirect classification,
so the README sentence now names the path: viewer prompts the owner host
forwards into a shared Session drive that Session's model requests. The
KV-cache paragraph and the bilingual pairing record follow.
* test(liveshare): pin the turn-start admission for steered and admitted reader input
The pre-step admission already re-reads Relay authority from each entering message's own source and refuses queued reader input whose grant ended before the model runs; the new cases pin the steer path and the admitted viewer turn, so the turn-start half stays proven next to the delivery-time recheck the Session Controller owns.
* test(liveshare): adapt the replay and cancel expectations to the parsed tier
* test(liveshare): align the access-state expectations with protocol v2
The parsed share-access-state frame always carries allowsFileUpload, the
withdrawn fork-readonly word no longer implies a view tier or forking, and a
hand-built frame may not name it. Update the hand-built expectations and the
two fixture specs that named the retired word, without touching production
semantics.
* test(liveshare): record the in-flight cancel race after the controller revert
The Session Controller no longer re-reads a caller's access before cancelling,
so a cancel admitted before the reader's grant ends keeps its effect. State that
as the known limitation the earlier refusal tests documented instead.
* feat(liveshare): add the viewer attachment-upload switch
The share record, registration handshake, access-state replay, and share-viewer
policy carry an owner switch that is off by default: it admits fileUploads/upload
on the shared Session and the viewer's own forks, is independent of the tier and
of forking, and is normalized to off at every untrusted state-file or frame
boundary.
* docs(liveshare): state the sandbox tiers and the attachment switch
Name the two execution tiers as a read-only sandbox and a bounded writable
sandbox, and document the independent default-off switch that lets admitted
viewers upload attachments, including that legacy shares read as off.
* refactor(liveshare): drop the withdrawn fork-readonly migration
The feature never shipped, so no stored record can name the withdrawn tier and
the boundary needs no compatibility path. Read a stored fork switch as exactly
what it states, let an old Relay state the switch explicitly instead of
inferring it from the tier, and stop accepting the retired mode name on create
or restore.
* fix(liveshare): preflight a resumed child's limit before publishing it
A resumed child is announced through agent/created before its execution limit
installs, so an installability failure left a created Session whose guard never
landed. Resolve the recorded child's granted workspace before activation and
refuse the resume there, so a child this host cannot confine is never published.
* refactor(liveshare): render the viewer page through the reader's own Peer
The served-page seam now hands the frontend reader the reader's Peer, which renders that page's own
opening access rows; the Liveshare side no longer assembles a global access snapshot and the removed
global is gone. The viewer read service builds the same Peer it already creates for every dispatch and
passes it to the asset reader.
* fix(liveshare): keep the owner upload switch across an older Relay's access frame
The Relay is the authority for what a viewer receives, but only for the fields its frame states. An
older Relay predates the upload switch and omits it entirely; the protocol parser rightly normalizes a
missing switch to off for frames that state it, so the host must inspect the raw answer to tell not
* test(liveshare): adapt the host specs to the current tool and session APIs
The host specs drove a single tool through the pre-batch executor shape and handed
some tests a Session outside its store; the current tool executor takes a call batch
and Session appends require the owning SessionStore. This adapts those fixtures to
the current shapes without changing what each test asserts.
Also gives the reader's own fork the same Session permissions as the source grant:
forking its own child again and renaming it are allowed on the child only, while the
source Session still refuses renaming and keeps forking as its one Session verb.
* fix(liveshare): let the owner's background turns run while a share is served
The requester fold only counts a message with `source.kind === 'user'`, so a
turn a background event opened has no attributable input and stayed `unknown`;
the source-session tool guard refused every tool in that turn. Establish the
owner's own turn for an input-less turn and leave unattributable input unknown.
* fix(liveshare): grant the reader its own fork's rename and gate child forks by the fork switch
* refactor(liveshare): read the served page through webServer.readResource
* feat(boot): offer the Liveshare host bundle from the official bundle list
`@deepseek-ai/dsh-official-bundles` owns the shipped template, retired, and
optional bundle lists now, so the liveshare bundle joins `OPTIONAL_BUNDLES`
there instead of being restated in the app-boot profile module.
* feat(liveshare): gate the reader's own fork independently of its input permissions
The reader's child gets prompt, cancel, and rename from a role with no extra
condition, while forking the shared Session or one of the reader's own forks
belongs to a separate role bound to the owner's fork switch. A viewer cannot
rename the shared Session, and a withdrawn fork switch also withdraws forking
a child.
* test(liveshare): adapt the admission specs to the current tool and driver APIs
* feat(liveshare): accept only the declarations a plugin's own package owns
A viewer plugin may contribute endpoints a share can offer, so a declaration
has to name a live Host Remote endpoint whose generated id belongs to the
declaring package. Fail closed: no loader entry, no local endpoint, no owning
package, or a foreign owner all refuse the declaration, and the recorded
attribution is the package name the owner sees.
The package's Typert artifact registers after its apply runs, so a plugin
declares once that registration has happened.
* feat(liveshare): classify every Remote endpoint before the reader policy decides it
The share-viewer policy refuses by default, so the endpoints it decides were a
handwritten whitelist that could drift from the generated endpoint set. State
every endpoint's reason in one shared table: the Client face proves it covers
`RemoteEndpoint` (both directions), the Host derives `POLICY_DECIDED_ACTIONS`
from the reader entries, and a load-time assertion fails if the derived set and
the roles' actions disagree.
* fix(liveshare): declare the Client face its classification gate compiles in
Typert attributes a package's exports to a face only for manifests declaring
`dsh.client` plus a `./client` subpath (`isDualFacePackage`). Without that row
the client catalog read `exports["."]` — the Host entry — from the Client
program, which holds only the classification table and its completeness gate,
and failed on the source that program does not contain.
Export the gate module as `./client`, declare the Client row, publish its
bundle, and exempt the package from Client/Host dependency treatment: the
runtime importing these dependencies is the Host's, and `dsh.client` here only
attributes the compilation face.
* test(liveshare): align worker fixtures with the protocol tenant contract
The protocol layer rejects a share RPC actor whose tenant is empty at the IPC ingress. The worker fixtures still described a peer normalizing the tenant to an empty string, so the Host dropped every fabricated request event and the lifecycle and correlation polls timed out. Use a concrete tenant in the fixtures; those scenarios do not depend on an empty tenant.
* chore(docs): count the liveshare persistence nodes in the format index
The regenerated current-checkout catalog adds the liveshare viewer-principal nodes, so the v4 row's node count moves from 622 to 626. Refresh the generated format index rather than keeping the pre-liveshare count.
* refactor(liveshare): consume the protocol package's single public entry
The protocol layer now publishes only its root entry, so the Host face reads the wire codecs, identity contract, and viewer-state vocabulary from the package root instead of the removed /protocol and /identity subpaths.
* fix(liveshare): classify the schedule cleanup endpoint before the Client gate reads it
The Client completeness gate compiles against the generated Remote endpoint map; master added schedule/deleteInactive after the table was last filled. It mutates the owner's schedules like its neighbours, so it stays owner-only.
* chore(release): carry the liveshare package to the rc.3 family version
* docs(liveshare): align the host docs with the shipped two-tier shares
The subsystem page still described a withdrawn fork-readonly compatibility, a
write-only source drive, and an immutable execution.turn. State the two tiers,
the independent fork and upload switches, the refused unknown mode, and the
turn derived from the Session boundary. Mirror the Chinese pages and re-record
the pairing hashes.
* fix(liveshare): describe the writable tier in the plugin card
The package description, both locale descriptions, and the three Web goldens
still told the owner that sharing is read-only. State driving, bounded writes,
forking, and the independent upload switch instead.
* chore(liveshare): forward the owner credential file from the bundle patch
The README lists LIVESHARE_OWNER_CREDENTIAL_FILE beside the other owner
settings, but the patch left it to a direct process.env read. Pass it through
the same config field as its siblings.
* docs(liveshare): drop stale fork module comments
The registry header still said read-only forks only, and both the registry
and the policy carried an orphan JSDoc block in front of the real one.
* refactor(liveshare): drop unreachable fork tool effect fields
ForkToolRequest.writesWorkspace and changesConfiguration had no producer in
the repository: the guard never sets them, and the only callers were the
tests. The write-denying branch also contradicted WRITE_FORK_CEILING, which
admits the bounded write tool. Remove the fields, their refusal codes, and
the test cases that manufactured them.
* refactor(liveshare-protocol): retire the attachment-upload capability
Sharing itself now carries attachment upload, so the protocol no longer
states an independent switch: `LIVESHARE_CAPABILITIES` drops
`file-upload`, and share specs and access-state frames drop
`allowsFileUpload`. Wire frames stay v1 and no Relay is deployed, so no
compatibility layer is needed.
* refactor(liveshare): grant attachment upload with visibility
The owner controls sharing, audience, the tier, and forking only.
`fileUploads/upload` now rides the Session read role, so every Session a
share serves the viewer accepts files, independent of the tier and the
fork switch. The owner record, the share APIs, the registration handshake,
and access-state adoption no longer carry an upload switch; an older owner
state file that still contains the field loads with it ignored.
Accepted risk, recorded in Known Limitations: an owner cannot refuse
uploads for an admitted viewer.
* feat(liveshare): share the owner wire records
Move the owner identity report into a module both compiler faces can import, and
declare the share-management request, result, audit, and capability records there
with the same fields the same-origin routes already answer. The Remote failure
vocabulary joins the same module so a client learns the liveshareShares/ codes
without importing the Host.
* refactor(liveshare): extract the owner share operations
Move the twelve share-management handler bodies out of the route closures into
operations implemented once inside apply(), leaving each HTTP route with its JSON
parsing, normalization, and legacy status/body. Each operation documents the
side-effect order it keeps and what reordering would break.
* feat(liveshare): serve share management over Typert Remote
Register a LiveshareShares Remote service over the same operations the routes
call, publish its ./typert and ./remote artifacts plus the shared ./types module,
and make the shared records part of the Client compiler face. The owner page gains
the Remote endpoints while the HTTP routes stay as thin adapters.
* chore(docs): regenerate the Cordis catalog for share management
Record the liveshareShares service on the LiveShare subsystem page, link its
wire records to that page, and regenerate the runtime API catalog. The service
declaration moves to the package entry so the host-face catalog projection can
render it.
* test(liveshare): refuse share management to viewer Peers over Remote
Cover the owner Peer's Remote list and the share-viewer denial of list, create,
stop, and setRelay. The refused calls leave the share list empty, the selected
Relay unchanged, and the worker channel without an add-share.
* chore(liveshare): mark the typert resource follow-ups behind #7003
The share-management Remote ships against today's resource registration. Default
resource resolvers and the stricter identity rules arrive with #7003, so the two
places that will change carry a TODO naming the PR.
* fix(docs): classify the liveshareShares service role
The share-management Remote adds one owner-side service, so the capability
seams graph owed it a role row; without the classification the generator
refuses to render and doc-sync fails.
* fix(liveshare): complete the bundle metadata and restore the static gates
The bundle shipped only two of the eight shipped-language metadata files, and its
browser face had no named tsdown config, so the locale metadata gate and the
browser bundle walk both failed. Ship the full locale set and name the client
build; share one owner-body registrar between the two POST adapters so jscpd
stops reporting an eight-line clone.
* fix(liveshare): give the bundle a client source route and a typed peer double
The product-use walk follows `${name}/client` for every mounted bundle, so the
package needs the source mapping and a Client entry the mapping resolves to.
Replace the unknown-cast peer double with a complete PeerScope literal.
* test(liveshare): adapt the viewer admission rows to the Session default resolver
#7003 replaced the `session/page` and `session/follow` resource readers with the
Session kind's default resolver. A body carrying both `sessionId` and `address`
is now refused as invalid resources before the share policy reads either, while
a lone hidden `sessionId` still resolves and is refused by the policy.
Records the new expectations; the served page names one identity per request.
* feat(liveshare): resolve create's request Session through the default resolver
#7003 registers the `session` kind's default resolver with the Session
Controller, and `liveshareShares/create` names its Session in the one request
object, so the Gateway resolves that Session for a non-owner Peer without a
reader declared on the method. The owner Peer reaches the operation without
an access decision.
Adds the Gateway resource assertion and the owner-path assertion to the
share-management security spec, regenerating the Cordis catalog.
* test(liveshare): refuse a viewer body naming two Session identities
A prompt or cancel body carrying both `sessionId` and `address` reaches the
Gateway, whose Session resolver refuses it as invalid resources, so the target
child operation never runs and no request content comes back. Prompt and
cancel requests name their Session by `sessionId` alone.
* test(liveshare): widen the two-identity coverage across the reader endpoints
The resolver refuses a request that names two Session identities for every
namespace, so cover the remaining reader endpoints with one parametrized case
instead of leaving them to the generic Gateway tests.
* refactor(liveshare): remove the unreferenced gateway heartbeat policy
The production worker keeps its own interval and missed-pong counter, so
nothing imported this module; only its spec did.
* refactor(liveshare): extract the owner state persistence
The state file reader, writer, serialized write queue, and stored-share
record types move out of the host plugin unchanged.
* refactor(liveshare): extract the Relay authority reader
The access-state cache, its generation fence, the admission rule, and the
authoritative read that adopts a frame move behind one factory.
* refactor(liveshare): extract the tunnel worker supervision
Worker start, settlement, registration replay, expiry timers, owed Relay
rows, and the credential state each registration presents move out of the
host plugin behind one factory.
* refactor(liveshare): extract the owner share operations
The twelve operations keep their order and side effects but move behind an
explicit deps factory, so the host plugin mounts them instead of owning
their bodies.
* refactor(liveshare): extract the owner routes and source access
The sixteen owner HTTP routes, their request adapters, and the credential
store move behind registerOwnerHttpRoutes. The confined source Session
layer and its turn control move to source-access, which the share-host
re-exports for its public helpers.
* refactor(liveshare): split the viewer reader into dispatch, fork, and lifecycle
The request entry and endpoint handlers, fork orchestration and branch
facts, and the streams/calls/Peers lifecycle move out of viewer-read,
which keeps the deps types and assembly. Order, TOCTOU re-checks, and
Peer ownership are unchanged.
* refactor(liveshare): share the wire JSON helpers and the fork enforcement record
The split duplicated `json`/`isRecord` across the extracted owner modules and the
child enforcement options at three call sites; the stored ACL selection type also
lost its reference to the wire type. One helper module and one record factory keep
the split modules from carrying their own copies.
* refactor(liveshare): move the shared owner record and one-definition helpers
The split published OwnerShare from the assembly while every extracted module
imported it back, and left each host module carrying its own isRecord. Move the
share record and its ACL summary to a neutral module, name the two optional
service seams instead of inline casts, and import one wire JSON helper.
* refactor(liveshare): remove the fork-enforcement audit event
Nothing consumes `liveshare/fork-enforcement` except the spec that watched
it, so the minimal-surface rule drops the declaration, the reporter, and
every report call instead of reserving an extension point for later.
The wiring spec now asserts the outcomes an observer could previously
infer stages from: an install that returns nothing leaves
`ForkRegistry.enforcementInstalled` false and the child's prompt gate
refused with `fork-ceiling-uninstalled`. The subsystem prose no longer
names the removed refusal code, and the Cordis/doc catalogs are
regenerated.
* fix(liveshare): surface fork enforcement failures
Three registration paths swallowed the error behind a fail-closed
refusal. Keep refusing, but carry the reason:
- `preflightForkChild` now throws `fork <id> preflight failed: <message>`
when the stored child cannot be read, instead of returning and letting
activation fail later; `share-host`'s `prepareChild` caller already
propagates that through the viewer's `fork-prepare-failed` answer.
- A child's confined `read`/`write` registration keeps its error in a
`ForkEnforcementFailure`, so `prepareChild` throws
`fork execution limits are unavailable: <message>` with the error as
the cause instead of the bare message.
- Source-session access keeps the refused registration on the
installation and logs it beside the existing confinement refusal.
The wiring spec asserts the preflight failure and both captured errors.
* refactor(liveshare): move the client placeholder face out of this layer
The `./client` entry existed only so the package's Client face could
compile the viewer endpoint classification against the generated Remote
map; it published no runtime this product used. P3b owns the real Client
face, so P3a drops the placeholder instead of shipping a surface ahead of
its consumer:
- delete `src/client/*` and the package's Client tsconfig; the endpoint
spec keeps the Host-table diagnostics, and the Host still derives the
policy action set from that table
- drop `dsh.client`, `exports["./client"]`, the `lib/client.js` publish
entry, the browser tsdown build, and the package path alias
- remove the dependency-policy exemption and the devDependencies only
those client sources imported
- the Host tsdown face still skips the Client build pass; `./typert` and
`./remote` stay Host-generated and the Client tsconfig never fed them
- README and subsystem prose no longer claim a browser face
* chore(ci): drop the stacked-PR e2e dispatch input
The narrow dispatch scope existed only to verify a stack's exact SHA while its
ordinary pull-request checks were unavailable; it is not part of LiveShare and
never belonged in this layer's diff.
* feat(liveshare): add the share dialogs, viewer seats, and client surfaces
The browser half of the bundle: the owner's share dialog and management surfaces, the owner sign-in flow, the viewer page's session plugin, brand, status, and seat components, and the read-only permission and model seats that replace the shipped composer controls at a shadow rank. The package README regains the client implementation links this layer provides.
* test(liveshare): cover the client surfaces and viewer seats
jsdom coverage for the share dialogs, owner login and identity, the viewer page composition, the read-only seats and their shadow rank, the served-page artifacts, and the client-face registration. The host-side suite stays in the lower layer.
* chore(build): ship the Liveshare client bundle
The client compiler face and solution reference, the tsdown client entry beside the host phase, the manifest's client export, client runtime files, locale assets, and client dependencies; the dependency-policy classifications whose consumers appear with the client face; the generated client slot catalog; and the plugin-manager expectations that list the bundle's card.
* fix(liveshare): shadow the shipped brand seats instead of colliding with them
sidebar.brand.mark and sidebar.brand.name are single slots, and a served viewer page mounts the owner's plugins, so on an official build ui-brand-official already registers both at the default rank. Register the viewer entries at a shadow rank and pin the collision in a registration spec, as the composer seats already do.
* fix(liveshare): clear the viewer's composer blocks when its plugin is disposed
The honest-composer effect raised a per-Session block but its disposer only unsubscribed, so a disposed or replaced viewer page left the owner's composer blocked. Track the Sessions it addressed and clear their blocks on disposal; a spec pins the recovery.
* style(liveshare): drop unnecessary type assertions in the registration specs
The slot test runtime's renderSlot already accepts these owner props, so the contracts-ready lint reports the as-never assertions as unnecessary.
* test(web): mark the client layer's LiveShare card experimental
The client layer ships the card that renders the bundle, and the recorded goldens already carry its Experimental badge. Add the bundle to the manager's always-held extension list and to the presentation's experimental set, and expect badge 1 in the plugin-manager spec.
* fix(liveshare-client): return to the share after viewer sign-in
The viewer page names its share in its own query (?shareId=...), so a
sign-in that returned to the bare path brought the reader back to a page
that no longer named their share. Build the Relay sign-in entry from the
page's path and query, and keep the entry's construction in one testable
function.
* fix(liveshare-client): state a half-saved share permission accurately
Saving the share permission writes the session tier first and the plugin
endpoint selection second. When the second write was refused the dialog
claimed the whole save had failed, though the tier and fork switch were
already stored. State which half landed, and re-read the host's record so
the fields show what it kept while the refused endpoint pick stays for the
retry.
* fix(liveshare-client): route viewer copy through the client locale seat
The viewer surfaces translated their own copy from navigator.language, so
a language chosen in Settings could not reach them and a Node boot read the
machine's language instead of the page's. Register the package dictionaries
once, as the client face already does, and take the bound translate seat:
React seats get it from their locale registration, and the plain-DOM status
banner takes it from the plugin and repaints on locale changes.
Also move the viewer status banner's copy and reason helpers to that seat,
and update the viewer specs to provide a LocaleRuntime the way the assembled
viewer page does.
* test(liveshare): assert the two-tier fork ceiling in the viewer artifact
The branched row states the ceiling the host installed: a view-tier
(fork-readonly reads as view) share's child runs under the read-only fork
ceiling, while a write-tier share's child carries the bounded write
ceiling, whose host half readonly-fork-cold-child.spec.ts covers. Read
that statement through the shipped Tooltip's pointer events: after the
rebase it listens to pointerenter/pointerleave, so the previous mouse-event
hover never raised the bubble and the row's statement stayed unread.
* feat(plugins): hide LiveShare until its plugin rows run
A default installation ships the LiveShare package but composes none of
its plugins, so the plugin manager must list it nowhere; enabling it
through the profile's cordis.patch.yml or its bundle selection starts
those rows and only then shows the card under Experimental plugins.
The visibility rule reads the bundle rows' own run state rather than the
profile's bundle selection, because a row inserted through cordis.patch.yml
runs while the bundle stays unselected. The hidden bundle ID stays
addressable, so openBundle still opens its details.
* test(web): assert the hidden LiveShare card across both lists
The plugin-manager scenario now checks that the default profile lists no
LiveShare card in the Experimental plugins group or on the More page, and
that the offered count is one lower than the shipped optional bundles. A
dedicated scaffold writes the bundle's declarations row into the profile
patch, waits for the loader to recompose it with bounded timeouts, and
checks the card joins the list and leaves it again when the row is removed.
* docs(plugins): document LiveShare's default hidden state and enablement
The package README now states that a default installation shows LiveShare
in neither plugin list, and gives both enable routes: inserting the
bundle's two entries in the profile's cordis.patch.yml (placeholders for
the deployment's Relay identity values, with the recomposition caveat), or
selecting the bundle in dsh.profile.bundles. It also states that removing
or disabling the rows takes the card away again. The subsystem page keeps
the rule and links to the README for the exact entries, and the plugin
manager README describes the hidden-until-running list behavior.
This also repairs the README's pre-existing Model Experience mismatch with
its audited indirect classification, which failed the documentation gate
before this change.
* docs(agent-notes): record LiveShare's hidden-until-running rule
Record why the plugin manager keys visibility on the bundle rows' run state
rather than the profile's bundle selection (the cordis.patch.yml route
leaves the bundle unselected while its plugins run), and why the detail
entry by bundle ID survives the hidden card. The rejected alternatives and
the costs of the decision are stated for review.
* test(web): expect the hidden LiveShare card in the configuration scenario
The configuration-page scenario reads the same More list as the plugin
manager, so its offered count is one lower than the installed optional
bundles while LiveShare's declared rows do not run.
* test(web): re-record the plugin goldens without the default LiveShare card
Refresh goldens remove the LiveShare entry from the Experimental plugins
list of both plugin-manager snapshots and from the plugin-configuration
snapshot, and drop the refresh card count from 12 to 11. Re-analysis under
replay confirms both scenarios green.
* fix(liveshare-client): release the viewer page state with its plugin
The viewer context facts, capability, and status stores are module-level so
every viewer surface reads one page's answer, but nothing released them when
the plugin owning the page was disposed or HMR-replaced, so the next mount
inherited the previous page's share facts, tier, and status. The viewer
session plugin now owns that lifetime: it clears the stores when it mounts
and disposes, and advances the read generation so a previous page's in-flight
answer cannot publish into the new page. A spec pins the disposed page and
the inherited state.
* feat(liveshare-client): add the viewer attachment-upload switch
The share carries whether viewers may upload attachments as its own switch,
off by default and independent of the session tier and the fork switch: a
view-tier share may allow uploads and a writable one may refuse them. The
share dialog sets it in both the create and edit flows and submits it with
the permission write; the manager sets it per share beside the fork switch.
A share the Host does not report reads as off. The dialog also states the
tier as the sandbox it runs in, so neither tier is described as carrying
file uploads.
* docs(liveshare): describe the sandbox tiers and the upload switch
The host layer owns the package README statement of the two tier sandboxes
and the upload switch; this layer's documentation adds the subsystem
contract for the switch and the client README's attachment-intake sentence —
file intake follows fileUploads/upload, which a share grants only while its
own switch is on.
* refactor(liveshare-client): drive the owner dialogs through the modal layer and shared primitives
Both owner dialogs ran their own focus trap beside Modal's layer, so initial focus, Tab wrapping, Escape
and focus restoration were each installed twice and could disagree. The hand-written trap is removed;
the shared layer owns the keyboard lifetime, including the dialog's own restore target. The hand-written
returns focus to the opener exactly as before.
The same surfaces also stop inventing their own controls: the session permission and the share lifetime
are SegmentedControl choices like the capability tier, and the independent fork and upload switches are
the shared Switch primitive. Stopping a published share now asks for the shared RiskConfirmation
acknowledgement before the destructive request runs.
* feat(liveshare-client): state the narrowed owner copy and correct the viewer surface
The share manager no longer promises a request-and-approval flow that the protocol dropped: its
description states the online state and access scope it actually shows. Stopping a share is now gated
on acknowledging that the published link stops working immediately.
The viewer status banner keeps its placement inline but takes its colors from the theme tokens with
system-color fallbacks, so the served page stays readable when the client stylesheet never loads. Both
owner dialogs size against the Modal padding box instead of a second viewport calculation, and a long
list title wraps instead of pushing the status out of its row.
A forked branch is stated as a branch, without claiming a read-only workspace the write tier does not
have; the same correction applies to a branch whose sandbox limits failed to install.
* fix(liveshare-client): align the viewer face with the current Client services
The rebased Client surface no longer carries uiConversation.noticeBranchRefusal: a refused branch leaves the view unchanged, so the viewer row consumes the rejection and the refusal-notice tests become containment tests. The plugin manager's bundle lists moved to dsh-official-bundles, so the liveshare bundle joins the centralized experimental and extension lists. Master's sidebar keeps the brand identity out of the accessibility tree when the page cannot start a Session, so the assembled-page test reads the viewer home link from the DOM. The roster gains the file-drag plugin ui-chat and ui-attachment now inject, and the fixture reads the protocol's Client-face carrier from its own project and brands the fabricated reasoning effort.
* refactor(liveshare-client): consume the protocol package's single public entry
The protocol layer now publishes only its root entry; the client tests read the wire and identity contracts from that root. The dependency policy keeps one liveshare entry carrying both the protocol vocabulary and the identity helpers.
* feat(plugin-manager): leave the LiveShare bundle unranked in the extension list
The bundle already stays invisible until one of its patch rows runs, which
keeps ordinary users from encountering it. Removing its ranking entry means an
internal profile that enables it finds the card at the end of the experimental
list instead of pinned to the front; the Experimental badge and the hidden-
until-running card both stay.
* refactor(liveshare-client): drop the attachment-upload switch
The share dialog and share management present only the tier and the fork
switch; attachment upload follows visibility on the Host, so there is
nothing left to toggle. Removes the field from the client share record,
both locale seats, and the dialog tests, and states the new rule in the
viewer README.
* feat(liveshare-client): drive share management through the liveshareShares Remote
The owner dialogs stop posting the twelve management routes and call the
generated namespace instead. The share list, creation, stopping, permission and
endpoint writes, the Relay read and override, the owner identity read, the
audit, and both Relay checks resolve to a RemoteResult, so a refusal is read
from its `liveshareShares/` code instead of an HTTP status. The sign-in round
trip keeps its three same-origin routes.
The package's client entry mounts its own generated contribution and passes the
namespace to the share surfaces through the slot inject face. `dsh.client.inject`
now names `@deepseek-ai/dsh-api-remotes`, and the viewer endpoint table
classifies the twelve management endpoints as owner-only so the Client
completeness gate stays total.
Client specs substitute the namespace with a scripted double instead of stubbing
`fetch`; the assertions read the recorded requests.
* test(liveshare): drive the owner host cases through the Remote service
The host cases no longer register a route map and post JSON to it. They call
`ctx.liveshareShares` directly, which runs the same OwnerShareOperations the
remote Gateway dispatches, so each case keeps its side-effect coverage and
asserts the RemoteError code and details a refusal carries instead of a status
and body.
The ping case is gone with the route: the header action reads `relay()` for the
effective address, which the Relay-state cases already cover. The e2e harness
publishes through `liveshareShares/create` over the owner's own `/api` carrier,
and the sign-in/credential cases keep their same-origin routes.
* refactor(liveshare): remove the owner share-management HTTP routes
The twelve same-origin management routes are gone, together with the thin
adapter layer that existed only for them: the status/body error translation,
the per-route request-body readers, and the capability-selection parser. Every
side effect stays in OwnerShareOperations, which the `liveshareShares` Remote
dispatches.
The four remaining routes are the sign-in and credential ones:
ownerLoginStart, ownerLoginRedeem, ownerLoginCancel, and ownerCredential. The
route-registration case now asserts exactly those.
* docs(liveshare): describe share management as the liveshareShares Remote
The package README (both languages) and the subsystem page now state that the
share list, creation, stopping, permission and endpoint writes, Relay state,
identity, audit, and both Relay checks are `liveshareShares` methods, and that
the sign-in round trip and credential storage are the only same-origin HTTP
routes left. The owner source table points at share-operations.ts and
share-remote.ts for management.
Re-record the README pairing hashes and regenerate the Cordis surface sections,
including the inspect catalog's service description.
* test(liveshare): restore the Client classification gate
P3a dropped the Client-face completeness gate together with its placeholder
face. P3b owns the browser runtime, so the gate returns: the Client program
proves every generated Remote endpoint has a table row, and the spec pins the
compiled export beside the diagnostics the Host also uses.
* chore(build): restore the Liveshare Client compiler face
The rebase onto the Host layer lost the solution reference and the Host
exclude that kept `src/client` out of the Host program. The package now
carries a real browser runtime, so it takes the ordinary Client/Host
dependency treatment instead of the exemption its placeholder face needed.
* docs(liveshare): restore the package's client faces
The subsystem overview names the client faces again now that the browser face
is back, and the translation pairing record is re-recorded.
* test(liveshare): cover the browser surfaces and client readers
The browser half of the package now meets the per-file gate on its own
terms: the viewer request decoder, the share-type readers, the viewer
session selection, and the owner identity readers are pinned by direct
specs, and the seats, brand row, share-path chip, status banner, model
seat, and menu row gain the cases their uncovered branches named.
Two internal simplifications remove branches that no input can reach: the
brand row strips build metadata with one replace instead of a split whose
second operand was unreachable, and the viewer-session subscription no
longer starts behind a placeholder disposer that subscribe can never call.
* test(liveshare): cover the owner host and gateway glue
The host half gains the direct specs its uncovered branches named: the
stored credential file (absent, corrupt, unbound, empty facts, deletion),
the viewer principal comparison, the share Remote's audit delegation, the
registration handshake's plain-socket scheme, the relay refusal status
reader, the JSON body reader, the fork policy's mode helpers and empty
prefix, and the fork guard's unreachable-context refusal. The worker entry
is covered through a mocked worker module, so its boot decision runs
without a spawned process.
The served-page resource answer no longer carries a `string` body: both
call sites hand it bytes, and the string branch could not run.
* test(liveshare): cover owner state, authorization, and the header action
Pins the owner state file's restore and refusal rules against real files
(every optional fact, every invalid record, the owed Relay rows, and a
failed write), the authorization transaction's four bindings and its
single-use state, the declaration surface's stable package order and
repeated withdrawal, and the Session-header action that opens the share
dialog and switches it to management.
The owner state write chain no longer catches a rejection it cannot
observe: the map holds only promises whose failures were already absorbed.
* test(liveshare): close the owner and declaration surface gaps
Pins the authorization URL the browser opens and the production clock and
lifetime a transaction gets when the host passes neither, the declaration
surface's stable package order and repeated withdrawal, the owner state
file's restore and refusal rules against real files, and the Session-header
action's open, manage, and close paths.
The declaration disposer's two optional lookups are annotated instead of
tested: this effect registers each accepted name once, so its own disposer
cannot reach a missing entry, and the effect disposers are idempotent, so a
second withdrawal never re-enters that loop.
* test(liveshare): satisfy the lint and compiler gates in the new specs
The refusal double takes the empty details its code declares, the waits
return nothing instead of a void expression, and the IPC entry reads the
channel through a computed access so the lint rule does not read it as an
unbound method reference.
* test(liveshare): cover the gateway worker and tunnel supervision
* test(liveshare): cover the owner, relay, fork, and viewer host modules
* refactor(liveshare): keep the coverage hooks behavior-preserving
* test(liveshare): fix the typed listener and endpoint fixtures
* test(liveshare): cover the owner login, share manager, and viewer plugin
* test(liveshare): cover the share dialog and host fork wiring
* test(liveshare): satisfy the contract lint in the gateway worker spec
* chore(coverage): drop the liveshare lane exemption
* feat(liveshare): ship the remaining shipped-language dictionaries
The locale parity gate requires every shipped language beside each object-form
dictionary, so the Liveshare browser plugin now carries Japanese, Spanish,
French, German, Russian, and Brazilian Portuguese alongside `zh` and `en`, and
registers all eight.
Each dictionary is typed `Record<keyof typeof zh, string>` so a missing or extra
key fails the build, and named placeholders, slash commands, and API field names
stay verbatim in every language.
* docs(liveshare): document the host config and two exported host contracts
`verify-export-jsdoc` requires prose on every exported declaration: `Config`
states what a deployment sets and why `relayUrl` has no default,
`requestedBoundary` states how a fork request names its prefix and what an
unnamed one becomes, and `OpenStream` states what the reader tracks and when it
releases the stream.
* chore(docs): regenerate the liveshare catalogs and acknowledgement after rebasing
Rebasing the host layer onto current master left the generated artifacts at the
new base's state, because each conflict was resolved to master's side rather
than merged by hand. Recompute them from the rebased tree with the repository
generators: `gen-config-catalog`, `gen-doc-graphs`, `gen-persistence-catalog`,
`gen-client-catalog`, `gen-tool-catalog`, and `verify-persistence-formats
--write`. `gen-module-graph`, `gen-cordis-catalog`, and
`gen-official-bundle-catalog` computed no change.
The LiveShare persistence acknowledgement predated master's later changes to the
four user-message source roots and stored the inventory in a non-canonical
layout, so `verify-persistence-changes` could not read it. Re-record it with
`persistence-changes --update ... --decision same-version`, which chains it onto
master's current tips and rewrites the snapshot, the bilingual declaration, and
their pairing record. Re-record the ui-plugin-manager README pair, whose
LiveShare paragraph now matches on both sides.
* test(liveshare): read attachments by the complete image reference
Current master sends `session/attachment` the complete image reference the
conversation folded from the log and answers with the stored reference plus
bytes, instead of accepting a bare `attachmentId`. The viewer fixture still
read the old field, so every assembled-page image read failed and the
viewer-shell and viewer-global-privacy artifact tests timed out waiting for the
delivered image. Follow the new request field and keep verifying by id against
the Session's log.
* test(liveshare): pass the complete reference in the owner attachment probe
`session/attachment` now takes the complete image reference, so the admission
spec's owner-side probe sends the fixture's reference instead of a bare id.
* fix(liveshare): classify the current Client endpoints for the share-viewer policy
Master added session read/observation endpoints to the Client's Remote map, and
the share-viewer policy's reader role is the only grant they can receive. Name
the six read endpoints in the reader role and in the classification table, keep
the endpoints this Client assembly cannot name out of the table (they stay
owner-only by default), and extend the served-page contract plus an admission
test so a hidden Session is still refused.
* fix(liveshare): await and type the turn-requester projection
Register the fold before publishing the policy and source layer that read
it, surface a refused registration instead of leaving it unobserved,
reset the retained handle when the projection service reloads, and type
the boundary and execution reads from Agent and TurnBoundaryProjection.
* fix(liveshare): withdraw only the fork children a revocation saw
Apply a withdrawal to the entries the registry file holds when it
commits, leave a child recorded afterwards live across restarts, and
retry a failed withdrawal without replaying it over a newer child.
* fix(liveshare): refuse a fork that names no Session
Answer 400 with a named code before dispatch, so a malformed fork body
cannot reach the owner's Gateway unrecorded.
* fix(liveshare): stop injecting a child id into fork requests
SessionForkRequest mints the child id, so the injected field was ignored.
Forward the caller's envelope and rely on the recorded operation for a
retry; document the crash window that needs a caller-supplied child id.
* fix(liveshare): classify and dispatch one normalized path
Use the same pathname plus query for the endpoint decision and the owner
dispatch, and parse with URL.canParse instead of an empty catch.
* docs(liveshare): record the two-tier driving model
Rewrite the implemented note's stale tier, turn-carrier, upload, and
retry facts, add the superseding decision note, and keep the subsystem
page and package READMEs aligned.
* fix(liveshare): publish only the exported type module from lib/types
The package published every tsc-emitted lib/types/**/*.js file, so the client
JavaScript that imports .module.css files entered the tarball without those
stylesheets. Retain only lib/types/share-api-types.js, the one runtime file
the ./types export names, alongside the declaration tree.
Teach the publication allowlist that this package's emitted tree is completed
by its exact runtime file rather than the whole glob, and pin both the accepted
and rejected payloads.
* test(liveshare): mock the generated remote for assembled viewer pages
The assembled viewer specs load the client entry, which statically imports the
generated ./remote contribution. A clean checkout has no lib/ build, and Vite
resolves a static import while transforming the entry, before vi.mock can
answer it, so the jsdom suites failed to import the page roster.
Mock the contribution in each assembly spec, matching the owner-side face
tests, and provide a resolvable test stand-in whenever the artifact is absent.
* fix(liveshare): guard hover styles and draw the viewer banner hairline
Wrap the owner action, dialog actions, and viewer wordmark hover rules in
@media (hover: hover) so touch devices do not latch the hover treatment, and
draw the viewer status banner's neutral border at the 0.5px hairline width.
* refactor(liveshare): name the owner gateway directory
The owner-side Relay connection process is LiveShare's own gateway, not the
Host API gateway; move it to src/owner-gateway so the published entry
lib/owner-gateway/cli.js and the module headers say which gateway they mean.
The protocol vocabulary (frames, tunnel mode) keeps the word gateway.
* docs(liveshare): merge the tier and visibility notes into the owner note
* docs(liveshare): call the Relay the Liveshare server
* docs(liveshare): name the Liveshare server in the share-management JSDoc
* docs(liveshare): document that new shares are organization links
The shipped Share dialog sends neither accessMode nor allowedSubjectIds, so
every share it creates is open. The agent note, both package READMEs, and
CreateShareRequest's JSDoc now say that selected/approval shares are legacy
stored records that keep their ACL and access summary, that the UI has no
creation entry for them, and that the create fields remain for those records
and direct Remote callers.
* refactor(liveshare): drop the configurable owner display name
The reader-facing owner name now always resolves from the Relay-verified
credential: its display name, otherwise the subject label, otherwise the
Relay's host name. Config.ownerDisplayName and the namedOwner dependency
only fed the removed override, so delete both and the test configuration
that set the field.
* docs(liveshare): read the owner name only from the verified credential
Remove the LIVESHARE_OWNER_NAME row and its cordis patch mapping, and say
in both READMEs that a reader-facing share name comes from the
Relay-verified credential rather than local configuration. The
LIVESHARE_OWNER_DISPLAY_NAME legacy identity label stays.
* feat(liveshare): save the relay address from the share dialog
The public address is the owner's runtime choice, not deployment configuration:
the host loads without one, the dialog saves it into the owner state, and new
shares publish there until the owner saves another or clears it. A host with no
saved address contacts no server and its sharing surfaces state that.
* docs(liveshare): describe the address saved in the share dialog
The README, subsystem page, generated API reference, and their bilingual
pairing now state the dialog-owned address and the no-address host state.
* refactor(liveshare): sandbox a shared session instead of attributing turns
Retire per-turn origin isolation: delete the turn-requester fold, the
turn-boundary derivation, and every per-turn verdict, and make the source
access layer a session-level sandbox.
While any share over a Session is active the layer's guard permits only the
confined read it mounted (plus the bounded write when some share may write);
every turn of that Session, the owner's own included, runs through them and
nothing else. The layer is released once no active share is left, which
restores the Session's own tools, and the read-only layer is re-installed
when the last write share narrows to view. Each operation re-reads the
shares' current Relay grants and checks the resolved target against the
granted root.
A viewer's session/cancel now travels the standard Gateway dispatch under
the source-write role instead of a host-side ownership comparison, and a
share that stops, expires, or loses admission stops whatever turn its
Session is running.
Behavior changes:
- The owner is confined too: while a share is active the owner's own turns
can only use the confined read (and bounded write), and the full tool set
returns when every share stops or expires.
- Cancellation has no attribution: a viewer's stop cancels the shared
Session's running turn, including one the owner started.
* test(liveshare): exercise the session sandbox and gateway cancel dispatch
Delete the specs that asserted per-turn attribution (turn-requester, source
cancel ownership, source execution turn, source turn revocation) and the test
fixtures only they used. Cover the behavior that replaced them: every turn of
a shared Session is confined while the layer is mounted, the layer is released
when no share is left, a write-to-view narrowing re-installs the read-only
layer, a share ending stops the running turn, and a viewer's cancel and prompt
both travel the standard Gateway dispatch as the reader's Peer.
The pre-step admission test now covers the messages' own principals, and the
projection double is gone with the projection it stood in for.
* docs(liveshare): document the session sandbox and retiring turn origin isolation
Update the package READMEs, the LiveShare subsystem, the share-viewer
principal persistence record, and the merged Agent Note: remove the
turn-requester fold, turn-boundary derivation, pinned source cancel, and
per-turn origin prose, and state the shipped facts instead — a Session-level
sandbox that also confines the owner while a share is active, a standard
Gateway cancel with no ownership comparison, and the pre-step admission check
as the principal's only consumer. Re-record the bilingual pairing records.
* refactor(liveshare): extract share dialog relay and identity hooks
Move the Relay address read/save/draft state and its connectivity and
permission checks into useShareRelayAddress, and the owner identity read
plus the one sign-in attempt into useOwnerIdentityLogin. ShareDialog
keeps the step guide and passes the identity facts saving an address
needs, so neither hook reaches into the other.
* refactor(liveshare): extract the share dialog create form
Move the session permission, fork switch, lifetime, and the create
action into useShareCreateForm and ShareCreateForm. The dialog keeps the
link, error, and created-record adoption it already owned, and the
shared choice builders live in share-options so the edit panel can use
the same session-mode list.
* refactor(liveshare): extract the share edit panel and tier picker
Move the stored share's permission, fork switch, endpoint tier, and the
one save into useShareEdit and ShareEditPanel, with the tier expansion and
summary in ShareCapabilitiesPicker. ShareDialog now composes the relay,
identity, create, and edit hooks and keeps only the link, advanced help,
and close/manage surface.
* fix(liveshare): take share dialog hook options as named parameters
The exported hooks documented an `options` parameter while destructuring it
in their signatures, so their JSDoc could not name the binding.
* chore(docs): regenerate graphs, catalogs, and pairing after rebasing on master
The rebase merged this branch's liveshare entries with master's forge entries;
the generated English sources and their bilingual pairing records now reflect
both.
* feat(liveshare): open the shared read and write tool surface
The source-session sandbox and each fork child's limit now admit one shared surface: read, read_image, glob, grep, present, todo_write, skill, web_search, and web_fetch at the view tier, plus edit and write at the write tier.
Every path a call declares is resolved and checked against the granted root before the deployment tool receives its canonical form; a pathless search uses the Session's working directory. Tools with no local file effect keep the deployment's own definition, which the guard vouches for by identity. Everything else, including bash, pwsh, cua, the plugin manager, and the schedule tools, stays refused.
* test(liveshare): cover the shared tool surface
Drive the view and write surfaces through the source sandbox and a fork child's limit: canonical paths, symlink and relative escapes, pathless searches, deliveries, the no-effect tools, both mutation tools, and every capability the surface does not name. Registration counts in the host wiring now read the shared table instead of one confined read.
* docs(liveshare): describe the shared tool surface
The package README, the subsystem reference, and the owner note now state the admitted tools per tier, how each declared path is checked, and that the no-effect tools keep the deployment's definition. Re-record the bilingual pairing and the generated event graph for the new fs/edit-intent consumer.
* feat(liveshare): confine viewer turns and admit PTC run_code
Owner turns of a shared Session keep the deployment's native tool chain. The
source layer now decides per turn, from the admitted input's share-viewer
principals, whether the turn is confined; agent/pre-step records that answer
in Host memory only, and the guard plus every confined replacement read it.
A turn the owner starts runs the deployment's tools unchanged, an owner's
steering input inside a viewer's turn stays confined, and stopping every
share still disposes the layer.
Both tiers also admit the PTC transport run_code. A non-empty
sandbox_permissions is refused; every nested tools.* call is a separate
execution through the same guard and confined replacements, so tools.bash
stays refused and read/edit/glob/grep keep their grantedRoot checks. Before
the runtime starts a program, run_code dispatches the new sandbox/policy
waterfall with the Session-resolved policy; the source layer caps it to the
share tier (read-only for view, workspace-write at most for write, never
danger-full-access) and drops the deployment's extra writable roots. A fork
child's installation applies the same cap from its live tier.
Verification: pnpm run typecheck, oxlint on the changed files, and the
focused liveshare specs for the turn marker, owner/viewer turns, run_code
admission and nested calls, and the policy caps. Local commits only; not
pushed.
* refactor(liveshare): drop the uncommitted-prefix fork state
The host never reads the source Session log, so it cannot know a completed
sequence. The forking command validates the requested boundary against its own
committed history instead, which makes the local boundary refusal unreachable.
* feat(ui-chat): export the official user renderer and shared-session copy
* feat(liveshare): mark shared-session reader messages through the chat node seat
* test(liveshare): cover shared-session attribution and the reused chat node seat
* fix(liveshare): leave steering rows to Chat
Only the message that opens a conversation carries the reader attribution;
steering is a turn-internal insertion, so its official Chat cell is untouched.
The wrapper now shadows the user cell alone.
* feat(plugin-manager): hide default bundles through their manifest
The LiveShare bundle now declares `dsh.bundle.listedByDefault: false` and the
page applies one manifest rule to every bundle: a default-hidden bundle is
listed only when the profile enables it, the installation carries it selected,
or one of its declared rows runs. The client-side name set and its special
details-by-id fallback are gone.
* docs(sandbox): document the per-program sandbox policy extension
The new `sandbox/policy` waterfall owns one event scope, the generated event
graph and subsystem reference now list it, and the catalog classifies its
payload type.
* chore(docs): regenerate the graphs and pairing after rebasing on master
The rebased branch now shares master's forge and sandbox service entries; the
generated English graphs and their Chinese counterparts are re-recorded.
* test(web): keep the plugin lists contiguous around the LiveShare card
The recorded accessible tree has no blank line between the last experimental
card and the installed-plugins heading.
* test(typert): expect the PTC sandbox policy event in the executor catalog
The new waterfall is part of the executor's model events.
* fix(liveshare): name the PTC transport without the unclassified tools export
The dependency policy does not classify @deepseek-ai/dsh-tools' RUN_CODE_NAME
as a safe host export. Liveshare now owns the reserved name locally, pinned to
the canonical constant by its test suite.
* fix(liveshare): close the coverage gaps in the owner-turn and PTC paths
The asynchronous policy resolver is covered by the executor tests; the
share-host guard covers unattributable executions and same-turn narrowing;
the owner's edit path exercises the native pass-through.
* test(web): align plugin goldens with the manifest visibility rule
The default profile no longer lists LiveShare before its rows run, the refresh
count includes the forge bundle master added, and the creation recommendation
skill catalog records the new bundle entry.
* fix(ptc): keep the disposed check lint-clean after policy resolution
The narrowed property read became an always-false conditional; the helper
method keeps the runtime check without the narrowing.
* test(liveshare): cover a relay probe stopped by host disposal
The probe checks the disposed flag after its fetch; a disposal landing during the
request now exercises that early return.
* fix(liveshare): encode identifiers without the base64url Buffer name
Packed worker deployments run a Buffer polyfill that only names standard
base64; the new helper produces the same unpadded base64url text from it. The
packed preview's generic bundle toggles skip the declaration-first Liveshare
bundle, which the ordinary Web scaffold covers.
* test(liveshare): build worker command fixtures from real file URLs
`file:///pkg/...` has no drive letter, so Windows `fileURLToPath` refuses it;
the launch-command test now derives both fixtures with pathToFileURL.
* feat(ui-chat): offer a user-origin seat above user rows
Chat now declares a session-scoped `conversation.chat.user.origin` list seat and passes the flow's renderer to the official user row through `ChatNodeOwnerProps.renderUserOrigin`. The flow supplies the callback only while the seat has an entry, and the official renderer calls it for `user` nodes alone, so steering keeps its DOM. Entries receive the durable message source and own their markup and copy; ui-chat ships none, and its shared-session dictionary entry moves back to the feature that writes it.
* feat(liveshare): attribute shared-session messages through Chat's origin seat
The client registers one `conversation.chat.user.origin` list entry on both faces instead of shadowing Chat's user node renderer. The component recognizes the durable share-viewer principal and states the Relay-asserted subject from the package's own `inputOrigin.sharedSession` copy in all eight dictionaries; owner-authored, malformed, and steering rows render nothing. The ui-chat runtime external and its client-inject edge are gone: the remaining ui-chat import is type-only, and `slots.inject` makes the registration independent of declaration order.
* chore(client): record the user-origin seat in the slot catalog
Regenerate the model-facing client slot catalog for `conversation.chat.user.origin`: the new list seat, its owner props, its declaring flow entry, and the Liveshare occupant. The subsystem slot tree follows the same declaration.
* chore(liveshare): publish the types entry as declarations only
`./types` no longer declares a runtime target into the tsc-emitted tree, so the
package no longer publishes `lib/types/share-api-types.js` and the workspace
constraint check no longer needs a package-name exception.
* docs(ui-chat): name the message-source decoration
The prose uses the exact field it decorates instead of the abstract term the
repository's concrete-terms gate rejects.
* fix(liveshare): classify master's tool-results stream after rebasing
Master added the `toolResults/watch` Remote endpoint and bumped the workspace to
0.2.1-rc.4; the viewer endpoint table and the read role now cover the stream,
and the package version follows the root.
* refactor(ptc): keep sandbox policy dispatch synchronous
The policy cap is a pure, cheap computation, so the waterfall should not force
every confined program through an await before the call is registered. The
event now returns the policy directly: no admission window between reading the
mode and registering the call, no async mode resolver, and no fallback branch
in PtcCalls. The event can still be dispatched twice for one Agent-owned
program; its contract names the synchronous, idempotent listener requirement
and tests lock both dispatch counts.
* docs(ptc): state the synchronous sandbox-policy contract
The README now names the synchronous waterfall and the two policy resolutions
an Agent-owned program performs, so readers know listeners must be synchronous,
pure, idempotent, and return the same cap each time.
* fix(liveshare): let the declaration entry win the fallback race
A live bundle activation can start the share host before the separate
declaration entry's service is visible in the host context. The host now gives
that entry one task turn before providing its own fallback surface, so both
rows no longer register `liveshareViewerDeclarations` twice.
* chore(liveshare): drop the now-unused require-await suppression
The deferred fallback makes apply genuinely await, so the file no longer needs
the suppression it carried for a synchronous throw.
* fix(liveshare): read the owner Remote namespace after mounting it
The client face accessed `remote.liveshareShares` on its own context before
that namespace existed, which the Remote carrier refuses without an inject
entry. The header action now registers inside a child scope injected after the
carrier mounts, and the face tests provide the mounted namespace.
* feat(liveshare): simplify the owner share dialog
Saving the relay address now checks it in the same action, and the numbered
step guide is gone. Sign-in is a single control above the share settings, and
every setting below it stays disabled until the owner signs in. Fork wording
and the read-only permission hint now state the actual permissions.
* feat(liveshare): save the relay address on blur
The address field no longer needs a Save button: leaving the field (or pressing
Enter) stores it and probes the address it put in force. Chinese copy now uses
观看者 consistently instead of mixing viewer and 观看者.
* chore(ptc): restore the run signature formatting
The synchronous policy refactor left only a line-wrap difference in this file;
the signature returns to its original one-line form.
* feat(liveshare): configure plugin sharing when creating a share
The create form now carries the same share-wide plugin-endpoint tier as the
stored-share editor and writes it immediately after the host creates the
share. The Advanced disclosure only renders for an existing share, where it
has stored-share details to show.
* fix(liveshare): show the owner name on shared-message attribution
The durable source names the reader by subject id, so the line showed the opaque
id even when the reader was the owner. The client now remembers the verified
owner identity it reads on mount, and the attribution uses that display name for
the matching subject while keeping the persisted id for every other reader.
* feat(liveshare): use the viewer's Relay name in shared-message attribution
The viewer context already carries the reader's own display name; reading it
lets a viewer's messages show their name instead of the opaque subject id,
while a reader with no reported name keeps the durable id.
* feat(liveshare): persist the viewer display name in message attribution
The Relay asserts a display name for the viewer it forwards. Copying that name
into the durable share-viewer principal lets the owner and every reader show
who sent a message, instead of only the current reader or an opaque subject id.
The name is attribution data only and stays out of authorization and model
requests; old logs and readers without it keep showing the subject id.
* feat(liveshare): share the permission fields between create and edit
Creating and managing a share now render the same session permission, fork
switch, and plugin-endpoint fields, and the stored-share view states its
lifetime and link scope inline instead of behind an empty Advanced disclosure.
The first version publishes only the never-expiring lifetime.
* feat(liveshare): edit a share lifetime and link scope after creation
`updatePermissions` now accepts a new deadline (null means never) and the
open/selected link scope. The shared permission fields expose both while
creating and editing; an existing share can be switched to the open link or
cleared back to never, and selected shares accept provider subject ids.
LiveShare prose now calls every fork product a 分叉会话.
* test(liveshare): remove duplicate lint suppression
* fix(liveshare): keep row labels on one line
* fix(liveshare): clear the static catalog and unknown-cast gates
The owner-display test no longer casts through unknown, and the generated
Cordis runtime catalog now includes the extended permission request type.
* test(liveshare): cover the unchanged update and subject-order branches
* test(liveshare): cover the unchanged restored-access branch
* fix(liveshare): re-probe a stale owner credential
* refactor(liveshare): remove the unfinished selected-colleague scope
The share dialog no longer offers or edits a selected-colleague link scope;
new shares use the organization link and stored legacy scopes stay read-only.
The create form's lifetime is the single never-expiring row, and the host
identity read re-probes a stale credential.
* feat(liveshare): simplify the share manager and add plugin sharing
The global manager now lists Session titles and opens the matching Session's
share dialog, which names the Session it edits and exposes one plugin-sharing
switch. Shares can still be listed without any plugin declaring endpoints, and
the switch states that absence.
* fix(liveshare): open the selected share from the manager
The manager's Manage action now opens that Session's share dialog directly,
and binds workspace navigation when the page has it. The rows use one grid so
titles, online state, and actions line up, and the footer offers Cancel next to
Done.
* refactor(liveshare): elect shared-session attribution through a chain seat
Chat now declares `conversation.chat.user.before` as a chain seat whose owner
props carry the durable source and row kind. Liveshare's selector elects only
share-viewer user rows, so the component no longer probes or returns null, and
the official user row stays unchanged. The manager aligns its columns, adds a
per-share cancellation action, and no longer offers a footer cancel that meant
the window rather than a share.
* refactor(liveshare): drop PTC sharing from this change
The share surface now admits only the native read/write tools. PTC
run_code admission, its sandbox-policy cap, and the executor-side policy
extension move to a separate change, so this PR keeps non-PTC sharing focused.
Core PTC files, sandbox docs, and generated catalogs return to master.
* docs(liveshare): fold the viewer display name into the principal record
The optional displayName is part of the share-viewer principal, so its
persistence acknowledgement now lives in the 2026-10-13 principal record
instead of a separate 2026-10-27 record.
* refactor(liveshare): render user attribution through its own chain slot
* refactor(liveshare): keep one user message renderer for the attribution seat
* refactor(liveshare): render the attribution seat inside the user bubble
* docs(liveshare): regenerate the event graph pages
* test(liveshare): close the endpoint control coverage gaps
Cover the endpoint tier control's empty-offer return and drop the unused expiry choice list.
* chore(docs): regenerate the persistence catalogs after rebasing onto master
* chore(liveshare): carry the 0.2.2-alpha.1 release version
16 KiB
LiveShare
English | 中文
可选的 LiveShare bundle(@deepseek-ai/dsh-experimental-liveshare)让一位所有者通过独立的 Liveshare 服务端 把一个会话分享给外部 viewer。viewer 永远拿不到所有者的工具:所有者宿主机自己读取 viewer 的每个请求,以该 viewer 自己的 Peer 分派它,Gateway 依据本包注册的 remote access 策略判定该 Peer 的 share-viewer principal,并把共享会话代表 viewer 运行的一切限制在分享所授予的工作区内。包 README负责配置、客户端界面与限制;Owner 说明负责其背后的安全姿态。
源码:packages/experimental/liveshare/src/host/fork-enforcement.ts
启用与可见性
本包随 dsh 一同交付,但在 profile 启用它之前不会出现在插件管理器的任何列表中。profile 可以把自己的 cordis.patch.yml 插入组合包声明的两条行,这样组合包本身保持未选中而插件照常运行;也可以改在 dsh.profile.bundles 中选中该组合包。包 README负责具体条目和部署需要替换的占位符。
插件管理器只有在组合包声明的行至少有一条在运行时才把卡片列在实验性插件下;删除这些行、把它们置为 disabled,或取消选中组合包,卡片会再次从该列表和更多页消失。两条路线都在 profile 下一次重新组合时生效,而不是在当前任务中途:启用 HMR 时会重新读取 profile,未启用时则等下一次启动。
分享模式
ViewerSessionMode 只有两档,两档都对应一个沙箱:view 读取共享会话,并在授予工作区的只读沙箱里驱动它的 loop,绝不写文件;它可以使用读取与检索面(read、read_image、glob、grep、present)和无本地文件副作用的工具(todo_write、skill、web_search、web_fetch),每个声明路径都按授予范围检查。write 在受宿主写入上限约束的可写沙箱里运行,通过有界 edit 与 write 修改该工作区内的文件。fork 不是一档:分享自带独立的 allowsFork 开关,与档位无关。附件上传也不是一档:分享向读者提供的每条会话都接受文件,与档位和分叉开关无关。已退场的 fork-readonly 名称不会读回为 view:持久化的 owner 记录若写有该值,owner 状态加载时会直接拒绝。任何环节都不会推断出 write,而宿主机无法确定模式的分享仍可读取,但绝不会被驱动。
fork 与其上限
fork 创建查看者拥有的新会话,源会话保持不变。Fork 授权检查分享、其 fork 开关、有效期、查看者准入、源身份与请求的边界。READ_ONLY_FORK_CEILING 允许读取与检索面——read、read_image、glob、grep、present、todo_write、skill、web_search、web_fetch——,WRITE_FORK_CEILING 增加 Host 的有界 edit 与 write。每个带路径的工具都有受限替代定义:解析它声明的所有路径并按授予根目录检查,再以规范路径委托;bash、pwsh、cua、plugin_manager、schedule_* 及工具面未列出的名字一律拒绝。
每个分叉会话都会记录授权它的分享、Liveshare 服务端断言的可信 viewer,以及它起始的边界,因此 viewer 的列表只显示它自己的分叉会话,被移除的分享会终止它们。只有在分叉会话自身作用域上安装好上限之后它才会被驱动:ForkRegistry 会拒绝每个上限未安装的分叉会话的 prompt(fork-ceiling-uninstalled),且安装是按分叉会话逐个验证,而非按宿主机验证。若分叉会话作用域拒绝注册受限替换或上限,就拒绝该分叉会话,而不是让它带着部署自身的工具发布。
冷态源会话与分叉会话通过 Host 常规 Agent lookup 激活,而非 Remote session/prepare 端点。串行 agent/created 监听器在排队工作放行前安装作用域执行限制;已经在线的 Agent 仍需检查自身安装。forkLineage 是 LiveShare 自有的按查看者 UI 投影,不是会话摘要字段、持久日志事件或权限授予。
重试、恢复与撤销
同一个逻辑 fork 请求可能被发送多次。其身份绑定可信 viewer、分享、源会话与调用方的操作 id;边界是与该身份比较而非折入其中,因此重试会重复它已经产生的分叉会话,同一身份指向另一个边界会冲突而不是悄悄拿到更早的分叉会话,且预留在任何分叉会话存在之前就已持久化。宿主机记录 owner 的 fork 应答返回的分叉会话,重试已记录的操作会重放该应答。owner 的 SessionForkRequest 自己生成分叉会话 id,因此在创建分叉会话与记录它之间崩溃的宿主机重试时无法指名该分叉会话,会再创建一个;要关闭这一窗口,需要 Session Controller 的请求接受调用方提供的分叉会话身份。
分叉会话工具守卫重新检查分享当前模式、有效期、查看者准入与撤销记录。撤回查看者会取消受影响的分叉会话工作与未决调用。write 降级为 view 后,写入守卫拒绝后续写入,不授予任何新工具,也不承诺立即取消正在运行的轮次。移除分享撤销已记录分叉会话并停止该会话正在运行的轮次;源执行层在该会话不再有任何分享时释放,并随 Agent 释放。已撤销分叉会话保留日志,源会话所有者可见历史绝不改写。
约束共享会话
每个分享都让它的 viewer 通过正常 prompt 路径驱动源会话,任一档位的分享在活跃期间都会安装有界沙箱。installSourceSessionAccess 在该会话自身作用域中为部署提供的每个读取与检索面工具注册受限替代,并在任一同会话分享允许写入时再注册有界 edit 与 write 替代。执行层挂在会话上,但只约束分享查看者发起的轮次:agent/pre-step 在 Host 内存中记录一个轮次的已准入输入是否带有 share-viewer principal,守卫与替代定义对该轮次的每次执行读取这一结论。查看者发起的轮次只能运行这些替代定义;所有者自己发起的轮次保留会话原生工具,包括 bash 与不受限的文件工具。该结论在轮次准入时确定,不写入会话日志;重启后从下一个准入步骤重新计算。所有者在查看者轮次中追加的输入仍留在该受限轮次内。该会话的所有分享停止后执行层被释放,会话恢复自己的工具;最后一个可写分享降为 view 时重装只读层。
安装结果报告源会话是否真正受到限制。没有 read 工具的部署或拒绝该替代注册的作用域会保留守卫并报告失败;某个工具自己的替代注册失败时,该工具保持拒绝,其余工具面照常运行。读取处理器以 source-write-unavailable 拒绝消息:限制未安装时,共享会话中查看者发起的轮次不会用所有者工具驱动。
每次操作都会重新读取维持该会话可驱动的分享的 Relay 授权,且读取与其授权的工具调用在同一同步步骤内完成,因此排队超过其准入授权的输入无法凭过期准入行动。执行层按会话安装:同一会话的多个分享共用一个安装;分享收窄或结束时改变该层允许的操作——没有任何活跃分享可写时拒绝有界写入,会话不再有分享时释放执行层。Host 不把正在运行的轮次归属给准入它的查看者,因此结束某个分享的授权会停止该会话正在运行的轮次,而不是只挑出该查看者的工作;内存中的查看者轮次标记只决定该轮次运行哪套工具面。
受限文件工具解析其自身参数声明的每个路径,检查获授根目录包含每个目标,再以目标的规范路径委托。无路径的 glob 或 grep 搜索会话的工作目录,由替代定义补齐并按命名路径一样检查;present 调用检查它列出的每个文件;无本地文件副作用的工具原样委托。有界编辑执行同样的包含检查,使用 fs/edit-intent,并发布 editText 返回的版本;有界写入使用 fs/write-intent,并发布 writeText 返回的版本。异步意图等待后,Host 解析当前会话沙箱策略并重新检查分享授权。该策略作为 editText 或 writeText 的第五个参数,位于 signal 之后,由沙箱后端据此限制变更。包含关系按路径检查,若本地进程在检查与打开之间把获授范围内的目录换成符号链接,操作可能被改指别处;基于目录句柄锚定操作留待单独变更引入。
查看者对源会话的提示词与停止都按标准 Gateway 分派走 share-viewer 策略的源会话写入角色:分享档位已确立且其会话受沙箱限制时策略放行,随后由所有者自己的会话控制器停止该会话当前运行的轮次。取消不按查看者比对,因此读者对共享会话的停止也会结束所有者发起的轮次。Session Controller 在 prompt 投递前、以及与 cancel 同一同步步骤内再次读取 remoteAccess.allows(),因此 Gateway 放行调用之后访问权才结束的查看者不会投递或取消任何内容。排队的外部源输入在 agent/pre-step 刷新 Liveshare 服务端授权;缺少授权时在模型请求之前拒绝步骤。
viewer 状态
一次以拒绝结束的 viewer 读取会指明它自己的状态,而不是让所有原因共用一种失败:链接不存在、owner 已停止分享、分享已过期、owner 的机器没有路由、登录已过期、读者尚未申请、申请仍在等待、申请被 owner 拒绝、owner 从未收到通知,每种都有各自的 HTTP 状态与错误码;页面联系不上 Liveshare 服务端时由页面自己陈述。@deepseek-ai/dsh-experimental-liveshare-protocol 中的 VIEWER_STATE_ANSWERS 就是这份词汇表,每种状态对应的答案由 共享协议 维护。没有任何一种答案会扩大 viewer 能读到的内容:owner 离线、分享已停止、申请被拒,三者都是拒绝。
viewer 页面渲染所用的工作区流与会话列表经同一策略过滤:只要工作区还持有共享会话或该 viewer 自己创建的分支就会下发,其成员与手工顺序只保留这些。失去它们的工作区要到该工作区或工作区顺序下次变化时才离开工作区流,届时流替换读者的基线;仅访问变化不会发送帧。因此读者看到的是围绕它被授予的那一个会话的 owner 工作区名称与分组,而不是 owner 其余的工作区。
查看流在轮询、替换与取消时均绑定打开它的主体。会话通知、控制基线与工作区成员只暴露源会话及该主体的分叉会话:Gateway 只向读者转发策略在这些会话上允许的 api-session/* 通知,Session 与 Workspace 控制器也经同一策略过滤其列表和流;交互审批与提问保留在 Host。被拒绝的读取不创建上游订阅。过期与撤权取消受影响的未决调用和流;120 秒未轮询的流被回收。Worker IPC 响应与取消必须匹配请求 token、分享 ID、Liveshare 服务端 ID 及原始 socket 或 worker generation;迟到响应不能结算替换请求。
Liveshare 服务端可选的 share-access-state 能力在连接和已提交变更时发布完整、带版本的授权快照,包括其他 Liveshare 服务端实例提交的变更。鉴权 GET /__liveshare/requests 返回同一组字段。Host 在连接丢失时清空缓存授权,在同一 generation 内拒绝过期修订,并对异步刷新检查 generation。缺少完整授权时拒绝准入;这不构成立即的分布式停止语义保证。
Cordis API
Generated from source by scripts/gen-cordis-catalog.ts (verified fresh by pnpm run verify-cordis-catalog in doc-sync; regenerate with pnpm run gen-cordis-catalog) — the language sides differ only in locale-specific paired document paths. Signature blocks use a ts cordis-catalog fence and keep the original source JSDoc; dispatch modes are defined in the primer, and the framework-inherited ctx API lives in cordis-api/inherited.md.
ctx.liveshareShares — LiveshareShares
Owner-only Remote surface over the share-management operations.
The Gateway decides each call through remote access, so a share-viewer Peer is refused before a method runs; the owner Peer reaches the one implementation that owns each share-management side effect. create takes its Session as the sessionId of its single request object, so the Session resource kind's default resolver names that Session for the call without a reader declared here.
/**
* Publish one Session and store the share.
* @param request - Session, title, access, lifetime, and both switches the owner chose.
* @returns The created share's link and stored values.
*/
@Remote('create') create(request: CreateShareRequest): Promise<CreatedShare>
/**
* Refresh titles and Liveshare server authority, then list this host's shares.
* @returns Every share this host publishes.
*/
@Remote('list') list(): Promise<OwnerShareList>
/**
* Stop one share locally, revoke its forks, and delete its row on the Liveshare server when reachable.
* @param request - Share to stop.
* @returns Whether the row on the Liveshare server still needs a retry.
*/
@Remote('stop') stop(request: StopShareRequest): Promise<StopShareResult>
/**
* Change one share's tier, fork switch, or both.
* @param request - Share and the switches to change.
* @returns The permissions the share now carries.
*/
@Remote('updatePermissions') updatePermissions(request: UpdateSharePermissionsRequest): Promise<SharePermissions>
/**
* Replace one share's exposed plugin endpoints.
* @param request - Share and the selection to store.
* @returns The capability selection the share now carries.
*/
@Remote('setCapabilities') setCapabilities(request: SetShareCapabilitiesRequest): Promise<ShareCapabilities>
/**
* Read the endpoints plugins currently offer.
* @returns The live offer list.
*/
@Remote('capabilities') capabilities(): ShareCapabilityOffers
/**
* Read the Liveshare server address the owner saved.
* @returns The current Liveshare server state, with both address fields absent while none is saved.
*/
@Remote('relay') relay(): OwnerRelayState
/**
* Choose the Liveshare server address later shares publish to.
* @param request - Normalized address or null to clear the saved one.
* @returns The Liveshare server state after the change.
*/
@Remote('setRelay') setRelay(request: SetRelayRequest): Promise<OwnerRelayState>
/**
* Report this host's owner identity for one Liveshare server address.
* @param request - Address to report, or the effective one when absent.
* @returns The owner identity status, without the credential.
*/
@Remote('identity') identity(request: OwnerIdentityRequest): Promise<OwnerIdentityStatus>
/**
* Read the Liveshare server's durable audit trail for one share.
* @param request - Share whose audit is read.
* @returns The audit events, or a structured failure when the Liveshare server cannot answer.
*/
@Remote('audit') audit(request: ShareAuditRequest): Promise<ShareAudit>
/**
* Check that the effective Liveshare server answers at all.
* @returns The anonymous connectivity result.
*/
@Remote('testRelay') testRelay(): Promise<RelayConnectivityView>
/**
* Register one throwaway share to check whether this host may publish.
* @param request - Session the throwaway registration names.
* @returns The Liveshare server's decision about this host's credential.
*/
@Remote('testPublish') testPublish(request: TestPublishRequest): Promise<RelayPublishView>
Source: packages/experimental/liveshare/src/host/share-remote.ts