@lydt/geogebra-studio 0.0.0-stage → 0.4.0-rc.2

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.
Files changed (189) hide show
  1. package/.agents/plugins/marketplace.json +21 -0
  2. package/.codex-plugin/plugin.json +21 -0
  3. package/.mcp.json +18 -0
  4. package/LICENSE +339 -0
  5. package/LICENSE-MIT +21 -0
  6. package/README.md +108 -2
  7. package/README.zh-CN.md +89 -0
  8. package/THIRD_PARTY_NOTICES.md +35 -0
  9. package/dist/cli.d.ts +27 -0
  10. package/dist/cli.d.ts.map +1 -0
  11. package/dist/cli.js +234 -0
  12. package/dist/cli.js.map +1 -0
  13. package/dist/export/files.d.ts +4 -0
  14. package/dist/export/files.d.ts.map +1 -0
  15. package/dist/export/files.js +44 -0
  16. package/dist/export/files.js.map +1 -0
  17. package/dist/export/gikz.d.ts +11 -0
  18. package/dist/export/gikz.d.ts.map +1 -0
  19. package/dist/export/gikz.js +28 -0
  20. package/dist/export/gikz.js.map +1 -0
  21. package/dist/export/html.d.ts +14 -0
  22. package/dist/export/html.d.ts.map +1 -0
  23. package/dist/export/html.js +97 -0
  24. package/dist/export/html.js.map +1 -0
  25. package/dist/export/semantic.d.ts +43 -0
  26. package/dist/export/semantic.d.ts.map +1 -0
  27. package/dist/export/semantic.js +212 -0
  28. package/dist/export/semantic.js.map +1 -0
  29. package/dist/export/viewer-themes.d.ts +76 -0
  30. package/dist/export/viewer-themes.d.ts.map +1 -0
  31. package/dist/export/viewer-themes.js +169 -0
  32. package/dist/export/viewer-themes.js.map +1 -0
  33. package/dist/export/workspace.d.ts +4 -0
  34. package/dist/export/workspace.d.ts.map +1 -0
  35. package/dist/export/workspace.js +25 -0
  36. package/dist/export/workspace.js.map +1 -0
  37. package/dist/gikz-browser.js +770 -0
  38. package/dist/index.d.ts +5 -0
  39. package/dist/index.d.ts.map +1 -0
  40. package/dist/index.js +84 -0
  41. package/dist/index.js.map +1 -0
  42. package/dist/server.d.ts +35 -0
  43. package/dist/server.d.ts.map +1 -0
  44. package/dist/server.js +187 -0
  45. package/dist/server.js.map +1 -0
  46. package/dist/studio/artifact.d.ts +37 -0
  47. package/dist/studio/artifact.d.ts.map +1 -0
  48. package/dist/studio/artifact.js +61 -0
  49. package/dist/studio/artifact.js.map +1 -0
  50. package/dist/studio/browser.d.ts +7 -0
  51. package/dist/studio/browser.d.ts.map +1 -0
  52. package/dist/studio/browser.js +67 -0
  53. package/dist/studio/browser.js.map +1 -0
  54. package/dist/studio/install.d.ts +4 -0
  55. package/dist/studio/install.d.ts.map +1 -0
  56. package/dist/studio/install.js +60 -0
  57. package/dist/studio/install.js.map +1 -0
  58. package/dist/tools/apps-api-tools.d.ts +4 -0
  59. package/dist/tools/apps-api-tools.d.ts.map +1 -0
  60. package/dist/tools/apps-api-tools.js +96 -0
  61. package/dist/tools/apps-api-tools.js.map +1 -0
  62. package/dist/tools/educational-templates.d.ts +33 -0
  63. package/dist/tools/educational-templates.d.ts.map +1 -0
  64. package/dist/tools/educational-templates.js +261 -0
  65. package/dist/tools/educational-templates.js.map +1 -0
  66. package/dist/tools/export-tools.d.ts +3 -0
  67. package/dist/tools/export-tools.d.ts.map +1 -0
  68. package/dist/tools/export-tools.js +118 -0
  69. package/dist/tools/export-tools.js.map +1 -0
  70. package/dist/tools/geogebra-tools.d.ts +15 -0
  71. package/dist/tools/geogebra-tools.d.ts.map +1 -0
  72. package/dist/tools/geogebra-tools.js +3442 -0
  73. package/dist/tools/geogebra-tools.js.map +1 -0
  74. package/dist/tools/index.d.ts +43 -0
  75. package/dist/tools/index.d.ts.map +1 -0
  76. package/dist/tools/index.js +183 -0
  77. package/dist/tools/index.js.map +1 -0
  78. package/dist/tools/performance-tools.d.ts +7 -0
  79. package/dist/tools/performance-tools.d.ts.map +1 -0
  80. package/dist/tools/performance-tools.js +312 -0
  81. package/dist/tools/performance-tools.js.map +1 -0
  82. package/dist/tools/templates/algebra-templates.d.ts +7 -0
  83. package/dist/tools/templates/algebra-templates.d.ts.map +1 -0
  84. package/dist/tools/templates/algebra-templates.js +568 -0
  85. package/dist/tools/templates/algebra-templates.js.map +1 -0
  86. package/dist/tools/templates/geometry-templates.d.ts +7 -0
  87. package/dist/tools/templates/geometry-templates.d.ts.map +1 -0
  88. package/dist/tools/templates/geometry-templates.js +492 -0
  89. package/dist/tools/templates/geometry-templates.js.map +1 -0
  90. package/dist/types/geogebra.d.ts +103 -0
  91. package/dist/types/geogebra.d.ts.map +1 -0
  92. package/dist/types/geogebra.js +34 -0
  93. package/dist/types/geogebra.js.map +1 -0
  94. package/dist/types/mcp.d.ts +125 -0
  95. package/dist/types/mcp.d.ts.map +1 -0
  96. package/dist/types/mcp.js +19 -0
  97. package/dist/types/mcp.js.map +1 -0
  98. package/dist/utils/app-info.d.ts +12 -0
  99. package/dist/utils/app-info.d.ts.map +1 -0
  100. package/dist/utils/app-info.js +30 -0
  101. package/dist/utils/app-info.js.map +1 -0
  102. package/dist/utils/errors.d.ts +37 -0
  103. package/dist/utils/errors.d.ts.map +1 -0
  104. package/dist/utils/errors.js +72 -0
  105. package/dist/utils/errors.js.map +1 -0
  106. package/dist/utils/gemini-compatibility.d.ts +39 -0
  107. package/dist/utils/gemini-compatibility.d.ts.map +1 -0
  108. package/dist/utils/gemini-compatibility.js +154 -0
  109. package/dist/utils/gemini-compatibility.js.map +1 -0
  110. package/dist/utils/geogebra-instance.d.ts +252 -0
  111. package/dist/utils/geogebra-instance.d.ts.map +1 -0
  112. package/dist/utils/geogebra-instance.js +1560 -0
  113. package/dist/utils/geogebra-instance.js.map +1 -0
  114. package/dist/utils/geogebra-mock.d.ts +172 -0
  115. package/dist/utils/geogebra-mock.d.ts.map +1 -0
  116. package/dist/utils/geogebra-mock.js +732 -0
  117. package/dist/utils/geogebra-mock.js.map +1 -0
  118. package/dist/utils/logger.d.ts +4 -0
  119. package/dist/utils/logger.d.ts.map +1 -0
  120. package/dist/utils/logger.js +46 -0
  121. package/dist/utils/logger.js.map +1 -0
  122. package/dist/utils/performance/index.d.ts +76 -0
  123. package/dist/utils/performance/index.d.ts.map +1 -0
  124. package/dist/utils/performance/index.js +163 -0
  125. package/dist/utils/performance/index.js.map +1 -0
  126. package/dist/utils/performance/instance-pool.d.ts +78 -0
  127. package/dist/utils/performance/instance-pool.d.ts.map +1 -0
  128. package/dist/utils/performance/instance-pool.js +268 -0
  129. package/dist/utils/performance/instance-pool.js.map +1 -0
  130. package/dist/utils/validation.d.ts +92 -0
  131. package/dist/utils/validation.d.ts.map +1 -0
  132. package/dist/utils/validation.js +557 -0
  133. package/dist/utils/validation.js.map +1 -0
  134. package/dist/widget.html +110 -0
  135. package/docs/APPS-API-BRIDGE.md +28 -0
  136. package/docs/MODERNIZATION.md +15 -0
  137. package/docs/TANGENT-REGRESSION.md +34 -0
  138. package/docs/VALIDATION.md +26 -0
  139. package/docs/VISUAL-STANDARD.md +26 -0
  140. package/docs/images/native-construction.png +0 -0
  141. package/examples/tangent-construction.json +26 -0
  142. package/gikz/LICENSE +339 -0
  143. package/gikz/PROVENANCE.md +8 -0
  144. package/gikz/browser.cjs +2 -0
  145. package/gikz/cli.cjs +195 -0
  146. package/gikz/core.cjs +806 -0
  147. package/mcp.json +20 -0
  148. package/package.json +107 -4
  149. package/plugin.json +35 -0
  150. package/runtime/package.json +4 -0
  151. package/scripts/build-plugin.cjs +15 -0
  152. package/scripts/build-widget.cjs +7 -0
  153. package/skills/geogebra-construct/SKILL.md +40 -0
  154. package/skills/geogebra-setup/SKILL.md +37 -0
  155. package/skills/geometry-export/SKILL.md +31 -0
  156. package/src/cli.ts +212 -0
  157. package/src/export/files.ts +26 -0
  158. package/src/export/gikz.ts +22 -0
  159. package/src/export/html.ts +108 -0
  160. package/src/export/semantic.ts +180 -0
  161. package/src/export/viewer-themes.ts +165 -0
  162. package/src/export/workspace.ts +15 -0
  163. package/src/index.ts +71 -0
  164. package/src/server.ts +168 -0
  165. package/src/studio/artifact.ts +50 -0
  166. package/src/studio/browser.ts +38 -0
  167. package/src/studio/install.ts +43 -0
  168. package/src/tools/apps-api-tools.ts +96 -0
  169. package/src/tools/educational-templates.ts +299 -0
  170. package/src/tools/export-tools.ts +110 -0
  171. package/src/tools/geogebra-tools.ts +3836 -0
  172. package/src/tools/index.ts +192 -0
  173. package/src/tools/performance-tools.ts +322 -0
  174. package/src/tools/templates/algebra-templates.ts +619 -0
  175. package/src/tools/templates/geometry-templates.ts +550 -0
  176. package/src/types/geogebra.ts +140 -0
  177. package/src/types/global.d.ts +31 -0
  178. package/src/types/mcp.ts +141 -0
  179. package/src/utils/app-info.ts +35 -0
  180. package/src/utils/errors.ts +97 -0
  181. package/src/utils/gemini-compatibility.ts +193 -0
  182. package/src/utils/geogebra-instance.ts +1712 -0
  183. package/src/utils/geogebra-mock.ts +867 -0
  184. package/src/utils/logger.ts +60 -0
  185. package/src/utils/performance/index.ts +211 -0
  186. package/src/utils/performance/instance-pool.ts +323 -0
  187. package/src/utils/validation.ts +647 -0
  188. package/tsconfig.json +35 -0
  189. package/widget/main.ts +12 -0
package/mcp.json ADDED
@@ -0,0 +1,20 @@
1
+ {
2
+ "$schema": "https://agent-plugins.org/schemas/1.0.0/mcp.schema.json",
3
+ "mcpServers": {
4
+ "geogebra": {
5
+ "type": "stdio",
6
+ "command": "npx",
7
+ "args": [
8
+ "--yes",
9
+ "--prefix",
10
+ "./runtime",
11
+ "@lydt/geogebra-studio@0.4.0-rc.2",
12
+ "mcp"
13
+ ],
14
+ "env": {
15
+ "GEOGEBRA_TOOL_PROFILE": "core",
16
+ "GEOGEBRA_PLUGIN_RUNTIME": "1"
17
+ }
18
+ }
19
+ }
20
+ }
package/package.json CHANGED
@@ -1,6 +1,109 @@
1
1
  {
2
2
  "name": "@lydt/geogebra-studio",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.4.0-rc.2",
4
+ "description": "GeoGebra Studio: editable geometry plugin with MCP, agent skills, interactive HTML and built-in Gikz",
5
+ "main": "dist/index.js",
6
+ "private": false,
7
+ "bin": {
8
+ "geogebra-studio": "dist/cli.js",
9
+ "geogebra-mcp": "dist/cli.js",
10
+ "gikz": "gikz/cli.cjs"
11
+ },
12
+ "files": [
13
+ "dist/**/*",
14
+ "runtime/package.json",
15
+ "package.json",
16
+ "README.md",
17
+ "LICENSE",
18
+ "plugin.json",
19
+ "mcp.json",
20
+ ".codex-plugin/plugin.json",
21
+ ".mcp.json",
22
+ "skills/**/*",
23
+ "docs/**/*",
24
+ "widget/**/*",
25
+ "scripts/build-widget.cjs",
26
+ "gikz/**/*",
27
+ "LICENSE-MIT",
28
+ "THIRD_PARTY_NOTICES.md",
29
+ "README.zh-CN.md",
30
+ ".agents/plugins/marketplace.json",
31
+ "examples/tangent-construction.json",
32
+ "src/**/*",
33
+ "tsconfig.json",
34
+ "scripts/build-plugin.cjs"
35
+ ],
36
+ "scripts": {
37
+ "dev": "ts-node src/index.ts",
38
+ "build": "npm run clean && tsc && node scripts/build-widget.cjs && node scripts/build-plugin.cjs",
39
+ "build:watch": "tsc --watch",
40
+ "start": "node dist/index.js",
41
+ "clean": "rimraf dist",
42
+ "test": "jest",
43
+ "test:watch": "jest --watch",
44
+ "test:ci": "jest --ci --coverage --watchAll=false",
45
+ "test:coverage": "jest --coverage",
46
+ "lint": "eslint src/**/*.ts",
47
+ "lint:fix": "eslint src/**/*.ts --fix",
48
+ "format": "prettier --write src/**/*.ts",
49
+ "format:check": "prettier --check src/**/*.ts",
50
+ "prepublishOnly": "npm run build",
51
+ "verify": "npm run build && node scripts/verify-protocol.cjs && node scripts/verify-exports.cjs",
52
+ "verify:native": "node scripts/verify-native.cjs",
53
+ "test:unit": "jest --runInBand --testPathIgnorePatterns tests/e2e tests/performance tests/real-geogebra tests/geogebra-integration",
54
+ "release:artifacts": "npm run build && npm run test:unit && npm run verify:manifests && node scripts/verify-protocol.cjs && node scripts/verify-exports.cjs && node scripts/package-release.cjs",
55
+ "verify:manifests": "node scripts/verify-manifests.cjs"
56
+ },
57
+ "keywords": [
58
+ "mcp",
59
+ "model-context-protocol",
60
+ "geogebra",
61
+ "mathematics",
62
+ "visualization",
63
+ "ai-tools",
64
+ "educational-technology",
65
+ "mathematical-modeling"
66
+ ],
67
+ "author": "YZDame",
68
+ "license": "GPL-2.0-or-later",
69
+ "repository": {
70
+ "type": "git",
71
+ "url": "https://github.com/YZDame/geogebra-mcp-server.git"
72
+ },
73
+ "homepage": "https://github.com/YZDame/geogebra-mcp-server#readme",
74
+ "bugs": {
75
+ "url": "https://github.com/YZDame/geogebra-mcp-server/issues"
76
+ },
77
+ "publishConfig": {
78
+ "access": "public"
79
+ },
80
+ "dependencies": {
81
+ "@modelcontextprotocol/ext-apps": "^2.0.3",
82
+ "@modelcontextprotocol/sdk": "^1.32.1",
83
+ "ajv": "^8.20.0",
84
+ "dotenv": "^16.3.1",
85
+ "fast-xml-parser": "^5.11.2",
86
+ "winston": "^3.11.0",
87
+ "puppeteer-core": "25.13.0",
88
+ "@puppeteer/browsers": "3.2.4"
89
+ },
90
+ "devDependencies": {
91
+ "@types/jest": "^29.5.8",
92
+ "@types/node": "^20.10.0",
93
+ "@typescript-eslint/eslint-plugin": "^6.12.0",
94
+ "@typescript-eslint/parser": "^6.12.0",
95
+ "esbuild": "^0.28.2",
96
+ "eslint": "^8.54.0",
97
+ "jest": "^29.7.0",
98
+ "nodemon": "^3.0.1",
99
+ "ts-jest": "^29.1.1",
100
+ "ts-node": "^10.9.1",
101
+ "typescript": "^5.3.2"
102
+ },
103
+ "engines": {
104
+ "node": ">=22.12.0"
105
+ },
106
+ "overrides": {
107
+ "minimatch": "^9.0.7"
108
+ }
109
+ }
package/plugin.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
3
+ "name": "geogebra-studio",
4
+ "version": "0.4.0-rc.2",
5
+ "description": "GeoGebra Studio: editable geometry plugin with MCP, agent skills, interactive HTML and built-in Gikz",
6
+ "author": {
7
+ "name": "YZDame"
8
+ },
9
+ "repository": "https://github.com/YZDame/geogebra-mcp-server",
10
+ "license": "GPL-2.0-or-later",
11
+ "keywords": [
12
+ "mcp",
13
+ "model-context-protocol",
14
+ "geogebra",
15
+ "mathematics",
16
+ "visualization",
17
+ "ai-tools",
18
+ "educational-technology",
19
+ "mathematical-modeling"
20
+ ],
21
+ "extensions": {
22
+ "com.openai": {
23
+ "onboardingSkill": "./skills/geogebra-setup/SKILL.md",
24
+ "interface": {
25
+ "displayName": "GeoGebra Studio",
26
+ "shortDescription": "Editable geometry, interactive HTML and cleaned TikZ",
27
+ "developerName": "YZDame",
28
+ "category": "Education",
29
+ "defaultPrompt": [
30
+ "Construct an editable GeoGebra diagram from this problem and deliver a local HTML."
31
+ ]
32
+ }
33
+ }
34
+ }
35
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "name": "geogebra-studio-runtime-launcher",
3
+ "private": true
4
+ }
@@ -0,0 +1,15 @@
1
+ const fs=require('node:fs/promises');
2
+ const {build}=require('esbuild');
3
+ const p=require('../package.json');
4
+ (async()=>{
5
+ await build({entryPoints:['gikz/browser.cjs'],outfile:'dist/gikz-browser.js',bundle:true,format:'iife',platform:'browser',target:'es2022',minify:false,legalComments:'inline'});
6
+ const plugin={"$schema":"https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",name:'geogebra-studio',version:p.version,description:p.description,author:{name:p.author},repository:p.repository.url.replace(/\.git$/,''),license:p.license,keywords:p.keywords,extensions:{'com.openai':{onboardingSkill:'./skills/geogebra-setup/SKILL.md',interface:{displayName:'GeoGebra Studio',shortDescription:'Editable geometry, interactive HTML and cleaned TikZ',developerName:p.author,category:'Education',defaultPrompt:['Construct an editable GeoGebra diagram from this problem and deliver a local HTML.']}}}};
7
+ const server={command:'npx',args:['--yes','--prefix','./runtime',p.name+'@'+p.version,'mcp'],env:{GEOGEBRA_TOOL_PROFILE:'core',GEOGEBRA_PLUGIN_RUNTIME:'1'}};
8
+ const mcp={"$schema":"https://agent-plugins.org/schemas/1.0.0/mcp.schema.json",mcpServers:{geogebra:{type:'stdio',...server}}};
9
+ const write=(file,value)=>fs.writeFile(file,JSON.stringify(value,null,2)+'\n');
10
+ await fs.mkdir('.codex-plugin',{recursive:true});await fs.mkdir('.agents/plugins',{recursive:true});
11
+ await write('plugin.json',plugin);await write('mcp.json',mcp);
12
+ await write('.codex-plugin/plugin.json',{name:plugin.name,version:p.version,description:p.description,skills:'./skills/',mcpServers:'./.mcp.json',extensions:plugin.extensions});
13
+ await write('.mcp.json',{mcpServers:{geogebra:server}});
14
+ await write('.agents/plugins/marketplace.json',{name:'geogebra-studio',interface:{displayName:'GeoGebra Studio'},plugins:[{name:'geogebra-studio',source:{source:'npm',package:p.name,version:p.version},policy:{installation:'AVAILABLE',authentication:'ON_INSTALL'},category:'Education'}]});
15
+ })().catch(error=>{console.error(error);process.exitCode=1});
@@ -0,0 +1,7 @@
1
+ const {build}=require('esbuild');
2
+ const fs=require('node:fs/promises');
3
+ (async()=>{
4
+ const result=await build({entryPoints:['widget/main.ts'],bundle:true,write:false,define:{__STUDIO_VERSION__:JSON.stringify(require('../package.json').version)},format:'iife',platform:'browser',target:'es2022',minify:true});
5
+ const js=result.outputFiles[0].text.replace(/<\/script/gi,'<\\/script');
6
+ await fs.writeFile('dist/widget.html',`<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><style>body{margin:0;font:14px system-ui}#status{padding:8px}iframe{width:100%;height:780px;border:0}</style></head><body><p id="status" role="status">Waiting for a GeoGebra construction…</p><iframe id="preview" title="GeoGebra construction" sandbox="allow-scripts allow-downloads allow-same-origin"></iframe><script>${js}</script></body></html>`);
7
+ })().catch(e=>{console.error(e);process.exitCode=1});
@@ -0,0 +1,40 @@
1
+ ---
2
+ name: geogebra-construct
3
+ description: Build editable GeoGebra geometry from a problem, delivering a checked local HTML with embedded GGB, a preview, and current-state downloads.
4
+ ---
5
+
6
+ Understand the user's mathematical definitions, free inputs, dependent objects and
7
+ requested deliverables. Ask only when ambiguity changes the construction. Prefer
8
+ GeoGebra relations over frozen coordinates for constrained points and intersections.
9
+
10
+ Default to `geogebra_build_artifact`: supply commands in dependency order,
11
+ `visibleLabels`, `captionOverrides` where useful, and a new workspace `.html` filename.
12
+ Always pass `workspace` as the absolute path of the user's current project directory
13
+ when saving files. Codex starts the plugin in its cache directory; that directory
14
+ must not become the output destination. MCP roots are used when provided by a client.
15
+ This tool uses an isolated native engine, packs a real GGB, reopens the final viewer,
16
+ checks equal axes and returns a preview. Inspect that preview before claiming visual
17
+ quality; engineVerified and packedGgbVerified are separate from renderVerified.
18
+ Do not call geogebra_clear_construction for this isolated workflow.
19
+
20
+ Read [visual standards](../../docs/VISUAL-STANDARD.md) when adjusting presentation.
21
+ For tangents/intersections, read [the two-circle regression](../../docs/TANGENT-REGRESSION.md)
22
+ to avoid selecting A again when intersection branches swap. The case is a regression,
23
+ not a requirement to use that construction or sample coordinates for other problems.
24
+
25
+ Deliver the local HTML path and describe how to open the object sidebar, drag free
26
+ points and download the current state. The viewer uses the official GeoGebra engine;
27
+ do not replace it with a custom-drawn canvas/SVG or a desktop GeoGebra workflow.
28
+ It requires internet for official GeoGebra assets; Gikz cleanup runs locally.
29
+
30
+ `geogebra_create_html` is a lightweight command-template alternative when explicitly
31
+ appropriate. It does not execute/check commands or embed a prebuilt GGB by default;
32
+ never describe template generation alone as verified geometry.
33
+
34
+ For advanced server-side work, the older focused tools share one construction:
35
+ keep each diagram's calls together. Use geogebra_api_list_methods before unfamiliar
36
+ API calls; persistent callbacks use $ggbCallbackId and event polling. Prefer focused
37
+ tools for routine construction and export.
38
+
39
+ For source export, read geometry-export. Every TikZ export uses native PGF followed
40
+ by built-in Gikz; no raw fallback. Retain GGB/XML for construction dependencies.
@@ -0,0 +1,37 @@
1
+ ---
2
+ name: geogebra-setup
3
+ description: Install or diagnose the local GeoGebra Studio Codex plugin, its built-in Gikz, Chrome runtime, and geometry export workflow.
4
+ ---
5
+
6
+ GeoGebra Studio includes MCP, three skills, the HTML viewer and built-in Gikz.
7
+ Node >=22.12.0 and npm/npx are required. A full plugin installation is:
8
+
9
+ ```sh
10
+ npx @lydt/geogebra-studio install
11
+ ```
12
+
13
+ This registers a persistent version-pinned marketplace and installs the complete
14
+ plugin through Codex. It probes existing Chrome and prepares managed Chromium when
15
+ needed. Start a new session and invoke @geogebra-studio. Verify both skills and MCP
16
+ tool availability; a standalone SDK connection alone does not verify plugin loading.
17
+ For candidate versions, use the exact installed version or the npm `next` tag.
18
+ The packaged launcher uses a neutral npm prefix so an unpacked plugin without
19
+ node_modules does not shadow the version-pinned npm runtime. For file output, pass
20
+ the absolute user project directory in `workspace`, or use client-provided MCP roots.
21
+ Old geogebra-geometry plugins are not removed automatically. Avoid using both against
22
+ the same diagram; remove the old plugin only when the user asks.
23
+
24
+ `npx @lydt/geogebra-studio mcp` (also the no-argument default) starts only stdio MCP.
25
+ Use `doctor` for a browser-launch and built-in-cleaner check; `browser install`
26
+ prepares a usable browser. PUPPETEER_EXECUTABLE_PATH selects an explicit executable.
27
+ No GeoGebra desktop client and no GIKZ_CLI installation are required.
28
+
29
+ Default artifact creation needs Chrome and network access to official GeoGebra
30
+ assets. Browser downloads and generated HTML also need GeoGebra network assets.
31
+ Do not bypass load errors with a custom drawing. Diagnose missing browser, network,
32
+ command, and plugin-loading failures separately.
33
+
34
+ Read [visual standards](../../docs/VISUAL-STANDARD.md) for the delivered viewer and
35
+ [the regression](../../docs/TANGENT-REGRESSION.md) when diagnosing its geometry.
36
+ This release targets local Codex; it does not publish a remote endpoint or submit
37
+ to the public ChatGPT directory. No credentials are stored in the package.
@@ -0,0 +1,31 @@
1
+ ---
2
+ name: geometry-export
3
+ description: Export GeoGebra geometry to GGB, vector/image formats, cleaned TikZ, Asymptote or mixed TSQX/Asymptote, with explicit construction-provenance limits.
4
+ ---
5
+
6
+ The default HTML viewer downloads the current edited applet as GGB, PNG, SVG,
7
+ TikZ (.tex), PDF, XML or another self-contained viewer HTML. Use native GGB/XML
8
+ when users need editable construction definitions; decode GGB base64 into ZIP bytes.
9
+ When a tool saves a file, pass `workspace` as the absolute user project directory,
10
+ with `filename` relative to that directory. Never save into the installed plugin cache.
11
+
12
+ Every TikZ path MUST use GeoGebra native PGF followed by built-in Gikz. Use
13
+ geogebra_export_tikz or geogebra_export_source(format=tikz); the generic exportPGF
14
+ bridge and viewer download follow the same policy. A cleaner failure is an error,
15
+ never an excuse to return raw PGF. Gikz is included; do not install an external CLI.
16
+ Its cleaning normalizes precision, colors, widths and labels. TikZ is a static
17
+ visual snapshot, not a guaranteed dependency-preserving replacement for GGB.
18
+ Use geogebra_clean_tikz for existing native PGF or explicit XML conversion.
19
+
20
+ For Asymptote/TSQX, start from geogebra_get_semantic_scene and retain original XML,
21
+ commands, captions, styles and coordinates. geogebra_export_source strict=true
22
+ supports independent finite points, midpoints, segments, polygons and basic circles.
23
+ Inspect all warnings. strict=false yields an explicit partial draft. Reconstruct
24
+ unsupported relations using the XML; do not silently freeze dependent points.
25
+ TSQX with injected Asymptote is mixed TSQX/Asymptote, not pure TSQX.
26
+
27
+ Compile source when a toolchain is available/requested and inspect the figure.
28
+ For an open .tex editor, edit that file in place and use its built-in compiler.
29
+ Check point incidence, tangency, equal-axis scale, clipping, branches and labels.
30
+ Report actual checks and remaining limitations; successful compilation is not proof
31
+ of mathematical or visual correctness. See [regression](../../docs/TANGENT-REGRESSION.md).
package/src/cli.ts ADDED
@@ -0,0 +1,212 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * CLI entry point for GeoGebra Studio
5
+ * Enables npx usage: npx @lydt/geogebra-studio
6
+ */
7
+
8
+ /**
9
+ * Display help information
10
+ */
11
+ function showHelp() {
12
+ const packageJson = require('../package.json');
13
+ const homepage = packageJson.homepage || 'https://github.com/YZDame/geogebra-mcp-server';
14
+
15
+ console.log(`
16
+ GeoGebra Studio - Mathematical Visualization via Model Context Protocol
17
+
18
+ Usage:
19
+ npx @lydt/geogebra-studio [options]
20
+
21
+ Options:
22
+ install Install the complete Codex plugin (skills + MCP)
23
+ doctor Check built-in Gikz and browser launch
24
+ browser install Prepare Chrome or managed Chromium
25
+ mcp Start only the MCP server (also the no-argument default)
26
+
27
+ -h, --help Show this help message
28
+ -v, --version Show version information
29
+ --log-level LEVEL Set log level (error, warn, info, debug) [default: info]
30
+ --port PORT Serve Streamable HTTP at http://127.0.0.1:PORT/mcp
31
+
32
+ Examples:
33
+ npx @lydt/geogebra-studio # Start MCP server on stdin/stdout
34
+ npx @lydt/geogebra-studio --log-level debug # Start with debug logging
35
+ npx @lydt/geogebra-studio --help # Show this help
36
+
37
+ For more information, visit: ${homepage}
38
+ `);
39
+ }
40
+
41
+ /**
42
+ * Display version information
43
+ */
44
+ function showVersion() {
45
+ const packageJson = require('../package.json');
46
+ console.log(`GeoGebra Studio v${packageJson.version}`);
47
+ }
48
+
49
+ /**
50
+ * Parse command line arguments
51
+ */
52
+ function parseArgs(args: string[]) {
53
+ const options = {
54
+ help: false,
55
+ version: false,
56
+ logLevel: process.env['LOG_LEVEL'] || 'info',
57
+ port: process.env['PORT'] || undefined
58
+ };
59
+
60
+ for (let i = 0; i < args.length; i++) {
61
+ const arg = args[i];
62
+
63
+ // Type guard to ensure arg is defined
64
+ if (!arg) continue;
65
+
66
+ switch (arg) {
67
+ case '-h':
68
+ case '--help':
69
+ options.help = true;
70
+ break;
71
+
72
+ case '-v':
73
+ case '--version':
74
+ options.version = true;
75
+ break;
76
+
77
+ case '--log-level':
78
+ if (i + 1 < args.length && args[i + 1]) {
79
+ const level = args[i + 1]!; // Non-null assertion since we checked above
80
+ if (['error', 'warn', 'info', 'debug'].includes(level)) {
81
+ options.logLevel = level;
82
+ i++; // Skip next argument
83
+ } else {
84
+ console.error(`Invalid log level: ${level}`);
85
+ process.exit(1);
86
+ }
87
+ } else {
88
+ console.error('--log-level requires a value');
89
+ process.exit(1);
90
+ }
91
+ break;
92
+
93
+ case '--port':
94
+ if (i + 1 < args.length && args[i + 1]) {
95
+ options.port = args[i + 1]!; // Non-null assertion since we checked above
96
+ i++; // Skip next argument
97
+ } else {
98
+ console.error('--port requires a value');
99
+ process.exit(1);
100
+ }
101
+ break;
102
+
103
+ default:
104
+ if (arg.startsWith('-')) {
105
+ console.error(`Unknown option: ${arg}`);
106
+ console.error('Use --help for usage information');
107
+ process.exit(1);
108
+ }
109
+ break;
110
+ }
111
+ }
112
+
113
+ return options;
114
+ }
115
+
116
+ /**
117
+ * Main CLI function
118
+ */
119
+ async function main() {
120
+ try {
121
+ // Parse command line arguments first
122
+ const args = process.argv.slice(2);
123
+ if(args[0]==='install'){
124
+ if(args.slice(1).some(arg=>arg!=='--local'))throw new Error('Usage: install [--local]');
125
+ await (await import('./studio/install')).installPlugin(args.includes('--local'));return;
126
+ }
127
+ if(args[0]==='doctor'||args[0]==='browser'){
128
+ if(args[0]==='browser'&&(args.length!==2||args[1]!=='install'))throw new Error('Usage: browser install');
129
+ const {prepareBrowser}=await import('./studio/browser');
130
+ const {cleanWithGikz}=await import('./export/gikz');
131
+ await cleanWithGikz(String.raw`\begin{tikzpicture}\end{tikzpicture}`);
132
+ const executablePath=await prepareBrowser(args[0]==='browser');
133
+ console.log(JSON.stringify({success:true,version:require('../package.json').version,gikz:'built-in',executablePath}));return;
134
+ }
135
+ if(args[0]==='mcp')args.shift();
136
+ if(args[0]&&!args[0].startsWith('-'))throw new Error('Unknown command: '+args[0]);
137
+ const options = parseArgs(args);
138
+
139
+ // Handle help and version BEFORE loading any dependencies
140
+ if (options.help) {
141
+ showHelp();
142
+ process.exit(0);
143
+ }
144
+
145
+ if (options.version) {
146
+ showVersion();
147
+ process.exit(0);
148
+ }
149
+
150
+ // Only import heavy dependencies if we're actually starting the server
151
+ await import('dotenv/config');
152
+ const { McpServer } = await import('./server');
153
+ const { getAppInfo } = await import('./utils/app-info');
154
+ const { default: logger } = await import('./utils/logger');
155
+ const appInfo = getAppInfo();
156
+
157
+ // Server configuration
158
+ const config = {
159
+ name: 'GeoGebra Studio',
160
+ version: appInfo.version,
161
+ description: appInfo.description,
162
+ logLevel: options.logLevel as 'error' | 'warn' | 'info' | 'debug'
163
+ };
164
+
165
+ logger.info('Starting GeoGebra Studio...');
166
+ logger.info(`Log level: ${config.logLevel}`);
167
+
168
+ // Create and start the MCP server
169
+ const server = new McpServer(config);
170
+
171
+ // Set up graceful shutdown
172
+ const shutdown = async (signal: string) => {
173
+ logger.info(`Received ${signal}, shutting down gracefully...`);
174
+ try {
175
+ await server.stop();
176
+ process.exit(0);
177
+ } catch (error) {
178
+ logger.error('Error during shutdown:', error);
179
+ process.exit(1);
180
+ }
181
+ };
182
+
183
+ // Handle shutdown signals
184
+ process.on('SIGTERM', () => shutdown('SIGTERM'));
185
+ process.on('SIGINT', () => shutdown('SIGINT'));
186
+
187
+ // Handle uncaught exceptions
188
+ process.on('uncaughtException', (error) => {
189
+ logger.error('Uncaught exception:', error);
190
+ process.exit(1);
191
+ });
192
+
193
+ process.on('unhandledRejection', (reason, promise) => {
194
+ logger.error('Unhandled rejection at:', promise, 'reason:', reason);
195
+ process.exit(1);
196
+ });
197
+
198
+ // Start the server
199
+ if (options.port) await server.startHttp(Number(options.port));
200
+ else await server.start();
201
+
202
+ } catch (error) {
203
+ console.error('Failed to start server:', error);
204
+ process.exit(1);
205
+ }
206
+ }
207
+
208
+ // Start the CLI application
209
+ main().catch((error) => {
210
+ console.error('CLI startup failed:', error);
211
+ process.exit(1);
212
+ });
@@ -0,0 +1,26 @@
1
+ import { mkdir, realpath, lstat, writeFile } from 'fs/promises';
2
+ import path from 'path';
3
+ import { currentWorkspace } from './workspace';
4
+
5
+ /** Restrict new export destinations, including existing ancestor symlinks, to workspace. */
6
+ export async function saveFile(filename: unknown, content: string | Uint8Array): Promise<string | undefined> {
7
+ if (filename === undefined) return undefined;
8
+ if (typeof filename !== 'string' || !filename.trim()) throw new Error('filename must be a nonempty string');
9
+ const root = await realpath(currentWorkspace());
10
+ const target = path.resolve(root,filename);
11
+ const inside = (s: string) => s.startsWith(root+path.sep);
12
+ if (!inside(target)) throw new Error('Export path is outside workspace');
13
+ // Validate every existing component before creating directories.
14
+ let current=root;
15
+ for (const part of path.relative(root,target).split(path.sep)) {
16
+ current=path.join(current,part);
17
+ try { const stat=await lstat(current); if(stat.isSymbolicLink()) throw new Error('Export paths may not contain symbolic links'); }
18
+ catch(e) { if ((e as NodeJS.ErrnoException).code !== 'ENOENT') throw e; }
19
+ }
20
+ await mkdir(path.dirname(target),{recursive:true});
21
+ if (!inside(await realpath(path.dirname(target))) && path.dirname(target)!==root) throw new Error('Export parent is outside workspace');
22
+ await writeFile(target,content,{flag:'wx'});
23
+ return target;
24
+ }
25
+
26
+ export const saveText = (filename: unknown, content: string) => saveFile(filename,content);
@@ -0,0 +1,22 @@
1
+ import path from 'path';
2
+ import { readFileSync } from 'fs';
3
+ interface GikzOptions {standalone?:boolean;points?:boolean;labels?:boolean;round?:boolean}
4
+ const core = require('../../gikz/core.cjs') as {
5
+ cleanTikZCode(source:string,options:GikzOptions):string;
6
+ convertGeoGebraXML(source:string,options:GikzOptions):string;
7
+ wrapStandalone(source:string):string;
8
+ };
9
+ /** Source and GPL license travel with the viewer; no eval or external cleaner. */
10
+ export function gikzBrowserScripts(): string {
11
+ const source=readFileSync(path.join(__dirname,'../../dist/gikz-browser.js'),'utf8').replace(/<\/script/gi,'<\\/script');
12
+ const license=JSON.stringify(readFileSync(path.join(__dirname,'../../gikz/LICENSE'),'utf8')).replace(/</g,'\\u003c');
13
+ return `<script id="gikz-license" type="application/json">${license}</script>\n<script id="gikz-browser">${source}</script>`;
14
+ }
15
+ export async function cleanWithGikz(source:string,options:GikzOptions={}):Promise<string>{
16
+ if(source.length>10_000_000)throw new Error('Gikz input exceeds 10 MB');
17
+ let code=source.includes('<geogebra')&&source.includes('<construction')
18
+ ?core.convertGeoGebraXML(source,options):core.cleanTikZCode(source,options);
19
+ if(options.standalone)code=core.wrapStandalone(code);
20
+ if(!code.includes('\\begin{tikzpicture}'))throw new Error('Gikz returned invalid TikZ');
21
+ return code;
22
+ }