api/remotes owns the allowlist and its type projection; type-meta owns the shape
predicate, the selection seat, and the internal remote/host-event carrier
signal; api/gateway's Client half turns that signal into $on callbacks through a
private dispatch. apiproxy forwards each allowlisted emission verbatim in one
host/remote-event frame, registered ahead of the derived invalidation frames so
frame order is unchanged, and drops the three per-event variants it replaces.
Owner packages move their Events declarations into client-safe ./types exports,
so a consumer's listener signature is the Host's own declaration.
The fixture comment still said the Trajectory action used window.fetch after the implementation moved to a temporary download anchor. That wording implied client-side response handling and buffering which the browser-download design deliberately avoids.\n\nDescribe the actual native download-manager handoff while retaining the important contract: the fixture download stub only satisfies the host type and is unreachable through fixture dispatch.
1504 hand-written ranges pointing at workspace members become workspace:^, so
pnpm pack substitutes each member's real version at publication: sibling
peerDependencies follow the family version instead of being pinned at ^0.0.1,
and a reference to a vendored package follows that package's own line. Without
this, publishing 0.0.2 ships peer ranges naming a version that does not exist,
and 0.0.1-rc.1 does not satisfy ^0.0.1 either.
It also retires ranges that had gone stale against the workspace: ^4.0.0-rc.6
for a 4.0.0-rc.7 checkout, ^3.17.0 for schemastery 3.18.0.
workspace:* stays where an exact published version is the point, which is how
the Landlock entry pins its platform packages.
A workspace constraint now requires the protocol, so a new package cannot
reintroduce a hand-written range. The same constraint caught packages/boot/cmdline
arriving on master without the publishable trio, which this change completes.
Every package under packages/, apps/, and vendor/ drops "private": true and
declares publishConfig.access "restricted": the repository now states which
packages it publishes instead of deciding it at publish time. Each one also
declares its repository and directory, which is how a consumer of a private
package reaches its source.
The Landlock packages move to restricted with them. They have never been
published, so nothing anonymous depends on them today, and the whole
@deepseek-ai scope stays private.
The workspace constraint that required every package to be private now applies
to non-members only, and asserts the publishable trio on each release member.
Machine-produced by `pnpm run rescope-vendor --apply` plus the regeneration it
prints: `pnpm install` for the lockfile, `pnpm run gen-third-party-notices`,
`verify-translation-pairing --write` for the touched bilingual pairs,
`gen-doc-graphs`, and one typert snapshot whose ids embed character offsets.
`pnpm run rescope-vendor --check` verifies the result.
Renames nine vendored packages (cordis, cosmokit, schemastery and the six
@cordisjs plugins) and every reference that resolves them: manifest names and
dependency keys, module specifiers including declare-module merges, cordis.yml
plugin names, tsconfig paths, every Markdown fence, and `docs/` prose.
Directory names, upstream versions, and dependency ranges are unchanged, so
vendor/README.md still reads as an upstream snapshot; its manifest table gains
an upstream-name column so THIRD_PARTY_NOTICES keeps MIT attribution pointed
at each fork's origin.
The tutorial tier follows the rename end to end: its yaml fences named plugins
the Loader can no longer resolve, its `ts ignore-check` fences disagreed with
the compiled fences beside them, and its prose quoted both. The contracts that
told readers to keep upstream names — the root convention and the vendoring
cookbook's tree comment and manifest invariant — now say to rescope instead.
Two rules read `@deepseek-ai/` as "another workspace plugin": the client bundle
purity gate now names the vendored libraries a browser bundle inlines, and the
files where a bare `cordis` is an agent-preset id keep that product data.
Toolbar strings route through the locale dictionary's standard t seat (the
export button no longer mixes languages in the English golden), exportLog
passes the response blob straight to the browser save instead of copying it
three times, the client id sanitizer rejects dot segments like the host one,
and the fixture stub comment no longer misattributes the 404.
The 导出 button fetches GET /api/session.export and saves the ZIP (root
artifact plus subagent descendants). The plugin exposes exportLog through
the view's inject face, resolves the tab label through the locale service,
and disables the button while in flight; fixture mode answers 404 so the
error bar explains the gap.
Delete design-session citations (decision/audit/plan ordinals, stack
positions), change narration, review choreography, and reviewer-addressed
justification from comments, JSDoc, docs, READMEs, Agent Notes, tests, and
generator templates; restate every affected fact as current-state contract
prose. Fix generated docs at their sources and regenerate the catalogs and
cordis-surface regions; re-paste type-equiv blocks; update every bilingual
counterpart and re-record the pairs. Record the citation rule in the
committed-artifact-citations Agent Note.
git mv per the regrouping RFC: the five human-collaboration seams and
tui join packages/interaction/, app-boot becomes packages/boot/, and
jsonrpc joins the renamed scaffold/ (formerly sdk/) as its server half
beside client/protocol/create-sdk/helper/scripts/telemetry, whose
folders drop the legacy sdk- prefix. Three new group README triplets
replace the ui/ and sdk/ ones; tsconfig references/paths/globs,
knip keys, vitest globs, gate scripts, catalogs, docs, and the
lockfile follow. Adds the four settled FIXME rename markers
(dsh-sdk-server, dsh-sdk-telemetry, dsh-sdk-helper, dsh-sdk-scripts).
The scaffold folders diverge from their npm names until those renames
land, so tsconfig.base.json maps the three affected names explicitly
beside the group wildcard. Also repairs two pre-existing stale-path
classes the strengthened sweep surfaced: docs/web-styling.md's retired
web-ui host package and type-model spec fixture-literal joins.
app-boot's three Loader-composition specs time out at the default 5s
under full-suite parallel load on this filesystem (pre-existing;
pass isolated with --testTimeout=30000); interaction/scaffold/boot
suites otherwise green (687 passed).
The task registry has run every background bash, pwsh, pty-send, and
one-shot subagent since it landed, but only the model could read it: a
human at the Web client could not see that a build was running, tell a
finished task from a stuck one, or find its outcome anywhere but the
`run_in_background` tool card that printed an id and never updated.
Task state now reaches the browser as one whole-snapshot `session/tasks`
mux frame per session, pushed at every registry commit that changes what
that session can see. `TaskService` gains `onTasksChanged`, which is
owner-granular because owner-disposal removal is a change no per-task
record can express. The carrier reads the exact owner the listener hands
it, so a push stays correct while that scope tears down, and reads the
baseline through the non-resuming `ctx.agents.get` so listing never
revives a cold session. The client keeps a last-wins mirror on
`SessionListState`, and a new `dsh-client-ui-task` package renders it
beside the subagent catalog — rendering nothing at all until the session
has a task, so an ordinary conversation grows no new chrome.
Streamed per-task output and human-initiated cancellation are separate
phases; the note records why neither has to undo this channel, and why
no Web path may call the consuming `ctx.tasks.read()`.
The web YAML editor is gone. agentPreset.write (arbitrary composition
text) became agentPreset.copy { from, agentPreset, name? }: a host-side
whole-directory copy of ids the host resolves itself — symlinks
dereferenced, modes re-tightened to owner-only with owner-execute kept,
metadata rewritten to keep the source's description but never its name or
roster order. No composition text or path crosses the wire in either
authoring direction, and the entryListSchema/!!js concern dissolves with
assertComposition itself.
The settings section becomes: a read-only viewer over shipped
compositions, a copy dialog (id + optional display name) as the only
create entry, delete for custom rows, and a location action leading into
the preset's own files — agentPreset.openDocument { agentPreset } resolves
the directory host-side and opens it natively, or answers
{ opened: false, path } for the row to show as text where the deployment
has no desktop. agentPreset.list reports hasDocument beside authorable;
the gateway's nativeOpen config pins the capability where
canOpenNativePath platform detection would mislead. The privileged set is
now read/copy/openDocument/remove.
With files as the only composition editor, standing mounts grew
stamp-keyed generations: ensureStanding compares the composition file's
mtime+size and starts the next generation for later sessions, while every
joined session keeps the generation it runs on.
New keyless web lane (agent-preset-authoring, overlay pins
nativeOpen: false so goldens render one branch on every platform) drives
view/copy/reveal/delete end to end; the real-composition CLI e2e switches
to copy semantics.
ctx.subagents.interrupt() stops one live continuable child's current turn
via Agent.cancel(cause, { keepInbox: true }) under either a human durable
parent address or an exact live ancestor Agent. Fire-and-return: admission
is synchronous, quiescence is not awaited. Pending inbox work, the
Activation, and published descendants are preserved; only a later waking
send resumes the parked FIFO queue. Absent, one-shot, and disposing
targets are accepted no-ops.
The new Host RPC subagent.interrupt calls only that primitive with user
authority — no catalog, history, persistence, or parent-registry lookup —
so a live child stays stoppable while its parent Agent is offline.
Refs #1535
The composer's preset seat stays removed here — this layer moved it to the
hero chip and the session-header action — so only the model seat takes the
`modelSeatLocked` narrowing master introduced.
Conflicts:
apps/web/tests/snapshots/*/*.expected.md
packages/client/connection/README.md
packages/client/connection/README.zh.md
packages/client/ui-conversation/src/client/skeleton/InputBar.tsx
packages/host/apiproxy/src/fetch/client.ts
The Client API carrier's `agentPresets` member was the one member of its class
without an `IApiClient[...]` annotation. Inferring it inlined `AgentPresetEntry`
into the emitted declaration by the specifier TS picks — the host `index.ts` —
dragging the whole gateway, and with it the host `Context` merges, into every
Client program importing the carrier. Annotated like its siblings.
`ApiRemoteAgentOptions.setup` now takes the inspected session rather than its
header alone: this layer resolves a resumed session's preset from the LOG,
because a session that switched while blank ran its turns under the newer
composition and the header is written once at creation.
Conflicts:
apps/web/tests/snapshots/*/*.expected.md
packages/client/ui-conversation/src/client/skeleton/InputBar.tsx
packages/host/apiproxy/src/api-proxy.ts
scripts/doc-budgets.manifest.json
Invocation is an ordinary session.prompt again: the pre-step gesture
boundary makes it deterministic host-side for every front end, so the
dedicated RPC (handler, wire schema, error codes, client face, fixtures)
and ui-skill's claim machinery are net deletions. The menu keeps decision
21 exactly — a pick lands literal /name text — plus the user-only marker
from skill.list's modelInvocable flag.
Deleting the preset a user default names left the setting pointed at an id
nothing will ever supply again, and every session created without an explicit
pick then failed to start — the delete dialog called it 'new sessions cannot
select it', which understates a hard creation error. `remove` now clears the
user layer when it named the preset just deleted, exposing the deployment's own
default underneath. Storing a default that does not exist YET stays deliberate:
the roster is a live directory, so a name absent now may exist by the time a
session asks, and `resolve` still reports that case.
`agentPreset.select` also leaves the loopback set. It was pinned as a real
escalation — one preset mounts the toolset that edits the live runtime — but
`session.create` already takes an `agentPreset`, so pinning only the switch left
the same capability one method over. The deeper reason is that the capability is
not the preset's to grant: the deployment's own default already carries `bash`
and the filesystem tools, so any caller that may start a session at all can
already run commands as this process. `read`/`write`/`remove` stay pinned on
their own footing — those touch files, not sessions.
The user-turn predicate (opensUserTurn) unifies the three parallel
consumers a new node kind silently missed — produced-files turn reset,
retry liveness, own-words force-scroll — so a skill invocation behaves as
the turn opener it is. The menu marker resolves through ctx.locale.bind
instead of a hand-rolled snapshot lookup; the dead legacy <skill> render
arm goes with the removal cut; command-over-skill name precedence is now
documented at the matchEnter seam; and the emptied replacement catalog
keeps the no-reload sentence, with the never-published residual recorded
in the Agent Note.