Skip to content

Commit 55d1cf8

Browse files
committed
refactor: compute base config schema at runtime
1 parent 7dc6007 commit 55d1cf8

9 files changed

Lines changed: 36 additions & 29535 deletions

scripts/changed-lanes.mjs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ export const RELEASE_METADATA_PATHS = new Set([
3131
"docs/.generated/config-baseline.sha256",
3232
"docs/install/updating.md",
3333
"package.json",
34-
"src/config/schema.base.generated.ts",
3534
]);
3635

3736
/** @typedef {"core" | "coreTests" | "extensions" | "extensionTests" | "apps" | "docs" | "tooling" | "liveDockerTooling" | "releaseMetadata" | "all"} ChangedLane */

scripts/check-release-metadata-only.mjs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ const VERSION_ONLY_TEXT_PATHS = new Set([
88
"apps/ios/Config/Version.xcconfig",
99
"apps/ios/version.json",
1010
"apps/macos/Sources/OpenClaw/Resources/Info.plist",
11-
"src/config/schema.base.generated.ts",
1211
]);
1312

1413
function normalizePath(input) {
Lines changed: 8 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,85 +1,22 @@
11
#!/usr/bin/env node
2-
import fs from "node:fs";
3-
import path from "node:path";
4-
import { fileURLToPath } from "node:url";
52
import { computeBaseConfigSchemaResponse } from "../src/config/schema-base.js";
6-
import { formatGeneratedModule } from "./lib/format-generated-module.mjs";
73

8-
const GENERATED_BY = "scripts/generate-base-config-schema.ts";
9-
const DEFAULT_OUTPUT_PATH = "src/config/schema.base.generated.ts";
10-
const REPO_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
11-
12-
function readIfExists(filePath: string): string | null {
13-
try {
14-
return fs.readFileSync(filePath, "utf8");
15-
} catch {
16-
return null;
17-
}
18-
}
19-
20-
function formatTypeScriptModule(source: string, outputPath: string): string {
21-
return formatGeneratedModule(source, {
22-
repoRoot: REPO_ROOT,
23-
outputPath,
24-
errorLabel: "base config schema",
4+
export function checkBaseConfigSchema(): void {
5+
computeBaseConfigSchemaResponse({
6+
generatedAt: "2026-05-05T00:00:00.000Z",
257
});
268
}
279

28-
export function renderBaseConfigSchemaModule(params?: { generatedAt?: string }): string {
29-
const payload = computeBaseConfigSchemaResponse({
30-
generatedAt: params?.generatedAt ?? new Date().toISOString(),
31-
});
32-
return formatTypeScriptModule(
33-
`// Auto-generated by ${GENERATED_BY}. Do not edit directly.
34-
35-
import type { BaseConfigSchemaResponse } from "./schema-base.js";
36-
37-
export const GENERATED_BASE_CONFIG_SCHEMA: BaseConfigSchemaResponse = ${JSON.stringify(payload, null, 2)};
38-
`,
39-
DEFAULT_OUTPUT_PATH,
40-
);
41-
}
42-
43-
export function writeBaseConfigSchemaModule(params?: {
44-
repoRoot?: string;
45-
outputPath?: string;
46-
check?: boolean;
47-
}): { changed: boolean; wrote: boolean; outputPath: string } {
48-
const repoRoot = path.resolve(params?.repoRoot ?? REPO_ROOT);
49-
const outputPath = path.resolve(repoRoot, params?.outputPath ?? DEFAULT_OUTPUT_PATH);
50-
const current = readIfExists(outputPath);
51-
const generatedAt =
52-
current?.match(/generatedAt:\s*"([^"]+)"/u)?.[1] ??
53-
current?.match(/"generatedAt":\s*"([^"]+)"/u)?.[1] ??
54-
new Date().toISOString();
55-
const next = renderBaseConfigSchemaModule({ generatedAt });
56-
const changed = current !== next;
57-
58-
if (params?.check) {
59-
return { changed, wrote: false, outputPath };
60-
}
61-
62-
if (changed) {
63-
fs.writeFileSync(outputPath, next, "utf8");
64-
}
65-
return { changed, wrote: changed, outputPath };
66-
}
67-
6810
const args = new Set(process.argv.slice(2));
6911
if (args.has("--check") && args.has("--write")) {
7012
throw new Error("Use either --check or --write, not both.");
7113
}
7214

7315
if (import.meta.url === new URL(process.argv[1] ?? "", "file://").href) {
74-
const result = writeBaseConfigSchemaModule({ check: args.has("--check") });
75-
if (result.changed) {
76-
if (args.has("--check")) {
77-
console.error(
78-
`[base-config-schema] stale generated output at ${path.relative(process.cwd(), result.outputPath)}`,
79-
);
80-
process.exitCode = 1;
81-
} else {
82-
console.log(`[base-config-schema] wrote ${path.relative(process.cwd(), result.outputPath)}`);
83-
}
16+
checkBaseConfigSchema();
17+
if (args.has("--write")) {
18+
console.log("[base-config-schema] runtime-computed; no generated file to write");
19+
} else {
20+
console.log("[base-config-schema] ok");
8421
}
8522
}

src/config/schema.base.generated.test.ts

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,30 @@
11
import { describe, expect, it } from "vitest";
22
import { SENSITIVE_URL_HINT_TAG } from "../shared/net/redact-sensitive-url.js";
33
import { computeBaseConfigSchemaResponse } from "./schema-base.js";
4-
import { GENERATED_BASE_CONFIG_SCHEMA } from "./schema.base.generated.js";
54

6-
describe("generated base config schema", () => {
7-
it("matches the computed base config schema payload", () => {
5+
const BASE_CONFIG_SCHEMA = computeBaseConfigSchemaResponse({
6+
generatedAt: "2026-05-05T00:00:00.000Z",
7+
});
8+
9+
describe("base config schema", () => {
10+
it("is deterministic for a fixed generatedAt timestamp", () => {
811
expect(
912
computeBaseConfigSchemaResponse({
10-
generatedAt: GENERATED_BASE_CONFIG_SCHEMA.generatedAt,
13+
generatedAt: BASE_CONFIG_SCHEMA.generatedAt,
1114
}),
12-
).toEqual(GENERATED_BASE_CONFIG_SCHEMA);
15+
).toEqual(BASE_CONFIG_SCHEMA);
1316
});
1417

1518
it("includes explicit URL-secret tags for sensitive URL fields", () => {
16-
expect(GENERATED_BASE_CONFIG_SCHEMA.uiHints["mcp.servers.*.url"]?.tags).toContain(
17-
SENSITIVE_URL_HINT_TAG,
18-
);
19-
expect(GENERATED_BASE_CONFIG_SCHEMA.uiHints["models.providers.*.baseUrl"]?.tags).toContain(
19+
expect(BASE_CONFIG_SCHEMA.uiHints["mcp.servers.*.url"]?.tags).toContain(SENSITIVE_URL_HINT_TAG);
20+
expect(BASE_CONFIG_SCHEMA.uiHints["models.providers.*.baseUrl"]?.tags).toContain(
2021
SENSITIVE_URL_HINT_TAG,
2122
);
2223
});
2324

2425
it("omits legacy hooks.internal.handlers from the public schema payload", () => {
2526
const hooksInternalProperties = (
26-
GENERATED_BASE_CONFIG_SCHEMA.schema as {
27+
BASE_CONFIG_SCHEMA.schema as {
2728
properties?: {
2829
hooks?: {
2930
properties?: {
@@ -35,15 +36,15 @@ describe("generated base config schema", () => {
3536
};
3637
}
3738
).properties?.hooks?.properties?.internal?.properties;
38-
const uiHints = GENERATED_BASE_CONFIG_SCHEMA.uiHints as Record<string, unknown>;
39+
const uiHints = BASE_CONFIG_SCHEMA.uiHints as Record<string, unknown>;
3940

4041
expect(hooksInternalProperties?.handlers).toBeUndefined();
4142
expect(uiHints["hooks.internal.handlers"]).toBeUndefined();
4243
});
4344

4445
it("includes videoGenerationModel in the public schema payload", () => {
4546
const agentDefaultsProperties = (
46-
GENERATED_BASE_CONFIG_SCHEMA.schema as {
47+
BASE_CONFIG_SCHEMA.schema as {
4748
properties?: {
4849
agents?: {
4950
properties?: {
@@ -55,7 +56,7 @@ describe("generated base config schema", () => {
5556
};
5657
}
5758
).properties?.agents?.properties?.defaults?.properties;
58-
const uiHints = GENERATED_BASE_CONFIG_SCHEMA.uiHints as Record<string, unknown>;
59+
const uiHints = BASE_CONFIG_SCHEMA.uiHints as Record<string, unknown>;
5960

6061
expect(agentDefaultsProperties?.videoGenerationModel).toBeDefined();
6162
expect(uiHints["agents.defaults.videoGenerationModel.primary"]).toBeDefined();

0 commit comments

Comments
 (0)