cyclecad 0.2.2 → 0.2.3
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/API-BUILD-MANIFEST.txt +339 -0
- package/API-SERVER.md +535 -0
- package/Architecture-Deck.pptx +0 -0
- package/CLAUDE.md +172 -11
- package/CLI-BUILD-SUMMARY.md +504 -0
- package/CLI-INDEX.md +356 -0
- package/CLI-README.md +466 -0
- package/COLLABORATION-INTEGRATION-GUIDE.md +325 -0
- package/CONNECTED_FABS_GUIDE.md +612 -0
- package/CONNECTED_FABS_README.md +310 -0
- package/DELIVERABLES.md +343 -0
- package/DFM-ANALYZER-INTEGRATION.md +368 -0
- package/DFM-QUICK-START.js +253 -0
- package/Dockerfile +69 -0
- package/IMPLEMENTATION.md +327 -0
- package/LICENSE +31 -0
- package/MARKETPLACE_QUICK_REFERENCE.txt +294 -0
- package/MCP-INDEX.md +264 -0
- package/QUICKSTART-API.md +388 -0
- package/QUICKSTART-CLI.md +211 -0
- package/QUICKSTART-MCP.md +196 -0
- package/README-MCP.md +208 -0
- package/TEST-TOKEN-ENGINE.md +319 -0
- package/TOKEN-ENGINE-SUMMARY.md +266 -0
- package/TOKENS-README.md +263 -0
- package/TOOLS-REFERENCE.md +254 -0
- package/app/index.html +168 -3
- package/app/js/TOKEN-INTEGRATION.md +391 -0
- package/app/js/agent-api.js +3 -3
- package/app/js/ai-copilot.js +1435 -0
- package/app/js/cam-pipeline.js +840 -0
- package/app/js/collaboration-ui.js +995 -0
- package/app/js/collaboration.js +1116 -0
- package/app/js/connected-fabs-example.js +404 -0
- package/app/js/connected-fabs.js +1449 -0
- package/app/js/dfm-analyzer.js +1760 -0
- package/app/js/marketplace.js +1994 -0
- package/app/js/material-library.js +2115 -0
- package/app/js/token-dashboard.js +563 -0
- package/app/js/token-engine.js +743 -0
- package/app/test-agent.html +1801 -0
- package/bin/cyclecad-cli.js +662 -0
- package/bin/cyclecad-mcp +2 -0
- package/bin/server.js +242 -0
- package/cycleCAD-Architecture.pptx +0 -0
- package/cycleCAD-Investor-Deck.pptx +0 -0
- package/demo-mcp.sh +60 -0
- package/docs/API-SERVER-SUMMARY.md +375 -0
- package/docs/API-SERVER.md +667 -0
- package/docs/CAM-EXAMPLES.md +344 -0
- package/docs/CAM-INTEGRATION.md +612 -0
- package/docs/CAM-QUICK-REFERENCE.md +199 -0
- package/docs/CLI-INTEGRATION.md +510 -0
- package/docs/CLI.md +872 -0
- package/docs/MARKETPLACE-API-SCHEMA.json +564 -0
- package/docs/MARKETPLACE-INTEGRATION.md +467 -0
- package/docs/MARKETPLACE-SETUP.html +439 -0
- package/docs/MCP-SERVER.md +403 -0
- package/examples/api-client-example.js +488 -0
- package/examples/api-client-example.py +359 -0
- package/examples/batch-manufacturing.txt +28 -0
- package/examples/batch-simple.txt +26 -0
- package/model-marketplace.html +1273 -0
- package/package.json +14 -3
- package/server/api-server.js +1120 -0
- package/server/mcp-server.js +1161 -0
- package/test-api-server.js +432 -0
- package/test-mcp.js +198 -0
- package/~$cycleCAD-Investor-Deck.pptx +0 -0
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
# CAM Pipeline — Quick Reference
|
|
2
|
+
|
|
3
|
+
## Quick Start (30 seconds)
|
|
4
|
+
|
|
5
|
+
```javascript
|
|
6
|
+
// 1. Get a mesh
|
|
7
|
+
const mesh = window.allParts[0];
|
|
8
|
+
|
|
9
|
+
// 2. Slice for 3D printing
|
|
10
|
+
const slice = window.cycleCAD.cam.slice(mesh, {
|
|
11
|
+
printer: 'ender3',
|
|
12
|
+
material: 'pla'
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
// 3. Download G-code
|
|
16
|
+
window.cycleCAD.cam.exportGcode(slice.gcode, 'part.gcode');
|
|
17
|
+
|
|
18
|
+
// 4. Compare costs
|
|
19
|
+
const costs = window.cycleCAD.cam.compareCosts(mesh);
|
|
20
|
+
console.table(costs.processes);
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## One-Liner Examples
|
|
24
|
+
|
|
25
|
+
```javascript
|
|
26
|
+
// FDM slicing
|
|
27
|
+
window.cycleCAD.cam.slice(mesh).estimatedTimeReadable
|
|
28
|
+
// Output: "6h 0m"
|
|
29
|
+
|
|
30
|
+
// CNC estimate
|
|
31
|
+
window.cycleCAD.cam.estimate(mesh, {process: 'CNC'}).totalCost
|
|
32
|
+
// Output: 47.50
|
|
33
|
+
|
|
34
|
+
// List all machines
|
|
35
|
+
window.cycleCAD.cam.getMachines().map(m => m.name)
|
|
36
|
+
// Output: ["Creality Ender 3", "Prusa MK4", ...]
|
|
37
|
+
|
|
38
|
+
// Nesting score
|
|
39
|
+
window.cycleCAD.cam.nest(parts, {width: 1000, height: 500}).nestingScore
|
|
40
|
+
// Output: "A"
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## API Cheat Sheet
|
|
44
|
+
|
|
45
|
+
| Command | Input | Output | Example |
|
|
46
|
+
|---------|-------|--------|---------|
|
|
47
|
+
| `slice()` | mesh, {printer, material, layerHeight} | {gcode, time, weight} | `slice(m, {printer:'ender3'})` |
|
|
48
|
+
| `toolpath()` | mesh, {tool, machine, strategy} | {gcode, time, passes} | `toolpath(m, {strategy:'contour'})` |
|
|
49
|
+
| `nest()` | parts[], sheetSize | {placements, utilization} | `nest([{w:100,h:50}], {w:1000})` |
|
|
50
|
+
| `compareCosts()` | mesh, {material} | {processes[]} | `compareCosts(m)` |
|
|
51
|
+
| `estimate()` | mesh, {process, quantity} | {cost, time, breakdown} | `estimate(m, {process:'FDM'})` |
|
|
52
|
+
| `exportGcode()` | gcode, filename | download | `exportGcode(gcode, 'p.gcode')` |
|
|
53
|
+
| `getMachines()` | none | {id, name, type, specs}[] | `getMachines()` |
|
|
54
|
+
| `getTools()` | none | {id, name, diameter}[] | `getTools()` |
|
|
55
|
+
| `getMaterials()` | none | {materials[]} | `getMaterials()` |
|
|
56
|
+
|
|
57
|
+
## Machine Quick Codes
|
|
58
|
+
|
|
59
|
+
| Code | Machine | Type | Build Volume |
|
|
60
|
+
|------|---------|------|---------------|
|
|
61
|
+
| `ender3` | Creality Ender 3 | FDM | 220×220×250 |
|
|
62
|
+
| `prusa_mk4` | Prusa MK4 | FDM | 250×210×210 |
|
|
63
|
+
| `bambu_x1` | Bambu Lab X1 | FDM | 256×256×256 |
|
|
64
|
+
| `elegoo_mars` | Elegoo Mars | SLA | 129×80×150 |
|
|
65
|
+
| `formlabs_form3` | Formlabs Form 3 | SLA | 145×145×185 |
|
|
66
|
+
| `shapeoko` | Shapeoko 5 | CNC | 400×400×75 |
|
|
67
|
+
| `nomad3` | Nomad 3 | CNC | 203×203×76 |
|
|
68
|
+
| `tormach_pcnc` | Tormach PCNC | CNC | 432×279×305 |
|
|
69
|
+
| `k40` | K40 Laser | Laser | 300×200 |
|
|
70
|
+
| `xtool_d1` | xTool M1 | Laser | 432×406 |
|
|
71
|
+
|
|
72
|
+
## Material Quick Codes
|
|
73
|
+
|
|
74
|
+
| Material | Density | Cost/kg | Best For |
|
|
75
|
+
|----------|---------|---------|----------|
|
|
76
|
+
| `pla` | 1.24 | €8.00 | FDM (default) |
|
|
77
|
+
| `petg` | 1.27 | €12.00 | FDM (tough) |
|
|
78
|
+
| `abs` | 1.05 | €10.00 | FDM (flexible) |
|
|
79
|
+
| `nylon` | 1.14 | €2.50 | FDM (strong) |
|
|
80
|
+
| `resin` | 1.15 | €35.00 | SLA (detail) |
|
|
81
|
+
| `steel` | 7.85 | €0.50 | CNC |
|
|
82
|
+
| `aluminum` | 2.70 | €1.20 | CNC |
|
|
83
|
+
|
|
84
|
+
## Keyboard Shortcuts (if integrated into UI)
|
|
85
|
+
|
|
86
|
+
| Key | Action |
|
|
87
|
+
|-----|--------|
|
|
88
|
+
| `Alt+C` | Toggle CAM panel |
|
|
89
|
+
| `S` | Slice current part |
|
|
90
|
+
| `E` | Export G-code |
|
|
91
|
+
| `Shift+C` | Compare costs |
|
|
92
|
+
|
|
93
|
+
## Common Workflows
|
|
94
|
+
|
|
95
|
+
### Print a Part
|
|
96
|
+
```javascript
|
|
97
|
+
const mesh = window.allParts[0];
|
|
98
|
+
const result = window.cycleCAD.cam.slice(mesh);
|
|
99
|
+
window.cycleCAD.cam.exportGcode(result.gcode, 'part.gcode');
|
|
100
|
+
// → Download G-code, open in Cura, print
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Find Cheapest Option
|
|
104
|
+
```javascript
|
|
105
|
+
const comparison = window.cycleCAD.cam.compareCosts(mesh);
|
|
106
|
+
const cheapest = comparison.processes[0];
|
|
107
|
+
console.log(`${cheapest.process}: €${cheapest.totalCost}`);
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### Batch Production Cost
|
|
111
|
+
```javascript
|
|
112
|
+
for (let qty of [1, 10, 100]) {
|
|
113
|
+
const est = window.cycleCAD.cam.estimate(mesh, {quantity: qty});
|
|
114
|
+
console.log(`${qty}x: €${est.totalBatch} (€${(est.totalBatch/qty).toFixed(2)}/unit)`);
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### Check Build Volume Fit
|
|
119
|
+
```javascript
|
|
120
|
+
const result = window.cycleCAD.cam.slice(mesh, {printer: 'ender3'});
|
|
121
|
+
if (!result.fits) {
|
|
122
|
+
console.warn('Too large for Ender 3');
|
|
123
|
+
const result2 = window.cycleCAD.cam.slice(mesh, {printer: 'bambu_x1'});
|
|
124
|
+
console.log(`Bambu X1: ${result2.fits ? 'fits' : 'too large'}`);
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### CNC Milling Setup
|
|
129
|
+
```javascript
|
|
130
|
+
const result = window.cycleCAD.cam.toolpath(mesh, {
|
|
131
|
+
machine: 'shapeoko',
|
|
132
|
+
tool: 't_6mm_flat',
|
|
133
|
+
strategy: 'contour',
|
|
134
|
+
feedRate: 600
|
|
135
|
+
});
|
|
136
|
+
console.log(`Time: ${result.estimatedTimeReadable}`);
|
|
137
|
+
window.cycleCAD.cam.exportGcode(result.gcode, 'mill.nc');
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## Troubleshooting
|
|
141
|
+
|
|
142
|
+
| Issue | Solution |
|
|
143
|
+
|-------|----------|
|
|
144
|
+
| "mesh is undefined" | Get mesh from `window.allParts[0]` |
|
|
145
|
+
| "printer not found" | Use `getMachines()` to list valid IDs |
|
|
146
|
+
| "Volume too large" | Try larger printer or rotate mesh |
|
|
147
|
+
| "G-code looks wrong" | Use output in dedicated slicer (Cura) |
|
|
148
|
+
| "Cost seems off" | Material costs vary; adjust in CAM-INTEGRATION.md |
|
|
149
|
+
|
|
150
|
+
## Response Format
|
|
151
|
+
|
|
152
|
+
All functions return an object with:
|
|
153
|
+
```javascript
|
|
154
|
+
{
|
|
155
|
+
// Main result
|
|
156
|
+
result: {}, // Function-specific output
|
|
157
|
+
|
|
158
|
+
// Common fields
|
|
159
|
+
time: number, // Estimated time in minutes
|
|
160
|
+
cost: number, // Total cost in EUR
|
|
161
|
+
fits: boolean, // Fits in build volume
|
|
162
|
+
gcode: string, // G-code output (if applicable)
|
|
163
|
+
|
|
164
|
+
// Error (if thrown)
|
|
165
|
+
error: string // Error message
|
|
166
|
+
}
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
## Performance
|
|
170
|
+
|
|
171
|
+
| Operation | Time |
|
|
172
|
+
|-----------|------|
|
|
173
|
+
| Slice simple mesh | <100ms |
|
|
174
|
+
| Slice complex mesh | <300ms |
|
|
175
|
+
| Toolpath generation | <200ms |
|
|
176
|
+
| Cost comparison | <50ms |
|
|
177
|
+
| Nesting 20 parts | <50ms |
|
|
178
|
+
| Export G-code | instant |
|
|
179
|
+
|
|
180
|
+
All operations are synchronous.
|
|
181
|
+
|
|
182
|
+
## Integration Points
|
|
183
|
+
|
|
184
|
+
1. **Console API** — Already available as `window.cycleCAD.cam`
|
|
185
|
+
2. **Agent API** — Add to `agent-api.js` commands
|
|
186
|
+
3. **UI Panel** — Copy HTML from CAM-INTEGRATION.md
|
|
187
|
+
4. **Toolbar** — Add button to toggle CAM panel
|
|
188
|
+
|
|
189
|
+
## Learning Path
|
|
190
|
+
|
|
191
|
+
1. **Try it now** → `const m = window.allParts[0]; console.log(window.cycleCAD.cam.slice(m))`
|
|
192
|
+
2. **Read examples** → See CAM-EXAMPLES.md
|
|
193
|
+
3. **Explore API** → Try each of the 11 functions
|
|
194
|
+
4. **Integrate UI** → Copy panel code to app/index.html
|
|
195
|
+
5. **Wire agent** → Add cam.* commands to agent-api.js
|
|
196
|
+
|
|
197
|
+
---
|
|
198
|
+
|
|
199
|
+
**Version 1.0** — Last updated 2026-03-26
|
|
@@ -0,0 +1,510 @@
|
|
|
1
|
+
# cycleCAD CLI Integration Guide
|
|
2
|
+
|
|
3
|
+
This guide explains how to integrate the cycleCAD CLI with your actual CAD application.
|
|
4
|
+
|
|
5
|
+
## Architecture Overview
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
┌─────────────────────────────────────────────────────────┐
|
|
9
|
+
│ Terminal / Script │
|
|
10
|
+
│ $ cyclecad shape.cylinder --radius 25 --height 80 │
|
|
11
|
+
└──────────────────┬──────────────────────────────────────┘
|
|
12
|
+
│
|
|
13
|
+
│ HTTP POST /api/execute
|
|
14
|
+
│ { method: "shape.cylinder", params: {...} }
|
|
15
|
+
│
|
|
16
|
+
┌──────────────────▼──────────────────────────────────────┐
|
|
17
|
+
│ cycleCAD API Server (Node.js / Express / FastAPI) │
|
|
18
|
+
│ - Receives command via /api/execute │
|
|
19
|
+
│ - Dispatches to cycleCAD modules │
|
|
20
|
+
│ - Returns JSON result │
|
|
21
|
+
└──────────────────┬──────────────────────────────────────┘
|
|
22
|
+
│
|
|
23
|
+
│ HTTP Response
|
|
24
|
+
│ { ok: true, result: {...} }
|
|
25
|
+
│
|
|
26
|
+
┌──────────────────▼──────────────────────────────────────┐
|
|
27
|
+
│ CLI Client │
|
|
28
|
+
│ - Parses response JSON │
|
|
29
|
+
│ - Formats output for terminal │
|
|
30
|
+
│ - Displays results │
|
|
31
|
+
└─────────────────────────────────────────────────────────┘
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Step 1: Implement the API Endpoint
|
|
35
|
+
|
|
36
|
+
Create a `/api/execute` endpoint in your server that receives commands and returns results.
|
|
37
|
+
|
|
38
|
+
### Express.js Example
|
|
39
|
+
|
|
40
|
+
```javascript
|
|
41
|
+
// server.js
|
|
42
|
+
const express = require('express');
|
|
43
|
+
const app = express();
|
|
44
|
+
|
|
45
|
+
app.use(express.json());
|
|
46
|
+
|
|
47
|
+
// Import cycleCAD modules
|
|
48
|
+
const { viewport, sketch, operations } = require('./cycleCAD');
|
|
49
|
+
|
|
50
|
+
// Main API endpoint
|
|
51
|
+
app.post('/api/execute', (req, res) => {
|
|
52
|
+
const { method, params } = req.body;
|
|
53
|
+
|
|
54
|
+
try {
|
|
55
|
+
// Dispatch command to appropriate handler
|
|
56
|
+
const result = executeCommand(method, params);
|
|
57
|
+
|
|
58
|
+
res.json({
|
|
59
|
+
ok: true,
|
|
60
|
+
result: result
|
|
61
|
+
});
|
|
62
|
+
} catch (error) {
|
|
63
|
+
res.status(400).json({
|
|
64
|
+
ok: false,
|
|
65
|
+
error: error.message
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
// Command dispatcher
|
|
71
|
+
function executeCommand(method, params) {
|
|
72
|
+
const [namespace, command] = method.split('.');
|
|
73
|
+
|
|
74
|
+
// Route to appropriate namespace handler
|
|
75
|
+
switch (namespace) {
|
|
76
|
+
case 'shape':
|
|
77
|
+
return handleShapeCommand(command, params);
|
|
78
|
+
case 'sketch':
|
|
79
|
+
return handleSketchCommand(command, params);
|
|
80
|
+
case 'feature':
|
|
81
|
+
return handleFeatureCommand(command, params);
|
|
82
|
+
// ... more namespaces
|
|
83
|
+
default:
|
|
84
|
+
throw new Error(`Unknown namespace: ${namespace}`);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Shape handlers
|
|
89
|
+
function handleShapeCommand(command, params) {
|
|
90
|
+
switch (command) {
|
|
91
|
+
case 'cylinder':
|
|
92
|
+
return viewport.createCylinder(params.radius, params.height);
|
|
93
|
+
case 'box':
|
|
94
|
+
return viewport.createBox(params.width, params.height, params.depth);
|
|
95
|
+
// ... more shape commands
|
|
96
|
+
default:
|
|
97
|
+
throw new Error(`Unknown command: shape.${command}`);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Similar handlers for other namespaces...
|
|
102
|
+
|
|
103
|
+
app.listen(3000, () => {
|
|
104
|
+
console.log('cycleCAD API server running on http://localhost:3000');
|
|
105
|
+
});
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### Python / FastAPI Example
|
|
109
|
+
|
|
110
|
+
```python
|
|
111
|
+
# server.py
|
|
112
|
+
from fastapi import FastAPI
|
|
113
|
+
from pydantic import BaseModel
|
|
114
|
+
import cyclecad
|
|
115
|
+
|
|
116
|
+
app = FastAPI()
|
|
117
|
+
|
|
118
|
+
class ExecuteRequest(BaseModel):
|
|
119
|
+
method: str
|
|
120
|
+
params: dict = {}
|
|
121
|
+
|
|
122
|
+
@app.post("/api/execute")
|
|
123
|
+
async def execute_command(request: ExecuteRequest):
|
|
124
|
+
try:
|
|
125
|
+
method, params = request.method, request.params
|
|
126
|
+
result = dispatch_command(method, params)
|
|
127
|
+
return {"ok": True, "result": result}
|
|
128
|
+
except Exception as e:
|
|
129
|
+
return {"ok": False, "error": str(e)}
|
|
130
|
+
|
|
131
|
+
def dispatch_command(method: str, params: dict):
|
|
132
|
+
namespace, command = method.split('.')
|
|
133
|
+
|
|
134
|
+
if namespace == 'shape':
|
|
135
|
+
if command == 'cylinder':
|
|
136
|
+
return cyclecad.create_cylinder(
|
|
137
|
+
radius=params.get('radius'),
|
|
138
|
+
height=params.get('height')
|
|
139
|
+
)
|
|
140
|
+
# ... more commands
|
|
141
|
+
elif namespace == 'sketch':
|
|
142
|
+
# ... sketch commands
|
|
143
|
+
pass
|
|
144
|
+
# ... more namespaces
|
|
145
|
+
|
|
146
|
+
raise ValueError(f"Unknown command: {method}")
|
|
147
|
+
|
|
148
|
+
if __name__ == "__main__":
|
|
149
|
+
import uvicorn
|
|
150
|
+
uvicorn.run(app, host="0.0.0.0", port=3000)
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## Step 2: Return Proper Response Format
|
|
154
|
+
|
|
155
|
+
Each command handler should return a result object. The response format is:
|
|
156
|
+
|
|
157
|
+
```json
|
|
158
|
+
{
|
|
159
|
+
"ok": true,
|
|
160
|
+
"result": {
|
|
161
|
+
"entityId": "unique_id",
|
|
162
|
+
"type": "shape/feature/assembly",
|
|
163
|
+
"property1": "value",
|
|
164
|
+
"property2": 123,
|
|
165
|
+
"message": "Human-readable message"
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### Examples
|
|
171
|
+
|
|
172
|
+
**Create a cylinder:**
|
|
173
|
+
```json
|
|
174
|
+
{
|
|
175
|
+
"ok": true,
|
|
176
|
+
"result": {
|
|
177
|
+
"entityId": "cylinder_1",
|
|
178
|
+
"type": "shape",
|
|
179
|
+
"radius": 25,
|
|
180
|
+
"height": 80,
|
|
181
|
+
"volume": 157079.63,
|
|
182
|
+
"message": "Created cylinder with radius 25mm and height 80mm"
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
**Validate dimensions:**
|
|
188
|
+
```json
|
|
189
|
+
{
|
|
190
|
+
"ok": true,
|
|
191
|
+
"result": {
|
|
192
|
+
"target": "extrude_1",
|
|
193
|
+
"dimensions": {
|
|
194
|
+
"width": 80,
|
|
195
|
+
"height": 40,
|
|
196
|
+
"depth": 30
|
|
197
|
+
},
|
|
198
|
+
"message": "Dimensions calculated"
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
**Estimate cost:**
|
|
204
|
+
```json
|
|
205
|
+
{
|
|
206
|
+
"ok": true,
|
|
207
|
+
"result": {
|
|
208
|
+
"target": "bracket",
|
|
209
|
+
"process": "CNC",
|
|
210
|
+
"material": "aluminum",
|
|
211
|
+
"cost": 45.50,
|
|
212
|
+
"costPerUnit": 0.4550,
|
|
213
|
+
"quantity": 100,
|
|
214
|
+
"message": "Cost estimation complete"
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
**Design review:**
|
|
220
|
+
```json
|
|
221
|
+
{
|
|
222
|
+
"ok": true,
|
|
223
|
+
"result": {
|
|
224
|
+
"target": "bracket",
|
|
225
|
+
"score": "B",
|
|
226
|
+
"warnings": [
|
|
227
|
+
"Wall thickness approaching minimum (0.9mm < 1.0mm)",
|
|
228
|
+
"Sharp corner at junction — consider adding fillet"
|
|
229
|
+
],
|
|
230
|
+
"suggestions": [
|
|
231
|
+
"Increase wall thickness by 0.5mm",
|
|
232
|
+
"Add 2mm fillet to corners",
|
|
233
|
+
"Check for draft angle on undercuts"
|
|
234
|
+
],
|
|
235
|
+
"message": "Design review complete with score: B"
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
## Step 3: Handle Each Namespace
|
|
241
|
+
|
|
242
|
+
### shape.* — Geometry Creation
|
|
243
|
+
|
|
244
|
+
```javascript
|
|
245
|
+
// Should create 3D geometry and return entityId
|
|
246
|
+
shape.cylinder({ radius: 25, height: 80 })
|
|
247
|
+
// Returns: { entityId: "cylinder_1", radius: 25, height: 80, volume: 157079.63 }
|
|
248
|
+
|
|
249
|
+
shape.box({ width: 50, height: 40, depth: 30 })
|
|
250
|
+
// Returns: { entityId: "box_1", width: 50, height: 40, depth: 30, volume: 60000 }
|
|
251
|
+
|
|
252
|
+
shape.sphere({ radius: 30 })
|
|
253
|
+
// Returns: { entityId: "sphere_1", radius: 30, volume: 113097.34 }
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
### sketch.* — 2D Sketch Operations
|
|
257
|
+
|
|
258
|
+
```javascript
|
|
259
|
+
// Sketch operations work within a sketch context
|
|
260
|
+
sketch.start({ plane: 'XY' })
|
|
261
|
+
// Returns: { sketchId: "sketch_1", plane: "XY", ready: true }
|
|
262
|
+
|
|
263
|
+
sketch.circle({ cx: 0, cy: 0, radius: 15 })
|
|
264
|
+
// Returns: { entityId: "circle_1", cx: 0, cy: 0, radius: 15 }
|
|
265
|
+
|
|
266
|
+
sketch.rect({ x: 0, y: 0, width: 100, height: 50 })
|
|
267
|
+
// Returns: { entityId: "rect_1", x: 0, y: 0, width: 100, height: 50 }
|
|
268
|
+
|
|
269
|
+
sketch.end()
|
|
270
|
+
// Returns: { sketchId: "sketch_1", entities: 3, ready: false }
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
### feature.* — 3D Feature Operations
|
|
274
|
+
|
|
275
|
+
```javascript
|
|
276
|
+
feature.extrude({ height: 10 })
|
|
277
|
+
// Returns: { entityId: "extrude_1", height: 10, volume: /* calculated */ }
|
|
278
|
+
|
|
279
|
+
feature.fillet({ radius: 5, edges: 'all' })
|
|
280
|
+
// Returns: { entityId: "fillet_1", radius: 5, edges: "all", applied: true }
|
|
281
|
+
|
|
282
|
+
feature.pattern({ type: 'rectangular', count: 3, spacing: 25 })
|
|
283
|
+
// Returns: { entityId: "pattern_1", type: "rectangular", count: 3, instances: 3 }
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
### validate.* — Analysis & Validation
|
|
287
|
+
|
|
288
|
+
```javascript
|
|
289
|
+
validate.dimensions({ target: 'extrude_1' })
|
|
290
|
+
// Returns: { target: "extrude_1", dimensions: { width: 80, height: 40, depth: 30 } }
|
|
291
|
+
|
|
292
|
+
validate.cost({ target: 'bracket', process: 'CNC', material: 'aluminum' })
|
|
293
|
+
// Returns: { target: "bracket", cost: 45.50, process: "CNC", material: "aluminum" }
|
|
294
|
+
|
|
295
|
+
validate.designReview({ target: 'bracket' })
|
|
296
|
+
// Returns: { target: "bracket", score: "B", warnings: [...], suggestions: [...] }
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
### render.* — Viewport Operations
|
|
300
|
+
|
|
301
|
+
```javascript
|
|
302
|
+
render.snapshot({ width: 1200, height: 800 })
|
|
303
|
+
// Returns: { imageUrl: "data:image/png;base64,..." }
|
|
304
|
+
|
|
305
|
+
render.multiview({ width: 400, height: 400 })
|
|
306
|
+
// Returns: { views: { front: "data:...", back: "data:...", ... } }
|
|
307
|
+
|
|
308
|
+
render.highlight({ target: 'cylinder_1', color: 0xffff00 })
|
|
309
|
+
// Returns: { target: "cylinder_1", highlighted: true }
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
### export.* — File Export
|
|
313
|
+
|
|
314
|
+
```javascript
|
|
315
|
+
export.stl({ filename: 'bracket.stl', binary: true })
|
|
316
|
+
// Returns: { filename: "bracket.stl", format: "STL", size: 2048000 }
|
|
317
|
+
|
|
318
|
+
export.json({ filename: 'bracket.json' })
|
|
319
|
+
// Returns: { filename: "bracket.json", format: "JSON", size: 45000 }
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
### assembly.* — Assembly Management
|
|
323
|
+
|
|
324
|
+
```javascript
|
|
325
|
+
assembly.addComponent({ name: 'bolt', meshOrFile: 'cylinder_1', position: [0, 0, 10] })
|
|
326
|
+
// Returns: { componentId: "bolt_1", name: "bolt", position: [0, 0, 10] }
|
|
327
|
+
|
|
328
|
+
assembly.bom({ target: 'assembly_1' })
|
|
329
|
+
// Returns: { target: "assembly_1", components: 23, subassemblies: 4 }
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
### meta.* — API Metadata
|
|
333
|
+
|
|
334
|
+
```javascript
|
|
335
|
+
meta.version()
|
|
336
|
+
// Returns: { version: "0.1.0", apiVersion: "1.0.0" }
|
|
337
|
+
|
|
338
|
+
meta.getSchema()
|
|
339
|
+
// Returns: { namespaces: 10, commands: 30, ... }
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
## Step 4: Testing
|
|
343
|
+
|
|
344
|
+
Once implemented, test with the CLI:
|
|
345
|
+
|
|
346
|
+
```bash
|
|
347
|
+
# Start your server
|
|
348
|
+
npm start
|
|
349
|
+
# or
|
|
350
|
+
python server.py
|
|
351
|
+
|
|
352
|
+
# In another terminal, test with CLI
|
|
353
|
+
node bin/cyclecad-cli.js shape.cylinder --radius 25 --height 80
|
|
354
|
+
# Should output: ✓ Command executed: shape.cylinder
|
|
355
|
+
|
|
356
|
+
node bin/cyclecad-cli.js --list
|
|
357
|
+
# Should list all available commands
|
|
358
|
+
|
|
359
|
+
node bin/cyclecad-cli.js --batch examples/batch-simple.txt
|
|
360
|
+
# Should execute batch and report results
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
## Step 5: Configuration
|
|
364
|
+
|
|
365
|
+
Allow the CLI to connect to different servers:
|
|
366
|
+
|
|
367
|
+
```bash
|
|
368
|
+
# Default server
|
|
369
|
+
cyclecad shape.cylinder --radius 25 --height 80
|
|
370
|
+
|
|
371
|
+
# Custom server
|
|
372
|
+
cyclecad --server http://production.cyclecad.com shape.cylinder --radius 25
|
|
373
|
+
|
|
374
|
+
# Environment variable
|
|
375
|
+
export CYCLECAD_SERVER=http://production.cyclecad.com
|
|
376
|
+
cyclecad shape.cylinder --radius 25
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
## Step 6: Error Handling
|
|
380
|
+
|
|
381
|
+
Return proper error responses:
|
|
382
|
+
|
|
383
|
+
```json
|
|
384
|
+
{
|
|
385
|
+
"ok": false,
|
|
386
|
+
"error": "Unknown command: invalid.method"
|
|
387
|
+
}
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
The CLI will display:
|
|
391
|
+
```
|
|
392
|
+
[10:37:35] ✗ Command failed: Unknown command: invalid.method
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
## Integration Checklist
|
|
396
|
+
|
|
397
|
+
- [ ] Create `/api/execute` endpoint
|
|
398
|
+
- [ ] Implement command dispatcher
|
|
399
|
+
- [ ] Implement all namespace handlers (shape, sketch, feature, etc.)
|
|
400
|
+
- [ ] Return proper JSON response format
|
|
401
|
+
- [ ] Test with CLI: `--help`, `--list`, single commands
|
|
402
|
+
- [ ] Test batch mode: `--batch examples/batch-simple.txt`
|
|
403
|
+
- [ ] Test JSON output: `--json`
|
|
404
|
+
- [ ] Test error cases
|
|
405
|
+
- [ ] Add CORS headers if needed
|
|
406
|
+
- [ ] Deploy to production server
|
|
407
|
+
- [ ] Update CLI server URL in configuration
|
|
408
|
+
- [ ] Document server API for other clients
|
|
409
|
+
|
|
410
|
+
## Example Integration in cycleCAD
|
|
411
|
+
|
|
412
|
+
Here's how to integrate in the existing `app/index.html`:
|
|
413
|
+
|
|
414
|
+
```javascript
|
|
415
|
+
// In your server initialization
|
|
416
|
+
import { initAgentAPI } from './app/js/agent-api.js';
|
|
417
|
+
|
|
418
|
+
// After initializing all modules
|
|
419
|
+
const { sessionId } = initAgentAPI({
|
|
420
|
+
viewport: window._viewport,
|
|
421
|
+
sketch: window._sketch,
|
|
422
|
+
operations: window._ops,
|
|
423
|
+
advancedOps: window._advancedOps,
|
|
424
|
+
exportModule: window._exportMod,
|
|
425
|
+
appState: window._appState,
|
|
426
|
+
tree: window._tree,
|
|
427
|
+
assembly: window._assemblyModule
|
|
428
|
+
});
|
|
429
|
+
|
|
430
|
+
// Expose HTTP API
|
|
431
|
+
const express = require('express');
|
|
432
|
+
const app = express();
|
|
433
|
+
|
|
434
|
+
app.post('/api/execute', (req, res) => {
|
|
435
|
+
const { method, params } = req.body;
|
|
436
|
+
try {
|
|
437
|
+
const result = window.cycleCAD.execute({ method, params });
|
|
438
|
+
res.json({ ok: true, result });
|
|
439
|
+
} catch (error) {
|
|
440
|
+
res.status(400).json({ ok: false, error: error.message });
|
|
441
|
+
}
|
|
442
|
+
});
|
|
443
|
+
|
|
444
|
+
app.listen(3000);
|
|
445
|
+
```
|
|
446
|
+
|
|
447
|
+
## Deployment Options
|
|
448
|
+
|
|
449
|
+
### 1. Single Node.js Server
|
|
450
|
+
```bash
|
|
451
|
+
node server.js
|
|
452
|
+
cyclecad shape.cylinder --radius 25
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
### 2. Containerized (Docker)
|
|
456
|
+
```dockerfile
|
|
457
|
+
FROM node:18-alpine
|
|
458
|
+
WORKDIR /app
|
|
459
|
+
COPY . .
|
|
460
|
+
EXPOSE 3000
|
|
461
|
+
CMD ["node", "server.js"]
|
|
462
|
+
```
|
|
463
|
+
|
|
464
|
+
### 3. Cloud Deployment (Vercel, Netlify)
|
|
465
|
+
```bash
|
|
466
|
+
npm install -g vercel
|
|
467
|
+
vercel --prod
|
|
468
|
+
```
|
|
469
|
+
|
|
470
|
+
## Performance Optimization
|
|
471
|
+
|
|
472
|
+
- Cache frequently accessed data
|
|
473
|
+
- Use database for history/state
|
|
474
|
+
- Implement request queuing for batch operations
|
|
475
|
+
- Add rate limiting for production
|
|
476
|
+
- Monitor API response times
|
|
477
|
+
|
|
478
|
+
## Security Considerations
|
|
479
|
+
|
|
480
|
+
- Add authentication (API keys, JWT)
|
|
481
|
+
- Validate input parameters
|
|
482
|
+
- Sanitize output for display
|
|
483
|
+
- Rate limit API endpoints
|
|
484
|
+
- Log all commands for audit trail
|
|
485
|
+
- Implement HTTPS for production
|
|
486
|
+
|
|
487
|
+
## Monitoring & Logging
|
|
488
|
+
|
|
489
|
+
```javascript
|
|
490
|
+
app.use((req, res, next) => {
|
|
491
|
+
const start = Date.now();
|
|
492
|
+
res.on('finish', () => {
|
|
493
|
+
const duration = Date.now() - start;
|
|
494
|
+
console.log(`${req.method} ${req.path} ${res.statusCode} ${duration}ms`);
|
|
495
|
+
});
|
|
496
|
+
next();
|
|
497
|
+
});
|
|
498
|
+
```
|
|
499
|
+
|
|
500
|
+
## Further Reading
|
|
501
|
+
|
|
502
|
+
- CLI Documentation: `docs/CLI.md`
|
|
503
|
+
- Quick Start: `QUICKSTART-CLI.md`
|
|
504
|
+
- Build Summary: `CLI-BUILD-SUMMARY.md`
|
|
505
|
+
- Agent API: `app/js/agent-api.js`
|
|
506
|
+
- Mock Server: `bin/server.js`
|
|
507
|
+
|
|
508
|
+
---
|
|
509
|
+
|
|
510
|
+
For questions or issues, refer to the main documentation or create an issue on GitHub.
|