app-server support for Windows sandbox setup. (#12025)

app-server support for initiating Windows sandbox setup.
server responds quickly to setup request and makes a future RPC call
back to client when the setup finishes.

The TUI implementation is unaffected but in a future PR I'll update the
TUI to use the shared setup helper
(`windows_sandbox.run_windows_sandbox_setup`)
This commit is contained in:
iceweasel-oai
2026-02-18 13:03:16 -08:00
committed by GitHub
Unverified
parent cc248e4681
commit 292542616a
21 changed files with 645 additions and 2 deletions
@@ -3311,6 +3311,24 @@
"type": "object"
}
]
},
"WindowsSandboxSetupMode": {
"enum": [
"elevated",
"unelevated"
],
"type": "string"
},
"WindowsSandboxSetupStartParams": {
"properties": {
"mode": {
"$ref": "#/definitions/WindowsSandboxSetupMode"
}
},
"required": [
"mode"
],
"type": "object"
}
},
"description": "Request from the client to the server.",
@@ -3939,6 +3957,30 @@
"title": "McpServerStatus/listRequest",
"type": "object"
},
{
"properties": {
"id": {
"$ref": "#/definitions/RequestId"
},
"method": {
"enum": [
"windowsSandbox/setupStart"
],
"title": "WindowsSandbox/setupStartRequestMethod",
"type": "string"
},
"params": {
"$ref": "#/definitions/WindowsSandboxSetupStartParams"
}
},
"required": [
"id",
"method",
"params"
],
"title": "WindowsSandbox/setupStartRequest",
"type": "object"
},
{
"properties": {
"id": {
@@ -8055,6 +8055,34 @@
}
]
},
"WindowsSandboxSetupCompletedNotification": {
"properties": {
"error": {
"type": [
"string",
"null"
]
},
"mode": {
"$ref": "#/definitions/WindowsSandboxSetupMode"
},
"success": {
"type": "boolean"
}
},
"required": [
"mode",
"success"
],
"type": "object"
},
"WindowsSandboxSetupMode": {
"enum": [
"elevated",
"unelevated"
],
"type": "string"
},
"WindowsWorldWritableWarningNotification": {
"properties": {
"extraCount": {
@@ -8747,6 +8775,26 @@
"title": "Windows/worldWritableWarningNotification",
"type": "object"
},
{
"properties": {
"method": {
"enum": [
"windowsSandbox/setupCompleted"
],
"title": "WindowsSandbox/setupCompletedNotificationMethod",
"type": "string"
},
"params": {
"$ref": "#/definitions/WindowsSandboxSetupCompletedNotification"
}
},
"required": [
"method",
"params"
],
"title": "WindowsSandbox/setupCompletedNotification",
"type": "object"
},
{
"properties": {
"method": {
@@ -1059,6 +1059,30 @@
"title": "McpServerStatus/listRequest",
"type": "object"
},
{
"properties": {
"id": {
"$ref": "#/definitions/RequestId"
},
"method": {
"enum": [
"windowsSandbox/setupStart"
],
"title": "WindowsSandbox/setupStartRequestMethod",
"type": "string"
},
"params": {
"$ref": "#/definitions/v2/WindowsSandboxSetupStartParams"
}
},
"required": [
"id",
"method",
"params"
],
"title": "WindowsSandbox/setupStartRequest",
"type": "object"
},
{
"properties": {
"id": {
@@ -8708,6 +8732,26 @@
"title": "Windows/worldWritableWarningNotification",
"type": "object"
},
{
"properties": {
"method": {
"enum": [
"windowsSandbox/setupCompleted"
],
"title": "WindowsSandbox/setupCompletedNotificationMethod",
"type": "string"
},
"params": {
"$ref": "#/definitions/v2/WindowsSandboxSetupCompletedNotification"
}
},
"required": [
"method",
"params"
],
"title": "WindowsSandbox/setupCompletedNotification",
"type": "object"
},
{
"properties": {
"method": {
@@ -17081,6 +17125,62 @@
],
"type": "string"
},
"WindowsSandboxSetupCompletedNotification": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"error": {
"type": [
"string",
"null"
]
},
"mode": {
"$ref": "#/definitions/v2/WindowsSandboxSetupMode"
},
"success": {
"type": "boolean"
}
},
"required": [
"mode",
"success"
],
"title": "WindowsSandboxSetupCompletedNotification",
"type": "object"
},
"WindowsSandboxSetupMode": {
"enum": [
"elevated",
"unelevated"
],
"type": "string"
},
"WindowsSandboxSetupStartParams": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"mode": {
"$ref": "#/definitions/v2/WindowsSandboxSetupMode"
}
},
"required": [
"mode"
],
"title": "WindowsSandboxSetupStartParams",
"type": "object"
},
"WindowsSandboxSetupStartResponse": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"started": {
"type": "boolean"
}
},
"required": [
"started"
],
"title": "WindowsSandboxSetupStartResponse",
"type": "object"
},
"WindowsWorldWritableWarningNotification": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
@@ -0,0 +1,32 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"WindowsSandboxSetupMode": {
"enum": [
"elevated",
"unelevated"
],
"type": "string"
}
},
"properties": {
"error": {
"type": [
"string",
"null"
]
},
"mode": {
"$ref": "#/definitions/WindowsSandboxSetupMode"
},
"success": {
"type": "boolean"
}
},
"required": [
"mode",
"success"
],
"title": "WindowsSandboxSetupCompletedNotification",
"type": "object"
}
@@ -0,0 +1,22 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"WindowsSandboxSetupMode": {
"enum": [
"elevated",
"unelevated"
],
"type": "string"
}
},
"properties": {
"mode": {
"$ref": "#/definitions/WindowsSandboxSetupMode"
}
},
"required": [
"mode"
],
"title": "WindowsSandboxSetupStartParams",
"type": "object"
}
@@ -0,0 +1,13 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"started": {
"type": "boolean"
}
},
"required": [
"started"
],
"title": "WindowsSandboxSetupStartResponse",
"type": "object"
}
@@ -53,8 +53,9 @@ import type { ThreadUnarchiveParams } from "./v2/ThreadUnarchiveParams";
import type { TurnInterruptParams } from "./v2/TurnInterruptParams";
import type { TurnStartParams } from "./v2/TurnStartParams";
import type { TurnSteerParams } from "./v2/TurnSteerParams";
import type { WindowsSandboxSetupStartParams } from "./v2/WindowsSandboxSetupStartParams";
/**
* Request from the client to the server.
*/
export type ClientRequest ={ "method": "initialize", id: RequestId, params: InitializeParams, } | { "method": "thread/start", id: RequestId, params: ThreadStartParams, } | { "method": "thread/resume", id: RequestId, params: ThreadResumeParams, } | { "method": "thread/fork", id: RequestId, params: ThreadForkParams, } | { "method": "thread/archive", id: RequestId, params: ThreadArchiveParams, } | { "method": "thread/name/set", id: RequestId, params: ThreadSetNameParams, } | { "method": "thread/unarchive", id: RequestId, params: ThreadUnarchiveParams, } | { "method": "thread/compact/start", id: RequestId, params: ThreadCompactStartParams, } | { "method": "thread/rollback", id: RequestId, params: ThreadRollbackParams, } | { "method": "thread/list", id: RequestId, params: ThreadListParams, } | { "method": "thread/loaded/list", id: RequestId, params: ThreadLoadedListParams, } | { "method": "thread/read", id: RequestId, params: ThreadReadParams, } | { "method": "skills/list", id: RequestId, params: SkillsListParams, } | { "method": "skills/remote/list", id: RequestId, params: SkillsRemoteReadParams, } | { "method": "skills/remote/export", id: RequestId, params: SkillsRemoteWriteParams, } | { "method": "app/list", id: RequestId, params: AppsListParams, } | { "method": "skills/config/write", id: RequestId, params: SkillsConfigWriteParams, } | { "method": "turn/start", id: RequestId, params: TurnStartParams, } | { "method": "turn/steer", id: RequestId, params: TurnSteerParams, } | { "method": "turn/interrupt", id: RequestId, params: TurnInterruptParams, } | { "method": "review/start", id: RequestId, params: ReviewStartParams, } | { "method": "model/list", id: RequestId, params: ModelListParams, } | { "method": "experimentalFeature/list", id: RequestId, params: ExperimentalFeatureListParams, } | { "method": "mcpServer/oauth/login", id: RequestId, params: McpServerOauthLoginParams, } | { "method": "config/mcpServer/reload", id: RequestId, params: undefined, } | { "method": "mcpServerStatus/list", id: RequestId, params: ListMcpServerStatusParams, } | { "method": "account/login/start", id: RequestId, params: LoginAccountParams, } | { "method": "account/login/cancel", id: RequestId, params: CancelLoginAccountParams, } | { "method": "account/logout", id: RequestId, params: undefined, } | { "method": "account/rateLimits/read", id: RequestId, params: undefined, } | { "method": "feedback/upload", id: RequestId, params: FeedbackUploadParams, } | { "method": "command/exec", id: RequestId, params: CommandExecParams, } | { "method": "config/read", id: RequestId, params: ConfigReadParams, } | { "method": "config/value/write", id: RequestId, params: ConfigValueWriteParams, } | { "method": "config/batchWrite", id: RequestId, params: ConfigBatchWriteParams, } | { "method": "configRequirements/read", id: RequestId, params: undefined, } | { "method": "account/read", id: RequestId, params: GetAccountParams, } | { "method": "newConversation", id: RequestId, params: NewConversationParams, } | { "method": "getConversationSummary", id: RequestId, params: GetConversationSummaryParams, } | { "method": "listConversations", id: RequestId, params: ListConversationsParams, } | { "method": "resumeConversation", id: RequestId, params: ResumeConversationParams, } | { "method": "forkConversation", id: RequestId, params: ForkConversationParams, } | { "method": "archiveConversation", id: RequestId, params: ArchiveConversationParams, } | { "method": "sendUserMessage", id: RequestId, params: SendUserMessageParams, } | { "method": "sendUserTurn", id: RequestId, params: SendUserTurnParams, } | { "method": "interruptConversation", id: RequestId, params: InterruptConversationParams, } | { "method": "addConversationListener", id: RequestId, params: AddConversationListenerParams, } | { "method": "removeConversationListener", id: RequestId, params: RemoveConversationListenerParams, } | { "method": "gitDiffToRemote", id: RequestId, params: GitDiffToRemoteParams, } | { "method": "loginApiKey", id: RequestId, params: LoginApiKeyParams, } | { "method": "loginChatGpt", id: RequestId, params: undefined, } | { "method": "cancelLoginChatGpt", id: RequestId, params: CancelLoginChatGptParams, } | { "method": "logoutChatGpt", id: RequestId, params: undefined, } | { "method": "getAuthStatus", id: RequestId, params: GetAuthStatusParams, } | { "method": "getUserSavedConfig", id: RequestId, params: undefined, } | { "method": "setDefaultModel", id: RequestId, params: SetDefaultModelParams, } | { "method": "getUserAgent", id: RequestId, params: undefined, } | { "method": "userInfo", id: RequestId, params: undefined, } | { "method": "fuzzyFileSearch", id: RequestId, params: FuzzyFileSearchParams, } | { "method": "execOneOffCommand", id: RequestId, params: ExecOneOffCommandParams, };
export type ClientRequest ={ "method": "initialize", id: RequestId, params: InitializeParams, } | { "method": "thread/start", id: RequestId, params: ThreadStartParams, } | { "method": "thread/resume", id: RequestId, params: ThreadResumeParams, } | { "method": "thread/fork", id: RequestId, params: ThreadForkParams, } | { "method": "thread/archive", id: RequestId, params: ThreadArchiveParams, } | { "method": "thread/name/set", id: RequestId, params: ThreadSetNameParams, } | { "method": "thread/unarchive", id: RequestId, params: ThreadUnarchiveParams, } | { "method": "thread/compact/start", id: RequestId, params: ThreadCompactStartParams, } | { "method": "thread/rollback", id: RequestId, params: ThreadRollbackParams, } | { "method": "thread/list", id: RequestId, params: ThreadListParams, } | { "method": "thread/loaded/list", id: RequestId, params: ThreadLoadedListParams, } | { "method": "thread/read", id: RequestId, params: ThreadReadParams, } | { "method": "skills/list", id: RequestId, params: SkillsListParams, } | { "method": "skills/remote/list", id: RequestId, params: SkillsRemoteReadParams, } | { "method": "skills/remote/export", id: RequestId, params: SkillsRemoteWriteParams, } | { "method": "app/list", id: RequestId, params: AppsListParams, } | { "method": "skills/config/write", id: RequestId, params: SkillsConfigWriteParams, } | { "method": "turn/start", id: RequestId, params: TurnStartParams, } | { "method": "turn/steer", id: RequestId, params: TurnSteerParams, } | { "method": "turn/interrupt", id: RequestId, params: TurnInterruptParams, } | { "method": "review/start", id: RequestId, params: ReviewStartParams, } | { "method": "model/list", id: RequestId, params: ModelListParams, } | { "method": "experimentalFeature/list", id: RequestId, params: ExperimentalFeatureListParams, } | { "method": "mcpServer/oauth/login", id: RequestId, params: McpServerOauthLoginParams, } | { "method": "config/mcpServer/reload", id: RequestId, params: undefined, } | { "method": "mcpServerStatus/list", id: RequestId, params: ListMcpServerStatusParams, } | { "method": "windowsSandbox/setupStart", id: RequestId, params: WindowsSandboxSetupStartParams, } | { "method": "account/login/start", id: RequestId, params: LoginAccountParams, } | { "method": "account/login/cancel", id: RequestId, params: CancelLoginAccountParams, } | { "method": "account/logout", id: RequestId, params: undefined, } | { "method": "account/rateLimits/read", id: RequestId, params: undefined, } | { "method": "feedback/upload", id: RequestId, params: FeedbackUploadParams, } | { "method": "command/exec", id: RequestId, params: CommandExecParams, } | { "method": "config/read", id: RequestId, params: ConfigReadParams, } | { "method": "config/value/write", id: RequestId, params: ConfigValueWriteParams, } | { "method": "config/batchWrite", id: RequestId, params: ConfigBatchWriteParams, } | { "method": "configRequirements/read", id: RequestId, params: undefined, } | { "method": "account/read", id: RequestId, params: GetAccountParams, } | { "method": "newConversation", id: RequestId, params: NewConversationParams, } | { "method": "getConversationSummary", id: RequestId, params: GetConversationSummaryParams, } | { "method": "listConversations", id: RequestId, params: ListConversationsParams, } | { "method": "resumeConversation", id: RequestId, params: ResumeConversationParams, } | { "method": "forkConversation", id: RequestId, params: ForkConversationParams, } | { "method": "archiveConversation", id: RequestId, params: ArchiveConversationParams, } | { "method": "sendUserMessage", id: RequestId, params: SendUserMessageParams, } | { "method": "sendUserTurn", id: RequestId, params: SendUserTurnParams, } | { "method": "interruptConversation", id: RequestId, params: InterruptConversationParams, } | { "method": "addConversationListener", id: RequestId, params: AddConversationListenerParams, } | { "method": "removeConversationListener", id: RequestId, params: RemoveConversationListenerParams, } | { "method": "gitDiffToRemote", id: RequestId, params: GitDiffToRemoteParams, } | { "method": "loginApiKey", id: RequestId, params: LoginApiKeyParams, } | { "method": "loginChatGpt", id: RequestId, params: undefined, } | { "method": "cancelLoginChatGpt", id: RequestId, params: CancelLoginChatGptParams, } | { "method": "logoutChatGpt", id: RequestId, params: undefined, } | { "method": "getAuthStatus", id: RequestId, params: GetAuthStatusParams, } | { "method": "getUserSavedConfig", id: RequestId, params: undefined, } | { "method": "setDefaultModel", id: RequestId, params: SetDefaultModelParams, } | { "method": "getUserAgent", id: RequestId, params: undefined, } | { "method": "userInfo", id: RequestId, params: undefined, } | { "method": "fuzzyFileSearch", id: RequestId, params: FuzzyFileSearchParams, } | { "method": "execOneOffCommand", id: RequestId, params: ExecOneOffCommandParams, };
@@ -37,9 +37,10 @@ import type { TurnCompletedNotification } from "./v2/TurnCompletedNotification";
import type { TurnDiffUpdatedNotification } from "./v2/TurnDiffUpdatedNotification";
import type { TurnPlanUpdatedNotification } from "./v2/TurnPlanUpdatedNotification";
import type { TurnStartedNotification } from "./v2/TurnStartedNotification";
import type { WindowsSandboxSetupCompletedNotification } from "./v2/WindowsSandboxSetupCompletedNotification";
import type { WindowsWorldWritableWarningNotification } from "./v2/WindowsWorldWritableWarningNotification";
/**
* Notification sent from the server to the client.
*/
export type ServerNotification = { "method": "error", "params": ErrorNotification } | { "method": "thread/started", "params": ThreadStartedNotification } | { "method": "thread/archived", "params": ThreadArchivedNotification } | { "method": "thread/unarchived", "params": ThreadUnarchivedNotification } | { "method": "thread/name/updated", "params": ThreadNameUpdatedNotification } | { "method": "thread/tokenUsage/updated", "params": ThreadTokenUsageUpdatedNotification } | { "method": "turn/started", "params": TurnStartedNotification } | { "method": "turn/completed", "params": TurnCompletedNotification } | { "method": "turn/diff/updated", "params": TurnDiffUpdatedNotification } | { "method": "turn/plan/updated", "params": TurnPlanUpdatedNotification } | { "method": "item/started", "params": ItemStartedNotification } | { "method": "item/completed", "params": ItemCompletedNotification } | { "method": "rawResponseItem/completed", "params": RawResponseItemCompletedNotification } | { "method": "item/agentMessage/delta", "params": AgentMessageDeltaNotification } | { "method": "item/plan/delta", "params": PlanDeltaNotification } | { "method": "item/commandExecution/outputDelta", "params": CommandExecutionOutputDeltaNotification } | { "method": "item/commandExecution/terminalInteraction", "params": TerminalInteractionNotification } | { "method": "item/fileChange/outputDelta", "params": FileChangeOutputDeltaNotification } | { "method": "item/mcpToolCall/progress", "params": McpToolCallProgressNotification } | { "method": "mcpServer/oauthLogin/completed", "params": McpServerOauthLoginCompletedNotification } | { "method": "account/updated", "params": AccountUpdatedNotification } | { "method": "account/rateLimits/updated", "params": AccountRateLimitsUpdatedNotification } | { "method": "app/list/updated", "params": AppListUpdatedNotification } | { "method": "item/reasoning/summaryTextDelta", "params": ReasoningSummaryTextDeltaNotification } | { "method": "item/reasoning/summaryPartAdded", "params": ReasoningSummaryPartAddedNotification } | { "method": "item/reasoning/textDelta", "params": ReasoningTextDeltaNotification } | { "method": "thread/compacted", "params": ContextCompactedNotification } | { "method": "model/rerouted", "params": ModelReroutedNotification } | { "method": "deprecationNotice", "params": DeprecationNoticeNotification } | { "method": "configWarning", "params": ConfigWarningNotification } | { "method": "fuzzyFileSearch/sessionUpdated", "params": FuzzyFileSearchSessionUpdatedNotification } | { "method": "fuzzyFileSearch/sessionCompleted", "params": FuzzyFileSearchSessionCompletedNotification } | { "method": "windows/worldWritableWarning", "params": WindowsWorldWritableWarningNotification } | { "method": "account/login/completed", "params": AccountLoginCompletedNotification } | { "method": "authStatusChange", "params": AuthStatusChangeNotification } | { "method": "loginChatGptComplete", "params": LoginChatGptCompleteNotification } | { "method": "sessionConfigured", "params": SessionConfiguredNotification };
export type ServerNotification = { "method": "error", "params": ErrorNotification } | { "method": "thread/started", "params": ThreadStartedNotification } | { "method": "thread/archived", "params": ThreadArchivedNotification } | { "method": "thread/unarchived", "params": ThreadUnarchivedNotification } | { "method": "thread/name/updated", "params": ThreadNameUpdatedNotification } | { "method": "thread/tokenUsage/updated", "params": ThreadTokenUsageUpdatedNotification } | { "method": "turn/started", "params": TurnStartedNotification } | { "method": "turn/completed", "params": TurnCompletedNotification } | { "method": "turn/diff/updated", "params": TurnDiffUpdatedNotification } | { "method": "turn/plan/updated", "params": TurnPlanUpdatedNotification } | { "method": "item/started", "params": ItemStartedNotification } | { "method": "item/completed", "params": ItemCompletedNotification } | { "method": "rawResponseItem/completed", "params": RawResponseItemCompletedNotification } | { "method": "item/agentMessage/delta", "params": AgentMessageDeltaNotification } | { "method": "item/plan/delta", "params": PlanDeltaNotification } | { "method": "item/commandExecution/outputDelta", "params": CommandExecutionOutputDeltaNotification } | { "method": "item/commandExecution/terminalInteraction", "params": TerminalInteractionNotification } | { "method": "item/fileChange/outputDelta", "params": FileChangeOutputDeltaNotification } | { "method": "item/mcpToolCall/progress", "params": McpToolCallProgressNotification } | { "method": "mcpServer/oauthLogin/completed", "params": McpServerOauthLoginCompletedNotification } | { "method": "account/updated", "params": AccountUpdatedNotification } | { "method": "account/rateLimits/updated", "params": AccountRateLimitsUpdatedNotification } | { "method": "app/list/updated", "params": AppListUpdatedNotification } | { "method": "item/reasoning/summaryTextDelta", "params": ReasoningSummaryTextDeltaNotification } | { "method": "item/reasoning/summaryPartAdded", "params": ReasoningSummaryPartAddedNotification } | { "method": "item/reasoning/textDelta", "params": ReasoningTextDeltaNotification } | { "method": "thread/compacted", "params": ContextCompactedNotification } | { "method": "model/rerouted", "params": ModelReroutedNotification } | { "method": "deprecationNotice", "params": DeprecationNoticeNotification } | { "method": "configWarning", "params": ConfigWarningNotification } | { "method": "fuzzyFileSearch/sessionUpdated", "params": FuzzyFileSearchSessionUpdatedNotification } | { "method": "fuzzyFileSearch/sessionCompleted", "params": FuzzyFileSearchSessionCompletedNotification } | { "method": "windows/worldWritableWarning", "params": WindowsWorldWritableWarningNotification } | { "method": "windowsSandbox/setupCompleted", "params": WindowsSandboxSetupCompletedNotification } | { "method": "account/login/completed", "params": AccountLoginCompletedNotification } | { "method": "authStatusChange", "params": AuthStatusChangeNotification } | { "method": "loginChatGptComplete", "params": LoginChatGptCompleteNotification } | { "method": "sessionConfigured", "params": SessionConfiguredNotification };
@@ -0,0 +1,6 @@
// GENERATED CODE! DO NOT MODIFY BY HAND!
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { WindowsSandboxSetupMode } from "./WindowsSandboxSetupMode";
export type WindowsSandboxSetupCompletedNotification = { mode: WindowsSandboxSetupMode, success: boolean, error: string | null, };
@@ -0,0 +1,5 @@
// GENERATED CODE! DO NOT MODIFY BY HAND!
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
export type WindowsSandboxSetupMode = "elevated" | "unelevated";
@@ -0,0 +1,6 @@
// GENERATED CODE! DO NOT MODIFY BY HAND!
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { WindowsSandboxSetupMode } from "./WindowsSandboxSetupMode";
export type WindowsSandboxSetupStartParams = { mode: WindowsSandboxSetupMode, };
@@ -0,0 +1,5 @@
// GENERATED CODE! DO NOT MODIFY BY HAND!
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
export type WindowsSandboxSetupStartResponse = { started: boolean, };
@@ -201,5 +201,9 @@ export type { TurnSteerParams } from "./TurnSteerParams";
export type { TurnSteerResponse } from "./TurnSteerResponse";
export type { UserInput } from "./UserInput";
export type { WebSearchAction } from "./WebSearchAction";
export type { WindowsSandboxSetupCompletedNotification } from "./WindowsSandboxSetupCompletedNotification";
export type { WindowsSandboxSetupMode } from "./WindowsSandboxSetupMode";
export type { WindowsSandboxSetupStartParams } from "./WindowsSandboxSetupStartParams";
export type { WindowsSandboxSetupStartResponse } from "./WindowsSandboxSetupStartResponse";
export type { WindowsWorldWritableWarningNotification } from "./WindowsWorldWritableWarningNotification";
export type { WriteStatus } from "./WriteStatus";
@@ -309,6 +309,11 @@ client_request_definitions! {
response: v2::ListMcpServerStatusResponse,
},
WindowsSandboxSetupStart => "windowsSandbox/setupStart" {
params: v2::WindowsSandboxSetupStartParams,
response: v2::WindowsSandboxSetupStartResponse,
},
LoginAccount => "account/login/start" {
params: v2::LoginAccountParams,
inspect_params: true,
@@ -805,6 +810,7 @@ server_notification_definitions! {
/// Notifies the user of world-writable directories on Windows, which cannot be protected by the sandbox.
WindowsWorldWritableWarning => "windows/worldWritableWarning" (v2::WindowsWorldWritableWarningNotification),
WindowsSandboxSetupCompleted => "windowsSandbox/setupCompleted" (v2::WindowsSandboxSetupCompletedNotification),
#[serde(rename = "account/login/completed")]
#[ts(rename = "account/login/completed")]
@@ -3193,6 +3193,37 @@ pub struct WindowsWorldWritableWarningNotification {
pub failed_scan: bool,
}
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export_to = "v2/")]
pub enum WindowsSandboxSetupMode {
Elevated,
Unelevated,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export_to = "v2/")]
pub struct WindowsSandboxSetupStartParams {
pub mode: WindowsSandboxSetupMode,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export_to = "v2/")]
pub struct WindowsSandboxSetupStartResponse {
pub started: bool,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export_to = "v2/")]
pub struct WindowsSandboxSetupCompletedNotification {
pub mode: WindowsSandboxSetupMode,
pub success: bool,
pub error: Option<String>,
}
/// Deprecated: Use `ContextCompaction` item type instead.
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
#[serde(rename_all = "camelCase")]
+5
View File
@@ -143,6 +143,7 @@ Example with notification opt-out:
- `tool/requestUserInput` — prompt the user with 13 short questions for a tool call and return their answers (experimental).
- `config/mcpServer/reload` — reload MCP server config from disk and queue a refresh for loaded threads (applied on each thread's next active turn); returns `{}`. Use this after editing `config.toml` without restarting the server.
- `mcpServerStatus/list` — enumerate configured MCP servers with their tools, resources, resource templates, and auth status; supports cursor+limit pagination.
- `windowsSandbox/setupStart` — start Windows sandbox setup for the selected mode (`elevated` or `unelevated`); returns `{ started: true }` immediately and later emits `windowsSandbox/setupCompleted`.
- `feedback/upload` — submit a feedback report (classification + optional reason/logs and conversation_id); returns the tracking thread id.
- `command/exec` — run a single command under the server sandbox without starting a thread/turn (handy for utilities and validation).
- `config/read` — fetch the effective config on disk after resolving config layering.
@@ -544,6 +545,10 @@ The fuzzy file search session API emits per-query notifications:
- `fuzzyFileSearch/sessionUpdated``{ sessionId, query, files }` with the current matching files for the active query.
- `fuzzyFileSearch/sessionCompleted``{ sessionId, query }` once indexing/matching for that query has completed.
### Windows sandbox setup events
- `windowsSandbox/setupCompleted``{ mode, success, error }` after a `windowsSandbox/setupStart` request finishes.
### Turn events
The app-server streams JSON-RPC notifications while a turn is running. Each turn starts with `turn/started` (initial `turn`) and ends with `turn/completed` (final `turn` status). Token usage events stream separately via `thread/tokenUsage/updated`. Clients subscribe to the events they care about, rendering each item incrementally as updates arrive. The per-item lifecycle is always: `item/started` → zero or more item-specific deltas → `item/completed`.
@@ -160,6 +160,10 @@ use codex_app_server_protocol::TurnSteerResponse;
use codex_app_server_protocol::UserInfoResponse;
use codex_app_server_protocol::UserInput as V2UserInput;
use codex_app_server_protocol::UserSavedConfig;
use codex_app_server_protocol::WindowsSandboxSetupCompletedNotification;
use codex_app_server_protocol::WindowsSandboxSetupMode;
use codex_app_server_protocol::WindowsSandboxSetupStartParams;
use codex_app_server_protocol::WindowsSandboxSetupStartResponse;
use codex_app_server_protocol::build_turns_from_rollout_items;
use codex_backend_client::Client as BackendClient;
use codex_chatgpt::connectors;
@@ -216,6 +220,8 @@ use codex_core::skills::remote::list_remote_skills;
use codex_core::state_db::StateDbHandle;
use codex_core::state_db::get_state_db;
use codex_core::windows_sandbox::WindowsSandboxLevelExt;
use codex_core::windows_sandbox::WindowsSandboxSetupMode as CoreWindowsSandboxSetupMode;
use codex_core::windows_sandbox::WindowsSandboxSetupRequest;
use codex_feedback::CodexFeedback;
use codex_login::ServerOptions as LoginServerOptions;
use codex_login::ShutdownHandle;
@@ -659,6 +665,10 @@ impl CodexMessageProcessor {
self.list_mcp_server_status(to_connection_request_id(request_id), params)
.await;
}
ClientRequest::WindowsSandboxSetupStart { request_id, params } => {
self.windows_sandbox_setup_start(to_connection_request_id(request_id), params)
.await;
}
ClientRequest::LoginAccount { request_id, params } => {
self.login_v2(to_connection_request_id(request_id), params)
.await;
@@ -6056,6 +6066,56 @@ impl CodexMessageProcessor {
}
}
async fn windows_sandbox_setup_start(
&mut self,
request_id: ConnectionRequestId,
params: WindowsSandboxSetupStartParams,
) {
self.outgoing
.send_response(
request_id.clone(),
WindowsSandboxSetupStartResponse { started: true },
)
.await;
let mode = match params.mode {
WindowsSandboxSetupMode::Elevated => CoreWindowsSandboxSetupMode::Elevated,
WindowsSandboxSetupMode::Unelevated => CoreWindowsSandboxSetupMode::Unelevated,
};
let config = Arc::clone(&self.config);
let outgoing = ThreadScopedOutgoingMessageSender::new(
Arc::clone(&self.outgoing),
vec![request_id.connection_id],
);
tokio::spawn(async move {
let setup_request = WindowsSandboxSetupRequest {
mode,
policy: config.permissions.sandbox_policy.get().clone(),
policy_cwd: config.cwd.clone(),
command_cwd: config.cwd.clone(),
env_map: std::env::vars().collect(),
codex_home: config.codex_home.clone(),
active_profile: config.active_profile.clone(),
};
let setup_result =
codex_core::windows_sandbox::run_windows_sandbox_setup(setup_request).await;
let notification = WindowsSandboxSetupCompletedNotification {
mode: match mode {
CoreWindowsSandboxSetupMode::Elevated => WindowsSandboxSetupMode::Elevated,
CoreWindowsSandboxSetupMode::Unelevated => WindowsSandboxSetupMode::Unelevated,
},
success: setup_result.is_ok(),
error: setup_result.err().map(|err| err.to_string()),
};
outgoing
.send_server_notification(ServerNotification::WindowsSandboxSetupCompleted(
notification,
))
.await;
});
}
async fn resolve_rollout_path(&self, conversation_id: ThreadId) -> Option<PathBuf> {
match self.thread_manager.get_thread(conversation_id).await {
Ok(conv) => conv.rollout_path(),
@@ -64,6 +64,7 @@ use codex_app_server_protocol::ThreadUnarchiveParams;
use codex_app_server_protocol::TurnInterruptParams;
use codex_app_server_protocol::TurnStartParams;
use codex_app_server_protocol::TurnSteerParams;
use codex_app_server_protocol::WindowsSandboxSetupStartParams;
use codex_core::default_client::CODEX_INTERNAL_ORIGINATOR_OVERRIDE_ENV_VAR;
use tokio::process::Command;
@@ -589,6 +590,14 @@ impl McpProcess {
self.send_request("review/start", params).await
}
pub async fn send_windows_sandbox_setup_start_request(
&mut self,
params: WindowsSandboxSetupStartParams,
) -> anyhow::Result<i64> {
let params = Some(serde_json::to_value(params)?);
self.send_request("windowsSandbox/setupStart", params).await
}
/// Send a `cancelLoginChatGpt` JSON-RPC request.
pub async fn send_cancel_login_chat_gpt_request(
&mut self,
@@ -30,3 +30,4 @@ mod turn_interrupt;
mod turn_start;
mod turn_start_zsh_fork;
mod turn_steer;
mod windows_sandbox_setup;
@@ -0,0 +1,63 @@
use anyhow::Context;
use anyhow::Result;
use app_test_support::McpProcess;
use app_test_support::create_mock_responses_server_sequence_unchecked;
use app_test_support::to_response;
use app_test_support::write_mock_responses_config_toml;
use codex_app_server_protocol::JSONRPCResponse;
use codex_app_server_protocol::RequestId;
use codex_app_server_protocol::WindowsSandboxSetupCompletedNotification;
use codex_app_server_protocol::WindowsSandboxSetupMode;
use codex_app_server_protocol::WindowsSandboxSetupStartParams;
use codex_app_server_protocol::WindowsSandboxSetupStartResponse;
use pretty_assertions::assert_eq;
use std::collections::BTreeMap;
use tempfile::TempDir;
use tokio::time::timeout;
const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10);
#[tokio::test]
async fn windows_sandbox_setup_start_emits_completion_notification() -> Result<()> {
let responses = Vec::new();
let server = create_mock_responses_server_sequence_unchecked(responses).await;
let codex_home = TempDir::new()?;
write_mock_responses_config_toml(
codex_home.path(),
&server.uri(),
&BTreeMap::new(),
500_000,
Some(false),
"mock_provider",
"compact prompt",
)?;
let mut mcp = McpProcess::new(codex_home.path()).await?;
timeout(DEFAULT_READ_TIMEOUT, mcp.initialize()).await??;
let request_id = mcp
.send_windows_sandbox_setup_start_request(WindowsSandboxSetupStartParams {
mode: WindowsSandboxSetupMode::Unelevated,
})
.await?;
let response: JSONRPCResponse = timeout(
DEFAULT_READ_TIMEOUT,
mcp.read_stream_until_response_message(RequestId::Integer(request_id)),
)
.await??;
let start_payload: WindowsSandboxSetupStartResponse = to_response(response)?;
assert!(start_payload.started);
let notification = timeout(
DEFAULT_READ_TIMEOUT,
mcp.read_stream_until_notification_message("windowsSandbox/setupCompleted"),
)
.await??;
let payload: WindowsSandboxSetupCompletedNotification = serde_json::from_value(
notification
.params
.context("missing windowsSandbox/setupCompleted params")?,
)?;
assert_eq!(payload.mode, WindowsSandboxSetupMode::Unelevated);
Ok(())
}
+183
View File
@@ -1,16 +1,20 @@
use crate::config::Config;
use crate::config::ConfigToml;
use crate::config::edit::ConfigEditsBuilder;
use crate::config::profile::ConfigProfile;
use crate::config::types::WindowsSandboxModeToml;
use crate::default_client::originator;
use crate::features::Feature;
use crate::features::Features;
use crate::features::FeaturesToml;
use crate::protocol::SandboxPolicy;
use codex_otel::sanitize_metric_tag_value;
use codex_protocol::config_types::WindowsSandboxLevel;
use std::collections::BTreeMap;
use std::collections::HashMap;
use std::path::Path;
use std::path::PathBuf;
use std::time::Instant;
/// Kill switch for the elevated sandbox NUX on Windows.
///
@@ -243,6 +247,185 @@ pub fn run_setup_refresh_with_extra_read_roots(
anyhow::bail!("Windows sandbox read-root refresh is only supported on Windows")
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum WindowsSandboxSetupMode {
Elevated,
Unelevated,
}
#[derive(Debug, Clone)]
pub struct WindowsSandboxSetupRequest {
pub mode: WindowsSandboxSetupMode,
pub policy: SandboxPolicy,
pub policy_cwd: PathBuf,
pub command_cwd: PathBuf,
pub env_map: HashMap<String, String>,
pub codex_home: PathBuf,
pub active_profile: Option<String>,
}
pub async fn run_windows_sandbox_setup(request: WindowsSandboxSetupRequest) -> anyhow::Result<()> {
let start = Instant::now();
let mode = request.mode;
let originator_tag = sanitize_metric_tag_value(originator().value.as_str());
let result = run_windows_sandbox_setup_and_persist(request).await;
match result {
Ok(()) => {
emit_windows_sandbox_setup_success_metrics(
mode,
originator_tag.as_str(),
start.elapsed(),
);
Ok(())
}
Err(err) => {
emit_windows_sandbox_setup_failure_metrics(
mode,
originator_tag.as_str(),
start.elapsed(),
&err,
);
Err(err)
}
}
}
async fn run_windows_sandbox_setup_and_persist(
request: WindowsSandboxSetupRequest,
) -> anyhow::Result<()> {
let mode = request.mode;
let policy = request.policy;
let policy_cwd = request.policy_cwd;
let command_cwd = request.command_cwd;
let env_map = request.env_map;
let codex_home = request.codex_home;
let active_profile = request.active_profile;
let setup_codex_home = codex_home.clone();
let setup_result = tokio::task::spawn_blocking(move || -> anyhow::Result<()> {
match mode {
WindowsSandboxSetupMode::Elevated => {
if !sandbox_setup_is_complete(setup_codex_home.as_path()) {
run_elevated_setup(
&policy,
policy_cwd.as_path(),
command_cwd.as_path(),
&env_map,
setup_codex_home.as_path(),
)?;
}
}
WindowsSandboxSetupMode::Unelevated => {
run_legacy_setup_preflight(
&policy,
policy_cwd.as_path(),
command_cwd.as_path(),
&env_map,
setup_codex_home.as_path(),
)?;
}
}
Ok(())
})
.await
.map_err(|join_err| anyhow::anyhow!("windows sandbox setup task failed: {join_err}"))?;
setup_result?;
ConfigEditsBuilder::new(codex_home.as_path())
.with_profile(active_profile.as_deref())
.set_windows_sandbox_mode(windows_sandbox_setup_mode_tag(mode))
.clear_legacy_windows_sandbox_keys()
.apply()
.await
.map_err(|err| anyhow::anyhow!("failed to persist windows sandbox mode: {err}"))
}
fn emit_windows_sandbox_setup_success_metrics(
mode: WindowsSandboxSetupMode,
originator_tag: &str,
duration: std::time::Duration,
) {
let Some(metrics) = codex_otel::metrics::global() else {
return;
};
let mode_tag = windows_sandbox_setup_mode_tag(mode);
let _ = metrics.record_duration(
"codex.windows_sandbox.setup_duration_ms",
duration,
&[
("result", "success"),
("originator", originator_tag),
("mode", mode_tag),
],
);
let _ = metrics.counter(
"codex.windows_sandbox.setup_success",
1,
&[("originator", originator_tag), ("mode", mode_tag)],
);
}
fn emit_windows_sandbox_setup_failure_metrics(
mode: WindowsSandboxSetupMode,
originator_tag: &str,
duration: std::time::Duration,
_err: &anyhow::Error,
) {
let Some(metrics) = codex_otel::metrics::global() else {
return;
};
let mode_tag = windows_sandbox_setup_mode_tag(mode);
let _ = metrics.record_duration(
"codex.windows_sandbox.setup_duration_ms",
duration,
&[
("result", "failure"),
("originator", originator_tag),
("mode", mode_tag),
],
);
let _ = metrics.counter(
"codex.windows_sandbox.setup_failure",
1,
&[("originator", originator_tag), ("mode", mode_tag)],
);
if matches!(mode, WindowsSandboxSetupMode::Elevated) {
#[cfg(target_os = "windows")]
{
let mut failure_tags: Vec<(&str, &str)> = vec![("originator", originator_tag)];
let mut code_tag: Option<String> = None;
let mut message_tag: Option<String> = None;
if let Some((code, message)) = elevated_setup_failure_details(_err) {
code_tag = Some(code);
message_tag = Some(message);
}
if let Some(code) = code_tag.as_deref() {
failure_tags.push(("code", code));
}
if let Some(message) = message_tag.as_deref() {
failure_tags.push(("message", message));
}
let _ = metrics.counter(elevated_setup_failure_metric_name(_err), 1, &failure_tags);
}
} else {
let _ = metrics.counter(
"codex.windows_sandbox.legacy_setup_preflight_failed",
1,
&[("originator", originator_tag)],
);
}
}
fn windows_sandbox_setup_mode_tag(mode: WindowsSandboxSetupMode) -> &'static str {
match mode {
WindowsSandboxSetupMode::Elevated => "elevated",
WindowsSandboxSetupMode::Unelevated => "unelevated",
}
}
#[cfg(test)]
mod tests {
use super::*;