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.
Files changed (69) hide show
  1. package/API-BUILD-MANIFEST.txt +339 -0
  2. package/API-SERVER.md +535 -0
  3. package/Architecture-Deck.pptx +0 -0
  4. package/CLAUDE.md +172 -11
  5. package/CLI-BUILD-SUMMARY.md +504 -0
  6. package/CLI-INDEX.md +356 -0
  7. package/CLI-README.md +466 -0
  8. package/COLLABORATION-INTEGRATION-GUIDE.md +325 -0
  9. package/CONNECTED_FABS_GUIDE.md +612 -0
  10. package/CONNECTED_FABS_README.md +310 -0
  11. package/DELIVERABLES.md +343 -0
  12. package/DFM-ANALYZER-INTEGRATION.md +368 -0
  13. package/DFM-QUICK-START.js +253 -0
  14. package/Dockerfile +69 -0
  15. package/IMPLEMENTATION.md +327 -0
  16. package/LICENSE +31 -0
  17. package/MARKETPLACE_QUICK_REFERENCE.txt +294 -0
  18. package/MCP-INDEX.md +264 -0
  19. package/QUICKSTART-API.md +388 -0
  20. package/QUICKSTART-CLI.md +211 -0
  21. package/QUICKSTART-MCP.md +196 -0
  22. package/README-MCP.md +208 -0
  23. package/TEST-TOKEN-ENGINE.md +319 -0
  24. package/TOKEN-ENGINE-SUMMARY.md +266 -0
  25. package/TOKENS-README.md +263 -0
  26. package/TOOLS-REFERENCE.md +254 -0
  27. package/app/index.html +168 -3
  28. package/app/js/TOKEN-INTEGRATION.md +391 -0
  29. package/app/js/agent-api.js +3 -3
  30. package/app/js/ai-copilot.js +1435 -0
  31. package/app/js/cam-pipeline.js +840 -0
  32. package/app/js/collaboration-ui.js +995 -0
  33. package/app/js/collaboration.js +1116 -0
  34. package/app/js/connected-fabs-example.js +404 -0
  35. package/app/js/connected-fabs.js +1449 -0
  36. package/app/js/dfm-analyzer.js +1760 -0
  37. package/app/js/marketplace.js +1994 -0
  38. package/app/js/material-library.js +2115 -0
  39. package/app/js/token-dashboard.js +563 -0
  40. package/app/js/token-engine.js +743 -0
  41. package/app/test-agent.html +1801 -0
  42. package/bin/cyclecad-cli.js +662 -0
  43. package/bin/cyclecad-mcp +2 -0
  44. package/bin/server.js +242 -0
  45. package/cycleCAD-Architecture.pptx +0 -0
  46. package/cycleCAD-Investor-Deck.pptx +0 -0
  47. package/demo-mcp.sh +60 -0
  48. package/docs/API-SERVER-SUMMARY.md +375 -0
  49. package/docs/API-SERVER.md +667 -0
  50. package/docs/CAM-EXAMPLES.md +344 -0
  51. package/docs/CAM-INTEGRATION.md +612 -0
  52. package/docs/CAM-QUICK-REFERENCE.md +199 -0
  53. package/docs/CLI-INTEGRATION.md +510 -0
  54. package/docs/CLI.md +872 -0
  55. package/docs/MARKETPLACE-API-SCHEMA.json +564 -0
  56. package/docs/MARKETPLACE-INTEGRATION.md +467 -0
  57. package/docs/MARKETPLACE-SETUP.html +439 -0
  58. package/docs/MCP-SERVER.md +403 -0
  59. package/examples/api-client-example.js +488 -0
  60. package/examples/api-client-example.py +359 -0
  61. package/examples/batch-manufacturing.txt +28 -0
  62. package/examples/batch-simple.txt +26 -0
  63. package/model-marketplace.html +1273 -0
  64. package/package.json +14 -3
  65. package/server/api-server.js +1120 -0
  66. package/server/mcp-server.js +1161 -0
  67. package/test-api-server.js +432 -0
  68. package/test-mcp.js +198 -0
  69. package/~$cycleCAD-Investor-Deck.pptx +0 -0
@@ -0,0 +1,612 @@
1
+ # Connected Fabs Module Guide
2
+
3
+ ## Overview
4
+ The Connected Fabs module (`app/js/connected-fabs.js`) implements the "CAD → CAM → Connected Fabs" pipeline from the architecture slide 10. It connects cycleCAD designs to a distributed network of manufacturing partners worldwide.
5
+
6
+ **Module size:** 1,449 lines
7
+ **Key features:** Fab registry, smart routing, job submission, token escrow, webhook simulation
8
+ **Storage:** localStorage (`cyclecad_fab_registry`, `cyclecad_fab_jobs`)
9
+ **Integration:** Hooks into `window.cycleCAD.tokens` for escrow management
10
+
11
+ ---
12
+
13
+ ## Quick Start
14
+
15
+ ### 1. Load the Module
16
+ Add to `app/index.html` in the `<head>` after other module scripts:
17
+
18
+ ```html
19
+ <script src="js/connected-fabs.js"></script>
20
+ ```
21
+
22
+ ### 2. Access the API
23
+ ```javascript
24
+ // List all fabs
25
+ window.cycleCAD.fabs.listFabs();
26
+
27
+ // Find best fab for a job
28
+ const results = window.cycleCAD.fabs.findBestFab({
29
+ capability: 'cnc_5axis',
30
+ material: 'aluminum',
31
+ partSize: { x: 500, y: 400, z: 200 },
32
+ maxLeadTime: 5
33
+ });
34
+
35
+ // Submit a manufacturing job
36
+ const job = window.cycleCAD.fabs.submitJob({
37
+ name: 'Bracket Assembly',
38
+ capability: 'cnc_3axis',
39
+ material: 'steel',
40
+ partSize: { x: 150, y: 100, z: 75 },
41
+ quantity: 10,
42
+ urgency: 'standard',
43
+ description: 'High-precision bracket for automotive'
44
+ });
45
+
46
+ // Toggle UI panel
47
+ window.cycleCAD.fabs.togglePanel();
48
+ ```
49
+
50
+ ---
51
+
52
+ ## API Reference
53
+
54
+ ### Fab Management
55
+
56
+ #### `registerFab(fabData)`
57
+ Register a new fab shop in the network.
58
+
59
+ ```javascript
60
+ const fab = window.cycleCAD.fabs.registerFab({
61
+ name: 'My CNC Shop',
62
+ location: { city: 'Berlin', country: 'DE', lat: 52.52, lng: 13.41 },
63
+ capabilities: ['cnc_3axis', 'cnc_5axis'],
64
+ materials: ['aluminum', 'steel'],
65
+ maxPartSize: { x: 500, y: 500, z: 300 },
66
+ pricing: { cnc_3axis: 0.08, cnc_5axis: 0.15 },
67
+ leadTime: { standard: 5, express: 2 },
68
+ rating: 4.8,
69
+ reviews: 100,
70
+ certifications: ['ISO 9001'],
71
+ description: 'Precision CNC machining'
72
+ });
73
+ ```
74
+
75
+ #### `listFabs(filters?)`
76
+ Get all fabs with optional filtering.
77
+
78
+ ```javascript
79
+ // Get all fabs
80
+ window.cycleCAD.fabs.listFabs();
81
+
82
+ // Filter by capability
83
+ window.cycleCAD.fabs.listFabs({ capability: '3d_print_fdm' });
84
+
85
+ // Filter by multiple criteria
86
+ window.cycleCAD.fabs.listFabs({
87
+ capability: 'cnc_5axis',
88
+ country: 'DE',
89
+ minRating: 4.5,
90
+ material: 'titanium'
91
+ });
92
+ ```
93
+
94
+ #### `getFab(fabId)`
95
+ Get a specific fab by ID.
96
+
97
+ ```javascript
98
+ const fab = window.cycleCAD.fabs.getFab('fab_001');
99
+ console.log(fab.name, fab.rating, fab.capabilities);
100
+ ```
101
+
102
+ #### `updateFab(fabId, updates)`
103
+ Update fab information.
104
+
105
+ ```javascript
106
+ window.cycleCAD.fabs.updateFab('fab_001', {
107
+ rating: 4.9,
108
+ reviews: 150,
109
+ leadTime: { standard: 4, express: 1 }
110
+ });
111
+ ```
112
+
113
+ #### `removeFab(fabId)`
114
+ Deregister a fab from the network.
115
+
116
+ ```javascript
117
+ window.cycleCAD.fabs.removeFab('fab_001');
118
+ ```
119
+
120
+ ---
121
+
122
+ ### Smart Routing & Quoting
123
+
124
+ #### `findBestFab(requirements)`
125
+ Find the best fab(s) for a manufacturing job. Returns ranked list with scoring.
126
+
127
+ **Scoring factors:**
128
+ - Capability match (required)
129
+ - Material availability
130
+ - Part size fit
131
+ - Price competitiveness
132
+ - Lead time
133
+ - Rating/reviews
134
+ - Distance (if user location provided)
135
+
136
+ ```javascript
137
+ const results = window.cycleCAD.fabs.findBestFab({
138
+ capability: 'cnc_5axis', // REQUIRED
139
+ material: 'titanium', // optional
140
+ partSize: { x: 400, y: 300, z: 250 }, // optional
141
+ quantity: 5, // optional
142
+ maxPrice: 0.20, // optional € per unit
143
+ maxLeadTime: 10, // optional days
144
+ userLocation: { lat: 48.14, lng: 11.58 } // optional for distance
145
+ });
146
+
147
+ // Returns: [{ fab, score, distance }, { fab, score, distance }, ...]
148
+ // fab = best match, score = ranking score, distance = km from user
149
+ ```
150
+
151
+ #### `getQuote(fabId, jobData)`
152
+ Get a price quote from a specific fab.
153
+
154
+ ```javascript
155
+ const quote = window.cycleCAD.fabs.getQuote('fab_001', {
156
+ capability: 'cnc_5axis',
157
+ partSize: { x: 400, y: 300, z: 250 },
158
+ quantity: 10,
159
+ material: 'aluminum',
160
+ urgency: 'express' // standard | express
161
+ });
162
+
163
+ // Returns:
164
+ // {
165
+ // fabId: 'fab_001',
166
+ // fabName: 'Lyon Precision',
167
+ // basePrice: 0.16,
168
+ // totalCost: 24.96,
169
+ // currency: '€',
170
+ // leadDays: 3,
171
+ // material: 'aluminum',
172
+ // capability: 'CNC 5-Axis'
173
+ // }
174
+ ```
175
+
176
+ ---
177
+
178
+ ### Job Management
179
+
180
+ #### `submitJob(jobData)`
181
+ Submit a manufacturing job. Automatically routes to best fab and creates token escrow.
182
+
183
+ ```javascript
184
+ const job = window.cycleCAD.fabs.submitJob({
185
+ name: 'Bracket Assembly',
186
+ capability: 'cnc_3axis',
187
+ material: 'steel',
188
+ partSize: { x: 150, y: 100, z: 75 },
189
+ quantity: 10,
190
+ urgency: 'standard', // standard | express
191
+ description: 'Precision bracket',
192
+ userLocation: { lat: 48.2, lng: 16.4 }, // optional for routing
193
+ fabricFile: 'assembly_v2.step' // optional reference
194
+ });
195
+
196
+ // Job lifecycle: DRAFT → SUBMITTED → ACCEPTED → IN_PROGRESS → QC → SHIPPED → DELIVERED → COMPLETED
197
+
198
+ // Returns job object with cost in tokens and escrow ID
199
+ ```
200
+
201
+ #### `getJob(jobId)`
202
+ Get job details.
203
+
204
+ ```javascript
205
+ const job = window.cycleCAD.fabs.getJob('job_1');
206
+ console.log(job.status, job.fabName, job.costInTokens);
207
+ ```
208
+
209
+ #### `listJobs(filters?)`
210
+ List all jobs with optional filtering.
211
+
212
+ ```javascript
213
+ // Get all jobs
214
+ window.cycleCAD.fabs.listJobs();
215
+
216
+ // Filter by status
217
+ window.cycleCAD.fabs.listJobs({ status: 'IN_PROGRESS' });
218
+
219
+ // Filter by fab
220
+ window.cycleCAD.fabs.listJobs({ fabId: 'fab_001' });
221
+
222
+ // Filter by material
223
+ window.cycleCAD.fabs.listJobs({ material: 'aluminum' });
224
+ ```
225
+
226
+ #### `cancelJob(jobId)`
227
+ Cancel a submitted job and release token escrow.
228
+
229
+ ```javascript
230
+ const job = window.cycleCAD.fabs.cancelJob('job_1');
231
+ // Only works if job is still in SUBMITTED state
232
+ ```
233
+
234
+ #### `rateJob(jobId, rating, review?)`
235
+ Rate a completed job and update fab ratings.
236
+
237
+ ```javascript
238
+ window.cycleCAD.fabs.rateJob('job_1', 5, 'Excellent quality! Exactly as specified.');
239
+
240
+ // Rating updates fab's overall rating
241
+ // Fab rating = (oldRating * oldReviewCount + newRating) / (oldReviewCount + 1)
242
+ ```
243
+
244
+ ---
245
+
246
+ ### Webhook System
247
+
248
+ #### `simulateWebhook(fabId, jobId, event, data?)`
249
+ Simulate a webhook event from a fab (status update). In production, fabs POST to your webhook endpoint.
250
+
251
+ **Valid events:**
252
+ - `job.accepted` → Status: ACCEPTED
253
+ - `job.started` → Status: IN_PROGRESS
254
+ - `job.qc_passed` → Status: QC
255
+ - `job.shipped` → Status: SHIPPED
256
+ - `job.delivered` → Status: DELIVERED
257
+
258
+ ```javascript
259
+ // Fab accepts the job
260
+ window.cycleCAD.fabs.simulateWebhook('fab_001', 'job_1', 'job.accepted', {
261
+ acceptedAt: new Date().toISOString(),
262
+ estimatedDelivery: '2026-04-15'
263
+ });
264
+
265
+ // Fab starts manufacturing
266
+ window.cycleCAD.fabs.simulateWebhook('fab_001', 'job_1', 'job.started', {
267
+ toolpath: 'part_001.nc',
268
+ machineId: 'cnc_5'
269
+ });
270
+
271
+ // Quality check passes
272
+ window.cycleCAD.fabs.simulateWebhook('fab_001', 'job_1', 'job.qc_passed', {
273
+ toleranceCheck: 'PASS',
274
+ surfaceFinish: 'Ra 1.6µm'
275
+ });
276
+
277
+ // Job ships
278
+ window.cycleCAD.fabs.simulateWebhook('fab_001', 'job_1', 'job.shipped', {
279
+ trackingNumber: 'DHL123456789',
280
+ carrier: 'DHL',
281
+ estimatedDelivery: '2026-04-18'
282
+ });
283
+
284
+ // Job delivered
285
+ window.cycleCAD.fabs.simulateWebhook('fab_001', 'job_1', 'job.delivered', {
286
+ signedBy: 'John Doe',
287
+ condition: 'GOOD'
288
+ });
289
+ ```
290
+
291
+ #### `getWebhookLog(jobId)`
292
+ Get all webhook events for a job (audit trail).
293
+
294
+ ```javascript
295
+ const events = window.cycleCAD.fabs.getWebhookLog('job_1');
296
+ // Returns: [
297
+ // { event: 'job.accepted', timestamp: '2026-03-27T...', data: {...}, fabName: '...' },
298
+ // { event: 'job.started', timestamp: '2026-03-28T...', data: {...}, fabName: '...' },
299
+ // ...
300
+ // ]
301
+ ```
302
+
303
+ ---
304
+
305
+ ### UI Panel
306
+
307
+ #### `togglePanel()`
308
+ Show/hide the Connected Fabs UI panel. Panel has 4 tabs:
309
+ 1. **Browse Fabs** — Search and filter fab network
310
+ 2. **Submit Job** — Create new manufacturing job
311
+ 3. **My Jobs** — Track submitted jobs
312
+ 4. **Dashboard** — Network stats and job analytics
313
+
314
+ ```javascript
315
+ window.cycleCAD.fabs.togglePanel();
316
+ ```
317
+
318
+ #### `switchTab(tabName)`
319
+ Programmatically switch panels.
320
+
321
+ ```javascript
322
+ window.cycleCAD.fabs.switchTab('fabs'); // Browse Fabs
323
+ window.cycleCAD.fabs.switchTab('submit'); // Submit Job
324
+ window.cycleCAD.fabs.switchTab('jobs'); // My Jobs
325
+ window.cycleCAD.fabs.switchTab('dashboard'); // Dashboard
326
+ ```
327
+
328
+ ---
329
+
330
+ ### Events
331
+
332
+ #### `on(event, listener)`
333
+ Listen for module events.
334
+
335
+ **Events:**
336
+ - `fab-registered` — New fab added to network
337
+ - `fab-updated` — Fab info updated
338
+ - `fab-removed` — Fab removed from network
339
+ - `job-submitted` — New job created
340
+ - `job-status-changed` — Job status updated (webhook event)
341
+ - `job-cancelled` — Job cancelled
342
+ - `job-rated` — Job rated
343
+
344
+ ```javascript
345
+ // Listen for new jobs
346
+ window.cycleCAD.fabs.on('job-submitted', (data) => {
347
+ console.log(`Job ${data.jobId} submitted to ${data.fabName}`);
348
+ console.log(`Cost: ${data.costInTokens} tokens`);
349
+ });
350
+
351
+ // Listen for status changes
352
+ window.cycleCAD.fabs.on('job-status-changed', (data) => {
353
+ console.log(`Job ${data.jobId}: ${data.oldStatus} → ${data.newStatus}`);
354
+ notifyUser(`Job update: ${data.event}`);
355
+ });
356
+
357
+ // Listen for new fabs joining network
358
+ window.cycleCAD.fabs.on('fab-registered', (data) => {
359
+ console.log(`New fab added: ${data.name}`);
360
+ });
361
+ ```
362
+
363
+ #### `off(event, listener)`
364
+ Remove an event listener.
365
+
366
+ ```javascript
367
+ const handler = (data) => console.log(data);
368
+ window.cycleCAD.fabs.on('job-submitted', handler);
369
+ window.cycleCAD.fabs.off('job-submitted', handler); // Stop listening
370
+ ```
371
+
372
+ ---
373
+
374
+ ## Manufacturing Types
375
+
376
+ Supported manufacturing processes with token costs:
377
+
378
+ | Type | Code | Cost (tokens) | Unit |
379
+ |------|------|---------------|------|
380
+ | 3D Print (FDM) | `3d_print_fdm` | 25 | per job |
381
+ | 3D Print (SLA) | `3d_print_sla` | 35 | per job |
382
+ | 3D Print (SLS) | `3d_print_sls` | 30 | per job |
383
+ | Laser Cut | `laser_cut` | 15 | per job |
384
+ | CNC 3-Axis | `cnc_3axis` | 60 | per job |
385
+ | CNC 5-Axis | `cnc_5axis` | 100 | per job |
386
+ | CNC Lathe | `cnc_lathe` | 40 | per job |
387
+ | Injection Mold | `injection_mold` | 250 | per job |
388
+ | Sheet Metal | `sheet_metal` | 45 | per job |
389
+ | PCB Manufacturing | `pcb_mfg` | 50 | per job |
390
+ | Waterjet Cut | `waterjet_cut` | 50 | per job |
391
+ | Sheet Bending | `bending` | 35 | per job |
392
+
393
+ ---
394
+
395
+ ## Demo Fabs
396
+
397
+ The module pre-loads 8 real-world demo fab shops:
398
+
399
+ 1. **Berlin CNC Works** (DE) — CNC 3/5-axis, laser, 4.7★
400
+ 2. **Munich Additive** (DE) — FDM/SLA/SLS 3D print, 4.8★
401
+ 3. **Rotterdam Metal** (NL) — CNC, lathe, sheet metal, 4.5★
402
+ 4. **Lyon Precision** (FR) — CNC 5-axis, aerospace, 4.9★
403
+ 5. **Milano Rapid** (IT) — SLA/SLS, injection mold, 4.6★
404
+ 6. **Barcelona Sheet** (ES) — Laser, bending, waterjet, 4.4★
405
+ 7. **Prague PCB** (CZ) — PCB manufacturing, 4.3★
406
+ 8. **Vienna Mold** (AT) — Injection molding, 4.7★
407
+
408
+ ---
409
+
410
+ ## Integration with Token Engine
411
+
412
+ The Connected Fabs module integrates with `window.cycleCAD.tokens` for escrow management:
413
+
414
+ ```javascript
415
+ // When a job is submitted:
416
+ // 1. Calculate cost in tokens based on manufacturing type
417
+ // 2. Create token escrow via tokens.createEscrow()
418
+ // 3. Store escrowId in job record
419
+ // 4. On job completion, release escrow: tokens.releaseEscrow()
420
+ // 5. On job cancellation, cancel escrow: tokens.cancelEscrow()
421
+
422
+ // Example:
423
+ const escrow = window.cycleCAD.tokens.createEscrow(
424
+ 100, // tokens to hold
425
+ 'job_1', // jobId
426
+ 'fab_001', // fabId
427
+ { jobName: 'Bracket', manufacturingType: 'cnc_5axis' }
428
+ );
429
+
430
+ // Later, when job completes:
431
+ window.cycleCAD.tokens.releaseEscrow(escrow.id);
432
+ ```
433
+
434
+ ---
435
+
436
+ ## Storage & Persistence
437
+
438
+ All data persists in localStorage:
439
+
440
+ - **`cyclecad_fab_registry`** — Array of fab objects
441
+ - **`cyclecad_fab_jobs`** — Object of { jobId: job }
442
+ - **`cyclecad_job_counter`** — Auto-incrementing job ID counter
443
+
444
+ To reset:
445
+ ```javascript
446
+ localStorage.removeItem('cyclecad_fab_registry');
447
+ localStorage.removeItem('cyclecad_fab_jobs');
448
+ localStorage.removeItem('cyclecad_job_counter');
449
+ ```
450
+
451
+ ---
452
+
453
+ ## Example Workflow
454
+
455
+ ### 1. User designs a part in cycleCAD
456
+ ```javascript
457
+ // User creates a bracket in the 3D viewport
458
+ ```
459
+
460
+ ### 2. User exports as STL and submits job
461
+ ```javascript
462
+ const job = window.cycleCAD.fabs.submitJob({
463
+ name: 'Bracket Assembly',
464
+ capability: 'cnc_5axis',
465
+ material: 'aluminum',
466
+ partSize: { x: 200, y: 150, z: 100 },
467
+ quantity: 10,
468
+ urgency: 'standard',
469
+ description: 'High-precision aerospace bracket'
470
+ });
471
+
472
+ console.log(`Job ${job.id} cost: ${job.costInTokens} tokens`);
473
+ console.log(`Routed to: ${job.fabName}`);
474
+ console.log(`Lead time: ${job.quote.leadDays} days`);
475
+ ```
476
+
477
+ ### 3. User tracks job in My Jobs tab
478
+ ```javascript
479
+ window.cycleCAD.fabs.switchTab('jobs');
480
+ // Shows job in SUBMITTED state
481
+ ```
482
+
483
+ ### 4. Fab accepts job (webhook event)
484
+ ```javascript
485
+ // In real system, fab would POST to webhook
486
+ // For demo, we simulate:
487
+ window.cycleCAD.fabs.simulateWebhook('fab_004', job.id, 'job.accepted', {
488
+ acceptedAt: new Date().toISOString()
489
+ });
490
+
491
+ // Job now shows as ACCEPTED
492
+ // Listen for status change:
493
+ window.cycleCAD.fabs.on('job-status-changed', (data) => {
494
+ console.log(`Status: ${data.newStatus}`);
495
+ updateUI();
496
+ });
497
+ ```
498
+
499
+ ### 5. Fab manufactures part (multiple webhooks)
500
+ ```javascript
501
+ // job.started
502
+ window.cycleCAD.fabs.simulateWebhook('fab_004', job.id, 'job.started');
503
+
504
+ // job.qc_passed
505
+ window.cycleCAD.fabs.simulateWebhook('fab_004', job.id, 'job.qc_passed', {
506
+ toleranceCheck: 'PASS'
507
+ });
508
+
509
+ // job.shipped
510
+ window.cycleCAD.fabs.simulateWebhook('fab_004', job.id, 'job.shipped', {
511
+ trackingNumber: 'DHL12345'
512
+ });
513
+ ```
514
+
515
+ ### 6. Job delivered
516
+ ```javascript
517
+ window.cycleCAD.fabs.simulateWebhook('fab_004', job.id, 'job.delivered');
518
+
519
+ // User rates the fab
520
+ window.cycleCAD.fabs.rateJob(job.id, 5, 'Perfect quality! Exactly as specified.');
521
+
522
+ // Token escrow is released and fab gets paid
523
+ window.cycleCAD.tokens.releaseEscrow(job.escrowId);
524
+ ```
525
+
526
+ ---
527
+
528
+ ## Architecture Notes
529
+
530
+ ### Design Principles
531
+ 1. **Agent-First** — All operations return structured JSON (no DOM dependencies)
532
+ 2. **Token-Aware** — Every job holds tokens in escrow until completion
533
+ 3. **Decentralized** — Fabs are just data; no central server required
534
+ 4. **Observable** — Full event system for UI synchronization
535
+ 5. **Persistent** — All state survives page reload
536
+
537
+ ### Scoring Algorithm
538
+ The `findBestFab()` function ranks candidates on:
539
+ - Capability match (required)
540
+ - Material availability (+20 points)
541
+ - Rating (+5 per star)
542
+ - Lead time match (+30 if within maxLeadTime)
543
+ - Price competitiveness (+15 if under maxPrice)
544
+ - Distance penalty (-1 per 100km from user)
545
+
546
+ Higher score = better match.
547
+
548
+ ### Job State Machine
549
+ ```
550
+ DRAFT ──submit──> SUBMITTED ──webhook: job.accepted──> ACCEPTED
551
+ ││
552
+ ├──webhook: job.started──> IN_PROGRESS
553
+ ├──webhook: job.qc_passed──> QC
554
+ ├──webhook: job.shipped──> SHIPPED
555
+ ├──webhook: job.delivered──> DELIVERED
556
+ └──complete──> COMPLETED
557
+
558
+ SUBMITTED ──user cancel──> CANCELLED
559
+ ```
560
+
561
+ ---
562
+
563
+ ## Testing
564
+
565
+ ```javascript
566
+ // List all fabs
567
+ console.log(window.cycleCAD.fabs.listFabs());
568
+
569
+ // Submit a test job
570
+ const job = window.cycleCAD.fabs.submitJob({
571
+ name: 'Test Part',
572
+ capability: 'cnc_3axis',
573
+ material: 'aluminum',
574
+ partSize: { x: 100, y: 100, z: 50 },
575
+ quantity: 1,
576
+ urgency: 'standard'
577
+ });
578
+
579
+ // Simulate full lifecycle
580
+ window.cycleCAD.fabs.simulateWebhook(job.fabId, job.id, 'job.accepted');
581
+ window.cycleCAD.fabs.simulateWebhook(job.fabId, job.id, 'job.started');
582
+ window.cycleCAD.fabs.simulateWebhook(job.fabId, job.id, 'job.qc_passed');
583
+ window.cycleCAD.fabs.simulateWebhook(job.fabId, job.id, 'job.shipped');
584
+ window.cycleCAD.fabs.simulateWebhook(job.fabId, job.id, 'job.delivered');
585
+
586
+ // View job details
587
+ console.log(window.cycleCAD.fabs.getJob(job.id));
588
+
589
+ // View webhook log
590
+ console.log(window.cycleCAD.fabs.getWebhookLog(job.id));
591
+ ```
592
+
593
+ ---
594
+
595
+ ## Future Enhancements
596
+
597
+ 1. **Real Webhook Integration** — POST to external fab APIs
598
+ 2. **Payment Integration** — Stripe/crypto for token redemption
599
+ 3. **Capacity Planning** — Fab load balancing and scheduling
600
+ 4. **Quality Tracking** — Post-delivery QC metrics
601
+ 5. **Vendor Management** — Custom pricing tiers, SLAs
602
+ 6. **Analytics Dashboard** — Cost trends, delivery times, fab ratings
603
+ 7. **API Gateway** — REST/GraphQL interface for external agents
604
+ 8. **Multi-user Collaboration** — Shared job tracking across teams
605
+
606
+ ---
607
+
608
+ ## License & Attribution
609
+
610
+ Part of cycleCAD — Agent-First OS for Manufacturing
611
+ (c) 2026 Sachin Kumar / cycleWASH
612
+ Open Source