@robota-sdk/agent-command 3.0.0-beta.97 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/CHANGELOG.md +1027 -2
  2. package/package.json +7 -7
package/CHANGELOG.md CHANGED
@@ -1,5 +1,1030 @@
1
1
  # @robota-sdk/agent-command
2
2
 
3
+ ## 3.0.0
4
+ ### Major Changes
5
+
6
+ - 64ba748: **BREAKING — ARCH-042: project filesystem access is now an explicit, host-issued authority instead of an ambient consequence of `cwd`.**
7
+
8
+ `@robota-sdk/agent-framework` adds `WorkspaceTrustService` and the opaque
9
+ `IWorkspaceProjectAuthority`, plus bounded reader, settings-writer, state-storage, and mutation
10
+ facets. Public session, settings, context, checkpoint, memory, contribution, query, and replay
11
+ contracts consume those facets. A caller that does not supply `projectAccess` is deliberately
12
+ restricted to user-owned host state and receives no project filesystem capability.
13
+
14
+ The framework removes or renames ambient Node/project exports. Migrate `checkSettingsFile` to
15
+ `checkNodeHostSettingsFile`, `readMergedProviderSettingsFromPaths` to
16
+ `readMergedProviderSettingsFromSources`, `resolveProviderSettingsWriteTargetPath` to
17
+ `resolveProviderSettingsWriteTarget`, `FileSystemMemoryStore` / `createFileSystemMemoryStore` to
18
+ `WorkspaceMemoryStore` / `createWorkspaceMemoryStore`, and `PluginSettingsStore` to
19
+ `NodeHostPluginSettingsStore`. Host-only git helpers now carry the `FromNodeHost` suffix.
20
+ `projectPaths`, `resolveSettingsPathForScope`, and `getProviderSettingsPaths` are removed; project
21
+ consumers must use the authority facets rather than recover absolute paths.
22
+
23
+ `@robota-sdk/agent-session` renames the Node filesystem implementation `SessionStore` to
24
+ `NodeSessionStore` and adds explicit session-log/external-payload source and sink ports. Session
25
+ replay no longer resolves external payload files from an ambient directory.
26
+
27
+ `@robota-sdk/agent-interface-transport` changes `ISkillExecutionPort.loadCommands(cwd, home?)` to
28
+ the authority-bound `loadCommands()` and removes the optional absolute-path leak
29
+ `IInteractiveSessionStore.getFilePath`. `@robota-sdk/agent-command` consequently replaces the
30
+ `cwd` option of `createSkillsCommandModule` with required `contributionSources`; default command
31
+ composition accepts explicit contribution sources and discovers no project skills when none are
32
+ provided.
33
+
34
+ `@robota-sdk/agent-cli`, `@robota-sdk/agent-transport`, and
35
+ `@robota-sdk/agent-transport-tui` thread the trusted-or-restricted project decision through every
36
+ session surface. Embedded callers that need project settings, state, context, skills, checkpoints,
37
+ or mutation must mint access through `WorkspaceTrustService` and pass the returned
38
+ `projectAccess` (and a separately approved mutation/settings facet where required). Omitting it is
39
+ still type-compatible but is behaviorally breaking: the surface now fails closed instead of
40
+ reading or writing the current directory.
41
+
42
+ ### Minor Changes
43
+
44
+ - 9c19c50: `/fork [name] [--same-dir]` copies the live conversation into a background session.
45
+
46
+ The session writes a copy of its own record under a fresh id — messages, system prompt, tool schemas
47
+ and full history, and deliberately not the sandbox snapshot, goal, plan or branch — then spawns a
48
+ background job carrying only `resumeSessionId`. The child restores that record itself, so no
49
+ conversation crosses the child-process boundary and the worker start payload's key set is unchanged.
50
+ The background panel gains an `attach` control that switches the terminal onto the forked session; it
51
+ is a view switch, never a merge, and a missing record or a terminal task is refused with the task's
52
+ own status.
53
+
54
+ **`@robota-sdk/agent-framework` is `major` for one reason: `ICommandHostSessionAccess` gains a
55
+ required member.** `forkSession({ name? })` is not optional, so an external implementation of that
56
+ role port stops compiling until it adds the method. Every other change in this set is additive:
57
+
58
+ - `agent-interface-execution` — `TExecutionControl` gains `'attach'`.
59
+ - `agent-interface-command` — `TCommandUiIntent` gains `{ type: 'switch-session'; sessionId }`.
60
+ - `agent-subagent-runner` — `ISubagentWorkerComposition` gains the optional `openSessionStore`, and
61
+ the worker resumes a record when the job names one. A composition that registers no store and
62
+ receives no `resumeSessionId` behaves exactly as before.
63
+ - `agent-framework` also gains the fork-record builder, `SessionTurnMemory`, and
64
+ `IAgentBackgroundTaskRequest.resumeSessionId?`; `loadSessionRecord` now returns
65
+ `restoredSystemPrompt`, which makes a record field that was written and never read take effect on
66
+ restore.
67
+ - `agent-executor`, `agent-command`, `agent-transport-tui`, `agent-cli` — the spawn input, the
68
+ `/fork` module and the attach control that carry it to the surface.
69
+ - 724fabb: External-event grants are given at start, carried exactly to a background session, listed without their
70
+ principal, and revoked by the owner.
71
+
72
+ - `agent-framework` (breaking) — `openExternalEventSource` and `ExternalEventIngress.open` take only
73
+ `{ grant, audit? }`: the session builds each grant's verifier from `grant.verifier` with the
74
+ `externalEventVerifierFactory` its host passed when the session was built (without one, no grant opens), and an
75
+ open that supplies a verifier or a factory is refused. `IExternalEventSource.revoke()` stops the grant's queued and running turns,
76
+ refuses its later events as `grant-revoked`, and keeps the label from being opened again. A submission the
77
+ session refuses is `shutting-down` only while it shuts down, and `session-unavailable` otherwise. New command
78
+ host adapter `externalEvents` (`ICommandExternalEventsAdapter`).
79
+ - `agent-ui-terminal` — forwards `externalEventVerifierFactory` from the render options to the session.
80
+ - `agent-interface-transport` — `TExternalEventRefusal` gains `session-unavailable`.
81
+ - `agent-command` — `/events` lists the session's grants (label, principal kind, state, counts) and
82
+ `/events revoke <grant-id>` withdraws one. User-only.
83
+ - `agent-cli` — a grant file (`grantId`, `issuer`, `resource` ending in `/events/<grantId>`, exactly one of
84
+ `subject` or `client`, `scopes`, optional `algorithms` and `rate`) is validated before anything starts, with a
85
+ reason that names the grant and no configured value. `robota --external-event-grant <file>` (TUI) and
86
+ `robota session start --background --external-event-grant <file>` open every grant or fail the start; a
87
+ background session receives its grants through a private file, opens them before it reports ready, and the
88
+ launcher refuses a readiness that names other grants. `robota session events list <id> [--json]` and
89
+ `robota session events revoke <id> <grant-id>` work over the generation-bound control socket, and
90
+ `robota session list --format json` shows each grant's counts. The retired `--external-event-allow` now points
91
+ at `--external-event-grant`.
92
+ - 9368d00: Advisor escalation: the main model can consult a second model at the decision points it chooses.
93
+
94
+ With an advisor configured (`--advisor <profile>[:<model>]`, or the `advisorModel` setting that
95
+ `/advisor` saves; the flag wins), the session gets an `Advisor({ question? })` tool. The advisor reads
96
+ the whole conversation — system prompt, messages, tool calls and results — serialized into one prompt
97
+ and sent with `toolChoice: 'none'`, truncated from the front to fit its window with the system prompt
98
+ kept, and declines when even that does not fit. Its answer comes back framed as guidance to verify;
99
+ an empty or refusing answer reads as declined. Calls are limited to two per turn and a fixed number
100
+ per session, parallel calls in one round share those limits, and a repeated question in the same
101
+ turn returns the earlier answer. A request that was sent counts even when the provider failed (the
102
+ decline is reported by class, never by its text); only a call declined before sending gives its slot
103
+ back.
104
+
105
+ Advisor usage, including in-process subagents', is recorded where each turn's usage is recorded —
106
+ the persisted session history, under the advisor's own provider and model — so `/cost`, usage reports
107
+ and resumed sessions include it. `/cost` now totals that history and prices each part on its own
108
+ model, showing "mixed" when more than one model was priced.
109
+
110
+ `/advisor <model>` and `/advisor off` change only where calls go, never the tool list, so the main
111
+ model's prompt cache is not invalidated mid-session; the tool is added only when a session starts
112
+ with an advisor. Sending history to a destination (provider type and endpoint host) the main model
113
+ does not already use needs a one-time consent per destination, kept in the user settings file; a
114
+ refusal is remembered for the session. The organization's `allowedProviders` applies, and
115
+ `PRODUCT_DISABLE_ADVISOR=1` turns it off completely. In-process subagents inherit the advisor, bound
116
+ to their own conversation; child-process subagents do not get it.
117
+
118
+ **`@robota-sdk/agent-framework` is `major` for one reason: `ICommandHostSessionAccess` gains a
119
+ required member,** `getSessionUsage()`, the session's persisted usage records. An external
120
+ implementation of that role port stops compiling until it adds the method. The rest is additive.
121
+
122
+ - `agent-session` — `formatConversationEntries`, the one text rendering of a conversation, now used
123
+ by compaction too. It keeps tool calls and results, marks a user message a peer session sent
124
+ (`user [from "peer:<id>"]`), and JSON-encodes every message onto one line so no content can forge
125
+ another entry; compaction previously flattened all of this. `Session.getProvider()` returns the
126
+ provider the session currently uses.
127
+ - `agent-framework` — `AdvisorController`, `createAdvisorTool`, the advisor spec helpers, provider
128
+ destinations (`describeProviderDestination`, `rememberProviderDestination`), `getSessionUsage` and
129
+ `ISessionUsageRecord`, the `onUsageRecorded` session option, and the optional `advisor` command
130
+ host adapter. Session assembly binds a host-supplied Advisor tool to the session holding it.
131
+ - `agent-command` — the `/advisor` command module; `/cost` reads the session's persisted usage.
132
+ - `agent-cli` — the `--advisor` flag, `advisorModel` setting, per-destination consent store and kill
133
+ switch.
134
+ - `agent-ui-terminal` — a usage line from another source (the advisor, a background task) names that
135
+ source and leaves out the context window it does not have.
136
+ - `agent-session-analytics` — personal usage counts an advisor call's tokens and cost toward its
137
+ turn without counting it as a turn.
138
+ - d4189b9: The rest of the per-server MCP OAuth lifecycle: signing in to a server without a local browser,
139
+ signing out of it with token revocation, and each server's sign-in state in `/mcp`.
140
+
141
+ - **`robota mcp login <name> --no-browser`** prints the authorization URL and reads the redirect URL
142
+ the user pastes back (not echoed). `runMCPOAuthLogin` takes `readRedirect` for this; nothing
143
+ listens on the redirect URI then. The pasted URL is held to the loopback listener's rules through
144
+ `createPastedRedirectAcceptor`: it must be the registered redirect URI (same origin and path, no
145
+ user info), carry the sign-in's `state` (compared in constant time), and is accepted once; an
146
+ error redirect is `authorization-denied` without its `error_description`, and the RFC 9207 `iss`
147
+ check applies as before. `openBrowser` now also receives the redirect URI. `readRedirect` gets a
148
+ signal that aborts on cancel or at `callbackTimeoutMs` (5 minutes by default, as for the loopback
149
+ listener); a paste longer than the prompt accepts fails as `redirect-too-long`.
150
+ - **Signing out** (`runMCPOAuthLogout`; `robota mcp logout <name>`; `/mcp logout <serverId>`):
151
+ deletes the stored credential under the refresh lock, then revokes the refresh token and the
152
+ access token (RFC 7009) when the stored issuer advertises `revocation_endpoint`. Revocation is a
153
+ POST through the egress policy that never follows a redirect and is byte-bounded; it authenticates
154
+ the client by `revocation_endpoint_auth_methods_supported` when advertised, otherwise the way its
155
+ refresh does. The local delete always happens. Each token's outcome is reported in `tokens`, and
156
+ overall as `revoked`, `partial`, `unsupported`, `failed` or `not-attempted`, with fixed reasons
157
+ only (new: `revocation-failed`, and `token-type-not-revocable` for RFC 7009
158
+ `unsupported_token_type`). `/mcp logout` also makes the session's authenticator drop the token it
159
+ holds (`IMCPOAuthAuthenticator.forget`).
160
+ - **Sign-in state:** `readMCPOAuthCredentialState` answers `signed-in`, `expired-refreshable`,
161
+ `sign-in-required` or `signed-out` — never anything token-derived. `/mcp` shows it for every
162
+ OAuth server; a server this session was told needs a sign-in reads `sign-in-required`.
163
+ `ICommandMCPActivationAdapter` gains optional `oauthStatus` and `oauthLogout`
164
+ (`ICommandMCPOAuthStatus`, `ICommandMCPOAuthLogoutResult`).
165
+ - **No in-session sign-in:** signing in stays `robota mcp login <server>` in a terminal, since it
166
+ needs the terminal (browser, pasted redirect, hidden secret prompt) a running session owns. `/mcp`
167
+ names that command for a server that needs a sign-in, as does the session's sign-in notice; the
168
+ server name is shown there only when it is safe to paste into any shell — a plain token not
169
+ starting with `-` or `=` — and is otherwise replaced by `<server>` (`shellArgumentForDisplay` in
170
+ `agent-core`; nothing is quoted, since quoting rules differ between shells). Server names in OAuth
171
+ notices have control and format characters escaped.
172
+ - **Refresh hardening:** on `invalid_grant`, the store is read again under the lock; a refresh token
173
+ another holder rotated in meanwhile is kept (and used when still valid) instead of being deleted.
174
+ The expiry skew is capped at half the token's lifetime, so a short-lived token is not refreshed on
175
+ every request; credentials now record `issuedAt` for this.
176
+ - af2f2ad: `/cd <directory>` continues the conversation in another directory.
177
+
178
+ - **A move is a new session in the target directory.** In the TUI, the configured CLI saves a copy of the
179
+ conversation where the target's session store will find it, ends the current run through its
180
+ normal end-of-life flow, and starts again in the target directory resuming that copy. The target's
181
+ settings, trust decision, tools, skills and `AGENTS.md` apply, exactly as if the configured CLI had been
182
+ launched there. The process boundary makes the move atomic, so no tool call can straddle it.
183
+ - **The system prompt is kept as recorded**, so a provider's prompt cache survives. One appended
184
+ `<workspace-move>` message tells the model the new directory, and which project instructions now
185
+ apply.
186
+ - **Refused** while a turn is running or a background task is still running, for a missing directory
187
+ or the current one, and for a target a `Cd(...)` deny rule names.
188
+ - **Access never widens:** a restricted session stays restricted after a move, and a trusted session
189
+ takes the target's own trust decision.
190
+ - New contracts: the `workspace-move` host action, `ICommandWorkspaceAdapter` /
191
+ `IWorkspaceMoveRequest`, `InteractiveSession.moveWorkspace`, and the `workspaceMovedFrom` session
192
+ option. The CLI's `--moved-from` and `--restricted-workspace` flags are internal.
193
+ - 34e50f0: A new permission mode, `auto`, lets a model classifier approve or block what would otherwise prompt.
194
+
195
+ - **What it decides:**
196
+ - Reads and in-workspace edits run as in `acceptEdits`.
197
+ - Commands and other calls the mode leaves open go to the classifier, a side call to the
198
+ session's own model. It sees the call, the working directory and the git remotes, never the
199
+ conversation.
200
+ - A block reaches the model with its reason, so it can take another route.
201
+ - **What still reaches a person, or is refused:**
202
+ - Deny rules and background ceilings apply first.
203
+ - `ask` rules, critical removals and protected paths ask a person.
204
+ - After 3 refusals in a row (blocks, or no usable verdict), or 20 blocks in the session, the
205
+ mode asks a person until one approves.
206
+ With no one to ask, the call is denied.
207
+ - **Allow rules:** in `auto` mode, allow rules that approve any command are set aside while the
208
+ mode is on. Examples are `Bash(*)`, an interpreter (`Bash(python *)`), a package runner
209
+ (`Bash(npm run *)`, `Bash(pnpm exec *)`), `Agent`, `ExecuteCommand` or `Computer`. Narrow
210
+ rules still apply.
211
+ - **Retry:** `/permissions` lists classifier blocks. `/permissions retry <n>` lets that exact call
212
+ run once, unjudged, when the model tries it again.
213
+ - **Turning it on and off:**
214
+ - `--permission-mode auto`, `/mode auto` or `/permissions auto`.
215
+ - An organization turns it off with `disableAutoMode` in the org policy.
216
+ - **New contracts:**
217
+ - `TPermissionMode` gains `'auto'`.
218
+ - `allowRulesForAutoMode` and `isBroadExecutionAllowRule`.
219
+ - `IPermissionClassifier` and `AutoModeGate`.
220
+ - The `permissionClassifier` session option.
221
+ - `Session.retryPermissionDenial`, and `retryDenial` on the permission-mode adapter.
222
+ - The `'classifier'` denial reason.
223
+ - `createModelPermissionClassifier`.
224
+ - The `disableAutoMode` option on `createSession` and `IOrgPolicy`.
225
+ - 722e88a: Shell commands can run in an OS-level sandbox: bubblewrap on Linux and WSL2, Seatbelt on macOS.
226
+
227
+ - **Confinement:** covers the command and every process it starts.
228
+ - Writes are limited to the working directory, the temporary directories and
229
+ `sandbox.filesystem.allowWrite`.
230
+ - Agent, git-hook, MCP and shell configuration inside the workspace stays read-only.
231
+ - `sandbox.filesystem.denyRead` hides paths from the command.
232
+ - The network is on or off (`sandbox.network.enabled`).
233
+ - **Modes:** `/sandbox` switches between `auto-allow`, `regular` and `off` for the next command and
234
+ saves the choice.
235
+ - In `auto-allow` (`sandbox.autoAllowBashIfSandboxed`), a confined command runs without a prompt
236
+ in `default` and `acceptEdits`.
237
+ - Deny rules, ask rules, critical removals and plan mode still apply first.
238
+ - **Exclusions:** `sandbox.excludedCommands` run unconfined, through the ordinary permission path.
239
+ - **When the sandbox cannot run:** a missing or unusable backend is reported at startup, in
240
+ `robota doctor` and in `/sandbox`, and commands then run unconfined.
241
+ `sandbox.failIfUnavailable` refuses to start instead.
242
+ - **New contracts:**
243
+ - `OsSandboxClient`, `detectOsSandbox`, `bubblewrapArguments`, `seatbeltProfile`.
244
+ - `ISandboxClient.wrapCommand` and `autoApproves`.
245
+ - `IPermissionEvaluationContext.sandboxAutoApproved`.
246
+ - The `commandSandbox` session option.
247
+ - The `sandbox` settings key and the `sandbox` command host adapter.
248
+ - a5cc36e: `/permissions` shows the rules the session enforces and the calls it refused.
249
+
250
+ - **Rules by source:** each allow, deny and ask rule the gate reads is listed under the settings file
251
+ that declares it. Rules added by a CLI flag, a preset or a command are listed under "this session".
252
+ A rule a settings file declares but the session does not enforce is not shown.
253
+ - **Recent denials:** the latest refused calls, most recent first, with the reason: a rule or the
254
+ mode, the user declining, or no one available to approve.
255
+ - New contracts: `Session.getRecentPermissionDenials()`, `PermissionEnforcer.getRecentDenials()`,
256
+ `IPermissionDenial`, the `permissionRules` host adapter (`createSettingsPermissionRulesAdapter`),
257
+ and `getPermissionRules` / `listRecentDenials` on `ICommandPermissionModeAdapter`. Settings
258
+ provenance now covers `permissions.ask`.
259
+ - 4dd45cc: `/peers` shows how each other local session's workspace relates to this one's: `same worktree`,
260
+ `same repo`, `different repo`, or `workspace unknown`.
261
+
262
+ A session now publishes a workspace claim with its rendezvous entry — the root commits reachable
263
+ from HEAD, a SHA-256 of its normalized `origin` URL (never the URL itself), and the real path of its
264
+ worktree — and re-reads it as it runs, so a first commit or a checkout does not leave it stale. The
265
+ reader does not take the claim as written: it reads git at the claimed path itself, and a claim whose
266
+ contents disagree is shown as `workspace claim mismatched, not believed` and relates to nothing. Those
267
+ git reads are local-only and asynchronous, run only for the view that shows the relation (and for
268
+ the sender of an incoming peer message), and are cached per announcement. The relation also reaches
269
+ the peer-turn origin, computed by the receiver; a relation the sender put on the wire is discarded,
270
+ and the admission never carries it.
271
+
272
+ The relation is display and routing information only and is never an authorization input.
273
+
274
+ Additive: `agent-interface-session-mobility` exports `TWorkspaceRelation` and gains the optional
275
+ `IPeerOrigin.workspaceRelation`; `agent-framework`'s `ILocalPeerSummary` gains the optional
276
+ `workspaceRelation` and `workspaceClaim`, and `ICommandLocalPeersAdapter` the optional
277
+ `listWithWorkspace()`.
278
+ - 28fa8a7: `/devices add` and `/devices join` enrol a new device into your devices.
279
+
280
+ - On a device that holds the signing key, `/devices add` shows a one-time code on the terminal. It
281
+ works once, for five minutes.
282
+ - On the new device, `/devices join [name]` asks for the code on the terminal, creates the device's
283
+ keys, and meets the other device through the signaling relay in
284
+ `transports.webrtc.options.relayUrl`. Both devices need that setting.
285
+ - The new device proves the code over the WebRTC connection's DTLS fingerprints before anything else
286
+ crosses, so a relay in the middle cannot enrol anyone.
287
+ - Both devices then show the same six digits, and both operators compare them and confirm. Someone
288
+ who saw the code cannot choose the digits: the new device commits to its part before it sees the
289
+ existing device's.
290
+ - Only when both operators say yes does the existing device certify the new one and issue a new
291
+ roster. The new device keeps its identity only once the chain it receives verifies.
292
+ - A wrong, expired or already used code is refused. So is a code after a few failed attempts. When
293
+ either operator declines, nothing is issued or kept.
294
+ - The code appears only on the two terminals. It never reaches history, transcripts or the model. A
295
+ code typed as a command argument is refused. Both commands stay user-only and refuse remote
296
+ surfaces.
297
+ - `agent-remote-pairing`: enrollment codes, the enrollment proof, the signed request with its
298
+ commitment, the short authentication string and the frame decoder.
299
+ - `agent-transport-webrtc`: `dialEnrollment` and `listenForEnrollment` provide a data channel bound to
300
+ the negotiated fingerprints.
301
+ - 44fc732: Add `/devices` for this device's identity among the user's devices: `list`, `init` (creates the identity: a recovery phrase, the master-certified signing key, this device's keys and certificate, the first roster and revocation list), `revoke <device-id>` (signing key only, no phrase; confirmed at the terminal) and `recover` (rotates the signing key from the phrase and revokes the old ones). Enrolling another device (`add` / `join`) comes with the device connection.
302
+
303
+ The recovery phrase never enters the session: it is shown once and read with no echo on the controlling terminal (opened apart from the session's input), on the alternate screen that is cleared afterwards, and never reaches prompt history, conversation history, transcripts, traces or the model. Without an interactive terminal the phrase commands refuse. `/devices` is operator-only: never model-invocable and refused from remote surfaces. Private keys live in the host credential store; certificates, roster, revocation lists and sequence marks are kept in owner-only files under `the configured user data directory`.
304
+
305
+ `agent-remote-pairing` adds `isRecoveryPhraseWord`, so a phrase can be checked one word at a time.
306
+ - 4f49d14: The device mesh can be turned on, and `/peers`, `/handoff` and `/devices` reach the user's other devices.
307
+
308
+ - New user setting `transports.mesh.enabled` (default `false`). When it is `true`, an interactive
309
+ session opens the device mesh at startup and closes it on exit. Only the user settings count; a
310
+ project's settings cannot turn it on. Print and serve runs never open it, and a device without an
311
+ identity is told to run `/devices init`. Only one session of a device opens it at a time; another
312
+ session on the same device says so in `/devices` and links nothing.
313
+ - By default a linked device may send messages, files and sessions. Each file and each session still
314
+ waits for the operator's yes on this machine's terminal; with no terminal the answer is no.
315
+ Delegating, observing and driving stay off unless `transports.mesh.options.capabilities` lists
316
+ them.
317
+ - A message from a linked device arrives like one from a session on this host: a peer turn with no
318
+ authority, attributed to the device the handshake proved, under the same rate limit and
319
+ conversation limits.
320
+ - `/peers` lists linked devices beside the sessions on this host; `/peers send` and
321
+ `/peers send-file` take a device id. `/handoff` lists linked devices and pushes the session to one.
322
+ Files arrive in the usual place aside, and sessions are saved without starting.
323
+ - `/devices` shows whether the mesh is on, how this device finds the others, and which are linked.
324
+ - The mesh uses the relay at `transports.webrtc.options.relayUrl` when one is set. Without one it
325
+ finds devices on the local network and over the public ways in `transports.mesh.options`.
326
+ - `/peers`, `/handoff` and `/devices` stay user-only. Their descriptions tell the model they cover
327
+ linked devices.
328
+ - `agent-framework`: the `/peers` port can list linked devices (`listDevices`, `ILinkedDeviceSummary`).
329
+ - `agent-command`: the `/devices` port can report the mesh (`meshStatus`, `IDevicesMeshStatus`).
330
+ - c7f9203: Connected sessions can send each other files.
331
+
332
+ - `/peers send-file <session-id> <path>` sends a copy of any file the operator can read to another
333
+ live session on this host.
334
+ - The model sends a file only through the `peer_send_file` tool. Every call asks the user, showing
335
+ the path, size, hash and destination; no permission mode, rule or remembered consent answers it.
336
+ The tool reaches only files inside the workspace whose path does not look like it holds secrets
337
+ (`.env*`, `~/.ssh`, keys and credentials), and it does not exist in a turn a peer's message started.
338
+ - The receiving operator approves every file. A received file is kept as an inert copy (mode 0600)
339
+ under `the configured user data directory<sender>/`. It is never run and never placed in the model's context.
340
+ The conversation is told only its name, size and sha256. A name that leaves that directory is
341
+ refused, a symbolic link is never written through, and nothing is overwritten.
342
+ - Transfers travel on a channel of their own (a separate connection on this host, a separate data
343
+ channel between devices), in chunks the receiver paces, up to 32 MiB, and are kept only when the
344
+ whole content matches the offered sha256. A transfer that ends early is discarded; there is no
345
+ resume.
346
+
347
+ **API**
348
+
349
+ - `agent-interface-session-mobility`: the `file` capability, which asks the operator for every
350
+ request; `ConnectionAuthority.authorizeFile`; `IFileOffer` and `IFileFrameChannel`.
351
+ - `agent-transport/node`: `sendFileOverChannel` and `receiveFileOverChannel`, the carrier over any
352
+ `IFileFrameChannel`; `DEFAULT_MAX_FILE_BYTES`.
353
+ - `agent-transport-webrtc`: `IDeviceMeshLink.openFileChannel` and `onFileChannel`.
354
+ - `agent-remote-pairing`: `file` joins `DEVICE_CAPABILITIES`. A device certificate that names it is
355
+ refused as malformed by an earlier version.
356
+ - `agent-core`: `IToolPermissionProfile.notInPeerTurn` withholds a tool from a turn a peer's message
357
+ started.
358
+ - `agent-framework`: `ICommandLocalPeersAdapter.prepareFile`.
359
+ - 004fe7f: `/handoff` moves a session over a real connection.
360
+
361
+ - `/handoff <session-id>` pushes this conversation to another the agent runtime session on this machine. The
362
+ same carrier also runs between two of the user's devices over their mesh connection; no command
363
+ opens that connection yet.
364
+ - A hand-off is push-only: only the operator of the session that holds it starts one. A session or
365
+ device that asks another for its session is refused.
366
+ - The source signs a grant for that one transfer over that one channel with its device key, so a
367
+ hand-off needs the device identity from `/devices init`. The receiving side checks it against the
368
+ sender's certificate, then asks its own operator; without a yes nothing is sent.
369
+ - The session travels on the file-transfer carrier, is kept aside until it matches the manifest, and
370
+ is saved without being started. The operator there resumes it with `robota --resume <id>`.
371
+ - The source gives the session up, and ends, only once the receiving side confirms it saved it.
372
+ Every other outcome leaves the session where it was; if the confirmation is lost, `/handoff` to the
373
+ same session again resends the same transfer, which the receiver settles without saving it twice.
374
+ Peer attribution (`driverId`, `turnSource`)
375
+ travels with it.
376
+ - `/handoff` stays user-only. Its description tells the model to suggest the command to the user.
377
+ - `agent-transport-webrtc`: an admitted mesh link exposes the DTLS fingerprints it is bound to, and
378
+ `judgeHandoffGrant` is exported.
379
+ - `agent-interface-session-mobility`: a hand-off carrier may move the sealed payload whole
380
+ (`sendPayload`), the destination verifies it with `receivePayload`, and the source can report its
381
+ open transfer (`status`) and abandon it for any refusal the destination names.
382
+ - 18b52cc: Built-in commands are offered to the model deliberately, each described for the model, and never
383
+ with a trust, credential or permission-widening action.
384
+
385
+ - `agent-interface-command` — `ICommand` gains `modelDescription?` (what the model is told, beside the
386
+ short `/help` line), and `modelInvocable` on a subcommand entry now narrows what the model may run.
387
+ - `agent-framework` — `ISystemCommand` gains `modelDescription?` and `modelRequiresPermission?`.
388
+ Once any subcommand of a model-invocable command declares `modelInvocable`, the model may run only
389
+ the bare command and the subcommands declared `true`; everything else, including an alias or an
390
+ undeclared subcommand, is refused before the command runs. The model-facing descriptor lists only
391
+ that subset. A model-requested monitor's command is now decided by the shell tool's gate (its
392
+ Bash/Shell rules, the mode and the prompt) and a refusal rejects with the new
393
+ `MonitorCommandRefusedError`. The `scriptedSession` test harness accepts `permissions` patterns.
394
+ - `agent-session` — `Session.checkToolPermission(toolName, toolArgs)` decides an action that has a
395
+ tool's effect by another route: that tool's PreToolUse hooks, then the gate's rules, mode,
396
+ remembered consent and prompt — never the command sandbox's auto-approval, since the action does
397
+ not run inside the sandbox.
398
+ - `agent-framework` also: `ICommandMCPActivationAdapter.userActionSurface?` tells `/mcp` whether the
399
+ user can type a session command, so the model's status names the terminal sign-in otherwise.
400
+ - `agent-command` — `/context` (bare and `list`), `/cost` (the report, not `budget`) and `/mcp`
401
+ (`status` only, without a prompt) are now model-invocable; `/memory approve` and `/memory reject`
402
+ are now user-only; the model's `/monitor` is decided by the shell gate rather than by consent to
403
+ the command's name. Every model-invocable command carries a model-facing description. The model's
404
+ `/mcp status` shows only safe names, states and the command to suggest, and a caller that does not
405
+ identify itself gets that view. `/context list` accounts only for turns still in context. New
406
+ `mcpUserActionNotice`, `mcpUserActionCommand` and `mcpUnavailableServersNotice` build the fixed
407
+ notices.
408
+ - `agent-command-workflows` — `/workflows` carries a model-facing description.
409
+ - `agent-mcp` — `createDiscoveredTool` accepts `authFailureNotice`: a call the server refuses for
410
+ authentication returns that host text instead of the generic failure.
411
+ - `agent-cli` — an MCP server that did not start because the user must approve it, trust the
412
+ workspace or sign in is named to the model at the start of an interactive session with the
413
+ command to suggest, and a
414
+ signed-in OAuth server that refuses a call tells the model to suggest `/mcp login <server>` — or, in print and serve runs, the terminal
415
+ `robota mcp login <server>`.
416
+
417
+ A command whose bare form is a complete action declares `runsBare`, so choosing `/cost` or `/mcp`
418
+ from the autocomplete menu still runs it even though they now declare subcommands.
419
+ - 9843fe6: Sign in to a remote MCP server from inside a session, and use its tools without restarting.
420
+
421
+ - **`/mcp login <server> [--no-browser]`** runs the same per-server OAuth sign-in as
422
+ `robota mcp login` (discovery checks, PKCE, `state`, RFC 9207 `iss`, RFC 8707 resource, the
423
+ loopback listener, the lock-guarded store). It opens the browser through the argv opener; with
424
+ `--no-browser`, or when no browser can be opened, it shows the authorization URL and asks for the
425
+ redirect URL in the session's own prompt (masked), held to the same rules as a pasted redirect in
426
+ the terminal. A failed, refused, timed-out or cancelled sign-in changes nothing and is reported by
427
+ a fixed reason only. `/mcp login <server> --client-secret` is refused: a secret is never typed into
428
+ a session, and `robota mcp login <server> --client-secret` is named instead (also after a failed
429
+ token exchange for a pre-registered client). `/mcp` stays user-only (`modelInvocable: false`).
430
+ - **Connected in the same session:** after a sign-in, a server that could not connect for want of
431
+ one goes through the normal admission (approval, fingerprint, trust) and connects, and its tools
432
+ are offered from the next message; a server that was already connected is admitted again and
433
+ reconnects, and its authenticator drops what it held and reads the new credential. A tool left out
434
+ because the session already has its name is reported, and only tools actually added get
435
+ provenance. In browser mode the authorization URL is shown in the session prompt before the
436
+ browser opens, where the user can also choose to paste the redirect instead or cancel.
437
+ - **`runMCPOAuthLogin`** takes `readRedirectWhenBrowserFails`: when `openBrowser` rejects, the
438
+ loopback listener stops and the pasted redirect is read instead, for the same redirect URI. The
439
+ loopback listener's time limit now runs from its first `wait()` — once the authorization page is
440
+ handed over — so time spent at a prompt before the browser opens does not count against it.
441
+ - **`Session.addTools`** (and `ICommandSessionTools.addTools`) offers tools that became usable
442
+ mid-session, through the same permission gate and — via `ISessionOptions.wrapAddedTools`, which
443
+ `createSession` sets — the same edit-checkpoint and reversible-execution wraps as the assembled
444
+ tools. A name the session already has is left out, never replaced. Calls are serialized, and tools
445
+ added while a turn runs are applied when the next turn starts, so a turn's rounds all see one
446
+ tool list and the prompt cache misses once, at that boundary.
447
+ - **Breaking (`agent-framework`, major):** `addTools` is a new required member of the
448
+ `ICommandSessionTools` role port (and so of `ICommandSessionRuntime`). A host that implements the
449
+ port itself must add it; one that passes an `agent-session` `Session` already has it.
450
+ - **`ICommandMCPActivationAdapter.oauthLogin`** (`ICommandMCPOAuthLoginRequest`,
451
+ `ICommandMCPOAuthLoginResult`, `ICommandMCPOAuthRedirectPrompt`) is the port behind it.
452
+ - The sign-in notice and `/mcp status` now suggest `/mcp login <server>` in a session and
453
+ `robota mcp login <server>` in a terminal; the server's name is shown only when it is safe to paste
454
+ into any shell, otherwise `<server>`.
455
+ - 7b72344: Every client can offer the session's commands and skills and show its status. The GUI uses them as a
456
+ desktop-style composer.
457
+
458
+ - `agent-interface-session` is **`major` because `IInteractiveSession` gains required members**:
459
+ `ISessionCommands.listSkills()` and a `statusRead` capability, `getStatusSnapshot()`. The snapshot
460
+ holds session, model, permission mode, effort, context and goal. An external implementation stops
461
+ compiling until it adds both.
462
+ - `agent-transport` is **`major` for the same reason on `IProtocolSession`**. It also gains the wire
463
+ messages `get-commands` → `commands` and `get-status` → `session_status`. Both are reads that the
464
+ observe role may send.
465
+ - `agent-interface-command` gains `ICommandSkillListEntry`, moved from `agent-framework`, which
466
+ re-exports it unchanged.
467
+ - `agent-ui-web` is **`major` because its state changes shape**:
468
+ - A command's outcome and a finished turn's tool calls are now conversation entries: `messages` is
469
+ `TConversationEntry[]`.
470
+ - The `uiIntentNotices` list, `dismissUiIntentNotice`, `applyUiIntentEvent`,
471
+ `removeUiIntentNotice` and `IUiIntentNotice` are removed. An intent now answers with an info
472
+ line in the conversation.
473
+ - Session notices keep only `session-error` and `protocol-error`.
474
+ - The state gains `commandCatalog` and `sessionStatus`.
475
+ - `agent-command` registers `/theme` and `/keybindings` even without a terminal. They then answer
476
+ that they belong to the configured CLI terminal, instead of being unknown.
477
+ - `agent-framework`:
478
+ - `InteractiveSession.getStatusSnapshot()`.
479
+ - The main-thread row previews the last chat message instead of the last record's type.
480
+ - `agent-cli` serves the full GUI web app, renamed from `agent-cli-web` to `agent-gui-web`, on
481
+ `robota --serve --open`.
482
+ - 9721162: The command catalog says who runs a command, and which surfaces can run it.
483
+
484
+ - **`agent-interface-command` (major).**
485
+ - Adds `TCommandRunner` (`'runtime' | 'client'`) and `TCommandSurface` (`'terminal' | 'gui'`).
486
+ - `ICommand` gains optional `runner` and `surfaces`.
487
+ - `ICommandListEntry` gains optional `surfaces` and a **required** `runner`. An implementation of `listCommands()`, or any code that constructs an `ICommandListEntry`, must now emit `runner`; a command that declares none gets `'runtime'`.
488
+ - **`agent-framework` (minor).**
489
+ - `ISystemCommand` gains optional `runner` and `surfaces`, and the command listing carries both.
490
+ - An undeclared runner resolves to `'runtime'`.
491
+ - `SessionTerminalHandoffGate` is exported for a terminal client that hands its own terminal to a command.
492
+ - **`agent-command` (minor).**
493
+ - `/shell`, `/editor`, `/theme` and `/keybindings` declare `runner: 'client'` and `surfaces: ['terminal']`.
494
+ - `createTerminalClientCommands()` builds the same four commands, from the same execute functions, for a terminal client to run itself. The set follows the preset's module selection.
495
+ - **`agent-ui-web` (minor).** The `/` menu marks a command that runs in the terminal with a "terminal" badge.
496
+ - 5bb675a: Provider commands check a profile's `$ENV:` or default credential against the host's environment snapshot, so `/provider switch`, `/provider test`, `/provider add`, `/provider edit` and a cross-profile `/model` keep working while the runtime withholds its own credentials from `process.env`.
497
+
498
+ - `IProviderCommandModuleOptions` takes an optional `env`, and `createDefaultCommandModules` takes `providerEnvironment`. The CLI passes its startup snapshot.
499
+ - The git that isolated subagents run, and so the repository's hooks, now get the command environment instead of the full snapshot.
500
+ - 2d3b2c0: ARCH-024 replaces framework knowledge of command-owner ids with optional, owner-declared semantic
501
+ roles. `ISystemCommand` can declare `skillActivation`, `contextReduction`, or `subagentSpawn`;
502
+ `SystemCommandExecutor` exposes the selected role projection and rejects duplicate owners with the
503
+ typed `DuplicateSystemCommandSemanticRoleError`, atomically across construction, registration, and
504
+ replacement.
505
+
506
+ This is a beta-line breaking contract correction: unannotated commands named `skills`, `compact`, or
507
+ `agent` no longer receive special framework behavior. `@robota-sdk/agent-command` now declares the
508
+ roles on its shipped skills, compact, and agent commands.
509
+ - 1e3f91a: CMD-004 Phase 2 Stage E (breaking, beta line): the legacy `TCommandEffect` union and
510
+ `ICommandResult.effects` are DELETED. Commands emit the split contract directly —
511
+ `hostActions` (session-executed via `ICommandHostAdapters`; works headless and remote) and
512
+ `uiIntents` (requester-routed `ui_intent` session events with UI-neutral `show-*` names).
513
+ Final carriers for the former notification effects: `session_renamed` and the new
514
+ `history_cleared` are BROADCAST session events (forwarded to every WS surface, folded by the
515
+ TUI transcript/title and the GUI reducer's new `sessionName`/transcript-reset state);
516
+ `session-execution-started` rides `result.data.sessionExecution`; the plugin-registry refresh
517
+ rides `result.data.pluginRegistryReloaded`. A mechanical grep floor
518
+ (`command-effect-grep-floor.test.ts`) keeps `tui-requested`/`TCommandEffect`/`effects:` out of
519
+ every `packages/*/src` production tree.
520
+ - 44393be: Add the `/remote-control` enable path (REMOTE-008 Stage B4-2b) — turn on P2P remote control locally, get
521
+ a QR + link, and a paired device co-drives the SAME live session over pairing-gated WebRTC. The command
522
+ is a declarative trigger returning `remote-control-enable-requested`/`-stop-requested` effects (SSOT
523
+ agent-interface-transport) and reads state via a new `ICommandHostAdapters.remoteControl.getStatus()`;
524
+ the TUI dispatches the effects to injected callbacks; all transport construction lives at the agent-cli
525
+ composition root (`WsSignalingClient` + pairing-gated `WebRtcTransport`, relay URL from
526
+ `transports.webrtc.options.relayUrl`, QR/link rendered into history). Fail-closed: no relay configured ⇒
527
+ does nothing; pairing mismatch/timeout ⇒ the session is never exposed. Consumes REMOTE-007 so a paired
528
+ remote owner answers their own permission/ask prompts over the WebRTC channel.
529
+ - cbee54e: Surface unmatched preset command-module names instead of silently dropping them (INFRA-032). A preset `enabledCommandModules`/`disabledCommandModules` entry that matches no built command module — a short form like `"editor"` instead of `agent-command-editor`, or a typo — is now reported as a non-fatal notice on both the startup `--preset` path (CLI terminal) and the in-session `/preset` path (command result). Detection lives once in agent-framework's new pure `findUnknownModuleNames`, and agent-command's duplicate module filter now delegates to the framework's `selectCommandModules`; `createDefaultCommandModules` returns `{ modules, unknownModuleNames }`.
530
+
531
+ ### Patch Changes
532
+
533
+ - b462ee7: Discriminate `IBackgroundTaskState` by kind, the same way `TBackgroundTaskRequest` and (as of the
534
+ prior change) `TBackgroundTaskResult` already are. Fields only one runner ever produces now live
535
+ only on that kind's member instead of being optional-and-cross-kind-reachable on every kind:
536
+
537
+ - `agent`-only: `agentType`, `isolation`, `resumeSessionId`, `promptPreview`, and the
538
+ worktree-isolation fields (`worktreePath`, `branchName`, `worktreeStatus`, `worktreeNextAction`,
539
+ `worktreeBaseRevision`, `parentWorktreeStatus`).
540
+ - `scheduled`-only: `schedule`, `nextFireAt`.
541
+ - Every kind except `agent`: `commandPreview` (a process command, an MCP tool-invocation summary, or
542
+ a schedule's shell command / wake instruction).
543
+ - `state.result` is now `IBackgroundTaskResult<K>` — correlated with `state.kind`, not the free
544
+ full-result union.
545
+
546
+ `pid`, `logPath`, and `transcriptPath` stay on the shared base rather than becoming agent- or
547
+ process-exclusive: the runner handle SPI already reports them for whichever runner's process
548
+ happens to produce them, and a subagent run via the worktree/child-process runner carries a `pid`
549
+ exactly as a `process`-kind task does. `timeoutReason` also stays base — session restore sets
550
+ `'stale_worker'` on any non-terminal, non-rearmable task regardless of kind, not only agent ones.
551
+
552
+ `IBackgroundTaskState<K>` narrows to the kind-specific member; called with no type argument it is
553
+ still the full union. The session-record decoder (`agent-session`) now rejects a persisted task
554
+ state carrying a field outside its own kind as corrupt, reported at that field's own path, the same
555
+ way it already rejects a `state.result` whose kind disagrees with `state.kind`.
556
+
557
+ **Breaking for `@robota-sdk/agent-interface-execution` and `@robota-sdk/agent-executor`**: code that
558
+ read a kind-specific field (e.g. `state.agentType`, `state.schedule`, `state.commandPreview`) off an
559
+ unnarrowed `IBackgroundTaskState` needs to narrow on `state.kind` first, since the fallback default
560
+ no longer carries every field on every kind. `agent-session`, `agent-framework`, and `agent-command`
561
+ land the corresponding narrowing at every read site the type change touched; no runtime behavior
562
+ changes there beyond the state decoder's new corruption checks.
563
+ - 4241fc5: Device mesh follow-ups.
564
+
565
+ - A device with no identity is pointed to `/devices add` on one of the user's devices and `/devices join`
566
+ here, as well as to `/devices init`. The message says that `init` is for the first device only,
567
+ because it creates a separate identity that can never link to the user's other devices. The `/devices`
568
+ description and the `init` subcommand say the same.
569
+ - An identity created mid-session (`/devices init`, or a successful `/devices join`) opens the mesh
570
+ without a restart when `transports.mesh.enabled` is on.
571
+ - If a session stalls for longer than the mesh lock's stale window (for example while the machine
572
+ sleeps), another session can take the mesh over. The stalled session now notices this on its next
573
+ lock refresh, closes its own mesh, and says why. Two sessions no longer run it together.
574
+ `holdExclusiveFileLock` has a new `onLost` option for this.
575
+ - `/peers` and `/handoff` still list and reach linked mesh devices when local same-host peer discovery
576
+ fails. `/peers` says why sessions on this host are not listed. `ICommandLocalPeersAdapter` has a new
577
+ optional `localDiscoveryOff` field for this.
578
+ - `agent-transport-webrtc`: when lists become newer on a node (reissued, revoked, or adopted from a
579
+ peer), the node sends them over every admitted connection instead of waiting for the next handshake.
580
+ Reissues, revocations and enrolments in the CLI take effect this way at once. A receiver adopts a
581
+ pushed list only if it is newer, issued by this user's signing key, and verifies. The push does not
582
+ depend on the peer's capabilities, and it never reaches the application's message handlers.
583
+ - ec5e477: Add a credential store port (`ICredentialStore` in `agent-core`) and keep the CLI's secrets behind it: the OS keychain through the optional `@napi-rs/keyring` binding (macOS Keychain, Windows Credential Manager, Linux Secret Service), else an owner-only file under `the configured user data directory`. The backend is chosen at first use, recorded, and named by `/remote-control status`; a recorded keychain that stops working fails closed instead of degrading to the file.
584
+
585
+ The remote-control host identity key moves into the store. The old `the configured user data directory` may have been copied by backups or dotfile sync, so it is not carried over: on the first run after upgrading a new host key is generated, the old file is removed, and the operator is told once that trusted devices must pair again.
586
+ - e15e22b: Two of one user's devices can connect to each other over WebRTC, admitted by the device handshake.
587
+
588
+ - `agent-transport-webrtc` — `DeviceMeshNode` keeps one connection per device pair, in either role: the
589
+ device with the lower id offers and the other answers, so concurrent attempts resolve by rule. Both
590
+ roles bind the handshake to the certificate the DTLS layer verified and take one remote description
591
+ with exactly one fingerprint; before admission only handshake frames cross, and a connection counts
592
+ as admitted only once both sides admitted each other. Each connection gets its own DTLS certificate
593
+ (`createDtlsKeys`). A new attempt never displaces an admitted connection until it is admitted
594
+ itself, and attempts per pair are paced. Lists adopted in a handshake, or handed over through
595
+ `refresh`, apply at once, and a device they revoke loses its connection. Signaling runs through
596
+ `IMeshRelay`: `WsMeshRelayClient` for the self-hosted relay's `presence` / `message` frames
597
+ (topics capped per source and relay-wide), `createInMemoryMeshRelayHub` for tests.
598
+ - `agent-remote-pairing` — the pair's two relay inbox topics, one per direction, come from their
599
+ pairwise secret (`derivePairRendezvous(...).relayInbox()`).
600
+ - `agent-cli` — a device holding the signing key reissues its roster and revocation list before they
601
+ expire while an interactive session runs. The host can open this device's mesh endpoint from the
602
+ identity under `the configured user data directory`, saving newer lists a peer hands over; no command starts it yet.
603
+ - `agent-command` — `/devices add|join` still reports that enrolment is not available yet.
604
+ - 007fd90: Authority per connection: pairing stays with the local operator, and driving needs the operator's yes.
605
+
606
+ - `agent-interface-session-mobility` — `ConnectionAuthority` decides what one connection may do.
607
+ `presence` and `message` are allowed; `delegate` and `handoff` ask the receiving operator for every
608
+ request; `observe` and `drive` ask once per connection. With no `IOperatorApprover` the answer is
609
+ no. `authorizeDelegation` turns an approved task into a peer turn from where admission placed the
610
+ peer, ignoring anything else on the request, so the receiver's policy decides what it may do.
611
+ - `agent-transport-webrtc` — `connectionApproval` asks the operator before a connection reaches the
612
+ session, after every proof has run. Frames the peer sends meanwhile are held (bounded) and delivered
613
+ only after a yes. A channel that closes first withdraws the question (the approval context carries
614
+ an `AbortSignal`), and a later answer admits nothing. A first-pairing device is pinned for
615
+ reconnect only once it is admitted.
616
+ - `agent-command` — `/remote-control enable` and `revoke` from a connected surface are refused, and
617
+ `status` never shows a connected surface the pairing link.
618
+ - `agent-framework` — the `remote-control-enable` host action runs only for the operator's own
619
+ command, whichever command asked for it.
620
+ - `agent-cli` — every remote-control connection, a returning trusted device included, is put to the
621
+ operator on the host terminal; without an interactive terminal it is refused.
622
+ - 57280bf: Every published package now declares `"engines": { "node": ">=22.12.0" }`. Before, 27 of the 38
623
+ packages declared no floor (`agent-core`, `agent-tools` and every provider among them),
624
+ `agent-session` and `agent-file-authority` declared `>=20.19.0`, and the other nine declared
625
+ `>=22.0.0`, so a consumer on Node 20 saw at most a warning from a transitive dependency.
626
+
627
+ Why 22.12: `agent-cli` and `agent-ui-terminal` need Node 22 through `ink` 7, and the CommonJS entries
628
+ of `agent-tools` and its dependents, `agent-transport`/`node` and its dependents, and
629
+ `agent-ui-terminal` `require()` ESM-only dependencies (`p-limit`, `jose`, `chalk`), which Node 22
630
+ supports unflagged only from 22.12. `engines` is advisory unless the consumer enables `engine-strict`.
631
+
632
+ No code changes: `tsdown` now reads `node22.12.0` as its build target from the field.
633
+ - 18c0d5c: Every published package now exports `./package.json`, so `require('<package>/package.json')` and
634
+ `import('<package>/package.json', { with: { type: 'json' } })` work instead of failing with
635
+ `ERR_PACKAGE_PATH_NOT_EXPORTED`, and each tarball now ships the package's `CHANGELOG.md`.
636
+ - caaab20: `/rewind` works again. Every session the CLI builds for a trusted workspace captures edit
637
+ checkpoints; before, none did, and `/rewind` failed everywhere with "Edit checkpoints require
638
+ project authority."
639
+
640
+ - `agent-cli` (patch): a trusted workspace composes an edit checkpoint store for the terminal UI, a
641
+ print run, a served runtime and each session a daemon keeps live. Every session gets its own
642
+ store, pooled or switched to in the terminal UI, since two can run turns at the same time. On a host that cannot prove a project write
643
+ stays inside the project (every platform but Linux), none is composed: a checkpoint could be
644
+ neither saved nor restored there.
645
+ - `agent-command` (patch): where a session has no checkpoints, `/rewind` says why: a restricted
646
+ workspace is told to run `robota trust --yes` and restart the configured CLI, and a host that cannot write
647
+ the project safely says so. `/rewind list` reports this as a failed command instead of throwing.
648
+ - `agent-framework` (minor): a checkpoint operation on a session without a store throws
649
+ `EditCheckpointsUnavailableError`, whose `reason` is `host-cannot-write-project`,
650
+ `restricted-workspace` or `no-checkpoint-store`. It is a `WorkspaceAuthorityRequiredError`, as
651
+ before, named `EditCheckpointsUnavailableError`. `HeadlessInteractionChannel` takes an
652
+ `editCheckpointStore` option.
653
+ - `agent-ui-terminal` (minor): `renderApp` takes `createEditCheckpointStore` in place of
654
+ `editCheckpointStore`, and builds each session its own store, since a session switch can build the
655
+ next session before the old one's turn ends. `TuiInteractionChannel` keeps `editCheckpointStore`:
656
+ a channel runs one session.
657
+ - 3c1967f: Reloading plugins updates the live session's skill routing and model skill catalogue together
658
+ with command completion. Disabled plugins stop being executable after reload, and unreadable
659
+ settings clear the plugin skill snapshot. Hook changes require a new session.
660
+ - db35dcd: MCP approvals now outlive the process, and an approval takes effect at once. The configured CLI keeps
661
+ activation decisions in `the configured user data directory` (owner-only) unless the host passes its own
662
+ `mcpApprovalStore`, so an approved server connects at later starts until its definition changes.
663
+ `/mcp approve <server>` now also connects the server in the running session, the way `/mcp reload`
664
+ does, instead of waiting for a restart. A remote server without OAuth therefore connects once
665
+ approved; stdio servers still need a host-supplied authority.
666
+ - 4cee6fb: Report unsupported MCP transports at startup and reload instead of silently skipping them,
667
+ and distinguish plugin MCP declaration inspection from a runtime connection.
668
+ - 043fd27: In `plan` mode the model can no longer save project memory with `/memory add`. The command is auto-approved, so it ran in plan mode while `Write` and `Edit` were denied there. Reading memory, and adding it by hand, still work in plan mode.
669
+ - 6ee8725: A user settings file that does not parse no longer reads as "no plugin is disabled". Plugin settings
670
+ now refuse to read it: no plugin loads (skills, commands, hooks and themes alike), a plugin command
671
+ such as `/plugin enable` fails instead of rewriting the whole settings file with the plugin keys
672
+ alone, and `robota doctor` reports the plugin check as failed while still inspecting each installed
673
+ plugin. The CLI already refuses to start with such a file; this covers a session started later in
674
+ the same process.
675
+ - e8d70ac: A first run finds a provider, instead of a dead end. `robota --serve` (and the daemon it starts) no
676
+ longer refuses when no provider is configured: it starts in setup mode, and the GUI's conversation area
677
+ shows a "Connect a model provider to start" panel with a "Set up provider" button in place of the
678
+ composer. Answering it configures and swaps in the first provider live, with no restart. A startup
679
+ failure now says why — `robota daemon start --json` and the desktop app's fatal screen report the
680
+ child's own reason instead of a generic "readiness channel closed", and the fatal screen gets a Try
681
+ again button. `trust status --json` and the desktop trust dialog list only sources whose state trust
682
+ would actually change, instead of naming one this platform could not determine; the dialog shows one
683
+ sentence and a collapsed Details section. `robota --serve --open` in an untrusted folder now asks at
684
+ the terminal (trust it, start Restricted, or quit) when someone is there to ask, instead of refusing
685
+ outright.
686
+ - 2c612ba: Release the migrated Robota product with its public SDK namespace, robota command, compatible SDK exports, internal product configuration, and verified CLI startup and delivery corrections.
687
+ - 7116367: Credentials the runtime holds for itself no longer reach the commands it runs.
688
+
689
+ - `agent-cli` — once a workspace's settings are admitted, every variable a provider profile or
690
+ definition names as its credential (`$ENV:` references, and defaults such as `OPENAI_API_KEY`)
691
+ leaves the process environment, so tools, hooks, background shells, a skill's `!` commands and
692
+ the environment an MCP header helper inherits no longer carry it, a hosted worker's broker token
693
+ included (a variable an MCP definition references explicitly still resolves); the provider keeps
694
+ authenticating from the startup snapshot. A user or managed settings layer can let
695
+ commands see one with `"commandEnvAllow": ["NAME"]`; project settings cannot. With the OS sandbox
696
+ on, confined commands can no longer read `settings.json`, `credentials/`, `mcp-credentials/` or
697
+ `remote-host-identity.json` under the user state directory. **Behavior change:** a command that
698
+ relied on inheriting a provider key now needs the opt-in, and a host embedding `startCli` finds
699
+ those variables gone from its own `process.env` afterwards — a later in-process call must pass them
700
+ in its `environment`.
701
+ - `agent-framework` — the settings schema gains `commandEnvAllow`; `checkSettingsDocument` and
702
+ `buildProviderProfilesSnapshot` take an optional environment map to resolve `$ENV:` references
703
+ against instead of the live process environment.
704
+ - `agent-command` — provider startup checks credentials against the host's environment snapshot.
705
+ - `agent-tools` — `OsSandboxClient` takes `hiddenPaths`, always hidden from confined commands and
706
+ not changeable by sandbox settings.
707
+ - `agent-subagent-runner` — a child-process subagent removes its provider credential variable from
708
+ its own environment once its provider is built, unless the start payload says the owner opted it in
709
+ (`keepProviderCredential`).
710
+ - `dag-node-instant-node` — prompt nodes accept an env resolver (`createPromptBackedNodeDefinition`'s
711
+ third argument, `rehydrateInstantNode`'s `resolveEnv`) for their `$ENV:` credential default.
712
+ - `agent-command-workflows` — `/workflows create` and `/workflows run` resolve prompt-node credentials
713
+ from the host's environment snapshot.
714
+ - 7d9cc66: Keep host-declared inline human controls reachable during active turns. Plugin disable and uninstall can withdraw future dispatch without changing model invocation or host command policy.
715
+ - 3a8876b: ARCH-029: decompose the command host into role ports
716
+
717
+ `ICommandHostContext`, `ICommandSessionRuntime` and `IAgentJobHostContext` are now empty `extends`
718
+ aggregates over 26 named role ports, so a command declares only the capability it uses. A role port
719
+ is a supertype of the aggregate, so narrowing a declared parameter still satisfies
720
+ `ISystemCommand.execute` by contravariance.
721
+
722
+ All 79 members are preserved (46 + 18 + 15) with the declaration kind unchanged, so implementors and
723
+ callers stay source-compatible.
724
+
725
+ **Breaking:** every role-port member is now required except the adapter bag, whose contents are
726
+ genuinely variational. 38 members went from optional to required. A host that previously omitted a
727
+ member must now provide one — including `validateCurrentSessionReplayLog`, which was an override
728
+ with a framework-computed default and no implementor. `createTestCommandHost`,
729
+ `createTestAgentJobHost` and `createTestSessionRuntime` are published from
730
+ `@robota-sdk/agent-framework/testing` as conformant, cast-free doubles for exactly this.
731
+
732
+ Also removed: the `clearConversationHistory` fallback that reached past the host into
733
+ `getSession().clearHistory()`. Those were never the same operation — the host path also broadcasts
734
+ `history_cleared` to every attached surface, so a fallback clear left other surfaces still showing
735
+ the transcript.
736
+ - 7d9cc66: Allow authenticated attached users to correct and forget project memory while preserving host remote-command policy and rejecting model curation.
737
+ - b330269: Align command test fixtures with the core run-loop state contract.
738
+ - 4f3c075: Assemble complete, verified package generations before switching build output; preserve the previous generation on build failure and pack only verified regular-file images. Include copied CLI web assets in affected-build ordering and artifact transfer. Preserve the CLI version in managed build paths. Public runtime contracts remain compatible (patch).
739
+ - 7d9cc66: Add user-only project memory topic correction and forgetting, prevent automatic restoration after restart, refresh retained startup context, and reconcile semantic recall with current durable source content.
740
+ - df02568: Local OpenAI-compatible servers can be set up without saving a placeholder API key. Explicit credentials and environment references remain effective for authenticated servers and connection tests. Optional credentials are managed through the user-only provider edit command.
741
+ - 7d9cc66: Add explicit MCP Skills selection, bounded supervisor access and persistent host content consent.
742
+ Users can inspect verified instructions, approve the exact content fingerprint and withdraw consent;
743
+ models can discover metadata only. Consent stays separate from server admission and model-turn activation.
744
+ - 7d9cc66: Route discovered MCP Skills through the shared skill command runtime with lazy verified content, source-bound invocation names, current user consent and execution-owned activation cleanup. Keep remote shell expressions inert and defer queued user skill reads until their own turn executes.
745
+ - dfb9b15: Release the integrated provider credential isolation and consumer runtime and interaction composition updates.
746
+ - d6b9404: Remove polynomial-ReDoS backtracking (SEC-003, CodeQL `js/polynomial-redos`) from three parsers whose input is not repo-controlled.
747
+
748
+ `parseStructuredResponseText` (agent-core) parses raw model output; its fenced-code-block regex used `\s*\n`, and because `\s` also matches a newline the two overlapped, so an unterminated fence containing many blank lines was rejected in O(n^2) — 12.7s for a 400 KB string, now ~1ms. The whitespace run is now restricted to horizontal whitespace, which makes the newline split point unique.
749
+
750
+ `/schedule cron` and `/monitor` (agent-command) are declared `modelInvocable: true`, so their argument string is composed by the model. Both matched the trailing instruction with `\s+(.+)$`; since `.` also matches a space the split point was ambiguous and a non-matching argument cost O(n^2) — ~15s for a 200 KB argument, now <1ms. The instruction is now required to start with a non-space character, which pins the split point without changing which inputs are accepted.
751
+
752
+ No behaviour change: the set of accepted inputs and the parsed values are identical in every case.
753
+ - 7d9cc66: Expose verified skill supporting resources only within their owning turn or fork, using the current host consent and manifest.
754
+ - 02053ec: Leave unregistered DeepSeek model costs unknown instead of applying unrelated legacy model prices.
755
+ - Updated dependencies [9c19c50]
756
+ - Updated dependencies [7b6234c]
757
+ - Updated dependencies [5307f8a]
758
+ - Updated dependencies [b462ee7]
759
+ - Updated dependencies [08a9bd6]
760
+ - Updated dependencies [37b4bd7]
761
+ - Updated dependencies [818f0c8]
762
+ - Updated dependencies [4eea54b]
763
+ - Updated dependencies [3c81769]
764
+ - Updated dependencies [724fabb]
765
+ - Updated dependencies [997f2fb]
766
+ - Updated dependencies [bfe8ed5]
767
+ - Updated dependencies [1698be4]
768
+ - Updated dependencies [9368d00]
769
+ - Updated dependencies [d4189b9]
770
+ - Updated dependencies [9edae52]
771
+ - Updated dependencies [4078a72]
772
+ - Updated dependencies [4c73a0b]
773
+ - Updated dependencies [af2f2ad]
774
+ - Updated dependencies [267af5f]
775
+ - Updated dependencies [196a900]
776
+ - Updated dependencies [f336838]
777
+ - Updated dependencies [34e50f0]
778
+ - Updated dependencies [722e88a]
779
+ - Updated dependencies [a5cc36e]
780
+ - Updated dependencies [d23c848]
781
+ - Updated dependencies [b70fa3d]
782
+ - Updated dependencies [2711ec6]
783
+ - Updated dependencies [3038eb7]
784
+ - Updated dependencies [02b7452]
785
+ - Updated dependencies [4dd45cc]
786
+ - Updated dependencies [e689c8e]
787
+ - Updated dependencies [4241fc5]
788
+ - Updated dependencies [ec5e477]
789
+ - Updated dependencies [4f49d14]
790
+ - Updated dependencies [007fd90]
791
+ - Updated dependencies [c7f9203]
792
+ - Updated dependencies [18b52cc]
793
+ - Updated dependencies [9843fe6]
794
+ - Updated dependencies [7b72344]
795
+ - Updated dependencies [6ae3f28]
796
+ - Updated dependencies [9721162]
797
+ - Updated dependencies [be0e53c]
798
+ - Updated dependencies [57f57f5]
799
+ - Updated dependencies [ba822c1]
800
+ - Updated dependencies [9721162]
801
+ - Updated dependencies [6e6b06b]
802
+ - Updated dependencies [7d77ce4]
803
+ - Updated dependencies [8bd5fac]
804
+ - Updated dependencies [57280bf]
805
+ - Updated dependencies [5033dd9]
806
+ - Updated dependencies [18c0d5c]
807
+ - Updated dependencies [dbd888d]
808
+ - Updated dependencies [1887e54]
809
+ - Updated dependencies [caaab20]
810
+ - Updated dependencies [f01868f]
811
+ - Updated dependencies [e8779c9]
812
+ - Updated dependencies [5a0ee96]
813
+ - Updated dependencies [9f46375]
814
+ - Updated dependencies [4e11579]
815
+ - Updated dependencies [41cca13]
816
+ - Updated dependencies [193a0bc]
817
+ - Updated dependencies [54e2848]
818
+ - Updated dependencies [3c1967f]
819
+ - Updated dependencies [ada3841]
820
+ - Updated dependencies [5093a30]
821
+ - Updated dependencies [5684612]
822
+ - Updated dependencies [6ee8725]
823
+ - Updated dependencies [6072e9a]
824
+ - Updated dependencies [94b2c87]
825
+ - Updated dependencies [3ab2eca]
826
+ - Updated dependencies [2e07cad]
827
+ - Updated dependencies [e8d70ac]
828
+ - Updated dependencies [2c612ba]
829
+ - Updated dependencies [66af868]
830
+ - Updated dependencies [e079992]
831
+ - Updated dependencies [7116367]
832
+ - Updated dependencies [5bb675a]
833
+ - Updated dependencies [e706b43]
834
+ - Updated dependencies [60f3965]
835
+ - Updated dependencies [115e104]
836
+ - Updated dependencies [04719a9]
837
+ - Updated dependencies [04a6de4]
838
+ - Updated dependencies [0ba247b]
839
+ - Updated dependencies [6f41c53]
840
+ - Updated dependencies [7d9cc66]
841
+ - Updated dependencies [378c585]
842
+ - Updated dependencies [4c5148e]
843
+ - Updated dependencies [37af5dc]
844
+ - Updated dependencies [807d161]
845
+ - Updated dependencies [fec722f]
846
+ - Updated dependencies [e82215f]
847
+ - Updated dependencies [52b7346]
848
+ - Updated dependencies [2ebff01]
849
+ - Updated dependencies [2ebff01]
850
+ - Updated dependencies [2d3b2c0]
851
+ - Updated dependencies [b078afa]
852
+ - Updated dependencies [2d3b2c0]
853
+ - Updated dependencies [baa6863]
854
+ - Updated dependencies [2d3b2c0]
855
+ - Updated dependencies [3a8876b]
856
+ - Updated dependencies [4772067]
857
+ - Updated dependencies [7b85767]
858
+ - Updated dependencies [0f98419]
859
+ - Updated dependencies [64ba748]
860
+ - Updated dependencies [9fbab1b]
861
+ - Updated dependencies [d312755]
862
+ - Updated dependencies [a009f5b]
863
+ - Updated dependencies [c207a31]
864
+ - Updated dependencies [9b4f63b]
865
+ - Updated dependencies [1e3f91a]
866
+ - Updated dependencies [4f3c075]
867
+ - Updated dependencies [7d9cc66]
868
+ - Updated dependencies [475e085]
869
+ - Updated dependencies [e477440]
870
+ - Updated dependencies [9dcb5da]
871
+ - Updated dependencies [a95ca85]
872
+ - Updated dependencies [b6d14ce]
873
+ - Updated dependencies [0382a51]
874
+ - Updated dependencies [93d061d]
875
+ - Updated dependencies [39554a1]
876
+ - Updated dependencies [d28430a]
877
+ - Updated dependencies [bed26ea]
878
+ - Updated dependencies [7d9cc66]
879
+ - Updated dependencies [fe48835]
880
+ - Updated dependencies [7d9cc66]
881
+ - Updated dependencies [1e40b5b]
882
+ - Updated dependencies [bad976f]
883
+ - Updated dependencies [7d9cc66]
884
+ - Updated dependencies [7d9cc66]
885
+ - Updated dependencies [7d9cc66]
886
+ - Updated dependencies [7d9cc66]
887
+ - Updated dependencies [7d9cc66]
888
+ - Updated dependencies [7d9cc66]
889
+ - Updated dependencies [df02568]
890
+ - Updated dependencies [7d9cc66]
891
+ - Updated dependencies [7d9cc66]
892
+ - Updated dependencies [4b76cfa]
893
+ - Updated dependencies [d9bd9ec]
894
+ - Updated dependencies [8865acf]
895
+ - Updated dependencies [90e7a10]
896
+ - Updated dependencies [fcb0da3]
897
+ - Updated dependencies [07b627f]
898
+ - Updated dependencies [d0de5b2]
899
+ - Updated dependencies [9c6a8db]
900
+ - Updated dependencies [dfb9b15]
901
+ - Updated dependencies [9665c6e]
902
+ - Updated dependencies [44393be]
903
+ - Updated dependencies [c7fa299]
904
+ - Updated dependencies [7d9cc66]
905
+ - Updated dependencies [7d9cc66]
906
+ - Updated dependencies [7d9cc66]
907
+ - Updated dependencies [5134b3b]
908
+ - Updated dependencies [dd444c1]
909
+ - Updated dependencies [1f57e7f]
910
+ - Updated dependencies [7911a7d]
911
+ - Updated dependencies [833afe1]
912
+ - Updated dependencies [d6b9404]
913
+ - Updated dependencies [7863b16]
914
+ - Updated dependencies [fde558e]
915
+ - Updated dependencies [db5c439]
916
+ - Updated dependencies [7d9cc66]
917
+ - Updated dependencies [62663ae]
918
+ - Updated dependencies [4a01a87]
919
+ - Updated dependencies [9c6a8db]
920
+ - Updated dependencies [cbee54e]
921
+ - Updated dependencies [23a30cd]
922
+ - Updated dependencies [7d9cc66]
923
+ - Updated dependencies [7d9cc66]
924
+ - Updated dependencies [9814afc]
925
+ - Updated dependencies [7d9cc66]
926
+ - Updated dependencies [02053ec]
927
+ - Updated dependencies [242a644]
928
+ - Updated dependencies [9c6a8db]
929
+ - @robota-sdk/agent-interface-execution@3.0.0
930
+ - @robota-sdk/agent-interface-command@3.0.0
931
+ - @robota-sdk/agent-framework@3.0.0
932
+ - @robota-sdk/agent-core@3.0.0
933
+ - @robota-sdk/agent-interface-session@3.0.0
934
+ - @robota-sdk/agent-preset@3.0.0
935
+
936
+ ## 3.0.0-beta.106
937
+ ### Patch Changes
938
+
939
+ - @robota-sdk/agent-core@3.0.0-beta.106
940
+ - @robota-sdk/agent-framework@3.0.0-beta.106
941
+ - @robota-sdk/agent-interface-command@3.0.0-beta.106
942
+ - @robota-sdk/agent-interface-execution@3.0.0-beta.106
943
+ - @robota-sdk/agent-interface-session@3.0.0-beta.106
944
+ - @robota-sdk/agent-preset@3.0.0-beta.106
945
+
946
+ ## 3.0.0-beta.105
947
+ ### Patch Changes
948
+
949
+ - @robota-sdk/agent-core@3.0.0-beta.105
950
+ - @robota-sdk/agent-framework@3.0.0-beta.105
951
+ - @robota-sdk/agent-interface-command@3.0.0-beta.105
952
+ - @robota-sdk/agent-interface-execution@3.0.0-beta.105
953
+ - @robota-sdk/agent-interface-session@3.0.0-beta.105
954
+ - @robota-sdk/agent-preset@3.0.0-beta.105
955
+
956
+ ## 3.0.0-beta.104
957
+ ### Patch Changes
958
+
959
+ - @robota-sdk/agent-core@3.0.0-beta.104
960
+ - @robota-sdk/agent-framework@3.0.0-beta.104
961
+ - @robota-sdk/agent-interface-command@3.0.0-beta.104
962
+ - @robota-sdk/agent-interface-execution@3.0.0-beta.104
963
+ - @robota-sdk/agent-interface-session@3.0.0-beta.104
964
+ - @robota-sdk/agent-preset@3.0.0-beta.104
965
+
966
+ ## 3.0.0-beta.103
967
+ ### Patch Changes
968
+
969
+ - Updated dependencies [6f41c53]
970
+ - @robota-sdk/agent-core@3.0.0-beta.103
971
+ - @robota-sdk/agent-framework@3.0.0-beta.103
972
+ - @robota-sdk/agent-interface-command@3.0.0-beta.103
973
+ - @robota-sdk/agent-interface-execution@3.0.0-beta.103
974
+ - @robota-sdk/agent-interface-session@3.0.0-beta.103
975
+ - @robota-sdk/agent-preset@3.0.0-beta.103
976
+
977
+ ## 3.0.0-beta.102
978
+ ### Patch Changes
979
+
980
+ - @robota-sdk/agent-core@3.0.0-beta.102
981
+ - @robota-sdk/agent-framework@3.0.0-beta.102
982
+ - @robota-sdk/agent-interface-command@3.0.0-beta.102
983
+ - @robota-sdk/agent-interface-execution@3.0.0-beta.102
984
+ - @robota-sdk/agent-interface-session@3.0.0-beta.102
985
+ - @robota-sdk/agent-preset@3.0.0-beta.102
986
+
987
+ ## 3.0.0-beta.101
988
+ ### Patch Changes
989
+
990
+ - Updated dependencies [62663ae]
991
+ - @robota-sdk/agent-core@3.0.0-beta.101
992
+ - @robota-sdk/agent-framework@3.0.0-beta.101
993
+ - @robota-sdk/agent-interface-command@3.0.0-beta.101
994
+ - @robota-sdk/agent-interface-execution@3.0.0-beta.101
995
+ - @robota-sdk/agent-interface-session@3.0.0-beta.101
996
+ - @robota-sdk/agent-preset@3.0.0-beta.101
997
+
998
+ ## 3.0.0-beta.100
999
+ ### Patch Changes
1000
+
1001
+ - @robota-sdk/agent-core@3.0.0-beta.100
1002
+ - @robota-sdk/agent-framework@3.0.0-beta.100
1003
+ - @robota-sdk/agent-interface-command@3.0.0-beta.100
1004
+ - @robota-sdk/agent-interface-execution@3.0.0-beta.100
1005
+ - @robota-sdk/agent-interface-session@3.0.0-beta.100
1006
+ - @robota-sdk/agent-preset@3.0.0-beta.100
1007
+
1008
+ ## 3.0.0-beta.99
1009
+ ### Patch Changes
1010
+
1011
+ - @robota-sdk/agent-core@3.0.0-beta.99
1012
+ - @robota-sdk/agent-framework@3.0.0-beta.99
1013
+ - @robota-sdk/agent-interface-command@3.0.0-beta.99
1014
+ - @robota-sdk/agent-interface-execution@3.0.0-beta.99
1015
+ - @robota-sdk/agent-interface-session@3.0.0-beta.99
1016
+ - @robota-sdk/agent-preset@3.0.0-beta.99
1017
+
1018
+ ## 3.0.0-beta.98
1019
+ ### Patch Changes
1020
+
1021
+ - @robota-sdk/agent-core@3.0.0-beta.98
1022
+ - @robota-sdk/agent-framework@3.0.0-beta.98
1023
+ - @robota-sdk/agent-interface-command@3.0.0-beta.98
1024
+ - @robota-sdk/agent-interface-execution@3.0.0-beta.98
1025
+ - @robota-sdk/agent-interface-session@3.0.0-beta.98
1026
+ - @robota-sdk/agent-preset@3.0.0-beta.98
1027
+
3
1028
  ## 3.0.0-beta.97
4
1029
  ### Patch Changes
5
1030
 
@@ -93,14 +1118,14 @@
93
1118
  ### Minor Changes
94
1119
 
95
1120
  - 5bb675a: Provider commands check a profile's `$ENV:` or default credential against the host's environment snapshot, so `/provider switch`, `/provider test`, `/provider add`, `/provider edit` and a cross-profile `/model` keep working while the runtime withholds its own credentials from `process.env`.
96
-
1121
+
97
1122
  - `IProviderCommandModuleOptions` takes an optional `env`, and `createDefaultCommandModules` takes `providerEnvironment`. The CLI passes its startup snapshot.
98
1123
  - The git that isolated subagents run, and so the repository's hooks, now get the command environment instead of the full snapshot.
99
1124
 
100
1125
  ### Patch Changes
101
1126
 
102
1127
  - 7116367: Credentials the runtime holds for itself no longer reach the commands it runs.
103
-
1128
+
104
1129
  - `agent-cli` — once a workspace's settings are admitted, every variable a provider profile or
105
1130
  definition names as its credential (`$ENV:` references, and defaults such as `OPENAI_API_KEY`)
106
1131
  leaves the process environment, so tools, hooks, background shells, a skill's `!` commands and
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@robota-sdk/agent-command",
3
- "version": "3.0.0-beta.97",
3
+ "version": "3.0.0",
4
4
  "description": "Slash-command modules for Robota SDK sessions (/help, /permissions, /mcp, /rewind, …)",
5
5
  "type": "module",
6
6
  "main": "dist/node/index.js",
@@ -40,12 +40,12 @@
40
40
  "CHANGELOG.md"
41
41
  ],
42
42
  "dependencies": {
43
- "@robota-sdk/agent-core": "3.0.0-beta.97",
44
- "@robota-sdk/agent-framework": "3.0.0-beta.97",
45
- "@robota-sdk/agent-interface-command": "3.0.0-beta.97",
46
- "@robota-sdk/agent-interface-execution": "3.0.0-beta.97",
47
- "@robota-sdk/agent-interface-session": "3.0.0-beta.97",
48
- "@robota-sdk/agent-preset": "3.0.0-beta.97"
43
+ "@robota-sdk/agent-core": "3.0.0",
44
+ "@robota-sdk/agent-framework": "3.0.0",
45
+ "@robota-sdk/agent-interface-command": "3.0.0",
46
+ "@robota-sdk/agent-interface-execution": "3.0.0",
47
+ "@robota-sdk/agent-preset": "3.0.0",
48
+ "@robota-sdk/agent-interface-session": "3.0.0"
49
49
  },
50
50
  "devDependencies": {
51
51
  "@types/node": "^22.19.21",