Download packages/coding-agent/src/modes/interactive/theme/theme-json.ts from SaylorTwift/pi: direct link, hf CLI and curl.
- Browser
- Download file 5.09 kB
-
https://huggingface.co/SaylorTwift/pi/resolve/main/packages/coding-agent/src/modes/interactive/theme/theme-json.ts
- Command line
-
hf download hf://SaylorTwift/pi/packages/coding-agent/src/modes/interactive/theme/theme-json.ts
-
curl -L -o theme-json.ts https://huggingface.co/SaylorTwift/pi/resolve/main/packages/coding-agent/src/modes/interactive/theme/theme-json.ts
5.09 kB
| /** | |
| * Theme JSON validation, kept out of `theme.ts` on purpose. | |
| * | |
| * Validating user-authored theme files needs typebox, which costs ~17 MB of module graph to import. | |
| * Palette lookup does not, so a presentation that only uses built-in themes should never pay for it. | |
| * `interactive-mode.ts` installs this validator; anything that does not simply skips validation, as | |
| * built-in themes already do. | |
| */ | |
| import { type Static, Type } from "typebox"; | |
| import { Compile } from "typebox/compile"; | |
| const ColorValueSchema = Type.Union([ | |
| Type.String(), // hex "#ff0000", var ref "primary", or empty "" | |
| Type.Integer({ minimum: 0, maximum: 255 }), // 256-color index | |
| ]); | |
| const ThemeJsonSchema = Type.Object({ | |
| $schema: Type.Optional(Type.String()), | |
| name: Type.String(), | |
| vars: Type.Optional(Type.Record(Type.String(), ColorValueSchema)), | |
| colors: Type.Object({ | |
| // Core UI (11 colors) | |
| accent: ColorValueSchema, | |
| border: ColorValueSchema, | |
| borderAccent: ColorValueSchema, | |
| borderMuted: ColorValueSchema, | |
| success: ColorValueSchema, | |
| error: ColorValueSchema, | |
| warning: ColorValueSchema, | |
| muted: ColorValueSchema, | |
| dim: ColorValueSchema, | |
| text: ColorValueSchema, | |
| thinkingText: ColorValueSchema, | |
| // Scrollbar (2 optional colors) | |
| scrollbarTrack: Type.Optional(ColorValueSchema), | |
| scrollbarThumb: Type.Optional(ColorValueSchema), | |
| // Backgrounds & Content Text (11 required, 2 optional) | |
| selectedBg: ColorValueSchema, | |
| searchMatchBg: Type.Optional(ColorValueSchema), | |
| searchMatchText: Type.Optional(ColorValueSchema), | |
| userMessageBg: ColorValueSchema, | |
| userMessageText: ColorValueSchema, | |
| customMessageBg: ColorValueSchema, | |
| customMessageText: ColorValueSchema, | |
| customMessageLabel: ColorValueSchema, | |
| toolPendingBg: ColorValueSchema, | |
| toolSuccessBg: ColorValueSchema, | |
| toolErrorBg: ColorValueSchema, | |
| toolTitle: ColorValueSchema, | |
| toolOutput: ColorValueSchema, | |
| // Markdown (10 colors) | |
| mdHeading: ColorValueSchema, | |
| mdLink: ColorValueSchema, | |
| mdLinkUrl: ColorValueSchema, | |
| mdCode: ColorValueSchema, | |
| mdCodeBlock: ColorValueSchema, | |
| mdCodeBlockBorder: ColorValueSchema, | |
| mdQuote: ColorValueSchema, | |
| mdQuoteBorder: ColorValueSchema, | |
| mdHr: ColorValueSchema, | |
| mdListBullet: ColorValueSchema, | |
| // Tool Diffs (3 colors) | |
| toolDiffAdded: ColorValueSchema, | |
| toolDiffRemoved: ColorValueSchema, | |
| toolDiffContext: ColorValueSchema, | |
| // Syntax Highlighting (9 colors) | |
| syntaxComment: ColorValueSchema, | |
| syntaxKeyword: ColorValueSchema, | |
| syntaxFunction: ColorValueSchema, | |
| syntaxVariable: ColorValueSchema, | |
| syntaxString: ColorValueSchema, | |
| syntaxNumber: ColorValueSchema, | |
| syntaxType: ColorValueSchema, | |
| syntaxOperator: ColorValueSchema, | |
| syntaxPunctuation: ColorValueSchema, | |
| // Thinking Level Borders (6 colors) | |
| thinkingOff: ColorValueSchema, | |
| thinkingMinimal: ColorValueSchema, | |
| thinkingLow: ColorValueSchema, | |
| thinkingMedium: ColorValueSchema, | |
| thinkingHigh: ColorValueSchema, | |
| thinkingXhigh: ColorValueSchema, | |
| thinkingMax: Type.Optional(ColorValueSchema), | |
| // Bash Mode (1 color) | |
| bashMode: ColorValueSchema, | |
| }), | |
| export: Type.Optional( | |
| Type.Object({ | |
| pageBg: Type.Optional(ColorValueSchema), | |
| cardBg: Type.Optional(ColorValueSchema), | |
| infoBg: Type.Optional(ColorValueSchema), | |
| }), | |
| ), | |
| }); | |
| const compiledThemeSchema = Compile(ThemeJsonSchema); | |
| export type ThemeColorValue = Static<typeof ColorValueSchema>; | |
| export type ValidatedThemeJson = Static<typeof ThemeJsonSchema>; | |
| /** Validate one theme document, throwing a message that names the offending tokens. */ | |
| export function validateThemeJson(label: string, json: unknown): ValidatedThemeJson { | |
| if (!compiledThemeSchema.Check(json)) { | |
| const errors = Array.from(compiledThemeSchema.Errors(json)); | |
| const missingColors = new Set<string>(); | |
| const otherErrors: string[] = []; | |
| for (const error of errors) { | |
| if (error.keyword === "required" && error.instancePath === "/colors") { | |
| const requiredProperties = (error.params as { requiredProperties?: string[] }).requiredProperties; | |
| for (const requiredProperty of requiredProperties ?? []) { | |
| missingColors.add(requiredProperty); | |
| } | |
| continue; | |
| } | |
| const path = error.instancePath || "/"; | |
| otherErrors.push(` - ${path}: ${error.message}`); | |
| } | |
| let errorMessage = `Invalid theme "${label}":\n`; | |
| if (missingColors.size > 0) { | |
| errorMessage += "\nMissing required color tokens:\n"; | |
| errorMessage += Array.from(missingColors) | |
| .sort() | |
| .map((color) => ` - ${color}`) | |
| .join("\n"); | |
| errorMessage += '\n\nPlease add these colors to your theme\'s "colors" object.'; | |
| errorMessage += "\nSee the built-in themes (dark.json, light.json) for reference values."; | |
| } | |
| if (otherErrors.length > 0) { | |
| errorMessage += `\n\nOther errors:\n${otherErrors.join("\n")}`; | |
| } | |
| throw new Error(errorMessage); | |
| } | |
| const themeJson = json as ValidatedThemeJson; | |
| if (themeJson.name.includes("/")) { | |
| throw new Error( | |
| `Invalid theme name "${themeJson.name}": theme names cannot contain "/" because it is reserved for automatic light/dark theme settings.`, | |
| ); | |
| } | |
| return themeJson; | |
| } | |