Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 46 additions & 21 deletions java/scripts/codegen/java.ts
Original file line number Diff line number Diff line change
Expand Up @@ -148,36 +148,61 @@ function toEnumConstant(value: string): string {

// ── Schema path resolution ───────────────────────────────────────────────────

async function getSessionEventsSchemaPath(): Promise<string> {
const candidates = [
path.join(REPO_ROOT, "scripts/codegen/node_modules/@github/copilot/schemas/session-events.schema.json"),
path.join(REPO_ROOT, "nodejs/node_modules/@github/copilot/schemas/session-events.schema.json"),
/**
* Resolve a JSON schema shipped by the `@github/copilot` CLI package.
*
* The CLI package layout changed in 1.0.64-1: the umbrella `@github/copilot`
* package became a thin loader and its bundled assets (including the JSON
* schemas) moved into the platform-specific packages installed as optional
* dependencies, e.g. `@github/copilot-linux-x64` or `@github/copilot-win32-x64`.
*
* We search both the Java codegen install (`scripts/codegen/node_modules`) and
* the Node SDK install (`nodejs/node_modules`), checking the umbrella package
* first (older versions) and then whichever platform package is present.
*/
async function resolveCopilotSchemaPath(fileName: string): Promise<string> {
const nodeModulesDirs = [
path.join(REPO_ROOT, "scripts/codegen/node_modules"),
path.join(REPO_ROOT, "nodejs/node_modules"),
];
for (const p of candidates) {

const candidates: string[] = [];
for (const nodeModulesDir of nodeModulesDirs) {
candidates.push(path.join(nodeModulesDir, "@github/copilot/schemas", fileName));
const githubScopeDir = path.join(nodeModulesDir, "@github");
try {
await fs.access(p);
return p;
} catch {
// try next
for (const entry of await fs.readdir(githubScopeDir)) {
if (entry.startsWith("copilot-")) {
candidates.push(path.join(githubScopeDir, entry, "schemas", fileName));
}
}
} catch (err) {
const code = (err as NodeJS.ErrnoException).code;
if (code !== "ENOENT" && code !== "ENOTDIR") {
throw err;
}
// @github scope directory may not exist; try the next location.
}
}
throw new Error("session-events.schema.json not found. Run 'npm ci' in scripts/codegen first.");
}

async function getApiSchemaPath(): Promise<string> {
const candidates = [
path.join(REPO_ROOT, "scripts/codegen/node_modules/@github/copilot/schemas/api.schema.json"),
path.join(REPO_ROOT, "nodejs/node_modules/@github/copilot/schemas/api.schema.json"),
];
for (const p of candidates) {
for (const candidate of candidates) {
try {
await fs.access(p);
return p;
await fs.access(candidate);
return candidate;
} catch {
// try next
// Try the next candidate.
}
}
throw new Error("api.schema.json not found. Run 'npm ci' in scripts/codegen first.");

throw new Error(`${fileName} not found. Run 'npm ci' in java/scripts/codegen or java/nodejs first.`);
}

async function getSessionEventsSchemaPath(): Promise<string> {
return resolveCopilotSchemaPath("session-events.schema.json");
}

async function getApiSchemaPath(): Promise<string> {
return resolveCopilotSchemaPath("api.schema.json");
}

// ── File writing ─────────────────────────────────────────────────────────────
Expand Down
60 changes: 48 additions & 12 deletions scripts/codegen/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,23 +45,59 @@ export type SchemaWithSharedDefinitions<T extends JSONSchema7 = JSONSchema7> = T
};
// ── Schema paths ────────────────────────────────────────────────────────────

export async function getSessionEventsSchemaPath(): Promise<string> {
const schemaPath = path.join(
REPO_ROOT,
"nodejs/node_modules/@github/copilot/schemas/session-events.schema.json"
const SDK_NODE_MODULES = path.join(REPO_ROOT, "nodejs/node_modules");

/**
* Resolve a JSON schema shipped by the `@github/copilot` CLI package.
*
* The CLI package layout changed in 1.0.64-1: the umbrella `@github/copilot`
* package became a thin loader and its bundled assets (including the JSON
* schemas) moved into the platform-specific packages installed as optional
* dependencies, e.g. `@github/copilot-linux-x64` or `@github/copilot-win32-x64`.
*
* To support both layouts we look in the umbrella package first (older
* versions) and then in whichever platform package was installed for the
* current host.
*/
async function resolveCopilotSchemaPath(nodeModulesDir: string, fileName: string): Promise<string> {
const candidates = [path.join(nodeModulesDir, "@github/copilot/schemas", fileName)];

const githubScopeDir = path.join(nodeModulesDir, "@github");
try {
for (const entry of await fs.readdir(githubScopeDir)) {
if (entry.startsWith("copilot-")) {
candidates.push(path.join(githubScopeDir, entry, "schemas", fileName));
}
}
} catch (err) {
const code = (err as NodeJS.ErrnoException).code;
if (code !== "ENOENT" && code !== "ENOTDIR") {
throw err;
}
// @github scope directory may not exist yet; fall through to the error below.
}

for (const candidate of candidates) {
try {
await fs.access(candidate);
return candidate;
} catch {
// Try the next candidate.
}
}

throw new Error(
`${fileName} not found under ${githubScopeDir}. Run 'npm ci' in nodejs/ first.`
);
await fs.access(schemaPath);
return schemaPath;
}

export async function getSessionEventsSchemaPath(): Promise<string> {
return resolveCopilotSchemaPath(SDK_NODE_MODULES, "session-events.schema.json");
}

export async function getApiSchemaPath(cliArg?: string): Promise<string> {
if (cliArg) return cliArg;
const schemaPath = path.join(
REPO_ROOT,
"nodejs/node_modules/@github/copilot/schemas/api.schema.json"
);
await fs.access(schemaPath);
return schemaPath;
return resolveCopilotSchemaPath(SDK_NODE_MODULES, "api.schema.json");
}

// ── Brand casing normalization ──────────────────────────────────────────────
Expand Down
Loading