diff --git a/dotnet/src/Generated/Rpc.cs b/dotnet/src/Generated/Rpc.cs index 0bea6e8db..342d35c25 100644 --- a/dotnet/src/Generated/Rpc.cs +++ b/dotnet/src/Generated/Rpc.cs @@ -493,6 +493,37 @@ internal sealed class ModeSetRequest public SessionMode Mode { get; set; } } +/// RPC data type for NameGet operations. +public sealed class NameGetResult +{ + /// The session name, falling back to the auto-generated summary, or null if neither exists. + [JsonPropertyName("name")] + public string? Name { get; set; } +} + +/// RPC data type for SessionNameGet operations. +internal sealed class SessionNameGetRequest +{ + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// RPC data type for NameSet operations. +internal sealed class NameSetRequest +{ + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; + + /// New session name (1–100 characters, trimmed of leading/trailing whitespace). + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")] + [MinLength(1)] + [MaxLength(100)] + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; +} + /// RPC data type for PlanRead operations. public sealed class PlanReadResult { @@ -537,32 +568,113 @@ internal sealed class SessionPlanDeleteRequest public string SessionId { get; set; } = string.Empty; } -/// RPC data type for WorkspaceListFiles operations. -public sealed class WorkspaceListFilesResult +/// RPC data type for WorkspacesGetWorkspaceResultWorkspace operations. +public sealed class WorkspacesGetWorkspaceResultWorkspace +{ + /// Gets or sets the id value. + [JsonPropertyName("id")] + public Guid Id { get; set; } + + /// Gets or sets the cwd value. + [JsonPropertyName("cwd")] + public string? Cwd { get; set; } + + /// Gets or sets the git_root value. + [JsonPropertyName("git_root")] + public string? GitRoot { get; set; } + + /// Gets or sets the repository value. + [JsonPropertyName("repository")] + public string? Repository { get; set; } + + /// Gets or sets the host_type value. + [JsonPropertyName("host_type")] + public WorkspacesGetWorkspaceResultWorkspaceHostType? HostType { get; set; } + + /// Gets or sets the branch value. + [JsonPropertyName("branch")] + public string? Branch { get; set; } + + /// Gets or sets the summary value. + [JsonPropertyName("summary")] + public string? Summary { get; set; } + + /// Gets or sets the name value. + [JsonPropertyName("name")] + public string? Name { get; set; } + + /// Gets or sets the summary_count value. + [Range((double)0, (double)long.MaxValue)] + [JsonPropertyName("summary_count")] + public long? SummaryCount { get; set; } + + /// Gets or sets the created_at value. + [JsonPropertyName("created_at")] + public DateTimeOffset? CreatedAt { get; set; } + + /// Gets or sets the updated_at value. + [JsonPropertyName("updated_at")] + public DateTimeOffset? UpdatedAt { get; set; } + + /// Gets or sets the mc_task_id value. + [JsonPropertyName("mc_task_id")] + public string? McTaskId { get; set; } + + /// Gets or sets the mc_session_id value. + [JsonPropertyName("mc_session_id")] + public string? McSessionId { get; set; } + + /// Gets or sets the mc_last_event_id value. + [JsonPropertyName("mc_last_event_id")] + public string? McLastEventId { get; set; } + + /// Gets or sets the session_sync_level value. + [JsonPropertyName("session_sync_level")] + public WorkspacesGetWorkspaceResultWorkspaceSessionSyncLevel? SessionSyncLevel { get; set; } +} + +/// RPC data type for WorkspacesGetWorkspace operations. +public sealed class WorkspacesGetWorkspaceResult +{ + /// Current workspace metadata, or null if not available. + [JsonPropertyName("workspace")] + public WorkspacesGetWorkspaceResultWorkspace? Workspace { get; set; } +} + +/// RPC data type for SessionWorkspacesGetWorkspace operations. +internal sealed class SessionWorkspacesGetWorkspaceRequest +{ + /// Target session identifier. + [JsonPropertyName("sessionId")] + public string SessionId { get; set; } = string.Empty; +} + +/// RPC data type for WorkspacesListFiles operations. +public sealed class WorkspacesListFilesResult { /// Relative file paths in the workspace files directory. [JsonPropertyName("files")] public IList Files { get => field ??= []; set; } } -/// RPC data type for SessionWorkspaceListFiles operations. -internal sealed class SessionWorkspaceListFilesRequest +/// RPC data type for SessionWorkspacesListFiles operations. +internal sealed class SessionWorkspacesListFilesRequest { /// Target session identifier. [JsonPropertyName("sessionId")] public string SessionId { get; set; } = string.Empty; } -/// RPC data type for WorkspaceReadFile operations. -public sealed class WorkspaceReadFileResult +/// RPC data type for WorkspacesReadFile operations. +public sealed class WorkspacesReadFileResult { /// File content as a UTF-8 string. [JsonPropertyName("content")] public string Content { get; set; } = string.Empty; } -/// RPC data type for WorkspaceReadFile operations. -internal sealed class WorkspaceReadFileRequest +/// RPC data type for WorkspacesReadFile operations. +internal sealed class WorkspacesReadFileRequest { /// Target session identifier. [JsonPropertyName("sessionId")] @@ -573,8 +685,8 @@ internal sealed class WorkspaceReadFileRequest public string Path { get; set; } = string.Empty; } -/// RPC data type for WorkspaceCreateFile operations. -internal sealed class WorkspaceCreateFileRequest +/// RPC data type for WorkspacesCreateFile operations. +internal sealed class WorkspacesCreateFileRequest { /// Target session identifier. [JsonPropertyName("sessionId")] @@ -1754,6 +1866,35 @@ public enum SessionMode } +/// Defines the allowed values. +[JsonConverter(typeof(JsonStringEnumConverter))] +public enum WorkspacesGetWorkspaceResultWorkspaceHostType +{ + /// The github variant. + [JsonStringEnumMemberName("github")] + Github, + /// The ado variant. + [JsonStringEnumMemberName("ado")] + Ado, +} + + +/// Defines the allowed values. +[JsonConverter(typeof(JsonStringEnumConverter))] +public enum WorkspacesGetWorkspaceResultWorkspaceSessionSyncLevel +{ + /// The local variant. + [JsonStringEnumMemberName("local")] + Local, + /// The user variant. + [JsonStringEnumMemberName("user")] + User, + /// The repo_and_user variant. + [JsonStringEnumMemberName("repo_and_user")] + RepoAndUser, +} + + /// Connection status: connected, failed, needs-auth, pending, disabled, or not_configured. [JsonConverter(typeof(JsonStringEnumConverter))] public enum McpServerStatus @@ -2036,8 +2177,9 @@ internal SessionRpc(JsonRpc rpc, string sessionId) _sessionId = sessionId; Model = new ModelApi(rpc, sessionId); Mode = new ModeApi(rpc, sessionId); + Name = new NameApi(rpc, sessionId); Plan = new PlanApi(rpc, sessionId); - Workspace = new WorkspaceApi(rpc, sessionId); + Workspaces = new WorkspacesApi(rpc, sessionId); Fleet = new FleetApi(rpc, sessionId); Agent = new AgentApi(rpc, sessionId); Skills = new SkillsApi(rpc, sessionId); @@ -2059,11 +2201,14 @@ internal SessionRpc(JsonRpc rpc, string sessionId) /// Mode APIs. public ModeApi Mode { get; } + /// Name APIs. + public NameApi Name { get; } + /// Plan APIs. public PlanApi Plan { get; } - /// Workspace APIs. - public WorkspaceApi Workspace { get; } + /// Workspaces APIs. + public WorkspacesApi Workspaces { get; } /// Fleet APIs. public FleetApi Fleet { get; } @@ -2166,6 +2311,33 @@ public async Task SetAsync(SessionMode mode, CancellationToken cancellationToken } } +/// Provides session-scoped Name APIs. +public sealed class NameApi +{ + private readonly JsonRpc _rpc; + private readonly string _sessionId; + + internal NameApi(JsonRpc rpc, string sessionId) + { + _rpc = rpc; + _sessionId = sessionId; + } + + /// Calls "session.name.get". + public async Task GetAsync(CancellationToken cancellationToken = default) + { + var request = new SessionNameGetRequest { SessionId = _sessionId }; + return await CopilotClient.InvokeRpcAsync(_rpc, "session.name.get", [request], cancellationToken); + } + + /// Calls "session.name.set". + public async Task SetAsync(string name, CancellationToken cancellationToken = default) + { + var request = new NameSetRequest { SessionId = _sessionId, Name = name }; + await CopilotClient.InvokeRpcAsync(_rpc, "session.name.set", [request], cancellationToken); + } +} + /// Provides session-scoped Plan APIs. public sealed class PlanApi { @@ -2200,37 +2372,44 @@ public async Task DeleteAsync(CancellationToken cancellationToken = default) } } -/// Provides session-scoped Workspace APIs. -public sealed class WorkspaceApi +/// Provides session-scoped Workspaces APIs. +public sealed class WorkspacesApi { private readonly JsonRpc _rpc; private readonly string _sessionId; - internal WorkspaceApi(JsonRpc rpc, string sessionId) + internal WorkspacesApi(JsonRpc rpc, string sessionId) { _rpc = rpc; _sessionId = sessionId; } - /// Calls "session.workspace.listFiles". - public async Task ListFilesAsync(CancellationToken cancellationToken = default) + /// Calls "session.workspaces.getWorkspace". + public async Task GetWorkspaceAsync(CancellationToken cancellationToken = default) + { + var request = new SessionWorkspacesGetWorkspaceRequest { SessionId = _sessionId }; + return await CopilotClient.InvokeRpcAsync(_rpc, "session.workspaces.getWorkspace", [request], cancellationToken); + } + + /// Calls "session.workspaces.listFiles". + public async Task ListFilesAsync(CancellationToken cancellationToken = default) { - var request = new SessionWorkspaceListFilesRequest { SessionId = _sessionId }; - return await CopilotClient.InvokeRpcAsync(_rpc, "session.workspace.listFiles", [request], cancellationToken); + var request = new SessionWorkspacesListFilesRequest { SessionId = _sessionId }; + return await CopilotClient.InvokeRpcAsync(_rpc, "session.workspaces.listFiles", [request], cancellationToken); } - /// Calls "session.workspace.readFile". - public async Task ReadFileAsync(string path, CancellationToken cancellationToken = default) + /// Calls "session.workspaces.readFile". + public async Task ReadFileAsync(string path, CancellationToken cancellationToken = default) { - var request = new WorkspaceReadFileRequest { SessionId = _sessionId, Path = path }; - return await CopilotClient.InvokeRpcAsync(_rpc, "session.workspace.readFile", [request], cancellationToken); + var request = new WorkspacesReadFileRequest { SessionId = _sessionId, Path = path }; + return await CopilotClient.InvokeRpcAsync(_rpc, "session.workspaces.readFile", [request], cancellationToken); } - /// Calls "session.workspace.createFile". + /// Calls "session.workspaces.createFile". public async Task CreateFileAsync(string path, string content, CancellationToken cancellationToken = default) { - var request = new WorkspaceCreateFileRequest { SessionId = _sessionId, Path = path, Content = content }; - await CopilotClient.InvokeRpcAsync(_rpc, "session.workspace.createFile", [request], cancellationToken); + var request = new WorkspacesCreateFileRequest { SessionId = _sessionId, Path = path, Content = content }; + await CopilotClient.InvokeRpcAsync(_rpc, "session.workspaces.createFile", [request], cancellationToken); } } @@ -2812,6 +2991,8 @@ public static void RegisterClientSessionApiHandlers(JsonRpc rpc, Func f.Contains("nested.txt")); } diff --git a/go/internal/e2e/rpc_test.go b/go/internal/e2e/rpc_test.go index 5a79a7509..819e8ccca 100644 --- a/go/internal/e2e/rpc_test.go +++ b/go/internal/e2e/rpc_test.go @@ -307,7 +307,7 @@ func TestSessionRpc(t *testing.T) { } // Initially no files - initialFiles, err := session.RPC.Workspace.ListFiles(t.Context()) + initialFiles, err := session.RPC.Workspaces.ListFiles(t.Context()) if err != nil { t.Fatalf("Failed to list files: %v", err) } @@ -317,7 +317,7 @@ func TestSessionRpc(t *testing.T) { // Create a file fileContent := "Hello, workspace!" - _, err = session.RPC.Workspace.CreateFile(t.Context(), &rpc.WorkspaceCreateFileRequest{ + _, err = session.RPC.Workspaces.CreateFile(t.Context(), &rpc.WorkspacesCreateFileRequest{ Path: "test.txt", Content: fileContent, }) @@ -326,7 +326,7 @@ func TestSessionRpc(t *testing.T) { } // List files - afterCreate, err := session.RPC.Workspace.ListFiles(t.Context()) + afterCreate, err := session.RPC.Workspaces.ListFiles(t.Context()) if err != nil { t.Fatalf("Failed to list files after create: %v", err) } @@ -335,7 +335,7 @@ func TestSessionRpc(t *testing.T) { } // Read file - readResult, err := session.RPC.Workspace.ReadFile(t.Context(), &rpc.WorkspaceReadFileRequest{ + readResult, err := session.RPC.Workspaces.ReadFile(t.Context(), &rpc.WorkspacesReadFileRequest{ Path: "test.txt", }) if err != nil { @@ -346,7 +346,7 @@ func TestSessionRpc(t *testing.T) { } // Create nested file - _, err = session.RPC.Workspace.CreateFile(t.Context(), &rpc.WorkspaceCreateFileRequest{ + _, err = session.RPC.Workspaces.CreateFile(t.Context(), &rpc.WorkspacesCreateFileRequest{ Path: "subdir/nested.txt", Content: "Nested content", }) @@ -354,7 +354,7 @@ func TestSessionRpc(t *testing.T) { t.Fatalf("Failed to create nested file: %v", err) } - afterNested, err := session.RPC.Workspace.ListFiles(t.Context()) + afterNested, err := session.RPC.Workspaces.ListFiles(t.Context()) if err != nil { t.Fatalf("Failed to list files after nested: %v", err) } diff --git a/go/rpc/generated_rpc.go b/go/rpc/generated_rpc.go index 75660a0e0..39478b0c4 100644 --- a/go/rpc/generated_rpc.go +++ b/go/rpc/generated_rpc.go @@ -344,6 +344,19 @@ type ModeSetRequest struct { Mode SessionMode `json:"mode"` } +type NameGetResult struct { + // The session name, falling back to the auto-generated summary, or null if neither exists + Name *string `json:"name"` +} + +type NameSetResult struct { +} + +type NameSetRequest struct { + // New session name (1–100 characters, trimmed of leading/trailing whitespace) + Name string `json:"name"` +} + type PlanReadResult struct { // The content of the plan file, or null if it does not exist Content *string `json:"content"` @@ -364,25 +377,48 @@ type PlanUpdateRequest struct { type PlanDeleteResult struct { } -type WorkspaceListFilesResult struct { +type WorkspacesGetWorkspaceResult struct { + // Current workspace metadata, or null if not available + Workspace *WorkspaceClass `json:"workspace"` +} + +type WorkspaceClass struct { + Branch *string `json:"branch,omitempty"` + CreatedAt *time.Time `json:"created_at,omitempty"` + Cwd *string `json:"cwd,omitempty"` + GitRoot *string `json:"git_root,omitempty"` + HostType *HostType `json:"host_type,omitempty"` + ID string `json:"id"` + McLastEventID *string `json:"mc_last_event_id,omitempty"` + McSessionID *string `json:"mc_session_id,omitempty"` + McTaskID *string `json:"mc_task_id,omitempty"` + Name *string `json:"name,omitempty"` + Repository *string `json:"repository,omitempty"` + SessionSyncLevel *SessionSyncLevel `json:"session_sync_level,omitempty"` + Summary *string `json:"summary,omitempty"` + SummaryCount *int64 `json:"summary_count,omitempty"` + UpdatedAt *time.Time `json:"updated_at,omitempty"` +} + +type WorkspacesListFilesResult struct { // Relative file paths in the workspace files directory Files []string `json:"files"` } -type WorkspaceReadFileResult struct { +type WorkspacesReadFileResult struct { // File content as a UTF-8 string Content string `json:"content"` } -type WorkspaceReadFileRequest struct { +type WorkspacesReadFileRequest struct { // Relative path within the workspace files directory Path string `json:"path"` } -type WorkspaceCreateFileResult struct { +type WorkspacesCreateFileResult struct { } -type WorkspaceCreateFileRequest struct { +type WorkspacesCreateFileRequest struct { // File content to write as a UTF-8 string Content string `json:"content"` // Relative path within the workspace files directory @@ -1058,8 +1094,8 @@ const ( type MCPConfigType string const ( - MCPConfigTypeLocal MCPConfigType = "local" MCPConfigTypeHTTP MCPConfigType = "http" + MCPConfigTypeLocal MCPConfigType = "local" MCPConfigTypeSSE MCPConfigType = "sse" MCPConfigTypeStdio MCPConfigType = "stdio" ) @@ -1103,6 +1139,21 @@ const ( SessionModePlan SessionMode = "plan" ) +type HostType string + +const ( + HostTypeAdo HostType = "ado" + HostTypeGithub HostType = "github" +) + +type SessionSyncLevel string + +const ( + SessionSyncLevelRepoAndUser SessionSyncLevel = "repo_and_user" + SessionSyncLevelLocal SessionSyncLevel = "local" + SessionSyncLevelUser SessionSyncLevel = "user" +) + // Connection status: connected, failed, needs-auth, pending, disabled, or not_configured type MCPServerStatus string @@ -1427,6 +1478,37 @@ func (a *ModeApi) Set(ctx context.Context, params *ModeSetRequest) (*ModeSetResu return &result, nil } +type NameApi sessionApi + +func (a *NameApi) Get(ctx context.Context) (*NameGetResult, error) { + req := map[string]any{"sessionId": a.sessionID} + raw, err := a.client.Request("session.name.get", req) + if err != nil { + return nil, err + } + var result NameGetResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + +func (a *NameApi) Set(ctx context.Context, params *NameSetRequest) (*NameSetResult, error) { + req := map[string]any{"sessionId": a.sessionID} + if params != nil { + req["name"] = params.Name + } + raw, err := a.client.Request("session.name.set", req) + if err != nil { + return nil, err + } + var result NameSetResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} + type PlanApi sessionApi func (a *PlanApi) Read(ctx context.Context) (*PlanReadResult, error) { @@ -1471,48 +1553,61 @@ func (a *PlanApi) Delete(ctx context.Context) (*PlanDeleteResult, error) { return &result, nil } -type WorkspaceApi sessionApi +type WorkspacesApi sessionApi + +func (a *WorkspacesApi) GetWorkspace(ctx context.Context) (*WorkspacesGetWorkspaceResult, error) { + req := map[string]any{"sessionId": a.sessionID} + raw, err := a.client.Request("session.workspaces.getWorkspace", req) + if err != nil { + return nil, err + } + var result WorkspacesGetWorkspaceResult + if err := json.Unmarshal(raw, &result); err != nil { + return nil, err + } + return &result, nil +} -func (a *WorkspaceApi) ListFiles(ctx context.Context) (*WorkspaceListFilesResult, error) { +func (a *WorkspacesApi) ListFiles(ctx context.Context) (*WorkspacesListFilesResult, error) { req := map[string]any{"sessionId": a.sessionID} - raw, err := a.client.Request("session.workspace.listFiles", req) + raw, err := a.client.Request("session.workspaces.listFiles", req) if err != nil { return nil, err } - var result WorkspaceListFilesResult + var result WorkspacesListFilesResult if err := json.Unmarshal(raw, &result); err != nil { return nil, err } return &result, nil } -func (a *WorkspaceApi) ReadFile(ctx context.Context, params *WorkspaceReadFileRequest) (*WorkspaceReadFileResult, error) { +func (a *WorkspacesApi) ReadFile(ctx context.Context, params *WorkspacesReadFileRequest) (*WorkspacesReadFileResult, error) { req := map[string]any{"sessionId": a.sessionID} if params != nil { req["path"] = params.Path } - raw, err := a.client.Request("session.workspace.readFile", req) + raw, err := a.client.Request("session.workspaces.readFile", req) if err != nil { return nil, err } - var result WorkspaceReadFileResult + var result WorkspacesReadFileResult if err := json.Unmarshal(raw, &result); err != nil { return nil, err } return &result, nil } -func (a *WorkspaceApi) CreateFile(ctx context.Context, params *WorkspaceCreateFileRequest) (*WorkspaceCreateFileResult, error) { +func (a *WorkspacesApi) CreateFile(ctx context.Context, params *WorkspacesCreateFileRequest) (*WorkspacesCreateFileResult, error) { req := map[string]any{"sessionId": a.sessionID} if params != nil { req["path"] = params.Path req["content"] = params.Content } - raw, err := a.client.Request("session.workspace.createFile", req) + raw, err := a.client.Request("session.workspaces.createFile", req) if err != nil { return nil, err } - var result WorkspaceCreateFileResult + var result WorkspacesCreateFileResult if err := json.Unmarshal(raw, &result); err != nil { return nil, err } @@ -2007,8 +2102,9 @@ type SessionRpc struct { Model *ModelApi Mode *ModeApi + Name *NameApi Plan *PlanApi - Workspace *WorkspaceApi + Workspaces *WorkspacesApi Fleet *FleetApi Agent *AgentApi Skills *SkillsApi @@ -2054,8 +2150,9 @@ func NewSessionRpc(client *jsonrpc2.Client, sessionID string) *SessionRpc { r.common = sessionApi{client: client, sessionID: sessionID} r.Model = (*ModelApi)(&r.common) r.Mode = (*ModeApi)(&r.common) + r.Name = (*NameApi)(&r.common) r.Plan = (*PlanApi)(&r.common) - r.Workspace = (*WorkspaceApi)(&r.common) + r.Workspaces = (*WorkspacesApi)(&r.common) r.Fleet = (*FleetApi)(&r.common) r.Agent = (*AgentApi)(&r.common) r.Skills = (*SkillsApi)(&r.common) diff --git a/nodejs/package-lock.json b/nodejs/package-lock.json index cc4407bbb..1c84c1d71 100644 --- a/nodejs/package-lock.json +++ b/nodejs/package-lock.json @@ -9,7 +9,7 @@ "version": "0.1.8", "license": "MIT", "dependencies": { - "@github/copilot": "^1.0.26-0", + "@github/copilot": "^1.0.26", "vscode-jsonrpc": "^8.2.1", "zod": "^4.3.6" }, @@ -663,26 +663,26 @@ } }, "node_modules/@github/copilot": { - "version": "1.0.26-0", - "resolved": "https://registry.npmjs.org/@github/copilot/-/copilot-1.0.26-0.tgz", - "integrity": "sha512-MHeddlLZCi5OFeuzKRtj7kmJVm1o/teNwgrL5/FHU9x0H6VioG+KGlY6gd1H/cTJ763dtYQyACMPYFUNVVY52g==", + "version": "1.0.26", + "resolved": "https://registry.npmjs.org/@github/copilot/-/copilot-1.0.26.tgz", + "integrity": "sha512-F7P6yimFzjvWxOF/A0F6k//vcpSVcVusQjaybb3IKyrEDhnd/LOv2tD+x6W0IoxCftGDDhkzBA2aon3rL9lPhQ==", "license": "SEE LICENSE IN LICENSE.md", "bin": { "copilot": "npm-loader.js" }, "optionalDependencies": { - "@github/copilot-darwin-arm64": "1.0.26-0", - "@github/copilot-darwin-x64": "1.0.26-0", - "@github/copilot-linux-arm64": "1.0.26-0", - "@github/copilot-linux-x64": "1.0.26-0", - "@github/copilot-win32-arm64": "1.0.26-0", - "@github/copilot-win32-x64": "1.0.26-0" + "@github/copilot-darwin-arm64": "1.0.26", + "@github/copilot-darwin-x64": "1.0.26", + "@github/copilot-linux-arm64": "1.0.26", + "@github/copilot-linux-x64": "1.0.26", + "@github/copilot-win32-arm64": "1.0.26", + "@github/copilot-win32-x64": "1.0.26" } }, "node_modules/@github/copilot-darwin-arm64": { - "version": "1.0.26-0", - "resolved": "https://registry.npmjs.org/@github/copilot-darwin-arm64/-/copilot-darwin-arm64-1.0.26-0.tgz", - "integrity": "sha512-C1GP4qrKjCjPoKr485o0IbcP3n1q/4LxKwAhpga0V+9ZHlvggZ58YB9AaUFySJ+Alpu1vBlw/FFpD9amroasvw==", + "version": "1.0.26", + "resolved": "https://registry.npmjs.org/@github/copilot-darwin-arm64/-/copilot-darwin-arm64-1.0.26.tgz", + "integrity": "sha512-eV+jDMj4vnjdGcG+c4zg11zZKVAp94Hm4sK4f9LnyWw8MumTfS5F2Yyse9zt7A3oGlegyczmJopKwuwZbQd4ww==", "cpu": [ "arm64" ], @@ -696,9 +696,9 @@ } }, "node_modules/@github/copilot-darwin-x64": { - "version": "1.0.26-0", - "resolved": "https://registry.npmjs.org/@github/copilot-darwin-x64/-/copilot-darwin-x64-1.0.26-0.tgz", - "integrity": "sha512-A/HSuoCe8i5+yc5yCi4ZMi6PQfOOExA0wwpN13zFKwmqDwdNdogb4/wX42DoGr7JwuOGhZSzXCEZirt/lqqxjQ==", + "version": "1.0.26", + "resolved": "https://registry.npmjs.org/@github/copilot-darwin-x64/-/copilot-darwin-x64-1.0.26.tgz", + "integrity": "sha512-2AAgu19F3scDlYhsiHxCn0cz4ZkINq8gxnqW0an8VQn6p15lDcah6PqHw+RJ+12qiYX5L5NNACty9UOkIK7Kzg==", "cpu": [ "x64" ], @@ -712,9 +712,9 @@ } }, "node_modules/@github/copilot-linux-arm64": { - "version": "1.0.26-0", - "resolved": "https://registry.npmjs.org/@github/copilot-linux-arm64/-/copilot-linux-arm64-1.0.26-0.tgz", - "integrity": "sha512-goMPZkMi5dCqA1JHbgsxaUKOmtZ6juBAeUfVomtKmdKee1KC74TFXlEuP8qJMGkeug2yivPOptAfQQXSyJJnHw==", + "version": "1.0.26", + "resolved": "https://registry.npmjs.org/@github/copilot-linux-arm64/-/copilot-linux-arm64-1.0.26.tgz", + "integrity": "sha512-SnM7+TGAZ/i9dim5FfHM7+ii01hdpHJzzh8vnnA1Fa7RPFJaQ2KTOdTDJFgfv6e/jLhKXZEelYIidgCA3vSQCQ==", "cpu": [ "arm64" ], @@ -728,9 +728,9 @@ } }, "node_modules/@github/copilot-linux-x64": { - "version": "1.0.26-0", - "resolved": "https://registry.npmjs.org/@github/copilot-linux-x64/-/copilot-linux-x64-1.0.26-0.tgz", - "integrity": "sha512-oK6uQ0Q0ZUO9IM3B+KJb9wyRHG5ZGP5qoTOOTN7JcC+p8ZveNSGCAHUAtzLSflUREJUFYfRZauUKcfV31/Y2LA==", + "version": "1.0.26", + "resolved": "https://registry.npmjs.org/@github/copilot-linux-x64/-/copilot-linux-x64-1.0.26.tgz", + "integrity": "sha512-x76vcwVbi0j03hFMhiQs+Eqefd9Xmc4qJoaj44YA2VsJuDbZw2Yv7ZBq7Vyxd/shJwJZjaKv36MHcx5bVUMBJQ==", "cpu": [ "x64" ], @@ -744,9 +744,9 @@ } }, "node_modules/@github/copilot-win32-arm64": { - "version": "1.0.26-0", - "resolved": "https://registry.npmjs.org/@github/copilot-win32-arm64/-/copilot-win32-arm64-1.0.26-0.tgz", - "integrity": "sha512-VXwm8xryO3cUHydVkzmSzb0M3WonwGDHCcgwI2GGS2YkHB9VjmRbdpVeLYeDB5EzmyZLSd7Nr4+i2X0gsU93ow==", + "version": "1.0.26", + "resolved": "https://registry.npmjs.org/@github/copilot-win32-arm64/-/copilot-win32-arm64-1.0.26.tgz", + "integrity": "sha512-enVRcy7W9RD1bwYkF+mcxR+biXsG/X5m46XBaD0opvfDeiBHceDnI8hEI0O1A5PYvRo88AZFvDEmEW3Gdj6+rQ==", "cpu": [ "arm64" ], @@ -760,9 +760,9 @@ } }, "node_modules/@github/copilot-win32-x64": { - "version": "1.0.26-0", - "resolved": "https://registry.npmjs.org/@github/copilot-win32-x64/-/copilot-win32-x64-1.0.26-0.tgz", - "integrity": "sha512-+4IFUZbYSg5jxchEFdgVEgSDJzDE/P3nRDtEBcIhpYlVb7/zAw2JCkCJr+i4Aruo4zysJnEybL0wM3TpcWTt/g==", + "version": "1.0.26", + "resolved": "https://registry.npmjs.org/@github/copilot-win32-x64/-/copilot-win32-x64-1.0.26.tgz", + "integrity": "sha512-DpJF6C1x4+sYIXUx5+vWCu6cFAbD2YlrXQ/BRttf2MMdc0DHwdgJxrttBBF2qCvmpfzjSE8cr5G0kt5EUk7FGw==", "cpu": [ "x64" ], diff --git a/nodejs/package.json b/nodejs/package.json index f4a3a2188..ca2e0afe7 100644 --- a/nodejs/package.json +++ b/nodejs/package.json @@ -56,7 +56,7 @@ "author": "GitHub", "license": "MIT", "dependencies": { - "@github/copilot": "^1.0.26-0", + "@github/copilot": "^1.0.26", "vscode-jsonrpc": "^8.2.1", "zod": "^4.3.6" }, diff --git a/nodejs/samples/package-lock.json b/nodejs/samples/package-lock.json index 3c5ebfd97..d85bc1e5e 100644 --- a/nodejs/samples/package-lock.json +++ b/nodejs/samples/package-lock.json @@ -18,7 +18,7 @@ "version": "0.1.8", "license": "MIT", "dependencies": { - "@github/copilot": "^1.0.22", + "@github/copilot": "^1.0.26", "vscode-jsonrpc": "^8.2.1", "zod": "^4.3.6" }, diff --git a/nodejs/src/generated/rpc.ts b/nodejs/src/generated/rpc.ts index 8214dec4e..9b70619f8 100644 --- a/nodejs/src/generated/rpc.ts +++ b/nodejs/src/generated/rpc.ts @@ -595,6 +595,20 @@ export interface ModeSetRequest { mode: SessionMode; } +export interface NameGetResult { + /** + * The session name, falling back to the auto-generated summary, or null if neither exists + */ + name: string | null; +} + +export interface NameSetRequest { + /** + * New session name (1–100 characters, trimmed of leading/trailing whitespace) + */ + name: string; +} + export interface PlanReadResult { /** * Whether the plan file exists in the workspace @@ -617,28 +631,51 @@ export interface PlanUpdateRequest { content: string; } -export interface WorkspaceListFilesResult { +export interface WorkspacesGetWorkspaceResult { + /** + * Current workspace metadata, or null if not available + */ + workspace: { + id: string; + cwd?: string; + git_root?: string; + repository?: string; + host_type?: "github" | "ado"; + branch?: string; + summary?: string; + name?: string; + summary_count?: number; + created_at?: string; + updated_at?: string; + mc_task_id?: string; + mc_session_id?: string; + mc_last_event_id?: string; + session_sync_level?: "local" | "user" | "repo_and_user"; + } | null; +} + +export interface WorkspacesListFilesResult { /** * Relative file paths in the workspace files directory */ files: string[]; } -export interface WorkspaceReadFileResult { +export interface WorkspacesReadFileResult { /** * File content as a UTF-8 string */ content: string; } -export interface WorkspaceReadFileRequest { +export interface WorkspacesReadFileRequest { /** * Relative path within the workspace files directory */ path: string; } -export interface WorkspaceCreateFileRequest { +export interface WorkspacesCreateFileRequest { /** * Relative path within the workspace files directory */ @@ -1593,6 +1630,12 @@ export function createSessionRpc(connection: MessageConnection, sessionId: strin set: async (params: Omit): Promise => connection.sendRequest("session.mode.set", { sessionId, ...params }), }, + name: { + get: async (): Promise => + connection.sendRequest("session.name.get", { sessionId }), + set: async (params: Omit): Promise => + connection.sendRequest("session.name.set", { sessionId, ...params }), + }, plan: { read: async (): Promise => connection.sendRequest("session.plan.read", { sessionId }), @@ -1601,13 +1644,15 @@ export function createSessionRpc(connection: MessageConnection, sessionId: strin delete: async (): Promise => connection.sendRequest("session.plan.delete", { sessionId }), }, - workspace: { - listFiles: async (): Promise => - connection.sendRequest("session.workspace.listFiles", { sessionId }), - readFile: async (params: Omit): Promise => - connection.sendRequest("session.workspace.readFile", { sessionId, ...params }), - createFile: async (params: Omit): Promise => - connection.sendRequest("session.workspace.createFile", { sessionId, ...params }), + workspaces: { + getWorkspace: async (): Promise => + connection.sendRequest("session.workspaces.getWorkspace", { sessionId }), + listFiles: async (): Promise => + connection.sendRequest("session.workspaces.listFiles", { sessionId }), + readFile: async (params: Omit): Promise => + connection.sendRequest("session.workspaces.readFile", { sessionId, ...params }), + createFile: async (params: Omit): Promise => + connection.sendRequest("session.workspaces.createFile", { sessionId, ...params }), }, /** @experimental */ fleet: { diff --git a/nodejs/test/e2e/rpc.test.ts b/nodejs/test/e2e/rpc.test.ts index bca4e8cd7..a4c333139 100644 --- a/nodejs/test/e2e/rpc.test.ts +++ b/nodejs/test/e2e/rpc.test.ts @@ -156,28 +156,28 @@ describe("Session RPC", async () => { const session = await client.createSession({ onPermissionRequest: approveAll }); // Initially no files - const initialFiles = await session.rpc.workspace.listFiles(); + const initialFiles = await session.rpc.workspaces.listFiles(); expect(initialFiles.files).toEqual([]); // Create a file const fileContent = "Hello, workspace!"; - await session.rpc.workspace.createFile({ path: "test.txt", content: fileContent }); + await session.rpc.workspaces.createFile({ path: "test.txt", content: fileContent }); // List files - const afterCreate = await session.rpc.workspace.listFiles(); + const afterCreate = await session.rpc.workspaces.listFiles(); expect(afterCreate.files).toContain("test.txt"); // Read file - const readResult = await session.rpc.workspace.readFile({ path: "test.txt" }); + const readResult = await session.rpc.workspaces.readFile({ path: "test.txt" }); expect(readResult.content).toBe(fileContent); // Create nested file - await session.rpc.workspace.createFile({ + await session.rpc.workspaces.createFile({ path: "subdir/nested.txt", content: "Nested content", }); - const afterNested = await session.rpc.workspace.listFiles(); + const afterNested = await session.rpc.workspaces.listFiles(); expect(afterNested.files).toContain("test.txt"); expect(afterNested.files.some((f) => f.includes("nested.txt"))).toBe(true); }); diff --git a/python/copilot/generated/rpc.py b/python/copilot/generated/rpc.py index b24f74e51..a4f15d9e2 100644 --- a/python/copilot/generated/rpc.py +++ b/python/copilot/generated/rpc.py @@ -10,19 +10,17 @@ from collections.abc import Callable from dataclasses import dataclass -from typing import Protocol - - -from dataclasses import dataclass -from typing import Any, TypeVar, Callable, cast from datetime import datetime from enum import Enum +from typing import Any, Protocol, TypeVar, cast from uuid import UUID + import dateutil.parser T = TypeVar("T") EnumT = TypeVar("EnumT", bound=Enum) + def from_str(x: Any) -> str: assert isinstance(x, str) return x @@ -766,7 +764,7 @@ def to_dict(self) -> dict: class MCPServerSource(Enum): """Configuration source - + Configuration source: user, workspace, plugin, or builtin """ BUILTIN = "builtin" @@ -1130,6 +1128,38 @@ def to_dict(self) -> dict: result["mode"] = to_enum(SessionMode, self.mode) return result +@dataclass +class NameGetResult: + name: str | None = None + """The session name, falling back to the auto-generated summary, or null if neither exists""" + + @staticmethod + def from_dict(obj: Any) -> 'NameGetResult': + assert isinstance(obj, dict) + name = from_union([from_none, from_str], obj.get("name")) + return NameGetResult(name) + + def to_dict(self) -> dict: + result: dict = {} + result["name"] = from_union([from_none, from_str], self.name) + return result + +@dataclass +class NameSetRequest: + name: str + """New session name (1–100 characters, trimmed of leading/trailing whitespace)""" + + @staticmethod + def from_dict(obj: Any) -> 'NameSetRequest': + assert isinstance(obj, dict) + name = from_str(obj.get("name")) + return NameSetRequest(name) + + def to_dict(self) -> dict: + result: dict = {} + result["name"] = from_str(self.name) + return result + @dataclass class PlanReadResult: exists: bool @@ -1172,16 +1202,112 @@ def to_dict(self) -> dict: result["content"] = from_str(self.content) return result +class HostType(Enum): + ADO = "ado" + GITHUB = "github" + +class SessionSyncLevel(Enum): + LOCAL = "local" + REPO_AND_USER = "repo_and_user" + USER = "user" + @dataclass -class WorkspaceListFilesResult: +class Workspace: + id: UUID + branch: str | None = None + created_at: datetime | None = None + cwd: str | None = None + git_root: str | None = None + host_type: HostType | None = None + mc_last_event_id: str | None = None + mc_session_id: str | None = None + mc_task_id: str | None = None + name: str | None = None + repository: str | None = None + session_sync_level: SessionSyncLevel | None = None + summary: str | None = None + summary_count: int | None = None + updated_at: datetime | None = None + + @staticmethod + def from_dict(obj: Any) -> 'Workspace': + assert isinstance(obj, dict) + id = UUID(obj.get("id")) + branch = from_union([from_str, from_none], obj.get("branch")) + created_at = from_union([from_datetime, from_none], obj.get("created_at")) + cwd = from_union([from_str, from_none], obj.get("cwd")) + git_root = from_union([from_str, from_none], obj.get("git_root")) + host_type = from_union([HostType, from_none], obj.get("host_type")) + mc_last_event_id = from_union([from_str, from_none], obj.get("mc_last_event_id")) + mc_session_id = from_union([from_str, from_none], obj.get("mc_session_id")) + mc_task_id = from_union([from_str, from_none], obj.get("mc_task_id")) + name = from_union([from_str, from_none], obj.get("name")) + repository = from_union([from_str, from_none], obj.get("repository")) + session_sync_level = from_union([SessionSyncLevel, from_none], obj.get("session_sync_level")) + summary = from_union([from_str, from_none], obj.get("summary")) + summary_count = from_union([from_int, from_none], obj.get("summary_count")) + updated_at = from_union([from_datetime, from_none], obj.get("updated_at")) + return Workspace(id, branch, created_at, cwd, git_root, host_type, mc_last_event_id, mc_session_id, mc_task_id, name, repository, session_sync_level, summary, summary_count, updated_at) + + def to_dict(self) -> dict: + result: dict = {} + result["id"] = str(self.id) + if self.branch is not None: + result["branch"] = from_union([from_str, from_none], self.branch) + if self.created_at is not None: + result["created_at"] = from_union([lambda x: x.isoformat(), from_none], self.created_at) + if self.cwd is not None: + result["cwd"] = from_union([from_str, from_none], self.cwd) + if self.git_root is not None: + result["git_root"] = from_union([from_str, from_none], self.git_root) + if self.host_type is not None: + result["host_type"] = from_union([lambda x: to_enum(HostType, x), from_none], self.host_type) + if self.mc_last_event_id is not None: + result["mc_last_event_id"] = from_union([from_str, from_none], self.mc_last_event_id) + if self.mc_session_id is not None: + result["mc_session_id"] = from_union([from_str, from_none], self.mc_session_id) + if self.mc_task_id is not None: + result["mc_task_id"] = from_union([from_str, from_none], self.mc_task_id) + if self.name is not None: + result["name"] = from_union([from_str, from_none], self.name) + if self.repository is not None: + result["repository"] = from_union([from_str, from_none], self.repository) + if self.session_sync_level is not None: + result["session_sync_level"] = from_union([lambda x: to_enum(SessionSyncLevel, x), from_none], self.session_sync_level) + if self.summary is not None: + result["summary"] = from_union([from_str, from_none], self.summary) + if self.summary_count is not None: + result["summary_count"] = from_union([from_int, from_none], self.summary_count) + if self.updated_at is not None: + result["updated_at"] = from_union([lambda x: x.isoformat(), from_none], self.updated_at) + return result + +@dataclass +class WorkspacesGetWorkspaceResult: + workspace: Workspace | None = None + """Current workspace metadata, or null if not available""" + + @staticmethod + def from_dict(obj: Any) -> 'WorkspacesGetWorkspaceResult': + assert isinstance(obj, dict) + workspace = from_union([Workspace.from_dict, from_none], obj.get("workspace")) + return WorkspacesGetWorkspaceResult(workspace) + + def to_dict(self) -> dict: + result: dict = {} + result["workspace"] = from_union([lambda x: to_class(Workspace, x), from_none], self.workspace) + return result + +@dataclass +class WorkspacesListFilesResult: files: list[str] """Relative file paths in the workspace files directory""" @staticmethod - def from_dict(obj: Any) -> 'WorkspaceListFilesResult': + def from_dict(obj: Any) -> 'WorkspacesListFilesResult': assert isinstance(obj, dict) files = from_list(from_str, obj.get("files")) - return WorkspaceListFilesResult(files) + return WorkspacesListFilesResult(files) def to_dict(self) -> dict: result: dict = {} @@ -1189,15 +1315,15 @@ def to_dict(self) -> dict: return result @dataclass -class WorkspaceReadFileResult: +class WorkspacesReadFileResult: content: str """File content as a UTF-8 string""" @staticmethod - def from_dict(obj: Any) -> 'WorkspaceReadFileResult': + def from_dict(obj: Any) -> 'WorkspacesReadFileResult': assert isinstance(obj, dict) content = from_str(obj.get("content")) - return WorkspaceReadFileResult(content) + return WorkspacesReadFileResult(content) def to_dict(self) -> dict: result: dict = {} @@ -1205,15 +1331,15 @@ def to_dict(self) -> dict: return result @dataclass -class WorkspaceReadFileRequest: +class WorkspacesReadFileRequest: path: str """Relative path within the workspace files directory""" @staticmethod - def from_dict(obj: Any) -> 'WorkspaceReadFileRequest': + def from_dict(obj: Any) -> 'WorkspacesReadFileRequest': assert isinstance(obj, dict) path = from_str(obj.get("path")) - return WorkspaceReadFileRequest(path) + return WorkspacesReadFileRequest(path) def to_dict(self) -> dict: result: dict = {} @@ -1221,7 +1347,7 @@ def to_dict(self) -> dict: return result @dataclass -class WorkspaceCreateFileRequest: +class WorkspacesCreateFileRequest: content: str """File content to write as a UTF-8 string""" @@ -1229,11 +1355,11 @@ class WorkspaceCreateFileRequest: """Relative path within the workspace files directory""" @staticmethod - def from_dict(obj: Any) -> 'WorkspaceCreateFileRequest': + def from_dict(obj: Any) -> 'WorkspacesCreateFileRequest': assert isinstance(obj, dict) content = from_str(obj.get("content")) path = from_str(obj.get("path")) - return WorkspaceCreateFileRequest(content, path) + return WorkspacesCreateFileRequest(content, path) def to_dict(self) -> dict: result: dict = {} @@ -2216,15 +2342,15 @@ class Kind(Enum): class PermissionDecision: kind: Kind """The permission request was approved - + Denied because approval rules explicitly blocked it - + Denied because no approval rule matched and user confirmation was unavailable - + Denied by the user during an interactive prompt - + Denied by the organization's content exclusion policy - + Denied by a permission request hook registered by an extension or plugin """ rules: list[Any] | None = None @@ -2235,7 +2361,7 @@ class PermissionDecision: message: str | None = None """Human-readable explanation of why the path was excluded - + Optional message from the hook explaining the denial """ path: str | None = None @@ -3235,6 +3361,18 @@ def mode_set_request_from_dict(s: Any) -> ModeSetRequest: def mode_set_request_to_dict(x: ModeSetRequest) -> Any: return to_class(ModeSetRequest, x) +def name_get_result_from_dict(s: Any) -> NameGetResult: + return NameGetResult.from_dict(s) + +def name_get_result_to_dict(x: NameGetResult) -> Any: + return to_class(NameGetResult, x) + +def name_set_request_from_dict(s: Any) -> NameSetRequest: + return NameSetRequest.from_dict(s) + +def name_set_request_to_dict(x: NameSetRequest) -> Any: + return to_class(NameSetRequest, x) + def plan_read_result_from_dict(s: Any) -> PlanReadResult: return PlanReadResult.from_dict(s) @@ -3247,29 +3385,35 @@ def plan_update_request_from_dict(s: Any) -> PlanUpdateRequest: def plan_update_request_to_dict(x: PlanUpdateRequest) -> Any: return to_class(PlanUpdateRequest, x) -def workspace_list_files_result_from_dict(s: Any) -> WorkspaceListFilesResult: - return WorkspaceListFilesResult.from_dict(s) +def workspaces_get_workspace_result_from_dict(s: Any) -> WorkspacesGetWorkspaceResult: + return WorkspacesGetWorkspaceResult.from_dict(s) + +def workspaces_get_workspace_result_to_dict(x: WorkspacesGetWorkspaceResult) -> Any: + return to_class(WorkspacesGetWorkspaceResult, x) -def workspace_list_files_result_to_dict(x: WorkspaceListFilesResult) -> Any: - return to_class(WorkspaceListFilesResult, x) +def workspaces_list_files_result_from_dict(s: Any) -> WorkspacesListFilesResult: + return WorkspacesListFilesResult.from_dict(s) -def workspace_read_file_result_from_dict(s: Any) -> WorkspaceReadFileResult: - return WorkspaceReadFileResult.from_dict(s) +def workspaces_list_files_result_to_dict(x: WorkspacesListFilesResult) -> Any: + return to_class(WorkspacesListFilesResult, x) -def workspace_read_file_result_to_dict(x: WorkspaceReadFileResult) -> Any: - return to_class(WorkspaceReadFileResult, x) +def workspaces_read_file_result_from_dict(s: Any) -> WorkspacesReadFileResult: + return WorkspacesReadFileResult.from_dict(s) -def workspace_read_file_request_from_dict(s: Any) -> WorkspaceReadFileRequest: - return WorkspaceReadFileRequest.from_dict(s) +def workspaces_read_file_result_to_dict(x: WorkspacesReadFileResult) -> Any: + return to_class(WorkspacesReadFileResult, x) -def workspace_read_file_request_to_dict(x: WorkspaceReadFileRequest) -> Any: - return to_class(WorkspaceReadFileRequest, x) +def workspaces_read_file_request_from_dict(s: Any) -> WorkspacesReadFileRequest: + return WorkspacesReadFileRequest.from_dict(s) -def workspace_create_file_request_from_dict(s: Any) -> WorkspaceCreateFileRequest: - return WorkspaceCreateFileRequest.from_dict(s) +def workspaces_read_file_request_to_dict(x: WorkspacesReadFileRequest) -> Any: + return to_class(WorkspacesReadFileRequest, x) -def workspace_create_file_request_to_dict(x: WorkspaceCreateFileRequest) -> Any: - return to_class(WorkspaceCreateFileRequest, x) +def workspaces_create_file_request_from_dict(s: Any) -> WorkspacesCreateFileRequest: + return WorkspacesCreateFileRequest.from_dict(s) + +def workspaces_create_file_request_to_dict(x: WorkspacesCreateFileRequest) -> Any: + return to_class(WorkspacesCreateFileRequest, x) def fleet_start_result_from_dict(s: Any) -> FleetStartResult: return FleetStartResult.from_dict(s) @@ -3709,6 +3853,20 @@ async def set(self, params: ModeSetRequest, *, timeout: float | None = None) -> await self._client.request("session.mode.set", params_dict, **_timeout_kwargs(timeout)) +class NameApi: + def __init__(self, client: "JsonRpcClient", session_id: str): + self._client = client + self._session_id = session_id + + async def get(self, *, timeout: float | None = None) -> NameGetResult: + return NameGetResult.from_dict(await self._client.request("session.name.get", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) + + async def set(self, params: NameSetRequest, *, timeout: float | None = None) -> None: + params_dict = {k: v for k, v in params.to_dict().items() if v is not None} + params_dict["sessionId"] = self._session_id + await self._client.request("session.name.set", params_dict, **_timeout_kwargs(timeout)) + + class PlanApi: def __init__(self, client: "JsonRpcClient", session_id: str): self._client = client @@ -3726,23 +3884,26 @@ async def delete(self, *, timeout: float | None = None) -> None: await self._client.request("session.plan.delete", {"sessionId": self._session_id}, **_timeout_kwargs(timeout)) -class WorkspaceApi: +class WorkspacesApi: def __init__(self, client: "JsonRpcClient", session_id: str): self._client = client self._session_id = session_id - async def list_files(self, *, timeout: float | None = None) -> WorkspaceListFilesResult: - return WorkspaceListFilesResult.from_dict(await self._client.request("session.workspace.listFiles", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) + async def get_workspace(self, *, timeout: float | None = None) -> WorkspacesGetWorkspaceResult: + return WorkspacesGetWorkspaceResult.from_dict(await self._client.request("session.workspaces.getWorkspace", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) + + async def list_files(self, *, timeout: float | None = None) -> WorkspacesListFilesResult: + return WorkspacesListFilesResult.from_dict(await self._client.request("session.workspaces.listFiles", {"sessionId": self._session_id}, **_timeout_kwargs(timeout))) - async def read_file(self, params: WorkspaceReadFileRequest, *, timeout: float | None = None) -> WorkspaceReadFileResult: + async def read_file(self, params: WorkspacesReadFileRequest, *, timeout: float | None = None) -> WorkspacesReadFileResult: params_dict = {k: v for k, v in params.to_dict().items() if v is not None} params_dict["sessionId"] = self._session_id - return WorkspaceReadFileResult.from_dict(await self._client.request("session.workspace.readFile", params_dict, **_timeout_kwargs(timeout))) + return WorkspacesReadFileResult.from_dict(await self._client.request("session.workspaces.readFile", params_dict, **_timeout_kwargs(timeout))) - async def create_file(self, params: WorkspaceCreateFileRequest, *, timeout: float | None = None) -> None: + async def create_file(self, params: WorkspacesCreateFileRequest, *, timeout: float | None = None) -> None: params_dict = {k: v for k, v in params.to_dict().items() if v is not None} params_dict["sessionId"] = self._session_id - await self._client.request("session.workspace.createFile", params_dict, **_timeout_kwargs(timeout)) + await self._client.request("session.workspaces.createFile", params_dict, **_timeout_kwargs(timeout)) # Experimental: this API group is experimental and may change or be removed. @@ -3957,8 +4118,9 @@ def __init__(self, client: "JsonRpcClient", session_id: str): self._session_id = session_id self.model = ModelApi(client, session_id) self.mode = ModeApi(client, session_id) + self.name = NameApi(client, session_id) self.plan = PlanApi(client, session_id) - self.workspace = WorkspaceApi(client, session_id) + self.workspaces = WorkspacesApi(client, session_id) self.fleet = FleetApi(client, session_id) self.agent = AgentApi(client, session_id) self.skills = SkillsApi(client, session_id) diff --git a/python/e2e/test_rpc.py b/python/e2e/test_rpc.py index 0d9f9a4eb..c5e9a7b79 100644 --- a/python/e2e/test_rpc.py +++ b/python/e2e/test_rpc.py @@ -187,8 +187,8 @@ async def test_read_update_and_delete_plan(self): async def test_create_list_and_read_workspace_files(self): """Test creating, listing, and reading workspace files""" from copilot.generated.rpc import ( - WorkspaceCreateFileRequest, - WorkspaceReadFileRequest, + WorkspacesCreateFileRequest, + WorkspacesReadFileRequest, ) client = CopilotClient(SubprocessConfig(cli_path=CLI_PATH, use_stdio=True)) @@ -200,31 +200,31 @@ async def test_create_list_and_read_workspace_files(self): ) # Initially no files - initial_files = await session.rpc.workspace.list_files() + initial_files = await session.rpc.workspaces.list_files() assert initial_files.files == [] # Create a file file_content = "Hello, workspace!" - await session.rpc.workspace.create_file( - WorkspaceCreateFileRequest(content=file_content, path="test.txt") + await session.rpc.workspaces.create_file( + WorkspacesCreateFileRequest(content=file_content, path="test.txt") ) # List files - after_create = await session.rpc.workspace.list_files() + after_create = await session.rpc.workspaces.list_files() assert "test.txt" in after_create.files # Read file - read_result = await session.rpc.workspace.read_file( - WorkspaceReadFileRequest(path="test.txt") + read_result = await session.rpc.workspaces.read_file( + WorkspacesReadFileRequest(path="test.txt") ) assert read_result.content == file_content # Create nested file - await session.rpc.workspace.create_file( - WorkspaceCreateFileRequest(content="Nested content", path="subdir/nested.txt") + await session.rpc.workspaces.create_file( + WorkspacesCreateFileRequest(content="Nested content", path="subdir/nested.txt") ) - after_nested = await session.rpc.workspace.list_files() + after_nested = await session.rpc.workspaces.list_files() assert "test.txt" in after_nested.files assert any("nested.txt" in f for f in after_nested.files) diff --git a/scripts/codegen/csharp.ts b/scripts/codegen/csharp.ts index 9e63b68ea..243047fb6 100644 --- a/scripts/codegen/csharp.ts +++ b/scripts/codegen/csharp.ts @@ -258,6 +258,11 @@ function emitDataAnnotations(schema: JSONSchema7, indent: string): string[] { } // [MinLength] / [MaxLength] for string constraints + if (typeof schema.minLength === "number" || typeof schema.maxLength === "number") { + attrs.push( + `${indent}[UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")]` + ); + } if (typeof schema.minLength === "number") { attrs.push(`${indent}[MinLength(${schema.minLength})]`); } diff --git a/scripts/codegen/python.ts b/scripts/codegen/python.ts index 62b53e1e6..46d11de83 100644 --- a/scripts/codegen/python.ts +++ b/scripts/codegen/python.ts @@ -1454,6 +1454,14 @@ async function generateRpc(schemaPath?: string): Promise { typesCode = modernizePython(typesCode); typesCode = collapsePlaceholderPythonDataclasses(typesCode); + // Strip quicktype's import block and preamble — we provide our own unified header. + // The preamble ends just before the first helper function (e.g. "def from_str") + // or class definition. + typesCode = typesCode.replace(/^[\s\S]*?(?=^(?:def |@dataclass|class )\w)/m, ""); + + // Strip trailing whitespace from blank lines (e.g. inside multi-line docstrings) + typesCode = typesCode.replace(/^\s+$/gm, ""); + // Annotate experimental data types const experimentalTypeNames = new Set(); for (const method of allMethods) { @@ -1494,7 +1502,15 @@ if TYPE_CHECKING: from collections.abc import Callable from dataclasses import dataclass -from typing import Protocol +from datetime import datetime +from enum import Enum +from typing import Any, Protocol, TypeVar, cast +from uuid import UUID + +import dateutil.parser + +T = TypeVar("T") +EnumT = TypeVar("EnumT", bound=Enum) `); lines.push(typesCode); diff --git a/test/harness/package-lock.json b/test/harness/package-lock.json index 691d66bf9..ba4ed7d10 100644 --- a/test/harness/package-lock.json +++ b/test/harness/package-lock.json @@ -9,7 +9,7 @@ "version": "1.0.0", "license": "ISC", "devDependencies": { - "@github/copilot": "^1.0.22", + "@github/copilot": "^1.0.26", "@modelcontextprotocol/sdk": "^1.26.0", "@types/node": "^25.3.3", "openai": "^6.17.0", @@ -462,27 +462,27 @@ } }, "node_modules/@github/copilot": { - "version": "1.0.22", - "resolved": "https://registry.npmjs.org/@github/copilot/-/copilot-1.0.22.tgz", - "integrity": "sha512-BR9oTJ1tQ51RV81xcxmlZe0zB3Tf8i/vFsKSTm2f5wRLJgtuVl2LgaFStoI/peTFcmgtZbhrqsnWTu5GkEPK5Q==", + "version": "1.0.26", + "resolved": "https://registry.npmjs.org/@github/copilot/-/copilot-1.0.26.tgz", + "integrity": "sha512-F7P6yimFzjvWxOF/A0F6k//vcpSVcVusQjaybb3IKyrEDhnd/LOv2tD+x6W0IoxCftGDDhkzBA2aon3rL9lPhQ==", "dev": true, "license": "SEE LICENSE IN LICENSE.md", "bin": { "copilot": "npm-loader.js" }, "optionalDependencies": { - "@github/copilot-darwin-arm64": "1.0.22", - "@github/copilot-darwin-x64": "1.0.22", - "@github/copilot-linux-arm64": "1.0.22", - "@github/copilot-linux-x64": "1.0.22", - "@github/copilot-win32-arm64": "1.0.22", - "@github/copilot-win32-x64": "1.0.22" + "@github/copilot-darwin-arm64": "1.0.26", + "@github/copilot-darwin-x64": "1.0.26", + "@github/copilot-linux-arm64": "1.0.26", + "@github/copilot-linux-x64": "1.0.26", + "@github/copilot-win32-arm64": "1.0.26", + "@github/copilot-win32-x64": "1.0.26" } }, "node_modules/@github/copilot-darwin-arm64": { - "version": "1.0.22", - "resolved": "https://registry.npmjs.org/@github/copilot-darwin-arm64/-/copilot-darwin-arm64-1.0.22.tgz", - "integrity": "sha512-cK42uX+oz46Cjsb7z+rdPw+DIGczfVSFWlc1WDcdVlwBW4cEfV0pzFXExpN1r1z179TFgAaVMbhkgLqhOZ/PeQ==", + "version": "1.0.26", + "resolved": "https://registry.npmjs.org/@github/copilot-darwin-arm64/-/copilot-darwin-arm64-1.0.26.tgz", + "integrity": "sha512-eV+jDMj4vnjdGcG+c4zg11zZKVAp94Hm4sK4f9LnyWw8MumTfS5F2Yyse9zt7A3oGlegyczmJopKwuwZbQd4ww==", "cpu": [ "arm64" ], @@ -497,9 +497,9 @@ } }, "node_modules/@github/copilot-darwin-x64": { - "version": "1.0.22", - "resolved": "https://registry.npmjs.org/@github/copilot-darwin-x64/-/copilot-darwin-x64-1.0.22.tgz", - "integrity": "sha512-Pmw0ipF+yeLbP6JctsEoMS2LUCpVdC2r557BnCoe48BN8lO8i9JLnkpuDDrJ1AZuCk1VjnujFKEQywOOdfVlpA==", + "version": "1.0.26", + "resolved": "https://registry.npmjs.org/@github/copilot-darwin-x64/-/copilot-darwin-x64-1.0.26.tgz", + "integrity": "sha512-2AAgu19F3scDlYhsiHxCn0cz4ZkINq8gxnqW0an8VQn6p15lDcah6PqHw+RJ+12qiYX5L5NNACty9UOkIK7Kzg==", "cpu": [ "x64" ], @@ -514,9 +514,9 @@ } }, "node_modules/@github/copilot-linux-arm64": { - "version": "1.0.22", - "resolved": "https://registry.npmjs.org/@github/copilot-linux-arm64/-/copilot-linux-arm64-1.0.22.tgz", - "integrity": "sha512-WVgG67VmZgHoD7GMlkTxEVe1qK8k9Ek9A02/Da7obpsDdtBInt3nJTwBEgm4cNDM4XaenQH17/jmwVtTwXB6lw==", + "version": "1.0.26", + "resolved": "https://registry.npmjs.org/@github/copilot-linux-arm64/-/copilot-linux-arm64-1.0.26.tgz", + "integrity": "sha512-SnM7+TGAZ/i9dim5FfHM7+ii01hdpHJzzh8vnnA1Fa7RPFJaQ2KTOdTDJFgfv6e/jLhKXZEelYIidgCA3vSQCQ==", "cpu": [ "arm64" ], @@ -531,9 +531,9 @@ } }, "node_modules/@github/copilot-linux-x64": { - "version": "1.0.22", - "resolved": "https://registry.npmjs.org/@github/copilot-linux-x64/-/copilot-linux-x64-1.0.22.tgz", - "integrity": "sha512-XRkHVFmdC7FMrczXOdPjbNKiknMr13asKtwJoErJO/Xdy4cmzKQHSvNsBk8VNrr7oyWrUcB1F6mbIxb2LFxPOw==", + "version": "1.0.26", + "resolved": "https://registry.npmjs.org/@github/copilot-linux-x64/-/copilot-linux-x64-1.0.26.tgz", + "integrity": "sha512-x76vcwVbi0j03hFMhiQs+Eqefd9Xmc4qJoaj44YA2VsJuDbZw2Yv7ZBq7Vyxd/shJwJZjaKv36MHcx5bVUMBJQ==", "cpu": [ "x64" ], @@ -548,9 +548,9 @@ } }, "node_modules/@github/copilot-win32-arm64": { - "version": "1.0.22", - "resolved": "https://registry.npmjs.org/@github/copilot-win32-arm64/-/copilot-win32-arm64-1.0.22.tgz", - "integrity": "sha512-Ao6gv1f2ZV+HVlkB1MV7YFdCuaB3NcFCnNu0a6/WLl2ypsfP1vWosPPkIB32jQJeBkT9ku3exOZLRj+XC0P3Mg==", + "version": "1.0.26", + "resolved": "https://registry.npmjs.org/@github/copilot-win32-arm64/-/copilot-win32-arm64-1.0.26.tgz", + "integrity": "sha512-enVRcy7W9RD1bwYkF+mcxR+biXsG/X5m46XBaD0opvfDeiBHceDnI8hEI0O1A5PYvRo88AZFvDEmEW3Gdj6+rQ==", "cpu": [ "arm64" ], @@ -565,9 +565,9 @@ } }, "node_modules/@github/copilot-win32-x64": { - "version": "1.0.22", - "resolved": "https://registry.npmjs.org/@github/copilot-win32-x64/-/copilot-win32-x64-1.0.22.tgz", - "integrity": "sha512-EppcL+3TpxC+X/eQEIYtkN0PaA3/cvtI9UJqldLIkKDPXNYk/0mw877Ru9ypRcBWBWokDN6iKIWk5IxYH+JIvg==", + "version": "1.0.26", + "resolved": "https://registry.npmjs.org/@github/copilot-win32-x64/-/copilot-win32-x64-1.0.26.tgz", + "integrity": "sha512-DpJF6C1x4+sYIXUx5+vWCu6cFAbD2YlrXQ/BRttf2MMdc0DHwdgJxrttBBF2qCvmpfzjSE8cr5G0kt5EUk7FGw==", "cpu": [ "x64" ], diff --git a/test/harness/package.json b/test/harness/package.json index def9f09cf..527c036b7 100644 --- a/test/harness/package.json +++ b/test/harness/package.json @@ -11,7 +11,7 @@ "test": "vitest run" }, "devDependencies": { - "@github/copilot": "^1.0.22", + "@github/copilot": "^1.0.26", "@modelcontextprotocol/sdk": "^1.26.0", "@types/node": "^25.3.3", "openai": "^6.17.0",