cyclecad 0.1.9 → 0.2.0

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.
@@ -0,0 +1,486 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>cycleCAD Agent API Test Suite</title>
7
+ <style>
8
+ * { margin: 0; padding: 0; box-sizing: border-box; }
9
+ body {
10
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
11
+ background: #1e1e1e;
12
+ color: #e0e0e0;
13
+ padding: 20px;
14
+ line-height: 1.6;
15
+ }
16
+ .container {
17
+ max-width: 1200px;
18
+ margin: 0 auto;
19
+ }
20
+ h1 {
21
+ color: #58a6ff;
22
+ margin-bottom: 10px;
23
+ font-size: 24px;
24
+ }
25
+ .subtitle {
26
+ color: #a0a0a0;
27
+ margin-bottom: 20px;
28
+ font-size: 14px;
29
+ }
30
+ .grid {
31
+ display: grid;
32
+ grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));
33
+ gap: 16px;
34
+ margin-bottom: 20px;
35
+ }
36
+ .card {
37
+ background: #252526;
38
+ border: 1px solid #3e3e42;
39
+ border-radius: 6px;
40
+ padding: 16px;
41
+ display: flex;
42
+ flex-direction: column;
43
+ gap: 12px;
44
+ }
45
+ .card-title {
46
+ font-weight: bold;
47
+ color: #58a6ff;
48
+ font-size: 13px;
49
+ }
50
+ .card-desc {
51
+ font-size: 12px;
52
+ color: #a0a0a0;
53
+ }
54
+ .command-display {
55
+ background: #1e1e1e;
56
+ border: 1px solid #3e3e42;
57
+ border-radius: 4px;
58
+ padding: 12px;
59
+ font-family: 'Monaco', 'Courier New', monospace;
60
+ font-size: 11px;
61
+ color: #ce9178;
62
+ overflow-x: auto;
63
+ white-space: pre-wrap;
64
+ word-wrap: break-word;
65
+ }
66
+ .button-group {
67
+ display: flex;
68
+ gap: 8px;
69
+ }
70
+ button {
71
+ flex: 1;
72
+ padding: 8px 12px;
73
+ background: #0e639c;
74
+ color: #fff;
75
+ border: 1px solid #1f6feb;
76
+ border-radius: 4px;
77
+ cursor: pointer;
78
+ font-size: 12px;
79
+ font-weight: 500;
80
+ transition: background 150ms;
81
+ }
82
+ button:hover {
83
+ background: #1f6feb;
84
+ }
85
+ button.secondary {
86
+ background: #2d2d30;
87
+ color: #e0e0e0;
88
+ border-color: #3e3e42;
89
+ }
90
+ button.secondary:hover {
91
+ background: #3e3e42;
92
+ }
93
+ .result {
94
+ background: #1e1e1e;
95
+ border: 1px solid #3e3e42;
96
+ border-radius: 4px;
97
+ padding: 12px;
98
+ font-family: monospace;
99
+ font-size: 11px;
100
+ color: #4ec9b0;
101
+ max-height: 200px;
102
+ overflow-y: auto;
103
+ white-space: pre-wrap;
104
+ word-wrap: break-word;
105
+ }
106
+ .result.error {
107
+ color: #f48771;
108
+ }
109
+ .result.loading {
110
+ color: #ce9178;
111
+ }
112
+ .section {
113
+ margin-bottom: 40px;
114
+ }
115
+ .section-title {
116
+ font-size: 18px;
117
+ color: #3fb950;
118
+ margin-bottom: 16px;
119
+ padding-bottom: 8px;
120
+ border-bottom: 1px solid #3e3e42;
121
+ }
122
+ .status {
123
+ background: #1e3a1f;
124
+ border: 1px solid #238636;
125
+ border-radius: 4px;
126
+ padding: 12px;
127
+ margin-bottom: 20px;
128
+ color: #3fb950;
129
+ font-size: 12px;
130
+ }
131
+ .status.error {
132
+ background: #3f1f1f;
133
+ border-color: #f85149;
134
+ color: #f85149;
135
+ }
136
+ </style>
137
+ </head>
138
+ <body>
139
+ <div class="container">
140
+ <h1>🤖 cycleCAD Agent API Test Suite</h1>
141
+ <p class="subtitle">Test the Agent-First OS for Manufacturing. Open the cycleCAD app in another tab, then use these tests.</p>
142
+
143
+ <div class="status" id="status">
144
+ ✓ Test suite loaded. Open /app/ in another tab, then run tests below.
145
+ </div>
146
+
147
+ <!-- Meta Tests -->
148
+ <div class="section">
149
+ <div class="section-title">Meta API (Health &amp; Schema)</div>
150
+ <div class="grid">
151
+ <div class="card">
152
+ <div class="card-title">Ping</div>
153
+ <div class="card-desc">Test API connectivity — should return pong + timestamp</div>
154
+ <div class="command-display">{ "method": "meta.ping", "params": {} }</div>
155
+ <div class="button-group">
156
+ <button onclick="runTest('meta.ping')">Run</button>
157
+ </div>
158
+ <div class="result" id="result-ping"></div>
159
+ </div>
160
+
161
+ <div class="card">
162
+ <div class="card-title">Version Info</div>
163
+ <div class="card-desc">Get cycleCAD version, modules, and API version</div>
164
+ <div class="command-display">{ "method": "meta.version", "params": {} }</div>
165
+ <div class="button-group">
166
+ <button onclick="runTest('meta.version')">Run</button>
167
+ </div>
168
+ <div class="result" id="result-version"></div>
169
+ </div>
170
+
171
+ <div class="card">
172
+ <div class="card-title">API Schema</div>
173
+ <div class="card-desc">Get full API schema with all commands, namespaces, and parameters</div>
174
+ <div class="command-display">{ "method": "meta.schema", "params": {} }</div>
175
+ <div class="button-group">
176
+ <button onclick="runTest('meta.schema')">Run</button>
177
+ </div>
178
+ <div class="result" id="result-schema"></div>
179
+ </div>
180
+ </div>
181
+ </div>
182
+
183
+ <!-- Sketch Tests -->
184
+ <div class="section">
185
+ <div class="section-title">Sketch (2D Drawing)</div>
186
+ <div class="grid">
187
+ <div class="card">
188
+ <div class="card-title">Start Sketch</div>
189
+ <div class="card-desc">Begin 2D sketch on XY plane</div>
190
+ <div class="command-display">{ "method": "sketch.start", "params": { "plane": "XY" } }</div>
191
+ <div class="button-group">
192
+ <button onclick="runTest('sketch.start')">Run</button>
193
+ </div>
194
+ <div class="result" id="result-sketch-start"></div>
195
+ </div>
196
+
197
+ <div class="card">
198
+ <div class="card-title">Draw Rectangle</div>
199
+ <div class="card-desc">Draw a 50x30mm rectangle</div>
200
+ <div class="command-display">{ "method": "sketch.rect", "params": { "width": 50, "height": 30 } }</div>
201
+ <div class="button-group">
202
+ <button onclick="runTest('sketch.rect')">Run</button>
203
+ </div>
204
+ <div class="result" id="result-sketch-rect"></div>
205
+ </div>
206
+
207
+ <div class="card">
208
+ <div class="card-title">Draw Circle</div>
209
+ <div class="card-desc">Draw a 20mm radius circle</div>
210
+ <div class="command-display">{ "method": "sketch.circle", "params": { "radius": 20 } }</div>
211
+ <div class="button-group">
212
+ <button onclick="runTest('sketch.circle')">Run</button>
213
+ </div>
214
+ <div class="result" id="result-sketch-circle"></div>
215
+ </div>
216
+
217
+ <div class="card">
218
+ <div class="card-title">End Sketch</div>
219
+ <div class="card-desc">Finish 2D sketch and return all entities</div>
220
+ <div class="command-display">{ "method": "sketch.end", "params": {} }</div>
221
+ <div class="button-group">
222
+ <button onclick="runTest('sketch.end')">Run</button>
223
+ </div>
224
+ <div class="result" id="result-sketch-end"></div>
225
+ </div>
226
+ </div>
227
+ </div>
228
+
229
+ <!-- Operations Tests -->
230
+ <div class="section">
231
+ <div class="section-title">Operations (3D Modeling)</div>
232
+ <div class="grid">
233
+ <div class="card">
234
+ <div class="card-title">Extrude</div>
235
+ <div class="card-desc">Extrude current sketch 10mm upward into 3D solid</div>
236
+ <div class="command-display">{ "method": "ops.extrude", "params": { "height": 10, "material": "steel" } }</div>
237
+ <div class="button-group">
238
+ <button onclick="runTest('ops.extrude')">Run</button>
239
+ </div>
240
+ <div class="result" id="result-ops-extrude"></div>
241
+ </div>
242
+
243
+ <div class="card">
244
+ <div class="card-title">Fillet</div>
245
+ <div class="card-desc">Apply 2mm fillet to edges of a feature (ID: extrude_1)</div>
246
+ <div class="command-display">{ "method": "ops.fillet", "params": { "target": "extrude_1", "radius": 2 } }</div>
247
+ <div class="button-group">
248
+ <button onclick="runTest('ops.fillet')">Run</button>
249
+ </div>
250
+ <div class="result" id="result-ops-fillet"></div>
251
+ </div>
252
+
253
+ <div class="card">
254
+ <div class="card-title">Primitive Box</div>
255
+ <div class="card-desc">Create a 50×30×20 mm box primitive</div>
256
+ <div class="command-display">{ "method": "ops.primitive", "params": { "shape": "box", "width": 50, "height": 30, "depth": 20 } }</div>
257
+ <div class="button-group">
258
+ <button onclick="runTest('ops.primitive')">Run</button>
259
+ </div>
260
+ <div class="result" id="result-ops-primitive"></div>
261
+ </div>
262
+ </div>
263
+ </div>
264
+
265
+ <!-- View Tests -->
266
+ <div class="section">
267
+ <div class="section-title">Viewport (Camera &amp; Display)</div>
268
+ <div class="grid">
269
+ <div class="card">
270
+ <div class="card-title">Set Isometric View</div>
271
+ <div class="card-desc">Rotate camera to isometric (3D perspective)</div>
272
+ <div class="command-display">{ "method": "view.set", "params": { "view": "isometric" } }</div>
273
+ <div class="button-group">
274
+ <button onclick="runTest('view.iso')">Isometric</button>
275
+ <button class="secondary" onclick="runTest('view.front')">Front</button>
276
+ </div>
277
+ <div class="result" id="result-view"></div>
278
+ </div>
279
+
280
+ <div class="card">
281
+ <div class="card-title">Fit to View</div>
282
+ <div class="card-desc">Zoom &amp; center camera to show all features</div>
283
+ <div class="command-display">{ "method": "view.fit", "params": {} }</div>
284
+ <div class="button-group">
285
+ <button onclick="runTest('view.fit')">Run</button>
286
+ </div>
287
+ <div class="result" id="result-view-fit"></div>
288
+ </div>
289
+
290
+ <div class="card">
291
+ <div class="card-title">Toggle Wireframe</div>
292
+ <div class="card-desc">Toggle wireframe rendering on/off</div>
293
+ <div class="command-display">{ "method": "view.wireframe", "params": { "enabled": true } }</div>
294
+ <div class="button-group">
295
+ <button onclick="runTest('view.wireframe')">Toggle</button>
296
+ </div>
297
+ <div class="result" id="result-view-wireframe"></div>
298
+ </div>
299
+ </div>
300
+ </div>
301
+
302
+ <!-- Query Tests -->
303
+ <div class="section">
304
+ <div class="section-title">Query (Model Inspection)</div>
305
+ <div class="grid">
306
+ <div class="card">
307
+ <div class="card-title">List Features</div>
308
+ <div class="card-desc">Get all features in current model</div>
309
+ <div class="command-display">{ "method": "query.features", "params": {} }</div>
310
+ <div class="button-group">
311
+ <button onclick="runTest('query.features')">Run</button>
312
+ </div>
313
+ <div class="result" id="result-query-features"></div>
314
+ </div>
315
+
316
+ <div class="card">
317
+ <div class="card-title">List Materials</div>
318
+ <div class="card-desc">Get available material presets (Steel, Aluminum, etc.)</div>
319
+ <div class="command-display">{ "method": "query.materials", "params": {} }</div>
320
+ <div class="button-group">
321
+ <button onclick="runTest('query.materials')">Run</button>
322
+ </div>
323
+ <div class="result" id="result-query-materials"></div>
324
+ </div>
325
+
326
+ <div class="card">
327
+ <div class="card-title">Session Info</div>
328
+ <div class="card-desc">Get current session ID and command count</div>
329
+ <div class="command-display">{ "method": "query.session", "params": {} }</div>
330
+ <div class="button-group">
331
+ <button onclick="runTest('query.session')">Run</button>
332
+ </div>
333
+ <div class="result" id="result-query-session"></div>
334
+ </div>
335
+ </div>
336
+ </div>
337
+
338
+ <!-- Validation Tests -->
339
+ <div class="section">
340
+ <div class="section-title">Validation (DFM &amp; Engineering)</div>
341
+ <div class="grid">
342
+ <div class="card">
343
+ <div class="card-title">Design Review</div>
344
+ <div class="card-desc">Auto-analyze part for manufacturing issues (geometry, wall thickness, aspect ratio)</div>
345
+ <div class="command-display">{ "method": "validate.designReview", "params": { "target": "extrude_1" } }</div>
346
+ <div class="button-group">
347
+ <button onclick="runTest('validate.designReview')">Run</button>
348
+ </div>
349
+ <div class="result" id="result-validate-designreview"></div>
350
+ </div>
351
+
352
+ <div class="card">
353
+ <div class="card-title">Printability Check</div>
354
+ <div class="card-desc">Check if part fits FDM 3D printer (build volume, wall thickness, aspect ratio)</div>
355
+ <div class="command-display">{ "method": "validate.printability", "params": { "target": "extrude_1", "process": "FDM" } }</div>
356
+ <div class="button-group">
357
+ <button onclick="runTest('validate.printability')">Run</button>
358
+ </div>
359
+ <div class="result" id="result-validate-printability"></div>
360
+ </div>
361
+
362
+ <div class="card">
363
+ <div class="card-title">Cost Estimation</div>
364
+ <div class="card-desc">Estimate manufacturing cost (material + machine time)</div>
365
+ <div class="command-display">{ "method": "validate.cost", "params": { "target": "extrude_1", "process": "FDM", "material": "PLA" } }</div>
366
+ <div class="button-group">
367
+ <button onclick="runTest('validate.cost')">Run</button>
368
+ </div>
369
+ <div class="result" id="result-validate-cost"></div>
370
+ </div>
371
+
372
+ <div class="card">
373
+ <div class="card-title">Mass Estimation</div>
374
+ <div class="card-desc">Estimate part weight based on material and volume</div>
375
+ <div class="command-display">{ "method": "validate.mass", "params": { "target": "extrude_1", "material": "aluminum" } }</div>
376
+ <div class="button-group">
377
+ <button onclick="runTest('validate.mass')">Run</button>
378
+ </div>
379
+ <div class="result" id="result-validate-mass"></div>
380
+ </div>
381
+ </div>
382
+ </div>
383
+
384
+ <!-- Export Tests -->
385
+ <div class="section">
386
+ <div class="section-title">Export (File Output)</div>
387
+ <div class="grid">
388
+ <div class="card">
389
+ <div class="card-title">Export STL</div>
390
+ <div class="card-desc">Export current model as STL (binary format for 3D printing)</div>
391
+ <div class="command-display">{ "method": "export.stl", "params": { "filename": "part.stl", "binary": true } }</div>
392
+ <div class="button-group">
393
+ <button onclick="runTest('export.stl')">Run</button>
394
+ </div>
395
+ <div class="result" id="result-export-stl"></div>
396
+ </div>
397
+
398
+ <div class="card">
399
+ <div class="card-title">Export JSON</div>
400
+ <div class="card-desc">Export model as cycleCAD native JSON format</div>
401
+ <div class="command-display">{ "method": "export.json", "params": { "filename": "model.cyclecad.json" } }</div>
402
+ <div class="button-group">
403
+ <button onclick="runTest('export.json')">Run</button>
404
+ </div>
405
+ <div class="result" id="result-export-json"></div>
406
+ </div>
407
+ </div>
408
+ </div>
409
+
410
+ </div>
411
+
412
+ <script>
413
+ async function runTest(testId) {
414
+ const resultEl = document.getElementById(`result-${testId.replace('.', '-')}`);
415
+ const tests = {
416
+ 'meta.ping': { method: 'meta.ping', params: {} },
417
+ 'meta.version': { method: 'meta.version', params: {} },
418
+ 'meta.schema': { method: 'meta.schema', params: {} },
419
+ 'sketch.start': { method: 'sketch.start', params: { plane: 'XY' } },
420
+ 'sketch.rect': { method: 'sketch.rect', params: { width: 50, height: 30 } },
421
+ 'sketch.circle': { method: 'sketch.circle', params: { radius: 20 } },
422
+ 'sketch.end': { method: 'sketch.end', params: {} },
423
+ 'ops.extrude': { method: 'ops.extrude', params: { height: 10, material: 'steel' } },
424
+ 'ops.fillet': { method: 'ops.fillet', params: { target: 'extrude_1', radius: 2 } },
425
+ 'ops.primitive': { method: 'ops.primitive', params: { shape: 'box', width: 50, height: 30, depth: 20 } },
426
+ 'view.iso': { method: 'view.set', params: { view: 'isometric' } },
427
+ 'view.front': { method: 'view.set', params: { view: 'front' } },
428
+ 'view.fit': { method: 'view.fit', params: {} },
429
+ 'view.wireframe': { method: 'view.wireframe', params: { enabled: true } },
430
+ 'query.features': { method: 'query.features', params: {} },
431
+ 'query.materials': { method: 'query.materials', params: {} },
432
+ 'query.session': { method: 'query.session', params: {} },
433
+ 'validate.designreview': { method: 'validate.designReview', params: { target: 'extrude_1' } },
434
+ 'validate.printability': { method: 'validate.printability', params: { target: 'extrude_1', process: 'FDM' } },
435
+ 'validate.cost': { method: 'validate.cost', params: { target: 'extrude_1', process: 'FDM', material: 'PLA' } },
436
+ 'validate.mass': { method: 'validate.mass', params: { target: 'extrude_1', material: 'aluminum' } },
437
+ 'export.stl': { method: 'export.stl', params: { filename: 'part.stl', binary: true } },
438
+ 'export.json': { method: 'export.json', params: { filename: 'model.cyclecad.json' } },
439
+ };
440
+
441
+ const cmd = tests[testId];
442
+ if (!cmd) {
443
+ resultEl.textContent = 'Test not found';
444
+ resultEl.classList.add('error');
445
+ return;
446
+ }
447
+
448
+ resultEl.textContent = 'Loading...';
449
+ resultEl.classList.remove('error');
450
+ resultEl.classList.add('loading');
451
+
452
+ setTimeout(() => {
453
+ try {
454
+ if (!window.opener || !window.opener.cycleCAD) {
455
+ resultEl.textContent = '❌ cycleCAD API not found in parent window. Open /app/ in another tab first.';
456
+ resultEl.classList.add('error');
457
+ resultEl.classList.remove('loading');
458
+ return;
459
+ }
460
+
461
+ const result = window.opener.cycleCAD.execute(cmd);
462
+ resultEl.textContent = JSON.stringify(result, null, 2);
463
+ resultEl.classList.remove('loading');
464
+ if (!result.ok) resultEl.classList.add('error');
465
+ } catch (e) {
466
+ resultEl.textContent = `❌ ${e.message}`;
467
+ resultEl.classList.add('error');
468
+ resultEl.classList.remove('loading');
469
+ }
470
+ }, 100);
471
+ }
472
+
473
+ // Check if cycleCAD is available
474
+ window.addEventListener('load', () => {
475
+ if (window.opener && window.opener.cycleCAD) {
476
+ const status = document.getElementById('status');
477
+ status.textContent = '✓ Connected to cycleCAD! All tests ready.';
478
+ } else {
479
+ const status = document.getElementById('status');
480
+ status.textContent = '⚠️ cycleCAD not detected. Open /app/ in another tab, then run tests.';
481
+ status.classList.add('error');
482
+ }
483
+ });
484
+ </script>
485
+ </body>
486
+ </html>