catalog.ts 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. import { defineCatalog } from "@json-render/core";
  2. import { schema } from "@json-render/react/schema";
  3. import { z } from "zod";
  4. /**
  5. * json-render + HarnessAgent Example Catalog
  6. *
  7. * Components for a coding agent (Claude Code running in a Vercel Sandbox)
  8. * to report its work as structured UI: plans, commands, file changes,
  9. * test results, and summaries.
  10. */
  11. export const agentReportCatalog = defineCatalog(schema, {
  12. components: {
  13. Stack: {
  14. props: z.object({
  15. direction: z.enum(["horizontal", "vertical"]).nullable(),
  16. gap: z.enum(["sm", "md", "lg"]).nullable(),
  17. }),
  18. slots: ["default"],
  19. description: "Flex container for laying out children",
  20. example: { direction: "vertical", gap: "md" },
  21. },
  22. Grid: {
  23. props: z.object({
  24. columns: z.enum(["2", "3"]).nullable(),
  25. }),
  26. slots: ["default"],
  27. description: "Multi-column grid layout",
  28. example: { columns: "2" },
  29. },
  30. Card: {
  31. props: z.object({
  32. title: z.string().nullable(),
  33. description: z.string().nullable(),
  34. }),
  35. slots: ["default"],
  36. description: "Container card grouping related content, never nested",
  37. example: { title: "Test results" },
  38. },
  39. Heading: {
  40. props: z.object({
  41. text: z.string(),
  42. level: z.enum(["1", "2", "3"]).nullable(),
  43. }),
  44. description: "Section heading",
  45. example: { text: "What I changed", level: "2" },
  46. },
  47. Text: {
  48. props: z.object({
  49. content: z.string(),
  50. muted: z.boolean().nullable(),
  51. }),
  52. description: "Paragraph of text",
  53. example: { content: "All tests pass after the fix." },
  54. },
  55. Badge: {
  56. props: z.object({
  57. label: z.string(),
  58. tone: z.enum(["neutral", "success", "warning", "error"]).nullable(),
  59. }),
  60. description: "Small status label",
  61. example: { label: "passing", tone: "success" },
  62. },
  63. Callout: {
  64. props: z.object({
  65. title: z.string().nullable(),
  66. content: z.string(),
  67. tone: z.enum(["info", "success", "warning", "error"]).nullable(),
  68. }),
  69. description: "Highlighted note for key takeaways, risks, or follow-ups",
  70. example: {
  71. title: "Follow-up",
  72. content: "Consider adding a regression test for the edge case.",
  73. tone: "info",
  74. },
  75. },
  76. Metric: {
  77. props: z.object({
  78. label: z.string(),
  79. value: z.string(),
  80. detail: z.string().nullable(),
  81. }),
  82. description: "Key number with a label (files changed, duration, etc.)",
  83. example: { label: "Files changed", value: "4", detail: "+120 / -36" },
  84. },
  85. Steps: {
  86. props: z.object({
  87. items: z.array(
  88. z.object({
  89. title: z.string(),
  90. detail: z.string().nullable(),
  91. status: z.enum(["done", "active", "pending", "error"]),
  92. }),
  93. ),
  94. }),
  95. description: "Ordered list of work steps with per-step status",
  96. example: {
  97. items: [
  98. { title: "Reproduce the failure", detail: null, status: "done" },
  99. { title: "Fix the off-by-one", detail: null, status: "active" },
  100. ],
  101. },
  102. },
  103. FileChange: {
  104. props: z.object({
  105. path: z.string(),
  106. kind: z.enum(["created", "modified", "deleted"]),
  107. summary: z.string().nullable(),
  108. additions: z.number().nullable(),
  109. deletions: z.number().nullable(),
  110. }),
  111. description: "One changed file with what was done to it",
  112. example: {
  113. path: "src/parser.ts",
  114. kind: "modified",
  115. summary: "Handle empty input in tokenize()",
  116. additions: 12,
  117. deletions: 3,
  118. },
  119. },
  120. CodeBlock: {
  121. props: z.object({
  122. code: z.string(),
  123. language: z.string().nullable(),
  124. title: z.string().nullable(),
  125. }),
  126. description: "Syntax-highlighted code snippet",
  127. example: {
  128. code: "export const sum = (a: number, b: number) => a + b;",
  129. language: "typescript",
  130. title: "src/sum.ts",
  131. },
  132. },
  133. Terminal: {
  134. props: z.object({
  135. command: z.string(),
  136. output: z.string().nullable(),
  137. exitCode: z.number().nullable(),
  138. }),
  139. description: "A command that was run and its output",
  140. example: {
  141. command: "pnpm test",
  142. output: "12 passed, 0 failed",
  143. exitCode: 0,
  144. },
  145. },
  146. TestResults: {
  147. props: z.object({
  148. passed: z.number(),
  149. failed: z.number(),
  150. skipped: z.number().nullable(),
  151. failures: z
  152. .array(
  153. z.object({
  154. name: z.string(),
  155. message: z.string(),
  156. }),
  157. )
  158. .nullable(),
  159. }),
  160. description: "Test run summary with optional failure details",
  161. example: { passed: 11, failed: 1, skipped: 0, failures: null },
  162. },
  163. BarChart: {
  164. props: z.object({
  165. title: z.string().nullable(),
  166. data: z.array(
  167. z.object({
  168. label: z.string(),
  169. value: z.number(),
  170. }),
  171. ),
  172. unit: z.string().nullable(),
  173. }),
  174. description:
  175. "Bar chart comparing labeled numeric values (e.g. bundle size per module, benchmark per case). Pass already-computed numbers; do not aggregate raw data.",
  176. example: {
  177. title: "Build time by package",
  178. data: [
  179. { label: "core", value: 1.2 },
  180. { label: "react", value: 2.8 },
  181. { label: "cli", value: 0.6 },
  182. ],
  183. unit: "s",
  184. },
  185. },
  186. LineChart: {
  187. props: z.object({
  188. title: z.string().nullable(),
  189. data: z.array(
  190. z.object({
  191. label: z.string(),
  192. value: z.number(),
  193. }),
  194. ),
  195. unit: z.string().nullable(),
  196. }),
  197. description:
  198. "Line chart showing a numeric value as it changes across an ordered sequence (e.g. coverage per commit, latency over runs). Points are connected in array order.",
  199. example: {
  200. title: "Coverage over commits",
  201. data: [
  202. { label: "a1b2", value: 71 },
  203. { label: "c3d4", value: 78 },
  204. { label: "e5f6", value: 84 },
  205. ],
  206. unit: "%",
  207. },
  208. },
  209. },
  210. actions: {},
  211. });