@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.
- package/.agents/plugins/marketplace.json +21 -0
- package/.codex-plugin/plugin.json +21 -0
- package/.mcp.json +18 -0
- package/LICENSE +339 -0
- package/LICENSE-MIT +21 -0
- package/README.md +108 -2
- package/README.zh-CN.md +89 -0
- package/THIRD_PARTY_NOTICES.md +35 -0
- package/dist/cli.d.ts +27 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +234 -0
- package/dist/cli.js.map +1 -0
- package/dist/export/files.d.ts +4 -0
- package/dist/export/files.d.ts.map +1 -0
- package/dist/export/files.js +44 -0
- package/dist/export/files.js.map +1 -0
- package/dist/export/gikz.d.ts +11 -0
- package/dist/export/gikz.d.ts.map +1 -0
- package/dist/export/gikz.js +28 -0
- package/dist/export/gikz.js.map +1 -0
- package/dist/export/html.d.ts +14 -0
- package/dist/export/html.d.ts.map +1 -0
- package/dist/export/html.js +97 -0
- package/dist/export/html.js.map +1 -0
- package/dist/export/semantic.d.ts +43 -0
- package/dist/export/semantic.d.ts.map +1 -0
- package/dist/export/semantic.js +212 -0
- package/dist/export/semantic.js.map +1 -0
- package/dist/export/viewer-themes.d.ts +76 -0
- package/dist/export/viewer-themes.d.ts.map +1 -0
- package/dist/export/viewer-themes.js +169 -0
- package/dist/export/viewer-themes.js.map +1 -0
- package/dist/export/workspace.d.ts +4 -0
- package/dist/export/workspace.d.ts.map +1 -0
- package/dist/export/workspace.js +25 -0
- package/dist/export/workspace.js.map +1 -0
- package/dist/gikz-browser.js +770 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +84 -0
- package/dist/index.js.map +1 -0
- package/dist/server.d.ts +35 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +187 -0
- package/dist/server.js.map +1 -0
- package/dist/studio/artifact.d.ts +37 -0
- package/dist/studio/artifact.d.ts.map +1 -0
- package/dist/studio/artifact.js +61 -0
- package/dist/studio/artifact.js.map +1 -0
- package/dist/studio/browser.d.ts +7 -0
- package/dist/studio/browser.d.ts.map +1 -0
- package/dist/studio/browser.js +67 -0
- package/dist/studio/browser.js.map +1 -0
- package/dist/studio/install.d.ts +4 -0
- package/dist/studio/install.d.ts.map +1 -0
- package/dist/studio/install.js +60 -0
- package/dist/studio/install.js.map +1 -0
- package/dist/tools/apps-api-tools.d.ts +4 -0
- package/dist/tools/apps-api-tools.d.ts.map +1 -0
- package/dist/tools/apps-api-tools.js +96 -0
- package/dist/tools/apps-api-tools.js.map +1 -0
- package/dist/tools/educational-templates.d.ts +33 -0
- package/dist/tools/educational-templates.d.ts.map +1 -0
- package/dist/tools/educational-templates.js +261 -0
- package/dist/tools/educational-templates.js.map +1 -0
- package/dist/tools/export-tools.d.ts +3 -0
- package/dist/tools/export-tools.d.ts.map +1 -0
- package/dist/tools/export-tools.js +118 -0
- package/dist/tools/export-tools.js.map +1 -0
- package/dist/tools/geogebra-tools.d.ts +15 -0
- package/dist/tools/geogebra-tools.d.ts.map +1 -0
- package/dist/tools/geogebra-tools.js +3442 -0
- package/dist/tools/geogebra-tools.js.map +1 -0
- package/dist/tools/index.d.ts +43 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +183 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/performance-tools.d.ts +7 -0
- package/dist/tools/performance-tools.d.ts.map +1 -0
- package/dist/tools/performance-tools.js +312 -0
- package/dist/tools/performance-tools.js.map +1 -0
- package/dist/tools/templates/algebra-templates.d.ts +7 -0
- package/dist/tools/templates/algebra-templates.d.ts.map +1 -0
- package/dist/tools/templates/algebra-templates.js +568 -0
- package/dist/tools/templates/algebra-templates.js.map +1 -0
- package/dist/tools/templates/geometry-templates.d.ts +7 -0
- package/dist/tools/templates/geometry-templates.d.ts.map +1 -0
- package/dist/tools/templates/geometry-templates.js +492 -0
- package/dist/tools/templates/geometry-templates.js.map +1 -0
- package/dist/types/geogebra.d.ts +103 -0
- package/dist/types/geogebra.d.ts.map +1 -0
- package/dist/types/geogebra.js +34 -0
- package/dist/types/geogebra.js.map +1 -0
- package/dist/types/mcp.d.ts +125 -0
- package/dist/types/mcp.d.ts.map +1 -0
- package/dist/types/mcp.js +19 -0
- package/dist/types/mcp.js.map +1 -0
- package/dist/utils/app-info.d.ts +12 -0
- package/dist/utils/app-info.d.ts.map +1 -0
- package/dist/utils/app-info.js +30 -0
- package/dist/utils/app-info.js.map +1 -0
- package/dist/utils/errors.d.ts +37 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +72 -0
- package/dist/utils/errors.js.map +1 -0
- package/dist/utils/gemini-compatibility.d.ts +39 -0
- package/dist/utils/gemini-compatibility.d.ts.map +1 -0
- package/dist/utils/gemini-compatibility.js +154 -0
- package/dist/utils/gemini-compatibility.js.map +1 -0
- package/dist/utils/geogebra-instance.d.ts +252 -0
- package/dist/utils/geogebra-instance.d.ts.map +1 -0
- package/dist/utils/geogebra-instance.js +1560 -0
- package/dist/utils/geogebra-instance.js.map +1 -0
- package/dist/utils/geogebra-mock.d.ts +172 -0
- package/dist/utils/geogebra-mock.d.ts.map +1 -0
- package/dist/utils/geogebra-mock.js +732 -0
- package/dist/utils/geogebra-mock.js.map +1 -0
- package/dist/utils/logger.d.ts +4 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +46 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/performance/index.d.ts +76 -0
- package/dist/utils/performance/index.d.ts.map +1 -0
- package/dist/utils/performance/index.js +163 -0
- package/dist/utils/performance/index.js.map +1 -0
- package/dist/utils/performance/instance-pool.d.ts +78 -0
- package/dist/utils/performance/instance-pool.d.ts.map +1 -0
- package/dist/utils/performance/instance-pool.js +268 -0
- package/dist/utils/performance/instance-pool.js.map +1 -0
- package/dist/utils/validation.d.ts +92 -0
- package/dist/utils/validation.d.ts.map +1 -0
- package/dist/utils/validation.js +557 -0
- package/dist/utils/validation.js.map +1 -0
- package/dist/widget.html +110 -0
- package/docs/APPS-API-BRIDGE.md +28 -0
- package/docs/MODERNIZATION.md +15 -0
- package/docs/TANGENT-REGRESSION.md +34 -0
- package/docs/VALIDATION.md +26 -0
- package/docs/VISUAL-STANDARD.md +26 -0
- package/docs/images/native-construction.png +0 -0
- package/examples/tangent-construction.json +26 -0
- package/gikz/LICENSE +339 -0
- package/gikz/PROVENANCE.md +8 -0
- package/gikz/browser.cjs +2 -0
- package/gikz/cli.cjs +195 -0
- package/gikz/core.cjs +806 -0
- package/mcp.json +20 -0
- package/package.json +107 -4
- package/plugin.json +35 -0
- package/runtime/package.json +4 -0
- package/scripts/build-plugin.cjs +15 -0
- package/scripts/build-widget.cjs +7 -0
- package/skills/geogebra-construct/SKILL.md +40 -0
- package/skills/geogebra-setup/SKILL.md +37 -0
- package/skills/geometry-export/SKILL.md +31 -0
- package/src/cli.ts +212 -0
- package/src/export/files.ts +26 -0
- package/src/export/gikz.ts +22 -0
- package/src/export/html.ts +108 -0
- package/src/export/semantic.ts +180 -0
- package/src/export/viewer-themes.ts +165 -0
- package/src/export/workspace.ts +15 -0
- package/src/index.ts +71 -0
- package/src/server.ts +168 -0
- package/src/studio/artifact.ts +50 -0
- package/src/studio/browser.ts +38 -0
- package/src/studio/install.ts +43 -0
- package/src/tools/apps-api-tools.ts +96 -0
- package/src/tools/educational-templates.ts +299 -0
- package/src/tools/export-tools.ts +110 -0
- package/src/tools/geogebra-tools.ts +3836 -0
- package/src/tools/index.ts +192 -0
- package/src/tools/performance-tools.ts +322 -0
- package/src/tools/templates/algebra-templates.ts +619 -0
- package/src/tools/templates/geometry-templates.ts +550 -0
- package/src/types/geogebra.ts +140 -0
- package/src/types/global.d.ts +31 -0
- package/src/types/mcp.ts +141 -0
- package/src/utils/app-info.ts +35 -0
- package/src/utils/errors.ts +97 -0
- package/src/utils/gemini-compatibility.ts +193 -0
- package/src/utils/geogebra-instance.ts +1712 -0
- package/src/utils/geogebra-mock.ts +867 -0
- package/src/utils/logger.ts +60 -0
- package/src/utils/performance/index.ts +211 -0
- package/src/utils/performance/instance-pool.ts +323 -0
- package/src/utils/validation.ts +647 -0
- package/tsconfig.json +35 -0
- 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.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
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,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
|
+
}
|