@@ -6003,31 +5958,6 @@ pub struct PushAttachmentFile {
pub r#type: PushAttachmentFileType,
}
-/// GitHub issue, pull request, or discussion reference
-///
-///
-///
-/// **Experimental.** This type is part of an experimental wire-protocol surface
-/// and may change or be removed in future SDK or CLI releases.
-///
-///
-#[derive(Debug, Clone, Default, Serialize, Deserialize)]
-#[serde(rename_all = "camelCase")]
-pub struct PushAttachmentGithubReference {
- /// Issue, pull request, or discussion number
- pub number: i64,
- /// Type of GitHub reference
- pub reference_type: PushAttachmentGithubReferenceType,
- /// Current state of the referenced item (e.g., open, closed, merged)
- pub state: String,
- /// Title of the referenced item
- pub title: String,
- /// Attachment type discriminator
- pub r#type: PushAttachmentGithubReferenceType,
- /// URL to the referenced item on GitHub
- pub url: String,
-}
-
/// End position of the selection
///
///
@@ -7118,26 +7048,6 @@ pub struct SessionInstalledPlugin {
pub version: Option
,
}
-/// Schema for the `SessionInstalledPluginSourceGithub` type.
-///
-///
-///
-/// **Experimental.** This type is part of an experimental wire-protocol surface
-/// and may change or be removed in future SDK or CLI releases.
-///
-///
-#[derive(Debug, Clone, Default, Serialize, Deserialize)]
-#[serde(rename_all = "camelCase")]
-pub struct SessionInstalledPluginSourceGithub {
- #[serde(skip_serializing_if = "Option::is_none")]
- pub path: Option,
- #[serde(skip_serializing_if = "Option::is_none")]
- pub r#ref: Option,
- pub repo: String,
- /// Constant value. Always "github".
- pub source: SessionInstalledPluginSourceGithubSource,
-}
-
/// Schema for the `SessionInstalledPluginSourceLocal` type.
///
///
@@ -9954,6 +9864,96 @@ pub struct WorkspaceSummary {
pub updated_at: Option
,
}
+/// GitHub issue, pull request, or discussion reference
+///
+///
+///
+/// **Experimental.** This type is part of an experimental wire-protocol surface
+/// and may change or be removed in future SDK or CLI releases.
+///
+///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)]
+#[serde(rename_all = "camelCase")]
+pub struct AttachmentGitHubReference {
+ /// Issue, pull request, or discussion number
+ pub number: i64,
+ /// Type of GitHub reference
+ pub reference_type: AttachmentGitHubReferenceType,
+ /// Current state of the referenced item (e.g., open, closed, merged)
+ pub state: String,
+ /// Title of the referenced item
+ pub title: String,
+ /// Attachment type discriminator
+ pub r#type: AttachmentGitHubReferenceType,
+ /// URL to the referenced item on GitHub
+ pub url: String,
+}
+
+/// Schema for the `InstalledPluginSourceGitHub` type.
+///
+///
+///
+/// **Experimental.** This type is part of an experimental wire-protocol surface
+/// and may change or be removed in future SDK or CLI releases.
+///
+///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)]
+#[serde(rename_all = "camelCase")]
+pub struct InstalledPluginSourceGitHub {
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub path: Option,
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub r#ref: Option,
+ pub repo: String,
+ /// Constant value. Always "github".
+ pub source: InstalledPluginSourceGitHubSource,
+}
+
+/// GitHub issue, pull request, or discussion reference
+///
+///
+///
+/// **Experimental.** This type is part of an experimental wire-protocol surface
+/// and may change or be removed in future SDK or CLI releases.
+///
+///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)]
+#[serde(rename_all = "camelCase")]
+pub struct PushAttachmentGitHubReference {
+ /// Issue, pull request, or discussion number
+ pub number: i64,
+ /// Type of GitHub reference
+ pub reference_type: PushAttachmentGitHubReferenceType,
+ /// Current state of the referenced item (e.g., open, closed, merged)
+ pub state: String,
+ /// Title of the referenced item
+ pub title: String,
+ /// Attachment type discriminator
+ pub r#type: PushAttachmentGitHubReferenceType,
+ /// URL to the referenced item on GitHub
+ pub url: String,
+}
+
+/// Schema for the `SessionInstalledPluginSourceGitHub` type.
+///
+///
+///
+/// **Experimental.** This type is part of an experimental wire-protocol surface
+/// and may change or be removed in future SDK or CLI releases.
+///
+///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)]
+#[serde(rename_all = "camelCase")]
+pub struct SessionInstalledPluginSourceGitHub {
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub path: Option,
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub r#ref: Option,
+ pub repo: String,
+ /// Constant value. Always "github".
+ pub source: SessionInstalledPluginSourceGitHubSource,
+}
+
/// List of Copilot models available to the resolved user, including capabilities and billing metadata.
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
@@ -13280,31 +13280,6 @@ pub enum AttachmentFileType {
File,
}
-/// Type of GitHub reference
-///
-///
-///
-/// **Experimental.** This type is part of an experimental wire-protocol surface
-/// and may change or be removed in future SDK or CLI releases.
-///
-///
-#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
-pub enum AttachmentGithubReferenceType {
- /// GitHub issue reference.
- #[serde(rename = "issue")]
- Issue,
- /// GitHub pull request reference.
- #[serde(rename = "pr")]
- Pr,
- /// GitHub discussion reference.
- #[serde(rename = "discussion")]
- Discussion,
- /// Unknown variant for forward compatibility.
- #[default]
- #[serde(other)]
- Unknown,
-}
-
/// Attachment type discriminator
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
pub enum AttachmentSelectionType {
@@ -13461,7 +13436,7 @@ pub enum ContentFilterMode {
pub enum CopilotApiTokenAuthInfoHost {
#[serde(rename = "https://github.com")]
#[default]
- HttpsGithubCom,
+ HttpsGitHubCom,
}
/// Direct Copilot API authentication via the `GITHUB_COPILOT_API_TOKEN` + `COPILOT_API_URL` environment-variable pair. The token itself is read from the environment by the runtime, not carried in this struct.
@@ -13708,7 +13683,7 @@ pub enum GhCliAuthInfoType {
pub enum HMACAuthInfoHost {
#[serde(rename = "https://github.com")]
#[default]
- HttpsGithubCom,
+ HttpsGitHubCom,
}
/// HMAC-based authentication used by GitHub-internal services.
@@ -13719,14 +13694,6 @@ pub enum HMACAuthInfoType {
Hmac,
}
-/// Constant value. Always "github".
-#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
-pub enum InstalledPluginSourceGithubSource {
- #[serde(rename = "github")]
- #[default]
- Github,
-}
-
/// Constant value. Always "local".
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
pub enum InstalledPluginSourceLocalSource {
@@ -14116,7 +14083,7 @@ pub enum McpSetEnvValueModeDetails {
pub enum SessionWorkingDirectoryContextHostType {
/// The working directory repository is hosted on GitHub.
#[serde(rename = "github")]
- Github,
+ GitHub,
/// The working directory repository is hosted on Azure DevOps.
#[serde(rename = "ado")]
Ado,
@@ -14854,31 +14821,6 @@ pub enum PushAttachmentFileType {
File,
}
-/// Type of GitHub reference
-///
-///
-///
-/// **Experimental.** This type is part of an experimental wire-protocol surface
-/// and may change or be removed in future SDK or CLI releases.
-///
-///
-#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
-pub enum PushAttachmentGithubReferenceType {
- /// GitHub issue reference.
- #[serde(rename = "issue")]
- Issue,
- /// GitHub pull request reference.
- #[serde(rename = "pr")]
- Pr,
- /// GitHub discussion reference.
- #[serde(rename = "discussion")]
- Discussion,
- /// Unknown variant for forward compatibility.
- #[default]
- #[serde(other)]
- Unknown,
-}
-
/// Attachment type discriminator
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
pub enum PushAttachmentSelectionType {
@@ -14996,7 +14938,7 @@ pub enum SendMode {
pub enum SessionContextHostType {
/// Session repository is hosted on GitHub.
#[serde(rename = "github")]
- Github,
+ GitHub,
/// Session repository is hosted on Azure DevOps.
#[serde(rename = "ado")]
Ado,
@@ -15088,14 +15030,6 @@ pub enum SessionFsSqliteQueryType {
Unknown,
}
-/// Constant value. Always "github".
-#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
-pub enum SessionInstalledPluginSourceGithubSource {
- #[serde(rename = "github")]
- #[default]
- Github,
-}
-
/// Constant value. Always "local".
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
pub enum SessionInstalledPluginSourceLocalSource {
@@ -15124,7 +15058,7 @@ pub enum SessionInstalledPluginSourceUrlSource {
pub enum WorkspaceSummaryHostType {
/// Workspace summary repository is hosted on GitHub.
#[serde(rename = "github")]
- Github,
+ GitHub,
/// Workspace summary repository is hosted on Azure DevOps.
#[serde(rename = "ado")]
Ado,
@@ -15582,7 +15516,7 @@ pub enum WorkspaceDiffMode {
pub enum WorkspacesWorkspaceDetailsHostType {
/// Workspace repository is hosted on GitHub.
#[serde(rename = "github")]
- Github,
+ GitHub,
/// Workspace repository is hosted on Azure DevOps.
#[serde(rename = "ado")]
Ado,
@@ -15591,3 +15525,69 @@ pub enum WorkspacesWorkspaceDetailsHostType {
#[serde(other)]
Unknown,
}
+
+/// Type of GitHub reference
+///
+///
+///
+/// **Experimental.** This type is part of an experimental wire-protocol surface
+/// and may change or be removed in future SDK or CLI releases.
+///
+///
+#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
+pub enum AttachmentGitHubReferenceType {
+ /// GitHub issue reference.
+ #[serde(rename = "issue")]
+ Issue,
+ /// GitHub pull request reference.
+ #[serde(rename = "pr")]
+ Pr,
+ /// GitHub discussion reference.
+ #[serde(rename = "discussion")]
+ Discussion,
+ /// Unknown variant for forward compatibility.
+ #[default]
+ #[serde(other)]
+ Unknown,
+}
+
+/// Constant value. Always "github".
+#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
+pub enum InstalledPluginSourceGitHubSource {
+ #[serde(rename = "github")]
+ #[default]
+ GitHub,
+}
+
+/// Type of GitHub reference
+///
+///
+///
+/// **Experimental.** This type is part of an experimental wire-protocol surface
+/// and may change or be removed in future SDK or CLI releases.
+///
+///
+#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
+pub enum PushAttachmentGitHubReferenceType {
+ /// GitHub issue reference.
+ #[serde(rename = "issue")]
+ Issue,
+ /// GitHub pull request reference.
+ #[serde(rename = "pr")]
+ Pr,
+ /// GitHub discussion reference.
+ #[serde(rename = "discussion")]
+ Discussion,
+ /// Unknown variant for forward compatibility.
+ #[default]
+ #[serde(other)]
+ Unknown,
+}
+
+/// Constant value. Always "github".
+#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
+pub enum SessionInstalledPluginSourceGitHubSource {
+ #[serde(rename = "github")]
+ #[default]
+ GitHub,
+}
diff --git a/rust/src/generated/session_events.rs b/rust/src/generated/session_events.rs
index 1828a3e41..e889cf942 100644
--- a/rust/src/generated/session_events.rs
+++ b/rust/src/generated/session_events.rs
@@ -3336,7 +3336,7 @@ pub struct McpAppToolCallCompleteData {
pub enum WorkingDirectoryContextHostType {
/// Repository is hosted on GitHub.
#[serde(rename = "github")]
- Github,
+ GitHub,
/// Repository is hosted on Azure DevOps.
#[serde(rename = "ado")]
Ado,
diff --git a/rust/tests/e2e/rpc_session_state.rs b/rust/tests/e2e/rpc_session_state.rs
index 956a8c90e..785752f1f 100644
--- a/rust/tests/e2e/rpc_session_state.rs
+++ b/rust/tests/e2e/rpc_session_state.rs
@@ -691,7 +691,7 @@ async fn should_call_metadata_snapshot_setworkingdirectory_and_recordcontextchan
cwd: subdir.display().to_string(),
git_root: Some(ctx.repo_root().display().to_string()),
head_commit: None,
- host_type: Some(SessionWorkingDirectoryContextHostType::Github),
+ host_type: Some(SessionWorkingDirectoryContextHostType::GitHub),
repository: Some("github/copilot-sdk".to_string()),
repository_host: Some("github.com".to_string()),
},
diff --git a/scripts/codegen/csharp.ts b/scripts/codegen/csharp.ts
index 883895cde..7b0f64a77 100644
--- a/scripts/codegen/csharp.ts
+++ b/scripts/codegen/csharp.ts
@@ -46,6 +46,8 @@ import {
getSessionEventVariantSchemas,
getSharedSessionEventEnvelopeProperties,
rewriteSharedDefinitionReferences,
+ loadSchemaJson,
+ fixBrandCasing,
REPO_ROOT,
type ApiSchema,
type DefinitionCollections,
@@ -217,7 +219,7 @@ function xmlDocEnumMemberComment(enumValueDescriptions: EnumValueDescriptions |
function toPascalCase(name: string): string {
const parts = splitCSharpIdentifierParts(name);
if (parts.length > 1) return parts.map(toPascalCasePart).join("");
- return name.charAt(0).toUpperCase() + name.slice(1);
+ return fixBrandCasing(name.charAt(0).toUpperCase() + name.slice(1));
}
function stripDurationMillisecondsSuffix(name: string): string {
@@ -244,7 +246,7 @@ function splitCSharpIdentifierParts(value: string): string[] {
}
function toPascalCasePart(value: string): string {
- return value.charAt(0).toUpperCase() + value.slice(1);
+ return fixBrandCasing(value.charAt(0).toUpperCase() + value.slice(1));
}
function toCSharpIdentifier(value: string, fallback: string): string {
@@ -1408,7 +1410,7 @@ namespace GitHub.Copilot;
export async function generateSessionEvents(schemaPath?: string): Promise {
console.log("C#: generating session-events...");
const resolvedPath = schemaPath ?? (await getSessionEventsSchemaPath());
- const schema = cloneSchemaForCodegen(JSON.parse(await fs.readFile(resolvedPath, "utf-8")) as JSONSchema7);
+ const schema = cloneSchemaForCodegen((await loadSchemaJson(resolvedPath)) as JSONSchema7);
const processed = propagateInternalVisibility(postProcessSchema(schema));
const code = generateSessionEventsCode(processed);
const outPath = await writeGeneratedFile("dotnet/src/Generated/SessionEvents.cs", code);
@@ -2392,7 +2394,7 @@ namespace GitHub.Copilot.Rpc;
export async function generateRpc(schemaPath?: string, sessionEventsSchema?: JSONSchema7): Promise {
console.log("C#: generating RPC types...");
const resolvedPath = schemaPath ?? (await getApiSchemaPath());
- let schema = fixNullableRequiredRefsInApiSchema(cloneSchemaForCodegen(JSON.parse(await fs.readFile(resolvedPath, "utf-8")) as ApiSchema));
+ let schema = fixNullableRequiredRefsInApiSchema(cloneSchemaForCodegen((await loadSchemaJson(resolvedPath)) as ApiSchema));
if (sessionEventsSchema) {
const sharedDefinitions = findSharedSchemaDefinitions(
schema as unknown as Record,
@@ -2449,7 +2451,7 @@ async function generate(sessionSchemaPath?: string, apiSchemaPath?: string): Pro
await generateSessionEvents(sessionSchemaPath);
try {
const resolvedSessionPath = sessionSchemaPath ?? (await getSessionEventsSchemaPath());
- const sessionSchema = propagateInternalVisibility(postProcessSchema(cloneSchemaForCodegen(JSON.parse(await fs.readFile(resolvedSessionPath, "utf-8")) as JSONSchema7)));
+ const sessionSchema = propagateInternalVisibility(postProcessSchema(cloneSchemaForCodegen((await loadSchemaJson(resolvedSessionPath)) as JSONSchema7)));
await generateRpc(apiSchemaPath, sessionSchema);
} catch (err) {
if ((err as NodeJS.ErrnoException).code === "ENOENT" && !apiSchemaPath) {
diff --git a/scripts/codegen/go.ts b/scripts/codegen/go.ts
index 86182a52c..69556d094 100644
--- a/scripts/codegen/go.ts
+++ b/scripts/codegen/go.ts
@@ -40,6 +40,7 @@ import {
isSchemaExperimental,
isSchemaInternal,
isVoidSchema,
+ loadSchemaJson,
parseExternalSchemaRef,
postProcessSchema,
propagateInternalVisibility,
@@ -78,6 +79,7 @@ const goIdentifierCasingOverrides = new Map([
["urls", "URLs"],
["uris", "URIs"],
["ids", "IDs"],
+ ["github", "GitHub"],
]);
const goCommentTextWrapLength = 90;
const wrapGoCommentText = wordwrap(goCommentTextWrapLength);
@@ -3628,7 +3630,7 @@ async function generateSessionEvents(schemaPath?: string, apiSchema?: ApiSchema)
console.log("Go: generating session-events...");
const resolvedPath = schemaPath ?? (await getSessionEventsSchemaPath());
- const schema = cloneSchemaForCodegen(JSON.parse(await fs.readFile(resolvedPath, "utf-8")) as JSONSchema7);
+ const schema = cloneSchemaForCodegen((await loadSchemaJson(resolvedPath)) as JSONSchema7);
const processed = propagateInternalVisibility(postProcessSchema(schema));
const processedApiSchema = apiSchema
? propagateInternalVisibility(postProcessSchema(cloneSchemaForCodegen(apiSchema as JSONSchema7)) as JSONSchema7)
@@ -3728,7 +3730,7 @@ async function generateRpc(schemaPath?: string): Promise {
console.log("Go: generating RPC types...");
const resolvedPath = schemaPath ?? (await getApiSchemaPath());
- const schema = propagateInternalVisibility(fixNullableRequiredRefsInApiSchema(cloneSchemaForCodegen(JSON.parse(await fs.readFile(resolvedPath, "utf-8")) as ApiSchema)) as JSONSchema7) as unknown as ApiSchema;
+ const schema = propagateInternalVisibility(fixNullableRequiredRefsInApiSchema(cloneSchemaForCodegen((await loadSchemaJson(resolvedPath)) as ApiSchema)) as JSONSchema7) as unknown as ApiSchema;
const allMethods = [
...collectRpcMethods(schema.server || {}),
@@ -4304,7 +4306,7 @@ async function generate(sessionSchemaPath?: string, apiSchemaPath?: string): Pro
let apiSchemaForSharing: ApiSchema | undefined;
try {
const resolvedApiPath = apiSchemaPath ?? (await getApiSchemaPath());
- apiSchemaForSharing = fixNullableRequiredRefsInApiSchema(cloneSchemaForCodegen(JSON.parse(await fs.readFile(resolvedApiPath, "utf-8")) as ApiSchema));
+ apiSchemaForSharing = fixNullableRequiredRefsInApiSchema(cloneSchemaForCodegen((await loadSchemaJson(resolvedApiPath)) as ApiSchema));
} catch (err) {
if ((err as NodeJS.ErrnoException).code !== "ENOENT" || apiSchemaPath) {
throw err;
diff --git a/scripts/codegen/python.ts b/scripts/codegen/python.ts
index 9e54dcc45..08a37945f 100644
--- a/scripts/codegen/python.ts
+++ b/scripts/codegen/python.ts
@@ -50,6 +50,8 @@ import {
getSessionEventVariantSchemas,
getSharedSessionEventEnvelopeProperties,
getEnumValueDescriptions,
+ loadSchemaJson,
+ fixBrandCasing,
type ApiSchema,
type DefinitionCollections,
type EnumValueDescriptions,
@@ -1176,10 +1178,12 @@ function removeRequiredAnyDefaultsForPython(
}
function toPascalCase(s: string): string {
- return s
- .split(/[._]/)
- .map((w) => w.charAt(0).toUpperCase() + w.slice(1))
- .join("");
+ return fixBrandCasing(
+ s
+ .split(/[._]/)
+ .map((w) => w.charAt(0).toUpperCase() + w.slice(1))
+ .join("")
+ );
}
function collectRpcMethods(node: Record): RpcMethod[] {
@@ -2682,7 +2686,7 @@ async function generateSessionEvents(schemaPath?: string): Promise {
console.log("Python: generating session-events...");
const resolvedPath = schemaPath ?? (await getSessionEventsSchemaPath());
- const schema = JSON.parse(await fs.readFile(resolvedPath, "utf-8")) as JSONSchema7;
+ const schema = (await loadSchemaJson(resolvedPath)) as JSONSchema7;
const processed = propagateInternalVisibility(postProcessSchema(schema));
let code = generatePythonSessionEventsCode(processed);
const { typeNames } = collectInternalSymbols(processed);
@@ -2699,7 +2703,7 @@ async function generateRpc(schemaPath?: string, sessionEventsSchema?: JSONSchema
const { FetchingJSONSchemaStore, InputData, JSONSchemaInput, quicktype } = await import("quicktype-core");
const resolvedPath = schemaPath ?? (await getApiSchemaPath());
- let schema = fixNullableRequiredRefsInApiSchema(cloneSchemaForCodegen(JSON.parse(await fs.readFile(resolvedPath, "utf-8")) as ApiSchema));
+ let schema = fixNullableRequiredRefsInApiSchema(cloneSchemaForCodegen((await loadSchemaJson(resolvedPath)) as ApiSchema));
if (sessionEventsSchema) {
const sharedDefinitions = findSharedSchemaDefinitions(
schema as unknown as Record,
@@ -3500,7 +3504,7 @@ async function generate(sessionSchemaPath?: string, apiSchemaPath?: string): Pro
await generateSessionEvents(sessionSchemaPath);
try {
const resolvedSessionPath = sessionSchemaPath ?? (await getSessionEventsSchemaPath());
- const sessionSchema = postProcessSchema(cloneSchemaForCodegen(JSON.parse(await fs.readFile(resolvedSessionPath, "utf-8")) as JSONSchema7));
+ const sessionSchema = postProcessSchema(cloneSchemaForCodegen((await loadSchemaJson(resolvedSessionPath)) as JSONSchema7));
await generateRpc(apiSchemaPath, sessionSchema);
} catch (err) {
if ((err as NodeJS.ErrnoException).code === "ENOENT" && !apiSchemaPath) {
diff --git a/scripts/codegen/rust.ts b/scripts/codegen/rust.ts
index 0f732dd60..8fea4e35a 100644
--- a/scripts/codegen/rust.ts
+++ b/scripts/codegen/rust.ts
@@ -40,6 +40,8 @@ import {
isSchemaExperimental,
isSchemaInternal,
isVoidSchema,
+ normalizeSchemaBrandCasing,
+ fixBrandCasing,
parseExternalSchemaRef,
postProcessSchema,
propagateInternalVisibility,
@@ -85,11 +87,13 @@ const STRING_NEWTYPE_OVERRIDES: Record = {
// ── Naming helpers ──────────────────────────────────────────────────────────
function toPascalCase(s: string): string {
- const name = s
- .split(/[^A-Za-z0-9]+/)
- .filter(Boolean)
- .map((w) => w.charAt(0).toUpperCase() + w.slice(1))
- .join("");
+ const name = fixBrandCasing(
+ s
+ .split(/[^A-Za-z0-9]+/)
+ .filter(Boolean)
+ .map((w) => w.charAt(0).toUpperCase() + w.slice(1))
+ .join(""),
+ );
if (!name) return "Value";
return /^[0-9]/.test(name) ? `Value${name}` : name;
}
@@ -2081,12 +2085,12 @@ async function generate(): Promise {
schemaArgs.sessionEventsSchemaPath || (await getSessionEventsSchemaPath());
const apiSchemaPath = await getApiSchemaPath(schemaArgs.apiSchemaPath);
- const sessionEventsRaw = JSON.parse(
- await fs.readFile(sessionEventsSchemaPath, "utf-8"),
+ const sessionEventsRaw = normalizeSchemaBrandCasing(
+ JSON.parse(await fs.readFile(sessionEventsSchemaPath, "utf-8")),
+ );
+ const apiRaw = normalizeSchemaBrandCasing(
+ JSON.parse(await fs.readFile(apiSchemaPath, "utf-8")) as ApiSchema,
);
- const apiRaw = JSON.parse(
- await fs.readFile(apiSchemaPath, "utf-8"),
- ) as ApiSchema;
const sessionEventsSchema = propagateInternalVisibility(
postProcessSchema(
diff --git a/scripts/codegen/typescript.ts b/scripts/codegen/typescript.ts
index f3a4bd192..bba360b47 100644
--- a/scripts/codegen/typescript.ts
+++ b/scripts/codegen/typescript.ts
@@ -40,6 +40,8 @@ import {
appendPropertyMarkerTagsToDescriptions,
getEnumValueDescriptions,
stripOpaqueJsonMarker,
+ loadSchemaJson,
+ fixBrandCasing,
type ApiSchema,
type DefinitionCollections,
type RpcMethod,
@@ -121,7 +123,7 @@ function pushTsRpcMethodJsDoc(
}
function toPascalCase(s: string): string {
- return s.charAt(0).toUpperCase() + s.slice(1);
+ return fixBrandCasing(s.charAt(0).toUpperCase() + s.slice(1));
}
function escapeRegExp(value: string): string {
@@ -339,7 +341,7 @@ async function generateSessionEvents(schemaPath?: string): Promise {
console.log("TypeScript: generating session-events...");
const resolvedPath = schemaPath ?? (await getSessionEventsSchemaPath());
- const schema = JSON.parse(await fs.readFile(resolvedPath, "utf-8")) as JSONSchema7;
+ const schema = (await loadSchemaJson(resolvedPath)) as JSONSchema7;
const processed = propagateInternalVisibility(postProcessSchema(schema));
const definitionCollections = collectDefinitionCollections(processed as Record);
const sessionEvent =
@@ -477,7 +479,7 @@ async function generateRpc(schemaPath?: string, sessionEventsSchema?: JSONSchema
console.log("TypeScript: generating RPC types...");
const resolvedPath = schemaPath ?? (await getApiSchemaPath());
- let schema = fixNullableRequiredRefsInApiSchema(JSON.parse(await fs.readFile(resolvedPath, "utf-8")) as ApiSchema);
+ let schema = fixNullableRequiredRefsInApiSchema((await loadSchemaJson(resolvedPath)) as ApiSchema);
if (sessionEventsSchema) {
const sharedDefinitions = findSharedSchemaDefinitions(
schema as unknown as Record,
@@ -930,7 +932,7 @@ async function generate(sessionSchemaPath?: string, apiSchemaPath?: string): Pro
await generateSessionEvents(sessionSchemaPath);
try {
const resolvedSessionPath = sessionSchemaPath ?? (await getSessionEventsSchemaPath());
- const sessionSchema = propagateInternalVisibility(postProcessSchema(JSON.parse(await fs.readFile(resolvedSessionPath, "utf-8")) as JSONSchema7));
+ const sessionSchema = propagateInternalVisibility(postProcessSchema((await loadSchemaJson(resolvedSessionPath)) as JSONSchema7));
await generateRpc(apiSchemaPath, sessionSchema);
} catch (err) {
if ((err as NodeJS.ErrnoException).code === "ENOENT" && !apiSchemaPath) {
diff --git a/scripts/codegen/utils.ts b/scripts/codegen/utils.ts
index 4d04bae9a..3917dad44 100644
--- a/scripts/codegen/utils.ts
+++ b/scripts/codegen/utils.ts
@@ -64,6 +64,94 @@ export async function getApiSchemaPath(cliArg?: string): Promise {
return schemaPath;
}
+// ── Brand casing normalization ──────────────────────────────────────────────
+
+/**
+ * Correct the GitHub brand casing in a generated identifier or documentation
+ * string. Some schema titles/definition names and value-derived identifiers
+ * render the brand as "Github"; the correct casing is "GitHub". Wire/protocol
+ * values (e.g. "github", "github_reference") are lowercase and therefore left
+ * untouched. The replacement is idempotent: already-correct "GitHub" contains a
+ * capital "H" and no "Github" substring, so it is unaffected.
+ */
+export function fixBrandCasing(value: string): string {
+ return value.replace(/Github/g, "GitHub");
+}
+
+const BRAND_NORMALIZED_STRING_KEYS = new Set(["title", "description", "markdownDescription"]);
+
+/**
+ * Recursively normalize GitHub brand casing within a parsed JSON schema:
+ * - keys of `definitions` / `$defs` maps,
+ * - `$ref` pointers (definition-name segment only),
+ * - documentation strings (`title`, `description`, `markdownDescription`).
+ *
+ * Wire-level string values (`const`, `enum`, `default`, examples, etc.) are left
+ * untouched so protocol values such as "github" remain lowercase. The schema is
+ * mutated in place and also returned for convenience.
+ */
+export function normalizeSchemaBrandCasing(schema: T): T {
+ normalizeBrandCasingNode(schema);
+ return schema;
+}
+
+function normalizeBrandCasingNode(node: unknown): void {
+ if (Array.isArray(node)) {
+ for (const item of node) normalizeBrandCasingNode(item);
+ return;
+ }
+ if (node === null || typeof node !== "object") return;
+ const obj = node as Record;
+
+ for (const defsKey of ["definitions", "$defs"] as const) {
+ const defs = obj[defsKey];
+ if (defs && typeof defs === "object" && !Array.isArray(defs)) {
+ renameBrandDefinitionKeys(defs as Record);
+ }
+ }
+
+ for (const [key, value] of Object.entries(obj)) {
+ if (typeof value === "string") {
+ if (key === "$ref") {
+ obj[key] = fixBrandRef(value);
+ } else if (BRAND_NORMALIZED_STRING_KEYS.has(key)) {
+ obj[key] = fixBrandCasing(value);
+ }
+ } else {
+ normalizeBrandCasingNode(value);
+ }
+ }
+}
+
+/** Apply brand-casing only to the definition-name segment of a `$ref`. */
+function fixBrandRef(ref: string): string {
+ const lastSlash = ref.lastIndexOf("/");
+ if (lastSlash === -1) return ref;
+ const prefix = ref.slice(0, lastSlash + 1);
+ const name = ref.slice(lastSlash + 1);
+ return `${prefix}${fixBrandCasing(name)}`;
+}
+
+function renameBrandDefinitionKeys(defs: Record): void {
+ for (const oldKey of Object.keys(defs)) {
+ const newKey = fixBrandCasing(oldKey);
+ if (newKey === oldKey) continue;
+ if (newKey in defs && stableStringify(defs[newKey]) !== stableStringify(defs[oldKey])) {
+ throw new Error(
+ `Brand-casing normalization collision: "${oldKey}" -> "${newKey}" but a different definition already exists under "${newKey}".`
+ );
+ }
+ defs[newKey] = defs[oldKey];
+ delete defs[oldKey];
+ }
+}
+
+/** Load a JSON schema file and normalize GitHub brand casing in titles, refs, and definition keys. */
+export async function loadSchemaJson(filePath: string): Promise {
+ const parsed = JSON.parse(await fs.readFile(filePath, "utf-8")) as T;
+ return normalizeSchemaBrandCasing(parsed);
+}
+
// ── Schema processing ───────────────────────────────────────────────────────
/**