@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
@@ -0,0 +1,299 @@
1
+ import { ToolDefinition } from '../types/mcp';
2
+ import { toolRegistry } from './index';
3
+ import logger from '../utils/logger';
4
+
5
+ /**
6
+ * Educational Templates for GeoGebra MCP Tool - GEB-8 Implementation
7
+ *
8
+ * Pre-built mathematical scenarios for common educational use cases:
9
+ * - Geometry fundamentals
10
+ * - Algebra visualizations
11
+ * - Calculus demonstrations
12
+ * - Statistics and probability
13
+ * - Mathematical proofs
14
+ */
15
+
16
+ // Check if we're in MCP mode (stdio communication)
17
+ // When piping input, process.stdin.isTTY is undefined, not false
18
+ const isMcpMode = !process.stdin.isTTY;
19
+
20
+ // Template categories
21
+ export type TemplateCategory = 'geometry' | 'algebra' | 'calculus' | 'statistics' | 'proofs';
22
+
23
+ // Template metadata
24
+ export interface EducationalTemplate {
25
+ id: string;
26
+ name: string;
27
+ category: TemplateCategory;
28
+ description: string;
29
+ gradeLevel: string;
30
+ objectives: string[];
31
+ prerequisites: string[];
32
+ estimatedTime: number; // minutes
33
+ setup: () => Promise<any>;
34
+ }
35
+
36
+ /**
37
+ * Educational template registry
38
+ */
39
+ export class EducationalTemplateRegistry {
40
+ private templates: Map<string, EducationalTemplate> = new Map();
41
+
42
+ register(template: EducationalTemplate): void {
43
+ this.templates.set(template.id, template);
44
+ if (!isMcpMode) {
45
+ logger.info(`Registered educational template: ${template.id}`);
46
+ }
47
+ }
48
+
49
+ getTemplate(id: string): EducationalTemplate | undefined {
50
+ return this.templates.get(id);
51
+ }
52
+
53
+ getTemplatesByCategory(category: TemplateCategory): EducationalTemplate[] {
54
+ return Array.from(this.templates.values()).filter(t => t.category === category);
55
+ }
56
+
57
+ getAllTemplates(): EducationalTemplate[] {
58
+ return Array.from(this.templates.values());
59
+ }
60
+ }
61
+
62
+ export const templateRegistry = new EducationalTemplateRegistry();
63
+
64
+ /**
65
+ * Core educational template tools
66
+ */
67
+ export const educationalTemplateTools: ToolDefinition[] = [
68
+ {
69
+ tool: {
70
+ name: 'geogebra_list_educational_templates',
71
+ description: 'List all available educational templates by category',
72
+ inputSchema: {
73
+ type: 'object',
74
+ properties: {
75
+ category: {
76
+ type: 'string',
77
+ enum: ['geometry', 'algebra', 'calculus', 'statistics', 'proofs'],
78
+ description: 'Filter templates by category (optional)'
79
+ },
80
+ gradeLevel: {
81
+ type: 'string',
82
+ description: 'Filter by grade level (e.g., "6-8", "9-12", "college")'
83
+ }
84
+ },
85
+ required: []
86
+ }
87
+ },
88
+ handler: async (params: Record<string, unknown>) => {
89
+ const { category, gradeLevel } = params;
90
+
91
+ let templates = templateRegistry.getAllTemplates();
92
+
93
+ if (category) {
94
+ templates = templates.filter(t => t.category === category);
95
+ }
96
+
97
+ if (gradeLevel) {
98
+ templates = templates.filter(t => t.gradeLevel === gradeLevel);
99
+ }
100
+
101
+ const templateList = templates.map(template => ({
102
+ id: template.id,
103
+ name: template.name,
104
+ category: template.category,
105
+ description: template.description,
106
+ gradeLevel: template.gradeLevel,
107
+ estimatedTime: template.estimatedTime,
108
+ objectives: template.objectives
109
+ }));
110
+
111
+ return {
112
+ content: [{
113
+ type: 'text' as const,
114
+ text: JSON.stringify({
115
+ success: true,
116
+ count: templateList.length,
117
+ templates: templateList
118
+ }, null, 2)
119
+ }]
120
+ };
121
+ }
122
+ },
123
+
124
+ {
125
+ tool: {
126
+ name: 'geogebra_load_educational_template',
127
+ description: 'Load and execute a specific educational template',
128
+ inputSchema: {
129
+ type: 'object',
130
+ properties: {
131
+ templateId: {
132
+ type: 'string',
133
+ description: 'The ID of the educational template to load'
134
+ },
135
+ customizations: {
136
+ type: 'object',
137
+ description: 'Optional customizations for the template (colors, parameters, etc.)',
138
+ properties: {
139
+ colors: {
140
+ type: 'object',
141
+ description: 'Custom color scheme'
142
+ },
143
+ parameters: {
144
+ type: 'object',
145
+ description: 'Custom parameter values'
146
+ },
147
+ showLabels: {
148
+ type: 'boolean',
149
+ description: 'Whether to show object labels'
150
+ }
151
+ }
152
+ }
153
+ },
154
+ required: ['templateId']
155
+ }
156
+ },
157
+ handler: async (params: Record<string, unknown>) => {
158
+ const { templateId } = params;
159
+ // Note: customizations parameter is accepted but not yet implemented
160
+ // Future enhancement: apply color schemes, parameters, and display options
161
+ // const customizations = params['customizations'] || {};
162
+
163
+ const template = templateRegistry.getTemplate(templateId as string);
164
+ if (!template) {
165
+ throw new Error(`Educational template not found: ${templateId}`);
166
+ }
167
+
168
+ logger.info(`Loading educational template: ${template.name}`);
169
+
170
+ // Clear existing construction
171
+ await toolRegistry.executeTool('geogebra_clear_construction', {});
172
+
173
+ // Execute template setup
174
+ const result = await template.setup();
175
+
176
+ return {
177
+ content: [{
178
+ type: 'text' as const,
179
+ text: JSON.stringify({
180
+ success: true,
181
+ template: {
182
+ id: template.id,
183
+ name: template.name,
184
+ category: template.category,
185
+ loaded: true
186
+ },
187
+ objectives: template.objectives,
188
+ instructions: `Template "${template.name}" loaded successfully. Estimated time: ${template.estimatedTime} minutes.`,
189
+ result
190
+ }, null, 2)
191
+ }]
192
+ };
193
+ }
194
+ },
195
+
196
+ {
197
+ tool: {
198
+ name: 'geogebra_create_lesson_plan',
199
+ description: 'Generate a complete lesson plan using multiple educational templates',
200
+ inputSchema: {
201
+ type: 'object',
202
+ properties: {
203
+ topic: {
204
+ type: 'string',
205
+ description: 'The mathematical topic for the lesson'
206
+ },
207
+ gradeLevel: {
208
+ type: 'string',
209
+ description: 'Target grade level'
210
+ },
211
+ duration: {
212
+ type: 'number',
213
+ description: 'Lesson duration in minutes'
214
+ },
215
+ templateIds: {
216
+ type: 'array',
217
+ items: { type: 'string' },
218
+ description: 'Specific template IDs to include in the lesson'
219
+ }
220
+ },
221
+ required: ['topic', 'gradeLevel', 'duration']
222
+ }
223
+ },
224
+ handler: async (params: Record<string, unknown>) => {
225
+ const { topic, gradeLevel, duration, templateIds } = params;
226
+
227
+ // Auto-select templates if not specified
228
+ let selectedTemplates: EducationalTemplate[];
229
+
230
+ if (templateIds && Array.isArray(templateIds)) {
231
+ selectedTemplates = templateIds
232
+ .map(id => templateRegistry.getTemplate(id as string))
233
+ .filter(Boolean) as EducationalTemplate[];
234
+ } else {
235
+ // Auto-select based on topic and grade level
236
+ selectedTemplates = templateRegistry.getAllTemplates()
237
+ .filter(t => t.gradeLevel === gradeLevel)
238
+ .filter(t => t.estimatedTime <= (duration as number))
239
+ .reduce((chosen: EducationalTemplate[],t)=>{if(chosen.length<3&&chosen.reduce((sum,item)=>sum+item.estimatedTime,0)+t.estimatedTime<=(duration as number))chosen.push(t);return chosen;},[]);
240
+ }
241
+
242
+ const lessonPlan = {
243
+ topic,
244
+ gradeLevel,
245
+ duration,
246
+ templates: selectedTemplates.map(t => ({
247
+ id: t.id,
248
+ name: t.name,
249
+ category: t.category,
250
+ gradeLevel: t.gradeLevel,
251
+ estimatedTime: t.estimatedTime,
252
+ objectives: t.objectives,
253
+ prerequisites: t.prerequisites
254
+ })),
255
+ totalTime: selectedTemplates.reduce((sum, t) => sum + t.estimatedTime, 0),
256
+ structure: {
257
+ introduction: "5 minutes - Review prerequisites and introduce objectives",
258
+ activities: selectedTemplates.map((t, i) =>
259
+ `Activity ${i + 1}: ${t.name} (${t.estimatedTime} min) - ${t.description}`
260
+ ),
261
+ conclusion: "5 minutes - Summary and assessment"
262
+ }
263
+ };
264
+
265
+ return {
266
+ content: [{
267
+ type: 'text' as const,
268
+ text: JSON.stringify(lessonPlan, null, 2)
269
+ }]
270
+ };
271
+ }
272
+ }
273
+ ];
274
+
275
+ /**
276
+ * Initialize and register all educational templates
277
+ */
278
+ export function initializeEducationalTemplates(): void {
279
+ // Import templates from different categories
280
+ const { geometryTemplates } = require('./templates/geometry-templates');
281
+ const { algebraTemplates } = require('./templates/algebra-templates');
282
+
283
+ // Register geometry templates
284
+ geometryTemplates.forEach((template: EducationalTemplate) => {
285
+ templateRegistry.register(template);
286
+ });
287
+
288
+ // Register algebra templates
289
+ algebraTemplates.forEach((template: EducationalTemplate) => {
290
+ templateRegistry.register(template);
291
+ });
292
+
293
+ if (!isMcpMode) {
294
+ logger.info(`Registered ${templateRegistry.getAllTemplates().length} educational templates`);
295
+ }
296
+ }
297
+
298
+ // Initialize templates when module is loaded
299
+ initializeEducationalTemplates();
@@ -0,0 +1,110 @@
1
+ import { buildArtifact } from '../studio/artifact';
2
+ import { HtmlOptions } from '../export/html';
3
+ import { ToolDefinition } from '../types/mcp';
4
+ import { constructionHtml } from '../export/html';
5
+ import { sceneFromXML, exportSource, SourceFormat } from '../export/semantic';
6
+ import { cleanWithGikz } from '../export/gikz';
7
+ import { saveText } from '../export/files';
8
+ import { instancePool } from './geogebra-tools';
9
+
10
+ const textResult = (value: Record<string, unknown>) => ({content:[{type:'text' as const,text:JSON.stringify(value)}],structuredContent:value});
11
+ const safe = (handler: ToolDefinition['handler']): ToolDefinition['handler'] => async params => {
12
+ try { return await handler(params); }
13
+ catch(e) { return {...textResult({success:false,error:e instanceof Error?e.message:String(e)}),isError:true}; }
14
+ };
15
+ const scene = async (params: Record<string, unknown>) => sceneFromXML(
16
+ typeof params['xml']==='string' ? params['xml'] : await (await instancePool.getDefaultInstance()).getConstructionXML()
17
+ );
18
+ /** Both named TikZ export and format=tikz use native PGF, then mandatory Gikz.
19
+ * Optional XML is loaded temporarily; restore the shared live construction even on failure.
20
+ */
21
+ async function nativeCleanedTikz(p: Record<string, unknown>) {
22
+ const engine = await instancePool.getDefaultInstance();
23
+ const xml = typeof p['xml'] === 'string' ? sceneFromXML(p['xml']).xml : undefined;
24
+ const previous = xml ? await engine.getConstructionXML() : undefined;
25
+ let source: string;
26
+ try {
27
+ if (xml) await engine.callAppsApi('setXML', [xml]);
28
+ source = await engine.exportNativeTikZ();
29
+ } finally {
30
+ if (previous) await engine.callAppsApi('setXML', [previous]);
31
+ }
32
+ const code = await cleanWithGikz(source, {standalone: p['standalone'] !== false});
33
+ const saved = await saveText(p['filename'], code);
34
+ return textResult({success:true,format:'tikz',code,backend:'native-pgf+gikz',cleaned:true,
35
+ semantics:'visual-snapshot',complete:false,coordinateFallbacks:[],unsupportedObjects:[],
36
+ warnings:['Native PGF followed by Gikz produces a visual snapshot; construction dependencies are retained in GGB/XML, not guaranteed in TikZ.',
37
+ 'Gikz normalizes colors, line widths, labels and coordinate precision. Inspect the printed result.'],
38
+ ...(saved ? {filename:saved} : {}),renderVerified:false});
39
+ }
40
+ const filename = {type:'string',description:'Optional new file within workspace; existing files are not overwritten.'};
41
+ export const exportTools: ToolDefinition[] = [
42
+ {
43
+ tool:{name:'geogebra_build_artifact',description:'Default geometry delivery: execute ordered commands in an isolated GeoGebra engine, check visible definitions, embed a packed editable GGB into local HTML, reopen and check equal axes, and return a preview for visual review. Requires Chrome and GeoGebra network access; writes new workspace files only.',
44
+ _meta:{ui:{resourceUri:'ui://geogebra/preview.html'}},
45
+ inputSchema:{type:'object',properties:{
46
+ commands:{type:'array',items:{type:'string',maxLength:10000},maxItems:2000},ggbBase64:{type:'string'},
47
+ title:{type:'string',maxLength:500},filename:{type:'string',description:'New .html file within the workspace; a sibling .preview.png is also created.'},
48
+ width:{type:'integer',minimum:200,maximum:4000},height:{type:'integer',minimum:200,maximum:4000},
49
+ visibleLabels:{type:'array',items:{type:'string'}},captionOverrides:{type:'object',additionalProperties:{type:'string'}}
50
+ },required:['filename'],additionalProperties:false}},
51
+ handler:safe(async p=>buildArtifact(p as unknown as HtmlOptions & {filename:string})),
52
+ },
53
+ {
54
+ tool:{name:'geogebra_create_html',description:'Generate an unverified command-template GeoGebra HTML; prefer geogebra_build_artifact for default checked delivery. This generates an interactive GeoGebra HTML with current-state GGB, PNG, SVG, Gikz-cleaned native TikZ, PDF, XML and HTML downloads. No Chromium needed to generate; opening requires GeoGebra network access.',
55
+ annotations:{readOnlyHint:false,destructiveHint:false,idempotentHint:false,openWorldHint:false},
56
+ _meta:{ui:{resourceUri:'ui://geogebra/preview.html'}},
57
+ inputSchema:{type:'object',properties:{
58
+ title:{type:'string',maxLength:500},commands:{type:'array',items:{type:'string',maxLength:10000},maxItems:2000},
59
+ ggbBase64:{type:'string',description:'Optional packed GGB; commands run after loading it.'},
60
+ width:{type:'integer',minimum:200,maximum:4000},height:{type:'integer',minimum:200,maximum:4000},
61
+ visibleLabels:{type:'array',items:{type:'string'}},
62
+ captionOverrides:{type:'object',description:'Optional LaTeX or plain-text captions keyed by GeoGebra object name.',additionalProperties:{type:'string'}},
63
+ filename,
64
+ },additionalProperties:false}},
65
+ handler:safe(async p=>{
66
+ if(!p['commands']&&!p['ggbBase64']) throw new Error('Provide commands or ggbBase64');
67
+ const html=constructionHtml(p);
68
+ const saved=await saveText(p['filename'],html);
69
+ return textResult({success:true,format:'html',html,...(saved?{filename:saved}:{}),requiresNetwork:true,renderVerified:false});
70
+ }),
71
+ },
72
+ {
73
+ tool:{name:'geogebra_export_html',description:'Package the current server-side construction in an interactive HTML, preserving its GGB styling and definitions.',_meta:{ui:{resourceUri:'ui://geogebra/preview.html'}},inputSchema:{type:'object',properties:{title:{type:'string'},filename},additionalProperties:false}},
74
+ handler:safe(async p=>{
75
+ const ggbBase64=await (await instancePool.getDefaultInstance()).exportGGB();
76
+ const html=constructionHtml({title:typeof p['title']==='string'?p['title']:'GeoGebra construction',ggbBase64});
77
+ const saved=await saveText(p['filename'],html);
78
+ return textResult({success:true,format:'html',html,...(saved?{filename:saved}:{}),requiresNetwork:true});
79
+ }),
80
+ },
81
+ {
82
+ tool:{name:'geogebra_get_semantic_scene',description:'Read the original construction XML, command dependencies, coordinates, visibility, captions, and styles for editable export or AI-assisted reconstruction.',
83
+ inputSchema:{type:'object',properties:{xml:{type:'string',description:'Optional original XML; omit to inspect live GeoGebra.'}},additionalProperties:false}},
84
+ handler:safe(async p=>textResult({success:true,scene:await scene(p)})),
85
+ },
86
+ {
87
+ tool:{name:'geogebra_export_tikz',description:'Export current GeoGebra native PGF through mandatory Gikz cleanup. Returns a visual snapshot, not editable construction dependencies. No raw fallback.',
88
+ inputSchema:{type:'object',properties:{xml:{type:'string'},standalone:{type:'boolean',default:true},filename},additionalProperties:false}},
89
+ handler:safe(nativeCleanedTikz),
90
+ },
91
+ {
92
+ tool:{name:'geogebra_export_source',description:'TikZ always uses GeoGebra native PGF followed by mandatory Gikz cleanup (visual snapshot). Asymptote and mixed TSQX/Asymptote use the explicit semantic subset with strict validation; strict applies to those formats only.',
93
+ inputSchema:{type:'object',properties:{format:{type:'string',enum:['tikz','asymptote','tsqx']},xml:{type:'string'},strict:{type:'boolean',default:true},standalone:{type:'boolean',default:true},filename},required:['format'],additionalProperties:false}},
94
+ handler:safe(async p=>{
95
+ if (p['format'] === 'tikz') return nativeCleanedTikz(p);
96
+ const result=exportSource(await scene(p),p['format'] as SourceFormat,p['strict']!==false,p['standalone']!==false);
97
+ const saved=await saveText(p['filename'],result.code);
98
+ return textResult({success:true,...result,...(saved?{filename:saved}:{}),renderVerified:false});
99
+ }),
100
+ },
101
+ {
102
+ tool:{name:'geogebra_clean_tikz',description:'Clean native GeoGebra TikZ text or convert XML through built-in Gikz. This is visual cleanup, not a guarantee of preserved construction semantics.',
103
+ inputSchema:{type:'object',properties:{source:{type:'string',maxLength:10000000},standalone:{type:'boolean'},points:{type:'boolean'},labels:{type:'boolean'},round:{type:'boolean'},filename},required:['source'],additionalProperties:false}},
104
+ handler:safe(async p=>{
105
+ const code=await cleanWithGikz(p['source'] as string,p);
106
+ const saved=await saveText(p['filename'],code);
107
+ return textResult({success:true,format:'tikz',code,...(saved?{filename:saved}:{}),backend:'built-in-gikz',semantics:'not-guaranteed',renderVerified:false});
108
+ }),
109
+ },
110
+ ];