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.
package/app/index.html CHANGED
@@ -1444,6 +1444,22 @@
1444
1444
  </button>
1445
1445
  </div>
1446
1446
 
1447
+ <!-- Agent API Panel -->
1448
+ <div class="toolbar-group">
1449
+ <button class="toolbar-button" id="btn-agent-panel" title="Agent Command Panel (Test API)">
1450
+ <span class="toolbar-icon">šŸ¤–</span>
1451
+ <span class="toolbar-label">Agent</span>
1452
+ </button>
1453
+ </div>
1454
+
1455
+ <!-- Hard Reset -->
1456
+ <div class="toolbar-group">
1457
+ <button class="toolbar-button" id="btn-hard-reset" title="Clear cache and reload" style="color:#f55;">
1458
+ <span class="toolbar-icon">šŸ”„</span>
1459
+ <span class="toolbar-label">Reset</span>
1460
+ </button>
1461
+ </div>
1462
+
1447
1463
  <!-- Edit Operations -->
1448
1464
  <div class="toolbar-group">
1449
1465
  <button class="toolbar-button" id="btn-undo" title="Undo (Ctrl+Z)">
@@ -1589,6 +1605,36 @@
1589
1605
  <!-- Context Menu -->
1590
1606
  <div id="context-menu"></div>
1591
1607
 
1608
+ <!-- Agent Command Panel -->
1609
+ <div id="agent-panel" style="display:none;position:fixed;bottom:40px;right:20px;width:450px;max-height:600px;background:var(--bg-secondary);border:1px solid var(--border-color);border-radius:6px;box-shadow:var(--shadow-lg);z-index:1000;flex-direction:column;gap:0;">
1610
+ <div style="padding:12px 16px;border-bottom:1px solid var(--border-color);display:flex;justify-content:space-between;align-items:center;user-select:none;">
1611
+ <strong style="font-size:13px;">Agent Command Panel</strong>
1612
+ <button onclick="document.getElementById('agent-panel').style.display='none'" style="background:transparent;border:none;color:var(--text-secondary);cursor:pointer;font-size:16px;padding:0;width:20px;height:20px;">āœ•</button>
1613
+ </div>
1614
+
1615
+ <div style="flex:1;overflow-y:auto;padding:12px;display:flex;flex-direction:column;gap:8px;min-height:0;">
1616
+ <div id="agent-log" style="flex:1;display:flex;flex-direction:column;gap:6px;font-family:monospace;font-size:11px;color:var(--text-secondary);overflow-y:auto;min-height:100px;max-height:400px;">
1617
+ <div style="color:var(--accent-green);">[Ready to accept commands]</div>
1618
+ </div>
1619
+ </div>
1620
+
1621
+ <div style="padding:12px;border-top:1px solid var(--border-color);display:flex;flex-direction:column;gap:8px;">
1622
+ <!-- Command input -->
1623
+ <input type="text" id="agent-command-input" placeholder="{ method: &quot;sketch.start&quot;, params: { plane: &quot;XY&quot; } }" style="width:100%;padding:8px 10px;background:var(--bg-tertiary);border:1px solid var(--border-color);border-radius:4px;color:var(--text-primary);font-family:monospace;font-size:11px;box-sizing:border-box;">
1624
+
1625
+ <!-- Quick command buttons -->
1626
+ <div style="display:grid;grid-template-columns:1fr 1fr;gap:6px;font-size:11px;">
1627
+ <button onclick="agentPanel.executeQuickCommand('ping')" style="padding:6px;background:var(--bg-tertiary);border:1px solid var(--border-color);border-radius:3px;color:var(--accent-blue);cursor:pointer;">Test (Ping)</button>
1628
+ <button onclick="agentPanel.executeQuickCommand('schema')" style="padding:6px;background:var(--bg-tertiary);border:1px solid var(--border-color);border-radius:3px;color:var(--accent-blue);cursor:pointer;">Schema</button>
1629
+ <button onclick="agentPanel.executeQuickCommand('newsketch')" style="padding:6px;background:var(--bg-tertiary);border:1px solid var(--border-color);border-radius:3px;color:var(--accent-green);cursor:pointer;">New Sketch</button>
1630
+ <button onclick="agentPanel.executeQuickCommand('features')" style="padding:6px;background:var(--bg-tertiary);border:1px solid var(--border-color);border-radius:3px;color:var(--accent-green);cursor:pointer;">List Features</button>
1631
+ </div>
1632
+
1633
+ <!-- Execute button -->
1634
+ <button onclick="agentPanel.executeCommand()" style="width:100%;padding:8px;background:var(--accent-blue);color:#fff;border:none;border-radius:4px;cursor:pointer;font-weight:bold;font-size:12px;">Execute Command</button>
1635
+ </div>
1636
+ </div>
1637
+
1592
1638
  <!-- Module Loader -->
1593
1639
  <script type="module">
1594
1640
  import * as THREE from 'https://cdn.jsdelivr.net/npm/three@0.170.0/build/three.module.js';
@@ -1778,11 +1824,65 @@
1778
1824
  // Initialize Agent API — the primary interface
1779
1825
  const agentImports = await import('./js/agent-api.js');
1780
1826
  const agentSession = initAgentAPI({
1781
- viewport: { getCamera, getControls, getScene, getRenderer: () => document.querySelector('#viewport-container canvas')?.getContext ? null : null, setView, fitToObject, addToScene, removeFromScene, toggleGrid: vpToggleGrid, toggleWireframe: (e) => {}, toggleAxisLines: () => {} },
1782
- sketch: { startSketch, endSketch, setTool, getEntities, clearSketch },
1783
- operations: { extrudeProfile, createPrimitive, rebuildFeature, createMaterial, fillet: () => {}, chamfer: () => {}, booleanUnion: () => {}, booleanCut: () => {}, booleanIntersect: () => {}, createShell: () => {}, createPattern: () => {}, getMaterialPresets: () => ({ steel: {}, aluminum: {}, plastic: {}, brass: {}, titanium: {}, nylon: {} }) },
1784
- advancedOps: { createSweep, createLoft, createBend, createFlange, createTab, createSlot, unfoldSheetMetal, createSpring, createThread },
1785
- exportModule: { exportSTL, exportOBJ, exportJSON, exportSTLBinary: exportSTL, exportGLTF: exportOBJ },
1827
+ viewport: {
1828
+ getCamera,
1829
+ getControls,
1830
+ getScene,
1831
+ setView,
1832
+ fitToObject,
1833
+ addToScene,
1834
+ removeFromScene,
1835
+ toggleGrid: vpToggleGrid,
1836
+ toggleWireframe: (e) => console.log('wireframe:', e),
1837
+ toggleAxisLines: () => {},
1838
+ getRenderer: () => null
1839
+ },
1840
+ sketch: {
1841
+ startSketch,
1842
+ endSketch,
1843
+ setTool,
1844
+ getEntities,
1845
+ clearSketch
1846
+ },
1847
+ operations: {
1848
+ extrudeProfile,
1849
+ createPrimitive,
1850
+ rebuildFeature,
1851
+ createMaterial,
1852
+ fillet: (mesh, edges, radius) => console.log('fillet:', mesh, edges, radius),
1853
+ chamfer: (mesh, edges, dist) => console.log('chamfer:', mesh, edges, dist),
1854
+ booleanUnion: (a, b) => { console.log('union:', a, b); return a; },
1855
+ booleanCut: (a, b) => { console.log('cut:', a, b); return a; },
1856
+ booleanIntersect: (a, b) => { console.log('intersect:', a, b); return a; },
1857
+ createShell: (mesh, thickness) => console.log('shell:', mesh, thickness),
1858
+ createPattern: (mesh, type, count, spacing) => { console.log('pattern:', mesh, type, count, spacing); return []; },
1859
+ getMaterialPresets: () => ({
1860
+ steel: { color: 0x7799bb, name: 'Steel' },
1861
+ aluminum: { color: 0xccccdd, name: 'Aluminum' },
1862
+ plastic: { color: 0x2c3e50, name: 'Plastic' },
1863
+ brass: { color: 0xcd7f32, name: 'Brass' },
1864
+ titanium: { color: 0x878786, name: 'Titanium' },
1865
+ nylon: { color: 0xf5f5dc, name: 'Nylon' }
1866
+ })
1867
+ },
1868
+ advancedOps: {
1869
+ createSweep,
1870
+ createLoft,
1871
+ createBend,
1872
+ createFlange,
1873
+ createTab,
1874
+ createSlot,
1875
+ unfoldSheetMetal,
1876
+ createSpring,
1877
+ createThread
1878
+ },
1879
+ exportModule: {
1880
+ exportSTL,
1881
+ exportOBJ,
1882
+ exportJSON,
1883
+ exportSTLBinary: exportSTL,
1884
+ exportGLTF: exportOBJ
1885
+ },
1786
1886
  appState: APP
1787
1887
  });
1788
1888
  console.log(`[Agent API] Ready. Session: ${agentSession.sessionId}`);
@@ -2604,6 +2704,70 @@
2604
2704
 
2605
2705
  window.cycleCAD = { version: '1.0.0', APP, init };
2606
2706
 
2707
+ // ========== Hard Reset (with browser detection) ==========
2708
+ const hardResetBtn = document.getElementById('btn-hard-reset');
2709
+ if (hardResetBtn) {
2710
+ function detectBrowserCC() {
2711
+ const ua = navigator.userAgent;
2712
+ if (/Edg\//i.test(ua)) return 'Edge';
2713
+ if (/Chrome\//i.test(ua) && !/Edg\//i.test(ua)) return 'Chrome';
2714
+ if (/Safari\//i.test(ua) && !/Chrome\//i.test(ua)) return 'Safari';
2715
+ if (/Firefox\//i.test(ua)) return 'Firefox';
2716
+ return 'Unknown';
2717
+ }
2718
+ hardResetBtn.addEventListener('click', async () => {
2719
+ const browser = detectBrowserCC();
2720
+ const msg = `Clear ALL cached data and reload?\n\nDetected browser: ${browser}\n\nThis will clear:\n• Service Workers\n• Cache API storage\n• IndexedDB databases\n• OPFS storage\n• localStorage & sessionStorage`;
2721
+ if (!confirm(msg)) return;
2722
+ const log = [];
2723
+ // 1. Unregister service workers
2724
+ try {
2725
+ if ('serviceWorker' in navigator) {
2726
+ const regs = await navigator.serviceWorker.getRegistrations();
2727
+ for (const r of regs) await r.unregister();
2728
+ log.push('SW: ' + regs.length);
2729
+ }
2730
+ } catch(e) {}
2731
+ // 2. Cache API
2732
+ try {
2733
+ if ('caches' in window) {
2734
+ const names = await caches.keys();
2735
+ for (const n of names) await caches.delete(n);
2736
+ log.push('Caches: ' + names.length);
2737
+ }
2738
+ } catch(e) {}
2739
+ // 3. IndexedDB — clear all
2740
+ try {
2741
+ if (indexedDB.databases) {
2742
+ const allDBs = await indexedDB.databases();
2743
+ for (const db of allDBs) { if (db.name) indexedDB.deleteDatabase(db.name); }
2744
+ log.push('IDB: ' + allDBs.length);
2745
+ }
2746
+ } catch(e) {}
2747
+ // 4. OPFS
2748
+ try {
2749
+ if (navigator.storage && navigator.storage.getDirectory) {
2750
+ const root = await navigator.storage.getDirectory();
2751
+ for await (const [name] of root.entries()) {
2752
+ try { await root.removeEntry(name, { recursive: true }); } catch(e) {}
2753
+ }
2754
+ log.push('OPFS: cleared');
2755
+ }
2756
+ } catch(e) {}
2757
+ // 5. Storage
2758
+ try { localStorage.clear(); } catch(e) {}
2759
+ try { sessionStorage.clear(); } catch(e) {}
2760
+ log.push('Storage: cleared');
2761
+ console.log('[Hard Reset]', browser, log.join(' | '));
2762
+ // 6. Browser-specific reload
2763
+ if (browser === 'Safari') {
2764
+ window.location.href = window.location.pathname + '?cachebust=' + Date.now();
2765
+ } else {
2766
+ setTimeout(() => { window.location.reload(true); }, 300);
2767
+ }
2768
+ });
2769
+ }
2770
+
2607
2771
  // ========== Operation Dialog Management ==========
2608
2772
  let currentDialogId = null;
2609
2773
 
@@ -2889,6 +3053,72 @@
2889
3053
  }
2890
3054
  });
2891
3055
 
3056
+ // ========== Agent Command Panel ==========
3057
+ const agentPanel = {
3058
+ executeCommand() {
3059
+ const input = document.getElementById('agent-command-input');
3060
+ const cmd = input.value.trim();
3061
+ if (!cmd) return;
3062
+
3063
+ this.log(`> ${cmd}`, 'input');
3064
+ try {
3065
+ const parsed = JSON.parse(cmd);
3066
+ if (!window.cycleCAD || !window.cycleCAD.execute) {
3067
+ this.log('āŒ Agent API not initialized', 'error');
3068
+ return;
3069
+ }
3070
+ const result = window.cycleCAD.execute(parsed);
3071
+ this.log(`āœ“ ${JSON.stringify(result, null, 2)}`, 'output');
3072
+ input.value = '';
3073
+ } catch (e) {
3074
+ this.log(`āŒ ${e.message}`, 'error');
3075
+ }
3076
+ },
3077
+
3078
+ executeQuickCommand(cmd) {
3079
+ const input = document.getElementById('agent-command-input');
3080
+ const commands = {
3081
+ 'ping': { method: 'meta.ping', params: {} },
3082
+ 'schema': { method: 'meta.schema', params: {} },
3083
+ 'newsketch': { method: 'sketch.start', params: { plane: 'XY' } },
3084
+ 'features': { method: 'query.features', params: {} },
3085
+ };
3086
+ const cmdObj = commands[cmd];
3087
+ if (cmdObj) {
3088
+ input.value = JSON.stringify(cmdObj);
3089
+ setTimeout(() => this.executeCommand(), 0);
3090
+ }
3091
+ },
3092
+
3093
+ log(msg, type = 'info') {
3094
+ const logEl = document.getElementById('agent-log');
3095
+ const div = document.createElement('div');
3096
+ if (type === 'input') div.style.color = 'var(--accent-blue)';
3097
+ if (type === 'output') div.style.color = 'var(--accent-green)';
3098
+ if (type === 'error') div.style.color = 'var(--accent-red)';
3099
+ div.textContent = msg;
3100
+ logEl.appendChild(div);
3101
+ logEl.scrollTop = logEl.scrollHeight;
3102
+ },
3103
+ };
3104
+
3105
+ // Wire Agent Panel button
3106
+ const agentPanelBtn = document.getElementById('btn-agent-panel');
3107
+ if (agentPanelBtn) {
3108
+ agentPanelBtn.addEventListener('click', () => {
3109
+ const panel = document.getElementById('agent-panel');
3110
+ panel.style.display = panel.style.display === 'none' ? 'flex' : 'none';
3111
+ });
3112
+ }
3113
+
3114
+ // Wire Enter key in command input
3115
+ document.getElementById('agent-command-input')?.addEventListener('keydown', (e) => {
3116
+ if (e.key === 'Enter') {
3117
+ e.preventDefault();
3118
+ agentPanel.executeCommand();
3119
+ }
3120
+ });
3121
+
2892
3122
  </script>
2893
3123
 
2894
3124
  <!-- Operation Dialogs -->
@@ -3238,5 +3468,6 @@
3238
3468
  </div>
3239
3469
  </div>
3240
3470
 
3471
+ <span id="version-badge" style="position:fixed;bottom:10px;left:50%;transform:translateX(-50%);z-index:70;font-size:0.85rem;color:rgba(255,255,255,0.7);letter-spacing:0.1em;white-space:nowrap;padding:5px 14px;user-select:all;pointer-events:auto;font-family:monospace;font-weight:600;background:rgba(0,0,0,0.5);border:1px solid rgba(255,255,255,0.15);border-radius:6px;text-shadow:0 1px 3px rgba(0,0,0,0.5);" title="cycleCAD version">cycleCAD v0.2.0</span>
3241
3472
  </body>
3242
3473
  </html>