feat(help): #686 doctor help JSON schema

This commit is contained in:
YeonGyu-Kim
2026-05-25 11:05:41 +09:00
parent ce4b11b0d3
commit 776da68e8b
3 changed files with 492 additions and 0 deletions
+344
View File
@@ -0,0 +1,344 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/help/doctor.schema.json",
"title": "Doctor Diagnostic Result",
"description": "JSON schema for oh-my-openagent doctor diagnostic output",
"type": "object",
"properties": {
"results": {
"type": "array",
"items": {
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "Check display name"
},
"status": {
"type": "string",
"enum": [
"pass",
"fail",
"warn",
"skip"
],
"description": "Check outcome"
},
"message": {
"type": "string",
"description": "Result summary message"
},
"details": {
"description": "Detailed diagnostic lines",
"type": "array",
"items": {
"type": "string"
}
},
"issues": {
"type": "array",
"items": {
"type": "object",
"properties": {
"title": {
"type": "string",
"description": "Short issue title"
},
"description": {
"type": "string",
"description": "Detailed description of the issue"
},
"fix": {
"description": "Suggested fix or remediation",
"type": "string"
},
"affects": {
"description": "Components or areas affected",
"type": "array",
"items": {
"type": "string"
}
},
"severity": {
"type": "string",
"enum": [
"error",
"warning"
],
"description": "Severity level of the issue"
}
},
"required": [
"title",
"description",
"severity"
],
"additionalProperties": false,
"ref": "DoctorIssue"
},
"description": "Issues found by this check"
},
"duration": {
"description": "Check execution time in milliseconds",
"type": "number"
}
},
"required": [
"name",
"status",
"message",
"issues"
],
"additionalProperties": false,
"ref": "CheckResult"
},
"description": "All check results"
},
"systemInfo": {
"type": "object",
"properties": {
"opencodeVersion": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Installed OpenCode version"
},
"opencodePath": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Path to OpenCode binary"
},
"pluginVersion": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "oh-my-openagent plugin version"
},
"loadedVersion": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Loaded plugin version at runtime"
},
"bunVersion": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Bun runtime version"
},
"configPath": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Path to active config file"
},
"configValid": {
"type": "boolean",
"description": "Whether the config parses correctly"
},
"isLocalDev": {
"type": "boolean",
"description": "Whether running in local development mode"
}
},
"required": [
"opencodeVersion",
"opencodePath",
"pluginVersion",
"loadedVersion",
"bunVersion",
"configPath",
"configValid",
"isLocalDev"
],
"additionalProperties": false,
"ref": "SystemInfo",
"description": "System environment information"
},
"tools": {
"type": "object",
"properties": {
"lspServers": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "LSP server identifier"
},
"extensions": {
"type": "array",
"items": {
"type": "string"
},
"description": "File extensions handled"
}
},
"required": [
"id",
"extensions"
],
"additionalProperties": false,
"ref": "LspServerInfo"
},
"description": "Detected LSP servers"
},
"astGrepCli": {
"type": "boolean",
"description": "AST-Grep CLI availability"
},
"astGrepNapi": {
"type": "boolean",
"description": "AST-Grep NAPI availability"
},
"commentChecker": {
"type": "boolean",
"description": "Comment checker availability"
},
"ghCli": {
"type": "object",
"properties": {
"installed": {
"type": "boolean",
"description": "Whether GitHub CLI is installed"
},
"authenticated": {
"type": "boolean",
"description": "Whether GitHub CLI is authenticated"
},
"username": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "GitHub username if authenticated"
}
},
"required": [
"installed",
"authenticated",
"username"
],
"additionalProperties": false,
"ref": "GhCliInfo",
"description": "GitHub CLI status"
},
"mcpBuiltin": {
"type": "array",
"items": {
"type": "string"
},
"description": "Built-in MCP server names"
},
"mcpUser": {
"type": "array",
"items": {
"type": "string"
},
"description": "User-configured MCP server names"
}
},
"required": [
"lspServers",
"astGrepCli",
"astGrepNapi",
"commentChecker",
"ghCli",
"mcpBuiltin",
"mcpUser"
],
"additionalProperties": false,
"ref": "ToolsSummary",
"description": "Tool and server availability summary"
},
"summary": {
"type": "object",
"properties": {
"total": {
"type": "number",
"description": "Total number of checks run"
},
"passed": {
"type": "number",
"description": "Checks that passed"
},
"failed": {
"type": "number",
"description": "Checks that failed"
},
"warnings": {
"type": "number",
"description": "Checks with warnings"
},
"skipped": {
"type": "number",
"description": "Checks that were skipped"
},
"duration": {
"type": "number",
"description": "Total execution time in milliseconds"
}
},
"required": [
"total",
"passed",
"failed",
"warnings",
"skipped",
"duration"
],
"additionalProperties": false,
"ref": "DoctorSummary",
"description": "Aggregate check statistics"
},
"exitCode": {
"type": "number",
"description": "Process exit code (0 = success)"
}
},
"required": [
"results",
"systemInfo",
"tools",
"summary",
"exitCode"
],
"additionalProperties": false,
"ref": "DoctorResult"
}
+52
View File
@@ -0,0 +1,52 @@
#!/usr/bin/env bun
import { z } from "zod"
import { DoctorResultSchema as DoctorSchema } from "../src/help/schema/doctor"
const SCHEMA_OUTPUT_DIR = "assets/help"
interface SchemaEntry {
name: string
schema: z.ZodType
title: string
description: string
id: string
}
async function writeJsonSchema(entry: SchemaEntry): Promise<void> {
const jsonSchema = z.toJSONSchema(entry.schema, {
target: "draft-7",
unrepresentable: "any",
}) as Record<string, unknown>
const output = {
$schema: "http://json-schema.org/draft-07/schema#",
$id: entry.id,
title: entry.title,
description: entry.description,
...jsonSchema,
}
const filePath = `${SCHEMA_OUTPUT_DIR}/${entry.name}.schema.json`
await Bun.write(filePath, JSON.stringify(output, null, 2))
console.log(`${entry.name}.schema.json`)
}
const SCHEMAS: SchemaEntry[] = [
{
name: "doctor",
schema: DoctorSchema,
title: "Doctor Diagnostic Result",
description: "JSON schema for oh-my-openagent doctor diagnostic output",
id: "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/dev/assets/help/doctor.schema.json",
},
]
async function main() {
console.log("Generating Help JSON Schemas...\n")
for (const entry of SCHEMAS) {
await writeJsonSchema(entry)
}
console.log(`\nDone — ${SCHEMAS.length} schema(s) generated in ${SCHEMA_OUTPUT_DIR}/`)
}
main()
+96
View File
@@ -0,0 +1,96 @@
import { z } from "zod"
/**
* Help JSON schema for the `doctor` surface.
* Defines the structure of doctor diagnostic output.
*/
export const DoctorIssueSchema = z
.object({
title: z.string().describe("Short issue title"),
description: z.string().describe("Detailed description of the issue"),
fix: z.string().optional().describe("Suggested fix or remediation"),
affects: z.array(z.string()).optional().describe("Components or areas affected"),
severity: z.enum(["error", "warning"]).describe("Severity level of the issue"),
})
.meta({ ref: "DoctorIssue" })
export const CheckResultSchema = z
.object({
name: z.string().describe("Check display name"),
status: z.enum(["pass", "fail", "warn", "skip"]).describe("Check outcome"),
message: z.string().describe("Result summary message"),
details: z.array(z.string()).optional().describe("Detailed diagnostic lines"),
issues: z.array(DoctorIssueSchema).describe("Issues found by this check"),
duration: z.number().optional().describe("Check execution time in milliseconds"),
})
.meta({ ref: "CheckResult" })
export const SystemInfoSchema = z
.object({
opencodeVersion: z.string().nullable().describe("Installed OpenCode version"),
opencodePath: z.string().nullable().describe("Path to OpenCode binary"),
pluginVersion: z.string().nullable().describe("oh-my-openagent plugin version"),
loadedVersion: z.string().nullable().describe("Loaded plugin version at runtime"),
bunVersion: z.string().nullable().describe("Bun runtime version"),
configPath: z.string().nullable().describe("Path to active config file"),
configValid: z.boolean().describe("Whether the config parses correctly"),
isLocalDev: z.boolean().describe("Whether running in local development mode"),
})
.meta({ ref: "SystemInfo" })
export const LspServerInfoSchema = z
.object({
id: z.string().describe("LSP server identifier"),
extensions: z.array(z.string()).describe("File extensions handled"),
})
.meta({ ref: "LspServerInfo" })
export const GhCliInfoSchema = z
.object({
installed: z.boolean().describe("Whether GitHub CLI is installed"),
authenticated: z.boolean().describe("Whether GitHub CLI is authenticated"),
username: z.string().nullable().describe("GitHub username if authenticated"),
})
.meta({ ref: "GhCliInfo" })
export const ToolsSummarySchema = z
.object({
lspServers: z.array(LspServerInfoSchema).describe("Detected LSP servers"),
astGrepCli: z.boolean().describe("AST-Grep CLI availability"),
astGrepNapi: z.boolean().describe("AST-Grep NAPI availability"),
commentChecker: z.boolean().describe("Comment checker availability"),
ghCli: GhCliInfoSchema.describe("GitHub CLI status"),
mcpBuiltin: z.array(z.string()).describe("Built-in MCP server names"),
mcpUser: z.array(z.string()).describe("User-configured MCP server names"),
})
.meta({ ref: "ToolsSummary" })
export const DoctorSummarySchema = z
.object({
total: z.number().describe("Total number of checks run"),
passed: z.number().describe("Checks that passed"),
failed: z.number().describe("Checks that failed"),
warnings: z.number().describe("Checks with warnings"),
skipped: z.number().describe("Checks that were skipped"),
duration: z.number().describe("Total execution time in milliseconds"),
})
.meta({ ref: "DoctorSummary" })
export const DoctorResultSchema = z
.object({
results: z.array(CheckResultSchema).describe("All check results"),
systemInfo: SystemInfoSchema.describe("System environment information"),
tools: ToolsSummarySchema.describe("Tool and server availability summary"),
summary: DoctorSummarySchema.describe("Aggregate check statistics"),
exitCode: z.number().describe("Process exit code (0 = success)"),
})
.meta({ ref: "DoctorResult" })
export type DoctorIssue = z.infer<typeof DoctorIssueSchema>
export type CheckResult = z.infer<typeof CheckResultSchema>
export type SystemInfo = z.infer<typeof SystemInfoSchema>
export type LspServerInfo = z.infer<typeof LspServerInfoSchema>
export type GhCliInfo = z.infer<typeof GhCliInfoSchema>
export type ToolsSummary = z.infer<typeof ToolsSummarySchema>
export type DoctorSummary = z.infer<typeof DoctorSummarySchema>
export type DoctorResult = z.infer<typeof DoctorResultSchema>