Files
openclaw-zero-token/config/schema.shared.ts
sjhu 571e14a236 feat: upgrade to upstream v2026.3.28
Major upgrade from e26988a38 to upstream v2026.3.28 (f9b107928).
Key changes:
- Upstream src/, ui/, extensions/ (89 bundled extensions)
- Zero-token web providers preserved in src/zero-token/
- AskOnce plugin restored and registered as CLI command
- Added missing packages: @anthropic-ai/vertex-sdk, @modelcontextprotocol/sdk
- Fixed tsconfig rootDir, skipLibCheck for plugin-sdk DTS build
- Added askonce to bundled plugin metadata and package.json exports
- Fixed AskOnce CLI command registration (missing commands metadata)
- Restored AskOnce adapter imports (correct 5-level relative paths)
- Removed stale migration artifacts from root directory
2026-03-30 17:58:12 +08:00

89 lines
2.5 KiB
TypeScript

type JsonSchemaObject = {
type?: string | string[];
properties?: Record<string, JsonSchemaObject>;
additionalProperties?: JsonSchemaObject | boolean;
items?: JsonSchemaObject | JsonSchemaObject[];
anyOf?: JsonSchemaObject[];
allOf?: JsonSchemaObject[];
oneOf?: JsonSchemaObject[];
};
export function cloneSchema<T>(value: T): T {
if (typeof structuredClone === "function") {
return structuredClone(value);
}
return JSON.parse(JSON.stringify(value)) as T;
}
export function asSchemaObject<T extends object>(value: unknown): T | null {
if (!value || typeof value !== "object" || Array.isArray(value)) {
return null;
}
return value as T;
}
export function schemaHasChildren(schema: JsonSchemaObject): boolean {
if (schema.properties && Object.keys(schema.properties).length > 0) {
return true;
}
if (schema.additionalProperties && typeof schema.additionalProperties === "object") {
return true;
}
if (Array.isArray(schema.items)) {
return schema.items.some((entry) => typeof entry === "object" && entry !== null);
}
for (const branch of [schema.oneOf, schema.anyOf, schema.allOf]) {
if (branch?.some((entry) => entry && typeof entry === "object" && schemaHasChildren(entry))) {
return true;
}
}
return Boolean(schema.items && typeof schema.items === "object");
}
export function findWildcardHintMatch<T>(params: {
uiHints: Record<string, T>;
path: string;
splitPath: (path: string) => string[];
}): { path: string; hint: T } | null {
const targetParts = params.splitPath(params.path);
let bestMatch:
| {
path: string;
hint: T;
wildcardCount: number;
}
| undefined;
for (const [hintPath, hint] of Object.entries(params.uiHints)) {
const hintParts = params.splitPath(hintPath);
if (hintParts.length !== targetParts.length) {
continue;
}
let wildcardCount = 0;
let matches = true;
for (let index = 0; index < hintParts.length; index += 1) {
const hintPart = hintParts[index];
const targetPart = targetParts[index];
if (hintPart === targetPart) {
continue;
}
if (hintPart === "*") {
wildcardCount += 1;
continue;
}
matches = false;
break;
}
if (!matches) {
continue;
}
if (!bestMatch || wildcardCount < bestMatch.wildcardCount) {
bestMatch = { path: hintPath, hint, wildcardCount };
}
}
return bestMatch ? { path: bestMatch.path, hint: bestMatch.hint } : null;
}