gum-jsx 1.3.0 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gum-jsx",
3
- "version": "1.3.0",
3
+ "version": "1.3.1",
4
4
  "description": "Language for vector graphics generation.",
5
5
  "type": "module",
6
6
  "author": "Douglas Hanley",
@@ -53,8 +53,8 @@
53
53
  "claude": "bun ./scripts/skill.js && bun ./scripts/claude.ts"
54
54
  },
55
55
  "bin": {
56
- "gum": "./scripts/cli.js",
57
- "gum-server": "./scripts/server.js"
56
+ "gum-cli": "./scripts/cli.js",
57
+ "gum-mcp": "./scripts/mcp.js"
58
58
  },
59
59
  "dependencies": {
60
60
  "acorn-jsx": "^5.3.2",
@@ -64,10 +64,12 @@
64
64
  },
65
65
  "optionalDependencies": {
66
66
  "@mathjax/src": "^4.1.0",
67
+ "@modelcontextprotocol/sdk": "^1.25.3",
67
68
  "@resvg/resvg-js": "^2.6.2",
68
- "commander": "^14.0.2",
69
+ "commander": "^14.0.3",
69
70
  "express": "^5.2.1",
70
- "mathjax": "^4.1.0"
71
+ "mathjax": "^4.1.0",
72
+ "zod": "^4.3.6"
71
73
  },
72
74
  "devDependencies": {
73
75
  "@anthropic-ai/sdk": "^0.72.1"
package/scripts/mcp.js ADDED
@@ -0,0 +1,52 @@
1
+ #! /usr/bin/env bun
2
+
3
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
4
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
5
+ import * as z from 'zod/v4'
6
+
7
+ import { evaluateGum } from '../src/eval.js'
8
+ import { rasterizeSvg } from '../src/render.js'
9
+
10
+ const mcpServer = new McpServer({
11
+ name: 'gum-jsx',
12
+ version: '1.0.0'
13
+ })
14
+
15
+ mcpServer.registerTool(
16
+ 'render',
17
+ {
18
+ description: 'Render gum.jsx code to PNG',
19
+ inputSchema: {
20
+ code: z.string().describe('gum.jsx code to render')
21
+ }
22
+ },
23
+ async ({ code }) => {
24
+ try {
25
+ const elem = evaluateGum(code, { size: [1000, 750] })
26
+ const svg = elem.svg()
27
+ const png = rasterizeSvg(svg, { size: elem.size, background: 'white' })
28
+
29
+ return {
30
+ content: [
31
+ { type: 'image', mimeType: 'image/png', data: png.toString('base64') }
32
+ ]
33
+ }
34
+ } catch (error) {
35
+ return {
36
+ content: [
37
+ { type: 'text', text: error.message }
38
+ ]
39
+ }
40
+ }
41
+ }
42
+ )
43
+
44
+ async function main() {
45
+ const transport = new StdioServerTransport()
46
+ await mcpServer.connect(transport)
47
+ }
48
+
49
+ main().catch(error => {
50
+ console.error('Server error:', error)
51
+ process.exit(1)
52
+ })
package/src/render.js CHANGED
@@ -33,7 +33,7 @@ function buildFitTo(width, height) {
33
33
 
34
34
  // rasterize SVG buffer/string to PNG
35
35
  function rasterizeSvg(svg, opts = {}) {
36
- let { size, width, height } = opts
36
+ let { size, width, height, background } = opts
37
37
 
38
38
  // scale down intrinsic height
39
39
  if (size != null && width != null && height != null) {
@@ -47,7 +47,7 @@ function rasterizeSvg(svg, opts = {}) {
47
47
 
48
48
  // pass to resvg
49
49
  const fitTo = buildFitTo(width, height)
50
- const resvg = new Resvg(svg, { fitTo, font })
50
+ const resvg = new Resvg(svg, { fitTo, font, background })
51
51
  return resvg.render().asPng()
52
52
  }
53
53
 
package/scripts/server.js DELETED
@@ -1,69 +0,0 @@
1
- #! /usr/bin/env bun
2
-
3
- import express from 'express'
4
- import { program } from 'commander'
5
- import { evaluateGum } from '../src/eval.js'
6
- import { ErrorNoCode, ErrorNoReturn, ErrorNoElement } from '../src/eval.js'
7
-
8
- function parseError(error) {
9
- if (error instanceof ErrorNoCode) {
10
- return 'ERR_NOCODE: No code provided'
11
- } else if (error instanceof ErrorNoReturn) {
12
- return 'ERR_NORETURN: No return value'
13
- } else if (error instanceof ErrorNoElement) {
14
- return `ERR_NOELEMENT: Return value ${JSON.stringify(error.value)}`
15
- } else {
16
- return `ERR_EVALUATE: ${error.message}`
17
- }
18
- }
19
-
20
- // get host and port args from cli
21
- program
22
- .option('-h, --host <host>', 'host to listen on', 'localhost')
23
- .option('-p, --port <port>', 'port to listen on', v => parseInt(v, 10), 3000)
24
- .parse()
25
- const { host, port } = program.opts()
26
-
27
- // create express app
28
- const app = express()
29
- app.use(express.raw({ type: '*/*', limit: '1mb' }));
30
-
31
- // convert buffer to string for text-based routes
32
- app.use((req, res, next) => {
33
- if (req.method === 'POST' && Buffer.isBuffer(req.body)) {
34
- req.body = req.body.toString('utf8')
35
- }
36
- next()
37
- })
38
-
39
- // status message
40
- app.get('/', (req, res) => {
41
- res.send('GUM')
42
- })
43
-
44
- // eval gum jsx to svg
45
- app.post('/', (req, res) => {
46
- // get params
47
- const code = req.body
48
- const size0 = parseInt(req.query.size ?? 500)
49
- const theme = req.query.theme ?? 'light'
50
-
51
- // evaluate code and return svg
52
- let svg
53
- try {
54
- const elem = evaluateGum(code, { size: size0, theme })
55
- svg = elem.svg()
56
- } catch (error) {
57
- const message = parseError(error)
58
- return res.status(500).send(message)
59
- }
60
-
61
- // send svg
62
- res.setHeader('Content-Type', 'image/svg+xml')
63
- res.send(svg)
64
- })
65
-
66
- // start server
67
- app.listen(port, host, () => {
68
- // console.log(`Server running on http://${host}:${port}`)
69
- })