tide-commander 1.44.0 → 1.46.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.
Files changed (53) hide show
  1. package/dist/assets/{BossLogsModal-CTo4Bbm7.js → BossLogsModal-BIFXXaaq.js} +1 -1
  2. package/dist/assets/BossSpawnModal-CL4eQrBS.js +1 -0
  3. package/dist/assets/ControlsModal-DX_FqPx7.js +1 -0
  4. package/dist/assets/{DockerLogsModal-CrHd6OZ3.js → DockerLogsModal-SoHgFfH1.js} +1 -1
  5. package/dist/assets/{EmbeddedEditor-h8IrAy4E.js → EmbeddedEditor-Dx6Y7JM3.js} +1 -1
  6. package/dist/assets/{GmailOAuthSetup-io57q0N8.js → GmailOAuthSetup-K-SZcqrr.js} +1 -1
  7. package/dist/assets/{GoogleOAuthSetup-YyNFVd9Y.js → GoogleOAuthSetup-BfpfXmbM.js} +1 -1
  8. package/dist/assets/{IframeModal-DqmSDXCT.js → IframeModal-BAgB3UQ3.js} +1 -1
  9. package/dist/assets/IntegrationsPanel-B1nXTZW8.js +2 -0
  10. package/dist/assets/{LogViewerModal-CGW8yajP.js → LogViewerModal-4do7lATm.js} +1 -1
  11. package/dist/assets/{MonitoringModal-BfsYrF1j.js → MonitoringModal-OAExiDTA.js} +1 -1
  12. package/dist/assets/{PM2LogsModal-BJytXxKY.js → PM2LogsModal-DnA2AsIM.js} +1 -1
  13. package/dist/assets/{RestoreArchivedAreaModal-CtRiwwzT.js → RestoreArchivedAreaModal-C0ADFzsM.js} +1 -1
  14. package/dist/assets/{SaveSnapshotModal-BHBdh1dK.js → SaveSnapshotModal-Ct4aW93y.js} +1 -1
  15. package/dist/assets/Scene2DCanvas-C5mj6yGY.js +1 -0
  16. package/dist/assets/{SceneManager-u4hiSYdk.js → SceneManager-CPtKPGZP.js} +1 -1
  17. package/dist/assets/SkillsPanel-B0XFw3Ae.js +28 -0
  18. package/dist/assets/SnapshotManager-0NaWlDXc.js +1 -0
  19. package/dist/assets/SpawnModal-BOJQ1pln.js +1 -0
  20. package/dist/assets/SubordinateAssignmentModal-BuzBY1CB.js +1 -0
  21. package/dist/assets/{SupervisorPanel-D0c7Kkzt.js → SupervisorPanel-B2_2QYL0.js} +1 -1
  22. package/dist/assets/{TriggerManagerPanel-RsbYDmIC.js → TriggerManagerPanel-CUD10Dg9.js} +2 -2
  23. package/dist/assets/{WorkflowEditorPanel-lpYmT8iN.js → WorkflowEditorPanel-qfjb7ozq.js} +2 -2
  24. package/dist/assets/{index-C6GdsxBK.js → index-BfXYjLRr.js} +4 -4
  25. package/dist/assets/{index-CpwhIgf8.js → index-BzvQBrQn.js} +3 -3
  26. package/dist/assets/{index-BOY5J4U4.js → index-CKitMIQJ.js} +1 -1
  27. package/dist/assets/{index-X9qZZBXG.js → index-CTdXoSNs.js} +2 -2
  28. package/dist/assets/{index-BexCA27h.js → index-D0e5Zn8j.js} +3 -3
  29. package/dist/assets/{index-BQdQ0iv_.js → index-DFTYc8O3.js} +1 -1
  30. package/dist/assets/index-K6Ld2Man.js +1 -0
  31. package/dist/assets/{index-BqPgrat9.js → index-RddWDRes.js} +1 -1
  32. package/dist/assets/{main-DjGrMNoB.css → main-Ch2CJGT4.css} +1 -1
  33. package/dist/assets/main-D3GShQ8B.js +153 -0
  34. package/dist/assets/{web-D94DaG2N.js → web-D0MII38C.js} +1 -1
  35. package/dist/assets/{web-XswRIovf.js → web-bLUMZcn-.js} +1 -1
  36. package/dist/index.html +2 -2
  37. package/dist/src/packages/server/data/index.js +28 -0
  38. package/dist/src/packages/server/routes/config.js +7 -0
  39. package/dist/src/packages/server/routes/custom-class-icons.js +138 -0
  40. package/dist/src/packages/server/routes/index.js +2 -0
  41. package/dist/src/packages/server/services/custom-class-service.js +7 -2
  42. package/dist/src/packages/server/websocket/handlers/agent-handler.js +3 -0
  43. package/package.json +1 -1
  44. package/dist/assets/BossSpawnModal-DOk9u7EW.js +0 -1
  45. package/dist/assets/ControlsModal-BzBzF0Cw.js +0 -1
  46. package/dist/assets/IntegrationsPanel-DiW8UeG5.js +0 -2
  47. package/dist/assets/Scene2DCanvas-BYUuUYur.js +0 -1
  48. package/dist/assets/SkillsPanel-D4IHFehE.js +0 -28
  49. package/dist/assets/SnapshotManager-Cys1dllC.js +0 -1
  50. package/dist/assets/SpawnModal-DUK7X8ql.js +0 -1
  51. package/dist/assets/SubordinateAssignmentModal-DeH34tA3.js +0 -1
  52. package/dist/assets/index-t5WzFf-W.js +0 -1
  53. package/dist/assets/main-CrRMpn-n.js +0 -153
@@ -1 +1 @@
1
- import{bx as a}from"./main-CrRMpn-n.js";import{ImpactStyle as i,NotificationType as r}from"./index-X9qZZBXG.js";import"./modulepreload-polyfill-B5Qt9EMX.js";import"./vendor-react--Eh9ivFN.js";import"./vendor-three-Chj50gSY.js";class u extends a{constructor(){super(...arguments),this.selectionStarted=!1}async impact(t){const e=this.patternForImpact(t==null?void 0:t.style);this.vibrateWithPattern(e)}async notification(t){const e=this.patternForNotification(t==null?void 0:t.type);this.vibrateWithPattern(e)}async vibrate(t){const e=(t==null?void 0:t.duration)||300;this.vibrateWithPattern([e])}async selectionStart(){this.selectionStarted=!0}async selectionChanged(){this.selectionStarted&&this.vibrateWithPattern([70])}async selectionEnd(){this.selectionStarted=!1}patternForImpact(t=i.Heavy){return t===i.Medium?[43]:t===i.Light?[20]:[61]}patternForNotification(t=r.Success){return t===r.Warning?[30,40,30,50,60]:t===r.Error?[27,45,50]:[35,65,21]}vibrateWithPattern(t){if(navigator.vibrate)navigator.vibrate(t);else throw this.unavailable("Browser does not support the vibrate API")}}export{u as HapticsWeb};
1
+ import{bz as a}from"./main-D3GShQ8B.js";import{ImpactStyle as i,NotificationType as r}from"./index-CTdXoSNs.js";import"./modulepreload-polyfill-B5Qt9EMX.js";import"./vendor-react--Eh9ivFN.js";import"./vendor-three-Chj50gSY.js";class u extends a{constructor(){super(...arguments),this.selectionStarted=!1}async impact(t){const e=this.patternForImpact(t==null?void 0:t.style);this.vibrateWithPattern(e)}async notification(t){const e=this.patternForNotification(t==null?void 0:t.type);this.vibrateWithPattern(e)}async vibrate(t){const e=(t==null?void 0:t.duration)||300;this.vibrateWithPattern([e])}async selectionStart(){this.selectionStarted=!0}async selectionChanged(){this.selectionStarted&&this.vibrateWithPattern([70])}async selectionEnd(){this.selectionStarted=!1}patternForImpact(t=i.Heavy){return t===i.Medium?[43]:t===i.Light?[20]:[61]}patternForNotification(t=r.Success){return t===r.Warning?[30,40,30,50,60]:t===r.Error?[27,45,50]:[35,65,21]}vibrateWithPattern(t){if(navigator.vibrate)navigator.vibrate(t);else throw this.unavailable("Browser does not support the vibrate API")}}export{u as HapticsWeb};
@@ -1 +1 @@
1
- import{bx as s}from"./main-CrRMpn-n.js";import"./modulepreload-polyfill-B5Qt9EMX.js";import"./vendor-react--Eh9ivFN.js";import"./vendor-three-Chj50gSY.js";class f extends s{constructor(){super(...arguments),this.pending=[],this.deliveredNotifications=[],this.hasNotificationSupport=()=>{if(!("Notification"in window)||!Notification.requestPermission)return!1;if(Notification.permission!=="granted")try{new Notification("")}catch(i){if(i instanceof Error&&i.name==="TypeError")return!1}return!0}}async getDeliveredNotifications(){const i=[];for(const t of this.deliveredNotifications){const e={title:t.title,id:parseInt(t.tag),body:t.body};i.push(e)}return{notifications:i}}async removeDeliveredNotifications(i){for(const t of i.notifications){const e=this.deliveredNotifications.find(n=>n.tag===String(t.id));e==null||e.close(),this.deliveredNotifications=this.deliveredNotifications.filter(()=>!e)}}async removeAllDeliveredNotifications(){for(const i of this.deliveredNotifications)i.close();this.deliveredNotifications=[]}async createChannel(){throw this.unimplemented("Not implemented on web.")}async deleteChannel(){throw this.unimplemented("Not implemented on web.")}async listChannels(){throw this.unimplemented("Not implemented on web.")}async schedule(i){if(!this.hasNotificationSupport())throw this.unavailable("Notifications not supported in this browser.");for(const t of i.notifications)this.sendNotification(t);return{notifications:i.notifications.map(t=>({id:t.id}))}}async getPending(){return{notifications:this.pending}}async registerActionTypes(){throw this.unimplemented("Not implemented on web.")}async cancel(i){this.pending=this.pending.filter(t=>!i.notifications.find(e=>e.id===t.id))}async areEnabled(){const{display:i}=await this.checkPermissions();return{value:i==="granted"}}async changeExactNotificationSetting(){throw this.unimplemented("Not implemented on web.")}async checkExactNotificationSetting(){throw this.unimplemented("Not implemented on web.")}async requestPermissions(){if(!this.hasNotificationSupport())throw this.unavailable("Notifications not supported in this browser.");return{display:this.transformNotificationPermission(await Notification.requestPermission())}}async checkPermissions(){if(!this.hasNotificationSupport())throw this.unavailable("Notifications not supported in this browser.");return{display:this.transformNotificationPermission(Notification.permission)}}transformNotificationPermission(i){switch(i){case"granted":return"granted";case"denied":return"denied";default:return"prompt"}}sendPending(){var i;const t=[],e=new Date().getTime();for(const n of this.pending)!((i=n.schedule)===null||i===void 0)&&i.at&&n.schedule.at.getTime()<=e&&(this.buildNotification(n),t.push(n));this.pending=this.pending.filter(n=>!t.find(o=>o===n))}sendNotification(i){var t;if(!((t=i.schedule)===null||t===void 0)&&t.at){const e=i.schedule.at.getTime()-new Date().getTime();this.pending.push(i),setTimeout(()=>{this.sendPending()},e);return}this.buildNotification(i)}buildNotification(i){const t=new Notification(i.title,{body:i.body,tag:String(i.id)});return t.addEventListener("click",this.onClick.bind(this,i),!1),t.addEventListener("show",this.onShow.bind(this,i),!1),t.addEventListener("close",()=>{this.deliveredNotifications=this.deliveredNotifications.filter(()=>!this)},!1),this.deliveredNotifications.push(t),t}onClick(i){const t={actionId:"tap",notification:i};this.notifyListeners("localNotificationActionPerformed",t)}onShow(i){this.notifyListeners("localNotificationReceived",i)}}export{f as LocalNotificationsWeb};
1
+ import{bz as s}from"./main-D3GShQ8B.js";import"./modulepreload-polyfill-B5Qt9EMX.js";import"./vendor-react--Eh9ivFN.js";import"./vendor-three-Chj50gSY.js";class f extends s{constructor(){super(...arguments),this.pending=[],this.deliveredNotifications=[],this.hasNotificationSupport=()=>{if(!("Notification"in window)||!Notification.requestPermission)return!1;if(Notification.permission!=="granted")try{new Notification("")}catch(i){if(i instanceof Error&&i.name==="TypeError")return!1}return!0}}async getDeliveredNotifications(){const i=[];for(const t of this.deliveredNotifications){const e={title:t.title,id:parseInt(t.tag),body:t.body};i.push(e)}return{notifications:i}}async removeDeliveredNotifications(i){for(const t of i.notifications){const e=this.deliveredNotifications.find(n=>n.tag===String(t.id));e==null||e.close(),this.deliveredNotifications=this.deliveredNotifications.filter(()=>!e)}}async removeAllDeliveredNotifications(){for(const i of this.deliveredNotifications)i.close();this.deliveredNotifications=[]}async createChannel(){throw this.unimplemented("Not implemented on web.")}async deleteChannel(){throw this.unimplemented("Not implemented on web.")}async listChannels(){throw this.unimplemented("Not implemented on web.")}async schedule(i){if(!this.hasNotificationSupport())throw this.unavailable("Notifications not supported in this browser.");for(const t of i.notifications)this.sendNotification(t);return{notifications:i.notifications.map(t=>({id:t.id}))}}async getPending(){return{notifications:this.pending}}async registerActionTypes(){throw this.unimplemented("Not implemented on web.")}async cancel(i){this.pending=this.pending.filter(t=>!i.notifications.find(e=>e.id===t.id))}async areEnabled(){const{display:i}=await this.checkPermissions();return{value:i==="granted"}}async changeExactNotificationSetting(){throw this.unimplemented("Not implemented on web.")}async checkExactNotificationSetting(){throw this.unimplemented("Not implemented on web.")}async requestPermissions(){if(!this.hasNotificationSupport())throw this.unavailable("Notifications not supported in this browser.");return{display:this.transformNotificationPermission(await Notification.requestPermission())}}async checkPermissions(){if(!this.hasNotificationSupport())throw this.unavailable("Notifications not supported in this browser.");return{display:this.transformNotificationPermission(Notification.permission)}}transformNotificationPermission(i){switch(i){case"granted":return"granted";case"denied":return"denied";default:return"prompt"}}sendPending(){var i;const t=[],e=new Date().getTime();for(const n of this.pending)!((i=n.schedule)===null||i===void 0)&&i.at&&n.schedule.at.getTime()<=e&&(this.buildNotification(n),t.push(n));this.pending=this.pending.filter(n=>!t.find(o=>o===n))}sendNotification(i){var t;if(!((t=i.schedule)===null||t===void 0)&&t.at){const e=i.schedule.at.getTime()-new Date().getTime();this.pending.push(i),setTimeout(()=>{this.sendPending()},e);return}this.buildNotification(i)}buildNotification(i){const t=new Notification(i.title,{body:i.body,tag:String(i.id)});return t.addEventListener("click",this.onClick.bind(this,i),!1),t.addEventListener("show",this.onShow.bind(this,i),!1),t.addEventListener("close",()=>{this.deliveredNotifications=this.deliveredNotifications.filter(()=>!this)},!1),this.deliveredNotifications.push(t),t}onClick(i){const t={actionId:"tap",notification:i};this.notifyListeners("localNotificationActionPerformed",t)}onShow(i){this.notifyListeners("localNotificationReceived",i)}}export{f as LocalNotificationsWeb};
package/dist/index.html CHANGED
@@ -22,11 +22,11 @@
22
22
  <link rel="icon" type="image/png" sizes="16x16" href="/assets/icons/favicon-16x16.png" />
23
23
  <link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png" />
24
24
  <title>Tide Commander</title>
25
- <script type="module" crossorigin src="/assets/main-CrRMpn-n.js"></script>
25
+ <script type="module" crossorigin src="/assets/main-D3GShQ8B.js"></script>
26
26
  <link rel="modulepreload" crossorigin href="/assets/modulepreload-polyfill-B5Qt9EMX.js">
27
27
  <link rel="modulepreload" crossorigin href="/assets/vendor-react--Eh9ivFN.js">
28
28
  <link rel="modulepreload" crossorigin href="/assets/vendor-three-Chj50gSY.js">
29
- <link rel="stylesheet" crossorigin href="/assets/main-DjGrMNoB.css">
29
+ <link rel="stylesheet" crossorigin href="/assets/main-Ch2CJGT4.css">
30
30
  </head>
31
31
  <body>
32
32
  <div id="app"></div>
@@ -29,6 +29,7 @@ const RUNNING_PROCESSES_FILE = path.join(DATA_DIR, 'running-processes.json');
29
29
  const SECRETS_FILE = path.join(DATA_DIR, 'secrets.json');
30
30
  const SESSION_HISTORY_FILE = path.join(DATA_DIR, 'session-history.json');
31
31
  const AREA_LOGOS_DIR = path.join(DATA_DIR, 'area-logos');
32
+ const CLASS_ICONS_DIR = path.join(DATA_DIR, 'custom-class-icons');
32
33
  // Maximum history entries per agent
33
34
  const MAX_HISTORY_PER_AGENT = 50;
34
35
  const MAX_SESSION_HISTORY_PER_AGENT = 100;
@@ -136,6 +137,9 @@ function toStoredAgents(agents) {
136
137
  lastAssignedTask: agent.lastAssignedTask,
137
138
  lastAssignedTaskTime: agent.lastAssignedTaskTime,
138
139
  taskLabel: agent.taskLabel,
140
+ trackingStatus: agent.trackingStatus,
141
+ trackingStatusDetail: agent.trackingStatusDetail,
142
+ trackingStatusTimestamp: agent.trackingStatusTimestamp,
139
143
  isBoss: agent.isBoss,
140
144
  subordinateIds: agent.subordinateIds,
141
145
  bossId: agent.bossId,
@@ -254,6 +258,30 @@ export function deleteAreaLogo(filename) {
254
258
  log.log(` Deleted area logo: ${filename}`);
255
259
  }
256
260
  }
261
+ /**
262
+ * Ensure custom class icons directory exists
263
+ */
264
+ export function ensureClassIconsDir() {
265
+ if (!fs.existsSync(CLASS_ICONS_DIR)) {
266
+ fs.mkdirSync(CLASS_ICONS_DIR, { recursive: true });
267
+ }
268
+ }
269
+ /**
270
+ * Get path to the custom class icons directory
271
+ */
272
+ export function getClassIconsDir() {
273
+ return CLASS_ICONS_DIR;
274
+ }
275
+ /**
276
+ * Delete a class icon file from disk
277
+ */
278
+ export function deleteClassIcon(filename) {
279
+ const filePath = path.join(CLASS_ICONS_DIR, path.basename(filename));
280
+ if (fs.existsSync(filePath)) {
281
+ fs.unlinkSync(filePath);
282
+ log.log(` Deleted class icon: ${filename}`);
283
+ }
284
+ }
257
285
  /**
258
286
  * Update a single agent's session ID
259
287
  */
@@ -72,6 +72,13 @@ const CONFIG_CATEGORIES = [
72
72
  files: ['custom-models/*'],
73
73
  sourceDir: 'home',
74
74
  },
75
+ {
76
+ id: 'custom-class-icons',
77
+ name: 'Custom Class Icons',
78
+ description: 'PNG/JPEG/WebP icon files for custom agent classes',
79
+ files: ['custom-class-icons/*'],
80
+ sourceDir: 'data',
81
+ },
75
82
  {
76
83
  id: 'hooks',
77
84
  name: 'Hooks',
@@ -0,0 +1,138 @@
1
+ /**
2
+ * Custom Class Icon Routes
3
+ * REST API endpoints for uploading, serving, and deleting custom class PNG icons
4
+ */
5
+ import { Router } from 'express';
6
+ import * as fs from 'fs';
7
+ import * as path from 'path';
8
+ import { ensureClassIconsDir, getClassIconsDir, deleteClassIcon } from '../data/index.js';
9
+ import { getCustomClass, updateCustomClass } from '../services/custom-class-service.js';
10
+ import { createLogger } from '../utils/logger.js';
11
+ const log = createLogger('ClassIcons');
12
+ const router = Router();
13
+ // Allowed image MIME types
14
+ const ALLOWED_IMAGE_TYPES = new Set([
15
+ 'image/png', 'image/jpeg', 'image/webp',
16
+ ]);
17
+ // Max icon file size: 2MB
18
+ const MAX_ICON_SIZE = 2 * 1024 * 1024;
19
+ // Extension map from content type
20
+ const EXT_MAP = {
21
+ 'image/png': '.png',
22
+ 'image/jpeg': '.jpg',
23
+ 'image/webp': '.webp',
24
+ };
25
+ // MIME map from file extension
26
+ const MIME_MAP = {
27
+ '.png': 'image/png',
28
+ '.jpg': 'image/jpeg',
29
+ '.jpeg': 'image/jpeg',
30
+ '.webp': 'image/webp',
31
+ };
32
+ // GET /api/custom-class-icons/:filename - Serve an icon file
33
+ router.get('/:filename', (req, res) => {
34
+ try {
35
+ ensureClassIconsDir();
36
+ const filename = path.basename(String(req.params.filename)); // sanitize
37
+ const filePath = path.join(getClassIconsDir(), filename);
38
+ if (!fs.existsSync(filePath)) {
39
+ res.status(404).json({ error: 'Icon not found' });
40
+ return;
41
+ }
42
+ const ext = path.extname(filename).toLowerCase();
43
+ const contentType = MIME_MAP[ext] || 'application/octet-stream';
44
+ res.setHeader('Content-Type', contentType);
45
+ res.setHeader('Cache-Control', 'public, max-age=31536000'); // 1 year - filenames are unique per class
46
+ fs.createReadStream(filePath).pipe(res);
47
+ }
48
+ catch (err) {
49
+ log.error(' Failed to serve class icon:', err);
50
+ res.status(500).json({ error: err.message });
51
+ }
52
+ });
53
+ // POST /api/custom-class-icons/:classId - Upload an icon for a custom class
54
+ router.post('/:classId', (req, res) => {
55
+ try {
56
+ ensureClassIconsDir();
57
+ const classId = String(req.params.classId);
58
+ const contentType = req.headers['content-type'] || '';
59
+ // Validate class exists
60
+ const customClass = getCustomClass(classId);
61
+ if (!customClass) {
62
+ res.status(404).json({ error: `Custom class not found: ${classId}` });
63
+ return;
64
+ }
65
+ // Validate image type
66
+ if (!ALLOWED_IMAGE_TYPES.has(contentType)) {
67
+ res.status(400).json({ error: `Invalid image type: ${contentType}. Allowed: ${[...ALLOWED_IMAGE_TYPES].join(', ')}` });
68
+ return;
69
+ }
70
+ // Delete existing icon for this class if any
71
+ if (customClass.iconPath) {
72
+ deleteClassIcon(customClass.iconPath);
73
+ }
74
+ // Determine extension and filename
75
+ const ext = EXT_MAP[contentType] || '.png';
76
+ const filename = `${classId}${ext}`;
77
+ const filePath = path.join(getClassIconsDir(), filename);
78
+ // Collect body data
79
+ const chunks = [];
80
+ let totalSize = 0;
81
+ req.on('data', (chunk) => {
82
+ totalSize += chunk.length;
83
+ if (totalSize > MAX_ICON_SIZE) {
84
+ res.status(413).json({ error: `Icon too large. Max size: ${MAX_ICON_SIZE / 1024 / 1024}MB` });
85
+ req.destroy();
86
+ return;
87
+ }
88
+ chunks.push(chunk);
89
+ });
90
+ req.on('end', () => {
91
+ if (res.headersSent)
92
+ return; // Already sent 413
93
+ const buffer = Buffer.concat(chunks);
94
+ fs.writeFileSync(filePath, buffer);
95
+ log.log(` Uploaded class icon: ${filename} (${buffer.length} bytes)`);
96
+ // Update the class's iconPath field
97
+ updateCustomClass(classId, { iconPath: filename });
98
+ res.json({
99
+ success: true,
100
+ filename,
101
+ url: `/api/custom-class-icons/${filename}`,
102
+ size: buffer.length,
103
+ });
104
+ });
105
+ req.on('error', (err) => {
106
+ log.error(' Icon upload error:', err);
107
+ if (!res.headersSent) {
108
+ res.status(500).json({ error: 'Upload failed' });
109
+ }
110
+ });
111
+ }
112
+ catch (err) {
113
+ log.error(' Failed to upload class icon:', err);
114
+ res.status(500).json({ error: err.message });
115
+ }
116
+ });
117
+ // DELETE /api/custom-class-icons/:classId - Delete the icon for a custom class
118
+ router.delete('/:classId', (req, res) => {
119
+ try {
120
+ const classId = String(req.params.classId);
121
+ const customClass = getCustomClass(classId);
122
+ if (!customClass) {
123
+ res.status(404).json({ error: `Custom class not found: ${classId}` });
124
+ return;
125
+ }
126
+ if (customClass.iconPath) {
127
+ deleteClassIcon(customClass.iconPath);
128
+ updateCustomClass(classId, { iconPath: undefined });
129
+ log.log(` Removed icon for class ${classId}`);
130
+ }
131
+ res.json({ success: true });
132
+ }
133
+ catch (err) {
134
+ log.error(' Failed to delete class icon:', err);
135
+ res.status(500).json({ error: err.message });
136
+ }
137
+ });
138
+ export default router;
@@ -16,6 +16,7 @@ import sttRouter from './stt.js';
16
16
  import voiceAssistantRouter from './voice-assistant.js';
17
17
  import snapshotsRouter from './snapshots.js';
18
18
  import areasRouter from './areas.js';
19
+ import customClassIconsRouter from './custom-class-icons.js';
19
20
  import workspacesRouter from './workspaces.js';
20
21
  import perfRouter from './perf.js';
21
22
  import triggerRouter, { setBroadcast as setTriggerBroadcast } from './trigger-routes.js';
@@ -40,6 +41,7 @@ router.use('/stt', sttRouter);
40
41
  router.use('/voice-assistant', voiceAssistantRouter);
41
42
  router.use('/snapshots', snapshotsRouter);
42
43
  router.use('/areas', areasRouter);
44
+ router.use('/custom-class-icons', customClassIconsRouter);
43
45
  router.use('/workspaces', workspacesRouter);
44
46
  router.use('/perf', perfRouter);
45
47
  router.use('/triggers', triggerRouter);
@@ -6,7 +6,7 @@ import { EventEmitter } from 'events';
6
6
  import * as fs from 'fs';
7
7
  import * as path from 'path';
8
8
  import * as os from 'os';
9
- import { loadCustomAgentClasses, saveCustomAgentClasses } from '../data/index.js';
9
+ import { loadCustomAgentClasses, saveCustomAgentClasses, deleteClassIcon } from '../data/index.js';
10
10
  import { createLogger, generateSlug } from '../utils/index.js';
11
11
  const log = createLogger('CustomClassService');
12
12
  // In-memory store
@@ -212,10 +212,15 @@ export function updateCustomClass(id, updates) {
212
212
  * Delete a custom agent class
213
213
  */
214
214
  export function deleteCustomClass(id) {
215
- if (!customClasses.has(id)) {
215
+ const existing = customClasses.get(id);
216
+ if (!existing) {
216
217
  log.warn(`Custom class not found: ${id}`);
217
218
  return false;
218
219
  }
220
+ // Delete class icon file if exists
221
+ if (existing.iconPath) {
222
+ deleteClassIcon(existing.iconPath);
223
+ }
219
224
  customClasses.delete(id);
220
225
  persistClasses();
221
226
  // Delete instructions file
@@ -750,6 +750,9 @@ export async function handleUpdateAgentProperties(ctx, payload) {
750
750
  }
751
751
  agentUpdates.cwd = updates.cwd;
752
752
  }
753
+ if (updates.shortcut !== undefined) {
754
+ agentUpdates.shortcut = updates.shortcut;
755
+ }
753
756
  // Apply agent property updates if any
754
757
  // agentService.updateAgent tracks pending property changes for notification on next command
755
758
  if (Object.keys(agentUpdates).length > 0) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tide-commander",
3
- "version": "1.44.0",
3
+ "version": "1.46.0",
4
4
  "description": "Visual multi-agent orchestrator and manager for Claude Code with 3D/2D interface",
5
5
  "repository": {
6
6
  "type": "git",
@@ -1 +0,0 @@
1
- import{u as $e,f as Ae,M as Le,L as Ee,r as t,P as _e,S as se,w as De,U as O,A as ae,a2 as P,a3 as j,j as s,W as Ie,Y as Be,Z as T,_ as A,$ as L,a1 as Re,s as Oe}from"./main-CrRMpn-n.js";import"./modulepreload-polyfill-B5Qt9EMX.js";import"./vendor-react--Eh9ivFN.js";import"./vendor-three-Chj50gSY.js";function ne(m){const h=j.filter(S=>!m.has(`Boss ${S}`));return h.length===0?`Boss ${j[Math.floor(Math.random()*j.length)]}-${Date.now()%1e3}`:`Boss ${h[Math.floor(Math.random()*h.length)]}`}function Fe({isOpen:m,onClose:h,onSpawnStart:S,onSpawnEnd:E,spawnPosition:le}){const{t:n}=$e(["terminal","common"]),{agents:g}=Ae(),o=Le(),C=Ee(),[r,p]=t.useState(""),[k,te]=t.useState(()=>_e(se.LAST_CWD)),[c,_]=t.useState("boss"),[U,q]=t.useState(!1),[ie,M]=t.useState(!1),[F,ce]=t.useState(!0),[W,oe]=t.useState("bypass"),[d,D]=t.useState("claude"),[b,N]=t.useState({fullAuto:!0,sandbox:"workspace-write",approvalMode:"on-request",search:!1}),[G,re]=t.useState("opus"),[K,de]=t.useState("gpt-5.3-codex"),[v,y]=t.useState(new Set),[z,I]=t.useState(new Set),[u,pe]=t.useState(""),[f,ue]=t.useState(""),[H,me]=t.useState(""),$=t.useRef(null),B=t.useRef(!1),J=t.useRef(!1),x=t.useMemo(()=>C.filter(e=>e.enabled),[C]),Y=t.useMemo(()=>{if(!f.trim())return x;const e=f.toLowerCase();return x.filter(a=>a.name.toLowerCase().includes(e)||a.description.toLowerCase().includes(e)||a.slug.toLowerCase().includes(e))},[x,f]),he=t.useMemo(()=>{var a;const e=o.find(l=>l.id===c);return(a=e==null?void 0:e.defaultSkillIds)!=null&&a.length?C.filter(l=>e.defaultSkillIds.includes(l.id)):[]},[o,c,C]),we=["full-notifications","streaming-exec","task-label","report-task-to-boss"];t.useEffect(()=>{if(m&&!J.current&&x.length>0){const a=x.filter(l=>we.includes(l.slug)).map(l=>l.id);a.length>0&&I(new Set(a))}J.current=m},[m,x]);const xe=t.useCallback(e=>{I(a=>{const l=new Set(a);return l.has(e)?l.delete(e):l.add(e),l})},[]),i=t.useMemo(()=>o.find(e=>e.id===c),[o,c]),be=t.useMemo(()=>{if(i!=null&&i.model)return i.model},[i]),fe=t.useMemo(()=>{if(i!=null&&i.customModelPath)return De(`/api/custom-models/${i.id}`)},[i]),je=i==null?void 0:i.modelScale,Ne=t.useMemo(()=>i?"scout":c==="boss"?"architect":c,[c,i]),V=Array.from(g.values()).filter(e=>!e.isBoss&&e.class!=="boss"&&!e.bossId),X=t.useMemo(()=>{if(!u.trim())return o;const e=u.toLowerCase();return o.filter(a=>a.name.toLowerCase().includes(e)||a.description.toLowerCase().includes(e)||a.id.toLowerCase().includes(e))},[o,u]),Z=t.useMemo(()=>{if(!u.trim())return O;const e=u.toLowerCase();return O.filter(a=>{const l=ae[a.id];return l?a.name.toLowerCase().includes(e)||a.id.toLowerCase().includes(e)||l.description.toLowerCase().includes(e):!1})},[u]),Q=t.useMemo(()=>{if(!u.trim())return!0;const e=u.toLowerCase(),a=P.boss;return"boss".includes(e)||a.description.toLowerCase().includes(e)},[u]);t.useEffect(()=>{if(m&&!B.current){B.current=!0;const e=new Set(Array.from(g.values()).map(l=>l.name)),a=o.find(l=>l.id===c);if(a){const l=j.filter(w=>!e.has(`${a.name} ${w}`));if(l.length===0){const w=j[Math.floor(Math.random()*j.length)];p(`${a.name} ${w}-${Date.now()%1e3}`)}else p(`${a.name} ${l[Math.floor(Math.random()*l.length)]}`)}else p(ne(e));y(new Set),$.current&&($.current.focus(),$.current.select())}else m||(B.current=!1)},[m,g]),t.useEffect(()=>{if(!m)return;const e=o.find(a=>a.id===c);if(e)if(r.startsWith("Boss ")){const a=r.substring(5);p(`${e.name} ${a}`)}else{const a=o.find(l=>r.startsWith(l.name+" "));if(a){const l=r.substring(a.name.length+1);p(`${e.name} ${l}`)}else p(`${e.name} ${r}`)}else{const a=o.find(l=>r.startsWith(l.name+" "));if(a){const l=r.substring(a.name.length+1);p(`Boss ${l}`)}else r.startsWith("Boss ")||p(`Boss ${r}`)}},[c]);const ve=()=>{if(M(!1),!k.trim()){M(!0);return}if(!r.trim()){const l=new Set(Array.from(g.values()).map(w=>w.name));p(ne(l));return}Re(se.LAST_CWD,k),S();const e=H.trim()||void 0,a=Array.from(z);Oe.spawnBossAgent(r.trim(),c,k.trim(),le||void 0,Array.from(v),d==="claude"?F:!1,W,d,d==="codex"?b:void 0,d==="codex"?K:void 0,d==="claude"?G:void 0,e,a),p(""),y(new Set),I(new Set),E(),h()},Se=()=>{q(!1),p(""),y(new Set),E(),h()},ge=()=>{q(!1),M(!0),E()};t.useEffect(()=>(window.__bossSpawnModalSuccess=Se,window.__bossSpawnModalError=ge,()=>{delete window.__bossSpawnModalSuccess,delete window.__bossSpawnModalError}),[r]);const Ce=e=>{e.target===e.currentTarget&&h()},ke=e=>{e.key==="Escape"&&h()},Me=e=>{const a=new Set(v);a.has(e)?a.delete(e):a.add(e),y(a)};if(!m)return null;const R=P.boss;return s.jsx("div",{className:`modal-overlay ${m?"visible":""}`,onClick:Ce,onKeyDown:ke,children:s.jsxs("div",{className:"modal boss-spawn-modal",children:[s.jsxs("div",{className:"modal-header",children:[s.jsx("span",{className:"boss-header-icon",children:R.icon}),n("terminal:spawn.deployBossTitle")]}),s.jsxs("div",{className:"modal-body spawn-modal-body",children:[s.jsxs("div",{className:"spawn-top-section",children:[s.jsx("div",{className:"spawn-preview-compact",children:s.jsx(Ie,{agentClass:Ne,modelFile:be,customModelUrl:fe,modelScale:je,width:100,height:120})}),s.jsxs("div",{className:"spawn-class-section",children:[s.jsx("div",{className:"spawn-class-label",children:n("terminal:spawn.bossClass")}),o.length+O.length+1>6&&s.jsx("input",{type:"text",className:"spawn-input class-search-input",placeholder:n("terminal:spawn.filterClasses"),value:u,onChange:e=>pe(e.target.value)}),s.jsxs("div",{className:"class-selector-inline",children:[X.map(e=>s.jsxs("button",{className:`class-chip ${c===e.id?"selected":""}`,onClick:()=>_(e.id),title:e.description,children:[s.jsx("span",{className:"class-chip-icon",children:e.icon}),s.jsx("span",{className:"class-chip-name",children:e.name})]},e.id)),Q&&s.jsxs("button",{className:`class-chip ${c==="boss"?"selected":""}`,onClick:()=>_("boss"),title:R.description,children:[s.jsx("span",{className:"class-chip-icon",children:R.icon}),s.jsx("span",{className:"class-chip-name",children:n("terminal:spawn.bossClassName")})]}),Z.map(e=>{const a=ae[e.id];return a?s.jsxs("button",{className:`class-chip ${c===e.id?"selected":""}`,onClick:()=>_(e.id),title:a.description,children:[s.jsx("span",{className:"class-chip-icon",children:a.icon}),s.jsx("span",{className:"class-chip-name",children:e.name})]},e.id):null}),u&&X.length===0&&!Q&&Z.length===0&&s.jsx("div",{className:"class-search-empty",children:n("terminal:spawn.noClassesMatch",{query:u})})]})]})]}),s.jsxs("div",{className:"spawn-form-section",children:[s.jsxs("div",{className:"spawn-form-row",children:[s.jsxs("div",{className:"spawn-field",children:[s.jsx("label",{className:"spawn-label",children:n("common:labels.name")}),s.jsx("input",{ref:$,type:"text",className:"spawn-input",placeholder:n("terminal:spawn.bossNamePlaceholder"),value:r,onChange:e=>p(e.target.value)})]}),s.jsxs("div",{className:"spawn-field spawn-field-wide",children:[s.jsx("label",{className:"spawn-label",children:n("terminal:spawn.workingDir")}),s.jsx(Be,{value:k,onChange:e=>{te(e),M(!1)},placeholder:n("terminal:spawn.workingDirPlaceholder"),className:"spawn-input",hasError:ie,directoriesOnly:!0})]})]}),s.jsxs("div",{className:"spawn-form-row",children:[s.jsxs("div",{className:"spawn-field",children:[s.jsx("label",{className:"spawn-label",children:n("common:labels.runtime")}),s.jsxs("div",{className:"spawn-select-row",children:[s.jsxs("button",{className:`spawn-select-btn ${d==="claude"?"selected":""}`,onClick:()=>D("claude"),title:n("terminal:spawn.useClaudeCli"),children:[s.jsx("img",{src:"/assets/claude.ico",alt:"Claude",className:"spawn-provider-icon"}),s.jsx("span",{children:"Claude"})]}),s.jsxs("button",{className:`spawn-select-btn ${d==="codex"?"selected":""}`,onClick:()=>D("codex"),title:n("terminal:spawn.useCodexCli"),children:[s.jsx("img",{src:"/assets/codex.ico",alt:"Codex",className:"spawn-provider-icon"}),s.jsx("span",{children:"Codex"})]}),s.jsxs("button",{className:`spawn-select-btn spawn-select-btn--opencode ${d==="opencode"?"selected":""}`,onClick:()=>D("opencode"),title:"Use OpenCode CLI (multi-provider)",children:[s.jsx("span",{children:"🟢"}),s.jsx("span",{children:"OpenCode"})]})]})]}),s.jsxs("div",{className:"spawn-field",children:[s.jsx("label",{className:"spawn-label",children:n("common:labels.permissions")}),s.jsx("div",{className:"spawn-select-row",children:Object.keys(T).map(e=>s.jsxs("button",{className:`spawn-select-btn ${W===e?"selected":""}`,onClick:()=>oe(e),title:T[e].description,children:[s.jsx("span",{children:e==="bypass"?"⚡":"🔐"}),s.jsx("span",{children:T[e].label})]},e))})]})]}),s.jsxs("div",{className:"spawn-form-row",children:[s.jsxs("div",{className:"spawn-field",children:[s.jsx("label",{className:"spawn-label",children:n("common:labels.model")}),d==="claude"?s.jsx("div",{className:"spawn-select-row",children:Object.keys(A).map(e=>s.jsxs("button",{className:`spawn-select-btn ${G===e?"selected":""}`,onClick:()=>re(e),title:A[e].description,children:[s.jsx("span",{children:A[e].icon}),s.jsx("span",{children:A[e].label})]},e))}):d==="codex"?s.jsx("div",{className:"spawn-select-row spawn-select-row--codex-models",children:Object.keys(L).map(e=>s.jsxs("button",{className:`spawn-select-btn ${K===e?"selected":""}`,onClick:()=>de(e),title:L[e].description,children:[s.jsx("span",{children:L[e].icon}),s.jsx("span",{children:L[e].label})]},e))}):d==="opencode"?s.jsx("input",{type:"text",className:"spawn-input",defaultValue:"minimax/MiniMax-M1-80k",placeholder:"provider/model (e.g., minimax/MiniMax-M1-80k)"}):s.jsx("div",{className:"spawn-inline-hint",children:n("terminal:spawn.codex.configuration")})]}),s.jsxs("div",{className:"spawn-field",children:[s.jsx("label",{className:"spawn-label",children:n("common:labels.browser")}),s.jsx("div",{className:"spawn-form-row spawn-options-row",children:s.jsxs("label",{className:"spawn-checkbox",children:[s.jsx("input",{type:"checkbox",checked:F,onChange:e=>ce(e.target.checked),disabled:d!=="claude"}),s.jsx("span",{children:n("terminal:spawn.chromeBrowser")})]})})]})]}),d==="codex"&&s.jsx("div",{className:"spawn-form-row",children:s.jsxs("div",{className:"spawn-field",children:[s.jsx("label",{className:"spawn-label",children:n("terminal:spawn.codex.config")}),s.jsxs("div",{className:"spawn-options-row",style:{display:"flex",flexDirection:"column",gap:8},children:[s.jsxs("label",{className:"spawn-checkbox",children:[s.jsx("input",{type:"checkbox",checked:b.fullAuto!==!1,onChange:e=>N(a=>({...a,fullAuto:e.target.checked}))}),s.jsx("span",{children:n("terminal:spawn.codex.useFullAuto")})]}),s.jsxs("label",{className:"spawn-checkbox",children:[s.jsx("input",{type:"checkbox",checked:!!b.search,onChange:e=>N(a=>({...a,search:e.target.checked}))}),s.jsx("span",{children:n("terminal:spawn.codex.enableSearch")})]}),b.fullAuto===!1&&s.jsxs(s.Fragment,{children:[s.jsxs("select",{className:"spawn-input",value:b.sandbox||"workspace-write",onChange:e=>N(a=>({...a,sandbox:e.target.value})),children:[s.jsx("option",{value:"read-only",children:n("terminal:spawn.codex.sandboxReadOnly")}),s.jsx("option",{value:"workspace-write",children:n("terminal:spawn.codex.sandboxWorkspaceWrite")}),s.jsx("option",{value:"danger-full-access",children:n("terminal:spawn.codex.sandboxDangerFullAccess")})]}),s.jsxs("select",{className:"spawn-input",value:b.approvalMode||"on-request",onChange:e=>N(a=>({...a,approvalMode:e.target.value})),children:[s.jsx("option",{value:"untrusted",children:n("terminal:spawn.codex.approvalsUntrusted")}),s.jsx("option",{value:"on-failure",children:n("terminal:spawn.codex.approvalsOnFailure")}),s.jsx("option",{value:"on-request",children:n("terminal:spawn.codex.approvalsOnRequest")}),s.jsx("option",{value:"never",children:n("terminal:spawn.codex.approvalsNever")})]})]}),s.jsx("input",{type:"text",className:"spawn-input",placeholder:n("terminal:spawn.codex.profileOptional"),value:b.profile||"",onChange:e=>N(a=>({...a,profile:e.target.value||void 0}))})]})]})}),x.length>0&&s.jsxs("div",{className:"spawn-skills-section",children:[s.jsxs("label",{className:"spawn-label",children:[n("terminal:spawn.skills")," ",s.jsxs("span",{className:"spawn-label-hint",children:["(",n("common:labels.optional"),")"]})]}),x.length>6&&s.jsx("input",{type:"text",className:"spawn-input skill-search-input",placeholder:n("terminal:spawn.filterSkills"),value:f,onChange:e=>ue(e.target.value)}),s.jsxs("div",{className:"spawn-skills-inline",children:[Y.map(e=>{const a=z.has(e.id);return he.some(w=>w.id===e.id)?null:s.jsxs("button",{className:`spawn-skill-chip ${a?"selected":""}`,onClick:()=>xe(e.id),title:e.description,children:[a&&s.jsx("span",{className:"spawn-skill-check",children:"✓"}),s.jsx("span",{children:e.name}),e.builtin&&s.jsx("span",{className:"spawn-skill-builtin",children:"TC"})]},e.id)}),f&&Y.length===0&&s.jsx("div",{className:"skill-search-empty",children:n("terminal:spawn.noSkillsMatch",{query:f})})]})]}),s.jsxs("div",{className:"spawn-custom-instructions-section",children:[s.jsxs("label",{className:"spawn-label",children:[n("terminal:spawn.customInstructions")," ",s.jsxs("span",{className:"spawn-label-hint",children:["(",n("common:labels.optional"),")"]})]}),s.jsx("textarea",{className:"spawn-input spawn-textarea",placeholder:n("terminal:spawn.customInstructionsBossPlaceholder"),value:H,onChange:e=>me(e.target.value),rows:3})]}),s.jsxs("div",{className:"spawn-subordinates-section",children:[s.jsxs("label",{className:"spawn-label",children:[n("terminal:spawn.initialSubordinates")," ",s.jsxs("span",{className:"spawn-label-hint",children:["(",n("common:labels.optional"),")"]})]}),s.jsx("div",{className:"subordinates-selector-compact",children:V.length===0?s.jsx("div",{className:"subordinates-empty",children:n("terminal:spawn.noAvailableAgents")}):V.map(e=>{const a=v.has(e.id),l=P[e.class],w=o.find(ye=>ye.id===e.class),ee=l||w||{icon:"🤖",color:"#888888"};return s.jsxs("button",{className:`subordinate-chip ${a?"selected":""}`,onClick:()=>Me(e.id),children:[a&&s.jsx("span",{className:"subordinate-check",children:"✓"}),s.jsx("span",{className:"subordinate-chip-icon",style:{color:ee.color},children:ee.icon}),s.jsx("span",{className:"subordinate-chip-name",children:e.name})]},e.id)})}),v.size>0&&s.jsxs("div",{className:"subordinates-count",children:[v.size," ",n("common:labels.selected").toLowerCase()]})]})]})]}),s.jsxs("div",{className:"modal-footer",children:[s.jsx("button",{className:"btn btn-secondary",onClick:h,children:n("common:buttons.cancel")}),s.jsx("button",{className:"btn btn-boss",onClick:ve,disabled:U,children:n(U?"common:buttons.deploying":"common:buttons2.deployBoss")})]})]})})}export{Fe as BossSpawnModal};
@@ -1 +0,0 @@
1
- import{u as S,b9 as Y,r as m,ba as X,b8 as w,j as e,f as _,bb as W,bc as Z,z as U,h as H,s as y,bd as z,be as A}from"./main-CrRMpn-n.js";import"./modulepreload-polyfill-B5Qt9EMX.js";import"./vendor-react--Eh9ivFN.js";import"./vendor-three-Chj50gSY.js";function q({shortcut:t,onUpdate:a}){const{t:s}=S(["config","terminal"]),o=Y(),[l,h]=m.useState(!1),[i,j]=m.useState(null),f=m.useRef(null),b=m.useMemo(()=>i?X(o,i,t.id,t.context):[],[i,o,t.id,t.context]);m.useEffect(()=>{if(!l)return;const p=c=>{if(c.preventDefault(),c.stopPropagation(),c.key==="Escape"&&!c.ctrlKey&&!c.altKey&&!c.shiftKey&&!c.metaKey){h(!1),j(null);return}if(["Control","Alt","Shift","Meta"].includes(c.key))return;let v=c.key;c.code.startsWith("Key")&&c.code.length===4?v=c.code.charAt(3).toLowerCase():c.code.startsWith("Digit")&&c.code.length===6?v=c.code.charAt(5):c.code==="Space"&&(v="Space");const x={key:v,modifiers:{ctrl:c.ctrlKey,alt:c.altKey,shift:c.shiftKey,meta:c.metaKey}};j(x)};return document.addEventListener("keydown",p,!0),()=>document.removeEventListener("keydown",p,!0)},[l]),m.useEffect(()=>{if(!l)return;const p=c=>{f.current&&!f.current.contains(c.target)&&(i&&b.length===0&&a(i),h(!1),j(null))};return document.addEventListener("mousedown",p),()=>document.removeEventListener("mousedown",p)},[l,i,b,a]);const k=()=>{l?(i&&b.length===0&&a(i),h(!1),j(null)):(h(!0),j(null))},g=p=>{p.stopPropagation(),a({key:"",modifiers:{}})};let d;return l?i?d=w({...t,...i}):d=s("config:shortcuts.pressKeys"):t.key?d=w(t):d=s("config:shortcuts.notSet"),e.jsxs("div",{className:"key-capture-container",children:[e.jsx("button",{ref:f,className:`key-capture-input ${l?"capturing":""} ${b.length>0?"conflict":""} ${t.enabled?"":"disabled"}`,onClick:k,title:s(l?"config:shortcuts.pressKeysOrClick":"config:shortcuts.clickToChange"),children:e.jsx("span",{className:"key-capture-value",children:d})}),t.key&&!l&&e.jsx("button",{className:"key-capture-clear",onClick:g,title:s("config:shortcuts.clearShortcut"),children:"×"}),b.length>0&&e.jsx("div",{className:"key-capture-conflict",children:s("config:shortcuts.conflictsWith",{names:b.map(p=>s(`terminal:controls.shortcuts.${p.id}.name`,{defaultValue:p.name})).join(", ")})})]})}const V={global:"terminal:controls.contextGlobal",commander:"terminal:controls.contextCommander",toolbox:"terminal:controls.contextToolbox"},Q={global:"terminal:controls.contextGlobalDesc",commander:"terminal:controls.contextCommanderDesc",toolbox:"terminal:controls.contextToolboxDesc"},R={camera:["camera-pan","camera-orbit","camera-rotate","camera-zoom","camera-tilt"],interaction:["primary-action","selection-box","context-menu","move-command"]},J={camera:"terminal:controls.cameraControls",interaction:"terminal:controls.interaction"};function oe({isOpen:t,onClose:a}){const{t:s}=S(["terminal","common"]),o=_(),l=W(),h=Z(),[i,j]=m.useState("keyboard"),[f,b]=m.useState(""),[k,g]=m.useState("all"),[d,p]=m.useState(!1),[c,v]=m.useState(null),x=U.useRef(null),{handleMouseDown:D,handleClick:M}=H(a);if(m.useEffect(()=>{if(!t||d)return;const r=n=>{n.key==="Escape"&&(n.preventDefault(),n.stopPropagation(),a())};return document.addEventListener("keydown",r,!0),()=>document.removeEventListener("keydown",r,!0)},[t,a,d]),m.useEffect(()=>{t||(b(""),p(!1),v(null))},[t]),m.useEffect(()=>{if(!t||!d)return;const r=n=>{if(n.key==="Escape"){n.preventDefault(),n.stopPropagation(),p(!1),v(null);return}if(["Control","Alt","Shift","Meta"].includes(n.key))return;n.preventDefault(),n.stopPropagation();let u=n.key;n.code.startsWith("Key")&&n.code.length===4?u=n.code.charAt(3).toLowerCase():n.code.startsWith("Digit")&&n.code.length===6?u=n.code.charAt(5):n.code==="Space"&&(u="Space"),v({key:u,modifiers:{ctrl:n.ctrlKey,alt:n.altKey,shift:n.shiftKey,meta:n.metaKey}})};return document.addEventListener("keydown",r,!0),()=>document.removeEventListener("keydown",r,!0)},[t,d]),!t)return null;const E=o.shortcuts.filter(r=>{const n=s(`terminal:controls.shortcuts.${r.id}.name`,{defaultValue:r.name}),u=s(`terminal:controls.shortcuts.${r.id}.description`,{defaultValue:r.description});if(d&&c){const O=C=>C===" "||C==="Space"?"Space":C.length===1?C.toLowerCase():C,$=O(r.key),B=O(c.key);if(!(B.length===1&&/^[a-zA-Z]$/.test($)?`Key${$.toUpperCase()}`==`Key${B.toUpperCase()}`:$===B))return!1;const K=r.modifiers,T=c.modifiers;return(K.ctrl||!1)===(T.ctrl||!1)&&(K.alt||!1)===(T.alt||!1)&&(K.shift||!1)===(T.shift||!1)&&(K.meta||!1)===(T.meta||!1)}if(!f)return!0;const N=f.toLowerCase();return n.toLowerCase().includes(N)||u.toLowerCase().includes(N)||w(r).toLowerCase().includes(N)}),L=E.reduce((r,n)=>(r[n.context]||(r[n.context]=[]),r[n.context].push(n),r),{}),G=(r,n)=>{y.updateShortcut(r,n)},F=()=>{i==="keyboard"?confirm(s("terminal:controls.confirmResetKeyboard"))&&y.resetShortcuts():i==="mouse"?confirm(s("terminal:controls.confirmResetMouse"))&&y.resetMouseControls():i==="trackpad"&&confirm(s("terminal:controls.confirmResetTrackpad"))&&y.resetMouseControls()},P=["global","commander","toolbox"],I=l.bindings.reduce((r,n)=>(R.camera.includes(n.action)?r.camera.push(n):R.interaction.includes(n.action)&&r.interaction.push(n),r),{camera:[],interaction:[]});return e.jsx("div",{className:"shortcuts-modal-overlay",onMouseDown:D,onClick:M,children:e.jsxs("div",{className:"shortcuts-modal controls-modal",children:[e.jsxs("div",{className:"shortcuts-modal-header",children:[e.jsxs("div",{className:"shortcuts-modal-title",children:[e.jsxs("svg",{width:"20",height:"20",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",children:[e.jsx("circle",{cx:"12",cy:"12",r:"3"}),e.jsx("path",{d:"M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 2.83-2.83l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z"})]}),e.jsx("span",{children:s("terminal:controls.title")})]}),e.jsx("button",{className:"shortcuts-modal-close",onClick:a,children:"×"})]}),e.jsxs("div",{className:"controls-main-tabs",children:[e.jsxs("button",{className:`controls-main-tab ${i==="keyboard"?"active":""}`,onClick:()=>j("keyboard"),children:[e.jsxs("svg",{width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",children:[e.jsx("rect",{x:"2",y:"4",width:"20",height:"16",rx:"2"}),e.jsx("path",{d:"M6 8h.01M10 8h.01M14 8h.01M18 8h.01M6 12h.01M18 12h.01M8 16h8"})]}),s("terminal:controls.keyboard")]}),e.jsxs("button",{className:`controls-main-tab ${i==="mouse"?"active":""}`,onClick:()=>j("mouse"),children:[e.jsxs("svg",{width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",children:[e.jsx("rect",{x:"6",y:"3",width:"12",height:"18",rx:"6"}),e.jsx("line",{x1:"12",y1:"7",x2:"12",y2:"11"})]}),s("terminal:controls.mouse")]}),e.jsxs("button",{className:`controls-main-tab ${i==="trackpad"?"active":""}`,onClick:()=>j("trackpad"),children:[e.jsxs("svg",{width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",children:[e.jsx("rect",{x:"2",y:"4",width:"20",height:"16",rx:"2"}),e.jsx("circle",{cx:"12",cy:"12",r:"3"})]}),s("terminal:controls.trackpad")]})]}),i==="keyboard"&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"shortcuts-modal-toolbar",children:[d?e.jsxs("div",{className:"shortcuts-search find-by-shortcut-active",children:[e.jsxs("svg",{width:"14",height:"14",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",children:[e.jsx("rect",{x:"2",y:"4",width:"20",height:"16",rx:"2"}),e.jsx("path",{d:"M6 8h.01M10 8h.01M14 8h.01M18 8h.01M6 12h.01M18 12h.01M8 16h8"})]}),c?e.jsxs("span",{className:"find-by-shortcut-display",children:[w({key:c.key,modifiers:c.modifiers}),e.jsx("button",{className:"shortcuts-search-clear",onClick:()=>v(null),children:"×"})]}):e.jsx("span",{className:"find-by-shortcut-prompt",children:s("terminal:controls.pressKeyCombination")})]}):e.jsxs("div",{className:"shortcuts-search",children:[e.jsxs("svg",{width:"14",height:"14",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",children:[e.jsx("circle",{cx:"11",cy:"11",r:"8"}),e.jsx("path",{d:"M21 21l-4.35-4.35"})]}),e.jsx("input",{ref:x,type:"text",placeholder:s("terminal:controls.searchShortcuts"),value:f,onChange:r=>b(r.target.value),autoFocus:!0}),f&&e.jsx("button",{className:"shortcuts-search-clear",onClick:()=>b(""),children:"×"})]}),e.jsx("button",{className:`shortcuts-find-by-key-btn ${d?"active":""}`,onClick:()=>{p(!d),v(null),b("")},title:s(d?"terminal:controls.switchToTextSearch":"terminal:controls.findByPressingKeys"),children:e.jsxs("svg",{width:"14",height:"14",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",children:[e.jsx("rect",{x:"2",y:"4",width:"20",height:"16",rx:"2"}),e.jsx("path",{d:"M6 8h.01M10 8h.01M14 8h.01M18 8h.01M6 12h.01M18 12h.01M8 16h8"})]})}),e.jsx("button",{className:"shortcuts-reset-all-btn",onClick:F,children:s("common:buttons.reset")})]}),e.jsxs("div",{className:"shortcuts-context-tabs",children:[e.jsxs("button",{className:`shortcuts-context-tab ${k==="all"?"active":""}`,onClick:()=>g("all"),children:[s("common:labels.all"),e.jsx("span",{className:"shortcuts-context-tab-count",children:E.length})]}),P.map(r=>{var u;const n=((u=L[r])==null?void 0:u.length)||0;return e.jsxs("button",{className:`shortcuts-context-tab ${k===r?"active":""}`,onClick:()=>g(r),children:[s(V[r]),e.jsx("span",{className:"shortcuts-context-tab-count",children:n})]},r)})]}),e.jsxs("div",{className:"shortcuts-modal-content",children:[P.map(r=>{const n=L[r]||[];return n.length===0||k!=="all"&&k!==r?null:e.jsxs("div",{className:"shortcuts-context-group",children:[k==="all"&&e.jsxs("div",{className:"shortcuts-context-header",children:[e.jsx("span",{className:"shortcuts-context-label",children:s(V[r])}),e.jsx("span",{className:"shortcuts-context-description",children:s(Q[r])})]}),e.jsx("div",{className:"shortcuts-grid",children:n.map(u=>e.jsxs("div",{className:"shortcut-item",children:[e.jsxs("div",{className:"shortcut-item-info",children:[e.jsx("span",{className:"shortcut-item-name",children:s(`terminal:controls.shortcuts.${u.id}.name`,{defaultValue:u.name})}),e.jsx("span",{className:"shortcut-item-description",children:s(`terminal:controls.shortcuts.${u.id}.description`,{defaultValue:u.description})})]}),e.jsx(q,{shortcut:u,onUpdate:N=>G(u.id,N)})]},u.id))})]},r)}),E.length===0&&e.jsx("div",{className:"shortcuts-empty",children:d?c?e.jsx("p",{children:s("terminal:controls.noShortcutBoundTo",{keys:w({key:c.key,modifiers:c.modifiers})})}):e.jsx("p",{children:s("terminal:controls.pressKeyCombinationToFind")}):e.jsx("p",{children:s("terminal:controls.noShortcutsFound",{query:f})})})]})]}),i==="mouse"&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"shortcuts-modal-toolbar",children:[e.jsx("span",{className:"mouse-controls-subtitle",children:s("terminal:controls.cameraAndInteraction")}),e.jsx("button",{className:"shortcuts-reset-all-btn",onClick:F,children:s("common:buttons.reset")})]}),e.jsxs("div",{className:"shortcuts-modal-content mouse-controls-content",children:[e.jsx("div",{className:"mouse-controls-bindings",children:Object.entries(I).map(([r,n])=>e.jsxs("div",{className:"shortcuts-context-group",children:[e.jsx("div",{className:"shortcuts-context-header",children:e.jsx("span",{className:"shortcuts-context-label",children:s(J[r])})}),e.jsx("div",{className:"shortcuts-grid",children:n.map(u=>e.jsx(ee,{binding:u},u.id))})]},r))}),e.jsxs("div",{className:"shortcuts-context-group",children:[e.jsxs("div",{className:"shortcuts-context-header",children:[e.jsx("span",{className:"shortcuts-context-label",children:s("terminal:controls.sensitivity")}),e.jsx("span",{className:"shortcuts-context-description",children:s("terminal:controls.adjustCameraSpeed")})]}),e.jsx(te,{sensitivity:l.sensitivity})]})]})]}),i==="trackpad"&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"shortcuts-modal-toolbar",children:[e.jsx("span",{className:"mouse-controls-subtitle",children:s("terminal:controls.trackpadGestureSettings")}),e.jsx("button",{className:"shortcuts-reset-all-btn",onClick:F,children:s("common:buttons.reset")})]}),e.jsx("div",{className:"shortcuts-modal-content trackpad-controls-content",children:e.jsx(se,{config:h})})]}),e.jsx("div",{className:"shortcuts-modal-footer",children:e.jsx("span",{className:"shortcuts-modal-hint",children:s(i==="keyboard"?d?"terminal:controls.hintFindByShortcut":"terminal:controls.hintKeyboard":i==="mouse"?"terminal:controls.hintMouse":"terminal:controls.hintTrackpad")})})]})})}function ee({binding:t}){const{t:a}=S(["terminal"]),s=W(),[o,l]=m.useState(!1),[h,i]=m.useState(null);m.useEffect(()=>{if(!o)return;const d=x=>{x.preventDefault(),x.stopPropagation();const M={0:"left",1:"middle",2:"right",3:"back",4:"forward"}[x.button];M&&i({button:M,modifiers:{ctrl:x.ctrlKey,alt:x.altKey,shift:x.shiftKey,meta:x.metaKey}})},p=x=>{x.key==="Escape"&&(x.preventDefault(),x.stopPropagation(),l(!1),i(null))},c=()=>{h&&z(s.bindings,h,t.id).length===0&&y.updateMouseBinding(t.id,{button:h.button,modifiers:h.modifiers}),l(!1),i(null)},v=setTimeout(()=>{document.addEventListener("mousedown",d,!0),document.addEventListener("keydown",p,!0),document.addEventListener("click",c,!0)},100);return()=>{clearTimeout(v),document.removeEventListener("mousedown",d,!0),document.removeEventListener("keydown",p,!0),document.removeEventListener("click",c,!0)}},[o,h,t.id,s.bindings]);const j=h?z(s.bindings,h,t.id):[],f=a(`terminal:controls.mouseBindings.${t.id}.name`,{defaultValue:t.name}),b=a(`terminal:controls.mouseBindings.${t.id}.description`,{defaultValue:t.description}),k=d=>a(`terminal:controls.mouseButtons.${d}`,{defaultValue:d}),g=h?A({...t,...h},k):A(t,k);return e.jsxs("div",{className:`shortcut-item ${t.enabled?"":"disabled"}`,children:[e.jsxs("div",{className:"shortcut-item-info",children:[e.jsx("span",{className:"shortcut-item-name",children:f}),e.jsx("span",{className:"shortcut-item-description",children:b})]}),e.jsxs("div",{className:"key-capture-container",children:[e.jsx("button",{className:`key-capture-input ${o?"capturing":""} ${j.length>0?"conflict":""}`,onClick:()=>l(!0),children:o?h?e.jsx("span",{className:"key-capture-value",style:{color:"#f1fa8c"},children:g}):e.jsx("span",{style:{color:"#6272a4",fontStyle:"italic"},children:a("terminal:controls.clickToCapture")}):e.jsx("span",{className:"key-capture-value",children:g})}),j.length>0&&e.jsxs("span",{className:"key-capture-conflict",children:[a("terminal:controls.conflicts"),": ",j.map(d=>a(`terminal:controls.mouseBindings.${d.id}.name`,{defaultValue:d.name})).join(", ")]})]})]})}function te({sensitivity:t}){const{t:a}=S(["terminal"]),s=m.useCallback((o,l)=>{y.updateCameraSensitivity({[o]:l})},[]);return e.jsxs("div",{className:"sensitivity-inline-settings",children:[e.jsxs("div",{className:"sensitivity-sliders",children:[e.jsxs("div",{className:"sensitivity-slider-row",children:[e.jsx("label",{children:a("terminal:controls.panSpeed")}),e.jsx("input",{type:"range",min:"0.1",max:"3",step:"0.1",value:t.panSpeed,onChange:o=>s("panSpeed",parseFloat(o.target.value))}),e.jsxs("span",{className:"sensitivity-slider-value",children:[t.panSpeed.toFixed(1),"x"]})]}),e.jsxs("div",{className:"sensitivity-slider-row",children:[e.jsx("label",{children:a("terminal:controls.orbitSpeed")}),e.jsx("input",{type:"range",min:"0.1",max:"3",step:"0.1",value:t.orbitSpeed,onChange:o=>s("orbitSpeed",parseFloat(o.target.value))}),e.jsxs("span",{className:"sensitivity-slider-value",children:[t.orbitSpeed.toFixed(1),"x"]})]}),e.jsxs("div",{className:"sensitivity-slider-row",children:[e.jsx("label",{children:a("terminal:controls.zoomSpeed")}),e.jsx("input",{type:"range",min:"0.1",max:"3",step:"0.1",value:t.zoomSpeed,onChange:o=>s("zoomSpeed",parseFloat(o.target.value))}),e.jsxs("span",{className:"sensitivity-slider-value",children:[t.zoomSpeed.toFixed(1),"x"]})]}),e.jsxs("div",{className:"sensitivity-slider-row",children:[e.jsx("label",{children:a("terminal:controls.smoothing")}),e.jsx("input",{type:"range",min:"0",max:"1",step:"0.1",value:t.smoothing,onChange:o=>s("smoothing",parseFloat(o.target.value))}),e.jsx("span",{className:"sensitivity-slider-value",children:t.smoothing.toFixed(1)})]})]}),e.jsxs("div",{className:"sensitivity-checkboxes-inline",children:[e.jsxs("label",{className:"sensitivity-checkbox-inline",children:[e.jsx("input",{type:"checkbox",checked:t.invertPanX,onChange:o=>s("invertPanX",o.target.checked)}),e.jsx("span",{children:a("terminal:controls.invertPanX")})]}),e.jsxs("label",{className:"sensitivity-checkbox-inline",children:[e.jsx("input",{type:"checkbox",checked:t.invertPanY,onChange:o=>s("invertPanY",o.target.checked)}),e.jsx("span",{children:a("terminal:controls.invertPanY")})]}),e.jsxs("label",{className:"sensitivity-checkbox-inline",children:[e.jsx("input",{type:"checkbox",checked:t.invertOrbitX,onChange:o=>s("invertOrbitX",o.target.checked)}),e.jsx("span",{children:a("terminal:controls.invertOrbitX")})]}),e.jsxs("label",{className:"sensitivity-checkbox-inline",children:[e.jsx("input",{type:"checkbox",checked:t.invertOrbitY,onChange:o=>s("invertOrbitY",o.target.checked)}),e.jsx("span",{children:a("terminal:controls.invertOrbitY")})]})]})]})}function se({config:t}){const{t:a}=S(["terminal"]),s=m.useCallback((l,h)=>{y.updateTrackpadConfig({[l]:h})},[]),o=m.useCallback((l,h)=>{y.updateTrackpadConfig({sensitivity:{[l]:h}})},[]);return e.jsxs("div",{className:"trackpad-settings",children:[e.jsxs("div",{className:"shortcuts-context-group",children:[e.jsxs("div",{className:"shortcuts-context-header",children:[e.jsx("span",{className:"shortcuts-context-label",children:a("terminal:controls.trackpadGestures")}),e.jsx("span",{className:"shortcuts-context-description",children:a("terminal:controls.enableTrackpadSupport")})]}),e.jsx("div",{className:"trackpad-toggle-row",children:e.jsxs("label",{className:"trackpad-toggle",children:[e.jsx("input",{type:"checkbox",checked:t.enabled,onChange:l=>s("enabled",l.target.checked)}),e.jsx("span",{className:"trackpad-toggle-label",children:a("terminal:controls.enableTrackpadGestures")})]})})]}),e.jsxs("div",{className:"shortcuts-context-group",children:[e.jsxs("div",{className:"shortcuts-context-header",children:[e.jsx("span",{className:"shortcuts-context-label",children:a("terminal:controls.gestureControls")}),e.jsx("span",{className:"shortcuts-context-description",children:a("terminal:controls.enableDisableGestures")})]}),e.jsxs("div",{className:"trackpad-gestures-grid",children:[e.jsxs("label",{className:`trackpad-gesture-item ${t.enabled?"":"disabled"}`,children:[e.jsx("input",{type:"checkbox",checked:t.pinchToZoom,onChange:l=>s("pinchToZoom",l.target.checked),disabled:!t.enabled}),e.jsxs("div",{className:"trackpad-gesture-info",children:[e.jsx("span",{className:"trackpad-gesture-name",children:a("terminal:controls.pinchToZoom")}),e.jsx("span",{className:"trackpad-gesture-desc",children:a("terminal:controls.pinchToZoomDesc")})]})]}),e.jsxs("label",{className:`trackpad-gesture-item ${t.enabled?"":"disabled"}`,children:[e.jsx("input",{type:"checkbox",checked:t.twoFingerPan,onChange:l=>s("twoFingerPan",l.target.checked),disabled:!t.enabled}),e.jsxs("div",{className:"trackpad-gesture-info",children:[e.jsx("span",{className:"trackpad-gesture-name",children:a("terminal:controls.twoFingerPan")}),e.jsx("span",{className:"trackpad-gesture-desc",children:a("terminal:controls.twoFingerPanDesc")})]})]}),e.jsxs("label",{className:`trackpad-gesture-item ${t.enabled?"":"disabled"}`,children:[e.jsx("input",{type:"checkbox",checked:t.shiftTwoFingerOrbit,onChange:l=>s("shiftTwoFingerOrbit",l.target.checked),disabled:!t.enabled}),e.jsxs("div",{className:"trackpad-gesture-info",children:[e.jsx("span",{className:"trackpad-gesture-name",children:a("terminal:controls.shiftTwoFingerOrbit")}),e.jsx("span",{className:"trackpad-gesture-desc",children:a("terminal:controls.shiftTwoFingerOrbitDesc")})]})]})]})]}),e.jsxs("div",{className:"shortcuts-context-group",children:[e.jsxs("div",{className:"shortcuts-context-header",children:[e.jsx("span",{className:"shortcuts-context-label",children:a("terminal:controls.sensitivity")}),e.jsx("span",{className:"shortcuts-context-description",children:a("terminal:controls.adjustGestureSensitivity")})]}),e.jsxs("div",{className:"trackpad-sensitivity-sliders",children:[e.jsxs("div",{className:`trackpad-slider-row ${!t.enabled||!t.pinchToZoom?"disabled":""}`,children:[e.jsx("label",{children:a("terminal:controls.zoom")}),e.jsx("input",{type:"range",min:"0.1",max:"3",step:"0.1",value:t.sensitivity.zoom,onChange:l=>o("zoom",parseFloat(l.target.value)),disabled:!t.enabled||!t.pinchToZoom}),e.jsxs("span",{className:"trackpad-slider-value",children:[t.sensitivity.zoom.toFixed(1),"x"]})]}),e.jsxs("div",{className:`trackpad-slider-row ${!t.enabled||!t.twoFingerPan?"disabled":""}`,children:[e.jsx("label",{children:a("terminal:controls.pan")}),e.jsx("input",{type:"range",min:"0.1",max:"3",step:"0.1",value:t.sensitivity.pan,onChange:l=>o("pan",parseFloat(l.target.value)),disabled:!t.enabled||!t.twoFingerPan}),e.jsxs("span",{className:"trackpad-slider-value",children:[t.sensitivity.pan.toFixed(1),"x"]})]}),e.jsxs("div",{className:`trackpad-slider-row ${!t.enabled||!t.shiftTwoFingerOrbit?"disabled":""}`,children:[e.jsx("label",{children:a("terminal:controls.orbit")}),e.jsx("input",{type:"range",min:"0.1",max:"3",step:"0.1",value:t.sensitivity.orbit,onChange:l=>o("orbit",parseFloat(l.target.value)),disabled:!t.enabled||!t.shiftTwoFingerOrbit}),e.jsxs("span",{className:"trackpad-slider-value",children:[t.sensitivity.orbit.toFixed(1),"x"]})]})]})]})]})}export{oe as ControlsModal};
@@ -1,2 +0,0 @@
1
- const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/GmailOAuthSetup-io57q0N8.js","assets/main-CrRMpn-n.js","assets/modulepreload-polyfill-B5Qt9EMX.js","assets/vendor-react--Eh9ivFN.js","assets/vendor-three-Chj50gSY.js","assets/main-DjGrMNoB.css","assets/GoogleOAuthSetup-YyNFVd9Y.js"])))=>i.map(i=>d[i]);
2
- import{r as c,V as I,w,j as e,z as B,aN as R}from"./main-CrRMpn-n.js";import"./modulepreload-polyfill-B5Qt9EMX.js";import"./vendor-react--Eh9ivFN.js";import"./vendor-three-Chj50gSY.js";const z={"gmail-oauth":c.lazy(()=>R(()=>import("./GmailOAuthSetup-io57q0N8.js"),__vite__mapDeps([0,1,2,3,4,5])).then(s=>({default:s.GmailOAuthSetup}))),"google-oauth":c.lazy(()=>R(()=>import("./GoogleOAuthSetup-YyNFVd9Y.js"),__vite__mapDeps([6,1,2,3,4,5])).then(s=>({default:s.GoogleOAuthSetup})))},E={gmail:"✉️",slack:"💬",jira:"📋","google-calendar":"📅",docx:"📄"},N={gmail:"Send and receive emails through Gmail. Supports OAuth 2.0 authentication for secure access to your inbox.",slack:"Connect to Slack workspaces. Send messages, receive notifications, and integrate with channels.",jira:"Manage Jira issues and projects. Create tickets, track progress, and handle service desk requests.","google-calendar":"Access Google Calendar events. Create, update, and monitor calendar entries.",docx:"Generate and manipulate DOCX documents. Create reports, templates, and formatted documents."},A={gmail:["Google Cloud Console project","OAuth 2.0 credentials (Client ID & Secret)","Gmail API enabled"],slack:["Slack App with Bot Token and App-Level Token (Socket Mode)",'Enable Socket Mode in your app settings under "Socket Mode"','Enable Events in the "Event Subscriptions" section of your app config',"Subscribe to bot events: message.channels, message.groups, message.im","Required Bot Token scopes: channels:history, channels:read, chat:write, groups:history, groups:read, im:history, im:read, users:read"],jira:["Jira Cloud instance URL","API Token (from Atlassian account)","Account email address"],"google-calendar":["Google Cloud Console project","OAuth 2.0 credentials","Calendar API enabled"],docx:["No external credentials required","Templates directory (optional)"]},o={overlay:{position:"fixed",inset:0,background:"rgba(0, 0, 0, 0.6)",display:"flex",alignItems:"center",justifyContent:"center",zIndex:1e4,backdropFilter:"blur(4px)",animation:"fadeIn 0.15s ease-out"},modal:{background:"var(--surface-0, #1e1e2e)",borderRadius:12,border:"1px solid var(--border, #313244)",width:"90vw",maxWidth:720,maxHeight:"85vh",display:"flex",flexDirection:"column",overflow:"hidden",boxShadow:"0 20px 60px rgba(0, 0, 0, 0.5)",animation:"slideUp 0.2s ease-out"},header:{display:"flex",alignItems:"center",justifyContent:"space-between",padding:"16px 20px",borderBottom:"1px solid var(--border, #313244)",background:"var(--surface-1, #181825)"},headerTitle:{fontSize:16,fontWeight:600,color:"var(--text-primary, #cdd6f4)",display:"flex",alignItems:"center",gap:8},closeBtn:{background:"none",border:"none",color:"var(--text-secondary, #a6adc8)",fontSize:20,cursor:"pointer",padding:"4px 8px",borderRadius:6,lineHeight:1},tabs:{display:"flex",borderBottom:"1px solid var(--border, #313244)",background:"var(--surface-1, #181825)",overflowX:"auto",scrollbarWidth:"none"},tab:s=>({padding:"10px 16px",background:"none",border:"none",borderBottom:s?"2px solid var(--accent, #89b4fa)":"2px solid transparent",color:s?"var(--accent, #89b4fa)":"var(--text-secondary, #a6adc8)",fontSize:13,fontWeight:s?600:400,cursor:"pointer",display:"flex",alignItems:"center",gap:6,whiteSpace:"nowrap",transition:"color 0.15s, border-color 0.15s",flexShrink:0}),tabStatus:(s,u)=>({width:6,height:6,borderRadius:"50%",background:u?"#f38ba8":s?"#a6e3a1":"#fab387",flexShrink:0}),body:{flex:1,overflow:"auto",padding:20},integrationHeader:{display:"flex",alignItems:"flex-start",gap:12,marginBottom:16},iconCircle:{width:44,height:44,borderRadius:10,background:"var(--surface-1, #181825)",border:"1px solid var(--border, #313244)",display:"flex",alignItems:"center",justifyContent:"center",fontSize:22,flexShrink:0},integrationMeta:{flex:1},integrationName:{fontSize:15,fontWeight:600,color:"var(--text-primary, #cdd6f4)",marginBottom:4,display:"flex",alignItems:"center",gap:8},description:{fontSize:13,color:"var(--text-secondary, #a6adc8)",lineHeight:1.5},statusBadge:(s,u)=>({display:"inline-flex",alignItems:"center",gap:4,padding:"2px 8px",borderRadius:10,fontSize:11,fontWeight:600,background:u?"rgba(243, 139, 168, 0.15)":s?"rgba(166, 227, 161, 0.15)":"rgba(250, 179, 135, 0.15)",color:u?"#f38ba8":s?"#a6e3a1":"#fab387"}),section:{marginTop:16,padding:12,borderRadius:8,background:"var(--surface-1, #181825)",border:"1px solid var(--border, #313244)"},sectionTitle:{fontSize:12,fontWeight:600,color:"var(--text-secondary, #a6adc8)",textTransform:"uppercase",letterSpacing:"0.5px",marginBottom:8},requirementList:{listStyle:"none",margin:0,padding:0,display:"flex",flexDirection:"column",gap:4},requirementItem:{fontSize:12,color:"var(--text-secondary, #a6adc8)",display:"flex",alignItems:"center",gap:6},formSection:{marginTop:16},formSectionTitle:{fontSize:12,fontWeight:600,color:"var(--text-secondary, #a6adc8)",textTransform:"uppercase",letterSpacing:"0.5px",marginBottom:12}};function O({integration:s,onSave:u,onCancel:g}){const[p,T]=c.useState({...s.values}),[m,x]=c.useState({}),[h,C]=c.useState(!1),[y,b]=c.useState(!1);c.useEffect(()=>{T({...s.values}),x({}),b(!1)},[s.id]);const f=(t,l)=>{T(r=>({...r,[t]:l})),x(r=>{const i={...r};return delete i[t],i}),b(!1)},k=async t=>{t.preventDefault();const l={};for(const r of s.schema)if(r.required&&!p[r.key]&&p[r.key]!==0&&p[r.key]!==!1&&(l[r.key]=`${r.label} is required`),r.validate){const i=r.validate(p[r.key]);i&&(l[r.key]=i)}if(Object.keys(l).length>0){x(l);return}C(!0);try{await u(p),b(!0),setTimeout(()=>b(!1),3e3)}catch(r){x({_form:String(r)})}finally{C(!1)}},v=new Map;for(const t of s.schema){const l=t.group||"";v.has(l)||v.set(l,[]),v.get(l).push(t)}const n={display:"flex",flexDirection:"column",gap:4,marginBottom:12},a={fontSize:13,fontWeight:500,color:"var(--text-primary, #cdd6f4)"},d={padding:"8px 10px",borderRadius:6,border:"1px solid var(--border, #313244)",background:"var(--surface-0, #1e1e2e)",color:"var(--text-primary, #cdd6f4)",fontSize:13,outline:"none",width:"100%",boxSizing:"border-box"},S={fontSize:11,color:"var(--text-secondary, #a6adc8)"},j={fontSize:11,color:"#f38ba8"},_=t=>{var r;const l=p[t.key]??t.defaultValue??"";switch(t.type){case"boolean":return e.jsxs("label",{style:{display:"flex",alignItems:"center",gap:8,fontSize:13,color:"var(--text-primary, #cdd6f4)",cursor:"pointer"},children:[e.jsx("input",{type:"checkbox",checked:!!l,onChange:i=>f(t.key,i.target.checked)}),t.label]});case"select":return e.jsxs("select",{style:d,value:String(l),onChange:i=>f(t.key,i.target.value),children:[e.jsx("option",{value:"",children:t.placeholder||"Select..."}),(r=t.options)==null?void 0:r.map(i=>e.jsx("option",{value:i.value,children:i.label},i.value))]});case"textarea":return e.jsx("textarea",{style:{...d,resize:"vertical",minHeight:80},value:String(l),placeholder:t.placeholder,onChange:i=>f(t.key,i.target.value),rows:4});case"number":return e.jsx("input",{type:"number",style:d,value:l===""?"":Number(l),placeholder:t.placeholder,onChange:i=>f(t.key,i.target.value===""?"":Number(i.target.value))});case"password":return e.jsx("input",{type:"password",style:d,value:String(l),placeholder:t.placeholder,onChange:i=>f(t.key,i.target.value),autoComplete:"off"});default:return e.jsx("input",{type:t.type,style:d,value:String(l),placeholder:t.placeholder,onChange:i=>f(t.key,i.target.value)})}};return e.jsxs("form",{onSubmit:k,children:[m._form&&e.jsx("div",{style:{...j,marginBottom:12,padding:"8px 10px",borderRadius:6,background:"rgba(243, 139, 168, 0.1)"},children:m._form}),Array.from(v.entries()).map(([t,l])=>e.jsxs("div",{children:[t&&e.jsx("div",{style:{...o.sectionTitle,marginTop:16,marginBottom:8},children:t}),l.map(r=>e.jsxs("div",{style:n,children:[r.type!=="boolean"&&e.jsxs("label",{style:a,children:[r.label,r.required&&e.jsx("span",{style:{color:"#f38ba8",marginLeft:2},children:"*"})]}),_(r),r.description&&e.jsx("span",{style:S,children:r.description}),m[r.key]&&e.jsx("span",{style:j,children:m[r.key]})]},r.key))]},t||"_default")),e.jsxs("div",{style:{display:"flex",gap:8,justifyContent:"flex-end",marginTop:16,paddingTop:12,borderTop:"1px solid var(--border, #313244)"},children:[e.jsx("button",{type:"button",onClick:g,style:{padding:"8px 16px",borderRadius:6,border:"1px solid var(--border, #313244)",background:"none",color:"var(--text-secondary, #a6adc8)",fontSize:13,cursor:"pointer"},children:"Cancel"}),e.jsx("button",{type:"submit",disabled:h,style:{padding:"8px 16px",borderRadius:6,border:"none",background:y?"#a6e3a1":"var(--accent, #89b4fa)",color:"#1e1e2e",fontSize:13,fontWeight:600,cursor:h?"wait":"pointer",opacity:h?.7:1},children:h?"Saving...":y?"Saved":"Save Configuration"})]})]})}function W({isOpen:s,onClose:u,initialTab:g}){const[p,T]=c.useState([]),[m,x]=c.useState(g||null),[h,C]=c.useState(!0),[y,b]=c.useState(null),f=c.useRef(g||null),k=c.useCallback(async()=>{try{const a=await I(w("/api/integrations"));if(!a.ok)throw new Error(`HTTP ${a.status}`);const d=await a.json();T(d),b(null),x(S=>{const j=S||g||(d.length>0?d[0].id:null);return f.current=j,j})}catch(a){b(`Failed to load integrations: ${a}`)}finally{C(!1)}},[g]);c.useEffect(()=>{s&&(C(!0),k(),g&&x(g))},[s,g]);const v=c.useCallback(async(a,d)=>{const S=await I(w(`/api/integrations/${a}/config`),{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify(d)});if(!S.ok){const j=await S.json().catch(()=>({}));throw new Error(j.error||`HTTP ${S.status}`)}await k()},[k]);if(!s)return null;const n=p.find(a=>a.id===m);return e.jsx("div",{style:o.overlay,onClick:u,children:e.jsxs("div",{style:o.modal,onClick:a=>a.stopPropagation(),children:[e.jsxs("div",{style:o.header,children:[e.jsxs("div",{style:o.headerTitle,children:[e.jsx("span",{children:"🔌"}),e.jsx("span",{children:"Integrations"})]}),e.jsx("button",{style:o.closeBtn,onClick:u,title:"Close",children:"×"})]}),h&&e.jsx("div",{style:{padding:40,textAlign:"center",color:"var(--text-secondary, #a6adc8)"},children:"Loading integrations..."}),y&&e.jsxs("div",{style:{padding:20,textAlign:"center"},children:[e.jsx("div",{style:{color:"#f38ba8",marginBottom:8},children:y}),e.jsx("button",{onClick:k,style:{padding:"6px 12px",borderRadius:6,border:"1px solid var(--border, #313244)",background:"none",color:"var(--text-primary, #cdd6f4)",cursor:"pointer",fontSize:13},children:"Retry"})]}),!h&&!y&&p.length>0&&e.jsxs(e.Fragment,{children:[e.jsx("div",{style:o.tabs,children:p.map(a=>e.jsxs("button",{style:o.tab(m===a.id),onClick:()=>x(a.id),children:[e.jsx("span",{children:E[a.id]||"🔌"}),e.jsx("span",{children:a.name}),e.jsx("span",{style:o.tabStatus(a.status.connected,!!a.status.error)})]},a.id))}),e.jsx("div",{style:o.body,children:n&&e.jsxs("div",{children:[e.jsxs("div",{style:o.integrationHeader,children:[e.jsx("div",{style:o.iconCircle,children:E[n.id]||"🔌"}),e.jsxs("div",{style:o.integrationMeta,children:[e.jsxs("div",{style:o.integrationName,children:[n.name,e.jsx("span",{style:o.statusBadge(n.status.connected,!!n.status.error),children:n.status.error?"✗ Error":n.status.connected?"✓ Connected":"⚠ Not Configured"})]}),e.jsx("div",{style:o.description,children:N[n.id]||n.description})]})]}),n.status.error&&e.jsxs("div",{style:{...o.section,borderColor:"rgba(243, 139, 168, 0.3)",background:"rgba(243, 139, 168, 0.05)"},children:[e.jsx("div",{style:{...o.sectionTitle,color:"#f38ba8"},children:"Error"}),e.jsx("div",{style:{fontSize:12,color:"#f38ba8"},children:n.status.error})]}),A[n.id]&&e.jsxs("div",{style:o.section,children:[e.jsx("div",{style:o.sectionTitle,children:"Requirements"}),e.jsx("ul",{style:o.requirementList,children:A[n.id].map((a,d)=>e.jsxs("li",{style:o.requirementItem,children:[e.jsx("span",{style:{color:"var(--accent, #89b4fa)"},children:"•"}),a]},d))})]}),e.jsxs("div",{style:o.formSection,children:[e.jsx("div",{style:o.formSectionTitle,children:"Configuration"}),n.customComponent&&z[n.customComponent]?e.jsx(c.Suspense,{fallback:e.jsx("div",{style:{color:"var(--text-secondary)",fontSize:13},children:"Loading..."}),children:B.createElement(z[n.customComponent],{key:n.id,integration:n,onSave:a=>v(n.id,a),onCancel:u})}):e.jsx(O,{integration:n,onSave:a=>v(n.id,a),onCancel:u})]})]})})]}),!h&&!y&&p.length===0&&e.jsx("div",{style:{padding:40,textAlign:"center",color:"var(--text-secondary, #a6adc8)"},children:"No integrations available."})]})})}export{W as IntegrationsPanel};