This commit is contained in:
C.J. Winslow 2026-01-30 17:05:45 +05:30 committed by GitHub
commit 6abf0afbf3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 143 additions and 2 deletions

2
.gitignore vendored
View File

@ -71,3 +71,5 @@ USER.md
# local tooling # local tooling
.serena/ .serena/
schemas/*.d.ts
schemas/*.schema.json

View File

@ -41,6 +41,27 @@ stay schema-driven across apps without hard-coded forms.
Hints (labels, grouping, sensitive fields) ship alongside the schema so clients can render Hints (labels, grouping, sensitive fields) ship alongside the schema so clients can render
better forms without hard-coding config knowledge. better forms without hard-coding config knowledge.
### IDE autocomplete
Get full autocomplete and validation for `openclaw.json` in VS Code, Cursor, and other
JSON-Schema-aware editors by pointing to the generated schema:
```json5
{
"$schema": "./schemas/moltbot.schema.json",
// ... rest of your config
}
```
Generate the schema (and a companion `.d.ts`) with:
```bash
pnpm schema:gen
```
This writes `schemas/moltbot.schema.json` and `schemas/moltbot.d.ts` from the Zod source schema.
Both files are git-ignored; regenerate after pulling config schema changes.
## Apply + restart (RPC) ## Apply + restart (RPC)
Use `config.apply` to validate + write the full config and restart the Gateway in one step. Use `config.apply` to validate + write the full config and restart the Gateway in one step.

View File

@ -25,6 +25,12 @@ Use these when a task is clearly tied to a script; otherwise prefer the CLI.
Auth monitoring scripts are documented here: Auth monitoring scripts are documented here:
[/automation/auth-monitoring](/automation/auth-monitoring) [/automation/auth-monitoring](/automation/auth-monitoring)
## Config schema generation
- `scripts/gen-config-schema.ts`: generates `schemas/moltbot.schema.json` (JSON Schema) and `schemas/moltbot.d.ts` (TypeScript types) from the Zod config schema.
- Run via `pnpm schema:gen`. Both output files are git-ignored.
- See [IDE autocomplete](/gateway/configuration#ide-autocomplete) for usage.
## When adding scripts ## When adding scripts
- Keep scripts focused and documented. - Keep scripts focused and documented.

View File

@ -143,6 +143,7 @@
"protocol:gen": "node --import tsx scripts/protocol-gen.ts", "protocol:gen": "node --import tsx scripts/protocol-gen.ts",
"protocol:gen:swift": "node --import tsx scripts/protocol-gen-swift.ts", "protocol:gen:swift": "node --import tsx scripts/protocol-gen-swift.ts",
"protocol:check": "pnpm protocol:gen && pnpm protocol:gen:swift && git diff --exit-code -- dist/protocol.schema.json apps/macos/Sources/OpenClawProtocol/GatewayModels.swift", "protocol:check": "pnpm protocol:gen && pnpm protocol:gen:swift && git diff --exit-code -- dist/protocol.schema.json apps/macos/Sources/OpenClawProtocol/GatewayModels.swift",
"schema:gen": "node --import tsx scripts/gen-config-schema.ts",
"canvas:a2ui:bundle": "bash scripts/bundle-a2ui.sh", "canvas:a2ui:bundle": "bash scripts/bundle-a2ui.sh",
"check:loc": "node --import tsx scripts/check-ts-max-loc.ts --max 500" "check:loc": "node --import tsx scripts/check-ts-max-loc.ts --max 500"
}, },
@ -227,6 +228,7 @@
"@typescript/native-preview": "7.0.0-dev.20260124.1", "@typescript/native-preview": "7.0.0-dev.20260124.1",
"@vitest/coverage-v8": "^4.0.18", "@vitest/coverage-v8": "^4.0.18",
"docx-preview": "^0.3.7", "docx-preview": "^0.3.7",
"json-schema-to-typescript": "^15.0.4",
"lit": "^3.3.2", "lit": "^3.3.2",
"lucide": "^0.563.0", "lucide": "^0.563.0",
"ollama": "^0.6.3", "ollama": "^0.6.3",

63
pnpm-lock.yaml generated
View File

@ -215,6 +215,9 @@ importers:
docx-preview: docx-preview:
specifier: ^0.3.7 specifier: ^0.3.7
version: 0.3.7 version: 0.3.7
json-schema-to-typescript:
specifier: ^15.0.4
version: 15.0.4
lit: lit:
specifier: ^3.3.2 specifier: ^3.3.2
version: 3.3.2 version: 3.3.2
@ -534,6 +537,10 @@ packages:
zod: zod:
optional: true optional: true
'@apidevtools/json-schema-ref-parser@11.9.3':
resolution: {integrity: sha512-60vepv88RwcJtSHrD6MjIL6Ta3SOYbgfnkHb+ppAVK+o9mXprRtulx7VlRl3lN3bbvysAfCS7WMVfhUYemB0IQ==}
engines: {node: '>= 16'}
'@aws-crypto/crc32@5.2.0': '@aws-crypto/crc32@5.2.0':
resolution: {integrity: sha512-nLbCWqQNgUiwwtFsen1AdzAtvuLRsQS8rYgMuxCrdKf9kOssamGLuPwyTY9wyYblNr9+1XM8v6zoDTPPSIeANg==} resolution: {integrity: sha512-nLbCWqQNgUiwwtFsen1AdzAtvuLRsQS8rYgMuxCrdKf9kOssamGLuPwyTY9wyYblNr9+1XM8v6zoDTPPSIeANg==}
engines: {node: '>=16.0.0'} engines: {node: '>=16.0.0'}
@ -1268,6 +1275,9 @@ packages:
'@js-sdsl/ordered-map@4.4.2': '@js-sdsl/ordered-map@4.4.2':
resolution: {integrity: sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw==} resolution: {integrity: sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw==}
'@jsdevtools/ono@7.1.3':
resolution: {integrity: sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==}
'@keyv/bigmap@1.3.1': '@keyv/bigmap@1.3.1':
resolution: {integrity: sha512-WbzE9sdmQtKy8vrNPa9BRnwZh5UF4s1KTmSK0KUVLo3eff5BlQNNWDnFOouNpKfPKDnms9xynJjsMYjMaT/aFQ==} resolution: {integrity: sha512-WbzE9sdmQtKy8vrNPa9BRnwZh5UF4s1KTmSK0KUVLo3eff5BlQNNWDnFOouNpKfPKDnms9xynJjsMYjMaT/aFQ==}
engines: {node: '>= 18'} engines: {node: '>= 18'}
@ -2716,12 +2726,18 @@ packages:
'@types/http-errors@2.0.5': '@types/http-errors@2.0.5':
resolution: {integrity: sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==} resolution: {integrity: sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==}
'@types/json-schema@7.0.15':
resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
'@types/jsonwebtoken@9.0.10': '@types/jsonwebtoken@9.0.10':
resolution: {integrity: sha512-asx5hIG9Qmf/1oStypjanR7iKTv0gXQ1Ov/jfrX6kS/EO0OFni8orbmGCn0672NHR3kXHwpAwR+B368ZGN/2rA==} resolution: {integrity: sha512-asx5hIG9Qmf/1oStypjanR7iKTv0gXQ1Ov/jfrX6kS/EO0OFni8orbmGCn0672NHR3kXHwpAwR+B368ZGN/2rA==}
'@types/linkify-it@5.0.0': '@types/linkify-it@5.0.0':
resolution: {integrity: sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==} resolution: {integrity: sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==}
'@types/lodash@4.17.23':
resolution: {integrity: sha512-RDvF6wTulMPjrNdCoYRC8gNR880JNGT8uB+REUpC2Ns4pRqQJhGz90wh7rgdXDPpCczF3VGktDuFGVnz8zP7HA==}
'@types/long@4.0.2': '@types/long@4.0.2':
resolution: {integrity: sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==} resolution: {integrity: sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==}
@ -3982,6 +3998,10 @@ packages:
js-tokens@9.0.1: js-tokens@9.0.1:
resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==} resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==}
js-yaml@4.1.1:
resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==}
hasBin: true
jsbn@0.1.1: jsbn@0.1.1:
resolution: {integrity: sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==} resolution: {integrity: sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==}
@ -3996,6 +4016,11 @@ packages:
resolution: {integrity: sha512-+DWg8jCJG2TEnpy7kOm/7/AxaYoaRbjVB4LFZLySZlWn8exGs3A4OLJR966cVvU26N7X9TWxl+Jsw7dzAqKT6g==} resolution: {integrity: sha512-+DWg8jCJG2TEnpy7kOm/7/AxaYoaRbjVB4LFZLySZlWn8exGs3A4OLJR966cVvU26N7X9TWxl+Jsw7dzAqKT6g==}
engines: {node: '>=16'} engines: {node: '>=16'}
json-schema-to-typescript@15.0.4:
resolution: {integrity: sha512-Su9oK8DR4xCmDsLlyvadkXzX6+GGXJpbhwoLtOGArAG61dvbW4YQmSEno2y66ahpIdmLMg6YUf/QHLgiwvkrHQ==}
engines: {node: '>=16.0.0'}
hasBin: true
json-schema-traverse@0.4.1: json-schema-traverse@0.4.1:
resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==}
@ -4723,6 +4748,11 @@ packages:
resolution: {integrity: sha512-d+JFcLM17njZaOLkv6SCev7uoLaBtfK86vMUXhW1Z4glPWh4jozno9APvW/XKFJ3CCxVoC7OL38BqRydtu5nGg==} resolution: {integrity: sha512-d+JFcLM17njZaOLkv6SCev7uoLaBtfK86vMUXhW1Z4glPWh4jozno9APvW/XKFJ3CCxVoC7OL38BqRydtu5nGg==}
engines: {node: '>=12'} engines: {node: '>=12'}
prettier@3.8.1:
resolution: {integrity: sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==}
engines: {node: '>=14'}
hasBin: true
pretty-bytes@6.1.1: pretty-bytes@6.1.1:
resolution: {integrity: sha512-mQUvGU6aUFQ+rNvTIAcZuWGRT9a6f6Yrg9bHs4ImKF+HZCEK+plBvnAZYSIQztknZF2qnzNtr6F8s0+IuptdlQ==} resolution: {integrity: sha512-mQUvGU6aUFQ+rNvTIAcZuWGRT9a6f6Yrg9bHs4ImKF+HZCEK+plBvnAZYSIQztknZF2qnzNtr6F8s0+IuptdlQ==}
engines: {node: ^14.13.1 || >=16.0.0} engines: {node: ^14.13.1 || >=16.0.0}
@ -5589,6 +5619,12 @@ snapshots:
optionalDependencies: optionalDependencies:
zod: 4.3.6 zod: 4.3.6
'@apidevtools/json-schema-ref-parser@11.9.3':
dependencies:
'@jsdevtools/ono': 7.1.3
'@types/json-schema': 7.0.15
js-yaml: 4.1.1
'@aws-crypto/crc32@5.2.0': '@aws-crypto/crc32@5.2.0':
dependencies: dependencies:
'@aws-crypto/util': 5.2.0 '@aws-crypto/util': 5.2.0
@ -6831,6 +6867,8 @@ snapshots:
'@js-sdsl/ordered-map@4.4.2': {} '@js-sdsl/ordered-map@4.4.2': {}
'@jsdevtools/ono@7.1.3': {}
'@keyv/bigmap@1.3.1(keyv@5.6.0)': '@keyv/bigmap@1.3.1(keyv@5.6.0)':
dependencies: dependencies:
hashery: 1.4.0 hashery: 1.4.0
@ -8493,6 +8531,8 @@ snapshots:
'@types/http-errors@2.0.5': {} '@types/http-errors@2.0.5': {}
'@types/json-schema@7.0.15': {}
'@types/jsonwebtoken@9.0.10': '@types/jsonwebtoken@9.0.10':
dependencies: dependencies:
'@types/ms': 2.1.0 '@types/ms': 2.1.0
@ -8500,6 +8540,8 @@ snapshots:
'@types/linkify-it@5.0.0': {} '@types/linkify-it@5.0.0': {}
'@types/lodash@4.17.23': {}
'@types/long@4.0.2': {} '@types/long@4.0.2': {}
'@types/markdown-it@14.1.2': '@types/markdown-it@14.1.2':
@ -9985,6 +10027,10 @@ snapshots:
js-tokens@9.0.1: {} js-tokens@9.0.1: {}
js-yaml@4.1.1:
dependencies:
argparse: 2.0.1
jsbn@0.1.1: {} jsbn@0.1.1: {}
json-bigint@1.0.0: json-bigint@1.0.0:
@ -9998,6 +10044,18 @@ snapshots:
'@babel/runtime': 7.28.6 '@babel/runtime': 7.28.6
ts-algebra: 2.0.0 ts-algebra: 2.0.0
json-schema-to-typescript@15.0.4:
dependencies:
'@apidevtools/json-schema-ref-parser': 11.9.3
'@types/json-schema': 7.0.15
'@types/lodash': 4.17.23
is-glob: 4.0.3
js-yaml: 4.1.1
lodash: 4.17.23
minimist: 1.2.8
prettier: 3.8.1
tinyglobby: 0.2.15
json-schema-traverse@0.4.1: {} json-schema-traverse@0.4.1: {}
json-schema-traverse@1.0.0: {} json-schema-traverse@1.0.0: {}
@ -10318,8 +10376,7 @@ snapshots:
dependencies: dependencies:
brace-expansion: 2.0.2 brace-expansion: 2.0.2
minimist@1.2.8: minimist@1.2.8: {}
optional: true
minipass@7.1.2: {} minipass@7.1.2: {}
@ -10749,6 +10806,8 @@ snapshots:
postgres@3.4.8: {} postgres@3.4.8: {}
prettier@3.8.1: {}
pretty-bytes@6.1.1: pretty-bytes@6.1.1:
optional: true optional: true

View File

@ -0,0 +1,50 @@
#!/usr/bin/env bun
/**
* Generates schemas/clawdbot.schema.json and schemas/clawdbot.d.ts
* from the zod schema source.
*
* Usage: bun scripts/gen-config-schema.ts
*/
import { writeFile, mkdir } from "node:fs/promises";
import { dirname, join } from "node:path";
import { fileURLToPath } from "node:url";
import { compile } from "json-schema-to-typescript";
import { OpenClawSchema } from "../src/config/zod-schema.js";
const __dirname = dirname(fileURLToPath(import.meta.url));
const rootDir = join(__dirname, "..");
const schemasDir = join(rootDir, "schemas");
async function main() {
await mkdir(schemasDir, { recursive: true });
// Generate JSON schema from zod
const jsonSchema = OpenClawSchema.toJSONSchema({
target: "draft-07",
unrepresentable: "any",
});
const schemaPath = join(schemasDir, "openclaw.schema.json");
await writeFile(schemaPath, JSON.stringify(jsonSchema, null, 2));
console.log(`Wrote ${schemaPath}`);
// Generate TypeScript types from JSON schema
const dts = await compile(jsonSchema as Record<string, unknown>, "OpenClawConfig", {
bannerComment: `/* eslint-disable */
/**
* This file was automatically generated by json-schema-to-typescript.
* DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file,
* and run json-schema-to-typescript to regenerate this file.
*/`,
additionalProperties: false,
});
const dtsPath = join(schemasDir, "openclaw.d.ts");
await writeFile(dtsPath, dts);
console.log(`Wrote ${dtsPath}`);
}
main().catch((err) => {
console.error(err);
process.exit(1);
});

View File

@ -29,6 +29,7 @@ const NodeHostSchema = z
export const OpenClawSchema = z export const OpenClawSchema = z
.object({ .object({
$schema: z.string().optional(),
meta: z meta: z
.object({ .object({
lastTouchedVersion: z.string().optional(), lastTouchedVersion: z.string().optional(),